Commit d4faecd1b9164c86146c2a5ea235c2540ceeab46

Authored by Antonio Terceiro
1 parent 509aeab0

rails3: development + packaging updates

Some specific points:

- ./script/quick-start not works from start to end on a clean Debian
  wheezy system
- Gemfile: remove checking for programs since the Gemfile is not really
  the right place to do this
- Gemfile.lock: lock gem versions against Debian wheezy.  This assumes
  package versions in Debian wheezy + some backported packages available
  at http://people.debian.org/~terceiro/noosfero-wheezy-backports/
- db:data:minimal: add an explicit contact email to the new environment.
  This fixes a long standing issue: when installing Noosfero on a brand
  new system, exim MTA will choke on a malformed sender address, and
  abort the entire installation.
- added a simple Vagrantfile for development purposes

Pending:

- provide proper backports for packages and drop the temporary
  http://people.debian.org/~terceiro/noosfero-wheezy-backports/
Gemfile
... ... @@ -3,11 +3,18 @@ gem 'rails'
3 3 gem 'fast_gettext'
4 4 gem 'acts-as-taggable-on'
5 5 gem 'prototype-rails'
6   -gem 'prototype_legacy_helper', '0.0.0', :git => 'http://git.github.com/rails/prototype_legacy_helper.git'
  6 +gem 'prototype_legacy_helper', '0.0.0', :path => 'vendor/prototype_legacy_helper'
7 7 gem 'rails_autolink'
8 8 gem 'pg'
9   -
10   -# TODO needs a rebuild diff-lcs wrt wheezy
  9 +gem 'rmagick'
  10 +gem 'RedCloth'
  11 +gem 'will_paginate'
  12 +gem 'ruby-feedparser'
  13 +gem 'daemons'
  14 +gem 'thin'
  15 +gem 'hpricot'
  16 +gem 'nokogiri'
  17 +gem 'rake', :require => false
11 18  
12 19 # FIXME list here all actual dependencies (i.e. the ones in debian/control),
13 20 # with their GEM names (not the Debian package names)
... ... @@ -35,12 +42,3 @@ Dir.glob(File.join('config', 'plugins', '*')).each do |plugin|
35 42 plugin_gemfile = File.join(plugin, 'Gemfile')
36 43 eval File.read(plugin_gemfile) if File.exists?(plugin_gemfile)
37 44 end
38   -
39   -def program(name)
40   - unless system("which #{name} > /dev/null")
41   - puts "W: Program #{name} is needed, but was not found in your PATH"
42   - end
43   -end
44   -
45   -program 'java'
46   -program 'firefox'
... ...
Gemfile.lock
1   -GIT
2   - remote: http://git.github.com/rails/prototype_legacy_helper.git
3   - revision: a2cd95c3e3c1a4f7a9566efdab5ce59c886cb05f
  1 +PATH
  2 + remote: vendor/prototype_legacy_helper
4 3 specs:
5 4 prototype_legacy_helper (0.0.0)
6 5  
7 6 GEM
8 7 remote: https://rubygems.org/
9 8 specs:
  9 + RedCloth (4.2.9)
10 10 actionmailer (3.2.6)
11 11 actionpack (= 3.2.6)
12 12 mail (~> 2.4.4)
... ... @@ -34,49 +34,51 @@ GEM
34 34 activesupport (3.2.6)
35 35 i18n (~> 0.6)
36 36 multi_json (~> 1.0)
37   - acts-as-taggable-on (3.0.1)
  37 + acts-as-taggable-on (3.0.2)
38 38 rails (>= 3, < 5)
39 39 arel (3.0.2)
40 40 builder (3.0.0)
41   - capybara (2.2.1)
  41 + capybara (2.1.0)
42 42 mime-types (>= 1.16)
43 43 nokogiri (>= 1.3.3)
44 44 rack (>= 1.0.0)
45 45 rack-test (>= 0.5.4)
46 46 xpath (~> 2.0)
47   - childprocess (0.4.0)
48   - ffi (~> 1.0, >= 1.0.11)
49   - cucumber (1.3.2)
  47 + childprocess (0.3.3)
  48 + ffi (~> 1.0.6)
  49 + cucumber (1.0.6)
50 50 builder (>= 2.1.2)
51   - diff-lcs (>= 1.1.3)
52   - gherkin (~> 2.12.0)
53   - multi_json (~> 1.3)
54   - cucumber-rails (1.4.0)
55   - capybara (>= 1.1.2)
56   - cucumber (>= 1.2.0)
  51 + diff-lcs (>= 1.1.2)
  52 + gherkin (~> 2.4.18)
  53 + json (>= 1.4.6)
  54 + term-ansicolor (>= 1.0.6)
  55 + cucumber-rails (1.0.6)
  56 + capybara (>= 1.1.1)
  57 + cucumber (>= 1.0.6)
57 58 nokogiri (>= 1.5.0)
58   - rails (>= 3.0.0)
  59 + daemons (1.1.5)
59 60 dalli (2.7.0)
60 61 database_cleaner (1.2.0)
61   - diff-lcs (1.2.5)
  62 + diff-lcs (1.1.3)
62 63 erubis (2.7.0)
  64 + eventmachine (0.12.11)
63 65 fast_gettext (0.6.8)
64   - ffi (1.9.3)
65   - gherkin (2.12.2)
66   - multi_json (~> 1.3)
  66 + ffi (1.0.11)
  67 + gherkin (2.4.21)
  68 + json (>= 1.4.6)
67 69 hike (1.2.1)
  70 + hpricot (0.8.6)
68 71 i18n (0.6.0)
69 72 journey (1.0.3)
  73 + json (1.7.3)
70 74 mail (2.4.4)
71 75 i18n (>= 0.4.0)
72 76 mime-types (~> 1.16)
73 77 treetop (~> 1.4.8)
74 78 mime-types (1.19)
75   - mini_portile (0.5.2)
76 79 multi_json (1.3.6)
77   - nokogiri (1.6.1)
78   - mini_portile (~> 0.5.0)
79   - pg (0.17.1)
  80 + nokogiri (1.5.5)
  81 + pg (0.13.2)
80 82 polyglot (0.3.3)
81 83 prototype-rails (3.2.1)
82 84 rails (~> 3.2)
... ... @@ -106,23 +108,22 @@ GEM
106 108 thor (>= 0.14.6, < 2.0)
107 109 rake (0.9.2.2)
108 110 rdoc (3.9.4)
109   - rspec (2.14.1)
110   - rspec-core (~> 2.14.0)
111   - rspec-expectations (~> 2.14.0)
112   - rspec-mocks (~> 2.14.0)
113   - rspec-core (2.14.7)
114   - rspec-expectations (2.14.5)
115   - diff-lcs (>= 1.1.3, < 2.0)
116   - rspec-mocks (2.14.5)
117   - rspec-rails (2.14.1)
  111 + rmagick (2.13.1)
  112 + rspec (2.10.0)
  113 + rspec-core (~> 2.10.0)
  114 + rspec-expectations (~> 2.10.0)
  115 + rspec-mocks (~> 2.10.0)
  116 + rspec-core (2.10.1)
  117 + rspec-expectations (2.10.0)
  118 + diff-lcs (~> 1.1.3)
  119 + rspec-mocks (2.10.1)
  120 + rspec-rails (2.10.1)
118 121 actionpack (>= 3.0)
119   - activemodel (>= 3.0)
120 122 activesupport (>= 3.0)
121 123 railties (>= 3.0)
122   - rspec-core (~> 2.14.0)
123   - rspec-expectations (~> 2.14.0)
124   - rspec-mocks (~> 2.14.0)
125   - rubyzip (1.1.0)
  124 + rspec (~> 2.10.0)
  125 + ruby-feedparser (0.7)
  126 + rubyzip (1.1.2)
126 127 selenium-webdriver (2.39.0)
127 128 childprocess (>= 0.2.5)
128 129 multi_json (~> 1.0)
... ... @@ -133,6 +134,11 @@ GEM
133 134 multi_json (~> 1.0)
134 135 rack (~> 1.0)
135 136 tilt (~> 1.1, != 1.3.0)
  137 + term-ansicolor (1.0.7)
  138 + thin (1.3.1)
  139 + daemons (>= 1.0.9)
  140 + eventmachine (>= 0.12.6)
  141 + rack (>= 1.0.0)
136 142 thor (0.15.3)
137 143 tilt (1.3.3)
138 144 treetop (1.4.10)
... ... @@ -140,6 +146,7 @@ GEM
140 146 polyglot (>= 0.3.1)
141 147 tzinfo (0.3.33)
142 148 websocket (1.0.7)
  149 + will_paginate (3.0.3)
143 150 xpath (2.0.0)
144 151 nokogiri (~> 1.3)
145 152  
... ... @@ -147,19 +154,27 @@ PLATFORMS
147 154 ruby
148 155  
149 156 DEPENDENCIES
  157 + RedCloth
150 158 acts-as-taggable-on
151 159 capybara
152 160 cucumber
153 161 cucumber-rails
  162 + daemons
154 163 dalli
155 164 database_cleaner
156 165 fast_gettext
  166 + hpricot
  167 + nokogiri
157 168 pg
158 169 prototype-rails
159 170 prototype_legacy_helper (= 0.0.0)!
160 171 rails
161 172 rails_autolink
162 173 rake
  174 + rmagick
163 175 rspec
164 176 rspec-rails
  177 + ruby-feedparser
165 178 selenium-webdriver
  179 + thin
  180 + will_paginate
