added first full working version of embeddable elections
author<mako@atdot.cc> <>
Tue, 19 Feb 2008 14:24:06 +0000 (09:24 -0500)
committer<mako@atdot.cc> <>
Tue, 19 Feb 2008 14:24:06 +0000 (09:24 -0500)
- added several new fields to the database to support unauthenticated,
  embeddable, and early result visible full elections

- modified full election create to allow for proper options and to
  display the full election code

- added new layouts, views, css, and images for embeddable elections

- modified full elections to work with the new form of images in the
  last commit

- fixed several bugs related to vote recording and timestamp,s

36 files changed:
.bzrignore
app/controllers/election_controller.rb
app/controllers/voter_controller.rb
app/models/election.rb
app/models/picture.rb
app/models/token.rb
app/models/vote.rb
app/views/election/_candidate_box_info.rhtml [new file with mode: 0644]
app/views/election/_candidate_form.rhtml
app/views/election/_candidate_line.rhtml
app/views/election/_candidate_line_edit.rhtml
app/views/election/_overview_form.rhtml
app/views/election/_voters_form.rhtml
app/views/election/edit.rhtml [deleted file]
app/views/election/edit_general_information.rhtml [new file with mode: 0644]
app/views/election/edit_voters.rhtml
app/views/election/show.rhtml
app/views/embed/full_vote.rhtml [new file with mode: 0644]
app/views/embed/results.rhtml [new file with mode: 0644]
app/views/layouts/embed.rhtml [new file with mode: 0644]
app/views/voter/_results_sidebar.rhtml
app/views/voter/_vote.rhtml
app/views/voter/_vote_sidebar.rhtml
app/views/voter/full_vote.rhtml
app/views/voter/review.rhtml
config/routes.rb
db/migrate/002_add_embeddable_support.rb [new file with mode: 0644]
db/schema.rb
public/images/default_icon.png [new file with mode: 0644]
public/images/embed_basic_bg.png [new file with mode: 0644]
public/images/embed_header_icon.png [new file with mode: 0644]
public/images/embed_results_changevote.png [new file with mode: 0644]
public/images/embed_voting_bg.png [new file with mode: 0644]
public/images/embed_voting_submitvote.png [new file with mode: 0644]
public/stylesheets/embed.css [new file with mode: 0644]
public/stylesheets/main.css

index 57a67d22f4ea29e16bc9f66a67611b06fdd8fbd6..5304d54136103c673695551947c79d3753d355c9 100644 (file)
@@ -7,3 +7,4 @@ tmp
 public/engine_files
 .DS_Store
 vendor/plugins/sitealizer/lib/last_update
+public/pictures
index 5949f567746444df5208f73913263e945a32bc40..94c203d104c902de9dd673a3713ad0c2e76a9fa7 100644 (file)
@@ -54,20 +54,13 @@ class ElectionController < ApplicationController
     end
   end
   
-  # add filter to verify that the person working on or looking at
+  # TODO add filter to verify that the person working on or looking at
   # something is the owner
-  def edit
+  def edit_general_information
     @election = Election.find(params[:id])
   end
-
-  def show
-    @sidebar_content = render_to_string :partial => 'progress',
-                                        :locals => { :page => 'review' }
-
-    @election = Election.find(params[:id])
-  end
-
-  def update
+  
+  def update_general_information
     @election = Election.find(params[:id])
     if @election.update_attributes(params[:election])
       flash[:notice] = 'Election was successfully updated.'
@@ -77,6 +70,14 @@ class ElectionController < ApplicationController
     end
   end
 
+
+  def show
+    @sidebar_content = render_to_string :partial => 'progress',
+                                        :locals => { :page => 'review' }
+
+    @election = Election.find(params[:id])
+  end
+
   def start_election
     @election = Election.find(params[:id])
     @election.voters.each do |voter|
@@ -103,6 +104,12 @@ class ElectionController < ApplicationController
     @election.candidates << @candidate
 
     if @candidate.save
+      # check to see if they've uploaded a picture
+      if params[:picture][:uploaded_data]
+        picture = Picture.new(params[:picture])
+        @candidate.picture = picture if picture.save
+      end
+
       @candidate = Candidate.new
       redirect_to :action => 'edit_candidates', :id => @election.id
     else
@@ -145,6 +152,16 @@ class ElectionController < ApplicationController
     voter = Voter.find( params[:id] )
     voter.destroy
   end
+
+  def toggle_authenticated
+    @election = Election.find(params[:id])
+    if params[:authenticated] == "1"
+      @election.authenticated = true
+    else
+      @election.authenticated = false
+    end
+    @election.save
+  end
   
   ## methods for computing and printing results
   ####################################################################
index 868bc4c7d2b994970bb17c0676651b06e9df0a97..cdc045da05c3e680d425918a7c0670685590eff5 100644 (file)
@@ -23,34 +23,48 @@ class VoterController < ApplicationController
   require_dependency "election"
 
   def index
