Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Store theme files and other generated assets in source for Heroku dep…

…loyment
  • Loading branch information...
commit c3bd4fef3eccd27e064da02d0844f661e761a5a4 1 parent 0535b5f
@rwdaigle authored
Showing with 3,665 additions and 24 deletions.
  1. +1 −5 .gitignore
  2. +1 −0  .rvmrc
  3. +16 −0 Gemfile
  4. +52 −0 Gemfile.lock
  5. +7 −7 config/environments/development.rb
  6. +14 −0 config/initializers/session_store.rb
  7. +3 −12 db/schema.rb
  8. BIN  export.20111220.dump
  9. +5 −0 public/plugin_assets/README
  10. +30 −0 public/plugin_assets/filtered_column_code_macro/default_codemacro.css
  11. +125 −0 public/plugin_assets/filtered_column_code_macro/default_coderay.css
  12. +5 −0 themes/development/site-1/scribbish-mephisto/about.yml
  13. BIN  themes/development/site-1/scribbish-mephisto/images/background.gif
  14. BIN  themes/development/site-1/scribbish-mephisto/images/gravatar.gif
  15. BIN  themes/development/site-1/scribbish-mephisto/images/header_shadow.gif
  16. BIN  themes/development/site-1/scribbish-mephisto/images/logomark_bw_sm.png
  17. BIN  themes/development/site-1/scribbish-mephisto/images/logomark_colored_lg.png
  18. BIN  themes/development/site-1/scribbish-mephisto/images/mephisto-badge-tiny.png
  19. BIN  themes/development/site-1/scribbish-mephisto/images/twitter.jpg
  20. BIN  themes/development/site-1/scribbish-mephisto/images/wwr.png
  21. +2,264 −0 themes/development/site-1/scribbish-mephisto/javascripts/prototype.js
  22. +90 −0 themes/development/site-1/scribbish-mephisto/javascripts/scribbish.js
  23. +207 −0 themes/development/site-1/scribbish-mephisto/layouts/layout.liquid
  24. BIN  themes/development/site-1/scribbish-mephisto/preview.png
  25. +38 −0 themes/development/site-1/scribbish-mephisto/stylesheets/application.css
  26. +105 −0 themes/development/site-1/scribbish-mephisto/stylesheets/coderay.css
  27. +105 −0 themes/development/site-1/scribbish-mephisto/stylesheets/coderay.css.jamisbuck
  28. +347 −0 themes/development/site-1/scribbish-mephisto/stylesheets/content.css
  29. +47 −0 themes/development/site-1/scribbish-mephisto/stylesheets/layout.css
  30. +40 −0 themes/development/site-1/scribbish-mephisto/stylesheets/local.css
  31. +17 −0 themes/development/site-1/scribbish-mephisto/templates/_article.liquid
  32. +22 −0 themes/development/site-1/scribbish-mephisto/templates/_article_ads.liquid
  33. +8 −0 themes/development/site-1/scribbish-mephisto/templates/_article_author.liquid
  34. +43 −0 themes/development/site-1/scribbish-mephisto/templates/_article_comments.liquid
  35. +8 −0 themes/development/site-1/scribbish-mephisto/templates/_article_content.liquid
  36. +20 −0 themes/development/site-1/scribbish-mephisto/templates/_article_meta.liquid
  37. +15 −0 themes/development/site-1/scribbish-mephisto/templates/_article_rdf.liquid
  38. +1 −0  themes/development/site-1/scribbish-mephisto/templates/archive.liquid
  39. +7 −0 themes/development/site-1/scribbish-mephisto/templates/bare.liquid
  40. +4 −0 themes/development/site-1/scribbish-mephisto/templates/error.liquid
  41. +1 −0  themes/development/site-1/scribbish-mephisto/templates/home.liquid
  42. +10 −0 themes/development/site-1/scribbish-mephisto/templates/search.liquid
  43. +1 −0  themes/development/site-1/scribbish-mephisto/templates/section.liquid
  44. +5 −0 themes/development/site-1/scribbish-mephisto/templates/single.liquid
  45. +1 −0  themes/development/site-1/scribbish-mephisto/templates/tag.liquid