... ...
Vagrantfile 0 → 100644
... ... @@ -0,0 +1,11 @@
  1 +# -*- mode: ruby -*-
  2 +# vi: set ft=ruby :
  3 +
  4 +VAGRANTFILE_API_VERSION = "2"
  5 +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
  6 + config.vm.box = "debian-wheezy"
  7 + config.vm.network :forwarded_port, host: 3000, guest: 3000
  8 + config.vm.provision :shell do |shell|
  9 + shell.inline = 'su vagrant -c /vagrant/script/vagrant'
  10 + end
  11 +end
... ...
config/initializers/01_load_config.rb
1 1 file = Rails.root.join('config', 'noosfero.yml')
2   -NOOSFERO_CONF = File.exists?(file) ? YAML.load_file(file)[RAILS_ENV] || {} : {}
  2 +NOOSFERO_CONF = File.exists?(file) ? YAML.load_file(file)[Rails.env] || {} : {}
... ...
debian/bundle/config 0 → 100644
... ... @@ -0,0 +1,3 @@
  1 +---
  2 +BUNDLE_WITHOUT: test:cucumber
  3 +
... ...
debian/control
... ... @@ -10,9 +10,19 @@ Build-Depends:
10 10 ruby-sqlite3,
11 11 rake,
12 12 rails3 (>= 3.2.6-1~),
  13 + ruby-rspec,
  14 + ruby-rspec-rails,
13 15 ruby-will-paginate,
  16 + cucumber,
  17 + ruby-cucumber-rails,
  18 + ruby-capybara,
  19 + ruby-database-cleaner,
  20 + ruby-selenium-webdriver,
  21 + ruby-tidy,
  22 + ruby-mocha,
  23 + imagemagick,
  24 + xvfb,
14 25 tango-icon-theme,
15   - rcov
16 26 Standards-Version: 3.8.4
17 27 Homepage: http://noosfero.org/
18 28 Vcs-Git: git://git.colivre.coop.br/noosfero.git
... ... @@ -25,8 +35,8 @@ Depends:
25 35 ruby,
26 36 ruby1.9.3,
27 37 rake,
  38 + ruby-dalli,
28 39 ruby-fast-gettext,
29   - ruby-sqlite3,
30 40 ruby-pg,
31 41 ruby-rmagick,
32 42 ruby-redcloth,
... ... @@ -34,12 +44,15 @@ Depends:
34 44 iso-codes,
35 45 ruby-feedparser,
36 46 ruby-daemons,
37   - rcov,
38 47 thin,
39 48 tango-icon-theme,
40 49 ruby-hpricot,
41 50 ruby-nokogiri,
  51 + ruby-acts-as-taggable-on,
  52 + ruby-prototype-rails,
  53 + ruby-rails-autolink,
42 54 memcached,
  55 + ruby-memcache-client,
43 56 debconf,
44 57 dbconfig-common,
45 58 adduser,
... ...
debian/noosfero.dirs
1 1 etc/noosfero
2 2 etc/noosfero/plugins
3 3 usr/share/noosfero/locale
  4 +usr/share/noosfero/.bundle
... ...
debian/noosfero.install
... ... @@ -5,18 +5,20 @@ lib usr/share/noosfero
5 5 script usr/share/noosfero
6 6 util usr/share/noosfero
7 7 Rakefile usr/share/noosfero
8   -vendor/cardmagic-contacts-f66219e6589ccaf3ab9e3574fdd41225d0dd5073 usr/share/noosfero/vendor
9   -vendor/gdata-1.1.1 usr/share/noosfero/vendor
10   -vendor/plugins usr/share/noosfero/vendor
11   -vendor/terceiro-fast_gettext-fe7bb09e30f7b1b5876a3b7a18fe8a254c6f59cb usr/share/noosfero/vendor
12   -vendor/ezcrypto-0.7.2 usr/share/noosfero/vendor
  8 +vendor usr/share/noosfero
13 9  
  10 +Gemfile usr/share/noosfero
  11 +Gemfile.lock usr/share/noosfero
  12 +debian/bundle/config usr/share/noosfero/.bundle
  13 +
  14 +config/application.rb usr/share/noosfero/config
14 15 config/boot.rb usr/share/noosfero/config
15 16 config/environment.rb usr/share/noosfero/config
16 17 config/environments usr/share/noosfero/config
17 18 config/initializers usr/share/noosfero/config
18 19 config/routes.rb usr/share/noosfero/config
19 20 config/locales usr/share/noosfero/config
  21 +config.ru usr/share/noosfero
20 22  
21 23 plugins usr/share/noosfero
22 24  
... ...
gitignore.example
1 1 .gitignore
2 2 .rbenv-*
  3 +.vagrant
3 4 vendor/rails
4 5 doc/api
5 6 doc/noosfero/plugins
... ...
lib/tasks/data.rake
1 1 namespace :db do
2 2 namespace :data do
3 3 task :minimal do
4   - sh 'rails', 'runner', "Environment.create!(:name => 'Noosfero', :is_default => true)"
  4 + sh 'rails', 'runner', "Environment.create!(:name => 'Noosfero', :contact_email => 'noosfero@localhost.localdomain', :is_default => true)"
5 5 unless ENV['NOOSFERO_DOMAIN'].blank?
6 6 sh 'rails', 'runner', "Environment.default.domains << Domain.new(:name => ENV['NOOSFERO_DOMAIN'])"
7 7 end
... ...
lib/tasks/doc.rake
... ... @@ -41,8 +41,8 @@ namespace :noosfero do
41 41 toc_sections.each do |toc|
42 42 section_topics = Dir.glob(File.dirname(toc) + '/*.textile').map {|item| item.sub('.textile', '.en.xhtml') }.reject {|item| ['index.en.xhtml', 'toc.en.xhtml' ].include?(File.basename(item))}
43 43 file toc => section_topics do |t|
44   - require 'app/models/doc_item'
45   - require 'app/models/doc_topic'
  44 + require './app/models/doc_item'
  45 + require './app/models/doc_topic'
46 46 begin
47 47 File.open(toc, 'w') do |output_file|
48 48 section = File.basename(File.dirname(toc))
... ... @@ -67,8 +67,9 @@ namespace :noosfero do
67 67  
68 68 top_level_toc = 'doc/noosfero/toc.en.xhtml'
69 69 file top_level_toc => index_sections do
70   - require 'app/models/doc_item'
71   - require 'app/models/doc_topic'
  70 + $LOAD_PATH << '.'
  71 + require './app/models/doc_item'
  72 + require './app/models/doc_topic'
72 73 begin
73 74 File.open(top_level_toc, 'w') do |output_file|
74 75 output_file.puts "<!-- THIS FILE IS AUTOGENERATED. DO NOT EDIT -->"
... ...
lib/tasks/gettext.rake
... ... @@ -6,7 +6,7 @@ makemo_stamp = &#39;tmp/makemo.stamp&#39;
6 6 desc "Create mo-files for L10n"
7 7 task :makemo => makemo_stamp
8 8 file makemo_stamp => Dir.glob('po/*/noosfero.po') do
9   - ruby '-rconfig/boot -e \'require "gettext"; require "gettext/utils"; GetText.create_mofiles(true, "po", "locale")\' 2>/dev/null'
  9 + ruby '-I. -rconfig/boot -e \'require "gettext"; require "gettext/utils"; GetText.create_mofiles(true, "po", "locale")\''