-    if params[:urlpassword]
+    if params[:election_id]
+      @election = Election.find(params[:election_id])
+      unless @election.authenticated?
+        @voter = Voter.find(:all,
+          :conditions => ["session_id = ? and election_id = ?",
+          session.session_id, @election.id])[0]
+      
+        @voter = Voter.new unless @voter
+
+        @voter.election = @election
+        @voter.session_id = session.session_id
+        @password = "open." + @election.id.to_s
+      end
+    elsif params[:urlpassword]
       password = params[:urlpassword]
 
       if @voter = FullVoter.find(:all,
         :conditions => [ "password = ?", password ] )[0]
+        @election = @voter.election
+        @password = @voter.password
+      end
+    end
 
-        @voter.vote = Vote.new if @voter.vote.nil?
-        @voter.vote.set_defaults! if @voter.vote.rankings.empty?
+    if @voter and @election
+      # initialize things if the vote is blank
+      if @voter.vote.nil?
+        @voter.vote = Vote.new 
+        @voter.save
+      end
+      
+      @voter.vote.set_defaults! if @voter.vote.rankings.empty?
 
-        @election = @voter.election
-        
-        # if the election is now finished 
-        if @election.enddate < Time.now
-          # compute and display results
-    
-          @results = @election.results
-          @candidates = {}
-          @election.candidates.each {|c| @candidates[c.id] = c}
-          @names = @election.names_by_id
-          
-          @sidebar_content = render_to_string(:partial => 'results_sidebar')
-          render :action => 'results'
+      # if the election is now finished 
+      if @election.enddate < Time.now
+        redirect_to :action => :results, :id => @password
+      else
+        @sidebar_content = render_to_string(:partial => 'vote_sidebar')
+        if @election.embeddable? and params[:embed] == "true"
+          render :template => 'embed/full_vote', :layout => 'embed'
         else
-          @sidebar_content = render_to_string(:partial => 'vote_sidebar')
           render :action => 'full_vote'
         end
-      elsif params[:urlpassword] 
-        redirect_to :action => 'index'
       end
     end
   end
@@ -100,7 +114,13 @@ class VoterController < ApplicationController
   def confirm
     if authenticate
       @voter.vote.confirm!
-      render :action => 'thanks'
+
+      if @voter.election.embeddable? and params[:embed] == "true" \
+        and @voter.election.early_results?
+        redirect_to :action => :results, :id => @password, :embed => 'true'
+      else
+        render :action => 'thanks'
+      end
     else
       redirect_to :action => 'index'
     end
@@ -117,11 +137,47 @@ class VoterController < ApplicationController
     end
   end
   
+  def results
+    if authenticate and
+      (@voter.election.early_results? \
+       or @voter.election.enddate < Time.now)
+      
+      @election = @voter.election
+      # compute and display results
+
+      @results = @election.results
+      @candidates = {}
+      @election.candidates.each {|c| @candidates[c.id] = c}
+      @names = @election.names_by_id
+        
+      @sidebar_content = render_to_string(:partial => 'results_sidebar')
+      if @election.embeddable? and params[:embed] == "true"
+        render :template => 'embed/results', :layout => 'embed'
+      else
+        render :action => 'results'
+      end
+    else
+      redirect_to :action => 'index'
+    end
+  end
   
   private
   def authenticate
     password = params[:id]
-    @voter = FullVoter.find(:all, :conditions => [ "password = ?", password ] )[0]
+    if password == "open"
+      election = Election.find(params[:format])
+      unless election.authenticated?
+        @voter = Voter.find(:all,
+          :conditions => ["session_id = ? and election_id = ?",
+                          session.session_id, election.id])[0]
+        @password = "open." + election.id.to_s
+      end
+    else
+      @voter = FullVoter.find(:all,
+        :conditions => [ "password = ?", password ] )[0]
+      @password = @voter.password
+    end
+    @voter
   end
 end
 
index 7d8ad80d883ee45ab6bee1a875ed446478d68151..08ef1a57c025d7fe5192d0dc396b828ada9a12f0 100644 (file)
@@ -73,7 +73,7 @@ class Election < ActiveRecord::Base
       reasons << "You must have at least two candidates."
     end
     
-    if self.voters.length <= 1
+    if self.voters.length <= 1 and self.authenticated?
       reasons << "You must have at least two voters."
     end
 
@@ -97,6 +97,10 @@ class Election < ActiveRecord::Base
     active == 2
   end
 
+  def authenticated?
+    authenticated
+  end
+  
   def shortdesc
     shortdesc = description.split(/\n/)[0]
   end
index 04b368ed67c4264254debdcadb8a73a29d42decf..9f17ec4c13b6a35491e1028fd9f9c5909d368d93 100644 (file)
@@ -21,7 +21,7 @@ class Picture < ActiveRecord::Base
  
   has_attachment  :storage => :file_system, 
                   :max_size => 1.megabytes,
-                  :thumbnails => { :thumb => '70x53>' },
+                  :thumbnails => { :thumb => '70x53' },
                   :processor => :Rmagick
 
   validates_as_attachment
