diff options
-rw-r--r-- | .bzrignore | 2 | ||||
-rw-r--r-- | dudle.css | 42 | ||||
-rwxr-xr-x | index.cgi | 254 |
3 files changed, 298 insertions, 0 deletions
diff --git a/.bzrignore b/.bzrignore new file mode 100644 index 0000000..0349ddf --- /dev/null +++ b/.bzrignore @@ -0,0 +1,2 @@ +*.yaml +extern diff --git a/dudle.css b/dudle.css new file mode 100644 index 0000000..7b177d7 --- /dev/null +++ b/dudle.css @@ -0,0 +1,42 @@ +td.true { background-color:#0F0; } +td.false { background-color:#F00; } +td.undecided { background-color:#DDD;color:#666 } +td.name { + text-align:right; +} +table { + border: none; +} +td { + vertical-align:middle; + text-align:center; + border-width: 0px; +} +td.sum, td.date, td.name, td.checkboxes { + background-color:Silver; +} +th { + color: white; + background-color:black; + font-weight: normal; +} +td.date { + color: Gray; + text-align: left; +} +html { + background: #CCCCD3; + color: black; +} +body { + background: white; + margin: 3ex auto; + width: 90%; + padding: 2em; + color: black; + line-height: 1.5em; + border: solid 1px black; +} +h1 { + text-align: center; +} diff --git a/index.cgi b/index.cgi new file mode 100755 index 0000000..9cc9541 --- /dev/null +++ b/index.cgi @@ -0,0 +1,254 @@ +#!/usr/bin/env ruby +require "yaml" +require "cgi" +require "pp" + +class Poll + attr_reader :head + def initialize + @head = [] + @data = {} + @comment = [] + end + def to_html + ret = "<div id='polltable'>\n" + ret += "<form method='post' action=''>\n" + ret += "<table border='1'><tr>\n" + + ret += "<td></td>\n" + @head.each{|columntitle| + ret += "<th>#{columntitle}</th>\n" + } + ret += "<th>Last Edit</th>\n" +# ret += "<th>" +# ret += "<form method='post' action=''>\n" +# ret += "<div>" +# ret += "<input size='16' type='text' name='__add_participant' />\n" +# ret += "<input type='hidden' name='#{SITE}' /><input type='submit' value='add/edit' />\n" +# ret += "</div>" +# ret += "</form>\n" +# ret += "</th>\n" + + @data.sort{|x,y| x[1]["timestamp"] <=> y[1]["timestamp"]}.each{|participant,poll| + ret += "</tr><tr>\n" + ret += "<td class='name'>#{participant}</td>\n" + @head.each{|columntitle| + klasse = poll[columntitle].nil? ? "undecided" : poll[columntitle] + value = poll[columntitle].nil? ? "?" : ( poll[columntitle] ? CGI.escapeHTML('✔') : CGI.escapeHTML('✘')) + ret += "<td class='#{klasse}' title='#{participant}: #{columntitle}'>#{value}</td>\n" + } + ret += "<td class='date'>#{poll['timestamp'].strftime('%d.%m, %H:%M')}</td>" + } + + ret += "</tr>\n" + ret += "<tr>\n" + ret += "<td class='name'><input size='16' type='text' name='__add_participant' /></td>\n" + @head.each{|columntitle| + ret += "<td class='checkboxes'><input type='checkbox' value='#{columntitle}' name='checked' title='#{columntitle}' /></td>\n" + } + ret += "<td class='checkboxes'><input type='hidden' name='#{SITE}' /><input type='submit' value='add/edit' /></td>\n" + + ret += "</tr>\n" + ret += "<tr><td class='name'>total</td>\n" + @head.each{|columntitle| + yes = 0 + undecided = 0 + @data.each_value{|participant| + if participant[columntitle] + yes += 1 + elsif !participant.has_key?(columntitle) + undecided += 1 + end + } + + if @data.empty? + percent_f = 0 + else + percent_f = 100*yes/@data.size + end + percent = "#{percent_f}#{CGI.escapeHTML("%")}" unless @data.empty? + if undecided > 0 + percent += "-#{(100.0*(undecided+yes)/@data.size).round}#{CGI.escapeHTML("%")}" + end + + ret += "<td class='sum' title='#{percent}' style='" + ["","background-"].each {|c| + ret += "#{c}color: rgb(" + 3.times{ + ret += (c == "" ? "#{155+percent_f}" : "#{100-percent_f}") + ret += "," + } + ret.chop! + ret += ");" + } + ret += "'>#{yes}</td>\n" + } + + ret += "</tr>" + ret += "</table>\n" + ret += "</form>\n" + ret += "</div>" + + ret += "<div id='comments'>" + unless @comment.empty? + ret += "<fieldset><legend>Comments</legend>" + @comment.each{|time,name,comment| + ret += "<fieldset><legend>#{name} said on #{time.strftime("%d.%m, %H:%M")}</legend>" + ret += comment + ret += "</fieldset>" + } + ret += "</fieldset>" + end + + ret += "</div>\n" + ret + end + def add_participant(name, agreed) + name = CGI.escapeHTML(name.strip) + @data[name] = {"timestamp" => Time.now} + @head.each{|columntitle| + @data[name][columntitle] = agreed.include?(columntitle) + } + store + end + def delete(name) + @data.delete(CGI.escapeHTML(name.strip)) + store + end + def store + File.open("#{SITE}.yaml", 'w') do |out| + out << "# This is a dudle poll file\n" + out << self.to_yaml + end + end + def add_comment name, comment + @comment << [Time.now, CGI.escapeHTML(name), CGI.escapeHTML(comment)] + store + end + def add_remove_column name + columntitle = CGI.escapeHTML(name.strip) + if @head.include?(columntitle) + @head.delete(columntitle) + else + @head << columntitle + @head.sort! + end + store + end +end + +#Content-type: application/xhtml+xml; charset=utf-8 +puts <<HEAD +Content-type: text/html; charset=utf-8 + +<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" + "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> +<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en"> +HEAD + +cgi = CGI.new +cgi.params.each_pair{|k,v| + if "" == v[0].to_s && !(k =~ /^__/) + if defined?(SITE) + puts "FEHLER, meld dich bei Ben!" + exit + else + SITE = k + end + end +} + +if defined?(SITE) + puts <<HEAD +<head> + <title>dudle - #{SITE}</title> + <link rel="stylesheet" type="text/css" href="dudle.css" /> +</head> +<body> +<h1>#{SITE}</h1> +HEAD + unless File.exist?(SITE + ".yaml" ) and table = YAML::load_file(SITE + ".yaml") + table = Poll.new + end + + if cgi.include?("__add_participant") + table.add_participant(cgi["__add_participant"],cgi["checked"]) + end + + if cgi.include?("__delete") + table.delete(cgi["__delete"]) + end + + if cgi.include?("__add_remove_column") + table.add_remove_column(cgi["__add_remove_column"]) + end + + if cgi.include?("__comment") + table.add_comment(cgi["__commentname"],cgi.params["__comment"][0]) + end + + puts table.to_html + + puts "<fieldset><legend>Hint</legend>" + puts "To change a line, add a new person with the same name!" + puts "</fieldset>" + + puts "<div id='delete'>" + puts "<fieldset><legend>delete</legend>" + puts "<form method='post' action=''>\n" + puts "<div>" + puts "<input size='16' type='text' name='__delete' />" + puts "<input type='hidden' name='#{SITE}' />" + puts "<input type='submit' value='delete' />" + puts "</div>" + puts "</form>" + puts "</fieldset>" + puts "</div>" + + puts "<div id='add_remove_column'>" + puts "<fieldset><legend>add/remove column</legend>" + puts "<form method='post' action=''>\n" + puts "<div>" + puts "<input size='16' type='text' name='__add_remove_column' />" + puts "<input type='hidden' name='#{SITE}' />" + puts "<input type='submit' value='add/remove column' />" + puts "</div>" + puts "</form>" + puts "</fieldset>" + puts "</div>" + + puts "<div id='add_comment'>" + puts "<fieldset><legend>Comment</legend>" + puts "<form method='post' action=''>\n" + puts "<div>" + puts "Name: <input value='anonymous' type='text' name='__commentname' /><br />" + puts "<textarea cols='50' rows='10' name='__comment' ></textarea><br />" + puts "<input type='hidden' name='#{SITE}' />" + puts "<input type='submit' value='Submit' />" + puts "</div>" + puts "</form>" + puts "</fieldset>" + puts "</div>" +else + + puts <<HEAD +<head> + <title>dudle</title> +</head> +<body> +HEAD + puts "<fieldset><legend>Available Polls</legend>" + Dir.new(".").collect{|f| + f.gsub(/\.yaml$/,'') if f =~ /\.yaml$/ + }.compact.each{|site| + puts "<a href='?#{site}'>#{site}</a><br />" + } + puts "</fieldset>" + + puts "<fieldset><legend>Hint</legend>" + puts CGI.escapeHTML("To add a poll, go to example.org/?<pollname>") + puts "</fieldset>" + +end + +puts "</body></html>" |