From 4aab8762fa1a8b37cec8ca553f1ac6c186c6614d Mon Sep 17 00:00:00 2001 From: Marco Gallardo Date: Thu, 29 Mar 2012 13:02:08 -0600 Subject: [PATCH] Locator feature added marker image for publisher, showing div for address, and added functionality to close it when clicking 'X' image showing marker image in publisher renamed map-marker to locator fixed style for map marker image in publisher added locator.js to get user's location loading google maps api removed unecessary append and showing location next to publisher moved location address inside div and added image to close location styled div location address an image to close location removing location when clicking close image cleaned code cleaned code showing loader while location is being obtained, translated normal js to backbone structure, created locations db stuff, and removing location div when clicking 'share' refactored code; started to move code to backbone refactored js code; moving functionality to backbone structure created address function to make accessible address variable value refactored locator.js showing and removing location div from dom created location; it belongs_to status_message added location model and created association with status_message added hidden field for location address and added respective code on js files to retrieve it on ajax call saving location for status_message (post) removing location when sharing renamed locator backbone view to location, added template, showing location, and saving lat and lng prepared and added template to show location added location to post model in order to have it accessible in backbone retrieving location to show it in template removed console.log XD fixes when removing location cleanind location_address hidden field when location is removed more fixes; showing location when sharing saving location just when it exists created method to retrieve location address just when location was created fixed issue about showing 'Near from' message when there was not any location added style for location cleaned code renamed locator view retrieving lat and lng from locator.js saving lat and lng in location_coords saving lat and lng added style for input location_address removed location_address hidden field; the value will be taken directly from input with the location replaced div with location for input; the user will be able to edit the place avoiding submitting the form when pressing Enter key on new input for location added missed spec file for location model refactored location_view code refactored location_view code cleaned code added sinon library for testing added describes for new publisher's view functions created test for destroyLocation function added test for showLocation publisher view function created test for avoidEnter publisher view function removed unnecessary div Created first test for locations view, added more specs, added Sinon.js, and fixed issue with assets loading locator.js for tests moved location stuff to app/assets moved locator.js and sinon.js to app/assets fixed route for images included locator.js to assets fixed issue when post object is different than StatusMessage; also fixed issue with lat and lng loading Sinon for specs refactoring locator errorGettingposition and start replacing google maps stuff with OSM added OpenLayers JS, osmlocator, and added them into the main js changing the locator from Google to OSM instance changing lat and lng value in the backbone view removing google javascript tag in application layout adding jasmine to locator test and removed locator.js adding jasmine to locator test using OSM adding Jasmine test to OSM locator removed locator.js removed require locator and updated schema fixed js response; added location since we are using OSM Locator we don't need locator-spec test fixed spec for location view; we are not using google maps anymore changed description of osmlocator-spec fixed issue with status-message-location template fixed style for location_address textbox fixed tests for locator moved split function to model created test for location model removed puts added effect for location marker added translations for locator removed conflicting-unnecessary lines that were loading files for specs removed sinon library; using sinon-rails gem removed useless code removed puts; added Rails.logger.error added sinon.js file added specific version of sinon-rails gem improving validations sintax using openlayers-rails gem removed 'google API' text using sinon gem isolating LocationStream view refactored validation getting location when post is a Reshare refactored code fixed aligment for elements under location message improved styling for location message refactored begin-rescue block getting absolute root instead of just the root added address method to retrive address of location removed code from Post model; also added descriptinon why it was removed removed validation when retrieving address; with latest refactorizations we dont need them any more interpolated location; using file in locales fixed width for div of location moved Sinon gem into development and test group fixed method's description added missed indexes updated schema with locations table removed openlayers-rails gem preventing location to be saved if there are not coordinates fixed spec; wrong closing tag --- Gemfile | 3 +- Gemfile.lock | 7 +- app/assets/images/icons/marker.png | Bin 0 -> 969 bytes .../javascripts/app/views/content_view.js | 11 +++- .../javascripts/app/views/location_stream.js | 3 + .../javascripts/app/views/location_view.js | 25 +++++++ .../javascripts/app/views/publisher_view.js | 33 +++++++++- .../app/views/stream_post_views.js | 7 +- app/assets/javascripts/jasmine-load-all.js | 3 +- app/assets/javascripts/main.js | 1 + app/assets/javascripts/osmlocator.js | 23 +++++++ app/assets/stylesheets/application.css.sass | 60 +++++++++++++++++ .../status-message-location_tpl.jst.hbs | 5 ++ .../templates/stream-element_tpl.jst.hbs | 1 + app/controllers/status_messages_controller.rb | 1 + app/models/location.rb | 12 ++++ app/models/post.rb | 4 ++ app/models/reshare.rb | 4 ++ app/models/status_message.rb | 6 ++ app/presenters/post_presenter.rb | 1 + app/views/shared/_publisher.html.haml | 8 ++- config/locales/diaspora/en.yml | 1 + config/locales/javascript/javascript.en.yml | 1 + db/migrate/20120405170105_create_locations.rb | 12 ++++ db/schema.rb | 9 +++ .../app/views/location_view_spec.js | 17 +++++ .../app/views/publisher_view_spec.js | 62 ++++++++++++++++++ spec/javascripts/osmlocator-spec.js | 24 +++++++ spec/models/location_spec.rb | 15 +++++ 29 files changed, 347 insertions(+), 12 deletions(-) create mode 100644 app/assets/images/icons/marker.png create mode 100644 app/assets/javascripts/app/views/location_stream.js create mode 100644 app/assets/javascripts/app/views/location_view.js create mode 100644 app/assets/javascripts/osmlocator.js create mode 100644 app/assets/templates/status-message-location_tpl.jst.hbs create mode 100644 app/models/location.rb create mode 100644 db/migrate/20120405170105_create_locations.rb create mode 100644 spec/javascripts/app/views/location_view_spec.js create mode 100644 spec/javascripts/osmlocator-spec.js create mode 100644 spec/models/location_spec.rb diff --git a/Gemfile b/Gemfile index 4a3de515a..9c3cc781d 100644 --- a/Gemfile +++ b/Gemfile @@ -160,7 +160,7 @@ group :development do gem 'guard-rspec', '2.5.3' gem 'rb-fsevent', '0.9.3', :require => false gem 'rb-inotify', '0.9.0', :require => false - + # Preloading environment gem 'guard-spork', '1.5.0' @@ -197,4 +197,5 @@ group :development, :test do # Jasmine (client side application tests (JS)) gem 'jasmine', '1.3.2' + gem 'sinon-rails', '1.4.2.1' end diff --git a/Gemfile.lock b/Gemfile.lock index 4922904e8..952c5910c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -211,7 +211,6 @@ GEM rails multi_json (1.7.2) multipart-post (1.2.0) - mysql2 (0.3.11) nested_form (0.3.2) net-scp (1.1.0) net-ssh (>= 2.6.5) @@ -241,6 +240,7 @@ GEM multi_json (~> 1.3) omniauth-oauth (~> 1.0) orm_adapter (0.4.0) + pg (0.15.1) polyglot (0.3.3) pry (0.9.12) coderay (~> 1.0.5) @@ -357,6 +357,8 @@ GEM rack (~> 1.3, >= 1.3.6) rack-protection (~> 1.2) tilt (~> 1.3, >= 1.3.3) + sinon-rails (1.4.2.1) + railties (>= 3.1) slim (1.3.8) temple (~> 0.6.3) tilt (~> 1.3.3) @@ -441,12 +443,12 @@ DEPENDENCIES messagebus_ruby_api (= 1.0.3) mini_magick (= 3.5) mobile-fu (= 1.1.1) - mysql2 (= 0.3.11) nokogiri (= 1.5.9) omniauth (= 1.1.4) omniauth-facebook (= 1.4.1) omniauth-tumblr (= 1.1) omniauth-twitter (= 0.0.16) + pg (= 0.15.1) rack-cors (= 0.2.7) rack-google-analytics (= 0.11.0) rack-piwik (= 0.2.2) @@ -470,6 +472,7 @@ DEPENDENCIES selenium-webdriver (= 2.32.1) sidekiq (= 2.11.1) sinatra (= 1.3.3) + sinon-rails (= 1.4.2.1) slim (= 1.3.8) spork (= 1.0.0rc3) timecop (= 0.6.1) diff --git a/app/assets/images/icons/marker.png b/app/assets/images/icons/marker.png new file mode 100644 index 0000000000000000000000000000000000000000..99286532988158449b24cb190629e4f49e29d29c GIT binary patch literal 969 zcmV;)12+7LP){Q70008+X+uL$Nkc;* zP;zf(X>4Tx0C)j~RL^S@K@|QrZmG~B2wH0nvUrdpNm;9CMbtL^5n^i$+aIn^?(HA4aZWV5ov6ELTdbo0FI&wK{O>*+w4vx20?>!`FrQsdJlnHR>OPy zcd~b_n$otK2Za4V;76L-DzNVtaSB-y0*E}{p()372;bw_^6ZZ}PI-92wGS&j#91PI zKs7DSe@(bk%_Y-7gGe}(^>I=@oY#w#*Bu9GZf3^F5WP>3rn}7Ut74&?PWBFvy`A)a zPP5)V!Xd&78LdA?xQ(9mjMYElVd13a#D+Z_7&Y|xU=_C-srWU*6kiZcC!$nw*)9$7 zn6CX+@=AhmkT}X@VSsa5NKe;HZuq)~1$`#h6R+ZTR#D-3j}vF!)ZOnz+5)dI4jl{{ z44Mr{P!L4~VVJN`K!!XTF*LGrKO?IK8z<8w`3e3jI8lUGNUta*C8 zn(P`s>{pjD=7Kek#B;Fw@hxAK%$F&Q6vg9J^Xf~4by_hu-=A!MJ3Znq&n~srbFGPs zH&&aMXZ>nO`|hf|ljc?VPhR!${AbO?W8x_>CU%PFA&Hm8F7cAsOREdwU~R_;ot1_u z(ruCYB-LPGn!NQdT|ZlRy+(fw^-+`=%+gee_kY4FWHg<*4sZI8+sFJD270UUORdLHO0nA4V) z%{fwsET5CQ>B?eK%uw4yQc~9?*JVo2}ze(;aRcp*ceL#HUJSllrgm5wQKR zQu+C;QrUh^8rFfA`ftFz{YAidi-`aL010qNS#tmY3ljhU3ljkVnw%H_004nWL_t&- z8GVmI4uBvG1Y6_3_=m6cBYM=c7vjZW7g<3dHfbo`X<0OcAit3SXV7j58o60I4nw3+ zpU}kr0A7;_up2|So0|c^n(s}uNOF3bR2%frlwVO*01Ru#?LrSQJ5ep`as%KCkWFJC r1~;HtK0#f^w|a`Xx;MaKz-QA96AnSENnNl&00000NkvXXu0mjf&$+@B literal 0 HcmV?d00001 diff --git a/app/assets/javascripts/app/views/content_view.js b/app/assets/javascripts/app/views/content_view.js index 68f5f26c8..c869707b7 100644 --- a/app/assets/javascripts/app/views/content_view.js +++ b/app/assets/javascripts/app/views/content_view.js @@ -7,7 +7,8 @@ app.views.Content = app.views.Base.extend({ return _.extend(this.defaultPresenter(), { text : app.helpers.textFormatter(this.model.get("text"), this.model), largePhoto : this.largePhoto(), - smallPhotos : this.smallPhotos() + smallPhotos : this.smallPhotos(), + location: this.location() }); }, @@ -34,12 +35,16 @@ app.views.Content = app.views.Base.extend({ $(evt.currentTarget).hide(); }, + location: function(){ + var address = this.model.get('address')? this.model.get('address') : ''; + return address; + }, + collapseOversized : function() { var collHeight = 200 , elem = this.$(".collapsible") , oembed = elem.find(".oembed") , addHeight = 0; - if($.trim(oembed.html()) != "") { addHeight = oembed.height(); } @@ -100,4 +105,4 @@ app.views.OEmbed = app.views.Base.extend({ insertHTML.attr("src", insertHTML.attr("src") + paramSeparator + "autoplay=1"); this.$el.html(insertHTML); } -}) \ No newline at end of file +}); diff --git a/app/assets/javascripts/app/views/location_stream.js b/app/assets/javascripts/app/views/location_stream.js new file mode 100644 index 000000000..fbf60f580 --- /dev/null +++ b/app/assets/javascripts/app/views/location_stream.js @@ -0,0 +1,3 @@ +app.views.LocationStream = app.views.Content.extend({ + templateName: "status-message-location" +}); diff --git a/app/assets/javascripts/app/views/location_view.js b/app/assets/javascripts/app/views/location_view.js new file mode 100644 index 000000000..a01f2709d --- /dev/null +++ b/app/assets/javascripts/app/views/location_view.js @@ -0,0 +1,25 @@ +app.views.Location = Backbone.View.extend({ + + el: "#location", + + initialize: function(){ + this.render(); + this.getLocation(); + }, + + render: function(){ + $(this.el).append('delete location'); + }, + + getLocation: function(e){ + element = this.el; + + locator = new OSM.Locator(); + locator.getAddress(function(address, latlng){ + $(element).html(''); + $('#location_coords').val(latlng.latitude + "," + latlng.longitude); + $(element).append('delete location'); + }); + }, +}); + diff --git a/app/assets/javascripts/app/views/publisher_view.js b/app/assets/javascripts/app/views/publisher_view.js index 56cd35f91..137bbe381 100644 --- a/app/assets/javascripts/app/views/publisher_view.js +++ b/app/assets/javascripts/app/views/publisher_view.js @@ -23,7 +23,10 @@ app.views.Publisher = Backbone.View.extend(_.extend( "click .post_preview_button" : "createPostPreview", "click .service_icon": "toggleService", "textchange #status_message_fake_text": "handleTextchange", - "click .dropdown .dropdown_list li": "toggleAspect" + "click .dropdown .dropdown_list li": "toggleAspect", + "click #locator" : "showLocation", + "click #hide_location" : "destroyLocation", + "keypress #location_address" : "avoidEnter" }, tooltipSelector: ".service_icon", @@ -79,7 +82,9 @@ app.views.Publisher = Backbone.View.extend(_.extend( }, "aspect_ids" : serializedForm["aspect_ids[]"], "photos" : serializedForm["photos[]"], - "services" : serializedForm["services[]"] + "services" : serializedForm["services[]"], + "location_address" : $("#location_address").val(), + "location_coords" : serializedForm["location[coords]"] }, { url : "/status_messages", success : function() { @@ -94,6 +99,30 @@ app.views.Publisher = Backbone.View.extend(_.extend( // clear state this.clear(); + + // clear location + this.destroyLocation(); + }, + + // creates the location + showLocation: function(){ + if($('#location').length == 0){ + $('#publisher_textarea_wrapper').after('
'); + app.views.location = new app.views.Location(); + } + }, + + // destroys the location + destroyLocation: function(){ + if(app.views.location){ + app.views.location.remove(); + } + }, + + // avoid submitting form when pressing Enter key + avoidEnter: function(evt){ + if(evt.keyCode == 13) + return false; }, createPostPreview : function(evt) { diff --git a/app/assets/javascripts/app/views/stream_post_views.js b/app/assets/javascripts/app/views/stream_post_views.js index 89ddf9927..a8a3d8c52 100644 --- a/app/assets/javascripts/app/views/stream_post_views.js +++ b/app/assets/javascripts/app/views/stream_post_views.js @@ -7,7 +7,8 @@ app.views.StreamPost = app.views.Post.extend({ ".likes" : "likesInfoView", ".comments" : "commentStreamView", ".post-content" : "postContentView", - ".oembed" : "oEmbedView" + ".oembed" : "oEmbedView", + ".status-message-location" : "postLocationStreamView" }, events: { @@ -47,6 +48,10 @@ app.views.StreamPost = app.views.Post.extend({ return new postClass({ model : this.model }) }, + postLocationStreamView : function(){ + return new app.views.LocationStream({ model : this.model}); + }, + removeNsfwShield: function(evt){ if(evt){ evt.preventDefault(); } this.model.set({nsfw : false}) diff --git a/app/assets/javascripts/jasmine-load-all.js b/app/assets/javascripts/jasmine-load-all.js index f7ca3afb4..755afb9a7 100644 --- a/app/assets/javascripts/jasmine-load-all.js +++ b/app/assets/javascripts/jasmine-load-all.js @@ -9,4 +9,5 @@ //= require mobile //= require profile //= require people -//= require photos \ No newline at end of file +//= require photos +//= require sinon diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 5562329d4..2df7a3a00 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -42,3 +42,4 @@ //= require bootstrap-popover //= require bootstrap-dropdown //= require bootstrap-scrollspy-custom +//= require osmlocator diff --git a/app/assets/javascripts/osmlocator.js b/app/assets/javascripts/osmlocator.js new file mode 100644 index 000000000..1ff766294 --- /dev/null +++ b/app/assets/javascripts/osmlocator.js @@ -0,0 +1,23 @@ +OSM = {}; + +OSM.Locator = function(){ + + var geolocalize = function(callback){ + navigator.geolocation.getCurrentPosition(function(position) { + lat=position.coords.latitude; + lon=position.coords.longitude; + var display_name =$.getJSON("http://nominatim.openstreetmap.org/reverse?format=json&lat="+lat+"&lon="+lon+"&addressdetails=3", function(data){ + return callback(data.display_name, position.coords); + }); + },errorGettingPosition); + }; + + function errorGettingPosition(err) { + $("#location").remove(); + }; + + return { + getAddress: geolocalize + } + +} diff --git a/app/assets/stylesheets/application.css.sass b/app/assets/stylesheets/application.css.sass index c0f9c516a..bda28d483 100644 --- a/app/assets/stylesheets/application.css.sass +++ b/app/assets/stylesheets/application.css.sass @@ -573,9 +573,22 @@ ul.as-selections & > .likes, & > .comments :margin-right 15px +.status-message-location + .near-from + :font-size smaller + :color #aaa + :width 100% + :float left + .address + :font-size 11px + :color #bbb + .stream_element .post-content .reshare :border-left 2px solid #ddd +.stream_element.loaded .media .bd .feedback + :clear both + form.new_comment input :display none @@ -697,6 +710,8 @@ form p.checkbox_select :height 100% :width 100% :cursor pointer + img + :margin-right 20px #publisher :z-index 1 @@ -876,6 +891,8 @@ form p.checkbox_select :position absolute :bottom 0 :right 35px + :width 430px + :left 5px :padding 0 li @@ -3120,3 +3137,46 @@ body :bottom 3px solid #3f8fba !important :background :color #e8f7ff + +#publisher-images + #locator + :bottom 1px !important + :display inline-block + :margin 0 + :position absolute !important + :right 30px + :cursor pointer + img + :padding-top 2px + @include opacity(0.4) + &:hover + :color #666 + :cursor pointer + img + @include opacity(0.8) + .btn + :height 19px + :width 19px + +#location + :border 1px solid #999 + :height 20px + #location_address + :border none + :color #aaa + :height 10px + :width 430px + :float left + a#hide_location + :position absolute + :right 22px + :filter alpha(opacity=30) + :-moz-opacity 0.3 + :-khtml-opacity 0.3 + :opacity 0.3 + :z-index 5 + a#hide_location:hover + @include opacity(0) + :-khtml-opacity 1 + :opacity 1 + :cursor pointer diff --git a/app/assets/templates/status-message-location_tpl.jst.hbs b/app/assets/templates/status-message-location_tpl.jst.hbs new file mode 100644 index 000000000..c6c7ea7ec --- /dev/null +++ b/app/assets/templates/status-message-location_tpl.jst.hbs @@ -0,0 +1,5 @@ +{{#if location}} +
+ {{ t "publisher.near_from" location=location}} +
+{{/if}} diff --git a/app/assets/templates/stream-element_tpl.jst.hbs b/app/assets/templates/stream-element_tpl.jst.hbs index 5a4df8288..be0587f72 100644 --- a/app/assets/templates/stream-element_tpl.jst.hbs +++ b/app/assets/templates/stream-element_tpl.jst.hbs @@ -55,6 +55,7 @@ {{/if}}
+
diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb index 3b8a4d120..119442805 100644 --- a/app/controllers/status_messages_controller.rb +++ b/app/controllers/status_messages_controller.rb @@ -46,6 +46,7 @@ class StatusMessagesController < ApplicationController services = [*params[:services]].compact @status_message = current_user.build_post(:status_message, params[:status_message]) + @status_message.build_location(:address => params[:location_address], :coordinates => params[:location_coords]) if params[:location_address].present? @status_message.attach_photos_by_ids(params[:photos]) if @status_message.save diff --git a/app/models/location.rb b/app/models/location.rb new file mode 100644 index 000000000..b3896c32e --- /dev/null +++ b/app/models/location.rb @@ -0,0 +1,12 @@ +class Location < ActiveRecord::Base + + before_validation :split_coords, :on => :create + + attr_accessor :coordinates + + belongs_to :status_message + + def split_coords + coordinates.present? ? (self.lat, self.lng = coordinates.split(',')) : false + end +end diff --git a/app/models/post.rb b/app/models/post.rb index 847f7ddda..3926a0abf 100644 --- a/app/models/post.rb +++ b/app/models/post.rb @@ -66,6 +66,10 @@ class Post < ActiveRecord::Base def mentioned_people; []; end def photos; []; end + #prevents error when trying to access @post.address in a post different than Reshare and StatusMessage types; + #check PostPresenter + def address + end def self.excluding_blocks(user) people = user.blocks.map{|b| b.person_id} diff --git a/app/models/reshare.rb b/app/models/reshare.rb index e5bdba9b9..1815badb4 100644 --- a/app/models/reshare.rb +++ b/app/models/reshare.rb @@ -79,6 +79,10 @@ class Reshare < Post current end + def address + absolute_root.location.try(:address) + end + private def after_parse diff --git a/app/models/status_message.rb b/app/models/status_message.rb index 949db615e..c46c3e3d3 100644 --- a/app/models/status_message.rb +++ b/app/models/status_message.rb @@ -18,6 +18,8 @@ class StatusMessage < Post has_many :photos, :dependent => :destroy, :foreign_key => :status_message_guid, :primary_key => :guid + has_one :location + # a StatusMessage is federated before its photos are so presence_of_content() fails erroneously if no text is present # therefore, we put the validation in a before_destory callback instead of a validation before_destroy :presence_of_content @@ -164,6 +166,10 @@ class StatusMessage < Post self.oembed_url = urls.find{ |url| !TRUSTED_OEMBED_PROVIDERS.find(url).nil? } end + def address + location.try(:address) + end + protected def presence_of_content unless text_and_photos_blank? diff --git a/app/presenters/post_presenter.rb b/app/presenters/post_presenter.rb index 895ff9a4f..03d05f559 100644 --- a/app/presenters/post_presenter.rb +++ b/app/presenters/post_presenter.rb @@ -33,6 +33,7 @@ class PostPresenter :title => title, :next_post => next_post_path, :previous_post => previous_post_path, + :address => @post.address, :interactions => { :likes => [user_like].compact, diff --git a/app/views/shared/_publisher.html.haml b/app/views/shared/_publisher.html.haml index f2150dfca..f892b4e44 100644 --- a/app/views/shared/_publisher.html.haml +++ b/app/views/shared/_publisher.html.haml @@ -26,8 +26,12 @@ = status.text_area :fake_text, :rows => 2, :value => h(publisher_formatted_text), :tabindex => 1, :placeholder => "#{t('contacts.index.start_a_conversation')}..." = status.hidden_field :text, :value => h(publisher_hidden_text), :class => 'clear_on_submit' - #file-upload{:title => t('.upload_photos')} - = image_tag 'icons/camera.png', :alt => t('.upload_photos').titleize + #publisher-images + #locator.btn{:title => t('.get_location')} + = image_tag 'icons/marker.png', :alt => t('.get_location').titleize, :class => 'publisher_image' + #file-upload.btn{:title => t('.upload_photos')} + = image_tag 'icons/camera.png', :alt => t('.upload_photos').titleize, :class => 'publisher_image' + = hidden_field :location, :coords - if publisher_public = hidden_field_tag 'aspect_ids[]', "public" diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 92984d995..6b98b10b2 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -794,6 +794,7 @@ en: make_public: "make public" all: "all" upload_photos: "Upload photos" + get_location: "Get your location" all_contacts: "all contacts" share_with: "share with" whats_on_your_mind: "What's on your mind?" diff --git a/config/locales/javascript/javascript.en.yml b/config/locales/javascript/javascript.en.yml index 44e6f0e42..4c2507c2f 100644 --- a/config/locales/javascript/javascript.en.yml +++ b/config/locales/javascript/javascript.en.yml @@ -41,6 +41,7 @@ en: at_least_one_aspect: "You must publish to at least one aspect" limited: "Limited - your post will only be seen by people you are sharing with" public: "Public - your post will be visible to everyone and found by search engines" + near_from: "Near from: <%= location %>" infinite_scroll: no_more: "No more posts." no_more_contacts: "No more contacts." diff --git a/db/migrate/20120405170105_create_locations.rb b/db/migrate/20120405170105_create_locations.rb new file mode 100644 index 000000000..f46d76860 --- /dev/null +++ b/db/migrate/20120405170105_create_locations.rb @@ -0,0 +1,12 @@ +class CreateLocations < ActiveRecord::Migration + def change + create_table :locations do |t| + t.string :address + t.string :lat + t.string :lng + t.integer :status_message_id + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 9b1ff820f..79e696a65 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -151,6 +151,15 @@ ActiveRecord::Schema.define(:version => 20130404211624) do add_index "likes", ["target_id", "author_id", "target_type"], :name => "index_likes_on_target_id_and_author_id_and_target_type", :unique => true add_index "likes", ["target_id"], :name => "index_likes_on_post_id" + create_table "locations", :force => true do |t| + t.string "address" + t.string "lat" + t.string "lng" + t.integer "status_message_id" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "mentions", :force => true do |t| t.integer "post_id", :null => false t.integer "person_id", :null => false diff --git a/spec/javascripts/app/views/location_view_spec.js b/spec/javascripts/app/views/location_view_spec.js new file mode 100644 index 000000000..68e5ac59b --- /dev/null +++ b/spec/javascripts/app/views/location_view_spec.js @@ -0,0 +1,17 @@ +describe("app.views.Location", function(){ + beforeEach(function(){ + OSM = {}; + OSM.Locator = function(){return { getAddress:function(){}}}; + + this.view = new app.views.Location(); + }); + + describe("When it gets instantiated", function(){ + it("creates #location_address", function(){ + + expect($("#location_address")).toBeTruthy(); + expect($("#location_coords")).toBeTruthy(); + expect($("#hide_location")).toBeTruthy(); + }) + }); +}); diff --git a/spec/javascripts/app/views/publisher_view_spec.js b/spec/javascripts/app/views/publisher_view_spec.js index e40c66466..5c9b0866a 100644 --- a/spec/javascripts/app/views/publisher_view_spec.js +++ b/spec/javascripts/app/views/publisher_view_spec.js @@ -292,4 +292,66 @@ describe("app.views.Publisher", function() { }); }); }); + + context("locator", function() { + beforeEach(function() { + // should be jasmine helper + loginAs({name: "alice", avatar : {small : "http://avatar.com/photo.jpg"}}); + + spec.loadFixture("aspects_index"); + this.view = new app.views.Publisher(); + }); + + describe('#showLocation', function(){ + it("Show location", function(){ + + // inserts location to the DOM; it is the location's view element + setFixtures('
'); + + // creates a fake Locator + OSM = {}; + OSM.Locator = function(){return { getAddress:function(){}}}; + + // validates there is not location + expect($("#location").length).toBe(0); + + // this should create a new location + this.view.showLocation(); + + // validates there is one location created + expect($("#location").length).toBe(1); + }) + }); + + describe('#destroyLocation', function(){ + it("Destroy location if exists", function(){ + + // inserts location to the DOM; it is the location's view element + setFixtures('
'); + + // creates a new Location view with the #location element + app.views.Location = new Backbone.View({el:"#location"}); + + // creates the mock + app.views.location = sinon.mock(app.views.Location).object; + + // calls the destroy function and test the expected result + this.view.destroyLocation(); + expect($("#location").length).toBe(0); + }) + }); + + describe('#avoidEnter', function(){ + it("Avoid submitting the form when pressing enter", function(){ + // simulates the event object + evt = {}; + evt.keyCode = 13; + + // should return false in order to avoid the form submition + expect(this.view.avoidEnter(evt)).toBeFalsy(); + }) + }); + }); + }); + diff --git a/spec/javascripts/osmlocator-spec.js b/spec/javascripts/osmlocator-spec.js new file mode 100644 index 000000000..5cd22fa69 --- /dev/null +++ b/spec/javascripts/osmlocator-spec.js @@ -0,0 +1,24 @@ +describe("Locator", function(){ + navigator.geolocation['getCurrentPosition'] = function(myCallback){ + lat = 1; + lon = 2; + position = { coords: { latitude: lat, longitude: lon} } + return myCallback(position); + }; + + $.getJSON = function(url, myCallback){ + if(url == "http://nominatim.openstreetmap.org/reverse?format=json&lat=1&lon=2&addressdetails=3") + { + return myCallback({ display_name: 'locator address' }) + } + } + + var osmlocator = new OSM.Locator(); + + it("should return address, latitude, and longitude using getAddress method", function(){ + osmlocator.getAddress(function(display_name, coordinates){ + expect(display_name, 'locator address') + expect(coordinates, { latitude: 1, longitude: 2 }) + }) + }); +}); diff --git a/spec/models/location_spec.rb b/spec/models/location_spec.rb new file mode 100644 index 000000000..f3c45d654 --- /dev/null +++ b/spec/models/location_spec.rb @@ -0,0 +1,15 @@ +require 'spec_helper' + +describe Location do + describe 'before validation' do + it 'should create new location when it has coordinates' do + location = Location.new(coordinates:'1,2') + location.save.should be true + end + + it 'should not create new location when it does not have coordinates' do + location = Location.new() + location.save.should be false + end + end +end