index aa432d659de0ca723569c22e2a9fab3e7a167310..c2d3667a9027a5a29da5628e04b9c73c0a6426d8 100644 (file)
@@ -23,7 +23,7 @@ class Token < ActiveRecord::Base
     super
 
     token_generator = UniqueTokenGenerator.new( 16 )
-    until not token.empty? and Token.find(:all, :conditions => [ "token = ?", token ]).empty?
+    until not token.empty? and Token.find(:all, :conditions => [ "token = ?", token ]).empty? and token[0..3] != "open"
       self.token = token_generator.token
     end
 
index bb91a6b53a84e07e3d4034eb8776c59c2e8ebbbb..bef35020a45b1a7d37ca25fdd86dec73259f8ab5 100644 (file)
@@ -69,13 +69,9 @@ class Vote < ActiveRecord::Base
     rankings.each { |ranking| ranking.destroy }
   end
 
-  def settime
-    self.time = Time.now
-    self.save
-  end
-
   def confirm!
     self.confirmed = 1
+    self.time = Time.now
     self.save
     
     unless self.voter.election.quickvote?
@@ -105,7 +101,7 @@ class Vote < ActiveRecord::Base
   # too. It creates a vote with the candidates listed in order of preference 
   # based on alphabetical order. Meant to be manipulated and then confirmed
   def set_defaults!  
-    self.votes = voter.election.candidates.sort.collect {|c| c.id }
+    self.votes = self.voter.election.candidates.sort_by { rand }.collect {|c| c.id }
     self.save
   end
          
diff --git a/app/views/election/_candidate_box_info.rhtml b/app/views/election/_candidate_box_info.rhtml
new file mode 100644 (file)
index 0000000..76d56c0
--- /dev/null
@@ -0,0 +1,15 @@
+<div class="candidate_box_info">
+  <% if @current_candidate.picture %>
+  <div class="candidate_box_picture">
+    <img src="<%= url_for @current_candidate.picture.public_filename(:thumb) %>" />
+  </div>
+  <% end %>
+  <div class="candidate_box_description">
+    <% if @current_candidate.description.length > 0 %>
+       <%= h(@current_candidate.description) %>
+    <% else %>
+      <!-- no description -->
+    <% end %>
+  </div>
+  <div class="clear-div"></div>
+</div>
index fcbf0721eeec4417ca084b26edc131e016d32df7..75e5c3ec3794f08423b959e983ce45834226c357 100644 (file)
@@ -6,6 +6,6 @@
 
 
 <p style="float: left;"><label for="candidate_picture">Picture</label> (optional and &lt; 100x100 pixels)<br />
-<%= file_field :candidate, :picture %></p>
+<%= file_field :picture, :uploaded_data%></p>
 
 <div class="clear-div"></div>
index 6b5b5530735ad8048f98d0cbb5f2f27a68d0b324..2fc9a6353728e61e6cf421ee2949b510d62369f9 100644 (file)
@@ -10,7 +10,7 @@
     <br />
 
     <div style="display: none;" id="candidate_description_<%= @current_candidate.id %>">
-    <%=h (@current_candidate.description) %>
+    <%= render :partial => 'candidate_box_info' %>
     </>
     </span>
   </li>
index 0fd5b67ecceb0a842979c9e4a76ed1897f108c98..bcb7cd92809eb2731549dd1cd584746bb9c4c0ec 100644 (file)
@@ -1,5 +1,7 @@
 <div class="candidate_box" id="cand<%= @current_candidate.id %>">
-  <div class="candidate_box_name"><%=h @current_candidate.name %></div>
+  <div class="candidate_box_name">
+  
+  <%=h @current_candidate.name %></div>
   <div class="candidate_box_menu">
   <%= link_to_remote "Delete",
                        :complete => "Element.remove('cand#{@current_candidate.id}')",
@@ -7,22 +9,6 @@
                       :id => @current_candidate.id } %>
    </div>
    <div class="clear-div"></div>
-
-   <div class="candidate_box_info">
-     <div class="candidate_box_picture">
-       <% if @current_candidate.picture? %>
-       <img src="<%= url_for :action => 'candidate_picture',
-                             :id => @current_candidate.id %>" />
-       <% end %>
-     </div>
-     <div class="candidate_box_description">
-       <% if @current_candidate.description.length > 0 %>
-          <%= h(@current_candidate.description) %>
-       <% else %>
-         <!-- no description -->
-       <% end %>
-     </div>
-     <div class="clear-div"></div>
-  </div>
+   <%= render :partial => 'candidate_box_info' %>
 </p>
 </div>
index 8efa1b3769651142c5455f41c7516be1c8618d81..8d1861d00b56b3d754ab1f54c4dd2f5692cbfccb 100644 (file)
@@ -2,14 +2,14 @@
 
 <!--[form:election]-->
 <p><label for="election_name">Title</label><br/>
-<%= text_field 'election', 'name', :size => 60 %></p>
+<%= text_field :election, :name, :size => 60 %></p>
 
 <p><label for="election_description">Description</label><br/>
