diff --git a/.gitignore b/.gitignore index d900c72..b602af9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,5 @@ -*~ -*.pyc -*.sqlite3 -photos +.bundle +db/*.sqlite3 +log/*.log +tmp/ .DS_Store -# Vim Temp Files -.*.swp -.*.un~ diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..746a7cb --- /dev/null +++ b/Gemfile @@ -0,0 +1,33 @@ +source 'http://rubygems.org' + +gem 'rails', '3.0.7' + +gem 'sqlite3' + +gem 'friendly_id' +gem 'paperclip' +gem 'rdiscount' +gem 'capistrano' +gem "cancan" +gem 'devise' +gem 'rails_admin', :git => 'git://github.com/sferik/rails_admin.git' + +# Use unicorn as the web server +# gem 'unicorn' + +# To use debugger (ruby-debug for Ruby 1.8.7+, ruby-debug19 for Ruby 1.9.2+) +# gem 'ruby-debug' +# gem 'ruby-debug19', :require => 'ruby-debug' + +# Bundle the extra gems: +# gem 'bj' +# gem 'nokogiri' +# gem 'sqlite3-ruby', :require => 'sqlite3' +# gem 'aws-s3', :require => 'aws/s3' + +# Bundle gems for the local environment. Make sure to +# put test-only gems in this group so their generators +# and rake tasks are available in development mode: +# group :development, :test do +# gem 'webrat' +# end diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..f5c5444 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,118 @@ +GIT + remote: git://github.com/sferik/rails_admin.git + revision: 319a23d4df85ec82cc023fb30c2ae60f5ceca214 + specs: + rails_admin (0.0.1) + builder (~> 2.1.0) + rails (~> 3.0.6) + +GEM + remote: http://rubygems.org/ + specs: + abstract (1.0.0) + actionmailer (3.0.7) + actionpack (= 3.0.7) + mail (~> 2.2.15) + actionpack (3.0.7) + activemodel (= 3.0.7) + activesupport (= 3.0.7) + builder (~> 2.1.2) + erubis (~> 2.6.6) + i18n (~> 0.5.0) + rack (~> 1.2.1) + rack-mount (~> 0.6.14) + rack-test (~> 0.5.7) + tzinfo (~> 0.3.23) + activemodel (3.0.7) + activesupport (= 3.0.7) + builder (~> 2.1.2) + i18n (~> 0.5.0) + activerecord (3.0.7) + activemodel (= 3.0.7) + activesupport (= 3.0.7) + arel (~> 2.0.2) + tzinfo (~> 0.3.23) + activeresource (3.0.7) + activemodel (= 3.0.7) + activesupport (= 3.0.7) + activesupport (3.0.7) + arel (2.0.9) + babosa (0.3.3) + bcrypt-ruby (2.1.4) + builder (2.1.2) + cancan (1.6.4) + capistrano (2.5.21) + highline + net-scp (>= 1.0.0) + net-sftp (>= 2.0.0) + net-ssh (>= 2.0.14) + net-ssh-gateway (>= 1.0.0) + devise (1.3.4) + bcrypt-ruby (~> 2.1.2) + orm_adapter (~> 0.0.3) + warden (~> 1.0.3) + erubis (2.6.6) + abstract (>= 1.0.0) + friendly_id (3.2.1.1) + babosa (~> 0.3.0) + highline (1.6.1) + i18n (0.5.0) + mail (2.2.19) + activesupport (>= 2.3.6) + i18n (>= 0.4.0) + mime-types (~> 1.16) + treetop (~> 1.4.8) + mime-types (1.16) + net-scp (1.0.4) + net-ssh (>= 1.99.1) + net-sftp (2.0.5) + net-ssh (>= 2.0.9) + net-ssh (2.1.4) + net-ssh-gateway (1.0.1) + net-ssh (>= 1.99.1) + orm_adapter (0.0.4) + paperclip (2.3.11) + activerecord (>= 2.3.0) + activesupport (>= 2.3.2) + polyglot (0.3.1) + rack (1.2.2) + rack-mount (0.6.14) + rack (>= 1.0.0) + rack-test (0.5.7) + rack (>= 1.0) + rails (3.0.7) + actionmailer (= 3.0.7) + actionpack (= 3.0.7) + activerecord (= 3.0.7) + activeresource (= 3.0.7) + activesupport (= 3.0.7) + bundler (~> 1.0) + railties (= 3.0.7) + railties (3.0.7) + actionpack (= 3.0.7) + activesupport (= 3.0.7) + rake (>= 0.8.7) + thor (~> 0.14.4) + rake (0.8.7) + rdiscount (1.6.8) + sqlite3 (1.3.3) + thor (0.14.6) + treetop (1.4.9) + polyglot (>= 0.3.1) + tzinfo (0.3.27) + warden (1.0.4) + rack (>= 1.0) + +PLATFORMS + ruby + +DEPENDENCIES + cancan + capistrano + devise + friendly_id + paperclip + rails (= 3.0.7) + rails_admin! + rdiscount + sqlite3 diff --git a/README.markdown b/LICENSE similarity index 96% rename from README.markdown rename to LICENSE index 9f00496..b710ecd 100644 --- a/README.markdown +++ b/LICENSE @@ -1,36 +1,3 @@ -Overview -======== - -This is the website of CSESoc (Computer Science and Engineering Society) of UNSW. This should be the first document that you read before before doing any work on the website. This is just the quick and dirty guide though. For a more complete and comprehensive guide you should visit the [CSESoc Sysadmin Wiki][1] and read up on how we do things. - -Requirements ------------- - -On Ubuntu to get it running: - - git clone git://github.com/UNSW-CSESoc/CSESoc-Django.git csesoc # read below for caveat - cd csesoc - sudo apt-get install python-django python-imaging - python manage.py runserver - -If all that works without any errors then you are in business. If there are errors then please contact to triage your problem. - -All pull requests can be sent through Github or via email to . - -Settings Information --------------------- - -The following are patched in when deploying: - - - All the passwords that you currently have are dummy ones. There are commits to add the real secure data back in. - - All debug modes are turned on in this repository for ease of development. The real server turns all debugging modes off. - - - [1]: http://wiki.csesoc.unsw.edu.au/Sysadmin - -## License - -``` GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 @@ -662,8 +629,8 @@ to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. - - Copyright (C) + UNSW CSESoc Website + Copyright (C) 2011 UNSW CSESoc This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by @@ -692,4 +659,3 @@ specific requirements. if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU AGPL, see . -``` \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..252c83c --- /dev/null +++ b/README.md @@ -0,0 +1,119 @@ +UNSW CSESoc Website +=================== + +How To Setup +------------ + + rvm install 1.9.2 + rvm use 1.9.2 --default + + bundle install + rake db:migrate + rake db:seed + rails server + +Auth Module +----------- + +A script similar to this needs to run on the CSESoc account on +a CSE Server to authenticate users. + + # Find the user if it exists + u = User.where(:cse_username => params[:cse_username]) + if u.any? + u = u.first + else + u = User.new + u.cse_username = params[:cse_username] + end + + # Give them a new token + token = User.authentication_token + u.authentication_token = token + u.save + + # Redirect them back with the new auth token + redirect_to("http://csesoc.unsw.edu.au/callback?auth_token=#{token}") + +Changes from Django +------------------- + +This list may be incomplete. + +### Models + +- User Model + - Added + - Added user sessions + - TODO: Facebook integration +- Static Model + - Text is now Content + - Removed creator + - Removed updater + - Now uses Markdown +- NewsItem Model + - Headline is now Title + - Text is now Content + - pubdate is now publish_date + - Now uses Markdown + - TODO: RSS Feed +- Event Model + - TODO: implement controller and views + - TODO: iCal RSS feed +- Beta Model + - Removed +- Sponsor Model + - Added Attachment + - TODO: Resize sizes and layouts +- Suggestion Model + - Changed sender to user_id + - TODO: Needs Comment nested controller and routes +- Comment Model + - name is now user_id + - suggestion to now suggestion_id + +### Design + +- Made titles of news posts links to articles +- Made Cal and Sponsors only show on home page +- Added a notice flash +- TODO: Javascript notice flash +- A lot of logic in views was removed +- Fixed murder players been different from CSE users +- Can now log out properly +- No passwords or emails, only cse auth + +### Development + +- Added Capistrano, anyone with ssh key can deploy +- Added migrations for DB +- Added DB seeds + +### TODO + +- Murder +- Scheduler +- Campleaders +- Campattendees +- rspec +- Music +- Game + +License +------- + + UNSW CSESoc Website + Copyright (C) 2011 UNSW CSESoc + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..087ab7d --- /dev/null +++ b/Rakefile @@ -0,0 +1,7 @@ +# Add your own tasks in files placed in lib/tasks ending in .rake, +# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. + +require File.expand_path('../config/application', __FILE__) +require 'rake' + +CSESocWebsite::Application.load_tasks diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb new file mode 100644 index 0000000..2ba25fa --- /dev/null +++ b/app/controllers/application_controller.rb @@ -0,0 +1,13 @@ +class ApplicationController < ActionController::Base + protect_from_forgery + before_filter :load_sponsors + + rescue_from CanCan::AccessDenied do |exception| + redirect_to root_url, :notice => exception.message + end + + private + def load_sponsors + @sponsors = Sponsor.visible + end +end diff --git a/app/controllers/comments_controller.rb b/app/controllers/comments_controller.rb new file mode 100644 index 0000000..defd5d6 --- /dev/null +++ b/app/controllers/comments_controller.rb @@ -0,0 +1,22 @@ +class CommentsController < ApplicationController + def create + @comment = Comment.new(params[:comment]) + + @comment.suggestion = Suggestion.find(params[:suggestion_id]) + @comment.user = current_user + + if @comment.save + respond_to do |f| + f.html {redirect_to @comment.suggestion, :notice => "Thanks for your comment!"} + f.js # Renders RJS template + end + else + respond_to do |f| + f.html {redirect_to @comment.suggestion, :notice => "Sorry, your comment could not be saved."} + f.js # Renders RJS template + end + end + + end + +end \ No newline at end of file diff --git a/app/controllers/events_controller.rb b/app/controllers/events_controller.rb new file mode 100644 index 0000000..aa82171 --- /dev/null +++ b/app/controllers/events_controller.rb @@ -0,0 +1,25 @@ +class EventsController < ApplicationController + before_filter :public_post, :only => :show + + def index + @events = Event.published + + respond_to do |format| + format.html # index.html.erb + # format.xml # TODO: Format as .ical + end + end + + def show + @event = Event.find(params[:id]) + end + + private + + def public_post + @event = Event.find(params[:id]) + unless @event.published? + redirect_to(:action => :index, :notice => "Event not available yet.") + end + end +end diff --git a/app/controllers/news_items_controller.rb b/app/controllers/news_items_controller.rb new file mode 100644 index 0000000..64a5d4c --- /dev/null +++ b/app/controllers/news_items_controller.rb @@ -0,0 +1,25 @@ +class NewsItemsController < ApplicationController + before_filter :public_post, :only => :show + + def index + @news_items = NewsItem.published + + respond_to do |format| + format.html + # format.xml # TODO: Create builder feed, use as RSS + Feedburner + end + end + + def show + @news_item = NewsItem.find(params[:id]) + end + + private + + def public_post + @news_item = NewsItem.find(params[:id]) + unless @news_item.published? + redirect_to(:action => :index, :notice => "Post not available yet.") + end + end +end diff --git a/app/controllers/sponsors_controller.rb b/app/controllers/sponsors_controller.rb new file mode 100644 index 0000000..c232129 --- /dev/null +++ b/app/controllers/sponsors_controller.rb @@ -0,0 +1,5 @@ +class SponsorsController < ApplicationController + def index + @sponsors = Sponsor.visible + end +end diff --git a/app/controllers/statics_controller.rb b/app/controllers/statics_controller.rb new file mode 100644 index 0000000..2691714 --- /dev/null +++ b/app/controllers/statics_controller.rb @@ -0,0 +1,7 @@ +class StaticsController < ApplicationController + + def show + @static = Static.find(params[:id]) + end + +end diff --git a/app/controllers/suggestions_controller.rb b/app/controllers/suggestions_controller.rb new file mode 100644 index 0000000..4abfb7a --- /dev/null +++ b/app/controllers/suggestions_controller.rb @@ -0,0 +1,25 @@ +class SuggestionsController < ApplicationController + def index + @suggestions = Suggestion.all + end + + def show + @suggestion = Suggestion.find(params[:id]) + end + + def new + @suggestion = Suggestion.new + end + + def create + @suggestion = Suggestion.new(params[:suggestion]) + @suggestion.user = current_user + + if @suggestion.save + redirect_to(@suggestion, :notice => 'Thanks for your suggestion.') + else + render :action => "new" + end + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb new file mode 100644 index 0000000..d41bbc2 --- /dev/null +++ b/app/helpers/application_helper.rb @@ -0,0 +1,14 @@ +module ApplicationHelper + + # A page's title + def page_title(y) + y = "#{y} - " unless y.empty? + "#{y}CSESoc - UNSW Computer Science and Engineering Society" + end + + # Link's to static content that may not exist + def static_content_path(name) + Static.find(name) + end + +end diff --git a/app/helpers/events_helper.rb b/app/helpers/events_helper.rb new file mode 100644 index 0000000..8a9a878 --- /dev/null +++ b/app/helpers/events_helper.rb @@ -0,0 +1,2 @@ +module EventsHelper +end diff --git a/app/helpers/news_items_helper.rb b/app/helpers/news_items_helper.rb new file mode 100644 index 0000000..0863be7 --- /dev/null +++ b/app/helpers/news_items_helper.rb @@ -0,0 +1,2 @@ +module NewsItemsHelper +end diff --git a/app/helpers/sponsors_helper.rb b/app/helpers/sponsors_helper.rb new file mode 100644 index 0000000..25bb284 --- /dev/null +++ b/app/helpers/sponsors_helper.rb @@ -0,0 +1,2 @@ +module SponsorsHelper +end diff --git a/app/helpers/statics_helper.rb b/app/helpers/statics_helper.rb new file mode 100644 index 0000000..7d485f2 --- /dev/null +++ b/app/helpers/statics_helper.rb @@ -0,0 +1,2 @@ +module StaticsHelper +end diff --git a/app/helpers/suggestions_helper.rb b/app/helpers/suggestions_helper.rb new file mode 100644 index 0000000..0e358dd --- /dev/null +++ b/app/helpers/suggestions_helper.rb @@ -0,0 +1,2 @@ +module SuggestionsHelper +end diff --git a/app/models/ability.rb b/app/models/ability.rb new file mode 100644 index 0000000..e21aba8 --- /dev/null +++ b/app/models/ability.rb @@ -0,0 +1,16 @@ +class Ability + include CanCan::Ability + + def initialize(user) + can :read, :all + + # Rails Admin + if user && user.admin? + can :access, :rails_admin + if user.role? :superadmin + can :manage, :all + end + end + + end +end diff --git a/app/models/comment.rb b/app/models/comment.rb new file mode 100644 index 0000000..8e47d0b --- /dev/null +++ b/app/models/comment.rb @@ -0,0 +1,8 @@ +class Comment < ActiveRecord::Base + belongs_to :suggestion + belongs_to :user + + validates :suggestion, :presence => true + validates :user, :presence => true + validates :comment, :presence => true +end diff --git a/app/models/event.rb b/app/models/event.rb new file mode 100644 index 0000000..a29de72 --- /dev/null +++ b/app/models/event.rb @@ -0,0 +1,22 @@ +class Event < ActiveRecord::Base + belongs_to :author, :class_name => "User", :foreign_key => "author_id" + + has_friendly_id :name, :use_slug => true + + validates :name, :presence => true + validates :time, :presence => true + validates :location, :presence => true + validates :description, :presence => true + validates :publish_date, :presence => true + validates :author, :presence => true + + validates_format_of :registration_email, :with => /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i, :unless => lambda {|event| event.registration_email.blank?} + validates_format_of :volunteers_email, :with => /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i, :unless => lambda {|event| event.volunteers_email.blank?} + + scope :published, lambda { where "events.publish_date <= ?", Time.now} + + # If this event is visible yet + def published? + self.publish_date <= DateTime.now + end +end diff --git a/app/models/news_item.rb b/app/models/news_item.rb new file mode 100644 index 0000000..ed6f9c0 --- /dev/null +++ b/app/models/news_item.rb @@ -0,0 +1,17 @@ +class NewsItem < ActiveRecord::Base + belongs_to :author, :class_name => "User", :foreign_key => "author_id" + + has_friendly_id :title, :use_slug => true + + validates :title, :presence => true + validates :content, :presence => true + validates :publish_date, :presence => true + validates :author, :presence => true + + scope :published, lambda { where "news_items.publish_date <= ?", Time.now} + + # If this news item is visible yet + def published? + self.publish_date <= DateTime.now + end +end diff --git a/app/models/sponsor.rb b/app/models/sponsor.rb new file mode 100644 index 0000000..fe9e966 --- /dev/null +++ b/app/models/sponsor.rb @@ -0,0 +1,17 @@ +class Sponsor < ActiveRecord::Base + has_friendly_id :name, :use_slug => true + has_attached_file :image, :styles => { :medium => "300x300>", :thumb => "100x100>" } + + validates :name, :presence => true + validates :website, :presence => true + validates :alt_text, :presence => true + validates :start_date, :presence => true + validates :expiry_date, :presence => true + + scope :visible, lambda { where "sponsors.expiry_date >= ?", Time.now} + + # If this sponsor is currently visible + def visible? + self.expiry_date >= DateTime.now + end +end diff --git a/app/models/static.rb b/app/models/static.rb new file mode 100644 index 0000000..6003782 --- /dev/null +++ b/app/models/static.rb @@ -0,0 +1,7 @@ +class Static < ActiveRecord::Base + has_friendly_id :slug_name, :use_slug => true + + validates :title, :presence => true + validates :content, :presence => true + validates :slug_name, :presence => true +end diff --git a/app/models/suggestion.rb b/app/models/suggestion.rb new file mode 100644 index 0000000..affa2bb --- /dev/null +++ b/app/models/suggestion.rb @@ -0,0 +1,8 @@ +class Suggestion < ActiveRecord::Base + has_many :comments + belongs_to :user + + validates :subject, :presence => true + validates :message, :presence => true + validates :user, :presence => true +end diff --git a/app/models/user.rb b/app/models/user.rb new file mode 100644 index 0000000..e04023d --- /dev/null +++ b/app/models/user.rb @@ -0,0 +1,28 @@ +class User < ActiveRecord::Base + ROLES = ['admin', 'superadmin'] + + has_many :events + has_many :comments + has_many :news_items + has_many :suggestions + + devise :token_authenticatable, :rememberable, :trackable + + validates :cse_username, :presence => true, :uniqueness => true + # Setup accessible (or protected) attributes for your model + attr_accessible :remember_me + + # Determine email from CSE Username + def email + "#{cse_username}@cse.unsw.edu.au" + end + + # Checks if a user is an admin + def admin? + ROLES.include?(self.role) + end + + def role?(role) + self.role == role.to_s + end +end diff --git a/app/views/comments/_comment.html.erb b/app/views/comments/_comment.html.erb new file mode 100644 index 0000000..f9cccd1 --- /dev/null +++ b/app/views/comments/_comment.html.erb @@ -0,0 +1,6 @@ +
+

<%= comment.user.cse_username %>

+

+ <%= comment.comment %> +

+
\ No newline at end of file diff --git a/app/views/comments/create.js.rjs b/app/views/comments/create.js.rjs new file mode 100644 index 0000000..455940f --- /dev/null +++ b/app/views/comments/create.js.rjs @@ -0,0 +1,7 @@ +if @comment.errors.any? + # Insert errors + page[:comment_errors].replace_html @comment.errors.full_messages.to_sentence +else + # Comment saved + page[:new_comment].replace_html :partial => @comment +end diff --git a/app/views/devise/sessions/create.html.erb b/app/views/devise/sessions/create.html.erb new file mode 100644 index 0000000..51f2f7c --- /dev/null +++ b/app/views/devise/sessions/create.html.erb @@ -0,0 +1,3 @@ +

Sign in

+ +Signed in! \ No newline at end of file diff --git a/app/views/devise/sessions/new.html.erb b/app/views/devise/sessions/new.html.erb new file mode 100644 index 0000000..50ccb2b --- /dev/null +++ b/app/views/devise/sessions/new.html.erb @@ -0,0 +1,3 @@ +

Sign in

+ +<%= link_to "Sign In", new_user_session_path %> diff --git a/app/views/events/index.html.erb b/app/views/events/index.html.erb new file mode 100644 index 0000000..df2a3b2 --- /dev/null +++ b/app/views/events/index.html.erb @@ -0,0 +1,41 @@ +

Listing events

+ + + + + + + + + + + + + + + + + + +<% @events.each do |event| %> + + + + + + + + + + + + + + + +<% end %> +
NameTimeLocationRegistration requiredRegistration emailVolunteers requiredVolunteers emailDescriptionPublish dateAuthor
<%= event.name %><%= event.time %><%= event.location %><%= event.registration_required %><%= event.registration_email %><%= event.volunteers_required %><%= event.volunteers_email %><%= event.description %><%= event.publish_date %><%= event.author %><%= link_to 'Show', event %><%= link_to 'Edit', edit_event_path(event) %><%= link_to 'Destroy', event, :confirm => 'Are you sure?', :method => :delete %>
+ +
+ +<%= link_to 'New Event', new_event_path %> diff --git a/app/views/events/show.html.erb b/app/views/events/show.html.erb new file mode 100644 index 0000000..7949248 --- /dev/null +++ b/app/views/events/show.html.erb @@ -0,0 +1,55 @@ + + +

+ Name: + <%= @event.name %> +

+ +

+ Time: + <%= @event.time %> +

+ +

+ Location: + <%= @event.location %> +

+ +

+ Registration required: + <%= @event.registration_required %> +

+ +

+ Registration email: + <%= @event.registration_email %> +

+ +

+ Volunteers required: + <%= @event.volunteers_required %> +

+ +

+ Volunteers email: + <%= @event.volunteers_email %> +

+ +

+ Description: + <%= @event.description %> +

+ +

+ Publish date: + <%= @event.publish_date %> +

+ +

+ Author: + <%= @event.author %> +

+ + +<%= link_to 'Edit', edit_event_path(@event) %> | +<%= link_to 'Back', events_path %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb new file mode 100644 index 0000000..3d56e86 --- /dev/null +++ b/app/views/layouts/application.html.erb @@ -0,0 +1,35 @@ + + + + <%= page_title(yield :title) %> + <%= stylesheet_link_tag :all %> + <%= javascript_include_tag :defaults %> + + <%= csrf_meta_tag %> + + <%= yield :head %> + + <%= render 'shared/analytics' %> + + +
+ + + +
+

<%= notice %>

+ <%= yield %> +
+ + + +
+ + + diff --git a/app/views/news_items/_news_item.html.erb b/app/views/news_items/_news_item.html.erb new file mode 100644 index 0000000..8a282fa --- /dev/null +++ b/app/views/news_items/_news_item.html.erb @@ -0,0 +1,17 @@ +
+
+
+ <%= news_item.publish_date.day %> + <%= news_item.publish_date.month %> + <%= news_item.publish_date.year %> + @ <%= news_item.publish_date.strftime("%H:%M") %> + by <%= news_item.author.cse_username %> +
+
+
+

<%= link_to_unless defined?(no_link), news_item.title, news_item %>

+
+ <%= RDiscount.new(news_item.content).to_html.html_safe %> +
+
+
\ No newline at end of file diff --git a/app/views/news_items/index.html.erb b/app/views/news_items/index.html.erb new file mode 100644 index 0000000..1173b2d --- /dev/null +++ b/app/views/news_items/index.html.erb @@ -0,0 +1,8 @@ +<%= render :layout => 'shared/three_columns' do %> +

News

+ + <% @news_items.each do |news_item| %> + <%= render news_item %> + <% end %> + +<% end %> \ No newline at end of file diff --git a/app/views/news_items/show.html.erb b/app/views/news_items/show.html.erb new file mode 100644 index 0000000..d2316ec --- /dev/null +++ b/app/views/news_items/show.html.erb @@ -0,0 +1,5 @@ + + +<%= render @news_item, :no_link => true %> + +<%= link_to 'Back', news_items_path %> diff --git a/app/views/shared/_analytics.html.erb b/app/views/shared/_analytics.html.erb new file mode 100644 index 0000000..fd0171c --- /dev/null +++ b/app/views/shared/_analytics.html.erb @@ -0,0 +1,13 @@ + \ No newline at end of file diff --git a/app/views/shared/_calendar.html.erb b/app/views/shared/_calendar.html.erb new file mode 100644 index 0000000..65301c3 --- /dev/null +++ b/app/views/shared/_calendar.html.erb @@ -0,0 +1,5 @@ +

Calendar

+ +
+ +
\ No newline at end of file diff --git a/app/views/shared/_header.html.erb b/app/views/shared/_header.html.erb new file mode 100644 index 0000000..2e0d3ba --- /dev/null +++ b/app/views/shared/_header.html.erb @@ -0,0 +1,59 @@ +
+ <%= link_to "", root_path, :id => "headerLink" %> + +
\ No newline at end of file diff --git a/app/views/shared/_sponsors.html.erb b/app/views/shared/_sponsors.html.erb new file mode 100644 index 0000000..7904b47 --- /dev/null +++ b/app/views/shared/_sponsors.html.erb @@ -0,0 +1,11 @@ +

Our sponsors

+ + + <% @sponsors.each do |sponsor| %> + + <% end %> +
+
+ <%= link_to image_tag(sponsor.image_path.url, :alt => sponsor.alt_text, :border => 0), sponsor.website rescue sponsor.name %> +
+
diff --git a/app/views/shared/_three_columns.html.erb b/app/views/shared/_three_columns.html.erb new file mode 100644 index 0000000..03e4af0 --- /dev/null +++ b/app/views/shared/_three_columns.html.erb @@ -0,0 +1,13 @@ +
+ <%= render 'shared/calendar' %> +
+ +
+ <%= yield %> +
+ +
+ <%= render 'shared/sponsors' %> +
+ + \ No newline at end of file diff --git a/app/views/sponsors/_sponsor.html.erb b/app/views/sponsors/_sponsor.html.erb new file mode 100644 index 0000000..e543aa4 --- /dev/null +++ b/app/views/sponsors/_sponsor.html.erb @@ -0,0 +1,9 @@ + + + <%= link_to image_tag(sponsor.image_path.url, :alt => sponsor.name), sponsor.website rescue nil %> + + + <%= link_to sponsor.name, sponsor.website %>
+ <%= sponsor.description %> + + diff --git a/app/views/sponsors/index.html.erb b/app/views/sponsors/index.html.erb new file mode 100644 index 0000000..58d302d --- /dev/null +++ b/app/views/sponsors/index.html.erb @@ -0,0 +1,9 @@ +

Our Sponsors

+ + + + <% @sponsors.each do |sponsor| %> + <%= render 'sponsor', :sponsor => sponsor %> + <% end %> + +
diff --git a/app/views/statics/show.html.erb b/app/views/statics/show.html.erb new file mode 100644 index 0000000..829a64e --- /dev/null +++ b/app/views/statics/show.html.erb @@ -0,0 +1,3 @@ +

<%= @static.title %>

+ +<%= RDiscount.new(@static.content).to_html.html_safe %> diff --git a/app/views/suggestions/_form.html.erb b/app/views/suggestions/_form.html.erb new file mode 100644 index 0000000..32eb709 --- /dev/null +++ b/app/views/suggestions/_form.html.erb @@ -0,0 +1,25 @@ +<%= form_for(@suggestion) do |f| %> + <% if @suggestion.errors.any? %> +
+

<%= pluralize(@suggestion.errors.count, "error") %> prohibited this suggestion from being saved:

+ +
    + <% @suggestion.errors.full_messages.each do |msg| %> +
  • <%= msg %>
  • + <% end %> +
+
+ <% end %> + +
+ <%= f.label :subject %>
+ <%= f.text_field :subject %> +
+
+ <%= f.label :message %>
+ <%= f.text_area :message %> +
+
+ <%= f.submit %> +
+<% end %> diff --git a/app/views/suggestions/index.html.erb b/app/views/suggestions/index.html.erb new file mode 100644 index 0000000..a19fe2e --- /dev/null +++ b/app/views/suggestions/index.html.erb @@ -0,0 +1,16 @@ +

Listing suggestions

+ +
    + <% @suggestions.each do |suggestion| %> +
  • +
    <%= suggestion.subject %>
    +
    <%= suggestion.message.truncate(200) %>
    +
    <%= suggestion.user_id %>
    + <%= link_to 'See more details', suggestion %> +
  • + <% end %> +
+ +
+ +<%= link_to 'New Suggestion', new_suggestion_path %> diff --git a/app/views/suggestions/new.html.erb b/app/views/suggestions/new.html.erb new file mode 100644 index 0000000..e27e598 --- /dev/null +++ b/app/views/suggestions/new.html.erb @@ -0,0 +1,5 @@ +

New suggestion

+ +<%= render 'form' %> + +<%= link_to 'Back', suggestions_path %> diff --git a/app/views/suggestions/show.html.erb b/app/views/suggestions/show.html.erb new file mode 100644 index 0000000..1a5ae6c --- /dev/null +++ b/app/views/suggestions/show.html.erb @@ -0,0 +1,28 @@ + +

+ <%= @suggestion.subject %> +

+

+ <%= @suggestion.user.cse_username %> +

+ +

+ <%= RDiscount.new(@suggestion.message).to_html.html_safe %> +

+ +

+ Comments +

+ +<% @suggestion.comments.each do |comment| %> + <%= render comment %> +<% end %> + +<%= form_for [@suggestion, @suggestion.comments.new], :remote => true do |f| %> +
+
+ <%= f.text_field :comment %> + <%= f.submit %> +<% end %> + +<%= link_to 'Back', suggestions_path %> diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..7da2ced --- /dev/null +++ b/config.ru @@ -0,0 +1,4 @@ +# This file is used by Rack-based servers to start the application. + +require ::File.expand_path('../config/environment', __FILE__) +run CSESocWebsite::Application diff --git a/config/application.rb b/config/application.rb new file mode 100644 index 0000000..d9382ae --- /dev/null +++ b/config/application.rb @@ -0,0 +1,42 @@ +require File.expand_path('../boot', __FILE__) + +require 'rails/all' + +# If you have a Gemfile, require the gems listed there, including any gems +# you've limited to :test, :development, or :production. +Bundler.require(:default, Rails.env) if defined?(Bundler) + +module CSESocWebsite + class Application < Rails::Application + # Settings in config/environments/* take precedence over those specified here. + # Application configuration should go into files in config/initializers + # -- all .rb files in that directory are automatically loaded. + + # Custom directories with classes and modules you want to be autoloadable. + # config.autoload_paths += %W(#{config.root}/extras) + + # Only load the plugins named here, in the order given (default is alphabetical). + # :all can be used as a placeholder for all plugins not explicitly named. + # config.plugins = [ :exception_notification, :ssl_requirement, :all ] + + # Activate observers that should always be running. + # config.active_record.observers = :cacher, :garbage_collector, :forum_observer + + # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. + # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. + # config.time_zone = 'Central Time (US & Canada)' + + # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. + # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] + # config.i18n.default_locale = :de + + # JavaScript files you want as :defaults (application.js is always included). + # config.action_view.javascript_expansions[:defaults] = %w(jquery rails) + + # Configure the default encoding used in templates for Ruby 1.9. + config.encoding = "utf-8" + + # Configure sensitive parameters which will be filtered from the log file. + config.filter_parameters += [:password] + end +end diff --git a/config/boot.rb b/config/boot.rb new file mode 100644 index 0000000..4489e58 --- /dev/null +++ b/config/boot.rb @@ -0,0 +1,6 @@ +require 'rubygems' + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) + +require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE']) diff --git a/config/database.yml b/config/database.yml new file mode 100644 index 0000000..90d87cc --- /dev/null +++ b/config/database.yml @@ -0,0 +1,22 @@ +# SQLite version 3.x +# gem install sqlite3 +development: + adapter: sqlite3 + database: db/development.sqlite3 + pool: 5 + timeout: 5000 + +# Warning: The database defined as "test" will be erased and +# re-generated from your development database when you run "rake". +# Do not set this db to the same as development or production. +test: + adapter: sqlite3 + database: db/test.sqlite3 + pool: 5 + timeout: 5000 + +production: + adapter: sqlite3 + database: db/production.sqlite3 + pool: 5 + timeout: 5000 diff --git a/config/environment.rb b/config/environment.rb new file mode 100644 index 0000000..71f1350 --- /dev/null +++ b/config/environment.rb @@ -0,0 +1,5 @@ +# Load the rails application +require File.expand_path('../application', __FILE__) + +# Initialize the rails application +CSESocWebsite::Application.initialize! diff --git a/config/environments/development.rb b/config/environments/development.rb new file mode 100644 index 0000000..c1528f5 --- /dev/null +++ b/config/environments/development.rb @@ -0,0 +1,26 @@ +CSESocWebsite::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # In the development environment your application's code is reloaded on + # every request. This slows down response time but is perfect for development + # since you don't have to restart the webserver when you make code changes. + config.cache_classes = false + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_view.debug_rjs = true + config.action_controller.perform_caching = false + + # Don't care if the mailer can't send + config.action_mailer.raise_delivery_errors = false + + # Print deprecation notices to the Rails logger + config.active_support.deprecation = :log + + # Only use best-standards-support built into browsers + config.action_dispatch.best_standards_support = :builtin +end + diff --git a/config/environments/production.rb b/config/environments/production.rb new file mode 100644 index 0000000..831e1cf --- /dev/null +++ b/config/environments/production.rb @@ -0,0 +1,49 @@ +CSESocWebsite::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # The production environment is meant for finished, "live" apps. + # Code is not reloaded between requests + config.cache_classes = true + + # Full error reports are disabled and caching is turned on + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Specifies the header that your server uses for sending files + config.action_dispatch.x_sendfile_header = "X-Sendfile" + + # For nginx: + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' + + # If you have no front-end server that supports something like X-Sendfile, + # just comment this out and Rails will serve the files + + # See everything in the log (default is :info) + # config.log_level = :debug + + # Use a different logger for distributed setups + # config.logger = SyslogLogger.new + + # Use a different cache store in production + # config.cache_store = :mem_cache_store + + # Disable Rails's static asset server + # In production, Apache or nginx will already do this + config.serve_static_assets = false + + # Enable serving of images, stylesheets, and javascripts from an asset server + # config.action_controller.asset_host = "http://assets.example.com" + + # Disable delivery errors, bad email addresses will be ignored + # config.action_mailer.raise_delivery_errors = false + + # Enable threaded mode + # config.threadsafe! + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation can not be found) + config.i18n.fallbacks = true + + # Send deprecation notices to registered listeners + config.active_support.deprecation = :notify +end diff --git a/config/environments/test.rb b/config/environments/test.rb new file mode 100644 index 0000000..459bd33 --- /dev/null +++ b/config/environments/test.rb @@ -0,0 +1,35 @@ +CSESocWebsite::Application.configure do + # Settings specified here will take precedence over those in config/application.rb + + # The test environment is used exclusively to run your application's + # test suite. You never need to work with it otherwise. Remember that + # your test database is "scratch space" for the test suite and is wiped + # and recreated between test runs. Don't rely on the data there! + config.cache_classes = true + + # Log error messages when you accidentally call methods on nil. + config.whiny_nils = true + + # Show full error reports and disable caching + config.consider_all_requests_local = true + config.action_controller.perform_caching = false + + # Raise exceptions instead of rendering exception templates + config.action_dispatch.show_exceptions = false + + # Disable request forgery protection in test environment + config.action_controller.allow_forgery_protection = false + + # Tell Action Mailer not to deliver emails to the real world. + # The :test delivery method accumulates sent emails in the + # ActionMailer::Base.deliveries array. + config.action_mailer.delivery_method = :test + + # Use SQL instead of Active Record's schema dumper when creating the test database. + # This is necessary if your schema can't be completely dumped by the schema dumper, + # like if you have constraints or database-specific column types + # config.active_record.schema_format = :sql + + # Print deprecation notices to the stderr + config.active_support.deprecation = :stderr +end diff --git a/config/initializers/backtrace_silencers.rb b/config/initializers/backtrace_silencers.rb new file mode 100644 index 0000000..59385cd --- /dev/null +++ b/config/initializers/backtrace_silencers.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. +# Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } + +# You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. +# Rails.backtrace_cleaner.remove_silencers! diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb new file mode 100644 index 0000000..34d219b --- /dev/null +++ b/config/initializers/devise.rb @@ -0,0 +1,194 @@ +# Use this hook to configure devise mailer, warden hooks and so forth. The first +# four configuration values can also be set straight in your models. +Devise.setup do |config| + # ==> Mailer Configuration + # Configure the e-mail address which will be shown in DeviseMailer. + config.mailer_sender = "noreply@csesoc.unsw.edu.au" + + # Configure the class responsible to send e-mails. + # config.mailer = "Devise::Mailer" + + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'devise/orm/active_record' + + # ==> Configuration for any authentication mechanism + # Configure which keys are used when authenticating a user. The default is + # just :email. You can configure it to use [:username, :subdomain], so for + # authenticating a user, both parameters are required. Remember that those + # parameters are used only when authenticating and not when retrieving from + # session. If you need permissions, you should implement that in a before filter. + # You can also supply a hash where the value is a boolean determining whether + # or not authentication should be aborted when the value is not present. + # config.authentication_keys = [ :email ] + + # Configure parameters from the request object used for authentication. Each entry + # given should be a request method and it will automatically be passed to the + # find_for_authentication method and considered in your model lookup. For instance, + # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. + # The same considerations mentioned for authentication_keys also apply to request_keys. + # config.request_keys = [] + + # Configure which authentication keys should be case-insensitive. + # These keys will be downcased upon creating or modifying a user and when used + # to authenticate or find a user. Default is :email. + config.case_insensitive_keys = [ :cse_username ] + + # Tell if authentication through request.params is enabled. True by default. + # config.params_authenticatable = true + + # Tell if authentication through HTTP Basic Auth is enabled. False by default. + # config.http_authenticatable = false + + # If http headers should be returned for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication. "Application" by default. + # config.http_authentication_realm = "Application" + + # ==> Configuration for :database_authenticatable + # For bcrypt, this is the cost for hashing the password and defaults to 10. If + # using other encryptors, it sets how many times you want the password re-encrypted. + config.stretches = 10 + + # Setup a pepper to generate the encrypted password. + # config.pepper = "65647b631fcdc276cc29076634a4d4b7c3ce8c06e4f3fa8411812745b3eb2a62bd8c1e9ac9525755ecfa4636cb51e0ba8ee083a58dcd5b43f9f25561d8f90deb" + + # ==> Configuration for :confirmable + # The time you want to give your user to confirm his account. During this time + # he will be able to access your application without confirming. Default is 0.days + # When confirm_within is zero, the user won't be able to sign in without confirming. + # You can use this to let your user access some features of your application + # without confirming the account, but blocking it after a certain period + # (ie 2 days). + # config.confirm_within = 2.days + + # Defines which key will be used when confirming an account + # config.confirmation_keys = [ :email ] + + # ==> Configuration for :rememberable + # The time the user will be remembered without asking for credentials again. + # config.remember_for = 2.weeks + + # If true, a valid remember token can be re-used between multiple browsers. + # config.remember_across_browsers = true + + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false + + # If true, uses the password salt as remember token. This should be turned + # to false if you are not using database authenticatable. + config.use_salt_as_remember_token = true + + # Options to be passed to the created cookie. For instance, you can set + # :secure => true in order to force SSL only cookies. + # config.cookie_options = {} + + # ==> Configuration for :validatable + # Range for password length. Default is 6..128. + # config.password_length = 6..128 + + # Regex to use to validate the email address + # config.email_regexp = /\A([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})\z/i + + # ==> Configuration for :timeoutable + # The time you want to timeout the user session without activity. After this + # time the user will be asked for credentials again. Default is 30 minutes. + # config.timeout_in = 30.minutes + + # ==> Configuration for :lockable + # Defines which strategy will be used to lock an account. + # :failed_attempts = Locks an account after a number of failed attempts to sign in. + # :none = No lock strategy. You should handle locking by yourself. + # config.lock_strategy = :failed_attempts + + # Defines which key will be used when locking and unlocking an account + # config.unlock_keys = [ :email ] + + # Defines which strategy will be used to unlock an account. + # :email = Sends an unlock link to the user email + # :time = Re-enables login after a certain amount of time (see :unlock_in below) + # :both = Enables both strategies + # :none = No unlock strategy. You should handle unlocking by yourself. + # config.unlock_strategy = :both + + # Number of authentication tries before locking an account if lock_strategy + # is failed attempts. + # config.maximum_attempts = 20 + + # Time interval to unlock the account if :time is enabled as unlock_strategy. + # config.unlock_in = 1.hour + + # ==> Configuration for :recoverable + # + # Defines which key will be used when recovering the password for an account + # config.reset_password_keys = [ :email ] + + # Time interval you can reset your password with a reset password key. + # Don't put a too small interval or your users won't have the time to + # change their passwords. + config.reset_password_within = 2.hours + + # ==> Configuration for :encryptable + # Allow you to use another encryption algorithm besides bcrypt (default). You can use + # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, + # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) + # and :restful_authentication_sha1 (then you should set stretches to 10, and copy + # REST_AUTH_SITE_KEY to pepper) + # config.encryptor = :sha512 + + # ==> Configuration for :token_authenticatable + # Defines name of the authentication token params key + config.token_authentication_key = :auth_token + + # If true, authentication through token does not store user in session and needs + # to be supplied on each request. Useful if you are using the token as API token. + # config.stateless_token = false + + # ==> Scopes configuration + # Turn scoped views on. Before rendering "sessions/new", it will first check for + # "users/sessions/new". It's turned off by default because it's slower if you + # are using only default views. + # config.scoped_views = false + + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes (usually :user). + # config.default_scope = :user + + # Configure sign_out behavior. + # Sign_out action can be scoped (i.e. /users/sign_out affects only :user scope). + # The default is true, which means any logout action will sign out all active scopes. + # config.sign_out_all_scopes = true + + # ==> Navigation configuration + # Lists the formats that should be treated as navigational. Formats like + # :html, should redirect to the sign in page when the user does not have + # access, but formats like :xml or :json, should return 401. + # + # If you have any extra navigational formats, like :iphone or :mobile, you + # should add them to the navigational formats lists. + # + # The :"*/*" and "*/*" formats below is required to match Internet + # Explorer requests. + # config.navigational_formats = [:"*/*", "*/*", :html] + + # The default HTTP method used to sign out a resource. Default is :get. + # config.sign_out_via = :get + + # ==> OmniAuth + # Add a new OmniAuth provider. Check the wiki for more information on setting + # up on your models and hooks. + # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' + + # ==> Warden configuration + # If you want to use other strategies, that are not supported by Devise, or + # change the failure app, you can configure them inside the config.warden block. + # + # config.warden do |manager| + # manager.failure_app = AnotherApp + # manager.intercept_401 = false + # manager.default_strategies(:scope => :user).unshift :some_external_strategy + # end +end diff --git a/config/initializers/inflections.rb b/config/initializers/inflections.rb new file mode 100644 index 0000000..9e8b013 --- /dev/null +++ b/config/initializers/inflections.rb @@ -0,0 +1,10 @@ +# Be sure to restart your server when you modify this file. + +# Add new inflection rules using the following format +# (all these examples are active by default): +# ActiveSupport::Inflector.inflections do |inflect| +# inflect.plural /^(ox)$/i, '\1en' +# inflect.singular /^(ox)en/i, '\1' +# inflect.irregular 'person', 'people' +# inflect.uncountable %w( fish sheep ) +# end diff --git a/config/initializers/mime_types.rb b/config/initializers/mime_types.rb new file mode 100644 index 0000000..72aca7e --- /dev/null +++ b/config/initializers/mime_types.rb @@ -0,0 +1,5 @@ +# Be sure to restart your server when you modify this file. + +# Add new mime types for use in respond_to blocks: +# Mime::Type.register "text/richtext", :rtf +# Mime::Type.register_alias "text/html", :iphone diff --git a/config/initializers/rails_admin.rb b/config/initializers/rails_admin.rb new file mode 100644 index 0000000..32c68f5 --- /dev/null +++ b/config/initializers/rails_admin.rb @@ -0,0 +1 @@ +RailsAdmin.authorize_with :cancan \ No newline at end of file diff --git a/config/initializers/secret_token.rb b/config/initializers/secret_token.rb new file mode 100644 index 0000000..1de3eab --- /dev/null +++ b/config/initializers/secret_token.rb @@ -0,0 +1,7 @@ +# Be sure to restart your server when you modify this file. + +# Your secret key for verifying the integrity of signed cookies. +# If you change this key, all old signed cookies will become invalid! +# Make sure the secret is at least 30 characters and all random, +# no regular words or you'll be exposed to dictionary attacks. +CSESocWebsite::Application.config.secret_token = '191a310a7defe174dbb15da9c7bc363621612f2da66b87e2b58da90e84d907c792dcea51c11d12a41121d40c51c5ea1cbb84e77c0af23be46453cdd953060ec1' diff --git a/config/initializers/session_store.rb b/config/initializers/session_store.rb new file mode 100644 index 0000000..450bffa --- /dev/null +++ b/config/initializers/session_store.rb @@ -0,0 +1,8 @@ +# Be sure to restart your server when you modify this file. + +CSESocWebsite::Application.config.session_store :cookie_store, :key => '_CSESoc-Website_session' + +# Use the database for sessions instead of the cookie-based default, +# which shouldn't be used to store highly confidential information +# (create the session table with "rails generate session_migration") +# CSESocWebsite::Application.config.session_store :active_record_store diff --git a/config/locales/devise.en.yml b/config/locales/devise.en.yml new file mode 100644 index 0000000..25022e1 --- /dev/null +++ b/config/locales/devise.en.yml @@ -0,0 +1,50 @@ +# Additional translations at http://github.com/plataformatec/devise/wiki/I18n + +en: + errors: + messages: + expired: "has expired, please request a new one" + not_found: "not found" + already_confirmed: "was already confirmed, please try signing in" + not_locked: "was not locked" + not_saved: + one: "1 error prohibited this %{resource} from being saved:" + other: "%{count} errors prohibited this %{resource} from being saved:" + + devise: + failure: + already_authenticated: 'You are already signed in.' + unauthenticated: 'You need to sign in or sign up before continuing.' + unconfirmed: 'You have to confirm your account before continuing.' + locked: 'Your account is locked.' + invalid: 'Invalid email or password.' + invalid_token: 'Invalid authentication token.' + timeout: 'Your session expired, please sign in again to continue.' + inactive: 'Your account was not activated yet.' + sessions: + signed_in: 'Signed in successfully.' + signed_out: 'Signed out successfully.' + passwords: + send_instructions: 'You will receive an email with instructions about how to reset your password in a few minutes.' + updated: 'Your password was changed successfully. You are now signed in.' + confirmations: + send_instructions: 'You will receive an email with instructions about how to confirm your account in a few minutes.' + confirmed: 'Your account was successfully confirmed. You are now signed in.' + registrations: + signed_up: 'Welcome! You have signed up successfully.' + inactive_signed_up: 'You have signed up successfully. However, we could not sign you in because your account is %{reason}.' + updated: 'You updated your account successfully.' + destroyed: 'Bye! Your account was successfully cancelled. We hope to see you again soon.' + unlocks: + send_instructions: 'You will receive an email with instructions about how to unlock your account in a few minutes.' + unlocked: 'Your account was successfully unlocked. You are now signed in.' + omniauth_callbacks: + success: 'Successfully authorized from %{kind} account.' + failure: 'Could not authorize you from %{kind} because "%{reason}".' + mailer: + confirmation_instructions: + subject: 'Confirmation instructions' + reset_password_instructions: + subject: 'Reset password instructions' + unlock_instructions: + subject: 'Unlock Instructions' diff --git a/config/locales/en.yml b/config/locales/en.yml new file mode 100644 index 0000000..a747bfa --- /dev/null +++ b/config/locales/en.yml @@ -0,0 +1,5 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + hello: "Hello world" diff --git a/config/locales/rails_admin.en.yml b/config/locales/rails_admin.en.yml new file mode 100644 index 0000000..6a00c7f --- /dev/null +++ b/config/locales/rails_admin.en.yml @@ -0,0 +1,60 @@ +# Sample localization file for English. Add more files in this directory for other locales. +# See http://github.com/svenfuchs/rails-i18n/tree/master/rails%2Flocale for starting points. + +en: + home: + name: "home" + admin: + dashboard: + pagename: "Site administration" + name: "Dashboard" + model_name: "Model name" + last_used: "Last used" + records: "Records" + modify: "Modify" + add_new: "Add new" + show: "Show" + ago: "ago" + history: + name: "History" + page_name: "History for %{name}" + no_activity: "No Activity" + credentials: + log_out: "Log out" + list: + edit_action: "Edit" + delete_action: "Delete" + select_action: "Select" + delete_selected: "Delete selected" + add_new: "Add new" + search: "Search" + select: "Select %{name} to edit" + show_all: "Show all" + new: + basic_info: "Basic info" + required: "Required" + optional: "Optional" + one_char: "character." + many_chars: "characters or fewer." + chosen: "Chosen %{name}" + select_choice: "Select your choice(s) and click" + chose_all: "Choose all" + clear_all: "Clear all" + save: "Save" + save_and_add_another: "Save and add another" + save_and_edit: "Save and edit" + cancel: "Cancel" + delete: + flash_confirmation: "%{name} was successfully destroyed" + confirmation: "Yes, I'm sure" + flash: + successful: "%{name} was successfully %{action}" + error: "%{name} failed to be %{action}" + noaction: "No actions were taken" + actions: + create: "create" + created: "created" + update: "update" + updated: "updated" + delete: "delete" + deleted: "deleted" \ No newline at end of file diff --git a/config/routes.rb b/config/routes.rb new file mode 100644 index 0000000..c08ffec --- /dev/null +++ b/config/routes.rb @@ -0,0 +1,76 @@ +CSESocWebsite::Application.routes.draw do + root :to => "news_items#index" + + get "users/sign_in", :as => :new_user_session, :to => redirect( "https://cgi.cse.unsw.edu.au/~csesoc/services/cse_auth/?") + devise_for :users do + get "callback", :to => "devise/sessions#create" + end + + resources :sponsors, :only => [:index] + resources :events, :only => [:index, :show] + resources :news_items, :only => [:index, :show] + resources :statics, :only => [:show] + + # Suggestions + resources :suggestions, :only => [:index, :show, :new, :create] do + # Comments on suggestions + resources :comments, :only => [:create] + end + + # The priority is based upon order of creation: + # first created -> highest priority. + + # Sample of regular route: + # match 'products/:id' => 'catalog#view' + # Keep in mind you can assign values other than :controller and :action + + # Sample of named route: + # match 'products/:id/purchase' => 'catalog#purchase', :as => :purchase + # This route can be invoked with purchase_url(:id => product.id) + + # Sample resource route (maps HTTP verbs to controller actions automatically): + # resources :products + + # Sample resource route with options: + # resources :products do + # member do + # get 'short' + # post 'toggle' + # end + # + # collection do + # get 'sold' + # end + # end + + # Sample resource route with sub-resources: + # resources :products do + # resources :comments, :sales + # resource :seller + # end + + # Sample resource route with more complex sub-resources + # resources :products do + # resources :comments + # resources :sales do + # get 'recent', :on => :collection + # end + # end + + # Sample resource route within a namespace: + # namespace :admin do + # # Directs /admin/products/* to Admin::ProductsController + # # (app/controllers/admin/products_controller.rb) + # resources :products + # end + + # You can have the root of your site routed with "root" + # just remember to delete public/index.html. + # root :to => "welcome#index" + + # See how all your routes lay out with "rake routes" + + # This is a legacy wild controller route that's not recommended for RESTful applications. + # Note: This route will make all actions in every controller accessible via GET requests. + # match ':controller(/:action(/:id(.:format)))' +end diff --git a/csesoc/auth/backends.py b/csesoc/auth/backends.py deleted file mode 100644 index 1bce46f..0000000 --- a/csesoc/auth/backends.py +++ /dev/null @@ -1,83 +0,0 @@ -from django.contrib.auth.backends import ModelBackend -from django.contrib.auth import authenticate, login -from django.http import HttpResponseRedirect -from django.contrib import admin -from django.conf import settings -from django.template import RequestContext -from django.shortcuts import render_to_response -from django.core.urlresolvers import resolve -from csesoc import admin_urls -from django.core.urlresolvers import get_resolver - -class CSEBackend(ModelBackend): - def authenticate(self, token=None): - import urllib - from django.contrib.auth.models import User - - #Check if we have turned off login (for dev work) - if settings.ADMIN_NO_LOGIN == False: - # Check the token and return a User. - token = urllib.unquote(token) - token = token.decode('iso-8859-1') - import MySQLdb - db = MySQLdb.connect(db='cse_auth', user=settings.DB_USERNAME, passwd=settings.DB_PASSWORD) - c = db.cursor() - c.execute('select `user` from `users` where `cookie` = %s;', (token,)) - - #If cookie already exists in DB, return the User - row = c.fetchone() - if row and row[0]: - username = row[0] - #Otherwise user has not actually logged in, so return None - else: - return None - - user, created = User.objects.get_or_create(username=username, - defaults={'password' : 'get from cse', - 'is_staff' : False, - 'is_superuser' : False}) - return user - #If login is turned off, just create a test_admin user - else: - user, created = User.objects.get_or_create(username="test_admin", - defaults={'password' : 'get from cse', - 'is_staff' : True, - 'is_superuser' : True}) - return user - -def cse_login(request, next=None): - from django.conf import settings - if "CSE" not in settings.AUTHENTICATION_BACKENDS[0]: - return login(request, next) - - #Check if already authenticated - if not request.user.is_authenticated(): - user = None - #If no login is turned on, then we don't need to pass in token - if settings.ADMIN_NO_LOGIN: - user = authenticate() - #If our cookie indicates we have already logged in before, just use the same token - elif request.COOKIES.has_key('cseauth'): - user = authenticate(token=request.COOKIES['cseauth']) - - #If we've managed to get a user, then log in... - if user is not None: - if user.is_active: - login(request, user) - else: - return render_to_response('go_away.html', context_instance=RequestContext(request)) - #...otherwise use the cse_auth login to set up DB and cookie - else: - return HttpResponseRedirect('https://cgi.cse.unsw.edu.au/~csesoc/services/cse_auth/?redirectTo=' + request.build_absolute_uri()) - - #Now just pass move onto the page the user was actually trying to get to - if request.GET.has_key('next'): - return HttpResponseRedirect(request.GET['next']) - else: - return HttpResponseRedirect(next) - -class CSEAdminSite(admin.sites.AdminSite): - def login(self, request, extra_context=None): - return cse_login(request, request.get_full_path()) -#override admin.site also so people can use admin.site.register -site = admin.site = CSEAdminSite() diff --git a/csesoc/campattendees/admin.py b/csesoc/campattendees/admin.py deleted file mode 100644 index 80eb35c..0000000 --- a/csesoc/campattendees/admin.py +++ /dev/null @@ -1,10 +0,0 @@ -from django.contrib import admin -from csesoc.campattendees.models import Application -from csesoc import campglobals - -class ApplicationAdmin(admin.ModelAdmin): - list_filter = ('year','shirt_size','gender', 'payment_status', 'medical_form') - list_display = ('full_name', 'cse_username', 'gender', 'age', 'cse_program','shirt_size','payment_status', 'medical_form', 'year') - actions = [campglobals.mark_depositpaid, campglobals.mark_arcpaid, campglobals.mark_fullpaid, campglobals.mark_medicalyes] - -admin.site.register(Application, ApplicationAdmin) diff --git a/csesoc/campattendees/models.py b/csesoc/campattendees/models.py deleted file mode 100644 index 017cd39..0000000 --- a/csesoc/campattendees/models.py +++ /dev/null @@ -1,28 +0,0 @@ -from django.db import models -from csesoc import campglobals - -class Application(models.Model): - full_name = models.CharField(max_length=100) - student_number = models.CharField(max_length=8) - contact_number = models.CharField(max_length=15) - cse_username = models.CharField(max_length=15, verbose_name='CSE username') - gender = models.CharField(max_length=1, choices=campglobals.GENDER_CHOICES) - - cse_program = models.CharField(max_length=2, choices=campglobals.PROGRAM_CHOICES, verbose_name='CSE program') - AGE_CHOICES = ( - ('Y', '18+'), - ('N', '0-17'), - ) - age = models.CharField(max_length=1, choices=AGE_CHOICES, verbose_name='Age on March 16 2012?', help_text='Proof of age will be required if you wish to consume alcohol.') - dietary = models.TextField(help_text='Please list any special dietary requirements above.', blank=True) - medical = models.TextField(help_text='Please list any medical conditions that should be disclosed above.', blank=True) - - payment_status = models.CharField(max_length=1, choices=campglobals.PAYMENT_CHOICES, default='N') - medical_form = models.BooleanField(default=False) - - year = models.IntegerField(verbose_name='Application Year', editable=False) - shirt_size = models.CharField(max_length=3, choices=campglobals.SHIRT_CHOICES, default='N') - - def __unicode__(self): - return self.full_name - diff --git a/csesoc/campattendees/views.py b/csesoc/campattendees/views.py deleted file mode 100644 index f81576b..0000000 --- a/csesoc/campattendees/views.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.forms import ModelForm -from django.shortcuts import render_to_response -from django.contrib.auth import authenticate -from models import Application -from django.conf import settings -from django.template import RequestContext -import datetime -import urllib - -class ApplicationForm(ModelForm): - class Meta: - model = Application - exclude = ('medical_form','payment_status',) - -def signup(request): - this_year = datetime.date.today().year - if request.method == 'POST': # form submitted - appl = Application(year=this_year) - form = ApplicationForm(request.POST, instance=appl) # form bound to POST data - if form.is_valid(): - form.save() # create new Application instance - return render_to_response('thanks-signup.html', context_instance=RequestContext(request)) - else: - username = '' - if request.COOKIES.has_key('cseauth'): - uname = request.COOKIES['cseauth'] - uname = urllib.unquote(uname) - uname = uname.decode('iso-8859-1') - import MySQLdb - db = MySQLdb.connect(db='cse_auth', user=settings.DB_USERNAME, passwd=settings.DB_PASSWORD) - c = db.cursor() - c.execute('select `user` from `users` where `cookie` = %s;', (uname,)) - - row = c.fetchone() - if row and row[0]: - username = row[0] - - appl = Application(year=this_year, cse_username = username) - form = ApplicationForm(instance=appl) # unbound form - - return render_to_response('signup.html', {'form' : form}, context_instance=RequestContext(request)) - diff --git a/csesoc/campglobals.py b/csesoc/campglobals.py deleted file mode 100644 index afd9b8b..0000000 --- a/csesoc/campglobals.py +++ /dev/null @@ -1,61 +0,0 @@ -PROGRAM_CHOICES = ( - ('CS', 'Computer Science'), - ('CE', 'Computer Engineering'), - ('SE', 'Software Engineering'), - ('BI', 'Bioinformatics'), - ('FF', 'Flexible First Year Engineering'), - ('CM', 'Coursework Masters'), - ('RM', 'Research Masters'), - ('PD', 'Ph.D'), - ('OT', 'Other'), - ) - -GENDER_CHOICES = ( - ('M', 'Male'), - ('F', 'Female'), - ) - - -PAYMENT_CHOICES = ( - ('N', 'Not Paid'), - ('D', 'Deposit Paid'), - ('A', 'Paid Arc Amount'), - ('F', 'Paid in Full'), - ) - -SHIRT_CHOICES = ( - ('S', 'Mens - Small'), - ('M', 'Mens - Medium'), - ('L', 'Mens - Large'), - ('XL', 'Mens - Extra Large'), - ('XXL', 'Mens - XXL'), - ('6', 'Ladies - 6'), - ('8', 'Ladies - 8'), - ('10', 'Ladies - 10'), - ('12', 'Ladies - 12'), - ('14', 'Ladies - 14'), - ('16', 'Ladies - 16'), - ) - - - -def make_accepted(modeladmin, request, queryset): - queryset.update(accepted=True) -make_accepted.short_description = "Accept Leaders" - -def mark_depositpaid(modeladmin, request, queryset): - queryset.update(payment_status='D') -mark_depositpaid.short_description = "Deposit Paid" - -def mark_fullpaid(modeladmin, request, queryset): - queryset.update(payment_status='F') -mark_fullpaid.short_description = "Paid Full" - -def mark_arcpaid(modeladmin, request, queryset): - queryset.update(payment_status='A') -mark_arcpaid.short_description = "Arc Paid" - -def mark_medicalyes(modeladmin, request, queryset): - queryset.update(medical_form=True) -mark_medicalyes.short_description = "Medical Form Handed In" - diff --git a/csesoc/campleaders/__init__.py b/csesoc/campleaders/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/campleaders/admin.py b/csesoc/campleaders/admin.py deleted file mode 100644 index f3d8a20..0000000 --- a/csesoc/campleaders/admin.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.contrib import admin -from csesoc.campleaders.models import Application -from csesoc.campleaders.models import AwkwardQuestion -from csesoc import campglobals - -def make_accepted(modeladmin, request, queryset): - queryset.update(accepted=True) -make_accepted.short_description = "Accept Leaders" - -class ApplicationAdmin(admin.ModelAdmin): - list_filter = ('year', 'accepted', 'shirt_size', 'payment_status', 'medical_form') - list_display = ('full_name', 'year','cse_username', 'gender', 'year_or_stage', 'year', 'shirt_size', 'payment_status', 'medical_form', 'accepted') - actions = [make_accepted, campglobals.mark_depositpaid, campglobals.mark_arcpaid, campglobals.mark_fullpaid, campglobals.mark_medicalyes] -admin.site.register(Application, ApplicationAdmin) -admin.site.register(AwkwardQuestion) - diff --git a/csesoc/campleaders/models.py b/csesoc/campleaders/models.py deleted file mode 100644 index c399147..0000000 --- a/csesoc/campleaders/models.py +++ /dev/null @@ -1,47 +0,0 @@ -from django.db import models -from csesoc import campglobals - -class AwkwardQuestion(models.Model): - question = models.TextField() - def __unicode__(self): - return self.question - -class Application(models.Model): - full_name = models.CharField(max_length=100) - student_number = models.CharField(max_length=8) - contact_number = models.CharField(max_length=15) - cse_username = models.CharField(max_length=15, verbose_name='CSE username') - gender = models.CharField(max_length=1, choices=campglobals.GENDER_CHOICES) - accepted = models.BooleanField(default=False) - - shirt_size = models.CharField(max_length=2, choices=campglobals.SHIRT_CHOICES, help_text='Preferred shirt size if chosen to be a leader?') - cse_program = models.CharField(max_length=2, choices=campglobals.PROGRAM_CHOICES, verbose_name='CSE program') - - payment_status = models.CharField(max_length=1, choices=campglobals.PAYMENT_CHOICES, default='N') - medical_form = models.BooleanField(default=False) - - year_or_stage = models.IntegerField(verbose_name='Year/Stage') - year = models.IntegerField(verbose_name='Application Year', editable=False) - dietary = models.TextField('Do you have any special dietary requirements?', blank=True) - medical = models.TextField('Do you have any medical conditions that should be disclosed?', blank=True) - FIRST_AID_CHOICES = ( - ('Y', 'Yes'), - ('M', 'Yes, but expired'), - ('N', 'No, but I can still be a leader!') - ) - first_aid_qualifications = models.CharField(max_length=1, choices=FIRST_AID_CHOICES, verbose_name='Do you have any medical/first aid qualifications?') - q1 = models.TextField('Why do you want to be a CSE Camp leader?') - q2 = models.TextField('What do you think is the purpose of CSE Camp?') - q3 = models.TextField('What experience have you had in leadership roles and/or working in groups?') - q4 = models.TextField('As a leader, what do you think your responsibilities at CSE Camp will entail?') - #dodgy hacks to add an remove questions - q5 = models.TextField('What personal attributes or characteristics can you bring to CSE Camp?', blank=True) - q6 = models.TextField('What would you do if one of the members in your group claims that he/she is being harassed by other people in the group?', blank=True) - q7 = models.TextField('What would you do if one member of the group is being excluded or feeling shy in getting involved in group activities?', blank=True) - q8 = models.TextField('If a member of your group is underage and wants to drink, what will you advise him/her to do?') - q9question = models.ForeignKey(AwkwardQuestion) - q9 = models.TextField(verbose_name=str(q9question)) - - def __unicode__(self): - return self.full_name - diff --git a/csesoc/campleaders/views.py b/csesoc/campleaders/views.py deleted file mode 100644 index f3b8b97..0000000 --- a/csesoc/campleaders/views.py +++ /dev/null @@ -1,57 +0,0 @@ -from django.forms import ModelForm -from django import forms -from django.shortcuts import render_to_response -from models import AwkwardQuestion -from models import Application -from django.conf import settings -import datetime -from datetime import timedelta -from django.contrib.auth.decorators import login_required -from django.template import RequestContext - -class ApplicationForm(ModelForm): - q9question = forms.ModelChoiceField(queryset=AwkwardQuestion.objects.all(), - widget=forms.HiddenInput) - def setQ9(self, q9question): - self.fields['q9'] = forms.CharField(widget=forms.Textarea, - #dodgy hack for poor design decision - label=str(q9question)) - - class Meta: - model = Application - # to use if we upgrade django - #http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#overriding-the-default-field-types-or-widgets - #widgets = {'q9question': forms.HiddenInput} - exclude = ( 'cse_username', 'q5', 'q6', 'q7', 'accepted', 'payment_status', 'medical_form' ) - -@login_required -def apply(request): - year = (datetime.date.today() + timedelta(weeks=21)).year - if request.method == 'POST': # form submitted - apps = Application.objects.filter(cse_username=request.user.username, year=year) - if len(apps) == 0: - appl = Application(year=year, cse_username=request.user.username) - else: - appl = apps[0] - form = ApplicationForm(request.POST, instance=appl) # form bound to POST data - form.setQ9(AwkwardQuestion.objects.get(id=int(request.POST['q9question']))) - if form.is_valid(): - form.save() # create new Application instance - return render_to_response('thanks.html', context_instance=RequestContext(request)) - else: - q9question = AwkwardQuestion.objects.order_by('?')[0] - apps = Application.objects.filter(cse_username=request.user.username).order_by('-year') - if len(apps) == 0: - most_recent_app = Application(cse_username=request.user.username) - initial = {'q9question': q9question.id} - else: - most_recent_app = apps[0] - if most_recent_app.year != year: - initial = {'q9question': q9question.id, 'q9': ''} - else: - initial = {} - most_recent_app.year = year - form = ApplicationForm(instance=most_recent_app, initial=initial) # unbound form - form.setQ9(q9question) - - return render_to_response('apply.html', {'form' : form}, context_instance=RequestContext(request)) diff --git a/csesoc/context_processors.py b/csesoc/context_processors.py deleted file mode 100644 index d5c1043..0000000 --- a/csesoc/context_processors.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.conf import settings - -def sponsors_list(request): - from csesoc.sponsors.models import Sponsor - sponsors = Sponsor.objects.order_by('-amount_paid', 'name') - return { 'sponsors' : sponsors } diff --git a/csesoc/forms/__init__.py b/csesoc/forms/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/forms/widgets.py b/csesoc/forms/widgets.py deleted file mode 100644 index e88be31..0000000 --- a/csesoc/forms/widgets.py +++ /dev/null @@ -1,44 +0,0 @@ -from django.utils.safestring import mark_safe -from django import forms -from django.conf import settings - -class SliderInput(forms.Select): - """ - A slider widget to include in your form - """ - - # TODO(davidc): wtf is choices for if i use self.choices? - def render(self, name, value, attrs={}, choices=()): - attributes = attrs - attributes['min'] = 0 - attributes['max'] = len(self.choices) - 1 - attributes['step'] = 1 - # TODO(jayen): replace this and the super.render with a regular label - # and use '' % - # flatatt(self.build_attrs(attrs, name=name)) - attributes['style'] = 'display:none' - - #TODO(davidc): clean up dodgy hack - values = [] - values_text = [] - #value_index = 0 - for i in range(0, len(self.choices)): - values.append(self.choices[i][0]) - values_text.append(self.choices[i][1]) - #if self.choices[i][0] == value: - # value_index = i - value_index = values.index(value) - - res = super(SliderInput, self).render(name, value, attrs = attributes) - res += '
' - res += '' % (name, value_index) - res += '
%s
' % (name, values_text[value_index]) - res += '' % (name, ','.join(values)) - res += '' % (name, ','.join(values_text)) - res += '
' % name - res += '
' - return mark_safe(res) - - class Media: - css = {'screen':(settings.STATIC_URL + 'css/widgets/slider.css',)} - js = (settings.STATIC_URL + 'js/widgets/slider.js',) diff --git a/csesoc/game/__init__.py b/csesoc/game/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/game/admin.py b/csesoc/game/admin.py deleted file mode 100644 index a902332..0000000 --- a/csesoc/game/admin.py +++ /dev/null @@ -1,31 +0,0 @@ -from django.contrib import admin -from csesoc.game.models import * - -class PuzzleAdmin(admin.ModelAdmin): - list_display = ('title', 'next_puzzle', 'points', 'creation_date', 'slug') - def save_model(self, request, obj, form, change): - obj.save() - -class PlayerProgressInline(admin.StackedInline): - model = PlayerProgress - extra = 2 - -class PlayerAdmin(admin.ModelAdmin): - list_display = ['username', 'score', 'upto', 'rank'] - search_fields = ['username'] - inlines = (PlayerProgressInline,) - model = Player - -class GameAdmin(admin.ModelAdmin): - model = Game - -class AttemptAdmin(admin.ModelAdmin): - list_display = ['attempt_time', '__unicode__'] - search_fields = ['progress__player__username', 'progress__puzzle__title', 'progress__puzzle__slug', 'attempt'] - model = PlayerAttempt - -admin.site.register(Puzzle, PuzzleAdmin) -admin.site.register(Game, GameAdmin) -admin.site.register(Player, PlayerAdmin) -admin.site.register(PlayerAttempt, AttemptAdmin) - diff --git a/csesoc/game/models.py b/csesoc/game/models.py deleted file mode 100644 index b1cf9a7..0000000 --- a/csesoc/game/models.py +++ /dev/null @@ -1,106 +0,0 @@ -from django.db import models -from django.contrib.contenttypes.models import ContentType -from django.db.models.signals import post_save -from django.db.models.signals import pre_delete -from django.contrib.auth.models import User -from django.contrib.contenttypes import generic -from django.template.loader import render_to_string -from datetime import datetime -from django.db.models import Sum -from django.shortcuts import get_object_or_404 - -class Game(models.Model): - name = models.CharField(max_length=200) - year = models.PositiveIntegerField(unique=True) - - def __unicode__(self): - return self.name - -class Puzzle(models.Model): - title = models.CharField(max_length=200) - text = models.TextField() - creation_date = models.DateTimeField(auto_now_add=True) - update_date = models.DateTimeField(auto_now=True) - slug = models.SlugField(help_text="slug is used for the URL. Can give small hints using it..", unique=True) - next_puzzle = models.ForeignKey('self', blank=True, null=True) - answer = models.CharField(max_length=1024) - points = models.IntegerField() - - - def __unicode__(self): - return self.title - -class Player(models.Model): - username = models.CharField(max_length=30, help_text='CSE username for CSE students, student ID for others') - email = models.EmailField(help_text='Defaults to @cse.unsw.edu.au. Override for non-cse students', blank=True) - - def save(self, force_insert=False, force_update=False): - if not self.email: - self.email = self.username + "@cse.unsw.edu.au" - super(Player, self).save(force_insert, force_update) # Call the "real" save() method. - - def __unicode__(self): - return self.username - - def upto(self): - unsolved = PlayerProgress.objects.filter(player = self).filter(solved_time__isnull=True) - if len(unsolved) > 0: - return unsolved[0].puzzle - else: - print "SUP" - first_puzzle = get_object_or_404(Puzzle, slug="start") - return first_puzzle - - def score(self): - sum = PlayerProgress.objects.filter(player = self).filter(solved_time__isnull=False).aggregate(Sum('puzzle__points'))['puzzle__points__sum'] - if sum == None: - sum = 0 - return sum - - def rank(self): - player_scores = PlayerProgress.objects.filter(game__year__startswith=2010).filter(solved_time__isnull=False).values('player__username').annotate(Sum('puzzle__points')).order_by('-puzzle__points__sum') - - self_score = self.score() - tied = 0 - i = 0 - last_i = i - scores = [] - - for player_score in player_scores: - user = player_score['player__username'] - score = player_score['puzzle__points__sum'] - if score < self_score: - break - else: - i += 1 - if score not in scores: - scores.append(score) - last_i = i - if score == self_score and user != self.username: - tied = 1 - return {'rank':last_i, 'tied':tied} - - #Write this please, Prashant! - #def isAdmin(self): - - -class PlayerProgress(models.Model): - game = models.ForeignKey(Game) - player = models.ForeignKey(Player) - puzzle = models.ForeignKey(Puzzle) - reached_time = models.DateTimeField() - solved_time = models.DateTimeField(blank=True,null=True) - def __unicode__(self): - if self.solved_time == None: - return unicode(self.player) + " reached " + unicode(self.puzzle) + " at " + unicode(self.reached_time) - else: - return unicode(self.player) + " solved " + unicode(self.puzzle) + " at " + unicode(self.solved_time) - -class PlayerAttempt(models.Model): - progress = models.ForeignKey(PlayerProgress) - attempt_time = models.DateTimeField() - attempt = models.CharField(max_length=1024) - - def __unicode__(self): - return unicode(self.progress.player) + " at " + unicode(self.progress.puzzle) + " guessed " + self.attempt[0:50] - diff --git a/csesoc/game/views.py b/csesoc/game/views.py deleted file mode 100644 index 3b919a4..0000000 --- a/csesoc/game/views.py +++ /dev/null @@ -1,133 +0,0 @@ -from django.template import RequestContext -from django.shortcuts import render_to_response -from django.shortcuts import get_object_or_404 -from django.contrib.auth.decorators import login_required -from django.http import HttpResponseRedirect -from csesoc.game.models import * -from django.conf import settings -import datetime -from django.db.models import Sum - -# presently using generic views for everything. add custom views here as needed - -def get_player(username): - p = Player.objects.filter(username=username) - if len(p) > 0: - return p[0] - else: - p = Player() - p.username = username - p.save() - return p - -def get_progress(puzzle, username): - player = get_player(username) - game = get_object_or_404(Game, year = datetime.datetime.now().year) - - progress = PlayerProgress.objects.filter(player=player, puzzle=puzzle, game=game) - if len(progress) > 0: - return progress[0] - else: - progress = PlayerProgress() - progress.game = game - progress.puzzle = puzzle - progress.player = player - progress.reached_time = datetime.datetime.now() - progress.save() - -def solved_puzzle(puzzle, username): - progress = get_progress(puzzle, username) - if progress.solved_time == None: - progress.solved_time = datetime.datetime.now() - progress.save() - -# check whether what they entered is the answer -def check_solved(puzzle, username, answer): - # exact matches are always good - if answer.lower() == puzzle.answer.lower(): - return True - elif ";" in puzzle.answer: - answerParts = answer.split(" ") - ansParts = puzzle.answer.split(";") - - # we should not have way more tems in answerParts than puzzle answer parts - if len(answerParts) > len(ansParts) + 5: - return False - - # check that all the parts are in there - for ans in ansParts: - if ans not in answerParts: - return False - - return True - else: - return False - - -def reached_puzzle(puzzle, username): - # automatically creates it if required - progress = get_progress(puzzle, username) - -def made_attempt(puzzle, username, value): - progress = get_progress(puzzle, username) - - attempt = PlayerAttempt() - attempt.progress = progress - attempt.attempt_time = datetime.datetime.now() - attempt.attempt = value - attempt.save() - -#TODO: check that the user is logged in and player.isAdmin() -# requires the player.isAdmin() function to be written first - -# returns "th", where "th" can be "st", "nd", "rd", or "th" -def ordinal(n): - return dict([(x,'th') for x in range(10,20)]).get(n%100,{1:'st',2:'nd',3:'rd'}.get(n%10,'th')) - -def get_player_scores(request, year): - return PlayerProgress.objects.filter(game__year__startswith=2010).filter(solved_time__isnull=False).values('player__username').annotate(Sum('puzzle__points')).order_by('-puzzle__points__sum') - -def game_scores(request, year): - if year == "": - year = datetime.datetime.now().year - else: - year = int(year) - - # the magical line that calculates the scores - scores = get_player_scores(request, year) - return render_to_response('scores.html', {'scores': scores}) - -@login_required -def game_static_latest(request): - p = get_player(request.user.username) - last_puzzle = p.upto() - return HttpResponseRedirect(last_puzzle.slug) - - -@login_required -def game_static(request, path): - if request.method == "POST": - p = get_object_or_404(Puzzle, slug=path.replace('/','_')) - answer = request.POST['answer'] - made_attempt(p, request.user.username, answer) - if check_solved(p, request.user.username, answer) and p.next_puzzle != None: - # we can go to the next puzzle! - next = p.next_puzzle - - solved_puzzle(p, request.user.username) - - return HttpResponseRedirect(next.slug) - - p = get_object_or_404(Puzzle, slug=path.replace('/','_')) - reached_puzzle(p, request.user.username) - - # get the player's rank - player_rank = get_player(request.user.username).rank() - rank = "You are " - if player_rank['tied']: - rank += "tied in" - else: - rank += "ranked" - rank += " "+str(player_rank['rank'])+ordinal(player_rank['rank'])+" place!" - - return render_to_response('game.html', { 'object' : p, 'user': request.user, 'showanswer' : (p.next_puzzle != None), 'rank' : rank }, context_instance=RequestContext(request) ) diff --git a/csesoc/helpers/__init__.py b/csesoc/helpers/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/helpers/templates/helpers/templatetags/generate_pagenumbers.html b/csesoc/helpers/templates/helpers/templatetags/generate_pagenumbers.html deleted file mode 100644 index 5683134..0000000 --- a/csesoc/helpers/templates/helpers/templatetags/generate_pagenumbers.html +++ /dev/null @@ -1,17 +0,0 @@ -
    -
  • {% if has_previous %}«{% else %}«{% endif %}
  • - {% for page in range %} -
  • - {% if page %} - {% ifnotequal page current %} - {{ page }} - {% else %} - {{ page }} - {% endifnotequal %} - {% else %} - ... - {% endif %} -
  • - {% endfor %} -
  • {% if has_next %}»{% else %}»{% endif %}
  • -
diff --git a/csesoc/helpers/templatetags/__init__.py b/csesoc/helpers/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/helpers/templatetags/helpers.py b/csesoc/helpers/templatetags/helpers.py deleted file mode 100644 index 978cce1..0000000 --- a/csesoc/helpers/templatetags/helpers.py +++ /dev/null @@ -1,23 +0,0 @@ -from django import template -from django.conf import settings - -register = template.Library() - -@register.inclusion_tag('helpers/templatetags/generate_pagenumbers.html') -def generate_pagenumbers(paginator, page_obj, extra_pages): - context = { - 'paginator': paginator, - 'page_obj': page_obj, - 'has_previous': page_obj.has_previous(), - 'has_next': page_obj.has_next(), - 'current': page_obj.number, - 'range': [], - } - # we add the first and last pages, as well as pages from n - extra to n + extra; False symbolises a redacted page range - for page in paginator.page_range: - if (page == paginator.page_range[0]) or (page == paginator.page_range[-1]) or ((page >= page_obj.number - extra_pages) and (page <= page_obj.number + extra_pages)): - context['range'].append(page) - elif context['range'][-1] != False: - context['range'].append(False) - return context - diff --git a/csesoc/import.py b/csesoc/import.py deleted file mode 100644 index a45a493..0000000 --- a/csesoc/import.py +++ /dev/null @@ -1,19 +0,0 @@ -import set_path -set_path.update_path() - -from django.core.management import setup_environ -import settings - -setup_environ(settings) - -from csesoc.murder.models import * - -for password in open('murder/passwords.txt'): - p = Password(text=password[:-1]) - p.save() - -for quip in open('murder/quips.txt'): - q = Quip(text=quip[:-1]) - q.save() - - diff --git a/csesoc/invoices/__init__.py b/csesoc/invoices/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/invoices/admin.py b/csesoc/invoices/admin.py deleted file mode 100644 index 7afe7a6..0000000 --- a/csesoc/invoices/admin.py +++ /dev/null @@ -1,52 +0,0 @@ -from django.contrib import admin -from csesoc.invoices.models import * -from django.conf import settings -from django import forms -import md5, re - -class InvoiceAdminForm(forms.ModelForm): - class Meta: - model = Invoice - - def clean_slug(self): - slug = self.cleaned_data.get('slug') - if not re.match(r'^[0-9]{8}$', slug): - raise forms.ValidationError("Must be made of 8 digits!") - else: - return slug - -class InvoiceAdmin(admin.ModelAdmin): - form = InvoiceAdminForm - - def price(obj): - return "$%s"%(str(obj.price)) - def discount(obj): - return "($%s)"%(str(obj.discount)) - def invoice_description(obj): - return obj.title - def invoice_number(obj): - return obj.slug - def link(obj): - url = "%sinvoice/%s/%s" % (settings.SITE_DOMAIN, obj.slug, obj.hash) - return "%s"%(url, url) - link.allow_tags = True - def company(obj): - if obj.students_login: - return "--- CSE Login required ---" - else: - return obj.company - - def hash_function(self, obj): - return md5.new(str(obj.slug) + str(obj.company)).hexdigest() - - def save_model(self, request, obj, form, change): - obj.hash = self.hash_function(obj) - obj.save() - - exclude = ('hash',) - list_filter = ('company','students_login') - list_display = (invoice_number,company,invoice_description,price,discount,link,'students_login') - search_fields = ['company', '^slug', 'title', '^hash'] - - -admin.site.register(Invoice, InvoiceAdmin) diff --git a/csesoc/invoices/models.py b/csesoc/invoices/models.py deleted file mode 100644 index 9b7d1d6..0000000 --- a/csesoc/invoices/models.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.db import models - -class Invoice(models.Model): - slug = models.SlugField(max_length=30) - slug.primary_key = True - company = models.CharField(max_length=255) - title = models.CharField(max_length=255) - price = models.PositiveIntegerField() - discount = models.IntegerField() - hash = models.CharField(max_length=32) - students_login = models.BooleanField(default=False) diff --git a/csesoc/invoices/tests.py b/csesoc/invoices/tests.py deleted file mode 100644 index 501deb7..0000000 --- a/csesoc/invoices/tests.py +++ /dev/null @@ -1,16 +0,0 @@ -""" -This file demonstrates writing tests using the unittest module. These will pass -when you run "manage.py test". - -Replace this with more appropriate tests for your application. -""" - -from django.test import TestCase - - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.assertEqual(1 + 1, 2) diff --git a/csesoc/invoices/views.py b/csesoc/invoices/views.py deleted file mode 100644 index 5552683..0000000 --- a/csesoc/invoices/views.py +++ /dev/null @@ -1,81 +0,0 @@ -import uuid -from django.shortcuts import render_to_response -from django.template import RequestContext -from django.shortcuts import get_object_or_404 -from django.core.urlresolvers import reverse -from django.conf import settings -from csesoc.paypal.standard.forms import PayPalPaymentsForm -from csesoc.invoices.models import * -from django.contrib.auth.views import redirect_to_login - -def invoice_thanks(request, slug): - product = get_object_or_404(Invoice, slug=slug) - return render_to_response('product_thanks.html', { - 'product':product, - 'title':"Thanks!", - }, RequestContext(request)) - -def invoice_detail(request, slug, hash): - product = get_object_or_404(Invoice, slug=slug, hash=hash) - - # The direct debit price with discount applied - price = product.price - product.discount - - # The paypal price is the direct debit price plus a 2.5% fee - paypal_price = price * 1.025 - - # Add the CSE login to the item name we send to paypal - if product.students_login: - if request.user.is_authenticated(): - item_name = '%s (%s)'%(product.title, request.user.username) - else: - return redirect_to_login(request.path) - else: - item_name = '%s: %s'%(str(product.slug),product.title) - - # See the following guide for more details on variables - # https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_WebsitePaymentsStandard_IntegrationGuide.pdf - paypal = { - 'amount': paypal_price, - 'currency_code' : "AUD", - 'no_shipping' : 1, # Don't prompt for an address - 'no_note' : 1, # Don't prompt for a note - - 'item_name': item_name, - # Need a 150x150px image - #'image_url' : settings.SITE_DOMAIN + '/static/header/header.png', - - # Unique invoice ID - 'invoice': str(uuid.uuid1()), - - # The URL they will return to - 'return_url': settings.SITE_DOMAIN + "invoice/thanks/" + product.slug, - - # The URL they will cancel to - 'cancel_return': settings.SITE_DOMAIN + "invoice/" + product.slug + "/" + str(product.hash), - } - - form = PayPalPaymentsForm(initial=paypal) - if settings.DEBUG: - rendered_form = form.sandbox() - else: - rendered_form = form.render() - - if product.students_login: - template = 'product_students_detail.html' - title = '%s'%product.title - dd_description = "%s %s"%(str(product.slug)[-5:],str(request.user.username)) - else: - template = 'product_detail.html' - title = 'Invoice #%s'%str(product.slug) - dd_description = str(product.slug) - return render_to_response(template, { - 'product':product, - 'form': rendered_form, - 'price' : "$%.2f"%product.price, - 'discount': "($%.2f)"%product.discount, - 'total_price' : "$%.2f"%(price), - 'paypal_price' : "$%.2f"%(paypal_price), - 'dd_description': dd_description, - 'title' : title - }, RequestContext(request)) diff --git a/csesoc/mainsite/__init__.py b/csesoc/mainsite/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/mainsite/admin.py b/csesoc/mainsite/admin.py deleted file mode 100644 index d6eae9f..0000000 --- a/csesoc/mainsite/admin.py +++ /dev/null @@ -1,42 +0,0 @@ -from django.contrib import admin -from csesoc.mainsite.models import Beta,NewsItem,Event,Static - -class NewsItemAdmin(admin.ModelAdmin): - exclude = ('author',) - def save_model(self, request, obj, form, change): - if not change: - obj.author = request.user - obj.save() - -admin.site.register(NewsItem, NewsItemAdmin) - -class BetaAdmin(admin.ModelAdmin): - exclude = ('author',) - def save_model(self, request, obj, form, change): - if not change: - obj.author = request.user - obj.save() - -admin.site.register(Beta, BetaAdmin) - -class EventAdmin(admin.ModelAdmin): - exclude = ('author',) - def save_model(self, request, obj, form, change): - if not change: - obj.author = request.user - obj.save() - -admin.site.register(Event, EventAdmin) - -class StaticAdmin(admin.ModelAdmin): - exclude = ('creator', 'updater',) - list_filter = ('creator',) - list_display = ('title', 'creation_date', 'creator', 'slug',) - def save_model(self, request, obj, form, change): - if not change: - obj.creator = request.user - obj.updater = request.user - obj.save() - -admin.site.register(Static, StaticAdmin) - diff --git a/csesoc/mainsite/models.py b/csesoc/mainsite/models.py deleted file mode 100644 index 34703ce..0000000 --- a/csesoc/mainsite/models.py +++ /dev/null @@ -1,113 +0,0 @@ -from django.db import models -from django.contrib.contenttypes.models import ContentType -from django.db.models.signals import post_save -from django.db.models.signals import pre_delete -from django.contrib.auth.models import User -from django.contrib.contenttypes import generic -from django.template.loader import render_to_string -from django.conf import settings -from datetime import datetime -from tinymce import models as tinymce_models -import os - -class Static(models.Model): - title = models.CharField(max_length=200) - #text = models.TextField() - text = tinymce_models.HTMLField() - template = models.FilePathField(path=os.path.join(settings.PROJECT_PATH, "templates"), match="static.*\.html") - creation_date = models.DateTimeField(auto_now_add=True) - creator = models.ForeignKey(User, related_name='page_creator') - update_date = models.DateTimeField(auto_now=True) - updater = models.ForeignKey(User, related_name='page_updater') - slug = models.SlugField(help_text="slug will be used in url generation, keep it simple, stupid.") - def __unicode__(self): - return self.title - def save(self, *args, **kwargs): - #the db should not contain absolute paths - #so the database gets fixed on saves - import re - self.template = re.sub(r'.*/templates/','',self.template) - super(Static, self).save(*args, **kwargs) # Call the "real" save() method. - -class NewsItem(models.Model): - headline = models.CharField(max_length=200) - text = tinymce_models.HTMLField() - pub_date = models.DateTimeField(default=datetime.now, help_text="News item will appear on homepage starting from date and time specified.") - author = models.ForeignKey(User) - def __unicode__(self): - return self.headline - -class Event(models.Model): - name = models.CharField(max_length=200) - time = models.DateTimeField() - location = models.CharField(max_length=200) - registration_required = models.BooleanField() - registration_email = models.EmailField(blank=True, help_text="Address to email in order to register") - volunteers_required = models.BooleanField() - volunteers_email = models.EmailField(blank=True, help_text="Address to email in order to volunteer") - description = tinymce_models.HTMLField(help_text="Description of the event, will appear on the front page.") - pub_date = models.DateTimeField(default=datetime.now, help_text="Event will appear on homepage starting from date and time specified.") - author = models.ForeignKey(User) - def __unicode__(self): - return self.name - -class Beta(models.Model): - title = models.CharField(max_length=200, default="Beta 09S1 Week X Now Available") - blurb = models.TextField() - pdf_url = models.URLField(verify_exists=True, help_text="Link to PDF of this issue of Beta", max_length=500) - pub_date = models.DateTimeField(default=datetime.now, help_text="Beta will appear on homepage starting from date and time specified.") - - author = models.ForeignKey(User) - def __unicode__(self): - return self.title - -class StreamItem(models.Model): - content_type = models.ForeignKey(ContentType) - object_id = models.PositiveIntegerField() - pub_date = models.DateTimeField() - - content_object = generic.GenericForeignKey('content_type', 'object_id') - - def get_rendered_html(self): - template_name = 'stream_item_%s.html' %(self.content_type.name) - template_name = template_name.replace(' ','_') - return render_to_string(template_name, { 'object': self.content_object }) - -# Hook for creating StreamItems - -def create_stream_item(sender, instance, signal, *args, **kwargs): - # Get the instance's content type - ctype = ContentType.objects.get_for_model(instance) - - # Get the instance's pub date - #if ctype.name == 'beta': - # pub_date = instance.announce_date - #elif ctype.name == 'somethin else': - # pub_date = instance.some_field - #else: - # pub_date = instance.pub_date - pub_date = instance.pub_date - - # Update or create the corresponding StreamItem - try: - si = StreamItem.objects.get(content_type=ctype, object_id=instance.id) - si.pub_date = pub_date - si.save() - except StreamItem.DoesNotExist: - si = StreamItem(content_type=ctype, object_id=instance.id, pub_date=pub_date) - si.save() - -# Hook for removing StreamItems -def remove_stream_item(sender, instance, signal, *args, **kwargs): - # Get the instance's content type - ctype = ContentType.objects.get_for_model(instance) - - # Get the stream item corresponding to the instance being removed, and delete it. - si = StreamItem.objects.get(content_type=ctype, object_id=instance.id) - si.delete() - -# send a signal on post_save and pre_delete for each of these models -for modelname in [NewsItem, Event, Beta]: - post_save.connect(create_stream_item, sender=modelname) - pre_delete.connect(remove_stream_item, sender=modelname) - diff --git a/csesoc/mainsite/urls.py b/csesoc/mainsite/urls.py deleted file mode 100644 index b32e911..0000000 --- a/csesoc/mainsite/urls.py +++ /dev/null @@ -1,55 +0,0 @@ -from datetime import datetime - -from django.conf.urls.defaults import * - -from csesoc.mainsite.models import StreamItem -from csesoc.mainsite.views import streamitem_index - -tumblog_dict = { - 'queryset': StreamItem.objects.all(), - 'date_field': 'pub_date', -} - -news_dict = { - 'queryset': StreamItem.objects.filter(content_type__name='news item'), - 'date_field': 'pub_date', -} - -events_dict = { - 'queryset': StreamItem.objects.filter(content_type__name='event'), - 'date_field': 'pub_date', -} - -beta_dict = { - 'queryset': StreamItem.objects.filter(content_type__name='beta'), - 'date_field': 'pub_date', -} - -urlpatterns = patterns('django.views.generic.date_based', - - # all news sources - (r'^$', streamitem_index, tumblog_dict, 'home'), - (r'^(?P\d{4})/$', 'archive_year', tumblog_dict, 'home-year'), - (r'^(?P\d{4})/(?P[a-z]{3})/$', 'archive_month', tumblog_dict, 'home-month'), - (r'^(?P\d{4})/(?P[a-z]{3})/(?P\w{1,2})/$', 'archive_day', tumblog_dict, 'home-day'), - - # news - (r'^news/$', streamitem_index, news_dict, 'home-news'), - (r'^news/(?P\d{4})/$', 'archive_year', news_dict, 'home-news-year'), - (r'^news/(?P\d{4})/(?P[a-z]{3})/$', 'archive_month', news_dict, 'home-news-month'), - (r'^news/(?P\d{4})/(?P[a-z]{3})/(?P\w{1,2})/$', 'archive_day', news_dict, 'home-news-day'), - - # events - (r'^events/$', streamitem_index, events_dict, 'home-events'), - (r'^events/(?P\d{4})/$', 'archive_year', events_dict, 'home-events-year'), - (r'^events/(?P\d{4})/(?P[a-z]{3})/$', 'archive_month', events_dict, 'home-events-month'), - (r'^events/(?P\d{4})/(?P[a-z]{3})/(?P\w{1,2})/$', 'archive_day', events_dict, 'home-events-day'), - - # beta (legacy code) - (r'^beta/$', streamitem_index, beta_dict, 'home-beta'), - (r'^beta/(?P\d{4})/$', 'archive_year', beta_dict, 'home-beta-year'), - (r'^beta/(?P\d{4})/(?P[a-z]{3})/$', 'archive_month', beta_dict, 'home-beta-month'), - (r'^beta/(?P\d{4})/(?P[a-z]{3})/(?P\w{1,2})/$', 'archive_day', beta_dict, 'home-beta-day'), - -) - diff --git a/csesoc/mainsite/views.py b/csesoc/mainsite/views.py deleted file mode 100644 index b9fbb2e..0000000 --- a/csesoc/mainsite/views.py +++ /dev/null @@ -1,34 +0,0 @@ -from datetime import datetime - -from django.conf import settings -from django.shortcuts import get_object_or_404, render_to_response -from django.template import RequestContext -from django.views.generic.list_detail import object_list - -from django.conf import settings -from csesoc.mainsite.models import Static -from csesoc.sponsors.views import sponsorsList - -import os - -# presently using generic views for everything. add custom views here as needed - -def streamitem_index(request, queryset, **kwargs): - context = { - 'request': request, - 'queryset': queryset.filter(pub_date__lte=datetime.now()).order_by('-pub_date'), - 'paginate_by': settings.STREAMITEMS_PER_PAGE, - 'template_name': 'mainsite/streamitem_archive.html', - 'extra_context': {'allSponsors' : sponsorsList(request)}, - } - return object_list(**context) - -def static(request, path): - p = get_object_or_404(Static, slug=path.replace('/','_')) - #until the database gets fixed - import re - template = re.sub(r'.*templates/', '', p.template) - return render_to_response(template, { 'allSponsors' : sponsorsList(request), 'object' : p }, context_instance=RequestContext(request) ) - -def thedate(request): - return render_to_response('thedate.html', { 'date' : datetime.now() }, context_instance=RequestContext(request) ) diff --git a/csesoc/manage.py b/csesoc/manage.py deleted file mode 100755 index f060208..0000000 --- a/csesoc/manage.py +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env python -import set_path -set_path.update_path() - -from django.core.management import execute_manager - -try: - import settings # Assumed to be in the same directory. -except ImportError: - import sys - sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__) - sys.exit(1) - -if __name__ == "__main__": - execute_manager(settings) diff --git a/csesoc/murder/__init__.py b/csesoc/murder/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/murder/admin.py b/csesoc/murder/admin.py deleted file mode 100644 index 4269392..0000000 --- a/csesoc/murder/admin.py +++ /dev/null @@ -1,51 +0,0 @@ -from django.contrib import admin -from django import forms -from csesoc.murder.models import * -from django.db.models import Q - -class GamePlayerInline(admin.StackedInline): - model = GamePlayer - extra = 5 - -class GameAdmin(admin.ModelAdmin): - inlines = (GamePlayerInline,) - exclude = ('slug',) - -class KillAdmin(admin.ModelAdmin): - fields = ('round','killer') - -# custom validation to stop 2 rounds occuring at once - -# ASCII art to describe the 4 different clash cases: -# stars are the round being created, dashed rounds clash (a,b,c,d) -# ******************** -# --a-- --b-- --c-- -# -------------d-------------- - -class MyRoundAdminForm(forms.ModelForm): - class Meta: - model = Round - def clean(self): # called after standard field validation - cleaned_data = self.cleaned_data - start = cleaned_data.get("start") - end = cleaned_data.get("end") - if cmp(start,end) >= 0: - raise forms.ValidationError("A round must end after it beings") - q = Q(start__lte=start, end__gte=start) | Q(start__gte=start, end__lte=end) | Q(start__lte=end, end__gte=end) | Q(start__lte=start, end__gte=end) - clashes = Round.objects.filter(q) - if clashes: - raise forms.ValidationError("Clash with existing round(s): " + unicode(clashes)) - return cleaned_data - -class RoundAdmin(admin.ModelAdmin): - form = MyRoundAdminForm - -admin.site.register(Player) -admin.site.register(Password) -admin.site.register(Quip) -admin.site.register(Game, GameAdmin) -admin.site.register(Round, RoundAdmin) -#admin.site.register(GamePlayer) -admin.site.register(RoundPlayer) -admin.site.register(Kill, KillAdmin) - diff --git a/csesoc/murder/import_players.py b/csesoc/murder/import_players.py deleted file mode 100755 index 9244d6c..0000000 --- a/csesoc/murder/import_players.py +++ /dev/null @@ -1,46 +0,0 @@ -#!/usr/bin/python -# Begin dirty path hack -import os -from os import path -import sys -baseDir = path.abspath(path.split(sys.argv[0])[0] + '/../..') -print baseDir -sys.path.insert(0, baseDir) -# end dirty path hack -from csesoc import set_path -set_path.update_path() - -from django.core.management import setup_environ -import settings - -setup_environ(settings) - -from csesoc.murder.models import * - -from glob import glob -from shutil import copy - -if len(sys.argv) != 2: - print 'Usage: %s image_dir_path/' % (sys.argv[0]) - sys.exit(1) - -photoLoc = Player._meta.get_field('photo').upload_to -photoDir = settings.MEDIA_ROOT + '/' + photoLoc -print "Importing to: " + photoDir - -allowedExt = ['.jpg', '.gif'] - -g = Game.objects.filter(name="2010 Session 1")[0] - -for image in glob(sys.argv[1] + "*"): - fileName = path.split(image)[1] - data = path.splitext(fileName) - if data[1] in allowedExt: - if Player.objects.filter(username=data[0]).count() == 0: - print 'Adding: ' + data[0] - temp = photoLoc + '/' + fileName - p = Player(username=data[0], photo=temp) - p.save() - gp = GamePlayer(player=p,game=g) - gp.save() - copy(image, photoDir) diff --git a/csesoc/murder/models.py b/csesoc/murder/models.py deleted file mode 100644 index 7bfbe41..0000000 --- a/csesoc/murder/models.py +++ /dev/null @@ -1,134 +0,0 @@ -from django.db import models -from django.template.loader import render_to_string -from django.template.defaultfilters import slugify -from django.contrib.auth.models import User -from django.db.models.signals import post_save -from django.core.mail import send_mail - -class Password(models.Model): - text = models.CharField(max_length=30) - def __unicode__(self): - return self.text - -class Quip(models.Model): - text = models.CharField(max_length=512) - def __unicode__(self): - return self.text - -class Player(models.Model): - username = models.CharField(max_length=30, help_text='CSE username for CSE students, student ID for others') - photo = models.ImageField(upload_to='photos', help_text='Crop and resize to < 800x600 before uploading') - email = models.EmailField(help_text='Defaults to @cse.unsw.edu.au. Override for non-cse students', blank=True) - - def save(self, force_insert=False, force_update=False): - if not self.email: - self.email = self.username + "@cse.unsw.edu.au" - super(Player, self).save(force_insert, force_update) # Call the "real" save() method. - - def __unicode__(self): - return self.username - -class Game(models.Model): - name = models.CharField(max_length=200) - slug = models.SlugField() - allow_late_entries = models.BooleanField(default=True, help_text='If true, players can join the game at any time, and will be assigned a victim at the start of the next round') - players = models.ManyToManyField(Player, through='GamePlayer') - start_day = models.DateField(help_text='The first day of the Game; for keeping track of which week we are on.') - last_day = models.DateField(help_text='The last day, of the last week, of the Game; for keeping track of when to end the game.') - - def save(self, force_insert=False, force_update=False): - self.slug = slugify(self.name) - super(Game, self).save(force_insert, force_update) - - def __unicode__(self): - return self.name - -class Round(models.Model): - name = models.CharField(max_length=100) - game = models.ForeignKey(Game) - start = models.DateTimeField() - end = models.DateTimeField() - - def save(self, force_insert=False, force_update=False): - # Call the "real" save() method first - super(Round, self).save(force_insert, force_update) - - # Generate 'ring of death', and update user accounts - roundplayers = list(self.game.players.order_by('?')) - for i in range(len(roundplayers)): - rp = RoundPlayer(player=roundplayers[i], startvictim=roundplayers[i-1], - currentvictim=roundplayers[i-1],round=self, - password=Password.objects.order_by('?')[0]) - rp.save() - - try: - u = User.objects.get(username=rp.player.username) - u.set_password(rp.password) - u.save() - - except User.DoesNotExist: - u = User.objects.create_user(rp.player.username, rp.player.email, rp.password) - u.save() - - def __unicode__(self): - return "running from " + unicode(self.start) + " to " + unicode(self.end) + " in game '" + unicode(self.game) + "'" - - -class GamePlayer(models.Model): - player = models.ForeignKey(Player) - game = models.ForeignKey(Game) - date_joined = models.DateTimeField(auto_now_add=True) - def __unicode__(self): - return unicode(self.player) + " joined '" + unicode(self.game) + "' on " + unicode(self.date_joined) - -class RoundPlayer(models.Model): - player = models.ForeignKey(Player) - startvictim = models.ForeignKey(Player, related_name='roundvictims_set') - currentvictim = models.ForeignKey(Player, related_name='currentvictims_set') - alive = models.BooleanField(default=True) - password = models.ForeignKey(Password) - round = models.ForeignKey(Round) - def __unicode__(self): - return unicode(self.player) + " -> " + unicode(self.startvictim)+ " in round " + unicode(self.round) - - -class Kill(models.Model): - round = models.ForeignKey(Round) - killer = models.ForeignKey(Player, related_name='killers_set') - victim = models.ForeignKey(Player, related_name='victims_set') - datetime = models.DateTimeField(auto_now_add=True) - quip = models.ForeignKey(Quip) - - def save(self, force_insert=False, force_update=False): - # derive other fields from round & killer - killer_rp = RoundPlayer.objects.get(player=self.killer, round=self.round) - self.victim = killer_rp.currentvictim - victim_rp = RoundPlayer.objects.get(player=self.victim, round=self.round) - killer_rp.currentvictim = victim_rp.currentvictim - self.quip = Quip.objects.order_by('?')[0] - victim_rp.alive = False - killer_rp.save() - victim_rp.save() - - # Call the "real" save() method - super(Kill, self).save(force_insert, force_update) - - def expandquip(self): - return unicode(self.quip).replace('!killer!', unicode(self.killer)).replace('!victim!',unicode(self.victim)) - - def __unicode__(self): - return "round: %s\nkiller: %s\nvictim: %s\ndatetime: %s\nquip: %s" % ( - unicode(self.round), unicode(self.killer), unicode(self.victim), - unicode(self.datetime), unicode(self.quip) - ) - - -def emailRoundPlayer(sender, **kwargs): - if kwargs['created']: - instance = kwargs['instance'] - # only send email on new RoundPlayer instances, not on every kill - message = render_to_string('email/newround.txt', {'rp':instance}) - send_mail('Welcome to Murder@CSE. Semester 1 2010', message, 'csesoc.murder@cse.unsw.edu.au', [instance.player.email], fail_silently=False) - -post_save.connect(emailRoundPlayer, sender=RoundPlayer) - diff --git a/csesoc/murder/new_week.py b/csesoc/murder/new_week.py deleted file mode 100755 index 43e0e8e..0000000 --- a/csesoc/murder/new_week.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/python -# Begin dirty path hack -import os -from os import path -import sys -baseDir = path.abspath(path.split(sys.argv[0])[0] + '/../..') -print baseDir -sys.path.insert(0, baseDir) -# end dirty path hack -from csesoc import set_path -set_path.update_path() - -from django.core.management import setup_environ -from datetime import date, datetime, timedelta -from django.conf import settings - -setup_environ(settings) - -from csesoc.murder.models import * - -# These change per session -gameName = '2012 Session 1' - -# start_day <= today <= last_day -currentGames = Game.objects.filter(start_day__lte=date.today()).filter(last_day__gte=date.today()) -if currentGames.count() > 0: - # there should only be one game but get game 0 just in case - currentGame = currentGames[0] - difference = date.today() - currentGame.start_day - roundname = "Week %d" % (difference.days / 7) - - # Set the round start and end dates - roundlength = timedelta(days=7) - timedelta(minutes=20) - startdate = datetime.now() - enddate = startdate + roundlength - - r = Round(name=roundname, start=startdate, end=enddate, game=currentGame) - r.save() - diff --git a/csesoc/murder/passwords.txt b/csesoc/murder/passwords.txt deleted file mode 100644 index 9bb3358..0000000 --- a/csesoc/murder/passwords.txt +++ /dev/null @@ -1,10 +0,0 @@ -aborted -academic -accessing -account -accumulator -accustomed -acolyte -action -actively -actual diff --git a/csesoc/murder/quips.txt b/csesoc/murder/quips.txt deleted file mode 100644 index f9bf4d8..0000000 --- a/csesoc/murder/quips.txt +++ /dev/null @@ -1,72 +0,0 @@ -!victim! was strangled with a noodle by !killer! -!killer! pickled !victim! alive -!killer! hugged !victim! to death -!killer! tied an extra long bungie rope to !victim!, then tossed !victim! of the top of the UNSW Library -!killer! beat !victim! to death with a bottle of fish sauce -!killer! considered poisoning !victim! but just fed them late afternoon union food -!killer! spaded !victim! to death -!killer! fed !victim! to a flock of starving college students -!killer! crumpled !victim! under a pile of law textbooks -!killer! gave !victim! love and war to read and !victim! died of old age -!killer! stole !victim!'s brain for later use -!killer! poisoned !victim! by feeding them left over Yum-cha -!killer! flattened !victim! with stale kegs of beer -!killer! over fed !victim! sausages at a CSESoc BBQ -!killer! pushed !victim! out of the mysterious doors on the 14th floor of the library -!killer! took !victim! to the mysterious university club and he was never seen again -!killer! handed !victim! a bomb in an apple cake -!victim! was offered a "ride" in !killer!'s car home, is now missing and presumed dead. -!killer! fed !victim! left over college food -!killer! used !victim! as a dart board -!victim! was made to do a on the spot practical exam by !killer! and didn't make it through -!killer! took !victim! to the top of a mountain, giving him a copper nose ring and a sword, stood him in a copper bathtub and made them scream "all gods are bastards!" -!killer! gave !victim! two free tickets for a ride on the titanic -!killer! thwacked !victim! with a clue, it was a mess -!victim! saw !killer! and died with fright -!killer! brainwashed !victim! into believing he was Bill Gates and pointed him to the Linux support office -!victim! was unfortunately chopped in half by !killer! during a impromptu magic trick -!killer! murdered !victim!, more disgusting details on the 6pm news :| -!killer! electrocuted !victim! with a mini MP3 player -!killer! annoyed !victim! to death with mobile phone rings -!victim! found dead after a rumoured clandestine meeting with !killer! -!killer! and !victim! went out for dinner together, !victim! died of poison. -!killer! follows !victim! into the kitchen and clubs !victim! with a lead pipe. -!killer! puts excessive horse tranquilsers in !victim!'s drink -!killer! gives !victim! doctored estacy pills and !victim! dies on the dance floor. -!killer! attempted to remove leeches from !victim!'s feet using tweezers. !victim! didn't make it. -!victim! was pushed in front of one of those maniac buses on anzac parade by !killer! -!victim! was pwned by !killer!'s panzerfaust -!killer! FFE'd on !victim!'s position -!victim! was killed by !killer!'s landmine -!victim! was knifed by the covert !killer! -!victim! was exploded by !killer!'s dynamite -!victim! was snipped by !killer!'s garand -!killer! sent !victim! to /dev/null -!victim! was ironed by !killer!'s HOT stolen Holden Astra Classic -!victim! ear drums wear blown away by the grunt of !killer!'s stolen Toyota Corolla -!victim! was blinded and smashed by !killer!'s shiny Subaru Impreza -!killer! dropped an anvil on !victim! -!killer! used a time machine to travel to the Middle Ages causing !victim!'s head to reform inside their ^_^... -!killer! burnt !victim! with him flamethrower -!killer! shot !victim! with an assault rilfe -!killer! shot !victim! with a semi-automatic hand granade, wat the? -!killer! came out ahead against !victim!in the 1vs1 sniper challenge -!victim! was shot out a cannon into a brick wall by !killer! -!killer! stuffed a flamethrower up !victim!'s ^_^ and turned it on -OMG !killer! killed Kenny, or was it !victim!, well both are dead now -!victim! could not handle the constant n00b questions of !killer! and commited suicide -!victim! was overwhelmed with the l33t speak of !killer! and commited suicide -!victim! was bored to death by !killer!'s code style guide -!victim! was confused to death by !killer! -!victim! found the password to the murder system and was burnt alive by both the admin and !killer! -!killer! hacked weill to get extra disk quota and blamed !victim!, and so !victim! was hung by ss -!victim! was frozen in oud by !killer! -!victim! was cooked alive in moog by !killer! -!victim!'s ear drums were blown by !killer!'s stolen Hyundai Getz and its beasty subwoofer -!killer! unleashed the ultimate 'yo mum' joke on !victim! -!killer! became a zombie just for the pleasure of devouring !victim! himself -!killer! caught !victim! wearing womens clothing...and liking it...then a can of whoopass opened -!killer! dereferenced a NULL pointer in !victims! brain -!victim! was incased in glue then peeled by !killer! -!victim! was deep fryed by !killer! then served as an entree -!killer! beat !victim! to death with spare change diff --git a/csesoc/murder/tests.py b/csesoc/murder/tests.py deleted file mode 100644 index 2247054..0000000 --- a/csesoc/murder/tests.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - -from django.test import TestCase - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) - -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -"""} - diff --git a/csesoc/murder/urls.py b/csesoc/murder/urls.py deleted file mode 100644 index 5b684fe..0000000 --- a/csesoc/murder/urls.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.conf.urls.defaults import * -from django.conf import settings -from csesoc.murder.views import * - -# Uncomment the next two lines to enable the admin: - -urlpatterns = patterns('', - # URLs for murder applcation - (r'^$', gamelist), - (r'^(?P[^/]*)/$', index), - (r'^(?P[^/]*)/scoreboard/$', scoreboard), - (r'^(?P[^/]*)/kills/$', newkills), - (r'^(?P[^/]*)/kills/(?P\d+)/$', roundkills), - (r'^(?P[^/]*)/myvictim/$', myvictim), -) - diff --git a/csesoc/murder/views.py b/csesoc/murder/views.py deleted file mode 100644 index c816a4e..0000000 --- a/csesoc/murder/views.py +++ /dev/null @@ -1,94 +0,0 @@ -from django.shortcuts import render_to_response -from csesoc.murder.models import * -from csesoc.sponsors.views import sponsorsList -from collections import defaultdict -from django.contrib.auth.decorators import login_required -from datetime import datetime -from django.contrib.auth import logout -from django import forms -from django.template import RequestContext - -def gamelist(request): - return render_to_response('games.html', RequestContext(request, { 'games': Game.objects.order_by('id'), 'allSponsors' : sponsorsList(request) })) - -def index(request, game): - try: - return render_to_response('index.html', RequestContext(request, { 'game': Game.objects.get(slug=game), 'allSponsors' : sponsorsList(request) })) - except Game.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'Invalid Game. Go Away!', 'allSponsors' : sponsorsList(request) })) - -def scoreboard(request, game): - try: - c = defaultdict(int) - gameo = Game.objects.get(slug=game) - total = 0 - for round in gameo.round_set.all(): - for kill in round.kill_set.all(): - c[kill.killer.username] += 1 - total += 1 - counts = sorted(c.iteritems(), key = lambda (k,v):(v,k), reverse=True) - return render_to_response('scoreboard.html', RequestContext(request, { 'game': gameo, 'counts': counts, 'total': total, 'allSponsors' : sponsorsList(request) })) - except Game.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'Invalid Game. Go Away!', 'allSponsors' : sponsorsList(request) })) - -def newkills(request, game): - try: - c = defaultdict(int) - gameo = Game.objects.get(slug=game) - kills = gameo.round_set.get(start__lt=datetime.now, end__gt=datetime.now()).kill_set.order_by('-datetime') - return render_to_response('newkills.html', RequestContext(request, { 'game': gameo, 'kills': kills, 'allSponsors' : sponsorsList(request) })) - - except Round.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'No Current Round. Go Away!', 'allSponsors' : sponsorsList(request) })) - except Game.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'Invalid Game. Go Away!', 'allSponsors' : sponsorsList(request) })) - -def roundkills(request, game, roundid): - return render_to_response('basic.html', RequestContext(request, { 'title':'roundkills', 'allSponsors' : sponsorsList(request) })) - -# form to kill victim -class KillForm(forms.Form): - password = forms.CharField(max_length=100) - -@login_required -def myvictim(request, game): - - try: - current_round = Game.objects.get(slug=game).round_set.get(start__lt=datetime.now, end__gt=datetime.now()) - - rp = current_round.roundplayer_set.get(player=Player.objects.get(username=request.user.username)) - - if not rp.alive: - return render_to_response('basic.html', RequestContext(request, { 'title':'You are DEAD. See you next week!', 'allSponsors' : sponsorsList(request) })) - - flash = '' - if request.method == 'POST': - form = KillForm(request.POST) - if form.is_valid(): - password = form.cleaned_data['password'] - if password == current_round.roundplayer_set.get(player=rp.currentvictim).password.text: - k = Kill(round=current_round, killer=rp.player) - k.save() - flash = 'Good Kill!' - rp = current_round.roundplayer_set.get(player=Player.objects.get(username=request.user.username)) - else: - flash = 'Wrong Password!' - else: - form = KillForm() - - return render_to_response('myvictim.html', - RequestContext(request, {'victim':rp.currentvictim, 'gameslug':game, 'flash':flash, 'form':form, 'allSponsors' : sponsorsList(request)})) - - except Round.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'No Current Round. Go Away!', 'allSponsors' : sponsorsList(request) })) - except Game.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'Invalid Game. Go Away!', 'allSponsors' : sponsorsList(request) })) - except RoundPlayer.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'You are not registered in this round. Go Away!', 'allSponsors' : sponsorsList(request) })) - except Player.DoesNotExist: - return render_to_response('basic.html', RequestContext(request, { 'title':'You are not registered in this game. Go Away!', 'allSponsors' : sponsorsList(request) })) - -def logout_game(request, game): - logout(request) - return index(request, game) - diff --git a/csesoc/music/__init__.py b/csesoc/music/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/music/admin.py b/csesoc/music/admin.py deleted file mode 100644 index 659b928..0000000 --- a/csesoc/music/admin.py +++ /dev/null @@ -1,19 +0,0 @@ -from django.contrib import admin -from csesoc.music.models import * - -class SongVoteInline(admin.StackedInline): - model = SongVote - extra = 1 - -class SongAdmin(admin.ModelAdmin): - list_display = ['title', 'artist', 'submitter', 'submitter_hassong'] - inlines = (SongVoteInline,) - search_fields = ["title", "artist", "submitter__username"] - -class SongVoteAdmin(admin.ModelAdmin): - list_display = ['amount', 'song', 'voter'] - search_fields = ["voter__username", "song__title", "song__artist", "amount"] - -admin.site.register(Song, SongAdmin) -admin.site.register(SongVote, SongVoteAdmin) - diff --git a/csesoc/music/models.py b/csesoc/music/models.py deleted file mode 100644 index 8fe321e..0000000 --- a/csesoc/music/models.py +++ /dev/null @@ -1,38 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User - -class Song(models.Model): - title = models.CharField(max_length=50, help_text='Title of song') - artist = models.CharField(max_length=50, help_text='Artist of song') - notes = models.TextField(max_length=200, help_text='Any notes?', blank=True, null=True) - submitter = models.ForeignKey(User) - submitter_hassong = models.BooleanField(help_text='Do you have this song') - - def vote(self, voter, voteAmt): - sv = SongVote.objects.filter(song=self, voter=voter) - if sv.count() > 0: - sv = sv[0] - else: - sv = SongVote(voter=voter, song=self) - - sv.amount = voteAmt - sv.save() - - def votes(self): - try: - from django.db.models import Sum - return int(self.songvote_set.aggregate(Sum('amount'))['amount__sum']) - except: - return 0 - - def __unicode__(self): - return self.artist + " - " + self.title - -class SongVote(models.Model): - voter = models.ForeignKey(User) - song = models.ForeignKey(Song) - amount = models.IntegerField(default=0) - - def __unicode__(self): - return str(self.amount) + " [" + self.voter.username + " for " + self.song.__unicode__() + "]" - diff --git a/csesoc/music/tests.py b/csesoc/music/tests.py deleted file mode 100644 index 2247054..0000000 --- a/csesoc/music/tests.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - -from django.test import TestCase - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) - -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -"""} - diff --git a/csesoc/music/views.py b/csesoc/music/views.py deleted file mode 100644 index 5310a38..0000000 --- a/csesoc/music/views.py +++ /dev/null @@ -1,110 +0,0 @@ -# Create your views here. -from django.template import RequestContext -from django.shortcuts import render_to_response -from django.shortcuts import get_object_or_404 -from django.contrib.auth.decorators import login_required -from django.http import HttpResponseRedirect, HttpResponse -from csesoc.music.models import * -from django.conf import settings -from django.template import Library - -# presently using generic views for everything. add custom views here as needed - -def getFinalList(user): - songs = Song.objects.all() - votes = SongVote.objects.filter(voter=user) - votesHash = {} - finalList = [] - for v in votes: - votesHash[v.song.id] = v.amount - for s in songs: - newS = {} - newS["song"] = s - newS["id"] = s.id - newS["votes"] = s.votes() - - if s.id in votesHash: - newS["vote"] = votesHash[s.id] - else: - newS["vote"] = 0 - - newS["states"] = calcVisibility(newS["vote"]) - finalList.append(newS) - - finalList = sorted(finalList, key=lambda a: a["id"], reverse=True) - return finalList - -@login_required -def music_submit_song(request): - if request.method == "POST": - # LOL CHECK - title = request.POST['title'] - artist = request.POST['artist'] - title = title.strip() - artist = artist.strip() - - notes = request.POST['notes'] if 'notes' in request.POST else "" - - songdetails = (artist + " - " + title) - existingSongs = Song.objects.filter(title__iexact=title, artist__iexact=artist) - if existingSongs.count() > 0: - existingSongs[0].vote(request.user, 1) - songdetails += " already exists! A vote" - return render_to_response('music.html', {'submitted': True, 'songdetails': songdetails, 'songs': getFinalList(request.user)}) - - if title == "" or artist == "": - return render_to_response('music.html', {'songs': getFinalList(request.user), 'submitted': False}) - - - if 'hassong' in request.POST: - hassong = "on" == request.POST['hassong'] - else: - hassong = False - - - # submit complete, show a little note, and display form again - s = Song(artist=artist, title=title, notes=notes, submitter_hassong=hassong, submitter=request.user) - s.save() - - s.vote(request.user, 1) - - return render_to_response('music.html', {'submitted': True, 'songdetails': songdetails, 'songs': getFinalList(request.user)}) - - else: - # yay submit a song template - return render_to_response('music.html', {'songs': getFinalList(request.user), 'submitted': False}) - -# returns a list for disabled state for up, none, and down -def calcVisibility(voteAmt): - res = [] - res.append(True if voteAmt > 0 else False) - res.append(True if voteAmt == 0 else False) - res.append(True if voteAmt < 0 else False) - return res - - -@login_required -def music_vote(request): - if request.method == "POST": - song_id = request.POST['song_id'] - vote = request.POST['vote'] - voteAmt = 0 - if vote == "up": - voteAmt = 1 - elif vote == "none": - voteAmt = 0 - else: - voteAmt = -1 - - # find the song - s = Song.objects.get(id=song_id) - u = request.user - s.vote(u, voteAmt) - - res = str(s.votes()) - for s in calcVisibility(voteAmt): - res += ";" + str(s) - - - return HttpResponse(res) - diff --git a/csesoc/paypal/README.md b/csesoc/paypal/README.md deleted file mode 100644 index a48229f..0000000 --- a/csesoc/paypal/README.md +++ /dev/null @@ -1,354 +0,0 @@ -Django PayPal -============= - - -About ------ - -Django PayPal is a pluggable application that implements with PayPal Payments -Standard and Payments Pro. - -Before diving in, a quick review of PayPal's payment methods is in order! [PayPal Payments Standard](https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_WebsitePaymentsStandard_IntegrationGuide.pdf) is the "Buy it Now" buttons you may have -seen floating around the internets. Buyers click on the button and are taken to PayPal's website where they can pay for the product. After completing the purchase PayPal makes an HTTP POST to your `notify_url`. PayPal calls this process [Instant Payment Notification](https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_OrderMgmt_IntegrationGuide.pdf) (IPN) but you may know it as [webhooks](http://blog.webhooks.org). This method kinda sucks because it drops your customers off at PayPal's website but it's easy to implement and doesn't require SSL. - -PayPal Payments Pro allows you to accept payments on your website. It contains two distinct payment flows - Direct Payment allows the user to enter credit card information on your website and pay on your website. Express Checkout sends the user over to PayPal to confirm their payment method before redirecting back to your website for confirmation. PayPal rules state that both methods must be implemented. - -There is currently an active discussion over the handling of some of the finer points of the PayPal API and the evolution of this code base - check it out over at [Django PayPal on Google Groups](http://groups.google.com/group/django-paypal). - - -Using PayPal Payments Standard IPN: -------------------------------- - -1. Download the code from GitHub: - - git clone git://github.com/johnboxall/django-paypal.git paypal - -1. Edit `settings.py` and add `paypal.standard.ipn` to your `INSTALLED_APPS` - and `PAYPAL_RECEIVER_EMAIL`: - - # settings.py - ... - INSTALLED_APPS = (... 'paypal.standard.ipn', ...) - ... - PAYPAL_RECEIVER_EMAIL = "yourpaypalemail@example.com" - -1. Create an instance of the `PayPalPaymentsForm` in the view where you would - like to collect money. Call `render` on the instance in your template to - write out the HTML. - - # views.py - ... - from paypal.standard.forms import PayPalPaymentsForm - - def view_that_asks_for_money(request): - - # What you want the button to do. - paypal_dict = { - "business": "yourpaypalemail@example.com", - "amount": "10000000.00", - "item_name": "name of the item", - "invoice": "unique-invoice-id", - "notify_url": "http://www.example.com/your-ipn-location/", - "return_url": "http://www.example.com/your-return-location/", - "cancel_return": "http://www.example.com/your-cancel-location/", - - } - - # Create the instance. - form = PayPalPaymentsForm(initial=paypal_dict) - context = {"form": form} - return render_to_response("payment.html", context) - - - - ... -

Show me the money!

- - {{ form.render }} - -1. When someone uses this button to buy something PayPal makes a HTTP POST to - your "notify_url". PayPal calls this Instant Payment Notification (IPN). - The view `paypal.standard.ipn.views.ipn` handles IPN processing. To set the - correct `notify_url` add the following to your `urls.py`: - - # urls.py - ... - urlpatterns = patterns('', - (r'^something/hard/to/guess/', include('paypal.standard.ipn.urls')), - ) - -1. Whenever an IPN is processed a signal will be sent with the result of the - transaction. Connect the signals to actions to perform the needed operations - when a successful payment is recieved. - - There are two signals for basic transactions: - - `payment_was_succesful` - - `payment_was_flagged` - - And four signals for subscriptions: - - `subscription_cancel` - Sent when a subscription is cancelled. - - `subscription_eot` - Sent when a subscription expires. - - `subscription_modify` - Sent when a subscription is modified. - - `subscription_signup` - Sent when a subscription is created. - - Connect to these signals and update your data accordingly. [Django Signals Documentation](http://docs.djangoproject.com/en/dev/topics/signals/). - - # models.py - ... - from paypal.standard.ipn.signals import payment_was_successful - - def show_me_the_money(sender, **kwargs): - ipn_obj = sender - # Undertake some action depending upon `ipn_obj`. - if ipn_obj.custom == "Upgrade all users!": - Users.objects.update(paid=True) - payment_was_successful.connect(show_me_the_money) - - -Using PayPal Payments Standard PDT: -------------------------------- - -Paypal Payment Data Transfer (PDT) allows you to display transaction details to a customer immediately on return to your site unlike PayPal IPN which may take some seconds. [You will need to enable PDT in your PayPal account to use it.your PayPal account to use it](https://cms.paypal.com/us/cgi-bin/?cmd=_render-content&content_ID=developer/howto_html_paymentdatatransfer). - -1. Download the code from GitHub: - - git clone git://github.com/johnboxall/django-paypal.git paypal - -1. Edit `settings.py` and add `paypal.standard.pdt` to your `INSTALLED_APPS`. Also set `PAYPAL_IDENTITY_TOKEN` - you can find the correct value of this setting from the PayPal website: - - # settings.py - ... - INSTALLED_APPS = (... 'paypal.standard.pdt', ...) - - PAYPAL_IDENTITY_TOKEN = "xxx" - -1. Create a view that uses `PayPalPaymentsForm` just like in PayPal IPN. - -1. After someone uses this button to buy something PayPal will return the user to your site at - your "return_url" with some extra GET parameters. PayPal calls this Payment Data Transfer (PDT). - The view `paypal.standard.pdt.views.pdt` handles PDT processing. to specify the correct - `return_url` add the following to your `urls.py`: - - # urls.py - ... - urlpatterns = patterns('', - (r'^paypal/pdt/', include('paypal.standard.pdt.urls')), - ... - ) - -Using PayPal Payments Standard with Subscriptions: -------------------------------- - -1. For subscription actions, you'll need to add a parameter to tell it to use the subscription buttons and the command, plus any - subscription-specific settings: - - # views.py - ... - paypal_dict = { - "cmd": "_xclick-subscriptions", - "business": "your_account@paypal", - "a3": "9.99", # monthly price - "p3": 1, # duration of each unit (depends on unit) - "t3": "M", # duration unit ("M for Month") - "src": "1", # make payments recur - "sra": "1", # reattempt payment on payment error - "no_note": "1", # remove extra notes (optional) - "item_name": "my cool subscription", - "notify_url": "http://www.example.com/your-ipn-location/", - "return_url": "http://www.example.com/your-return-location/", - "cancel_return": "http://www.example.com/your-cancel-location/", - } - - # Create the instance. - form = PayPalPaymentsForm(initial=paypal_dict, button_type="subscribe") - - # Output the button. - form.render() - - -Using PayPal Payments Standard with Encrypted Buttons: ------------------------------------------------------- - -Use this method to encrypt your button so sneaky gits don't try to hack it. Thanks to [Jon Atkinson](http://jonatkinson.co.uk/) for the [tutorial](http://jonatkinson.co.uk/paypal-encrypted-buttons-django/). - -1. Encrypted buttons require the `M2Crypto` library: - - easy_install M2Crypto - - -1. Encrypted buttons require certificates. Create a private key: - - openssl genrsa -out paypal.pem 1024 - -1. Create a public key: - - openssl req -new -key paypal.pem -x509 -days 365 -out pubpaypal.pem - -1. Upload your public key to the paypal website (sandbox or live). - - [https://www.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert](https://www.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert) - - [https://www.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert](https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_profile-website-cert) - -1. Copy your `cert id` - you'll need it in two steps. It's on the screen where - you uploaded your public key. - -1. Download PayPal's public certificate - it's also on that screen. - -1. Edit your `settings.py` to include cert information: - - # settings.py - PAYPAL_PRIVATE_CERT = '/path/to/paypal.pem' - PAYPAL_PUBLIC_CERT = '/path/to/pubpaypal.pem' - PAYPAL_CERT = '/path/to/paypal_cert.pem' - PAYPAL_CERT_ID = 'get-from-paypal-website' - -1. Swap out your unencrypted button for a `PayPalEncryptedPaymentsForm`: - - # views.py - from paypal.standard.forms import PayPalEncryptedPaymentsForm - - def view_that_asks_for_money(request): - ... - # Create the instance. - form = PayPalPaymentsForm(initial=paypal_dict) - # Works just like before! - form.render() - - -Using PayPal Payments Standard with Encrypted Buttons and Shared Secrets: -------------------------------------------------------------------------- - -This method uses Shared secrets instead of IPN postback to verify that transactions -are legit. PayPal recommends you should use Shared Secrets if: - - * You are not using a shared website hosting service. - * You have enabled SSL on your web server. - * You are using Encrypted Website Payments. - * You use the notify_url variable on each individual payment transaction. - -Use postbacks for validation if: - * You rely on a shared website hosting service - * You do not have SSL enabled on your web server - -1. Swap out your button for a `PayPalSharedSecretEncryptedPaymentsForm`: - - # views.py - from paypal.standard.forms import PayPalSharedSecretEncryptedPaymentsForm - - def view_that_asks_for_money(request): - ... - # Create the instance. - form = PayPalSharedSecretEncryptedPaymentsForm(initial=paypal_dict) - # Works just like before! - form.render() - -1. Verify that your IPN endpoint is running on SSL - `request.is_secure()` should return `True`! - - -Using PayPal Payments Pro (WPP) -------------------------------- - -WPP is the more awesome version of PayPal that lets you accept payments on your -site. WPP reuses code from `paypal.standard` so you'll need to include both -apps. [There is an explanation of WPP in the PayPal Forums](http://www.pdncommunity.com/pdn/board/message?board.id=wppro&thread.id=192). - - -1. Edit `settings.py` and add `paypal.standard` and `paypal.pro` to your - `INSTALLED_APPS`, also set your PayPal settings: - - # settings.py - ... - INSTALLED_APPS = (... 'paypal.standard', 'paypal.pro', ...) - PAYPAL_TEST = True # Testing mode on - PAYPAL_WPP_USER = "???" # Get from PayPal - PAYPAL_WPP_PASSWORD = "???" - PAYPAL_WPP_SIGNATURE = "???" - -1. Run `python manage.py syncdb` to add the required tables. - -1. Write a wrapper view for `paypal.pro.views.PayPalPro`: - - # views.py - from paypal.pro.views import PayPalPro - - def buy_my_item(request): - item = {"amt": "10.00", # amount to charge for item - "inv": "inventory", # unique tracking variable paypal - "custom": "tracking", # custom tracking variable for you - "cancelurl": "http://...", # Express checkout cancel url - "returnurl": "http://..."} # Express checkout return url - - kw = {"item": item, # what you're selling - "payment_template": "payment.html", # template name for payment - "confirm_template": "confirmation.html", # template name for confirmation - "success_url": "/success/"} # redirect location after success - - ppp = PayPalPro(**kw) - return ppp(request) - - -1. Create templates for payment and confirmation. By default both templates are - populated with the context variable `form` which contains either a - `PaymentForm` or a `Confirmation` form. - - -

Show me the money

-
- {{ form }} - -
- - -

Are you sure you want to buy this thing?

-
- {{ form }} - -
- -1. Add your view to `urls.py`, and add the IPN endpoint to receive callbacks - from PayPal: - - # urls.py - ... - urlpatterns = ('', - ... - (r'^payment-url/$', 'myproject.views.buy_my_item') - (r'^some/obscure/name/', include('paypal.standard.ipn.urls')), - ) - -1. Profit. - - -Links: ------- - -1. [Set your IPN Endpoint on the PayPal Sandbox](https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_profile-ipn-notify) - -2. [Django PayPal on Google Groups](http://groups.google.com/group/django-paypal) - -License (MIT) -============= - -Copyright (c) 2009 Handi Mobility Inc. - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/csesoc/paypal/__init__.py b/csesoc/paypal/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/paypal/pro/__init__.py b/csesoc/paypal/pro/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/paypal/pro/admin.py b/csesoc/paypal/pro/admin.py deleted file mode 100644 index 1fecc56..0000000 --- a/csesoc/paypal/pro/admin.py +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from string import split as L -from django.contrib import admin -from paypal.pro.models import PayPalNVP - - -class PayPalNVPAdmin(admin.ModelAdmin): - list_display = L("user method flag flag_code created_at") -admin.site.register(PayPalNVP, PayPalNVPAdmin) diff --git a/csesoc/paypal/pro/creditcard.py b/csesoc/paypal/pro/creditcard.py deleted file mode 100644 index ed31b9a..0000000 --- a/csesoc/paypal/pro/creditcard.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -""" -Adapted from: - - http://www.djangosnippets.org/snippets/764/ - - http://www.satchmoproject.com/trac/browser/satchmo/trunk/satchmo/apps/satchmo_utils/views.py - - http://tinyurl.com/shoppify-credit-cards -""" -import re - - -# Well known card regular expressions. -CARDS = { - 'Visa': re.compile(r"^4\d{12}(\d{3})?$"), - 'Mastercard': re.compile(r"(5[1-5]\d{4}|677189)\d{10}$"), - 'Dinersclub': re.compile(r"^3(0[0-5]|[68]\d)\d{11}"), - 'Amex': re.compile("^3[47]\d{13}$"), - 'Discover': re.compile("^(6011|65\d{2})\d{12}$"), -} - -# Well known test numbers -TEST_NUMBERS = [ - "378282246310005", "371449635398431", "378734493671000", "30569309025904", - "38520000023237", "6011111111111117", "6011000990139424", "555555555554444", - "5105105105105100", "4111111111111111", "4012888888881881", "4222222222222" -] - -def verify_credit_card(number): - """Returns the card type for given card number or None if invalid.""" - return CreditCard(number).verify() - -class CreditCard(object): - def __init__(self, number): - self.number = number - - def is_number(self): - """True if there is at least one digit in number.""" - self.number = re.sub(r'[^\d]', '', self.number) - return self.number.isdigit() - - def is_mod10(self): - """Returns True if number is valid according to mod10.""" - double = 0 - total = 0 - for i in range(len(self.number) - 1, -1, -1): - for c in str((double + 1) * int(self.number[i])): - total = total + int(c) - double = (double + 1) % 2 - return (total % 10) == 0 - - def is_test(self): - """Returns True if number is a test card number.""" - return self.number in TEST_NUMBERS - - def get_type(self): - """Return the type if it matches one of the cards.""" - for card, pattern in CARDS.iteritems(): - if pattern.match(self.number): - return card - return None - - def verify(self): - """Returns the card type if valid else None.""" - if self.is_number() and not self.is_test() and self.is_mod10(): - return self.get_type() - return None \ No newline at end of file diff --git a/csesoc/paypal/pro/fields.py b/csesoc/paypal/pro/fields.py deleted file mode 100644 index d9dd9d4..0000000 --- a/csesoc/paypal/pro/fields.py +++ /dev/null @@ -1,339 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from calendar import monthrange -from datetime import date - -from django.db import models -from django import forms -from django.utils.translation import ugettext as _ - -from paypal.pro.creditcard import verify_credit_card - - -class CreditCardField(forms.CharField): - """Form field for checking out a credit card.""" - def __init__(self, *args, **kwargs): - kwargs.setdefault('max_length', 20) - super(CreditCardField, self).__init__(*args, **kwargs) - - def clean(self, value): - """Raises a ValidationError if the card is not valid and stashes card type.""" - self.card_type = verify_credit_card(value) - if self.card_type is None: - raise forms.ValidationError("Invalid credit card number.") - return value - - -# Credit Card Expiry Fields from: -# http://www.djangosnippets.org/snippets/907/ -class CreditCardExpiryWidget(forms.MultiWidget): - """MultiWidget for representing credit card expiry date.""" - def decompress(self, value): - if value: - return [value.month, value.year] - else: - return [None, None] - - def format_output(self, rendered_widgets): - html = u' / '.join(rendered_widgets) - return u'%s' % html - -class CreditCardExpiryField(forms.MultiValueField): - EXP_MONTH = [(x, x) for x in xrange(1, 13)] - EXP_YEAR = [(x, x) for x in xrange(date.today().year, date.today().year + 15)] - - default_error_messages = { - 'invalid_month': u'Enter a valid month.', - 'invalid_year': u'Enter a valid year.', - } - - def __init__(self, *args, **kwargs): - errors = self.default_error_messages.copy() - if 'error_messages' in kwargs: - errors.update(kwargs['error_messages']) - - fields = ( - forms.ChoiceField(choices=self.EXP_MONTH, error_messages={'invalid': errors['invalid_month']}), - forms.ChoiceField(choices=self.EXP_YEAR, error_messages={'invalid': errors['invalid_year']}), - ) - - super(CreditCardExpiryField, self).__init__(fields, *args, **kwargs) - self.widget = CreditCardExpiryWidget(widgets=[fields[0].widget, fields[1].widget]) - - def clean(self, value): - exp = super(CreditCardExpiryField, self).clean(value) - if date.today() > exp: - raise forms.ValidationError("The expiration date you entered is in the past.") - return exp - - def compress(self, data_list): - if data_list: - if data_list[1] in forms.fields.EMPTY_VALUES: - error = self.error_messages['invalid_year'] - raise forms.ValidationError(error) - if data_list[0] in forms.fields.EMPTY_VALUES: - error = self.error_messages['invalid_month'] - raise forms.ValidationError(error) - year = int(data_list[1]) - month = int(data_list[0]) - # find last day of the month - day = monthrange(year, month)[1] - return date(year, month, day) - return None - - -class CreditCardCVV2Field(forms.CharField): - def __init__(self, *args, **kwargs): - kwargs.setdefault('max_length', 4) - super(CreditCardCVV2Field, self).__init__(*args, **kwargs) - - -# Country Field from: -# http://www.djangosnippets.org/snippets/494/ -# http://xml.coverpages.org/country3166.html -COUNTRIES = ( - ('US', _('United States of America')), - ('CA', _('Canada')), - ('AD', _('Andorra')), - ('AE', _('United Arab Emirates')), - ('AF', _('Afghanistan')), - ('AG', _('Antigua & Barbuda')), - ('AI', _('Anguilla')), - ('AL', _('Albania')), - ('AM', _('Armenia')), - ('AN', _('Netherlands Antilles')), - ('AO', _('Angola')), - ('AQ', _('Antarctica')), - ('AR', _('Argentina')), - ('AS', _('American Samoa')), - ('AT', _('Austria')), - ('AU', _('Australia')), - ('AW', _('Aruba')), - ('AZ', _('Azerbaijan')), - ('BA', _('Bosnia and Herzegovina')), - ('BB', _('Barbados')), - ('BD', _('Bangladesh')), - ('BE', _('Belgium')), - ('BF', _('Burkina Faso')), - ('BG', _('Bulgaria')), - ('BH', _('Bahrain')), - ('BI', _('Burundi')), - ('BJ', _('Benin')), - ('BM', _('Bermuda')), - ('BN', _('Brunei Darussalam')), - ('BO', _('Bolivia')), - ('BR', _('Brazil')), - ('BS', _('Bahama')), - ('BT', _('Bhutan')), - ('BV', _('Bouvet Island')), - ('BW', _('Botswana')), - ('BY', _('Belarus')), - ('BZ', _('Belize')), - ('CC', _('Cocos (Keeling) Islands')), - ('CF', _('Central African Republic')), - ('CG', _('Congo')), - ('CH', _('Switzerland')), - ('CI', _('Ivory Coast')), - ('CK', _('Cook Iislands')), - ('CL', _('Chile')), - ('CM', _('Cameroon')), - ('CN', _('China')), - ('CO', _('Colombia')), - ('CR', _('Costa Rica')), - ('CU', _('Cuba')), - ('CV', _('Cape Verde')), - ('CX', _('Christmas Island')), - ('CY', _('Cyprus')), - ('CZ', _('Czech Republic')), - ('DE', _('Germany')), - ('DJ', _('Djibouti')), - ('DK', _('Denmark')), - ('DM', _('Dominica')), - ('DO', _('Dominican Republic')), - ('DZ', _('Algeria')), - ('EC', _('Ecuador')), - ('EE', _('Estonia')), - ('EG', _('Egypt')), - ('EH', _('Western Sahara')), - ('ER', _('Eritrea')), - ('ES', _('Spain')), - ('ET', _('Ethiopia')), - ('FI', _('Finland')), - ('FJ', _('Fiji')), - ('FK', _('Falkland Islands (Malvinas)')), - ('FM', _('Micronesia')), - ('FO', _('Faroe Islands')), - ('FR', _('France')), - ('FX', _('France, Metropolitan')), - ('GA', _('Gabon')), - ('GB', _('United Kingdom (Great Britain)')), - ('GD', _('Grenada')), - ('GE', _('Georgia')), - ('GF', _('French Guiana')), - ('GH', _('Ghana')), - ('GI', _('Gibraltar')), - ('GL', _('Greenland')), - ('GM', _('Gambia')), - ('GN', _('Guinea')), - ('GP', _('Guadeloupe')), - ('GQ', _('Equatorial Guinea')), - ('GR', _('Greece')), - ('GS', _('South Georgia and the South Sandwich Islands')), - ('GT', _('Guatemala')), - ('GU', _('Guam')), - ('GW', _('Guinea-Bissau')), - ('GY', _('Guyana')), - ('HK', _('Hong Kong')), - ('HM', _('Heard & McDonald Islands')), - ('HN', _('Honduras')), - ('HR', _('Croatia')), - ('HT', _('Haiti')), - ('HU', _('Hungary')), - ('ID', _('Indonesia')), - ('IE', _('Ireland')), - ('IL', _('Israel')), - ('IN', _('India')), - ('IO', _('British Indian Ocean Territory')), - ('IQ', _('Iraq')), - ('IR', _('Islamic Republic of Iran')), - ('IS', _('Iceland')), - ('IT', _('Italy')), - ('JM', _('Jamaica')), - ('JO', _('Jordan')), - ('JP', _('Japan')), - ('KE', _('Kenya')), - ('KG', _('Kyrgyzstan')), - ('KH', _('Cambodia')), - ('KI', _('Kiribati')), - ('KM', _('Comoros')), - ('KN', _('St. Kitts and Nevis')), - ('KP', _('Korea, Democratic People\'s Republic of')), - ('KR', _('Korea, Republic of')), - ('KW', _('Kuwait')), - ('KY', _('Cayman Islands')), - ('KZ', _('Kazakhstan')), - ('LA', _('Lao People\'s Democratic Republic')), - ('LB', _('Lebanon')), - ('LC', _('Saint Lucia')), - ('LI', _('Liechtenstein')), - ('LK', _('Sri Lanka')), - ('LR', _('Liberia')), - ('LS', _('Lesotho')), - ('LT', _('Lithuania')), - ('LU', _('Luxembourg')), - ('LV', _('Latvia')), - ('LY', _('Libyan Arab Jamahiriya')), - ('MA', _('Morocco')), - ('MC', _('Monaco')), - ('MD', _('Moldova, Republic of')), - ('MG', _('Madagascar')), - ('MH', _('Marshall Islands')), - ('ML', _('Mali')), - ('MN', _('Mongolia')), - ('MM', _('Myanmar')), - ('MO', _('Macau')), - ('MP', _('Northern Mariana Islands')), - ('MQ', _('Martinique')), - ('MR', _('Mauritania')), - ('MS', _('Monserrat')), - ('MT', _('Malta')), - ('MU', _('Mauritius')), - ('MV', _('Maldives')), - ('MW', _('Malawi')), - ('MX', _('Mexico')), - ('MY', _('Malaysia')), - ('MZ', _('Mozambique')), - ('NA', _('Namibia')), - ('NC', _('New Caledonia')), - ('NE', _('Niger')), - ('NF', _('Norfolk Island')), - ('NG', _('Nigeria')), - ('NI', _('Nicaragua')), - ('NL', _('Netherlands')), - ('NO', _('Norway')), - ('NP', _('Nepal')), - ('NR', _('Nauru')), - ('NU', _('Niue')), - ('NZ', _('New Zealand')), - ('OM', _('Oman')), - ('PA', _('Panama')), - ('PE', _('Peru')), - ('PF', _('French Polynesia')), - ('PG', _('Papua New Guinea')), - ('PH', _('Philippines')), - ('PK', _('Pakistan')), - ('PL', _('Poland')), - ('PM', _('St. Pierre & Miquelon')), - ('PN', _('Pitcairn')), - ('PR', _('Puerto Rico')), - ('PT', _('Portugal')), - ('PW', _('Palau')), - ('PY', _('Paraguay')), - ('QA', _('Qatar')), - ('RE', _('Reunion')), - ('RO', _('Romania')), - ('RU', _('Russian Federation')), - ('RW', _('Rwanda')), - ('SA', _('Saudi Arabia')), - ('SB', _('Solomon Islands')), - ('SC', _('Seychelles')), - ('SD', _('Sudan')), - ('SE', _('Sweden')), - ('SG', _('Singapore')), - ('SH', _('St. Helena')), - ('SI', _('Slovenia')), - ('SJ', _('Svalbard & Jan Mayen Islands')), - ('SK', _('Slovakia')), - ('SL', _('Sierra Leone')), - ('SM', _('San Marino')), - ('SN', _('Senegal')), - ('SO', _('Somalia')), - ('SR', _('Suriname')), - ('ST', _('Sao Tome & Principe')), - ('SV', _('El Salvador')), - ('SY', _('Syrian Arab Republic')), - ('SZ', _('Swaziland')), - ('TC', _('Turks & Caicos Islands')), - ('TD', _('Chad')), - ('TF', _('French Southern Territories')), - ('TG', _('Togo')), - ('TH', _('Thailand')), - ('TJ', _('Tajikistan')), - ('TK', _('Tokelau')), - ('TM', _('Turkmenistan')), - ('TN', _('Tunisia')), - ('TO', _('Tonga')), - ('TP', _('East Timor')), - ('TR', _('Turkey')), - ('TT', _('Trinidad & Tobago')), - ('TV', _('Tuvalu')), - ('TW', _('Taiwan, Province of China')), - ('TZ', _('Tanzania, United Republic of')), - ('UA', _('Ukraine')), - ('UG', _('Uganda')), - ('UM', _('United States Minor Outlying Islands')), - ('UY', _('Uruguay')), - ('UZ', _('Uzbekistan')), - ('VA', _('Vatican City State (Holy See)')), - ('VC', _('St. Vincent & the Grenadines')), - ('VE', _('Venezuela')), - ('VG', _('British Virgin Islands')), - ('VI', _('United States Virgin Islands')), - ('VN', _('Viet Nam')), - ('VU', _('Vanuatu')), - ('WF', _('Wallis & Futuna Islands')), - ('WS', _('Samoa')), - ('YE', _('Yemen')), - ('YT', _('Mayotte')), - ('YU', _('Yugoslavia')), - ('ZA', _('South Africa')), - ('ZM', _('Zambia')), - ('ZR', _('Zaire')), - ('ZW', _('Zimbabwe')), - ('ZZ', _('Unknown or unspecified country')), -) - -class CountryField(forms.ChoiceField): - def __init__(self, *args, **kwargs): - kwargs.setdefault('choices', COUNTRIES) - super(CountryField, self).__init__(*args, **kwargs) \ No newline at end of file diff --git a/csesoc/paypal/pro/forms.py b/csesoc/paypal/pro/forms.py deleted file mode 100644 index 5c8be5c..0000000 --- a/csesoc/paypal/pro/forms.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django import forms - -from paypal.pro.fields import CreditCardField, CreditCardExpiryField, CreditCardCVV2Field, CountryField - - -class PaymentForm(forms.Form): - """Form used to process direct payments.""" - firstname = forms.CharField(255, label="First Name") - lastname = forms.CharField(255, label="Last Name") - street = forms.CharField(255, label="Street Address") - city = forms.CharField(255, label="City") - state = forms.CharField(255, label="State") - countrycode = CountryField(label="Country", initial="US") - zip = forms.CharField(32, label="Postal / Zip Code") - acct = CreditCardField(label="Credit Card Number") - expdate = CreditCardExpiryField(label="Expiration Date") - cvv2 = CreditCardCVV2Field(label="Card Security Code") - - def process(self, request, item): - """Process a PayPal direct payment.""" - from paypal.pro.helpers import PayPalWPP - wpp = PayPalWPP(request) - params = self.cleaned_data - params['creditcardtype'] = self.fields['acct'].card_type - params['expdate'] = self.cleaned_data['expdate'].strftime("%m%Y") - params['ipaddress'] = request.META.get("REMOTE_ADDR", "") - params.update(item) - - # Create single payment: - if 'billingperiod' not in params: - response = wpp.doDirectPayment(params) - - # Create recurring payment: - else: - response = wpp.createRecurringPaymentsProfile(params, direct=True) - - return response - - -class ConfirmForm(forms.Form): - """Hidden form used by ExpressPay flow to keep track of payer information.""" - token = forms.CharField(max_length=255, widget=forms.HiddenInput()) - PayerID = forms.CharField(max_length=255, widget=forms.HiddenInput()) \ No newline at end of file diff --git a/csesoc/paypal/pro/helpers.py b/csesoc/paypal/pro/helpers.py deleted file mode 100644 index b43fc1d..0000000 --- a/csesoc/paypal/pro/helpers.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import datetime -import pprint -import time -import urllib -import urllib2 - -from django.conf import settings -from django.forms.models import fields_for_model -from django.utils.datastructures import MergeDict -from django.utils.http import urlencode - -from paypal.pro.models import PayPalNVP, L - - -TEST = settings.PAYPAL_TEST -USER = settings.PAYPAL_WPP_USER -PASSWORD = settings.PAYPAL_WPP_PASSWORD -SIGNATURE = settings.PAYPAL_WPP_SIGNATURE -VERSION = 54.0 -BASE_PARAMS = dict(USER=USER , PWD=PASSWORD, SIGNATURE=SIGNATURE, VERSION=VERSION) -ENDPOINT = "https://api-3t.paypal.com/nvp" -SANDBOX_ENDPOINT = "https://api-3t.sandbox.paypal.com/nvp" -NVP_FIELDS = fields_for_model(PayPalNVP).keys() - - -def paypal_time(time_obj=None): - """Returns a time suitable for PayPal time fields.""" - if time_obj is None: - time_obj = time.gmtime() - return time.strftime(PayPalNVP.TIMESTAMP_FORMAT, time_obj) - -def paypaltime2datetime(s): - """Convert a PayPal time string to a DateTime.""" - return datetime.datetime(*(time.strptime(s, PayPalNVP.TIMESTAMP_FORMAT)[:6])) - - -class PayPalError(TypeError): - """Error thrown when something be wrong.""" - - -class PayPalWPP(object): - """ - Wrapper class for the PayPal Website Payments Pro. - - Website Payments Pro Integration Guide: - https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_WPP_IntegrationGuide.pdf - - Name-Value Pair API Developer Guide and Reference: - https://cms.paypal.com/cms_content/US/en_US/files/developer/PP_NVPAPI_DeveloperGuide.pdf - """ - def __init__(self, request, params=BASE_PARAMS): - """Required - USER / PWD / SIGNATURE / VERSION""" - self.request = request - if TEST: - self.endpoint = SANDBOX_ENDPOINT - else: - self.endpoint = ENDPOINT - self.signature_values = params - self.signature = urlencode(self.signature_values) + "&" - - def doDirectPayment(self, params): - """Call PayPal DoDirectPayment method.""" - defaults = {"method": "DoDirectPayment", "paymentaction": "Sale"} - required = L("creditcardtype acct expdate cvv2 ipaddress firstname lastname street city state countrycode zip amt") - nvp_obj = self._fetch(params, required, defaults) - # @@@ Could check cvv2match / avscode are both 'X' or '0' - # qd = django.http.QueryDict(nvp_obj.response) - # if qd.get('cvv2match') not in ['X', '0']: - # nvp_obj.set_flag("Invalid cvv2match: %s" % qd.get('cvv2match') - # if qd.get('avscode') not in ['X', '0']: - # nvp_obj.set_flag("Invalid avscode: %s" % qd.get('avscode') - return not nvp_obj.flag - - def setExpressCheckout(self, params): - """ - Initiates an Express Checkout transaction. - Optionally, the SetExpressCheckout API operation can set up billing agreements for - reference transactions and recurring payments. - Returns a NVP instance - check for token and payerid to continue! - """ - if self._is_recurring(params): - params = self._recurring_setExpressCheckout_adapter(params) - - defaults = {"method": "SetExpressCheckout", "noshipping": 1} - required = L("returnurl cancelurl amt") - return self._fetch(params, required, defaults) - - def doExpressCheckoutPayment(self, params): - """ - Check the dude out: - """ - defaults = {"method": "DoExpressCheckoutPayment", "paymentaction": "Sale"} - required =L("returnurl cancelurl amt token payerid") - nvp_obj = self._fetch(params, required, defaults) - return not nvp_obj.flag - - def createRecurringPaymentsProfile(self, params, direct=False): - """ - Set direct to True to indicate that this is being called as a directPayment. - Returns True PayPal successfully creates the profile otherwise False. - """ - defaults = {"method": "CreateRecurringPaymentsProfile"} - required = L("profilestartdate billingperiod billingfrequency amt") - - # Direct payments require CC data - if direct: - required + L("creditcardtype acct expdate firstname lastname") - else: - required + L("token payerid") - - nvp_obj = self._fetch(params, required, defaults) - - # Flag if profile_type != ActiveProfile - return not nvp_obj.flag - - def getExpressCheckoutDetails(self, params): - raise NotImplementedError - - def setCustomerBillingAgreement(self, params): - raise DeprecationWarning - - def getTransactionDetails(self, params): - raise NotImplementedError - - def massPay(self, params): - raise NotImplementedError - - def getRecurringPaymentsProfileDetails(self, params): - raise NotImplementedError - - def updateRecurringPaymentsProfile(self, params): - raise NotImplementedError - - def billOutstandingAmount(self, params): - raise NotImplementedError - - def manangeRecurringPaymentsProfileStatus(self, params): - raise NotImplementedError - - def refundTransaction(self, params): - raise NotImplementedError - - def _is_recurring(self, params): - """Returns True if the item passed is a recurring transaction.""" - return 'billingfrequency' in params - - def _recurring_setExpressCheckout_adapter(self, params): - """ - The recurring payment interface to SEC is different than the recurring payment - interface to ECP. This adapts a normal call to look like a SEC call. - """ - params['l_billingtype0'] = "RecurringPayments" - params['l_billingagreementdescription0'] = params['desc'] - - REMOVE = L("billingfrequency billingperiod profilestartdate desc") - for k in params.keys(): - if k in REMOVE: - del params[k] - - return params - - def _fetch(self, params, required, defaults): - """Make the NVP request and store the response.""" - defaults.update(params) - pp_params = self._check_and_update_params(required, defaults) - pp_string = self.signature + urlencode(pp_params) - response = self._request(pp_string) - response_params = self._parse_response(response) - - if settings.DEBUG: - print 'PayPal Request:' - pprint.pprint(defaults) - print '\nPayPal Response:' - pprint.pprint(response_params) - - # Gather all NVP parameters to pass to a new instance. - nvp_params = {} - for k, v in MergeDict(defaults, response_params).items(): - if k in NVP_FIELDS: - nvp_params[k] = v - - # PayPal timestamp has to be formatted. - if 'timestamp' in nvp_params: - nvp_params['timestamp'] = paypaltime2datetime(nvp_params['timestamp']) - - nvp_obj = PayPalNVP(**nvp_params) - nvp_obj.init(self.request, params, response_params) - nvp_obj.save() - return nvp_obj - - def _request(self, data): - """Moved out to make testing easier.""" - return urllib2.urlopen(self.endpoint, data).read() - - def _check_and_update_params(self, required, params): - """ - Ensure all required parameters were passed to the API call and format - them correctly. - """ - for r in required: - if r not in params: - raise PayPalError("Missing required param: %s" % r) - - # Upper case all the parameters for PayPal. - return (dict((k.upper(), v) for k, v in params.iteritems())) - - def _parse_response(self, response): - """Turn the PayPal response into a dict""" - response_tokens = {} - for kv in response.split('&'): - key, value = kv.split("=") - response_tokens[key.lower()] = urllib.unquote(value) - return response_tokens \ No newline at end of file diff --git a/csesoc/paypal/pro/models.py b/csesoc/paypal/pro/models.py deleted file mode 100644 index 7e5dccd..0000000 --- a/csesoc/paypal/pro/models.py +++ /dev/null @@ -1,101 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from string import split as L -from django.db import models -from django.utils.http import urlencode -from django.forms.models import model_to_dict -from django.contrib.auth.models import User - - -class PayPalNVP(models.Model): - """Record of a NVP interaction with PayPal.""" - TIMESTAMP_FORMAT = "%Y-%m-%dT%H:%M:%SZ" # 2009-02-03T17:47:41Z - RESTRICTED_FIELDS = L("expdate cvv2 acct") - ADMIN_FIELDS = L("id user flag flag_code flag_info query response created_at updated_at ") - ITEM_FIELDS = L("amt custom invnum") - DIRECT_FIELDS = L("firstname lastname street city state countrycode zip") - - # Response fields - method = models.CharField(max_length=64, blank=True) - ack = models.CharField(max_length=32, blank=True) - profilestatus = models.CharField(max_length=32, blank=True) - timestamp = models.DateTimeField(blank=True, null=True) - profileid = models.CharField(max_length=32, blank=True) # I-E596DFUSD882 - profilereference = models.CharField(max_length=128, blank=True) # PROFILEREFERENCE - correlationid = models.CharField(max_length=32, blank=True) # 25b380cda7a21 - token = models.CharField(max_length=64, blank=True) - payerid = models.CharField(max_length=64, blank=True) - - # Transaction Fields - firstname = models.CharField("First Name", max_length=255, blank=True) - lastname = models.CharField("Last Name", max_length=255, blank=True) - street = models.CharField("Street Address", max_length=255, blank=True) - city = models.CharField("City", max_length=255, blank=True) - state = models.CharField("State", max_length=255, blank=True) - countrycode = models.CharField("Country", max_length=2,blank=True) - zip = models.CharField("Postal / Zip Code", max_length=32, blank=True) - - # Custom fields - invnum = models.CharField(max_length=255, blank=True) - custom = models.CharField(max_length=255, blank=True) - - # Admin fields - user = models.ForeignKey(User, blank=True, null=True) - flag = models.BooleanField(default=False, blank=True) - flag_code = models.CharField(max_length=32, blank=True) - flag_info = models.TextField(blank=True) - ipaddress = models.IPAddressField(blank=True) - query = models.TextField(blank=True) - response = models.TextField(blank=True) - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - - class Meta: - db_table = "paypal_nvp" - verbose_name = "PayPal NVP" - - def init(self, request, paypal_request, paypal_response): - """Initialize a PayPalNVP instance from a HttpRequest.""" - self.ipaddress = request.META.get('REMOTE_ADDR', '') - if hasattr(request, "user") and request.user.is_authenticated(): - self.user = request.user - - # No storing credit card info. - query_data = dict((k,v) for k, v in paypal_request.iteritems() if k not in self.RESTRICTED_FIELDS) - self.query = urlencode(query_data) - self.response = urlencode(paypal_response) - - # Was there a flag on the play? - ack = paypal_response.get('ack', False) - if ack != "Success": - if ack == "SuccessWithWarning": - self.flag_info = paypal_response.get('l_longmessage0', '') - else: - self.set_flag(paypal_response.get('l_longmessage0', ''), paypal_response.get('l_errorcode', '')) - - def set_flag(self, info, code=None): - """Flag this instance for investigation.""" - self.flag = True - self.flag_info += info - if code is not None: - self.flag_code = code - - def process(self, request, item): - """Do a direct payment.""" - from paypal.pro.helpers import PayPalWPP - wpp = PayPalWPP(request) - - # Change the model information into a dict that PayPal can understand. - params = model_to_dict(self, exclude=self.ADMIN_FIELDS) - params['acct'] = self.acct - params['creditcardtype'] = self.creditcardtype - params['expdate'] = self.expdate - params['cvv2'] = self.cvv2 - params.update(item) - - # Create recurring payment: - if 'billingperiod' in params: - return wpp.createRecurringPaymentsProfile(params, direct=True) - # Create single payment: - else: - return wpp.doDirectPayment(params) diff --git a/csesoc/paypal/pro/signals.py b/csesoc/paypal/pro/signals.py deleted file mode 100644 index 66e4a1a..0000000 --- a/csesoc/paypal/pro/signals.py +++ /dev/null @@ -1,16 +0,0 @@ -from django.dispatch import Signal - -""" -These signals are different from IPN signals in that they are sent the second -the payment is failed or succeeds and come with the `item` object passed to -PayPalPro rather than an IPN object. - -### SENDER is the item? is that right??? - -""" - -# Sent when a payment is successfully processed. -payment_was_successful = Signal() #providing_args=["item"]) - -# Sent when a payment is flagged. -payment_was_flagged = Signal() #providing_args=["item"]) diff --git a/csesoc/paypal/pro/templates/pro/confirm.html b/csesoc/paypal/pro/templates/pro/confirm.html deleted file mode 100644 index 4ea1e05..0000000 --- a/csesoc/paypal/pro/templates/pro/confirm.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - -
- - - {{ form.as_table }} - - -
-
- - - - - - - diff --git a/csesoc/paypal/pro/templates/pro/payment.html b/csesoc/paypal/pro/templates/pro/payment.html deleted file mode 100644 index 434f9c9..0000000 --- a/csesoc/paypal/pro/templates/pro/payment.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - -
- - - {% if errors %}{% endif %} - - {{ form.as_table }} - - -
{{ errors }}
Pay by PayPal
-
- - - - - - - diff --git a/csesoc/paypal/pro/tests.py b/csesoc/paypal/pro/tests.py deleted file mode 100644 index e00f57f..0000000 --- a/csesoc/paypal/pro/tests.py +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/python -# -*- coding: utf-8 -*- -from django.conf import settings -from django.core.handlers.wsgi import WSGIRequest -from django.forms import ValidationError -from django.http import QueryDict -from django.test import TestCase -from django.test.client import Client - -from paypal.pro.fields import CreditCardField -from paypal.pro.helpers import PayPalWPP, PayPalError - - -class RequestFactory(Client): - # Used to generate request objects. - def request(self, **request): - environ = { - 'HTTP_COOKIE': self.cookies, - 'PATH_INFO': '/', - 'QUERY_STRING': '', - 'REQUEST_METHOD': 'GET', - 'SCRIPT_NAME': '', - 'SERVER_NAME': 'testserver', - 'SERVER_PORT': 80, - 'SERVER_PROTOCOL': 'HTTP/1.1', - } - environ.update(self.defaults) - environ.update(request) - return WSGIRequest(environ) - -RF = RequestFactory() -REQUEST = RF.get("/pay/", REMOTE_ADDR="127.0.0.1:8000") - - -class DummyPayPalWPP(PayPalWPP): - pass -# """Dummy class for testing PayPalWPP.""" -# responses = { -# # @@@ Need some reals data here. -# "DoDirectPayment": """ack=Success×tamp=2009-03-12T23%3A52%3A33Z&l_severitycode0=Error&l_shortmessage0=Security+error&l_longmessage0=Security+header+is+not+valid&version=54.0&build=854529&l_errorcode0=&correlationid=""", -# } -# -# def _request(self, data): -# return self.responses["DoDirectPayment"] - - -class CreditCardFieldTest(TestCase): - def testCreditCardField(self): - field = CreditCardField() - field.clean('4797503429879309') - self.assertEquals(field.card_type, "Visa") - self.assertRaises(ValidationError, CreditCardField().clean, '1234567890123455') - - -class PayPalWPPTest(TestCase): - def setUp(self): - - # Avoding blasting real requests at PayPal. - self.old_debug = settings.DEBUG - settings.DEBUG = True - - self.item = { - 'amt': '9.95', - 'inv': 'inv', - 'custom': 'custom', - 'next': 'http://www.example.com/next/', - 'returnurl': 'http://www.example.com/pay/', - 'cancelurl': 'http://www.example.com/cancel/' - } - self.wpp = DummyPayPalWPP(REQUEST) - - def tearDown(self): - settings.DEBUG = self.old_debug - - def test_doDirectPayment_missing_params(self): - data = {'firstname': 'Chewbacca'} - self.assertRaises(PayPalError, self.wpp.doDirectPayment, data) - - def test_doDirectPayment_valid(self): - data = { - 'firstname': 'Brave', - 'lastname': 'Star', - 'street': '1 Main St', - 'city': u'San Jos\xe9', - 'state': 'CA', - 'countrycode': 'US', - 'zip': '95131', - 'expdate': '012019', - 'cvv2': '037', - 'acct': '4797503429879309', - 'creditcardtype': 'visa', - 'ipaddress': '10.0.1.199',} - data.update(self.item) - self.assertTrue(self.wpp.doDirectPayment(data)) - - def test_doDirectPayment_invalid(self): - data = { - 'firstname': 'Epic', - 'lastname': 'Fail', - 'street': '100 Georgia St', - 'city': 'Vancouver', - 'state': 'BC', - 'countrycode': 'CA', - 'zip': 'V6V 1V1', - 'expdate': '012019', - 'cvv2': '999', - 'acct': '1234567890', - 'creditcardtype': 'visa', - 'ipaddress': '10.0.1.199',} - data.update(self.item) - self.assertFalse(self.wpp.doDirectPayment(data)) - - def test_setExpressCheckout(self): - # We'll have to stub out tests for doExpressCheckoutPayment and friends - # because they're behind paypal's doors. - nvp_obj = self.wpp.setExpressCheckout(self.item) - self.assertTrue(nvp_obj.ack == "Success") - - -### DoExpressCheckoutPayment -# PayPal Request: -# {'amt': '10.00', -# 'cancelurl': u'http://xxx.xxx.xxx.xxx/deploy/480/upgrade/?upgrade=cname', -# 'custom': u'website_id=480&cname=1', -# 'inv': u'website-480-cname', -# 'method': 'DoExpressCheckoutPayment', -# 'next': u'http://xxx.xxx.xxx.xxx/deploy/480/upgrade/?upgrade=cname', -# 'payerid': u'BN5JZ2V7MLEV4', -# 'paymentaction': 'Sale', -# 'returnurl': u'http://xxx.xxx.xxx.xxx/deploy/480/upgrade/?upgrade=cname', -# 'token': u'EC-6HW17184NE0084127'} -# -# PayPal Response: -# {'ack': 'Success', -# 'amt': '10.00', -# 'build': '848077', -# 'correlationid': '375f4773c3d34', -# 'currencycode': 'USD', -# 'feeamt': '0.59', -# 'ordertime': '2009-03-04T20:56:08Z', -# 'paymentstatus': 'Completed', -# 'paymenttype': 'instant', -# 'pendingreason': 'None', -# 'reasoncode': 'None', -# 'taxamt': '0.00', -# 'timestamp': '2009-03-04T20:56:09Z', -# 'token': 'EC-6HW17184NE0084127', -# 'transactionid': '3TG42202A7335864V', -# 'transactiontype': 'expresscheckout', -# 'version': '54.0'} \ No newline at end of file diff --git a/csesoc/paypal/pro/views.py b/csesoc/paypal/pro/views.py deleted file mode 100644 index 0d357c1..0000000 --- a/csesoc/paypal/pro/views.py +++ /dev/null @@ -1,203 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django.template import RequestContext -from django.shortcuts import render_to_response -from django.http import HttpResponseRedirect -from django.utils.http import urlencode - -from paypal.pro.forms import PaymentForm, ConfirmForm -from paypal.pro.models import PayPalNVP -from paypal.pro.helpers import PayPalWPP, TEST -from paypal.pro.signals import payment_was_successful, payment_was_flagged - - -# PayPal Edit IPN URL: -# https://www.sandbox.paypal.com/us/cgi-bin/webscr?cmd=_profile-ipn-notify -EXPRESS_ENDPOINT = "https://www.paypal.com/webscr?cmd=_express-checkout&%s" -SANDBOX_EXPRESS_ENDPOINT = "https://www.sandbox.paypal.com/webscr?cmd=_express-checkout&%s" - - -class PayPalPro(object): - """ - This class-based view takes care of PayPal WebsitePaymentsPro (WPP). - PayPalPro has two separate flows - DirectPayment and ExpressPayFlow. In - DirectPayment the user buys on your site. In ExpressPayFlow the user is - direct to PayPal to confirm their purchase. PayPalPro implements both - flows. To it create an instance using the these parameters: - - item: a dictionary that holds information about the item being purchased. - - For single item purchase (pay once): - - Required Keys: - * amt: Float amount of the item. - - Optional Keys: - * custom: You can set this to help you identify a transaction. - * invnum: Unique ID that identifies this transaction. - - For recurring billing: - - Required Keys: - * amt: Float amount for each billing cycle. - * billingperiod: String unit of measure for the billing cycle (Day|Week|SemiMonth|Month|Year) - * billingfrequency: Integer number of periods that make up a cycle. - * profilestartdate: The date to begin billing. "2008-08-05T17:00:00Z" UTC/GMT - * desc: Description of what you're billing for. - - Optional Keys: - * trialbillingperiod: String unit of measure for trial cycle (Day|Week|SemiMonth|Month|Year) - * trialbillingfrequency: Integer # of periods in a cycle. - * trialamt: Float amount to bill for the trial period. - * trialtotalbillingcycles: Integer # of cycles for the trial payment period. - * failedinitamtaction: set to continue on failure (ContinueOnFailure / CancelOnFailure) - * maxfailedpayments: number of payments before profile is suspended. - * autobilloutamt: automatically bill outstanding amount. - * subscribername: Full name of the person who paid. - * profilereference: Unique reference or invoice number. - * taxamt: How much tax. - * initamt: Initial non-recurring payment due upon creation. - * currencycode: defaults to USD - * + a bunch of shipping fields - - payment_form_cls: form class that will be used to display the payment form. - It should inherit from `paypal.pro.forms.PaymentForm` if you're adding more. - - payment_template: template used to ask the dude for monies. To comply with - PayPal standards it must include a link to PayPal Express Checkout. - - confirm_form_cls: form class that will be used to display the confirmation form. - It should inherit from `paypal.pro.forms.ConfirmForm`. It is only used in the Express flow. - - success_url / fail_url: URLs to be redirected to when the payment successful or fails. - """ - errors = { - "processing": "There was an error processing your payment. Check your information and try again.", - "form": "Please correct the errors below and try again.", - "paypal": "There was a problem contacting PayPal. Please try again later." - } - - def __init__(self, item=None, payment_form_cls=PaymentForm, - payment_template="pro/payment.html", confirm_form_cls=ConfirmForm, - confirm_template="pro/confirm.html", success_url="?success", - fail_url=None, context=None, form_context_name="form"): - self.item = item - self.payment_form_cls = payment_form_cls - self.payment_template = payment_template - self.confirm_form_cls = confirm_form_cls - self.confirm_template = confirm_template - self.success_url = success_url - self.fail_url = fail_url - self.context = context or {} - self.form_context_name = form_context_name - - def __call__(self, request): - """Return the appropriate response for the state of the transaction.""" - self.request = request - if request.method == "GET": - if self.should_redirect_to_express(): - return self.redirect_to_express() - elif self.should_render_confirm_form(): - return self.render_confirm_form() - elif self.should_render_payment_form(): - return self.render_payment_form() - else: - if self.should_validate_confirm_form(): - return self.validate_confirm_form() - elif self.should_validate_payment_form(): - return self.validate_payment_form() - - # Default to the rendering the payment form. - return self.render_payment_form() - - def is_recurring(self): - return self.item is not None and 'billingperiod' in self.item - - def should_redirect_to_express(self): - return 'express' in self.request.GET - - def should_render_confirm_form(self): - return 'token' in self.request.GET and 'PayerID' in self.request.GET - - def should_render_payment_form(self): - return True - - def should_validate_confirm_form(self): - return 'token' in self.request.POST and 'PayerID' in self.request.POST - - def should_validate_payment_form(self): - return True - - def render_payment_form(self): - """Display the DirectPayment for entering payment information.""" - self.context[self.form_context_name] = self.payment_form_cls() - return render_to_response(self.payment_template, self.context, RequestContext(self.request)) - - def validate_payment_form(self): - """Try to validate and then process the DirectPayment form.""" - form = self.payment_form_cls(self.request.POST) - if form.is_valid(): - success = form.process(self.request, self.item) - if success: - payment_was_successful.send(sender=self.item) - return HttpResponseRedirect(self.success_url) - else: - self.context['errors'] = self.errors['processing'] - - self.context[self.form_context_name] = form - self.context.setdefault("errors", self.errors['form']) - return render_to_response(self.payment_template, self.context, RequestContext(self.request)) - - def get_endpoint(self): - if TEST: - return SANDBOX_EXPRESS_ENDPOINT - else: - return EXPRESS_ENDPOINT - - def redirect_to_express(self): - """ - First step of ExpressCheckout. Redirect the request to PayPal using the - data returned from setExpressCheckout. - """ - wpp = PayPalWPP(self.request) - nvp_obj = wpp.setExpressCheckout(self.item) - if not nvp_obj.flag: - pp_params = dict(token=nvp_obj.token, AMT=self.item['amt'], - RETURNURL=self.item['returnurl'], - CANCELURL=self.item['cancelurl']) - pp_url = self.get_endpoint() % urlencode(pp_params) - return HttpResponseRedirect(pp_url) - else: - self.context['errors'] = self.errors['paypal'] - return self.render_payment_form() - - def render_confirm_form(self): - """ - Second step of ExpressCheckout. Display an order confirmation form which - contains hidden fields with the token / PayerID from PayPal. - """ - initial = dict(token=self.request.GET['token'], PayerID=self.request.GET['PayerID']) - self.context[self.form_context_name] = self.confirm_form_cls(initial=initial) - return render_to_response(self.confirm_template, self.context, RequestContext(self.request)) - - def validate_confirm_form(self): - """ - Third and final step of ExpressCheckout. Request has pressed the confirmation but - and we can send the final confirmation to PayPal using the data from the POST'ed form. - """ - wpp = PayPalWPP(self.request) - pp_data = dict(token=self.request.POST['token'], payerid=self.request.POST['PayerID']) - self.item.update(pp_data) - - # @@@ This check and call could be moved into PayPalWPP. - if self.is_recurring(): - success = wpp.createRecurringPaymentsProfile(self.item) - else: - success = wpp.doExpressCheckoutPayment(self.item) - - if success: - payment_was_successful.send(sender=self.item) - return HttpResponseRedirect(self.success_url) - else: - self.context['errors'] = self.errors['processing'] - return self.render_payment_form() diff --git a/csesoc/paypal/standard/__init__.py b/csesoc/paypal/standard/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/paypal/standard/conf.py b/csesoc/paypal/standard/conf.py deleted file mode 100644 index 1a6c11d..0000000 --- a/csesoc/paypal/standard/conf.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.conf import settings - -class PayPalSettingsError(Exception): - """Raised when settings be bad.""" - - -TEST = getattr(settings, "PAYPAL_TEST", True) - - -RECEIVER_EMAIL = settings.PAYPAL_RECEIVER_EMAIL - - -# API Endpoints. -POSTBACK_ENDPOINT = "https://www.paypal.com/cgi-bin/webscr" -SANDBOX_POSTBACK_ENDPOINT = "https://www.sandbox.paypal.com/cgi-bin/webscr" - -# Images -IMAGE = getattr(settings, "PAYPAL_IMAGE", "http://images.paypal.com/images/x-click-but01.gif") -SUBSCRIPTION_IMAGE = "https://www.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif" -SANDBOX_IMAGE = getattr(settings, "PAYPAL_SANDBOX_IMAGE", "https://www.sandbox.paypal.com/en_US/i/btn/btn_buynowCC_LG.gif") -SUBSCRIPTION_SANDBOX_IMAGE = "https://www.sandbox.paypal.com/en_US/i/btn/btn_subscribeCC_LG.gif" \ No newline at end of file diff --git a/csesoc/paypal/standard/forms.py b/csesoc/paypal/standard/forms.py deleted file mode 100644 index 6639146..0000000 --- a/csesoc/paypal/standard/forms.py +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django import forms -from django.conf import settings -from django.utils.safestring import mark_safe -from paypal.standard.conf import * -from paypal.standard.widgets import ValueHiddenInput, ReservedValueHiddenInput -from paypal.standard.conf import (POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT, - RECEIVER_EMAIL) - - -# 20:18:05 Jan 30, 2009 PST - PST timezone support is not included out of the box. -# PAYPAL_DATE_FORMAT = ("%H:%M:%S %b. %d, %Y PST", "%H:%M:%S %b %d, %Y PST",) -# PayPal dates have been spotted in the wild with these formats, beware! -PAYPAL_DATE_FORMAT = ("%H:%M:%S %b. %d, %Y PST", - "%H:%M:%S %b. %d, %Y PDT", - "%H:%M:%S %b %d, %Y PST", - "%H:%M:%S %b %d, %Y PDT",) - -class PayPalPaymentsForm(forms.Form): - """ - Creates a PayPal Payments Standard "Buy It Now" button, configured for a - selling a single item with no shipping. - - For a full overview of all the fields you can set (there is a lot!) see: - http://tinyurl.com/pps-integration - - Usage: - >>> f = PayPalPaymentsForm(initial={'item_name':'Widget 001', ...}) - >>> f.render() - u'
...' - - """ - CMD_CHOICES = ( - ("_xclick", "Buy now or Donations"), - ("_cart", "Shopping cart"), - ("_xclick-subscriptions", "Subscribe") - ) - SHIPPING_CHOICES = ((1, "No shipping"), (0, "Shipping")) - NO_NOTE_CHOICES = ((1, "No Note"), (0, "Include Note")) - RECURRING_PAYMENT_CHOICES = ( - (1, "Subscription Payments Recur"), - (0, "Subscription payments do not recur") - ) - REATTEMPT_ON_FAIL_CHOICES = ( - (1, "reattempt billing on Failure"), - (0, "Do Not reattempt on failure") - ) - - # Where the money goes. - business = forms.CharField(widget=ValueHiddenInput(), initial=RECEIVER_EMAIL) - - # Item information. - amount = forms.IntegerField(widget=ValueHiddenInput()) - item_name = forms.CharField(widget=ValueHiddenInput()) - item_number = forms.CharField(widget=ValueHiddenInput()) - quantity = forms.CharField(widget=ValueHiddenInput()) - - # Subscription Related. - a1 = forms.CharField(widget=ValueHiddenInput()) # Trial 1 Price - p1 = forms.CharField(widget=ValueHiddenInput()) # Trial 1 Duration - t1 = forms.CharField(widget=ValueHiddenInput()) # Trial 1 unit of Duration, default to Month - a2 = forms.CharField(widget=ValueHiddenInput()) # Trial 2 Price - p2 = forms.CharField(widget=ValueHiddenInput()) # Trial 2 Duration - t2 = forms.CharField(widget=ValueHiddenInput()) # Trial 2 unit of Duration, default to Month - a3 = forms.CharField(widget=ValueHiddenInput()) # Subscription Price - p3 = forms.CharField(widget=ValueHiddenInput()) # Subscription Duration - t3 = forms.CharField(widget=ValueHiddenInput()) # Subscription unit of Duration, default to Month - src = forms.CharField(widget=ValueHiddenInput()) # Is billing recurring? default to yes - sra = forms.CharField(widget=ValueHiddenInput()) # Reattempt billing on failed cc transaction - no_note = forms.CharField(widget=ValueHiddenInput()) - # Can be either 1 or 2. 1 = modify or allow new subscription creation, 2 = modify only - modify = forms.IntegerField(widget=ValueHiddenInput()) # Are we modifying an existing subscription? - - # Localization / PayPal Setup - lc = forms.CharField(widget=ValueHiddenInput()) - page_style = forms.CharField(widget=ValueHiddenInput()) - cbt = forms.CharField(widget=ValueHiddenInput()) - - # IPN control. - notify_url = forms.CharField(widget=ValueHiddenInput()) - cancel_return = forms.CharField(widget=ValueHiddenInput()) - return_url = forms.CharField(widget=ReservedValueHiddenInput(attrs={"name":"return"})) - custom = forms.CharField(widget=ValueHiddenInput()) - invoice = forms.CharField(widget=ValueHiddenInput()) - - # Default fields. - cmd = forms.ChoiceField(widget=forms.HiddenInput(), initial=CMD_CHOICES[0][0]) - charset = forms.CharField(widget=forms.HiddenInput(), initial="utf-8") - currency_code = forms.CharField(widget=forms.HiddenInput(), initial="USD") - no_shipping = forms.ChoiceField(widget=forms.HiddenInput(), choices=SHIPPING_CHOICES, - initial=SHIPPING_CHOICES[0][0]) - - def __init__(self, button_type="buy", *args, **kwargs): - super(PayPalPaymentsForm, self).__init__(*args, **kwargs) - self.button_type = button_type - - def render(self): - return mark_safe(u""" - %s - -
""" % (POSTBACK_ENDPOINT, self.as_p(), self.get_image())) - - - def sandbox(self): - return mark_safe(u"""
- %s - -
""" % (SANDBOX_POSTBACK_ENDPOINT, self.as_p(), self.get_image())) - - def get_image(self): - return { - (True, True): SUBSCRIPTION_SANDBOX_IMAGE, - (True, False): SANDBOX_IMAGE, - (False, True): SUBSCRIPTION_IMAGE, - (False, False): IMAGE - }[TEST, self.is_subscription()] - - def is_transaction(self): - return self.button_type == "buy" - - def is_subscription(self): - return self.button_type == "subscribe" - - -class PayPalEncryptedPaymentsForm(PayPalPaymentsForm): - """ - Creates a PayPal Encrypted Payments "Buy It Now" button. - Requires the M2Crypto package. - - Based on example at: - http://blog.mauveweb.co.uk/2007/10/10/paypal-with-django/ - - """ - def _encrypt(self): - """Use your key thing to encrypt things.""" - from M2Crypto import BIO, SMIME, X509 - # @@@ Could we move this to conf.py? - CERT = settings.PAYPAL_PRIVATE_CERT - PUB_CERT = settings.PAYPAL_PUBLIC_CERT - PAYPAL_CERT = settings.PAYPAL_CERT - CERT_ID = settings.PAYPAL_CERT_ID - - # Iterate through the fields and pull out the ones that have a value. - plaintext = 'cert_id=%s\n' % CERT_ID - for name, field in self.fields.iteritems(): - value = None - if name in self.initial: - value = self.initial[name] - elif field.initial is not None: - value = field.initial - if value is not None: - # @@@ Make this less hackish and put it in the widget. - if name == "return_url": - name = "return" - plaintext += u'%s=%s\n' % (name, value) - plaintext = plaintext.encode('utf-8') - - # Begin crypto weirdness. - s = SMIME.SMIME() - s.load_key_bio(BIO.openfile(CERT), BIO.openfile(PUB_CERT)) - p7 = s.sign(BIO.MemoryBuffer(plaintext), flags=SMIME.PKCS7_BINARY) - x509 = X509.load_cert_bio(BIO.openfile(settings.PAYPAL_CERT)) - sk = X509.X509_Stack() - sk.push(x509) - s.set_x509_stack(sk) - s.set_cipher(SMIME.Cipher('des_ede3_cbc')) - tmp = BIO.MemoryBuffer() - p7.write_der(tmp) - p7 = s.encrypt(tmp, flags=SMIME.PKCS7_BINARY) - out = BIO.MemoryBuffer() - p7.write(out) - return out.read() - - def as_p(self): - return mark_safe(u""" - - - """ % self._encrypt()) - - -class PayPalSharedSecretEncryptedPaymentsForm(PayPalEncryptedPaymentsForm): - """ - Creates a PayPal Encrypted Payments "Buy It Now" button with a Shared Secret. - Shared secrets should only be used when your IPN endpoint is on HTTPS. - - Adds a secret to the notify_url based on the contents of the form. - - """ - def __init__(self, *args, **kwargs): - "Make the secret from the form initial data and slip it into the form." - from paypal.standard.helpers import make_secret - super(PayPalSharedSecretEncryptedPaymentsForm, self).__init__(self, *args, **kwargs) - # @@@ Attach the secret parameter in a way that is safe for other query params. - secret_param = "?secret=%s" % make_secret(self) - # Initial data used in form construction overrides defaults - if 'notify_url' in self.initial: - self.initial['notify_url'] += secret_param - else: - self.fields['notify_url'].initial += secret_param - - -class PayPalStandardBaseForm(forms.ModelForm): - """Form used to receive and record PayPal IPN/PDT.""" - # PayPal dates have non-standard formats. - time_created = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT) - payment_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT) - next_payment_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT) - subscr_date = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT) - subscr_effective = forms.DateTimeField(required=False, input_formats=PAYPAL_DATE_FORMAT) \ No newline at end of file diff --git a/csesoc/paypal/standard/helpers.py b/csesoc/paypal/standard/helpers.py deleted file mode 100644 index 7fb523b..0000000 --- a/csesoc/paypal/standard/helpers.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django.conf import settings - - -def duplicate_txn_id(ipn_obj): - """Returns True if a record with this transaction id exists.""" - return ipn_obj._default_manager.filter(txn_id=ipn_obj.txn_id).count() > 0 - -def make_secret(form_instance, secret_fields=None): - """ - Returns a secret for use in a EWP form or an IPN verification based on a - selection of variables in params. Should only be used with SSL. - - """ - # @@@ Moved here as temporary fix to avoid dependancy on auth.models. - from django.contrib.auth.models import get_hexdigest - # @@@ amount is mc_gross on the IPN - where should mapping logic go? - # @@@ amount / mc_gross is not nessecarily returned as it was sent - how to use it? 10.00 vs. 10.0 - # @@@ the secret should be based on the invoice or custom fields as well - otherwise its always the same. - - # Build the secret with fields availible in both PaymentForm and the IPN. Order matters. - if secret_fields is None: - secret_fields = ['business', 'item_name'] - - data = "" - for name in secret_fields: - if hasattr(form_instance, 'cleaned_data'): - if name in form_instance.cleaned_data: - data += unicode(form_instance.cleaned_data[name]) - else: - # Initial data passed into the constructor overrides defaults. - if name in form_instance.initial: - data += unicode(form_instance.initial[name]) - elif name in form_instance.fields and form_instance.fields[name].initial is not None: - data += unicode(form_instance.fields[name].initial) - - secret = get_hexdigest('sha1', settings.SECRET_KEY, data) - return secret - -def check_secret(form_instance, secret): - """ - Returns true if received `secret` matches expected secret for form_instance. - Used to verify IPN. - - """ - # @@@ add invoice & custom - # secret_fields = ['business', 'item_name'] - return make_secret(form_instance) == secret \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/__init__.py b/csesoc/paypal/standard/ipn/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/paypal/standard/ipn/admin.py b/csesoc/paypal/standard/ipn/admin.py deleted file mode 100644 index 173c97c..0000000 --- a/csesoc/paypal/standard/ipn/admin.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django.contrib import admin -from paypal.standard.ipn.models import PayPalIPN - - -class PayPalIPNAdmin(admin.ModelAdmin): - date_hierarchy = 'payment_date' - fieldsets = ( - (None, { - "fields": [ - "flag", "txn_id", "txn_type", "payment_status", "payment_date", - "transaction_entity", "reason_code", "pending_reason", - "mc_gross", "mc_fee", "auth_status", "auth_amount", "auth_exp", - "auth_id" - ] - }), - ("Address", { - "description": "The address of the Buyer.", - 'classes': ('collapse',), - "fields": [ - "address_city", "address_country", "address_country_code", - "address_name", "address_state", "address_status", - "address_street", "address_zip" - ] - }), - ("Buyer", { - "description": "The information about the Buyer.", - 'classes': ('collapse',), - "fields": [ - "first_name", "last_name", "payer_business_name", "payer_email", - "payer_id", "payer_status", "contact_phone", "residence_country" - ] - }), - ("Seller", { - "description": "The information about the Seller.", - 'classes': ('collapse',), - "fields": [ - "business", "item_name", "item_number", "quantity", - "receiver_email", "receiver_id", "custom", "invoice", "memo" - ] - }), - ("Recurring", { - "description": "Information about recurring Payments.", - "classes": ("collapse",), - "fields": [ - "profile_status", "initial_payment_amount", "amount_per_cycle", - "outstanding_balance", "period_type", "product_name", - "product_type", "recurring_payment_id", "receipt_id", - "next_payment_date" - ] - }), - ("Admin", { - "description": "Additional Info.", - "classes": ('collapse',), - "fields": [ - "test_ipn", "ipaddress", "query", "response", "flag_code", - "flag_info" - ] - }), - ) - list_display = [ - "__unicode__", "flag", "flag_info", "invoice", "custom", - "payment_status", "created_at" - ] - search_fields = ["txn_id", "recurring_payment_id"] - - -admin.site.register(PayPalIPN, PayPalIPNAdmin) \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/forms.py b/csesoc/paypal/standard/ipn/forms.py deleted file mode 100644 index 8df7327..0000000 --- a/csesoc/paypal/standard/ipn/forms.py +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from paypal.standard.forms import PayPalStandardBaseForm -from paypal.standard.ipn.models import PayPalIPN - - -class PayPalIPNForm(PayPalStandardBaseForm): - """ - Form used to receive and record PayPal IPN notifications. - - PayPal IPN test tool: - https://developer.paypal.com/us/cgi-bin/devscr?cmd=_tools-session - """ - class Meta: - model = PayPalIPN - diff --git a/csesoc/paypal/standard/ipn/migrations/0001_first_migration.py b/csesoc/paypal/standard/ipn/migrations/0001_first_migration.py deleted file mode 100644 index d30de71..0000000 --- a/csesoc/paypal/standard/ipn/migrations/0001_first_migration.py +++ /dev/null @@ -1,247 +0,0 @@ -# -*- coding: utf-8 -*- -from django.db import models -from south.db import db -from paypal.standard.ipn.models import * - - -class Migration: - def forwards(self, orm): - # Adding model 'PayPalIPN' - db.create_table('paypal_ipn', ( - ('id', models.AutoField(primary_key=True)), - ('business', models.CharField(max_length=127, blank=True)), - ('charset', models.CharField(max_length=32, blank=True)), - ('custom', models.CharField(max_length=255, blank=True)), - ('notify_version', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('parent_txn_id', models.CharField("Parent Transaction ID", max_length=19, blank=True)), - ('receiver_email', models.EmailField(max_length=127, blank=True)), - ('receiver_id', models.CharField(max_length=127, blank=True)), - ('residence_country', models.CharField(max_length=2, blank=True)), - ('test_ipn', models.BooleanField(default=False, blank=True)), - ('txn_id', models.CharField("Transaction ID", max_length=19, blank=True)), - ('txn_type', models.CharField("Transaction Type", max_length=128, blank=True)), - ('verify_sign', models.CharField(max_length=255, blank=True)), - ('address_country', models.CharField(max_length=64, blank=True)), - ('address_city', models.CharField(max_length=40, blank=True)), - ('address_country_code', models.CharField(max_length=64, blank=True)), - ('address_name', models.CharField(max_length=128, blank=True)), - ('address_state', models.CharField(max_length=40, blank=True)), - ('address_status', models.CharField(max_length=11, blank=True)), - ('address_street', models.CharField(max_length=200, blank=True)), - ('address_zip', models.CharField(max_length=20, blank=True)), - ('contact_phone', models.CharField(max_length=20, blank=True)), - ('first_name', models.CharField(max_length=64, blank=True)), - ('last_name', models.CharField(max_length=64, blank=True)), - ('payer_business_name', models.CharField(max_length=127, blank=True)), - ('payer_email', models.CharField(max_length=127, blank=True)), - ('payer_id', models.CharField(max_length=13, blank=True)), - ('auth_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('auth_exp', models.CharField(max_length=28, blank=True)), - ('auth_id', models.CharField(max_length=19, blank=True)), - ('auth_status', models.CharField(max_length=9, blank=True)), - ('exchange_rate', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=16, blank=True)), - ('invoice', models.CharField(max_length=127, blank=True)), - ('item_name', models.CharField(max_length=127, blank=True)), - ('item_number', models.CharField(max_length=127, blank=True)), - ('mc_currency', models.CharField(default='USD', max_length=32, blank=True)), - ('mc_fee', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_handling', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('memo', models.CharField(max_length=255, blank=True)), - ('num_cart_items', models.IntegerField(default=0, null=True, blank=True)), - ('option_name1', models.CharField(max_length=64, blank=True)), - ('option_name2', models.CharField(max_length=64, blank=True)), - ('payer_status', models.CharField(max_length=10, blank=True)), - ('payment_date', models.DateTimeField(null=True, blank=True)), - ('payment_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('payment_status', models.CharField(max_length=9, blank=True)), - ('payment_type', models.CharField(max_length=7, blank=True)), - ('pending_reason', models.CharField(max_length=14, blank=True)), - ('protection_eligibility', models.CharField(max_length=32, blank=True)), - ('quantity', models.IntegerField(default=1, null=True, blank=True)), - ('reason_code', models.CharField(max_length=15, blank=True)), - ('remaining_settle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('settle_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('settle_currency', models.CharField(max_length=32, blank=True)), - ('shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('shipping_method', models.CharField(max_length=255, blank=True)), - ('tax', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('transaction_entity', models.CharField(max_length=7, blank=True)), - ('auction_buyer_id', models.CharField(max_length=64, blank=True)), - ('auction_closing_date', models.DateTimeField(null=True, blank=True)), - ('auction_multi_item', models.IntegerField(default=0, null=True, blank=True)), - ('for_auction', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount_per_cycle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('initial_payment_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('next_payment_date', models.DateTimeField(null=True, blank=True)), - ('outstanding_balance', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('payment_cycle', models.CharField(max_length=32, blank=True)), - ('period_type', models.CharField(max_length=32, blank=True)), - ('product_name', models.CharField(max_length=128, blank=True)), - ('product_type', models.CharField(max_length=128, blank=True)), - ('profile_status', models.CharField(max_length=32, blank=True)), - ('recurring_payment_id', models.CharField(max_length=128, blank=True)), - ('rp_invoice_id', models.CharField(max_length=127, blank=True)), - ('time_created', models.DateTimeField(null=True, blank=True)), - ('amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('password', models.CharField(max_length=24, blank=True)), - ('period1', models.CharField(max_length=32, blank=True)), - ('period2', models.CharField(max_length=32, blank=True)), - ('period3', models.CharField(max_length=32, blank=True)), - ('reattempt', models.CharField(max_length=1, blank=True)), - ('recur_times', models.IntegerField(default=0, null=True, blank=True)), - ('recurring', models.CharField(max_length=1, blank=True)), - ('retry_at', models.DateTimeField(null=True, blank=True)), - ('subscr_date', models.DateTimeField(null=True, blank=True)), - ('subscr_effective', models.DateTimeField(null=True, blank=True)), - ('subscr_id', models.CharField(max_length=19, blank=True)), - ('username', models.CharField(max_length=64, blank=True)), - ('case_creation_date', models.DateTimeField(null=True, blank=True)), - ('case_id', models.CharField(max_length=14, blank=True)), - ('case_type', models.CharField(max_length=24, blank=True)), - ('receipt_id', models.CharField(max_length=64, blank=True)), - ('currency_code', models.CharField(default='USD', max_length=32, blank=True)), - ('handling_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('transaction_subject', models.CharField(max_length=255, blank=True)), - ('ipaddress', models.IPAddressField(blank=True)), - ('flag', models.BooleanField(default=False, blank=True)), - ('flag_code', models.CharField(max_length=16, blank=True)), - ('flag_info', models.TextField(blank=True)), - ('query', models.TextField(blank=True)), - ('response', models.TextField(blank=True)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('from_view', models.CharField(max_length=6, null=True, blank=True)), - )) - db.send_create_signal('ipn', ['PayPalIPN']) - - def backwards(self, orm): - # Deleting model 'PayPalIPN' - db.delete_table('paypal_ipn') - - - models = { - 'ipn.paypalipn': { - 'Meta': {'db_table': '"paypal_ipn"'}, - 'address_city': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}), - 'address_country': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'address_country_code': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'address_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'address_state': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}), - 'address_status': ('models.CharField', [], {'max_length': '11', 'blank': 'True'}), - 'address_street': ('models.CharField', [], {'max_length': '200', 'blank': 'True'}), - 'address_zip': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount_per_cycle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'auction_buyer_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'auction_closing_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'auction_multi_item': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), - 'auth_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'auth_exp': ('models.CharField', [], {'max_length': '28', 'blank': 'True'}), - 'auth_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}), - 'auth_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}), - 'business': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'case_creation_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'case_id': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}), - 'case_type': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}), - 'charset': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'contact_phone': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'created_at': ('models.DateTimeField', [], {'auto_now_add': 'True'}), - 'currency_code': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}), - 'custom': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'exchange_rate': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16', 'blank': 'True'}), - 'first_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'flag': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'flag_code': ('models.CharField', [], {'max_length': '16', 'blank': 'True'}), - 'flag_info': ('models.TextField', [], {'blank': 'True'}), - 'for_auction': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'from_view': ('models.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}), - 'handling_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'id': ('models.AutoField', [], {'primary_key': 'True'}), - 'initial_payment_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'invoice': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'ipaddress': ('models.IPAddressField', [], {'blank': 'True'}), - 'item_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'item_number': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'last_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'mc_amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_currency': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}), - 'mc_fee': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_handling': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'memo': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'next_payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'notify_version': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'num_cart_items': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), - 'option_name1': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'option_name2': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'outstanding_balance': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'parent_txn_id': ('models.CharField', ['"Parent Transaction ID"'], {'max_length': '19', 'blank': 'True'}), - 'password': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}), - 'payer_business_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'payer_email': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'payer_id': ('models.CharField', [], {'max_length': '13', 'blank': 'True'}), - 'payer_status': ('models.CharField', [], {'max_length': '10', 'blank': 'True'}), - 'payment_cycle': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'payment_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'payment_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}), - 'payment_type': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}), - 'pending_reason': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}), - 'period1': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'period2': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'period3': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'period_type': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'product_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'product_type': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'profile_status': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'protection_eligibility': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'quantity': ('models.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}), - 'query': ('models.TextField', [], {'blank': 'True'}), - 'reason_code': ('models.CharField', [], {'max_length': '15', 'blank': 'True'}), - 'reattempt': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}), - 'receipt_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'receiver_email': ('models.EmailField', [], {'max_length': '127', 'blank': 'True'}), - 'receiver_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'recur_times': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), - 'recurring': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}), - 'recurring_payment_id': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'remaining_settle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'residence_country': ('models.CharField', [], {'max_length': '2', 'blank': 'True'}), - 'response': ('models.TextField', [], {'blank': 'True'}), - 'retry_at': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'rp_invoice_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'settle_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'settle_currency': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'shipping_method': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'subscr_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'subscr_effective': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'subscr_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}), - 'tax': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'test_ipn': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'time_created': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'transaction_entity': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}), - 'transaction_subject': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'txn_id': ('models.CharField', ['"Transaction ID"'], {'max_length': '19', 'blank': 'True'}), - 'txn_type': ('models.CharField', ['"Transaction Type"'], {'max_length': '128', 'blank': 'True'}), - 'updated_at': ('models.DateTimeField', [], {'auto_now': 'True'}), - 'username': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'verify_sign': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}) - } - } - - complete_apps = ['ipn'] \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/migrations/__init__.py b/csesoc/paypal/standard/ipn/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/paypal/standard/ipn/models.py b/csesoc/paypal/standard/ipn/models.py deleted file mode 100644 index 7e6df1a..0000000 --- a/csesoc/paypal/standard/ipn/models.py +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -import urllib2 -from paypal.standard.models import PayPalStandardBase -from paypal.standard.ipn.signals import * - - -class PayPalIPN(PayPalStandardBase): - """Logs PayPal IPN interactions.""" - format = u"" - - class Meta: - db_table = "paypal_ipn" - verbose_name = "PayPal IPN" - - def _postback(self): - """Perform PayPal Postback validation.""" - return urllib2.urlopen(self.get_endpoint(), "cmd=_notify-validate&%s" % self.query).read() - - def _verify_postback(self): - if self.response != "VERIFIED": - self.set_flag("Invalid postback. (%s)" % self.response) - - def send_signals(self): - """Shout for the world to hear whether a txn was successful.""" - # Transaction signals: - if self.is_transaction(): - if self.flag: - payment_was_flagged.send(sender=self) - else: - payment_was_successful.send(sender=self) - # Subscription signals: - else: - if self.is_subscription_cancellation(): - subscription_cancel.send(sender=self) - elif self.is_subscription_signup(): - subscription_signup.send(sender=self) - elif self.is_subscription_end_of_term(): - subscription_eot.send(sender=self) - elif self.is_subscription_modified(): - subscription_modify.send(sender=self) \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/signals.py b/csesoc/paypal/standard/ipn/signals.py deleted file mode 100644 index 12ba61d..0000000 --- a/csesoc/paypal/standard/ipn/signals.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Note that sometimes you will get duplicate signals emitted, depending on configuration of your systems. -If you do encounter this, you will need to add the "dispatch_uid" to your connect handlers: -http://code.djangoproject.com/wiki/Signals#Helppost_saveseemstobeemittedtwiceforeachsave - -""" -from django.dispatch import Signal - -# Sent when a payment is successfully processed. -payment_was_successful = Signal() - -# Sent when a payment is flagged. -payment_was_flagged = Signal() - -# Sent when a subscription was cancelled. -subscription_cancel = Signal() - -# Sent when a subscription expires. -subscription_eot = Signal() - -# Sent when a subscription was modified. -subscription_modify = Signal() - -# Sent when a subscription is created. -subscription_signup = Signal() \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/templates/ipn/ipn.html b/csesoc/paypal/standard/ipn/templates/ipn/ipn.html deleted file mode 100644 index cd07c1e..0000000 --- a/csesoc/paypal/standard/ipn/templates/ipn/ipn.html +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - -
- - {{ form.as_p }} - - - - - -
- -
-
- - - - - - - diff --git a/csesoc/paypal/standard/ipn/templates/ipn/ipn_test.html b/csesoc/paypal/standard/ipn/templates/ipn/ipn_test.html deleted file mode 100644 index 6d90062..0000000 --- a/csesoc/paypal/standard/ipn/templates/ipn/ipn_test.html +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/templates/ipn/paypal.html b/csesoc/paypal/standard/ipn/templates/ipn/paypal.html deleted file mode 100644 index 695b241..0000000 --- a/csesoc/paypal/standard/ipn/templates/ipn/paypal.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - -{{ form.sandbox }} - - - - - - - - diff --git a/csesoc/paypal/standard/ipn/tests/__init__.py b/csesoc/paypal/standard/ipn/tests/__init__.py deleted file mode 100644 index 46c5a96..0000000 --- a/csesoc/paypal/standard/ipn/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from test_ipn import * \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/tests/test_ipn.py b/csesoc/paypal/standard/ipn/tests/test_ipn.py deleted file mode 100644 index 243cb4b..0000000 --- a/csesoc/paypal/standard/ipn/tests/test_ipn.py +++ /dev/null @@ -1,114 +0,0 @@ -from django.conf import settings -from django.http import HttpResponse -from django.test import TestCase -from django.test.client import Client - -from paypal.standard.ipn.models import PayPalIPN -from paypal.standard.ipn.signals import (payment_was_successful, - payment_was_flagged) - - -IPN_POST_PARAMS = { - "protection_eligibility": "Ineligible", - "last_name": "User", - "txn_id": "51403485VH153354B", - "receiver_email": settings.PAYPAL_RECEIVER_EMAIL, - "payment_status": "Completed", - "payment_gross": "10.00", - "tax": "0.00", - "residence_country": "US", - "invoice": "0004", - "payer_status": "verified", - "txn_type": "express_checkout", - "handling_amount": "0.00", - "payment_date": "23:04:06 Feb 02, 2009 PST", - "first_name": "Test", - "item_name": "", - "charset": "windows-1252", - "custom": "website_id=13&user_id=21", - "notify_version": "2.6", - "transaction_subject": "", - "test_ipn": "1", - "item_number": "", - "receiver_id": "258DLEHY2BDK6", - "payer_id": "BN5JZ2V7MLEV4", - "verify_sign": "An5ns1Kso7MWUdW4ErQKJJJ4qi4-AqdZy6dD.sGO3sDhTf1wAbuO2IZ7", - "payment_fee": "0.59", - "mc_fee": "0.59", - "mc_currency": "USD", - "shipping": "0.00", - "payer_email": "bishan_1233269544_per@gmail.com", - "payment_type": "instant", - "mc_gross": "10.00", - "quantity": "1", -} - - -class IPNTest(TestCase): - urls = 'paypal.standard.ipn.tests.test_urls' - - def setUp(self): - self.old_debug = settings.DEBUG - settings.DEBUG = True - - # Monkey patch over PayPalIPN to make it get a VERFIED response. - self.old_postback = PayPalIPN._postback - PayPalIPN._postback = lambda self: "VERIFIED" - - def tearDown(self): - settings.DEBUG = self.old_debug - PayPalIPN._postback = self.old_postback - - def assertGotSignal(self, signal, flagged): - # Check the signal was sent. These get lost if they don't reference self. - self.got_signal = False - self.signal_obj = None - - def handle_signal(sender, **kwargs): - self.got_signal = True - self.signal_obj = sender - signal.connect(handle_signal) - - response = self.client.post("/ipn/", IPN_POST_PARAMS) - self.assertEqual(response.status_code, 200) - ipns = PayPalIPN.objects.all() - self.assertEqual(len(ipns), 1) - ipn_obj = ipns[0] - self.assertEqual(ipn_obj.flag, flagged) - - self.assertTrue(self.got_signal) - self.assertEqual(self.signal_obj, ipn_obj) - - def test_correct_ipn(self): - self.assertGotSignal(payment_was_successful, False) - - def test_failed_ipn(self): - PayPalIPN._postback = lambda self: "INVALID" - self.assertGotSignal(payment_was_flagged, True) - - def assertFlagged(self, updates, flag_info): - params = IPN_POST_PARAMS.copy() - params.update(updates) - response = self.client.post("/ipn/", params) - self.assertEqual(response.status_code, 200) - ipn_obj = PayPalIPN.objects.all()[0] - self.assertEqual(ipn_obj.flag, True) - self.assertEqual(ipn_obj.flag_info, flag_info) - - def test_incorrect_receiver_email(self): - update = {"receiver_email": "incorrect_email@someotherbusiness.com"} - flag_info = "Invalid receiver_email. (incorrect_email@someotherbusiness.com)" - self.assertFlagged(update, flag_info) - - def test_invalid_payment_status(self): - update = {"payment_status": "Failed"} - flag_info = "Invalid payment_status. (Failed)" - self.assertFlagged(update, flag_info) - - def test_duplicate_txn_id(self): - self.client.post("/ipn/", IPN_POST_PARAMS) - self.client.post("/ipn/", IPN_POST_PARAMS) - self.assertEqual(len(PayPalIPN.objects.all()), 2) - ipn_obj = PayPalIPN.objects.order_by('-created_at')[1] - self.assertEqual(ipn_obj.flag, True) - self.assertEqual(ipn_obj.flag_info, "Duplicate txn_id. (51403485VH153354B)") \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/tests/test_urls.py b/csesoc/paypal/standard/ipn/tests/test_urls.py deleted file mode 100644 index 55d7f07..0000000 --- a/csesoc/paypal/standard/ipn/tests/test_urls.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.conf.urls.defaults import * - -urlpatterns = patterns('paypal.standard.ipn.views', - (r'^ipn/$', 'ipn'), -) diff --git a/csesoc/paypal/standard/ipn/urls.py b/csesoc/paypal/standard/ipn/urls.py deleted file mode 100644 index 9de742b..0000000 --- a/csesoc/paypal/standard/ipn/urls.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.conf.urls.defaults import * - -urlpatterns = patterns('paypal.standard.ipn.views', - url(r'^$', 'ipn', name="paypal-ipn"), -) \ No newline at end of file diff --git a/csesoc/paypal/standard/ipn/views.py b/csesoc/paypal/standard/ipn/views.py deleted file mode 100644 index 7da8113..0000000 --- a/csesoc/paypal/standard/ipn/views.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django.http import HttpResponse -from django.views.decorators.http import require_POST -from paypal.standard.ipn.forms import PayPalIPNForm -from paypal.standard.ipn.models import PayPalIPN - - -@require_POST -def ipn(request, item_check_callable=None): - """ - PayPal IPN endpoint (notify_url). - Used by both PayPal Payments Pro and Payments Standard to confirm transactions. - http://tinyurl.com/d9vu9d - - PayPal IPN Simulator: - https://developer.paypal.com/cgi-bin/devscr?cmd=_ipn-link-session - """ - flag = None - ipn_obj = None - form = PayPalIPNForm(request.POST) - if form.is_valid(): - try: - ipn_obj = form.save(commit=False) - except Exception, e: - flag = "Exception while processing. (%s)" % e - else: - flag = "Invalid form. (%s)" % form.errors - - if ipn_obj is None: - ipn_obj = PayPalIPN() - - ipn_obj.initialize(request) - - if flag is not None: - ipn_obj.set_flag(flag) - else: - # Secrets should only be used over SSL. - if request.is_secure() and 'secret' in request.GET: - ipn_obj.verify_secret(form, request.GET['secret']) - else: - ipn_obj.verify(item_check_callable) - - ipn_obj.save() - return HttpResponse("OKAY") \ No newline at end of file diff --git a/csesoc/paypal/standard/models.py b/csesoc/paypal/standard/models.py deleted file mode 100644 index 6b8a62f..0000000 --- a/csesoc/paypal/standard/models.py +++ /dev/null @@ -1,260 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django.db import models -from django.conf import settings -from paypal.standard.helpers import duplicate_txn_id, check_secret -from paypal.standard.conf import RECEIVER_EMAIL, POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT - - -class PayPalStandardBase(models.Model): - """Meta class for common variables shared by IPN and PDT: http://tinyurl.com/cuq6sj""" - # @@@ Might want to add all these one distant day. - # FLAG_CODE_CHOICES = ( - # PAYMENT_STATUS_CHOICES = "Canceled_ Reversal Completed Denied Expired Failed Pending Processed Refunded Reversed Voided".split() - # AUTH_STATUS_CHOICES = "Completed Pending Voided".split() - # ADDRESS_STATUS_CHOICES = "confirmed unconfirmed".split() - # PAYER_STATUS_CHOICES = "verified / unverified".split() - # PAYMENT_TYPE_CHOICES = "echeck / instant.split() - # PENDING_REASON = "address authorization echeck intl multi-currency unilateral upgrade verify other".split() - # REASON_CODE = "chargeback guarantee buyer_complaint refund other".split() - # TRANSACTION_ENTITY_CHOICES = "auth reauth order payment".split() - - # Transaction and Notification-Related Variables - business = models.CharField(max_length=127, blank=True, help_text="Email where the money was sent.") - charset=models.CharField(max_length=32, blank=True) - custom = models.CharField(max_length=255, blank=True) - notify_version = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - parent_txn_id = models.CharField("Parent Transaction ID", max_length=19, blank=True) - receiver_email = models.EmailField(max_length=127, blank=True) - receiver_id = models.CharField(max_length=127, blank=True) # 258DLEHY2BDK6 - residence_country = models.CharField(max_length=2, blank=True) - test_ipn = models.BooleanField(default=False, blank=True) - txn_id = models.CharField("Transaction ID", max_length=19, blank=True, help_text="PayPal transaction ID.") - txn_type = models.CharField("Transaction Type", max_length=128, blank=True, help_text="PayPal transaction type.") - verify_sign = models.CharField(max_length=255, blank=True) - - # Buyer Information Variables - address_country = models.CharField(max_length=64, blank=True) - address_city = models.CharField(max_length=40, blank=True) - address_country_code = models.CharField(max_length=64, blank=True, help_text="ISO 3166") - address_name = models.CharField(max_length=128, blank=True) - address_state = models.CharField(max_length=40, blank=True) - address_status = models.CharField(max_length=11, blank=True) - address_street = models.CharField(max_length=200, blank=True) - address_zip = models.CharField(max_length=20, blank=True) - contact_phone = models.CharField(max_length=20, blank=True) - first_name = models.CharField(max_length=64, blank=True) - last_name = models.CharField(max_length=64, blank=True) - payer_business_name = models.CharField(max_length=127, blank=True) - payer_email = models.CharField(max_length=127, blank=True) - payer_id = models.CharField(max_length=13, blank=True) - - # Payment Information Variables - auth_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - auth_exp = models.CharField(max_length=28, blank=True) - auth_id = models.CharField(max_length=19, blank=True) - auth_status = models.CharField(max_length=9, blank=True) - exchange_rate = models.DecimalField(max_digits=64, decimal_places=16, default=0, blank=True, null=True) - invoice = models.CharField(max_length=127, blank=True) - item_name = models.CharField(max_length=127, blank=True) - item_number = models.CharField(max_length=127, blank=True) - mc_currency = models.CharField(max_length=32, default="USD", blank=True) - mc_fee = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - mc_gross = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - mc_handling = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - mc_shipping = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - memo = models.CharField(max_length=255, blank=True) - num_cart_items = models.IntegerField(blank=True, default=0, null=True) - option_name1 = models.CharField(max_length=64, blank=True) - option_name2 = models.CharField(max_length=64, blank=True) - payer_status = models.CharField(max_length=10, blank=True) - payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - payment_gross = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - payment_status = models.CharField(max_length=9, blank=True) - payment_type = models.CharField(max_length=7, blank=True) - pending_reason = models.CharField(max_length=14, blank=True) - protection_eligibility=models.CharField(max_length=32, blank=True) - quantity = models.IntegerField(blank=True, default=1, null=True) - reason_code = models.CharField(max_length=15, blank=True) - remaining_settle = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - settle_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - settle_currency = models.CharField(max_length=32, blank=True) - shipping = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - shipping_method = models.CharField(max_length=255, blank=True) - tax = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - transaction_entity = models.CharField(max_length=7, blank=True) - - # Auction Variables - auction_buyer_id = models.CharField(max_length=64, blank=True) - auction_closing_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - auction_multi_item = models.IntegerField(blank=True, default=0, null=True) - for_auction = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - - # Recurring Payments Variables - amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - amount_per_cycle = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - initial_payment_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - next_payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - outstanding_balance = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - payment_cycle= models.CharField(max_length=32, blank=True) #Monthly - period_type = models.CharField(max_length=32, blank=True) - product_name = models.CharField(max_length=128, blank=True) - product_type= models.CharField(max_length=128, blank=True) - profile_status = models.CharField(max_length=32, blank=True) - recurring_payment_id = models.CharField(max_length=128, blank=True) # I-FA4XVST722B9 - rp_invoice_id= models.CharField(max_length=127, blank=True) # 1335-7816-2936-1451 - time_created = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - - # Subscription Variables - amount1 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - amount2 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - amount3 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - mc_amount1 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - mc_amount2 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - mc_amount3 = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - password = models.CharField(max_length=24, blank=True) - period1 = models.CharField(max_length=32, blank=True) - period2 = models.CharField(max_length=32, blank=True) - period3 = models.CharField(max_length=32, blank=True) - reattempt = models.CharField(max_length=1, blank=True) - recur_times = models.IntegerField(blank=True, default=0, null=True) - recurring = models.CharField(max_length=1, blank=True) - retry_at = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - subscr_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - subscr_effective = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - subscr_id = models.CharField(max_length=19, blank=True) - username = models.CharField(max_length=64, blank=True) - - # Dispute Resolution Variables - case_creation_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - case_id = models.CharField(max_length=14, blank=True) - case_type = models.CharField(max_length=24, blank=True) - - # Variables not categorized - receipt_id= models.CharField(max_length=64, blank=True) # 1335-7816-2936-1451 - currency_code = models.CharField(max_length=32, default="USD", blank=True) - handling_amount = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - transaction_subject = models.CharField(max_length=255, blank=True) - - # @@@ Mass Pay Variables (Not Implemented, needs a separate model, for each transaction x) - # fraud_managment_pending_filters_x = models.CharField(max_length=255, blank=True) - # option_selection1_x = models.CharField(max_length=200, blank=True) - # option_selection2_x = models.CharField(max_length=200, blank=True) - # masspay_txn_id_x = models.CharField(max_length=19, blank=True) - # mc_currency_x = models.CharField(max_length=32, default="USD", blank=True) - # mc_fee_x = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - # mc_gross_x = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - # mc_handlingx = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - # payment_date = models.DateTimeField(blank=True, null=True, help_text="HH:MM:SS DD Mmm YY, YYYY PST") - # payment_status = models.CharField(max_length=9, blank=True) - # reason_code = models.CharField(max_length=15, blank=True) - # receiver_email_x = models.EmailField(max_length=127, blank=True) - # status_x = models.CharField(max_length=9, blank=True) - # unique_id_x = models.CharField(max_length=13, blank=True) - - # Non-PayPal Variables - full IPN/PDT query and time fields. - ipaddress = models.IPAddressField(blank=True) - flag = models.BooleanField(default=False, blank=True) - flag_code = models.CharField(max_length=16, blank=True) - flag_info = models.TextField(blank=True) - query = models.TextField(blank=True) # What we sent to PayPal. - response = models.TextField(blank=True) # What we got back. - created_at = models.DateTimeField(auto_now_add=True) - updated_at = models.DateTimeField(auto_now=True) - - class Meta: - abstract = True - - def __unicode__(self): - if self.is_transaction(): - return self.format % ("Transaction", self.txn_id) - else: - return self.format % ("Recurring", self.recurring_payment_id) - - def is_transaction(self): - return len(self.txn_id) > 0 - - def is_recurring(self): - return len(self.recurring_payment_id) > 0 - - def is_subscription_cancellation(self): - return self.txn_type == "subscr_cancel" - - def is_subscription_end_of_term(self): - return self.txn_type == "subscr_eot" - - def is_subscription_modified(self): - return self.txn_type == "subscr_modify" - - def is_subscription_signup(self): - return self.txn_type == "subscr_signup" - - def set_flag(self, info, code=None): - """Sets a flag on the transaction and also sets a reason.""" - self.flag = True - self.flag_info += info - if code is not None: - self.flag_code = code - - def verify(self, item_check_callable=None): - """ - Verifies an IPN and a PDT. - Checks for obvious signs of weirdness in the payment and flags appropriately. - - Provide a callable that takes an instance of this class as a parameter and returns - a tuple (False, None) if the item is valid. Should return (True, "reason") if the - item isn't valid. Strange but backward compatible :) This function should check - that `mc_gross`, `mc_currency` `item_name` and `item_number` are all correct. - - """ - self.response = self._postback() - self._verify_postback() - if not self.flag: - if self.is_transaction(): - if self.payment_status != "Completed": - self.set_flag("Invalid payment_status. (%s)" % self.payment_status) - if duplicate_txn_id(self): - self.set_flag("Duplicate txn_id. (%s)" % self.txn_id) - if self.receiver_email != RECEIVER_EMAIL: - self.set_flag("Invalid receiver_email. (%s)" % self.receiver_email) - if callable(item_check_callable): - flag, reason = item_check_callable(self) - if flag: - self.set_flag(reason) - else: - # @@@ Run a different series of checks on recurring payments. - pass - - self.save() - self.send_signals() - - def verify_secret(self, form_instance, secret): - """Verifies an IPN payment over SSL using EWP.""" - if not check_secret(form_instance, secret): - self.set_flag("Invalid secret. (%s)") % secret - self.save() - self.send_signals() - - def get_endpoint(self): - """Set Sandbox endpoint if the test variable is present.""" - if self.test_ipn: - return SANDBOX_POSTBACK_ENDPOINT - else: - return POSTBACK_ENDPOINT - - def initialize(self, request): - """Store the data we'll need to make the postback from the request object.""" - self.query = getattr(request, request.method).urlencode() - self.ipaddress = request.META.get('REMOTE_ADDR', '') - - def send_signals(self): - """After a transaction is completed use this to send success/fail signals""" - raise NotImplementedError - - def _postback(self): - """Perform postback to PayPal and store the response in self.response.""" - raise NotImplementedError - - def _verify_postback(self): - """Check self.response is valid andcall self.set_flag if there is an error.""" - raise NotImplementedError \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/__init__.py b/csesoc/paypal/standard/pdt/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/paypal/standard/pdt/admin.py b/csesoc/paypal/standard/pdt/admin.py deleted file mode 100644 index d7f16cb..0000000 --- a/csesoc/paypal/standard/pdt/admin.py +++ /dev/null @@ -1,48 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from string import split as L -from django.contrib import admin -from paypal.standard.pdt.models import PayPalPDT - - -# ToDo: How similiar is this to PayPalIPNAdmin? Could we just inherit off one common admin model? -class PayPalPDTAdmin(admin.ModelAdmin): - date_hierarchy = 'payment_date' - fieldsets = ( - (None, { - "fields": L("flag txn_id txn_type payment_status payment_date transaction_entity reason_code pending_reason mc_gross mc_fee auth_status auth_amount auth_exp auth_id") - }), - ("Address", { - "description": "The address of the Buyer.", - 'classes': ('collapse',), - "fields": L("address_city address_country address_country_code address_name address_state address_status address_street address_zip") - }), - ("Buyer", { - "description": "The information about the Buyer.", - 'classes': ('collapse',), - "fields": L("first_name last_name payer_business_name payer_email payer_id payer_status contact_phone residence_country") - }), - ("Seller", { - "description": "The information about the Seller.", - 'classes': ('collapse',), - "fields": L("business item_name item_number quantity receiver_email receiver_id custom invoice memo") - }), - ("Subscriber", { - "description": "The information about the Subscription.", - 'classes': ('collapse',), - "fields": L("subscr_id subscr_date subscr_effective") - }), - ("Recurring", { - "description": "Information about recurring Payments.", - "classes": ("collapse",), - "fields": L("profile_status initial_payment_amount amount_per_cycle outstanding_balance period_type product_name product_type recurring_payment_id receipt_id next_payment_date") - }), - ("Admin", { - "description": "Additional Info.", - "classes": ('collapse',), - "fields": L("test_ipn ipaddress query flag_code flag_info") - }), - ) - list_display = L("__unicode__ flag invoice custom payment_status created_at") - search_fields = L("txn_id recurring_payment_id") -admin.site.register(PayPalPDT, PayPalPDTAdmin) \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/forms.py b/csesoc/paypal/standard/pdt/forms.py deleted file mode 100644 index db6c4da..0000000 --- a/csesoc/paypal/standard/pdt/forms.py +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from paypal.standard.forms import PayPalStandardBaseForm -from paypal.standard.pdt.models import PayPalPDT - - -class PayPalPDTForm(PayPalStandardBaseForm): - class Meta: - model = PayPalPDT \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/migrations/0001_first_migration.py b/csesoc/paypal/standard/pdt/migrations/0001_first_migration.py deleted file mode 100644 index ab7b921..0000000 --- a/csesoc/paypal/standard/pdt/migrations/0001_first_migration.py +++ /dev/null @@ -1,263 +0,0 @@ -# -*- coding: utf-8 -*- - -from south.db import db -from django.db import models -from paypal.standard.pdt.models import * - -class Migration: - - def forwards(self, orm): - - # Adding model 'PayPalPDT' - db.create_table('paypal_pdt', ( - ('id', models.AutoField(primary_key=True)), - ('business', models.CharField(max_length=127, blank=True)), - ('charset', models.CharField(max_length=32, blank=True)), - ('custom', models.CharField(max_length=255, blank=True)), - ('notify_version', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('parent_txn_id', models.CharField("Parent Transaction ID", max_length=19, blank=True)), - ('receiver_email', models.EmailField(max_length=127, blank=True)), - ('receiver_id', models.CharField(max_length=127, blank=True)), - ('residence_country', models.CharField(max_length=2, blank=True)), - ('test_ipn', models.BooleanField(default=False, blank=True)), - ('txn_id', models.CharField("Transaction ID", max_length=19, blank=True)), - ('txn_type', models.CharField("Transaction Type", max_length=128, blank=True)), - ('verify_sign', models.CharField(max_length=255, blank=True)), - ('address_country', models.CharField(max_length=64, blank=True)), - ('address_city', models.CharField(max_length=40, blank=True)), - ('address_country_code', models.CharField(max_length=64, blank=True)), - ('address_name', models.CharField(max_length=128, blank=True)), - ('address_state', models.CharField(max_length=40, blank=True)), - ('address_status', models.CharField(max_length=11, blank=True)), - ('address_street', models.CharField(max_length=200, blank=True)), - ('address_zip', models.CharField(max_length=20, blank=True)), - ('contact_phone', models.CharField(max_length=20, blank=True)), - ('first_name', models.CharField(max_length=64, blank=True)), - ('last_name', models.CharField(max_length=64, blank=True)), - ('payer_business_name', models.CharField(max_length=127, blank=True)), - ('payer_email', models.CharField(max_length=127, blank=True)), - ('payer_id', models.CharField(max_length=13, blank=True)), - ('auth_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('auth_exp', models.CharField(max_length=28, blank=True)), - ('auth_id', models.CharField(max_length=19, blank=True)), - ('auth_status', models.CharField(max_length=9, blank=True)), - ('exchange_rate', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=16, blank=True)), - ('invoice', models.CharField(max_length=127, blank=True)), - ('item_name', models.CharField(max_length=127, blank=True)), - ('item_number', models.CharField(max_length=127, blank=True)), - ('mc_currency', models.CharField(default='USD', max_length=32, blank=True)), - ('mc_fee', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_handling', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('memo', models.CharField(max_length=255, blank=True)), - ('num_cart_items', models.IntegerField(default=0, null=True, blank=True)), - ('option_name1', models.CharField(max_length=64, blank=True)), - ('option_name2', models.CharField(max_length=64, blank=True)), - ('payer_status', models.CharField(max_length=10, blank=True)), - ('payment_date', models.DateTimeField(null=True, blank=True)), - ('payment_gross', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('payment_status', models.CharField(max_length=9, blank=True)), - ('payment_type', models.CharField(max_length=7, blank=True)), - ('pending_reason', models.CharField(max_length=14, blank=True)), - ('protection_eligibility', models.CharField(max_length=32, blank=True)), - ('quantity', models.IntegerField(default=1, null=True, blank=True)), - ('reason_code', models.CharField(max_length=15, blank=True)), - ('remaining_settle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('settle_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('settle_currency', models.CharField(max_length=32, blank=True)), - ('shipping', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('shipping_method', models.CharField(max_length=255, blank=True)), - ('tax', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('transaction_entity', models.CharField(max_length=7, blank=True)), - ('auction_buyer_id', models.CharField(max_length=64, blank=True)), - ('auction_closing_date', models.DateTimeField(null=True, blank=True)), - ('auction_multi_item', models.IntegerField(default=0, null=True, blank=True)), - ('for_auction', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount_per_cycle', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('initial_payment_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('next_payment_date', models.DateTimeField(null=True, blank=True)), - ('outstanding_balance', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('payment_cycle', models.CharField(max_length=32, blank=True)), - ('period_type', models.CharField(max_length=32, blank=True)), - ('product_name', models.CharField(max_length=128, blank=True)), - ('product_type', models.CharField(max_length=128, blank=True)), - ('profile_status', models.CharField(max_length=32, blank=True)), - ('recurring_payment_id', models.CharField(max_length=128, blank=True)), - ('rp_invoice_id', models.CharField(max_length=127, blank=True)), - ('time_created', models.DateTimeField(null=True, blank=True)), - ('amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_amount1', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_amount2', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('mc_amount3', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('password', models.CharField(max_length=24, blank=True)), - ('period1', models.CharField(max_length=32, blank=True)), - ('period2', models.CharField(max_length=32, blank=True)), - ('period3', models.CharField(max_length=32, blank=True)), - ('reattempt', models.CharField(max_length=1, blank=True)), - ('recur_times', models.IntegerField(default=0, null=True, blank=True)), - ('recurring', models.CharField(max_length=1, blank=True)), - ('retry_at', models.DateTimeField(null=True, blank=True)), - ('subscr_date', models.DateTimeField(null=True, blank=True)), - ('subscr_effective', models.DateTimeField(null=True, blank=True)), - ('subscr_id', models.CharField(max_length=19, blank=True)), - ('username', models.CharField(max_length=64, blank=True)), - ('case_creation_date', models.DateTimeField(null=True, blank=True)), - ('case_id', models.CharField(max_length=14, blank=True)), - ('case_type', models.CharField(max_length=24, blank=True)), - ('receipt_id', models.CharField(max_length=64, blank=True)), - ('currency_code', models.CharField(default='USD', max_length=32, blank=True)), - ('handling_amount', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('transaction_subject', models.CharField(max_length=255, blank=True)), - ('ipaddress', models.IPAddressField(blank=True)), - ('flag', models.BooleanField(default=False, blank=True)), - ('flag_code', models.CharField(max_length=16, blank=True)), - ('flag_info', models.TextField(blank=True)), - ('query', models.TextField(blank=True)), - ('response', models.TextField(blank=True)), - ('created_at', models.DateTimeField(auto_now_add=True)), - ('updated_at', models.DateTimeField(auto_now=True)), - ('from_view', models.CharField(max_length=6, null=True, blank=True)), - ('amt', models.DecimalField(default=0, null=True, max_digits=64, decimal_places=2, blank=True)), - ('cm', models.CharField(max_length=255, blank=True)), - ('sig', models.CharField(max_length=255, blank=True)), - ('tx', models.CharField(max_length=255, blank=True)), - ('st', models.CharField(max_length=32, blank=True)), - )) - db.send_create_signal('pdt', ['PayPalPDT']) - - - - def backwards(self, orm): - - # Deleting model 'PayPalPDT' - db.delete_table('paypal_pdt') - - - - models = { - 'pdt.paypalpdt': { - 'Meta': {'db_table': '"paypal_pdt"'}, - 'address_city': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}), - 'address_country': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'address_country_code': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'address_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'address_state': ('models.CharField', [], {'max_length': '40', 'blank': 'True'}), - 'address_status': ('models.CharField', [], {'max_length': '11', 'blank': 'True'}), - 'address_street': ('models.CharField', [], {'max_length': '200', 'blank': 'True'}), - 'address_zip': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amount_per_cycle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'amt': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'auction_buyer_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'auction_closing_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'auction_multi_item': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), - 'auth_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'auth_exp': ('models.CharField', [], {'max_length': '28', 'blank': 'True'}), - 'auth_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}), - 'auth_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}), - 'business': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'case_creation_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'case_id': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}), - 'case_type': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}), - 'charset': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'cm': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'contact_phone': ('models.CharField', [], {'max_length': '20', 'blank': 'True'}), - 'created_at': ('models.DateTimeField', [], {'auto_now_add': 'True'}), - 'currency_code': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}), - 'custom': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'exchange_rate': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '16', 'blank': 'True'}), - 'first_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'flag': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'flag_code': ('models.CharField', [], {'max_length': '16', 'blank': 'True'}), - 'flag_info': ('models.TextField', [], {'blank': 'True'}), - 'for_auction': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'from_view': ('models.CharField', [], {'max_length': '6', 'null': 'True', 'blank': 'True'}), - 'handling_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'id': ('models.AutoField', [], {'primary_key': 'True'}), - 'initial_payment_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'invoice': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'ipaddress': ('models.IPAddressField', [], {'blank': 'True'}), - 'item_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'item_number': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'last_name': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'mc_amount1': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_amount2': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_amount3': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_currency': ('models.CharField', [], {'default': "'USD'", 'max_length': '32', 'blank': 'True'}), - 'mc_fee': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_handling': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'mc_shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'memo': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'next_payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'notify_version': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'num_cart_items': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), - 'option_name1': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'option_name2': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'outstanding_balance': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'parent_txn_id': ('models.CharField', ['"Parent Transaction ID"'], {'max_length': '19', 'blank': 'True'}), - 'password': ('models.CharField', [], {'max_length': '24', 'blank': 'True'}), - 'payer_business_name': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'payer_email': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'payer_id': ('models.CharField', [], {'max_length': '13', 'blank': 'True'}), - 'payer_status': ('models.CharField', [], {'max_length': '10', 'blank': 'True'}), - 'payment_cycle': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'payment_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'payment_gross': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'payment_status': ('models.CharField', [], {'max_length': '9', 'blank': 'True'}), - 'payment_type': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}), - 'pending_reason': ('models.CharField', [], {'max_length': '14', 'blank': 'True'}), - 'period1': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'period2': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'period3': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'period_type': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'product_name': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'product_type': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'profile_status': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'protection_eligibility': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'quantity': ('models.IntegerField', [], {'default': '1', 'null': 'True', 'blank': 'True'}), - 'query': ('models.TextField', [], {'blank': 'True'}), - 'reason_code': ('models.CharField', [], {'max_length': '15', 'blank': 'True'}), - 'reattempt': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}), - 'receipt_id': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'receiver_email': ('models.EmailField', [], {'max_length': '127', 'blank': 'True'}), - 'receiver_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'recur_times': ('models.IntegerField', [], {'default': '0', 'null': 'True', 'blank': 'True'}), - 'recurring': ('models.CharField', [], {'max_length': '1', 'blank': 'True'}), - 'recurring_payment_id': ('models.CharField', [], {'max_length': '128', 'blank': 'True'}), - 'remaining_settle': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'residence_country': ('models.CharField', [], {'max_length': '2', 'blank': 'True'}), - 'response': ('models.TextField', [], {'blank': 'True'}), - 'retry_at': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'rp_invoice_id': ('models.CharField', [], {'max_length': '127', 'blank': 'True'}), - 'settle_amount': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'settle_currency': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'shipping': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'shipping_method': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'sig': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'st': ('models.CharField', [], {'max_length': '32', 'blank': 'True'}), - 'subscr_date': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'subscr_effective': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'subscr_id': ('models.CharField', [], {'max_length': '19', 'blank': 'True'}), - 'tax': ('models.DecimalField', [], {'default': '0', 'null': 'True', 'max_digits': '64', 'decimal_places': '2', 'blank': 'True'}), - 'test_ipn': ('models.BooleanField', [], {'default': 'False', 'blank': 'True'}), - 'time_created': ('models.DateTimeField', [], {'null': 'True', 'blank': 'True'}), - 'transaction_entity': ('models.CharField', [], {'max_length': '7', 'blank': 'True'}), - 'transaction_subject': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'tx': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}), - 'txn_id': ('models.CharField', ['"Transaction ID"'], {'max_length': '19', 'blank': 'True'}), - 'txn_type': ('models.CharField', ['"Transaction Type"'], {'max_length': '128', 'blank': 'True'}), - 'updated_at': ('models.DateTimeField', [], {'auto_now': 'True'}), - 'username': ('models.CharField', [], {'max_length': '64', 'blank': 'True'}), - 'verify_sign': ('models.CharField', [], {'max_length': '255', 'blank': 'True'}) - } - } - - complete_apps = ['pdt'] diff --git a/csesoc/paypal/standard/pdt/migrations/__init__.py b/csesoc/paypal/standard/pdt/migrations/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/paypal/standard/pdt/models.py b/csesoc/paypal/standard/pdt/models.py deleted file mode 100644 index 9129e81..0000000 --- a/csesoc/paypal/standard/pdt/models.py +++ /dev/null @@ -1,90 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from urllib import unquote_plus -import urllib2 -from django.db import models -from django.conf import settings -from django.http import QueryDict -from django.utils.http import urlencode -from paypal.standard.models import PayPalStandardBase -from paypal.standard.conf import POSTBACK_ENDPOINT, SANDBOX_POSTBACK_ENDPOINT -from paypal.standard.pdt.signals import pdt_successful, pdt_failed - -# ### Todo: Move this logic to conf.py: -# if paypal.standard.pdt is in installed apps -# ... then check for this setting in conf.py -class PayPalSettingsError(Exception): - """Raised when settings are incorrect.""" - -try: - IDENTITY_TOKEN = settings.PAYPAL_IDENTITY_TOKEN -except: - raise PayPalSettingsError("You must set PAYPAL_IDENTITY_TOKEN in settings.py. Get this token by enabling PDT in your PayPal account.") - - -class PayPalPDT(PayPalStandardBase): - format = u"" - - amt = models.DecimalField(max_digits=64, decimal_places=2, default=0, blank=True, null=True) - cm = models.CharField(max_length=255, blank=True) - sig = models.CharField(max_length=255, blank=True) - tx = models.CharField(max_length=255, blank=True) - st = models.CharField(max_length=32, blank=True) - - class Meta: - db_table = "paypal_pdt" - verbose_name = "PayPal PDT" - - def _postback(self): - """ - Perform PayPal PDT Postback validation. - Sends the transaction ID and business token to PayPal which responses with - SUCCESS or FAILED. - - """ - postback_dict = dict(cmd="_notify-synch", at=IDENTITY_TOKEN, tx=self.tx) - postback_params = urlencode(postback_dict) - return urllib2.urlopen(self.get_endpoint(), postback_params).read() - - def get_endpoint(self): - """Use the sandbox when in DEBUG mode as we don't have a test_ipn variable in pdt.""" - if settings.DEBUG: - return SANDBOX_POSTBACK_ENDPOINT - else: - return POSTBACK_ENDPOINT - - def _verify_postback(self): - # ### Now we don't really care what result was, just whether a flag was set or not. - from paypal.standard.pdt.forms import PayPalPDTForm - result = False - response_list = self.response.split('\n') - response_dict = {} - for i, line in enumerate(response_list): - unquoted_line = unquote_plus(line).strip() - if i == 0: - self.st = unquoted_line - if self.st == "SUCCESS": - result = True - else: - if self.st != "SUCCESS": - self.set_flag(line) - break - try: - if not unquoted_line.startswith(' -'): - k, v = unquoted_line.split('=') - response_dict[k.strip()] = v.strip() - except ValueError, e: - pass - - qd = QueryDict('', mutable=True) - qd.update(response_dict) - qd.update(dict(ipaddress=self.ipaddress, st=self.st, flag_info=self.flag_info)) - pdt_form = PayPalPDTForm(qd, instance=self) - pdt_form.save(commit=False) - - def send_signals(self): - # Send the PDT signals... - if self.flag: - pdt_failed.send(sender=self) - else: - pdt_successful.send(sender=self) \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/signals.py b/csesoc/paypal/standard/pdt/signals.py deleted file mode 100644 index 8df31f1..0000000 --- a/csesoc/paypal/standard/pdt/signals.py +++ /dev/null @@ -1,25 +0,0 @@ -""" -Note that sometimes you will get duplicate signals emitted, depending on configuration of your systems. -If you do encounter this, you will need to add the "dispatch_uid" to your connect handlers: -http://code.djangoproject.com/wiki/Signals#Helppost_saveseemstobeemittedtwiceforeachsave - -""" -from django.dispatch import Signal - -# Sent when a payment is successfully processed. -pdt_successful = Signal() - -# Sent when a payment is flagged. -pdt_failed = Signal() - -# # Sent when a subscription was cancelled. -# subscription_cancel = Signal() -# -# # Sent when a subscription expires. -# subscription_eot = Signal() -# -# # Sent when a subscription was modified. -# subscription_modify = Signal() -# -# # Sent when a subscription ends. -# subscription_signup = Signal() \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/templates/pdt/pdt.html b/csesoc/paypal/standard/pdt/templates/pdt/pdt.html deleted file mode 100755 index f0f3dd4..0000000 --- a/csesoc/paypal/standard/pdt/templates/pdt/pdt.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "base.html" %} -{% block content %} - -{% ifequal pdt_obj.st 'SUCCESS' %} -

Transaction complete

-

Thank you for your payment

-

Please print this page for your records

- -
- - - - - - -
Payer:{{ pdt_obj.first_name }} {{ pdt_obj.last_name }}
Payer Email:{{ pdt_obj.payer_email }}
Amount:{{ pdt_obj.mc_currency }} {{ pdt_obj.mc_gross }}
Reference:{{ pdt_obj.txn_id }}
-
- -{% else %} -

Transaction Failed

-

Sorry transaction failed, please try a different form of payment

-{% endifequal %} - -{% endblock %} - - diff --git a/csesoc/paypal/standard/pdt/templates/pdt/test_pdt_response.html b/csesoc/paypal/standard/pdt/templates/pdt/test_pdt_response.html deleted file mode 100644 index affa30f..0000000 --- a/csesoc/paypal/standard/pdt/templates/pdt/test_pdt_response.html +++ /dev/null @@ -1,35 +0,0 @@ -{{st}} -mc_gross={{mc_gross}} -invoice=66 -settle_amount=289.83 -protection_eligibility=Ineligible -payer_id=8MZ9FQTSAMUPJ -tax=0.00 -payment_date=04%3A53%3A52+Apr+12%2C+2009+PDT -payment_status=Completed -charset=windows-1252 -first_name=Test -mc_fee=6.88 -exchange_rate=1.32876 -settle_currency=USD -custom={{custom}} -payer_status=verified -business={{business}} -quantity=1 -payer_email=buyer_1239119200_per%40yoursite.com -txn_id={{txn_id}} -payment_type=instant -last_name=User -receiver_email={{business}} -payment_fee= -receiver_id=746LDC2EQAP4W -txn_type=web_accept -item_name=Advertising+Campaign%3A+1+Month+%28225.00%29 -mc_currency=EUR -item_number= -residence_country=US -handling_amount=0.00 -transaction_subject={{custom}} -payment_gross= -shipping=0.00 - - \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/tests/__init__.py b/csesoc/paypal/standard/pdt/tests/__init__.py deleted file mode 100644 index 4b59eb2..0000000 --- a/csesoc/paypal/standard/pdt/tests/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from test_pdt import * \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/tests/templates/pdt/pdt.html b/csesoc/paypal/standard/pdt/tests/templates/pdt/pdt.html deleted file mode 100755 index e492b0a..0000000 --- a/csesoc/paypal/standard/pdt/tests/templates/pdt/pdt.html +++ /dev/null @@ -1,19 +0,0 @@ -{% ifequal pdt_obj.st 'SUCCESS' %} -

Transaction complete

-

Thank you for your payment

-

Please print this page for your records

- -
- - - - - - -
Payer:{{ pdt_obj.first_name }} {{ pdt_obj.last_name }}
Payer Email:{{ pdt_obj.payer_email }}
Amount:{{ pdt_obj.mc_currency }} {{ pdt_obj.mc_gross }}
Reference:{{ pdt_obj.txn_id }}
-
- -{% else %} -

Transaction Failed

-

Sorry transaction failed, please try a different form of payment

-{% endifequal %} \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/tests/test_pdt.py b/csesoc/paypal/standard/pdt/tests/test_pdt.py deleted file mode 100644 index dbcd8ff..0000000 --- a/csesoc/paypal/standard/pdt/tests/test_pdt.py +++ /dev/null @@ -1,118 +0,0 @@ -""" -run this with ./manage.py test website -see http://www.djangoproject.com/documentation/testing/ for details -""" -import os -from django.conf import settings -from django.shortcuts import render_to_response -from django.test import TestCase -from paypal.standard.pdt.forms import PayPalPDTForm -from paypal.standard.pdt.models import PayPalPDT -from paypal.standard.pdt.signals import pdt_successful, pdt_failed - - -class DummyPayPalPDT(object): - - def __init__(self, update_context_dict={}): - self.context_dict = {'st': 'SUCCESS', 'custom':'cb736658-3aad-4694-956f-d0aeade80194', - 'txn_id':'1ED550410S3402306', 'mc_gross': '225.00', - 'business': settings.PAYPAL_RECEIVER_EMAIL, 'error': 'Error code: 1234'} - - self.context_dict.update(update_context_dict) - - def update_with_get_params(self, get_params): - if get_params.has_key('tx'): - self.context_dict['txn_id'] = get_params.get('tx') - if get_params.has_key('amt'): - self.context_dict['mc_gross'] = get_params.get('amt') - if get_params.has_key('cm'): - self.context_dict['custom'] = get_params.get('cm') - - def _postback(self, test=True): - """Perform a Fake PayPal PDT Postback request.""" - # @@@ would be cool if this could live in the test templates dir... - return render_to_response("pdt/test_pdt_response.html", self.context_dict).content - -class PDTTest(TestCase): - urls = "paypal.standard.pdt.tests.test_urls" - template_dirs = [os.path.join(os.path.dirname(__file__), 'templates'),] - - def setUp(self): - # set up some dummy PDT get parameters - self.get_params = {"tx":"4WJ86550014687441", "st":"Completed", "amt":"225.00", "cc":"EUR", - "cm":"a3e192b8-8fea-4a86-b2e8-d5bf502e36be", "item_number":"", - "sig":"blahblahblah"} - - # monkey patch the PayPalPDT._postback function - self.dpppdt = DummyPayPalPDT() - self.dpppdt.update_with_get_params(self.get_params) - PayPalPDT._postback = self.dpppdt._postback - - def test_verify_postback(self): - dpppdt = DummyPayPalPDT() - paypal_response = dpppdt._postback() - assert('SUCCESS' in paypal_response) - self.assertEqual(len(PayPalPDT.objects.all()), 0) - pdt_obj = PayPalPDT() - pdt_obj.ipaddress = '127.0.0.1' - pdt_obj.response = paypal_response - pdt_obj._verify_postback() - self.assertEqual(len(PayPalPDT.objects.all()), 0) - self.assertEqual(pdt_obj.txn_id, '1ED550410S3402306') - - def test_pdt(self): - self.assertEqual(len(PayPalPDT.objects.all()), 0) - self.dpppdt.update_with_get_params(self.get_params) - paypal_response = self.client.get("/pdt/", self.get_params) - self.assertContains(paypal_response, 'Transaction complete', status_code=200) - self.assertEqual(len(PayPalPDT.objects.all()), 1) - - def test_pdt_signals(self): - self.successful_pdt_fired = False - self.failed_pdt_fired = False - - def successful_pdt(sender, **kwargs): - self.successful_pdt_fired = True - pdt_successful.connect(successful_pdt) - - def failed_pdt(sender, **kwargs): - self.failed_pdt_fired = True - pdt_failed.connect(failed_pdt) - - self.assertEqual(len(PayPalPDT.objects.all()), 0) - paypal_response = self.client.get("/pdt/", self.get_params) - self.assertContains(paypal_response, 'Transaction complete', status_code=200) - self.assertEqual(len(PayPalPDT.objects.all()), 1) - self.assertTrue(self.successful_pdt_fired) - self.assertFalse(self.failed_pdt_fired) - pdt_obj = PayPalPDT.objects.all()[0] - self.assertEqual(pdt_obj.flag, False) - - def test_double_pdt_get(self): - self.assertEqual(len(PayPalPDT.objects.all()), 0) - paypal_response = self.client.get("/pdt/", self.get_params) - self.assertContains(paypal_response, 'Transaction complete', status_code=200) - self.assertEqual(len(PayPalPDT.objects.all()), 1) - pdt_obj = PayPalPDT.objects.all()[0] - self.assertEqual(pdt_obj.flag, False) - paypal_response = self.client.get("/pdt/", self.get_params) - self.assertContains(paypal_response, 'Transaction complete', status_code=200) - self.assertEqual(len(PayPalPDT.objects.all()), 1) # we don't create a new pdt - pdt_obj = PayPalPDT.objects.all()[0] - self.assertEqual(pdt_obj.flag, False) - - def test_no_txn_id_in_pdt(self): - self.dpppdt.context_dict.pop('txn_id') - self.get_params={} - paypal_response = self.client.get("/pdt/", self.get_params) - self.assertContains(paypal_response, 'Transaction Failed', status_code=200) - self.assertEqual(len(PayPalPDT.objects.all()), 0) - - def test_custom_passthrough(self): - self.assertEqual(len(PayPalPDT.objects.all()), 0) - self.dpppdt.update_with_get_params(self.get_params) - paypal_response = self.client.get("/pdt/", self.get_params) - self.assertContains(paypal_response, 'Transaction complete', status_code=200) - self.assertEqual(len(PayPalPDT.objects.all()), 1) - pdt_obj = PayPalPDT.objects.all()[0] - self.assertEqual(pdt_obj.custom, self.get_params['cm'] ) \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/tests/test_urls.py b/csesoc/paypal/standard/pdt/tests/test_urls.py deleted file mode 100644 index 0eb164c..0000000 --- a/csesoc/paypal/standard/pdt/tests/test_urls.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.conf.urls.defaults import * - -urlpatterns = patterns('paypal.standard.pdt.views', - (r'^pdt/$', 'pdt'), -) diff --git a/csesoc/paypal/standard/pdt/urls.py b/csesoc/paypal/standard/pdt/urls.py deleted file mode 100644 index 9a088ff..0000000 --- a/csesoc/paypal/standard/pdt/urls.py +++ /dev/null @@ -1,5 +0,0 @@ -from django.conf.urls.defaults import * - -urlpatterns = patterns('paypal.standard.pdt.views', - url(r'^$', 'pdt', name="paypal-pdt"), -) \ No newline at end of file diff --git a/csesoc/paypal/standard/pdt/views.py b/csesoc/paypal/standard/pdt/views.py deleted file mode 100644 index 0993411..0000000 --- a/csesoc/paypal/standard/pdt/views.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django.template import RequestContext -from django.shortcuts import render_to_response -from django.views.decorators.http import require_GET -from paypal.standard.pdt.models import PayPalPDT -from paypal.standard.pdt.forms import PayPalPDTForm - - -@require_GET -def pdt(request, item_check_callable=None, template="pdt/pdt.html", context=None): - """Payment data transfer implementation: http://tinyurl.com/c9jjmw""" - context = context or {} - pdt_obj = None - txn_id = request.GET.get('tx') - failed = False - if txn_id is not None: - # If an existing transaction with the id tx exists: use it - try: - pdt_obj = PayPalPDT.objects.get(txn_id=txn_id) - except PayPalPDT.DoesNotExist: - # This is a new transaction so we continue processing PDT request - pass - - if pdt_obj is None: - form = PayPalPDTForm(request.GET) - if form.is_valid(): - try: - pdt_obj = form.save(commit=False) - except Exception, e: - error = repr(e) - failed = True - else: - error = form.errors - failed = True - - if failed: - pdt_obj = PayPalPDT() - pdt_obj.set_flag("Invalid form. %s" % error) - - pdt_obj.initialize(request) - - if not failed: - # The PDT object gets saved during verify - pdt_obj.verify(item_check_callable) - else: - pass # we ignore any PDT requests that don't have a transaction id - - context.update({"failed":failed, "pdt_obj":pdt_obj}) - return render_to_response(template, context, RequestContext(request)) \ No newline at end of file diff --git a/csesoc/paypal/standard/widgets.py b/csesoc/paypal/standard/widgets.py deleted file mode 100644 index 51aea94..0000000 --- a/csesoc/paypal/standard/widgets.py +++ /dev/null @@ -1,31 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -from django import forms -from django.forms.util import flatatt -from django.utils.safestring import mark_safe -from django.utils.encoding import force_unicode - - -class ValueHiddenInput(forms.HiddenInput): - """ - Widget that renders only if it has a value. - Used to remove unused fields from PayPal buttons. - """ - def render(self, name, value, attrs=None): - if value is None: - return u'' - else: - return super(ValueHiddenInput, self).render(name, value, attrs) - -class ReservedValueHiddenInput(ValueHiddenInput): - """ - Overrides the default name attribute of the form. - Used for the PayPal `return` field. - """ - def render(self, name, value, attrs=None): - if value is None: - value = '' - final_attrs = self.build_attrs(attrs, type=self.input_type) - if value != '': - final_attrs['value'] = force_unicode(value) - return mark_safe(u'' % flatatt(final_attrs)) \ No newline at end of file diff --git a/csesoc/polls/__init__.py b/csesoc/polls/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/polls/admin.py b/csesoc/polls/admin.py deleted file mode 100644 index 778c0dc..0000000 --- a/csesoc/polls/admin.py +++ /dev/null @@ -1,13 +0,0 @@ -from csesoc.polls.models import Poll, PollOption -from django.contrib import admin - -class PollOptionInline(admin.TabularInline): - model = PollOption - extra = 2 - -class PollAdmin(admin.ModelAdmin): - inlines = [PollOptionInline] - - list_display = ('question', 'pubDate', 'endDate') - -admin.site.register(Poll, PollAdmin) diff --git a/csesoc/polls/models.py b/csesoc/polls/models.py deleted file mode 100644 index d5055f8..0000000 --- a/csesoc/polls/models.py +++ /dev/null @@ -1,21 +0,0 @@ -from django.db import models - -class Poll(models.Model): - question = models.CharField(max_length = 200) - pubDate = models.DateTimeField('Date published') - endDate = models.DateTimeField('End date') - - def __unicode__(self): - return self.question - -class PollOption(models.Model): - poll = models.ForeignKey(Poll) - description = models.CharField(max_length = 200) - votes = models.IntegerField(default = 0) - - def __unicode__(self): - return self.description - -class Vote(models.Model): - username = models.CharField(max_length = 20) - poll = models.ForeignKey(Poll) diff --git a/csesoc/polls/tests.py b/csesoc/polls/tests.py deleted file mode 100644 index 2247054..0000000 --- a/csesoc/polls/tests.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -This file demonstrates two different styles of tests (one doctest and one -unittest). These will both pass when you run "manage.py test". - -Replace these with more appropriate tests for your application. -""" - -from django.test import TestCase - -class SimpleTest(TestCase): - def test_basic_addition(self): - """ - Tests that 1 + 1 always equals 2. - """ - self.failUnlessEqual(1 + 1, 2) - -__test__ = {"doctest": """ -Another way to test that 1 + 1 is equal to 2. - ->>> 1 + 1 == 2 -True -"""} - diff --git a/csesoc/polls/urls.py b/csesoc/polls/urls.py deleted file mode 100644 index 4daa3df..0000000 --- a/csesoc/polls/urls.py +++ /dev/null @@ -1,8 +0,0 @@ -from django.conf.urls.defaults import patterns, include, url - -urlpatterns = patterns('csesoc.polls.views', - (r'^$', 'index'), - (r'^(\d+)/vote/$', 'castvote'), - (r'^(\d+)/results/$', 'results'), - (r'^(\d+)/processvote/$', 'processvote'), -) diff --git a/csesoc/polls/views.py b/csesoc/polls/views.py deleted file mode 100644 index 4b4b1fb..0000000 --- a/csesoc/polls/views.py +++ /dev/null @@ -1,58 +0,0 @@ -from csesoc.polls.models import Poll, PollOption, Vote -from django.shortcuts import render_to_response, get_object_or_404, redirect -from django.http import HttpResponseRedirect -from django.core.urlresolvers import reverse -from django.contrib.auth.decorators import login_required -from django.template import RequestContext -from datetime import datetime - -@login_required -def castvote(request, id, error = None): - poll = get_object_or_404(Poll, pk = id) - - return render_to_response('polls/vote.html', - {'poll': poll, 'error': error}, - context_instance = RequestContext(request)) - -@login_required -def processvote(request, id): - poll = get_object_or_404(Poll, pk = id) - - #Poll has ended - if (poll.endDate < datetime.now()): - return render_to_response('polls/results.html', - {'poll': poll, 'error': "This poll has already ended."}, - context_instance = RequestContext(request)) - #Check if user has alredy voted - elif (Vote.objects.filter(username = request.user.username).filter(poll = poll).count() == 0): - try: - option = poll.polloption_set.get(pk = request.POST['option']) - #No option selected - except (KeyError, PollOption.DoesNotExist): - return render_to_response('polls/vote.html', - {'poll': poll, 'error': "You must select an option."}, - context_instance = RequestContext(request)) - #Successful vote - else: - option.votes += 1 - option.save() - Vote(username = request.user.username, poll = poll).save() - - return redirect(reverse('csesoc.polls.views.results', args = (id,))) - else: - return render_to_response('polls/results.html', - {'poll': poll, 'error': "You have already voted on this poll. Your vote has not been counted."}, - context_instance = RequestContext(request)) - -def results(request, id, error = None): - poll = get_object_or_404(Poll, pk = id) - return render_to_response('polls/results.html', - {'poll': poll, 'error': error}, - context_instance = RequestContext(request)) - -def index(request): - return render_to_response('polls/index.html', - {'openPolls': Poll.objects.all().filter(endDate__gt=datetime.now()).order_by("-endDate"), - 'closedPolls': Poll.objects.all().filter(endDate__lte=datetime.now()).order_by("-endDate")}, - context_instance = RequestContext(request)) - diff --git a/csesoc/scheduler/__init__.py b/csesoc/scheduler/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/scheduler/admin.py b/csesoc/scheduler/admin.py deleted file mode 100644 index 99e34e9..0000000 --- a/csesoc/scheduler/admin.py +++ /dev/null @@ -1,6 +0,0 @@ -from django.contrib import admin -from csesoc.scheduler.models import Slot, Availability - -admin.site.register(Slot) -admin.site.register(Availability) - diff --git a/csesoc/scheduler/models.py b/csesoc/scheduler/models.py deleted file mode 100644 index 650c33b..0000000 --- a/csesoc/scheduler/models.py +++ /dev/null @@ -1,30 +0,0 @@ -from django.db import models -from django.contrib.auth.models import User - -class Slot(models.Model): - title = models.CharField(max_length=200) - start = models.DateTimeField() - end = models.DateTimeField() - def __unicode__(self): - return self.title + ' ' + unicode(self.start) + ' to ' + unicode(self.end) - class Meta: - ordering = ('start',) - -class Availability(models.Model): - person = models.ForeignKey(User) - slot = models.ForeignKey(Slot) - LEVEL_CHOICES = ( - ('IM', 'Impossible'), - ('DL', 'Dislike'), - ('PO', 'Possible'), - ('PR', 'Preferred'), - ) - LEVEL_DICT = {} - for code, full in LEVEL_CHOICES: - LEVEL_DICT[code] = full - level = models.CharField(max_length=2, choices=LEVEL_CHOICES) - def __unicode__(self): - return unicode(self.person) + ' ' + unicode(self.slot) + ' ' + self.LEVEL_DICT[self.level] - class Meta: - ordering = ('person',) - diff --git a/csesoc/scheduler/templatetags/__init__.py b/csesoc/scheduler/templatetags/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/scheduler/templatetags/csesoc_template_extras.py b/csesoc/scheduler/templatetags/csesoc_template_extras.py deleted file mode 100644 index 01eb0b2..0000000 --- a/csesoc/scheduler/templatetags/csesoc_template_extras.py +++ /dev/null @@ -1,7 +0,0 @@ -from csesoc.scheduler.models import Availability -from django import template -register = template.Library() -@register.filter -def showlevel(value): - return Availability.get_level_display(value) - diff --git a/csesoc/scheduler/views.py b/csesoc/scheduler/views.py deleted file mode 100644 index 72d5f32..0000000 --- a/csesoc/scheduler/views.py +++ /dev/null @@ -1,58 +0,0 @@ -from django.forms import ModelForm -from django import forms -from django.shortcuts import render_to_response -from django.contrib.auth import authenticate, login -from django.http import HttpResponseRedirect -from django.contrib.auth.models import User -from csesoc.scheduler.models import Slot, Availability -from django.conf import settings -from csesoc.forms.widgets import SliderInput -from django.contrib.auth.decorators import login_required -from django.template import RequestContext - -import datetime - -class JoinForm(forms.Form): - def __init__(self, *args, **kwargs): - slots = kwargs.pop('slots') - super(forms.Form, self).__init__(*args, **kwargs) - for slot in slots: - label = slot.title + ' ' + str(slot.start) + ' to ' + str(slot.end) - self.fields.insert(-1, str(slot.id), forms.ChoiceField(choices=Availability.LEVEL_CHOICES, label=label, widget=SliderInput())) - def __unicode__(self): - return unicode(self.fields) - -@login_required -def join(request): - allslots = Slot.objects.filter(start__year=2012) - message = "Hi " + request.user.username + ", please use the sliders to select which times are best for you from the calendar below:" - if request.method == 'POST': # form submitted - form = JoinForm(request.POST, slots=allslots) # form bound to POST data - if form.is_valid(): - for field in form.fields: - slot = Slot.objects.get(id=field) - level = form.cleaned_data[field] - availability = Availability.objects.get(person=request.user, slot=slot) - availability.level = level - availability.save() - message = "Thanks " + request.user.username + " for submitting your preferences, you may edit them if you wish:" - else: - message = form._get_errors() - else: - initial = {} - for slot in allslots: - availability, created = Availability.objects.get_or_create(person=request.user, slot=slot, - defaults={'level': Availability.LEVEL_CHOICES[0][0]}) - initial[str(slot.id)] = availability.level - form = JoinForm(initial=initial, slots=allslots) # unbound form - - return render_to_response('scheduler_register.html', {'message' : message, 'form' : form, 'slots' : allslots}, context_instance=RequestContext(request)) - -@login_required -def results(request): - allslots = Slot.objects.filter(start__year=2012) - slots = [] - for s in allslots: - slots.append((s,Availability.objects.filter(slot=s).exclude(level='IM').order_by('-level'),)) - return render_to_response('weekcalendar.html', {'slots' : slots}, context_instance=RequestContext(request)) - diff --git a/csesoc/set_path.py b/csesoc/set_path.py deleted file mode 100644 index 0cf3f57..0000000 --- a/csesoc/set_path.py +++ /dev/null @@ -1,4 +0,0 @@ -import sys - -def update_path(): - return diff --git a/csesoc/settings.py b/csesoc/settings.py deleted file mode 100644 index 4afb3ae..0000000 --- a/csesoc/settings.py +++ /dev/null @@ -1,171 +0,0 @@ -# Django settings for csesoc project. - -import os -PROJECT_PATH = os.path.abspath(os.path.dirname(__file__)) -DEBUG = True -TEMPLATE_DEBUG = DEBUG - -# Turn this on in production but for the here and now it just lets you send emails to non standard -# addresses instead so that you can debug email messages. Just a heads up, if you are on your local -# linux machine then your username@computer-name should send to your mailbox in /var/mail/username. -# For example I put 'robert@Shhnap' in the email fields when I am testing. -CSESOC_SUGGEST_LIST = 'root@localhost' -ADMINS = ( - ('Sysadmin Head', 'root@localhost'), -) - -MANAGERS = ADMINS - -FILE_UPLOAD_PERMISSIONS = 0644 - -DATABASES = { - 'default': { - 'ENGINE': 'django.db.backends.sqlite3', - 'NAME': os.path.join(PROJECT_PATH, 'db.sqlite3') - } -} - -# Mail Settings -SMTP_HOST = 'smtp.unsw.edu.au' -SMTP_PORT = '25' -SEND_BROKEN_LINKS = False - -# Local time zone for this installation. Choices can be found here: -# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name -# although not all choices may be available on all operating systems. -# If running in a Windows environment this must be set to the same as your -# system time zone. -TIME_ZONE = 'Australia/Sydney' - -# Language code for this installation. All choices can be found here: -# http://www.i18nguy.com/unicode/language-identifiers.html -LANGUAGE_CODE = 'en-AU' - -SITE_ID = 1 - -# If you set this to False, Django will make some optimizations so as not -# to load the internationalization machinery. -USE_I18N = True - -# URL where the django authentication login view is accessible -LOGIN_URL = "/accounts/login" - -# Absolute path to the directory that holds media. -# Example: "/home/media/media.lawrence.com/" -MEDIA_ROOT = os.path.join(PROJECT_PATH, '../public/system') -#until we switch to using collectstatic, we use STATICFILES_DIRS and not STATIC_ROOT -#STATIC_ROOT = os.path.join(PROJECT_PATH, '../public/static') -STATICFILES_DIRS = (os.path.realpath(os.path.join(PROJECT_PATH, '../public/static')),) - -# URL that handles the media served from MEDIA_ROOT. Make sure to use a -# trailing slash if there is a path component (optional in other cases). -# Examples: "http://media.lawrence.com", "http://example.com/media/" -MEDIA_URL = 'http://www.csesoc.unsw.edu.au/system/' -STATIC_URL = '/static/' - -# Make this unique, and don't share it with anybody. -SECRET_KEY = '0g$%0eu0flf(0o0n@k0al$h@0fo0@lk=s0obe0**@r+dupn00l' - -# List of callables that know how to import templates from various sources. -TEMPLATE_LOADERS = ( - ('django.template.loaders.cached.Loader', ( - 'django.template.loaders.filesystem.Loader', - 'django.template.loaders.app_directories.Loader', - )), -) - -TEMPLATE_CONTEXT_PROCESSORS = ( - 'django.contrib.auth.context_processors.auth', - 'django.core.context_processors.debug', - 'django.core.context_processors.i18n', - 'django.core.context_processors.request', # we need this to provide the request variable to each template - 'django.core.context_processors.media', - 'django.core.context_processors.static', - 'csesoc.context_processors.sponsors_list', -) - -MIDDLEWARE_CLASSES = ( - 'django.middleware.common.CommonMiddleware', - 'django.contrib.sessions.middleware.SessionMiddleware', - 'django.contrib.auth.middleware.AuthenticationMiddleware', -) - -ROOT_URLCONF = 'csesoc.urls' - -TEMPLATE_DIRS = ( - # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". - # Always use forward slashes, even on Windows. - # Don't forget to use absolute paths, not relative paths. - os.path.join(PROJECT_PATH, 'templates'), - os.path.join(PROJECT_PATH, 'templates/murder'), - os.path.join(PROJECT_PATH, 'templates/game'), - os.path.join(PROJECT_PATH, 'templates/suggestions'), - os.path.join(PROJECT_PATH, 'templates/music'), - os.path.join(PROJECT_PATH, 'templates/polls'), -) -TINYMCE_JS_URL = "http://www.csesoc.unsw.edu.au/tinymce/tiny_mce.js" -TINYMCE_DEFAULT_CONFIG = { - 'plugins': "safari,pagebreak,style,layer,table,save,advhr,advimage,advlink,emotions,iespell,inlinepopups,insertdatetime,preview,media,searchreplace,print,contextmenu,paste,directionality,fullscreen,noneditable,visualchars,nonbreaking,xhtmlxtras,template", - 'theme': "advanced", - 'theme_advanced_buttons1' : "save,newdocument,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull,|,styleselect,formatselect,fontselect,fontsizeselect", - 'theme_advanced_buttons2' : "cut,copy,paste,pastetext,pasteword,|,search,replace,|,bullist,numlist,|,outdent,indent,blockquote,|,undo,redo,|,link,unlink,anchor,image,cleanup,help,code,|,insertdate,inserttime,preview,|,forecolor,backcolor", - 'width': "600", - 'height':"300", - 'theme_advanced_toolbar_location' : "top", - 'theme_advanced_toolbar_align' : "left", - 'theme_advanced_statusbar_location' : "bottom", - 'theme_advanced_resizing' : 'true', - 'content_css' : "http://www.csesoc.unsw.edu.au/static/style.css", -} -TINYMCE_SPELLCHECKER = False -TINYMCE_COMPRESSOR = False - -INSTALLED_APPS = ( - 'django.contrib.auth', - 'django.contrib.contenttypes', - 'django.contrib.sessions', - 'django.contrib.sites', - 'django.contrib.admin', - 'django.contrib.staticfiles', - 'csesoc.helpers', - 'csesoc.mainsite', - 'csesoc.campleaders', - 'csesoc.campattendees', - 'csesoc.scheduler', - 'csesoc.sponsors', - 'csesoc.suggestions', - 'csesoc.murder', - 'csesoc.game', - 'csesoc.music', - 'csesoc.polls', - 'csesoc.paypal.standard.ipn', - 'csesoc.invoices', - 'tinymce', -) - -AUTHENTICATION_BACKENDS = ( - 'csesoc.auth.backends.CSEBackend', - #'django.contrib.auth.backends.ModelBackend', -) - -# maxiumum number of StreamItems per paginated index page -STREAMITEMS_PER_PAGE = 5 - -# Only ever set to true in Development, this will always be false on the live -# site because setting this variable to true activates a back door that allows -# anyone access to the admin site without a password or any form of -# verification. -ADMIN_NO_LOGIN = True - -# django-paypal settings -PAYPAL_RECEIVER_EMAIL = "csesoc@cse.unsw.edu.au" -# Sandbox email: -#PAYPAL_RECEIVER_EMAIL = "razori_1326182346_biz@gmail.com" -SITE_DOMAIN = "http://www.csesoc.cse.unsw.edu.au/" - -CACHES = { - 'default': { - 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', - 'LOCATION': '127.0.0.1:11211', - } -} diff --git a/csesoc/sponsors/__init__.py b/csesoc/sponsors/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/sponsors/admin.py b/csesoc/sponsors/admin.py deleted file mode 100644 index de65060..0000000 --- a/csesoc/sponsors/admin.py +++ /dev/null @@ -1,7 +0,0 @@ -from django.contrib import admin -from csesoc.sponsors.models import Sponsor - -class SponsorAdmin(admin.ModelAdmin): - list_display = ('name', 'website', 'expiry_date',) - -admin.site.register(Sponsor, SponsorAdmin) diff --git a/csesoc/sponsors/models.py b/csesoc/sponsors/models.py deleted file mode 100644 index 5e4c36d..0000000 --- a/csesoc/sponsors/models.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.db import models -from django.template.loader import render_to_string -from datetime import date -from django.template import RequestContext -from django.conf import settings -from django.core.files.storage import FileSystemStorage - -class Sponsor(models.Model): - name = models.CharField(max_length=200) - description = models.TextField(blank=True) - website = models.URLField(verify_exists=False) - logo = models.ImageField(upload_to='sponsors') - alt_text = models.CharField(max_length=150) - amount_paid = models.PositiveIntegerField() - start_date = models.DateField(auto_now_add=True, editable=False) - expiry_date = models.DateField() - html_override = models.TextField(null=True, blank=True) - - def __unicode__(self): - return self.name - - def get_linked_logo(self): - return render_to_string("sponsor-linked-logo.html", { 'object': self, 'SPONSOR_LOGOS_URL' : settings.MEDIA_URL + 'sponsors/' }) - - def get_rendered_html(self): - return render_to_string("sponsor-description.html", { 'object': self, 'SPONSOR_LOGOS_URL' : settings.MEDIA_URL + 'sponsors/' }) - - def is_default_html(self): - return self.html_override is None or self.html_override == "" diff --git a/csesoc/sponsors/views.py b/csesoc/sponsors/views.py deleted file mode 100644 index d78372e..0000000 --- a/csesoc/sponsors/views.py +++ /dev/null @@ -1,17 +0,0 @@ -from django.shortcuts import render_to_response, get_list_or_404 -from django.template import RequestContext -from csesoc.sponsors.models import Sponsor -from datetime import date -from django.conf import settings - -def sponsors(request): - return render_to_response('sponsor.html', - {'allSponsors' : Sponsor.objects.order_by('amount_paid').reverse().filter(expiry_date__gte=date.today), - 'nav' : 'oursponsors',}, - context_instance = RequestContext(request)) - -def sponsorsList(request): - return list(Sponsor.objects.order_by('amount_paid').reverse().filter(expiry_date__gte=date.today)) - - - diff --git a/csesoc/suggestions/__init__.py b/csesoc/suggestions/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/csesoc/suggestions/admin.py b/csesoc/suggestions/admin.py deleted file mode 100644 index 319d718..0000000 --- a/csesoc/suggestions/admin.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.contrib import admin -from csesoc.suggestions.models import * - -class SuggestionAdmin(admin.ModelAdmin): - date_hierarchy = 'last_modified' - -class CommentAdmin(admin.ModelAdmin): - date_hierarchy = 'created' - -admin.site.register(Suggestion, SuggestionAdmin) -admin.site.register(Comment, CommentAdmin) diff --git a/csesoc/suggestions/initial_data.json b/csesoc/suggestions/initial_data.json deleted file mode 100644 index eca7647..0000000 --- a/csesoc/suggestions/initial_data.json +++ /dev/null @@ -1,64 +0,0 @@ -[ - { - "pk": 1, - "model": "suggestions.suggestion", - "fields": { - "message": "This should be a lorem ipsum message but it is about something serious instead.", - "created": "2010-10-02 13:36:52", - "sender": "robertmassaioli@gmail.com", - "last_modified": "2010-10-02 14:04:06", - "subject": "The first almighty suggestion." - } - }, - { - "pk": 2, - "model": "suggestions.suggestion", - "fields": { - "message": "This should appear first however.", - "created": "2010-10-02 14:02:24", - "sender": "", - "last_modified": "2010-10-02 15:24:41", - "subject": "This is the second suggestion." - } - }, - { - "pk": 1, - "model": "suggestions.comment", - "fields": { - "comment": "This person is making a comment; how uninteresting are they...", - "name": "Commenter", - "suggestion": 1, - "created": "2010-10-02 14:04:06" - } - }, - { - "pk": 2, - "model": "suggestions.comment", - "fields": { - "comment": "If you are reading this then congratulations; you were just eaten by a grue.", - "name": "Lol In Your Face", - "suggestion": 2, - "created": "2010-10-02 14:13:51" - } - }, - { - "pk": 3, - "model": "suggestions.comment", - "fields": { - "comment": "The second comment never hurt any web framework.", - "name": "Second Man", - "suggestion": 2, - "created": "2010-10-02 15:23:40" - } - }, - { - "pk": 4, - "model": "suggestions.comment", - "fields": { - "comment": "Because Campers are always happy, especially when they snipe you in the face.", - "name": "Camper", - "suggestion": 2, - "created": "2010-10-02 15:24:41" - } - } -] diff --git a/csesoc/suggestions/models.py b/csesoc/suggestions/models.py deleted file mode 100644 index 545e452..0000000 --- a/csesoc/suggestions/models.py +++ /dev/null @@ -1,20 +0,0 @@ -from django.db import models - -class Suggestion(models.Model): - subject = models.TextField(max_length=100) - message = models.TextField() - sender = models.EmailField() - created = models.DateTimeField() - last_modified = models.DateTimeField() - - def __unicode__(self): - return "Suggestion: %s" % self.subject - -class Comment(models.Model): - suggestion = models.ForeignKey(Suggestion) - name = models.CharField(max_length=50) - comment = models.TextField() - created = models.DateTimeField() - - def __unicode__(self): - return unicode(self.name) + ": " + unicode(self.comment[0:50] + "...") diff --git a/csesoc/suggestions/urls.py b/csesoc/suggestions/urls.py deleted file mode 100644 index fc8aefe..0000000 --- a/csesoc/suggestions/urls.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.conf.urls.defaults import * -from django.conf import settings -from csesoc.suggestions.views import * - -urlpatterns = patterns('', - # URLs for suggestions applcation - (r'^$', list_suggestions), - (r'^(?P[0-9]+)/$', comments), - (r'^new/$', suggest), -) - diff --git a/csesoc/suggestions/views.py b/csesoc/suggestions/views.py deleted file mode 100644 index 6adc356..0000000 --- a/csesoc/suggestions/views.py +++ /dev/null @@ -1,153 +0,0 @@ -# Create your views here. -from django.http import HttpResponseRedirect -from django.core.mail import send_mail -from django.shortcuts import render_to_response -from models import Suggestion, Comment -from django.conf import settings -from django.template import RequestContext -from django.http import Http404 -from django import forms -from datetime import datetime -from django.template.loader import render_to_string -from django.core.paginator import Paginator, InvalidPage, EmptyPage - -def comments(request, suggestion): - this_suggestion = Suggestion.objects.get(id=suggestion) - - comment_form = CommentForm() - if request.method == 'POST': - form = CommentForm(request.POST) - if form.is_valid(): - clean_name = form.cleaned_data['name'] - clean_comment = form.cleaned_data['comment'] - - # create and save the new comment - stamp = datetime.now() - new_comment = Comment( - suggestion=this_suggestion, - name=clean_name, - comment=clean_comment, - created = stamp - ) - new_comment.save() - - # update the timestamp of the parent - this_suggestion.last_modified = stamp - this_suggestion.save() - - # send a message to the comment holder and the mailing list - comment_email = render_to_string('email/comment_made.txt', - { - 'comment': new_comment - }) - people_to_email = [settings.CSESOC_SUGGEST_LIST] - if this_suggestion.sender and this_suggestion.sender != '': - people_to_email.append(this_suggestion.sender) - - # send an email to the suggestions mailing list - send_mail( - '[CSESoc Suggestion Comment] %s' % new_comment.name, - comment_email, - 'comment_notifier@csesoc.unsw.edu.au', - people_to_email - ) - - - else: - comment_form = form - - try: - return_page = int(request.GET.get('page', '1')) - except ValueError: - return_page = 1 - - comments_for_suggestion = Comment.objects.filter(suggestion=suggestion) - return render_to_response('suggestion_with_comments.html', - RequestContext(request, { - 'comments': comments_for_suggestion, - 'suggestion': this_suggestion, - 'form': comment_form, - 'return_page_number': return_page, - })) - -class CommentForm(forms.Form): - name = forms.CharField(min_length=1, max_length=50) - comment = forms.CharField(widget=forms.Textarea()) - -def suggest(request): - if request.method == 'POST': - form = SuggestionForm(request.POST) - if form.is_valid(): - clean_subject = form.cleaned_data['subject'] - clean_message = form.cleaned_data['message'] - clean_sender = form.cleaned_data.get('sender', 'anon@csesoc.cse.unsw.edu.au') - - stamp = datetime.now() - suggestion = Suggestion( - subject = clean_subject, - message = clean_message, - sender = clean_sender, - created = stamp, - last_modified = stamp - ) - suggestion.save() - - - suggestion_email = render_to_string('email/suggestion_made.txt', - { - 'suggestion': suggestion - }) - people_to_email = [settings.CSESOC_SUGGEST_LIST] - if form.cleaned_data.get('sender'): - people_to_email.append(clean_sender) - - # send an email to the suggestions mailing list - send_mail( - '[CSESoc Suggestion] %s' % clean_subject, - suggestion_email, - clean_sender, - people_to_email - ) - - return render_to_response('thanks-suggestion.html', context_instance=RequestContext(request)) - else: - form = SuggestionForm() - - return render_to_response('suggest.html', context_instance=RequestContext(request, {'form': form})) - -class SuggestionForm(forms.Form): - subject = forms.CharField(max_length=100) - message = forms.CharField(widget=forms.Textarea(), initial="Replace with your suggestion.") - sender = forms.EmailField(required=False) - -def list_suggestions(request): - suggestions = Suggestion.objects.order_by('-last_modified') - pagn = Paginator(suggestions, settings.STREAMITEMS_PER_PAGE) - - try: - page = int(request.GET.get('page', '1')) - except ValueError: - page = 1 - - try: - this_suggestions = pagn.page(page) - except (EmptyPage, InvalidPage): - this_suggestions = paginator.page(paginator.num_pages) - - comments_list = [] - for suggestion in this_suggestions.object_list: - comments_list.append(Comment.objects.filter(suggestion=suggestion).count()) - - comments_list.reverse() - - return render_to_response('list_suggestions.html', - context_instance=RequestContext(request, - { - 'page_obj': this_suggestions, - 'paginator': pagn, - 'comments_list': comments_list, - #'page_obj': pagn.page(1), - 'is_paginated': True, - 'paginate_by': settings.STREAMITEMS_PER_PAGE, - })) - diff --git a/csesoc/templates/1-column.html b/csesoc/templates/1-column.html deleted file mode 100644 index 4892499..0000000 --- a/csesoc/templates/1-column.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "main.html" %} -{% block allcontent %} - -
- {% block middlecontent %}{% endblock %} -
- -{% endblock %} diff --git a/csesoc/templates/2-column-left-w-sponsors.html b/csesoc/templates/2-column-left-w-sponsors.html deleted file mode 100644 index 8d8b6e4..0000000 --- a/csesoc/templates/2-column-left-w-sponsors.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "2-column-left.html" %} - -{% block rightcontent %} - -

Our sponsors

- - -{% for sponsor in allSponsors %} - -{% endfor %} -
{{ sponsor.get_linked_logo }}
- -{% endblock %} diff --git a/csesoc/templates/2-column-left.html b/csesoc/templates/2-column-left.html deleted file mode 100644 index ea18aad..0000000 --- a/csesoc/templates/2-column-left.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "main.html" %} -{% block allcontent %} -
- {% block middlecontent %}{% endblock %} -
- -
- {% block rightcontent %}{% endblock %} -
-{% endblock %} diff --git a/csesoc/templates/2-column-right-w-calendar.html b/csesoc/templates/2-column-right-w-calendar.html deleted file mode 100644 index 4320ce6..0000000 --- a/csesoc/templates/2-column-right-w-calendar.html +++ /dev/null @@ -1,12 +0,0 @@ - -{% extends "2-column-right.html" %} - -{% block leftcontent %} - -

Calendar

- -
- -
- -{% endblock %} diff --git a/csesoc/templates/2-column-right.html b/csesoc/templates/2-column-right.html deleted file mode 100644 index 1ab10cc..0000000 --- a/csesoc/templates/2-column-right.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "main.html" %} -{% block allcontent %} -
- {% block leftcontent %}{% endblock %} -
- -
- {% block middlecontent %}{% endblock %} -
-{% endblock %} diff --git a/csesoc/templates/3-column-w-cal-sponsors.html b/csesoc/templates/3-column-w-cal-sponsors.html deleted file mode 100644 index 9439255..0000000 --- a/csesoc/templates/3-column-w-cal-sponsors.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends '3-column-w-calendar.html' %} - -{% block rightcontent %} - -

Our sponsors

- - -{% for sponsor in allSponsors %} - -{% endfor %} -
{{ sponsor.get_linked_logo }}
- -{% endblock %} diff --git a/csesoc/templates/3-column-w-calendar.html b/csesoc/templates/3-column-w-calendar.html deleted file mode 100644 index fc3cd26..0000000 --- a/csesoc/templates/3-column-w-calendar.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends '3-column.html' %} - -{% block leftcontent %} - -

Calendar

- -
- -
- -{% endblock %} diff --git a/csesoc/templates/3-column.html b/csesoc/templates/3-column.html deleted file mode 100644 index 60836f5..0000000 --- a/csesoc/templates/3-column.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "main.html" %} -{% block allcontent %} -
- {% block leftcontent %}{% endblock %} -
- -
- {% block middlecontent %}{% endblock %} -
- -
- {% block rightcontent %}{% endblock %} -
-{% endblock %} diff --git a/csesoc/templates/404.html b/csesoc/templates/404.html deleted file mode 100644 index fc42f41..0000000 --- a/csesoc/templates/404.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %} - -{% block titlecontent %}404 Not Found{% endblock %} - -{% block middlecontent %} - -

Oh noes! The tubes are missing!

- -

We've searched everywhere, but couldn't find the page you wanted. Please try using the navigation links on the side instead. If you believe this is a mistake on our part, please email us at csesoc DOT sysadmin AT cse DOT unsw DOT edu DOT au.

- -{% endblock %} diff --git a/csesoc/templates/500.html b/csesoc/templates/500.html deleted file mode 100644 index a0c3384..0000000 --- a/csesoc/templates/500.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - 500 Internal Server Error - CSESoc - - - - -
-

Oh noes! The tubes are broken!

-

Something went wrong, and we were unable to process your request at this time. The CSESoc Sysadmins have been alerted to this issue, and we're working to resolve it as quickly as possible. Please try again later. If you have time, please provide us with details as to what you were doing at csesoc DOT sysadmin AT cse DOT unsw DOT edu DOT au.

-

In the meantime, feel free to return to our home page.

-
- - diff --git a/csesoc/templates/apply.html b/csesoc/templates/apply.html deleted file mode 100644 index 6febcdf..0000000 --- a/csesoc/templates/apply.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends "main.html" %} -{% block titlecontent %}Camp Leader Application{% endblock %} -{% block allcontent %} -
-

CSESoc Camp - Leader Application Form

-
    -
  • There will be a CSE Camp at the end of Week 3 (16th - 18th March). Location : Wombaroo
  • -
  • Camp Leaders must pay for their own tickets.
  • -
  • All candidates must be able to attend a compulsory training session (Date and Location TBA).
  • -
  • Applications close 26th January at 11:59pm.
  • -
  • Camp Leaders will be selected purely on the merit of their applications. Applications that are not taken seriously will be disregarded. Any relationship you may have with a member of the CSESoc Executive will have no effect on your application.
  • -
- -
- - {{ form.as_table }} -
-
- -
-
-
-{% endblock %} diff --git a/csesoc/templates/base.html b/csesoc/templates/base.html deleted file mode 100644 index 379535a..0000000 --- a/csesoc/templates/base.html +++ /dev/null @@ -1,110 +0,0 @@ - - - - - - - {% block title %}{% if object.title %}{{ object.title }} - CSESoc{% else %}CSESoc - UNSW Computer Science & Engineering Students Society{% endif %}{% endblock %} - - - {% block headextra %}{% endblock %} - -
- - -
- {% block nav %} - - - - - - - {% for sponsor in sponsors %} - {{ sponsor.get_rendered_sidebar_html }} - {% endfor %} - - - - - - {% endblock %} -
- -
- {% block content %} -

Updates

- {% for stream_item in stream_item_list %} -
- {{ stream_item.get_rendered_html }} -
-
- {% endfor %} - {% endblock %} -
- - -
- - - - diff --git a/csesoc/templates/game/game.html b/csesoc/templates/game/game.html deleted file mode 100644 index 2fdd083..0000000 --- a/csesoc/templates/game/game.html +++ /dev/null @@ -1,19 +0,0 @@ - - -CSESoc - {{ object.title }} - - - - -

{{ object.title }}

-
-{{ object.text|safe }} -
-
-{% if showanswer %} -
- Answer: - -
-{% endif %} -

{{ rank }}

diff --git a/csesoc/templates/game/scores.html b/csesoc/templates/game/scores.html deleted file mode 100644 index 266fcc9..0000000 --- a/csesoc/templates/game/scores.html +++ /dev/null @@ -1,11 +0,0 @@ -Scores - - -{% for user in scores %} - - - - -{% endfor %} -
{{ user.player__username }}{{ user.puzzle__points__sum }}
- diff --git a/csesoc/templates/go_away.html b/csesoc/templates/go_away.html deleted file mode 100644 index 7e62a2d..0000000 --- a/csesoc/templates/go_away.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "base.html" %} -{% block content %} -

Authentication Failed!

-

We were unable to authenticate you with a valid CSE account, if the problem persists contact sysadmin [ at ] cse [ dot ] unsw [ dot ] edu [ dot ] au.

-{% endblock %} - diff --git a/csesoc/templates/main.html b/csesoc/templates/main.html deleted file mode 100644 index 307ed3e..0000000 --- a/csesoc/templates/main.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - - {% block titlecontent %}{% endblock %} - CSESoc - UNSW Computer Science and Engineering Society - {% block extraheadercontent %}{% endblock %} - - - -
- - -
- {% block allcontent %}{% endblock %} -
- - - -
- - - - - - - diff --git a/csesoc/templates/mainsite/streamitem_archive.html b/csesoc/templates/mainsite/streamitem_archive.html deleted file mode 100644 index d5c7e14..0000000 --- a/csesoc/templates/mainsite/streamitem_archive.html +++ /dev/null @@ -1,16 +0,0 @@ -{% extends '3-column-w-cal-sponsors.html' %} - -{% block titlecontent %}Home{% endblock %} - -{% block middlecontent %}{% spaceless %} - -

News

- -{% for stream_item in object_list %} - {{ stream_item.get_rendered_html }} -

-{% endfor %} - -{% if is_paginated %}{% load helpers %}{% generate_pagenumbers paginator page_obj 2 %}{% endif %} - -{% endspaceless %}{% endblock %} diff --git a/csesoc/templates/mainsite/streamitem_archive_day.html b/csesoc/templates/mainsite/streamitem_archive_day.html deleted file mode 100644 index 16fe1ff..0000000 --- a/csesoc/templates/mainsite/streamitem_archive_day.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.html" %} -{% block content %} -

{{ day|date:"l jS o\f F, Y" }}

- {% for object in object_list %} -
- {{ object.get_rendered_html }} -
-
- {% endfor %} -{% endblock %} - diff --git a/csesoc/templates/mainsite/streamitem_archive_month.html b/csesoc/templates/mainsite/streamitem_archive_month.html deleted file mode 100644 index b982058..0000000 --- a/csesoc/templates/mainsite/streamitem_archive_month.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends "base.html" %} -{% block content %} -

{{ month|date:"F, Y" }}

- {% for object in object_list %} -
- {{ object.get_rendered_html }} -
-
- {% endfor %} -{% endblock %} - diff --git a/csesoc/templates/mainsite/streamitem_archive_year.html b/csesoc/templates/mainsite/streamitem_archive_year.html deleted file mode 100644 index f082d0a..0000000 --- a/csesoc/templates/mainsite/streamitem_archive_year.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "base.html" %} -{% block content %} -

{{ year }}

- -{% endblock %} - diff --git a/csesoc/templates/murder/basic.html b/csesoc/templates/murder/basic.html deleted file mode 100644 index 2769285..0000000 --- a/csesoc/templates/murder/basic.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %} - -{% block titlecontent %}{{ title }}{% endblock %} - -{% block middlecontent %} -

{{ title }}

-{% endblock %} diff --git a/csesoc/templates/murder/email/newround.txt b/csesoc/templates/murder/email/newround.txt deleted file mode 100644 index 63fcf62..0000000 --- a/csesoc/templates/murder/email/newround.txt +++ /dev/null @@ -1,17 +0,0 @@ -Dear {{ rp.player.username }}, - -You are playing in Murder@CSE, {{ rp.round.game.name }}. The current round '{{ rp.round.name }}', runs from: -{{ rp.round.start|date:"D d M Y H:i" }} to {{ rp.round.end|date:"D d M Y H:i" }}. - -Your password for this round is: -{{ rp.password.text }} - -IMPORTANT: Remember the password '{{ rp.password.text }}' because, in the event that you are assassinated, you will need to give this password to your assassin. Should you not give the password on the spot then you run the risk of being killed by the Sysadmin Ninjas. - -Use your CSE username and password to login at http://csesoc.unsw.edu.au/murder to see your victim. - -For more information, rules, etc. see http://www.csesoc.unsw.edu.au/csemurder/ - -Good hunting! - -Murder@CSE diff --git a/csesoc/templates/murder/games.html b/csesoc/templates/murder/games.html deleted file mode 100644 index eab414f..0000000 --- a/csesoc/templates/murder/games.html +++ /dev/null @@ -1,14 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %} - -{% block titlecontent %}Game Listing{% endblock %} - -{% block middlecontent %} -

List of Murder Games

- -{% endblock %} - - diff --git a/csesoc/templates/murder/index.html b/csesoc/templates/murder/index.html deleted file mode 100644 index 5097410..0000000 --- a/csesoc/templates/murder/index.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %} - -{% block titlecontent %}Game Details{% endblock %} - -{% block middlecontent %} -

{{ game.name }}

- -{% endblock %} - diff --git a/csesoc/templates/murder/myvictim.html b/csesoc/templates/murder/myvictim.html deleted file mode 100644 index 6c4cabb..0000000 --- a/csesoc/templates/murder/myvictim.html +++ /dev/null @@ -1,21 +0,0 @@ -{% extends "2-column-right-w-calendar.html" %} - -{% block titlecontent %}My Victim{% endblock %} - -{% block middlecontent %} - -

Hello {{user.username}}

-

Your current victim is {{victim.username}}

-

{{victim.username}}

-
-

Enter {{victim.username}}'s password to kill:

-{{ form.as_p }} - -{% if flash %} -

{{ flash }}

-{% endif %} -
- -{% endblock %} - - diff --git a/csesoc/templates/murder/newkills.html b/csesoc/templates/murder/newkills.html deleted file mode 100644 index f6c9425..0000000 --- a/csesoc/templates/murder/newkills.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %} - -{% block titlecontent %}Game Scoreboard{% endblock %} - -{% block middlecontent %} -

{{ game.name }} - Recent Kills

-
    - {% for kill in kills %} -
  • {{ kill.expandquip }} - {{ kill.datetime|date:"D M j, H:i" }}
  • - {% endfor %} -
-{% endblock %} - - - diff --git a/csesoc/templates/murder/registration/login.html b/csesoc/templates/murder/registration/login.html deleted file mode 100644 index eb09bd6..0000000 --- a/csesoc/templates/murder/registration/login.html +++ /dev/null @@ -1,22 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %j - -{% block titlecontent %}Murder Login{%endblock%} - -{% block middlecontent %} - -{% if form.errors %} -

Your username and password didn't match. Please try again.

-{% endif %} - -
- - - -
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
- - - -
- -{% endblock %} - diff --git a/csesoc/templates/murder/scoreboard.html b/csesoc/templates/murder/scoreboard.html deleted file mode 100644 index f7f7bbe..0000000 --- a/csesoc/templates/murder/scoreboard.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %} - -{% block titlecontent %}Game Scoreboard{% endblock %} - -{% block middlecontent %} -

{{ game.name }} - Scoreboard

- - - - - {% for killer, kills in counts %} - - - - {% endfor %} - - - - -
KillerKills
{{ killer }}{{ kills }}
Total{{ total }}
-{% endblock %} - - - diff --git a/csesoc/templates/music/music.html b/csesoc/templates/music/music.html deleted file mode 100644 index d5b3c41..0000000 --- a/csesoc/templates/music/music.html +++ /dev/null @@ -1,204 +0,0 @@ - - -Song Suggestions - - - - - - - - - - - -

- Soctail Night Song Suggestions -

-
-
-

Suggest a song

- - - - - - - - - - - - - {% if submitted %} - - {% endif %} -
Artist - Title - Do you have the song? - Notes -   -
-
- Your suggestion of {{ songdetails }} has been added, thanks! -
-
-
- - - {% if songs|length %} -

Current suggestions

- - - - - - - - - - - - - - - {% for f in songs %} - - - - - - - {% endfor %} - {% endif %} -
Artist - Title - Votes - Vote for this song -
Rebecca BlackFriday9001 - - - - - -
{{ f.song.artist }}{{ f.song.title }}{{ f.song.votes }} - - - - - -
-
- - - diff --git a/csesoc/templates/polls/index.html b/csesoc/templates/polls/index.html deleted file mode 100644 index 9396a3a..0000000 --- a/csesoc/templates/polls/index.html +++ /dev/null @@ -1,36 +0,0 @@ -{% extends '3-column-w-cal-sponsors.html' %} - -{% block titlecontent %}Polls{% endblock %} - -{% block middlecontent %} - -

Polls - Index

- -

Open

- -{% for poll in openPolls %} - - - - - - - - -{% endfor %} -
{{ poll.question }}
VoteResultsCloses: {{ poll.endDate|date:"D, d M Y, H:i:s" }}
- -

Closed

- -{% for poll in closedPolls %} - - - - - - - -{% endfor %} -
{{ poll.question }}
ResultsClosed: {{ poll.endDate|date:"D, d M Y, H:i:s" }}
- -{% endblock %} diff --git a/csesoc/templates/polls/results.html b/csesoc/templates/polls/results.html deleted file mode 100644 index 23573b5..0000000 --- a/csesoc/templates/polls/results.html +++ /dev/null @@ -1,45 +0,0 @@ -{% extends '3-column-w-cal-sponsors.html' %} - -{% block titlecontent %}Poll: {{ poll.question }}{% endblock %} - -{% block extraheadercontent %} - - - - - -{% endblock %} - -{% block middlecontent %} - -

Poll - Results

- -

{{ poll.question }}

-{% if error %}

{{ error }}

{% endif %} -

Poll ends: {{ poll.endDate|date:"D, d M Y, H:i:s" }}

-
- -{% endblock %} diff --git a/csesoc/templates/polls/vote.html b/csesoc/templates/polls/vote.html deleted file mode 100644 index c0d90d6..0000000 --- a/csesoc/templates/polls/vote.html +++ /dev/null @@ -1,23 +0,0 @@ -{% extends '3-column-w-cal-sponsors.html' %} - -{% block titlecontent %}Poll: {{ poll.question }}{% endblock %} - -{% block middlecontent %} - -

Poll - Vote

- -

{{ poll.question }}

- -{% if error %}

{{ error }}

{% endif %} - -
-{% for option in poll.polloption_set.all %} - -
-{% endfor %} -
-

Poll ends: {{ poll.endDate|date:"D, d M Y, H:i:s" }}

- -
- -{% endblock %} diff --git a/csesoc/templates/product_detail.html b/csesoc/templates/product_detail.html deleted file mode 100644 index 291cc06..0000000 --- a/csesoc/templates/product_detail.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "1-column.html" %} -{% block titlecontent %}{{ title }}{% endblock %} -{% block middlecontent %} -
-

Invoice #{{ product.slug }}

-

for {{product.company}}

- - - {% if product.discount > 0 %} - - {% endif %} - - - - - - - - - - -
{{product.title}}{{price}}
Discount{{discount}}

Direct Debit Price:

{{total_price }}

Account Name:CSE SOCIETY
BSB:062 303
Account Number:1048 5828
Payment Description:{{product.slug}}
-

Paypal/Credit Card Price:

{{paypal_price }}

- Note: Paying by credit card or PayPal incurs a 2.5% fee, as shown above.
-{{ form }} -
-
-{% endblock %} diff --git a/csesoc/templates/product_students_detail.html b/csesoc/templates/product_students_detail.html deleted file mode 100644 index e24a914..0000000 --- a/csesoc/templates/product_students_detail.html +++ /dev/null @@ -1,57 +0,0 @@ -{% extends "1-column.html" %} -{% block titlecontent %}{{ title }}{% endblock %} -{% block extraheadercontent %} - -{% endblock %} -{% block middlecontent %} -
-

{{ product.title }}

-

for {{request.user.username}}

- - - {% if product.discount > 0 %} - - {% endif %} - - - - - - - - - - - - -
{{product.title}}{{price}}
Discount{{discount}}

Choose payment method:

Cash or Direct Deposit

{{total_price }}

Please pay cash in person to a CSESoc Executive, at the Socs Office, Basement Level, Building K17, UNSW.
Account Name:CSE SOCIETY
BSB:062 303
Account Number:1048 5828
Payment Description:{{dd_description}}
- Please ensure your CSE username ({{user.username}}) is present in the payment description.
-

Paypal or Credit Card

{{paypal_price }}

- Note: Paying by credit card or PayPal incurs a 2.5% fee, as shown above.
Please ensure your CSE username is {{user.username}} before you continue.
-{{ form }} -
-
-{% endblock %} diff --git a/csesoc/templates/product_thanks.html b/csesoc/templates/product_thanks.html deleted file mode 100644 index 6e25ea7..0000000 --- a/csesoc/templates/product_thanks.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "1-column.html" %} -{% block titlecontent %}{{ title }}{% endblock %} -{% block middlecontent %} -
-

Thanks, {{ product.company }}!

-

Your support of our society is greatly appreciated!
Your payment will be processed shortly.

-
-{% endblock %} diff --git a/csesoc/templates/registration/login.html b/csesoc/templates/registration/login.html deleted file mode 100644 index 7dceb1d..0000000 --- a/csesoc/templates/registration/login.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "base.html" %} - -{% block content %} - -{% if form.errors %} -

Your username and password didn't match. Please try again.

-{% endif %} - -
- - - - - - - - - -
{{ form.username.label_tag }}{{ form.username }}
{{ form.password.label_tag }}{{ form.password }}
- - - -
- -{% endblock %} - diff --git a/csesoc/templates/scheduler_register.html b/csesoc/templates/scheduler_register.html deleted file mode 100644 index 43900c9..0000000 --- a/csesoc/templates/scheduler_register.html +++ /dev/null @@ -1,94 +0,0 @@ -{% extends "1-column.html" %} -{% block extraheadercontent %} - - - - - -{{ form.media }} - - - - - -{% endblock %} -{% block middlecontent %} - -

CSESoc - Register to help out!

-

{{ message }}

-

To see who's already available for each time, check the slots page

-

Notes for stall volunteers: -

    -
  • Wear your CSESoc shirt, if you have one
  • -
  • Bring a bottle of water, as it may be hot
  • -
  • Make sure the cash box is secure and locked when not in use. The executive member at the stall will hold the key -
  • Keep track of who has keys, so they don't leave the stall with them
  • -
  • Come on time to relieve the person before you
  • -
  • Keep track of who has deposited for camp. Keep a list and be sure to give a receipt
  • -
  • Give a receipt for any purchases and keep a carbon copy. Shirts are $10, and mugs are $15.
  • -
  • Promote everything (camp, csesoc, installfest, bbqs, shirts, quake, etc.)
  • -
-

-
-

-
-

-
- -{% endblock %} diff --git a/csesoc/templates/signup.html b/csesoc/templates/signup.html deleted file mode 100644 index ada88cf..0000000 --- a/csesoc/templates/signup.html +++ /dev/null @@ -1,71 +0,0 @@ -{% extends "1-column.html" %} -{% block extraheadercontent %} - - - - -{% endblock %} - -{% block middlecontent %} -
-

CSESoc First Year Camp 2012 - Application Form

-
-
    -
  • Date: End of Week 3 Semester 1 (16th March - 18th March)
  • -
  • Theme: Sci-fi and Fantasy
  • -
  • Location: Wombaroo Adventure Centre
  • -
  • Payment:
  • -
  • - Early bird special: Pay in full by the end of Monday of Week 2 to receive $10 off full price.
  • -
  • - $70 for Arc members (must show your Arc membership sticker)
  • -
  • - $80 for non-Arc
  • -
  • - A $10 deposit can be put down to secure your spot if you cannot pay in full at the moment
  • -
  • Includes free camp t-shirt
  • -
  • Payment must be made in full (and cleared if by DD) by 14th March.
  • -
  • Click here for more information about camp.
  • -
-
-
- - {{ form.as_table }} -
-
- -
-
-
-{% endblock %} - diff --git a/csesoc/templates/sponsor-description.html b/csesoc/templates/sponsor-description.html deleted file mode 100644 index 7389c75..0000000 --- a/csesoc/templates/sponsor-description.html +++ /dev/null @@ -1,4 +0,0 @@ - - {{ object.alt_text|safe }} - {{ object.name }}
{{ object.description|safe }} - diff --git a/csesoc/templates/sponsor-linked-logo.html b/csesoc/templates/sponsor-linked-logo.html deleted file mode 100644 index 70e1ecb..0000000 --- a/csesoc/templates/sponsor-linked-logo.html +++ /dev/null @@ -1,5 +0,0 @@ -{% if object.is_default_html %} - {{ object.alt_text|safe }}
-{% else %} - {{ object.html_override|safe }} -{% endif %} diff --git a/csesoc/templates/sponsor-sidebar.html b/csesoc/templates/sponsor-sidebar.html deleted file mode 100644 index a74d443..0000000 --- a/csesoc/templates/sponsor-sidebar.html +++ /dev/null @@ -1,11 +0,0 @@ -{% if object.has_not_expired %} - {% if object.is_default_html %} -
- - {{ object.alt_text|safe }} -
-
- {% else %} - {{ object.html_override|safe }} - {% endif %} -{% endif %} diff --git a/csesoc/templates/sponsor.html b/csesoc/templates/sponsor.html deleted file mode 100644 index 9808bb1..0000000 --- a/csesoc/templates/sponsor.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends '2-column-left.html' %} - -{% block titlecontent %}Our Sponsors{% endblock %} - -{% block middlecontent %} - -

Our Sponsors

- - -{% for sponsor in allSponsors %} - {{ sponsor.get_rendered_html }} -{% endfor %} -
- -{% endblock %} - -{% block rightcontent %} -
-

Become a sponsor

-

For information about how you can sponsor CSESoc, please see our 2012 Sponsorship Proposal.

- -
- -

For further enquiries and to discuss sponsorship opportunities, please email csesoc.copresidents@csesoc.unsw.edu.au

-
-{% endblock %} diff --git a/csesoc/templates/static-1-column-middle.html b/csesoc/templates/static-1-column-middle.html deleted file mode 100644 index cdfc9c0..0000000 --- a/csesoc/templates/static-1-column-middle.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends "1-column.html" %} -{% block titlecontent %}{{ object.title }}{% endblock %} -{% block middlecontent %} -

{{ object.title }}

- {{ object.text|safe }} -
-{% endblock %} diff --git a/csesoc/templates/static-2-column-left-w-sponsors.html b/csesoc/templates/static-2-column-left-w-sponsors.html deleted file mode 100644 index 759b276..0000000 --- a/csesoc/templates/static-2-column-left-w-sponsors.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "2-column-left-w-sponsors.html" %} -{% block titlecontent %}{{ object.title }}{% endblock %} -{% block middlecontent %} -

{{ object.title }}

- {{ object.text|safe }} -
-{% endblock %} - diff --git a/csesoc/templates/static-2-column-right-w-calendar.html b/csesoc/templates/static-2-column-right-w-calendar.html deleted file mode 100644 index 63738e6..0000000 --- a/csesoc/templates/static-2-column-right-w-calendar.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "2-column-right-w-calendar.html" %} -{% block titlecontent %}{{ object.title }}{% endblock %} -{% block middlecontent %} -

{{ object.title }}

- {{ object.text|safe }} -
-{% endblock %} - diff --git a/csesoc/templates/static-3-column-w-cal-sponsors.html b/csesoc/templates/static-3-column-w-cal-sponsors.html deleted file mode 100644 index 98fe314..0000000 --- a/csesoc/templates/static-3-column-w-cal-sponsors.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "3-column-w-cal-sponsors.html" %} -{% block titlecontent %}{{ object.title }}{% endblock %} -{% block middlecontent %} -

{{ object.title }}

- {{ object.text|safe }} -
-{% endblock %} - diff --git a/csesoc/templates/static.html b/csesoc/templates/static.html deleted file mode 100644 index 19a4f2d..0000000 --- a/csesoc/templates/static.html +++ /dev/null @@ -1,8 +0,0 @@ -{% extends "static-3-column-w-cal-sponsors.html" %} -{% block titlecontent %}{{ object.title }}{% endblock %} -{% block middlecontent %} -

{{ object.title }}

- {{ object.text|safe }} -
-{% endblock %} - diff --git a/csesoc/templates/stream_item_beta.html b/csesoc/templates/stream_item_beta.html deleted file mode 100644 index ca89a38..0000000 --- a/csesoc/templates/stream_item_beta.html +++ /dev/null @@ -1,5 +0,0 @@ -

{{ object.title }}

-{{ object.blurb|safe }} -

Download this issue of Beta in PDF

-

Posted by {{ object.author }} on {{ object.pub_date }}

- diff --git a/csesoc/templates/stream_item_event.html b/csesoc/templates/stream_item_event.html deleted file mode 100644 index f95f13e..0000000 --- a/csesoc/templates/stream_item_event.html +++ /dev/null @@ -1,12 +0,0 @@ -{{ object.pub_date|date:"d M y"|upper }}
{{ object.author }} @ {{ object.pub_date|date:"H:i" }} -

{{ object.name }}

-{{ object.description|safe }} -

-When: {{ object.time }}
-Where: {{ object.location|safe }}
-{% if object.registration_required %} -Registration: Email {{ object.registration_email }} to register
-{% endif %} -{% if object.volunteers_required %} -Volunteers: Email {{ object.volunteers_email }} to volunteer
-{% endif %} diff --git a/csesoc/templates/stream_item_news_item.html b/csesoc/templates/stream_item_news_item.html deleted file mode 100644 index 212142f..0000000 --- a/csesoc/templates/stream_item_news_item.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
-
- {{ object.pub_date|date:"d" }} - {{ object.pub_date|date:"M"|upper }} - {{ object.pub_date|date:"Y" }} - @ {{ object.pub_date|date:"H:i" }} - by {{ object.author }} -
-
-
-

{{ object.headline }}

-
- {{ object.text|safe }} -
-
-
diff --git a/csesoc/templates/suggestions/email/comment_made.txt b/csesoc/templates/suggestions/email/comment_made.txt deleted file mode 100644 index ba84072..0000000 --- a/csesoc/templates/suggestions/email/comment_made.txt +++ /dev/null @@ -1,15 +0,0 @@ -A new comment has been made on the CSESoc Website: http://csesoc.unsw.edu.au/suggestions/{{ comment.suggestion.id }} - -The comment was made by: {{ comment.name }} - -====== Start Comment ====== - -{{ comment.comment }} - -====== End Comment ====== - -From, -Your friendly CSESoc Website - -P.S. You are recieving this email because you made the suggestion or you are on the CSESoc -suggestions mailing list. diff --git a/csesoc/templates/suggestions/email/suggestion_made.txt b/csesoc/templates/suggestions/email/suggestion_made.txt deleted file mode 100644 index 7aeda7a..0000000 --- a/csesoc/templates/suggestions/email/suggestion_made.txt +++ /dev/null @@ -1,13 +0,0 @@ -A new suggestion has been made on the CSESoc Website: http://csesoc.unsw.edu.au/suggestions/{{ suggestion.id }} - -====== Start Message ====== - -{{ suggestion.message }} - -====== End Message ====== - -From, -Your friendly CSESoc Website - -P.S. You are recieving this email because you made the suggestion or you are on the CSESoc -suggestions mailing list. diff --git a/csesoc/templates/suggestions/list_suggestions.html b/csesoc/templates/suggestions/list_suggestions.html deleted file mode 100644 index 7a94639..0000000 --- a/csesoc/templates/suggestions/list_suggestions.html +++ /dev/null @@ -1,31 +0,0 @@ -{% extends "suggestion_base.html" %} - -{% block suggestion_headextra %} - -{% endblock %} - -{% block middlecontent %} - {% spaceless %} -

Suggestions

- Make a new suggestion or click on a suggestion below to see the comments.

- {% if page_obj.object_list %} - {% for suggestion in page_obj.object_list %} -
-

{{ suggestion.subject|title }}

-

{{ suggestion.message|urlize }}

- Last Modified: {{ suggestion.last_modified }}
- Comments ({{ comments_list.pop }}) -

-
- {% endfor %} - {% else %} -
- There are currently no suggestions. -
- {% endif %} - {% if is_paginated %}{% load helpers %}{% generate_pagenumbers paginator page_obj 2 %}{% endif %} - {% endspaceless %} -{% endblock %} diff --git a/csesoc/templates/suggestions/suggest.html b/csesoc/templates/suggestions/suggest.html deleted file mode 100644 index b14fec0..0000000 --- a/csesoc/templates/suggestions/suggest.html +++ /dev/null @@ -1,13 +0,0 @@ -{% extends "suggestion_base.html" %} -{% block middlecontent %} -

Make a suggestion

-
- - {{ form.as_table }} - - - -
-
-{% endblock %} - diff --git a/csesoc/templates/suggestions/suggestion_base.html b/csesoc/templates/suggestions/suggestion_base.html deleted file mode 100644 index cebd70f..0000000 --- a/csesoc/templates/suggestions/suggestion_base.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "1-column.html" %} -{% block extraheadercontent %} - - {% block suggestion_headextra %}{% endblock %} -{% endblock %} -{% block titlecontent %}Suggestions{% endblock %} diff --git a/csesoc/templates/suggestions/suggestion_with_comments.html b/csesoc/templates/suggestions/suggestion_with_comments.html deleted file mode 100644 index e647075..0000000 --- a/csesoc/templates/suggestions/suggestion_with_comments.html +++ /dev/null @@ -1,33 +0,0 @@ -{% extends "suggestion_base.html" %} - -{% block middlecontent %} - Go Back -

Suggestion: {{ suggestion.subject|title }}

-

Message

-

{{ suggestion.message|urlize }}

- -
-

Comments

- {% if comments %} - {% for comment in comments %} -
{{ comment.comment|urlize }}
- - {{ comment.name|title }} -
- {% endfor %} - {% else %} -

No comments yet.

- {% endif %} - -


- -
- - {{ form.as_table }} - - - -
-
-
-{% endblock %} - diff --git a/csesoc/templates/thanks-signup.html b/csesoc/templates/thanks-signup.html deleted file mode 100644 index 240b10a..0000000 --- a/csesoc/templates/thanks-signup.html +++ /dev/null @@ -1,12 +0,0 @@ -{% extends "1-column.html" %} -{% block extraheadercontent %} - -{% endblock %} -{% block middlecontent %} -

Thanks!

-

Thanks for signing up, you'll hear from us soon!

-

Meanwhile, don't forget to pay your deposit if you want to secure your spot! Deposits can be made in person (cash only) at a CSESoc BBQ or to a CSESoc Executive in the Socs Office (K17 Basement).

-

Alternatively, you may pay the full amount by DD or Paypal. See the camp details page for more information.

-

Return to form

-{% endblock %} - diff --git a/csesoc/templates/thanks-suggestion.html b/csesoc/templates/thanks-suggestion.html deleted file mode 100644 index 58bb6d0..0000000 --- a/csesoc/templates/thanks-suggestion.html +++ /dev/null @@ -1,9 +0,0 @@ -{% extends "1-column.html" %} -{% block content %} -

Thanks!

-

- Thanks for taking the time to make a suggestion to csesoc! We appreciate all and any suggestions you - give us and will listen with open ears. -

-{% endblock %} - diff --git a/csesoc/templates/thanks.html b/csesoc/templates/thanks.html deleted file mode 100644 index a0cbd15..0000000 --- a/csesoc/templates/thanks.html +++ /dev/null @@ -1,6 +0,0 @@ -{% extends "main.html" %} -{% block allcontent %} -

Thanks!

-

Thanks for taking the time to apply, you'll hear from us soon!

-{% endblock %} - diff --git a/csesoc/templates/thedate.html b/csesoc/templates/thedate.html deleted file mode 100644 index 15d352c..0000000 --- a/csesoc/templates/thedate.html +++ /dev/null @@ -1,10 +0,0 @@ -{% extends "base.html" %} - -{% block title %}Surprise! - CSESoc{% endblock %} - -{% block content %} -

Right now it's...

-

{{ date|date:"g:i:s a T o\n l jS o\f F, Y" }}

-

The date/time was brought to you by...

- -{% endblock %} diff --git a/csesoc/templates/weekcalendar.html b/csesoc/templates/weekcalendar.html deleted file mode 100644 index ea73ec4..0000000 --- a/csesoc/templates/weekcalendar.html +++ /dev/null @@ -1,15 +0,0 @@ -{% extends "1-column.html" %} -{% load csesoc_template_extras %} -{% block middlecontent %} -

O-Week Slots

-

To volunteer, go to the sign up page

- {% for slot, availabilities in slots %} -

{{ slot }}

-
    - {% for availability in availabilities %} -
  • {{ availability|showlevel }} - {{ availability.person }}
  • - {% endfor %} -
- {% endfor %} -{% endblock %} - diff --git a/csesoc/urls.py b/csesoc/urls.py deleted file mode 100644 index f2d70af..0000000 --- a/csesoc/urls.py +++ /dev/null @@ -1,71 +0,0 @@ -from datetime import datetime - -from django.conf.urls.defaults import * -from django.contrib import admin - -from django.conf import settings -from csesoc.campattendees.views import signup -from csesoc.campleaders.views import apply -from csesoc.game.views import game_scores, game_static, game_static_latest -from csesoc.mainsite.views import static, thedate -from csesoc.scheduler.views import join, results -from csesoc.sponsors.views import sponsors -from csesoc.music.views import music_submit_song, music_vote -from csesoc.invoices.views import invoice_detail, invoice_thanks -from csesoc.auth import backends - -admin.autodiscover() - - -urlpatterns = patterns('', - - # admin site - (r'^admin/', include(backends.site.urls)), - - # login redirect - (r'accounts/login/$', 'csesoc.auth.backends.cse_login'), - - # camp leader applications - (r'^apply/$', apply), - # camp attendee applications - (r'^signup/$', signup), - - # suggestions form - (r'^suggestions/', include('csesoc.suggestions.urls')), - - # scheduler signup - (r'^oweek/signup/$', join), - (r'^oweek/slots/$', results), - - # sponsors page - (r'^sponsors/$', sponsors), - - # urls for murder - (r'^murder/', include('csesoc.murder.urls')), - - # paypal invoices - (r'^invoice/thanks/(?P[0-9]{8})/?$', invoice_thanks), - (r'^invoice/(?P[0-9]{8})/(?P[0-9a-zA-Z]+)/?$', invoice_detail), - - # url for the game - (r'^game/scores/(?P[0-9]*)$', game_scores), - (r'^game/scores$', game_scores, {'year':''}), - (r'^game/$', game_static_latest), - (r'^game/(?P.*)$', game_static), - - # urls for music - (r'^music/$', music_submit_song), - (r'^music/vote/$', music_vote), - - # urls for polls - (r'^polls/', include('csesoc.polls.urls')), - - # news-related stuff - (r'^', include('csesoc.mainsite.urls')), - - # the date - (r'^thedate/$', thedate), - - # miscellaneous articles - (r'^(?P.*)/$', static), -) diff --git a/csesoc/wsgiserver.py b/csesoc/wsgiserver.py deleted file mode 100755 index fb354d8..0000000 --- a/csesoc/wsgiserver.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/python -#http://docs.python.org/library/wsgiref.html#examples -from wsgiref.simple_server import make_server - -import os -import sys - -path = os.path.abspath(os.path.realpath(os.path.join(os.path.dirname(__file__),'..'))) -if path not in sys.path: - sys.path.append(path) - -import site -site.addsitedir('/home/www/virtualenv/lib/python2.6/site-packages/') - -os.environ['DJANGO_SETTINGS_MODULE'] = 'csesoc.settings' - -import django.core.handlers.wsgi -application = django.core.handlers.wsgi.WSGIHandler() -httpd = make_server('', 8001, application) -print "Serving on port 8001..." - -# Serve until process is killed -httpd.serve_forever() diff --git a/db/migrate/20110507094232_create_slugs.rb b/db/migrate/20110507094232_create_slugs.rb new file mode 100644 index 0000000..bd1f61a --- /dev/null +++ b/db/migrate/20110507094232_create_slugs.rb @@ -0,0 +1,18 @@ +class CreateSlugs < ActiveRecord::Migration + def self.up + create_table :slugs do |t| + t.string :name + t.integer :sluggable_id + t.integer :sequence, :null => false, :default => 1 + t.string :sluggable_type, :limit => 40 + t.string :scope + t.datetime :created_at + end + add_index :slugs, :sluggable_id + add_index :slugs, [:name, :sluggable_type, :sequence, :scope], :name => "index_slugs_on_n_s_s_and_s", :unique => true + end + + def self.down + drop_table :slugs + end +end diff --git a/db/migrate/20110507094645_create_statics.rb b/db/migrate/20110507094645_create_statics.rb new file mode 100644 index 0000000..b87950f --- /dev/null +++ b/db/migrate/20110507094645_create_statics.rb @@ -0,0 +1,15 @@ +class CreateStatics < ActiveRecord::Migration + def self.up + create_table :statics do |t| + t.string :title + t.text :content + t.string :slug_name + + t.timestamps + end + end + + def self.down + drop_table :statics + end +end diff --git a/db/migrate/20110507094824_create_news_items.rb b/db/migrate/20110507094824_create_news_items.rb new file mode 100644 index 0000000..a174337 --- /dev/null +++ b/db/migrate/20110507094824_create_news_items.rb @@ -0,0 +1,16 @@ +class CreateNewsItems < ActiveRecord::Migration + def self.up + create_table :news_items do |t| + t.string :title + t.text :content + t.datetime :publish_date + t.integer :author_id + + t.timestamps + end + end + + def self.down + drop_table :news_items + end +end diff --git a/db/migrate/20110507094950_create_events.rb b/db/migrate/20110507094950_create_events.rb new file mode 100644 index 0000000..acc3969 --- /dev/null +++ b/db/migrate/20110507094950_create_events.rb @@ -0,0 +1,22 @@ +class CreateEvents < ActiveRecord::Migration + def self.up + create_table :events do |t| + t.string :name + t.datetime :time + t.string :location + t.boolean :registration_required + t.string :registration_email + t.boolean :volunteers_required + t.string :volunteers_email + t.text :description + t.datetime :publish_date + t.integer :author_id + + t.timestamps + end + end + + def self.down + drop_table :events + end +end diff --git a/db/migrate/20110507100252_create_sponsors.rb b/db/migrate/20110507100252_create_sponsors.rb new file mode 100644 index 0000000..c271c27 --- /dev/null +++ b/db/migrate/20110507100252_create_sponsors.rb @@ -0,0 +1,25 @@ +class CreateSponsors < ActiveRecord::Migration + def self.up + create_table :sponsors do |t| + t.string :name + t.text :description + t.string :website + t.string :alt_text + t.integer :amount_paid + t.datetime :start_date + t.datetime :expiry_date + t.text :html_override + + t.string :image_file_name + t.string :image_content_type + t.integer :image_file_size + t.datetime :image_updated_at + + t.timestamps + end + end + + def self.down + drop_table :sponsors + end +end diff --git a/db/migrate/20110507100507_create_suggestions.rb b/db/migrate/20110507100507_create_suggestions.rb new file mode 100644 index 0000000..59efc84 --- /dev/null +++ b/db/migrate/20110507100507_create_suggestions.rb @@ -0,0 +1,15 @@ +class CreateSuggestions < ActiveRecord::Migration + def self.up + create_table :suggestions do |t| + t.string :subject + t.text :message + t.integer :user_id + + t.timestamps + end + end + + def self.down + drop_table :suggestions + end +end diff --git a/db/migrate/20110507100554_create_comments.rb b/db/migrate/20110507100554_create_comments.rb new file mode 100644 index 0000000..93f8918 --- /dev/null +++ b/db/migrate/20110507100554_create_comments.rb @@ -0,0 +1,15 @@ +class CreateComments < ActiveRecord::Migration + def self.up + create_table :comments do |t| + t.integer :suggestion_id + t.integer :user_id + t.text :comment + + t.timestamps + end + end + + def self.down + drop_table :comments + end +end diff --git a/db/migrate/20110507160439_devise_create_users.rb b/db/migrate/20110507160439_devise_create_users.rb new file mode 100644 index 0000000..430d7ba --- /dev/null +++ b/db/migrate/20110507160439_devise_create_users.rb @@ -0,0 +1,18 @@ +class DeviseCreateUsers < ActiveRecord::Migration + def self.up + create_table(:users) do |t| + t.token_authenticatable + t.rememberable + t.trackable + t.string :cse_username + + t.timestamps + end + + add_index :users, :authentication_token, :unique => true + end + + def self.down + drop_table :users + end +end diff --git a/db/migrate/20110507163905_create_histories_table.rb b/db/migrate/20110507163905_create_histories_table.rb new file mode 100644 index 0000000..7884b5d --- /dev/null +++ b/db/migrate/20110507163905_create_histories_table.rb @@ -0,0 +1,18 @@ +class CreateHistoriesTable < ActiveRecord::Migration + def self.up + create_table :histories do |t| + t.string :message # title, name, or object_id + t.string :username + t.integer :item + t.string :table + t.integer :month, :limit => 2 + t.integer :year, :limit => 5 + t.timestamps + end + add_index(:histories, [:item, :table, :month, :year]) + end + + def self.down + drop_table :histories + end +end diff --git a/db/migrate/20110507163906_rename_histories_to_rails_admin_histories.rb b/db/migrate/20110507163906_rename_histories_to_rails_admin_histories.rb new file mode 100644 index 0000000..b5a87f3 --- /dev/null +++ b/db/migrate/20110507163906_rename_histories_to_rails_admin_histories.rb @@ -0,0 +1,9 @@ +class RenameHistoriesToRailsAdminHistories < ActiveRecord::Migration + def self.up + rename_table :histories, :rails_admin_histories + end + + def self.down + rename_table :rails_admin_histories, :histories + end +end diff --git a/db/migrate/20110508094121_add_role_to_users.rb b/db/migrate/20110508094121_add_role_to_users.rb new file mode 100644 index 0000000..9bdeb79 --- /dev/null +++ b/db/migrate/20110508094121_add_role_to_users.rb @@ -0,0 +1,9 @@ +class AddRoleToUsers < ActiveRecord::Migration + def self.up + add_column :users, :role, :string + end + + def self.down + remove_column :users, :role + end +end diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..f311e99 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,121 @@ +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20110508094121) do + + create_table "comments", :force => true do |t| + t.integer "suggestion_id" + t.integer "user_id" + t.text "comment" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "events", :force => true do |t| + t.string "name" + t.datetime "time" + t.string "location" + t.boolean "registration_required" + t.string "registration_email" + t.boolean "volunteers_required" + t.string "volunteers_email" + t.text "description" + t.datetime "publish_date" + t.integer "author_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "news_items", :force => true do |t| + t.string "title" + t.text "content" + t.datetime "publish_date" + t.integer "author_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "rails_admin_histories", :force => true do |t| + t.string "message" + t.string "username" + t.integer "item" + t.string "table" + t.integer "month", :limit => 2 + t.integer "year", :limit => 5 + t.datetime "created_at" + t.datetime "updated_at" + end + + add_index "rails_admin_histories", ["item", "table", "month", "year"], :name => "index_histories_on_item_and_table_and_month_and_year" + + create_table "slugs", :force => true do |t| + t.string "name" + t.integer "sluggable_id" + t.integer "sequence", :default => 1, :null => false + t.string "sluggable_type", :limit => 40 + t.string "scope" + t.datetime "created_at" + end + + add_index "slugs", ["name", "sluggable_type", "sequence", "scope"], :name => "index_slugs_on_n_s_s_and_s", :unique => true + add_index "slugs", ["sluggable_id"], :name => "index_slugs_on_sluggable_id" + + create_table "sponsors", :force => true do |t| + t.string "name" + t.text "description" + t.string "website" + t.string "alt_text" + t.integer "amount_paid" + t.datetime "start_date" + t.datetime "expiry_date" + t.text "html_override" + t.string "image_file_name" + t.string "image_content_type" + t.integer "image_file_size" + t.datetime "image_updated_at" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "statics", :force => true do |t| + t.string "title" + t.text "content" + t.string "slug_name" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "suggestions", :force => true do |t| + t.string "subject" + t.text "message" + t.integer "user_id" + t.datetime "created_at" + t.datetime "updated_at" + end + + create_table "users", :force => true do |t| + t.string "authentication_token" + t.datetime "remember_created_at" + t.integer "sign_in_count", :default => 0 + t.datetime "current_sign_in_at" + t.datetime "last_sign_in_at" + t.string "current_sign_in_ip" + t.string "last_sign_in_ip" + t.string "cse_username" + t.datetime "created_at" + t.datetime "updated_at" + t.string "role" + end + + add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token", :unique => true + +end diff --git a/db/seeds.rb b/db/seeds.rb new file mode 100644 index 0000000..e789380 --- /dev/null +++ b/db/seeds.rb @@ -0,0 +1,27 @@ +# This file should contain all the record creation needed to seed the database with its default values. +# The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). +# +# Examples: +# +# cities = City.create([{ :name => 'Chicago' }, { :name => 'Copenhagen' }]) +# Mayor.create(:name => 'Daley', :city => cities.first) + +Static.create :title => "About CSESoc", :content => "About CSESoc.", :slug_name => "about" +Static.create :title => "A Brief History of CSESoc", :content => "History of CSESoc.", :slug_name => "history" +Static.create :title => "Constitution", :content => "CSESoc Constitution.", :slug_name => "constitution" +Static.create :title => "CSESoc Exec & Heads", :content => "Exec & Heads", :slug_name => "execheads" +Static.create :title => "Working Groups", :content => "Working groups.", :slug_name => "workinggroups" +Static.create :title => "Beta", :content => "Beta.", :slug_name => "workinggroupsbeta" +Static.create :title => "Publicity", :content => "Publicity.", :slug_name => "workinggroupspublicity" +Static.create :title => "Social", :content => "Social.", :slug_name => "workinggroupssocial" +Static.create :title => "Sysadmin", :content => "Sysadmin.", :slug_name => "workinggroupssysadmin" +Static.create :title => "Tech", :content => "Tech.", :slug_name => "workinggroupstech" +Static.create :title => "Volunteer!", :content => "Volunteer.", :slug_name => "workinggroupsvolunteer" +Static.create :title => "Students", :content => "Students.", :slug_name => "students" +Static.create :title => "Murder", :content => "Murder.", :slug_name => "murder" +Static.create :title => "Bling", :content => "Bling.", :slug_name => "bling" +Static.create :title => "Games", :content => "Games.", :slug_name => "games" +Static.create :title => "IRC", :content => "Irc.", :slug_name => "irc" +Static.create :title => "Contact Us", :content => "Contact us.", :slug_name => "contact" + +Sponsor.create :name => "UNSW CSE", :description => "UNSW Computer Science and Engineering", :website => "http://www.cse.unsw.edu.au", :alt_text => "CSE", :amount_paid => 1, :start_date => DateTime.parse("2011, 1, 1"), :expiry_date => DateTime.parse("2012, 1, 1") diff --git a/doc/README_FOR_APP b/doc/README_FOR_APP new file mode 100644 index 0000000..fe41f5c --- /dev/null +++ b/doc/README_FOR_APP @@ -0,0 +1,2 @@ +Use this README file to introduce your application and point to useful places in the API for learning more. +Run "rake doc:app" to generate API documentation for your models, controllers, helpers, and libraries. diff --git a/git-hook-post-merge b/git-hook-post-merge deleted file mode 100755 index ca8f04a..0000000 --- a/git-hook-post-merge +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash -export PYTHONPATH=/home/www/virtualenv/lib/python2.6/site-packages/ -cd $GIT_DIR/../csesoc -./manage.py syncdb -touch ~/public_html/index.wsgi diff --git a/csesoc/__init__.py b/lib/tasks/.gitkeep similarity index 100% rename from csesoc/__init__.py rename to lib/tasks/.gitkeep diff --git a/public/.htaccess b/public/.htaccess deleted file mode 100644 index 45eb2e5..0000000 --- a/public/.htaccess +++ /dev/null @@ -1,6 +0,0 @@ -Options +ExecCGI +FollowSymlinks -RewriteEngine On -RewriteCond %{REQUEST_FILENAME} !-f -RewriteCond %{REQUEST_FILENAME} !-d -RewriteRule ^(.*)$ /~www/index.wsgi/$1 [QSA,PT,L] -RewriteRule ^$ /~www/index.wsgi/$1 [QSA,PT,L] diff --git a/public/404.html b/public/404.html new file mode 100644 index 0000000..9a48320 --- /dev/null +++ b/public/404.html @@ -0,0 +1,26 @@ + + + + The page you were looking for doesn't exist (404) + + + + + +
+

The page you were looking for doesn't exist.

+

You may have mistyped the address or the page may have moved.

+
+ + diff --git a/public/422.html b/public/422.html new file mode 100644 index 0000000..83660ab --- /dev/null +++ b/public/422.html @@ -0,0 +1,26 @@ + + + + The change you wanted was rejected (422) + + + + + +
+

The change you wanted was rejected.

+

Maybe you tried to change something you didn't have access to.

+
+ + diff --git a/public/500.html b/public/500.html new file mode 100644 index 0000000..b80307f --- /dev/null +++ b/public/500.html @@ -0,0 +1,26 @@ + + + + We're sorry, but something went wrong (500) + + + + + +
+

We're sorry, but something went wrong.

+

We've been notified about this issue and we'll take a look at it shortly.

+
+ + diff --git a/public/favicon.ico b/public/favicon.ico new file mode 100644 index 0000000..e6555d0 Binary files /dev/null and b/public/favicon.ico differ diff --git a/public/static/icon.png b/public/icon.png similarity index 100% rename from public/static/icon.png rename to public/icon.png diff --git a/public/static/header/dropdown.png b/public/images/header/dropdown.png similarity index 100% rename from public/static/header/dropdown.png rename to public/images/header/dropdown.png diff --git a/public/static/header/header.png b/public/images/header/header.png similarity index 100% rename from public/static/header/header.png rename to public/images/header/header.png diff --git a/public/static/header/reg_menu_centre.png b/public/images/header/reg_menu_centre.png similarity index 100% rename from public/static/header/reg_menu_centre.png rename to public/images/header/reg_menu_centre.png diff --git a/public/static/header/reg_menu_left.png b/public/images/header/reg_menu_left.png similarity index 100% rename from public/static/header/reg_menu_left.png rename to public/images/header/reg_menu_left.png diff --git a/public/static/header/reg_menu_right.png b/public/images/header/reg_menu_right.png similarity index 100% rename from public/static/header/reg_menu_right.png rename to public/images/header/reg_menu_right.png diff --git a/public/images/rails.png b/public/images/rails.png new file mode 100644 index 0000000..d5edc04 Binary files /dev/null and b/public/images/rails.png differ diff --git a/public/index.wsgi b/public/index.wsgi deleted file mode 100755 index 26d505f..0000000 --- a/public/index.wsgi +++ /dev/null @@ -1,26 +0,0 @@ -import os -import sys - -path = os.path.abspath(os.path.realpath(os.path.join(os.path.dirname(__file__),'..'))) -if path not in sys.path: - sys.path.append(path) - -import site -site.addsitedir('/home/www/virtualenv/lib/python2.6/site-packages/') - -os.environ['DJANGO_SETTINGS_MODULE'] = 'csesoc.production_settings' - -import django.core.handlers.wsgi -application = django.core.handlers.wsgi.WSGIHandler() -""" -import posixpath -def application(environ, start_response): - # Wrapper to set SCRIPT_NAME to actual mount point. - environ['SCRIPT_NAME'] = posixpath.dirname(environ['SCRIPT_NAME']) - if environ['SCRIPT_NAME'] == '/': - environ['SCRIPT_NAME'] = '' - import pprint - start_response('200 OK', [('Content-Type', 'text/plain')]) - yield pprint.pformat(environ) -# return _application(environ, start_response) -""" diff --git a/public/javascripts/application.js b/public/javascripts/application.js new file mode 100644 index 0000000..fe45776 --- /dev/null +++ b/public/javascripts/application.js @@ -0,0 +1,2 @@ +// Place your application-specific JavaScript functions and classes here +// This file is automatically included by javascript_include_tag :defaults diff --git a/public/javascripts/controls.js b/public/javascripts/controls.js new file mode 100644 index 0000000..7392fb6 --- /dev/null +++ b/public/javascripts/controls.js @@ -0,0 +1,965 @@ +// script.aculo.us controls.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 + +// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// (c) 2005-2009 Ivan Krstic (http://blogs.law.harvard.edu/ivan) +// (c) 2005-2009 Jon Tirsen (http://www.tirsen.com) +// Contributors: +// Richard Livsey +// Rahul Bhargava +// Rob Wills +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// Autocompleter.Base handles all the autocompletion functionality +// that's independent of the data source for autocompletion. This +// includes drawing the autocompletion menu, observing keyboard +// and mouse events, and similar. +// +// Specific autocompleters need to provide, at the very least, +// a getUpdatedChoices function that will be invoked every time +// the text inside the monitored textbox changes. This method +// should get the text for which to provide autocompletion by +// invoking this.getToken(), NOT by directly accessing +// this.element.value. This is to allow incremental tokenized +// autocompletion. Specific auto-completion logic (AJAX, etc) +// belongs in getUpdatedChoices. +// +// Tokenized incremental autocompletion is enabled automatically +// when an autocompleter is instantiated with the 'tokens' option +// in the options parameter, e.g.: +// new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); +// will incrementally autocomplete with a comma as the token. +// Additionally, ',' in the above example can be replaced with +// a token array, e.g. { tokens: [',', '\n'] } which +// enables autocompletion on multiple tokens. This is most +// useful when one of the tokens is \n (a newline), as it +// allows smart autocompletion after linebreaks. + +if(typeof Effect == 'undefined') + throw("controls.js requires including script.aculo.us' effects.js library"); + +var Autocompleter = { }; +Autocompleter.Base = Class.create({ + baseInitialize: function(element, update, options) { + element = $(element); + this.element = element; + this.update = $(update); + this.hasFocus = false; + this.changed = false; + this.active = false; + this.index = 0; + this.entryCount = 0; + this.oldElementValue = this.element.value; + + if(this.setOptions) + this.setOptions(options); + else + this.options = options || { }; + + this.options.paramName = this.options.paramName || this.element.name; + this.options.tokens = this.options.tokens || []; + this.options.frequency = this.options.frequency || 0.4; + this.options.minChars = this.options.minChars || 1; + this.options.onShow = this.options.onShow || + function(element, update){ + if(!update.style.position || update.style.position=='absolute') { + update.style.position = 'absolute'; + Position.clone(element, update, { + setHeight: false, + offsetTop: element.offsetHeight + }); + } + Effect.Appear(update,{duration:0.15}); + }; + this.options.onHide = this.options.onHide || + function(element, update){ new Effect.Fade(update,{duration:0.15}) }; + + if(typeof(this.options.tokens) == 'string') + this.options.tokens = new Array(this.options.tokens); + // Force carriage returns as token delimiters anyway + if (!this.options.tokens.include('\n')) + this.options.tokens.push('\n'); + + this.observer = null; + + this.element.setAttribute('autocomplete','off'); + + Element.hide(this.update); + + Event.observe(this.element, 'blur', this.onBlur.bindAsEventListener(this)); + Event.observe(this.element, 'keydown', this.onKeyPress.bindAsEventListener(this)); + }, + + show: function() { + if(Element.getStyle(this.update, 'display')=='none') this.options.onShow(this.element, this.update); + if(!this.iefix && + (Prototype.Browser.IE) && + (Element.getStyle(this.update, 'position')=='absolute')) { + new Insertion.After(this.update, + ''); + this.iefix = $(this.update.id+'_iefix'); + } + if(this.iefix) setTimeout(this.fixIEOverlapping.bind(this), 50); + }, + + fixIEOverlapping: function() { + Position.clone(this.update, this.iefix, {setTop:(!this.update.style.height)}); + this.iefix.style.zIndex = 1; + this.update.style.zIndex = 2; + Element.show(this.iefix); + }, + + hide: function() { + this.stopIndicator(); + if(Element.getStyle(this.update, 'display')!='none') this.options.onHide(this.element, this.update); + if(this.iefix) Element.hide(this.iefix); + }, + + startIndicator: function() { + if(this.options.indicator) Element.show(this.options.indicator); + }, + + stopIndicator: function() { + if(this.options.indicator) Element.hide(this.options.indicator); + }, + + onKeyPress: function(event) { + if(this.active) + switch(event.keyCode) { + case Event.KEY_TAB: + case Event.KEY_RETURN: + this.selectEntry(); + Event.stop(event); + case Event.KEY_ESC: + this.hide(); + this.active = false; + Event.stop(event); + return; + case Event.KEY_LEFT: + case Event.KEY_RIGHT: + return; + case Event.KEY_UP: + this.markPrevious(); + this.render(); + Event.stop(event); + return; + case Event.KEY_DOWN: + this.markNext(); + this.render(); + Event.stop(event); + return; + } + else + if(event.keyCode==Event.KEY_TAB || event.keyCode==Event.KEY_RETURN || + (Prototype.Browser.WebKit > 0 && event.keyCode == 0)) return; + + this.changed = true; + this.hasFocus = true; + + if(this.observer) clearTimeout(this.observer); + this.observer = + setTimeout(this.onObserverEvent.bind(this), this.options.frequency*1000); + }, + + activate: function() { + this.changed = false; + this.hasFocus = true; + this.getUpdatedChoices(); + }, + + onHover: function(event) { + var element = Event.findElement(event, 'LI'); + if(this.index != element.autocompleteIndex) + { + this.index = element.autocompleteIndex; + this.render(); + } + Event.stop(event); + }, + + onClick: function(event) { + var element = Event.findElement(event, 'LI'); + this.index = element.autocompleteIndex; + this.selectEntry(); + this.hide(); + }, + + onBlur: function(event) { + // needed to make click events working + setTimeout(this.hide.bind(this), 250); + this.hasFocus = false; + this.active = false; + }, + + render: function() { + if(this.entryCount > 0) { + for (var i = 0; i < this.entryCount; i++) + this.index==i ? + Element.addClassName(this.getEntry(i),"selected") : + Element.removeClassName(this.getEntry(i),"selected"); + if(this.hasFocus) { + this.show(); + this.active = true; + } + } else { + this.active = false; + this.hide(); + } + }, + + markPrevious: function() { + if(this.index > 0) this.index--; + else this.index = this.entryCount-1; + this.getEntry(this.index).scrollIntoView(true); + }, + + markNext: function() { + if(this.index < this.entryCount-1) this.index++; + else this.index = 0; + this.getEntry(this.index).scrollIntoView(false); + }, + + getEntry: function(index) { + return this.update.firstChild.childNodes[index]; + }, + + getCurrentEntry: function() { + return this.getEntry(this.index); + }, + + selectEntry: function() { + this.active = false; + this.updateElement(this.getCurrentEntry()); + }, + + updateElement: function(selectedElement) { + if (this.options.updateElement) { + this.options.updateElement(selectedElement); + return; + } + var value = ''; + if (this.options.select) { + var nodes = $(selectedElement).select('.' + this.options.select) || []; + if(nodes.length>0) value = Element.collectTextNodes(nodes[0], this.options.select); + } else + value = Element.collectTextNodesIgnoreClass(selectedElement, 'informal'); + + var bounds = this.getTokenBounds(); + if (bounds[0] != -1) { + var newValue = this.element.value.substr(0, bounds[0]); + var whitespace = this.element.value.substr(bounds[0]).match(/^\s+/); + if (whitespace) + newValue += whitespace[0]; + this.element.value = newValue + value + this.element.value.substr(bounds[1]); + } else { + this.element.value = value; + } + this.oldElementValue = this.element.value; + this.element.focus(); + + if (this.options.afterUpdateElement) + this.options.afterUpdateElement(this.element, selectedElement); + }, + + updateChoices: function(choices) { + if(!this.changed && this.hasFocus) { + this.update.innerHTML = choices; + Element.cleanWhitespace(this.update); + Element.cleanWhitespace(this.update.down()); + + if(this.update.firstChild && this.update.down().childNodes) { + this.entryCount = + this.update.down().childNodes.length; + for (var i = 0; i < this.entryCount; i++) { + var entry = this.getEntry(i); + entry.autocompleteIndex = i; + this.addObservers(entry); + } + } else { + this.entryCount = 0; + } + + this.stopIndicator(); + this.index = 0; + + if(this.entryCount==1 && this.options.autoSelect) { + this.selectEntry(); + this.hide(); + } else { + this.render(); + } + } + }, + + addObservers: function(element) { + Event.observe(element, "mouseover", this.onHover.bindAsEventListener(this)); + Event.observe(element, "click", this.onClick.bindAsEventListener(this)); + }, + + onObserverEvent: function() { + this.changed = false; + this.tokenBounds = null; + if(this.getToken().length>=this.options.minChars) { + this.getUpdatedChoices(); + } else { + this.active = false; + this.hide(); + } + this.oldElementValue = this.element.value; + }, + + getToken: function() { + var bounds = this.getTokenBounds(); + return this.element.value.substring(bounds[0], bounds[1]).strip(); + }, + + getTokenBounds: function() { + if (null != this.tokenBounds) return this.tokenBounds; + var value = this.element.value; + if (value.strip().empty()) return [-1, 0]; + var diff = arguments.callee.getFirstDifferencePos(value, this.oldElementValue); + var offset = (diff == this.oldElementValue.length ? 1 : 0); + var prevTokenPos = -1, nextTokenPos = value.length; + var tp; + for (var index = 0, l = this.options.tokens.length; index < l; ++index) { + tp = value.lastIndexOf(this.options.tokens[index], diff + offset - 1); + if (tp > prevTokenPos) prevTokenPos = tp; + tp = value.indexOf(this.options.tokens[index], diff + offset); + if (-1 != tp && tp < nextTokenPos) nextTokenPos = tp; + } + return (this.tokenBounds = [prevTokenPos + 1, nextTokenPos]); + } +}); + +Autocompleter.Base.prototype.getTokenBounds.getFirstDifferencePos = function(newS, oldS) { + var boundary = Math.min(newS.length, oldS.length); + for (var index = 0; index < boundary; ++index) + if (newS[index] != oldS[index]) + return index; + return boundary; +}; + +Ajax.Autocompleter = Class.create(Autocompleter.Base, { + initialize: function(element, update, url, options) { + this.baseInitialize(element, update, options); + this.options.asynchronous = true; + this.options.onComplete = this.onComplete.bind(this); + this.options.defaultParams = this.options.parameters || null; + this.url = url; + }, + + getUpdatedChoices: function() { + this.startIndicator(); + + var entry = encodeURIComponent(this.options.paramName) + '=' + + encodeURIComponent(this.getToken()); + + this.options.parameters = this.options.callback ? + this.options.callback(this.element, entry) : entry; + + if(this.options.defaultParams) + this.options.parameters += '&' + this.options.defaultParams; + + new Ajax.Request(this.url, this.options); + }, + + onComplete: function(request) { + this.updateChoices(request.responseText); + } +}); + +// The local array autocompleter. Used when you'd prefer to +// inject an array of autocompletion options into the page, rather +// than sending out Ajax queries, which can be quite slow sometimes. +// +// The constructor takes four parameters. The first two are, as usual, +// the id of the monitored textbox, and id of the autocompletion menu. +// The third is the array you want to autocomplete from, and the fourth +// is the options block. +// +// Extra local autocompletion options: +// - choices - How many autocompletion choices to offer +// +// - partialSearch - If false, the autocompleter will match entered +// text only at the beginning of strings in the +// autocomplete array. Defaults to true, which will +// match text at the beginning of any *word* in the +// strings in the autocomplete array. If you want to +// search anywhere in the string, additionally set +// the option fullSearch to true (default: off). +// +// - fullSsearch - Search anywhere in autocomplete array strings. +// +// - partialChars - How many characters to enter before triggering +// a partial match (unlike minChars, which defines +// how many characters are required to do any match +// at all). Defaults to 2. +// +// - ignoreCase - Whether to ignore case when autocompleting. +// Defaults to true. +// +// It's possible to pass in a custom function as the 'selector' +// option, if you prefer to write your own autocompletion logic. +// In that case, the other options above will not apply unless +// you support them. + +Autocompleter.Local = Class.create(Autocompleter.Base, { + initialize: function(element, update, array, options) { + this.baseInitialize(element, update, options); + this.options.array = array; + }, + + getUpdatedChoices: function() { + this.updateChoices(this.options.selector(this)); + }, + + setOptions: function(options) { + this.options = Object.extend({ + choices: 10, + partialSearch: true, + partialChars: 2, + ignoreCase: true, + fullSearch: false, + selector: function(instance) { + var ret = []; // Beginning matches + var partial = []; // Inside matches + var entry = instance.getToken(); + var count = 0; + + for (var i = 0; i < instance.options.array.length && + ret.length < instance.options.choices ; i++) { + + var elem = instance.options.array[i]; + var foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase()) : + elem.indexOf(entry); + + while (foundPos != -1) { + if (foundPos == 0 && elem.length != entry.length) { + ret.push("
  • " + elem.substr(0, entry.length) + "" + + elem.substr(entry.length) + "
  • "); + break; + } else if (entry.length >= instance.options.partialChars && + instance.options.partialSearch && foundPos != -1) { + if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos-1,1))) { + partial.push("
  • " + elem.substr(0, foundPos) + "" + + elem.substr(foundPos, entry.length) + "" + elem.substr( + foundPos + entry.length) + "
  • "); + break; + } + } + + foundPos = instance.options.ignoreCase ? + elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : + elem.indexOf(entry, foundPos + 1); + + } + } + if (partial.length) + ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)); + return "
      " + ret.join('') + "
    "; + } + }, options || { }); + } +}); + +// AJAX in-place editor and collection editor +// Full rewrite by Christophe Porteneuve (April 2007). + +// Use this if you notice weird scrolling problems on some browsers, +// the DOM might be a bit confused when this gets called so do this +// waits 1 ms (with setTimeout) until it does the activation +Field.scrollFreeActivate = function(field) { + setTimeout(function() { + Field.activate(field); + }, 1); +}; + +Ajax.InPlaceEditor = Class.create({ + initialize: function(element, url, options) { + this.url = url; + this.element = element = $(element); + this.prepareOptions(); + this._controls = { }; + arguments.callee.dealWithDeprecatedOptions(options); // DEPRECATION LAYER!!! + Object.extend(this.options, options || { }); + if (!this.options.formId && this.element.id) { + this.options.formId = this.element.id + '-inplaceeditor'; + if ($(this.options.formId)) + this.options.formId = ''; + } + if (this.options.externalControl) + this.options.externalControl = $(this.options.externalControl); + if (!this.options.externalControl) + this.options.externalControlOnly = false; + this._originalBackground = this.element.getStyle('background-color') || 'transparent'; + this.element.title = this.options.clickToEditText; + this._boundCancelHandler = this.handleFormCancellation.bind(this); + this._boundComplete = (this.options.onComplete || Prototype.emptyFunction).bind(this); + this._boundFailureHandler = this.handleAJAXFailure.bind(this); + this._boundSubmitHandler = this.handleFormSubmission.bind(this); + this._boundWrapperHandler = this.wrapUp.bind(this); + this.registerListeners(); + }, + checkForEscapeOrReturn: function(e) { + if (!this._editing || e.ctrlKey || e.altKey || e.shiftKey) return; + if (Event.KEY_ESC == e.keyCode) + this.handleFormCancellation(e); + else if (Event.KEY_RETURN == e.keyCode) + this.handleFormSubmission(e); + }, + createControl: function(mode, handler, extraClasses) { + var control = this.options[mode + 'Control']; + var text = this.options[mode + 'Text']; + if ('button' == control) { + var btn = document.createElement('input'); + btn.type = 'submit'; + btn.value = text; + btn.className = 'editor_' + mode + '_button'; + if ('cancel' == mode) + btn.onclick = this._boundCancelHandler; + this._form.appendChild(btn); + this._controls[mode] = btn; + } else if ('link' == control) { + var link = document.createElement('a'); + link.href = '#'; + link.appendChild(document.createTextNode(text)); + link.onclick = 'cancel' == mode ? this._boundCancelHandler : this._boundSubmitHandler; + link.className = 'editor_' + mode + '_link'; + if (extraClasses) + link.className += ' ' + extraClasses; + this._form.appendChild(link); + this._controls[mode] = link; + } + }, + createEditField: function() { + var text = (this.options.loadTextURL ? this.options.loadingText : this.getText()); + var fld; + if (1 >= this.options.rows && !/\r|\n/.test(this.getText())) { + fld = document.createElement('input'); + fld.type = 'text'; + var size = this.options.size || this.options.cols || 0; + if (0 < size) fld.size = size; + } else { + fld = document.createElement('textarea'); + fld.rows = (1 >= this.options.rows ? this.options.autoRows : this.options.rows); + fld.cols = this.options.cols || 40; + } + fld.name = this.options.paramName; + fld.value = text; // No HTML breaks conversion anymore + fld.className = 'editor_field'; + if (this.options.submitOnBlur) + fld.onblur = this._boundSubmitHandler; + this._controls.editor = fld; + if (this.options.loadTextURL) + this.loadExternalText(); + this._form.appendChild(this._controls.editor); + }, + createForm: function() { + var ipe = this; + function addText(mode, condition) { + var text = ipe.options['text' + mode + 'Controls']; + if (!text || condition === false) return; + ipe._form.appendChild(document.createTextNode(text)); + }; + this._form = $(document.createElement('form')); + this._form.id = this.options.formId; + this._form.addClassName(this.options.formClassName); + this._form.onsubmit = this._boundSubmitHandler; + this.createEditField(); + if ('textarea' == this._controls.editor.tagName.toLowerCase()) + this._form.appendChild(document.createElement('br')); + if (this.options.onFormCustomization) + this.options.onFormCustomization(this, this._form); + addText('Before', this.options.okControl || this.options.cancelControl); + this.createControl('ok', this._boundSubmitHandler); + addText('Between', this.options.okControl && this.options.cancelControl); + this.createControl('cancel', this._boundCancelHandler, 'editor_cancel'); + addText('After', this.options.okControl || this.options.cancelControl); + }, + destroy: function() { + if (this._oldInnerHTML) + this.element.innerHTML = this._oldInnerHTML; + this.leaveEditMode(); + this.unregisterListeners(); + }, + enterEditMode: function(e) { + if (this._saving || this._editing) return; + this._editing = true; + this.triggerCallback('onEnterEditMode'); + if (this.options.externalControl) + this.options.externalControl.hide(); + this.element.hide(); + this.createForm(); + this.element.parentNode.insertBefore(this._form, this.element); + if (!this.options.loadTextURL) + this.postProcessEditField(); + if (e) Event.stop(e); + }, + enterHover: function(e) { + if (this.options.hoverClassName) + this.element.addClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onEnterHover'); + }, + getText: function() { + return this.element.innerHTML.unescapeHTML(); + }, + handleAJAXFailure: function(transport) { + this.triggerCallback('onFailure', transport); + if (this._oldInnerHTML) { + this.element.innerHTML = this._oldInnerHTML; + this._oldInnerHTML = null; + } + }, + handleFormCancellation: function(e) { + this.wrapUp(); + if (e) Event.stop(e); + }, + handleFormSubmission: function(e) { + var form = this._form; + var value = $F(this._controls.editor); + this.prepareSubmission(); + var params = this.options.callback(form, value) || ''; + if (Object.isString(params)) + params = params.toQueryParams(); + params.editorId = this.element.id; + if (this.options.htmlResponse) { + var options = Object.extend({ evalScripts: true }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Updater({ success: this.element }, this.url, options); + } else { + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: params, + onComplete: this._boundWrapperHandler, + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.url, options); + } + if (e) Event.stop(e); + }, + leaveEditMode: function() { + this.element.removeClassName(this.options.savingClassName); + this.removeForm(); + this.leaveHover(); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + if (this.options.externalControl) + this.options.externalControl.show(); + this._saving = false; + this._editing = false; + this._oldInnerHTML = null; + this.triggerCallback('onLeaveEditMode'); + }, + leaveHover: function(e) { + if (this.options.hoverClassName) + this.element.removeClassName(this.options.hoverClassName); + if (this._saving) return; + this.triggerCallback('onLeaveHover'); + }, + loadExternalText: function() { + this._form.addClassName(this.options.loadingClassName); + this._controls.editor.disabled = true; + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._form.removeClassName(this.options.loadingClassName); + var text = transport.responseText; + if (this.options.stripLoadedTextTags) + text = text.stripTags(); + this._controls.editor.value = text; + this._controls.editor.disabled = false; + this.postProcessEditField(); + }.bind(this), + onFailure: this._boundFailureHandler + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + postProcessEditField: function() { + var fpc = this.options.fieldPostCreation; + if (fpc) + $(this._controls.editor)['focus' == fpc ? 'focus' : 'activate'](); + }, + prepareOptions: function() { + this.options = Object.clone(Ajax.InPlaceEditor.DefaultOptions); + Object.extend(this.options, Ajax.InPlaceEditor.DefaultCallbacks); + [this._extraDefaultOptions].flatten().compact().each(function(defs) { + Object.extend(this.options, defs); + }.bind(this)); + }, + prepareSubmission: function() { + this._saving = true; + this.removeForm(); + this.leaveHover(); + this.showSaving(); + }, + registerListeners: function() { + this._listeners = { }; + var listener; + $H(Ajax.InPlaceEditor.Listeners).each(function(pair) { + listener = this[pair.value].bind(this); + this._listeners[pair.key] = listener; + if (!this.options.externalControlOnly) + this.element.observe(pair.key, listener); + if (this.options.externalControl) + this.options.externalControl.observe(pair.key, listener); + }.bind(this)); + }, + removeForm: function() { + if (!this._form) return; + this._form.remove(); + this._form = null; + this._controls = { }; + }, + showSaving: function() { + this._oldInnerHTML = this.element.innerHTML; + this.element.innerHTML = this.options.savingText; + this.element.addClassName(this.options.savingClassName); + this.element.style.backgroundColor = this._originalBackground; + this.element.show(); + }, + triggerCallback: function(cbName, arg) { + if ('function' == typeof this.options[cbName]) { + this.options[cbName](this, arg); + } + }, + unregisterListeners: function() { + $H(this._listeners).each(function(pair) { + if (!this.options.externalControlOnly) + this.element.stopObserving(pair.key, pair.value); + if (this.options.externalControl) + this.options.externalControl.stopObserving(pair.key, pair.value); + }.bind(this)); + }, + wrapUp: function(transport) { + this.leaveEditMode(); + // Can't use triggerCallback due to backward compatibility: requires + // binding + direct element + this._boundComplete(transport, this.element); + } +}); + +Object.extend(Ajax.InPlaceEditor.prototype, { + dispose: Ajax.InPlaceEditor.prototype.destroy +}); + +Ajax.InPlaceCollectionEditor = Class.create(Ajax.InPlaceEditor, { + initialize: function($super, element, url, options) { + this._extraDefaultOptions = Ajax.InPlaceCollectionEditor.DefaultOptions; + $super(element, url, options); + }, + + createEditField: function() { + var list = document.createElement('select'); + list.name = this.options.paramName; + list.size = 1; + this._controls.editor = list; + this._collection = this.options.collection || []; + if (this.options.loadCollectionURL) + this.loadCollection(); + else + this.checkForExternalText(); + this._form.appendChild(this._controls.editor); + }, + + loadCollection: function() { + this._form.addClassName(this.options.loadingClassName); + this.showLoadingText(this.options.loadingCollectionText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + var js = transport.responseText.strip(); + if (!/^\[.*\]$/.test(js)) // TODO: improve sanity check + throw('Server returned an invalid collection representation.'); + this._collection = eval(js); + this.checkForExternalText(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadCollectionURL, options); + }, + + showLoadingText: function(text) { + this._controls.editor.disabled = true; + var tempOption = this._controls.editor.firstChild; + if (!tempOption) { + tempOption = document.createElement('option'); + tempOption.value = ''; + this._controls.editor.appendChild(tempOption); + tempOption.selected = true; + } + tempOption.update((text || '').stripScripts().stripTags()); + }, + + checkForExternalText: function() { + this._text = this.getText(); + if (this.options.loadTextURL) + this.loadExternalText(); + else + this.buildOptionList(); + }, + + loadExternalText: function() { + this.showLoadingText(this.options.loadingText); + var options = Object.extend({ method: 'get' }, this.options.ajaxOptions); + Object.extend(options, { + parameters: 'editorId=' + encodeURIComponent(this.element.id), + onComplete: Prototype.emptyFunction, + onSuccess: function(transport) { + this._text = transport.responseText.strip(); + this.buildOptionList(); + }.bind(this), + onFailure: this.onFailure + }); + new Ajax.Request(this.options.loadTextURL, options); + }, + + buildOptionList: function() { + this._form.removeClassName(this.options.loadingClassName); + this._collection = this._collection.map(function(entry) { + return 2 === entry.length ? entry : [entry, entry].flatten(); + }); + var marker = ('value' in this.options) ? this.options.value : this._text; + var textFound = this._collection.any(function(entry) { + return entry[0] == marker; + }.bind(this)); + this._controls.editor.update(''); + var option; + this._collection.each(function(entry, index) { + option = document.createElement('option'); + option.value = entry[0]; + option.selected = textFound ? entry[0] == marker : 0 == index; + option.appendChild(document.createTextNode(entry[1])); + this._controls.editor.appendChild(option); + }.bind(this)); + this._controls.editor.disabled = false; + Field.scrollFreeActivate(this._controls.editor); + } +}); + +//**** DEPRECATION LAYER FOR InPlace[Collection]Editor! **** +//**** This only exists for a while, in order to let **** +//**** users adapt to the new API. Read up on the new **** +//**** API and convert your code to it ASAP! **** + +Ajax.InPlaceEditor.prototype.initialize.dealWithDeprecatedOptions = function(options) { + if (!options) return; + function fallback(name, expr) { + if (name in options || expr === undefined) return; + options[name] = expr; + }; + fallback('cancelControl', (options.cancelLink ? 'link' : (options.cancelButton ? 'button' : + options.cancelLink == options.cancelButton == false ? false : undefined))); + fallback('okControl', (options.okLink ? 'link' : (options.okButton ? 'button' : + options.okLink == options.okButton == false ? false : undefined))); + fallback('highlightColor', options.highlightcolor); + fallback('highlightEndColor', options.highlightendcolor); +}; + +Object.extend(Ajax.InPlaceEditor, { + DefaultOptions: { + ajaxOptions: { }, + autoRows: 3, // Use when multi-line w/ rows == 1 + cancelControl: 'link', // 'link'|'button'|false + cancelText: 'cancel', + clickToEditText: 'Click to edit', + externalControl: null, // id|elt + externalControlOnly: false, + fieldPostCreation: 'activate', // 'activate'|'focus'|false + formClassName: 'inplaceeditor-form', + formId: null, // id|elt + highlightColor: '#ffff99', + highlightEndColor: '#ffffff', + hoverClassName: '', + htmlResponse: true, + loadingClassName: 'inplaceeditor-loading', + loadingText: 'Loading...', + okControl: 'button', // 'link'|'button'|false + okText: 'ok', + paramName: 'value', + rows: 1, // If 1 and multi-line, uses autoRows + savingClassName: 'inplaceeditor-saving', + savingText: 'Saving...', + size: 0, + stripLoadedTextTags: false, + submitOnBlur: false, + textAfterControls: '', + textBeforeControls: '', + textBetweenControls: '' + }, + DefaultCallbacks: { + callback: function(form) { + return Form.serialize(form); + }, + onComplete: function(transport, element) { + // For backward compatibility, this one is bound to the IPE, and passes + // the element directly. It was too often customized, so we don't break it. + new Effect.Highlight(element, { + startcolor: this.options.highlightColor, keepBackgroundImage: true }); + }, + onEnterEditMode: null, + onEnterHover: function(ipe) { + ipe.element.style.backgroundColor = ipe.options.highlightColor; + if (ipe._effect) + ipe._effect.cancel(); + }, + onFailure: function(transport, ipe) { + alert('Error communication with the server: ' + transport.responseText.stripTags()); + }, + onFormCustomization: null, // Takes the IPE and its generated form, after editor, before controls. + onLeaveEditMode: null, + onLeaveHover: function(ipe) { + ipe._effect = new Effect.Highlight(ipe.element, { + startcolor: ipe.options.highlightColor, endcolor: ipe.options.highlightEndColor, + restorecolor: ipe._originalBackground, keepBackgroundImage: true + }); + } + }, + Listeners: { + click: 'enterEditMode', + keydown: 'checkForEscapeOrReturn', + mouseover: 'enterHover', + mouseout: 'leaveHover' + } +}); + +Ajax.InPlaceCollectionEditor.DefaultOptions = { + loadingCollectionText: 'Loading options...' +}; + +// Delayed observer, like Form.Element.Observer, +// but waits for delay after last key input +// Ideal for live-search fields + +Form.Element.DelayedObserver = Class.create({ + initialize: function(element, delay, callback) { + this.delay = delay || 0.5; + this.element = $(element); + this.callback = callback; + this.timer = null; + this.lastValue = $F(this.element); + Event.observe(this.element,'keyup',this.delayedListener.bindAsEventListener(this)); + }, + delayedListener: function(event) { + if(this.lastValue == $F(this.element)) return; + if(this.timer) clearTimeout(this.timer); + this.timer = setTimeout(this.onTimerEvent.bind(this), this.delay * 1000); + this.lastValue = $F(this.element); + }, + onTimerEvent: function() { + this.timer = null; + this.callback(this.element, $F(this.element)); + } +}); \ No newline at end of file diff --git a/public/javascripts/dragdrop.js b/public/javascripts/dragdrop.js new file mode 100644 index 0000000..15c6dbc --- /dev/null +++ b/public/javascripts/dragdrop.js @@ -0,0 +1,974 @@ +// script.aculo.us dragdrop.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 + +// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +if(Object.isUndefined(Effect)) + throw("dragdrop.js requires including script.aculo.us' effects.js library"); + +var Droppables = { + drops: [], + + remove: function(element) { + this.drops = this.drops.reject(function(d) { return d.element==$(element) }); + }, + + add: function(element) { + element = $(element); + var options = Object.extend({ + greedy: true, + hoverclass: null, + tree: false + }, arguments[1] || { }); + + // cache containers + if(options.containment) { + options._containers = []; + var containment = options.containment; + if(Object.isArray(containment)) { + containment.each( function(c) { options._containers.push($(c)) }); + } else { + options._containers.push($(containment)); + } + } + + if(options.accept) options.accept = [options.accept].flatten(); + + Element.makePositioned(element); // fix IE + options.element = element; + + this.drops.push(options); + }, + + findDeepestChild: function(drops) { + deepest = drops[0]; + + for (i = 1; i < drops.length; ++i) + if (Element.isParent(drops[i].element, deepest.element)) + deepest = drops[i]; + + return deepest; + }, + + isContained: function(element, drop) { + var containmentNode; + if(drop.tree) { + containmentNode = element.treeNode; + } else { + containmentNode = element.parentNode; + } + return drop._containers.detect(function(c) { return containmentNode == c }); + }, + + isAffected: function(point, element, drop) { + return ( + (drop.element!=element) && + ((!drop._containers) || + this.isContained(element, drop)) && + ((!drop.accept) || + (Element.classNames(element).detect( + function(v) { return drop.accept.include(v) } ) )) && + Position.within(drop.element, point[0], point[1]) ); + }, + + deactivate: function(drop) { + if(drop.hoverclass) + Element.removeClassName(drop.element, drop.hoverclass); + this.last_active = null; + }, + + activate: function(drop) { + if(drop.hoverclass) + Element.addClassName(drop.element, drop.hoverclass); + this.last_active = drop; + }, + + show: function(point, element) { + if(!this.drops.length) return; + var drop, affected = []; + + this.drops.each( function(drop) { + if(Droppables.isAffected(point, element, drop)) + affected.push(drop); + }); + + if(affected.length>0) + drop = Droppables.findDeepestChild(affected); + + if(this.last_active && this.last_active != drop) this.deactivate(this.last_active); + if (drop) { + Position.within(drop.element, point[0], point[1]); + if(drop.onHover) + drop.onHover(element, drop.element, Position.overlap(drop.overlap, drop.element)); + + if (drop != this.last_active) Droppables.activate(drop); + } + }, + + fire: function(event, element) { + if(!this.last_active) return; + Position.prepare(); + + if (this.isAffected([Event.pointerX(event), Event.pointerY(event)], element, this.last_active)) + if (this.last_active.onDrop) { + this.last_active.onDrop(element, this.last_active.element, event); + return true; + } + }, + + reset: function() { + if(this.last_active) + this.deactivate(this.last_active); + } +}; + +var Draggables = { + drags: [], + observers: [], + + register: function(draggable) { + if(this.drags.length == 0) { + this.eventMouseUp = this.endDrag.bindAsEventListener(this); + this.eventMouseMove = this.updateDrag.bindAsEventListener(this); + this.eventKeypress = this.keyPress.bindAsEventListener(this); + + Event.observe(document, "mouseup", this.eventMouseUp); + Event.observe(document, "mousemove", this.eventMouseMove); + Event.observe(document, "keypress", this.eventKeypress); + } + this.drags.push(draggable); + }, + + unregister: function(draggable) { + this.drags = this.drags.reject(function(d) { return d==draggable }); + if(this.drags.length == 0) { + Event.stopObserving(document, "mouseup", this.eventMouseUp); + Event.stopObserving(document, "mousemove", this.eventMouseMove); + Event.stopObserving(document, "keypress", this.eventKeypress); + } + }, + + activate: function(draggable) { + if(draggable.options.delay) { + this._timeout = setTimeout(function() { + Draggables._timeout = null; + window.focus(); + Draggables.activeDraggable = draggable; + }.bind(this), draggable.options.delay); + } else { + window.focus(); // allows keypress events if window isn't currently focused, fails for Safari + this.activeDraggable = draggable; + } + }, + + deactivate: function() { + this.activeDraggable = null; + }, + + updateDrag: function(event) { + if(!this.activeDraggable) return; + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + // Mozilla-based browsers fire successive mousemove events with + // the same coordinates, prevent needless redrawing (moz bug?) + if(this._lastPointer && (this._lastPointer.inspect() == pointer.inspect())) return; + this._lastPointer = pointer; + + this.activeDraggable.updateDrag(event, pointer); + }, + + endDrag: function(event) { + if(this._timeout) { + clearTimeout(this._timeout); + this._timeout = null; + } + if(!this.activeDraggable) return; + this._lastPointer = null; + this.activeDraggable.endDrag(event); + this.activeDraggable = null; + }, + + keyPress: function(event) { + if(this.activeDraggable) + this.activeDraggable.keyPress(event); + }, + + addObserver: function(observer) { + this.observers.push(observer); + this._cacheObserverCallbacks(); + }, + + removeObserver: function(element) { // element instead of observer fixes mem leaks + this.observers = this.observers.reject( function(o) { return o.element==element }); + this._cacheObserverCallbacks(); + }, + + notify: function(eventName, draggable, event) { // 'onStart', 'onEnd', 'onDrag' + if(this[eventName+'Count'] > 0) + this.observers.each( function(o) { + if(o[eventName]) o[eventName](eventName, draggable, event); + }); + if(draggable.options[eventName]) draggable.options[eventName](draggable, event); + }, + + _cacheObserverCallbacks: function() { + ['onStart','onEnd','onDrag'].each( function(eventName) { + Draggables[eventName+'Count'] = Draggables.observers.select( + function(o) { return o[eventName]; } + ).length; + }); + } +}; + +/*--------------------------------------------------------------------------*/ + +var Draggable = Class.create({ + initialize: function(element) { + var defaults = { + handle: false, + reverteffect: function(element, top_offset, left_offset) { + var dur = Math.sqrt(Math.abs(top_offset^2)+Math.abs(left_offset^2))*0.02; + new Effect.Move(element, { x: -left_offset, y: -top_offset, duration: dur, + queue: {scope:'_draggable', position:'end'} + }); + }, + endeffect: function(element) { + var toOpacity = Object.isNumber(element._opacity) ? element._opacity : 1.0; + new Effect.Opacity(element, {duration:0.2, from:0.7, to:toOpacity, + queue: {scope:'_draggable', position:'end'}, + afterFinish: function(){ + Draggable._dragging[element] = false + } + }); + }, + zindex: 1000, + revert: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + snap: false, // false, or xy or [x,y] or function(x,y){ return [x,y] } + delay: 0 + }; + + if(!arguments[1] || Object.isUndefined(arguments[1].endeffect)) + Object.extend(defaults, { + starteffect: function(element) { + element._opacity = Element.getOpacity(element); + Draggable._dragging[element] = true; + new Effect.Opacity(element, {duration:0.2, from:element._opacity, to:0.7}); + } + }); + + var options = Object.extend(defaults, arguments[1] || { }); + + this.element = $(element); + + if(options.handle && Object.isString(options.handle)) + this.handle = this.element.down('.'+options.handle, 0); + + if(!this.handle) this.handle = $(options.handle); + if(!this.handle) this.handle = this.element; + + if(options.scroll && !options.scroll.scrollTo && !options.scroll.outerHTML) { + options.scroll = $(options.scroll); + this._isScrollChild = Element.childOf(this.element, options.scroll); + } + + Element.makePositioned(this.element); // fix IE + + this.options = options; + this.dragging = false; + + this.eventMouseDown = this.initDrag.bindAsEventListener(this); + Event.observe(this.handle, "mousedown", this.eventMouseDown); + + Draggables.register(this); + }, + + destroy: function() { + Event.stopObserving(this.handle, "mousedown", this.eventMouseDown); + Draggables.unregister(this); + }, + + currentDelta: function() { + return([ + parseInt(Element.getStyle(this.element,'left') || '0'), + parseInt(Element.getStyle(this.element,'top') || '0')]); + }, + + initDrag: function(event) { + if(!Object.isUndefined(Draggable._dragging[this.element]) && + Draggable._dragging[this.element]) return; + if(Event.isLeftClick(event)) { + // abort on form elements, fixes a Firefox issue + var src = Event.element(event); + if((tag_name = src.tagName.toUpperCase()) && ( + tag_name=='INPUT' || + tag_name=='SELECT' || + tag_name=='OPTION' || + tag_name=='BUTTON' || + tag_name=='TEXTAREA')) return; + + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + var pos = this.element.cumulativeOffset(); + this.offset = [0,1].map( function(i) { return (pointer[i] - pos[i]) }); + + Draggables.activate(this); + Event.stop(event); + } + }, + + startDrag: function(event) { + this.dragging = true; + if(!this.delta) + this.delta = this.currentDelta(); + + if(this.options.zindex) { + this.originalZ = parseInt(Element.getStyle(this.element,'z-index') || 0); + this.element.style.zIndex = this.options.zindex; + } + + if(this.options.ghosting) { + this._clone = this.element.cloneNode(true); + this._originallyAbsolute = (this.element.getStyle('position') == 'absolute'); + if (!this._originallyAbsolute) + Position.absolutize(this.element); + this.element.parentNode.insertBefore(this._clone, this.element); + } + + if(this.options.scroll) { + if (this.options.scroll == window) { + var where = this._getWindowScroll(this.options.scroll); + this.originalScrollLeft = where.left; + this.originalScrollTop = where.top; + } else { + this.originalScrollLeft = this.options.scroll.scrollLeft; + this.originalScrollTop = this.options.scroll.scrollTop; + } + } + + Draggables.notify('onStart', this, event); + + if(this.options.starteffect) this.options.starteffect(this.element); + }, + + updateDrag: function(event, pointer) { + if(!this.dragging) this.startDrag(event); + + if(!this.options.quiet){ + Position.prepare(); + Droppables.show(pointer, this.element); + } + + Draggables.notify('onDrag', this, event); + + this.draw(pointer); + if(this.options.change) this.options.change(this); + + if(this.options.scroll) { + this.stopScrolling(); + + var p; + if (this.options.scroll == window) { + with(this._getWindowScroll(this.options.scroll)) { p = [ left, top, left+width, top+height ]; } + } else { + p = Position.page(this.options.scroll); + p[0] += this.options.scroll.scrollLeft + Position.deltaX; + p[1] += this.options.scroll.scrollTop + Position.deltaY; + p.push(p[0]+this.options.scroll.offsetWidth); + p.push(p[1]+this.options.scroll.offsetHeight); + } + var speed = [0,0]; + if(pointer[0] < (p[0]+this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[0]+this.options.scrollSensitivity); + if(pointer[1] < (p[1]+this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[1]+this.options.scrollSensitivity); + if(pointer[0] > (p[2]-this.options.scrollSensitivity)) speed[0] = pointer[0]-(p[2]-this.options.scrollSensitivity); + if(pointer[1] > (p[3]-this.options.scrollSensitivity)) speed[1] = pointer[1]-(p[3]-this.options.scrollSensitivity); + this.startScrolling(speed); + } + + // fix AppleWebKit rendering + if(Prototype.Browser.WebKit) window.scrollBy(0,0); + + Event.stop(event); + }, + + finishDrag: function(event, success) { + this.dragging = false; + + if(this.options.quiet){ + Position.prepare(); + var pointer = [Event.pointerX(event), Event.pointerY(event)]; + Droppables.show(pointer, this.element); + } + + if(this.options.ghosting) { + if (!this._originallyAbsolute) + Position.relativize(this.element); + delete this._originallyAbsolute; + Element.remove(this._clone); + this._clone = null; + } + + var dropped = false; + if(success) { + dropped = Droppables.fire(event, this.element); + if (!dropped) dropped = false; + } + if(dropped && this.options.onDropped) this.options.onDropped(this.element); + Draggables.notify('onEnd', this, event); + + var revert = this.options.revert; + if(revert && Object.isFunction(revert)) revert = revert(this.element); + + var d = this.currentDelta(); + if(revert && this.options.reverteffect) { + if (dropped == 0 || revert != 'failure') + this.options.reverteffect(this.element, + d[1]-this.delta[1], d[0]-this.delta[0]); + } else { + this.delta = d; + } + + if(this.options.zindex) + this.element.style.zIndex = this.originalZ; + + if(this.options.endeffect) + this.options.endeffect(this.element); + + Draggables.deactivate(this); + Droppables.reset(); + }, + + keyPress: function(event) { + if(event.keyCode!=Event.KEY_ESC) return; + this.finishDrag(event, false); + Event.stop(event); + }, + + endDrag: function(event) { + if(!this.dragging) return; + this.stopScrolling(); + this.finishDrag(event, true); + Event.stop(event); + }, + + draw: function(point) { + var pos = this.element.cumulativeOffset(); + if(this.options.ghosting) { + var r = Position.realOffset(this.element); + pos[0] += r[0] - Position.deltaX; pos[1] += r[1] - Position.deltaY; + } + + var d = this.currentDelta(); + pos[0] -= d[0]; pos[1] -= d[1]; + + if(this.options.scroll && (this.options.scroll != window && this._isScrollChild)) { + pos[0] -= this.options.scroll.scrollLeft-this.originalScrollLeft; + pos[1] -= this.options.scroll.scrollTop-this.originalScrollTop; + } + + var p = [0,1].map(function(i){ + return (point[i]-pos[i]-this.offset[i]) + }.bind(this)); + + if(this.options.snap) { + if(Object.isFunction(this.options.snap)) { + p = this.options.snap(p[0],p[1],this); + } else { + if(Object.isArray(this.options.snap)) { + p = p.map( function(v, i) { + return (v/this.options.snap[i]).round()*this.options.snap[i] }.bind(this)); + } else { + p = p.map( function(v) { + return (v/this.options.snap).round()*this.options.snap }.bind(this)); + } + }} + + var style = this.element.style; + if((!this.options.constraint) || (this.options.constraint=='horizontal')) + style.left = p[0] + "px"; + if((!this.options.constraint) || (this.options.constraint=='vertical')) + style.top = p[1] + "px"; + + if(style.visibility=="hidden") style.visibility = ""; // fix gecko rendering + }, + + stopScrolling: function() { + if(this.scrollInterval) { + clearInterval(this.scrollInterval); + this.scrollInterval = null; + Draggables._lastScrollPointer = null; + } + }, + + startScrolling: function(speed) { + if(!(speed[0] || speed[1])) return; + this.scrollSpeed = [speed[0]*this.options.scrollSpeed,speed[1]*this.options.scrollSpeed]; + this.lastScrolled = new Date(); + this.scrollInterval = setInterval(this.scroll.bind(this), 10); + }, + + scroll: function() { + var current = new Date(); + var delta = current - this.lastScrolled; + this.lastScrolled = current; + if(this.options.scroll == window) { + with (this._getWindowScroll(this.options.scroll)) { + if (this.scrollSpeed[0] || this.scrollSpeed[1]) { + var d = delta / 1000; + this.options.scroll.scrollTo( left + d*this.scrollSpeed[0], top + d*this.scrollSpeed[1] ); + } + } + } else { + this.options.scroll.scrollLeft += this.scrollSpeed[0] * delta / 1000; + this.options.scroll.scrollTop += this.scrollSpeed[1] * delta / 1000; + } + + Position.prepare(); + Droppables.show(Draggables._lastPointer, this.element); + Draggables.notify('onDrag', this); + if (this._isScrollChild) { + Draggables._lastScrollPointer = Draggables._lastScrollPointer || $A(Draggables._lastPointer); + Draggables._lastScrollPointer[0] += this.scrollSpeed[0] * delta / 1000; + Draggables._lastScrollPointer[1] += this.scrollSpeed[1] * delta / 1000; + if (Draggables._lastScrollPointer[0] < 0) + Draggables._lastScrollPointer[0] = 0; + if (Draggables._lastScrollPointer[1] < 0) + Draggables._lastScrollPointer[1] = 0; + this.draw(Draggables._lastScrollPointer); + } + + if(this.options.change) this.options.change(this); + }, + + _getWindowScroll: function(w) { + var T, L, W, H; + with (w.document) { + if (w.document.documentElement && documentElement.scrollTop) { + T = documentElement.scrollTop; + L = documentElement.scrollLeft; + } else if (w.document.body) { + T = body.scrollTop; + L = body.scrollLeft; + } + if (w.innerWidth) { + W = w.innerWidth; + H = w.innerHeight; + } else if (w.document.documentElement && documentElement.clientWidth) { + W = documentElement.clientWidth; + H = documentElement.clientHeight; + } else { + W = body.offsetWidth; + H = body.offsetHeight; + } + } + return { top: T, left: L, width: W, height: H }; + } +}); + +Draggable._dragging = { }; + +/*--------------------------------------------------------------------------*/ + +var SortableObserver = Class.create({ + initialize: function(element, observer) { + this.element = $(element); + this.observer = observer; + this.lastValue = Sortable.serialize(this.element); + }, + + onStart: function() { + this.lastValue = Sortable.serialize(this.element); + }, + + onEnd: function() { + Sortable.unmark(); + if(this.lastValue != Sortable.serialize(this.element)) + this.observer(this.element) + } +}); + +var Sortable = { + SERIALIZE_RULE: /^[^_\-](?:[A-Za-z0-9\-\_]*)[_](.*)$/, + + sortables: { }, + + _findRootElement: function(element) { + while (element.tagName.toUpperCase() != "BODY") { + if(element.id && Sortable.sortables[element.id]) return element; + element = element.parentNode; + } + }, + + options: function(element) { + element = Sortable._findRootElement($(element)); + if(!element) return; + return Sortable.sortables[element.id]; + }, + + destroy: function(element){ + element = $(element); + var s = Sortable.sortables[element.id]; + + if(s) { + Draggables.removeObserver(s.element); + s.droppables.each(function(d){ Droppables.remove(d) }); + s.draggables.invoke('destroy'); + + delete Sortable.sortables[s.element.id]; + } + }, + + create: function(element) { + element = $(element); + var options = Object.extend({ + element: element, + tag: 'li', // assumes li children, override with tag: 'tagname' + dropOnEmpty: false, + tree: false, + treeTag: 'ul', + overlap: 'vertical', // one of 'vertical', 'horizontal' + constraint: 'vertical', // one of 'vertical', 'horizontal', false + containment: element, // also takes array of elements (or id's); or false + handle: false, // or a CSS class + only: false, + delay: 0, + hoverclass: null, + ghosting: false, + quiet: false, + scroll: false, + scrollSensitivity: 20, + scrollSpeed: 15, + format: this.SERIALIZE_RULE, + + // these take arrays of elements or ids and can be + // used for better initialization performance + elements: false, + handles: false, + + onChange: Prototype.emptyFunction, + onUpdate: Prototype.emptyFunction + }, arguments[1] || { }); + + // clear any old sortable with same element + this.destroy(element); + + // build options for the draggables + var options_for_draggable = { + revert: true, + quiet: options.quiet, + scroll: options.scroll, + scrollSpeed: options.scrollSpeed, + scrollSensitivity: options.scrollSensitivity, + delay: options.delay, + ghosting: options.ghosting, + constraint: options.constraint, + handle: options.handle }; + + if(options.starteffect) + options_for_draggable.starteffect = options.starteffect; + + if(options.reverteffect) + options_for_draggable.reverteffect = options.reverteffect; + else + if(options.ghosting) options_for_draggable.reverteffect = function(element) { + element.style.top = 0; + element.style.left = 0; + }; + + if(options.endeffect) + options_for_draggable.endeffect = options.endeffect; + + if(options.zindex) + options_for_draggable.zindex = options.zindex; + + // build options for the droppables + var options_for_droppable = { + overlap: options.overlap, + containment: options.containment, + tree: options.tree, + hoverclass: options.hoverclass, + onHover: Sortable.onHover + }; + + var options_for_tree = { + onHover: Sortable.onEmptyHover, + overlap: options.overlap, + containment: options.containment, + hoverclass: options.hoverclass + }; + + // fix for gecko engine + Element.cleanWhitespace(element); + + options.draggables = []; + options.droppables = []; + + // drop on empty handling + if(options.dropOnEmpty || options.tree) { + Droppables.add(element, options_for_tree); + options.droppables.push(element); + } + + (options.elements || this.findElements(element, options) || []).each( function(e,i) { + var handle = options.handles ? $(options.handles[i]) : + (options.handle ? $(e).select('.' + options.handle)[0] : e); + options.draggables.push( + new Draggable(e, Object.extend(options_for_draggable, { handle: handle }))); + Droppables.add(e, options_for_droppable); + if(options.tree) e.treeNode = element; + options.droppables.push(e); + }); + + if(options.tree) { + (Sortable.findTreeElements(element, options) || []).each( function(e) { + Droppables.add(e, options_for_tree); + e.treeNode = element; + options.droppables.push(e); + }); + } + + // keep reference + this.sortables[element.identify()] = options; + + // for onupdate + Draggables.addObserver(new SortableObserver(element, options.onUpdate)); + + }, + + // return all suitable-for-sortable elements in a guaranteed order + findElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.tag); + }, + + findTreeElements: function(element, options) { + return Element.findChildren( + element, options.only, options.tree ? true : false, options.treeTag); + }, + + onHover: function(element, dropon, overlap) { + if(Element.isParent(dropon, element)) return; + + if(overlap > .33 && overlap < .66 && Sortable.options(dropon).tree) { + return; + } else if(overlap>0.5) { + Sortable.mark(dropon, 'before'); + if(dropon.previousSibling != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, dropon); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } else { + Sortable.mark(dropon, 'after'); + var nextElement = dropon.nextSibling || null; + if(nextElement != element) { + var oldParentNode = element.parentNode; + element.style.visibility = "hidden"; // fix gecko rendering + dropon.parentNode.insertBefore(element, nextElement); + if(dropon.parentNode!=oldParentNode) + Sortable.options(oldParentNode).onChange(element); + Sortable.options(dropon.parentNode).onChange(element); + } + } + }, + + onEmptyHover: function(element, dropon, overlap) { + var oldParentNode = element.parentNode; + var droponOptions = Sortable.options(dropon); + + if(!Element.isParent(dropon, element)) { + var index; + + var children = Sortable.findElements(dropon, {tag: droponOptions.tag, only: droponOptions.only}); + var child = null; + + if(children) { + var offset = Element.offsetSize(dropon, droponOptions.overlap) * (1.0 - overlap); + + for (index = 0; index < children.length; index += 1) { + if (offset - Element.offsetSize (children[index], droponOptions.overlap) >= 0) { + offset -= Element.offsetSize (children[index], droponOptions.overlap); + } else if (offset - (Element.offsetSize (children[index], droponOptions.overlap) / 2) >= 0) { + child = index + 1 < children.length ? children[index + 1] : null; + break; + } else { + child = children[index]; + break; + } + } + } + + dropon.insertBefore(element, child); + + Sortable.options(oldParentNode).onChange(element); + droponOptions.onChange(element); + } + }, + + unmark: function() { + if(Sortable._marker) Sortable._marker.hide(); + }, + + mark: function(dropon, position) { + // mark on ghosting only + var sortable = Sortable.options(dropon.parentNode); + if(sortable && !sortable.ghosting) return; + + if(!Sortable._marker) { + Sortable._marker = + ($('dropmarker') || Element.extend(document.createElement('DIV'))). + hide().addClassName('dropmarker').setStyle({position:'absolute'}); + document.getElementsByTagName("body").item(0).appendChild(Sortable._marker); + } + var offsets = dropon.cumulativeOffset(); + Sortable._marker.setStyle({left: offsets[0]+'px', top: offsets[1] + 'px'}); + + if(position=='after') + if(sortable.overlap == 'horizontal') + Sortable._marker.setStyle({left: (offsets[0]+dropon.clientWidth) + 'px'}); + else + Sortable._marker.setStyle({top: (offsets[1]+dropon.clientHeight) + 'px'}); + + Sortable._marker.show(); + }, + + _tree: function(element, options, parent) { + var children = Sortable.findElements(element, options) || []; + + for (var i = 0; i < children.length; ++i) { + var match = children[i].id.match(options.format); + + if (!match) continue; + + var child = { + id: encodeURIComponent(match ? match[1] : null), + element: element, + parent: parent, + children: [], + position: parent.children.length, + container: $(children[i]).down(options.treeTag) + }; + + /* Get the element containing the children and recurse over it */ + if (child.container) + this._tree(child.container, options, child); + + parent.children.push (child); + } + + return parent; + }, + + tree: function(element) { + element = $(element); + var sortableOptions = this.options(element); + var options = Object.extend({ + tag: sortableOptions.tag, + treeTag: sortableOptions.treeTag, + only: sortableOptions.only, + name: element.id, + format: sortableOptions.format + }, arguments[1] || { }); + + var root = { + id: null, + parent: null, + children: [], + container: element, + position: 0 + }; + + return Sortable._tree(element, options, root); + }, + + /* Construct a [i] index for a particular node */ + _constructIndex: function(node) { + var index = ''; + do { + if (node.id) index = '[' + node.position + ']' + index; + } while ((node = node.parent) != null); + return index; + }, + + sequence: function(element) { + element = $(element); + var options = Object.extend(this.options(element), arguments[1] || { }); + + return $(this.findElements(element, options) || []).map( function(item) { + return item.id.match(options.format) ? item.id.match(options.format)[1] : ''; + }); + }, + + setSequence: function(element, new_sequence) { + element = $(element); + var options = Object.extend(this.options(element), arguments[2] || { }); + + var nodeMap = { }; + this.findElements(element, options).each( function(n) { + if (n.id.match(options.format)) + nodeMap[n.id.match(options.format)[1]] = [n, n.parentNode]; + n.parentNode.removeChild(n); + }); + + new_sequence.each(function(ident) { + var n = nodeMap[ident]; + if (n) { + n[1].appendChild(n[0]); + delete nodeMap[ident]; + } + }); + }, + + serialize: function(element) { + element = $(element); + var options = Object.extend(Sortable.options(element), arguments[1] || { }); + var name = encodeURIComponent( + (arguments[1] && arguments[1].name) ? arguments[1].name : element.id); + + if (options.tree) { + return Sortable.tree(element, arguments[1]).children.map( function (item) { + return [name + Sortable._constructIndex(item) + "[id]=" + + encodeURIComponent(item.id)].concat(item.children.map(arguments.callee)); + }).flatten().join('&'); + } else { + return Sortable.sequence(element, arguments[1]).map( function(item) { + return name + "[]=" + encodeURIComponent(item); + }).join('&'); + } + } +}; + +// Returns true if child is contained within element +Element.isParent = function(child, element) { + if (!child.parentNode || child == element) return false; + if (child.parentNode == element) return true; + return Element.isParent(child.parentNode, element); +}; + +Element.findChildren = function(element, only, recursive, tagName) { + if(!element.hasChildNodes()) return null; + tagName = tagName.toUpperCase(); + if(only) only = [only].flatten(); + var elements = []; + $A(element.childNodes).each( function(e) { + if(e.tagName && e.tagName.toUpperCase()==tagName && + (!only || (Element.classNames(e).detect(function(v) { return only.include(v) })))) + elements.push(e); + if(recursive) { + var grandchildren = Element.findChildren(e, only, recursive, tagName); + if(grandchildren) elements.push(grandchildren); + } + }); + + return (elements.length>0 ? elements.flatten() : []); +}; + +Element.offsetSize = function (element, type) { + return element['offset' + ((type=='vertical' || type=='height') ? 'Height' : 'Width')]; +}; \ No newline at end of file diff --git a/public/javascripts/effects.js b/public/javascripts/effects.js new file mode 100644 index 0000000..c81e6c7 --- /dev/null +++ b/public/javascripts/effects.js @@ -0,0 +1,1123 @@ +// script.aculo.us effects.js v1.8.3, Thu Oct 08 11:23:33 +0200 2009 + +// Copyright (c) 2005-2009 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) +// Contributors: +// Justin Palmer (http://encytemedia.com/) +// Mark Pilgrim (http://diveintomark.org/) +// Martin Bialasinki +// +// script.aculo.us is freely distributable under the terms of an MIT-style license. +// For details, see the script.aculo.us web site: http://script.aculo.us/ + +// converts rgb() and #xxx to #xxxxxx format, +// returns self (or first argument) if not convertable +String.prototype.parseColor = function() { + var color = '#'; + if (this.slice(0,4) == 'rgb(') { + var cols = this.slice(4,this.length-1).split(','); + var i=0; do { color += parseInt(cols[i]).toColorPart() } while (++i<3); + } else { + if (this.slice(0,1) == '#') { + if (this.length==4) for(var i=1;i<4;i++) color += (this.charAt(i) + this.charAt(i)).toLowerCase(); + if (this.length==7) color = this.toLowerCase(); + } + } + return (color.length==7 ? color : (arguments[0] || this)); +}; + +/*--------------------------------------------------------------------------*/ + +Element.collectTextNodes = function(element) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + (node.hasChildNodes() ? Element.collectTextNodes(node) : '')); + }).flatten().join(''); +}; + +Element.collectTextNodesIgnoreClass = function(element, className) { + return $A($(element).childNodes).collect( function(node) { + return (node.nodeType==3 ? node.nodeValue : + ((node.hasChildNodes() && !Element.hasClassName(node,className)) ? + Element.collectTextNodesIgnoreClass(node, className) : '')); + }).flatten().join(''); +}; + +Element.setContentZoom = function(element, percent) { + element = $(element); + element.setStyle({fontSize: (percent/100) + 'em'}); + if (Prototype.Browser.WebKit) window.scrollBy(0,0); + return element; +}; + +Element.getInlineOpacity = function(element){ + return $(element).style.opacity || ''; +}; + +Element.forceRerendering = function(element) { + try { + element = $(element); + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch(e) { } +}; + +/*--------------------------------------------------------------------------*/ + +var Effect = { + _elementDoesNotExistError: { + name: 'ElementDoesNotExistError', + message: 'The specified DOM element does not exist, but is required for this effect to operate' + }, + Transitions: { + linear: Prototype.K, + sinoidal: function(pos) { + return (-Math.cos(pos*Math.PI)/2) + .5; + }, + reverse: function(pos) { + return 1-pos; + }, + flicker: function(pos) { + var pos = ((-Math.cos(pos*Math.PI)/4) + .75) + Math.random()/4; + return pos > 1 ? 1 : pos; + }, + wobble: function(pos) { + return (-Math.cos(pos*Math.PI*(9*pos))/2) + .5; + }, + pulse: function(pos, pulses) { + return (-Math.cos((pos*((pulses||5)-.5)*2)*Math.PI)/2) + .5; + }, + spring: function(pos) { + return 1 - (Math.cos(pos * 4.5 * Math.PI) * Math.exp(-pos * 6)); + }, + none: function(pos) { + return 0; + }, + full: function(pos) { + return 1; + } + }, + DefaultOptions: { + duration: 1.0, // seconds + fps: 100, // 100= assume 66fps max. + sync: false, // true for combining + from: 0.0, + to: 1.0, + delay: 0.0, + queue: 'parallel' + }, + tagifyText: function(element) { + var tagifyStyle = 'position:relative'; + if (Prototype.Browser.IE) tagifyStyle += ';zoom:1'; + + element = $(element); + $A(element.childNodes).each( function(child) { + if (child.nodeType==3) { + child.nodeValue.toArray().each( function(character) { + element.insertBefore( + new Element('span', {style: tagifyStyle}).update( + character == ' ' ? String.fromCharCode(160) : character), + child); + }); + Element.remove(child); + } + }); + }, + multiple: function(element, effect) { + var elements; + if (((typeof element == 'object') || + Object.isFunction(element)) && + (element.length)) + elements = element; + else + elements = $(element).childNodes; + + var options = Object.extend({ + speed: 0.1, + delay: 0.0 + }, arguments[2] || { }); + var masterDelay = options.delay; + + $A(elements).each( function(element, index) { + new effect(element, Object.extend(options, { delay: index * options.speed + masterDelay })); + }); + }, + PAIRS: { + 'slide': ['SlideDown','SlideUp'], + 'blind': ['BlindDown','BlindUp'], + 'appear': ['Appear','Fade'] + }, + toggle: function(element, effect, options) { + element = $(element); + effect = (effect || 'appear').toLowerCase(); + + return Effect[ Effect.PAIRS[ effect ][ element.visible() ? 1 : 0 ] ](element, Object.extend({ + queue: { position:'end', scope:(element.id || 'global'), limit: 1 } + }, options || {})); + } +}; + +Effect.DefaultOptions.transition = Effect.Transitions.sinoidal; + +/* ------------- core effects ------------- */ + +Effect.ScopedQueue = Class.create(Enumerable, { + initialize: function() { + this.effects = []; + this.interval = null; + }, + _each: function(iterator) { + this.effects._each(iterator); + }, + add: function(effect) { + var timestamp = new Date().getTime(); + + var position = Object.isString(effect.options.queue) ? + effect.options.queue : effect.options.queue.position; + + switch(position) { + case 'front': + // move unstarted effects after this effect + this.effects.findAll(function(e){ return e.state=='idle' }).each( function(e) { + e.startOn += effect.finishOn; + e.finishOn += effect.finishOn; + }); + break; + case 'with-last': + timestamp = this.effects.pluck('startOn').max() || timestamp; + break; + case 'end': + // start effect after last queued effect has finished + timestamp = this.effects.pluck('finishOn').max() || timestamp; + break; + } + + effect.startOn += timestamp; + effect.finishOn += timestamp; + + if (!effect.options.queue.limit || (this.effects.length < effect.options.queue.limit)) + this.effects.push(effect); + + if (!this.interval) + this.interval = setInterval(this.loop.bind(this), 15); + }, + remove: function(effect) { + this.effects = this.effects.reject(function(e) { return e==effect }); + if (this.effects.length == 0) { + clearInterval(this.interval); + this.interval = null; + } + }, + loop: function() { + var timePos = new Date().getTime(); + for(var i=0, len=this.effects.length;i= this.startOn) { + if (timePos >= this.finishOn) { + this.render(1.0); + this.cancel(); + this.event('beforeFinish'); + if (this.finish) this.finish(); + this.event('afterFinish'); + return; + } + var pos = (timePos - this.startOn) / this.totalTime, + frame = (pos * this.totalFrames).round(); + if (frame > this.currentFrame) { + this.render(pos); + this.currentFrame = frame; + } + } + }, + cancel: function() { + if (!this.options.sync) + Effect.Queues.get(Object.isString(this.options.queue) ? + 'global' : this.options.queue.scope).remove(this); + this.state = 'finished'; + }, + event: function(eventName) { + if (this.options[eventName + 'Internal']) this.options[eventName + 'Internal'](this); + if (this.options[eventName]) this.options[eventName](this); + }, + inspect: function() { + var data = $H(); + for(property in this) + if (!Object.isFunction(this[property])) data.set(property, this[property]); + return '#'; + } +}); + +Effect.Parallel = Class.create(Effect.Base, { + initialize: function(effects) { + this.effects = effects || []; + this.start(arguments[1]); + }, + update: function(position) { + this.effects.invoke('render', position); + }, + finish: function(position) { + this.effects.each( function(effect) { + effect.render(1.0); + effect.cancel(); + effect.event('beforeFinish'); + if (effect.finish) effect.finish(position); + effect.event('afterFinish'); + }); + } +}); + +Effect.Tween = Class.create(Effect.Base, { + initialize: function(object, from, to) { + object = Object.isString(object) ? $(object) : object; + var args = $A(arguments), method = args.last(), + options = args.length == 5 ? args[3] : null; + this.method = Object.isFunction(method) ? method.bind(object) : + Object.isFunction(object[method]) ? object[method].bind(object) : + function(value) { object[method] = value }; + this.start(Object.extend({ from: from, to: to }, options || { })); + }, + update: function(position) { + this.method(position); + } +}); + +Effect.Event = Class.create(Effect.Base, { + initialize: function() { + this.start(Object.extend({ duration: 0 }, arguments[0] || { })); + }, + update: Prototype.emptyFunction +}); + +Effect.Opacity = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + // make this work on IE on elements without 'layout' + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + var options = Object.extend({ + from: this.element.getOpacity() || 0.0, + to: 1.0 + }, arguments[1] || { }); + this.start(options); + }, + update: function(position) { + this.element.setOpacity(position); + } +}); + +Effect.Move = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + x: 0, + y: 0, + mode: 'relative' + }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + this.element.makePositioned(); + this.originalLeft = parseFloat(this.element.getStyle('left') || '0'); + this.originalTop = parseFloat(this.element.getStyle('top') || '0'); + if (this.options.mode == 'absolute') { + this.options.x = this.options.x - this.originalLeft; + this.options.y = this.options.y - this.originalTop; + } + }, + update: function(position) { + this.element.setStyle({ + left: (this.options.x * position + this.originalLeft).round() + 'px', + top: (this.options.y * position + this.originalTop).round() + 'px' + }); + } +}); + +// for backwards compatibility +Effect.MoveBy = function(element, toTop, toLeft) { + return new Effect.Move(element, + Object.extend({ x: toLeft, y: toTop }, arguments[3] || { })); +}; + +Effect.Scale = Class.create(Effect.Base, { + initialize: function(element, percent) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + scaleX: true, + scaleY: true, + scaleContent: true, + scaleFromCenter: false, + scaleMode: 'box', // 'box' or 'contents' or { } with provided values + scaleFrom: 100.0, + scaleTo: percent + }, arguments[2] || { }); + this.start(options); + }, + setup: function() { + this.restoreAfterFinish = this.options.restoreAfterFinish || false; + this.elementPositioning = this.element.getStyle('position'); + + this.originalStyle = { }; + ['top','left','width','height','fontSize'].each( function(k) { + this.originalStyle[k] = this.element.style[k]; + }.bind(this)); + + this.originalTop = this.element.offsetTop; + this.originalLeft = this.element.offsetLeft; + + var fontSize = this.element.getStyle('font-size') || '100%'; + ['em','px','%','pt'].each( function(fontSizeType) { + if (fontSize.indexOf(fontSizeType)>0) { + this.fontSize = parseFloat(fontSize); + this.fontSizeType = fontSizeType; + } + }.bind(this)); + + this.factor = (this.options.scaleTo - this.options.scaleFrom)/100; + + this.dims = null; + if (this.options.scaleMode=='box') + this.dims = [this.element.offsetHeight, this.element.offsetWidth]; + if (/^content/.test(this.options.scaleMode)) + this.dims = [this.element.scrollHeight, this.element.scrollWidth]; + if (!this.dims) + this.dims = [this.options.scaleMode.originalHeight, + this.options.scaleMode.originalWidth]; + }, + update: function(position) { + var currentScale = (this.options.scaleFrom/100.0) + (this.factor * position); + if (this.options.scaleContent && this.fontSize) + this.element.setStyle({fontSize: this.fontSize * currentScale + this.fontSizeType }); + this.setDimensions(this.dims[0] * currentScale, this.dims[1] * currentScale); + }, + finish: function(position) { + if (this.restoreAfterFinish) this.element.setStyle(this.originalStyle); + }, + setDimensions: function(height, width) { + var d = { }; + if (this.options.scaleX) d.width = width.round() + 'px'; + if (this.options.scaleY) d.height = height.round() + 'px'; + if (this.options.scaleFromCenter) { + var topd = (height - this.dims[0])/2; + var leftd = (width - this.dims[1])/2; + if (this.elementPositioning == 'absolute') { + if (this.options.scaleY) d.top = this.originalTop-topd + 'px'; + if (this.options.scaleX) d.left = this.originalLeft-leftd + 'px'; + } else { + if (this.options.scaleY) d.top = -topd + 'px'; + if (this.options.scaleX) d.left = -leftd + 'px'; + } + } + this.element.setStyle(d); + } +}); + +Effect.Highlight = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ startcolor: '#ffff99' }, arguments[1] || { }); + this.start(options); + }, + setup: function() { + // Prevent executing on elements not in the layout flow + if (this.element.getStyle('display')=='none') { this.cancel(); return; } + // Disable background image during the effect + this.oldStyle = { }; + if (!this.options.keepBackgroundImage) { + this.oldStyle.backgroundImage = this.element.getStyle('background-image'); + this.element.setStyle({backgroundImage: 'none'}); + } + if (!this.options.endcolor) + this.options.endcolor = this.element.getStyle('background-color').parseColor('#ffffff'); + if (!this.options.restorecolor) + this.options.restorecolor = this.element.getStyle('background-color'); + // init color calculations + this._base = $R(0,2).map(function(i){ return parseInt(this.options.startcolor.slice(i*2+1,i*2+3),16) }.bind(this)); + this._delta = $R(0,2).map(function(i){ return parseInt(this.options.endcolor.slice(i*2+1,i*2+3),16)-this._base[i] }.bind(this)); + }, + update: function(position) { + this.element.setStyle({backgroundColor: $R(0,2).inject('#',function(m,v,i){ + return m+((this._base[i]+(this._delta[i]*position)).round().toColorPart()); }.bind(this)) }); + }, + finish: function() { + this.element.setStyle(Object.extend(this.oldStyle, { + backgroundColor: this.options.restorecolor + })); + } +}); + +Effect.ScrollTo = function(element) { + var options = arguments[1] || { }, + scrollOffsets = document.viewport.getScrollOffsets(), + elementOffsets = $(element).cumulativeOffset(); + + if (options.offset) elementOffsets[1] += options.offset; + + return new Effect.Tween(null, + scrollOffsets.top, + elementOffsets[1], + options, + function(p){ scrollTo(scrollOffsets.left, p.round()); } + ); +}; + +/* ------------- combination effects ------------- */ + +Effect.Fade = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + var options = Object.extend({ + from: element.getOpacity() || 1.0, + to: 0.0, + afterFinishInternal: function(effect) { + if (effect.options.to!=0) return; + effect.element.hide().setStyle({opacity: oldOpacity}); + } + }, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Appear = function(element) { + element = $(element); + var options = Object.extend({ + from: (element.getStyle('display') == 'none' ? 0.0 : element.getOpacity() || 0.0), + to: 1.0, + // force Safari to render floated elements properly + afterFinishInternal: function(effect) { + effect.element.forceRerendering(); + }, + beforeSetup: function(effect) { + effect.element.setOpacity(effect.options.from).show(); + }}, arguments[1] || { }); + return new Effect.Opacity(element,options); +}; + +Effect.Puff = function(element) { + element = $(element); + var oldStyle = { + opacity: element.getInlineOpacity(), + position: element.getStyle('position'), + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height + }; + return new Effect.Parallel( + [ new Effect.Scale(element, 200, + { sync: true, scaleFromCenter: true, scaleContent: true, restoreAfterFinish: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 } ) ], + Object.extend({ duration: 1.0, + beforeSetupInternal: function(effect) { + Position.absolutize(effect.effects[0].element); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().setStyle(oldStyle); } + }, arguments[1] || { }) + ); +}; + +Effect.BlindUp = function(element) { + element = $(element); + element.makeClipping(); + return new Effect.Scale(element, 0, + Object.extend({ scaleContent: false, + scaleX: false, + restoreAfterFinish: true, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }, arguments[1] || { }) + ); +}; + +Effect.BlindDown = function(element) { + element = $(element); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: 0, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping(); + } + }, arguments[1] || { })); +}; + +Effect.SwitchOff = function(element) { + element = $(element); + var oldOpacity = element.getInlineOpacity(); + return new Effect.Appear(element, Object.extend({ + duration: 0.4, + from: 0, + transition: Effect.Transitions.flicker, + afterFinishInternal: function(effect) { + new Effect.Scale(effect.element, 1, { + duration: 0.3, scaleFromCenter: true, + scaleX: false, scaleContent: false, restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned().setStyle({opacity: oldOpacity}); + } + }); + } + }, arguments[1] || { })); +}; + +Effect.DropOut = function(element) { + element = $(element); + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left'), + opacity: element.getInlineOpacity() }; + return new Effect.Parallel( + [ new Effect.Move(element, {x: 0, y: 100, sync: true }), + new Effect.Opacity(element, { sync: true, to: 0.0 }) ], + Object.extend( + { duration: 0.5, + beforeSetup: function(effect) { + effect.effects[0].element.makePositioned(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoPositioned().setStyle(oldStyle); + } + }, arguments[1] || { })); +}; + +Effect.Shake = function(element) { + element = $(element); + var options = Object.extend({ + distance: 20, + duration: 0.5 + }, arguments[1] || {}); + var distance = parseFloat(options.distance); + var split = parseFloat(options.duration) / 10.0; + var oldStyle = { + top: element.getStyle('top'), + left: element.getStyle('left') }; + return new Effect.Move(element, + { x: distance, y: 0, duration: split, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: distance*2, y: 0, duration: split*2, afterFinishInternal: function(effect) { + new Effect.Move(effect.element, + { x: -distance, y: 0, duration: split, afterFinishInternal: function(effect) { + effect.element.undoPositioned().setStyle(oldStyle); + }}); }}); }}); }}); }}); }}); +}; + +Effect.SlideDown = function(element) { + element = $(element).cleanWhitespace(); + // SlideDown need to have the content of the element wrapped in a container element with fixed height! + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, 100, Object.extend({ + scaleContent: false, + scaleX: false, + scaleFrom: window.opera ? 0 : 1, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().setStyle({height: '0px'}).show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); } + }, arguments[1] || { }) + ); +}; + +Effect.SlideUp = function(element) { + element = $(element).cleanWhitespace(); + var oldInnerBottom = element.down().getStyle('bottom'); + var elementDimensions = element.getDimensions(); + return new Effect.Scale(element, window.opera ? 0 : 1, + Object.extend({ scaleContent: false, + scaleX: false, + scaleMode: 'box', + scaleFrom: 100, + scaleMode: {originalHeight: elementDimensions.height, originalWidth: elementDimensions.width}, + restoreAfterFinish: true, + afterSetup: function(effect) { + effect.element.makePositioned(); + effect.element.down().makePositioned(); + if (window.opera) effect.element.setStyle({top: ''}); + effect.element.makeClipping().show(); + }, + afterUpdateInternal: function(effect) { + effect.element.down().setStyle({bottom: + (effect.dims[0] - effect.element.clientHeight) + 'px' }); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().undoPositioned(); + effect.element.down().undoPositioned().setStyle({bottom: oldInnerBottom}); + } + }, arguments[1] || { }) + ); +}; + +// Bug in opera makes the TD containing this element expand for a instance after finish +Effect.Squish = function(element) { + return new Effect.Scale(element, window.opera ? 1 : 0, { + restoreAfterFinish: true, + beforeSetup: function(effect) { + effect.element.makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping(); + } + }); +}; + +Effect.Grow = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.full + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var initialMoveX, initialMoveY; + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + initialMoveX = initialMoveY = moveX = moveY = 0; + break; + case 'top-right': + initialMoveX = dims.width; + initialMoveY = moveY = 0; + moveX = -dims.width; + break; + case 'bottom-left': + initialMoveX = moveX = 0; + initialMoveY = dims.height; + moveY = -dims.height; + break; + case 'bottom-right': + initialMoveX = dims.width; + initialMoveY = dims.height; + moveX = -dims.width; + moveY = -dims.height; + break; + case 'center': + initialMoveX = dims.width / 2; + initialMoveY = dims.height / 2; + moveX = -dims.width / 2; + moveY = -dims.height / 2; + break; + } + + return new Effect.Move(element, { + x: initialMoveX, + y: initialMoveY, + duration: 0.01, + beforeSetup: function(effect) { + effect.element.hide().makeClipping().makePositioned(); + }, + afterFinishInternal: function(effect) { + new Effect.Parallel( + [ new Effect.Opacity(effect.element, { sync: true, to: 1.0, from: 0.0, transition: options.opacityTransition }), + new Effect.Move(effect.element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }), + new Effect.Scale(effect.element, 100, { + scaleMode: { originalHeight: dims.height, originalWidth: dims.width }, + sync: true, scaleFrom: window.opera ? 1 : 0, transition: options.scaleTransition, restoreAfterFinish: true}) + ], Object.extend({ + beforeSetup: function(effect) { + effect.effects[0].element.setStyle({height: '0px'}).show(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.undoClipping().undoPositioned().setStyle(oldStyle); + } + }, options) + ); + } + }); +}; + +Effect.Shrink = function(element) { + element = $(element); + var options = Object.extend({ + direction: 'center', + moveTransition: Effect.Transitions.sinoidal, + scaleTransition: Effect.Transitions.sinoidal, + opacityTransition: Effect.Transitions.none + }, arguments[1] || { }); + var oldStyle = { + top: element.style.top, + left: element.style.left, + height: element.style.height, + width: element.style.width, + opacity: element.getInlineOpacity() }; + + var dims = element.getDimensions(); + var moveX, moveY; + + switch (options.direction) { + case 'top-left': + moveX = moveY = 0; + break; + case 'top-right': + moveX = dims.width; + moveY = 0; + break; + case 'bottom-left': + moveX = 0; + moveY = dims.height; + break; + case 'bottom-right': + moveX = dims.width; + moveY = dims.height; + break; + case 'center': + moveX = dims.width / 2; + moveY = dims.height / 2; + break; + } + + return new Effect.Parallel( + [ new Effect.Opacity(element, { sync: true, to: 0.0, from: 1.0, transition: options.opacityTransition }), + new Effect.Scale(element, window.opera ? 1 : 0, { sync: true, transition: options.scaleTransition, restoreAfterFinish: true}), + new Effect.Move(element, { x: moveX, y: moveY, sync: true, transition: options.moveTransition }) + ], Object.extend({ + beforeStartInternal: function(effect) { + effect.effects[0].element.makePositioned().makeClipping(); + }, + afterFinishInternal: function(effect) { + effect.effects[0].element.hide().undoClipping().undoPositioned().setStyle(oldStyle); } + }, options) + ); +}; + +Effect.Pulsate = function(element) { + element = $(element); + var options = arguments[1] || { }, + oldOpacity = element.getInlineOpacity(), + transition = options.transition || Effect.Transitions.linear, + reverser = function(pos){ + return 1 - transition((-Math.cos((pos*(options.pulses||5)*2)*Math.PI)/2) + .5); + }; + + return new Effect.Opacity(element, + Object.extend(Object.extend({ duration: 2.0, from: 0, + afterFinishInternal: function(effect) { effect.element.setStyle({opacity: oldOpacity}); } + }, options), {transition: reverser})); +}; + +Effect.Fold = function(element) { + element = $(element); + var oldStyle = { + top: element.style.top, + left: element.style.left, + width: element.style.width, + height: element.style.height }; + element.makeClipping(); + return new Effect.Scale(element, 5, Object.extend({ + scaleContent: false, + scaleX: false, + afterFinishInternal: function(effect) { + new Effect.Scale(element, 1, { + scaleContent: false, + scaleY: false, + afterFinishInternal: function(effect) { + effect.element.hide().undoClipping().setStyle(oldStyle); + } }); + }}, arguments[1] || { })); +}; + +Effect.Morph = Class.create(Effect.Base, { + initialize: function(element) { + this.element = $(element); + if (!this.element) throw(Effect._elementDoesNotExistError); + var options = Object.extend({ + style: { } + }, arguments[1] || { }); + + if (!Object.isString(options.style)) this.style = $H(options.style); + else { + if (options.style.include(':')) + this.style = options.style.parseStyle(); + else { + this.element.addClassName(options.style); + this.style = $H(this.element.getStyles()); + this.element.removeClassName(options.style); + var css = this.element.getStyles(); + this.style = this.style.reject(function(style) { + return style.value == css[style.key]; + }); + options.afterFinishInternal = function(effect) { + effect.element.addClassName(effect.options.style); + effect.transforms.each(function(transform) { + effect.element.style[transform.style] = ''; + }); + }; + } + } + this.start(options); + }, + + setup: function(){ + function parseColor(color){ + if (!color || ['rgba(0, 0, 0, 0)','transparent'].include(color)) color = '#ffffff'; + color = color.parseColor(); + return $R(0,2).map(function(i){ + return parseInt( color.slice(i*2+1,i*2+3), 16 ); + }); + } + this.transforms = this.style.map(function(pair){ + var property = pair[0], value = pair[1], unit = null; + + if (value.parseColor('#zzzzzz') != '#zzzzzz') { + value = value.parseColor(); + unit = 'color'; + } else if (property == 'opacity') { + value = parseFloat(value); + if (Prototype.Browser.IE && (!this.element.currentStyle.hasLayout)) + this.element.setStyle({zoom: 1}); + } else if (Element.CSS_LENGTH.test(value)) { + var components = value.match(/^([\+\-]?[0-9\.]+)(.*)$/); + value = parseFloat(components[1]); + unit = (components.length == 3) ? components[2] : null; + } + + var originalValue = this.element.getStyle(property); + return { + style: property.camelize(), + originalValue: unit=='color' ? parseColor(originalValue) : parseFloat(originalValue || 0), + targetValue: unit=='color' ? parseColor(value) : value, + unit: unit + }; + }.bind(this)).reject(function(transform){ + return ( + (transform.originalValue == transform.targetValue) || + ( + transform.unit != 'color' && + (isNaN(transform.originalValue) || isNaN(transform.targetValue)) + ) + ); + }); + }, + update: function(position) { + var style = { }, transform, i = this.transforms.length; + while(i--) + style[(transform = this.transforms[i]).style] = + transform.unit=='color' ? '#'+ + (Math.round(transform.originalValue[0]+ + (transform.targetValue[0]-transform.originalValue[0])*position)).toColorPart() + + (Math.round(transform.originalValue[1]+ + (transform.targetValue[1]-transform.originalValue[1])*position)).toColorPart() + + (Math.round(transform.originalValue[2]+ + (transform.targetValue[2]-transform.originalValue[2])*position)).toColorPart() : + (transform.originalValue + + (transform.targetValue - transform.originalValue) * position).toFixed(3) + + (transform.unit === null ? '' : transform.unit); + this.element.setStyle(style, true); + } +}); + +Effect.Transform = Class.create({ + initialize: function(tracks){ + this.tracks = []; + this.options = arguments[1] || { }; + this.addTracks(tracks); + }, + addTracks: function(tracks){ + tracks.each(function(track){ + track = $H(track); + var data = track.values().first(); + this.tracks.push($H({ + ids: track.keys().first(), + effect: Effect.Morph, + options: { style: data } + })); + }.bind(this)); + return this; + }, + play: function(){ + return new Effect.Parallel( + this.tracks.map(function(track){ + var ids = track.get('ids'), effect = track.get('effect'), options = track.get('options'); + var elements = [$(ids) || $$(ids)].flatten(); + return elements.map(function(e){ return new effect(e, Object.extend({ sync:true }, options)) }); + }).flatten(), + this.options + ); + } +}); + +Element.CSS_PROPERTIES = $w( + 'backgroundColor backgroundPosition borderBottomColor borderBottomStyle ' + + 'borderBottomWidth borderLeftColor borderLeftStyle borderLeftWidth ' + + 'borderRightColor borderRightStyle borderRightWidth borderSpacing ' + + 'borderTopColor borderTopStyle borderTopWidth bottom clip color ' + + 'fontSize fontWeight height left letterSpacing lineHeight ' + + 'marginBottom marginLeft marginRight marginTop markerOffset maxHeight '+ + 'maxWidth minHeight minWidth opacity outlineColor outlineOffset ' + + 'outlineWidth paddingBottom paddingLeft paddingRight paddingTop ' + + 'right textIndent top width wordSpacing zIndex'); + +Element.CSS_LENGTH = /^(([\+\-]?[0-9\.]+)(em|ex|px|in|cm|mm|pt|pc|\%))|0$/; + +String.__parseStyleElement = document.createElement('div'); +String.prototype.parseStyle = function(){ + var style, styleRules = $H(); + if (Prototype.Browser.WebKit) + style = new Element('div',{style:this}).style; + else { + String.__parseStyleElement.innerHTML = '
    '; + style = String.__parseStyleElement.childNodes[0].style; + } + + Element.CSS_PROPERTIES.each(function(property){ + if (style[property]) styleRules.set(property, style[property]); + }); + + if (Prototype.Browser.IE && this.include('opacity')) + styleRules.set('opacity', this.match(/opacity:\s*((?:0|1)?(?:\.\d*)?)/)[1]); + + return styleRules; +}; + +if (document.defaultView && document.defaultView.getComputedStyle) { + Element.getStyles = function(element) { + var css = document.defaultView.getComputedStyle($(element), null); + return Element.CSS_PROPERTIES.inject({ }, function(styles, property) { + styles[property] = css[property]; + return styles; + }); + }; +} else { + Element.getStyles = function(element) { + element = $(element); + var css = element.currentStyle, styles; + styles = Element.CSS_PROPERTIES.inject({ }, function(results, property) { + results[property] = css[property]; + return results; + }); + if (!styles.opacity) styles.opacity = element.getOpacity(); + return styles; + }; +} + +Effect.Methods = { + morph: function(element, style) { + element = $(element); + new Effect.Morph(element, Object.extend({ style: style }, arguments[2] || { })); + return element; + }, + visualEffect: function(element, effect, options) { + element = $(element); + var s = effect.dasherize().camelize(), klass = s.charAt(0).toUpperCase() + s.substring(1); + new Effect[klass](element, options); + return element; + }, + highlight: function(element, options) { + element = $(element); + new Effect.Highlight(element, options); + return element; + } +}; + +$w('fade appear grow shrink fold blindUp blindDown slideUp slideDown '+ + 'pulsate shake puff squish switchOff dropOut').each( + function(effect) { + Effect.Methods[effect] = function(element, options){ + element = $(element); + Effect[effect.charAt(0).toUpperCase() + effect.substring(1)](element, options); + return element; + }; + } +); + +$w('getInlineOpacity forceRerendering setContentZoom collectTextNodes collectTextNodesIgnoreClass getStyles').each( + function(f) { Effect.Methods[f] = Element[f]; } +); + +Element.addMethods(Effect.Methods); \ No newline at end of file diff --git a/public/javascripts/prototype.js b/public/javascripts/prototype.js new file mode 100644 index 0000000..06249a6 --- /dev/null +++ b/public/javascripts/prototype.js @@ -0,0 +1,6001 @@ +/* Prototype JavaScript framework, version 1.7_rc2 + * (c) 2005-2010 Sam Stephenson + * + * Prototype is freely distributable under the terms of an MIT-style license. + * For details, see the Prototype web site: http://www.prototypejs.org/ + * + *--------------------------------------------------------------------------*/ + +var Prototype = { + + Version: '1.7_rc2', + + Browser: (function(){ + var ua = navigator.userAgent; + var isOpera = Object.prototype.toString.call(window.opera) == '[object Opera]'; + return { + IE: !!window.attachEvent && !isOpera, + Opera: isOpera, + WebKit: ua.indexOf('AppleWebKit/') > -1, + Gecko: ua.indexOf('Gecko') > -1 && ua.indexOf('KHTML') === -1, + MobileSafari: /Apple.*Mobile/.test(ua) + } + })(), + + BrowserFeatures: { + XPath: !!document.evaluate, + + SelectorsAPI: !!document.querySelector, + + ElementExtensions: (function() { + var constructor = window.Element || window.HTMLElement; + return !!(constructor && constructor.prototype); + })(), + SpecificElementExtensions: (function() { + if (typeof window.HTMLDivElement !== 'undefined') + return true; + + var div = document.createElement('div'), + form = document.createElement('form'), + isSupported = false; + + if (div['__proto__'] && (div['__proto__'] !== form['__proto__'])) { + isSupported = true; + } + + div = form = null; + + return isSupported; + })() + }, + + ScriptFragment: ']*>([\\S\\s]*?)<\/script>', + JSONFilter: /^\/\*-secure-([\s\S]*)\*\/\s*$/, + + emptyFunction: function() { }, + + K: function(x) { return x } +}; + +if (Prototype.Browser.MobileSafari) + Prototype.BrowserFeatures.SpecificElementExtensions = false; + + +var Abstract = { }; + + +var Try = { + these: function() { + var returnValue; + + for (var i = 0, length = arguments.length; i < length; i++) { + var lambda = arguments[i]; + try { + returnValue = lambda(); + break; + } catch (e) { } + } + + return returnValue; + } +}; + +/* Based on Alex Arnell's inheritance implementation. */ + +var Class = (function() { + + var IS_DONTENUM_BUGGY = (function(){ + for (var p in { toString: 1 }) { + if (p === 'toString') return false; + } + return true; + })(); + + function subclass() {}; + function create() { + var parent = null, properties = $A(arguments); + if (Object.isFunction(properties[0])) + parent = properties.shift(); + + function klass() { + this.initialize.apply(this, arguments); + } + + Object.extend(klass, Class.Methods); + klass.superclass = parent; + klass.subclasses = []; + + if (parent) { + subclass.prototype = parent.prototype; + klass.prototype = new subclass; + parent.subclasses.push(klass); + } + + for (var i = 0, length = properties.length; i < length; i++) + klass.addMethods(properties[i]); + + if (!klass.prototype.initialize) + klass.prototype.initialize = Prototype.emptyFunction; + + klass.prototype.constructor = klass; + return klass; + } + + function addMethods(source) { + var ancestor = this.superclass && this.superclass.prototype, + properties = Object.keys(source); + + if (IS_DONTENUM_BUGGY) { + if (source.toString != Object.prototype.toString) + properties.push("toString"); + if (source.valueOf != Object.prototype.valueOf) + properties.push("valueOf"); + } + + for (var i = 0, length = properties.length; i < length; i++) { + var property = properties[i], value = source[property]; + if (ancestor && Object.isFunction(value) && + value.argumentNames()[0] == "$super") { + var method = value; + value = (function(m) { + return function() { return ancestor[m].apply(this, arguments); }; + })(property).wrap(method); + + value.valueOf = method.valueOf.bind(method); + value.toString = method.toString.bind(method); + } + this.prototype[property] = value; + } + + return this; + } + + return { + create: create, + Methods: { + addMethods: addMethods + } + }; +})(); +(function() { + + var _toString = Object.prototype.toString, + NULL_TYPE = 'Null', + UNDEFINED_TYPE = 'Undefined', + BOOLEAN_TYPE = 'Boolean', + NUMBER_TYPE = 'Number', + STRING_TYPE = 'String', + OBJECT_TYPE = 'Object', + BOOLEAN_CLASS = '[object Boolean]', + NUMBER_CLASS = '[object Number]', + STRING_CLASS = '[object String]', + ARRAY_CLASS = '[object Array]', + NATIVE_JSON_STRINGIFY_SUPPORT = window.JSON && + typeof JSON.stringify === 'function' && + JSON.stringify(0) === '0' && + typeof JSON.stringify(Prototype.K) === 'undefined'; + + function Type(o) { + switch(o) { + case null: return NULL_TYPE; + case (void 0): return UNDEFINED_TYPE; + } + var type = typeof o; + switch(type) { + case 'boolean': return BOOLEAN_TYPE; + case 'number': return NUMBER_TYPE; + case 'string': return STRING_TYPE; + } + return OBJECT_TYPE; + } + + function extend(destination, source) { + for (var property in source) + destination[property] = source[property]; + return destination; + } + + function inspect(object) { + try { + if (isUndefined(object)) return 'undefined'; + if (object === null) return 'null'; + return object.inspect ? object.inspect() : String(object); + } catch (e) { + if (e instanceof RangeError) return '...'; + throw e; + } + } + + function toJSON(value) { + return Str('', { '': value }, []); + } + + function Str(key, holder, stack) { + var value = holder[key], + type = typeof value; + + if (Type(value) === OBJECT_TYPE && typeof value.toJSON === 'function') { + value = value.toJSON(key); + } + + var _class = _toString.call(value); + + switch (_class) { + case NUMBER_CLASS: + case BOOLEAN_CLASS: + case STRING_CLASS: + value = value.valueOf(); + } + + switch (value) { + case null: return 'null'; + case true: return 'true'; + case false: return 'false'; + } + + type = typeof value; + switch (type) { + case 'string': + return value.inspect(true); + case 'number': + return isFinite(value) ? String(value) : 'null'; + case 'object': + + for (var i = 0, length = stack.length; i < length; i++) { + if (stack[i] === value) { throw new TypeError(); } + } + stack.push(value); + + var partial = []; + if (_class === ARRAY_CLASS) { + for (var i = 0, length = value.length; i < length; i++) { + var str = Str(i, value, stack); + partial.push(typeof str === 'undefined' ? 'null' : str); + } + partial = '[' + partial.join(',') + ']'; + } else { + var keys = Object.keys(value); + for (var i = 0, length = keys.length; i < length; i++) { + var key = keys[i], str = Str(key, value, stack); + if (typeof str !== "undefined") { + partial.push(key.inspect(true)+ ':' + str); + } + } + partial = '{' + partial.join(',') + '}'; + } + stack.pop(); + return partial; + } + } + + function stringify(object) { + return JSON.stringify(object); + } + + function toQueryString(object) { + return $H(object).toQueryString(); + } + + function toHTML(object) { + return object && object.toHTML ? object.toHTML() : String.interpret(object); + } + + function keys(object) { + if (Type(object) !== OBJECT_TYPE) { throw new TypeError(); } + var results = []; + for (var property in object) { + if (object.hasOwnProperty(property)) { + results.push(property); + } + } + return results; + } + + function values(object) { + var results = []; + for (var property in object) + results.push(object[property]); + return results; + } + + function clone(object) { + return extend({ }, object); + } + + function isElement(object) { + return !!(object && object.nodeType == 1); + } + + function isArray(object) { + return _toString.call(object) === ARRAY_CLASS; + } + + var hasNativeIsArray = (typeof Array.isArray == 'function') + && Array.isArray([]) && !Array.isArray({}); + + if (hasNativeIsArray) { + isArray = Array.isArray; + } + + function isHash(object) { + return object instanceof Hash; + } + + function isFunction(object) { + return typeof object === "function"; + } + + function isString(object) { + return _toString.call(object) === STRING_CLASS; + } + + function isNumber(object) { + return _toString.call(object) === NUMBER_CLASS; + } + + function isUndefined(object) { + return typeof object === "undefined"; + } + + extend(Object, { + extend: extend, + inspect: inspect, + toJSON: NATIVE_JSON_STRINGIFY_SUPPORT ? stringify : toJSON, + toQueryString: toQueryString, + toHTML: toHTML, + keys: Object.keys || keys, + values: values, + clone: clone, + isElement: isElement, + isArray: isArray, + isHash: isHash, + isFunction: isFunction, + isString: isString, + isNumber: isNumber, + isUndefined: isUndefined + }); +})(); +Object.extend(Function.prototype, (function() { + var slice = Array.prototype.slice; + + function update(array, args) { + var arrayLength = array.length, length = args.length; + while (length--) array[arrayLength + length] = args[length]; + return array; + } + + function merge(array, args) { + array = slice.call(array, 0); + return update(array, args); + } + + function argumentNames() { + var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1] + .replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '') + .replace(/\s+/g, '').split(','); + return names.length == 1 && !names[0] ? [] : names; + } + + function bind(context) { + if (arguments.length < 2 && Object.isUndefined(arguments[0])) return this; + var __method = this, args = slice.call(arguments, 1); + return function() { + var a = merge(args, arguments); + return __method.apply(context, a); + } + } + + function bindAsEventListener(context) { + var __method = this, args = slice.call(arguments, 1); + return function(event) { + var a = update([event || window.event], args); + return __method.apply(context, a); + } + } + + function curry() { + if (!arguments.length) return this; + var __method = this, args = slice.call(arguments, 0); + return function() { + var a = merge(args, arguments); + return __method.apply(this, a); + } + } + + function delay(timeout) { + var __method = this, args = slice.call(arguments, 1); + timeout = timeout * 1000; + return window.setTimeout(function() { + return __method.apply(__method, args); + }, timeout); + } + + function defer() { + var args = update([0.01], arguments); + return this.delay.apply(this, args); + } + + function wrap(wrapper) { + var __method = this; + return function() { + var a = update([__method.bind(this)], arguments); + return wrapper.apply(this, a); + } + } + + function methodize() { + if (this._methodized) return this._methodized; + var __method = this; + return this._methodized = function() { + var a = update([this], arguments); + return __method.apply(null, a); + }; + } + + return { + argumentNames: argumentNames, + bind: bind, + bindAsEventListener: bindAsEventListener, + curry: curry, + delay: delay, + defer: defer, + wrap: wrap, + methodize: methodize + } +})()); + + + +(function(proto) { + + + function toISOString() { + return this.getUTCFullYear() + '-' + + (this.getUTCMonth() + 1).toPaddedString(2) + '-' + + this.getUTCDate().toPaddedString(2) + 'T' + + this.getUTCHours().toPaddedString(2) + ':' + + this.getUTCMinutes().toPaddedString(2) + ':' + + this.getUTCSeconds().toPaddedString(2) + 'Z'; + } + + + function toJSON() { + return this.toISOString(); + } + + if (!proto.toISOString) proto.toISOString = toISOString; + if (!proto.toJSON) proto.toJSON = toJSON; + +})(Date.prototype); + + +RegExp.prototype.match = RegExp.prototype.test; + +RegExp.escape = function(str) { + return String(str).replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1'); +}; +var PeriodicalExecuter = Class.create({ + initialize: function(callback, frequency) { + this.callback = callback; + this.frequency = frequency; + this.currentlyExecuting = false; + + this.registerCallback(); + }, + + registerCallback: function() { + this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000); + }, + + execute: function() { + this.callback(this); + }, + + stop: function() { + if (!this.timer) return; + clearInterval(this.timer); + this.timer = null; + }, + + onTimerEvent: function() { + if (!this.currentlyExecuting) { + try { + this.currentlyExecuting = true; + this.execute(); + this.currentlyExecuting = false; + } catch(e) { + this.currentlyExecuting = false; + throw e; + } + } + } +}); +Object.extend(String, { + interpret: function(value) { + return value == null ? '' : String(value); + }, + specialChar: { + '\b': '\\b', + '\t': '\\t', + '\n': '\\n', + '\f': '\\f', + '\r': '\\r', + '\\': '\\\\' + } +}); + +Object.extend(String.prototype, (function() { + var NATIVE_JSON_PARSE_SUPPORT = window.JSON && + typeof JSON.parse === 'function' && + JSON.parse('{"test": true}').test; + + function prepareReplacement(replacement) { + if (Object.isFunction(replacement)) return replacement; + var template = new Template(replacement); + return function(match) { return template.evaluate(match) }; + } + + function gsub(pattern, replacement) { + var result = '', source = this, match; + replacement = prepareReplacement(replacement); + + if (Object.isString(pattern)) + pattern = RegExp.escape(pattern); + + if (!(pattern.length || pattern.source)) { + replacement = replacement(''); + return replacement + source.split('').join(replacement) + replacement; + } + + while (source.length > 0) { + if (match = source.match(pattern)) { + result += source.slice(0, match.index); + result += String.interpret(replacement(match)); + source = source.slice(match.index + match[0].length); + } else { + result += source, source = ''; + } + } + return result; + } + + function sub(pattern, replacement, count) { + replacement = prepareReplacement(replacement); + count = Object.isUndefined(count) ? 1 : count; + + return this.gsub(pattern, function(match) { + if (--count < 0) return match[0]; + return replacement(match); + }); + } + + function scan(pattern, iterator) { + this.gsub(pattern, iterator); + return String(this); + } + + function truncate(length, truncation) { + length = length || 30; + truncation = Object.isUndefined(truncation) ? '...' : truncation; + return this.length > length ? + this.slice(0, length - truncation.length) + truncation : String(this); + } + + function strip() { + return this.replace(/^\s+/, '').replace(/\s+$/, ''); + } + + function stripTags() { + return this.replace(/<\w+(\s+("[^"]*"|'[^']*'|[^>])+)?>|<\/\w+>/gi, ''); + } + + function stripScripts() { + return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), ''); + } + + function extractScripts() { + var matchAll = new RegExp(Prototype.ScriptFragment, 'img'), + matchOne = new RegExp(Prototype.ScriptFragment, 'im'); + return (this.match(matchAll) || []).map(function(scriptTag) { + return (scriptTag.match(matchOne) || ['', ''])[1]; + }); + } + + function evalScripts() { + return this.extractScripts().map(function(script) { return eval(script) }); + } + + function escapeHTML() { + return this.replace(/&/g,'&').replace(//g,'>'); + } + + function unescapeHTML() { + return this.stripTags().replace(/</g,'<').replace(/>/g,'>').replace(/&/g,'&'); + } + + + function toQueryParams(separator) { + var match = this.strip().match(/([^?#]*)(#.*)?$/); + if (!match) return { }; + + return match[1].split(separator || '&').inject({ }, function(hash, pair) { + if ((pair = pair.split('='))[0]) { + var key = decodeURIComponent(pair.shift()), + value = pair.length > 1 ? pair.join('=') : pair[0]; + + if (value != undefined) value = decodeURIComponent(value); + + if (key in hash) { + if (!Object.isArray(hash[key])) hash[key] = [hash[key]]; + hash[key].push(value); + } + else hash[key] = value; + } + return hash; + }); + } + + function toArray() { + return this.split(''); + } + + function succ() { + return this.slice(0, this.length - 1) + + String.fromCharCode(this.charCodeAt(this.length - 1) + 1); + } + + function times(count) { + return count < 1 ? '' : new Array(count + 1).join(this); + } + + function camelize() { + return this.replace(/-+(.)?/g, function(match, chr) { + return chr ? chr.toUpperCase() : ''; + }); + } + + function capitalize() { + return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase(); + } + + function underscore() { + return this.replace(/::/g, '/') + .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') + .replace(/([a-z\d])([A-Z])/g, '$1_$2') + .replace(/-/g, '_') + .toLowerCase(); + } + + function dasherize() { + return this.replace(/_/g, '-'); + } + + function inspect(useDoubleQuotes) { + var escapedString = this.replace(/[\x00-\x1f\\]/g, function(character) { + if (character in String.specialChar) { + return String.specialChar[character]; + } + return '\\u00' + character.charCodeAt().toPaddedString(2, 16); + }); + if (useDoubleQuotes) return '"' + escapedString.replace(/"/g, '\\"') + '"'; + return "'" + escapedString.replace(/'/g, '\\\'') + "'"; + } + + function unfilterJSON(filter) { + return this.replace(filter || Prototype.JSONFilter, '$1'); + } + + function isJSON() { + var str = this; + if (str.blank()) return false; + str = str.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@'); + str = str.replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']'); + str = str.replace(/(?:^|:|,)(?:\s*\[)+/g, ''); + return (/^[\],:{}\s]*$/).test(str); + } + + function evalJSON(sanitize) { + var json = this.unfilterJSON(), + cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g; + if (cx.test(json)) { + json = json.replace(cx, function (a) { + return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4); + }); + } + try { + if (!sanitize || json.isJSON()) return eval('(' + json + ')'); + } catch (e) { } + throw new SyntaxError('Badly formed JSON string: ' + this.inspect()); + } + + function parseJSON() { + var json = this.unfilterJSON(); + return JSON.parse(json); + } + + function include(pattern) { + return this.indexOf(pattern) > -1; + } + + function startsWith(pattern) { + return this.lastIndexOf(pattern, 0) === 0; + } + + function endsWith(pattern) { + var d = this.length - pattern.length; + return d >= 0 && this.indexOf(pattern, d) === d; + } + + function empty() { + return this == ''; + } + + function blank() { + return /^\s*$/.test(this); + } + + function interpolate(object, pattern) { + return new Template(this, pattern).evaluate(object); + } + + return { + gsub: gsub, + sub: sub, + scan: scan, + truncate: truncate, + strip: String.prototype.trim || strip, + stripTags: stripTags, + stripScripts: stripScripts, + extractScripts: extractScripts, + evalScripts: evalScripts, + escapeHTML: escapeHTML, + unescapeHTML: unescapeHTML, + toQueryParams: toQueryParams, + parseQuery: toQueryParams, + toArray: toArray, + succ: succ, + times: times, + camelize: camelize, + capitalize: capitalize, + underscore: underscore, + dasherize: dasherize, + inspect: inspect, + unfilterJSON: unfilterJSON, + isJSON: isJSON, + evalJSON: NATIVE_JSON_PARSE_SUPPORT ? parseJSON : evalJSON, + include: include, + startsWith: startsWith, + endsWith: endsWith, + empty: empty, + blank: blank, + interpolate: interpolate + }; +})()); + +var Template = Class.create({ + initialize: function(template, pattern) { + this.template = template.toString(); + this.pattern = pattern || Template.Pattern; + }, + + evaluate: function(object) { + if (object && Object.isFunction(object.toTemplateReplacements)) + object = object.toTemplateReplacements(); + + return this.template.gsub(this.pattern, function(match) { + if (object == null) return (match[1] + ''); + + var before = match[1] || ''; + if (before == '\\') return match[2]; + + var ctx = object, expr = match[3], + pattern = /^([^.[]+|\[((?:.*?[^\\])?)\])(\.|\[|$)/; + + match = pattern.exec(expr); + if (match == null) return before; + + while (match != null) { + var comp = match[1].startsWith('[') ? match[2].replace(/\\\\]/g, ']') : match[1]; + ctx = ctx[comp]; + if (null == ctx || '' == match[3]) break; + expr = expr.substring('[' == match[3] ? match[1].length : match[0].length); + match = pattern.exec(expr); + } + + return before + String.interpret(ctx); + }); + } +}); +Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/; + +var $break = { }; + +var Enumerable = (function() { + function each(iterator, context) { + var index = 0; + try { + this._each(function(value) { + iterator.call(context, value, index++); + }); + } catch (e) { + if (e != $break) throw e; + } + return this; + } + + function eachSlice(number, iterator, context) { + var index = -number, slices = [], array = this.toArray(); + if (number < 1) return array; + while ((index += number) < array.length) + slices.push(array.slice(index, index+number)); + return slices.collect(iterator, context); + } + + function all(iterator, context) { + iterator = iterator || Prototype.K; + var result = true; + this.each(function(value, index) { + result = result && !!iterator.call(context, value, index); + if (!result) throw $break; + }); + return result; + } + + function any(iterator, context) { + iterator = iterator || Prototype.K; + var result = false; + this.each(function(value, index) { + if (result = !!iterator.call(context, value, index)) + throw $break; + }); + return result; + } + + function collect(iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + this.each(function(value, index) { + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function detect(iterator, context) { + var result; + this.each(function(value, index) { + if (iterator.call(context, value, index)) { + result = value; + throw $break; + } + }); + return result; + } + + function findAll(iterator, context) { + var results = []; + this.each(function(value, index) { + if (iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function grep(filter, iterator, context) { + iterator = iterator || Prototype.K; + var results = []; + + if (Object.isString(filter)) + filter = new RegExp(RegExp.escape(filter)); + + this.each(function(value, index) { + if (filter.match(value)) + results.push(iterator.call(context, value, index)); + }); + return results; + } + + function include(object) { + if (Object.isFunction(this.indexOf)) + if (this.indexOf(object) != -1) return true; + + var found = false; + this.each(function(value) { + if (value == object) { + found = true; + throw $break; + } + }); + return found; + } + + function inGroupsOf(number, fillWith) { + fillWith = Object.isUndefined(fillWith) ? null : fillWith; + return this.eachSlice(number, function(slice) { + while(slice.length < number) slice.push(fillWith); + return slice; + }); + } + + function inject(memo, iterator, context) { + this.each(function(value, index) { + memo = iterator.call(context, memo, value, index); + }); + return memo; + } + + function invoke(method) { + var args = $A(arguments).slice(1); + return this.map(function(value) { + return value[method].apply(value, args); + }); + } + + function max(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value >= result) + result = value; + }); + return result; + } + + function min(iterator, context) { + iterator = iterator || Prototype.K; + var result; + this.each(function(value, index) { + value = iterator.call(context, value, index); + if (result == null || value < result) + result = value; + }); + return result; + } + + function partition(iterator, context) { + iterator = iterator || Prototype.K; + var trues = [], falses = []; + this.each(function(value, index) { + (iterator.call(context, value, index) ? + trues : falses).push(value); + }); + return [trues, falses]; + } + + function pluck(property) { + var results = []; + this.each(function(value) { + results.push(value[property]); + }); + return results; + } + + function reject(iterator, context) { + var results = []; + this.each(function(value, index) { + if (!iterator.call(context, value, index)) + results.push(value); + }); + return results; + } + + function sortBy(iterator, context) { + return this.map(function(value, index) { + return { + value: value, + criteria: iterator.call(context, value, index) + }; + }).sort(function(left, right) { + var a = left.criteria, b = right.criteria; + return a < b ? -1 : a > b ? 1 : 0; + }).pluck('value'); + } + + function toArray() { + return this.map(); + } + + function zip() { + var iterator = Prototype.K, args = $A(arguments); + if (Object.isFunction(args.last())) + iterator = args.pop(); + + var collections = [this].concat(args).map($A); + return this.map(function(value, index) { + return iterator(collections.pluck(index)); + }); + } + + function size() { + return this.toArray().length; + } + + function inspect() { + return '#'; + } + + + + + + + + + + return { + each: each, + eachSlice: eachSlice, + all: all, + every: all, + any: any, + some: any, + collect: collect, + map: collect, + detect: detect, + findAll: findAll, + select: findAll, + filter: findAll, + grep: grep, + include: include, + member: include, + inGroupsOf: inGroupsOf, + inject: inject, + invoke: invoke, + max: max, + min: min, + partition: partition, + pluck: pluck, + reject: reject, + sortBy: sortBy, + toArray: toArray, + entries: toArray, + zip: zip, + size: size, + inspect: inspect, + find: detect + }; +})(); + +function $A(iterable) { + if (!iterable) return []; + if ('toArray' in Object(iterable)) return iterable.toArray(); + var length = iterable.length || 0, results = new Array(length); + while (length--) results[length] = iterable[length]; + return results; +} + + +function $w(string) { + if (!Object.isString(string)) return []; + string = string.strip(); + return string ? string.split(/\s+/) : []; +} + +Array.from = $A; + + +(function() { + var arrayProto = Array.prototype, + slice = arrayProto.slice, + _each = arrayProto.forEach; // use native browser JS 1.6 implementation if available + + function each(iterator) { + for (var i = 0, length = this.length; i < length; i++) + iterator(this[i]); + } + if (!_each) _each = each; + + function clear() { + this.length = 0; + return this; + } + + function first() { + return this[0]; + } + + function last() { + return this[this.length - 1]; + } + + function compact() { + return this.select(function(value) { + return value != null; + }); + } + + function flatten() { + return this.inject([], function(array, value) { + if (Object.isArray(value)) + return array.concat(value.flatten()); + array.push(value); + return array; + }); + } + + function without() { + var values = slice.call(arguments, 0); + return this.select(function(value) { + return !values.include(value); + }); + } + + function reverse(inline) { + return (inline === false ? this.toArray() : this)._reverse(); + } + + function uniq(sorted) { + return this.inject([], function(array, value, index) { + if (0 == index || (sorted ? array.last() != value : !array.include(value))) + array.push(value); + return array; + }); + } + + function intersect(array) { + return this.uniq().findAll(function(item) { + return array.detect(function(value) { return item === value }); + }); + } + + + function clone() { + return slice.call(this, 0); + } + + function size() { + return this.length; + } + + function inspect() { + return '[' + this.map(Object.inspect).join(', ') + ']'; + } + + function indexOf(item, i) { + i || (i = 0); + var length = this.length; + if (i < 0) i = length + i; + for (; i < length; i++) + if (this[i] === item) return i; + return -1; + } + + function lastIndexOf(item, i) { + i = isNaN(i) ? this.length : (i < 0 ? this.length + i : i) + 1; + var n = this.slice(0, i).reverse().indexOf(item); + return (n < 0) ? n : i - n - 1; + } + + function concat() { + var array = slice.call(this, 0), item; + for (var i = 0, length = arguments.length; i < length; i++) { + item = arguments[i]; + if (Object.isArray(item) && !('callee' in item)) { + for (var j = 0, arrayLength = item.length; j < arrayLength; j++) + array.push(item[j]); + } else { + array.push(item); + } + } + return array; + } + + Object.extend(arrayProto, Enumerable); + + if (!arrayProto._reverse) + arrayProto._reverse = arrayProto.reverse; + + Object.extend(arrayProto, { + _each: _each, + clear: clear, + first: first, + last: last, + compact: compact, + flatten: flatten, + without: without, + reverse: reverse, + uniq: uniq, + intersect: intersect, + clone: clone, + toArray: clone, + size: size, + inspect: inspect + }); + + var CONCAT_ARGUMENTS_BUGGY = (function() { + return [].concat(arguments)[0][0] !== 1; + })(1,2) + + if (CONCAT_ARGUMENTS_BUGGY) arrayProto.concat = concat; + + if (!arrayProto.indexOf) arrayProto.indexOf = indexOf; + if (!arrayProto.lastIndexOf) arrayProto.lastIndexOf = lastIndexOf; +})(); +function $H(object) { + return new Hash(object); +}; + +var Hash = Class.create(Enumerable, (function() { + function initialize(object) { + this._object = Object.isHash(object) ? object.toObject() : Object.clone(object); + } + + + function _each(iterator) { + for (var key in this._object) { + var value = this._object[key], pair = [key, value]; + pair.key = key; + pair.value = value; + iterator(pair); + } + } + + function set(key, value) { + return this._object[key] = value; + } + + function get(key) { + if (this._object[key] !== Object.prototype[key]) + return this._object[key]; + } + + function unset(key) { + var value = this._object[key]; + delete this._object[key]; + return value; + } + + function toObject() { + return Object.clone(this._object); + } + + + + function keys() { + return this.pluck('key'); + } + + function values() { + return this.pluck('value'); + } + + function index(value) { + var match = this.detect(function(pair) { + return pair.value === value; + }); + return match && match.key; + } + + function merge(object) { + return this.clone().update(object); + } + + function update(object) { + return new Hash(object).inject(this, function(result, pair) { + result.set(pair.key, pair.value); + return result; + }); + } + + function toQueryPair(key, value) { + if (Object.isUndefined(value)) return key; + return key + '=' + encodeURIComponent(String.interpret(value)); + } + + function toQueryString() { + return this.inject([], function(results, pair) { + var key = encodeURIComponent(pair.key), values = pair.value; + + if (values && typeof values == 'object') { + if (Object.isArray(values)) + return results.concat(values.map(toQueryPair.curry(key))); + } else results.push(toQueryPair(key, values)); + return results; + }).join('&'); + } + + function inspect() { + return '#'; + } + + function clone() { + return new Hash(this); + } + + return { + initialize: initialize, + _each: _each, + set: set, + get: get, + unset: unset, + toObject: toObject, + toTemplateReplacements: toObject, + keys: keys, + values: values, + index: index, + merge: merge, + update: update, + toQueryString: toQueryString, + inspect: inspect, + toJSON: toObject, + clone: clone + }; +})()); + +Hash.from = $H; +Object.extend(Number.prototype, (function() { + function toColorPart() { + return this.toPaddedString(2, 16); + } + + function succ() { + return this + 1; + } + + function times(iterator, context) { + $R(0, this, true).each(iterator, context); + return this; + } + + function toPaddedString(length, radix) { + var string = this.toString(radix || 10); + return '0'.times(length - string.length) + string; + } + + function abs() { + return Math.abs(this); + } + + function round() { + return Math.round(this); + } + + function ceil() { + return Math.ceil(this); + } + + function floor() { + return Math.floor(this); + } + + return { + toColorPart: toColorPart, + succ: succ, + times: times, + toPaddedString: toPaddedString, + abs: abs, + round: round, + ceil: ceil, + floor: floor + }; +})()); + +function $R(start, end, exclusive) { + return new ObjectRange(start, end, exclusive); +} + +var ObjectRange = Class.create(Enumerable, (function() { + function initialize(start, end, exclusive) { + this.start = start; + this.end = end; + this.exclusive = exclusive; + } + + function _each(iterator) { + var value = this.start; + while (this.include(value)) { + iterator(value); + value = value.succ(); + } + } + + function include(value) { + if (value < this.start) + return false; + if (this.exclusive) + return value < this.end; + return value <= this.end; + } + + return { + initialize: initialize, + _each: _each, + include: include + }; +})()); + + + +var Ajax = { + getTransport: function() { + return Try.these( + function() {return new XMLHttpRequest()}, + function() {return new ActiveXObject('Msxml2.XMLHTTP')}, + function() {return new ActiveXObject('Microsoft.XMLHTTP')} + ) || false; + }, + + activeRequestCount: 0 +}; + +Ajax.Responders = { + responders: [], + + _each: function(iterator) { + this.responders._each(iterator); + }, + + register: function(responder) { + if (!this.include(responder)) + this.responders.push(responder); + }, + + unregister: function(responder) { + this.responders = this.responders.without(responder); + }, + + dispatch: function(callback, request, transport, json) { + this.each(function(responder) { + if (Object.isFunction(responder[callback])) { + try { + responder[callback].apply(responder, [request, transport, json]); + } catch (e) { } + } + }); + } +}; + +Object.extend(Ajax.Responders, Enumerable); + +Ajax.Responders.register({ + onCreate: function() { Ajax.activeRequestCount++ }, + onComplete: function() { Ajax.activeRequestCount-- } +}); +Ajax.Base = Class.create({ + initialize: function(options) { + this.options = { + method: 'post', + asynchronous: true, + contentType: 'application/x-www-form-urlencoded', + encoding: 'UTF-8', + parameters: '', + evalJSON: true, + evalJS: true + }; + Object.extend(this.options, options || { }); + + this.options.method = this.options.method.toLowerCase(); + + if (Object.isString(this.options.parameters)) + this.options.parameters = this.options.parameters.toQueryParams(); + else if (Object.isHash(this.options.parameters)) + this.options.parameters = this.options.parameters.toObject(); + } +}); +Ajax.Request = Class.create(Ajax.Base, { + _complete: false, + + initialize: function($super, url, options) { + $super(options); + this.transport = Ajax.getTransport(); + this.request(url); + }, + + request: function(url) { + this.url = url; + this.method = this.options.method; + var params = Object.clone(this.options.parameters); + + if (!['get', 'post'].include(this.method)) { + params['_method'] = this.method; + this.method = 'post'; + } + + this.parameters = params; + + if (params = Object.toQueryString(params)) { + if (this.method == 'get') + this.url += (this.url.include('?') ? '&' : '?') + params; + else if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) + params += '&_='; + } + + try { + var response = new Ajax.Response(this); + if (this.options.onCreate) this.options.onCreate(response); + Ajax.Responders.dispatch('onCreate', this, response); + + this.transport.open(this.method.toUpperCase(), this.url, + this.options.asynchronous); + + if (this.options.asynchronous) this.respondToReadyState.bind(this).defer(1); + + this.transport.onreadystatechange = this.onStateChange.bind(this); + this.setRequestHeaders(); + + this.body = this.method == 'post' ? (this.options.postBody || params) : null; + this.transport.send(this.body); + + /* Force Firefox to handle ready state 4 for synchronous requests */ + if (!this.options.asynchronous && this.transport.overrideMimeType) + this.onStateChange(); + + } + catch (e) { + this.dispatchException(e); + } + }, + + onStateChange: function() { + var readyState = this.transport.readyState; + if (readyState > 1 && !((readyState == 4) && this._complete)) + this.respondToReadyState(this.transport.readyState); + }, + + setRequestHeaders: function() { + var headers = { + 'X-Requested-With': 'XMLHttpRequest', + 'X-Prototype-Version': Prototype.Version, + 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*' + }; + + if (this.method == 'post') { + headers['Content-type'] = this.options.contentType + + (this.options.encoding ? '; charset=' + this.options.encoding : ''); + + /* Force "Connection: close" for older Mozilla browsers to work + * around a bug where XMLHttpRequest sends an incorrect + * Content-length header. See Mozilla Bugzilla #246651. + */ + if (this.transport.overrideMimeType && + (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005) + headers['Connection'] = 'close'; + } + + if (typeof this.options.requestHeaders == 'object') { + var extras = this.options.requestHeaders; + + if (Object.isFunction(extras.push)) + for (var i = 0, length = extras.length; i < length; i += 2) + headers[extras[i]] = extras[i+1]; + else + $H(extras).each(function(pair) { headers[pair.key] = pair.value }); + } + + for (var name in headers) + this.transport.setRequestHeader(name, headers[name]); + }, + + success: function() { + var status = this.getStatus(); + return !status || (status >= 200 && status < 300); + }, + + getStatus: function() { + try { + return this.transport.status || 0; + } catch (e) { return 0 } + }, + + respondToReadyState: function(readyState) { + var state = Ajax.Request.Events[readyState], response = new Ajax.Response(this); + + if (state == 'Complete') { + try { + this._complete = true; + (this.options['on' + response.status] + || this.options['on' + (this.success() ? 'Success' : 'Failure')] + || Prototype.emptyFunction)(response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + var contentType = response.getHeader('Content-type'); + if (this.options.evalJS == 'force' + || (this.options.evalJS && this.isSameOrigin() && contentType + && contentType.match(/^\s*(text|application)\/(x-)?(java|ecma)script(;.*)?\s*$/i))) + this.evalResponse(); + } + + try { + (this.options['on' + state] || Prototype.emptyFunction)(response, response.headerJSON); + Ajax.Responders.dispatch('on' + state, this, response, response.headerJSON); + } catch (e) { + this.dispatchException(e); + } + + if (state == 'Complete') { + this.transport.onreadystatechange = Prototype.emptyFunction; + } + }, + + isSameOrigin: function() { + var m = this.url.match(/^\s*https?:\/\/[^\/]*/); + return !m || (m[0] == '#{protocol}//#{domain}#{port}'.interpolate({ + protocol: location.protocol, + domain: document.domain, + port: location.port ? ':' + location.port : '' + })); + }, + + getHeader: function(name) { + try { + return this.transport.getResponseHeader(name) || null; + } catch (e) { return null; } + }, + + evalResponse: function() { + try { + return eval((this.transport.responseText || '').unfilterJSON()); + } catch (e) { + this.dispatchException(e); + } + }, + + dispatchException: function(exception) { + (this.options.onException || Prototype.emptyFunction)(this, exception); + Ajax.Responders.dispatch('onException', this, exception); + } +}); + +Ajax.Request.Events = + ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete']; + + + + + + + + +Ajax.Response = Class.create({ + initialize: function(request){ + this.request = request; + var transport = this.transport = request.transport, + readyState = this.readyState = transport.readyState; + + if ((readyState > 2 && !Prototype.Browser.IE) || readyState == 4) { + this.status = this.getStatus(); + this.statusText = this.getStatusText(); + this.responseText = String.interpret(transport.responseText); + this.headerJSON = this._getHeaderJSON(); + } + + if (readyState == 4) { + var xml = transport.responseXML; + this.responseXML = Object.isUndefined(xml) ? null : xml; + this.responseJSON = this._getResponseJSON(); + } + }, + + status: 0, + + statusText: '', + + getStatus: Ajax.Request.prototype.getStatus, + + getStatusText: function() { + try { + return this.transport.statusText || ''; + } catch (e) { return '' } + }, + + getHeader: Ajax.Request.prototype.getHeader, + + getAllHeaders: function() { + try { + return this.getAllResponseHeaders(); + } catch (e) { return null } + }, + + getResponseHeader: function(name) { + return this.transport.getResponseHeader(name); + }, + + getAllResponseHeaders: function() { + return this.transport.getAllResponseHeaders(); + }, + + _getHeaderJSON: function() { + var json = this.getHeader('X-JSON'); + if (!json) return null; + json = decodeURIComponent(escape(json)); + try { + return json.evalJSON(this.request.options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + }, + + _getResponseJSON: function() { + var options = this.request.options; + if (!options.evalJSON || (options.evalJSON != 'force' && + !(this.getHeader('Content-type') || '').include('application/json')) || + this.responseText.blank()) + return null; + try { + return this.responseText.evalJSON(options.sanitizeJSON || + !this.request.isSameOrigin()); + } catch (e) { + this.request.dispatchException(e); + } + } +}); + +Ajax.Updater = Class.create(Ajax.Request, { + initialize: function($super, container, url, options) { + this.container = { + success: (container.success || container), + failure: (container.failure || (container.success ? null : container)) + }; + + options = Object.clone(options); + var onComplete = options.onComplete; + options.onComplete = (function(response, json) { + this.updateContent(response.responseText); + if (Object.isFunction(onComplete)) onComplete(response, json); + }).bind(this); + + $super(url, options); + }, + + updateContent: function(responseText) { + var receiver = this.container[this.success() ? 'success' : 'failure'], + options = this.options; + + if (!options.evalScripts) responseText = responseText.stripScripts(); + + if (receiver = $(receiver)) { + if (options.insertion) { + if (Object.isString(options.insertion)) { + var insertion = { }; insertion[options.insertion] = responseText; + receiver.insert(insertion); + } + else options.insertion(receiver, responseText); + } + else receiver.update(responseText); + } + } +}); + +Ajax.PeriodicalUpdater = Class.create(Ajax.Base, { + initialize: function($super, container, url, options) { + $super(options); + this.onComplete = this.options.onComplete; + + this.frequency = (this.options.frequency || 2); + this.decay = (this.options.decay || 1); + + this.updater = { }; + this.container = container; + this.url = url; + + this.start(); + }, + + start: function() { + this.options.onComplete = this.updateComplete.bind(this); + this.onTimerEvent(); + }, + + stop: function() { + this.updater.options.onComplete = undefined; + clearTimeout(this.timer); + (this.onComplete || Prototype.emptyFunction).apply(this, arguments); + }, + + updateComplete: function(response) { + if (this.options.decay) { + this.decay = (response.responseText == this.lastText ? + this.decay * this.options.decay : 1); + + this.lastText = response.responseText; + } + this.timer = this.onTimerEvent.bind(this).delay(this.decay * this.frequency); + }, + + onTimerEvent: function() { + this.updater = new Ajax.Updater(this.container, this.url, this.options); + } +}); + + +function $(element) { + if (arguments.length > 1) { + for (var i = 0, elements = [], length = arguments.length; i < length; i++) + elements.push($(arguments[i])); + return elements; + } + if (Object.isString(element)) + element = document.getElementById(element); + return Element.extend(element); +} + +if (Prototype.BrowserFeatures.XPath) { + document._getElementsByXPath = function(expression, parentElement) { + var results = []; + var query = document.evaluate(expression, $(parentElement) || document, + null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null); + for (var i = 0, length = query.snapshotLength; i < length; i++) + results.push(Element.extend(query.snapshotItem(i))); + return results; + }; +} + +/*--------------------------------------------------------------------------*/ + +if (!Node) var Node = { }; + +if (!Node.ELEMENT_NODE) { + Object.extend(Node, { + ELEMENT_NODE: 1, + ATTRIBUTE_NODE: 2, + TEXT_NODE: 3, + CDATA_SECTION_NODE: 4, + ENTITY_REFERENCE_NODE: 5, + ENTITY_NODE: 6, + PROCESSING_INSTRUCTION_NODE: 7, + COMMENT_NODE: 8, + DOCUMENT_NODE: 9, + DOCUMENT_TYPE_NODE: 10, + DOCUMENT_FRAGMENT_NODE: 11, + NOTATION_NODE: 12 + }); +} + + + +(function(global) { + + var HAS_EXTENDED_CREATE_ELEMENT_SYNTAX = (function(){ + try { + var el = document.createElement(''); + return el.tagName.toLowerCase() === 'input' && el.name === 'x'; + } + catch(err) { + return false; + } + })(); + + var element = global.Element; + + global.Element = function(tagName, attributes) { + attributes = attributes || { }; + tagName = tagName.toLowerCase(); + var cache = Element.cache; + if (HAS_EXTENDED_CREATE_ELEMENT_SYNTAX && attributes.name) { + tagName = '<' + tagName + ' name="' + attributes.name + '">'; + delete attributes.name; + return Element.writeAttribute(document.createElement(tagName), attributes); + } + if (!cache[tagName]) cache[tagName] = Element.extend(document.createElement(tagName)); + return Element.writeAttribute(cache[tagName].cloneNode(false), attributes); + }; + + Object.extend(global.Element, element || { }); + if (element) global.Element.prototype = element.prototype; + +})(this); + +Element.idCounter = 1; +Element.cache = { }; + +function purgeElement(element) { + var uid = element._prototypeUID; + if (uid) { + Element.stopObserving(element); + element._prototypeUID = void 0; + delete Element.Storage[uid]; + } +} + +Element.Methods = { + visible: function(element) { + return $(element).style.display != 'none'; + }, + + toggle: function(element) { + element = $(element); + Element[Element.visible(element) ? 'hide' : 'show'](element); + return element; + }, + + hide: function(element) { + element = $(element); + element.style.display = 'none'; + return element; + }, + + show: function(element) { + element = $(element); + element.style.display = ''; + return element; + }, + + remove: function(element) { + element = $(element); + element.parentNode.removeChild(element); + return element; + }, + + update: (function(){ + + var SELECT_ELEMENT_INNERHTML_BUGGY = (function(){ + var el = document.createElement("select"), + isBuggy = true; + el.innerHTML = ""; + if (el.options && el.options[0]) { + isBuggy = el.options[0].nodeName.toUpperCase() !== "OPTION"; + } + el = null; + return isBuggy; + })(); + + var TABLE_ELEMENT_INNERHTML_BUGGY = (function(){ + try { + var el = document.createElement("table"); + if (el && el.tBodies) { + el.innerHTML = "test"; + var isBuggy = typeof el.tBodies[0] == "undefined"; + el = null; + return isBuggy; + } + } catch (e) { + return true; + } + })(); + + var SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING = (function () { + var s = document.createElement("script"), + isBuggy = false; + try { + s.appendChild(document.createTextNode("")); + isBuggy = !s.firstChild || + s.firstChild && s.firstChild.nodeType !== 3; + } catch (e) { + isBuggy = true; + } + s = null; + return isBuggy; + })(); + + function update(element, content) { + element = $(element); + + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + while (i--) purgeElement(descendants[i]); + + if (content && content.toElement) + content = content.toElement(); + + if (Object.isElement(content)) + return element.update().insert(content); + + content = Object.toHTML(content); + + var tagName = element.tagName.toUpperCase(); + + if (tagName === 'SCRIPT' && SCRIPT_ELEMENT_REJECTS_TEXTNODE_APPENDING) { + element.text = content; + return element; + } + + if (SELECT_ELEMENT_INNERHTML_BUGGY || TABLE_ELEMENT_INNERHTML_BUGGY) { + if (tagName in Element._insertionTranslations.tags) { + while (element.firstChild) { + element.removeChild(element.firstChild); + } + Element._getContentFromAnonymousElement(tagName, content.stripScripts()) + .each(function(node) { + element.appendChild(node) + }); + } + else { + element.innerHTML = content.stripScripts(); + } + } + else { + element.innerHTML = content.stripScripts(); + } + + content.evalScripts.bind(content).defer(); + return element; + } + + return update; + })(), + + replace: function(element, content) { + element = $(element); + if (content && content.toElement) content = content.toElement(); + else if (!Object.isElement(content)) { + content = Object.toHTML(content); + var range = element.ownerDocument.createRange(); + range.selectNode(element); + content.evalScripts.bind(content).defer(); + content = range.createContextualFragment(content.stripScripts()); + } + element.parentNode.replaceChild(content, element); + return element; + }, + + insert: function(element, insertions) { + element = $(element); + + if (Object.isString(insertions) || Object.isNumber(insertions) || + Object.isElement(insertions) || (insertions && (insertions.toElement || insertions.toHTML))) + insertions = {bottom:insertions}; + + var content, insert, tagName, childNodes; + + for (var position in insertions) { + content = insertions[position]; + position = position.toLowerCase(); + insert = Element._insertionTranslations[position]; + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + insert(element, content); + continue; + } + + content = Object.toHTML(content); + + tagName = ((position == 'before' || position == 'after') + ? element.parentNode : element).tagName.toUpperCase(); + + childNodes = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + + if (position == 'top' || position == 'after') childNodes.reverse(); + childNodes.each(insert.curry(element)); + + content.evalScripts.bind(content).defer(); + } + + return element; + }, + + wrap: function(element, wrapper, attributes) { + element = $(element); + if (Object.isElement(wrapper)) + $(wrapper).writeAttribute(attributes || { }); + else if (Object.isString(wrapper)) wrapper = new Element(wrapper, attributes); + else wrapper = new Element('div', wrapper); + if (element.parentNode) + element.parentNode.replaceChild(wrapper, element); + wrapper.appendChild(element); + return wrapper; + }, + + inspect: function(element) { + element = $(element); + var result = '<' + element.tagName.toLowerCase(); + $H({'id': 'id', 'className': 'class'}).each(function(pair) { + var property = pair.first(), + attribute = pair.last(), + value = (element[property] || '').toString(); + if (value) result += ' ' + attribute + '=' + value.inspect(true); + }); + return result + '>'; + }, + + recursivelyCollect: function(element, property, maximumLength) { + element = $(element); + maximumLength = maximumLength || -1; + var elements = []; + + while (element = element[property]) { + if (element.nodeType == 1) + elements.push(Element.extend(element)); + if (elements.length == maximumLength) + break; + } + + return elements; + }, + + ancestors: function(element) { + return Element.recursivelyCollect(element, 'parentNode'); + }, + + descendants: function(element) { + return Element.select(element, "*"); + }, + + firstDescendant: function(element) { + element = $(element).firstChild; + while (element && element.nodeType != 1) element = element.nextSibling; + return $(element); + }, + + immediateDescendants: function(element) { + var results = [], child = $(element).firstChild; + while (child) { + if (child.nodeType === 1) { + results.push(Element.extend(child)); + } + child = child.nextSibling; + } + return results; + }, + + previousSiblings: function(element, maximumLength) { + return Element.recursivelyCollect(element, 'previousSibling'); + }, + + nextSiblings: function(element) { + return Element.recursivelyCollect(element, 'nextSibling'); + }, + + siblings: function(element) { + element = $(element); + return Element.previousSiblings(element).reverse() + .concat(Element.nextSiblings(element)); + }, + + match: function(element, selector) { + element = $(element); + if (Object.isString(selector)) + return Prototype.Selector.match(element, selector); + return selector.match(element); + }, + + up: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return $(element.parentNode); + var ancestors = Element.ancestors(element); + return Object.isNumber(expression) ? ancestors[expression] : + Prototype.Selector.find(ancestors, expression, index); + }, + + down: function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return Element.firstDescendant(element); + return Object.isNumber(expression) ? Element.descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + }, + + previous: function(element, expression, index) { + element = $(element); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.previousSiblings(), expression, index); + } else { + return element.recursivelyCollect("previousSibling", index + 1)[index]; + } + }, + + next: function(element, expression, index) { + element = $(element); + if (Object.isNumber(expression)) index = expression, expression = false; + if (!Object.isNumber(index)) index = 0; + + if (expression) { + return Prototype.Selector.find(element.nextSiblings(), expression, index); + } else { + var maximumLength = Object.isNumber(index) ? index + 1 : 1; + return element.recursivelyCollect("nextSibling", index + 1)[index]; + } + }, + + + select: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element); + }, + + adjacent: function(element) { + element = $(element); + var expressions = Array.prototype.slice.call(arguments, 1).join(', '); + return Prototype.Selector.select(expressions, element.parentNode).without(element); + }, + + identify: function(element) { + element = $(element); + var id = Element.readAttribute(element, 'id'); + if (id) return id; + do { id = 'anonymous_element_' + Element.idCounter++ } while ($(id)); + Element.writeAttribute(element, 'id', id); + return id; + }, + + readAttribute: function(element, name) { + element = $(element); + if (Prototype.Browser.IE) { + var t = Element._attributeTranslations.read; + if (t.values[name]) return t.values[name](element, name); + if (t.names[name]) name = t.names[name]; + if (name.include(':')) { + return (!element.attributes || !element.attributes[name]) ? null : + element.attributes[name].value; + } + } + return element.getAttribute(name); + }, + + writeAttribute: function(element, name, value) { + element = $(element); + var attributes = { }, t = Element._attributeTranslations.write; + + if (typeof name == 'object') attributes = name; + else attributes[name] = Object.isUndefined(value) ? true : value; + + for (var attr in attributes) { + name = t.names[attr] || attr; + value = attributes[attr]; + if (t.values[attr]) name = t.values[attr](element, value); + if (value === false || value === null) + element.removeAttribute(name); + else if (value === true) + element.setAttribute(name, name); + else element.setAttribute(name, value); + } + return element; + }, + + getHeight: function(element) { + return Element.getDimensions(element).height; + }, + + getWidth: function(element) { + return Element.getDimensions(element).width; + }, + + classNames: function(element) { + return new Element.ClassNames(element); + }, + + hasClassName: function(element, className) { + if (!(element = $(element))) return; + var elementClassName = element.className; + return (elementClassName.length > 0 && (elementClassName == className || + new RegExp("(^|\\s)" + className + "(\\s|$)").test(elementClassName))); + }, + + addClassName: function(element, className) { + if (!(element = $(element))) return; + if (!Element.hasClassName(element, className)) + element.className += (element.className ? ' ' : '') + className; + return element; + }, + + removeClassName: function(element, className) { + if (!(element = $(element))) return; + element.className = element.className.replace( + new RegExp("(^|\\s+)" + className + "(\\s+|$)"), ' ').strip(); + return element; + }, + + toggleClassName: function(element, className) { + if (!(element = $(element))) return; + return Element[Element.hasClassName(element, className) ? + 'removeClassName' : 'addClassName'](element, className); + }, + + cleanWhitespace: function(element) { + element = $(element); + var node = element.firstChild; + while (node) { + var nextNode = node.nextSibling; + if (node.nodeType == 3 && !/\S/.test(node.nodeValue)) + element.removeChild(node); + node = nextNode; + } + return element; + }, + + empty: function(element) { + return $(element).innerHTML.blank(); + }, + + descendantOf: function(element, ancestor) { + element = $(element), ancestor = $(ancestor); + + if (element.compareDocumentPosition) + return (element.compareDocumentPosition(ancestor) & 8) === 8; + + if (ancestor.contains) + return ancestor.contains(element) && ancestor !== element; + + while (element = element.parentNode) + if (element == ancestor) return true; + + return false; + }, + + scrollTo: function(element) { + element = $(element); + var pos = Element.cumulativeOffset(element); + window.scrollTo(pos[0], pos[1]); + return element; + }, + + getStyle: function(element, style) { + element = $(element); + style = style == 'float' ? 'cssFloat' : style.camelize(); + var value = element.style[style]; + if (!value || value == 'auto') { + var css = document.defaultView.getComputedStyle(element, null); + value = css ? css[style] : null; + } + if (style == 'opacity') return value ? parseFloat(value) : 1.0; + return value == 'auto' ? null : value; + }, + + getOpacity: function(element) { + return $(element).getStyle('opacity'); + }, + + setStyle: function(element, styles) { + element = $(element); + var elementStyle = element.style, match; + if (Object.isString(styles)) { + element.style.cssText += ';' + styles; + return styles.include('opacity') ? + element.setOpacity(styles.match(/opacity:\s*(\d?\.?\d*)/)[1]) : element; + } + for (var property in styles) + if (property == 'opacity') element.setOpacity(styles[property]); + else + elementStyle[(property == 'float' || property == 'cssFloat') ? + (Object.isUndefined(elementStyle.styleFloat) ? 'cssFloat' : 'styleFloat') : + property] = styles[property]; + + return element; + }, + + setOpacity: function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + return element; + }, + + makePositioned: function(element) { + element = $(element); + var pos = Element.getStyle(element, 'position'); + if (pos == 'static' || !pos) { + element._madePositioned = true; + element.style.position = 'relative'; + if (Prototype.Browser.Opera) { + element.style.top = 0; + element.style.left = 0; + } + } + return element; + }, + + undoPositioned: function(element) { + element = $(element); + if (element._madePositioned) { + element._madePositioned = undefined; + element.style.position = + element.style.top = + element.style.left = + element.style.bottom = + element.style.right = ''; + } + return element; + }, + + makeClipping: function(element) { + element = $(element); + if (element._overflow) return element; + element._overflow = Element.getStyle(element, 'overflow') || 'auto'; + if (element._overflow !== 'hidden') + element.style.overflow = 'hidden'; + return element; + }, + + undoClipping: function(element) { + element = $(element); + if (!element._overflow) return element; + element.style.overflow = element._overflow == 'auto' ? '' : element._overflow; + element._overflow = null; + return element; + }, + + cumulativeOffset: function(element) { + var valueT = 0, valueL = 0; + if (element.parentNode) { + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + } + return Element._returnOffset(valueL, valueT); + }, + + positionedOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (element.tagName.toUpperCase() == 'BODY') break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + absolutize: function(element) { + element = $(element); + if (Element.getStyle(element, 'position') == 'absolute') return element; + + var offsets = Element.positionedOffset(element), + top = offsets[1], + left = offsets[0], + width = element.clientWidth, + height = element.clientHeight; + + element._originalLeft = left - parseFloat(element.style.left || 0); + element._originalTop = top - parseFloat(element.style.top || 0); + element._originalWidth = element.style.width; + element._originalHeight = element.style.height; + + element.style.position = 'absolute'; + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.width = width + 'px'; + element.style.height = height + 'px'; + return element; + }, + + relativize: function(element) { + element = $(element); + if (Element.getStyle(element, 'position') == 'relative') return element; + + element.style.position = 'relative'; + var top = parseFloat(element.style.top || 0) - (element._originalTop || 0), + left = parseFloat(element.style.left || 0) - (element._originalLeft || 0); + + element.style.top = top + 'px'; + element.style.left = left + 'px'; + element.style.height = element._originalHeight; + element.style.width = element._originalWidth; + return element; + }, + + cumulativeScrollOffset: function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return Element._returnOffset(valueL, valueT); + }, + + getOffsetParent: function(element) { + if (element.offsetParent) return $(element.offsetParent); + if (element == document.body) return $(element); + + while ((element = element.parentNode) && element != document.body) + if (Element.getStyle(element, 'position') != 'static') + return $(element); + + return $(document.body); + }, + + viewportOffset: function(forElement) { + var valueT = 0, + valueL = 0, + element = forElement; + + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + + if (element.offsetParent == document.body && + Element.getStyle(element, 'position') == 'absolute') break; + + } while (element = element.offsetParent); + + element = forElement; + do { + if (!Prototype.Browser.Opera || (element.tagName && (element.tagName.toUpperCase() == 'BODY'))) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + + return Element._returnOffset(valueL, valueT); + }, + + clonePosition: function(element, source) { + var options = Object.extend({ + setLeft: true, + setTop: true, + setWidth: true, + setHeight: true, + offsetTop: 0, + offsetLeft: 0 + }, arguments[2] || { }); + + source = $(source); + var p = Element.viewportOffset(source), delta = [0, 0], parent = null; + + element = $(element); + + if (Element.getStyle(element, 'position') == 'absolute') { + parent = Element.getOffsetParent(element); + delta = Element.viewportOffset(parent); + } + + if (parent == document.body) { + delta[0] -= document.body.offsetLeft; + delta[1] -= document.body.offsetTop; + } + + if (options.setLeft) element.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px'; + if (options.setTop) element.style.top = (p[1] - delta[1] + options.offsetTop) + 'px'; + if (options.setWidth) element.style.width = source.offsetWidth + 'px'; + if (options.setHeight) element.style.height = source.offsetHeight + 'px'; + return element; + } +}; + +Object.extend(Element.Methods, { + getElementsBySelector: Element.Methods.select, + + childElements: Element.Methods.immediateDescendants +}); + +Element._attributeTranslations = { + write: { + names: { + className: 'class', + htmlFor: 'for' + }, + values: { } + } +}; + +if (Prototype.Browser.Opera) { + Element.Methods.getStyle = Element.Methods.getStyle.wrap( + function(proceed, element, style) { + switch (style) { + case 'left': case 'top': case 'right': case 'bottom': + if (proceed(element, 'position') === 'static') return null; + case 'height': case 'width': + if (!Element.visible(element)) return null; + + var dim = parseInt(proceed(element, style), 10); + + if (dim !== element['offset' + style.capitalize()]) + return dim + 'px'; + + var properties; + if (style === 'height') { + properties = ['border-top-width', 'padding-top', + 'padding-bottom', 'border-bottom-width']; + } + else { + properties = ['border-left-width', 'padding-left', + 'padding-right', 'border-right-width']; + } + return properties.inject(dim, function(memo, property) { + var val = proceed(element, property); + return val === null ? memo : memo - parseInt(val, 10); + }) + 'px'; + default: return proceed(element, style); + } + } + ); + + Element.Methods.readAttribute = Element.Methods.readAttribute.wrap( + function(proceed, element, attribute) { + if (attribute === 'title') return element.title; + return proceed(element, attribute); + } + ); +} + +else if (Prototype.Browser.IE) { + Element.Methods.getOffsetParent = Element.Methods.getOffsetParent.wrap( + function(proceed, element) { + element = $(element); + if (!element.parentNode) return $(document.body); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + + $w('positionedOffset viewportOffset').each(function(method) { + Element.Methods[method] = Element.Methods[method].wrap( + function(proceed, element) { + element = $(element); + if (!element.parentNode) return Element._returnOffset(0, 0); + var position = element.getStyle('position'); + if (position !== 'static') return proceed(element); + var offsetParent = element.getOffsetParent(); + if (offsetParent && offsetParent.getStyle('position') === 'fixed') + offsetParent.setStyle({ zoom: 1 }); + element.setStyle({ position: 'relative' }); + var value = proceed(element); + element.setStyle({ position: position }); + return value; + } + ); + }); + + Element.Methods.getStyle = function(element, style) { + element = $(element); + style = (style == 'float' || style == 'cssFloat') ? 'styleFloat' : style.camelize(); + var value = element.style[style]; + if (!value && element.currentStyle) value = element.currentStyle[style]; + + if (style == 'opacity') { + if (value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/)) + if (value[1]) return parseFloat(value[1]) / 100; + return 1.0; + } + + if (value == 'auto') { + if ((style == 'width' || style == 'height') && (element.getStyle('display') != 'none')) + return element['offset' + style.capitalize()] + 'px'; + return null; + } + return value; + }; + + Element.Methods.setOpacity = function(element, value) { + function stripAlpha(filter){ + return filter.replace(/alpha\([^\)]*\)/gi,''); + } + element = $(element); + var currentStyle = element.currentStyle; + if ((currentStyle && !currentStyle.hasLayout) || + (!currentStyle && element.style.zoom == 'normal')) + element.style.zoom = 1; + + var filter = element.getStyle('filter'), style = element.style; + if (value == 1 || value === '') { + (filter = stripAlpha(filter)) ? + style.filter = filter : style.removeAttribute('filter'); + return element; + } else if (value < 0.00001) value = 0; + style.filter = stripAlpha(filter) + + 'alpha(opacity=' + (value * 100) + ')'; + return element; + }; + + Element._attributeTranslations = (function(){ + + var classProp = 'className', + forProp = 'for', + el = document.createElement('div'); + + el.setAttribute(classProp, 'x'); + + if (el.className !== 'x') { + el.setAttribute('class', 'x'); + if (el.className === 'x') { + classProp = 'class'; + } + } + el = null; + + el = document.createElement('label'); + el.setAttribute(forProp, 'x'); + if (el.htmlFor !== 'x') { + el.setAttribute('htmlFor', 'x'); + if (el.htmlFor === 'x') { + forProp = 'htmlFor'; + } + } + el = null; + + return { + read: { + names: { + 'class': classProp, + 'className': classProp, + 'for': forProp, + 'htmlFor': forProp + }, + values: { + _getAttr: function(element, attribute) { + return element.getAttribute(attribute); + }, + _getAttr2: function(element, attribute) { + return element.getAttribute(attribute, 2); + }, + _getAttrNode: function(element, attribute) { + var node = element.getAttributeNode(attribute); + return node ? node.value : ""; + }, + _getEv: (function(){ + + var el = document.createElement('div'), f; + el.onclick = Prototype.emptyFunction; + var value = el.getAttribute('onclick'); + + if (String(value).indexOf('{') > -1) { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + attribute = attribute.toString(); + attribute = attribute.split('{')[1]; + attribute = attribute.split('}')[0]; + return attribute.strip(); + }; + } + else if (value === '') { + f = function(element, attribute) { + attribute = element.getAttribute(attribute); + if (!attribute) return null; + return attribute.strip(); + }; + } + el = null; + return f; + })(), + _flag: function(element, attribute) { + return $(element).hasAttribute(attribute) ? attribute : null; + }, + style: function(element) { + return element.style.cssText.toLowerCase(); + }, + title: function(element) { + return element.title; + } + } + } + } + })(); + + Element._attributeTranslations.write = { + names: Object.extend({ + cellpadding: 'cellPadding', + cellspacing: 'cellSpacing' + }, Element._attributeTranslations.read.names), + values: { + checked: function(element, value) { + element.checked = !!value; + }, + + style: function(element, value) { + element.style.cssText = value ? value : ''; + } + } + }; + + Element._attributeTranslations.has = {}; + + $w('colSpan rowSpan vAlign dateTime accessKey tabIndex ' + + 'encType maxLength readOnly longDesc frameBorder').each(function(attr) { + Element._attributeTranslations.write.names[attr.toLowerCase()] = attr; + Element._attributeTranslations.has[attr.toLowerCase()] = attr; + }); + + (function(v) { + Object.extend(v, { + href: v._getAttr2, + src: v._getAttr2, + type: v._getAttr, + action: v._getAttrNode, + disabled: v._flag, + checked: v._flag, + readonly: v._flag, + multiple: v._flag, + onload: v._getEv, + onunload: v._getEv, + onclick: v._getEv, + ondblclick: v._getEv, + onmousedown: v._getEv, + onmouseup: v._getEv, + onmouseover: v._getEv, + onmousemove: v._getEv, + onmouseout: v._getEv, + onfocus: v._getEv, + onblur: v._getEv, + onkeypress: v._getEv, + onkeydown: v._getEv, + onkeyup: v._getEv, + onsubmit: v._getEv, + onreset: v._getEv, + onselect: v._getEv, + onchange: v._getEv + }); + })(Element._attributeTranslations.read.values); + + if (Prototype.BrowserFeatures.ElementExtensions) { + (function() { + function _descendants(element) { + var nodes = element.getElementsByTagName('*'), results = []; + for (var i = 0, node; node = nodes[i]; i++) + if (node.tagName !== "!") // Filter out comment nodes. + results.push(node); + return results; + } + + Element.Methods.down = function(element, expression, index) { + element = $(element); + if (arguments.length == 1) return element.firstDescendant(); + return Object.isNumber(expression) ? _descendants(element)[expression] : + Element.select(element, expression)[index || 0]; + } + })(); + } + +} + +else if (Prototype.Browser.Gecko && /rv:1\.8\.0/.test(navigator.userAgent)) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1) ? 0.999999 : + (value === '') ? '' : (value < 0.00001) ? 0 : value; + return element; + }; +} + +else if (Prototype.Browser.WebKit) { + Element.Methods.setOpacity = function(element, value) { + element = $(element); + element.style.opacity = (value == 1 || value === '') ? '' : + (value < 0.00001) ? 0 : value; + + if (value == 1) + if (element.tagName.toUpperCase() == 'IMG' && element.width) { + element.width++; element.width--; + } else try { + var n = document.createTextNode(' '); + element.appendChild(n); + element.removeChild(n); + } catch (e) { } + + return element; + }; + + Element.Methods.cumulativeOffset = function(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == document.body) + if (Element.getStyle(element, 'position') == 'absolute') break; + + element = element.offsetParent; + } while (element); + + return Element._returnOffset(valueL, valueT); + }; +} + +if ('outerHTML' in document.documentElement) { + Element.Methods.replace = function(element, content) { + element = $(element); + + if (content && content.toElement) content = content.toElement(); + if (Object.isElement(content)) { + element.parentNode.replaceChild(content, element); + return element; + } + + content = Object.toHTML(content); + var parent = element.parentNode, tagName = parent.tagName.toUpperCase(); + + if (Element._insertionTranslations.tags[tagName]) { + var nextSibling = element.next(), + fragments = Element._getContentFromAnonymousElement(tagName, content.stripScripts()); + parent.removeChild(element); + if (nextSibling) + fragments.each(function(node) { parent.insertBefore(node, nextSibling) }); + else + fragments.each(function(node) { parent.appendChild(node) }); + } + else element.outerHTML = content.stripScripts(); + + content.evalScripts.bind(content).defer(); + return element; + }; +} + +Element._returnOffset = function(l, t) { + var result = [l, t]; + result.left = l; + result.top = t; + return result; +}; + +Element._getContentFromAnonymousElement = function(tagName, html) { + var div = new Element('div'), + t = Element._insertionTranslations.tags[tagName]; + if (t) { + div.innerHTML = t[0] + html + t[1]; + for (var i = t[2]; i--; ) { + div = div.firstChild; + } + } + else { + div.innerHTML = html; + } + return $A(div.childNodes); +}; + +Element._insertionTranslations = { + before: function(element, node) { + element.parentNode.insertBefore(node, element); + }, + top: function(element, node) { + element.insertBefore(node, element.firstChild); + }, + bottom: function(element, node) { + element.appendChild(node); + }, + after: function(element, node) { + element.parentNode.insertBefore(node, element.nextSibling); + }, + tags: { + TABLE: ['', '
    ', 1], + TBODY: ['', '
    ', 2], + TR: ['', '
    ', 3], + TD: ['
    ', '
    ', 4], + SELECT: ['', 1] + } +}; + +(function() { + var tags = Element._insertionTranslations.tags; + Object.extend(tags, { + THEAD: tags.TBODY, + TFOOT: tags.TBODY, + TH: tags.TD + }); +})(); + +Element.Methods.Simulated = { + hasAttribute: function(element, attribute) { + attribute = Element._attributeTranslations.has[attribute] || attribute; + var node = $(element).getAttributeNode(attribute); + return !!(node && node.specified); + } +}; + +Element.Methods.ByTag = { }; + +Object.extend(Element, Element.Methods); + +(function(div) { + + if (!Prototype.BrowserFeatures.ElementExtensions && div['__proto__']) { + window.HTMLElement = { }; + window.HTMLElement.prototype = div['__proto__']; + Prototype.BrowserFeatures.ElementExtensions = true; + } + + div = null; + +})(document.createElement('div')); + +Element.extend = (function() { + + function checkDeficiency(tagName) { + if (typeof window.Element != 'undefined') { + var proto = window.Element.prototype; + if (proto) { + var id = '_' + (Math.random()+'').slice(2), + el = document.createElement(tagName); + proto[id] = 'x'; + var isBuggy = (el[id] !== 'x'); + delete proto[id]; + el = null; + return isBuggy; + } + } + return false; + } + + function extendElementWith(element, methods) { + for (var property in methods) { + var value = methods[property]; + if (Object.isFunction(value) && !(property in element)) + element[property] = value.methodize(); + } + } + + var HTMLOBJECTELEMENT_PROTOTYPE_BUGGY = checkDeficiency('object'); + + if (Prototype.BrowserFeatures.SpecificElementExtensions) { + if (HTMLOBJECTELEMENT_PROTOTYPE_BUGGY) { + return function(element) { + if (element && typeof element._extendedByPrototype == 'undefined') { + var t = element.tagName; + if (t && (/^(?:object|applet|embed)$/i.test(t))) { + extendElementWith(element, Element.Methods); + extendElementWith(element, Element.Methods.Simulated); + extendElementWith(element, Element.Methods.ByTag[t.toUpperCase()]); + } + } + return element; + } + } + return Prototype.K; + } + + var Methods = { }, ByTag = Element.Methods.ByTag; + + var extend = Object.extend(function(element) { + if (!element || typeof element._extendedByPrototype != 'undefined' || + element.nodeType != 1 || element == window) return element; + + var methods = Object.clone(Methods), + tagName = element.tagName.toUpperCase(); + + if (ByTag[tagName]) Object.extend(methods, ByTag[tagName]); + + extendElementWith(element, methods); + + element._extendedByPrototype = Prototype.emptyFunction; + return element; + + }, { + refresh: function() { + if (!Prototype.BrowserFeatures.ElementExtensions) { + Object.extend(Methods, Element.Methods); + Object.extend(Methods, Element.Methods.Simulated); + } + } + }); + + extend.refresh(); + return extend; +})(); + +if (document.documentElement.hasAttribute) { + Element.hasAttribute = function(element, attribute) { + return element.hasAttribute(attribute); + }; +} +else { + Element.hasAttribute = Element.Methods.Simulated.hasAttribute; +} + +Element.addMethods = function(methods) { + var F = Prototype.BrowserFeatures, T = Element.Methods.ByTag; + + if (!methods) { + Object.extend(Form, Form.Methods); + Object.extend(Form.Element, Form.Element.Methods); + Object.extend(Element.Methods.ByTag, { + "FORM": Object.clone(Form.Methods), + "INPUT": Object.clone(Form.Element.Methods), + "SELECT": Object.clone(Form.Element.Methods), + "TEXTAREA": Object.clone(Form.Element.Methods) + }); + } + + if (arguments.length == 2) { + var tagName = methods; + methods = arguments[1]; + } + + if (!tagName) Object.extend(Element.Methods, methods || { }); + else { + if (Object.isArray(tagName)) tagName.each(extend); + else extend(tagName); + } + + function extend(tagName) { + tagName = tagName.toUpperCase(); + if (!Element.Methods.ByTag[tagName]) + Element.Methods.ByTag[tagName] = { }; + Object.extend(Element.Methods.ByTag[tagName], methods); + } + + function copy(methods, destination, onlyIfAbsent) { + onlyIfAbsent = onlyIfAbsent || false; + for (var property in methods) { + var value = methods[property]; + if (!Object.isFunction(value)) continue; + if (!onlyIfAbsent || !(property in destination)) + destination[property] = value.methodize(); + } + } + + function findDOMClass(tagName) { + var klass; + var trans = { + "OPTGROUP": "OptGroup", "TEXTAREA": "TextArea", "P": "Paragraph", + "FIELDSET": "FieldSet", "UL": "UList", "OL": "OList", "DL": "DList", + "DIR": "Directory", "H1": "Heading", "H2": "Heading", "H3": "Heading", + "H4": "Heading", "H5": "Heading", "H6": "Heading", "Q": "Quote", + "INS": "Mod", "DEL": "Mod", "A": "Anchor", "IMG": "Image", "CAPTION": + "TableCaption", "COL": "TableCol", "COLGROUP": "TableCol", "THEAD": + "TableSection", "TFOOT": "TableSection", "TBODY": "TableSection", "TR": + "TableRow", "TH": "TableCell", "TD": "TableCell", "FRAMESET": + "FrameSet", "IFRAME": "IFrame" + }; + if (trans[tagName]) klass = 'HTML' + trans[tagName] + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName + 'Element'; + if (window[klass]) return window[klass]; + klass = 'HTML' + tagName.capitalize() + 'Element'; + if (window[klass]) return window[klass]; + + var element = document.createElement(tagName), + proto = element['__proto__'] || element.constructor.prototype; + + element = null; + return proto; + } + + var elementPrototype = window.HTMLElement ? HTMLElement.prototype : + Element.prototype; + + if (F.ElementExtensions) { + copy(Element.Methods, elementPrototype); + copy(Element.Methods.Simulated, elementPrototype, true); + } + + if (F.SpecificElementExtensions) { + for (var tag in Element.Methods.ByTag) { + var klass = findDOMClass(tag); + if (Object.isUndefined(klass)) continue; + copy(T[tag], klass.prototype); + } + } + + Object.extend(Element, Element.Methods); + delete Element.ByTag; + + if (Element.extend.refresh) Element.extend.refresh(); + Element.cache = { }; +}; + + +document.viewport = { + + getDimensions: function() { + return { width: this.getWidth(), height: this.getHeight() }; + }, + + getScrollOffsets: function() { + return Element._returnOffset( + window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft, + window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop); + } +}; + +(function(viewport) { + var B = Prototype.Browser, doc = document, element, property = {}; + + function getRootElement() { + if (B.WebKit && !doc.evaluate) + return document; + + if (B.Opera && window.parseFloat(window.opera.version()) < 9.5) + return document.body; + + return document.documentElement; + } + + function define(D) { + if (!element) element = getRootElement(); + + property[D] = 'client' + D; + + viewport['get' + D] = function() { return element[property[D]] }; + return viewport['get' + D](); + } + + viewport.getWidth = define.curry('Width'); + + viewport.getHeight = define.curry('Height'); +})(document.viewport); + + +Element.Storage = { + UID: 1 +}; + +Element.addMethods({ + getStorage: function(element) { + if (!(element = $(element))) return; + + var uid; + if (element === window) { + uid = 0; + } else { + if (typeof element._prototypeUID === "undefined") + element._prototypeUID = Element.Storage.UID++; + uid = element._prototypeUID; + } + + if (!Element.Storage[uid]) + Element.Storage[uid] = $H(); + + return Element.Storage[uid]; + }, + + store: function(element, key, value) { + if (!(element = $(element))) return; + + if (arguments.length === 2) { + Element.getStorage(element).update(key); + } else { + Element.getStorage(element).set(key, value); + } + + return element; + }, + + retrieve: function(element, key, defaultValue) { + if (!(element = $(element))) return; + var hash = Element.getStorage(element), value = hash.get(key); + + if (Object.isUndefined(value)) { + hash.set(key, defaultValue); + value = defaultValue; + } + + return value; + }, + + clone: function(element, deep) { + if (!(element = $(element))) return; + var clone = element.cloneNode(deep); + clone._prototypeUID = void 0; + if (deep) { + var descendants = Element.select(clone, '*'), + i = descendants.length; + while (i--) { + descendants[i]._prototypeUID = void 0; + } + } + return Element.extend(clone); + }, + + purge: function(element) { + if (!(element = $(element))) return; + purgeElement(element); + + var descendants = element.getElementsByTagName('*'), + i = descendants.length; + + while (i--) purgeElement(descendants[i]); + + return null; + } +}); + +(function() { + + function toDecimal(pctString) { + var match = pctString.match(/^(\d+)%?$/i); + if (!match) return null; + return (Number(match[1]) / 100); + } + + function getPixelValue(value, property) { + if (Object.isElement(value)) { + element = value; + value = element.getStyle(property); + } + if (value === null) { + return null; + } + + if ((/^(?:-)?\d+(\.\d+)?(px)?$/i).test(value)) { + return window.parseFloat(value); + } + + if (/\d/.test(value) && element.runtimeStyle) { + var style = element.style.left, rStyle = element.runtimeStyle.left; + element.runtimeStyle.left = element.currentStyle.left; + element.style.left = value || 0; + value = element.style.pixelLeft; + element.style.left = style; + element.runtimeStyle.left = rStyle; + + return value; + } + + if (value.include('%')) { + var decimal = toDecimal(value); + var whole; + if (property.include('left') || property.include('right') || + property.include('width')) { + whole = $(element.parentNode).measure('width'); + } else if (property.include('top') || property.include('bottom') || + property.include('height')) { + whole = $(element.parentNode).measure('height'); + } + + return whole * decimal; + } + + return 0; + } + + function toCSSPixels(number) { + if (Object.isString(number) && number.endsWith('px')) { + return number; + } + return number + 'px'; + } + + function isDisplayed(element) { + var originalElement = element; + while (element && element.parentNode) { + var display = element.getStyle('display'); + if (display === 'none') { + return false; + } + element = $(element.parentNode); + } + return true; + } + + var hasLayout = Prototype.K; + if ('currentStyle' in document.documentElement) { + hasLayout = function(element) { + if (!element.currentStyle.hasLayout) { + element.style.zoom = 1; + } + return element; + }; + } + + function cssNameFor(key) { + if (key.include('border')) key = key + '-width'; + return key.camelize(); + } + + Element.Layout = Class.create(Hash, { + initialize: function($super, element, preCompute) { + $super(); + this.element = $(element); + + Element.Layout.PROPERTIES.each( function(property) { + this._set(property, null); + }, this); + + if (preCompute) { + this._preComputing = true; + this._begin(); + Element.Layout.PROPERTIES.each( this._compute, this ); + this._end(); + this._preComputing = false; + } + }, + + _set: function(property, value) { + return Hash.prototype.set.call(this, property, value); + }, + + set: function(property, value) { + throw "Properties of Element.Layout are read-only."; + }, + + get: function($super, property) { + var value = $super(property); + return value === null ? this._compute(property) : value; + }, + + _begin: function() { + if (this._prepared) return; + + var element = this.element; + if (isDisplayed(element)) { + this._prepared = true; + return; + } + + var originalStyles = { + position: element.style.position || '', + width: element.style.width || '', + visibility: element.style.visibility || '', + display: element.style.display || '' + }; + + element.store('prototype_original_styles', originalStyles); + + var position = element.getStyle('position'), + width = element.getStyle('width'); + + element.setStyle({ + position: 'absolute', + visibility: 'hidden', + display: 'block' + }); + + var positionedWidth = element.getStyle('width'); + + var newWidth; + if (width && (positionedWidth === width)) { + newWidth = getPixelValue(width); + } else if (width && (position === 'absolute' || position === 'fixed')) { + newWidth = getPixelValue(width); + } else { + var parent = element.parentNode, pLayout = $(parent).getLayout(); + + newWidth = pLayout.get('width') - + this.get('margin-left') - + this.get('border-left') - + this.get('padding-left') - + this.get('padding-right') - + this.get('border-right') - + this.get('margin-right'); + } + + element.setStyle({ width: newWidth + 'px' }); + + this._prepared = true; + }, + + _end: function() { + var element = this.element; + var originalStyles = element.retrieve('prototype_original_styles'); + element.store('prototype_original_styles', null); + element.setStyle(originalStyles); + this._prepared = false; + }, + + _compute: function(property) { + var COMPUTATIONS = Element.Layout.COMPUTATIONS; + if (!(property in COMPUTATIONS)) { + throw "Property not found."; + } + return this._set(property, COMPUTATIONS[property].call(this, this.element)); + }, + + toObject: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var obj = {}; + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + var value = this.get(key); + if (value != null) obj[key] = value; + }, this); + return obj; + }, + + toHash: function() { + var obj = this.toObject.apply(this, arguments); + return new Hash(obj); + }, + + toCSS: function() { + var args = $A(arguments); + var keys = (args.length === 0) ? Element.Layout.PROPERTIES : + args.join(' ').split(' '); + var css = {}; + + keys.each( function(key) { + if (!Element.Layout.PROPERTIES.include(key)) return; + if (Element.Layout.COMPOSITE_PROPERTIES.include(key)) return; + + var value = this.get(key); + if (value != null) css[cssNameFor(key)] = value + 'px'; + }, this); + return css; + }, + + inspect: function() { + return "#"; + } + }); + + Object.extend(Element.Layout, { + PROPERTIES: $w('height width top left right bottom border-left border-right border-top border-bottom padding-left padding-right padding-top padding-bottom margin-top margin-bottom margin-left margin-right padding-box-width padding-box-height border-box-width border-box-height margin-box-width margin-box-height'), + + COMPOSITE_PROPERTIES: $w('padding-box-width padding-box-height margin-box-width margin-box-height border-box-width border-box-height'), + + COMPUTATIONS: { + 'height': function(element) { + if (!this._preComputing) this._begin(); + + var bHeight = this.get('border-box-height'); + if (bHeight <= 0) return 0; + + var bTop = this.get('border-top'), + bBottom = this.get('border-bottom'); + + var pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + if (!this._preComputing) this._end(); + + return bHeight - bTop - bBottom - pTop - pBottom; + }, + + 'width': function(element) { + if (!this._preComputing) this._begin(); + + var bWidth = this.get('border-box-width'); + if (bWidth <= 0) return 0; + + var bLeft = this.get('border-left'), + bRight = this.get('border-right'); + + var pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + if (!this._preComputing) this._end(); + + return bWidth - bLeft - bRight - pLeft - pRight; + }, + + 'padding-box-height': function(element) { + var height = this.get('height'), + pTop = this.get('padding-top'), + pBottom = this.get('padding-bottom'); + + return height + pTop + pBottom; + }, + + 'padding-box-width': function(element) { + var width = this.get('width'), + pLeft = this.get('padding-left'), + pRight = this.get('padding-right'); + + return width + pLeft + pRight; + }, + + 'border-box-height': function(element) { + return element.offsetHeight; + }, + + 'border-box-width': function(element) { + return element.offsetWidth; + }, + + 'margin-box-height': function(element) { + var bHeight = this.get('border-box-height'), + mTop = this.get('margin-top'), + mBottom = this.get('margin-bottom'); + + if (bHeight <= 0) return 0; + + return bHeight + mTop + mBottom; + }, + + 'margin-box-width': function(element) { + var bWidth = this.get('border-box-width'), + mLeft = this.get('margin-left'), + mRight = this.get('margin-right'); + + if (bWidth <= 0) return 0; + + return bWidth + mLeft + mRight; + }, + + 'top': function(element) { + var offset = element.positionedOffset(); + return offset.top; + }, + + 'bottom': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pHeight = parent.measure('height'); + + var mHeight = this.get('border-box-height'); + + return pHeight - mHeight - offset.top; + }, + + 'left': function(element) { + var offset = element.positionedOffset(); + return offset.left; + }, + + 'right': function(element) { + var offset = element.positionedOffset(), + parent = element.getOffsetParent(), + pWidth = parent.measure('width'); + + var mWidth = this.get('border-box-width'); + + return pWidth - mWidth - offset.left; + }, + + 'padding-top': function(element) { + return getPixelValue(element, 'paddingTop'); + }, + + 'padding-bottom': function(element) { + return getPixelValue(element, 'paddingBottom'); + }, + + 'padding-left': function(element) { + return getPixelValue(element, 'paddingLeft'); + }, + + 'padding-right': function(element) { + return getPixelValue(element, 'paddingRight'); + }, + + 'border-top': function(element) { + return Object.isNumber(element.clientTop) ? element.clientTop : + getPixelValue(element, 'borderTopWidth'); + }, + + 'border-bottom': function(element) { + return Object.isNumber(element.clientBottom) ? element.clientBottom : + getPixelValue(element, 'borderBottomWidth'); + }, + + 'border-left': function(element) { + return Object.isNumber(element.clientLeft) ? element.clientLeft : + getPixelValue(element, 'borderLeftWidth'); + }, + + 'border-right': function(element) { + return Object.isNumber(element.clientRight) ? element.clientRight : + getPixelValue(element, 'borderRightWidth'); + }, + + 'margin-top': function(element) { + return getPixelValue(element, 'marginTop'); + }, + + 'margin-bottom': function(element) { + return getPixelValue(element, 'marginBottom'); + }, + + 'margin-left': function(element) { + return getPixelValue(element, 'marginLeft'); + }, + + 'margin-right': function(element) { + return getPixelValue(element, 'marginRight'); + } + } + }); + + if ('getBoundingClientRect' in document.documentElement) { + Object.extend(Element.Layout.COMPUTATIONS, { + 'right': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.right - rect.right).round(); + }, + + 'bottom': function(element) { + var parent = hasLayout(element.getOffsetParent()); + var rect = element.getBoundingClientRect(), + pRect = parent.getBoundingClientRect(); + + return (pRect.bottom - rect.bottom).round(); + } + }); + } + + Element.Offset = Class.create({ + initialize: function(left, top) { + this.left = left.round(); + this.top = top.round(); + + this[0] = this.left; + this[1] = this.top; + }, + + relativeTo: function(offset) { + return new Element.Offset( + this.left - offset.left, + this.top - offset.top + ); + }, + + inspect: function() { + return "#".interpolate(this); + }, + + toString: function() { + return "[#{left}, #{top}]".interpolate(this); + }, + + toArray: function() { + return [this.left, this.top]; + } + }); + + function getLayout(element, preCompute) { + return new Element.Layout(element, preCompute); + } + + function measure(element, property) { + return $(element).getLayout().get(property); + } + + function getDimensions(element) { + var layout = $(element).getLayout(); + return { + width: layout.get('width'), + height: layout.get('height') + }; + } + + function getOffsetParent(element) { + if (isDetached(element)) return $(document.body); + + var isInline = (Element.getStyle(element, 'display') === 'inline'); + if (!isInline && element.offsetParent) return $(element.offsetParent); + if (element === document.body) return $(element); + + while ((element = element.parentNode) && element !== document.body) { + if (Element.getStyle(element, 'position') !== 'static') { + return (element.nodeName === 'HTML') ? $(document.body) : $(element); + } + } + + return $(document.body); + } + + + function cumulativeOffset(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + } while (element); + return new Element.Offset(valueL, valueT); + } + + function positionedOffset(element) { + var layout = element.getLayout(); + + var valueT = 0, valueL = 0; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + element = element.offsetParent; + if (element) { + if (isBody(element)) break; + var p = Element.getStyle(element, 'position'); + if (p !== 'static') break; + } + } while (element); + + valueL -= layout.get('margin-top'); + valueT -= layout.get('margin-left'); + + return new Element.Offset(valueL, valueT); + } + + function cumulativeScrollOffset(element) { + var valueT = 0, valueL = 0; + do { + valueT += element.scrollTop || 0; + valueL += element.scrollLeft || 0; + element = element.parentNode; + } while (element); + return new Element.Offset(valueL, valueT); + } + + function viewportOffset(forElement) { + var valueT = 0, valueL = 0, docBody = document.body; + + var element = forElement; + do { + valueT += element.offsetTop || 0; + valueL += element.offsetLeft || 0; + if (element.offsetParent == docBody && + Element.getStyle(element, 'position') == 'absolute') break; + } while (element = element.offsetParent); + + element = forElement; + do { + if (element != docBody) { + valueT -= element.scrollTop || 0; + valueL -= element.scrollLeft || 0; + } + } while (element = element.parentNode); + return new Element.Offset(valueL, valueT); + } + + function absolutize(element) { + element = $(element); + + if (Element.getStyle(element, 'position') === 'absolute') { + return element; + } + + var offsetParent = getOffsetParent(element); + var eOffset = element.viewportOffset(), + pOffset = offsetParent.viewportOffset(); + + var offset = eOffset.relativeTo(pOffset); + var layout = element.getLayout(); + + element.store('prototype_absolutize_original_styles', { + left: element.getStyle('left'), + top: element.getStyle('top'), + width: element.getStyle('width'), + height: element.getStyle('height') + }); + + element.setStyle({ + position: 'absolute', + top: offset.top + 'px', + left: offset.left + 'px', + width: layout.get('width') + 'px', + height: layout.get('height') + 'px' + }); + + return element; + } + + function relativize(element) { + element = $(element); + if (Element.getStyle(element, 'position') === 'relative') { + return element; + } + + var originalStyles = + element.retrieve('prototype_absolutize_original_styles'); + + if (originalStyles) element.setStyle(originalStyles); + return element; + } + + Element.addMethods({ + getLayout: getLayout, + measure: measure, + getDimensions: getDimensions, + getOffsetParent: getOffsetParent, + cumulativeOffset: cumulativeOffset, + positionedOffset: positionedOffset, + cumulativeScrollOffset: cumulativeScrollOffset, + viewportOffset: viewportOffset, + absolutize: absolutize, + relativize: relativize + }); + + function isBody(element) { + return element.nodeName.toUpperCase() === 'BODY'; + } + + function isDetached(element) { + return element !== document.body && + !Element.descendantOf(element, document.body); + } + + if ('getBoundingClientRect' in document.documentElement) { + Element.addMethods({ + viewportOffset: function(element) { + element = $(element); + if (isDetached(element)) return new Element.Offset(0, 0); + + var rect = element.getBoundingClientRect(), + docEl = document.documentElement; + return new Element.Offset(rect.left - docEl.clientLeft, + rect.top - docEl.clientTop); + }, + + positionedOffset: function(element) { + element = $(element); + var parent = element.getOffsetParent(); + if (isDetached(element)) return new Element.Offset(0, 0); + + if (element.offsetParent && + element.offsetParent.nodeName.toUpperCase() === 'HTML') { + return positionedOffset(element); + } + + var eOffset = element.viewportOffset(), + pOffset = isBody(parent) ? viewportOffset(parent) : + parent.viewportOffset(); + var retOffset = eOffset.relativeTo(pOffset); + + var layout = element.getLayout(); + var top = retOffset.top - layout.get('margin-top'); + var left = retOffset.left - layout.get('margin-left'); + + return new Element.Offset(left, top); + } + }); + } +})(); +window.$$ = function() { + var expression = $A(arguments).join(', '); + return Prototype.Selector.select(expression, document); +}; + +Prototype.Selector = (function() { + + function select() { + throw new Error('Method "Prototype.Selector.select" must be defined.'); + } + + function match() { + throw new Error('Method "Prototype.Selector.match" must be defined.'); + } + + function find(elements, expression, index) { + index = index || 0; + var match = Prototype.Selector.match, length = elements.length, matchIndex = 0, i; + + for (i = 0; i < length; i++) { + if (match(elements[i], expression) && index == matchIndex++) { + return Element.extend(elements[i]); + } + } + } + + function extendElements(elements) { + for (var i = 0, length = elements.length; i < length; i++) { + Element.extend(elements[i]); + } + return elements; + } + + + var K = Prototype.K; + + return { + select: select, + match: match, + find: find, + extendElements: (Element.extend === K) ? K : extendElements, + extendElement: Element.extend + }; +})(); +Prototype._original_property = window.Sizzle; +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, check, mode, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) + selector += parts.shift(); + + set = posProcess( selector, set ); + } + } + } else { + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + throw "Syntax error, unrecognized expression: " + (cur || selector); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.match[ type ].exec( expr )) != null ) { + var filter = Expr.filter[ type ], found, item; + anyFound = false; + + if ( curLoop == result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + if ( expr == old ) { + if ( anyFound == null ) { + throw "Syntax error, unrecognized expression: " + expr; + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]*)((?:\([^\)]+\)|[^\2\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag && !isXML ) { + part = part.toUpperCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part, isXML){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = isXML ? part : part.toUpperCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = isXML ? part : part.toUpperCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context, isXML){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").indexOf(match) >= 0) ) { + if ( !inplace ) + result.push( elem ); + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + for ( var i = 0; curLoop[i] === false; i++ ){} + return curLoop[i] && isXML(curLoop[i]) ? match[1] : match[1].toUpperCase(); + }, + CHILD: function(match){ + if ( match[1] == "nth" ) { + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] == "even" && "2n" || match[2] == "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toUpperCase() === "BUTTON"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 == i; + }, + eq: function(elem, i, match){ + return match[3] - 0 == i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) return false; + } + if ( type == 'first') return true; + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) return false; + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first == 1 && last == 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first == 0 ) { + return diff == 0; + } else { + return ( diff % first == 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value != check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source ); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 ); + +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return 0; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +(function(){ + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + if ( !!document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

    "; + + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE +})(); + +if ( document.getElementsByClassName && document.documentElement.getElementsByClassName ) (function(){ + var div = document.createElement("div"); + div.innerHTML = "
    "; + + if ( div.getElementsByClassName("e").length === 0 ) + return; + + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) + return; + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ){ + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + var sibDir = dir == "previousSibling" && !isXML; + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + if ( sibDir && elem.nodeType === 1 ) { + elem.sizcache = doneName; + elem.sizset = i; + } + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return a.compareDocumentPosition(b) & 16; +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + return elem.nodeType === 9 && elem.documentElement.nodeName !== "HTML" || + !!elem.ownerDocument && elem.ownerDocument.documentElement.nodeName !== "HTML"; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + + +window.Sizzle = Sizzle; + +})(); + +;(function(engine) { + var extendElements = Prototype.Selector.extendElements; + + function select(selector, scope) { + return extendElements(engine(selector, scope || document)); + } + + function match(element, selector) { + return engine.matches(selector, [element]).length == 1; + } + + Prototype.Selector.engine = engine; + Prototype.Selector.select = select; + Prototype.Selector.match = match; +})(Sizzle); + +window.Sizzle = Prototype._original_property; +delete Prototype._original_property; + +var Form = { + reset: function(form) { + form = $(form); + form.reset(); + return form; + }, + + serializeElements: function(elements, options) { + if (typeof options != 'object') options = { hash: !!options }; + else if (Object.isUndefined(options.hash)) options.hash = true; + var key, value, submitted = false, submit = options.submit; + + var data = elements.inject({ }, function(result, element) { + if (!element.disabled && element.name) { + key = element.name; value = $(element).getValue(); + if (value != null && element.type != 'file' && (element.type != 'submit' || (!submitted && + submit !== false && (!submit || key == submit) && (submitted = true)))) { + if (key in result) { + if (!Object.isArray(result[key])) result[key] = [result[key]]; + result[key].push(value); + } + else result[key] = value; + } + } + return result; + }); + + return options.hash ? data : Object.toQueryString(data); + } +}; + +Form.Methods = { + serialize: function(form, options) { + return Form.serializeElements(Form.getElements(form), options); + }, + + getElements: function(form) { + var elements = $(form).getElementsByTagName('*'), + element, + arr = [ ], + serializers = Form.Element.Serializers; + for (var i = 0; element = elements[i]; i++) { + arr.push(element); + } + return arr.inject([], function(elements, child) { + if (serializers[child.tagName.toLowerCase()]) + elements.push(Element.extend(child)); + return elements; + }) + }, + + getInputs: function(form, typeName, name) { + form = $(form); + var inputs = form.getElementsByTagName('input'); + + if (!typeName && !name) return $A(inputs).map(Element.extend); + + for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) { + var input = inputs[i]; + if ((typeName && input.type != typeName) || (name && input.name != name)) + continue; + matchingInputs.push(Element.extend(input)); + } + + return matchingInputs; + }, + + disable: function(form) { + form = $(form); + Form.getElements(form).invoke('disable'); + return form; + }, + + enable: function(form) { + form = $(form); + Form.getElements(form).invoke('enable'); + return form; + }, + + findFirstElement: function(form) { + var elements = $(form).getElements().findAll(function(element) { + return 'hidden' != element.type && !element.disabled; + }); + var firstByIndex = elements.findAll(function(element) { + return element.hasAttribute('tabIndex') && element.tabIndex >= 0; + }).sortBy(function(element) { return element.tabIndex }).first(); + + return firstByIndex ? firstByIndex : elements.find(function(element) { + return /^(?:input|select|textarea)$/i.test(element.tagName); + }); + }, + + focusFirstElement: function(form) { + form = $(form); + form.findFirstElement().activate(); + return form; + }, + + request: function(form, options) { + form = $(form), options = Object.clone(options || { }); + + var params = options.parameters, action = form.readAttribute('action') || ''; + if (action.blank()) action = window.location.href; + options.parameters = form.serialize(true); + + if (params) { + if (Object.isString(params)) params = params.toQueryParams(); + Object.extend(options.parameters, params); + } + + if (form.hasAttribute('method') && !options.method) + options.method = form.method; + + return new Ajax.Request(action, options); + } +}; + +/*--------------------------------------------------------------------------*/ + + +Form.Element = { + focus: function(element) { + $(element).focus(); + return element; + }, + + select: function(element) { + $(element).select(); + return element; + } +}; + +Form.Element.Methods = { + + serialize: function(element) { + element = $(element); + if (!element.disabled && element.name) { + var value = element.getValue(); + if (value != undefined) { + var pair = { }; + pair[element.name] = value; + return Object.toQueryString(pair); + } + } + return ''; + }, + + getValue: function(element) { + element = $(element); + var method = element.tagName.toLowerCase(); + return Form.Element.Serializers[method](element); + }, + + setValue: function(element, value) { + element = $(element); + var method = element.tagName.toLowerCase(); + Form.Element.Serializers[method](element, value); + return element; + }, + + clear: function(element) { + $(element).value = ''; + return element; + }, + + present: function(element) { + return $(element).value != ''; + }, + + activate: function(element) { + element = $(element); + try { + element.focus(); + if (element.select && (element.tagName.toLowerCase() != 'input' || + !(/^(?:button|reset|submit)$/i.test(element.type)))) + element.select(); + } catch (e) { } + return element; + }, + + disable: function(element) { + element = $(element); + element.disabled = true; + return element; + }, + + enable: function(element) { + element = $(element); + element.disabled = false; + return element; + } +}; + +/*--------------------------------------------------------------------------*/ + +var Field = Form.Element; + +var $F = Form.Element.Methods.getValue; + +/*--------------------------------------------------------------------------*/ + +Form.Element.Serializers = { + input: function(element, value) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + return Form.Element.Serializers.inputSelector(element, value); + default: + return Form.Element.Serializers.textarea(element, value); + } + }, + + inputSelector: function(element, value) { + if (Object.isUndefined(value)) return element.checked ? element.value : null; + else element.checked = !!value; + }, + + textarea: function(element, value) { + if (Object.isUndefined(value)) return element.value; + else element.value = value; + }, + + select: function(element, value) { + if (Object.isUndefined(value)) + return this[element.type == 'select-one' ? + 'selectOne' : 'selectMany'](element); + else { + var opt, currentValue, single = !Object.isArray(value); + for (var i = 0, length = element.length; i < length; i++) { + opt = element.options[i]; + currentValue = this.optionValue(opt); + if (single) { + if (currentValue == value) { + opt.selected = true; + return; + } + } + else opt.selected = value.include(currentValue); + } + } + }, + + selectOne: function(element) { + var index = element.selectedIndex; + return index >= 0 ? this.optionValue(element.options[index]) : null; + }, + + selectMany: function(element) { + var values, length = element.length; + if (!length) return null; + + for (var i = 0, values = []; i < length; i++) { + var opt = element.options[i]; + if (opt.selected) values.push(this.optionValue(opt)); + } + return values; + }, + + optionValue: function(opt) { + return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text; + } +}; + +/*--------------------------------------------------------------------------*/ + + +Abstract.TimedObserver = Class.create(PeriodicalExecuter, { + initialize: function($super, element, frequency, callback) { + $super(callback, frequency); + this.element = $(element); + this.lastValue = this.getValue(); + }, + + execute: function() { + var value = this.getValue(); + if (Object.isString(this.lastValue) && Object.isString(value) ? + this.lastValue != value : String(this.lastValue) != String(value)) { + this.callback(this.element, value); + this.lastValue = value; + } + } +}); + +Form.Element.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.Observer = Class.create(Abstract.TimedObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); + +/*--------------------------------------------------------------------------*/ + +Abstract.EventObserver = Class.create({ + initialize: function(element, callback) { + this.element = $(element); + this.callback = callback; + + this.lastValue = this.getValue(); + if (this.element.tagName.toLowerCase() == 'form') + this.registerFormCallbacks(); + else + this.registerCallback(this.element); + }, + + onElementEvent: function() { + var value = this.getValue(); + if (this.lastValue != value) { + this.callback(this.element, value); + this.lastValue = value; + } + }, + + registerFormCallbacks: function() { + Form.getElements(this.element).each(this.registerCallback, this); + }, + + registerCallback: function(element) { + if (element.type) { + switch (element.type.toLowerCase()) { + case 'checkbox': + case 'radio': + Event.observe(element, 'click', this.onElementEvent.bind(this)); + break; + default: + Event.observe(element, 'change', this.onElementEvent.bind(this)); + break; + } + } + } +}); + +Form.Element.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.Element.getValue(this.element); + } +}); + +Form.EventObserver = Class.create(Abstract.EventObserver, { + getValue: function() { + return Form.serialize(this.element); + } +}); +(function() { + + var Event = { + KEY_BACKSPACE: 8, + KEY_TAB: 9, + KEY_RETURN: 13, + KEY_ESC: 27, + KEY_LEFT: 37, + KEY_UP: 38, + KEY_RIGHT: 39, + KEY_DOWN: 40, + KEY_DELETE: 46, + KEY_HOME: 36, + KEY_END: 35, + KEY_PAGEUP: 33, + KEY_PAGEDOWN: 34, + KEY_INSERT: 45, + + cache: {} + }; + + var docEl = document.documentElement; + var MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED = 'onmouseenter' in docEl + && 'onmouseleave' in docEl; + + var _isButton; + if (Prototype.Browser.IE) { + var buttonMap = { 0: 1, 1: 4, 2: 2 }; + _isButton = function(event, code) { + return event.button === buttonMap[code]; + }; + } else if (Prototype.Browser.WebKit) { + _isButton = function(event, code) { + switch (code) { + case 0: return event.which == 1 && !event.metaKey; + case 1: return event.which == 1 && event.metaKey; + default: return false; + } + }; + } else { + _isButton = function(event, code) { + return event.which ? (event.which === code + 1) : (event.button === code); + }; + } + + function isLeftClick(event) { return _isButton(event, 0) } + + function isMiddleClick(event) { return _isButton(event, 1) } + + function isRightClick(event) { return _isButton(event, 2) } + + function element(event) { + event = Event.extend(event); + + var node = event.target, type = event.type, + currentTarget = event.currentTarget; + + if (currentTarget && currentTarget.tagName) { + if (type === 'load' || type === 'error' || + (type === 'click' && currentTarget.tagName.toLowerCase() === 'input' + && currentTarget.type === 'radio')) + node = currentTarget; + } + + if (node.nodeType == Node.TEXT_NODE) + node = node.parentNode; + + return Element.extend(node); + } + + function findElement(event, expression) { + var element = Event.element(event); + if (!expression) return element; + while (element) { + if (Object.isElement(element) && Prototype.Selector.match(element, expression)) { + return Element.extend(element); + } + element = element.parentNode; + } + } + + function pointer(event) { + return { x: pointerX(event), y: pointerY(event) }; + } + + function pointerX(event) { + var docElement = document.documentElement, + body = document.body || { scrollLeft: 0 }; + + return event.pageX || (event.clientX + + (docElement.scrollLeft || body.scrollLeft) - + (docElement.clientLeft || 0)); + } + + function pointerY(event) { + var docElement = document.documentElement, + body = document.body || { scrollTop: 0 }; + + return event.pageY || (event.clientY + + (docElement.scrollTop || body.scrollTop) - + (docElement.clientTop || 0)); + } + + + function stop(event) { + Event.extend(event); + event.preventDefault(); + event.stopPropagation(); + + event.stopped = true; + } + + Event.Methods = { + isLeftClick: isLeftClick, + isMiddleClick: isMiddleClick, + isRightClick: isRightClick, + + element: element, + findElement: findElement, + + pointer: pointer, + pointerX: pointerX, + pointerY: pointerY, + + stop: stop + }; + + + var methods = Object.keys(Event.Methods).inject({ }, function(m, name) { + m[name] = Event.Methods[name].methodize(); + return m; + }); + + if (Prototype.Browser.IE) { + function _relatedTarget(event) { + var element; + switch (event.type) { + case 'mouseover': element = event.fromElement; break; + case 'mouseout': element = event.toElement; break; + default: return null; + } + return Element.extend(element); + } + + Object.extend(methods, { + stopPropagation: function() { this.cancelBubble = true }, + preventDefault: function() { this.returnValue = false }, + inspect: function() { return '[object Event]' } + }); + + Event.extend = function(event, element) { + if (!event) return false; + if (event._extendedByPrototype) return event; + + event._extendedByPrototype = Prototype.emptyFunction; + var pointer = Event.pointer(event); + + Object.extend(event, { + target: event.srcElement || element, + relatedTarget: _relatedTarget(event), + pageX: pointer.x, + pageY: pointer.y + }); + + return Object.extend(event, methods); + }; + } else { + Event.prototype = window.Event.prototype || document.createEvent('HTMLEvents').__proto__; + Object.extend(Event.prototype, methods); + Event.extend = Prototype.K; + } + + function _createResponder(element, eventName, handler) { + var registry = Element.retrieve(element, 'prototype_event_registry'); + + if (Object.isUndefined(registry)) { + CACHE.push(element); + registry = Element.retrieve(element, 'prototype_event_registry', $H()); + } + + var respondersForEvent = registry.get(eventName); + if (Object.isUndefined(respondersForEvent)) { + respondersForEvent = []; + registry.set(eventName, respondersForEvent); + } + + if (respondersForEvent.pluck('handler').include(handler)) return false; + + var responder; + if (eventName.include(":")) { + responder = function(event) { + if (Object.isUndefined(event.eventName)) + return false; + + if (event.eventName !== eventName) + return false; + + Event.extend(event, element); + handler.call(element, event); + }; + } else { + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED && + (eventName === "mouseenter" || eventName === "mouseleave")) { + if (eventName === "mouseenter" || eventName === "mouseleave") { + responder = function(event) { + Event.extend(event, element); + + var parent = event.relatedTarget; + while (parent && parent !== element) { + try { parent = parent.parentNode; } + catch(e) { parent = element; } + } + + if (parent === element) return; + + handler.call(element, event); + }; + } + } else { + responder = function(event) { + Event.extend(event, element); + handler.call(element, event); + }; + } + } + + responder.handler = handler; + respondersForEvent.push(responder); + return responder; + } + + function _destroyCache() { + for (var i = 0, length = CACHE.length; i < length; i++) { + Event.stopObserving(CACHE[i]); + CACHE[i] = null; + } + } + + var CACHE = []; + + if (Prototype.Browser.IE) + window.attachEvent('onunload', _destroyCache); + + if (Prototype.Browser.WebKit) + window.addEventListener('unload', Prototype.emptyFunction, false); + + + var _getDOMEventName = Prototype.K, + translations = { mouseenter: "mouseover", mouseleave: "mouseout" }; + + if (!MOUSEENTER_MOUSELEAVE_EVENTS_SUPPORTED) { + _getDOMEventName = function(eventName) { + return (translations[eventName] || eventName); + }; + } + + function observe(element, eventName, handler) { + element = $(element); + + var responder = _createResponder(element, eventName, handler); + + if (!responder) return element; + + if (eventName.include(':')) { + if (element.addEventListener) + element.addEventListener("dataavailable", responder, false); + else { + element.attachEvent("ondataavailable", responder); + element.attachEvent("onfilterchange", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + + if (element.addEventListener) + element.addEventListener(actualEventName, responder, false); + else + element.attachEvent("on" + actualEventName, responder); + } + + return element; + } + + function stopObserving(element, eventName, handler) { + element = $(element); + + var registry = Element.retrieve(element, 'prototype_event_registry'); + if (!registry) return element; + + if (!eventName) { + registry.each( function(pair) { + var eventName = pair.key; + stopObserving(element, eventName); + }); + return element; + } + + var responders = registry.get(eventName); + if (!responders) return element; + + if (!handler) { + responders.each(function(r) { + stopObserving(element, eventName, r.handler); + }); + return element; + } + + var responder = responders.find( function(r) { return r.handler === handler; }); + if (!responder) return element; + + if (eventName.include(':')) { + if (element.removeEventListener) + element.removeEventListener("dataavailable", responder, false); + else { + element.detachEvent("ondataavailable", responder); + element.detachEvent("onfilterchange", responder); + } + } else { + var actualEventName = _getDOMEventName(eventName); + if (element.removeEventListener) + element.removeEventListener(actualEventName, responder, false); + else + element.detachEvent('on' + actualEventName, responder); + } + + registry.set(eventName, responders.without(responder)); + + return element; + } + + function fire(element, eventName, memo, bubble) { + element = $(element); + + if (Object.isUndefined(bubble)) + bubble = true; + + if (element == document && document.createEvent && !element.dispatchEvent) + element = document.documentElement; + + var event; + if (document.createEvent) { + event = document.createEvent('HTMLEvents'); + event.initEvent('dataavailable', true, true); + } else { + event = document.createEventObject(); + event.eventType = bubble ? 'ondataavailable' : 'onfilterchange'; + } + + event.eventName = eventName; + event.memo = memo || { }; + + if (document.createEvent) + element.dispatchEvent(event); + else + element.fireEvent(event.eventType, event); + + return Event.extend(event); + } + + Event.Handler = Class.create({ + initialize: function(element, eventName, selector, callback) { + this.element = $(element); + this.eventName = eventName; + this.selector = selector; + this.callback = callback; + this.handler = this.handleEvent.bind(this); + }, + + start: function() { + Event.observe(this.element, this.eventName, this.handler); + return this; + }, + + stop: function() { + Event.stopObserving(this.element, this.eventName, this.handler); + return this; + }, + + handleEvent: function(event) { + var element = event.findElement(this.selector); + if (element) this.callback.call(this.element, event, element); + } + }); + + function on(element, eventName, selector, callback) { + element = $(element); + if (Object.isFunction(selector) && Object.isUndefined(callback)) { + callback = selector, selector = null; + } + + return new Event.Handler(element, eventName, selector, callback).start(); + } + + Object.extend(Event, Event.Methods); + + Object.extend(Event, { + fire: fire, + observe: observe, + stopObserving: stopObserving, + on: on + }); + + Element.addMethods({ + fire: fire, + + observe: observe, + + stopObserving: stopObserving, + + on: on + }); + + Object.extend(document, { + fire: fire.methodize(), + + observe: observe.methodize(), + + stopObserving: stopObserving.methodize(), + + on: on.methodize(), + + loaded: false + }); + + if (window.Event) Object.extend(window.Event, Event); + else window.Event = Event; +})(); + +(function() { + /* Support for the DOMContentLoaded event is based on work by Dan Webb, + Matthias Miller, Dean Edwards, John Resig, and Diego Perini. */ + + var timer; + + function fireContentLoadedEvent() { + if (document.loaded) return; + if (timer) window.clearTimeout(timer); + document.loaded = true; + document.fire('dom:loaded'); + } + + function checkReadyState() { + if (document.readyState === 'complete') { + document.stopObserving('readystatechange', checkReadyState); + fireContentLoadedEvent(); + } + } + + function pollDoScroll() { + try { document.documentElement.doScroll('left'); } + catch(e) { + timer = pollDoScroll.defer(); + return; + } + fireContentLoadedEvent(); + } + + if (document.addEventListener) { + document.addEventListener('DOMContentLoaded', fireContentLoadedEvent, false); + } else { + document.observe('readystatechange', checkReadyState); + if (window == top) + timer = pollDoScroll.defer(); + } + + Event.observe(window, 'load', fireContentLoadedEvent); +})(); + +Element.addMethods(); + +/*------------------------------- DEPRECATED -------------------------------*/ + +Hash.toQueryString = Object.toQueryString; + +var Toggle = { display: Element.toggle }; + +Element.Methods.childOf = Element.Methods.descendantOf; + +var Insertion = { + Before: function(element, content) { + return Element.insert(element, {before:content}); + }, + + Top: function(element, content) { + return Element.insert(element, {top:content}); + }, + + Bottom: function(element, content) { + return Element.insert(element, {bottom:content}); + }, + + After: function(element, content) { + return Element.insert(element, {after:content}); + } +}; + +var $continue = new Error('"throw $continue" is deprecated, use "return" instead'); + +var Position = { + includeScrollOffsets: false, + + prepare: function() { + this.deltaX = window.pageXOffset + || document.documentElement.scrollLeft + || document.body.scrollLeft + || 0; + this.deltaY = window.pageYOffset + || document.documentElement.scrollTop + || document.body.scrollTop + || 0; + }, + + within: function(element, x, y) { + if (this.includeScrollOffsets) + return this.withinIncludingScrolloffsets(element, x, y); + this.xcomp = x; + this.ycomp = y; + this.offset = Element.cumulativeOffset(element); + + return (y >= this.offset[1] && + y < this.offset[1] + element.offsetHeight && + x >= this.offset[0] && + x < this.offset[0] + element.offsetWidth); + }, + + withinIncludingScrolloffsets: function(element, x, y) { + var offsetcache = Element.cumulativeScrollOffset(element); + + this.xcomp = x + offsetcache[0] - this.deltaX; + this.ycomp = y + offsetcache[1] - this.deltaY; + this.offset = Element.cumulativeOffset(element); + + return (this.ycomp >= this.offset[1] && + this.ycomp < this.offset[1] + element.offsetHeight && + this.xcomp >= this.offset[0] && + this.xcomp < this.offset[0] + element.offsetWidth); + }, + + overlap: function(mode, element) { + if (!mode) return 0; + if (mode == 'vertical') + return ((this.offset[1] + element.offsetHeight) - this.ycomp) / + element.offsetHeight; + if (mode == 'horizontal') + return ((this.offset[0] + element.offsetWidth) - this.xcomp) / + element.offsetWidth; + }, + + + cumulativeOffset: Element.Methods.cumulativeOffset, + + positionedOffset: Element.Methods.positionedOffset, + + absolutize: function(element) { + Position.prepare(); + return Element.absolutize(element); + }, + + relativize: function(element) { + Position.prepare(); + return Element.relativize(element); + }, + + realOffset: Element.Methods.cumulativeScrollOffset, + + offsetParent: Element.Methods.getOffsetParent, + + page: Element.Methods.viewportOffset, + + clone: function(source, target, options) { + options = options || { }; + return Element.clonePosition(target, source, options); + } +}; + +/*--------------------------------------------------------------------------*/ + +if (!document.getElementsByClassName) document.getElementsByClassName = function(instanceMethods){ + function iter(name) { + return name.blank() ? null : "[contains(concat(' ', @class, ' '), ' " + name + " ')]"; + } + + instanceMethods.getElementsByClassName = Prototype.BrowserFeatures.XPath ? + function(element, className) { + className = className.toString().strip(); + var cond = /\s/.test(className) ? $w(className).map(iter).join('') : iter(className); + return cond ? document._getElementsByXPath('.//*' + cond, element) : []; + } : function(element, className) { + className = className.toString().strip(); + var elements = [], classNames = (/\s/.test(className) ? $w(className) : null); + if (!classNames && !className) return elements; + + var nodes = $(element).getElementsByTagName('*'); + className = ' ' + className + ' '; + + for (var i = 0, child, cn; child = nodes[i]; i++) { + if (child.className && (cn = ' ' + child.className + ' ') && (cn.include(className) || + (classNames && classNames.all(function(name) { + return !name.toString().blank() && cn.include(' ' + name + ' '); + })))) + elements.push(Element.extend(child)); + } + return elements; + }; + + return function(className, parentElement) { + return $(parentElement || document.body).getElementsByClassName(className); + }; +}(Element.Methods); + +/*--------------------------------------------------------------------------*/ + +Element.ClassNames = Class.create(); +Element.ClassNames.prototype = { + initialize: function(element) { + this.element = $(element); + }, + + _each: function(iterator) { + this.element.className.split(/\s+/).select(function(name) { + return name.length > 0; + })._each(iterator); + }, + + set: function(className) { + this.element.className = className; + }, + + add: function(classNameToAdd) { + if (this.include(classNameToAdd)) return; + this.set($A(this).concat(classNameToAdd).join(' ')); + }, + + remove: function(classNameToRemove) { + if (!this.include(classNameToRemove)) return; + this.set($A(this).without(classNameToRemove).join(' ')); + }, + + toString: function() { + return $A(this).join(' '); + } +}; + +Object.extend(Element.ClassNames.prototype, Enumerable); + +/*--------------------------------------------------------------------------*/ + +(function() { + window.Selector = Class.create({ + initialize: function(expression) { + this.expression = expression.strip(); + }, + + findElements: function(rootElement) { + return Prototype.Selector.select(this.expression, rootElement); + }, + + match: function(element) { + return Prototype.Selector.match(element, this.expression); + }, + + toString: function() { + return this.expression; + }, + + inspect: function() { + return "#"; + } + }); + + Object.extend(Selector, { + matchElements: function(elements, expression) { + var match = Prototype.Selector.match, + results = []; + + for (var i = 0, length = elements.length; i < length; i++) { + var element = elements[i]; + if (match(element, expression)) { + results.push(Element.extend(element)); + } + } + return results; + }, + + findElement: function(elements, expression, index) { + index = index || 0; + var matchIndex = 0, element; + for (var i = 0, length = elements.length; i < length; i++) { + element = elements[i]; + if (Prototype.Selector.match(element, expression) && index === matchIndex++) { + return Element.extend(element); + } + } + }, + + findChildElements: function(element, expressions) { + var selector = expressions.toArray().join(', '); + return Prototype.Selector.select(selector, element || document); + } + }); +})(); diff --git a/public/javascripts/rails.js b/public/javascripts/rails.js new file mode 100644 index 0000000..aed6aed --- /dev/null +++ b/public/javascripts/rails.js @@ -0,0 +1,191 @@ +(function() { + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + function isEventSupported(eventName) { + var el = document.createElement('div'); + eventName = 'on' + eventName; + var isSupported = (eventName in el); + if (!isSupported) { + el.setAttribute(eventName, 'return;'); + isSupported = typeof el[eventName] == 'function'; + } + el = null; + return isSupported; + } + + function isForm(element) { + return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM' + } + + function isInput(element) { + if (Object.isElement(element)) { + var name = element.nodeName.toUpperCase() + return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA' + } + else return false + } + + var submitBubbles = isEventSupported('submit'), + changeBubbles = isEventSupported('change') + + if (!submitBubbles || !changeBubbles) { + // augment the Event.Handler class to observe custom events when needed + Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap( + function(init, element, eventName, selector, callback) { + init(element, eventName, selector, callback) + // is the handler being attached to an element that doesn't support this event? + if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) || + (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) { + // "submit" => "emulated:submit" + this.eventName = 'emulated:' + this.eventName + } + } + ) + } + + if (!submitBubbles) { + // discover forms on the page by observing focus events which always bubble + document.on('focusin', 'form', function(focusEvent, form) { + // special handler for the real "submit" event (one-time operation) + if (!form.retrieve('emulated:submit')) { + form.on('submit', function(submitEvent) { + var emulated = form.fire('emulated:submit', submitEvent, true) + // if custom event received preventDefault, cancel the real one too + if (emulated.returnValue === false) submitEvent.preventDefault() + }) + form.store('emulated:submit', true) + } + }) + } + + if (!changeBubbles) { + // discover form inputs on the page + document.on('focusin', 'input, select, texarea', function(focusEvent, input) { + // special handler for real "change" events + if (!input.retrieve('emulated:change')) { + input.on('change', function(changeEvent) { + input.fire('emulated:change', changeEvent, true) + }) + input.store('emulated:change', true) + } + }) + } + + function handleRemote(element) { + var method, url, params; + + var event = element.fire("ajax:before"); + if (event.stopped) return false; + + if (element.tagName.toLowerCase() === 'form') { + method = element.readAttribute('method') || 'post'; + url = element.readAttribute('action'); + params = element.serialize(); + } else { + method = element.readAttribute('data-method') || 'get'; + url = element.readAttribute('href'); + params = {}; + } + + new Ajax.Request(url, { + method: method, + parameters: params, + evalScripts: true, + + onComplete: function(request) { element.fire("ajax:complete", request); }, + onSuccess: function(request) { element.fire("ajax:success", request); }, + onFailure: function(request) { element.fire("ajax:failure", request); } + }); + + element.fire("ajax:after"); + } + + function handleMethod(element) { + var method = element.readAttribute('data-method'), + url = element.readAttribute('href'), + csrf_param = $$('meta[name=csrf-param]')[0], + csrf_token = $$('meta[name=csrf-token]')[0]; + + var form = new Element('form', { method: "POST", action: url, style: "display: none;" }); + element.parentNode.insert(form); + + if (method !== 'post') { + var field = new Element('input', { type: 'hidden', name: '_method', value: method }); + form.insert(field); + } + + if (csrf_param) { + var param = csrf_param.readAttribute('content'), + token = csrf_token.readAttribute('content'), + field = new Element('input', { type: 'hidden', name: param, value: token }); + form.insert(field); + } + + form.submit(); + } + + + document.on("click", "*[data-confirm]", function(event, element) { + var message = element.readAttribute('data-confirm'); + if (!confirm(message)) event.stop(); + }); + + document.on("click", "a[data-remote]", function(event, element) { + if (event.stopped) return; + handleRemote(element); + event.stop(); + }); + + document.on("click", "a[data-method]", function(event, element) { + if (event.stopped) return; + handleMethod(element); + event.stop(); + }); + + document.on("submit", function(event) { + var element = event.findElement(), + message = element.readAttribute('data-confirm'); + if (message && !confirm(message)) { + event.stop(); + return false; + } + + var inputs = element.select("input[type=submit][data-disable-with]"); + inputs.each(function(input) { + input.disabled = true; + input.writeAttribute('data-original-value', input.value); + input.value = input.readAttribute('data-disable-with'); + }); + + var element = event.findElement("form[data-remote]"); + if (element) { + handleRemote(element); + event.stop(); + } + }); + + document.on("ajax:after", "form", function(event, element) { + var inputs = element.select("input[type=submit][disabled=true][data-disable-with]"); + inputs.each(function(input) { + input.value = input.readAttribute('data-original-value'); + input.removeAttribute('data-original-value'); + input.disabled = false; + }); + }); + + Ajax.Responders.register({ + onCreate: function(request) { + var csrf_meta_tag = $$('meta[name=csrf-token]')[0]; + + if (csrf_meta_tag) { + var header = 'X-CSRF-Token', + token = csrf_meta_tag.readAttribute('content'); + + if (!request.options.requestHeaders) { + request.options.requestHeaders = {}; + } + request.options.requestHeaders[header] = token; + } + } + }); +})(); diff --git a/public/robots.txt b/public/robots.txt index 0640f8a..085187f 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -1,2 +1,5 @@ -User-agent: * -Disallow: /trac/ \ No newline at end of file +# See http://www.robotstxt.org/wc/norobots.html for documentation on how to use the robots.txt file +# +# To ban all spiders from the entire site uncomment the next two lines: +# User-Agent: * +# Disallow: / diff --git a/public/static/.gitignore b/public/static/.gitignore deleted file mode 100644 index 16633ff..0000000 --- a/public/static/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Don't add the images, just takes up space and they are there regardless. -*.jpg -*.png diff --git a/public/static/ARC_UNSW_logo.png b/public/static/ARC_UNSW_logo.png deleted file mode 100644 index 24e7ae3..0000000 Binary files a/public/static/ARC_UNSW_logo.png and /dev/null differ diff --git a/public/static/CSE_UNSW_logo.jpg b/public/static/CSE_UNSW_logo.jpg deleted file mode 100644 index 2e873d7..0000000 Binary files a/public/static/CSE_UNSW_logo.jpg and /dev/null differ diff --git a/public/static/CSE_UNSW_logo_small.jpg b/public/static/CSE_UNSW_logo_small.jpg deleted file mode 100644 index f2c7e94..0000000 Binary files a/public/static/CSE_UNSW_logo_small.jpg and /dev/null differ diff --git a/public/static/ENG_UNSW_logo_small.png b/public/static/ENG_UNSW_logo_small.png deleted file mode 100644 index d1d9055..0000000 Binary files a/public/static/ENG_UNSW_logo_small.png and /dev/null differ diff --git a/public/static/SponsorshipProposal2012.pdf b/public/static/SponsorshipProposal2012.pdf deleted file mode 100755 index ebff94e..0000000 Binary files a/public/static/SponsorshipProposal2012.pdf and /dev/null differ diff --git a/public/static/admin b/public/static/admin deleted file mode 120000 index 9b8456e..0000000 --- a/public/static/admin +++ /dev/null @@ -1 +0,0 @@ -/home/www/virtualenv/lib/python2.6/site-packages/django/contrib/admin/media \ No newline at end of file diff --git a/public/static/calendar/restylegc-1.1.0/archive/2084c397356eced98f5f2893e7a07f39embedcompiled.css b/public/static/calendar/restylegc-1.1.0/archive/2084c397356eced98f5f2893e7a07f39embedcompiled.css deleted file mode 100644 index 5bd5ed9..0000000 --- a/public/static/calendar/restylegc-1.1.0/archive/2084c397356eced98f5f2893e7a07f39embedcompiled.css +++ /dev/null @@ -1,1524 +0,0 @@ -/* Copyright 2009 Google Inc. All Rights Reserved. */ -html>body .goog-inline-block { - display:-moz-inline-box; - display:inline-block; -} - -.goog-inline-block { - position:relative; - display:inline-block; -} - -* html .goog-inline-block { - display:inline; -} - -*:first-child+html .goog-inline-block { - display:inline; -} - -.t1 { - font-size:1px; - height:1px; - line-height:1px; - margin:0 2px; - overflow:hidden; -} - -.t2 { - font-size:1px; - height:1px; - line-height:1px; - margin:0 1px; - overflow:hidden; -} - -.calendar-list input { - display:inline; - padding:0; - margin-bottom:1px; -} - -.calendar-list span { - color:#0f0; - font-weight:bold; -} - -.calendar-list label { - cursor:pointer; -} - -.chip { - position:absolute; - overflow:hidden; - cursor:default; - color:#fff; - -moz-user-select:none; -} - -.chip dl { - margin:0; - padding-bottom:1px; - border-left:1px solid; - border-right:1px solid; - overflow:hidden; -} - -.chip dt { - margin-top:-1px; - font:bold 80%/normal Verdana, sans-serif; - white-space:nowrap; - overflow:hidden; - padding-left:1px; - text-align:left; -} - -.ie6 .chip dl { - zoom:1; -} - -.ie6 .chip dt { - width:100%; - margin-right:-1px; -} - -.chip dd { - margin:0; - overflow:hidden; - padding:0 1px; - font:100%/1.3em Verdana, sans-serif; - text-align:left; - word-wrap:break-word; -} - -.cbrd { - border:1px solid; - -moz-border-radius:3px; - -webkit-border-radius:3px; -} - -.cbrd dt { - margin-top:0; -} - -.ct { - height:0; - overflow:hidden; - border-style:solid dotted; - border-width:0 2px 2px; - border-color:transparent; -} - -.cb1, .cb2 { - border-style:solid; - overflow:hidden; -} - -.cb1 { - height:1px; - margin:0 1px; - border-width:0 1px; -} - -.cb2 { - height:0; - margin:0 2px; - border-width:0 0 1px; -} - -.cro dl { - padding-left:1px; -} - -.cro dt { - margin-top:1px; -} - -.chip a:link, .chip a:visited, .chip a:active { - text-decoration:none; - color:#fff; -} - -.cic { - background-repeat:no-repeat; - display:inline-block; - margin-left:2px; - width:9px; - height:7px; - line-height:7px; - background-image:url(//calendar.google.com/googlecalendar/images/combined_v9.gif); -} - -.ff2 .cic { - display:-moz-inline-box; - vertical-align:bottom; - position:relative; - top:-2px; -} - -.cic-ques { - margin-left:0; - margin-right:2px; - width:9px; - height:9px; - line-height:9px; - background-position:-56px -50px; -} - -.cic-prsn { - background-position:-28px -50px; -} - -.cic-noprs { - background-position:-46px -50px; -} - -.cic-tmr { - background-position:-28px -57px; -} - -.cic-rcr { - background-position:-37px -50px; -} - -.cic-spcl { - background-position:-37px -57px; -} - -.cic-priv { - background-position:-11px -64px; -} - -.chip .location { - display:block; - font-style:normal; -} - -.resizer { - position:absolute; - height:7px; - line-height:7px; - width:100%; - bottom:0; - cursor:ns-resize; - *cursor:s-resize; -} - -.rszr_icon { - border-top:3px double white; - font-size:0; - line-height:0; - height:0; - width:10px; - margin-left:auto; - margin-right:auto; -} - -.cwci { - height:16px; - width:16px; - margin:-1px 0; - vertical-align:top; -} - -.calendar-container { - margin:0; - padding:0; - font-size-adjust:none; - position:relative; -} - -.view-cap, .view-container-border { - background-color:#c3d9ff; -} - -.view-container { - overflow:hidden; - position:relative; -} - -.view-container-border { - padding:0 8px; - position:relative; - zoom:1; -} - -.loading { - background-color:#cc4444; - color:white; - padding:2px; - position:absolute; - top:0; - right:2px; - z-index:25000001; - display:none; - white-space:nowrap; -} - -.detail-item { - padding:0; - margin:0; -} - -.event-details-label { - display:block; - clear:left; - float:left; - font-size:100%; - font-weight:bold; - padding:3px 0; - margin:0; - width:7.0em; - color:#4e4e4e; -} - -.event-when, .event-where, .event-description, .event-who, .event-going { - display:block; - margin-left:7em; - padding:3px 0; -} - -.detail-content { - padding:1em 0; -} - -.bubble .details .title { - font-weight:bold; - font-size:medium; -} - -.bubble .detail-content { - padding-bottom:0; -} - -.bubble .separator { - height:1px; - line-height:0; - font-size:0; - width:100%; - margin-top:10px; - margin-bottom:5px; -} - -* html .event-detail-item { - margin-right:-3px; -} - -* html .event-when, * html .event-where, * html .event-description, * html .event-who, * html .event-going { - height:1%; - margin:0; -} - -.cc { - position:absolute; - font:11px/normal Arial, sans-serif; - border:1px solid gray; - background-color:white; - visibility:hidden; -} - -.cc-titlebar { - background-color:#e8eef7; -} - -.cc-close { - margin:2px 2px 0 0; - position:absolute; - right:0; - cursor:pointer; - width:14px; - height:13px; - background:url(//calendar.google.com/googlecalendar/images/combined_v9.gif) 0 -50px; -} - -.cc-title { - padding:2px; - font-weight:bold; -} - -.wc-root { - border:0 none; - width:100%; - height:100%; -} - -.calendar-container { - font-family:Arial, sans-serif; - font-size:small; -} - -.footer { - padding:4px 0 2px 0; - font-size:85%; - text-decoration:none; -} - -.subscribe-image { - cursor:pointer; -} - -.menu-arrow { - vertical-align:bottom; - cursor:pointer; -} - -.header { - padding:0 2px; -} - -.header img { - border:0 none; - vertical-align:middle; -} - -.nav-table { - white-space:nowrap; - cursor:pointer; -} - -.nav-table tr { - padding:0; - margin:0; -} - -.nav-table td { - vertical-align:middle; -} - -.navSpacer { - width:100%; - cursor:default; -} - -.legend-bullet { - margin:0.2em; - border:0.05em solid grey; - padding:0; - vertical-align:text-bottom; - width:0.9em; - height:0.9em; - overflow:hidden; -} - -.date-buttons img { - vertical-align:middle; -} - -.arrowImg { - margin-left:5px; - margin-right:5px; -} - -.date-picker-on { - border:1px solid #808080; -} - -.date-picker-off { - padding:1px; -} - -.date-picker-arrow-on { - background-color:#c3d9ff; -} - -.date-top, .date-top-on, .date-top-over { - font-weight:bold; - padding-top:1px; - padding-left:.3em; - padding-right:.3em; - white-space:nowrap; -} - -.date-top-over { - text-decoration:underline; -} - -.cal-menu { - position:absolute; - left:11px; - top:37px; - z-index:100001; - border:1px solid #808080; -} - -.calendar-list { - font-family:Arial, sans-serif; - padding:2px; - font-size:9pt; - border:1px solid gray; - background-color:white; - width:14em; -} - -.calendar-nav img { - width:15px; - height:14px; -} - -.calendar-list .subscribeButton { - width:100%; - margin:2px 0 0; -} - -.calendar-list img { - cursor:pointer; - margin-left:3px; -} - -.today-button { - font-size:85%; - padding:0 1px; - vertical-align:middle; -} - -.navbutton { - cursor:pointer; - border:0 none; - height:17px; - padding:0 2px; - vertical-align:middle; - width:29px; -} - -.navBack { - background-position:-148px -17px; - background-image:url(//calendar.google.com/googlecalendar/images/combined_v9.gif); -} - -.navForward { - background-position:-148px 0; - background-image:url(//calendar.google.com/googlecalendar/images/combined_v9.gif); -} - -.rtl .navBack { - background-position:-148px 0; -} - -.rtl .navForward { - background-position:-148px -17px; -} - -.view-tab { - vertical-align:bottom; - padding-left:4px; -} - -.view-tab-unselected { - background-color:#e8eef7; - color:#20c; - cursor:pointer; -} - -.view-tab-selected { - background-color:#c3d9ff; - font-weight:bold; -} - -.tab-name { - padding:4px 5px 3px; - white-space:nowrap; -} - -.tab-spacer { - width:3px; - cursor:default; -} - -.link-tab-selected, .link-tab-unselected { - cursor:pointer; - padding:0 3px; -} - -.link-tab-selected { - color:#000; - font-weight:bold; -} - -.link-tab-unselected { - font-weight:normal; - color:#20c; - text-decoration:underline; -} - -.link-tab-unselected:hover { - color:#cc0000; -} - -.bubble { - position:absolute; - visibility:hidden; - left:0; - top:0; - font-size:9pt; -} - -.bubble-table { - table-layout:fixed; - width:100%; -} - -.bubble-cell-side { - width:25px; -} - -.bubble-cell-main { - width:100%; -} - -.bubble-sprite { - width:148px; - height:96px; - position:absolute; - background-image:url(//calendar.google.com/googlecalendar/images/bubble_combined.png); -} - -.ie6 .bubble-sprite { - background:transparent; - filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(sizingMethod="crop", src="//calendar.google.com/googlecalendar/images/bubble_combined.png"); -} - -.bubble-corner { - width:25px; - height:25px; - position:relative; - overflow:hidden; -} - -.bubble-tl { - left:0; -} - -.bubble-tr { - left:-25px; -} - -.bubble-bl { - left:0; - top:-25px; -} - -.bubble-br { - left:-25px; - top:-25px; -} - -.bubble-closebutton { - right:10px; - top:10px; - width:14px; - height:13px; - cursor:pointer; - position:absolute; - background:url(//calendar.google.com/googlecalendar/images/combined_v9.gif) 0 -50px; -} - -.bubble-top, .bubble-bottom { - height:24px; - background:#fff; -} - -.bubble-top { - border-top:1px solid #ababab; -} - -.bubble-bottom { - border-bottom:1px solid #ababab; -} - -.bubble-mid { - background:#fff; - border-left:1px solid #ababab; - border-right:1px solid #ababab; - padding:0 20px; -} - -.prong { - width:98px; - height:72px; - margin-bottom:-72px; - position:relative; - top:-1px; - overflow:hidden; -} - -.prong .bubble-sprite { - left:-50px; - top:-24px; -} - -.te { - padding:1px; - overflow:hidden; - white-space:nowrap; - zoom:1; -} - -.te-t { - font-size:91%; - font-family:Arial, sans-serif; - font-weight:bold; - white-space:nowrap; - line-height:1.2; - vertical-align:bottom; -} - -.te-rev { - width:100%; -} - -.te-rev-s { - width:100%; - white-space:nowrap; - vertical-align:bottom; -} - -.te-rev-spos { - position:relative; - zoom:1; -} - -.te-rev-scont { - text-align:left; - position:absolute; - left:0; - width:100%; - top:0; - overflow:hidden; -} - -.rb-n { - padding:1px 1px 1px 3px; - overflow:hidden; - white-space:nowrap; - color:white; - -webkit-border-radius:3px; - -moz-border-radius:3px; -} - -.rb-o { - margin:0 1px; - border-width:1px 0; - border-style:solid; -} - -.rb-m { - padding-left:3px; - margin:0 -1px; - border-width:0 1px; - border-style:solid; - zoom:1; -} - -.rb-i { - overflow:hidden; - color:white; - white-space:nowrap; - width:100%; -} - -.st-bg-table { - position:absolute; - top:0; - left:0; - height:100%; - width:100%; - table-layout:fixed; -} - -.st-bg { - border-left:1px solid #c3d9ff; -} - -.st-bg-today { - background-color:#ffc; -} - -.bg-exists .st-bg-today { - background-color:#eee; - border:1px solid #579; - opacity:0.8; -} - -.st-grid { - position:relative; - table-layout:fixed; - width:100%; -} - -.st-c { - padding:1px 1px 0 2px; - vertical-align:top; - font-family:Verdana, sans-serif; - cursor:pointer; -} - -.st-s { - padding-bottom:2px; - cursor:default; -} - -.st-dtitle { - border-left:1px solid #c3d9ff; - border-top:1px solid #c3d9ff; - background-color:#e8eef7; - color:#444; - padding-right:2px; - text-align:right; - line-height:16px; - overflow:hidden; -} - -.bg-exists .st-dtitle { - opacity:0.8; - filter:alpha(opacity=80); -} - -.st-dtitle-nonmonth { - background-color:#eee; - color:#888; -} - -.st-dtitle-today { - background-color:#bcd; -} - -.st-wc { - vertical-align:bottom; - float:left; - height:16px; - width:16px; - padding:0; -} - -.st-wc-click { - cursor:pointer; -} - -.st-c .te { - cursor:pointer; -} - -.bg-exists .te { - background-color:white; - padding-left:2px; - -moz-border-radius:3px; - -webkit-border-radius:3px; -} - -.st-ad-ml, .st-ad-mr { - position:relative; - top:2px; - margin-bottom:-8px; - height:0; - width:0; - line-height:0; - font-size:0; - border-top:4px dotted transparent; - border-bottom:4px dotted transparent; -} - -.st-ad-mpad { - padding-left:10px; -} - -.st-ad-ml { - border-right:4px solid white; - margin-left:-7px; - margin-right:auto; -} - -.st-ad-mr { - border-left:4px solid white; - margin-left:auto; - margin-right:3px; -} - -.st-more { - color:#20c; - text-align:center; - cursor:pointer; - font-family:Arial, sans-serif; -} - -.st-moreul { - text-decoration:underline; -} - -.st-moreicon { - background-color:#d0d6de; - color:#627487; - margin:1px; - padding-right:5px; - text-align:right; - font-size:85%; -} - -.drag-lasso-container { - position:absolute; - left:0; - top:0; - width:0; - height:0; -} - -.drag-lasso { - font-size:0; - line-height:0; - position:absolute; - background-color:#c3d9ff; - opacity:0.5; - -khtml-opacity:0.5; - filter:alpha(opacity=50); -} - -.drag-event { - font-family:Verdana, sans-serif; - z-index:1000; - position:absolute; - cursor:pointer; -} - -.drag-chip-wrapper { - z-index:1; - position:absolute; - left:0; - width:100%; -} - -.drag-chip { - cursor:pointer; - opacity:.8; - -khtml-opacity:.8; - filter:alpha(opacity=80); -} - -.agenda { - background:white; -} - -.agenda-padding { - font-size:1px; - line-height:1px; - height:6px; -} - -.agenda .scrollbox { - overflow:auto; - overflow-x:hidden; - overflow-y:auto; - border-top:1px solid #a2bbdd; - border-left:1px solid #a2bbdd; - border-bottom:1px solid #fff; - background-color:white; - margin-top:6px; -} - -.agenda-scrollboxBoundary { - background-color:#c3d9ff; -} - -.agenda .event { - clear:both; - cursor:pointer; - border-top:1px solid #cde; - margin:0; -} - -.agenda .day { - border-bottom:1px solid #cde; -} - -.agenda .event-summary, .agenda .event-summary-expanded { - white-space:nowrap; -} - -.agenda .event-details { - display:block; - float:none; - clear:both; - cursor:default; - padding:0; -} - -.agenda .event-details-inner { - padding:0 0 .3em 0; -} - -.agenda .event-details, .agenda .event-summary, .agenda .event-summary-expanded { - margin:.3em 1em; -} - -.agenda .add-icon { - float:right; - padding-left:1em; - display:block; -} - -.agenda .event-time { - display:block; - width:2.5em; - margin:0; - padding:0; - float:left; -} - -.agenda .all-day .event-time { - display:none; -} - -.agenda .event-title { - display:block; - clear:none; - white-space:nowrap; - margin:0; - overflow:hidden; -} - -.agenda .title-wrapper { - margin:0 0 0 2.5em; - display:block; - padding:0; -} - -.agenda .all-day .title-wrapper { - margin-left:0; -} - -.agenda .event-reply-status { - display:block; - margin:0; - width:2em; - float:left; - border:0; - padding:0; -} - -.agenda .event-reply-status img { - border:0; -} - -.agenda .all-day .event-reply-status { - width:0; -} - -.agenda .event-summary-expanded { - font-weight:bold; -} - -.agenda .attendee-no { - color:gray; -} - -.agenda .attendee-maybe { - color:gray; -} - -.agenda .attendee-yes { - color:black; -} - -.agenda .date-label { - font-weight:bold; - background:#e5ecf9; - position:relative; -} - -.agenda .date-label, .agenda .underflow-bot, .agenda .underflow-top { - padding:0.2em 1em; -} - -.agenda .underflow-top { - border-bottom:1px solid #cde; -} - -img.agenda-web-content { - cursor:pointer; - height:16px; - width:16px; - border:0 none; - vertical-align:top; -} - -.agenda-wc { - margin-bottom:-3px; -} - -.agenda-more { - color:#20c; - cursor:pointer; - text-decoration:underline; - white-space:nowrap; -} - -.agenda .underflow-bot, .agenda .underflow-top { - color:#666; - font-style:italic; -} - -.ie6 .agenda .event-time { - margin-right:-3px; -} - -.ie6 .agenda .event-title { - height:1%; - margin:0; - overflow:inherit; - overflow-x:hidden; - overflow-y:visible; -} - -.agenda .event-links { - margin-left:7em; -} - -.wk-table { - margin:0; - padding:0; -} - -.wk-weektop { - table-layout:fixed; - width:100%; - background-color:#c3d9ff; - overflow:hidden; - font-size:11px; - line-height:14px; -} - -.wk-dayname { - font-weight:normal; - color:#20c; - padding:2px 4px; - margin-left:4px; - white-space:nowrap; -} - -.wk-today { - color:#fff; - font-weight:bold; - background-color:#8ac; - padding:1px 3px; - border-top:1px solid #6786a7; - border-left:1px solid #6786a7; - border-bottom:1px solid #ace; - border-right:1px solid #ace; -} - -.wk-dummyth { - vertical-align:top; - background-color:#c3d9ff; - padding:0; -} - -.wk-allday { - background-color:#e8eef7; - font-size:11px; - line-height:14px; - border-color:#a2bbdd #fff #fff #a2bbdd; - border-style:solid; - border-width:1px; -} - -.wk-allday .st-c { - padding-left:0; - padding-right:0; - border-left:3px double #ddd; -} - -.wk-webcontent-td { - font-size:0; - padding-left:2px; - height:5px; -} - -.wk-scrolltimedevents { - position:relative; - overflow-y:scroll; - overflow-x:hidden; - border-top:1px solid #a2bbdd; - border-left:1px solid #a2bbdd; - border-bottom:1px solid #fff; - padding:0; - font-size:11px; - line-height:normal; -} - -.tg-timedevents { - background-color:#fff; - table-layout:fixed; - width:100%; - margin-top:-1px; -} - -.bg-exists .tg-timedevents { - background:transparent; -} - -.bg-exists .tg-times-pri, .bg-exists .tg-times-sec, .bg-exists .chip { - opacity:0.9; - filter:alpha(opacity=90); -} - -.tg-times-pri, .tg-times-sec { - padding:0; - background-color:#e8eef7; - color:#468; - text-align:right; - vertical-align:top; - padding-right:1px; - padding-top:1px; -} - -.tg-times-sec { - background-color:#e8eef7; - color:#468; -} - -.tg-time-pri, .tg-time-sec { - border-bottom:1px Solid #ddd; - padding-right:2px; -} - -.tg-time-sec { - border-bottom:1px Solid #ddd; -} - -.tg-timesnotlast { - border-right:1px Solid #ddd; -} - -.tg-col { - border-left:3px double #ddd; - vertical-align:top; -} - -.tg-col-overlaywrapper { - position:relative; - height:0; -} - -.tg-col-eventwrapper { - position:relative; - cursor:default; -} - -.tg-today { - background-color:#ffc; -} - -.bg-exists .tg-today { - background-color:#eee; - opacity:0.5; - filter:alpha(opacity=50); -} - -.tg-spanningwrapper { - position:relative; - margin-left:3px; - top:1px; -} - -.tg-chipspanningwrapper { - margin-right:10px; - z-index:1; -} - -.tg-hourmarkers { - position:absolute; - width:100%; -} - -.tg-dualmarker { - border-top:1px solid #ddd; - height:1em; - line-height:1em; - border-bottom:1px dotted #ddd; - margin-bottom:1em; -} - -.tg-nowmarker { - position:absolute; - left:0; - width:100%; - top:0; - height:0; - border-top:2px solid #ff0000; - overflow:hidden; - opacity:0.4; - filter:alpha(opacity=40); -} - -.tg-nowptr { - position:absolute; - background-position:-60px -68px; - width:5px; - height:9px; - background-image:url(//calendar.google.com/googlecalendar/images/combined_v9.gif); -} - -.rtl .tg-nowptr { - background-position:-67px -68px; -} - -.wk-tzlabel { - color:#468; - vertical-align:bottom; - text-align:center; - overflow:hidden; - padding-bottom:2px; -} - -.wk-moreevents { - padding:8px 8px 8px 8px; -} - -.wk-moreevents .st-c { - padding:1px 2px 0 2px; - border:none; -} - -.wk-sideevents { - width:20%; - font-family:Verdana, sans-serif; - vertical-align:top; - padding-top:1px; -} - -.wk-more-prealign { - text-align:right; -} - -.wk-sarr { - float:right; - cursor:pointer; - width:15px; - height:13px; - vertical-align:center; - background:url(//calendar.google.com/googlecalendar/images/combined_v9.gif) no-repeat; -} - -.wk-sarr-no { - visibility:hidden; -} - -.wk-sarr-u { - background-position:-182px 0; -} - -.wk-sarr-d { - background-position:-182px -11px; -} - -.wk-sarr-ud { - background-position:-182px -22px; -} - -.today .wk-sarr-u { - background-position:-199px 0; -} - -.today .wk-sarr-d { - background-position:-199px -11px; -} - -.today .wk-sarr-ud { - background-position:-199px -22px; -} - -.wk-disclose { - position:absolute; - top:2em; -} - -.wk-zip { - cursor:pointer; - width:11px; - height:11px; - overflow:hidden; - background-image:url(//calendar.google.com/googlecalendar/images/combined_v9.gif); - background-position:-37px -64px; -} - -.goog-zippy-collapsed .wk-zip { - background-position:-15px -103px; -} - -.rtl .goog-zippy-collapsed .wk-zip { - background-position:-49px -67px; -} - -.mv-container { - height:100%; - position:relative; - white-space:nowrap; -} - -.bg-exists .mv-container { - background-color:transparent; -} - -.st-contents, .mv-container { - font-size:11px; - line-height:14px; -} - -.mv-daynames-table { - position:absolute; - table-layout:fixed; - top:0; - left:0; - width:100%; - background:#c3d9ff; - color:#20c; -} - -.mv-dayname { - font-weight:normal; -} - -.mv-event-container { - overflow:hidden; - position:absolute; - left:0; - width:100%; - top:14px; - bottom:0; - background:white; -} - -.month-row { - position:absolute; - left:0; - width:100%; - overflow:hidden; -} - -.bg-exists .month-row { - opacity:0.9; - filter:alpha(opacity=90); -} - -.extraevents { - padding:1px 1px 2px 0; -} - -.dp-popup { - position:absolute; - border:1px solid black; - background:#c3d9ff; - font-size:9pt; - line-height:1em; - width:170px; - z-index:25000003; -} - -.dp-dayh { - font-size:78%; -} - -.dp-monthtable { - width:100%; - padding:0; - border-bottom:1px #a2bbdd solid; - -webkit-user-select:none; - -khtml-user-select:none; -} - -.ie .dp-monthtable { - table-layout:fixed; -} - -.dp-cell { - text-align:center; - padding:2px; - font-family:Verdana, sans-serif; - font-size:85%; -} - -.dp-heading { - color:#20c; - font-weight:bold; - vertical-align:middle; -} - -.dp-cur { - font-weight:bold; - padding-bottom:4px; - text-align:center; - white-space:nowrap; - font-size:100%; -} - -.dp-prev, .dp-next { - font-size:100%; - padding-bottom:6px; - cursor:pointer; -} - -.dp-prev { - text-align:right; -} - -.dp-next { - text-align:left; -} - -.dp-weekday { - background:#fff; -} - -.dp-weekday-selected { - background:#ace; -} - -.dp-weekend { - background:#eee; -} - -.dp-weekend-selected { - background:#9bd; -} - -.dp-with-events { - font-weight:bold!important; -} - -.dp-offmonth { - color:#888; -} - -.dp-day-left { - border-left:1px #a2bbdd solid; -} - -.dp-day-right { - border-right:1px #a2bbdd solid; -} - -.dp-dayh { - border-bottom:1px #a2bbdd solid; -} - -.dp-today, .dp-today-selected { - padding:1px; - color:#fff; - border:1px solid; -} - -.dp-today { - background:#9ab; - border-color:#567 #abc #abc #567; -} - -.dp-today-selected { - background:#579; - border-color:#246 #9bd #9bd #246; -} - -.dp-onhover { - background-color:#def; - color:black; -} - - - diff --git a/public/static/calendar/restylegc-1.1.0/archive/2084c397356eced98f5f2893e7a07f39embedcompiled__en.js b/public/static/calendar/restylegc-1.1.0/archive/2084c397356eced98f5f2893e7a07f39embedcompiled__en.js deleted file mode 100644 index a8f730b..0000000 --- a/public/static/calendar/restylegc-1.1.0/archive/2084c397356eced98f5f2893e7a07f39embedcompiled__en.js +++ /dev/null @@ -1,197 +0,0 @@ -function aa(a){throw a;}var i=true,j=null,l=false,ba=encodeURIComponent,n=window,ca=NaN,da=Object,o=parseInt,ea=parseFloat,fa=String,ga=document,ha=decodeURIComponent,p=isNaN,ia=Array,q=Math;function ja(a,b){return a.toString=b}function ka(a,b){return a.length=b}function la(a,b){return a.className=b}function ma(a,b){return a.width=b}function na(a,b){return a.navigate=b}function t(a,b){return a.innerHTML=b}function oa(a,b){return a.currentTarget=b}function pa(a,b){return a.left=b} -function qa(a,b){return a.target=b}function ra(a,b){return a.keyCode=b}function sa(a,b){return a.type=b}function ta(a,b){return a.contains=b}function ua(a,b){return a.display=b}function va(a,b){return a.height=b}function xa(a,b){return a.visibility=b} -var ya="appendChild",za="scrollTop",u="push",Aa="filter",x="toString",z="length",Ba="propertyIsEnumerable",Ca="title",Da="getBoundingClientRect",B="prototype",Ea="test",Fa="className",D="width",Ga="clientWidth",Ha="round",Ia="slice",Ja="setTimeout",E="replace",Ka="navigate",La="nodeType",Ma="document",Na="split",Oa="floor",Pa="getUTCDate",Qa="offsetWidth",Ra="concat",Sa="constructor",Ta="location",F="indexOf",Ua="offsetLeft",Va="hasOwnProperty",Wa="getComputedStyle",G="style",Xa="capture",Ya="body", -I="left",Za="ownerDocument",J="target",$a="screenX",ab="screenY",K="call",bb="match",cb="getBoxObjectFor",L="start",db="createElement",eb="keyCode",fb="firstChild",gb="forEach",hb="clientHeight",ib="scrollLeft",jb="clientLeft",kb="charCodeAt",lb="currentStyle",mb="href",nb="substring",ob="clientTop",pb="handleEvent",M="type",qb="contains",rb="apply",sb="childNodes",tb="tagName",ub="defaultView",vb="navigator",wb="name",xb="parentNode",yb="offsetTop",N="height",zb="offsetHeight",O="join",Ab="toLowerCase", -Bb="clientX",Cb="clientY",Db="documentElement",Eb="substr";function Fb(){return function(){}}function Gb(a){return function(){return this[a]}}var P;n._Messages=[][Ra](n._Messages||[],{SEARCHING_FOR_MORE_MATCHES:"Searching for more matches ...",SEARCHING_FOR_MATCHES:"Searching for matches ...",AND_OTHERS:"And {$count} others..."});function Hb(a){return"Showing events after "+a}function Ib(a){return"Showing events until "+a}function Jb(a){return""+a+" days"} -function Kb(a){return""+a+" hrs"}function Lb(a){return""+a+" mins"}function Mb(a,b){return""+a+" \u2013 "+b}function Nb(a,b){return""+a+" "+b}function Ob(a,b){a=p(a)?"??":""+a;if(a[z]<2)a="0"+a;b=!p(b)?(b<10?"0":"")+b:"??";return""+a+":"+b}function Pb(a,b){var c=a<12?"am":"pm";a=p(a)?"??":""+(a%12||12);b=!p(b)?(b<10?"0":"")+b:"??";return""+a+":"+b+c}function Qb(a){var b=a<12?"am":"pm";return""+(p(a)?"??":""+(a%12||12))+b} -function Rb(a,b){var c=a<12?"":"p";a=p(a)?"??":""+(a%12||12);b=!p(b)?(b<10?"0":"")+b:"??";return""+a+":"+b+c}function Sb(a){var b=a<12?"":"p";return""+(p(a)?"??":""+(a%12||12))+b};var Tb=Tb||{},Q=this;function Ub(a,b,c){a=a[Na](".");c=c||Q;!(a[0]in c)&&c.execScript&&c.execScript("var "+a[0]);for(var d;a[z]&&(d=a.shift());)if(!a[z]&&b!==undefined)c[d]=b;else c=c[d]?c[d]:(c[d]={})}function Vb(a,b){a=a[Na](".");b=b||Q;for(var c;c=a.shift();)if(b[c])b=b[c];else return j;return b}function Wb(){}function Xb(a){a.Jb=function(){return a.a||(a.a=new a)}} -function Yb(a){var b=typeof a;if(b=="object")if(a){if(a instanceof ia||!(a instanceof da)&&da[B][x][K](a)=="[object Array]"||typeof a[z]=="number"&&typeof a.splice!="undefined"&&typeof a[Ba]!="undefined"&&!a[Ba]("splice"))return"array";if(!(a instanceof da)&&(da[B][x][K](a)=="[object Function]"||typeof a[K]!="undefined"&&typeof a[Ba]!="undefined"&&!a[Ba]("call")))return"function"}else return"null";else if(b=="function"&&typeof a[K]=="undefined")return"object";return b} -function Zb(a){return Yb(a)=="array"}function $b(a){var b=Yb(a);return b=="array"||b=="object"&&typeof a[z]=="number"}function R(a){return typeof a=="string"}function ac(a){return Yb(a)=="function"}function bc(a){a=Yb(a);return a=="object"||a=="array"||a=="function"}function cc(a){if(a[Va]&&a[Va](dc))return a[dc];a[dc]||(a[dc]=++ec);return a[dc]}var dc="closure_hashCode_"+q[Oa](q.random()*2147483648)[x](36),ec=0; -function fc(a){var b=Yb(a);if(b=="object"||b=="array"){if(a.ba)return a.ba[K](a);b=b=="array"?[]:{};for(var c in a)b[c]=fc(a[c]);return b}return a}function S(a,b){var c=b||Q;if(arguments[z]>2){var d=ia[B][Ia][K](arguments,2);return function(){var e=ia[B][Ia][K](arguments);ia[B].unshift[rb](e,d);return a[rb](c,e)}}else return function(){return a[rb](c,arguments)}} -function gc(a){var b=ia[B][Ia][K](arguments,1);return function(){var c=ia[B][Ia][K](arguments);c.unshift[rb](c,b);return a[rb](this,c)}}var hc=Date.now||function(){return(new Date).getTime()};function T(a,b){function c(){}c.prototype=b[B];a.s=b[B];a.prototype=new c;a[B].constructor=a};function ic(a){return a[E](/^[\s\xa0]+|[\s\xa0]+$/g,"")}function jc(a,b){a=fa(a)[Ab]();b=fa(b)[Ab]();return a")!=-1)a=a[E](pc,">");if(a[F]('"')!=-1)a=a[E](qc,""");return a}} -var nc=/&/g,oc=//g,qc=/\"/g,rc=/[&<>\"]/;function sc(a,b){return a[F](b)!=-1}function tc(){return ia[B][O][K](arguments,"")} -function uc(a,b){var c=0;a=ic(fa(a))[Na](".");b=ic(fa(b))[Na](".");for(var d=q.max(a[z],b[z]),e=0;c==0&&eb)return 1;return 0}hc();function wc(a){return a<10?"0"+a:fa(a)}var xc=[,31,,31,30,31,30,31,31,30,31,30,31];function yc(a,b){return xc[b]||xc[a]||(xc[a]=28+((a&3?l:a%100?i:a%400?l:i)?1:0))}function zc(a){return a==0||a==6}var Ac={};function Bc(a,b){var c=a<<4|b;return Ac[c]||(Ac[c]=(new Date(a,b-1,1,0,0,0,0)).getDay())}var Cc=[,0,31,59,90,120,151,181,212,243,273,304,334];function Dc(a,b,c){a=b<=2||29-yc(a,2);return Cc[b]+c-a};var Ec=1/131072;function Fc(a){if((a&31)<28)return a+1;var b=a>>5&15;if((a&31)<(xc[b]||yc((a>>9)+1970,2)))return a+1;else{var c=(a>>9)+1970;if(++b>12){b=1;++c}return((c-1970<<4)+b<<5)+1+a%1}}function Gc(a,b){var c=a;a%1||(a+=Ec);(b-Ec)%1||(b-=Ec);return function(d,e){return da||d>=c)}};function Hc(){}P=Hc[B];P.i=ca;P.g=ca;P.e=ca;P.j=ca;P.l=ca;P.r=ca;ja(P,function(){return this.c||(this.c=this.b())});P.t=function(){var a;return a=this.f()|0};P.min=function(a){return this.f()a.f()?this:a};function Ic(a,b){var c=Jc(a);if(!p(a.i)){c.i=ca;c.g=ca;c.e=Kc(a,b)}if(!p(a.j)){c.j-=b.j;c.l-=b.l;c.r-=b.r}return new Lc(c.e,c.j,c.l,c.r)} -function Kc(a,b){return a.i==b.i?Dc(a.i,a.g,a.e)-Dc(b.i,b.g,b.e):q[Ha]((Date.UTC(a.i,a.g-1,a.e)-Date.UTC(b.i,b.g-1,b.e))/86400000)}function Mc(a){var b;b=a.i;var c=a.g;a=a.e;if(++a>28&&a>yc(b,c)){a=1;if(++c===13){c=1;++b}}return b=Nc(b,c,a)}function Oc(a){return a.j||a.l||a.r?Mc(a):a.q()}function Pc(a,b){return Qc(a.i,a.g,a.e+b).q()}function Rc(a,b){return Pc(a,-((a.Z()-b+7)%7))}Hc[B].Z=function(){return(Bc(this.i,this.g)+this.e-1)%7};Hc[B].q=function(){return Nc(this.i||0,this.g||1,this.e||1)}; -Hc[B].Na=function(){return new Sc(this.i||0,this.g||1,this.e||1,this.j||0,this.l||0,this.r||0)};Hc[B].Ec=function(){return new Tc(this.j||0,this.l||0,this.r||0)};function Uc(a){return a.j*60+a.l};function Vc(){}T(Vc,Hc);function Tc(a,b,c){Hc[K](this);this.j=a;this.l=b;this.r=c}T(Tc,Hc);Tc[B].Ec=function(){return this};Tc[B].b=function(){return tc("T",wc(this.j),wc(this.l),wc(this.r))};Tc[B].F=function(a){return this[Sa]===a[Sa]&&this.f()==a.f()};Tc[B].f=function(){return this.a||(this.a=(((this.j<<6)+this.l<<6)+this.r+1)*Ec)};function Sc(a,b,c,d,e,f){this.i=a;this.g=b;this.e=c;this.j=d;this.l=e;this.r=f}T(Sc,Vc);Sc[B].Na=function(){return this};Sc[B].f=function(){return this.a||(this.a=((this.i-1970<<4)+this.g<<5)+this.e+(((this.j<<6)+this.l<<6)+this.r+1)*Ec)};Sc[B].b=function(){return tc(fa(this.i),wc(this.g),wc(this.e),"T",wc(this.j),wc(this.l),wc(this.r))};Sc[B].F=function(a){return this[Sa]===a[Sa]&&this.f()==a.f()}; -function Wc(a){return new Sc(a.getUTCFullYear(),a.getUTCMonth()+1,a[Pa](),a.getUTCHours(),a.getUTCMinutes(),a.getUTCSeconds())}function Xc(a){return new Sc(a.getFullYear(),a.getMonth()+1,a.getDate(),a.getHours(),a.getMinutes(),a.getSeconds())};function Yc(){}T(Yc,Vc);function Zc(a,b,c,d){var e=new Yc;e.i=a;e.g=b;e.e=c;e.a=d;return $c[d]=e}Yc[B].q=function(){return this};Yc[B].f=Gb("a");Yc[B].b=function(){return tc(fa(this.i),wc(this.g),wc(this.e))};Yc[B].F=function(a){return this===a};var $c={};function Nc(a,b,c){var d=((a-1970<<4)+b<<5)+c;return $c[d]||Zc(a,b,c,d)}function ad(a){return $c[a]||Zc((a>>9)+1970,a>>5&15,a&31,a)}function bd(a){return Nc(a.getUTCFullYear(),a.getUTCMonth()+1,a[Pa]())};function Lc(a,b,c,d){Hc[K](this);this.d=a=((a*24+b)*60+c)*60+d;this.r=a%60;a=a/60|0;this.l=a%60;a=a/60|0;this.j=a%24;this.e=a/24|0}T(Lc,Hc);Lc[B].f=function(){return this.a||(this.a=this.e+(((this.j<<6)+this.l<<6)+this.r+1)*Ec)};Lc[B].b=function(){var a=this.j||this.l||this.r||0,b=this.e||a;b=b<0?-1:b>0?1:0;var c=b<0?"-P":"P";if(this.e)c+=this.e%7?b*this.e+"D":b*this.e/7+"W";if(a){c+="T";if(this.j)c+=b*this.j+"H";if(this.l)c+=b*this.l+"M";if(this.r)c+=b*this.r+"S"}else b||(c+="0D");return c}; -Lc[B].F=function(a){return this[Sa]===a[Sa]&&this.f()==a.f()};new Lc(1,0,0,0);function cd(){}T(cd,Hc);P=cd[B];P.i=0;P.g=0;P.e=0;P.j=0;P.l=0;P.r=0;P.f=function(){var a=this.t();p(this.j)||(a+=(((this.j<<6)+this.l<<6)+this.r+1)*Ec);return a};P.t=function(){dd(this);return((this.i-1970<<4)+this.g<<5)+this.e};function dd(a){if(a.j||a.l||a.r){var b=(a.j*60+a.l)*60+a.r,c=q[Oa](b/86400);b-=c*86400;a.e+=c;a.r=b%60;b/=60;a.l=(b|0)%60;b/=60;a.j=(b|0)%24}ed(a);for(b=yc(a.i,a.g);a.e<1;){a.g-=1;ed(a);b=yc(a.i,a.g);a.e+=b}for(;a.e>b;){a.e-=b;a.g+=1;ed(a);b=yc(a.i,a.g)}} -function ed(a){var b;if(a.g<1||a.g>12){b=q[Oa]((a.g-1)/12);a.g-=12*b;a.i+=b}}P=cd[B];P.q=function(){dd(this);return Nc(this.i,this.g,this.e)};P.Na=function(){dd(this);return new Sc(this.i,this.g,this.e,this.j,this.l,this.r)};P.Ec=function(){dd(this);return new Tc(this.j,this.l,this.r)};P.Z=function(){dd(this);return(Bc(this.i,this.g)+this.e-1)%7};P.F=function(a){return this[Sa]==a[Sa]&&this.f()==a.f()};function Jc(a){return fd(a.i||0,a.g||0,a.e||0,a.j||0,a.l||0,a.r||0)} -function fd(a,b,c,d,e,f){var g=new cd;g.i=a;g.g=b;g.e=c;g.j=d;g.l=e;g.r=f;return g}function Qc(a,b,c){var d=new cd;d.i=a;d.g=b;d.e=c;return d};function gd(a,b){this.start=a;if(b[Sa]===Lc){a=Jc(a);a.e+=b.e;a.j+=b.j;a.l+=b.l;a.r+=b.r;this.w=this[L]instanceof Sc?a.Na():a.q();this.a=b}else{this.w=b;this.a=Ic(this.w,this[L])}}ja(gd[B],function(){return this[L]+"/"+this.w});gd[B].F=function(a){return this[Sa]===a[Sa]&&this[L].F(a[L])&&this.w.F(a.w)};function hd(a,b){return a[L].f()<=b[L].f()&&a.w.f()>=b.w.f()}ta(gd[B],function(a){a=a.f();return a>=this[L].f()&&a-1}function pd(a,b){b=md(a,b);var c;if(c=b!=-1)ia[B].splice[K](a,b,1)[z]==1;return c} -function qd(a){if(Zb(a))return a[Ra]();else{for(var b=[],c=0,d=a[z];c>1,g=c(b,a[f]);if(g>0)d=f+1;else if(g<0)e=f-1;else return f}return-(d+1)}function vd(a,b){return a>b?1:a=0)};function ie(a){return a?new je(ke(a)):xd||(xd=new je)}function le(a){return R(a)?ga.getElementById(a):a}function me(a,b){Fd(b,function(c,d){if(d=="style")a[G].cssText=c;else if(d=="class")la(a,c);else if(d=="for")a.htmlFor=c;else if(d in ne)a.setAttribute(ne[d],c);else a[d]=c})}var ne={cellpadding:"cellPadding",cellspacing:"cellSpacing",colspan:"colSpan",rowspan:"rowSpan",valign:"vAlign",height:"height",width:"width",usemap:"useMap",frameborder:"frameBorder",type:"type"}; -function oe(a){a=a||n;var b=a[Ma];if(ae&&!he("500")&&!be){if(typeof a.innerHeight=="undefined")a=n;b=a.innerHeight;var c=a[Ma][Db].scrollHeight;if(a==a.top)if(c");c=c[O]("")}var e=a[db](c);if(d)if(R(d))la(e,d);else me(e,d);if(b[z]>2){function f(g){if(g)e[ya](R(g)?a.createTextNode(g):g)}for(d=2;d0)?nd(re(c)?qd(c):c,f):f(c)}}return e}function se(a,b){a[ya](b)}function te(a){return a&&a[xb]?a[xb].removeChild(a):j}var ue=ae&&he("522"); -function ve(a,b){if(typeof a[qb]!="undefined"&&!ue&&b[La]==1)return a==b||a[qb](b);if(typeof a.compareDocumentPosition!="undefined")return a==b||Boolean(a.compareDocumentPosition(b)&16);for(;b&&a!=b;)b=b[xb];return b==a}function ke(a){return a[La]==9?a:a[Za]||a[Ma]}function re(a){if(a&&typeof a[z]=="number")if(bc(a))return typeof a.item=="function"||typeof a.item=="string";else if(ac(a))return typeof a.item=="function";return l} -function we(a,b,c){return xe(a,function(d){return(!b||d.nodeName==b)&&(!c||od(yd(d),c))},i)}function xe(a,b,c,d){if(!c)a=a[xb];c=d==j;for(var e=0;a&&(c||e<=d);){if(b(a))return a;a=a[xb];e++}return j}function je(a){this.H=a||Q[Ma]||ga}je[B].L=function(a){return R(a)?this.H.getElementById(a):a};je[B].a=je[B].L; -je[B].b=function(a,b,c){a:{var d=this.H;c=c||d;a=a&&a!="*"?a[Ab]():"";if(c.querySelectorAll&&(a||b)&&(!ae||1))b=c.querySelectorAll(a+(b?"."+b:""));else{if(b&&c.getElementsByClassName){c=c.getElementsByClassName(b);if(a){d={};for(var e=0,f=0,g;g=c[f];f++)if(a==g.nodeName[Ab]())d[e++]=g;ka(d,e);b=d;break a}else{b=c;break a}}c=c.getElementsByTagName(a||"*");if(b){d={};for(f=e=0;g=c[f];f++){a=g[Fa];if(typeof a[Na]=="function"&&od(a[Na](" "),b))d[e++]=g}ka(d,e);b=d}else b=c}}return b}; -je[B].d=function(){return qe(this.H,arguments)};function ye(a,b){var c=a.H;a=c[db]("div");t(a,b);if(a[sb][z]==1)b=a[fb];else{for(b=c.createDocumentFragment();a[fb];)b[ya](a[fb]);b=b}return b}function ze(){return i}function Ae(a){a=!ae?a.H[Db]:a.H[Ya];return a=new Cd(a[ib],a[za])}je[B].c=se;je[B].h=te;ta(je[B],ve);function Be(a,b,c,d){this.top=a;this.b=b;this.a=c;pa(this,d)}Be[B].ba=function(){return new Be(this.top,this.b,this.a,this[I])};ta(Be[B],function(a){a=!this||!a?l:a instanceof Be?a[I]>=this[I]&&a.b<=this.b&&a.top>=this.top&&a.a<=this.a:a.x>=this[I]&&a.x<=this.b&&a.y>=this.top&&a.y<=this.a;return a});function Ce(a,b,c,d){pa(this,a);this.top=b;ma(this,c);va(this,d)}Ce[B].ba=function(){return new Ce(this[I],this.top,this[D],this[N])};function De(a,b){var c=q.max(a[I],b[I]),d=q.min(a[I]+a[D],b[I]+b[D]);if(c<=d){var e=q.max(a.top,b.top);b=q.min(a.top+a[N],b.top+b[N]);if(e<=b){pa(a,c);a.top=e;ma(a,d-c);va(a,b-e);return i}}return l} -ta(Ce[B],function(a){return a instanceof Ce?this[I]<=a[I]&&this[I]+this[D]>=a[I]+a[D]&&this.top<=a.top&&this.top+this[N]>=a.top+a[N]:a.x>=this[I]&&a.x<=this[I]+this[D]&&a.y>=this.top&&a.y<=this.top+this[N]});var Ee,Fe,Ge,He,Ie,Je;(function(){Je=Ie=He=Ge=Fe=Ee=l;var a=Wd();if(a)if(a[F]("Firefox")!=-1)Ee=i;else if(a[F]("Camino")!=-1)Fe=i;else if(a[F]("iPhone")!=-1||a[F]("iPod")!=-1)Ge=i;else if(a[F]("Android")!=-1)He=i;else if(a[F]("Chrome")!=-1)Ie=i;else if(a[F]("Safari")!=-1)Je=i})();function Ke(a,b){var c=ke(a);if(c[ub]&&c[ub][Wa])if(a=c[ub][Wa](a,""))return a[b];return j}function Le(a,b){return Ke(a,b)||(a[lb]?a[lb][b]:j)||a[G][b]}function Me(a,b,c){var d,e=$d&&(de||ee)&&he("1.9");if(b instanceof Cd){d=b.x;b=b.y}else{d=b;b=c}pa(a[G],typeof d=="number"?(e?q[Ha](d):d)+"px":d);a[G].top=typeof b=="number"?(e?q[Ha](b):b)+"px":b}function Ne(a){a=a?a[La]==9?a:ke(a):ga;if(Zd&&!ze(ie(a)))return a[Ya];return a[Db]} -function Oe(a){var b=a[Da]();if(Zd){a=a[Za];b.left-=a[Db][jb]+a[Ya][jb];b.top-=a[Db][ob]+a[Ya][ob]}return b}function Pe(a){if(Zd)return a.offsetParent;var b=ke(a),c=Le(a,"position"),d=c=="fixed"||c=="absolute";for(a=a[xb];a&&a!=b;a=a[xb]){c=Le(a,"position");d=d&&c=="static"&&a!=b[Db]&&a!=b[Ya];if(!d&&(a.scrollWidth>a[Ga]||a.scrollHeight>a[hb]||c=="fixed"||c=="absolute"))return a}return j} -function Qe(a){var b=new Be(0,Infinity,Infinity,0),c=ie(a),d=!ae?c.H[Db]:c.H[Ya],e;for(a=a;a=Pe(a);)if((!Zd||a[Ga]!=0)&&(a.scrollWidth!=a[Ga]||a.scrollHeight!=a[hb])&&Le(a,"overflow")!="visible"){var f=Re(a),g;g=a;if($d&&!he("1.9")){var h=ea(Ke(g,"borderLeftWidth"));if(Se(g)){var m=g[Qa]-g[Ga]-h-ea(Ke(g,"borderRightWidth"));h+=m}g=new Cd(h,ea(Ke(g,"borderTopWidth")))}else g=new Cd(g[jb],g[ob]);f.x+=g.x;f.y+=g.y;b.top=q.max(b.top,f.y);b.b=q.min(b.b,f.x+a[Ga]);b.a=q.min(b.a,f.y+a[hb]);pa(b,q.max(b[I], -f.x));e=e||a!=d}a=d[ib];d=d[za];if(ae){b.left+=a;b.top+=d}else{pa(b,q.max(b[I],a));b.top=q.max(b.top,d)}if(!e||ae){b.b+=a;b.a+=d}c=oe(pe(c.H));b.b=q.min(b.b,a+c[D]);b.a=q.min(b.a,d+c[N]);return b.top>=0&&b[I]>=0&&b.a>b.top&&b.b>b[I]?b:j} -function Re(a){var b,c=ke(a),d=Le(a,"position"),e=$d&&c[cb]&&!a[Da]&&d=="absolute"&&(b=c[cb](a))&&(b[$a]<0||b[ab]<0),f=new Cd(0,0),g=Ne(c);if(a==g)return f;if(a[Da]){b=Oe(a);a=Ae(ie(c));f.x=b[I]+a.x;f.y=b.top+a.y}else if(c[cb]&&!e){b=c[cb](a);a=c[cb](g);f.x=b[$a]-a[$a];f.y=b[ab]-a[ab]}else{b=a;do{f.x+=b[Ua];f.y+=b[yb];if(b!=a){f.x+=b[jb]||0;f.y+=b[ob]||0}if(ae&&Le(b,"position")=="fixed"){f.x+=c[Ya][ib];f.y+=c[Ya][za];break}b=b.offsetParent}while(b&&b!=a);if(Yd||ae&&d=="absolute")f.y-=c[Ya][yb];for(b= -a;(b=Pe(b))&&b!=c[Ya]&&b!=g;){f.x-=b[ib];if(!Yd||b[tb]!="TR")f.y-=b[za]}}return f}function Te(a){var b=new Cd;if(a[La]==1)if(a[Da]){var c=Oe(a);b.x=c[I];b.y=c.top}else{c=Ae(ie(a));a=Re(a);b.x=a.x-c.x;b.y=a.y-c.y}else{b.x=a[Bb];b.y=a[Cb]}return b}function Ue(a,b,c){if(b instanceof Ed){c=b[N];b=b[D]}else{if(c==undefined)aa(Error("missing height argument"));c=c}ma(a[G],typeof b=="number"?q[Ha](b)+"px":b);va(a[G],typeof c=="number"?q[Ha](c)+"px":c)} -function Ve(a){var b=Yd&&!he("10");if(Le(a,"display")!="none")return b?new Ed(a[Qa]||a[Ga],a[zb]||a[hb]):new Ed(a[Qa],a[zb]);var c=a[G],d=c.display,e=c.visibility,f=c.position;xa(c,"hidden");c.position="absolute";ua(c,"inline");if(b){b=a[Qa]||a[Ga];a=a[zb]||a[hb]}else{b=a[Qa];a=a[zb]}ua(c,d);c.position=f;xa(c,e);return new Ed(b,a)}function We(a){var b=Re(a);a=Ve(a);return new Ce(b.x,b.y,a[D],a[N])}function Xe(a,b){ua(a[G],b?"":"none")}function Se(a){return"rtl"==Le(a,"direction")};var Ye=/<[^>]*>|&[^;]+;/g,Ze=new RegExp("[\u0591-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]"),$e=new RegExp("^[^A-Za-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u0300-\u0590\u0800-\u1fff\u2c00-\ufb1c\ufe00-\ufe6f\ufefd-\uffff]*[\u0591-\u07ff\ufb1d-\ufdff\ufe70-\ufefc]"),af=new RegExp("^[\u0000- !-@[-`{-\u00bf\u00d7\u00f7\u02b9-\u02ff\u2000-\u2bff]*$|^http://"),bf=/(\([^\)]*\))|(\[[^\]]*\])|({[^}]*})|(<[^>]*>)/g;function cf(a){var b=Ze[Ea](a)?"\u200f":"\u200e";return a[E](bf,b+"$&"+b)} -function df(a){if(a.charAt(0)=="<")return a[E](/<\w+/,"$& dir=rtl");return"\n"+a+""}function ef(a,b){var c;var d=c=0;a=(b?a[E](Ye," "):a)[Na](" ");for(b=0;b0.4};var ff;Zd&&uc(fe,"6");Zd&&uc(fe,"7");var gf=ae&&uc(fe,"522")>=0,hf=$d&&uc(fe,"1.9")<0,jf=$d&&uc(fe,"1.9")>=0;(function(){var a=l;if(ae)if(Q[vb])a=Q[vb].userAgent[F](" Chrome/")!=-1;ff=a})();var kf={};function lf(a,b){var c;c=ef(a);a=b||a;return c=c?df(a):a}function mf(a){return"\u202b"+a+"\u202c"}function nf(a,b){return hf&&b!==l?'
    '+a+"
    ":a};var of=Zd?'
    ':"",pf=Zd?"
    ":"",qf=0;function rf(){if(qf)return qf;var a=ga[db]("div");a[G].cssText="visibility:hidden;overflow-y:scroll;position:absolute;top:0;width:100px;height:100px";ga[Ya][ya](a);qf=a[Qa]-a[Ga]||18;ga[Ya].removeChild(a);return qf};function U(){}U[B].yc=l;U[B].C=function(){if(!this.yc){this.yc=i;this.m()}};U[B].m=Fb();function sf(a){a&&typeof a.C=="function"&&a.C()};function tf(a,b){U[K](this);this.ze=b;this.Ra=[];if(a>this.ze)aa(Error("[goog.structs.SimplePool] Initial cannot be greater than max"));for(b=0;b=0;k--){var s=m[k];if((f||b==s[M])&&(g||c==s[Xa])){Qf(s.fa);d++}}});else{a=cc(a);if(Df[a]){a=Df[a];for(e=a[z]-1;e>=0;e--){var h=a[e];if((f||b==h[M])&&(g||c==h[Xa])){Qf(h.fa);d++}}}}return d}function Nf(a){if(a in Mf)return Mf[a];return Mf[a]="on"+a} -function Tf(a,b,c,d,e){var f=1;b=cc(b);if(a[b]){a.ja--;a=a[b];if(a.oa)a.oa++;else a.oa=1;try{for(var g=a[z],h=0;h=0&&f.ja;r--){oa(h,k[r]);e&=Tf(f,k[r],c,i,h)}if(g){f=d[l];f.ja= -f.N;for(r=0;!h.Ma&&r=0&&f.ja;g--){oa(a,c[g]);b&=Tf(f,c[g],a[M],i,a)&&a.sb!=l}}if(l in e){f=e[l];f.ja=f.N;if(d)for(g=0;!a.Ma&&g=30000)Yf=a-hc()}Wf[B].b=function(){this.wb=$f(this)};function Xf(a,b){var c=a.xf;if(c===undefined)c=(new Date(b)).getTimezoneOffset()*-60000;else if(b>=a.Hg)c=a.ng;return c}function ag(a){var b=hc()+Yf;return Xf(a,b)+b}function $f(a){return new Date(ag(a))} -Wf[B].c=function(){var a=this.wb,b=$f(this),c=1800000-b.getTime()%1800000;n[Ja](S(this.c,this),c);if(a[Pa]()!==b[Pa]()){this.b();this.n("newday")}};function bg(a){this.Wf=a}T(bg,U);var cg=new tf(0,100);function X(a,b,c,d,e,f){if(Zb(c))for(var g=0;gc.b&&d&16){b.width-=a.x+b[D]-c.b;e|=4}if(a.x+b[D]>c.b&&d&1){a.x=q.max(c.b-b[D],c[I]);e|=1}if(d&2)e|=(a.xc.b?32:0);if(a.y=c.top&&a.y+b[N]>c.a&&d&32){b.height-=a.y+b[N]-c.a;e|=8}if(a.y+b[N]>c.a&&d&4){a.y=q.max(c.a-b[N],c.top);e|=2}if(d&8)e|=(a.yc.a?128:0);return e};var gg={8:"backspace",9:"tab",13:"enter",16:"shift",17:"ctrl",18:"alt",19:"pause",20:"caps-lock",27:"esc",32:"space",33:"pg-up",34:"pg-down",35:"end",36:"home",37:"left",38:"up",39:"right",40:"down",45:"insert",46:"delete",48:"0",49:"1",50:"2",51:"3",52:"4",53:"5",54:"6",55:"7",56:"8",57:"9",65:"a",66:"b",67:"c",68:"d",69:"e",70:"f",71:"g",72:"h",73:"i",74:"j",75:"k",76:"l",77:"m",78:"n",79:"o",80:"p",81:"q",82:"r",83:"s",84:"t",85:"u",86:"v",87:"w",88:"x",89:"y",90:"z",93:"context",107:"num-plus", -109:"num-minus",112:"f1",113:"f2",114:"f3",115:"f4",116:"f5",117:"f6",118:"f7",119:"f8",120:"f9",121:"f10",122:"f11",123:"f12",187:"equals",188:",",190:".",191:"/",220:"\\",224:"win"};var hg=Q.window;function ig(a,b,c){if(ac(a)){if(c)a=S(a,c)}else if(a&&typeof a[pb]=="function")a=S(a[pb],a);else aa(Error("Invalid listener argument"));return b>2147483647?-1:hg[Ja](a,b||0)};function jg(a){W[K](this);this.Vb={};this.a={bb:[],Ve:0};this.oe=Ld(kg);this.o=i;this.Dd=l;this.c=a;V(this.c,"keydown",this.d,l,this);de&&$d&&he("1.8")&&V(this.c,"keyup",this.h,l,this)}var lg;T(jg,W);var kg=[27,112,113,114,115,116,117,118,119,120,121,122,123,19],mg={nf:"shortcut",mf:"shortcut_"};jg[B].b=function(a){ng(this.Vb,og(this,1,arguments),a)}; -function og(a,b,c){if(R(c[b])){b=c[b];b=b[E](/[ +]*\+[ +]*/g,"+")[E](/[ ]+/g," ")[Ab]();b=b[Na](" ");c=[];var d;for(a=0;d=b[a];a++){var e=d[Na]("+"),f;d=0;for(var g,h=0;g=e[h];h++){switch(g){case "shift":d|=1;continue;case "ctrl":d|=2;continue;case "alt":d|=4;continue;case "meta":d|=8;continue}f=g;if(!lg){e={};for(var m in gg)e[gg[m]]=m;lg=e}f=lg[f];break}c[u]({keyCode:f,Be:d})}b=c}else{m=c;f=b;if(Zb(c[b])){m=c[b];f=0}for(b=[];f1)return pg(a,b,c+1,d);return d} -jg[B].d=function(a){if(!(a[eb]==16||a[eb]==17||a[eb]==18)){var b=a[J];if(b[tb]=="TEXTAREA"||b[tb]=="INPUT"||b[tb]=="BUTTON"||b[tb]=="SELECT"){if(!a.$c&&!a.ad&&!a.Kb&&!qg(this,a[eb],b))return}else if((b.isContentEditable||b[Za]&&b[Za].designMode=="on")&&!this.oe[a[eb]]&&!this.Dd)return;b=a[eb]&255|((a.pe?1:0)|(a.ad?2:0)|(a.$c?4:0)|(a.Kb?8:0))<<8;var c,d,e=hc();if(this.a.bb[z]&&e-this.a.Ve<=1500)c=pg(this,this.a.bb);else ka(this.a.bb,0);c=c?c[b]:this.Vb[b];if(!c){c=this.Vb[b];this.a.bb=[]}if(c&&R(c))d= -c;else if(c){this.a.bb[u](b);this.a.Ve=e;$d&&a.Ha()}else ka(this.a.bb,0);if(d){c=this.n(new rg(mg.nf,d,a[J]));d=new rg(mg.mf+d,d,a[J]);c&=this.n(d);if(this.o||!c)a.Ha();ka(this.a.bb,0)}}};function qg(a,b,c){if(a.oe[b]||a.Dd)return i;if(c[tb]=="INPUT"&&(c[M]=="text"||c[M]=="password"))return b==13;if(c[tb]=="INPUT"||c[tb]=="BUTTON")return b!=32;if(c[tb]=="TEXTAREA"||c[tb]=="SELECT")return l;return i}function rg(a,b,c){xf[K](this,a,c);this.a=b}T(rg,xf);var sg=/^(?:([^:\/?#]+):)?(?:\/\/(?:([^\/?#]*)@)?([^\/?#:@]*)(?::([0-9]+))?)?([^?#]+)?(?:\?([^#]*))?(?:#(.*))?$/;function tg(a){var b=a[bb](sg);a=b[1];var c=b[2],d=b[3];b=b[4];var e=[];a&&e[u](a,":");if(d){e[u]("//");c&&e[u](c,"@");e[u](d);b&&e[u](":",b)}return a=e[O]("")}function ug(a){if(a[1]){var b=a[0][F]("?");if(b<0)a[1]="?";else if(b==a[0][z]-1)a[1]=""}return a[O]("")} -function vg(a,b,c){q.max(b[z]-(c||0),0)%2==0;for(c=c||0;c=Fc(a);this.z=!this.c&&Uc(c)==0;this.o=(a<<1)+!this.d+a%1}yg[B].b="";yg[B].h="";yg[B].Ed=-1;function zg(a,b){a.Ed=b}yg[B].Q=Gb("v");yg[B].a=function(){return j};yg[B].F=function(a){if(this==a)return i;return!!a&&a.Q()==this.Q()};function Ag(a,b,c){return b.o-c.o||c.J.f()-b.J.f()||a(b,c)||jc(b.b,c.b)};function Bg(a){this.a=a}ja(Bg[B],Gb("a"));function Dg(a,b){this.b=a;this.Wa=b}var Eg=/^[a-zA-Z0-9_]+$/;function Fg(a){return!!a.Wa&&Gg(a)!="CHIP"}function Hg(a){if(a.Wa)return i;return l}function Ig(a,b,c,d,e,f){if(a.$()!=1)return j;b="http://www.gmodules.com/gadgets/ifr?url="+ba(Jg(a))+"&synd=calendar&w="+Kg(a)+"&h="+Lg(a)+"&up_startdate="+b.q()[x]()+"&up_enddate="+c.q()[x]()+"&lang="+d[E]("_","-");if(e)b+="&up_tzoffset="+ba(fa(e));if(f)b+="&country="+ba(f);a.ea();if(a=a.Hf)for(var g in a)if(g[bb](Eg))b+="&up_"+g+"="+ba(a[g]);return b};function Mg(a,b,c){yg[K](this,a,b,c);this.I=[]}T(Mg,yg);P=Mg[B];P.xc=j;P.bf=j;P.zb="";P.la=j;P.uc=l;function Ng(a,b){a.xc=b}Mg[B].a=Gb("bf");function Og(a){a.uc=i}function Pg(a,b){return a.la&&b.la&&(a.la.c-b.la.c||jc(a.la.Hb,b.la.Hb))||0};function Qg(a){this.ie=a}Qg[B].Q=Gb("ie");function Rg(a,b){a=Number(a);b=Number(b);this.start=a=0?Zg[a]:j} -function ah(a,b,c){function d(g){return o(g,16)}var e=Tg(d(a[Eb](1,2)),d(b[Eb](1,2)),c),f=Tg(d(a[Eb](3,2)),d(b[Eb](3,2)),c);a=Tg(d(a[Eb](5,2)),d(b[Eb](5,2)),c);return"#"+bh(e)+bh(f)+bh(a)}function bh(a){a=Number(a|0)[x](16);return a[z]<2?"0"+a:a};function ch(a,b,c,d){Qg[K](this,a);this.Hb=c||a;a=this.ce=b;b=this.Q();if(b in a.Xa)aa(new Error("Already registered an event source with id "+b));c=new dh(b);a.Xa[b]=c;a.rc[b]=this;this.b=d||eh()}T(ch,Qg);ch[B].c=0;function fh(a,b){a.Hb=b}ch[B].a=function(a,b){b[K](j,[],j)};var gh=0;function eh(){var a=Wg[(Xg[gh]+1)%Wg[z]];gh=a;return Zg[a]};function hh(){}hh[B].a=Fb();function ih(a,b){this.element=a;this.b=b}T(ih,hh);ih[B].a=function(a,b,c){eg(this.element,this.b,a,b,undefined,c)};function jh(a,b){this.ta=new bg(this);a=a||j;kh(this);this.U=a;b&&lh(this,b)}T(jh,W);P=jh[B];P.U=j;P.Ab=i;P.Fd=j;P.ua=l;P.zg=l;P.kd=-1;P.jd=-1;P.qc=l;P.Rc=i;P.lb="toggle_display";P.$=Gb("lb");function lh(a,b){a.lb=b}jh[B].L=Gb("U");function kh(a){if(a.ua)aa(Error("Can not change this state of the popup while showing."))}jh[B].mb=function(){return this.ua||hc()-this.jd<150};jh[B].ga=function(a){a?mh(this):nh(this)};jh[B].Lb=Fb(); -function mh(a){if(!a.ua)if(a.n("beforeshow")){if(!a.U)aa(Error("Caller must call setElement before trying to show the popup"));a.Lb();var b=ke(a.U);a.qc&&X(a.ta,b,"keydown",a.pg,i);if(a.Ab){X(a.ta,b,"mousedown",a.Ge,i);if(Zd){for(var c=b.activeElement;c&&c.nodeName=="IFRAME";){try{var d,e=undefined;d=e=ae?c[Ma]||c.contentWindow[Ma]:c.contentDocument||c.contentWindow[Ma]}catch(f){break}b=d;c=b.activeElement}X(a.ta,b,"mousedown",a.Ge,i);X(a.ta,b,"deactivate",a.Fe)}else X(a.ta,b,"blur",a.Fe)}if(a.lb== -"toggle_display"){xa(a.U[G],"visible");Xe(a.U,i)}else a.lb=="move_offscreen"&&a.Lb();a.ua=i;a.kd=hc();a.jd=-1;a.n("show")}}function nh(a,b){if(!a.ua||!a.n({type:"beforehide",target:b}))return l;a.ta&&dg(a.ta);if(a.lb=="toggle_display")a.zg?ig(a.ue,0,a):a.ue();else a.lb=="move_offscreen"&&oh(a);a.ua=l;a.jd=hc();a.n({type:"hide",target:b});return i}jh[B].ue=function(){xa(this.U[G],"hidden");Xe(this.U,l)};function oh(a){pa(a.U[G],"-200px");a.U[G].top="-200px"} -jh[B].Ge=function(a){a=a[J];if(!ve(this.U,a)&&(!this.Fd||ve(this.Fd,a))&&!(hc()-this.kd<150))nh(this,a)};jh[B].pg=function(a){if(a[eb]==27)if(nh(this,a[J])){a.Ha();a.bd()}};jh[B].Fe=function(a){if(this.Rc){var b=ke(this.U);if(Zd||Yd){if((a=b.activeElement)&&ve(this.U,a))return}else if(a[J]!=b)return;hc()-this.kd<150||nh(this)}};jh[B].m=function(){jh.s.m[K](this);this.ta.C();delete this.U;delete this.ta};function ph(a,b){this.Ke=4;this.sd=b||undefined;jh[K](this,a)}T(ph,jh);ph[B].Lb=function(){if(this.sd){var a=!this.ua&&this.$()!="move_offscreen",b=this.L();if(a){xa(b[G],"hidden");Xe(b,i)}this.sd.a(b,this.Ke,this.b);a&&Xe(b,l)}};Wf[B].b=function(){this.wb=$f(this);this.a=bd(this.wb)};function qh(a,b,c){this.name=a;this.title=b;this.a=c?c[E]("{hl}",ba("en")):j};function rh(){};var sh=["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],th=["S","M","T","W","T","F","S"],uh=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],vh=[,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],wh=[,"January","February","March","April","May","June","July","August","September","October","November","December"];function xh(a){this.Ba=a||new yh}T(xh,Fb());function zh(a,b,c){return a=(c?vh:wh)[b]}function Ah(a,b,c,d){a=a.Ba.c||p(b.j)?Ob:c&&0==b.l?d?Sb:Qb:d?Rb:Pb;return a(b.j,b.l)}function Bh(a,b,c,d){d=zh(a,b.g,d);a=b.i==a.Ba.b.i&&q.abs(b.g-a.Ba.b.g)<4?Nb(d,b.e):""+d+" "+b.e+", "+b.i;return b=""+(c?sh:uh)[b.Z()]+", "+a}xh[B].a=function(a){return a.e==1?Nb(zh(this,a.g,i),a.e):fa(a.e)}; -function Ch(a,b){var c;a:{c=b[L];var d=Pc(b.w,-1);b=c.i;var e=c.g,f=c.e,g=d.i,h=d.g;d=d.e;var m=zh(a,e,i);a=zh(a,h,i);if(b==g)if(e==h)if(f==d){a=""+m+" "+f+", "+b;c=""+uh[c.Z()]+", "+a;break a}else{c=""+m+" "+f+" \u2013 "+d+" "+b;break a}else{c=""+m+" "+f+" \u2013 "+a+" "+d+", "+b;break a}c=Mb(""+m+" "+f+", "+b,""+a+" "+d+", "+g)}return c}function Dh(a,b){return Nb(wh[b.g],b.i)} -function Eh(a,b,c){if(p(c.j)){var d;d=Ic(c,b).d/3600|0;a=d>=24?Ch(a,new gd(b,c)):Bh(a,b,i)}else{d=!(b.l||c.l);a=Mb(Bh(a,b,i)+", "+Ah(a,b,d),(b.q()!=c.q()?Bh(a,c,i)+", ":"")+Ah(a,c,d))}return a}function Fh(a,b){return b}function Gh(a,b){if(p(b))return"?";return b[x]()}var Hh={jf:Lb(0),kf:"1 min",lf:Lb,hf:"1 hr",Cd:Kb,ff:"1 day",gf:Jb};function yh(a,b,c){this.c=a||l;this.a=b||0;this.b=c||bd(new Date)} -function Ih(a,b){switch(b){case 1:return""+a.e+"/"+a.g;case 0:return""+a.g+"/"+a.e;case 2:return""+a.g+"/"+a.e;default:return""+a.g+"/"+a.e}};function Jh(){rh[K](this)}T(Jh,rh);function Kh(a,b,c,d){this.a=a;this.b=b;this.Kf=d;this.Xe=c;this.fd=this.a+"calendar"+(b?"/hosted/"+this.b:"");this.c=this.a+"calendar/feeds"};function Lh(a){for(var b in Mh)b in a||(a[b]=Mh[b]);this.yc=a.collapseAllday;var c=a.format24hour;b=o(a.dateFieldOrder,10);new Jh;this.Za=a.autoResize;c=c;b=b;c=!!c;b=b||0;this.b=b=new xh(new yh(c,b));this.va=(b=a.hostedDomain)?new qh(b[wb],b[Ca],b.maplink):j;this.o=a.baseUrl;if(!tg(this.o))this.o=tg(n[Ta][mb])+this.o;this.h=a.weekstart;this.d=a.imagePath;this.z=a.timezone||j;this.nb=a.timezoneLocalized;this.Qb=a.haveQuickAdd;"nowMs"in a&&Zf(o(a.nowMs,10));this.a=new Wf(Nh(a.timezoneOffsetMs),Nh(a.timezoneNextTransitionMs), -Nh(a.timezoneNextOffsetMs));this.c=a.showWeekends;this.na=o(a.firstWeekday,10);this.I=o(a.workWeekLength,10);this.Sb=a.showCurrentTime;this.v=new Kh(this.o,this.va&&this.va[wb]||"",this.z,this.h)}function Nh(a){a=o(a,10);if(p(a))a=undefined;return a} -var Mh={autoResize:i,baseUrl:"http://www.google.com/",collapseAllday:l,dateFieldOrder:0,format24hour:i,hostedDomain:j,imagePath:"http://www.google.com/calendar/images/",showCurrentTime:i,showWeekends:i,preloadEnd:j,preloadStart:j,weekstart:0,haveQuickAdd:l,firstWeekday:1,workWeekLength:5};function Oh(a){return function(){return a}}Oh(l);Oh(i);function dh(a){this.a=a;this.db={};this.gd={};this.Sa=this.Ca=this.Da=j}function Ph(a,b,c){var d,e;if(!a.Da||b[L].f()<=a.Da.f()){a.Da=b[L].q();d=i}if(!a.Ca||b.w.f()>=a.Ca.f()){a.Ca=b.w.q();e=i}c&&d&&e&&Qh(a,c)}function Qh(a,b){if(!a.Sa||b>a.Sa)a.Sa=b}function Rh(a,b){var c=b[L].q();b=b.w.q();var d=c.t();c=b.t();b={};var e=[];for(d=d;d=h.Sa);var k=c[L].f()h.Ca.f();m=!k&&!s?m?new gd(h.Da,h.Ca):j:k&&s?c:s?new gd(m?h.Da:h.Ca,c.w.q()):new gd(c[L].q(),m?h.Ca:h.Da)}if(m)d.a[g]=m;else e||d.b[u](Rh(h,c))}return d}Sh[B].qg=function(a,b,c,d){c&&$h(this,a,c,b.d,d);b.b[u](Rh(this.Xa[a],b.d));delete b.a[a];if(Id(b.a)){Zh(this,b);this.n(Vh)}}; -function Zh(a,b){--a.rd;var c=b.b;c=ai(a,c);b=b.h;a.ab[b]=c;for(var d=a.Tb[b],e=0;e1){if(b%2)aa(Error("Uneven number of arguments"));for(var c=0;c=c[z])aa(ci);var h=c[b++];return a?h:d[h]}};return g};/\uffff/[Ea]("\uffff");function li(a){if($d){var b=a.Wb.pop();mi(a,b)}}function ni(a,b){if($d){b=cc(b);for(var c=0;c0)this.cb=hg[Ja](S(this.c,this),this.Dc);this.sc=i;this.p.send(a);this.sc=l}catch(g){Bi(this,5,g)}};wi[B].n=function(a){if(this.p){if($d){var b=R(this.p)?this.p:bc(this.p)?cc(this.p):"";pi.Wb[u](b)}try{wi.s.n[K](this,a)}finally{li(pi)}}else wi.s.n[K](this,a)}; -wi[B].c=function(){if(typeof Tb!="undefined")if(this.p){this.vc="Timed out after "+this.Dc+"ms, aborting";this.Ob=8;this.n("timeout");if(this.p){this.ya=l;this.Ya=i;this.p.abort();this.Ya=l;this.Ob=8;this.n("complete");this.n("abort");Ci(this)}}};function Bi(a,b,c){a.ya=l;if(a.p){a.Ya=i;a.p.abort();a.Ya=l}a.vc=c;a.Ob=b;Di(a);Ci(a)}function Di(a){if(!a.Sc){a.Sc=i;a.n("complete");a.n("error")}}wi[B].m=function(){if(this.p){if(this.ya){this.ya=l;this.Ya=i;this.p.abort();this.Ya=l}Ci(this,i)}wi.s.m[K](this)}; -wi[B].He=function(){!this.hd&&!this.sc&&!this.Ya?this.b():Ei(this)};wi[B].b=function(){Ei(this)};function Ei(a){if(a.ya)if(typeof Tb!="undefined")if(!(a.Fc[1]&&Fi(a)==4&&Gi(a)==2))if(a.sc&&Fi(a)==4)hg[Ja](S(a.He,a),0);else{a.n("readystatechange");if(Fi(a)==4){a.ya=l;var b;a:switch(Gi(a)){case 0:case 200:case 204:case 304:b=i;break a;default:b=l;break a}if(b){a.n("complete");a.n("success")}else{a.Ob=6;a.vc=Hi(a)+" ["+Gi(a)+"]";Di(a)}Ci(a)}}} -function Ci(a,b){if(a.p){a.p.onreadystatechange=a.Fc[0]?Wb:j;var c=a.p;a.p=j;a.Fc=j;if(a.cb){hg.clearTimeout(a.cb);a.cb=j}if(!b){if($d){b=R(c)?c:bc(c)?cc(c):"";pi.Wb[u](b)}a.n("ready");li(pi)}if($d){a=cc(c);delete pi.Gc[a];for(var d in pi.Pa){pd(pi.Pa[d],a);pi.Pa[d][z]==0&&delete pi.Pa[d]}}}}function Fi(a){return a.p?a.p.readyState:0}function Gi(a){try{return Fi(a)>2?a.p.status:-1}catch(b){return-1}}function Hi(a){try{return Fi(a)>2?a.p.statusText:""}catch(b){return""}};var Ii,Ji=j,Ki=/calendar\/(?:a|hosted)\/([^\/]*)\//;function Li(a,b,c){b=new RegExp(fa(b+"=")[E](/([-()\[\]{}+?*.$\^|,:#=0;--e){var f=d[e];f.la=a;var g=a.Q();f.pf=g}$h(a.ce,a.Q(),d,c,b)} -cj[B].a=function(a,b,c){var d=this.d,e=a[L].q(),f=a.w.q(),g=Xf(this.v,hc()+Yf);a=Qi(e.Na(),g/60000);g=Qi(f.Na(),g/60000);e=Ic(f,e).e;d=wg(d,"singleevents","true","start-min",a,"start-max",g,"max-results",e*48,"updated-min",c);c=undefined;e="SCRIPT";if(this.I){c=Mi();e="GET"}d=new Vi(d,c,e);V(d,"complete",S(this.z,this,b));V(d,"error",S(this.o,this,b));if(d.a=="SCRIPT"){b=++Xi;Wi[b]=d;c=wg(d.c,"alt","json-in-script","callback","goog$calendar$GdataRequest$callback","reqid",b);d=ga[db]("script");d.src= -c;c=ga[db]("div");ua(c[G],"none");t(c,"'; -$buffer = preg_replace($pattern, $replacement, $buffer); - -// Use DHTML to modify the DOM after the calendar loads -$pattern = '/(<\/head>)/'; -$replacement = << - - -RGC; -$buffer = preg_replace($pattern, $replacement, $buffer); - -// display the calendar -print $buffer; -?> diff --git a/public/static/csesoc_banner.png b/public/static/csesoc_banner.png deleted file mode 100644 index f55c1f6..0000000 Binary files a/public/static/csesoc_banner.png and /dev/null differ diff --git a/public/static/default.css b/public/static/default.css deleted file mode 100644 index ac4dc01..0000000 --- a/public/static/default.css +++ /dev/null @@ -1,156 +0,0 @@ -body { - font-family:arial, verdana, helvetica, sans-serif; - font-size:12px; - cursor:default; - background-color:#FFFFEE; - margin: 0px; - padding: 0px; - text-decoration: none; -} - -a > img { border: 0 none; } - -html { - height:100%; - margin-bottom:1px; -} -#container { - width: 950px; - margin-right: auto; - margin-left: auto; - text-align: left; - background-color: #FFFFFF; -} -#header { - width:100%; - padding-top:15px; - text-align: center; -} -.spacer { - width:100%; - height:15px; -} -hr { - border:0px; - color:#CCCCCC; - background-color:#CDCDCD; - height: 1px; - width: 100%; - text-align: left; -} -h1 { - font-size:28px; - color:#ffa100; - background-color:#FFFFFF; - font-family:Arial, Verdana, Helvetica, sans-serif; - font-weight:500; -} -h2 { - margin-top: 10px; - font-size:15px; - color:#323232; - font-family:Arial, Verdana, Helvetica, sans-serif; - font-weight:bold; - background-color:#FFFFFF; -} -h3 { - color:#ffa100; - font-size:15px; - text-align:left; - font-weight:500; - padding:5px; - margin-top:5px; -} - -#left { - float:left; - width:170px; - background-color:#FFFFFF; - color:black; -} - -#main { - margin : 5px 5px 5px 180px; - padding : 15px; - border-left : 1px solid silver; -} - -#swipe { - margin : 150px auto 150px auto; - text-align : center; - padding : 15px; -} - -#full-width { - margin : 5px 5px 5px 5px; -} - -p { - color:black; - background-color:#FFFFFF; - line-height:20px; - padding:5px; -} -a { - color:#dc641e; - # background-color:#FFFFFF; - text-decoration:none; - font-weight:bold; -} -a:hover { - color:#ffb844; - background-color:#FFFFFF; - text-decoration:underline; -} -#footer { - clear:both; - font-size:12px; - font-family:Verdana, Arial, Helvetica, sans-serif; -} -.right { - color:#9d8867; - background-color:#FFFFFF; - float:right; - font-size:100%; - margin-top:5px; -} -.left { - color:#9d8867; - background-color:#FFFFFF; - float:left; - font-size:100%; - margin-top:5px; -} -ul ul { - padding-left: 20px; - margin-left: 0px; -} - -.pagenumbers { - list-style: none; - margin: 0.5em auto; - padding: 0; - text-align: center; -} - -.pagenumbers li, .pagenumbers li>* { - display: inline-block; -} - -.pagenumbers li>* { - border: 1px transparent solid; - height: 2em; - width: 2em; - line-height: 2em; - text-align: center; -} - -.pagenumbers a:hover, .pagenumbers a:active, .pagenumbers a:focus { - background-color: #ffffff; - border: 1px #cdcdcd solid; - text-decoration: none; -} - -.pagenumbers .disabled { - color: #888a85; -} diff --git a/public/static/djangopony.png b/public/static/djangopony.png deleted file mode 100644 index da10b91..0000000 Binary files a/public/static/djangopony.png and /dev/null differ diff --git a/public/static/game/default.css b/public/static/game/default.css deleted file mode 100644 index b3630a9..0000000 --- a/public/static/game/default.css +++ /dev/null @@ -1,6 +0,0 @@ -html {height:0%; margin:0px;} -body {background-color: #fff;} -h1 {margin:20px; text-align:center;} -h2 {margin:20px; padding-bottom:20px; text-align:left; font-size:13px;} -div#content, form {margin:20px; font-size:13px;} -p {padding-left:0px;} diff --git a/public/static/header/header_tiny.png b/public/static/header/header_tiny.png deleted file mode 100644 index cf330d5..0000000 Binary files a/public/static/header/header_tiny.png and /dev/null differ diff --git a/public/static/jquery-1.4.4.min.js b/public/static/jquery-1.4.4.min.js deleted file mode 100644 index 8f3ca2e..0000000 --- a/public/static/jquery-1.4.4.min.js +++ /dev/null @@ -1,167 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.4 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Thu Nov 11 19:04:53 2010 -0500 - */ -(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h= -h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;kd)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La, -"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this, -e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a, -"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+ -a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/, -C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j, -s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this, -j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length}, -toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j=== --1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false; -if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload", -b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&& -!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&& -l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H
    a";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"), -k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false, -scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent= -false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom= -1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="
    ";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="
    t
    ";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display= -"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h= -c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando); -else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one"; -if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true}, -attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&& -b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0}; -c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem, -arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid= -d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+ -c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType=== -8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k=== -"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+ -d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired= -B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type=== -"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]=== -0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}}); -(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3]; -break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr, -q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h= -l;g.sort(w);if(h)for(var i=1;i0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n, -m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled=== -true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"=== -g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return in[3]-0},nth:function(g,i,n){return n[3]- -0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()=== -i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]]; -if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m, -g);else if(typeof g.length==="number")for(var p=g.length;n";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g); -n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&& -function(){var g=k,i=t.createElement("div");i.innerHTML="

    ";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F|| -p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g= -t.createElement("div");g.innerHTML="
    ";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition? -function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n0)for(var h=d;h0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h= -h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context): -c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a, -2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a, -b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&& -e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/\s]+\/)>/g,P={option:[1, -""],legend:[1,"
    ","
    "],thead:[1,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],col:[2,"","
    "],area:[1,"",""],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div
    ","
    "];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d= -c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this}, -wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})}, -prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b, -this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild); -return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null; -else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1>");try{for(var b=0,d=this.length;b0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append", -prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument|| -b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]===""&&!x?r.childNodes:[];for(o=k.length- -1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script")))); -d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i, -jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true, -zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b), -h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b); -if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f= -d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left; -e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/)<[^<]*)*<\/script>/gi, -ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b=== -"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("
    ").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&& -!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})}, -getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html", -script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data|| -!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache= -false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset; -A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type", -b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&& -c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d|| -c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]= -encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess", -[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"), -e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}}); -if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show", -3),a,b,d);else{d=0;for(var e=this.length;d=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b, -d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a* -Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)} -var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true; -this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide|| -this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a= -c.timers,b=0;b-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a, -e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&& -c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase(); -c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+ -b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window); diff --git a/public/static/jquery.weekcalendar.css b/public/static/jquery.weekcalendar.css deleted file mode 100644 index 4e30be6..0000000 --- a/public/static/jquery.weekcalendar.css +++ /dev/null @@ -1,194 +0,0 @@ - - -.wc-container { - font-size: 14px; - font-family: arial, helvetica; -} - -.wc-nav { - padding: 1em; - text-align: right; -} - -.wc-nav button { - margin: 0 0.5em; -} - - -.wc-container table { - border-collapse: collapse; - border-spacing: 0; -} -.wc-container table td { - margin: 0; - padding: 0; -} - -.wc-header { - background: #eee; - border-top: 1px solid #aaa; - border-bottom: 1px solid #aaa; - width: 100%; -} - -.wc-header .wc-time-column-header { - width: 6%; -} - -.wc-header .wc-scrollbar-shim { - width: 16px; -} - -.wc-header .wc-day-column-header { - text-align: center; - padding: 0.4em; -} -.wc-header td { - background-color: #eee; -} - -.wc-grid-timeslot-header { - width: 6%; - background: #eee; -} - - - -.wc-scrollable-grid { - overflow: auto; - overflow-x: hidden !important; - overflow-y: auto !important; - position: relative; - background-color: #fff; - width: 100%; -} - - -table.wc-time-slots { - width: 100%; - table-layout: fixed; - cursor: default; -} - -.wc-day-column { - width: 13.5%; - border-left: 1px solid #ddd; - overflow: visible; - vertical-align: top; -} - -.wc-day-column-inner { - width: 100%; - position:relative; -} - -.wc-time-slot-wrapper { - position:relative; - height: 1px; - top: 1px; -} - -.wc-time-slots { - position: absolute; - width: 100%; -} - - -.wc-time-header-cell { - padding: 5px; - height: 80px; /* reference height */ -} - - -.wc-time-slot { - border-bottom: 1px dotted #ddd; -} - -.wc-hour-header { - text-align: right; -} - -.wc-hour-end, .wc-hour-header { - border-bottom: 1px solid #ccc; - color: #555; -} - -.wc-business-hours { - background-color: #E6EEF1; - border-bottom: 1px solid #ccc; - color: #333; - font-size: 1.4em; -} - -.wc-business-hours .wc-am-pm { - font-size: 0.6em; -} - -.wc-day-header-cell { - text-align: center; - vertical-align: middle; - padding: 5px; -} - - - -.wc-time-slot-header .wc-header-cell { - text-align: right; - padding-right: 10px; -} - -.wc-header .wc-today { - font-weight: bold; -} - -.wc-time-slots .wc-today { - background-color: #ffffcc; -} - - -.wc-cal-event { - background-color: #68a1e5; - filter:alpha(opacity=80); - -moz-opacity:0.8; - -khtml-opacity: 0.8; - opacity: 0.8; - position: absolute; - text-align: center; - overflow: hidden; - cursor: pointer; - color: #fff; - width: 100%; - display: none; -} - - -.wc-cal-event div { - padding: 0 5px; - -} - -.wc-cal-event .wc-time { - background-color: #2b72d0; - border: 1px solid #1b62c0; - color: #fff; - padding: 0; - font-weight: bold; -} - -.wc-container .ui-draggable .wc-time { - cursor: move; -} - -.wc-cal-event .wc-title { - position: relative; -} - -.wc-container .ui-resizable-s { - height: 10px; - bottom: -8px; -} - - -.wc-container .ui-draggable-dragging { - z-index: 1000; -} diff --git a/public/static/jquery.weekcalendar.js b/public/static/jquery.weekcalendar.js deleted file mode 100644 index 43b69a5..0000000 --- a/public/static/jquery.weekcalendar.js +++ /dev/null @@ -1,1407 +0,0 @@ -/* - * jQuery.weekCalendar v1.2.2 - * http://www.redredred.com.au/ - * - * Requires: - * - jquery.weekcalendar.css - * - jquery 1.3.x - * - jquery-ui 1.7.x (widget, drag, drop, resize) - * - * Copyright (c) 2009 Rob Monie - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * - * If you're after a monthly calendar plugin, check out http://arshaw.com/fullcalendar/ - */ - -(function($) { - - $.widget("ui.weekCalendar", { - - /*********************** - * Initialise calendar * - ***********************/ - _init : function() { - var self = this; - self._computeOptions(); - self._setupEventDelegation(); - self._renderCalendar(); - self._loadCalEvents(); - self._resizeCalendar(); - self._scrollToHour(self.options.date.getHours()); - - $(window).unbind("resize.weekcalendar"); - $(window).bind("resize.weekcalendar", function() { - self._resizeCalendar(); - }); - - }, - - /******************** - * public functions * - ********************/ - /* - * Refresh the events for the currently displayed week. - */ - refresh : function() { - this._clearCalendar(); - this._loadCalEvents(this.element.data("startDate")); //reload with existing week - }, - - /* - * Clear all events currently loaded into the calendar - */ - clear : function() { - this._clearCalendar(); - }, - - /* - * Go to this week - */ - today : function() { - this._clearCalendar(); - this._loadCalEvents(new Date()); - }, - - /* - * Go to the previous week relative to the currently displayed week - */ - prevWeek : function() { - //minus more than 1 day to be sure we're in previous week - account for daylight savings or other anomolies - var newDate = new Date(this.element.data("startDate").getTime() - (MILLIS_IN_WEEK / 6)); - this._clearCalendar(); - this._loadCalEvents(newDate); - }, - - /* - * Go to the next week relative to the currently displayed week - */ - nextWeek : function() { - //add 8 days to be sure of being in prev week - allows for daylight savings or other anomolies - var newDate = new Date(this.element.data("startDate").getTime() + MILLIS_IN_WEEK + (MILLIS_IN_WEEK / 7)); - this._clearCalendar(); - this._loadCalEvents(newDate); - }, - - /* - * Reload the calendar to whatever week the date passed in falls on. - */ - gotoWeek : function(date) { - this._clearCalendar(); - this._loadCalEvents(date); - }, - - /* - * Remove an event based on it's id - */ - removeEvent : function(eventId) { - - var self = this; - - self.element.find(".wc-cal-event").each(function() { - if ($(this).data("calEvent").id === eventId) { - $(this).remove(); - return false; - } - }); - - //this could be more efficient rather than running on all days regardless... - self.element.find(".wc-day-column-inner").each(function() { - self._adjustOverlappingEvents($(this)); - }); - }, - - /* - * Removes any events that have been added but not yet saved (have no id). - * This is useful to call after adding a freshly saved new event. - */ - removeUnsavedEvents : function() { - - var self = this; - - self.element.find(".wc-new-cal-event").each(function() { - $(this).remove(); - }); - - //this could be more efficient rather than running on all days regardless... - self.element.find(".wc-day-column-inner").each(function() { - self._adjustOverlappingEvents($(this)); - }); - }, - - /* - * update an event in the calendar. If the event exists it refreshes - * it's rendering. If it's a new event that does not exist in the calendar - * it will be added. - */ - updateEvent : function (calEvent) { - this._updateEventInCalendar(calEvent); - }, - - /* - * Returns an array of timeslot start and end times based on - * the configured grid of the calendar. Returns in both date and - * formatted time based on the 'timeFormat' config option. - */ - getTimeslotTimes : function(date) { - var options = this.options; - var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0; - var startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), firstHourDisplayed); - - var times = [] - var startMillis = startDate.getTime(); - for (var i = 0; i < options.timeslotsPerDay; i++) { - var endMillis = startMillis + options.millisPerTimeslot; - times[i] = { - start: new Date(startMillis), - startFormatted: this._formatDate(new Date(startMillis), options.timeFormat), - end: new Date(endMillis), - endFormatted: this._formatDate(new Date(endMillis), options.timeFormat) - }; - startMillis = endMillis; - } - return times; - }, - - formatDate : function(date, format) { - if (format) { - return this._formatDate(date, format); - } else { - return this._formatDate(date, this.options.dateFormat); - } - }, - - formatTime : function(date, format) { - if (format) { - return this._formatDate(date, format); - } else { - return this._formatDate(date, this.options.timeFormat); - } - }, - - getData : function(key) { - return this._getData(key); - }, - - /********************* - * private functions * - *********************/ - // compute dynamic options based on other config values - _computeOptions : function() { - - var options = this.options; - - if (options.businessHours.limitDisplay) { - options.timeslotsPerDay = options.timeslotsPerHour * (options.businessHours.end - options.businessHours.start); - options.millisToDisplay = (options.businessHours.end - options.businessHours.start) * 60 * 60 * 1000; - options.millisPerTimeslot = options.millisToDisplay / options.timeslotsPerDay; - } else { - options.timeslotsPerDay = options.timeslotsPerHour * 24; - options.millisToDisplay = MILLIS_IN_DAY; - options.millisPerTimeslot = MILLIS_IN_DAY / options.timeslotsPerDay; - } - }, - - /* - * Resize the calendar scrollable height based on the provided function in options. - */ - _resizeCalendar : function () { - - var options = this.options; - if (options && $.isFunction(options.height)) { - var calendarHeight = options.height(this.element); - var headerHeight = this.element.find(".wc-header").outerHeight(); - var navHeight = this.element.find(".wc-nav").outerHeight(); - this.element.find(".wc-scrollable-grid").height(calendarHeight - navHeight - headerHeight); - } - }, - - /* - * configure calendar interaction events that are able to use event - * delegation for greater efficiency - */ - _setupEventDelegation : function() { - var self = this; - var options = this.options; - this.element.click(function(event) { - var $target = $(event.target); - if ($target.data("preventClick")) { - return; - } - if ($target.hasClass("wc-cal-event")) { - options.eventClick($target.data("calEvent"), $target, event); - } else if ($target.parent().hasClass("wc-cal-event")) { - options.eventClick($target.parent().data("calEvent"), $target.parent(), event); - } - }).mouseover(function(event) { - var $target = $(event.target); - - if (self._isDraggingOrResizing($target)) { - return; - } - - if ($target.hasClass("wc-cal-event")) { - options.eventMouseover($target.data("calEvent"), $target, event); - } - }).mouseout(function(event) { - var $target = $(event.target); - if (self._isDraggingOrResizing($target)) { - return; - } - if ($target.hasClass("wc-cal-event")) { - if ($target.data("sizing")) return; - options.eventMouseout($target.data("calEvent"), $target, event); - - } - }); - }, - - /* - * check if a ui draggable or resizable is currently being dragged or resized - */ - _isDraggingOrResizing : function ($target) { - return $target.hasClass("ui-draggable-dragging") || $target.hasClass("ui-resizable-resizing"); - }, - - /* - * Render the main calendar layout - */ - _renderCalendar : function() { - - var $calendarContainer, calendarNavHtml, calendarHeaderHtml, calendarBodyHtml, $weekDayColumns; - var self = this; - var options = this.options; - - $calendarContainer = $("
    ").appendTo(self.element); - - if (options.buttons) { - calendarNavHtml = "
    \ - \ - \ - \ -
    "; - - $(calendarNavHtml).appendTo($calendarContainer); - - $calendarContainer.find(".wc-nav .wc-today").click(function() { - self.element.weekCalendar("today"); - return false; - }); - - $calendarContainer.find(".wc-nav .wc-prev").click(function() { - self.element.weekCalendar("prevWeek"); - return false; - }); - - $calendarContainer.find(".wc-nav .wc-next").click(function() { - self.element.weekCalendar("nextWeek"); - return false; - }); - - } - - //render calendar header - calendarHeaderHtml = "
    "; - for (var i = 1; i <= options.daysToShow; i++) { - calendarHeaderHtml += ""; - } - calendarHeaderHtml += "
    "; - - //render calendar body - calendarBodyHtml = "
    \ - \ - \ - \ - \ - "; - - for (var i = 1; i <= options.daysToShow; i++) { - calendarBodyHtml += "" - } - - calendarBodyHtml += "
    \ -
    \ -
    "; - - var start = options.businessHours.limitDisplay ? options.businessHours.start : 0; - var end = options.businessHours.limitDisplay ? options.businessHours.end : 24; - - for (var i = start; i < end; i++) { - for (var j = 0; j < options.timeslotsPerHour - 1; j++) { - calendarBodyHtml += "
    "; - } - calendarBodyHtml += "
    "; - } - - calendarBodyHtml += "
    "; - - for (var i = start; i < end; i++) { - - var bhClass = (options.businessHours.start <= i && options.businessHours.end > i) ? "wc-business-hours" : ""; - calendarBodyHtml += "
    " - if (options.use24Hour) { - calendarBodyHtml += "
    " + self._24HourForIndex(i) + "
    "; - } else { - calendarBodyHtml += "
    " + self._hourForIndex(i) + "" + self._amOrPm(i) + "
    "; - } - calendarBodyHtml += "
    "; - } - - calendarBodyHtml += "
    "; - - //append all calendar parts to container - $(calendarHeaderHtml + calendarBodyHtml).appendTo($calendarContainer); - - $weekDayColumns = $calendarContainer.find(".wc-day-column-inner"); - $weekDayColumns.each(function(i, val) { - $(this).height(options.timeslotHeight * options.timeslotsPerDay); - if (!options.readonly) { - self._addDroppableToWeekDay($(this)); - self._setupEventCreationForWeekDay($(this)); - } - }); - - $calendarContainer.find(".wc-time-slot").height(options.timeslotHeight - 1); //account for border - - $calendarContainer.find(".wc-time-header-cell").css({ - height : (options.timeslotHeight * options.timeslotsPerHour) - 11, - padding: 5 - }); - - - }, - - /* - * setup mouse events for capturing new events - */ - _setupEventCreationForWeekDay : function($weekDay) { - var self = this; - var options = this.options; - $weekDay.mousedown(function(event) { - var $target = $(event.target); - if ($target.hasClass("wc-day-column-inner")) { - - var $newEvent = $("
    "); - - $newEvent.css({lineHeight: (options.timeslotHeight - 2) + "px", fontSize: (options.timeslotHeight / 2) + "px"}); - $target.append($newEvent); - - var columnOffset = $target.offset().top; - var clickY = event.pageY - columnOffset; - var clickYRounded = (clickY - (clickY % options.timeslotHeight)) / options.timeslotHeight; - var topPosition = clickYRounded * options.timeslotHeight; - $newEvent.css({top: topPosition}); - - $target.bind("mousemove.newevent", function(event) { - $newEvent.show(); - $newEvent.addClass("ui-resizable-resizing"); - var height = Math.round(event.pageY - columnOffset - topPosition); - var remainder = height % options.timeslotHeight; - //snap to closest timeslot - if (remainder < (height / 2)) { - var useHeight = height - remainder; - $newEvent.css("height", useHeight < options.timeslotHeight ? options.timeslotHeight : useHeight); - } else { - $newEvent.css("height", height + (options.timeslotHeight - remainder)); - } - }).mouseup(function() { - $target.unbind("mousemove.newevent"); - $newEvent.addClass("ui-corner-all"); - }); - } - - }).mouseup(function(event) { - var $target = $(event.target); - - var $weekDay = $target.closest(".wc-day-column-inner"); - var $newEvent = $weekDay.find(".wc-new-cal-event-creating"); - - if ($newEvent.length) { - //if even created from a single click only, default height - if (!$newEvent.hasClass("ui-resizable-resizing")) { - $newEvent.css({height: options.timeslotHeight * options.defaultEventLength}).show(); - } - var top = parseInt($newEvent.css("top")); - var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $newEvent, top); - - $newEvent.remove(); - var newCalEvent = {start: eventDuration.start, end: eventDuration.end, title: options.newEventText}; - var $renderedCalEvent = self._renderEvent(newCalEvent, $weekDay); - - if (!options.allowCalEventOverlap) { - self._adjustForEventCollisions($weekDay, $renderedCalEvent, newCalEvent, newCalEvent); - self._positionEvent($weekDay, $renderedCalEvent); - } else { - self._adjustOverlappingEvents($weekDay); - } - - options.eventNew(eventDuration, $renderedCalEvent); - } - }); - }, - - /* - * load calendar events for the week based on the date provided - */ - _loadCalEvents : function(dateWithinWeek) { - - var date, weekStartDate, endDate, $weekDayColumns; - var self = this; - var options = this.options; - date = dateWithinWeek || options.date; - weekStartDate = self._dateFirstDayOfWeek(date); - weekEndDate = self._dateLastMilliOfWeek(date); - - options.calendarBeforeLoad(self.element); - - self.element.data("startDate", weekStartDate); - self.element.data("endDate", weekEndDate); - - $weekDayColumns = self.element.find(".wc-day-column-inner"); - - self._updateDayColumnHeader($weekDayColumns); - - //load events by chosen means - if (typeof options.data == 'string') { - if (options.loading) options.loading(true); - var jsonOptions = {}; - jsonOptions[options.startParam || 'start'] = Math.round(weekStartDate.getTime() / 1000); - jsonOptions[options.endParam || 'end'] = Math.round(weekEndDate.getTime() / 1000); - $.getJSON(options.data, jsonOptions, function(data) { - self._renderEvents(data, $weekDayColumns); - if (options.loading) options.loading(false); - }); - } - else if ($.isFunction(options.data)) { - options.data(weekStartDate, weekEndDate, - function(data) { - self._renderEvents(data, $weekDayColumns); - }); - } - else if (options.data) { - self._renderEvents(options.data, $weekDayColumns); - } - - self._disableTextSelect($weekDayColumns); - - - }, - - /* - * update the display of each day column header based on the calendar week - */ - _updateDayColumnHeader : function ($weekDayColumns) { - var self = this; - var options = this.options; - var currentDay = self._cloneDate(self.element.data("startDate")); - - self.element.find(".wc-header td.wc-day-column-header").each(function(i, val) { - - var dayName = options.useShortDayNames ? options.shortDays[currentDay.getDay()] : options.longDays[currentDay.getDay()]; - - $(this).html(dayName + "
    " + self._formatDate(currentDay, options.dateFormat)); - if (self._isToday(currentDay)) { - $(this).addClass("wc-today"); - } else { - $(this).removeClass("wc-today"); - } - currentDay = self._addDays(currentDay, 1); - - }); - - currentDay = self._dateFirstDayOfWeek(self._cloneDate(self.element.data("startDate"))); - - $weekDayColumns.each(function(i, val) { - - $(this).data("startDate", self._cloneDate(currentDay)); - $(this).data("endDate", new Date(currentDay.getTime() + (MILLIS_IN_DAY))); - if (self._isToday(currentDay)) { - $(this).parent().addClass("wc-today"); - } else { - $(this).parent().removeClass("wc-today"); - } - - currentDay = self._addDays(currentDay, 1); - }); - - }, - - /* - * Render the events into the calendar - */ - _renderEvents : function (events, $weekDayColumns) { - var self = this; - var options = this.options; - var eventsToRender; - - if ($.isArray(events)) { - eventsToRender = self._cleanEvents(events); - } else if (events.events) { - eventsToRender = self._cleanEvents(events.events); - } - if (events.options) { - - var updateLayout = false; - //update options - $.each(events.options, function(key, value) { - if (value !== options[key]) { - options[key] = value; - updateLayout = true; - } - }); - - self._computeOptions(); - - if (updateLayout) { - self.element.empty(); - self._renderCalendar(); - $weekDayColumns = self.element.find(".wc-time-slots .wc-day-column-inner"); - self._updateDayColumnHeader($weekDayColumns); - self._resizeCalendar(); - } - - } - - - $.each(eventsToRender, function(i, calEvent) { - - var $weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns); - - if ($weekDay) { - self._renderEvent(calEvent, $weekDay); - } - }); - - $weekDayColumns.each(function() { - self._adjustOverlappingEvents($(this)); - }); - - options.calendarAfterLoad(self.element); - - if (!eventsToRender.length) { - options.noEvents(); - } - - }, - - /* - * Render a specific event into the day provided. Assumes correct - * day for calEvent date - */ - _renderEvent: function (calEvent, $weekDay) { - var self = this; - var options = this.options; - if (calEvent.start.getTime() > calEvent.end.getTime()) { - return; // can't render a negative height - } - - var eventClass, eventHtml, $calEvent, $modifiedEvent; - - eventClass = calEvent.id ? "wc-cal-event" : "wc-cal-event wc-new-cal-event"; - eventHtml = "
    \ -
    \ -
    "; - - $calEvent = $(eventHtml); - $modifiedEvent = options.eventRender(calEvent, $calEvent); - $calEvent = $modifiedEvent ? $modifiedEvent.appendTo($weekDay) : $calEvent.appendTo($weekDay); - $calEvent.css({lineHeight: (options.timeslotHeight - 2) + "px", fontSize: (options.timeslotHeight / 2) + "px"}); - - self._refreshEventDetails(calEvent, $calEvent); - self._positionEvent($weekDay, $calEvent); - $calEvent.show(); - - if (!options.readonly && options.resizable(calEvent, $calEvent)) { - self._addResizableToCalEvent(calEvent, $calEvent, $weekDay) - } - if (!options.readonly && options.draggable(calEvent, $calEvent)) { - self._addDraggableToCalEvent(calEvent, $calEvent); - } - - options.eventAfterRender(calEvent, $calEvent); - - return $calEvent; - - }, - - _adjustOverlappingEvents : function($weekDay) { - var self = this; - if (self.options.allowCalEventOverlap) { - var groupsList = self._groupOverlappingEventElements($weekDay); - $.each(groupsList, function() { - var curGroups = this; - $.each(curGroups, function(groupIndex) { - var curGroup = this; - - // do we want events to be displayed as overlapping - if (self.options.overlapEventsSeparate) { - var newWidth = 100 / curGroups.length; - var newLeft = groupIndex * newWidth; - } else { - // TODO what happens when the group has more than 10 elements - var newWidth = 100 - ( (curGroups.length - 1) * 10 ); - var newLeft = groupIndex * 10; - } - $.each(curGroup, function() { - // bring mouseovered event to the front - if (!self.options.overlapEventsSeparate) { - $(this).bind("mouseover.z-index", function() { - var $elem = $(this); - $.each(curGroup, function() { - $(this).css({"z-index": "1"}); - }); - $elem.css({"z-index": "3"}); - }); - } - $(this).css({width: newWidth + "%", left:newLeft + "%", right: 0}); - }); - }); - }); - } - }, - - - /* - * Find groups of overlapping events - */ - _groupOverlappingEventElements : function($weekDay) { - var $events = $weekDay.find(".wc-cal-event:visible"); - var sortedEvents = $events.sort(function(a, b) { - return $(a).data("calEvent").start.getTime() - $(b).data("calEvent").start.getTime(); - }); - - var lastEndTime = new Date(0, 0, 0); - var groups = []; - var curGroups = []; - var $curEvent; - $.each(sortedEvents, function() { - $curEvent = $(this); - //checks, if the current group list is not empty, if the overlapping is finished - if (curGroups.length > 0) { - if (lastEndTime.getTime() <= $curEvent.data("calEvent").start.getTime()) { - //finishes the current group list by adding it to the resulting list of groups and cleans it - - groups.push(curGroups); - curGroups = []; - } - } - - //finds the first group to fill with the event - for (var groupIndex = 0; groupIndex < curGroups.length; groupIndex++) { - if (curGroups[groupIndex].length > 0) { - //checks if the event starts after the end of the last event of the group - if (curGroups[groupIndex][curGroups [groupIndex].length - 1].data("calEvent").end.getTime() <= $curEvent.data("calEvent").start.getTime()) { - curGroups[groupIndex].push($curEvent); - if (lastEndTime.getTime() < $curEvent.data("calEvent").end.getTime()) { - lastEndTime = $curEvent.data("calEvent").end; - } - return; - } - } - } - //if not found, creates a new group - curGroups.push([$curEvent]); - if (lastEndTime.getTime() < $curEvent.data("calEvent").end.getTime()) { - lastEndTime = $curEvent.data("calEvent").end; - } - }); - //adds the last groups in result - if (curGroups.length > 0) { - groups.push(curGroups); - } - return groups; - }, - - - /* - * find the weekday in the current calendar that the calEvent falls within - */ - _findWeekDayForEvent : function(calEvent, $weekDayColumns) { - - var $weekDay; - $weekDayColumns.each(function() { - if ($(this).data("startDate").getTime() <= calEvent.start.getTime() && $(this).data("endDate").getTime() >= calEvent.end.getTime()) { - $weekDay = $(this); - return false; - } - }); - return $weekDay; - }, - - /* - * update the events rendering in the calendar. Add if does not yet exist. - */ - _updateEventInCalendar : function (calEvent) { - var self = this; - var options = this.options; - self._cleanEvent(calEvent); - - if (calEvent.id) { - self.element.find(".wc-cal-event").each(function() { - if ($(this).data("calEvent").id === calEvent.id || $(this).hasClass("wc-new-cal-event")) { - $(this).remove(); - return false; - } - }); - } - - var $weekDay = self._findWeekDayForEvent(calEvent, self.element.find(".wc-time-slots .wc-day-column-inner")); - if ($weekDay) { - var $calEvent = self._renderEvent(calEvent, $weekDay); - self._adjustForEventCollisions($weekDay, $calEvent, calEvent, calEvent); - self._refreshEventDetails(calEvent, $calEvent); - self._positionEvent($weekDay, $calEvent); - self._adjustOverlappingEvents($weekDay); - } - }, - - /* - * Position the event element within the weekday based on it's start / end dates. - */ - _positionEvent : function($weekDay, $calEvent) { - var options = this.options; - var calEvent = $calEvent.data("calEvent"); - var pxPerMillis = $weekDay.height() / options.millisToDisplay; - var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0; - var startMillis = calEvent.start.getTime() - new Date(calEvent.start.getFullYear(), calEvent.start.getMonth(), calEvent.start.getDate(), firstHourDisplayed).getTime(); - var eventMillis = calEvent.end.getTime() - calEvent.start.getTime(); - var pxTop = pxPerMillis * startMillis; - var pxHeight = pxPerMillis * eventMillis; - $calEvent.css({top: pxTop, height: pxHeight}); - }, - - /* - * Determine the actual start and end times of a calevent based on it's - * relative position within the weekday column and the starting hour of the - * displayed calendar. - */ - _getEventDurationFromPositionedEventElement : function($weekDay, $calEvent, top) { - var options = this.options; - var startOffsetMillis = options.businessHours.limitDisplay ? options.businessHours.start * 60 * 60 * 1000 : 0; - var start = new Date($weekDay.data("startDate").getTime() + startOffsetMillis + Math.round(top / options.timeslotHeight) * options.millisPerTimeslot); - var end = new Date(start.getTime() + ($calEvent.height() / options.timeslotHeight) * options.millisPerTimeslot); - return {start: start, end: end}; - }, - - /* - * If the calendar does not allow event overlap, adjust the start or end date if necessary to - * avoid overlapping of events. Typically, shortens the resized / dropped event to it's max possible - * duration based on the overlap. If no satisfactory adjustment can be made, the event is reverted to - * it's original location. - */ - _adjustForEventCollisions : function($weekDay, $calEvent, newCalEvent, oldCalEvent, maintainEventDuration) { - var options = this.options; - - if (options.allowCalEventOverlap) { - return; - } - var adjustedStart, adjustedEnd; - var self = this; - - $weekDay.find(".wc-cal-event").not($calEvent).each(function() { - var currentCalEvent = $(this).data("calEvent"); - - //has been dropped onto existing event overlapping the end time - if (newCalEvent.start.getTime() < currentCalEvent.end.getTime() - && newCalEvent.end.getTime() >= currentCalEvent.end.getTime()) { - - adjustedStart = currentCalEvent.end; - } - - - //has been dropped onto existing event overlapping the start time - if (newCalEvent.end.getTime() > currentCalEvent.start.getTime() - && newCalEvent.start.getTime() <= currentCalEvent.start.getTime()) { - - adjustedEnd = currentCalEvent.start; - } - //has been dropped inside existing event with same or larger duration - if (! oldCalEvent.resizable || (newCalEvent.end.getTime() <= currentCalEvent.end.getTime() - && newCalEvent.start.getTime() >= currentCalEvent.start.getTime())) { - - adjustedStart = oldCalEvent.start; - adjustedEnd = oldCalEvent.end; - return false; - } - - }); - - - newCalEvent.start = adjustedStart || newCalEvent.start; - - if (adjustedStart && maintainEventDuration) { - newCalEvent.end = new Date(adjustedStart.getTime() + (oldCalEvent.end.getTime() - oldCalEvent.start.getTime())); - self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, oldCalEvent); - } else { - newCalEvent.end = adjustedEnd || newCalEvent.end; - } - - - //reset if new cal event has been forced to zero size - if (newCalEvent.start.getTime() >= newCalEvent.end.getTime()) { - newCalEvent.start = oldCalEvent.start; - newCalEvent.end = oldCalEvent.end; - } - - $calEvent.data("calEvent", newCalEvent); - }, - - /* - * Add draggable capabilities to an event - */ - _addDraggableToCalEvent : function(calEvent, $calEvent) { - var self = this; - var options = this.options; - var $weekDay = self._findWeekDayForEvent(calEvent, self.element.find(".wc-time-slots .wc-day-column-inner")); - $calEvent.draggable({ - handle : ".wc-time", - containment: ".wc-scrollable-grid", - revert: 'valid', - opacity: 0.5, - grid : [$calEvent.outerWidth() + 1, options.timeslotHeight ], - start : function(event, ui) { - var $calEvent = ui.draggable; - options.eventDrag(calEvent, $calEvent); - } - }); - - }, - - /* - * Add droppable capabilites to weekdays to allow dropping of calEvents only - */ - _addDroppableToWeekDay : function($weekDay) { - var self = this; - var options = this.options; - $weekDay.droppable({ - accept: ".wc-cal-event", - drop: function(event, ui) { - var $calEvent = ui.draggable; - var top = Math.round(parseInt(ui.position.top)); - var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $calEvent, top); - var calEvent = $calEvent.data("calEvent"); - var newCalEvent = $.extend(true, {start: eventDuration.start, end: eventDuration.end}, calEvent); - self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent, true); - var $weekDayColumns = self.element.find(".wc-day-column-inner"); - var $newEvent = self._renderEvent(newCalEvent, self._findWeekDayForEvent(newCalEvent, $weekDayColumns)); - $calEvent.hide(); - - //trigger drop callback - options.eventDrop(newCalEvent, calEvent, $newEvent); - $calEvent.data("preventClick", true); - - var $weekDayOld = self._findWeekDayForEvent($calEvent.data("calEvent"), self.element.find(".wc-time-slots .wc-day-column-inner")); - - if ($weekDayOld.data("startDate") != $weekDay.data("startDate")) { - self._adjustOverlappingEvents($weekDayOld); - } - self._adjustOverlappingEvents($weekDay); - - setTimeout(function() { - $calEvent.remove(); - }, 1000); - - } - }); - }, - - /* - * Add resizable capabilities to a calEvent - */ - _addResizableToCalEvent : function(calEvent, $calEvent, $weekDay) { - var self = this; - var options = this.options; - $calEvent.resizable({ - grid: options.timeslotHeight, - containment : $weekDay, - handles: "s", - minHeight: options.timeslotHeight, - stop :function(event, ui) { - var $calEvent = ui.element; - var newEnd = new Date($calEvent.data("calEvent").start.getTime() + ($calEvent.height() / options.timeslotHeight) * options.millisPerTimeslot); - var newCalEvent = $.extend(true, {start: calEvent.start, end: newEnd}, calEvent); - self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent); - - self._refreshEventDetails(newCalEvent, $calEvent); - self._positionEvent($weekDay, $calEvent); - self._adjustOverlappingEvents($weekDay); - //trigger resize callback - options.eventResize(newCalEvent, calEvent, $calEvent); - $calEvent.data("preventClick", true); - setTimeout(function() { - $calEvent.removeData("preventClick"); - }, 500); - } - }); - }, - - /* - * Refresh the displayed details of a calEvent in the calendar - */ - _refreshEventDetails : function(calEvent, $calEvent) { - var self = this; - var options = this.options; - $calEvent.find(".wc-time").html(self._formatDate(calEvent.start, options.timeFormat) + options.timeSeparator + self._formatDate(calEvent.end, options.timeFormat)); - $calEvent.find(".wc-title").html(calEvent.title); - $calEvent.data("calEvent", calEvent); - }, - - /* - * Clear all cal events from the calendar - */ - _clearCalendar : function() { - this.element.find(".wc-day-column-inner div").remove(); - }, - - /* - * Scroll the calendar to a specific hour - */ - _scrollToHour : function(hour) { - var self = this; - var options = this.options; - var $scrollable = this.element.find(".wc-scrollable-grid"); - var slot = hour; - if (self.options.businessHours.limitDisplay) { - if (hour <= self.options.businessHours.start) { - slot = 0; - } else if (hour > self.options.businessHours.end) { - slot = self.options.businessHours.end - - self.options.businessHours.start - 1; - } else { - slot = hour - self.options.businessHours.start; - } - - } - - var $target = this.element.find(".wc-grid-timeslot-header .wc-hour-header:eq(" + slot + ")"); - - $scrollable.animate({scrollTop: 0}, 0, function() { - var targetOffset = $target.offset().top; - var scroll = targetOffset - $scrollable.offset().top - $target.outerHeight(); - $scrollable.animate({scrollTop: scroll}, options.scrollToHourMillis); - }); - }, - - /* - * find the hour (12 hour day) for a given hour index - */ - _hourForIndex : function(index) { - if (index === 0) { //midnight - return 12; - } else if (index < 13) { //am - return index; - } else { //pm - return index - 12; - } - }, - - _24HourForIndex : function(index) { - if (index === 0) { //midnight - return "00:00"; - } else if (index < 10) { - return "0" + index + ":00"; - } else { - return index + ":00"; - } - }, - - _amOrPm : function (hourOfDay) { - return hourOfDay < 12 ? "AM" : "PM"; - }, - - _isToday : function(date) { - var clonedDate = this._cloneDate(date); - this._clearTime(clonedDate); - var today = new Date(); - this._clearTime(today); - return today.getTime() === clonedDate.getTime(); - }, - - /* - * Clean events to ensure correct format - */ - _cleanEvents : function(events) { - var self = this; - $.each(events, function(i, event) { - self._cleanEvent(event); - }); - return events; - }, - - /* - * Clean specific event - */ - _cleanEvent : function (event) { - if (event.date) { - event.start = event.date; - } - event.start = this._cleanDate(event.start); - event.end = this._cleanDate(event.end); - if (!event.end) { - event.end = this._addDays(this._cloneDate(event.start), 1); - } - }, - - /* - * Disable text selection of the elements in different browsers - */ - _disableTextSelect : function($elements) { - $elements.each(function() { - if ($.browser.mozilla) {//Firefox - $(this).css('MozUserSelect', 'none'); - } else if ($.browser.msie) {//IE - $(this).bind('selectstart', function() { - return false; - }); - } else {//Opera, etc. - $(this).mousedown(function() { - return false; - }); - } - }); - }, - - /* - * returns the date on the first millisecond of the week - */ - _dateFirstDayOfWeek : function(date) { - var self = this; - var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); - var millisToSubtract = self._getAdjustedDayIndex(midnightCurrentDate) * 86400000; - return new Date(midnightCurrentDate.getTime() - millisToSubtract); - - }, - - /* - * returns the date on the first millisecond of the last day of the week - */ - _dateLastDayOfWeek : function(date) { - var self = this; - var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); - var millisToAdd = (6 - self._getAdjustedDayIndex(midnightCurrentDate)) * MILLIS_IN_DAY; - return new Date(midnightCurrentDate.getTime() + millisToAdd); - }, - - /* - * gets the index of the current day adjusted based on options - */ - _getAdjustedDayIndex : function(date) { - - var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate()); - var currentDayOfStandardWeek = midnightCurrentDate.getDay(); - var days = [0,1,2,3,4,5,6]; - this._rotate(days, this.options.firstDayOfWeek); - return days[currentDayOfStandardWeek]; - }, - - /* - * returns the date on the last millisecond of the week - */ - _dateLastMilliOfWeek : function(date) { - var lastDayOfWeek = this._dateLastDayOfWeek(date); - return new Date(lastDayOfWeek.getTime() + (MILLIS_IN_DAY)); - - }, - - /* - * Clear the time components of a date leaving the date - * of the first milli of day - */ - _clearTime : function(d) { - d.setHours(0); - d.setMinutes(0); - d.setSeconds(0); - d.setMilliseconds(0); - return d; - }, - - /* - * add specific number of days to date - */ - _addDays : function(d, n, keepTime) { - d.setDate(d.getDate() + n); - if (keepTime) { - return d; - } - return this._clearTime(d); - }, - - /* - * Rotate an array by specified number of places. - */ - _rotate : function(a /*array*/, p /* integer, positive integer rotate to the right, negative to the left... */) { - for (var l = a.length, p = (Math.abs(p) >= l && (p %= l),p < 0 && (p += l),p), i, x; p; p = (Math.ceil(l / p) - 1) * p - l + (l = p)) { - for (i = l; i > p; x = a[--i],a[i] = a[i - p],a[i - p] = x); - } - return a; - }, - - _cloneDate : function(d) { - return new Date(d.getTime()); - }, - - /* - * return a date for different representations - */ - _cleanDate : function(d) { - if (typeof d == 'string') { - return $.weekCalendar.parseISO8601(d, true) || Date.parse(d) || new Date(parseInt(d)); - } - if (typeof d == 'number') { - return new Date(d); - } - return d; - }, - - /* - * date formatting is adapted from - * http://jacwright.com/projects/javascript/date_format - */ - _formatDate : function(date, format) { - var options = this.options; - var returnStr = ''; - for (var i = 0; i < format.length; i++) { - var curChar = format.charAt(i); - if ($.isFunction(this._replaceChars[curChar])) { - returnStr += this._replaceChars[curChar](date, options); - } else { - returnStr += curChar; - } - } - return returnStr; - }, - - _replaceChars : { - - // Day - d: function(date) { - return (date.getDate() < 10 ? '0' : '') + date.getDate(); - }, - D: function(date, options) { - return options.shortDays[date.getDay()]; - }, - j: function(date) { - return date.getDate(); - }, - l: function(date, options) { - return options.longDays[date.getDay()]; - }, - N: function(date) { - return date.getDay() + 1; - }, - S: function(date) { - return (date.getDate() % 10 == 1 && date.getDate() != 11 ? 'st' : (date.getDate() % 10 == 2 && date.getDate() != 12 ? 'nd' : (date.getDate() % 10 == 3 && date.getDate() != 13 ? 'rd' : 'th'))); - }, - w: function(date) { - return date.getDay(); - }, - z: function(date) { - return "Not Yet Supported"; - }, - // Week - W: function(date) { - return "Not Yet Supported"; - }, - // Month - F: function(date, options) { - return options.longMonths[date.getMonth()]; - }, - m: function(date) { - return (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1); - }, - M: function(date, options) { - return options.shortMonths[date.getMonth()]; - }, - n: function(date) { - return date.getMonth() + 1; - }, - t: function(date) { - return "Not Yet Supported"; - }, - // Year - L: function(date) { - return "Not Yet Supported"; - }, - o: function(date) { - return "Not Supported"; - }, - Y: function(date) { - return date.getFullYear(); - }, - y: function(date) { - return ('' + date.getFullYear()).substr(2); - }, - // Time - a: function(date) { - return date.getHours() < 12 ? 'am' : 'pm'; - }, - A: function(date) { - return date.getHours() < 12 ? 'AM' : 'PM'; - }, - B: function(date) { - return "Not Yet Supported"; - }, - g: function(date) { - return date.getHours() % 12 || 12; - }, - G: function(date) { - return date.getHours(); - }, - h: function(date) { - return ((date.getHours() % 12 || 12) < 10 ? '0' : '') + (date.getHours() % 12 || 12); - }, - H: function(date) { - return (date.getHours() < 10 ? '0' : '') + date.getHours(); - }, - i: function(date) { - return (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); - }, - s: function(date) { - return (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); - }, - // Timezone - e: function(date) { - return "Not Yet Supported"; - }, - I: function(date) { - return "Not Supported"; - }, - O: function(date) { - return (date.getTimezoneOffset() < 0 ? '-' : '+') + (date.getTimezoneOffset() / 60 < 10 ? '0' : '') + (date.getTimezoneOffset() / 60) + '00'; - }, - T: function(date) { - return "Not Yet Supported"; - }, - Z: function(date) { - return date.getTimezoneOffset() * 60; - }, - // Full Date/Time - c: function(date) { - return "Not Yet Supported"; - }, - r: function(date) { - return date.toString(); - }, - U: function(date) { - return date.getTime() / 1000; - } - } - - }); - - $.extend($.ui.weekCalendar, { - version: '1.2.2-pre', - getter: ['getTimeslotTimes', 'getData', 'formatDate', 'formatTime'], - defaults: { - date: new Date(), - timeFormat : "h:i a", - dateFormat : "M d, Y", - use24Hour : false, - daysToShow : 7, - firstDayOfWeek : 0, // 0 = Sunday, 1 = Monday, 2 = Tuesday, ... , 6 = Saturday - useShortDayNames: false, - timeSeparator : " to ", - startParam : "start", - endParam : "end", - businessHours : {start: 8, end: 18, limitDisplay : false}, - newEventText : "New Event", - timeslotHeight: 20, - defaultEventLength : 2, - timeslotsPerHour : 4, - buttons : true, - buttonText : { - today : "today", - lastWeek : " < ", - nextWeek : " > " - }, - scrollToHourMillis : 500, - allowCalEventOverlap : false, - overlapEventsSeparate: false, - readonly: false, - draggable : function(calEvent, element) { - return true; - }, - resizable : function(calEvent, element) { - return true; - }, - eventClick : function() { - }, - eventRender : function(calEvent, element) { - return element; - }, - eventAfterRender : function(calEvent, element) { - return element; - }, - eventDrag : function(calEvent, element) { - }, - eventDrop : function(calEvent, element) { - }, - eventResize : function(calEvent, element) { - }, - eventNew : function(calEvent, element) { - }, - eventMouseover : function(calEvent, $event) { - }, - eventMouseout : function(calEvent, $event) { - }, - calendarBeforeLoad : function(calendar) { - }, - calendarAfterLoad : function(calendar) { - }, - noEvents : function() { - }, - shortMonths : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - longMonths : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], - shortDays : ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], - longDays : ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] - } - }); - - var MILLIS_IN_DAY = 86400000; - var MILLIS_IN_WEEK = MILLIS_IN_DAY * 7; - - $.weekCalendar = function() { - return { - parseISO8601 : function(s, ignoreTimezone) { - - // derived from http://delete.me.uk/2005/03/iso8601.html - var regexp = "([0-9]{4})(-([0-9]{2})(-([0-9]{2})" + - "(T([0-9]{2}):([0-9]{2})(:([0-9]{2})(\.([0-9]+))?)?" + - "(Z|(([-+])([0-9]{2}):([0-9]{2})))?)?)?)?"; - var d = s.match(new RegExp(regexp)); - if (!d) return null; - var offset = 0; - var date = new Date(d[1], 0, 1); - if (d[3]) { - date.setMonth(d[3] - 1); - } - if (d[5]) { - date.setDate(d[5]); - } - if (d[7]) { - date.setHours(d[7]); - } - if (d[8]) { - date.setMinutes(d[8]); - } - if (d[10]) { - date.setSeconds(d[10]); - } - if (d[12]) { - date.setMilliseconds(Number("0." + d[12]) * 1000); - } - if (!ignoreTimezone) { - if (d[14]) { - offset = (Number(d[16]) * 60) + Number(d[17]); - offset *= ((d[15] == '-') ? 1 : -1); - } - offset -= date.getTimezoneOffset(); - } - return new Date(Number(date) + (offset * 60 * 1000)); - } - }; - }(); - - -})(jQuery); diff --git a/public/static/js/widgets/slider.js b/public/static/js/widgets/slider.js deleted file mode 100644 index 09e0077..0000000 --- a/public/static/js/widgets/slider.js +++ /dev/null @@ -1,43 +0,0 @@ -function slider_behavior() { - $('.slider').each(function (index) { - var input_id = '#id_' + this.id.replace('_slider', ''); - var slider_slider = '#' + this.id; - var slider_val = '#' + this.id + '_value'; - var slider_val_text = '#' + this.id + '_value_text'; - var slider_vals = '#' + this.id + '_values'; - var slider_val_texts = '#' + this.id + '_value_texts'; - var red = 255 - $(slider_val).html() * 255 / $(input_id).attr('max'); - var green = 255; - var blue = red; - var rgb = (red << 16) + (green << 8) + blue; - var color = rgb.toString(16); - while(color.length < 6) - color = '0' + color; - color = '#' + color; - $(slider_slider).css('background', color); - //$(slider_val_text).css('color', color); - $('#'+this.id).slider({ - max:+$(input_id).attr('max'), - min:+$(input_id).attr('min'), - step:+$(input_id).attr('step'), - value:+$(slider_val).html(), - slide: function(event, ui) { - $(input_id).val($(slider_vals).html().split(',')[ui.value]); - $(slider_val).html(ui.value); - $(slider_val_text).html($(slider_val_texts).html().split(',')[ui.value]); - var red = 255 - ui.value * 255 / $(input_id).attr('max'); - var green = 255; - var blue = red; - var rgb = (red << 16) + (green << 8) + blue; - var color = rgb.toString(16); - while(color.length < 6) - color = '0' + color; - color = '#' + color; - $(slider_slider).css('background', color); - //$(slider_val_text).css('color', color); - } - }) - }); -} - -add_behavior(slider_behavior); diff --git a/public/static/loading_animation_small.gif b/public/static/loading_animation_small.gif deleted file mode 100644 index 13ccf87..0000000 Binary files a/public/static/loading_animation_small.gif and /dev/null differ diff --git a/public/static/music/asc.gif b/public/static/music/asc.gif deleted file mode 100644 index 344a110..0000000 Binary files a/public/static/music/asc.gif and /dev/null differ diff --git a/public/static/music/bg.gif b/public/static/music/bg.gif deleted file mode 100644 index de69e25..0000000 Binary files a/public/static/music/bg.gif and /dev/null differ diff --git a/public/static/music/desc.gif b/public/static/music/desc.gif deleted file mode 100644 index a55d8d6..0000000 Binary files a/public/static/music/desc.gif and /dev/null differ diff --git a/public/static/music/downBright.png b/public/static/music/downBright.png deleted file mode 100644 index 4c0b50c..0000000 Binary files a/public/static/music/downBright.png and /dev/null differ diff --git a/public/static/music/downDull.png b/public/static/music/downDull.png deleted file mode 100644 index 8476da0..0000000 Binary files a/public/static/music/downDull.png and /dev/null differ diff --git a/public/static/music/jquery.tablesorter.js b/public/static/music/jquery.tablesorter.js deleted file mode 100644 index 9b58731..0000000 --- a/public/static/music/jquery.tablesorter.js +++ /dev/null @@ -1,1031 +0,0 @@ -/* - * - * TableSorter 2.0 - Client-side table sorting with ease! - * Version 2.0.5b - * @requires jQuery v1.2.3 - * - * Copyright (c) 2007 Christian Bach - * Examples and docs at: http://tablesorter.com - * Dual licensed under the MIT and GPL licenses: - * http://www.opensource.org/licenses/mit-license.php - * http://www.gnu.org/licenses/gpl.html - * - */ -/** - * - * @description Create a sortable table with multi-column sorting capabilitys - * - * @example $('table').tablesorter(); - * @desc Create a simple tablesorter interface. - * - * @example $('table').tablesorter({ sortList:[[0,0],[1,0]] }); - * @desc Create a tablesorter interface and sort on the first and secound column column headers. - * - * @example $('table').tablesorter({ headers: { 0: { sorter: false}, 1: {sorter: false} } }); - * - * @desc Create a tablesorter interface and disableing the first and second column headers. - * - * - * @example $('table').tablesorter({ headers: { 0: {sorter:"integer"}, 1: {sorter:"currency"} } }); - * - * @desc Create a tablesorter interface and set a column parser for the first - * and second column. - * - * - * @param Object - * settings An object literal containing key/value pairs to provide - * optional settings. - * - * - * @option String cssHeader (optional) A string of the class name to be appended - * to sortable tr elements in the thead of the table. Default value: - * "header" - * - * @option String cssAsc (optional) A string of the class name to be appended to - * sortable tr elements in the thead on a ascending sort. Default value: - * "headerSortUp" - * - * @option String cssDesc (optional) A string of the class name to be appended - * to sortable tr elements in the thead on a descending sort. Default - * value: "headerSortDown" - * - * @option String sortInitialOrder (optional) A string of the inital sorting - * order can be asc or desc. Default value: "asc" - * - * @option String sortMultisortKey (optional) A string of the multi-column sort - * key. Default value: "shiftKey" - * - * @option String textExtraction (optional) A string of the text-extraction - * method to use. For complex html structures inside td cell set this - * option to "complex", on large tables the complex option can be slow. - * Default value: "simple" - * - * @option Object headers (optional) An array containing the forces sorting - * rules. This option let's you specify a default sorting rule. Default - * value: null - * - * @option Array sortList (optional) An array containing the forces sorting - * rules. This option let's you specify a default sorting rule. Default - * value: null - * - * @option Array sortForce (optional) An array containing forced sorting rules. - * This option let's you specify a default sorting rule, which is - * prepended to user-selected rules. Default value: null - * - * @option Boolean sortLocaleCompare (optional) Boolean flag indicating whatever - * to use String.localeCampare method or not. Default set to true. - * - * - * @option Array sortAppend (optional) An array containing forced sorting rules. - * This option let's you specify a default sorting rule, which is - * appended to user-selected rules. Default value: null - * - * @option Boolean widthFixed (optional) Boolean flag indicating if tablesorter - * should apply fixed widths to the table columns. This is usefull when - * using the pager companion plugin. This options requires the dimension - * jquery plugin. Default value: false - * - * @option Boolean cancelSelection (optional) Boolean flag indicating if - * tablesorter should cancel selection of the table headers text. - * Default value: true - * - * @option Boolean debug (optional) Boolean flag indicating if tablesorter - * should display debuging information usefull for development. - * - * @type jQuery - * - * @name tablesorter - * - * @cat Plugins/Tablesorter - * - * @author Christian Bach/christian.bach@polyester.se - */ - -(function ($) { - $.extend({ - tablesorter: new - function () { - - var parsers = [], - widgets = []; - - this.defaults = { - cssHeader: "header", - cssAsc: "headerSortUp", - cssDesc: "headerSortDown", - cssChildRow: "expand-child", - sortInitialOrder: "asc", - sortMultiSortKey: "shiftKey", - sortForce: null, - sortAppend: null, - sortLocaleCompare: true, - textExtraction: "simple", - parsers: {}, widgets: [], - widgetZebra: { - css: ["even", "odd"] - }, headers: {}, widthFixed: false, - cancelSelection: true, - sortList: [], - headerList: [], - dateFormat: "us", - decimal: '/\.|\,/g', - onRenderHeader: null, - selectorHeaders: 'thead th', - debug: false - }; - - /* debuging utils */ - - function benchmark(s, d) { - log(s + "," + (new Date().getTime() - d.getTime()) + "ms"); - } - - this.benchmark = benchmark; - - function log(s) { - if (typeof console != "undefined" && typeof console.debug != "undefined") { - console.log(s); - } else { - alert(s); - } - } - - /* parsers utils */ - - function buildParserCache(table, $headers) { - - if (table.config.debug) { - var parsersDebug = ""; - } - - if (table.tBodies.length == 0) return; // In the case of empty tables - var rows = table.tBodies[0].rows; - - if (rows[0]) { - - var list = [], - cells = rows[0].cells, - l = cells.length; - - for (var i = 0; i < l; i++) { - - var p = false; - - if ($.metadata && ($($headers[i]).metadata() && $($headers[i]).metadata().sorter)) { - - p = getParserById($($headers[i]).metadata().sorter); - - } else if ((table.config.headers[i] && table.config.headers[i].sorter)) { - - p = getParserById(table.config.headers[i].sorter); - } - if (!p) { - - p = detectParserForColumn(table, rows, -1, i); - } - - if (table.config.debug) { - parsersDebug += "column:" + i + " parser:" + p.id + "\n"; - } - - list.push(p); - } - } - - if (table.config.debug) { - log(parsersDebug); - } - - return list; - }; - - function detectParserForColumn(table, rows, rowIndex, cellIndex) { - var l = parsers.length, - node = false, - nodeValue = false, - keepLooking = true; - while (nodeValue == '' && keepLooking) { - rowIndex++; - if (rows[rowIndex]) { - node = getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex); - nodeValue = trimAndGetNodeText(table.config, node); - if (table.config.debug) { - log('Checking if value was empty on row:' + rowIndex); - } - } else { - keepLooking = false; - } - } - for (var i = 1; i < l; i++) { - if (parsers[i].is(nodeValue, table, node)) { - return parsers[i]; - } - } - // 0 is always the generic parser (text) - return parsers[0]; - } - - function getNodeFromRowAndCellIndex(rows, rowIndex, cellIndex) { - return rows[rowIndex].cells[cellIndex]; - } - - function trimAndGetNodeText(config, node) { - return $.trim(getElementText(config, node)); - } - - function getParserById(name) { - var l = parsers.length; - for (var i = 0; i < l; i++) { - if (parsers[i].id.toLowerCase() == name.toLowerCase()) { - return parsers[i]; - } - } - return false; - } - - /* utils */ - - function buildCache(table) { - - if (table.config.debug) { - var cacheTime = new Date(); - } - - var totalRows = (table.tBodies[0] && table.tBodies[0].rows.length) || 0, - totalCells = (table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length) || 0, - parsers = table.config.parsers, - cache = { - row: [], - normalized: [] - }; - - for (var i = 0; i < totalRows; ++i) { - - /** Add the table data to main data array */ - var c = $(table.tBodies[0].rows[i]), - cols = []; - - // if this is a child row, add it to the last row's children and - // continue to the next row - if (c.hasClass(table.config.cssChildRow)) { - cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add(c); - // go to the next for loop - continue; - } - - cache.row.push(c); - - for (var j = 0; j < totalCells; ++j) { - cols.push(parsers[j].format(getElementText(table.config, c[0].cells[j]), table, c[0].cells[j])); - } - - cols.push(cache.normalized.length); // add position for rowCache - cache.normalized.push(cols); - cols = null; - }; - - if (table.config.debug) { - benchmark("Building cache for " + totalRows + " rows:", cacheTime); - } - - return cache; - }; - - function getElementText(config, node) { - - var text = ""; - - if (!node) return ""; - - if (!config.supportsTextContent) config.supportsTextContent = node.textContent || false; - - if (config.textExtraction == "simple") { - if (config.supportsTextContent) { - text = node.textContent; - } else { - if (node.childNodes[0] && node.childNodes[0].hasChildNodes()) { - text = node.childNodes[0].innerHTML; - } else { - text = node.innerHTML; - } - } - } else { - if (typeof(config.textExtraction) == "function") { - text = config.textExtraction(node); - } else { - text = $(node).text(); - } - } - return text; - } - - function appendToTable(table, cache) { - - if (table.config.debug) { - var appendTime = new Date() - } - - var c = cache, - r = c.row, - n = c.normalized, - totalRows = n.length, - checkCell = (n[0].length - 1), - tableBody = $(table.tBodies[0]), - rows = []; - - - for (var i = 0; i < totalRows; i++) { - var pos = n[i][checkCell]; - - rows.push(r[pos]); - - if (!table.config.appender) { - - //var o = ; - var l = r[pos].length; - for (var j = 0; j < l; j++) { - tableBody[0].appendChild(r[pos][j]); - } - - // - } - } - - - - if (table.config.appender) { - - table.config.appender(table, rows); - } - - rows = null; - - if (table.config.debug) { - benchmark("Rebuilt table:", appendTime); - } - - // apply table widgets - applyWidget(table); - - // trigger sortend - setTimeout(function () { - $(table).trigger("sortEnd"); - }, 0); - - }; - - function buildHeaders(table) { - - if (table.config.debug) { - var time = new Date(); - } - - var meta = ($.metadata) ? true : false; - - var header_index = computeTableHeaderCellIndexes(table); - - $tableHeaders = $(table.config.selectorHeaders, table).each(function (index) { - - this.column = header_index[this.parentNode.rowIndex + "-" + this.cellIndex]; - // this.column = index; - this.order = formatSortingOrder(table.config.sortInitialOrder); - - - this.count = this.order; - - if (checkHeaderMetadata(this) || checkHeaderOptions(table, index)) this.sortDisabled = true; - if (checkHeaderOptionsSortingLocked(table, index)) this.order = this.lockedOrder = checkHeaderOptionsSortingLocked(table, index); - - if (!this.sortDisabled) { - var $th = $(this).addClass(table.config.cssHeader); - if (table.config.onRenderHeader) table.config.onRenderHeader.apply($th); - } - - // add cell to headerList - table.config.headerList[index] = this; - }); - - if (table.config.debug) { - benchmark("Built headers:", time); - log($tableHeaders); - } - - return $tableHeaders; - - }; - - // from: - // http://www.javascripttoolbox.com/lib/table/examples.php - // http://www.javascripttoolbox.com/temp/table_cellindex.html - - - function computeTableHeaderCellIndexes(t) { - var matrix = []; - var lookup = {}; - var thead = t.getElementsByTagName('THEAD')[0]; - var trs = thead.getElementsByTagName('TR'); - - for (var i = 0; i < trs.length; i++) { - var cells = trs[i].cells; - for (var j = 0; j < cells.length; j++) { - var c = cells[j]; - - var rowIndex = c.parentNode.rowIndex; - var cellId = rowIndex + "-" + c.cellIndex; - var rowSpan = c.rowSpan || 1; - var colSpan = c.colSpan || 1 - var firstAvailCol; - if (typeof(matrix[rowIndex]) == "undefined") { - matrix[rowIndex] = []; - } - // Find first available column in the first row - for (var k = 0; k < matrix[rowIndex].length + 1; k++) { - if (typeof(matrix[rowIndex][k]) == "undefined") { - firstAvailCol = k; - break; - } - } - lookup[cellId] = firstAvailCol; - for (var k = rowIndex; k < rowIndex + rowSpan; k++) { - if (typeof(matrix[k]) == "undefined") { - matrix[k] = []; - } - var matrixrow = matrix[k]; - for (var l = firstAvailCol; l < firstAvailCol + colSpan; l++) { - matrixrow[l] = "x"; - } - } - } - } - return lookup; - } - - function checkCellColSpan(table, rows, row) { - var arr = [], - r = table.tHead.rows, - c = r[row].cells; - - for (var i = 0; i < c.length; i++) { - var cell = c[i]; - - if (cell.colSpan > 1) { - arr = arr.concat(checkCellColSpan(table, headerArr, row++)); - } else { - if (table.tHead.length == 1 || (cell.rowSpan > 1 || !r[row + 1])) { - arr.push(cell); - } - // headerArr[row] = (i+row); - } - } - return arr; - }; - - function checkHeaderMetadata(cell) { - if (($.metadata) && ($(cell).metadata().sorter === false)) { - return true; - }; - return false; - } - - function checkHeaderOptions(table, i) { - if ((table.config.headers[i]) && (table.config.headers[i].sorter === false)) { - return true; - }; - return false; - } - - function checkHeaderOptionsSortingLocked(table, i) { - if ((table.config.headers[i]) && (table.config.headers[i].lockedOrder)) return table.config.headers[i].lockedOrder; - return false; - } - - function applyWidget(table) { - var c = table.config.widgets; - var l = c.length; - for (var i = 0; i < l; i++) { - - getWidgetById(c[i]).format(table); - } - - } - - function getWidgetById(name) { - var l = widgets.length; - for (var i = 0; i < l; i++) { - if (widgets[i].id.toLowerCase() == name.toLowerCase()) { - return widgets[i]; - } - } - }; - - function formatSortingOrder(v) { - if (typeof(v) != "Number") { - return (v.toLowerCase() == "desc") ? 1 : 0; - } else { - return (v == 1) ? 1 : 0; - } - } - - function isValueInArray(v, a) { - var l = a.length; - for (var i = 0; i < l; i++) { - if (a[i][0] == v) { - return true; - } - } - return false; - } - - function setHeadersCss(table, $headers, list, css) { - // remove all header information - $headers.removeClass(css[0]).removeClass(css[1]); - - var h = []; - $headers.each(function (offset) { - if (!this.sortDisabled) { - h[this.column] = $(this); - } - }); - - var l = list.length; - for (var i = 0; i < l; i++) { - h[list[i][0]].addClass(css[list[i][1]]); - } - } - - function fixColumnWidth(table, $headers) { - var c = table.config; - if (c.widthFixed) { - var colgroup = $(''); - $("tr:first td", table.tBodies[0]).each(function () { - colgroup.append($('').css('width', $(this).width())); - }); - $(table).prepend(colgroup); - }; - } - - function updateHeaderSortCount(table, sortList) { - var c = table.config, - l = sortList.length; - for (var i = 0; i < l; i++) { - var s = sortList[i], - o = c.headerList[s[0]]; - o.count = s[1]; - o.count++; - } - } - - /* sorting methods */ - - function multisort(table, sortList, cache) { - - if (table.config.debug) { - var sortTime = new Date(); - } - - var dynamicExp = "var sortWrapper = function(a,b) {", - l = sortList.length; - - // TODO: inline functions. - for (var i = 0; i < l; i++) { - - var c = sortList[i][0]; - var order = sortList[i][1]; - // var s = (getCachedSortType(table.config.parsers,c) == "text") ? - // ((order == 0) ? "sortText" : "sortTextDesc") : ((order == 0) ? - // "sortNumeric" : "sortNumericDesc"); - // var s = (table.config.parsers[c].type == "text") ? ((order == 0) - // ? makeSortText(c) : makeSortTextDesc(c)) : ((order == 0) ? - // makeSortNumeric(c) : makeSortNumericDesc(c)); - var s = (table.config.parsers[c].type == "text") ? ((order == 0) ? makeSortFunction("text", "asc", c) : makeSortFunction("text", "desc", c)) : ((order == 0) ? makeSortFunction("numeric", "asc", c) : makeSortFunction("numeric", "desc", c)); - var e = "e" + i; - - dynamicExp += "var " + e + " = " + s; // + "(a[" + c + "],b[" + c - // + "]); "; - dynamicExp += "if(" + e + ") { return " + e + "; } "; - dynamicExp += "else { "; - - } - - // if value is the same keep orignal order - var orgOrderCol = cache.normalized[0].length - 1; - dynamicExp += "return a[" + orgOrderCol + "]-b[" + orgOrderCol + "];"; - - for (var i = 0; i < l; i++) { - dynamicExp += "}; "; - } - - dynamicExp += "return 0; "; - dynamicExp += "}; "; - - if (table.config.debug) { - benchmark("Evaling expression:" + dynamicExp, new Date()); - } - - eval(dynamicExp); - - cache.normalized.sort(sortWrapper); - - if (table.config.debug) { - benchmark("Sorting on " + sortList.toString() + " and dir " + order + " time:", sortTime); - } - - return cache; - }; - - function makeSortFunction(type, direction, index) { - var a = "a[" + index + "]", - b = "b[" + index + "]"; - if (type == 'text' && direction == 'asc') { - return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + a + " < " + b + ") ? -1 : 1 )));"; - } else if (type == 'text' && direction == 'desc') { - return "(" + a + " == " + b + " ? 0 : (" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : (" + b + " < " + a + ") ? -1 : 1 )));"; - } else if (type == 'numeric' && direction == 'asc') { - return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + a + " - " + b + "));"; - } else if (type == 'numeric' && direction == 'desc') { - return "(" + a + " === null && " + b + " === null) ? 0 :(" + a + " === null ? Number.POSITIVE_INFINITY : (" + b + " === null ? Number.NEGATIVE_INFINITY : " + b + " - " + a + "));"; - } - }; - - function makeSortText(i) { - return "((a[" + i + "] < b[" + i + "]) ? -1 : ((a[" + i + "] > b[" + i + "]) ? 1 : 0));"; - }; - - function makeSortTextDesc(i) { - return "((b[" + i + "] < a[" + i + "]) ? -1 : ((b[" + i + "] > a[" + i + "]) ? 1 : 0));"; - }; - - function makeSortNumeric(i) { - return "a[" + i + "]-b[" + i + "];"; - }; - - function makeSortNumericDesc(i) { - return "b[" + i + "]-a[" + i + "];"; - }; - - function sortText(a, b) { - if (table.config.sortLocaleCompare) return a.localeCompare(b); - return ((a < b) ? -1 : ((a > b) ? 1 : 0)); - }; - - function sortTextDesc(a, b) { - if (table.config.sortLocaleCompare) return b.localeCompare(a); - return ((b < a) ? -1 : ((b > a) ? 1 : 0)); - }; - - function sortNumeric(a, b) { - return a - b; - }; - - function sortNumericDesc(a, b) { - return b - a; - }; - - function getCachedSortType(parsers, i) { - return parsers[i].type; - }; /* public methods */ - this.construct = function (settings) { - return this.each(function () { - // if no thead or tbody quit. - if (!this.tHead || !this.tBodies) return; - // declare - var $this, $document, $headers, cache, config, shiftDown = 0, - sortOrder; - // new blank config object - this.config = {}; - // merge and extend. - config = $.extend(this.config, $.tablesorter.defaults, settings); - // store common expression for speed - $this = $(this); - // save the settings where they read - $.data(this, "tablesorter", config); - // build headers - $headers = buildHeaders(this); - // try to auto detect column type, and store in tables config - this.config.parsers = buildParserCache(this, $headers); - // build the cache for the tbody cells - cache = buildCache(this); - // get the css class names, could be done else where. - var sortCSS = [config.cssDesc, config.cssAsc]; - // fixate columns if the users supplies the fixedWidth option - fixColumnWidth(this); - // apply event handling to headers - // this is to big, perhaps break it out? - $headers.click( - - function (e) { - var totalRows = ($this[0].tBodies[0] && $this[0].tBodies[0].rows.length) || 0; - if (!this.sortDisabled && totalRows > 0) { - // Only call sortStart if sorting is - // enabled. - $this.trigger("sortStart"); - // store exp, for speed - var $cell = $(this); - // get current column index - var i = this.column; - // get current column sort order - this.order = this.count++ % 2; - // always sort on the locked order. - if(this.lockedOrder) this.order = this.lockedOrder; - - // user only whants to sort on one - // column - if (!e[config.sortMultiSortKey]) { - // flush the sort list - config.sortList = []; - if (config.sortForce != null) { - var a = config.sortForce; - for (var j = 0; j < a.length; j++) { - if (a[j][0] != i) { - config.sortList.push(a[j]); - } - } - } - // add column to sort list - config.sortList.push([i, this.order]); - // multi column sorting - } else { - // the user has clicked on an all - // ready sortet column. - if (isValueInArray(i, config.sortList)) { - // revers the sorting direction - // for all tables. - for (var j = 0; j < config.sortList.length; j++) { - var s = config.sortList[j], - o = config.headerList[s[0]]; - if (s[0] == i) { - o.count = s[1]; - o.count++; - s[1] = o.count % 2; - } - } - } else { - // add column to sort list array - config.sortList.push([i, this.order]); - } - }; - setTimeout(function () { - // set css for headers - setHeadersCss($this[0], $headers, config.sortList, sortCSS); - appendToTable( - $this[0], multisort( - $this[0], config.sortList, cache) - ); - }, 1); - // stop normal event by returning false - return false; - } - // cancel selection - }).mousedown(function () { - if (config.cancelSelection) { - this.onselectstart = function () { - return false - }; - return false; - } - }); - // apply easy methods that trigger binded events - $this.bind("update", function () { - var me = this; - setTimeout(function () { - // rebuild parsers. - me.config.parsers = buildParserCache( - me, $headers); - // rebuild the cache map - cache = buildCache(me); - }, 1); - }).bind("updateCell", function (e, cell) { - var config = this.config; - // get position from the dom. - var pos = [(cell.parentNode.rowIndex - 1), cell.cellIndex]; - // update cache - cache.normalized[pos[0]][pos[1]] = config.parsers[pos[1]].format( - getElementText(config, cell), cell); - }).bind("sorton", function (e, list) { - $(this).trigger("sortStart"); - config.sortList = list; - // update and store the sortlist - var sortList = config.sortList; - // update header count index - updateHeaderSortCount(this, sortList); - // set css for headers - setHeadersCss(this, $headers, sortList, sortCSS); - // sort the table and append it to the dom - appendToTable(this, multisort(this, sortList, cache)); - }).bind("appendCache", function () { - appendToTable(this, cache); - }).bind("applyWidgetId", function (e, id) { - getWidgetById(id).format(this); - }).bind("applyWidgets", function () { - // apply widgets - applyWidget(this); - }); - if ($.metadata && ($(this).metadata() && $(this).metadata().sortlist)) { - config.sortList = $(this).metadata().sortlist; - } - // if user has supplied a sort list to constructor. - if (config.sortList.length > 0) { - $this.trigger("sorton", [config.sortList]); - } - // apply widgets - applyWidget(this); - }); - }; - this.addParser = function (parser) { - var l = parsers.length, - a = true; - for (var i = 0; i < l; i++) { - if (parsers[i].id.toLowerCase() == parser.id.toLowerCase()) { - a = false; - } - } - if (a) { - parsers.push(parser); - }; - }; - this.addWidget = function (widget) { - widgets.push(widget); - }; - this.formatFloat = function (s) { - var i = parseFloat(s); - return (isNaN(i)) ? 0 : i; - }; - this.formatInt = function (s) { - var i = parseInt(s); - return (isNaN(i)) ? 0 : i; - }; - this.isDigit = function (s, config) { - // replace all an wanted chars and match. - return /^[-+]?\d*$/.test($.trim(s.replace(/[,.']/g, ''))); - }; - this.clearTableBody = function (table) { - if ($.browser.msie) { - function empty() { - while (this.firstChild) - this.removeChild(this.firstChild); - } - empty.apply(table.tBodies[0]); - } else { - table.tBodies[0].innerHTML = ""; - } - }; - } - }); - - // extend plugin scope - $.fn.extend({ - tablesorter: $.tablesorter.construct - }); - - // make shortcut - var ts = $.tablesorter; - - // add default parsers - ts.addParser({ - id: "text", - is: function (s) { - return true; - }, format: function (s) { - return $.trim(s.toLocaleLowerCase()); - }, type: "text" - }); - - ts.addParser({ - id: "digit", - is: function (s, table) { - var c = table.config; - return $.tablesorter.isDigit(s, c); - }, format: function (s) { - return $.tablesorter.formatFloat(s); - }, type: "numeric" - }); - - ts.addParser({ - id: "currency", - is: function (s) { - return /^[£$€?.]/.test(s); - }, format: function (s) { - return $.tablesorter.formatFloat(s.replace(new RegExp(/[£$€]/g), "")); - }, type: "numeric" - }); - - ts.addParser({ - id: "ipAddress", - is: function (s) { - return /^\d{2,3}[\.]\d{2,3}[\.]\d{2,3}[\.]\d{2,3}$/.test(s); - }, format: function (s) { - var a = s.split("."), - r = "", - l = a.length; - for (var i = 0; i < l; i++) { - var item = a[i]; - if (item.length == 2) { - r += "0" + item; - } else { - r += item; - } - } - return $.tablesorter.formatFloat(r); - }, type: "numeric" - }); - - ts.addParser({ - id: "url", - is: function (s) { - return /^(https?|ftp|file):\/\/$/.test(s); - }, format: function (s) { - return jQuery.trim(s.replace(new RegExp(/(https?|ftp|file):\/\//), '')); - }, type: "text" - }); - - ts.addParser({ - id: "isoDate", - is: function (s) { - return /^\d{4}[\/-]\d{1,2}[\/-]\d{1,2}$/.test(s); - }, format: function (s) { - return $.tablesorter.formatFloat((s != "") ? new Date(s.replace( - new RegExp(/-/g), "/")).getTime() : "0"); - }, type: "numeric" - }); - - ts.addParser({ - id: "percent", - is: function (s) { - return /\%$/.test($.trim(s)); - }, format: function (s) { - return $.tablesorter.formatFloat(s.replace(new RegExp(/%/g), "")); - }, type: "numeric" - }); - - ts.addParser({ - id: "usLongDate", - is: function (s) { - return s.match(new RegExp(/^[A-Za-z]{3,10}\.? [0-9]{1,2}, ([0-9]{4}|'?[0-9]{2}) (([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(AM|PM)))$/)); - }, format: function (s) { - return $.tablesorter.formatFloat(new Date(s).getTime()); - }, type: "numeric" - }); - - ts.addParser({ - id: "shortDate", - is: function (s) { - return /\d{1,2}[\/\-]\d{1,2}[\/\-]\d{2,4}/.test(s); - }, format: function (s, table) { - var c = table.config; - s = s.replace(/\-/g, "/"); - if (c.dateFormat == "us") { - // reformat the string in ISO format - s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$1/$2"); - } else if (c.dateFormat == "uk") { - // reformat the string in ISO format - s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{4})/, "$3/$2/$1"); - } else if (c.dateFormat == "dd/mm/yy" || c.dateFormat == "dd-mm-yy") { - s = s.replace(/(\d{1,2})[\/\-](\d{1,2})[\/\-](\d{2})/, "$1/$2/$3"); - } - return $.tablesorter.formatFloat(new Date(s).getTime()); - }, type: "numeric" - }); - ts.addParser({ - id: "time", - is: function (s) { - return /^(([0-2]?[0-9]:[0-5][0-9])|([0-1]?[0-9]:[0-5][0-9]\s(am|pm)))$/.test(s); - }, format: function (s) { - return $.tablesorter.formatFloat(new Date("2000/01/01 " + s).getTime()); - }, type: "numeric" - }); - ts.addParser({ - id: "metadata", - is: function (s) { - return false; - }, format: function (s, table, cell) { - var c = table.config, - p = (!c.parserMetadataName) ? 'sortValue' : c.parserMetadataName; - return $(cell).metadata()[p]; - }, type: "numeric" - }); - // add default widgets - ts.addWidget({ - id: "zebra", - format: function (table) { - if (table.config.debug) { - var time = new Date(); - } - var $tr, row = -1, - odd; - // loop through the visible rows - $("tr:visible", table.tBodies[0]).each(function (i) { - $tr = $(this); - // style children rows the same way the parent - // row was styled - if (!$tr.hasClass(table.config.cssChildRow)) row++; - odd = (row % 2 == 0); - $tr.removeClass( - table.config.widgetZebra.css[odd ? 0 : 1]).addClass( - table.config.widgetZebra.css[odd ? 1 : 0]) - }); - if (table.config.debug) { - $.tablesorter.benchmark("Applying Zebra widget", time); - } - } - }); -})(jQuery); \ No newline at end of file diff --git a/public/static/music/loading_animation_small.gif b/public/static/music/loading_animation_small.gif deleted file mode 100644 index 13ccf87..0000000 Binary files a/public/static/music/loading_animation_small.gif and /dev/null differ diff --git a/public/static/music/upBright.png b/public/static/music/upBright.png deleted file mode 100644 index c04d98a..0000000 Binary files a/public/static/music/upBright.png and /dev/null differ diff --git a/public/static/music/upDull.png b/public/static/music/upDull.png deleted file mode 100644 index f2379d0..0000000 Binary files a/public/static/music/upDull.png and /dev/null differ diff --git a/public/static/sponsorship_proposal_thumbnail.png b/public/static/sponsorship_proposal_thumbnail.png deleted file mode 100755 index d7a9608..0000000 Binary files a/public/static/sponsorship_proposal_thumbnail.png and /dev/null differ diff --git a/public/static/style.css b/public/static/style.css deleted file mode 100644 index 8866a57..0000000 --- a/public/static/style.css +++ /dev/null @@ -1,420 +0,0 @@ -h1,h2,h3,h4 { - font-weight:normal; -} -h1 { - text-transform:uppercase; - font-size:24px; - letter-spacing:-2px; - color:#88a5b4; - margin-top:20px; -} -h6 { - border-bottom:1px solid #EEE; - padding-bottom:10px; -} -#header { - display:block; - background:none repeat scroll 0 0 #F2F2F2; - border: 1px solid #C2C2C2; - margin-bottom:10px; -} -#headerLink { - background:url('header/header.png') no-repeat; - height:100px; - width:700px; - display:block; - margin:20px 0; -} -#headerLink { - text-indent:-9999em; -} -#nav_region { - clear:both; - height:38px; - background: ; - position:relative; - margin-bottom:20px; - background:url('header/reg_menu_centre.png') repeat-x; - z-index:1; -} -#nav_region a { - text-decoration:none; -} -#nav_region a:hover { - color:#cd282f; -} -#nav_region_centre { - height:38px; - padding:0 10px; - float:left; -} -#nav_region_centre li { - list-style:none; -} -#nav_region_left { - background:url('header/reg_menu_left.png') no-repeat; - float:left; - width:5px; - height:38px; - position:relative; -} -#nav_region_right { - background:url('header/reg_menu_right.png') no-repeat; - float:right; - width:5px; - height:38px; - position:relative; - top:0; -} -#nav_region_centre .nav_tier1{ - margin:0; - padding:0; - list-style:none; -} -#nav_region_centre .nav_tier1>li{ - display:inline; - margin:0; - float:left; - margin-left:10px; - position:relative; -} -#nav_region_centre .nav_tier1>li a { - color:#333; - font-size:18px; - padding-top:5px; - padding-left:10px; - padding-right:10px; - display:block; -} -#nav_region_centre .nav_tier1>li a:hover { - color:#cd282f; -} -#nav_region_centre li.first { - padding-top:10px; -} -#nav_region_centre .nav_tier1 ul li { - padding-left:10px; -} -#nav_region_centre ul.nav_tier1 { - list-style: none outside none; - margin: 0; - padding: 0; - display:inline; -} -#nav_region_centre ul.nav_tier1 li { - position: relative; - margin:0; -} -#nav_region_centre li ul { - display: none; - left: 0; - position: absolute; - top: 37px; - background:url('header/dropdown.png'); - width:182px; - -moz-box-shadow:0 1px 0px #999; - -webkit-box-shadow:0 1px 1px #999; - -o-box-shadow:0 1px 1px #999; - box-shadow:0 1px 0px #999; - -moz-border-radius:6px; - -webkit-border-radius:6px; - -o-border-radius:6px; -} -#nav_region_centre ul li a { - -moz-border-bottom-colors: none; - -moz-border-image: none; - -moz-border-left-colors: none; - -moz-border-right-colors: none; - -moz-border-top-colors: none; - color: #777777; - display: block; - padding: 5px; - font-size:18px; - text-decoration: none; -} -#nav_region_centre * html ul li { - float: left; - height: 1%; -} -#nav_region_centre * html ul li a { - height: 1%; -} -#nav_region_centre ul li a:hover { -} -#nav_region_centre li ul li a { - padding: 2px 5px; -} -#nav_region_centre li:hover ul, li.over ul { - display: block; -} -#nav_region_centre .nav_tier1>li span { - -} -#nav_region_centre .nav_tier2 { - overflow:visible !important; - position:absolute; - display:none; - top:0; - left:0; -} -#nav_region_centre .nav_tier2>li{ - margin:0; -} -#nav_region_centre .nav_tier2:hover{ - display:block; -} -#content { - clear:both; -} -.timestamp { - color:#999; -} -ul.pagenumbers { - text-align: center; -} -.pagenumbers li{ - list-style:none; - display:inline-block; - font-size:16px; -} -.pagenumbers li a{ - text-decoration:none; -} -.pagenumbers .disabled { - padding: 5px; -} -.pagenumbers .current { - padding: 5px; - font-weight:bold; - color:#cd282f; -} -.pagenumbers a:hover { - color:#cd282f; -} -#calendar { - border:1px solid #c2c2c2; -} -#sponsorsTable { - border:1px solid #c2c2c2; -} -#sponsorsColumnTable td { - border:0px solid #c2c2c2; - text-align:center; - vertical-align:middle; - padding: 5px; -} -#sponsorsPageTable { - width: 100%; -} -#sponsorsPageTable tr { - border-bottom:1px solid #c2c2c2; - border-top:1px solid #c2c2c2; -} -#sponsorsPageTable td { - padding-left:10px; - padding-right:10px; - padding-top:20px; - padding-bottom:20px; -} -#sponsorsPageTable td.sponsorImage { - text-align:center; - vertical-align:middle; -} -#sponsorsPageTable td.sponsorDescription .sponsorName { - font-weight:bold; -} -#footerText { - text-align:center; - padding-top:20px; -} -.news-title { - /*color:#2c5c75;*/ - /*color:#b86952;*/ - color:#CD282F; - line-height:28px; -} - -.news-title h2 { - margin-bottom:10px; -} - -hr { - border:0px solid; - padding:10px 0px; -} - -#rightcontent h1 { - text-align:center; -} - -.news a { - color:#2f58cd; -} - -.news a:hover { - color:#cf582d; -} -.news .itemTitle { - width: 100%; - border-top: 1px solid #c2c2c2; - border-bottom: 1px solid #c2c2c2; - padding-top: 5px; - padding-bottom: 5px; -} -a { - color:#2f58cd; -} -a:hover { - color:#cf582d; -} -.pollsIndexTable { - width: 100%; -} -.pollsIndexTable tr { - border-bottom:1px solid #c2c2c2; - border-top:1px solid #c2c2c2; -} -.pollsIndexTable td { - padding-left:10px; - padding-right:10px; - padding-top:20px; - padding-bottom:20px; -} -div.centered_block { - width:700px; - margin: 0px auto; -} -div.invoice { - width: 600px; - margin: 0px auto; -} -div.invoice.small { - width: 500px; -} -div.invoice h2{ - width:500px; - font-size:14px; - font-weight:bold; - margin:-20px 0px 10px 0px; -} -div.invoice h3{ - margin: 10px 0px 0px 0px; - padding: 0px; - color:#009900; -} -div.invoice h4 { - margin: 30px 0px 0px 0px; - padding: 0px; - font-weight:bold; -} -div.invoice table{ - padding: 0px; - margin: 0px; - width:100%; - border:0px; - font-size:14px; -} -div.invoice td.price { - width:150px; -} -div.invoice.small td.price { - width:100px; -} - -/*========================*/ -/* Changes for Sem1, 2012 */ -/*========================*/ - -/* Camp Leader application forms. */ -div.application_form { - width: 600px; - margin: 0px auto; -} -div.application_form table { - width: 600px; -} -div.application_form table td, div.application_form table th { - width: 50%; - padding: 5px; - vertical-align:middle; -} -div.application_form table th { - text-align:right; -} -.camp_form ul { - list-style-type:none; - margin-left:-30px; -} -.camp_form ul em { - display:block; - background: #eef; - padding: 5px; - margin: 10px -5px; - font-style: normal; - text-align: justify; -} -.camp_form div.submit_button { - display:block; - text-align:center; - margin: 30px 0px 100px 0px; -} -.camp_form input[type=submit] { - padding:10px 50px; - font-weight: bold; -} - -/* Fix for layout */ -div#middlecontent { - margin: 0px auto; -} - -/* Fix for exec heads tables */ -table.exec_head_table { - width: 500px; - margin: 0px auto; - margin-top:40px; -} -table.exec_head_table th, table.exec_head_table td { - padding:1px 5px; -} -table.exec_head_table th { - font-weight:bold; - text-align:right; -} -table.exec_head_table strong { - display:block; - text-align:center; - font-size:16px; - border-bottom: 1px solid #ccc; -} -table.exec_head_table h2 { - text-align:center; - margin:0px; - font-size:20px; -} - -ul.errorlist li { - color: red; - font-weight: bold; - list-style-type:none; - padding: 0px; - margin: 0px; -} -ul.errorlist { - padding: 0px; - margin: 0px; -} -form th { - vertical-align: middle; - text-align: right; -} -form td, form th { - padding: 10px; -} - -form input[type=submit] { - padding:10px; - margin: 0px auto; - text-align: center; - font-weight: bold; -} diff --git a/public/static/suggestions.css b/public/static/suggestions.css deleted file mode 100644 index f4f720b..0000000 --- a/public/static/suggestions.css +++ /dev/null @@ -1,30 +0,0 @@ -div.comments { - margin-left: 30px; -} - -div.comments .comment { - padding-top: 5px; - padding-bottom: 5px; - padding-left: 10px; - padding-right: 10px; - white-space: pre-wrap; -} - -div.comments .comment.odd { - background-color: #E0E0E0; -} - -form table th { - vertical-align: top; -} - -form table th label { - font-weight: normal; -} - -div.list_suggestion { - padding: 5px 5px 5px 5px; - margin-bottom: 5px; - margin-top: 5px; - border: solid 1px #c2c2c2; -} diff --git a/public/static/suggestions.js b/public/static/suggestions.js deleted file mode 100644 index 3447694..0000000 --- a/public/static/suggestions.js +++ /dev/null @@ -1,11 +0,0 @@ -function suggestion_item_over(suggestion) { - suggestion.style.backgroundColor = '#d9e6ed' -} - -function suggestion_item_onclick(suggestion, suggestion_number, page_number) { - window.location = "./" + suggestion_number + "?page=" + page_number; -} - -function suggestion_item_out(suggestion) { - suggestion.style.backgroundColor = 'white'; -} diff --git a/public/static/tiny_mce b/public/static/tiny_mce deleted file mode 120000 index 39ccfaa..0000000 --- a/public/static/tiny_mce +++ /dev/null @@ -1 +0,0 @@ -/home/www/virtualenv/lib/python2.6/site-packages/tinymce/static/tiny_mce \ No newline at end of file diff --git a/csesoc/auth/__init__.py b/public/stylesheets/.gitkeep similarity index 100% rename from csesoc/auth/__init__.py rename to public/stylesheets/.gitkeep diff --git a/public/static/1020_12_10_10.css b/public/stylesheets/1020_12_10_10.css similarity index 100% rename from public/static/1020_12_10_10.css rename to public/stylesheets/1020_12_10_10.css diff --git a/public/static/reset.css b/public/stylesheets/reset.css similarity index 100% rename from public/static/reset.css rename to public/stylesheets/reset.css diff --git a/public/stylesheets/scaffold.css b/public/stylesheets/scaffold.css new file mode 100644 index 0000000..14de1f0 --- /dev/null +++ b/public/stylesheets/scaffold.css @@ -0,0 +1,54 @@ + +pre { + background-color: #eee; + padding: 10px; + font-size: 11px; +} + +div.field, div.actions { + margin-bottom: 10px; +} + +#notice { + color: green; +} + +.field_with_errors { + padding: 2px; + background-color: red; + display: table; +} + +#error_explanation { + width: 450px; + border: 2px solid red; + padding: 7px; + padding-bottom: 0; + margin-bottom: 20px; + background-color: #f0f0f0; +} + +#error_explanation h2 { + text-align: left; + font-weight: bold; + padding: 5px 5px 5px 15px; + font-size: 12px; + margin: -7px; + margin-bottom: 0px; + background-color: #c00; + color: #fff; +} + +#error_explanation ul li { + font-size: 12px; + list-style: square; +} + +.bar-text { + color: #88A5B4; + font-size: 18px; + padding-top: 5px; + padding-left: 10px; + padding-right: 10px; + display:block ; +} diff --git a/public/stylesheets/style.css b/public/stylesheets/style.css new file mode 100644 index 0000000..4f90a84 --- /dev/null +++ b/public/stylesheets/style.css @@ -0,0 +1,275 @@ +h1,h2,h3 { + font-weight:normal; +} +h1 { + text-transform:uppercase; + font-size:24px; + letter-spacing:-2px; + color:#88a5b4; +} +h6 { + border-bottom:1px solid #EEE; + padding-bottom:10px; +} +#header { + display:block; + background:none repeat scroll 0 0 #F2F2F2; + border: 1px solid #C2C2C2; + margin-bottom:10px; +} +#headerLink { + background:url('/images/header/header.png') no-repeat; + height:100px; + width:700px; + display:block; + margin:20px 0; +} +#headerLink { + text-indent:-9999em; +} +#nav_region { + clear:both; + height:38px; + background: ; + position:relative; + margin-bottom:20px; + background:url('/images/header/reg_menu_centre.png') repeat-x; +} +#nav_region a { + text-decoration:none; +} +#nav_region a:hover { + color:#cd282f; +} +#nav_region_centre { + height:38px; + padding:0 10px; + float:left; +} +#nav_region_centre li { + list-style:none; +} +#nav_region_left { + background:url('/images/header/reg_menu_left.png') no-repeat; + float:left; + width:5px; + height:38px; + position:relative; +} +#nav_region_right { + background:url('/images/header/reg_menu_right.png') no-repeat; + float:right; + width:5px; + height:38px; + position:relative; + top:0; +} +#nav_region_mid_right { + float:right; + height:38px; + padding:0 10px; + float:right; +} +#nav_region_mid_right .nav_tier1{ + margin:0; + padding:0; + list-style:none; +} +#nav_region_mid_right .nav_tier1>li{ + display:inline; + margin:0; + float:right; + margin-left:10px; + position:relative; +} +#nav_region_mid_right .nav_tier1>li a { + color:#333; + font-size:18px; + padding-top:5px; + padding-left:10px; + padding-right:10px; + display:block; +} +#nav_region_mid_right .nav_tier1>li a:hover { + color:#cd282f; +} + + +#nav_region_centre .nav_tier1{ + margin:0; + padding:0; + list-style:none; +} +#nav_region_centre .nav_tier1>li{ + display:inline; + margin:0; + float:left; + margin-left:10px; + position:relative; +} +#nav_region_centre .nav_tier1>li a { + color:#333; + font-size:18px; + padding-top:5px; + padding-left:10px; + padding-right:10px; + display:block; +} +#nav_region_centre .nav_tier1>li a:hover { + color:#cd282f; +} +li.first { + padding-top:10px; +} +.nav_tier1 ul li { + padding-left:10px; +} +ul.nav_tier1 { + list-style: none outside none; + margin: 0; + padding: 0; + display:inline; +} +ul.nav_tier1 li { + position: relative; + margin:0; +} +li ul { + display: none; + left: 0; + position: absolute; + top: 37px; + background:url('/images/header/dropdown.png'); + width:182px; + -moz-box-shadow:0 1px 0px #999; + -webkit-box-shadow:0 1px 1px #999; + -o-box-shadow:0 1px 1px #999; + box-shadow:0 1px 0px #999; + -moz-border-radius:6px; + -webkit-border-radius:6px; + -o-border-radius:6px; +} +ul li a { + -moz-border-bottom-colors: none; + -moz-border-image: none; + -moz-border-left-colors: none; + -moz-border-right-colors: none; + -moz-border-top-colors: none; + color: #777777; + display: block; + padding: 5px; + font-size:18px; + text-decoration: none; +} +* html ul li { + float: left; + height: 1%; +} +* html ul li a { + height: 1%; +} +ul li a:hover { +} +li ul li a { + padding: 2px 5px; +} +li:hover ul, li.over ul { + display: block; +} +#nav_region_centre .nav_tier1>li span { + +} +#nav_region_centre .nav_tier2 { + overflow:visible !important; + position:absolute; + display:none; + top:0; + left:0; +} +#nav_region_centre .nav_tier2>li{ + margin:0; +} +#nav_region_centre .nav_tier2:hover{ + display:block; +} +#content { + clear:both; +} +.timestamp { + color:#999; +} +ul.pagenumbers { + text-align: center; +} +.pagenumbers li{ + list-style:none; + display:inline-block; +} +.pagenumbers .disabled { + padding: 5px; + font-size:18px; +} +.pagenumbers .current { + padding: 5px; + font-weight:bold; + font-size:18px; +} +.pagenumbers a:hover { + color:#cd282f; +} +#calendar { + border:1px solid #c2c2c2; +} +#sponsorsTable { + border:1px solid #c2c2c2; +} +#sponsorsColumnTable td { + border:1px solid #c2c2c2; + text-align:center; + vertical-align:middle; + padding: 5px; +} +#sponsorsPageTable { + width: 100%; +} +#sponsorsPageTable tr { + border-bottom:1px solid #c2c2c2; + border-top:1px solid #c2c2c2; +} +#sponsorsPageTable td { + padding-left:10px; + padding-right:10px; + padding-top:20px; + padding-bottom:20px; +} +#sponsorsPageTable td.sponsorImage { + text-align:center; + vertical-align:middle; +} +#sponsorsPageTable td.sponsorDescription .sponsorName { + font-weight:bold; +} +#footerText { + text-align:center; + padding-top:20px; +} +.news-title { + color:#2f586d; +} +.news-title h2 a { + color:#2f586d; +} +.news a { + color:#2f58cd; +} +.news a:hover { + color:#cf582d; +} + +.news .itemTitle { + width: 100%; + border-top: 1px solid #c2c2c2; + border-bottom: 1px solid #c2c2c2; + padding-top: 5px; + padding-bottom: 5px; +} diff --git a/public/static/text.css b/public/stylesheets/text.css similarity index 97% rename from public/static/text.css rename to public/stylesheets/text.css index 99e40ab..dd03ad2 100644 --- a/public/static/text.css +++ b/public/stylesheets/text.css @@ -32,15 +32,15 @@ h3 { } h4 { - font-size: 17px; + font-size: 19px; } h5 { - font-size: 15px; + font-size: 17px; } h6 { - font-size: 13px; + font-size: 15px; } /* `Spacing @@ -74,4 +74,4 @@ table, address, fieldset { margin-bottom: 20px; -} +} \ No newline at end of file diff --git a/script/rails b/script/rails new file mode 100755 index 0000000..f8da2cf --- /dev/null +++ b/script/rails @@ -0,0 +1,6 @@ +#!/usr/bin/env ruby +# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application. + +APP_PATH = File.expand_path('../../config/application', __FILE__) +require File.expand_path('../../config/boot', __FILE__) +require 'rails/commands' diff --git a/csesoc/campattendees/__init__.py b/vendor/plugins/.gitkeep similarity index 100% rename from csesoc/campattendees/__init__.py rename to vendor/plugins/.gitkeep