10 10 Rake::Task['symlinkmo'].invoke
11 11 FileUtils.mkdir_p 'tmp'
12 12 FileUtils.touch makemo_stamp
... ...
lib/tasks/multitenancy.rake
... ... @@ -19,7 +19,7 @@ end
19 19 namespace :db do
20 20  
21 21 task :migrate_other_environments => :environment do
22   - envs = ActiveRecord::Base.configurations.keys.select{ |k| k.match(/_#{RAILS_ENV}$/) }
  22 + envs = ActiveRecord::Base.configurations.keys.select{ |k| k.match(/_#{Rails.env}$/) }
23 23 envs.each do |e|
24 24 puts "*** Migrating #{e}" if Rake.application.options.trace
25 25 system "rake db:migrate RAILS_ENV=#{e}"
... ...
po/eo/noosfero-doc.po
... ... @@ -7,12 +7,12 @@ msgid &quot;&quot;
7 7 msgstr ""
8 8 "Project-Id-Version: PACKAGE VERSION\n"
9 9 "POT-Creation-Date: 2013-12-10 15:48-0300\n"
10   -"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
  10 +"PO-Revision-Date: 2014-03-23 17:11-0300\n"
11 11 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
12 12 "Language-Team: LANGUAGE <LL@li.org>\n"
13 13 "Language: eo\n"
14 14 "MIME-Version: 1.0\n"
15   -"Content-Type: text/plain; charset=CHARSET\n"
  15 +"Content-Type: text/plain; charset=UTF-8\n"
16 16 "Content-Transfer-Encoding: 8bit\n"
17 17 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
18 18  
... ...
po/es/noosfero-doc.po
... ... @@ -7,14 +7,14 @@ msgid &quot;&quot;
7 7 msgstr ""
8 8 "Project-Id-Version: PACKAGE VERSION\n"
9 9 "POT-Creation-Date: 2013-12-10 15:48-0300\n"
10   -"PO-Revision-Date: 2012-10-04 13:01-0600\n"
  10 +"PO-Revision-Date: 2014-03-23 17:11-0300\n"
11 11 "Last-Translator: Luis David Aguilar Carlos <ludwig9003@gmail.com>, Freddy "
12 12 "Martn Hernndez Facio <fmhf14@gmail.com>, Pedro Alonzo Ramrez Tovar <pedro."
13 13 "alonzo709@gmail.com>\n"
14 14 "Language-Team: Spanish <LL@li.org>\n"
15 15 "Language: \n"
16 16 "MIME-Version: 1.0\n"
17   -"Content-Type: text/plain; charset=CHARSET\n"
  17 +"Content-Type: text/plain; charset=UTF-8\n"
18 18 "Content-Transfer-Encoding: ENCODING\n"
19 19  
20 20 # type: Content of: <h1>
... ...
po/it/noosfero-doc.po
... ... @@ -8,12 +8,12 @@ msgid &quot;&quot;
8 8 msgstr ""
9 9 "Project-Id-Version: noosfero 0.36.6\n"
10 10 "POT-Creation-Date: 2013-12-10 15:48-0300\n"
11   -"PO-Revision-Date: 2012-06-05 10:32-0300\n"
  11 +"PO-Revision-Date: 2014-03-23 17:10-0300\n"
12 12 "Last-Translator: Daniela Feitosa <danielafeitosa@colivre.coop.br>\n"
13 13 "Language-Team: LANGUAGE TEAM <LL@li.org>\n"
14 14 "Language: \n"
15 15 "MIME-Version: 1.0\n"
16   -"Content-Type: text/plain; charset=CHARSET\n"
  16 +"Content-Type: text/plain; charset=UTF-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 18  
19 19 #. type: Content of: <h1>
... ...
po/noosfero-doc.pot
... ... @@ -13,7 +13,7 @@ msgstr &quot;&quot;
13 13 "Language-Team: LANGUAGE <LL@li.org>\n"
14 14 "Language: \n"
15 15 "MIME-Version: 1.0\n"
16   -"Content-Type: text/plain; charset=CHARSET\n"
  16 +"Content-Type: text/plain; charset=UTF-8\n"
17 17 "Content-Transfer-Encoding: 8bit\n"
18 18  
19 19 #. type: Content of: <h1>
... ...
script/install-dependencies/debian-wheezy.sh
1   -# needed to run noosfero
2   -runtime_dependencies=$(sed -e '/^\s*#/d; 1,/^Depends:/d; /^Recommends:/,$ d; s/([^)]*)//g; s/,\s*/\n/g' debian/control | grep -v 'memcached\|debconf\|dbconfig-common\|postgresql\|misc:Depends\|adduser\|mail-transport-agent')
3   -run sudo apt-get -y install $runtime_dependencies
4   -sudo apt-get -y install iceweasel || sudo apt-get -y install firefox
  1 +# FIXME upload to a more official repository and sign with an existing key
  2 +if [ ! -e /etc/apt/sources.list.d/noosfero.list ]; then
  3 + sudo tee /etc/apt/sources.list.d/noosfero.list <<EOF
  4 +deb http://people.debian.org/~terceiro/noosfero-wheezy-backports/ ./
  5 +EOF
  6 + sudo apt-key add - <<EOF
  7 +-----BEGIN PGP PUBLIC KEY BLOCK-----
  8 +Version: GnuPG v1
5 9  
6   -# needed for development
7   -run sudo apt-get -y install ruby-tidy ruby-mocha imagemagick po4a xvfb libxml2-dev libxslt1-dev
  10 +mQINBEo1mTQBEAD29YIKM0hM2IsB+TzBOpQja6h5hJ1gVeP7IWhC8E11jwaaoP1K
  11 +SXESKFMVPt0es0aCSDftm5TVTvLl08MG9fZBFT8pERfkWTEWWhY1MJ28sV8PRBHf
  12 +nhN0mv5aduvgVx32+aCD0mWhI/3XHObf6c/X9WMwEaH+6A9UFiXRCyflra9YOfHU
  13 +inXj5aYllc2UNiNxPhJ5sQTv97hdVbb/dFa+t9A2LFgPADbwUW+ShJN8zGR3XMne
  14 +lXTcOgPhBadiNPPi8PztfOgcUk/NqZ5H4i0cXXbZB6leWcGMMMiWNexapgea/Hvp
  15 +aXT2kSIug7OySFXM4nhM4xGo426+r9QHx1dzndHP5AW+WRuJmi3hMEdj22ifIFrV
  16 +XtwovTb6/R2nG7WLVSHKg1AuFvIfG1RrTaVUVMcXVGX83CB2qKjfMHFRyMKUxoK7
  17 +cZZkgD+sst47L+P3MlrRPfuB6selEySIrcwXTxFiuhLf74Zc8AZZeOi5ae2GObGr
  18 +b40wIT4HpJZO9M2YfZkMcnFsAqB8D4tPz9OjXiZdqNrXBMKJo0nsOFsYqkOCpnXP
  19 +ic4HQvmEaEWzNuPlWFH54AQf3zAWMoawLXOfgAOYAc8gf1dxYOTMJEBIplBBj8ch
  20 +E7WeiTv/f9vxuyX4CfTuuX/EEPTvkJ69bcBExtSm+bNs7fgwQwju0sHE7QARAQAB
  21 +tC1BbnRvbmlvIFRlcmNlaXJvIDx0ZXJjZWlyb0Bzb2Z0d2FyZWxpdnJlLm9yZz6J
  22 +AjoEEwEIACQCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AFAko1mzkCGQEACgkQ
  23 +/A2xu81GC96yww/9HLaTgFTwnKZUhFEgcR9uOyZrb87NvCuXRkGAcy9sr5axSewh
  24 +Fibf0I6eFWvq2goOMaPp4rKAFI8UDm/clFUrO62LRKUXy+1/8KWvTJm4c7p7mg9f
  25 +Yhs8DPdQAKhl1AOqsT0m93ck+rQcYfAmSkBkX3usu+xEECrVH7oxD0nv3K+UDupT
  26 +TXHYYvSBb2xjB8H7MQqEM04utbZb8osRFBKlz7TEbwuxyacvZPEq9qlchStPVMCm
  27 +sr/sxeSSZawjKl3oZBG58JPj4+/nLkK+ADVP8E/lEtK45u47576QxgA8YHiNYtFm
  28 +lmsrvCyHNaS2g4Pj9gYamYDeFehdH2roQnp28829b/VEs2sUMltj/hZQ58QQNdqe
  29 +CpQVuHELD9tIw7CjGwjUYEMD8sow2ebwnl+ZNj5gz4PtOfetTR+0VBJG69kug1GC
  30 +lD5SsRrdUp3dSfFAIoMG0LTDnfobjDX/VbJ24hBbCAkdE/1io/57X6GSlDg2tZ4+
  31 +gwIexMXzoRSl+to3XQBXSi8CdU99ePlf7MRNIJHpCZnFKZIMVlWpDckqvrGn4Ubv
  32 +UfDBnS7K7lBOKxWvOX+uvYxSD0Deo5tbCPKH40pYmDT9R87QQhzI8QnrUUaUEcM0
  33 +G28XNcamChJFH/mEU3+Is9fSV4eyoN1sKi0gbvtgha0AZewFbeUkCH5aLae0J0Fu
  34 +dG9uaW8gVGVyY2Vpcm8gPHRlcmNlaXJvQGRjYy51ZmJhLmJyPokCNwQTAQgAIQUC
  35 +SjWa4AIbAwULCQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRD8DbG7zUYL3u4FD/4x
  36 +qv8lFOEc8so7Iktp/1b3wLJ6jCyQ1XtgC2Bem91Rda0VGCoTj83nh1NXW2tV1Phi
  37 +yIo82LA8/oRqsQnMVZZLe1kRX7vnpLzOjUG17kVOwpt7KwuK2VpXFoSYlntSR8cH
  38 +P/vfyhuySN5Gd9RN/liSJLEMUb+r16ibm56mOSWpHFddiQtCGYkqP7Iz1w6L2axq
  39 ++d+LPtD4jKVvQHTh9WPMDjZLNn4+glNOCXWj24GjWzdwsJuUJnOybDbgEpNLdpV0
  40 +I1Tr52ObTB4V1JmMQQ33pPwe70xeV9FcyIhKJKy+6NE/S7yiJDqYd1a10pDQDNvJ
  41 +H2t+d6bxuI6+E3AEhvoOw6mTNrbLWIBciNGEWFSZc18gkmOLEijiu5cmFbvp6btu
  42 +6glgPphTJGkGqkS96KKJcohCYtok9s6QFNr4+yb3iXb1nB2j484vCdukjEg0xoxE
  43 +4sfhf/QRDuKfl5SWwebIhTxv50pJ+WCdXCTneK19SZO86EaGYInNdjZkEF4dO51O
  44 +cLYvbcy+zMMpINdZu+yp2eaaAtJbFPBaMtbY2KJGDp4gzfRiYhyGcujZ3vJ1u5Ch
  45 +KWqtPDsIXsr6a5hy9xI0WFeZ2CeHVO1UvW6i7qj+bgSDI9riAuub4ksk1LJvEL08
  46 +48yC3EZ5Vdai0PY40lVm7+u7Guq8WJku2LnTx2owUbQrQW50b25pbyBUZXJjZWly
  47 +byA8dGVyY2Vpcm9AY29saXZyZS5jb29wLmJyPokCNwQTAQgAIQUCSjWazAIbAwUL
  48 +CQgHAwUVCgkICwUWAgMBAAIeAQIXgAAKCRD8DbG7zUYL3o7ND/9yesmfkHbrezjL
  49 +nTthjgFizm96wDqCpX9Vif6/YNjorXxy5Yrd+Q3XHrPwkDvJQtrIbuG9IfQDvFRQ
  50 +OdvieMquBDbCfIxFVfi8Vbvji6WyR5NU81TbcIw3MC9HXZP9fKJ7ZtFeqjXdjJEs
  51 +stfoi4LmNPzPZqAD8DlV3gpTZ2gIPivA4QxxRR+tX3DHktklbLr8cektLzi1LJIH
  52 +eXYMpVR9l0TyCmaszQiQOzVBUETmANuSgKOvs9qK80bvjrkuA5R7gx5py/VUOFht
  53 +SJzjutL/eVlW/mqJQ/D7l6Je8XhX+niCw0HhbnHMtUruP8pwjcRkdf1b9ikxC1ib
  54 +zpcxw0b6hn5tbcFZxcGWKQYv3H37ve4JJ74ZUnQPwbLKGhxXYi5UpNb1D1gePE/+
  55 +685bwDYI+4r9NB8Wqm7D+Qthaucmwg44lBscXtqUYZJqKGBR8PNH05j83H9q6FLy
  56 +6M0/XYe9dDv6+PJ8QdtRe9ovQ5CibJZV/BERehm4g66k0t6WXofcDuw9mipLz+Os
  57 +YUcx5MSnlbCGFtJjDlgNGaFh7S3cnWf1MX8lAJvftuzbtNq5FWKG0YihxhzMOiUf
  58 +0BTWrh4DYmf3wVs8EGL6JVhTZK6bJRYQjyUrwQ1LuAJ8C40N0bjAnMEMBi5Sratn
  59 +3uZRWXmoqepFn1D4nin/vXxI3p3ZN7QmQW50b25pbyBUZXJjZWlybyA8dGVyY2Vp
  60 +cm9AZGViaWFuLm9yZz6JAjcEEwEIACEFAk4ocKwCGwMFCwkIBwMFFQoJCAsFFgID
  61 +AQACHgECF4AACgkQ/A2xu81GC94nahAA8/gqJeozduayDxTWF/iNnC8PMOD0Stnn
  62 +8GxuoamLmxspmu6etbwSm2FBBrBBZOGOVx6rV6OvtmzYnyIallEqY0lMEi7yySA/
  63 +spPvvEihB8KkVj8CW55BE8vaNhynXzneVzHpheV6zoH8o6YzBzg84LB4X3+IG3EZ
  64 +52SUVMUoek6ZSUrTXLA0AuJE/LrchzRsVzEQj6Y9h5gpCsj9P/8n+4y403k26tuO
  65 +sZWqLv/Sb3byinB0hdrg4U9sm9fk4yDB9fmFWQUaj5nUDxxPgWjdKrvI+y9+d4nP
  66 +09Jg0fgG8viiQTer/Kg0n3Pwka7zGEn2o2BvZ/1LQBF0h+0BqNM0uXxoJoGVyOgY
  67 +P1CIgfy/LZyl9f9kxDN8IYco0sCAjq8ZYIfjc0TLOI6F3StZZaEXDpXfFGfROh2e
  68 +0/1gNEIKicgdLWYQNzcNf3Y7GqJtigRQaGSXpqN2WVL54vTpR55+IPEGgZUNlEU+
  69 +cG366pk9gj8gJo3Myhtm8jibXsPfVbVMz7QPJR/DfBte6s3maFdTDM4X8VbuMGRm
  70 +PqH/6P7+KNVXdOBBMZMk223sZ2xdFVrrFE0njVSnXq+0kX6qmmG323YBm76XNdBO
  71 +4a2s3weSJAboygKJ7uLUGgt2/6FZt2eMlUizta9eGxzkQ0c5e5MVBxHoC0BD1jTu
  72 +FkQeKfqTDH60LkFudG9uaW8gVGVyY2Vpcm8gPGFudG9uaW8udGVyY2Vpcm9AbGlu
  73 +YXJvLm9yZz6JAjcEEwEIACEFAlBGLZoCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgEC
  74 +F4AACgkQ/A2xu81GC96aExAAgz2svW9mADXyLLUEOFMbpNR6G4gtXRTKZNmOsJBe
  75 +7DRewKFWdKlXbtxLs77uZPqzX7S/sNFXetOieg1C2MBM1rL5artKpaXrHxWZEyCa
  76 +DbWVeDdnCC0/WYn6hqrIyqjAJx9h+e3fpGTqxOuztMcp2uiMijuYVaPyCN0z6Hnj
  77 +Y7p/IUTAUtUDU8dLQqzYimKrmsioIEPWlzt44g1MOLt2znQjedMTrDwQOstJj2G7
  78 +9v0meFVllTpMBSECKnt1I4SQEk0kq/R3cPqqLBJ75K+DH0fsGlqb6tW0oIB2BZDn
  79 +nGnttUphS3xgSd1qy3/wTB047w2i5DqrHfleUgyWOMydSck8PK11i1x9UYdV0137
  80 +foVbTnRdY8/uoH32r4SjlRCeQA5VSeBxIq4EDW+G6tGEDawRji4x94TDgXYm54hO
  81 +OzFhkL7zi0wtWc1GFQF7vZyLE93hYkhID70MnajqU0umZL+losmBiOvQGkIt9hSC
  82 +iL+oTlmRw+SXtu7aPmu7Ue9s1ieaeivTMlFf7OD3tB1m/YiRbQH/XcBMaQp0GELI
  83 +QeSzYmmY03E8E/X5IPtF0tRCvfp9GmUn3lfBDWcYhaWy6k3YqvLw8FS+uhmYwfhx
  84 +j5bUV6MRIfNv06rXklhjgX22FUL9p0qilYqJmYQqVYku2Ff431dyDuzv7q0AkMoP
  85 +N6+0JUFudG9uaW8gVGVyY2Vpcm8gPHRlcmNlaXJvQGNzLnViYy5jYT6JAjcEEwEI
  86 +ACEFAk2SGLsCGwMFCwkIBwMFFQoJCAsFFgIDAQACHgECF4AACgkQ/A2xu81GC95+
  87 +mg/+MGbOb7ntM05SO95GNKP8fTQXEnYa6xYIkASkHY7wPfBhYWdYE8kLajWdD1ec
  88 +hDIS3nJ/4fVDUrF1ZJM37lIWJZhhQWwLPONCTlxWYTScosYzKkTeQ0PzBBrrsqOF
  89 +xTtANvb8N9fE6rxkzl7cT48Ty+B0o+U2BolgtM/lmzdu44c7Wr9QIkCpE3wqMfj2
  90 +kw3JUMojOSVDTwavZyPHGa1wibH6R59rQ+WhG6OxiZAXCh8QIEbe6Z50R5Araqc4
  91 +x9/yvBN03j7YCSOJ0hDpRS9VWRWiGNEnn20My0mZRPI+VjvnYmR9w6cHWU33LwQ1
  92 +/xmpJfhJg989/rDRZlJZ4nYgGZoope+5+HcrOud+wrXBUXht3mMDuZTBoBMM5ey/
  93 +Z4Rl1FikNYgD58MDt3bNUyrb+MsUjNuCDPmmdH5CLTG0abxaSjRJ4dR6AZDVqt2x
  94 +KVlhzkGEEBRyKRDmphMoC6AG+kIYuJqfnr1zh35QDuBZNRytt22HzDQk8RcMslrd
  95 +nx94X/53LRvkdXNXoijhMMz4bt6exBz1GbRcW1Oe3JNeW3btekEgSizTfj5rFxQG
  96 +Z8syg28WfQscpY4ffl+YlFALj+8ZqpIzezxa2aB0WqMq8BcFUe7+6NZliDwbOC35
  97 +ufMBt8SqCJd/o4Egmz09AZxVfWHlmQfApzKs3ARXnSkLeoK5Ag0ETXvdtwEQAOjS
  98 +WZVeJx12YPlaz4ylULBrVpgbcSucTIYkx5sPFc0cJCRseG7AKBOG+Me4SfLma25/
  99 +IhcmoEsxCgo9eNM5XMysg3jo7Pui6g8OEw5wNIlKHsrOXk0ITSZpimxltrEMLm5a
  100 +eaF95Ne35VNyr285H/AL1qM+Ubwfmpwd1Eu49z39/aY/0IDymdO11Aai8kz2OHED
  101 +Rkx/Fe95Xx4JhdkwSYoaE3Tzz8GGU6Rig+MwJZeb9YiFSXHqRgP1+IjI+Ht1APvH
  102 +kUKwXfmM1IuGBLE6pw0a6V4mWASW4Dy2+0PE/jR1R5AVxh03sd5eUC/BPQ/wFKH7
  103 +0+EryemO5181YLoOv3/RRDHmsxSk9C1BDLboSFbO9Mo5e78xYHkFHonm7iGejYto
  104 +DLE9xHixOiyc86jbAkdL7Qjc6NJVNtCvTU58/4aArFBVzfEvWdz1umFcPmJKaCEp
  105 +8YI8LalWK5meTbVUDuRWE/mtu8/k3jaCzHhj83GFIoFP6YNWGWlAZJGklhvM5Spr
  106 +tvaD78hoaNpuPCh+u0Atuv3uWBHIsczIVxJYbSNvpLu+EN7O4DNnxkFI6GBDhHX+
  107 +lGEJdHn5JXmD43c2JVykS9d3XJcWdlyXgwdwRviXz2/kYdP7iAVLhl7T0skk8/A4
  108 +xv6p2FRMgixM/PIp1GZu915egPlilrFxYAg1xMGLABEBAAGJAh8EGAEIAAkFAk17
  109 +3bcCGwwACgkQ/A2xu81GC97B0w//QT1SS/s1fgJ8IDmbcUrfk3Y5+PvDnmHr8gsJ
  110 +8A8hMJ2OLdxa2lrcWXebmiSPConAJlzBUKqYm+WZItjJYqEvRfLjKpzTJuxxSae1
  111 +v5v7Y2kUPKgIKmaD9EYl3c3SsyQB8lJ9cBhU6vSdo2L7/nckKSheiEw99MnJBK3B
  112 +iyTYikt2NILuInZ0RErZ7xz1jpinCfkvZSYwJ+IiGxCFefYzDFECjj9bWjIE6vz6
  113 +4HyrXjtSdXsCcFrL+fSnhWOpdgmUuzdUWBH84mAWM6aXqNzAHOIrp5VatDWpHBPH
  114 +bi3M/TIHyjrKnsaYrYU5fmhnTdLig2LMZhKg3vHAqvZfb1XbRgYTSuayGW9sGFG5
  115 +AWZDUOuv+E9FAvHGlv7EZJsy+yhQh4cNWlJQJnGEA/HxA2sRZlwGawwjbZ0xF6MG
  116 +0Dj8x+9Eu3/nRYO0VYgzAYVKMF5cBfblNnWG8p5Npz6lfr1sLY1W9E/2XWkwvnr5
  117 +KDSaDo9iTj+Bhk60vWFDjD69oY1HpAZMGuBd/Z0qy0W/l+ovuMAIU6vH9gHtizdY
  118 +uZe/53J8oBHx+zXgPxzCE7mylVCrVgq6MV6NZtEBQSa5PjPrzu12HAnfzHhV/z3Y
  119 +o9boBnVcNoOCGxUTqpg1aCDvzH8B8Y6hQKVETA077iYfLMFcqMaMLGwAXxGGJbCy
  120 +y/cBuQY=
  121 +=oYoG
  122 +-----END PGP PUBLIC KEY BLOCK-----
  123 +EOF
  124 + run sudo apt-get update
  125 +fi
8 126  
9   -sudo apt-get -y install bundler apt-file
10   -sudo apt-file update
  127 +run sudo apt-get -y install dctrl-tools
11 128  
12   -run ./script/debundler
  129 +# needed to run noosfero
  130 +packages=$(grep-dctrl -n -s Build-Depends,Depends,Recommends -S -X noosfero debian/control | sed -e 's/([^)]*)//g; s/,\s*/\n/g' | grep -v 'memcached\|debconf\|dbconfig-common\|misc:Depends\|adduser\|mail-transport-agent')
  131 +run sudo apt-get -y install $packages
  132 +sudo apt-get -y install iceweasel || sudo apt-get -y install firefox
13 133  
14 134 run bundle --local
... ...
script/vagrant 0 → 100755
... ... @@ -0,0 +1,16 @@
  1 +#!/bin/sh
  2 +
  3 +set -e
  4 +sudo apt-get install netcat-traditional
  5 +
  6 +# apt-cacher-ng running on the host
  7 +# 10.0.2.2 = host ip on virtualbox/qemu
  8 +# 192.168..122.1 = host ip on default libvirt bridge
  9 +for ip in 10.0.2.2 192.168.122.1; do
  10 + if nc -z -w 1 $ip 3142; then
  11 + echo "Acquire::http::Proxy \"http://$ip:3142\";" | sudo tee /etc/apt/apt.conf.d/01proxy
  12 + fi
  13 +done
  14 +
  15 +cd /vagrant
  16 +./script/quick-start
... ...
vendor/prototype_legacy_helper/README.markdown 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +# Prototype Legacy Helper
  2 +
  3 +This plugin adds support for `form_remote_tag`, etc from Rails 2 to Rails 3.
  4 +
  5 +## Installation
  6 +
  7 +Either add the following to your `Gemfile` and run `bundle`:
  8 +
  9 + gem 'prototype_legacy_helper', '0.0.0', :git => 'git://github.com/rails/prototype_legacy_helper.git'
  10 +
  11 +or run the following command to vendor the plugin within your app:
  12 +
  13 + rails plugin install git://github.com/rails/prototype_legacy_helper.git
... ...
vendor/prototype_legacy_helper/init.rb 0 → 100644
... ... @@ -0,0 +1 @@
  1 +require 'prototype_legacy_helper'
... ...
vendor/prototype_legacy_helper/lib/prototype_legacy_helper.rb 0 → 100644
... ... @@ -0,0 +1,432 @@
  1 +module PrototypeHelper
  2 + # Creates a button with an onclick event which calls a remote action
  3 + # via XMLHttpRequest
  4 + # The options for specifying the target with :url
  5 + # and defining callbacks is the same as link_to_remote.
  6 + def button_to_remote(name, options = {}, html_options = {})
  7 + button_to_function(name, remote_function(options), html_options)
  8 + end
  9 +
  10 + # Returns a button input tag with the element name of +name+ and a value (i.e., display text) of +value+
  11 + # that will submit form using XMLHttpRequest in the background instead of a regular POST request that
  12 + # reloads the page.
  13 + #
  14 + # # Create a button that submits to the create action
  15 + # #
  16 + # # Generates: <input name="create_btn" onclick="new Ajax.Request('/testing/create',
  17 + # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
  18 + # # return false;" type="button" value="Create" />
  19 + # <%= submit_to_remote 'create_btn', 'Create', :url => { :action => 'create' } %>
  20 + #
  21 + # # Submit to the remote action update and update the DIV succeed or fail based
  22 + # # on the success or failure of the request
  23 + # #
  24 + # # Generates: <input name="update_btn" onclick="new Ajax.Updater({success:'succeed',failure:'fail'},
  25 + # # '/testing/update', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});
  26 + # # return false;" type="button" value="Update" />
  27 + # <%= submit_to_remote 'update_btn', 'Update', :url => { :action => 'update' },
  28 + # :update => { :success => "succeed", :failure => "fail" }
  29 + #
  30 + # <tt>options</tt> argument is the same as in form_remote_tag.
  31 + def submit_to_remote(name, value, options = {})
  32 + options[:with] ||= 'Form.serialize(this.form)'
  33 +
  34 + html_options = options.delete(:html) || {}
  35 + html_options[:name] = name
  36 +
  37 + button_to_remote(value, options, html_options)
  38 + end
  39 +
  40 + # Returns a link to a remote action defined by <tt>options[:url]</tt>
  41 + # (using the url_for format) that's called in the background using
  42 + # XMLHttpRequest. The result of that request can then be inserted into a
  43 + # DOM object whose id can be specified with <tt>options[:update]</tt>.
  44 + # Usually, the result would be a partial prepared by the controller with
  45 + # render :partial.
  46 + #
  47 + # Examples:
  48 + # # Generates: <a href="#" onclick="new Ajax.Updater('posts', '/blog/destroy/3', {asynchronous:true, evalScripts:true});
  49 + # # return false;">Delete this post</a>
  50 + # link_to_remote "Delete this post", :update => "posts",
  51 + # :url => { :action => "destroy", :id => post.id }
  52 + #
  53 + # # Generates: <a href="#" onclick="new Ajax.Updater('emails', '/mail/list_emails', {asynchronous:true, evalScripts:true});
  54 + # # return false;"><img alt="Refresh" src="/images/refresh.png?" /></a>
  55 + # link_to_remote(image_tag("refresh"), :update => "emails",
  56 + # :url => { :action => "list_emails" })
  57 + #
  58 + # You can override the generated HTML options by specifying a hash in
  59 + # <tt>options[:html]</tt>.
  60 + #
  61 + # link_to_remote "Delete this post", :update => "posts",
  62 + # :url => post_url(@post), :method => :delete,
  63 + # :html => { :class => "destructive" }
  64 + #
  65 + # You can also specify a hash for <tt>options[:update]</tt> to allow for
  66 + # easy redirection of output to an other DOM element if a server-side
  67 + # error occurs:
  68 + #
  69 + # Example:
  70 + # # Generates: <a href="#" onclick="new Ajax.Updater({success:'posts',failure:'error'}, '/blog/destroy/5',
  71 + # # {asynchronous:true, evalScripts:true}); return false;">Delete this post</a>
  72 + # link_to_remote "Delete this post",
  73 + # :url => { :action => "destroy", :id => post.id },
  74 + # :update => { :success => "posts", :failure => "error" }
  75 + #
  76 + # Optionally, you can use the <tt>options[:position]</tt> parameter to
  77 + # influence how the target DOM element is updated. It must be one of
  78 + # <tt>:before</tt>, <tt>:top</tt>, <tt>:bottom</tt>, or <tt>:after</tt>.
  79 + #
  80 + # The method used is by default POST. You can also specify GET or you
  81 + # can simulate PUT or DELETE over POST. All specified with <tt>options[:method]</tt>
  82 + #
  83 + # Example:
  84 + # # Generates: <a href="#" onclick="new Ajax.Request('/person/4', {asynchronous:true, evalScripts:true, method:'delete'});
  85 + # # return false;">Destroy</a>
  86 + # link_to_remote "Destroy", :url => person_url(:id => person), :method => :delete
  87 + #
  88 + # By default, these remote requests are processed asynchronous during
  89 + # which various JavaScript callbacks can be triggered (for progress
  90 + # indicators and the likes). All callbacks get access to the
  91 + # <tt>request</tt> object, which holds the underlying XMLHttpRequest.
  92 + #
  93 + # To access the server response, use <tt>request.responseText</tt>, to
  94 + # find out the HTTP status, use <tt>request.status</tt>.
  95 + #
  96 + # Example:
  97 + # # Generates: <a href="#" onclick="new Ajax.Request('/words/undo?n=33', {asynchronous:true, evalScripts:true,
  98 + # # onComplete:function(request){undoRequestCompleted(request)}}); return false;">hello</a>
  99 + # word = 'hello'
  100 + # link_to_remote word,
  101 + # :url => { :action => "undo", :n => word_counter },
  102 + # :complete => "undoRequestCompleted(request)"
  103 + #
  104 + # The callbacks that may be specified are (in order):
  105 + #
  106 + # <tt>:loading</tt>:: Called when the remote document is being
  107 + # loaded with data by the browser.
  108 + # <tt>:loaded</tt>:: Called when the browser has finished loading
  109 + # the remote document.
  110 + # <tt>:interactive</tt>:: Called when the user can interact with the
  111 + # remote document, even though it has not
  112 + # finished loading.
  113 + # <tt>:success</tt>:: Called when the XMLHttpRequest is completed,
  114 + # and the HTTP status code is in the 2XX range.
  115 + # <tt>:failure</tt>:: Called when the XMLHttpRequest is completed,
  116 + # and the HTTP status code is not in the 2XX
  117 + # range.
  118 + # <tt>:complete</tt>:: Called when the XMLHttpRequest is complete
  119 + # (fires after success/failure if they are
  120 + # present).
  121 + #
  122 + # You can further refine <tt>:success</tt> and <tt>:failure</tt> by
  123 + # adding additional callbacks for specific status codes.
  124 + #
  125 + # Example:
  126 + # # Generates: <a href="#" onclick="new Ajax.Request('/testing/action', {asynchronous:true, evalScripts:true,
  127 + # # on404:function(request){alert('Not found...? Wrong URL...?')},
  128 + # # onFailure:function(request){alert('HTTP Error ' + request.status + '!')}}); return false;">hello</a>
  129 + # link_to_remote word,
  130 + # :url => { :action => "action" },
  131 + # 404 => "alert('Not found...? Wrong URL...?')",
  132 + # :failure => "alert('HTTP Error ' + request.status + '!')"
  133 + #
  134 + # A status code callback overrides the success/failure handlers if
  135 + # present.
  136 + #
  137 + # If you for some reason or another need synchronous processing (that'll
  138 + # block the browser while the request is happening), you can specify
  139 + # <tt>options[:type] = :synchronous</tt>.
  140 + #
  141 + # You can customize further browser side call logic by passing in
  142 + # JavaScript code snippets via some optional parameters. In their order
  143 + # of use these are:
  144 + #
  145 + # <tt>:confirm</tt>:: Adds confirmation dialog.
  146 + # <tt>:condition</tt>:: Perform remote request conditionally
  147 + # by this expression. Use this to
  148 + # describe browser-side conditions when
  149 + # request should not be initiated.
  150 + # <tt>:before</tt>:: Called before request is initiated.
  151 + # <tt>:after</tt>:: Called immediately after request was
  152 + # initiated and before <tt>:loading</tt>.
  153 + # <tt>:submit</tt>:: Specifies the DOM element ID that's used
  154 + # as the parent of the form elements. By
  155 + # default this is the current form, but
  156 + # it could just as well be the ID of a
  157 + # table row or any other DOM element.
  158 + # <tt>:with</tt>:: A JavaScript expression specifying
  159 + # the parameters for the XMLHttpRequest.
  160 + # Any expressions should return a valid
  161 + # URL query string.
  162 + #
  163 + # Example:
  164 + #
  165 + # :with => "'name=' + $('name').value"
  166 + #
  167 + # You can generate a link that uses AJAX in the general case, while
  168 + # degrading gracefully to plain link behavior in the absence of
  169 + # JavaScript by setting <tt>html_options[:href]</tt> to an alternate URL.
  170 + # Note the extra curly braces around the <tt>options</tt> hash separate
  171 + # it as the second parameter from <tt>html_options</tt>, the third.
  172 + #
  173 + # Example:
  174 + # link_to_remote "Delete this post",
  175 + # { :update => "posts", :url => { :action => "destroy", :id => post.id } },
  176 + # :href => url_for(:action => "destroy", :id => post.id)
  177 + def link_to_remote(name, options = {}, html_options = nil)
  178 + link_to_function(name, remote_function(options), html_options || options.delete(:html))
  179 + end
  180 +
  181 + # Returns a form tag that will submit using XMLHttpRequest in the
  182 + # background instead of the regular reloading POST arrangement. Even
  183 + # though it's using JavaScript to serialize the form elements, the form
  184 + # submission will work just like a regular submission as viewed by the
  185 + # receiving side (all elements available in <tt>params</tt>). The options for
  186 + # specifying the target with <tt>:url</tt> and defining callbacks is the same as
  187 + # +link_to_remote+.
  188 + #
  189 + # A "fall-through" target for browsers that doesn't do JavaScript can be
  190 + # specified with the <tt>:action</tt>/<tt>:method</tt> options on <tt>:html</tt>.
  191 + #
  192 + # Example:
  193 + # # Generates:
  194 + # # <form action="/some/place" method="post" onsubmit="new Ajax.Request('',
  195 + # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">
  196 + # form_remote_tag :html => { :action =>
  197 + # url_for(:controller => "some", :action => "place") }
  198 + #
  199 + # The Hash passed to the <tt>:html</tt> key is equivalent to the options (2nd)
  200 + # argument in the FormTagHelper.form_tag method.
  201 + #
  202 + # By default the fall-through action is the same as the one specified in
  203 + # the <tt>:url</tt> (and the default method is <tt>:post</tt>).
  204 + #
  205 + # form_remote_tag also takes a block, like form_tag:
  206 + # # Generates:
  207 + # # <form action="/" method="post" onsubmit="new Ajax.Request('/',
  208 + # # {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)});
  209 + # # return false;"> <div><input name="commit" type="submit" value="Save" /></div>
  210 + # # </form>
  211 + # <% form_remote_tag :url => '/posts' do -%>
  212 + # <div><%= submit_tag 'Save' %></div>
  213 + # <% end -%>
  214 + def form_remote_tag(options = {}, &block)
  215 + options[:form] = true
  216 +
  217 + options[:html] ||= {}
  218 + options[:html][:onsubmit] =
  219 + (options[:html][:onsubmit] ? options[:html][:onsubmit] + "; " : "") +
  220 + "#{remote_function(options)}; return false;"
  221 +
  222 + form_tag(options[:html].delete(:action) || url_for(options[:url]), options[:html], &block)
  223 + end
  224 +
  225 + # Creates a form that will submit using XMLHttpRequest in the background
  226 + # instead of the regular reloading POST arrangement and a scope around a
  227 + # specific resource that is used as a base for questioning about
  228 + # values for the fields.
  229 + #
  230 + # === Resource
  231 + #
  232 + # Example:
  233 + # <% remote_form_for(@post) do |f| %>
  234 + # ...
  235 + # <% end %>
  236 + #
  237 + # This will expand to be the same as:
  238 + #
  239 + # <% remote_form_for :post, @post, :url => post_path(@post), :html => { :method => :put, :class => "edit_post", :id => "edit_post_45" } do |f| %>
  240 + # ...
  241 + # <% end %>
  242 + #
  243 + # === Nested Resource
  244 + #
  245 + # Example:
  246 + # <% remote_form_for([@post, @comment]) do |f| %>
  247 + # ...
  248 + # <% end %>
  249 + #
  250 + # This will expand to be the same as:
  251 + #
  252 + # <% remote_form_for :comment, @comment, :url => post_comment_path(@post, @comment), :html => { :method => :put, :class => "edit_comment", :id => "edit_comment_45" } do |f| %>
  253 + # ...
  254 + # <% end %>
  255 + #
  256 + # If you don't need to attach a form to a resource, then check out form_remote_tag.
  257 + #
  258 + # See FormHelper#form_for for additional semantics.
  259 + def remote_form_for(record_or_name_or_array, *args, &proc)
  260 + options = args.extract_options!
  261 +
  262 + case record_or_name_or_array
  263 + when String, Symbol
  264 + object_name = record_or_name_or_array
  265 + when Array
  266 + object = record_or_name_or_array.last
  267 + object_name = ActiveModel::Naming.singular(object)
  268 + apply_form_for_options!(record_or_name_or_array, options)
  269 + args.unshift object
  270 + else
  271 + object = record_or_name_or_array
  272 + object_name = ActiveModel::Naming.singular(record_or_name_or_array)
  273 + apply_form_for_options!(object, options)
  274 + args.unshift object
  275 + end
  276 +
  277 + form_remote_tag options do
  278 + fields_for object_name, *(args << options), &proc
  279 + end
  280 + end
  281 + alias_method :form_remote_for, :remote_form_for
  282 +
  283 + # Returns '<tt>eval(request.responseText)</tt>' which is the JavaScript function
  284 + # that +form_remote_tag+ can call in <tt>:complete</tt> to evaluate a multiple
  285 + # update return document using +update_element_function+ calls.
  286 + def evaluate_remote_response
  287 + "eval(request.responseText)"
  288 + end
  289 +
  290 + # Observes the field with the DOM ID specified by +field_id+ and calls a
  291 + # callback when its contents have changed. The default callback is an
  292 + # Ajax call. By default the value of the observed field is sent as a
  293 + # parameter with the Ajax call.
  294 + #
  295 + # Example:
  296 + # # Generates: new Form.Element.Observer('suggest', 0.25, function(element, value) {new Ajax.Updater('suggest',
  297 + # # '/testing/find_suggestion', {asynchronous:true, evalScripts:true, parameters:'q=' + value})})
  298 + # <%= observe_field :suggest, :url => { :action => :find_suggestion },
  299 + # :frequency => 0.25,
  300 + # :update => :suggest,
  301 + # :with => 'q'
  302 + # %>
  303 + #
  304 + # Required +options+ are either of:
  305 + # <tt>:url</tt>:: +url_for+-style options for the action to call
  306 + # when the field has changed.
  307 + # <tt>:function</tt>:: Instead of making a remote call to a URL, you
  308 + # can specify javascript code to be called instead.
  309 + # Note that the value of this option is used as the
  310 + # *body* of the javascript function, a function definition
  311 + # with parameters named element and value will be generated for you
  312 + # for example:
  313 + # observe_field("glass", :frequency => 1, :function => "alert('Element changed')")
  314 + # will generate:
  315 + # new Form.Element.Observer('glass', 1, function(element, value) {alert('Element changed')})
  316 + # The element parameter is the DOM element being observed, and the value is its value at the
  317 + # time the observer is triggered.
  318 + #
  319 + # Additional options are:
  320 + # <tt>:frequency</tt>:: The frequency (in seconds) at which changes to
  321 + # this field will be detected. Not setting this
  322 + # option at all or to a value equal to or less than
  323 + # zero will use event based observation instead of
  324 + # time based observation.
  325 + # <tt>:update</tt>:: Specifies the DOM ID of the element whose
  326 + # innerHTML should be updated with the
  327 + # XMLHttpRequest response text.
  328 + # <tt>:with</tt>:: A JavaScript expression specifying the parameters
  329 + # for the XMLHttpRequest. The default is to send the
  330 + # key and value of the observed field. Any custom
  331 + # expressions should return a valid URL query string.
  332 + # The value of the field is stored in the JavaScript
  333 + # variable +value+.
  334 + #
  335 + # Examples
  336 + #
  337 + # :with => "'my_custom_key=' + value"
  338 + # :with => "'person[name]=' + prompt('New name')"
  339 + # :with => "Form.Element.serialize('other-field')"
  340 + #
  341 + # Finally
  342 + # :with => 'name'
  343 + # is shorthand for
  344 + # :with => "'name=' + value"
  345 + # This essentially just changes the key of the parameter.
  346 + #
  347 + # Additionally, you may specify any of the options documented in the
  348 + # <em>Common options</em> section at the top of this document.
  349 + #
  350 + # Example:
  351 + #
  352 + # # Sends params: {:title => 'Title of the book'} when the book_title input
  353 + # # field is changed.
  354 + # observe_field 'book_title',
  355 + # :url => 'http://example.com/books/edit/1',
  356 + # :with => 'title'
  357 + #
  358 + #
  359 + def observe_field(field_id, options = {})
  360 + if options[:frequency] && options[:frequency] > 0
  361 + build_observer('Form.Element.Observer', field_id, options)
  362 + else
  363 + build_observer('Form.Element.EventObserver', field_id, options)
  364 + end
  365 + end
  366 +
  367 + # Observes the form with the DOM ID specified by +form_id+ and calls a
  368 + # callback when its contents have changed. The default callback is an
  369 + # Ajax call. By default all fields of the observed field are sent as
  370 + # parameters with the Ajax call.
  371 + #
  372 + # The +options+ for +observe_form+ are the same as the options for
  373 + # +observe_field+. The JavaScript variable +value+ available to the
  374 + # <tt>:with</tt> option is set to the serialized form by default.
  375 + def observe_form(form_id, options = {})
  376 + if options[:frequency]
  377 + build_observer('Form.Observer', form_id, options)
  378 + else
  379 + build_observer('Form.EventObserver', form_id, options)
  380 + end
  381 + end
  382 +
  383 + # Periodically calls the specified url (<tt>options[:url]</tt>) every
  384 + # <tt>options[:frequency]</tt> seconds (default is 10). Usually used to
  385 + # update a specified div (<tt>options[:update]</tt>) with the results
  386 + # of the remote call. The options for specifying the target with <tt>:url</tt>
  387 + # and defining callbacks is the same as link_to_remote.
  388 + # Examples:
  389 + # # Call get_averages and put its results in 'avg' every 10 seconds
  390 + # # Generates:
  391 + # # new PeriodicalExecuter(function() {new Ajax.Updater('avg', '/grades/get_averages',
  392 + # # {asynchronous:true, evalScripts:true})}, 10)
  393 + # periodically_call_remote(:url => { :action => 'get_averages' }, :update => 'avg')
  394 + #
  395 + # # Call invoice every 10 seconds with the id of the customer
  396 + # # If it succeeds, update the invoice DIV; if it fails, update the error DIV
  397 + # # Generates:
  398 + # # new PeriodicalExecuter(function() {new Ajax.Updater({success:'invoice',failure:'error'},
  399 + # # '/testing/invoice/16', {asynchronous:true, evalScripts:true})}, 10)
  400 + # periodically_call_remote(:url => { :action => 'invoice', :id => customer.id },
  401 + # :update => { :success => "invoice", :failure => "error" }
  402 + #
  403 + # # Call update every 20 seconds and update the new_block DIV
  404 + # # Generates:
  405 + # # new PeriodicalExecuter(function() {new Ajax.Updater('news_block', 'update', {asynchronous:true, evalScripts:true})}, 20)
  406 + # periodically_call_remote(:url => 'update', :frequency => '20', :update => 'news_block')
  407 + #
  408 + def periodically_call_remote(options = {})
  409 + frequency = options[:frequency] || 10 # every ten seconds by default
  410 + code = "new PeriodicalExecuter(function() {#{remote_function(options)}}, #{frequency})"
  411 + javascript_tag(code)
  412 + end
  413 +
  414 + protected
  415 + def build_observer(klass, name, options = {})
  416 + if options[:with] && (options[:with] !~ /[\{=(.]/)
  417 + options[:with] = "'#{options[:with]}=' + encodeURIComponent(value)"
  418 + else
  419 + options[:with] ||= 'value' unless options[:function]
  420 + end
  421 +
  422 + callback = options[:function] || remote_function(options)
  423 + javascript = "new #{klass}('#{name}', "
  424 + javascript << "#{options[:frequency]}, " if options[:frequency]
  425 + javascript << "function(element, value) {"
  426 + javascript << "#{callback}}"
  427 + javascript << ")"
  428 + javascript_tag(javascript)
  429 + end
  430 +end
  431 +
  432 +ActionController::Base.helper PrototypeHelper
... ...
vendor/prototype_legacy_helper/test/test_prototype_helper.rb 0 → 100644
... ... @@ -0,0 +1,297 @@
  1 +if ENV['RAILS_ROOT']
  2 + environment = File.expand_path('vendor/gems/environment', ENV['RAILS_ROOT'])
  3 + require environment if File.exist?("#{environment}.rb")
  4 +end
  5 +
  6 +$:.unshift File.expand_path('../../lib', __FILE__)
  7 +
  8 +require 'test/unit'
  9 +require 'action_view'
  10 +require 'action_controller'
  11 +require 'active_model'
  12 +require 'prototype_helper'
  13 +
  14 +class Bunny < Struct.new(:Bunny, :id)
  15 +end
  16 +
  17 +class Author
  18 + extend ActiveModel::Naming
  19 +
  20 + attr_reader :id
  21 + def save; @id = 1 end
  22 + def new_record?; @id.nil? end
  23 + def name
  24 + @id.nil? ? 'new author' : "author ##{@id}"
  25 + end
  26 +end
  27 +
  28 +class Article
  29 + extend ActiveModel::Naming
  30 +
  31 + attr_reader :id
  32 + attr_reader :author_id
  33 + def save; @id = 1; @author_id = 1 end
  34 + def new_record?; @id.nil? end
  35 + def name
  36 + @id.nil? ? 'new article' : "article ##{@id}"
  37 + end
  38 +end
  39 +
  40 +class Author::Nested < Author; end
  41 +
  42 +class PrototypeHelperTest < ActionView::TestCase
  43 + attr_accessor :formats, :output_buffer, :template_format
  44 +
  45 + def _evaluate_assigns_and_ivars() end
  46 +
  47 + def reset_formats(format)
  48 + @format = format
  49 + end
  50 +
  51 + def setup
  52 + @record = @author = Author.new
  53 + @article = Article.new
  54 + super
  55 + @template = self
  56 + @controller = Class.new do
  57 + def url_for(options)
  58 + if options.is_a?(String)
  59 + options
  60 + else
  61 + url = "http://www.example.com/"
  62 + url << options[:action].to_s if options and options[:action]
  63 + url << "?a=#{options[:a]}" if options && options[:a]
  64 + url << "&b=#{options[:b]}" if options && options[:a] && options[:b]
  65 + url
  66 + end
  67 + end
  68 + end.new
  69 + end
  70 +
  71 +
  72 + def test_observe_form
  73 + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {new Ajax.Request('http://www.example.com/cart_changed', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
  74 + observe_form("cart", :frequency => 2, :url => { :action => "cart_changed" })
  75 + end
  76 +
  77 + def test_observe_form_using_function_for_callback
  78 + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Observer('cart', 2, function(element, value) {alert('Form changed')})\n//]]>\n</script>),
  79 + observe_form("cart", :frequency => 2, :function => "alert('Form changed')")
  80 + end
  81 +
  82 + def test_observe_field
  83 + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/reorder_if_empty', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
  84 + observe_field("glass", :frequency => 5.minutes, :url => { :action => "reorder_if_empty" })
  85 + end
  86 +
  87 + def test_observe_field_using_with_option
  88 + expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:'id=' + encodeURIComponent(value)})})\n//]]>\n</script>)
  89 + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => 'id')
  90 + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "'id=' + encodeURIComponent(value)")
  91 + end
  92 +
  93 + def test_observe_field_using_json_in_with_option
  94 + expected = %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {new Ajax.Request('http://www.example.com/check_value', {asynchronous:true, evalScripts:true, parameters:{'id':value}})})\n//]]>\n</script>)
  95 + assert_dom_equal expected, observe_field("glass", :frequency => 5.minutes, :url => { :action => "check_value" }, :with => "{'id':value}")
  96 + end
  97 +
  98 + def test_observe_field_using_function_for_callback
  99 + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.Observer('glass', 300, function(element, value) {alert('Element changed')})\n//]]>\n</script>),
  100 + observe_field("glass", :frequency => 5.minutes, :function => "alert('Element changed')")
  101 + end
  102 +
  103 + def test_observe_field_without_frequency
  104 + assert_dom_equal %(<script type=\"text/javascript\">\n//<![CDATA[\nnew Form.Element.EventObserver('glass', function(element, value) {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:value})})\n//]]>\n</script>),
  105 + observe_field("glass")
  106 + end
  107 +
  108 +
  109 + def test_periodically_call_remote
  110 + assert_dom_equal %(<script type="text/javascript">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Updater('schremser_bier', 'http://www.example.com/mehr_bier', {asynchronous:true, evalScripts:true})}, 10)\n//]]>\n</script>),
  111 + periodically_call_remote(:update => "schremser_bier", :url => { :action => "mehr_bier" })
  112 + end
  113 +
  114 + def test_periodically_call_remote_with_frequency
  115 + assert_dom_equal(
  116 + "<script type=\"text/javascript\">\n//<![CDATA[\nnew PeriodicalExecuter(function() {new Ajax.Request('http://www.example.com/', {asynchronous:true, evalScripts:true})}, 2)\n//]]>\n</script>",
  117 + periodically_call_remote(:frequency => 2)
  118 + )
  119 + end
  120 +
  121 +
  122 + def test_form_remote_tag
  123 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
  124 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast })
  125 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
  126 + form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast })
  127 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
  128 + form_remote_tag(:update => { :failure => "glass_of_water" }, :url => { :action => :fast })
  129 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">),
  130 + form_remote_tag(:update => { :success => 'glass_of_beer', :failure => "glass_of_water" }, :url => { :action => :fast })
  131 + end
  132 +
  133 + def test_form_remote_tag_with_method
  134 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\"><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div>),
  135 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :html => { :method => :put })
  136 + end
  137 +
  138 + def test_form_remote_tag_with_block_in_erb
  139 + __in_erb_template = ''
  140 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }) { concat "Hello world!" }
  141 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;\">Hello world!</form>), output_buffer
  142 + end
  143 +
  144 + def test_on_callbacks
  145 + callbacks = [:uninitialized, :loading, :loaded, :interactive, :complete, :success, :failure]
  146 + callbacks.each do |callback|
  147 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
  148 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
  149 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
  150 + form_remote_tag(:update => { :success => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
  151 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({failure:'glass_of_beer'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
  152 + form_remote_tag(:update => { :failure => "glass_of_beer" }, :url => { :action => :fast }, callback=>"monkeys();")
  153 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater({success:'glass_of_beer',failure:'glass_of_water'}, 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
  154 + form_remote_tag(:update => { :success => "glass_of_beer", :failure => "glass_of_water" }, :url => { :action => :fast }, callback=>"monkeys();")
  155 + end
  156 +
  157 + #HTTP status codes 200 up to 599 have callbacks
  158 + #these should work
  159 + 100.upto(599) do |callback|
  160 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on#{callback.to_s.capitalize}:function(request){monkeys();}, parameters:Form.serialize(this)}); return false;">),
  161 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
  162 + end
  163 +
  164 + #test 200 and 404
  165 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, parameters:Form.serialize(this)}); return false;">),
  166 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, 200=>"monkeys();", 404=>"bananas();")
  167 +
  168 + #these shouldn't
  169 + 1.upto(99) do |callback|
  170 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
  171 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
  172 + end
  173 + 600.upto(999) do |callback|
  174 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;">),
  175 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, callback=>"monkeys();")
  176 + end
  177 +
  178 + #test ultimate combo
  179 + assert_dom_equal %(<form action=\"http://www.example.com/fast\" method=\"post\" onsubmit=\"new Ajax.Updater('glass_of_beer', 'http://www.example.com/fast', {asynchronous:true, evalScripts:true, on200:function(request){monkeys();}, on404:function(request){bananas();}, onComplete:function(request){c();}, onFailure:function(request){f();}, onLoading:function(request){c1()}, onSuccess:function(request){s()}, parameters:Form.serialize(this)}); return false;\">),
  180 + form_remote_tag(:update => "glass_of_beer", :url => { :action => :fast }, :loading => "c1()", :success => "s()", :failure => "f();", :complete => "c();", 200=>"monkeys();", 404=>"bananas();")
  181 + end
  182 +
  183 + def test_remote_form_for_with_record_identification_with_new_record
  184 + remote_form_for(@record, {:html => { :id => 'create-author' }}) {}
  185 +
  186 + expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' id='create-author' method='post'></form>)
  187 + assert_dom_equal expected, output_buffer
  188 + end
  189 +
  190 + def test_remote_form_for_with_record_identification_without_html_options
  191 + remote_form_for(@record) {}
  192 +
  193 + expected = %(<form action='#{authors_path}' onsubmit="new Ajax.Request('#{authors_path}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_author' method='post' id='new_author'></form>)
  194 + assert_dom_equal expected, output_buffer
  195 + end
  196 +
  197 + def test_remote_form_for_with_record_identification_with_existing_record
  198 + @record.save
  199 + remote_form_for(@record) {}
  200 +
  201 + expected = %(<form action='#{author_path(@record)}' id='edit_author_1' method='post' onsubmit="new Ajax.Request('#{author_path(@record)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_author'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
  202 + assert_dom_equal expected, output_buffer
  203 + end
  204 +
  205 + def test_remote_form_for_with_new_object_in_list
  206 + remote_form_for([@author, @article]) {}
  207 +
  208 + expected = %(<form action='#{author_articles_path(@author)}' onsubmit="new Ajax.Request('#{author_articles_path(@author)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='new_article' method='post' id='new_article'></form>)
  209 + assert_dom_equal expected, output_buffer
  210 + end
  211 +
  212 + def test_remote_form_for_with_existing_object_in_list
  213 + @author.save
  214 + @article.save
  215 + remote_form_for([@author, @article]) {}
  216 +
  217 + expected = %(<form action='#{author_article_path(@author, @article)}' id='edit_article_1' method='post' onsubmit="new Ajax.Request('#{author_article_path(@author, @article)}', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this)}); return false;" class='edit_article'><div style='margin:0;padding:0;display:inline'><input name='_method' type='hidden' value='put' /></div></form>)
  218 + assert_dom_equal expected, output_buffer
  219 + end
  220 +
  221 +
  222 + def test_button_to_remote
  223 + assert_dom_equal %(<input class=\"fine\" type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true});\" />),
  224 + button_to_remote("Remote outpost", { :url => { :action => "whatnot" }}, { :class => "fine" })
  225 + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.reponseText)}});\" />),
  226 + button_to_remote("Remote outpost", :complete => "alert(request.reponseText)", :url => { :action => "whatnot" })
  227 + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.reponseText)}});\" />),
  228 + button_to_remote("Remote outpost", :success => "alert(request.reponseText)", :url => { :action => "whatnot" })
  229 + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />),
  230 + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot" })
  231 + assert_dom_equal %(<input type=\"button\" value=\"Remote outpost\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.reponseText)}});\" />),
  232 + button_to_remote("Remote outpost", :failure => "alert(request.reponseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
  233 + end
  234 +
  235 + def test_submit_to_remote
  236 + assert_dom_equal %(<input name=\"More beer!\" onclick=\"new Ajax.Updater('empty_bottle', 'http://www.example.com/', {asynchronous:true, evalScripts:true, parameters:Form.serialize(this.form)});\" type=\"button\" value=\"1000000\" />),
  237 + submit_to_remote("More beer!", 1_000_000, :update => "empty_bottle")
  238 + end
  239 +
  240 +
  241 + def test_link_to_remote
  242 + assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
  243 + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }}, { :class => "fine" })
  244 + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onComplete:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
  245 + link_to_remote("Remote outauthor", :complete => "alert(request.responseText)", :url => { :action => "whatnot" })
  246 + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onSuccess:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
  247 + link_to_remote("Remote outauthor", :success => "alert(request.responseText)", :url => { :action => "whatnot" })
  248 + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
  249 + link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot" })
  250 + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot?a=10&amp;b=20', {asynchronous:true, evalScripts:true, onFailure:function(request){alert(request.responseText)}}); return false;\">Remote outauthor</a>),
  251 + link_to_remote("Remote outauthor", :failure => "alert(request.responseText)", :url => { :action => "whatnot", :a => '10', :b => '20' })
  252 + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:false, evalScripts:true}); return false;\">Remote outauthor</a>),
  253 + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :type => :synchronous)
  254 + assert_dom_equal %(<a href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true, insertion:'bottom'}); return false;\">Remote outauthor</a>),
  255 + link_to_remote("Remote outauthor", :url => { :action => "whatnot" }, :position => :bottom)
  256 + end
  257 +
  258 + def test_link_to_remote_html_options
  259 + assert_dom_equal %(<a class=\"fine\" href=\"#\" onclick=\"new Ajax.Request('http://www.example.com/whatnot', {asynchronous:true, evalScripts:true}); return false;\">Remote outauthor</a>),
  260 + link_to_remote("Remote outauthor", { :url => { :action => "whatnot" }, :html => { :class => "fine" } })
  261 + end
  262 +
  263 + def test_link_to_remote_url_quote_escaping
  264 + assert_dom_equal %(<a href="#" onclick="new Ajax.Request('http://www.example.com/whatnot\\\'s', {asynchronous:true, evalScripts:true}); return false;">Remote</a>),
  265 + link_to_remote("Remote", { :url => { :action => "whatnot's" } })
  266 + end
  267 +
  268 + protected
  269 + def request_forgery_protection_token
  270 + nil
  271 + end
  272 +
  273 + def protect_against_forgery?
  274 + false
  275 + end
  276 +
  277 + def create_generator
  278 + block = Proc.new { |*args| yield *args if block_given? }
  279 + JavaScriptGenerator.new self, &block
  280 + end
  281 +
  282 + def author_path(record)
  283 + "/authors/#{record.id}"
  284 + end
  285 +
  286 + def authors_path
  287 + "/authors"
  288 + end
  289 +
  290 + def author_articles_path(author)
  291 + "/authors/#{author.id}/articles"
  292 + end
  293 +
  294 + def author_article_path(author, article)
  295 + "/authors/#{author.id}/articles/#{article.id}"
  296 + end
  297 +end
... ...