-<%= text_area 'election', 'description', :rows => 5, :cols => 60 %></p>
+<%= text_area :election, :description, :rows => 5, :cols => 60 %></p>
 
 <!--
 <p><label for="election_anonymous">Anonymous Vote</label>
-<%= check_box 'election', 'anonymous', {}, 1, 0  %></p>
+<%= check_box :election, :anonymous, {}, 1, 0  %></p>
 
 <p>Election/Voting Start Date<br />
 <%= datetime_select :election, :startdate %></p>
 <% type_hash = {}; ELECTION_TYPES.each {|k,v| type_hash[v] = k} %>
 <%= select_tag 'election[election_method]', options_for_select(type_hash, @election.election_method) %></p>
 
+<p><label for="election_election_method">Enable Embeddable Elections?</label>
+<%= check_box :election, :embeddable %></p>
+
+<p><label for="election_election_method">Should results be visible before end of election?</label>
+<%= check_box :election, :early_results%></p>
 <!--[eoform:election]-->
 
index 8130ade671508151d596998c08af3aaa4ab110a2..7819429b1e7668c515a58fc82da152bde5e61ddb 100644 (file)
@@ -11,5 +11,5 @@ address per line).</p>
 -->
 <%= hidden_field :raw_voter_list, :email, :value => 2 %>
 </p>
-
 <p><%= submit_tag "Add Voters" %></p>
+
diff --git a/app/views/election/edit.rhtml b/app/views/election/edit.rhtml
deleted file mode 100644 (file)
index 40aaad2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<h1><strong><%=h @election.name %>:</strong> Edit Overview</h1>
-
-<% form_tag(:action => 'update', :id => @election) do %>
-  <%= render :partial => 'overview_form' %>
-  <%= submit_tag 'Done!' %>
-<% end %>
diff --git a/app/views/election/edit_general_information.rhtml b/app/views/election/edit_general_information.rhtml
new file mode 100644 (file)
index 0000000..c2f1cf5
--- /dev/null
@@ -0,0 +1,9 @@
+<div id="title-header">
+  <span class="header">Election Overview</span>
+  <span class="subheader"></span>
+</div>
+
+<% form_tag(:action => 'update_general_information', :id => @election) do %>
+  <%= render :partial => 'overview_form' %>
+  <%= submit_tag 'Done' %>
+<% end %>
index 8819b952d03b158e4334d8c2115ea873506f57cb..77093fe5262db3783c7589a014291708b199e5ef 100644 (file)
@@ -3,11 +3,26 @@
   <span class="subheader"></span>
 </div>
 
+<p id="unauth_notice" <%= 'style="display: none;"' if @election.authenticated %>>Anyone will be able to
+vote in this election.</p>
+
+<div id="voter_info_box" <%= 'style="display: none;"' unless @election.authenticated %>>
 <%= render :partial => 'voter_list' %>
 
 <% form_tag (:action => 'edit_voters', :id => @election.id) do %>
 <%= render :partial => 'voters_form' %>
 <% end %>
+</div>
+
+<%= check_box :election, :authenticated %> Only allow registered voters 
+
+<%= observe_field "election_authenticated",
+      :url => { :action => 'toggle_authenticated', :id => @election.id },
+      :complete => 'Element.toggle($("voter_info_box")); Element.toggle($("unauth_notice"));',
+      :with => 'authenticated' %>
+
+<script type="text/javascript">
+</script>
 
 <div class="normal-header">
   <span class="header">Continue</span>
index 3e636281fcccbbb099d294ea624d0e84d7aded53..87529d18c1c41633fcff130b10e5b83c0b881534 100644 (file)
@@ -9,6 +9,11 @@
 <% elsif @election.done? %>
   <div id="status">Election is finished. <%= link_to "View results",
   :action => 'results', :id => @election.id %>.</div>
+<% else %>
+  <p style="text-align: right;">
+    <%= link_to "Edit General Information",
+                :action => 'edit_general_information', :id => @election.id %>
+  </p>
 <% end %>
 
 <p><strong>Summary</strong></p>
 <%= h(@election.description) %>
 </blockquote>
 
-<p><strong>End Date</strong></p>
+<p><strong>Additional Information</strong></p>
 
-<blockquote>
-<%= @election.enddate %>
-</blockquote>
+<ul> <li>Elections will end at <strong><%= @election.enddate
+%></strong>.</li> <li>Elections results <strong><% if
+@election.early_results %>will be<% else %>will not be<% end
+%></strong> will be visible while election is in progress.</li>
 
-<% unless @election.active %>
-<p><%= link_to "Edit overview.", :action => 'edit', :id => @election.id %></p>
+<% if @election.embeddable %>
+<li>Elections <strong>will be</strong> embeddable.</li>
 <% end %>
 
+</ul>
+
+
 <div class="normal-header">
   <span class="header">Candidates</span>
   <span class="subheader"></span>
 </div>
 
