Skip to content

Instantly share code, notes, and snippets.

@elmer
Forked from bhanuprasad143/application.js
Created June 28, 2010 10:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elmer/455695 to your computer and use it in GitHub Desktop.
Save elmer/455695 to your computer and use it in GitHub Desktop.
// Place your application-specific JavaScript functions and classes here
// This file is automatically included by javascript_include_tag :defaults
$(function() {
MIN_ANSWERS = 2
MAX_ANSWERS = 10
MIN_ANSWERS_MSG = "Minimum of two(2) answers required."
MAX_ANSWERS_MSG = "Maximum of ten(10) answers only."
TOP_ANSWER_MSG = "Can't go up answer is on the top list."
BOTTOM_ANSWER_MSG = "Can't go down answer is on the bottom list."
// this will be the elements to be inserted
repeat_elements = '\n<li class="poll_answers">'
repeat_elements += '\n<a style="display: none" href="#" class="move_answer"><img alt="Move" src="/images/move.png" /></a>'
repeat_elements += '\n<input id="poll_answers_answer_{ph}" name="poll_answers[answer_{ph}]" size="30" type="text" value="New Answer"/>'
repeat_elements += '\n<input id="answers_id_answer_{ph}" name="answers_id[answer_{ph}]" value=0 type="hidden">'
repeat_elements += '\n<a href="#" class="insert_answer"><img alt="Insert_ans" src="/images/insert_ans.gif" /></a>'
repeat_elements += '\n<a href="#" class="remove_answer"><img alt="Remove_ans" src="/images/remove_ans.gif" /></a>'
repeat_elements += '\n</li>'
//$("#poll_answer_list").sortable()
// bind events
$('#poll_answer_list a.insert_answer').bind('click', insert_answer)
$('#poll_answer_list a.remove_answer').bind('click', remove_answer)
/*
$('#poll_answer_list a.up_answer').bind('click', move_up_answer)
$('#poll_answer_list a.down_answer').bind('click', move_down_answer)
*/
$("#poll_answer_list li.poll_answers").bind("mouseover", field_mouseover)
$("#poll_answer_list li.poll_answers").bind("mouseout", field_mouseout)
$("#poll_answer_list a.move_answer").bind("mouseover", drag_handle_mouseover)
$("#poll_answer_list a.mov ie_answer").bind("mouseout", drag_handle_mouseout)
$('a.add_new_answer').bind('click', add_new_answer)
$('table.poll_list tbody tr').bind('mouseover', show_crud_controller)
$('table.poll_list tbody tr').bind('mouseout', hide_crud_controller)
// inserting new fiel
function insert_answer() {
if(!checkFieldsCount("insert")) return
input_id = $(this).prev("input").attr("id")
order = getOrder(input_id)
next_order = order + 1
repeat_elements = repeat_elements.replace(/{ph}/g, next_order)
$(this).parents("li").after(repeat_elements)
$(this).parents("li").next().fadeIn(1000, function() {
new_field_id = "#poll_answers_answer_" + next_order
reOrderFields()
$(new_field_id).next().next().bind('click', insert_answer)
$(new_field_id).next().next().next().bind('click', remove_answer)
$(new_field_id).parents("li").bind('mouseover', field_mouseover)
$(new_field_id).parents("li").bind('mouseout', field_mouseout)
$(new_field_id).prev().bind('mouseover', drag_handle_mouseover)
$(new_field_id).prev().bind('mouseout', drag_handle_mouseout)
})
}
// removing fields
function remove_answer() {
if(!checkFieldsCount("remove")) return
$(this).parents("li").fadeOut(1000, function() {
$(this).remove()
reOrderFields()
})
}
// returns the order of the field
function getOrder(input) {
input_a = input.split("_")
return parseInt(input_a[input_a.length - 1])
}
// reset field orders
function reOrderFields() {
temp = null
$("#poll_answer_list").children().each(function() {
var input_id = $(this).find("input").attr("id")
var order = getOrder(input_id)
if(!temp) {
if(order != 1) {
order = 1
new_id = "poll_answers_answer_" + order
new_name = "poll_answers[answer_" + order + "]"
$(this).find("input").attr({
id : new_id,
name: new_name
})
}
temp = order
}
else {
var expected = temp + 1
if(expected != order) {
new_id = "poll_answers_answer_" + expected
new_name = "poll_answers[answer_" + expected + "]"
$(this).find("input").attr({
id : new_id,
name: new_name
})
}
temp = expected
}
})
}
// displays a message if violates the allowable minimum and maximum number of answers
function checkFieldsCount(action) {
if(action == "insert" && $("#poll_answer_list").children().size() == MAX_ANSWERS ) {
alert(MAX_ANSWERS_MSG)
return false
}
else if(action == "remove" && $("#poll_answer_list").children().size() == MIN_ANSWERS ) {
alert(MIN_ANSWERS_MSG)
return false
}
else return true
}
/*
// moving answer up
function move_up_answer() {
if($(this).parents("li").find("input").attr("id") == "poll_answers_answer_1") {
alert(TOP_ANSWER_MSG)
return false
}
$(this).parents("li").clone(true).insertBefore($(this).parents("li").prev())
$(this).parents("li").remove()
reOrderFields()
}
// moving answer down
function move_down_answer() {
last_field_id = $("#poll_answer_list li:last-child").find("input").attr("id")
if($(this).parents("li").find("input").attr("id") == last_field_id) {
alert(BOTTOM_ANSWER_MSG)
return false
}
$(this).parents("li").clone(true).insertAfter($(this).parents("li").next())
$(this).parents("li").remove()
reOrderFields()
}
*/
// add new answer
function add_new_answer() {
// we just need to trigger the click on insert answer of the last field on the list
$("#poll_answer_list li:last-child").find("a.insert_answer").trigger("click")
}
// field mouseover handler
function field_mouseover(e) {
$(this).children("a:first-child").show()
}
// field mouseout handler
function field_mouseout() {
$(this).children("a:first-child").hide()
}
// move answer drag handle mouseover handler
function drag_handle_mouseover() {
$("#poll_answer_list").sortable({
update: reOrderFields()
})
}
// move answer drag handle mouseout handler
function drag_handle_mouseout() {
$("#poll_answer_list").sortable("disable")
}
// crud controller mouseover handler
function show_crud_controller() {
$(this).children(':first-child').next().find("ul").show()
}
// crud controller mouseout handler
function hide_crud_controller() {
$(this).children(':first-child').next().find("ul").hide()
}
})
/*** let us take this out for awhile
*** I think I misunderstood the specs
function update_filter(element, value) {
$('div#result_filter').show()
switch(parseInt(value)) {
case 0:
$('div#result_filter').hide()
break;
case 1:
$('div.filters').hide()
$('div#filter_age').show()
break;
case 2:
$('div.filters').hide()
$('div#filter_gender').show()
break;
case 3:
$('div.filters').hide()
$('div#filter_country').show()
break;
}
}
*/
$(function() {
var resource = "/tweet/search?f="
var thread = "/tweet/thread?id="
var filter = {}
// fn: sends ajax request for pulling off a thread/conversation
// once response is recieved we toggle the Show/Hide Conversation
function twitter_thread_ajax(url) {
$.ajax({
url: url,
type: "Get",
success: function(html){
if($("a#sc_" + id[1]).text() == "Show Conversation") {
$("div#thread_" + id[1]).html(html).slideDown("slow")
$("a#sc_" + id[1]).text("Hide Conversation")
}
else {
$("div#thread_" + id[1]).slideUp("slow")
$("a#sc_" + id[1]).text("Show Conversation")
}
}
})
}
// fn: sends ajax request every time word is selected
// once response is recieved we mock it to the view
// and make necessary bindings of events
function twitter_ajax(url) {
$.ajax({
url: url,
type: "Get",
success: function(html) {
// mock the html response to the view
$("#twitter_feed").html(html)
// makes all the links on tweet feeds popup
$("ul#tweets a:not([name='show_conversation'])").click(function() {
window.open($(this).attr('href'))
return false
})
// binds click event to <a name="show_conversation">
// then sends an ajax request
$('a[name="show_conversation"]').click(function() {
id = $(this).attr("id").split("_")
url = thread + id[1]
twitter_thread_ajax(url)
})
// binds onchange event to language select
// then send an ajax request to filter the tweets
// according to language
$("select#lang_select").change(function() {
lang = $(this).val()
url = resource + process_filters(lang)
twitter_ajax(url)
})
}
})
}
// fn: processes the filters for search as well as the language
// returns the concatenated filters
function process_filters(language) {
var params = ""
lang = language || "all"
for(key in filter) { params += filter[key] + "+" }
return params + "&lang=" + lang
}
// toggles the class(gray background)
$('a[name="tweet_filter"]').toggle(function() {
$(this).addClass('tweet_filter_selected')
value = $(this).text()
key = "'" + value + "'"
filter[key] = value
},function() {
$(this).removeClass('tweet_filter_selected')
value = $(this).text()
key = "'" + value + "'"
delete(filter[key])
})
// binds onclick event to <a name="tweet_filter">
$('a[name="tweet_filter"]').click(function() {
lang = $("select#lang_select").val()
url = resource + process_filters(lang)
twitter_ajax(url)
})
$("#ajax-loader").bind("ajaxSend", function(){
$(this).show();
}).bind("ajaxComplete", function(){
$(this).hide();
})
}) // end ready function
module Veebox
module API
module Voteable
def self.included(base) # :nodoc:
base.extend ClassMethods
end
module ClassMethods
def is_voteable
Object.const_set(:VoteableApiError, Class.new(StandardError)) unless defined?(VoteableApiError)
has_many :votes
extend Veebox::API::Voteable::SingletonMethods
include Veebox::API::Voteable::InstanceMethods
end
end
module InstanceMethods
end
module SingletonMethods
end
end
module Voter
def self.included(base) # :nodoc:
base.extend ClassMethods
end
module ClassMethods
def is_voter
Object.const_set(:VoteableApiError, Class.new(StandardError)) unless defined?(VoteableApiError)
has_many :votes
cattr_accessor :current_answer_voted
extend Veebox::API::Voter::SingletonMethods
include Veebox::API::Voter::InstanceMethods
end
end
module InstanceMethods
def cast_a_vote
raise VoteableApiError, "Please provide #current_poll in order to cast your vote." unless self.current_poll
raise VoteableApiError, "Please provide #current_answer_voted in order to cast your vote." unless self.current_answer_voted
raise VoteableApiError, "Poll answer does not belong to this Poll." unless answer_belongs_to_this_poll?
raise VoteableApiError, "User already voted this poll." if self.has_voted_this_poll?
raise VoteableApiError, "User already voted this answer." if self.has_voted_this_answer?
country = self.country if self.respond_to?(:country)
vote = self.votes.new :poll_answer_id => current_answer_voted,
:country => country
vote.save!
end
def has_voted_this_answer?(poll_answer_id=nil)
pa = poll_answer_id || current_answer_voted
self.votes.map(&:poll_answer_id).include?(pa)
end
def answer_belongs_to_this_poll?(poll_answer_id=nil, poll_id=nil)
pa = (poll_answer_id || current_answer_voted).to_i
p = (poll_id || current_poll).to_i
raise VoteableApiError, "Poll does not exist." unless poll = Poll.find_by_id(p)
poll.poll_answers.map(&:id).include?(pa)
end
end
module SingletonMethods
end
end
end
end
ActiveRecord::Base.send :include, Veebox::API::Voteable
ActiveRecord::Base.send :include, Veebox::API::Voter
module Veebox
module API
module PollSystem
def self.included(base) # :nodoc:
base.extend ClassMethods
end
module ClassMethods
def with_polls
Object.const_set(:PollApiError, Class.new(StandardError)) unless defined?(PollApiError)
has_many :polls
cattr_accessor :poll, :answers, :current_poll, :answers_id
cattr_accessor :ip_address
extend Veebox::API::PollSystem::SingletonMethods
include Veebox::API::PollSystem::InstanceMethods
end
end # ClassMethods
module InstanceMethods
# Transactionally saved users poll along with the poll answers
# Expects poll attributes and array of poll answer attributes
# Example format would be:
# params ={"poll"=>{"title"=>"My Poll"}, "poll_answers"=>{"answer_1"=>"My answer 1", "answer_2"=>"Any answer"}
def save_poll
raise PollApiError, "Expects #poll, please pass params[:poll]" unless self.poll
raise PollApiError, "Expects #answers, please pass params[:answers]" unless self.answers
begin
p, p_answers = nil, nil
transaction do
p = self.polls.new self.poll
p.save!
self.answers.collect do |k,v|
order = k.split("_")[1]
pa = {:answer => v, :order => order}
p_answers = p.poll_answers.new pa
p_answers.save!
end
# reset poll
self.poll = nil
self.answers = nil
# return the current poll saved
self.polls.last
end
rescue Exception => e
return p
end
end
def poll_with_votes
# TODO current user's polls that has a votes
# TODO implement only if needed
end
# These are the polls where the current_user has cast a vote
def voted_polls
sql = <<-EOS
SELECT * from polls p
WHERE p.id = ANY(SELECT poll_id from poll_answers pa
WHERE pa.id = ANY(SELECT poll_answer_id from votes v
WHERE v.user_id = #{self.id}))
EOS
Poll.find_by_sql(sql)
end
def has_voted_this_poll?(poll_id=nil)
poll = poll_id || current_poll
voted_polls.map(&:id).include?(poll)
end
def owner_of_this_poll?(poll_id=nil)
poll = poll_id || current_poll
return self == poll.user if poll.is_a?(Poll)
return self == Poll.find_by_id(poll).user if poll.is_a?(Fixnum)
end
def update_poll
raise PollApiError, "Expects #poll, please pass params[:poll]" unless self.poll
raise PollApiError, "Expects #answers, please pass params[:answers]" unless self.answers
raise PollApiError, "Expects #current_poll, please pass params[:id]" unless self.current_poll
raise PollApiError, "Expects #answers_id, please pass params[:answers_id]" unless self.answers_id
begin
p, p_answers = nil, nil
transaction do
now = Time.now
p = self.polls.find_by_id self.current_poll
p.update_attributes(:title => self.poll[:title], :updated_at => now)
self.answers.collect do |k,v|
order = k.split("_")[1]
p_answers = p.poll_answers.find_by_id self.answers_id[k]
if p_answers
p_answers.update_attributes(:answer => v, :order => order, :updated_at => now)
else
pa = {:answer => v, :order => order}
p_answers = p.poll_answers.new pa
p_answers.save!
self.answers_id.delete(k) # we need to remove the new item that bears id of 0
self.answers_id.update(k=>p_answers.id) # and insert the new answer saved
end
end
# this is to delete answer in the record, that has been removed
# TODO : how to deal deleted answers that has votes
cond = "poll_id = #{p.id} AND id NOT IN (#{self.answers_id.values.join(',')})"
PollAnswer.delete_all(cond)
# reset poll
self.poll = nil
self.answers = nil
# return the current poll saved
return p
end
rescue Exception => e
return p
end
end
end # InstanceMethods
module SingletonMethods
# This will fill an anonymous user for non logged voters
# We used UUID to ensure uniqueness
def fill_anonymous(options={})
raise PollApiError, "Expects .ip_address, please pass request.remote_ip" unless ip_address || options[:fb_uid]
#raise PollApiError, "geoiplookup Not found, please install geoiplookup for your system" unless system "geoiplookup 127.0.0.1"
if options[:fb_uid] # facebook user
uid = options[:fb_uid].to_s
if user = self.find_by_login(uid)
return user
end
login = uid
email = uid + "@facebook-user.com"
password = uid
password_confirm = password
else
uuid = (UUID.new).generate
login = uuid
email = uuid + "@anonymous-voter.com"
password = uuid
password_confirm = password
end
# we will try to detect what country our anonymous voter from
if system "geoiploo 127.0.0.1" # if geoiplookup is present
country = `geoiplookup #{ip_address}`.split(",")[-1].strip
else # set country to unknown
country = "N/A"
end
# we add anonymous user but we never activate it
user = User.new(:login => login, :email => email, :password => password,
:password_confirmation => password_confirm)
# then we tag them anonymous users
# and return the current user
if user.save!
# we do these here, because i do not have any idea
# why it will not work above on User.new
user.anonymous = !options[:fb_uid]
user.country = options[:country] || country
user.first_name = options[:first_name] || ''
user.last_name = options[:last_name] || ''
end
return user if user.save!
end
end # SingleTonMethods
end
end
end
ActiveRecord::Base.send :include, Veebox::API::PollSystem
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment