From e72f4e1da7d2ac9fa2a77d4eec2d451ed5a96c87 Mon Sep 17 00:00:00 2001 From: MrZYX Date: Sat, 20 Nov 2010 16:35:22 +0100 Subject: [PATCH 1/8] translatable status is good again made default aspects translatable fix all the misssing translations I found cleanup en.yml --- app/helpers/dashboards_helper.rb | 2 +- app/models/user.rb | 4 +- app/views/aspects/index.html.haml | 4 +- app/views/devise/confirmations/new.html.haml | 2 +- app/views/devise/passwords/edit.html.haml | 2 +- app/views/devise/shared/_links.haml | 4 +- app/views/devise/unlocks/new.html.haml | 2 +- app/views/home/show.html.haml | 23 ++--- app/views/invitations/edit.html.haml | 2 +- app/views/layouts/_header.html.haml | 4 +- app/views/people/_profile_sidebar.html.haml | 4 +- app/views/photos/_new_photo.haml | 6 ++ app/views/photos/show.html.haml | 10 +-- .../requests/_new_request_to_person.haml | 2 +- app/views/shared/_add_contact.html.haml | 8 +- app/views/shared/_aspect_contacts.haml | 32 +++---- app/views/shared/_author_info.html.haml | 2 +- app/views/shared/_contact_list.html.haml | 2 +- app/views/shared/_publisher.haml | 4 +- app/views/status_messages/show.html.haml | 2 +- app/views/users/getting_started.html.haml | 2 +- .../users/getting_started/_step_1.html.haml | 2 +- .../users/getting_started/_step_4.html.haml | 2 +- config/locales/devise/devise.en.yml | 9 +- config/locales/diaspora/en.yml | 83 ++++++++++++------- public/javascripts/view.js | 1 + 26 files changed, 123 insertions(+), 97 deletions(-) diff --git a/app/helpers/dashboards_helper.rb b/app/helpers/dashboards_helper.rb index 57d64397c..a5cf68cd5 100644 --- a/app/helpers/dashboards_helper.rb +++ b/app/helpers/dashboards_helper.rb @@ -4,6 +4,6 @@ module DashboardsHelper def title_for_page - I18n.t('dashboards.helper.home') + I18n.t('_home') end end diff --git a/app/models/user.rb b/app/models/user.rb index 269804111..44190e99b 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -382,8 +382,8 @@ class User def seed_aspects - self.aspects.create(:name => "Family") - self.aspects.create(:name => "Work") + self.aspects.create(:name => I18n.t('aspects.seed.family')) + self.aspects.create(:name => I18n.t('aspects.seed.work')) end def as_json(opts={}) diff --git a/app/views/aspects/index.html.haml b/app/views/aspects/index.html.haml index 6331458a6..be12ea3db 100644 --- a/app/views/aspects/index.html.haml +++ b/app/views/aspects/index.html.haml @@ -4,11 +4,11 @@ .span-24.last %h2{:style => "position:relative;"} - Home + = t('_home') .right %span.description = current_user.diaspora_handle - = info_text("This is your diaspora handle. Like an email address, you can give this to people to reach you.") + = info_text(t('.handle_explanation')) .span-15.last = render 'aspects/no_contacts_message', :aspect => @aspect, :contact_count => @contacts.count diff --git a/app/views/devise/confirmations/new.html.haml b/app/views/devise/confirmations/new.html.haml index 548a024bc..04965f756 100644 --- a/app/views/devise/confirmations/new.html.haml +++ b/app/views/devise/confirmations/new.html.haml @@ -6,5 +6,5 @@ %br/ = f.text_field :email %p - = f.submit "Resend confirmation instructions" + = f.submit t('.resend_confirmation') = render :partial => "devise/shared/links" diff --git a/app/views/devise/passwords/edit.html.haml b/app/views/devise/passwords/edit.html.haml index 025c214b0..267436a63 100644 --- a/app/views/devise/passwords/edit.html.haml +++ b/app/views/devise/passwords/edit.html.haml @@ -11,5 +11,5 @@ %br/ = f.password_field :password_confirmation %p - = f.submit "Change my password" + = f.submit t('.change_password') = render :partial => "devise/shared/links" diff --git a/app/views/devise/shared/_links.haml b/app/views/devise/shared/_links.haml index ef8b2c6e1..9d0c4d843 100644 --- a/app/views/devise/shared/_links.haml +++ b/app/views/devise/shared/_links.haml @@ -8,8 +8,8 @@ = link_to t('.forgot_your_password'), new_password_path(resource_name) %br/ - if devise_mapping.confirmable? && controller_name != 'confirmations' - = link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name) + = link_to t('.receive_confirmation'), new_confirmation_path(resource_name) %br/ - if devise_mapping.lockable? && resource_class.unlock_strategy_enabled?(:email) && controller_name != 'unlocks' - = link_to "Didn't receive unlock instructions?", new_unlock_path(resource_name) + = link_to t('.receive_unlock'), new_unlock_path(resource_name) %br/ diff --git a/app/views/devise/unlocks/new.html.haml b/app/views/devise/unlocks/new.html.haml index 24b7eb862..6fff589eb 100644 --- a/app/views/devise/unlocks/new.html.haml +++ b/app/views/devise/unlocks/new.html.haml @@ -6,5 +6,5 @@ %br/ = f.text_field :email %p - = f.submit "Resend unlock instructions" + = f.submit t('.resend_unlock') = render :partial => "devise/shared/links" diff --git a/app/views/home/show.html.haml b/app/views/home/show.html.haml index 39f6ff848..554e0a766 100644 --- a/app/views/home/show.html.haml +++ b/app/views/home/show.html.haml @@ -13,27 +13,20 @@ #why.span-22.prepend-1.last .span-7 %h2 - Choice + = t('.choice') %p - Diaspora allows you to sort your connections into groups called Aspects. - Unique to Diaspora, Aspects ensure your photos, stories and jokes are shared - with only the people you want them to be. + = t('.choice_explanation') .span-7 %h2 - Ownership + = t('.ownership') %p - You own your pictures, and you shouldn’t have to give that up just in order - to share them. You maintain ownership of everything you share on Diaspora, - giving you full control over how it is distributed. - + = t('.ownership_explanation') .span-7 %h2 - Simplicity + = t('.simplicity') %p - Diaspora makes sharing clean and easy – this goes doubly so for privacy. - Innherently private, Diaspora doesn’t have pages of settings and options to - wade through to keep your profile secure and to your liking. + = t('.simplicity_explanation') .span-22.prepend-1.last @@ -47,12 +40,12 @@ #info_links.span-22.prepend-1.last .span-10 %h3 - Learn about how to host your own Diaspora server + = t('.learn_about_host') .span-11 %h3 - Learn more about Diaspora as an open source project. + = t('.learn_about_open_source') .span-24.last{:style=>"text-align:center;"} diff --git a/app/views/invitations/edit.html.haml b/app/views/invitations/edit.html.haml index 957432bb5..1eac967f6 100644 --- a/app/views/invitations/edit.html.haml +++ b/app/views/invitations/edit.html.haml @@ -10,5 +10,5 @@ = f.password_field :password_confirmation = f.hidden_field :invitation_token - = f.submit 'sign_up' + = f.submit t('.sign_up') = render :partial => "devise/shared/links" diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index 4749e3511..4c3bbc1e1 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -33,13 +33,13 @@ #aspect_nav %ul %li{:class => ("selected" if @aspect == :all)} - = link_to ((@request_count == 0)? "Home" : "Home (#{@request_count})"), root_path, :class => new_request(@request_count) + = link_to ((@request_count == 0)? t('_home') : "#{t('_home')} (#{@request_count})"), root_path, :class => new_request(@request_count) - for aspect in @aspects %li{:class => ("selected" if current_aspect?(aspect))} = link_for_aspect aspect %li - = link_to '+', '#add_aspect_pane', :class => "add_aspect_button", :title => t('.add_a_new_aspect') + = link_to '+', '#add_aspect_pane', :class => "add_aspect_button", :title => t('aspects.manage.add_a_new_aspect') .fancybox_content #add_aspect_pane diff --git a/app/views/people/_profile_sidebar.html.haml b/app/views/people/_profile_sidebar.html.haml index 954fcc92b..0f678a460 100644 --- a/app/views/people/_profile_sidebar.html.haml +++ b/app/views/people/_profile_sidebar.html.haml @@ -10,7 +10,7 @@ }); $('.delete').bind('ajax:failure', function() { - alert("Cannot remove #{person.real_name} from last aspect."); + alert("#{t('.cannot_remove', :name => person.real_name)}"); }); }); @@ -30,7 +30,7 @@ - for aspect in @aspects_with_person %li = link_to aspect.name, aspect - = link_to "x", {:controller => "aspects", :action => "remove_from_aspect", :person_id => person.id, :aspect_id => aspect.id}, :confirm => "Remove #{person.real_name} from #{aspect}?", :remote => true, :class => "delete" + = link_to "x", {:controller => "aspects", :action => "remove_from_aspect", :person_id => person.id, :aspect_id => aspect.id}, :confirm => t('.remove_from', :name => person.real_name, :aspect => aspect), :remote => true, :class => "delete" -if is_contact || person == current_user.person diff --git a/app/views/photos/_new_photo.haml b/app/views/photos/_new_photo.haml index a9b6bc29c..f17a3a0b4 100644 --- a/app/views/photos/_new_photo.haml +++ b/app/views/photos/_new_photo.haml @@ -18,6 +18,12 @@ var progress = Math.round(loaded / total * 100 ); $('#fileInfo').text(fileName + ' ' + progress + '%'); }, + + messages: { + typeError: "#{t('.invalid_ext')}", + sizeError: "#{t('.size_error')}", + emptyError: "#{t('.empty')}" + }, onSubmit: function(id, fileName){ $('#file-upload').addClass("loading"); diff --git a/app/views/photos/show.html.haml b/app/views/photos/show.html.haml index 8a12ac3be..c94cfb7a9 100644 --- a/app/views/photos/show.html.haml +++ b/app/views/photos/show.html.haml @@ -43,7 +43,7 @@ .photo_options{:data=>{:actor=>"#{@photo.person.owner.id}",:actor_person=>"#{@photo.person.id}",:image_url=>"#{@photo.url(:thumb_large)}"}} = link_to t('.make_profile_photo'), '#', :class => 'make_profile_photo' | - = link_to 'edit', '#', :id => "edit_photo_toggle" + = link_to t('.edit'), '#', :id => "edit_photo_toggle" -else = image_tag @photo.url(:scaled_full) @@ -55,7 +55,7 @@ -if @ownership #photo_edit_options - %h4 Edit photo description / delete photo + %h4= t('.edit_delete_photo') %p = form_for @photo, :remote => true do |p| = p.text_field :caption, :value => @photo.caption @@ -67,8 +67,8 @@ - if @photo.status_message_id #original_post_info %h4{:style=>"position:relative;"} - Original Post - = link_to 'view', @photo.status_message + = t('.original_post') + = link_to t('.view'), @photo.status_message %p = @photo.status_message.message @@ -77,7 +77,7 @@ - for photo in @photo.status_message.photos = link_to (image_tag photo.url(:thumb_small)), object_path(photo) - %h4 Comments + %h4= t('_comments') - if @photo.status_message_id %div{:id => 'status_message_stream', :class => 'stream show'} diff --git a/app/views/requests/_new_request_to_person.haml b/app/views/requests/_new_request_to_person.haml index b1fbee6c9..52f207b74 100644 --- a/app/views/requests/_new_request_to_person.haml +++ b/app/views/requests/_new_request_to_person.haml @@ -8,4 +8,4 @@ = request.hidden_field :to, :value => destination_handle = request.submit t('people.person.add_contact'), :disable_with => t('requests.create.sending') .message.hidden - %i sent! + %i= t('.sent') diff --git a/app/views/shared/_add_contact.html.haml b/app/views/shared/_add_contact.html.haml index ced70b7af..fb6fd8480 100644 --- a/app/views/shared/_add_contact.html.haml +++ b/app/views/shared/_add_contact.html.haml @@ -3,14 +3,14 @@ -# the COPYRIGHT file. -%h3 Add a new contact +%h3= t('aspects.manage.add_a_new_contact') = form_tag(person_by_handle_path, :id => "new_request_to_#{aspect.id}", :class => "webfinger_form", :remote => true) do =t('.enter_a_diaspora_username') %br %i= t '.your_diaspora_username_is', :diaspora_handle => current_user.diaspora_handle - = search_field_tag :diaspora_handle,'', :id => "request_d_handle_to_#{aspect.id}", :results => 5, :placeholder => "Diaspora handle" + = search_field_tag :diaspora_handle,'', :id => "request_d_handle_to_#{aspect.id}", :results => 5, :placeholder => t('.diaspora_handle') = hidden_field_tag :aspect_id, aspect.id - if defined?(getting_started) @@ -18,13 +18,13 @@ - if defined?(manage) = hidden_field_tag :manage, true - = submit_tag t('.create_request') + = submit_tag t('requests.manage_aspect_contacts.create_request') %br #loader.hidden= image_tag 'ajax-loader.gif' %ul#request_result{:aspect_id => aspect.id} %li.error.hidden #message - = link_to "Know their email address? You should invite them", "#invite_user_pane", :class => "invite_user_button" + = link_to t('requests.manage_aspect_contacts.know_email'), "#invite_user_pane", :class => "invite_user_button" %br .yo{ :style => "display:none;"} #invite_user_pane diff --git a/app/views/shared/_aspect_contacts.haml b/app/views/shared/_aspect_contacts.haml index a2b726a61..c01d80fab 100644 --- a/app/views/shared/_aspect_contacts.haml +++ b/app/views/shared/_aspect_contacts.haml @@ -25,13 +25,13 @@ $("#edit_aspect_pane").addClass("active"); $(".contact_pictures").fadeOut(200, function(){ $("#edit_aspect_pane").fadeIn(200); - trigger.html("done editing"); + trigger.html("#{t('.done_editing')}"); }); }, fadeOut: function(){ var trigger = $("#edit_aspect_trigger"); - trigger.html("edit aspect"); + trigger.html("#{t('.edit_aspect')}"); $("#edit_aspect_pane").removeClass("active"); $("#edit_aspect_pane").fadeOut(200, function(){ @@ -51,9 +51,9 @@ #new_request_pane{:class => "everyone"} %h1.new_request - if @request_count > 1 - = link_to "#{@request_count} new requests!", aspects_manage_path + = link_to t('.new_requests', :count => @request_count), aspects_manage_path - else - = link_to "#{@request_count} new request!", aspects_manage_path + = link_to t('.new_request', :count => @request_count), aspects_manage_path #left_pane{:class => ("everyone" if aspect == :all)} - if aspect == :all @@ -62,26 +62,26 @@ %h2{:style=>"position:relative;margin-bottom:0;"} = aspect .right - = link_to "edit aspect", "#", :id => "edit_aspect_trigger", :class => "button" + = link_to t('.edit_aspect'), "#", :id => "edit_aspect_trigger", :class => "button" %span.aspect_contact_count{:style=>"color:#999;font-size:14px;"} = aspect.contacts.count - if aspect.contacts.count == 1 - contact + = t('.contact') - else - contacts + = t('.contacts') - unless aspect == :all #edit_aspect_pane - if @contacts.count > 0 - %h3 Add an existing contact + %h3= t('.add_existing') = render 'shared/contact_list', :aspect => aspect, :contacts => @contacts, :manage => defined?(manage) = render 'shared/add_contact', :aspect => aspect - %h3 Aspect settings + %h3= t('.aspect_settings') .big_buttons - = button_to "Remove Aspect", aspect, :method => "delete", :confirm => "Remove aspect?" + = button_to t('.remove_aspect'), aspect, :method => "delete", :confirm => t('.confirm_remove_aspect') .contact_pictures - for contact in contacts @@ -89,7 +89,7 @@ - if aspect == :all && @contacts.count == 0 %h4 - You currently have no contacts. Find your contacts here. + = t('.no_contacts') = form_tag(people_path, :method => 'get') do = text_field_tag 'q', nil, :placeholder => t('search'), :type => 'search', :results => 5 @@ -101,9 +101,9 @@ %br %h3{:style=>"position:relative;"} - Aspects + = t('.aspects') .right{:style=>"font-size:12px;top:7px;"} - = link_to 'add aspect', '#add_aspect_pane', :class => "add_aspect_button" + = link_to t('.add_aspect'), '#add_aspect_pane', :class => "add_aspect_button" - for user_aspect in current_user.aspects @@ -111,7 +111,7 @@ %h4.aspect_title_right{:style => "margin-bottom:0;"} = link_to user_aspect, user_aspect %span{:style=>"font-size:12px;color:#888;"} - = "#{user_aspect.contacts.count} contacts" + = "#{user_aspect.contacts.count} #{t('.contacts')}" - if user_aspect.contacts.count > 0 - for aspect_contact in user_aspect.contacts[0..8] @@ -124,7 +124,7 @@ %br %br - %h3 Invites - %p invite people to join Diaspora. + %h3= t('.invites') + %p= t('.invite_people') = render "shared/invitations", :invites => @invites diff --git a/app/views/shared/_author_info.html.haml b/app/views/shared/_author_info.html.haml index 9cebe4f87..65ba39764 100644 --- a/app/views/shared/_author_info.html.haml +++ b/app/views/shared/_author_info.html.haml @@ -13,5 +13,5 @@ - for aspect in current_user.aspects_with_post( post.id ) %li= link_to aspect.name, aspect #person_nav_links - = link_to t('.view_profile'), person_path(person) + = link_to t('layouts.header.view_profile'), person_path(person) = link_to t('_photos'), person_photos_path(person) diff --git a/app/views/shared/_contact_list.html.haml b/app/views/shared/_contact_list.html.haml index 29aae463c..9b998dced 100644 --- a/app/views/shared/_contact_list.html.haml +++ b/app/views/shared/_contact_list.html.haml @@ -45,7 +45,7 @@ }); $('.remove').live('ajax:failure', function(data, html, xhr) { - alert("Cannot remove person from last aspect."); + alert("#{t('.cannot_remove')}"); }); $('.add').live('ajax:success', function(data, html, xhr) { diff --git a/app/views/shared/_publisher.haml b/app/views/shared/_publisher.haml index 265991084..7551a55c6 100644 --- a/app/views/shared/_publisher.haml +++ b/app/views/shared/_publisher.haml @@ -27,11 +27,11 @@ %ul#photodropzone = status.error_messages #file-upload.button - add photos + = t('.add_photos') %p %params - = status.label :message, t('.post_a_message_to', :aspect => (aspect == :all ? "all contacts" : aspect)) + = status.label :message, t('.post_a_message_to', :aspect => (aspect == :all ? t('.all_contacts') : aspect)) = status.text_area :message, :rows => 2, :value => params[:prefill] = status.hidden_field :to, :value => (aspect == :all ? aspect : aspect.id) diff --git a/app/views/status_messages/show.html.haml b/app/views/status_messages/show.html.haml index 3ffde4d07..5aa7c9104 100644 --- a/app/views/status_messages/show.html.haml +++ b/app/views/status_messages/show.html.haml @@ -19,7 +19,7 @@ = link_to t('.destroy'), @status_message, :confirm => t('are_you_sure'), :method => :delete .span-9.last - %h4{:style=>"margin-bottom:5px;"} Comments + %h4{:style=>"margin-bottom:5px;"}= t('_comments') %div{:class => 'stream show', :id => 'status_message_stream'} %li.message{:data=>{:guid=>@status_message.id}} = render "comments/comments", :post => @status_message diff --git a/app/views/users/getting_started.html.haml b/app/views/users/getting_started.html.haml index 68e822261..8b2a5b617 100644 --- a/app/views/users/getting_started.html.haml +++ b/app/views/users/getting_started.html.haml @@ -12,7 +12,7 @@ $(".aspects li").find(".delete").live("click", function(){ var aspectElement = $(this).parent("li"); - if (confirm("are you sure?")){ + if (confirm(#{t('are_you_sure')})){ aspectElement.fadeOut(300, function(){aspectElement.remove();}); } }); diff --git a/app/views/users/getting_started/_step_1.html.haml b/app/views/users/getting_started/_step_1.html.haml index 038d9a724..c24bc0519 100644 --- a/app/views/users/getting_started/_step_1.html.haml +++ b/app/views/users/getting_started/_step_1.html.haml @@ -5,7 +5,7 @@ = form_for @person, :html => { :multipart => true } do |person| %h3 - = t('.your_profile') + = t('people.edit.your_profile') .description = t('people.edit.info_available_to') diff --git a/app/views/users/getting_started/_step_4.html.haml b/app/views/users/getting_started/_step_4.html.haml index 99c6c5512..d749110ed 100644 --- a/app/views/users/getting_started/_step_4.html.haml +++ b/app/views/users/getting_started/_step_4.html.haml @@ -31,7 +31,7 @@ = t('.user_menu') %p = t('.manage_aspects') - %b #{t('shared.aspect_nav.manage')} + %b #{t('.manage')} = t('.tab_also_added') .submit_block diff --git a/config/locales/devise/devise.en.yml b/config/locales/devise/devise.en.yml index c6cec0c6c..77ead1831 100644 --- a/config/locales/devise/devise.en.yml +++ b/config/locales/devise/devise.en.yml @@ -27,12 +27,16 @@ en: passwords: send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' updated: 'Your password was changed successfully. You are now signed in.' + edit: + change_password: "Change my password" new: forgot_password: "Forgot your password?" send_password_instructions: "Send me reset password instructions" confirmations: send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' confirmed: 'Your account was successfully confirmed. You are now signed in.' + new: + resend_confirmation: "Resend confirmation instructions" registrations: signed_up: 'You have signed up successfully. If enabled, a confirmation was sent to your e-mail.' updated: 'You updated your account successfully.' @@ -40,6 +44,8 @@ en: unlocks: send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' unlocked: 'Your account was successfully unlocked. You are now signed in.' + new: + resend_unlock: "Resend unlock instructions" invitations: send_instructions: 'Your invitation has been sent.' invitation_token_invalid: 'The invitation token provided is not valid!' @@ -76,4 +82,5 @@ en: sign_in: 'Sign in' sign_up: 'Sign up' forgot_your_password: 'Forgot your password?' - + receive_confirmation: "Didn't receive confirmation instructions?" + receive_unlock: "Didn't receive unlock instructions?" diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 66506aad5..3f93bbf92 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -26,6 +26,8 @@ en: back: "Back" the_world: "the world" search: "Search" + _home: "Home" + _comments: "Comments" activemodel: errors: @@ -60,10 +62,6 @@ en: blog: "blog" developers: "developers" login: "login" - add_a_new_aspect: "add a new aspect" - manage: "Manage" - manage_your_aspects: "Manage your Aspects" - everyone: "Everyone" application: powered_by: "POWERED BY DIASPORA*" shared: @@ -77,27 +75,34 @@ en: share_with_all: "Share with all aspects" share_with: "Share with %{aspect}" all: "all" + add_photos: "add photos" + all_contacts: "all contacts" aspect_contacts: - add_contacts: "add contacts" - everyone: "Everyone" add_to: "add to %{aspect}" - add_a_new_contact_to: "Add a new contact to" + done_editing: "done editing" + new_requests: "%{count} new requests!" + new_request: "%{count} new request!" + edit_aspect: "edit aspect" + contact: "contact" + contacts: "contacts" + add_existing: "Add an existing contact" + aspect_settings: "Aspect settings" + remove_aspect: "Remove Aspect" + confirm_remove_aspect: "Remove aspect?" + no_contacts: "You currently have no contacts. Find your contacts here." + aspects: "Aspects" + add_aspect: "add aspect" + invites: "Invites" + invite_people: "invite people to join Diaspora." add_contact: enter_a_diaspora_username: "Enter a Diaspora username:" your_diaspora_username_is: "Your Diaspora username is: %{diaspora_handle}" - contact_username: "Contact's username" - create_request: "Create request" + diaspora_handle: "Diaspora handle" invitations: - invites: "Invites" invite_someone: "Invite someone" invitations_left: "(%{count} left)" reshare: reshare: "Reshare" - author_info: - view_profile: "View profile" - status_messages: "status messages" - viewing: "viewing" - all: "all" public_explain: title: "You are about to post a public message!" outside: "Public messages will be available for others outside of Diaspora to see." @@ -107,8 +112,7 @@ en: new: "New %{type} from %{from}" contact_list: search_contacts: "Search contacts" - add_to: "Add %{name} to %{aspect}" - remove_from: "Remove %{name} from %{aspect}" + cannot_remove: "Cannot remove person from last aspect." aspects: no_contacts_message: nobody: "We know you know people — bring them to Diaspora!" @@ -149,6 +153,11 @@ en: remove_from_aspect: success: "Successfully removed person from aspect" failure: "Failed to remove person from aspect" + seed: + family: "Family" + work: "Work" + index: + handle_explanation: "This is your diaspora handle. Like an email address, you can give this to people to reach you." users: edit: invite_contacts: "Invite contacts" @@ -169,8 +178,6 @@ en: finished: "Finished!" skip: "skip getting started" save_and_continue: "Save and continue" - step_1: - your_profile: "Your Profile" step_2: your_aspects: "Your aspects" description: "Tell Diaspora what different aspects of you are seen by different contacts. You can manage these later by clicking the manage tab on the top right. Your aspects are unique to you, and not visible by others." @@ -189,6 +196,7 @@ en: manage_aspects: "You can manage your aspects any time by clicking the" tab_also_added: "tab. Your contacts can also be added while on a particular aspect page, as well." finish: "Finish" + manage: "Manage" update: password_changed: "Password Changed" password_not_changed: "Password Change Failed" @@ -203,13 +211,12 @@ en: photos: show: delete_photo: "Delete Photo" - prev: "prev" - full_size: "full size" - next: "next" - edit_photo: "Edit Photo" - add_a_description: "Add a description" make_profile_photo: "make profile photo" update_photo: "Update Photo" + view: "view" + edit: "edit" + edit_delete_photo: "Edit photo description / delete photo" + original_post: "Original Post" edit: editing: "Editing" photo: @@ -228,9 +235,6 @@ en: destroy: notice: "Photo deleted." new_photo: - drop: "Drop photos here to upload" - upload: "Upload a photo" - failed: "Failed" invalid_ext: "{file} has invalid extension. Only {extensions} are allowed." size_error: "{file} is too large, maximum file size is {sizeLimit}." empty: "{file} is empty, please select files again without it." @@ -263,6 +267,8 @@ en: send_invitation: "Send invitation" check_token: not_found: "Invitation token not found" + edit: + sign_up: "sign_up" status_messages: new_status_message: tell_me_something_good: "tell me something good" @@ -305,11 +311,12 @@ en: profile_sidebar: remove_contact: "remove contact" edit_my_profile: "Edit my profile" - last_seen: "last seen: %{how_long_ago}" bio: "bio" gender: "gender" born: "born" in_aspects: "in aspects" + cannot_remove: "Cannot remove %{name} from last aspect." + remove_from: "Remove %{name} from %{aspect}?" helper: results_for: " results for %{params}" people_on_pod_are_aware_of: " people on pod are aware of" @@ -329,7 +336,8 @@ en: create: sending: "Sending..." sent: "You've asked to share with %{name}. They should see it next time they log in to Diaspora." - tried: "we tried our best to send a message to %{account}" + new_request_to_person: + sent: "sent!" services: index: logged_in_as: "logged in as" @@ -341,9 +349,6 @@ en: success: "Authentication successful." destroy: success: "Successfully destroyed authentication." - dashboards: - helper: - home: "Home" notifier: hello: "Hello %{name}!" love: "love," @@ -362,3 +367,17 @@ en: share_what_you_want: "Share what you want, with who you want." already_account: "already have an account?" login_here: "log in here" + choice: "Choice" + choice_explanation: "Diaspora allows you to sort your connections into groups called Aspects. +Unique to Diaspora, Aspects ensure your photos, stories and jokes are shared +with only the people you want them to be." + ownership: "Ownership" + ownership_explanation: "You own your pictures, and you shouldn’t have to give that up just in order +to share them. You maintain ownership of everything you share on Diaspora, +giving you full control over how it is distributed." + simplicity: "Simplicity" + simplicity_explanation: "Diaspora makes sharing clean and easy – this goes doubly so for privacy. +Innherently private, Diaspora doesn’t have pages of settings and options to +wade through to keep your profile secure and to your liking." + learn_about_host: "Learn about how to host your own Diaspora server" + learn_about_open_source: "Learn more about Diaspora as an open source project." diff --git a/public/javascripts/view.js b/public/javascripts/view.js index f67dc0d7d..3e8138c19 100644 --- a/public/javascripts/view.js +++ b/public/javascripts/view.js @@ -121,6 +121,7 @@ $.fn.clearForm = function() { var video_active_container = null; + function openVideo(type, videoid, link) { var container = document.createElement('div'), $container = $(container); From ab37fd0d9863b2fb3e2242c92ebe5ea11f44cd22 Mon Sep 17 00:00:00 2001 From: Sarah Mei Date: Mon, 22 Nov 2010 14:11:27 -0800 Subject: [PATCH 2/8] Fix type-o on front page, copy edit a bit. --- config/locales/diaspora/en.yml | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 3f93bbf92..51901b871 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -368,16 +368,10 @@ en: already_account: "already have an account?" login_here: "log in here" choice: "Choice" - choice_explanation: "Diaspora allows you to sort your connections into groups called Aspects. -Unique to Diaspora, Aspects ensure your photos, stories and jokes are shared -with only the people you want them to be." + choice_explanation: "Diaspora lets you sort your connections into groups called aspects. Unique to Diaspora, aspects ensure that your photos, stories and jokes are shared only with the people you intend." ownership: "Ownership" - ownership_explanation: "You own your pictures, and you shouldn’t have to give that up just in order -to share them. You maintain ownership of everything you share on Diaspora, -giving you full control over how it is distributed." + ownership_explanation: "You own your pictures, and you shouldn’t have to give that up just to share them. You maintain ownership of everything you share on Diaspora, giving you full control over how it's distributed." simplicity: "Simplicity" - simplicity_explanation: "Diaspora makes sharing clean and easy – this goes doubly so for privacy. -Innherently private, Diaspora doesn’t have pages of settings and options to -wade through to keep your profile secure and to your liking." + simplicity_explanation: "Diaspora makes sharing clean and easy – and this goes for privacy too. Inherently private, Diaspora doesn’t make you wade through pages of settings and options just to keep your profile secure." learn_about_host: "Learn about how to host your own Diaspora server" learn_about_open_source: "Learn more about Diaspora as an open source project." From 0e7b1f5eb718fac9b68b7637bc5b757dc49232e6 Mon Sep 17 00:00:00 2001 From: danielvincent Date: Mon, 22 Nov 2010 13:26:00 -0800 Subject: [PATCH 3/8] status messages and comments made by user will ajax onto the current page, and websocket everywhere else. --- app/controllers/comments_controller.rb | 10 +++- app/controllers/status_messages_controller.rb | 13 ++++- app/helpers/sockets_helper.rb | 3 +- app/views/comments/_comment.html.haml | 2 +- public/javascripts/stream.js | 17 ++++++ public/javascripts/web-socket-receiver.js | 56 ++++++++++--------- 6 files changed, 71 insertions(+), 30 deletions(-) diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb index b8f051e57..5b39a1008 100644 --- a/app/controllers/comments_controller.rb +++ b/app/controllers/comments_controller.rb @@ -3,6 +3,7 @@ # the COPYRIGHT file. class CommentsController < ApplicationController + include ApplicationHelper before_filter :authenticate_user! respond_to :html @@ -15,7 +16,14 @@ class CommentsController < ApplicationController @comment = current_user.comment(text, :on => target) if target if @comment Rails.logger.info("event=comment_create user=#{current_user.inspect} status=success comment=#{@comment.inspect}") - render :nothing => true, :status => 201 + + respond_to do |format| + format.js{ render :json => { :post_id => @comment.post_id, + :comment_id => @comment.id, + :html => render_to_string(:partial => type_partial(@comment), :locals => {:post => @comment, :current_user => current_user})}, + :status => 201 } + format.html{ render :nothing => true, :status => 201 } + end else render :nothing => true, :status => 401 end diff --git a/app/controllers/status_messages_controller.rb b/app/controllers/status_messages_controller.rb index 54487dbeb..d4992fb25 100644 --- a/app/controllers/status_messages_controller.rb +++ b/app/controllers/status_messages_controller.rb @@ -26,9 +26,18 @@ class StatusMessagesController < ApplicationController for photo in photos current_user.dispatch_post(photo, :to => params[:status_message][:to]) end + + respond_to do |format| + format.js{ render :json => { :post_id => @status_message.id, + :html => render_to_string(:partial => 'shared/stream_element', :locals => {:post => @status_message, :current_user => current_user})}, + :status => 201 } + format.html{ respond_with @status_message } + end + else + respond_to do |format| + format.js{ render :status => 401 } + end end - - render :nothing => true end diff --git a/app/helpers/sockets_helper.rb b/app/helpers/sockets_helper.rb index d646f0e4e..214665ef3 100644 --- a/app/helpers/sockets_helper.rb +++ b/app/helpers/sockets_helper.rb @@ -23,13 +23,14 @@ module SocketsHelper Rails.logger.error("web socket view rendering failed for object #{object.inspect}.") raise e end - action_hash = {:class =>object.class.to_s.underscore.pluralize, :html => v, :post_id => obj_id(object)} + action_hash = {:class =>object.class.to_s.underscore.pluralize, :html => v, :post_id => obj_id(object)} action_hash.merge! opts if object.is_a? Photo action_hash[:photo_hash] = object.thumb_hash end if object.is_a? Comment + action_hash[:comment_id] = object.id action_hash[:my_post?] = (object.post.person.owner.id == uid) action_hash[:notification] = notification(object) end diff --git a/app/views/comments/_comment.html.haml b/app/views/comments/_comment.html.haml index f84d4b6d5..fe94bd6fd 100644 --- a/app/views/comments/_comment.html.haml +++ b/app/views/comments/_comment.html.haml @@ -2,7 +2,7 @@ -# licensed under the Affero General Public License version 3 or later. See -# the COPYRIGHT file. -%li.comment +%li.comment{:data=>{:guid=>post.id}} = person_image_link(post.person) .content .from diff --git a/public/javascripts/stream.js b/public/javascripts/stream.js index a3495e720..1a8e9b31b 100644 --- a/public/javascripts/stream.js +++ b/public/javascripts/stream.js @@ -6,6 +6,7 @@ $(document).ready(function(){ var $stream = $(".stream"); + var $publisher = $("#publisher"); // expand all comments on page load $(".stream:not('.show')").find('.comments').each(function(index) { var comments = $(this); @@ -51,6 +52,22 @@ $(document).ready(function(){ } }); + $(".new_status_message").bind('ajax:success', function(data, json, xhr){ + json = $.parseJSON(json); + WebSocketReceiver.addPostToStream(json['post_id'],json['html']); + }); + $(".new_status_message").bind('ajax:failure', function(data, html, xhr){ + alert('failed to post message!'); + }); + + $(".new_comment").live('ajax:success', function(data, json, xhr){ + json = $.parseJSON(json); + WebSocketReceiver.processComment(json['post_id'],json['comment_id'],json['html'],false); + }); + $(".new_comment").live('ajax:failure', function(data, html, xhr){ + alert('failed to post message!'); + }); + });//end document ready diff --git a/public/javascripts/web-socket-receiver.js b/public/javascripts/web-socket-receiver.js index 4fa546f93..66b044cc2 100644 --- a/public/javascripts/web-socket-receiver.js +++ b/public/javascripts/web-socket-receiver.js @@ -27,10 +27,10 @@ var WebSocketReceiver = { WebSocketReceiver.processRetraction(obj['post_id']); }else if (obj['class']=="comments"){ - WebSocketReceiver.processComment(obj['post_id'], obj['html'], {'notification':obj['notification'], 'mine?':obj['mine?'], 'my_post?':obj['my_post?']}) + WebSocketReceiver.processComment(obj['post_id'], obj['comment_id'], obj['html'], {'notification':obj['notification'], 'mine?':obj['mine?'], 'my_post?':obj['my_post?']}) }else{ - WebSocketReceiver.processPost(obj['class'], obj['html'], obj['aspect_ids']) + WebSocketReceiver.processPost(obj['class'], obj['post_id'], obj['html'], obj['aspect_ids']) } } }, @@ -62,44 +62,50 @@ var WebSocketReceiver = { } }, - processComment: function(post_id, html, opts){ - post = $("*[data-guid='"+post_id+"']'"); - $('.comments li:last', post ).before( - $(html).fadeIn("fast", function(){}) - ); - toggler = $('.show_post_comments', post); + processComment: function(postId, commentId, html, opts){ - if(toggler.length > 0){ - toggler.html( - toggler.html().replace(/\d+/,$('.comments', post)[0].childElementCount -1) + if( $(".comment[data-guid='"+commentId+"']").length == 0 ){ + + post = $("*[data-guid='"+postId+"']'"); + $('.comments li:last', post ).before( + $(html).fadeIn("fast", function(){}) ); + toggler = $('.show_post_comments', post); - if( !$(".comments", post).is(':visible') ){ - toggler.click(); + if(toggler.length > 0){ + toggler.html( + toggler.html().replace(/\d+/,$('.comments', post)[0].childElementCount -1) + ); + + if( !$(".comments", post).is(':visible') ){ + toggler.click(); + } } - } - if( !opts['mine?'] && opts['my_post?']) { - WebSocketReceiver.processNotification(opts['notification']); + if( !opts['mine?'] && opts['my_post?']) { + WebSocketReceiver.processNotification(opts['notification']); + } } }, - processPost: function(className, html, aspectIds){ + processPost: function(className, postId, html, aspectIds){ if(WebSocketReceiver.onPageForAspects(aspectIds)){ if( $("#no_posts").is(":visible") ){ - $("#no_posts").fadeOut(400, WebSocketReceiver.addPostToStream(html)).hide(); + $("#no_posts").fadeOut(400, WebSocketReceiver.addPostToStream(postId, html)).hide(); } else { - WebSocketReceiver.addPostToStream(html); + WebSocketReceiver.addPostToStream(postId, html); } } }, - addPostToStream: function(html){ - $("#main_stream:not('.show')").prepend( - $(html).fadeIn("fast", function(){ - $("#main_stream").find("label").first().inFieldLabels(); - }) - ); + addPostToStream: function(postId, html){ + if( $(".message[data-guid='"+postId+"']").length == 0 ){ + $("#main_stream:not('.show')").prepend( + $(html).fadeIn("fast", function(){ + $("#main_stream").find("label").first().inFieldLabels(); + }) + ); + } }, onPageForClass: function(className){ From 26a11f7ab60205336ed33624db93281c7c276dfb Mon Sep 17 00:00:00 2001 From: danielvincent Date: Mon, 22 Nov 2010 14:52:01 -0800 Subject: [PATCH 4/8] firefox bugfix on photo#show --- public/stylesheets/sass/application.sass | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/public/stylesheets/sass/application.sass b/public/stylesheets/sass/application.sass index 4cc044cc5..1859a8e91 100644 --- a/public/stylesheets/sass/application.sass +++ b/public/stylesheets/sass/application.sass @@ -159,8 +159,9 @@ header :background :color #000 - :border - :radius 5px + :-webkit-border-radius 5px + :-moz-border-radius 5px + :border-radius 5px :position absolute :display inline @@ -688,6 +689,8 @@ li.message .from .right :-moz-border-radius 3px :border-radius 3px + :max-width 100% + img :z-index 2 :position relative @@ -1261,7 +1264,10 @@ ul#settings_nav :color rgb(250,250,250) :border 1px solid #ddd :padding 11px + :-webkit-border-radius 4px + :-moz-border-radius 4px + :border-radius 4px h2,h3 :border @@ -1954,6 +1960,8 @@ h3,h4 :color #ccc :-webkit-border-radius 10px + :-moz-border-radius 10px + :border-radius 10px :width 15px :max-width 12px From edbb0bdf07c6dbbb225b5a42cec2682fea4ed835 Mon Sep 17 00:00:00 2001 From: zhitomirskiyi Date: Mon, 22 Nov 2010 14:52:39 -0800 Subject: [PATCH 5/8] slightly more discriptive cannot remove the person from the last aspect messagge --- config/deploy_config.yml | 2 +- config/locales/diaspora/en.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/deploy_config.yml b/config/deploy_config.yml index 6538e273c..06a6747e1 100644 --- a/config/deploy_config.yml +++ b/config/deploy_config.yml @@ -6,7 +6,7 @@ cross_server: deploy_to: '/usr/local/app/diaspora' user: 'root' repo: 'git://github.com/diaspora/diaspora.git' - branch: 'homepage' + branch: 'master' default_env: 'development' servers: tom: diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 51901b871..58a4e5b4a 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -112,7 +112,7 @@ en: new: "New %{type} from %{from}" contact_list: search_contacts: "Search contacts" - cannot_remove: "Cannot remove person from last aspect." + cannot_remove: "Cannot remove person from last aspect.(If you want to disconnect from this person you must remove contact.)" aspects: no_contacts_message: nobody: "We know you know people — bring them to Diaspora!" From e84ce5591f594faa0907bd020bd79e9dadad13a1 Mon Sep 17 00:00:00 2001 From: zhitomirskiyi Date: Mon, 22 Nov 2010 14:55:30 -0800 Subject: [PATCH 6/8] The discription in several places --- config/locales/diaspora/en.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/config/locales/diaspora/en.yml b/config/locales/diaspora/en.yml index 58a4e5b4a..e33a0d542 100644 --- a/config/locales/diaspora/en.yml +++ b/config/locales/diaspora/en.yml @@ -112,7 +112,7 @@ en: new: "New %{type} from %{from}" contact_list: search_contacts: "Search contacts" - cannot_remove: "Cannot remove person from last aspect.(If you want to disconnect from this person you must remove contact.)" + cannot_remove: "Cannot remove person from last aspect. (If you want to disconnect from this person you must remove contact.)" aspects: no_contacts_message: nobody: "We know you know people — bring them to Diaspora!" @@ -315,7 +315,7 @@ en: gender: "gender" born: "born" in_aspects: "in aspects" - cannot_remove: "Cannot remove %{name} from last aspect." + cannot_remove: "Cannot remove %{name} from last aspect. (If you want to disconnect from this person you must remove contact.)" remove_from: "Remove %{name} from %{aspect}?" helper: results_for: " results for %{params}" From bedc7ca41b250487d24e0f748ed47d08365a5978 Mon Sep 17 00:00:00 2001 From: Sarah Mei Date: Mon, 22 Nov 2010 15:02:25 -0800 Subject: [PATCH 7/8] Made landing page and log in views content-type agnostic. Added an un-minified version of jquery-mobile for debugging. --- app/views/aspects/index.mobile.haml | 12 +- .../sessions/{new.html.haml => new.haml} | 0 app/views/home/{show.html.haml => show.haml} | 0 config/assets.yml | 1 - public/javascripts/custom-mobile-scripting.js | 14 +- public/javascripts/vendor/jquery_mobile_a2.js | 3541 +++++++++++++++++ 6 files changed, 3552 insertions(+), 16 deletions(-) rename app/views/devise/sessions/{new.html.haml => new.haml} (100%) rename app/views/home/{show.html.haml => show.haml} (100%) create mode 100644 public/javascripts/vendor/jquery_mobile_a2.js diff --git a/app/views/aspects/index.mobile.haml b/app/views/aspects/index.mobile.haml index 95c790844..51b700fe0 100644 --- a/app/views/aspects/index.mobile.haml +++ b/app/views/aspects/index.mobile.haml @@ -1,13 +1,9 @@ +-# Copyright (c) 2010, Diaspora Inc. This file is +-# licensed under the Affero General Public License version 3 or later. See +-# the COPYRIGHT file. + %div{:data => {:role => 'content'}} %div{:data => {:role => 'fieldcontain'}} =render 'shared/publisher', :aspect => @aspect = render 'shared/stream', :posts => @posts - -/%div{:data => {:role => 'footer', :id => 'footer-toolbar', :position => 'fixed'}} -/ %div{:data => {:role => 'navbar'}} -/ %ul -/ %li{:class => 'ui-btn-active'} -/ = link_to 'posts', '#' -/ %li -/ =link_to 'contacts', '#' diff --git a/app/views/devise/sessions/new.html.haml b/app/views/devise/sessions/new.haml similarity index 100% rename from app/views/devise/sessions/new.html.haml rename to app/views/devise/sessions/new.haml diff --git a/app/views/home/show.html.haml b/app/views/home/show.haml similarity index 100% rename from app/views/home/show.html.haml rename to app/views/home/show.haml diff --git a/config/assets.yml b/config/assets.yml index 4a194cd3f..5a14264ae 100644 --- a/config/assets.yml +++ b/config/assets.yml @@ -17,7 +17,6 @@ javascripts: mobile: - public/javascripts/vendor/jquery144.min.js - public/javascripts/custom-mobile-scripting.js - - public/javascripts/rails.js - public/javascripts/vendor/jquery-ui-1.8.6.custom.min.js - public/javascripts/vendor/jquery_mobile_a2.min.js - public/javascripts/mobile.js diff --git a/public/javascripts/custom-mobile-scripting.js b/public/javascripts/custom-mobile-scripting.js index e435105d3..6d7583b6a 100644 --- a/public/javascripts/custom-mobile-scripting.js +++ b/public/javascripts/custom-mobile-scripting.js @@ -1,7 +1,7 @@ -$(document).bind("mobileinit", function(){ - $.extend( $.mobile , { - - ajaxLinksEnabled : false - ajaxFormsEnabled : false - }); -}); +// $(document).bind("mobileinit", function(){ +// $.extend( $.mobile , { +// +// ajaxLinksEnabled : false +// ajaxFormsEnabled : false +// }); +// }); diff --git a/public/javascripts/vendor/jquery_mobile_a2.js b/public/javascripts/vendor/jquery_mobile_a2.js new file mode 100644 index 000000000..6b9484d23 --- /dev/null +++ b/public/javascripts/vendor/jquery_mobile_a2.js @@ -0,0 +1,3541 @@ +/*! + * jQuery Mobile v1.0a2 + * http://jquerymobile.com/ + * + * Copyright 2010, jQuery Project + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + */ +/*! + * jQuery UI Widget @VERSION + * + * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Widget + */ +(function( $, undefined ) { + +// jQuery 1.4+ +if ( $.cleanData ) { + var _cleanData = $.cleanData; + $.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + $( elem ).triggerHandler( "remove" ); + } + _cleanData( elems ); + }; +} else { + var _remove = $.fn.remove; + $.fn.remove = function( selector, keepData ) { + return this.each(function() { + if ( !keepData ) { + if ( !selector || $.filter( selector, [ this ] ).length ) { + $( "*", this ).add( [ this ] ).each(function() { + $( this ).triggerHandler( "remove" ); + }); + } + } + return _remove.call( $(this), selector, keepData ); + }); + }; +} + +$.widget = function( name, base, prototype ) { + var namespace = name.split( "." )[ 0 ], + fullName; + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName ] = function( elem ) { + return !!$.data( elem, name ); + }; + + $[ namespace ] = $[ namespace ] || {}; + $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without initializing for simple inheritance + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + + var basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from +// $.each( basePrototype, function( key, val ) { +// if ( $.isPlainObject(val) ) { +// basePrototype[ key ] = $.extend( {}, val ); +// } +// }); + basePrototype.options = $.extend( true, {}, basePrototype.options ); + $[ namespace ][ name ].prototype = $.extend( true, basePrototype, { + namespace: namespace, + widgetName: name, + widgetEventPrefix: $[ namespace ][ name ].prototype.widgetEventPrefix || name, + widgetBaseClass: fullName + }, prototype ); + + $.widget.bridge( name, $[ namespace ][ name ] ); +}; + +$.widget.bridge = function( name, object ) { + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = Array.prototype.slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.extend.apply( null, [ true, options ].concat(args) ) : + options; + + // prevent calls to internal methods + if ( isMethodCall && options.charAt( 0 ) === "_" ) { + return returnValue; + } + + if ( isMethodCall ) { + this.each(function() { + var instance = $.data( this, name ); + if ( !instance ) { + throw "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'"; + } + if ( !$.isFunction( instance[options] ) ) { + throw "no such method '" + options + "' for " + name + " widget instance"; + } + var methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, name ); + if ( instance ) { + instance.option( options || {} )._init(); + } else { + $.data( this, name, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( options, element ) { + // allow instantiation without initializing for simple inheritance + if ( arguments.length ) { + this._createWidget( options, element ); + } +}; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + options: { + disabled: false + }, + _createWidget: function( options, element ) { + // $.widget.bridge stores the plugin instance, but we do it anyway + // so that it's stored even before the _create function runs + $.data( element, this.widgetName, this ); + this.element = $( element ); + this.options = $.extend( true, {}, + this.options, + this._getCreateOptions(), + options ); + + var self = this; + this.element.bind( "remove." + this.widgetName, function() { + self.destroy(); + }); + + this._create(); + this._trigger( "create" ); + this._init(); + }, + _getCreateOptions: function() { + var options = {}; + if ( $.metadata ) { + options = $.metadata.get( element )[ this.widgetName ]; + } + return options; + }, + _create: function() {}, + _init: function() {}, + + destroy: function() { + this.element + .unbind( "." + this.widgetName ) + .removeData( this.widgetName ); + this.widget() + .unbind( "." + this.widgetName ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetBaseClass + "-disabled " + + "ui-state-disabled" ); + }, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.extend( {}, this.options ); + } + + if (typeof key === "string" ) { + if ( value === undefined ) { + return this.options[ key ]; + } + options = {}; + options[ key ] = value; + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var self = this; + $.each( options, function( key, value ) { + self._setOption( key, value ); + }); + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + [ value ? "addClass" : "removeClass"]( + this.widgetBaseClass + "-disabled" + " " + + "ui-state-disabled" ) + .attr( "aria-disabled", value ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _trigger: function( type, event, data ) { + var callback = this.options[ type ]; + + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + data = data || {}; + + // copy original event properties over to the new event + // this would happen if we could call $.event.fix instead of $.Event + // but we don't have a way to force an event to be fixed multiple times + if ( event.originalEvent ) { + for ( var i = $.event.props.length, prop; i; ) { + prop = $.event.props[ --i ]; + event[ prop ] = event.originalEvent[ prop ]; + } + } + + this.element.trigger( event, data ); + + return !( $.isFunction(callback) && + callback.call( this.element[0], event, data ) === false || + event.isDefaultPrevented() ); + } +}; + +})( jQuery ); +/* +* jQuery Mobile Framework : widget factory extentions for mobile +* Copyright (c) jQuery Project +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* Note: Code is in draft form and is subject to change +*/ +(function($, undefined ) { + +$.widget( "mobile.widget", { + _getCreateOptions: function() { + var elem = this.element, + options = {}; + $.each( this.options, function( option ) { + var value = elem.data( option.replace( /[A-Z]/g, function( c ) { + return "-" + c.toLowerCase(); + } ) ); + if ( value !== undefined ) { + options[ option ] = value; + } + }); + return options; + } +}); + +})( jQuery ); +/* +* jQuery Mobile Framework : support tests +* Copyright (c) jQuery Project +* Dual licensed under the MIT (MIT-LICENSE.txt) and GPL (GPL-LICENSE.txt) licenses. +* Note: Code is in draft form and is subject to change +*/ +(function($, undefined ) { + +// test whether a CSS media type or query applies +$.media = (function() { + // TODO: use window.matchMedia once at least one UA implements it + var cache = {}, + $html = $( "html" ), + testDiv = $( "
" ), + fakeBody = $( "" ).append( testDiv ); + + return function( query ) { + if ( !( query in cache ) ) { + var styleBlock = $( "" ); + $html.prepend( fakeBody ).prepend( styleBlock ); + cache[ query ] = testDiv.css( "position" ) === "absolute"; + fakeBody.add( styleBlock ).remove(); + } + return cache[ query ]; + }; +})(); + +var fakeBody = $( "" ).prependTo( "html" ), + fbCSS = fakeBody[0].style, + vendors = ['webkit','moz','o'], + webos = window.palmGetResource || window.PalmServiceBridge, //only used to rule out scrollTop + bb = window.blackberry; //only used to rule out box shadow, as it's filled opaque on BB + +//thx Modernizr +function propExists( prop ){ + var uc_prop = prop.charAt(0).toUpperCase() + prop.substr(1), + props = (prop + ' ' + vendors.join(uc_prop + ' ') + uc_prop).split(' '); + for(var v in props){ + if( fbCSS[ v ] !== undefined ){ + return true; + } + } +}; + +//test for dynamic-updating base tag support (allows us to avoid href,src attr rewriting) +function baseTagTest(){ + var fauxBase = location.protocol + '//' + location.host + location.pathname + "ui-dir/", + base = $("", {"href": fauxBase}).appendTo("head"), + link = $( "" ).prependTo( fakeBody ), + rebase = link[0].href; + base.remove(); + return rebase.indexOf(fauxBase) === 0; +}; + +$.extend( $.support, { + orientation: "orientation" in window, + touch: "ontouchend" in document, + cssTransitions: "WebKitTransitionEvent" in window, + pushState: !!history.pushState, + mediaquery: $.media('only all'), + cssPseudoElement: !!propExists('content'), + boxShadow: !!propExists('boxShadow') && !bb, + scrollTop: ("pageXOffset" in window || "scrollTop" in document.documentElement || "scrollTop" in fakeBody[0]) && !webos, + dynamicBaseTag: baseTagTest() +}); + +fakeBody.remove(); + +//for ruling out shadows via css +if( !$.support.boxShadow ){ $('html').addClass('ui-mobile-nosupport-boxshadow'); } + +})( jQuery );(function($, undefined ) { + +// add new event shortcuts +$.each( "touchstart touchmove touchend orientationchange tap taphold swipe swipeleft swiperight scrollstart scrollstop".split( " " ), function( i, name ) { + $.fn[ name ] = function( fn ) { + return fn ? this.bind( name, fn ) : this.trigger( name ); + }; + $.attrFn[ name ] = true; +}); + +var supportTouch = $.support.touch, + scrollEvent = "touchmove scroll", + touchStartEvent = supportTouch ? "touchstart" : "mousedown", + touchStopEvent = supportTouch ? "touchend" : "mouseup", + touchMoveEvent = supportTouch ? "touchmove" : "mousemove"; + +// also handles scrollstop +$.event.special.scrollstart = { + enabled: true, + + setup: function() { + var thisObject = this, + $this = $( thisObject ), + scrolling, + timer; + + function trigger( event, state ) { + scrolling = state; + var originalType = event.type; + event.type = scrolling ? "scrollstart" : "scrollstop"; + $.event.handle.call( thisObject, event ); + event.type = originalType; + } + + // iPhone triggers scroll after a small delay; use touchmove instead + $this.bind( scrollEvent, function( event ) { + if ( !$.event.special.scrollstart.enabled ) { + return; + } + + if ( !scrolling ) { + trigger( event, true ); + } + + clearTimeout( timer ); + timer = setTimeout(function() { + trigger( event, false ); + }, 50 ); + }); + } +}; + +// also handles taphold +$.event.special.tap = { + setup: function() { + var thisObject = this, + $this = $( thisObject ); + + $this + .bind( touchStartEvent, function( event ) { + if ( event.which && event.which !== 1 ) { + return; + } + + var moved = false, + touching = true, + origPos = [ event.pageX, event.pageY ], + originalType, + timer; + + function moveHandler() { + if ((Math.abs(origPos[0] - event.pageX) > 10) || + (Math.abs(origPos[1] - event.pageY) > 10)) { + moved = true; + } + } + + timer = setTimeout(function() { + if ( touching && !moved ) { + originalType = event.type; + event.type = "taphold"; + $.event.handle.call( thisObject, event ); + event.type = originalType; + } + }, 750 ); + + $this + .one( touchMoveEvent, moveHandler) + .one( touchStopEvent, function( event ) { + $this.unbind( touchMoveEvent, moveHandler ); + clearTimeout( timer ); + touching = false; + + if ( !moved ) { + originalType = event.type; + event.type = "tap"; + $.event.handle.call( thisObject, event ); + event.type = originalType; + } + }); + }); + } +}; + +// also handles swipeleft, swiperight +$.event.special.swipe = { + setup: function() { + var thisObject = this, + $this = $( thisObject ); + + $this + .bind( touchStartEvent, function( event ) { + var data = event.originalEvent.touches ? + event.originalEvent.touches[ 0 ] : + event, + start = { + time: (new Date).getTime(), + coords: [ data.pageX, data.pageY ], + origin: $( event.target ) + }, + stop; + + function moveHandler( event ) { + if ( !start ) { + return; + } + + var data = event.originalEvent.touches ? + event.originalEvent.touches[ 0 ] : + event; + stop = { + time: (new Date).getTime(), + coords: [ data.pageX, data.pageY ] + }; + + // prevent scrolling + if ( Math.abs( start.coords[0] - stop.coords[0] ) > 10 ) { + event.preventDefault(); + } + } + + $this + .bind( touchMoveEvent, moveHandler ) + .one( touchStopEvent, function( event ) { + $this.unbind( touchMoveEvent, moveHandler ); + if ( start && stop ) { + if ( stop.time - start.time < 1000 && + Math.abs( start.coords[0] - stop.coords[0]) > 30 && + Math.abs( start.coords[1] - stop.coords[1]) < 75 ) { + start.origin + .trigger( "swipe" ) + .trigger( start.coords[0] > stop.coords[0] ? "swipeleft" : "swiperight" ); + } + } + start = stop = undefined; + }); + }); + } +}; + +(function($){ + // "Cowboy" Ben Alman + + var win = $(window), + special_event, + get_orientation, + last_orientation; + + $.event.special.orientationchange = special_event = { + setup: function(){ + // If the event is supported natively, return false so that jQuery + // will bind to the event using DOM methods. + if ( $.support.orientation ) { return false; } + + // Get the current orientation to avoid initial double-triggering. + last_orientation = get_orientation(); + + // Because the orientationchange event doesn't exist, simulate the + // event by testing window dimensions on resize. + win.bind( "resize", handler ); + }, + teardown: function(){ + // If the event is not supported natively, return false so that + // jQuery will unbind the event using DOM methods. + if ( $.support.orientation ) { return false; } + + // Because the orientationchange event doesn't exist, unbind the + // resize event handler. + win.unbind( "resize", handler ); + }, + add: function( handleObj ) { + // Save a reference to the bound event handler. + var old_handler = handleObj.handler; + + handleObj.handler = function( event ) { + // Modify event object, adding the .orientation property. + event.orientation = get_orientation(); + + // Call the originally-bound event handler and return its result. + return old_handler.apply( this, arguments ); + }; + } + }; + + // If the event is not supported natively, this handler will be bound to + // the window resize event to simulate the orientationchange event. + function handler() { + // Get the current orientation. + var orientation = get_orientation(); + + if ( orientation !== last_orientation ) { + // The orientation has changed, so trigger the orientationchange event. + last_orientation = orientation; + win.trigger( "orientationchange" ); + } + }; + + // Get the current page orientation. This method is exposed publicly, should it + // be needed, as jQuery.event.special.orientationchange.orientation() + special_event.orientation = get_orientation = function() { + var elem = document.documentElement; + return elem && elem.clientWidth / elem.clientHeight < 1.1 ? "portrait" : "landscape"; + }; + +})(jQuery); + +$.each({ + scrollstop: "scrollstart", + taphold: "tap", + swipeleft: "swipe", + swiperight: "swipe" +}, function( event, sourceEvent ) { + $.event.special[ event ] = { + setup: function() { + $( this ).bind( sourceEvent, $.noop ); + } + }; +}); + +})( jQuery ); +/*! + * jQuery hashchange event - v1.3 - 7/21/2010 + * http://benalman.com/projects/jquery-hashchange-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ + +// Script: jQuery hashchange event +// +// *Version: 1.3, Last updated: 7/21/2010* +// +// Project Home - http://benalman.com/projects/jquery-hashchange-plugin/ +// GitHub - http://github.com/cowboy/jquery-hashchange/ +// Source - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.js +// (Minified) - http://github.com/cowboy/jquery-hashchange/raw/master/jquery.ba-hashchange.min.js (0.8kb gzipped) +// +// About: License +// +// Copyright (c) 2010 "Cowboy" Ben Alman, +// Dual licensed under the MIT and GPL licenses. +// http://benalman.com/about/license/ +// +// About: Examples +// +// These working examples, complete with fully commented code, illustrate a few +// ways in which this plugin can be used. +// +// hashchange event - http://benalman.com/code/projects/jquery-hashchange/examples/hashchange/ +// document.domain - http://benalman.com/code/projects/jquery-hashchange/examples/document_domain/ +// +// About: Support and Testing +// +// Information about what version or versions of jQuery this plugin has been +// tested with, what browsers it has been tested in, and where the unit tests +// reside (so you can test it yourself). +// +// jQuery Versions - 1.2.6, 1.3.2, 1.4.1, 1.4.2 +// Browsers Tested - Internet Explorer 6-8, Firefox 2-4, Chrome 5-6, Safari 3.2-5, +// Opera 9.6-10.60, iPhone 3.1, Android 1.6-2.2, BlackBerry 4.6-5. +// Unit Tests - http://benalman.com/code/projects/jquery-hashchange/unit/ +// +// About: Known issues +// +// While this jQuery hashchange event implementation is quite stable and +// robust, there are a few unfortunate browser bugs surrounding expected +// hashchange event-based behaviors, independent of any JavaScript +// window.onhashchange abstraction. See the following examples for more +// information: +// +// Chrome: Back Button - http://benalman.com/code/projects/jquery-hashchange/examples/bug-chrome-back-button/ +// Firefox: Remote XMLHttpRequest - http://benalman.com/code/projects/jquery-hashchange/examples/bug-firefox-remote-xhr/ +// WebKit: Back Button in an Iframe - http://benalman.com/code/projects/jquery-hashchange/examples/bug-webkit-hash-iframe/ +// Safari: Back Button from a different domain - http://benalman.com/code/projects/jquery-hashchange/examples/bug-safari-back-from-diff-domain/ +// +// Also note that should a browser natively support the window.onhashchange +// event, but not report that it does, the fallback polling loop will be used. +// +// About: Release History +// +// 1.3 - (7/21/2010) Reorganized IE6/7 Iframe code to make it more +// "removable" for mobile-only development. Added IE6/7 document.title +// support. Attempted to make Iframe as hidden as possible by using +// techniques from http://www.paciellogroup.com/blog/?p=604. Added +// support for the "shortcut" format $(window).hashchange( fn ) and +// $(window).hashchange() like jQuery provides for built-in events. +// Renamed jQuery.hashchangeDelay to and +// lowered its default value to 50. Added +// and properties plus document-domain.html +// file to address access denied issues when setting document.domain in +// IE6/7. +// 1.2 - (2/11/2010) Fixed a bug where coming back to a page using this plugin +// from a page on another domain would cause an error in Safari 4. Also, +// IE6/7 Iframe is now inserted after the body (this actually works), +// which prevents the page from scrolling when the event is first bound. +// Event can also now be bound before DOM ready, but it won't be usable +// before then in IE6/7. +// 1.1 - (1/21/2010) Incorporated document.documentMode test to fix IE8 bug +// where browser version is incorrectly reported as 8.0, despite +// inclusion of the X-UA-Compatible IE=EmulateIE7 meta tag. +// 1.0 - (1/9/2010) Initial Release. Broke out the jQuery BBQ event.special +// window.onhashchange functionality into a separate plugin for users +// who want just the basic event & back button support, without all the +// extra awesomeness that BBQ provides. This plugin will be included as +// part of jQuery BBQ, but also be available separately. + +(function($,window,undefined){ + '$:nomunge'; // Used by YUI compressor. + + // Reused string. + var str_hashchange = 'hashchange', + + // Method / object references. + doc = document, + fake_onhashchange, + special = $.event.special, + + // Does the browser support window.onhashchange? Note that IE8 running in + // IE7 compatibility mode reports true for 'onhashchange' in window, even + // though the event isn't supported, so also test document.documentMode. + doc_mode = doc.documentMode, + supports_onhashchange = 'on' + str_hashchange in window && ( doc_mode === undefined || doc_mode > 7 ); + + // Get location.hash (or what you'd expect location.hash to be) sans any + // leading #. Thanks for making this necessary, Firefox! + function get_fragment( url ) { + url = url || location.href; + return '#' + url.replace( /^[^#]*#?(.*)$/, '$1' ); + }; + + // Method: jQuery.fn.hashchange + // + // Bind a handler to the window.onhashchange event or trigger all bound + // window.onhashchange event handlers. This behavior is consistent with + // jQuery's built-in event handlers. + // + // Usage: + // + // > jQuery(window).hashchange( [ handler ] ); + // + // Arguments: + // + // handler - (Function) Optional handler to be bound to the hashchange + // event. This is a "shortcut" for the more verbose form: + // jQuery(window).bind( 'hashchange', handler ). If handler is omitted, + // all bound window.onhashchange event handlers will be triggered. This + // is a shortcut for the more verbose + // jQuery(window).trigger( 'hashchange' ). These forms are described in + // the section. + // + // Returns: + // + // (jQuery) The initial jQuery collection of elements. + + // Allow the "shortcut" format $(elem).hashchange( fn ) for binding and + // $(elem).hashchange() for triggering, like jQuery does for built-in events. + $.fn[ str_hashchange ] = function( fn ) { + return fn ? this.bind( str_hashchange, fn ) : this.trigger( str_hashchange ); + }; + + // Property: jQuery.fn.hashchange.delay + // + // The numeric interval (in milliseconds) at which the + // polling loop executes. Defaults to 50. + + // Property: jQuery.fn.hashchange.domain + // + // If you're setting document.domain in your JavaScript, and you want hash + // history to work in IE6/7, not only must this property be set, but you must + // also set document.domain BEFORE jQuery is loaded into the page. This + // property is only applicable if you are supporting IE6/7 (or IE8 operating + // in "IE7 compatibility" mode). + // + // In addition, the property must be set to the + // path of the included "document-domain.html" file, which can be renamed or + // modified if necessary (note that the document.domain specified must be the + // same in both your main JavaScript as well as in this file). + // + // Usage: + // + // jQuery.fn.hashchange.domain = document.domain; + + // Property: jQuery.fn.hashchange.src + // + // If, for some reason, you need to specify an Iframe src file (for example, + // when setting document.domain as in ), you can + // do so using this property. Note that when using this property, history + // won't be recorded in IE6/7 until the Iframe src file loads. This property + // is only applicable if you are supporting IE6/7 (or IE8 operating in "IE7 + // compatibility" mode). + // + // Usage: + // + // jQuery.fn.hashchange.src = 'path/to/file.html'; + + $.fn[ str_hashchange ].delay = 50; + /* + $.fn[ str_hashchange ].domain = null; + $.fn[ str_hashchange ].src = null; + */ + + // Event: hashchange event + // + // Fired when location.hash changes. In browsers that support it, the native + // HTML5 window.onhashchange event is used, otherwise a polling loop is + // initialized, running every milliseconds to + // see if the hash has changed. In IE6/7 (and IE8 operating in "IE7 + // compatibility" mode), a hidden Iframe is created to allow the back button + // and hash-based history to work. + // + // Usage as described in : + // + // > // Bind an event handler. + // > jQuery(window).hashchange( function(e) { + // > var hash = location.hash; + // > ... + // > }); + // > + // > // Manually trigger the event handler. + // > jQuery(window).hashchange(); + // + // A more verbose usage that allows for event namespacing: + // + // > // Bind an event handler. + // > jQuery(window).bind( 'hashchange', function(e) { + // > var hash = location.hash; + // > ... + // > }); + // > + // > // Manually trigger the event handler. + // > jQuery(window).trigger( 'hashchange' ); + // + // Additional Notes: + // + // * The polling loop and Iframe are not created until at least one handler + // is actually bound to the 'hashchange' event. + // * If you need the bound handler(s) to execute immediately, in cases where + // a location.hash exists on page load, via bookmark or page refresh for + // example, use jQuery(window).hashchange() or the more verbose + // jQuery(window).trigger( 'hashchange' ). + // * The event can be bound before DOM ready, but since it won't be usable + // before then in IE6/7 (due to the necessary Iframe), recommended usage is + // to bind it inside a DOM ready handler. + + // Override existing $.event.special.hashchange methods (allowing this plugin + // to be defined after jQuery BBQ in BBQ's source code). + special[ str_hashchange ] = $.extend( special[ str_hashchange ], { + + // Called only when the first 'hashchange' event is bound to window. + setup: function() { + // If window.onhashchange is supported natively, there's nothing to do.. + if ( supports_onhashchange ) { return false; } + + // Otherwise, we need to create our own. And we don't want to call this + // until the user binds to the event, just in case they never do, since it + // will create a polling loop and possibly even a hidden Iframe. + $( fake_onhashchange.start ); + }, + + // Called only when the last 'hashchange' event is unbound from window. + teardown: function() { + // If window.onhashchange is supported natively, there's nothing to do.. + if ( supports_onhashchange ) { return false; } + + // Otherwise, we need to stop ours (if possible). + $( fake_onhashchange.stop ); + } + + }); + + // fake_onhashchange does all the work of triggering the window.onhashchange + // event for browsers that don't natively support it, including creating a + // polling loop to watch for hash changes and in IE 6/7 creating a hidden + // Iframe to enable back and forward. + fake_onhashchange = (function(){ + var self = {}, + timeout_id, + + // Remember the initial hash so it doesn't get triggered immediately. + last_hash = get_fragment(), + + fn_retval = function(val){ return val; }, + history_set = fn_retval, + history_get = fn_retval; + + // Start the polling loop. + self.start = function() { + timeout_id || poll(); + }; + + // Stop the polling loop. + self.stop = function() { + timeout_id && clearTimeout( timeout_id ); + timeout_id = undefined; + }; + + // This polling loop checks every $.fn.hashchange.delay milliseconds to see + // if location.hash has changed, and triggers the 'hashchange' event on + // window when necessary. + function poll() { + var hash = get_fragment(), + history_hash = history_get( last_hash ); + + if ( hash !== last_hash ) { + history_set( last_hash = hash, history_hash ); + + $(window).trigger( str_hashchange ); + + } else if ( history_hash !== last_hash ) { + location.href = location.href.replace( /#.*/, '' ) + history_hash; + } + + timeout_id = setTimeout( poll, $.fn[ str_hashchange ].delay ); + }; + + // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + // vvvvvvvvvvvvvvvvvvv REMOVE IF NOT SUPPORTING IE6/7/8 vvvvvvvvvvvvvvvvvvv + // vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv + $.browser.msie && !supports_onhashchange && (function(){ + // Not only do IE6/7 need the "magical" Iframe treatment, but so does IE8 + // when running in "IE7 compatibility" mode. + + var iframe, + iframe_src; + + // When the event is bound and polling starts in IE 6/7, create a hidden + // Iframe for history handling. + self.start = function(){ + if ( !iframe ) { + iframe_src = $.fn[ str_hashchange ].src; + iframe_src = iframe_src && iframe_src + get_fragment(); + + // Create hidden Iframe. Attempt to make Iframe as hidden as possible + // by using techniques from http://www.paciellogroup.com/blog/?p=604. + iframe = $('