-<% unless @election.candidates.empty? %>
-  <%= render :partial => 'candidate_list' %>
-  <% unless @election.active %>
-  <p><%= link_to "Add, remove, or edit candidates.", :action => 'edit_candidates', :id => @election.id %></p>
-  <% end %>
-<% else %>
-  <p><em>There are currently no candidates registered.  <%= link_to "Add some!", :action => 'edit_candidates', :id => @election.id unless @election.active %></em></p>
 
+<% if not (@election.active? or @election.done?) %>
+  <p style="text-align: right;">
+    <%= link_to "Edit Candidates",
+               :action => 'edit_candidates', :id => @election.id %></p>
+<% end %>
+
+
+<% if @election.candidates.empty? %>
+  <p><em>There are currently no candidates registered.</em>
+     <%= link_to "Add some!", :action => 'edit_candidates', :id => @election.id %>
+  </p>
+<% else %>
+  <%= render :partial => 'candidate_list' %>
 <% end %>
 
 <div class="normal-header">
   <span class="subheader"></span>
 </div>
 
-<% unless @election.voters.empty? %>
-  <%= render :partial => 'voter_list' %>
-  <%= link_to "Add or remove voters.", :action => 'edit_voters', :id => @election.id unless @election.active %></em></p>
+<% if not (@election.active?  or @election.done?) %>
+<p style="text-align: right;">
+  <%= link_to "Change Voters/Options",
+              :action => 'edit_voters', :id => @election.id %></p>
+<% end %>
+
+<% if not @election.authenticated? %>
+  <p><em>This election is open the public.</em></p>
+<% elsif @election.voters.empty? %>
+  <p><em>There are currently no voters registered. </em>
+     <%= link_to "Add some!", :action => 'edit_voters',
+                 :id => @election.id %></p>
 <% else %>
-  <p><em>There are currently no voters registered.  <%= link_to "Add some!", :action => 'edit_voters', :id => @election.id unless @election.active %></em></p>
+  <%= render :partial => 'voter_list' %>
+  <p><em><%= link_to "Add or remove voters.", :action => 'edit_voters',
+              :id => @election.id unless @election.active? or @election.done? %>
+  </em></p>
 <% end %>
 
-<% unless @election.active? %>
+<% if not (@election.active? or @election.done?)  %>
 
 <div class="normal-header">
   <span class="header">Start Election</span>
     <ul>
     <li>The vote will be "frozen" so that further edits to the
         candidate list and voting list cannot occur.</li>
+    <% if @election.authenticated? %>
     <li>All voters will be emailed notifying them that the vote has
         begun and of their unique login token.</li>
+    <% end %>
     </ul>
 
     <%= button_to 'Start Election!', :action => 'start_election', :id => @election.id %>
   <% end %>
 
+<% elsif @election.embeddable? %>
+
+<div class="normal-header">
+  <span class="header">Embedding</span>
+  <span class="subheader"></span>
+</div>
+
+
+<p>To embed your election, copy and paste the following code into your
+homepage:</p>
+
+<blockquote>
+<tt><pre><%= h("<iframe src='") + votepassword_url(:urlpassword => "open." + @election.id.to_s) + h("'") + "<br />" + h(" width='330px' height='370px'></iframe>") %></pre></tt>
+</blockquote>
+
 <% end %>
