bcms_polling 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYRIGHT.txt +23 -0
- data/LICENSE.txt +165 -0
- data/README.markdown +48 -0
- data/Rakefile +42 -0
- data/VERSION +1 -0
- data/app/controllers/cms/polls_controller.rb +2 -0
- data/app/controllers/polling_controller.rb +44 -0
- data/app/helpers/cms/polls_helper.rb +10 -0
- data/app/models/poll.rb +37 -0
- data/app/models/poll_response.rb +4 -0
- data/app/views/cms/polls/_form.html.erb +68 -0
- data/app/views/cms/polls/render.html.erb +28 -0
- data/app/views/polling/results.html.erb +13 -0
- data/db/migrate/20110216195733_create_polls.rb +25 -0
- data/doc/README_FOR_APP +2 -0
- data/lib/bcms_polling/routes.rb +12 -0
- data/lib/bcms_polling.rb +1 -0
- data/public/bcms/polling/README +1 -0
- data/public/bcms/polling/bcms-polling.css +35 -0
- data/public/bcms/polling/bcms-polling.js +44 -0
- data/rails/init.rb +4 -0
- data/test/functional/cms/poll_responses_controller_test.rb +11 -0
- data/test/functional/cms/polls_controller_test.rb +11 -0
- data/test/functional/poll_responses_controller_test.rb +8 -0
- data/test/functional/polls_controller_test.rb +8 -0
- data/test/performance/browsing_test.rb +9 -0
- data/test/test_helper.rb +38 -0
- data/test/unit/helpers/poll_responses_helper_test.rb +4 -0
- data/test/unit/helpers/polls_helper_test.rb +4 -0
- data/test/unit/models/poll_response_test.rb +9 -0
- data/test/unit/models/poll_test.rb +41 -0
- metadata +107 -0
data/COPYRIGHT.txt
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
All BrowserCMS code is Copyright (C) 1998-2010 by BrowserMedia, LLC.
|
2
|
+
|
3
|
+
This program is free software: you can redistribute it and/or modify
|
4
|
+
it under the terms of the GNU Lesser General Public License as published by
|
5
|
+
the Free Software Foundation, either version 3 of the License, or
|
6
|
+
(at your option) any later version.
|
7
|
+
|
8
|
+
This program is distributed in the hope that it will be useful,
|
9
|
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
GNU Lesser General Public License for more details.
|
12
|
+
|
13
|
+
You should have received a copy of the GNU Lesser General Public License
|
14
|
+
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
BrowserCMS is a registered trademark of BrowserMedia, LLC.
|
17
|
+
|
18
|
+
BrowserCMS includes works under other copyright notices and distributed
|
19
|
+
according to the terms of the GNU Lesser Public License or a compatible
|
20
|
+
license, including:
|
21
|
+
|
22
|
+
- jQuery - Copyright (C) 2009 John Resig
|
23
|
+
- CKEditor - Copyright (C) 2003-2009 Frederico Caldeira Knabben
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
GNU LESSER GENERAL PUBLIC LICENSE
|
2
|
+
Version 3, 29 June 2007
|
3
|
+
|
4
|
+
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
5
|
+
Everyone is permitted to copy and distribute verbatim copies
|
6
|
+
of this license document, but changing it is not allowed.
|
7
|
+
|
8
|
+
|
9
|
+
This version of the GNU Lesser General Public License incorporates
|
10
|
+
the terms and conditions of version 3 of the GNU General Public
|
11
|
+
License, supplemented by the additional permissions listed below.
|
12
|
+
|
13
|
+
0. Additional Definitions.
|
14
|
+
|
15
|
+
As used herein, "this License" refers to version 3 of the GNU Lesser
|
16
|
+
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
17
|
+
General Public License.
|
18
|
+
|
19
|
+
"The Library" refers to a covered work governed by this License,
|
20
|
+
other than an Application or a Combined Work as defined below.
|
21
|
+
|
22
|
+
An "Application" is any work that makes use of an interface provided
|
23
|
+
by the Library, but which is not otherwise based on the Library.
|
24
|
+
Defining a subclass of a class defined by the Library is deemed a mode
|
25
|
+
of using an interface provided by the Library.
|
26
|
+
|
27
|
+
A "Combined Work" is a work produced by combining or linking an
|
28
|
+
Application with the Library. The particular version of the Library
|
29
|
+
with which the Combined Work was made is also called the "Linked
|
30
|
+
Version".
|
31
|
+
|
32
|
+
The "Minimal Corresponding Source" for a Combined Work means the
|
33
|
+
Corresponding Source for the Combined Work, excluding any source code
|
34
|
+
for portions of the Combined Work that, considered in isolation, are
|
35
|
+
based on the Application, and not on the Linked Version.
|
36
|
+
|
37
|
+
The "Corresponding Application Code" for a Combined Work means the
|
38
|
+
object code and/or source code for the Application, including any data
|
39
|
+
and utility programs needed for reproducing the Combined Work from the
|
40
|
+
Application, but excluding the System Libraries of the Combined Work.
|
41
|
+
|
42
|
+
1. Exception to Section 3 of the GNU GPL.
|
43
|
+
|
44
|
+
You may convey a covered work under sections 3 and 4 of this License
|
45
|
+
without being bound by section 3 of the GNU GPL.
|
46
|
+
|
47
|
+
2. Conveying Modified Versions.
|
48
|
+
|
49
|
+
If you modify a copy of the Library, and, in your modifications, a
|
50
|
+
facility refers to a function or data to be supplied by an Application
|
51
|
+
that uses the facility (other than as an argument passed when the
|
52
|
+
facility is invoked), then you may convey a copy of the modified
|
53
|
+
version:
|
54
|
+
|
55
|
+
a) under this License, provided that you make a good faith effort to
|
56
|
+
ensure that, in the event an Application does not supply the
|
57
|
+
function or data, the facility still operates, and performs
|
58
|
+
whatever part of its purpose remains meaningful, or
|
59
|
+
|
60
|
+
b) under the GNU GPL, with none of the additional permissions of
|
61
|
+
this License applicable to that copy.
|
62
|
+
|
63
|
+
3. Object Code Incorporating Material from Library Header Files.
|
64
|
+
|
65
|
+
The object code form of an Application may incorporate material from
|
66
|
+
a header file that is part of the Library. You may convey such object
|
67
|
+
code under terms of your choice, provided that, if the incorporated
|
68
|
+
material is not limited to numerical parameters, data structure
|
69
|
+
layouts and accessors, or small macros, inline functions and templates
|
70
|
+
(ten or fewer lines in length), you do both of the following:
|
71
|
+
|
72
|
+
a) Give prominent notice with each copy of the object code that the
|
73
|
+
Library is used in it and that the Library and its use are
|
74
|
+
covered by this License.
|
75
|
+
|
76
|
+
b) Accompany the object code with a copy of the GNU GPL and this license
|
77
|
+
document.
|
78
|
+
|
79
|
+
4. Combined Works.
|
80
|
+
|
81
|
+
You may convey a Combined Work under terms of your choice that,
|
82
|
+
taken together, effectively do not restrict modification of the
|
83
|
+
portions of the Library contained in the Combined Work and reverse
|
84
|
+
engineering for debugging such modifications, if you also do each of
|
85
|
+
the following:
|
86
|
+
|
87
|
+
a) Give prominent notice with each copy of the Combined Work that
|
88
|
+
the Library is used in it and that the Library and its use are
|
89
|
+
covered by this License.
|
90
|
+
|
91
|
+
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
92
|
+
document.
|
93
|
+
|
94
|
+
c) For a Combined Work that displays copyright notices during
|
95
|
+
execution, include the copyright notice for the Library among
|
96
|
+
these notices, as well as a reference directing the user to the
|
97
|
+
copies of the GNU GPL and this license document.
|
98
|
+
|
99
|
+
d) Do one of the following:
|
100
|
+
|
101
|
+
0) Convey the Minimal Corresponding Source under the terms of this
|
102
|
+
License, and the Corresponding Application Code in a form
|
103
|
+
suitable for, and under terms that permit, the user to
|
104
|
+
recombine or relink the Application with a modified version of
|
105
|
+
the Linked Version to produce a modified Combined Work, in the
|
106
|
+
manner specified by section 6 of the GNU GPL for conveying
|
107
|
+
Corresponding Source.
|
108
|
+
|
109
|
+
1) Use a suitable shared library mechanism for linking with the
|
110
|
+
Library. A suitable mechanism is one that (a) uses at run time
|
111
|
+
a copy of the Library already present on the user's computer
|
112
|
+
system, and (b) will operate properly with a modified version
|
113
|
+
of the Library that is interface-compatible with the Linked
|
114
|
+
Version.
|
115
|
+
|
116
|
+
e) Provide Installation Information, but only if you would otherwise
|
117
|
+
be required to provide such information under section 6 of the
|
118
|
+
GNU GPL, and only to the extent that such information is
|
119
|
+
necessary to install and execute a modified version of the
|
120
|
+
Combined Work produced by recombining or relinking the
|
121
|
+
Application with a modified version of the Linked Version. (If
|
122
|
+
you use option 4d0, the Installation Information must accompany
|
123
|
+
the Minimal Corresponding Source and Corresponding Application
|
124
|
+
Code. If you use option 4d1, you must provide the Installation
|
125
|
+
Information in the manner specified by section 6 of the GNU GPL
|
126
|
+
for conveying Corresponding Source.)
|
127
|
+
|
128
|
+
5. Combined Libraries.
|
129
|
+
|
130
|
+
You may place library facilities that are a work based on the
|
131
|
+
Library side by side in a single library together with other library
|
132
|
+
facilities that are not Applications and are not covered by this
|
133
|
+
License, and convey such a combined library under terms of your
|
134
|
+
choice, if you do both of the following:
|
135
|
+
|
136
|
+
a) Accompany the combined library with a copy of the same work based
|
137
|
+
on the Library, uncombined with any other library facilities,
|
138
|
+
conveyed under the terms of this License.
|
139
|
+
|
140
|
+
b) Give prominent notice with the combined library that part of it
|
141
|
+
is a work based on the Library, and explaining where to find the
|
142
|
+
accompanying uncombined form of the same work.
|
143
|
+
|
144
|
+
6. Revised Versions of the GNU Lesser General Public License.
|
145
|
+
|
146
|
+
The Free Software Foundation may publish revised and/or new versions
|
147
|
+
of the GNU Lesser General Public License from time to time. Such new
|
148
|
+
versions will be similar in spirit to the present version, but may
|
149
|
+
differ in detail to address new problems or concerns.
|
150
|
+
|
151
|
+
Each version is given a distinguishing version number. If the
|
152
|
+
Library as you received it specifies that a certain numbered version
|
153
|
+
of the GNU Lesser General Public License "or any later version"
|
154
|
+
applies to it, you have the option of following the terms and
|
155
|
+
conditions either of that published version or of any later version
|
156
|
+
published by the Free Software Foundation. If the Library as you
|
157
|
+
received it does not specify a version number of the GNU Lesser
|
158
|
+
General Public License, you may choose any version of the GNU Lesser
|
159
|
+
General Public License ever published by the Free Software Foundation.
|
160
|
+
|
161
|
+
If the Library as you received it specifies that a proxy can decide
|
162
|
+
whether future versions of the GNU Lesser General Public License shall
|
163
|
+
apply, that proxy's public statement of acceptance of any version is
|
164
|
+
permanent authorization for you to choose that version for the
|
165
|
+
Library.
|
data/README.markdown
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
This is a polling module for BrowerCMS. It allows editors to create polls which have a single question, and an unlimited number of answers.
|
2
|
+
Users can participate in polls by voting (once), and can see the results ahead of time. This module is primarily designed to
|
3
|
+
provide a simple feedback option for sites to collect information from visitors.
|
4
|
+
|
5
|
+
* Editors should have the ability to easily create, edit and delete polls on any page of
|
6
|
+
the website
|
7
|
+
* Polls should consist of a question followed by a series of potential answers
|
8
|
+
* Users should be limited to selecting only one answer, and submitting that answer to any
|
9
|
+
given Poll only once
|
10
|
+
* Users should be able to view Poll results in a simple, graphical format, without requiring
|
11
|
+
users to leave or refresh the page
|
12
|
+
* Pages should be able to contain one or many Polls
|
13
|
+
* A single Poll should be able to reside on one or many pages simultaneously
|
14
|
+
* Content Editors have a convient link to 'reset' their voting privileges in order to support testing.
|
15
|
+
|
16
|
+
Security Caveat:
|
17
|
+
=====
|
18
|
+
Security to prevent multiple voting is extremely simple, storing a cookie when a user votes, so this solution is not appropriate for 'serious' voting. Users can
|
19
|
+
vote multiple times from multiple computers or just clear their cookies to revote.
|
20
|
+
|
21
|
+
Installation:
|
22
|
+
=============
|
23
|
+
|
24
|
+
gem install bcms_polling
|
25
|
+
|
26
|
+
Follow standard module installation after that.
|
27
|
+
|
28
|
+
Finally, edit your project's app/helpers/application_helper.rb so it looks like:
|
29
|
+
|
30
|
+
module ApplicationHelper
|
31
|
+
include Cms::PollsHelper
|
32
|
+
end
|
33
|
+
|
34
|
+
Finally, add the default stylesheet for polls to your template, tweaking as necessary or inlining into the site's main stylesheet.
|
35
|
+
|
36
|
+
<%= stylesheet_link_tag '/bcms/polling/bcms-polling' %>
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
Bugs:
|
41
|
+
====
|
42
|
+
* Tab order for responses is wrong. [Minor Issue]
|
43
|
+
|
44
|
+
BrowserCMS Core Notes:
|
45
|
+
================
|
46
|
+
* Using nested_attributes doesn't work without some monkeying around. Specifically, BrowserCMS doesn't consider nested attributes as 'changes', so
|
47
|
+
updates (and a new version) doesn't get saved. Can fix this by timestamping 'updated_at' but the core CMS should be aware of
|
48
|
+
nested_attributes and save correctly if they are present.
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
2
|
+
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
3
|
+
|
4
|
+
require(File.join(File.dirname(__FILE__), 'config', 'boot'))
|
5
|
+
|
6
|
+
require 'rake'
|
7
|
+
require 'rake/testtask'
|
8
|
+
require 'rake/rdoctask'
|
9
|
+
|
10
|
+
require 'tasks/rails'
|
11
|
+
|
12
|
+
begin
|
13
|
+
require 'jeweler'
|
14
|
+
Jeweler::Tasks.new do |gemspec|
|
15
|
+
gemspec.name = "bcms_polling"
|
16
|
+
gemspec.rubyforge_project = "browsercms"
|
17
|
+
gemspec.summary = "A Polling Module for BrowserCMS"
|
18
|
+
gemspec.email = "github@browsermedia.com"
|
19
|
+
gemspec.homepage = "http://browsercms.org"
|
20
|
+
gemspec.description = "Allows for user feedback via short polling questions."
|
21
|
+
gemspec.authors = ["BrowserMedia"]
|
22
|
+
gemspec.files = []
|
23
|
+
gemspec.files += Dir["app/**/*"]
|
24
|
+
gemspec.files -= Dir["app/views/layouts/templates/*"]
|
25
|
+
gemspec.files -= Dir["app/controllers/application_controller.rb"]
|
26
|
+
gemspec.files -= Dir["app/helpers/application_helper.rb"]
|
27
|
+
gemspec.files += Dir["doc/**/*"]
|
28
|
+
gemspec.files += Dir["db/migrate/[0-9]*.rb"].reject {|f| f =~ /_browsercms|_load_seed/ }
|
29
|
+
gemspec.files += Dir["lib/**/*"]
|
30
|
+
gemspec.files += Dir["rails/init.rb"]
|
31
|
+
gemspec.files += Dir["public/bcms/polling/**/*"]
|
32
|
+
gemspec.files += Dir["README.markdown"]
|
33
|
+
gemspec.files += Dir["Rakefile"]
|
34
|
+
gemspec.files += Dir["LICENSE.txt"]
|
35
|
+
gemspec.files += Dir["COPYRIGHT.txt"]
|
36
|
+
gemspec.files += Dir["VERSION"]
|
37
|
+
end
|
38
|
+
rescue LoadError
|
39
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
40
|
+
end
|
41
|
+
|
42
|
+
Jeweler::GemcutterTasks.new
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
1.0.0
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Handles the public submissions of answers to poll questions.
|
2
|
+
class PollingController < ApplicationController
|
3
|
+
include Cms::PollsHelper
|
4
|
+
include Cms::Authentication::Controller
|
5
|
+
|
6
|
+
def update
|
7
|
+
@response = PollResponse.find(params[:id])
|
8
|
+
unique_key = cookie_key(@response.poll)
|
9
|
+
|
10
|
+
if !cookies[unique_key]
|
11
|
+
@response.votes += 1
|
12
|
+
@response.save!
|
13
|
+
|
14
|
+
cookies[unique_key] = {
|
15
|
+
:value => true,
|
16
|
+
:expires => 1.year.from_now
|
17
|
+
}
|
18
|
+
logger.warn "Saving cookie called '#{unique_key}'"
|
19
|
+
else
|
20
|
+
logger.warn "User attempted to submit another answer to the same poll."
|
21
|
+
end
|
22
|
+
|
23
|
+
render :nothing => true, :status => :ok
|
24
|
+
end
|
25
|
+
|
26
|
+
def results
|
27
|
+
@poll = Poll.find(params[:id])
|
28
|
+
render :layout => false
|
29
|
+
end
|
30
|
+
|
31
|
+
def reset
|
32
|
+
@poll = Poll.find(params[:id])
|
33
|
+
|
34
|
+
cookie = cookie_key(@poll)
|
35
|
+
cookies.delete(cookie)
|
36
|
+
|
37
|
+
redirect_to "/"
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
def cookie_key(poll)
|
42
|
+
cookie_for(poll)
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Cms::PollsHelper
|
2
|
+
def response_results(response)
|
3
|
+
total = response.poll.total_votes == 0 ? 0 : (response.votes.to_f / response.poll.total_votes.to_f) * 100
|
4
|
+
"#{response.votes} votes (#{sprintf("%.2f", total)}%)"
|
5
|
+
end
|
6
|
+
|
7
|
+
def cookie_for(poll)
|
8
|
+
"cmspolls_#{poll.id}".to_sym
|
9
|
+
end
|
10
|
+
end
|
data/app/models/poll.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
class Poll < ActiveRecord::Base
|
2
|
+
acts_as_content_block
|
3
|
+
|
4
|
+
has_many :responses, :class_name => "PollResponse"
|
5
|
+
accepts_nested_attributes_for :responses, :allow_destroy => true
|
6
|
+
|
7
|
+
validates_presence_of :question
|
8
|
+
|
9
|
+
def total_votes
|
10
|
+
self.responses.inject(0) { |sum, r| sum += r.votes }
|
11
|
+
end
|
12
|
+
|
13
|
+
def name
|
14
|
+
question
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
# Overridden to make sure nested attributes (i.e. poll responses) will correctly update.
|
19
|
+
def update_attributes(attributes)
|
20
|
+
unless attributes[:responses_attributes].blank?
|
21
|
+
logger.debug "Forcing update of poll so updated answers are saved."
|
22
|
+
self.updated_at = Time.now # Force this block to update, regardless of what was submitted.
|
23
|
+
|
24
|
+
else
|
25
|
+
logger.debug "No poll attributes were submitted."
|
26
|
+
end
|
27
|
+
super(attributes)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Overridden for purely debugging purposes.
|
31
|
+
def different_from_last_draft?
|
32
|
+
result = super
|
33
|
+
logger.debug "Is this poll is different than the last draft? '#{result}'"
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
<script type="text/javascript">
|
2
|
+
|
3
|
+
var new_response = '<div class="fields text_fields">\n';
|
4
|
+
new_response += '<label for="poll_responses">Response #X</label>\n';
|
5
|
+
new_response += '<input type="text" value="" tabindex="5" size="30" name="" id="poll_responses">\n';
|
6
|
+
new_response += '</div>';
|
7
|
+
|
8
|
+
function addResponse() {
|
9
|
+
var responseCount = $('div#responses > div').length;
|
10
|
+
$('div#responses').append(new_response);
|
11
|
+
$('div.fields.text_fields > label[for="poll_responses"]:last').text('Response #' + (responseCount + 1));
|
12
|
+
$('div.fields.text_fields > input#poll_responses:last').attr('name', 'poll[responses_attributes][' + responseCount + '][answer]');
|
13
|
+
}
|
14
|
+
|
15
|
+
$(document).ready(function() {
|
16
|
+
var new_record = <%= @block.new_record? %>;
|
17
|
+
if (new_record) {
|
18
|
+
addResponse();
|
19
|
+
addResponse();
|
20
|
+
}
|
21
|
+
});
|
22
|
+
|
23
|
+
function removeResponse(element){
|
24
|
+
var delete_button = $(element);
|
25
|
+
delete_button.prev().hide();
|
26
|
+
delete_button.hide();
|
27
|
+
var delete_checkbox_class = '#poll_responses_attributes_'+ delete_button.attr('data-count-id') +'__destroy';
|
28
|
+
$(delete_checkbox_class).attr('checked', 'checked');
|
29
|
+
}
|
30
|
+
</script>
|
31
|
+
|
32
|
+
<style>
|
33
|
+
div.response {
|
34
|
+
position: relative;
|
35
|
+
}
|
36
|
+
|
37
|
+
div.response a {
|
38
|
+
position: absolute;
|
39
|
+
top: 15px;
|
40
|
+
right: 170px;
|
41
|
+
}
|
42
|
+
|
43
|
+
div.response > div.text_fields input {
|
44
|
+
width: 400px;
|
45
|
+
padding-bottom: 0px;
|
46
|
+
}
|
47
|
+
</style>
|
48
|
+
|
49
|
+
<%= f.cms_text_field :question %>
|
50
|
+
|
51
|
+
|
52
|
+
<div id="responses">
|
53
|
+
<% count = 0 -%>
|
54
|
+
<% available_responses = PollResponse.find(:all, :conditions => {:poll_id => f.object.id}) %>
|
55
|
+
<% f.fields_for(:responses, available_responses) do |response_fields| %>
|
56
|
+
<%= response_fields.cms_text_field :answer, :label => "Response ##{count = count + 1}" %>
|
57
|
+
<%= link_to_function('Delete', 'removeResponse(this)', 'data-count-id'=>count-1, :style=>'position: relative; left: 465px; top: -25px;') %>
|
58
|
+
<%= response_fields.check_box :_destroy, :style=>"display:none" %>
|
59
|
+
|
60
|
+
<% end %>
|
61
|
+
|
62
|
+
</div>
|
63
|
+
|
64
|
+
<div class="fields">
|
65
|
+
<label style="padding-left: 140px"></label>
|
66
|
+
<%= link_to_function('Add response', 'addResponse()') %>
|
67
|
+
</div>
|
68
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<% unless self.controller.instance_variable_defined? :@include_js_http_methods -%>
|
2
|
+
<%= javascript_include_tag 'jquery', '/bcms/polling/bcms-polling' %>
|
3
|
+
<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? -%>
|
4
|
+
<% self.controller.instance_variable_set(:@include_js_http_methods, true) -%>
|
5
|
+
<% end -%>
|
6
|
+
|
7
|
+
|
8
|
+
<div id='vote-<%= @content_block.id %>' class="bcms_poll">
|
9
|
+
<span class="question"><%= @content_block.question %></span>
|
10
|
+
|
11
|
+
<ul class="vote-choices">
|
12
|
+
<% for response in PollResponse.find(:all, :conditions => {:poll_id => @content_block.id}) %>
|
13
|
+
<li>
|
14
|
+
<span class="response"><%= response.answer %></span>
|
15
|
+
<%= link_to "Vote!", poll_response_url(response), :class => "vote-this", 'data-poll-id'=>@content_block.id %>
|
16
|
+
</li>
|
17
|
+
<% end %>
|
18
|
+
</ul>
|
19
|
+
<span class="show-results"><%= link_to "See the results", "#", 'data-poll-id'=>@content_block.id, :class => "show-results" %></span>
|
20
|
+
</div>
|
21
|
+
|
22
|
+
<% if cookies[cookie_for(@content_block)] -%>
|
23
|
+
<script type="text/javascript">
|
24
|
+
$(document).ready(function() {
|
25
|
+
showResults(<%= @content_block.id %>, false);
|
26
|
+
});
|
27
|
+
</script>
|
28
|
+
<% end -%>
|
@@ -0,0 +1,13 @@
|
|
1
|
+
<ul class="vote-results">
|
2
|
+
<% for response in @poll.responses %>
|
3
|
+
<li>
|
4
|
+
<strong><%= response.answer %></strong> — <%= response_results(response) %>
|
5
|
+
</li>
|
6
|
+
<% end %>
|
7
|
+
</ul>
|
8
|
+
<% if cookies[cookie_for(@poll)] && current_user.able_to?(:edit_content)-%>
|
9
|
+
<%= link_to "Vote Again (Reset Cookie)", poll_reset_path(@poll) %>
|
10
|
+
<% end %>
|
11
|
+
<% if params[:return] == 'true' %>
|
12
|
+
<%= link_to_function "Back to Poll", 'history.go(0);return false;' %>
|
13
|
+
<% end %>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
class CreatePolls < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_content_table :polls do |t|
|
4
|
+
t.string :name
|
5
|
+
t.text :question
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :poll_responses do |t|
|
9
|
+
t.text :answer
|
10
|
+
t.integer :votes, :default => 0
|
11
|
+
t.belongs_to :poll
|
12
|
+
end
|
13
|
+
|
14
|
+
ContentType.create!(:name => "Poll", :group_name => "Polling")
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
ContentType.delete_all(['name = ?', 'Poll'])
|
19
|
+
CategoryType.all(:conditions => ['name = ?', 'Poll']).each(&:destroy)
|
20
|
+
#If you aren't creating a versioned table, be sure to comment this out.
|
21
|
+
drop_table :poll_responses
|
22
|
+
drop_table :poll_versions
|
23
|
+
drop_table :polls
|
24
|
+
end
|
25
|
+
end
|
data/doc/README_FOR_APP
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
module Cms::Routes
|
2
|
+
def routes_for_bcms_polling
|
3
|
+
|
4
|
+
poll_results '/polls/:id/results', :controller=>"polling", :action=>'results'
|
5
|
+
poll_reset '/polls/:id/reset', :controller=>"polling", :action=>'reset'
|
6
|
+
poll_response '/poll_responses/:id', :controller=>"polling", :action=>'update'
|
7
|
+
namespace(:cms) do |cms|
|
8
|
+
cms.content_blocks :poll_responses
|
9
|
+
cms.content_blocks :polls
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/bcms_polling.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'bcms_polling/routes'
|
@@ -0,0 +1 @@
|
|
1
|
+
Use this directory to add public files that should copied from the gem into the project.
|
@@ -0,0 +1,35 @@
|
|
1
|
+
.bcms_poll .question {
|
2
|
+
font-weight: bold;
|
3
|
+
}
|
4
|
+
|
5
|
+
ul.vote-choices, ul.vote-results {
|
6
|
+
margin: 10px 0 !important;
|
7
|
+
padding: 0 !important;
|
8
|
+
}
|
9
|
+
|
10
|
+
ul.vote-choices li, ul.vote-results li {
|
11
|
+
background: none !important;
|
12
|
+
padding: 5px 0 !important;
|
13
|
+
}
|
14
|
+
|
15
|
+
a.vote-this, a.show-results {
|
16
|
+
display: inline;
|
17
|
+
text-align: center;
|
18
|
+
text-transform: uppercase;
|
19
|
+
background: #A2BC39;
|
20
|
+
color: #FFF;
|
21
|
+
font-size: 90%;
|
22
|
+
margin: 10px 0 !important;
|
23
|
+
padding: 2px 5px;
|
24
|
+
text-decoration: none;
|
25
|
+
}
|
26
|
+
|
27
|
+
a.vote-this {
|
28
|
+
|
29
|
+
}
|
30
|
+
|
31
|
+
a.show-results {
|
32
|
+
width: 60px;
|
33
|
+
right: 0;
|
34
|
+
font-weight: bold;
|
35
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
function _ajax_request(url, data, callback, type, method) {
|
2
|
+
if (jQuery.isFunction(data)) {
|
3
|
+
callback = data;
|
4
|
+
data = {};
|
5
|
+
}
|
6
|
+
|
7
|
+
data = (data ? data + "&" : "") + "authenticity_token=" + encodeURIComponent(AUTH_TOKEN);
|
8
|
+
|
9
|
+
return jQuery.ajax({
|
10
|
+
type: method,
|
11
|
+
url: url,
|
12
|
+
data: data,
|
13
|
+
success: callback,
|
14
|
+
dataType: type
|
15
|
+
});
|
16
|
+
}
|
17
|
+
|
18
|
+
jQuery.extend({
|
19
|
+
put: function(url, data, callback, type) {
|
20
|
+
return _ajax_request(url, data, callback, type, 'PUT');
|
21
|
+
},
|
22
|
+
delete_: function(url, data, callback, type) {
|
23
|
+
return _ajax_request(url, data, callback, type, 'DELETE');
|
24
|
+
}
|
25
|
+
});
|
26
|
+
|
27
|
+
function showResults(id, add_return_link) {
|
28
|
+
var pollUrl = '/polls/' + id + '/results?return=' + add_return_link;
|
29
|
+
$('div#vote-' + id).load(pollUrl);
|
30
|
+
}
|
31
|
+
|
32
|
+
$(document).ready(function() {
|
33
|
+
$('a.vote-this').click(function(eventObject) {
|
34
|
+
$.put(eventObject.target);
|
35
|
+
showResults($(this).attr('data-poll-id'), false);
|
36
|
+
return false;
|
37
|
+
});
|
38
|
+
|
39
|
+
$('.show-results').click(function(eventObject) {
|
40
|
+
showResults($(this).attr('data-poll-id'), true);
|
41
|
+
return false;
|
42
|
+
});
|
43
|
+
|
44
|
+
});
|
data/rails/init.rb
ADDED
data/test/test_helper.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + "/../config/environment")
|
3
|
+
require 'test_help'
|
4
|
+
|
5
|
+
class ActiveSupport::TestCase
|
6
|
+
# Transactional fixtures accelerate your tests by wrapping each test method
|
7
|
+
# in a transaction that's rolled back on completion. This ensures that the
|
8
|
+
# test database remains unchanged so your fixtures don't have to be reloaded
|
9
|
+
# between every test method. Fewer database queries means faster tests.
|
10
|
+
#
|
11
|
+
# Read Mike Clark's excellent walkthrough at
|
12
|
+
# http://clarkware.com/cgi/blosxom/2005/10/24#Rails10FastTesting
|
13
|
+
#
|
14
|
+
# Every Active Record database supports transactions except MyISAM tables
|
15
|
+
# in MySQL. Turn off transactional fixtures in this case; however, if you
|
16
|
+
# don't care one way or the other, switching from MyISAM to InnoDB tables
|
17
|
+
# is recommended.
|
18
|
+
#
|
19
|
+
# The only drawback to using transactional fixtures is when you actually
|
20
|
+
# need to test transactions. Since your test is bracketed by a transaction,
|
21
|
+
# any transactions started in your code will be automatically rolled back.
|
22
|
+
self.use_transactional_fixtures = true
|
23
|
+
|
24
|
+
# Instantiated fixtures are slow, but give you @david where otherwise you
|
25
|
+
# would need people(:david). If you don't want to migrate your existing
|
26
|
+
# test cases which use the @david style and don't mind the speed hit (each
|
27
|
+
# instantiated fixtures translates to a database query per test method),
|
28
|
+
# then set this back to true.
|
29
|
+
self.use_instantiated_fixtures = false
|
30
|
+
|
31
|
+
# Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
|
32
|
+
#
|
33
|
+
# Note: You'll currently still have to declare fixtures explicitly in integration tests
|
34
|
+
# -- they do not yet inherit this setting
|
35
|
+
fixtures :all
|
36
|
+
|
37
|
+
# Add more helper methods to be used by all tests here...
|
38
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '/../../test_helper')
|
2
|
+
|
3
|
+
class PollTest < ActiveSupport::TestCase
|
4
|
+
|
5
|
+
test "should be able to create new block" do
|
6
|
+
assert Poll.create!(:question=>"A?")
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
test "Should have responses" do
|
11
|
+
p = Poll.create!(:question=>"What color?")
|
12
|
+
|
13
|
+
p.responses << PollResponse.create!(:answer=>"Red")
|
14
|
+
p.responses << PollResponse.create!(:answer=>"Blue")
|
15
|
+
|
16
|
+
found = Poll.find(p.id)
|
17
|
+
assert_equal 2, p.responses.size
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
test "Should have responses unpublished" do
|
22
|
+
p = Poll.create!(:question=>"What color?")
|
23
|
+
|
24
|
+
p.responses << PollResponse.create!(:answer=>"Red")
|
25
|
+
p.responses << PollResponse.create!(:answer=>"Blue")
|
26
|
+
|
27
|
+
found = Poll.find(p.id)
|
28
|
+
found = found.as_of_draft_version
|
29
|
+
assert_equal 2, p.responses.size
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
test "Binding responses as nested attributes for new object" do
|
34
|
+
poll = Poll.create!(:question=>"Are you different?")
|
35
|
+
poll.update_attributes({ :responses_attributes=>{"0"=>{"answer"=>"Answer 1"}}})
|
36
|
+
assert_equal 1, poll.responses.size
|
37
|
+
assert_equal 1, PollResponse.count
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bcms_polling
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- BrowserMedia
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-02-17 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Allows for user feedback via short polling questions.
|
23
|
+
email: github@browsermedia.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- LICENSE.txt
|
30
|
+
- README.markdown
|
31
|
+
files:
|
32
|
+
- COPYRIGHT.txt
|
33
|
+
- LICENSE.txt
|
34
|
+
- README.markdown
|
35
|
+
- Rakefile
|
36
|
+
- VERSION
|
37
|
+
- app/controllers/cms/polls_controller.rb
|
38
|
+
- app/controllers/polling_controller.rb
|
39
|
+
- app/helpers/cms/polls_helper.rb
|
40
|
+
- app/models/poll.rb
|
41
|
+
- app/models/poll_response.rb
|
42
|
+
- app/views/cms/polls/_form.html.erb
|
43
|
+
- app/views/cms/polls/render.html.erb
|
44
|
+
- app/views/polling/results.html.erb
|
45
|
+
- db/migrate/20110216195733_create_polls.rb
|
46
|
+
- doc/README_FOR_APP
|
47
|
+
- lib/bcms_polling.rb
|
48
|
+
- lib/bcms_polling/routes.rb
|
49
|
+
- public/bcms/polling/README
|
50
|
+
- public/bcms/polling/bcms-polling.css
|
51
|
+
- public/bcms/polling/bcms-polling.js
|
52
|
+
- rails/init.rb
|
53
|
+
- test/functional/cms/poll_responses_controller_test.rb
|
54
|
+
- test/functional/cms/polls_controller_test.rb
|
55
|
+
- test/functional/poll_responses_controller_test.rb
|
56
|
+
- test/functional/polls_controller_test.rb
|
57
|
+
- test/performance/browsing_test.rb
|
58
|
+
- test/test_helper.rb
|
59
|
+
- test/unit/helpers/poll_responses_helper_test.rb
|
60
|
+
- test/unit/helpers/polls_helper_test.rb
|
61
|
+
- test/unit/models/poll_response_test.rb
|
62
|
+
- test/unit/models/poll_test.rb
|
63
|
+
has_rdoc: true
|
64
|
+
homepage: http://browsercms.org
|
65
|
+
licenses: []
|
66
|
+
|
67
|
+
post_install_message:
|
68
|
+
rdoc_options: []
|
69
|
+
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 3
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
none: false
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
hash: 3
|
87
|
+
segments:
|
88
|
+
- 0
|
89
|
+
version: "0"
|
90
|
+
requirements: []
|
91
|
+
|
92
|
+
rubyforge_project: browsercms
|
93
|
+
rubygems_version: 1.3.7
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: A Polling Module for BrowserCMS
|
97
|
+
test_files:
|
98
|
+
- test/functional/cms/poll_responses_controller_test.rb
|
99
|
+
- test/functional/cms/polls_controller_test.rb
|
100
|
+
- test/functional/poll_responses_controller_test.rb
|
101
|
+
- test/functional/polls_controller_test.rb
|
102
|
+
- test/performance/browsing_test.rb
|
103
|
+
- test/test_helper.rb
|
104
|
+
- test/unit/helpers/poll_responses_helper_test.rb
|
105
|
+
- test/unit/helpers/polls_helper_test.rb
|
106
|
+
- test/unit/models/poll_response_test.rb
|
107
|
+
- test/unit/models/poll_test.rb
|