View
6 .gitignore
@@ -3,12 +3,8 @@
Capfile
config/database.yml
config/deploy.rb
-config/initializers/session_store.rb
db/*.sqlite3
log/*.log
-public/assets
public/cache
-public/plugin_assets
tmp
-themes
-*~
+*~
View
1  .rvmrc
@@ -0,0 +1 @@
+rvm use ree-1.8.7-2010.02@ryandaigle.com --create
View
16 Gemfile
@@ -0,0 +1,16 @@
+source "http://rubygems.org"
+
+gem "rails", "2.2.2"
+gem 'RedCloth', '3.0.4', :require => 'redcloth'
+gem 'BlueCloth', '>= 1.0.0', :require => 'bluecloth'
+gem 'rubyzip', '>= 0.9.1', :require => 'zip/zipfilesystem'
+gem 'liquid', '~> 1.9.0'
+gem 'will_paginate', '>= 2.2.2'
+gem 'mocha', '>= 0.9.3'
+gem 'coderay', '>= 0.8.260'
+gem 'tzinfo', '>= 0.3.12'
+gem 'safe_erb','>= 0.1.2', :require => 'safe_erb', :git => 'https://github.com/emk/safe_erb.git'
+
+group :development, :test do
+# gem 'brynary-webrat', '>= 0.3.2.2'
+end
View
52 Gemfile.lock
@@ -0,0 +1,52 @@
+GIT
+ remote: https://github.com/emk/safe_erb.git
+ revision: 59327ee8a18bbaa26c613aac5c6f1d9575aa6202
+ specs:
+ safe_erb (0.1.2)
+
+GEM
+ remote: http://rubygems.org/
+ specs:
+ BlueCloth (1.0.1)
+ RedCloth (3.0.4)
+ actionmailer (2.2.2)
+ actionpack (= 2.2.2)
+ actionpack (2.2.2)
+ activesupport (= 2.2.2)
+ activerecord (2.2.2)
+ activesupport (= 2.2.2)
+ activeresource (2.2.2)
+ activesupport (= 2.2.2)
+ activesupport (2.2.2)
+ coderay (0.9.7)
+ hoe (2.12.5)
+ rake (~> 0.8)
+ liquid (1.9.0)
+ hoe (>= 1.5.1)
+ mocha (0.9.12)
+ rails (2.2.2)
+ actionmailer (= 2.2.2)
+ actionpack (= 2.2.2)
+ activerecord (= 2.2.2)
+ activeresource (= 2.2.2)
+ activesupport (= 2.2.2)
+ rake (>= 0.8.3)
+ rake (0.8.7)
+ rubyzip (0.9.4)
+ tzinfo (0.3.26)
+ will_paginate (2.3.15)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ BlueCloth (>= 1.0.0)
+ RedCloth (= 3.0.4)
+ coderay (>= 0.8.260)
+ liquid (~> 1.9.0)
+ mocha (>= 0.9.3)
+ rails (= 2.2.2)
+ rubyzip (>= 0.9.1)
+ safe_erb (>= 0.1.2)!
+ tzinfo (>= 0.3.12)
+ will_paginate (>= 2.2.2)
View
14 config/environments/development.rb
@@ -20,10 +20,10 @@
# gems:install' from the development environment than from the test
# environment, and (2) anyone doing Mephisto development should _really_ be
# running the tests anyway.
-config.gem 'ruby-debug'
-config.gem 'faker', :version => '>= 0.3.1'
-config.gem 'notahat-machinist', :version => '>= 0.1.2', :lib => 'machinist',
- :source => 'http://gems.github.com'
-config.gem 'nokogiri', :version => '>= 1.1.0' # Used by webrat.
-config.gem 'brynary-webrat', :version => '>= 0.3.2.2', :lib => 'webrat',
- :source => 'http://gems.github.com'
+# config.gem 'ruby-debug'
+# config.gem 'faker', :version => '>= 0.3.1'
+# config.gem 'notahat-machinist', :version => '>= 0.1.2', :lib => 'machinist',
+# :source => 'http://gems.github.com'
+# config.gem 'nokogiri', :version => '>= 1.1.0' # Used by webrat.
+# config.gem 'brynary-webrat', :version => '>= 0.3.2.2', :lib => 'webrat',
+# :source => 'http://gems.github.com'
View
14 config/initializers/session_store.rb
@@ -0,0 +1,14 @@
+# This file was generated by 'rake config/initializers/session_store.rb',
+# and should not be made visible to public. Do not check it into github!
+# If you have a load-balancing Mephisto cluster, you will need to use the
+# same version of this file on each machine. And be sure to restart your
+# server when you modify this file.
+
+# Your secret key for verifying cookie session data integrity. If you
+# change this key, all old sessions 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.
+ActionController::Base.session = {
+ :session_key => '_mephisto_session_2',
+ :secret => 'e3554211809f09796910e563721bca0b9aa478a8cea06043b9f42624c857c66a41e19a05cc6b82b9'
+}
View
15 db/schema.rb
@@ -110,7 +110,7 @@
t.integer "assets_count", :default => 0
end
- add_index "contents", ["article_id", "approved", "type"], :name => "idx_comments"
+ add_index "contents", ["approved", "article_id", "type"], :name => "idx_comments"
add_index "contents", ["published_at"], :name => "idx_articles_published"
create_table "events", :force => true do |t|
@@ -125,15 +125,6 @@
t.integer "site_id"
end
- create_table "feedbacks", :force => true do |t|
- t.integer "site_id"
- t.string "name"
- t.string "email"
- t.text "body"
- t.string "key"
- t.datetime "created_at"
- end
-
create_table "memberships", :force => true do |t|
t.integer "site_id"
t.integer "user_id"
@@ -168,6 +159,8 @@
t.text "ping_urls"
t.integer "articles_per_page", :default => 15
t.string "host"
+ t.string "akismet_key", :limit => 100
+ t.string "akismet_url"
t.boolean "approve_comments"
t.integer "comment_age"
t.string "timezone"
@@ -177,8 +170,6 @@
t.string "tag_path"
t.string "tag_layout"
t.string "current_theme_path"
- t.string "akismet_key", :limit => 100
- t.string "akismet_url"
t.string "lang", :default => "en-US", :null => false
end
View
BIN  export.20111220.dump
Binary file not shown
View
5 public/plugin_assets/README
@@ -0,0 +1,5 @@
+Files in this directory are automatically generated from your plugins.
+They are copied from the 'assets' directories of each plugin into this directory
+each time Rails starts (script/server, script/console... and so on).
+Any edits you make will NOT persist across the next server restart; instead you
+should edit the files within the <plugin_name>/assets/ directory itself.
View
30 public/plugin_assets/filtered_column_code_macro/default_codemacro.css
@@ -0,0 +1,30 @@
+/*
+ CSS for <macro:code lang="ruby">
+
+ This css will provide horizontally scrolling code listings. This means
+ that the code listings will no longer have to have a fixed width. It
+ can now dynamically flow with the width of your layout. It is a bit
+ touchy on IE6 due to a bug when trying to mix a <div> styled with
+ overflow:auto with a nested <table>.
+*/
+
+div.CodeMacro {
+ width: 100%; /* required for IE6 horizontal scroll */
+ overflow-x: auto;
+ border: 1px solid silver;
+ margin-bottom: 15px;
+ margin-top: 15px;
+}
+
+div.CodeMacro .CodeRay {
+ border-style: none;
+ padding: 0;
+}
+
+div.CodeMacro table.CodeRay {
+ display: inline-block; /* required for IE6 horizontal scroll */
+}
+
+div.CodeMacro table.CodeRay tbody {
+ background-color: #f8f8f8; /* fix background to fill width of code */
+}
View
125 public/plugin_assets/filtered_column_code_macro/default_coderay.css
@@ -0,0 +1,125 @@
+.CodeRay {
+ background-color: #f8f8f8;
+ border: 1px solid silver;
+ font-family: 'Courier New', 'Terminal', monospace;
+ color: #100;
+}
+.CodeRay pre { margin: 0px }
+
+div.CodeRay { }
+
+span.CodeRay { white-space: pre; border: 0px; padding: 2px }
+
+table.CodeRay { border-collapse: collapse; width: 100%; padding: 2px }
+table.CodeRay td { padding: 2px 4px; vertical-align: top }
+
+.CodeRay .line_numbers, .CodeRay .no {
+ background-color: #def;
+ color: gray;
+ text-align: right;
+}
+.CodeRay .line_numbers tt { font-weight: bold }
+.CodeRay .no { padding: 0px 4px }
+.CodeRay .code { width: 100% }
+
+ol.CodeRay { font-size: 10pt }
+ol.CodeRay li { white-space: pre }
+
+.CodeRay .code pre { overflow: auto }
+
+.CodeRay .debug { color:white ! important; background:blue ! important; }
+
+.CodeRay .af { color:#00C }
+.CodeRay .an { color:#007 }
+.CodeRay .at { color:#f08 }
+.CodeRay .av { color:#700 }
+.CodeRay .aw { color:#C00 }
+.CodeRay .bi { color:#509; font-weight:bold }
+.CodeRay .c { color:#666; }
+
+.CodeRay .ch { color:#04D }
+.CodeRay .ch .k { color:#04D }
+.CodeRay .ch .dl { color:#039 }
+
+.CodeRay .cl { color:#B06; font-weight:bold }
+.CodeRay .co { color:#036; font-weight:bold }
+.CodeRay .cr { color:#0A0 }
+.CodeRay .cv { color:#369 }
+.CodeRay .df { color:#099; font-weight:bold }
+.CodeRay .di { color:#088; font-weight:bold }
+.CodeRay .dl { color:black }
+.CodeRay .do { color:#970 }
+.CodeRay .ds { color:#D42; font-weight:bold }
+.CodeRay .e { color:#666; font-weight:bold }
+.CodeRay .en { color:#800; font-weight:bold }
+.CodeRay .er { color:#F00; background-color:#FAA }
+.CodeRay .ex { color:#F00; font-weight:bold }
+.CodeRay .fl { color:#60E; font-weight:bold }
+.CodeRay .fu { color:#06B; font-weight:bold }
+.CodeRay .gv { color:#d70; font-weight:bold }
+.CodeRay .hx { color:#058; font-weight:bold }
+.CodeRay .i { color:#00D; font-weight:bold }
+.CodeRay .ic { color:#B44; font-weight:bold }
+
+.CodeRay .il { background: #eee }
+.CodeRay .il .il { background: #ddd }
+.CodeRay .il .il .il { background: #ccc }
+.CodeRay .il .idl { font-weight: bold; color: #888 }
+
+.CodeRay .im { color:#f00; }
+.CodeRay .in { color:#B2B; font-weight:bold }
+.CodeRay .iv { color:#33B }
+.CodeRay .la { color:#970; font-weight:bold }
+.CodeRay .lv { color:#963 }
+.CodeRay .oc { color:#40E; font-weight:bold }
+.CodeRay .of { color:#000; font-weight:bold }
+.CodeRay .op { }
+.CodeRay .pc { color:#038; font-weight:bold }
+.CodeRay .pd { color:#369; font-weight:bold }
+.CodeRay .pp { color:#579; }
+.CodeRay .ps { color:#00C; font-weight: bold; }
+.CodeRay .pt { color:#339; font-weight:bold }
+.CodeRay .r, .kw { color:#080; font-weight:bold }
+
+.CodeRay .ke { color: #808; }
+.CodeRay .ke .dl { color: #606; }
+.CodeRay .ke .ch { color: #80f; }
+.CodeRay .vl { color: #088; }
+
+.CodeRay .rx { background-color:#fff0ff }
+.CodeRay .rx .k { color:#808 }
+.CodeRay .rx .dl { color:#404 }
+.CodeRay .rx .mod { color:#C2C }
+.CodeRay .rx .fu { color:#404; font-weight: bold }
+
+.CodeRay .s { background-color:#fff0f0 }
+.CodeRay .s .s { background-color:#ffe0e0 }
+.CodeRay .s .s .s { background-color:#ffd0d0 }
+.CodeRay .s .k { color: #D20; }
+.CodeRay .s .ch { color: #b0b; }
+.CodeRay .s .dl { color: #710; }
+
+.CodeRay .sh { background-color:#f0fff0 }
+.CodeRay .sh .k { color:#2B2 }
+.CodeRay .sh .dl { color:#161 }
+
+.CodeRay .sy { color:#A60 }
+.CodeRay .sy .k { color:#A60 }
+.CodeRay .sy .dl { color:#630 }
+
+.CodeRay .ta { color:#070 }
+.CodeRay .tf { color:#070; font-weight:bold }
+.CodeRay .ts { color:#D70; font-weight:bold }
+.CodeRay .ty { color:#339; font-weight:bold }
+.CodeRay .v { color:#036 }
+.CodeRay .xt { color:#444 }
+
+.CodeRay .ins { background: #afa; }
+.CodeRay .del { background: #faa; }
+.CodeRay .chg { color: #aaf; background: #007; }
+.CodeRay .head { color: #f8f; background: #505 }
+
+.CodeRay .ins .ins { color: #080; font-weight:bold }
+.CodeRay .del .del { color: #800; font-weight:bold }
+.CodeRay .chg .chg { color: #66f; }
+.CodeRay .head .head { color: #f4f; }
View
5 themes/development/site-1/scribbish-mephisto/about.yml
@@ -0,0 +1,5 @@
+title: Scribbish
+author: packagethief
+version: 2.0
+homepage: http://quotedprintable.com/pages/scribbish
+summary: Scribbish is a Typo, Mephisto, and Wordpress theme, and a good starting point for new new themes. Its layout standardizes on a simple xhtml structure, blog entries are formatted using the hAtom microformat specification, and styles are separated into individual files which are included in the correct order, making it easier to control the cascade and to figure out 'what-goes-where'. Use it as-is, or copy it to make new themes.
View
BIN  themes/development/site-1/scribbish-mephisto/images/background.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  themes/development/site-1/scribbish-mephisto/images/gravatar.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  themes/development/site-1/scribbish-mephisto/images/header_shadow.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  themes/development/site-1/scribbish-mephisto/images/logomark_bw_sm.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  themes/development/site-1/scribbish-mephisto/images/logomark_colored_lg.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  themes/development/site-1/scribbish-mephisto/images/mephisto-badge-tiny.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  themes/development/site-1/scribbish-mephisto/images/twitter.jpg
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN  themes/development/site-1/scribbish-mephisto/images/wwr.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
2,264 themes/development/site-1/scribbish-mephisto/javascripts/prototype.js
@@ -0,0 +1,2264 @@
+/* Prototype JavaScript framework, version 1.5.0_rc1
+ * (c) 2005 Sam Stephenson <sam@conio.net>
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.5.0_rc1',
+ BrowserFeatures: {
+ XPath: !!document.evaluate
+ },
+
+ ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)',
+ emptyFunction: function() {},
+ K: function(x) { return x }
+}
+
+var Class = {
+ create: function() {
+ return function() {
+ this.initialize.apply(this, arguments);
+ }
+ }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+ for (var property in source) {
+ destination[property] = source[property];
+ }
+ return destination;
+}
+
+Object.extend(Object, {
+ inspect: function(object) {
+ try {
+ if (object == undefined) return 'undefined';
+ if (object == null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ },
+
+ keys: function(object) {
+ var keys = [];
+ for (var property in object)
+ keys.push(property);
+ return keys;
+ },
+
+ values: function(object) {
+ var values = [];
+ for (var property in object)
+ values.push(object[property]);
+ return values;
+ },
+
+ clone: function(object) {
+ return Object.extend({}, object);
+ }
+});
+
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event) {
+ return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
+ }
+}
+
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ var digits = this.toString(16);
+ if (this < 16) return '0' + digits;
+ return digits;
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0; i < arguments.length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
+
+ return returnValue;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+ 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);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.callback(this);
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+}
+Object.extend(String.prototype, {
+ gsub: function(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += (replacement(match) || '').toString();
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
+
+ sub: function(pattern, replacement, count) {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = count === undefined ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ },
+
+ scan: function(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return this;
+ },
+
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = truncation === undefined ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : this;
+ },
+
+ strip: function() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
+
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ },
+
+ escapeHTML: function() {
+ var div = document.createElement('div');
+ var text = document.createTextNode(this);
+ div.appendChild(text);
+ return div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = document.createElement('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? div.childNodes[0].nodeValue : '';
+ },
+
+ toQueryParams: function() {
+ var pairs = this.match(/^\??(.*)$/)[1].split('&');
+ return pairs.inject({}, function(params, pairString) {
+ var pair = pairString.split('=');
+ var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+ params[decodeURIComponent(pair[0])] = value;
+ return params;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ camelize: function() {
+ var oStringList = this.split('-');
+ if (oStringList.length == 1) return oStringList[0];
+
+ var camelizedString = this.indexOf('-') == 0
+ ? oStringList[0].charAt(0).toUpperCase() + oStringList[0].substring(1)
+ : oStringList[0];
+
+ for (var i = 1, len = oStringList.length; i < len; i++) {
+ var s = oStringList[i];
+ camelizedString += s.charAt(0).toUpperCase() + s.substring(1);
+ }
+
+ return camelizedString;
+ },
+
+ inspect: function(useDoubleQuotes) {
+ var escapedString = this.replace(/\\/g, '\\\\');
+ if (useDoubleQuotes)
+ return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ else
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (typeof replacement == 'function') return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ return this.template.gsub(this.pattern, function(match) {
+ var before = match[1];
+ if (before == '\\') return match[2];
+ return before + (object[match[3]] || '').toString();
+ });
+ }
+}
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function(iterator) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ try {
+ iterator(value, index++);
+ } catch (e) {
+ if (e != $continue) throw e;
+ }
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ },
+
+ all: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator) {
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!(iterator || Prototype.K)(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(iterator(value, index));
+ });
+ return results;
+ },
+
+ detect: function (iterator) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(pattern, iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ var stringValue = value.toString();
+ if (stringValue.match(pattern))
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function(object) {
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inject: function(memo, iterator) {
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.collect(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value >= result)
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value < result)
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator) {
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ ((iterator || Prototype.K)(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator) {
+ return this.collect(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.collect(Prototype.K);
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (typeof args.last() == 'function')
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ },
+
+ inspect: function() {
+ return '#<Enumerable:' + this.toArray().inspect() + '>';
+ }
+}
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0; i < iterable.length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse)
+ Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0; i < this.length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != undefined || value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(value && value.constructor == Array ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function(object) {
+ for (var i = 0; i < this.length; i++)
+ if (this[i] == object) return i;
+ return -1;
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ reduce: function() {
+ return this.length > 1 ? this : this[0];
+ },
+
+ uniq: function() {
+ return this.inject([], function(array, value) {
+ return array.include(value) ? array : array.concat([value]);
+ });
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+var Hash = {
+ _each: function(iterator) {
+ for (var key in this) {
+ var value = this[key];
+ if (typeof value == 'function') continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ merge: function(hash) {
+ return $H(hash).inject($H(this), function(mergedHash, pair) {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ toQueryString: function() {
+ return this.map(function(pair) {
+ return pair.map(encodeURIComponent).join('=');
+ }).join('&');
+ },
+
+ inspect: function() {
+ return '#<Hash:{' + this.map(function(pair) {
+ return pair.map(Object.inspect).join(': ');
+ }).join(', ') + '}>';
+ }
+}
+
+function $H(object) {
+ var hash = Object.extend({}, object || {});
+ Object.extend(hash, Enumerable);
+ Object.extend(hash, Hash);
+ return hash;
+}
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ while (this.include(value)) {
+ iterator(value);
+ value = value.succ();
+ }
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
+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(responderToAdd) {
+ if (!this.include(responderToAdd))
+ this.responders.push(responderToAdd);
+ },
+
+ unregister: function(responderToRemove) {
+ this.responders = this.responders.without(responderToRemove);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (responder[callback] && typeof responder[callback] == 'function') {
+ 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 = function() {};
+Ajax.Base.prototype = {
+ setOptions: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ parameters: ''
+ }
+ Object.extend(this.options, options || {});
+ },
+
+ responseIsSuccess: function() {
+ return this.transport.status == undefined
+ || this.transport.status == 0
+ || (this.transport.status >= 200 && this.transport.status < 300);
+ },
+
+ responseIsFailure: function() {
+ return !this.responseIsSuccess();
+ }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(url, options) {
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+ this.request(url);
+ },
+
+ request: function(url) {
+ var parameters = this.options.parameters || '';
+ if (parameters.length > 0) parameters += '&_=';
+
+ /* Simulate other verbs over post */
+ if (this.options.method != 'get' && this.options.method != 'post') {
+ parameters += (parameters.length > 0 ? '&' : '') + '_method=' + this.options.method;
+ this.options.method = 'post';
+ }
+
+ try {
+ this.url = url;
+ if (this.options.method == 'get' && parameters.length > 0)
+ this.url += (this.url.match(/\?/) ? '&' : '?') + parameters;
+
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.options.method, this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous)
+ setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ var body = this.options.postBody ? this.options.postBody : parameters;
+ this.transport.send(this.options.method == 'post' ? body : null);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
+ this.onStateChange();
+
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ setRequestHeaders: function() {
+ var requestHeaders =
+ ['X-Requested-With', 'XMLHttpRequest',
+ 'X-Prototype-Version', Prototype.Version,
+ 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];
+
+ if (this.options.method == 'post') {
+ requestHeaders.push('Content-type', this.options.contentType);
+
+ /* Force "Connection: close" for Mozilla browsers to work around
+ * a bug where XMLHttpReqeuest sends an incorrect Content-length
+ * header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType)
+ requestHeaders.push('Connection', 'close');
+ }
+
+ if (this.options.requestHeaders)
+ requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);
+
+ for (var i = 0; i < requestHeaders.length; i += 2)
+ this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState != 1)
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ header: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) {}
+ },
+
+ evalJSON: function() {
+ try {
+ return eval('(' + this.header('X-JSON') + ')');
+ } catch (e) {}
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ respondToReadyState: function(readyState) {
+ var event = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
+
+ if (event == 'Complete') {
+ try {
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if ((this.header('Content-type') || '').match(/^text\/javascript/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + event] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + event, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ /* Avoid memory leak in MSIE: clean up the oncomplete event handler */
+ if (event == 'Complete')
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+ initialize: function(container, url, options) {
+ this.containers = {
+ success: container.success ? $(container.success) : $(container),
+ failure: container.failure ? $(container.failure) :
+ (container.success ? null : $(container))
+ }
+
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
+ this.options.onComplete = (function(transport, object) {
+ this.updateContent();
+ onComplete(transport, object);
+ }).bind(this);
+
+ this.request(url);
+ },
+
+ updateContent: function() {
+ var receiver = this.responseIsSuccess() ?
+ this.containers.success : this.containers.failure;
+ var response = this.transport.responseText;
+
+ if (!this.options.evalScripts)
+ response = response.stripScripts();
+
+ if (receiver) {
+ if (this.options.insertion) {
+ new this.options.insertion(receiver, response);
+ } else {
+ Element.update(receiver, response);
+ }
+ }
+
+ if (this.responseIsSuccess()) {
+ if (this.onComplete)
+ setTimeout(this.onComplete.bind(this), 10);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(container, url, options) {
+ this.setOptions(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(request) {
+ if (this.options.decay) {
+ this.decay = (request.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
+ }
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.decay * this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+function $() {
+ var results = [], element;
+ for (var i = 0; i < arguments.length; i++) {
+ element = arguments[i];
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ results.push(Element.extend(element));
+ }
+ return results.reduce();
+}
+
+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, len = query.snapshotLength; i < len; i++)
+ results.push(query.snapshotItem(i));
+ return results;
+ }
+}
+
+document.getElementsByClassName = function(className, parentElement) {
+ if (Prototype.BrowserFeatures.XPath) {
+ var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
+ return document._getElementsByXPath(q, parentElement);
+ } else {
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ var elements = [], child;
+ for (var i = 0, len = children.length; i < len; i++) {
+ child = children[i];
+ if (child.className.length == 0) continue;
+ if (child.className == className ||
+ child.className.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element)
+ var Element = new Object();
+
+Element.extend = function(element) {
+ if (!element) return;
+ if (_nativeExtensions || element.nodeType == 3) return element;
+
+ if (!element._extended && element.tagName && element != window) {
+ var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
+
+ if (element.tagName == 'FORM')
+ Object.extend(methods, Form.Methods);
+ if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
+ Object.extend(methods, Form.Element.Methods);
+
+ for (var property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function')
+ element[property] = cache.findOrStore(value);
+ }
+ }
+
+ element._extended = true;
+ return element;
+}
+
+Element.extend.cache = {
+ findOrStore: function(value) {
+ return this[value] = this[value] || function() {
+ return value.apply(null, [this].concat($A(arguments)));
+ }
+ }
+}
+
+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).style.display = 'none';
+ return element;
+ },
+
+ show: function(element) {
+ $(element).style.display = '';
+ return element;
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ },
+
+ update: function(element, html) {
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ },
+
+ replace: function(element, html) {
+ element = $(element);
+ if (element.outerHTML) {
+ element.outerHTML = html.stripScripts();
+ } else {
+ var range = element.ownerDocument.createRange();
+ range.selectNodeContents(element);
+ element.parentNode.replaceChild(
+ range.createContextualFragment(html.stripScripts()), element);
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ },
+
+ 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();
+ var value = (element[property] || '').toString();
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
+ });
+ return result + '>';
+ },
+
+ recursivelyCollect: function(element, property) {
+ element = $(element);
+ var elements = [];
+ while (element = element[property])
+ if (element.nodeType == 1)
+ elements.push(Element.extend(element));
+ return elements;
+ },
+
+ ancestors: function(element) {
+ return $(element).recursivelyCollect('parentNode');
+ },
+
+ descendants: function(element) {
+ element = $(element);
+ return $A(element.getElementsByTagName('*'));
+ },
+
+ previousSiblings: function(element) {
+ return $(element).recursivelyCollect('previousSibling');
+ },
+
+ nextSiblings: function(element) {
+ return $(element).recursivelyCollect('nextSibling');
+ },
+
+ siblings: function(element) {
+ element = $(element);
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
+ },
+
+ match: function(element, selector) {
+ element = $(element);
+ if (typeof selector == 'string')
+ selector = new Selector(selector);
+ return selector.match(element);
+ },
+
+ up: function(element, expression, index) {
+ return Selector.findElement($(element).ancestors(), expression, index);
+ },
+
+ down: function(element, expression, index) {
+ return Selector.findElement($(element).descendants(), expression, index);
+ },
+
+ previous: function(element, expression, index) {
+ return Selector.findElement($(element).previousSiblings(), expression, index);
+ },
+
+ next: function(element, expression, index) {
+ return Selector.findElement($(element).nextSiblings(), expression, index);
+ },
+
+ getElementsBySelector: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element, args);
+ },
+
+ getElementsByClassName: function(element, className) {
+ element = $(element);
+ return document.getElementsByClassName(className, element);
+ },
+
+ getHeight: function(element) {
+ element = $(element);
+ return element.offsetHeight;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ return Element.classNames(element).include(className);
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element).add(className);
+ return element;
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element).remove(className);
+ return element;
+ },
+
+ observe: function() {
+ Event.observe.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+ stopObserving: function() {
+ Event.stopObserving.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+ // removes whitespace-only text node children
+ 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.match(/^\s*$/);
+ },
+
+ childOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var x = element.x ? element.x : element.offsetLeft,
+ y = element.y ? element.y : element.offsetTop;
+ window.scrollTo(x, y);
+ return element;
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ var value = element.style[style.camelize()];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css.getPropertyValue(style) : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style.camelize()];
+ }
+ }
+
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function(element, style) {
+ element = $(element);
+ for (var name in style)
+ element.style[name.camelize()] = style[name];
+ return element;
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ if (Element.getStyle(element, 'display') != 'none')
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = '';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = 'none';
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.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._overflow = element.style.overflow || 'auto';
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+ element.style.overflow = 'hidden';
+ return element;
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (!element._overflow) return;
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+ element._overflow = null;
+ return element;
+ }
+}
+
+// IE is missing .innerHTML support for TABLE-related elements
+if(document.all){
+ Element.Methods.update = function(element, html) {
+ element = $(element);
+ var tagName = element.tagName.toUpperCase();
+ if (['THEAD','TBODY','TR','TD'].indexOf(tagName) > -1) {
+ var div = document.createElement('div');
+ switch (tagName) {
+ case 'THEAD':
+ case 'TBODY':
+ div.innerHTML = '<table><tbody>' + html.stripScripts() + '</tbody></table>';
+ depth = 2;
+ break;
+ case 'TR':
+ div.innerHTML = '<table><tbody><tr>' + html.stripScripts() + '</tr></tbody></table>';
+ depth = 3;
+ break;
+ case 'TD':
+ div.innerHTML = '<table><tbody><tr><td>' + html.stripScripts() + '</td></tr></tbody></table>';
+ depth = 4;
+ }
+ $A(element.childNodes).each(function(node){
+ element.removeChild(node)
+ });
+ depth.times(function(){ div = div.firstChild });
+
+ $A(div.childNodes).each(
+ function(node){ element.appendChild(node) });
+ } else {
+ element.innerHTML = html.stripScripts();
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ }
+}
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if (!window.HTMLElement && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ /* Emulate HTMLElement, HTMLFormElement, HTMLInputElement, HTMLTextAreaElement,
+ and HTMLSelectElement in Safari */
+ ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
+ var klass = window['HTML' + tag + 'Element'] = {};
+ klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
+ });
+}
+
+Element.addMethods = function(methods) {
+ Object.extend(Element.Methods, methods || {});
+
+ function copy(methods, destination) {
+ var cache = Element.extend.cache;
+ for (var property in methods) {
+ var value = methods[property];
+ destination[property] = cache.findOrStore(value);
+ }
+ }
+
+ if (typeof HTMLElement != 'undefined') {
+ copy(Element.Methods, HTMLElement.prototype);
+ copy(Form.Methods, HTMLFormElement.prototype);
+ [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
+ copy(Form.Element.Methods, klass.prototype);
+ });
+ _nativeExtensions = true;
+ }
+}
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+ this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+ initialize: function(element, content) {
+ this.element = $(element);
+ this.content = content.stripScripts();
+
+ if (this.adjacency && this.element.insertAdjacentHTML) {
+ try {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ } catch (e) {
+ var tagName = this.element.tagName.toLowerCase();
+ if (tagName == 'tbody' || tagName == 'tr') {
+ this.insertContent(this.contentFromAnonymousTable());
+ } else {
+ throw e;
+ }
+ }
+ } else {
+ this.range = this.element.ownerDocument.createRange();
+ if (this.initializeRange) this.initializeRange();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
+ }
+
+ setTimeout(function() {content.evalScripts()}, 10);
+ },
+
+ contentFromAnonymousTable: function() {
+ var div = document.createElement('div');
+ div.innerHTML = '<table><tbody>' + this.content + '</tbody></table>';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
+ }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+ initializeRange: function() {
+ this.range.setStartBefore(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
+ }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(true);
+ },
+
+ insertContent: function(fragments) {
+ fragments.reverse(false).each((function(fragment) {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
+ }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.appendChild(fragment);
+ }).bind(this));
+ }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+ initializeRange: function() {
+ this.range.setStartAfter(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment,
+ this.element.nextSibling);
+ }).bind(this));
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+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(this.toArray().concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set(this.select(function(className) {
+ return className != classNameToRemove;
+ }).join(' '));
+ },
+
+ toString: function() {
+ return this.toArray().join(' ');
+ }
+}
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Selector = Class.create();
+Selector.prototype = {
+ initialize: function(expression) {
+ this.params = {classNames: []};
+ this.expression = expression.toString().strip();
+ this.parseExpression();
+ this.compileMatcher();
+ },
+
+ parseExpression: function() {
+ function abort(message) { throw 'Parse error in selector: ' + message; }
+
+ if (this.expression == '') abort('empty expression');
+
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+ params.attributes = params.attributes || [];
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+ expr = match[1];
+ }
+
+ if (expr == '*') return this.params.wildcard = true;
+
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
+ modifier = match[1], clause = match[2], rest = match[3];
+ switch (modifier) {
+ case '#': params.id = clause; break;
+ case '.': params.classNames.push(clause); break;
+ case '':
+ case undefined: params.tagName = clause.toUpperCase(); break;
+ default: abort(expr.inspect());
+ }
+ expr = rest;
+ }
+
+ if (expr.length > 0) abort(expr.inspect());
+ },
+
+ buildMatchExpression: function() {
+ var params = this.params, conditions = [], clause;
+
+ if (params.wildcard)
+ conditions.push('true');
+ if (clause = params.id)
+ conditions.push('element.id == ' + clause.inspect());
+ if (clause = params.tagName)
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+ if ((clause = params.classNames).length > 0)
+ for (var i = 0; i < clause.length; i++)
+ conditions.push('Element.hasClassName(element, ' + clause[i].inspect() + ')');
+ if (clause = params.attributes) {
+ clause.each(function(attribute) {
+ var value = 'element.getAttribute(' + attribute.name.inspect() + ')';
+ var splitValueBy = function(delimiter) {
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+ }
+
+ switch (attribute.operator) {
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
+ case '|=': conditions.push(
+ splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
+ ); break;
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
+ case '':
+ case undefined: conditions.push(value + ' != null'); break;
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
+ }
+ });
+ }
+
+ return conditions.join(' && ');
+ },
+
+ compileMatcher: function() {
+ this.match = new Function('element', 'if (!element.tagName) return false; \
+ return ' + this.buildMatchExpression());
+ },
+
+ findElements: function(scope) {
+ var element;
+
+ if (element = $(this.params.id))
+ if (this.match(element))
+ if (!scope || Element.childOf(element, scope))
+ return [element];
+
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+ var results = [];
+ for (var i = 0; i < scope.length; i++)
+ if (this.match(element = scope[i]))
+ results.push(Element.extend(element));
+
+ return results;
+ },
+
+ toString: function() {
+ return this.expression;
+ }
+}
+
+Object.extend(Selector, {
+ matchElements: function(elements, expression) {
+ var selector = new Selector(expression);
+ return elements.select(selector.match.bind(selector));
+ },
+
+ findElement: function(elements, expression, index) {
+ if (typeof expression == 'number') index = expression, expression = false;
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function(element, expressions) {
+ return expressions.map(function(expression) {
+ return expression.strip().split(/\s+/).inject([null], function(results, expr) {
+ var selector = new Selector(expr);
+ return results.inject([], function(elements, result) {
+ return elements.concat(selector.findElements(result || element));
+ });
+ });
+ }).flatten();
+ }
+});
+
+function $$() {
+ return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+ reset: function(form) {
+ $(form).reset();
+ return form;
+ }
+};
+
+Form.Methods = {
+ serialize: function(form) {
+ return this.serializeElements(Form.getElements($(form)));
+ },
+
+ serializeElements: function(elements) {
+ var queryComponents = new Array();
+
+ for (var i = 0; i < elements.length; i++) {
+ var queryComponent = Form.Element.serialize(elements[i]);
+ if (queryComponent)
+ queryComponents.push(queryComponent);
+ }
+
+ return queryComponents.join('&');
+ },
+
+ getElements: function(form) {
+ return $A($(form).getElementsByTagName('*')).inject([], function(elements, child) {
+ if (Form.Element.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 inputs;
+
+ var matchingInputs = new Array();
+ for (var i = 0; i < inputs.length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) ||
+ (name && input.name != name))
+ continue;
+ matchingInputs.push(input);
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ form = $(form);
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.blur();
+ element.disabled = 'true';
+ }
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ var elements = Form.getElements(form);
+ for (var i = 0; i < elements.length; i++) {
+ var element = elements[i];
+ element.disabled = '';
+ }
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ return Form.getElements(form).find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ Field.activate(Form.findFirstElement(form));
+ return form;
+ }
+}
+
+Object.extend(Form, Form.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+ focus: function(element) {
+ $(element).focus();
+ return element;
+ },
+
+ select: function(element) {
+ $(element).select();
+ return element;
+ }
+}
+
+Form.Element.Methods = {
+ serialize: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter) {
+ var key = encodeURIComponent(parameter[0]);
+ if (key.length == 0) return;
+
+ if (parameter[1].constructor != Array)
+ parameter[1] = [parameter[1]];
+
+ return parameter[1].map(function(value) {
+ return key + '=' + encodeURIComponent(value);
+ }).join('&');
+ }
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ var parameter = Form.Element.Serializers[method](element);
+
+ if (parameter)
+ return parameter[1];
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ element.focus();
+ if (element.select)
+ element.select();
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.blur();
+ element.disabled = false;
+ return element;
+ }
+}
+
+Object.extend(Form.Element, Form.Element.Methods);
+var Field = Form.Element;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+ input: function(element) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element);
+ default:
+ return Form.Element.Serializers.textarea(element);
+ }
+ return false;
+ },
+
+ inputSelector: function(element) {
+ if (element.checked)
+ return [element.name, element.value];
+ },
+
+ textarea: function(element) {
+ return [element.name, element.value];
+ },
+
+ select: function(element) {
+ return Form.Element.Serializers[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ },
+
+ selectOne: function(element) {
+ var value = '', opt, index = element.selectedIndex;
+ if (index >= 0) {
+ opt = element.options[index];
+ value = opt.value || opt.text;
+ }
+ return [element.name, value];
+ },
+
+ selectMany: function(element) {
+ var value = [];
+ for (var i = 0; i < element.length; i++) {
+ var opt = element.options[i];
+ if (opt.selected)
+ value.push(opt.value || opt.text);
+ }
+ return [element.name, value];
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+ initialize: function(element, frequency, callback) {
+ this.frequency = frequency;
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+ 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;
+ }
+ },
+