diff --git a/app/views/embed/full_vote.rhtml b/app/views/embed/full_vote.rhtml
new file mode 100644 (file)
index 0000000..70a6825
--- /dev/null
@@ -0,0 +1,35 @@
+<div id="header">
+<img id="header_icon" src="/images/embed_header_icon.png" />
+<h2>Vote Now</h2>
+</div>
+<div id="voting-box">
+       
+       <ul id="rankings-list">
+      <% @voter.vote.rankings.each do |ranking| %>
+               <li class="ranking" id="ranking_<%= ranking.candidate.id %>">
+                       <img alt="<%= white_list ranking.candidate.name %>"
+                 src="<% if ranking.candidate.picture -%>
+                      <%= url_for ranking.candidate.picture.public_filename(:thumb) -%>
+                     <%- else -%>
+                     /images/default_icon.png
+                     <%- end %>" />
+                       <p class="ranking-info">
+            <strong><%= white_list ranking.candidate.name %></strong><br />
+            <%= white_list ranking.candidate.description %></p>
+               </li>
+      <% end %>
+       </ul>
+       
+       <div style="clear:both;"></div>
+       
+       <div id="voting-bottom">
+               <div id="container">
+                       <a href="<%= url_for :action => :confirm, :id => @password, :embed => 'true' %>"><h2 id="submit_vote_button">Submit Vote</h2></a>
+                       <p><b>Drag and drop</b> to rank your favorite videos</p>
+               </div>
+       </div>
+</div>
+
+<%= sortable_element 'rankings-list',
+    :url => { :action => "sort_candidates", :id => @voter.vote.id } %>
+
diff --git a/app/views/embed/results.rhtml b/app/views/embed/results.rhtml
new file mode 100644 (file)
index 0000000..b9b1eb4
--- /dev/null
@@ -0,0 +1,36 @@
+<div id="header">
+<img id="header_icon" src="/images/embed_header_icon.png" />
+<h2>Current Standings</h2>
+</div>
+<div id="voting-box">
+       
+       <ul id="rankings-list">
+      <% @election.ssd_result.ranked_candidates.flatten.each do |ranking_id| %>
+       <% ranking = @candidates[ranking_id] %>
+               <li class="ranking" id="ranking_<%= ranking.id %>">
+                       <img alt="<%= white_list ranking.name %>"
+                 src="<% if ranking.picture -%>
+                      <%= url_for ranking.picture.public_filename(:thumb) -%>
+                     <%- else -%>
+                     /images/default_icon.png
+                     <%- end %>" />
+                       <p class="ranking-info">
+            <strong><%= white_list ranking.name %></strong><br />
+            <%= white_list ranking.description %></p>
+               </li>
+      <% end %>
+       </ul>
+       
+       <div style="clear:both;"></div>
+       
+       <div id="results-bottom">
+               <div id="container">
+                <a href="<%= votepassword_url :urlpassword => "open." + @voter.election.id.to_s, 'embed' => 'true' %>"><h2>Results</h2></a>
+                       
+            <p>Your vote was recorded correctly.</p>
+
+               </div>
+       </div>
+</div>
+
+
diff --git a/app/views/layouts/embed.rhtml b/app/views/layouts/embed.rhtml
new file mode 100644 (file)
index 0000000..d8290fa
--- /dev/null
@@ -0,0 +1,19 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+  <head>
+    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+    <title>Selectricity</title>
+    <%= stylesheet_link_tag "embed", :media => "all" %>
+    <%begin%>
+      <%= stylesheet_link_tag "ie6hacks", :media => "all" if 
+      request.user_agent =~ /msie\s(5\.[5-9]|[6]\.[0-9]*).*(win)/i %>
+    <%rescue NoMethodError%>
+    <%end%>
+    <%= javascript_include_tag "prototype", "effects", "dragdrop", "controls" %>
+  </head>
+
+  <body>
+  <%= @content_for_layout %>
+  </body>
+
+</html>
index 9814aed4c0f966922aac5025051a010c7e4b5b15..3a9ebb01fb95e2907de1460fe7afb47d0e454fc7 100644 (file)
@@ -3,5 +3,5 @@
 
 <h2>Details</h2>
 
-<p><%= link_to "Auditing Information", { :action => 'details', :id => @voter.password }, :popup => [] %></p>
+<p><%= link_to "Auditing Information", { :action => 'details', :id => @password }, :popup => [] %></p>
 
index 914077ce1d50783317fdf7cb1616bb19083eb441..bd1040efc842dfa48b2d774753d3d7237abae46a 100644 (file)
@@ -11,7 +11,7 @@
 least preferred. Please list <em>all</em> choices in every vote.
 <em>(For example, 123 or 321 or 213, etc.)</em></p>
 
-<%= form_tag :action => 'review', :id => @voter.password %>
+<%= form_tag :action => 'review', :id => @password %>
 <%= text_field :vote, :votestring -%>
 <%= submit_tag "Vote!" %>
 
index 5b8d038178fe9d93c9aa39f92d4bee65e64843e4..2f250e077e536b65c6f7dbdc25ee1554f6cee276 100644 (file)
@@ -6,5 +6,5 @@ order.</p>
 <%= render :partial => 'common/sortable_vote' %>
 
 <div style="margin-left: 30pt;">
-<%= button_to "Submit Vote", :action => 'review', :id => @voter.password %>
+<%= button_to "Submit Vote", :action => 'review', :id => @password %>
 </div>
index 9d4f1d0675042eae322e577a5421c015e07f2941..5e8a8d1695669256b4a963212fd0eb6e0c1332dc 100644 (file)
@@ -30,12 +30,10 @@ vote.</p>
 
 <% @voter.election.candidates.each do |candidate| %>
   <% @current_candidate = candidate %>
-
   <div id="cand<%= @current_candidate.id %>">
-  <h3><%=h @current_candidate.name -%></h3>
-      <blockquote>
-      <%=h (@current_candidate.description) %>
-      </blockquote>
+  <h3><%= h @current_candidate.name %></h3>
+  <%= render :partial => 'election/candidate_box_info' %>
   </div>
     <% end %>
 </ul>
+
index d9ecf19cdd427d9583103665a56d2d458d13f48d..657c075702d2aacfcfbb4bd95107d9e5c9721920 100644 (file)
@@ -24,13 +24,12 @@ preferred to least preferred:</p>
 <p>Please select from one of the following pages.</p>
 
 <div style="text-align: center;">
-  <p><%= button_to 'Confirm This Vote', :action => 'confirm', :id => @voter.password %></p>
+  <p><%= button_to 'Confirm This Vote', :action => 'confirm', :id => @password %></p>
 
   <p>If you choose, you will be able to go back<br />and change it up until
   the end of hte voting period.</p>
-
   <p><%= button_to 'Discard This Vote', votepassword_url(
-                   :action => 'index', :urlpassword => @voter.password) %></p>
+                   :action => 'index', :urlpassword => @password) %></p>
 
   <p>You will be returned to the voting page to vote<br /> again, if you choose.</p>
 
