require "camping" require "camping/session" require "pathname" require "markaby" Markaby::Builder.set(:indent, 2) Camping.goes :Anne unless defined? PUBLIC_DIR PUBLIC_DIR = Pathname.new(__FILE__).dirname + "public" IMAGE_DIR = PUBLIC_DIR + "images" end module Anne include Camping::Session secret "JeMoeder" def self.create Anne::Models.create_schema end end module Anne::Models class User < Base end class Vote < Base belongs_to :user end class BasicFields < V 1.0 def self.up create_table User.table_name do |t| t.string :study, :gender, :spaciousness, :email, :comments t.integer :study_year t.boolean :colorblind, :prize, :results t.timestamps end create_table Vote.table_name do |t| t.string :image, :choice t.integer :user_id end end def self.down drop_table User.table_name drop_table Vote.table_name end end end module Anne::Helpers def next_image all_images = Pathname.glob(IMAGE_DIR + "*-l.png").map { |img| img.basename.to_s.sub("-l.png", "") } all_votes = Anne::Models::Vote.find(:all, :conditions => { :user_id => @state["user"].id }) voted_images = all_votes.map { |vote| vote.image } remaining_images = all_images - voted_images return nil, 100 if remaining_images.empty? return remaining_images.sort_by { rand }.first, 100 - (remaining_images.length * 100.0 / all_images.length).ceil end end module Anne::Controllers class Index def get render :intro end end class Start def get return redirect Vote if @state["user"] render :start end def post @state["user"] = User.create( :study => @input.user_study, :study_year => @input.user_study_year, :gender => @input.user_gender, :colorblind => @input.user_colorblind == "ja", :spaciousness => @input.user_spaciousness) redirect Vote end end class Vote def get return redirect Index if not @state["user"] image, progress = next_image return redirect Finish if image.nil? render :vote, image, progress end def post choice = if @input["left.x"] then "left" elsif @input["right.x"] then "right" else raise "no choice made!" end vote = Anne::Models::Vote.create( :user_id => @state["user"].id, :image => @input.image, :choice => choice ) redirect Vote end end class ImageX def get(file) unless file =~ /\.\./ headers["Content-Type"] = "image/png" headers["X-Sendfile"] = (IMAGE_DIR.relative_path_from(PUBLIC_DIR) + file).to_s else @status = 403 "You're not allowed to retrieve #{file}!" end end end class Finish def get return redirect Index if not @state["user"] return redirect Vote unless next_image.first.nil? return redirect Thanks unless @state["user"].results.nil? render :finish end def post user = @state["user"] raise "unknown user" if user.nil? user.email = @input.email user.prize = !@input.prize.nil? user.results = !@input.results.nil? user.comments = @input.comments user.save redirect Thanks end end class Style < R '/style\.css' STYLE = File.read(__FILE__).gsub(/.*__END__/m, '') def get @headers['Content-Type'] = 'text/css; charset=utf-8' STYLE end end class Thanks def get render :thanks end end end module Anne::Views def layout xhtml_strict do head do title "Enquête ruimtelijke effecten" link :rel => "stylesheet", :type => "text/css", :media => "screen", :href => "/style.css" end body do div.header! do h1 do span.left "Enquête ruimtelijke effecten" img.right :src => R(ImageX, "tuelogo.gif"), :alt => "[TU/e logo]", :style => "right: 180px"; img.right :src => R(ImageX, "philipslogo.gif"), :alt => "[Philips logo]", :style => "padding: 5px 5px; margin: 13px 0px; background: white;" end end div.content! { self << yield } div.footer! do p "Copyright © 2010 Anne Pijl, Bram Senders, Paul van Tilburg" end end end end def intro p "Met deze enquête worden een aantal ruimtelijke effecten onderzocht. " \ "Je krijgt 45 keer twee afbeeldingen te zien. Je kiest welke afbeelding" \ " je ruimtelijker ervaart. In welke afbeelding zie je meer diepte, " \ "welke afbeelding lijkt jou het meest 3-dimensionaal? Als je het niet " \ "weet, klik je op een willekeurige afbeelding. De test duurt 5 " \ "minuten. Succes!" p "Doe de test volledig om kans te maken op eerste prijs van een " \ "Philips Living Colors lamp of de tweede prijs van 20 euro." p "– Anne Pijl" form :action => R(Start), :method => :get do input :type => "submit", :value => "Ga verder" end end def make_select(label_name, name, options) p do label label_name, :for => name select :name => name do options.each { |option_str| option option_str } end end end def start h2 "Persoonlijke karakteristieken" p "Graag zou ik ten behoeve van de statistiek het volgende van je willen weten:" form :action => R(Start), :method => :post do make_select "Faculteit", "user_study", ["niet van toepassing", "Biomedische Technologie", "Bouwkunde", "Electrical Engineering", "Industrial Design", "Scheikundige Technologie", "Industrial Engineering & Innovation Sciences", "Technische Natuurkunde", "Werktuigbouwkunde", "Wiskunde & Informatica"] make_select "Studiejaar", "user_study_year", ["niet van toepassing"] + (1998..2009).to_a make_select "Geslacht", "user_gender", ["", "man", "vrouw"] make_select "Ben je kleurenblind?", "user_colorblind", ["nee", "ja"] make_select "Vind je dat je een goed ruimtelijk voorstellingsvermogen hebt?", "user_spaciousness", ["neutraal", "ja", "nee"] input :type => "submit", :value => "Start de enquête!" end end def vote(image, progress = 0) h2 "Welk beeld is ruimtelijker?" form.images! :action => R(Vote), :method => :post do input :type => "hidden", :name => "image", :value => image input :type => "image", :src => R(ImageX, "#{image}-l.png"), :name => "left", :class => "left image" input :type => "image", :src => R(ImageX, "#{image}-r.png"), :name => "right", :class => "right image" end div.progressbar! do div.done! :style => "width: #{progress}%" do end end end def finish h2 "Dank je wel voor het meedoen aan dit onderzoek." p "Als je geïnteresseerd bent in de resultaten van de enquête of je wilt " \ "meedingen naar de Philips Living Colors lamp of de prijs van 20 " \ "euro, vul dan hier je e-mailadres in." form :action => R(Finish), :method => :post do p do label "E-mailadres", :for => "email" input :type => "text", :name => "email" end p do input :type => "checkbox", :name => "prize", :checked => true label "Ik wil meedingen naar de prijs.", :for => "prize" end p do input :type => "checkbox", :name => "results", :checked => true label "Ik wil de resultaten van het onderzoek ontvangen.", :for => "results" end p "Je e-mailadres wordt enkel gebruikt voor de enquête-resultaten en " \ "om je op de hoogte te stellen als je gewonnen hebt." p do label "Opmerkingen over dit onderzoek", :for => "comments" br textarea :name => "comments", :cols => 80, :rows => 5 end input :type => "submit", :value => "Verstuur" end end def thanks h2 "Bedankt!" p "Je antwoorden zijn verstuurd." end end __END__ /* Style sheet for the Anne Survey Camping app */ html { background: #333; } body { margin: 10px auto; padding: 10px; width: 960px; font-family: Verdana, Geneva, Arial, Helvetica, sans-serif; color: white; background-color: black; -webkit-border-radius: 12px; -moz-border-radius: 12px; border-radius: 12px; } #header { position: relative; height: 73px; } #header span { bottom: 10px; } #images { position: relative; height: 470px; } .image { border: thin solid #888; } .left { position: absolute; left: 0px; } .right { position: absolute; right: 0px; } #progressbar { height: 6px; margin-top: 8px; background-color: #101073; } #progressbar #done { height: 6px; background-color: #d6007b; } #footer { padding: 0px 0px 0px 8px; margin-top: 14px; border-top: thin #eee solid; font-size: 69.4%; }