index e2f458d3e2afeed8eea48e44df290ed4b8c0b728..8c52ca077ad23e90fea7493117831242c2b55d9f 100644 (file)
@@ -17,13 +17,17 @@ ActionController::Routing::Routes.draw do |map|
 
   map.connect 'voter/:action',
               :controller => 'voter',
-              :requirements => { :action => /(review|confirm|authenticate|index|login|reminder)/ }
+              :requirements => { :action => /(review|confirm|authenticate|index|login|reminder|results)/ }
+
+  map.voteopen 'voter/open.:election_id',
+                   :controller => 'voter',
+                   :action => 'index'
 
   map.votepassword 'voter/:urlpassword',
                    :controller => 'voter',
                    :action => 'index'
 
-  map.connect 'quickvote/:action/:id',
+  map.connect 'quickvote/:action/(open.)?:id',
                :controller => 'quickvote',
                :requirements => { :action => /(create|add_candidate|sort_candidates|my_quickvotes)/ }
 
diff --git a/db/migrate/002_add_embeddable_support.rb b/db/migrate/002_add_embeddable_support.rb
new file mode 100644 (file)
index 0000000..48fa00d
--- /dev/null
@@ -0,0 +1,16 @@
+class AddEmbeddableSupport < ActiveRecord::Migration
+  def self.up
+    add_column :elections, :embeddable, :boolean,
+               :null => false, :default => false
+    add_column :elections, :authenticated, :boolean,
+               :null => false, :default => true
+    add_column :elections, :early_results, :boolean,
+               :null => false, :default => false
+  end
+
+  def self.down
+    remove_column :elections, :embeddable
+    remove_column :elections, :authenticated
+    remove_column :elections, :early_results
+  end
+end
index 1195e09286dcff910140f93f171c3186b5e58ac7..aa46f6fa78c1033e26b97e4e0818175135db77a0 100644 (file)
@@ -2,7 +2,7 @@
 # migrations feature of ActiveRecord to incrementally modify your database, and
 # then regenerate this schema definition.
 
-ActiveRecord::Schema.define(:version => 1) do
+ActiveRecord::Schema.define(:version => 2) do
 
   create_table "candidates", :force => true do |t|
     t.column "election_id", :integer,                                :null => false
@@ -23,6 +23,9 @@ ActiveRecord::Schema.define(:version => 1) do
     t.column "quickuser",       :string
     t.column "election_method", :string,   :limit => 100, :default => "ssd"
     t.column "type",            :string,   :limit => 100, :default => "",    :null => false
+    t.column "embeddable",      :boolean,                 :default => false, :null => false
+    t.column "authenticated",   :boolean,                 :default => true,  :null => false
+    t.column "early_results",   :boolean,                 :default => false, :null => false
   end
 
   add_index "elections", ["user_id"], :name => "fk_user_election"
diff --git a/public/images/default_icon.png b/public/images/default_icon.png
new file mode 100644 (file)
index 0000000..57c9731
Binary files /dev/null and b/public/images/default_icon.png differ
diff --git a/public/images/embed_basic_bg.png b/public/images/embed_basic_bg.png
new file mode 100644 (file)
index 0000000..a014a01
Binary files /dev/null and b/public/images/embed_basic_bg.png differ
diff --git a/public/images/embed_header_icon.png b/public/images/embed_header_icon.png
new file mode 100644 (file)
index 0000000..5c65105
Binary files /dev/null and b/public/images/embed_header_icon.png differ
diff --git a/public/images/embed_results_changevote.png b/public/images/embed_results_changevote.png
new file mode 100644 (file)
index 0000000..534533b
Binary files /dev/null and b/public/images/embed_results_changevote.png differ
diff --git a/public/images/embed_voting_bg.png b/public/images/embed_voting_bg.png
new file mode 100644 (file)
index 0000000..bbf30b9
Binary files /dev/null and b/public/images/embed_voting_bg.png differ
diff --git a/public/images/embed_voting_submitvote.png b/public/images/embed_voting_submitvote.png
new file mode 100644 (file)
index 0000000..a435188
Binary files /dev/null and b/public/images/embed_voting_submitvote.png differ
diff --git a/public/stylesheets/embed.css b/public/stylesheets/embed.css
new file mode 100644 (file)
index 0000000..fe0b7f2
--- /dev/null
@@ -0,0 +1,202 @@
+@charset "utf-8";\r
+/* CSS Document */\r
+\r
+/*****************************************************************************************\r
+ *\r
+ * "Reset Reloaded"\r
+ * Thanks to Eric Meyer\r
+ * http://meyerweb.com/eric/thoughts/2007/05/01/reset-reloaded/\r
+ *\r
+ */\r
+\r
+html, body, div, span, applet, object, iframe,\r
+h1, h2, h3, h4, h5, h6, p, blockquote, pre,\r
+a, abbr, acronym, address, big, cite, code,\r
+del, dfn, em, font, img, ins, kbd, q, s, samp,\r
+small, strike, strong, sub, sup, tt, var,\r
+dl, dt, dd, fieldset, form, label, legend,\r
+table, caption, tbody, tfoot, thead, tr, th, td {\r
+       margin: 0;\r
+       padding: 0;\r
+       border: 0;\r
+       outline: 0;\r
+       font-weight: inherit;\r
+       font-style: inherit;\r
+       font-size: 100%; \r
+       font-family: inherit;\r
+       vertical-align: baseline;\r
+}\r
+\r
+strong, h2, h3 {\r
+    font-weight: bold;\r
+}\r
+\r
+body {\r
+       line-height: 1;\r
+       color: black;\r
+       background: white;\r
+}\r
+\r
+/* tables still need 'cellspacing="0"' in the markup */\r
+table {\r
+       border-collapse: separate;\r
+       border-spacing: 0;\r
+}\r
+\r
+caption, th, td {\r
+       text-align: left;\r
+       font-weight: normal;\r
+}\r
+\r
+blockquote:before, blockquote:after,\r
+q:before, q:after {\r
+       content: "";\r
+}\r
+\r
+blockquote, q {\r
+       quotes: "" "";\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/* GENERIC *****************************************************************************/\r
+\r
+body {\r
+       font-family: helvetica,verdana;\r
+       font-size: 11px;\r
+       color: white;\r
+}\r
+\r
+a {\r
+       color: inherit;\r
+       text-decoration: none;\r
+}\r
+\r
+.submit_vote_button {\r
+       cursor: pointer;\r
+}\r
+\r
+\r
+#header {\r
+    width: 330px;\r
+    height: 53px;\r
+       background: transparent url(/images/embed_basic_bg.png) top left no-repeat;\r
+       margin: 0px;\r
+       padding: 0px;\r
+       overflow: hidden;\r
+}\r
+\r
+#header h2 {\r
+    font-size: 25px;\r
+    margin: 12px 0px 12px 7px;\r
+    color: #FFF;\r
+    font-weight: normal;\r
+}\r
+#header_icon {\r
+    display: float;\r
+    float: right;\r
+}\r
+\r
+\r
+/* VOTING ******************************************************************************/\r
+\r
+#voting-box {\r
+       width: 330px;\r
+       height: 317px;\r
+       background: transparent url(/images/embed_voting_bg.png) top left no-repeat;\r
+       margin: 0px;\r
+       padding: 0px;\r
+       overflow: hidden;\r
+}\r
+\r
+ul {\r
+       margin: 0 0 0 40px;\r
+       padding: 0 0 0 0;\r
+       list-style: none;\r
+}\r
+\r
+.ranking {\r
+       margin: 0px;\r
+       height: 53px;\r
+    overflow: hidden !important;\r
+}\r
+\r
+.ranking img {\r
+       margin: 0 0 0 0;\r
+       padding: 0 0 0 0;\r
+       float: left;\r
+       clear: left;\r
+}\r
+\r
+.ranking-info {\r
+       margin-left: 70px;\r
+       width: 202px;\r
+       height: 23px;\r
+       padding: 11px 6px 13px 6px;\r
+       color: #666666;\r
+       line-height: 1.2em;\r
+       border: 3px solid transparent;\r
+}\r
+\r
+.ranking-info a {\r
+       font-weight: bold;\r
+       color: #666666;\r
+}\r
+\r
+#voting-bottom {\r
+       color: #464646;\r
+    position: absolute;\r
+    top: 318px;\r
+    width: 330px;\r
+}\r
+\r
+#container {\r
+       margin: 0 auto 0 auto;\r
+       width: 90%;\r
+}\r
+\r
+#voting-bottom h2, #results-bottom h2 {\r
+       padding-top: 20px;\r
+       height: 0px;\r
+       width: 119px;\r
+       overflow: hidden;\r
+       float: left;\r
+       margin-top: 16px;\r
+}\r
+\r
+#voting-bottom p, #results-bottom p {\r
+       float: left;\r
+       width: 160px;\r
+       margin-top: 12px;\r
+       margin-left: 10px;\r
+       line-height: 1.3em;\r
+}\r
+\r
+\r
+#voting-bottom h2 {\r
+       background: transparent url(/images/embed_voting_submitvote.png);\r
+}\r
+\r
+#results-bottom h2 {\r
+       background: transparent url(/images/embed_results_changevote.png);\r
+}\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
+\r
index e7ff4a6587ec91b1854b689e5ccabf64676c3043..1ac598a690632ed6400287698997628574713c22 100644 (file)
@@ -439,14 +439,9 @@ div.photo img {
 .candidate_box_info {
  margin: 0.5em 0 0.5em 3em;
 }
-/*.candidate_box_picture {
- width: 100px;
+.candidate_box_picture {
  float: left;
- margin: 0 0.8em 0.5em 0;
-}*/
-.candidate_box_picture img {
- width: 100px;
- border: 1px solid black;
+ margin: 0 0.8em 0.4em 0;
 }
 .candidate_box_description {
  display: inline;

Benjamin Mako Hill || Want to submit a patch?