hobo 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE.txt +22 -0
- data/README.txt +18 -0
- data/bin/hobo +81 -0
- data/hobo_files/plugin/CHANGES.txt +963 -0
- data/hobo_files/plugin/LICENSE.txt +22 -0
- data/hobo_files/plugin/README +4 -0
- data/hobo_files/plugin/Rakefile +11 -0
- data/hobo_files/plugin/generators/hobo/hobo_generator.rb +37 -0
- data/hobo_files/plugin/generators/hobo/templates/application.dryml +2 -0
- data/hobo_files/plugin/generators/hobo/templates/guest.rb +31 -0
- data/hobo_files/plugin/generators/hobo_front_controller/USAGE +11 -0
- data/hobo_files/plugin/generators/hobo_front_controller/hobo_front_controller_generator.rb +90 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/controller.rb +51 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/functional_test.rb +18 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +43 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/login.dryml +44 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +18 -0
- data/hobo_files/plugin/generators/hobo_front_controller/templates/signup.dryml +45 -0
- data/hobo_files/plugin/generators/hobo_model/USAGE +26 -0
- data/hobo_files/plugin/generators/hobo_model/hobo_model_generator.rb +38 -0
- data/hobo_files/plugin/generators/hobo_model/templates/fixtures.yml +11 -0
- data/hobo_files/plugin/generators/hobo_model/templates/migration.rb +13 -0
- data/hobo_files/plugin/generators/hobo_model/templates/model.rb +24 -0
- data/hobo_files/plugin/generators/hobo_model/templates/unit_test.rb +10 -0
- data/hobo_files/plugin/generators/hobo_model_controller/USAGE +30 -0
- data/hobo_files/plugin/generators/hobo_model_controller/hobo_model_controller_generator.rb +43 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +5 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/functional_test.rb +18 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/helper.rb +2 -0
- data/hobo_files/plugin/generators/hobo_model_controller/templates/view.rhtml +2 -0
- data/hobo_files/plugin/generators/hobo_rapid/hobo_rapid_generator.rb +51 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +436 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/default_mapping.rb +11 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/banner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_bodytop.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_01.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_02.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_03.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_corner_04.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_bottom.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_left.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_right.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/bkg_shadow_top.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_blue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_dblue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_green.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_purple.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/header_red.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/logo.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/spinner.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_dblue.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_green.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_purple.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/txt_list_img_red.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_01.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_02.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_03.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_corner_04.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_bottom.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_left.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_right.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/images/window_shadow_top.gif +0 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +390 -0
- data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +104 -0
- data/hobo_files/plugin/generators/hobo_user_model/USAGE +26 -0
- data/hobo_files/plugin/generators/hobo_user_model/hobo_user_model_generator.rb +38 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/fixtures.yml +11 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/migration.rb +15 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +58 -0
- data/hobo_files/plugin/generators/hobo_user_model/templates/unit_test.rb +10 -0
- data/hobo_files/plugin/init.rb +44 -0
- data/hobo_files/plugin/lib/action_view_extensions/base.rb +14 -0
- data/hobo_files/plugin/lib/active_record/has_many_association.rb +54 -0
- data/hobo_files/plugin/lib/active_record/has_many_through_association.rb +22 -0
- data/hobo_files/plugin/lib/active_record/table_definition.rb +34 -0
- data/hobo_files/plugin/lib/extensions.rb +245 -0
- data/hobo_files/plugin/lib/extensions/test_case.rb +130 -0
- data/hobo_files/plugin/lib/hobo.rb +353 -0
- data/hobo_files/plugin/lib/hobo/HtmlString +3 -0
- data/hobo_files/plugin/lib/hobo/authenticated_user.rb +106 -0
- data/hobo_files/plugin/lib/hobo/authentication_support.rb +108 -0
- data/hobo_files/plugin/lib/hobo/composite_model.rb +66 -0
- data/hobo_files/plugin/lib/hobo/controller.rb +134 -0
- data/hobo_files/plugin/lib/hobo/controller_helpers.rb +135 -0
- data/hobo_files/plugin/lib/hobo/core.rb +475 -0
- data/hobo_files/plugin/lib/hobo/define_tags.rb +56 -0
- data/hobo_files/plugin/lib/hobo/dryml.rb +161 -0
- data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +126 -0
- data/hobo_files/plugin/lib/hobo/dryml/tag_module.rb +9 -0
- data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +57 -0
- data/hobo_files/plugin/lib/hobo/dryml/template.rb +586 -0
- data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +302 -0
- data/hobo_files/plugin/lib/hobo/dryml/template_handler.rb +19 -0
- data/hobo_files/plugin/lib/hobo/generator.rb +25 -0
- data/hobo_files/plugin/lib/hobo/html_string.rb +3 -0
- data/hobo_files/plugin/lib/hobo/lazy_hash.rb +28 -0
- data/hobo_files/plugin/lib/hobo/mapping_tags.rb +262 -0
- data/hobo_files/plugin/lib/hobo/markdown_string.rb +7 -0
- data/hobo_files/plugin/lib/hobo/model.rb +391 -0
- data/hobo_files/plugin/lib/hobo/model_controller.rb +676 -0
- data/hobo_files/plugin/lib/hobo/model_queries.rb +92 -0
- data/hobo_files/plugin/lib/hobo/model_support.rb +44 -0
- data/hobo_files/plugin/lib/hobo/password_string.rb +3 -0
- data/hobo_files/plugin/lib/hobo/predicate_dispatch.rb +78 -0
- data/hobo_files/plugin/lib/hobo/proc_binding.rb +32 -0
- data/hobo_files/plugin/lib/hobo/rapid.rb +447 -0
- data/hobo_files/plugin/lib/hobo/static_tags +92 -0
- data/hobo_files/plugin/lib/hobo/text.rb +3 -0
- data/hobo_files/plugin/lib/hobo/textile_string.rb +13 -0
- data/hobo_files/plugin/lib/hobo/undefined.rb +41 -0
- data/hobo_files/plugin/lib/hobo/undefined_access_error.rb +5 -0
- data/hobo_files/plugin/lib/hobo/where_fragment.rb +23 -0
- data/hobo_files/plugin/lib/rexml.rb +345 -0
- data/hobo_files/plugin/tags/core.dryml +6 -0
- data/hobo_files/plugin/tags/rapid.dryml +177 -0
- data/hobo_files/plugin/tags/rapid_editing.dryml +168 -0
- data/hobo_files/plugin/tags/rapid_navigation.dryml +95 -0
- data/hobo_files/plugin/tags/rapid_pages.dryml +175 -0
- data/hobo_files/plugin/tasks/environments.rake +19 -0
- data/hobo_files/plugin/tasks/hobo_tasks.rake +4 -0
- data/hobo_files/plugin/test/hobo_dryml_template_test.rb +7 -0
- data/hobo_files/plugin/test/hobo_test.rb +7 -0
- data/hobo_files/plugin/uninstall.rb +1 -0
- metadata +206 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
The model generator creates stubs for a new model.
|
|
3
|
+
|
|
4
|
+
The generator takes a model name as its argument. The model name may be given in CamelCase or under_score and
|
|
5
|
+
should not be suffixed with 'Model'.
|
|
6
|
+
|
|
7
|
+
As additional parameters, the generator will take attribute pairs described by name and type. These attributes will
|
|
8
|
+
be used to prepopulate the migration to create the table for the model and give you a set of predefined fixture.
|
|
9
|
+
You don't have to think up all attributes up front, but it's a good idea of adding just the baseline of what's
|
|
10
|
+
needed to start really working with the resource.
|
|
11
|
+
|
|
12
|
+
The generator creates a model class in app/models, a test suite in test/unit, test fixtures in
|
|
13
|
+
test/fixtures/singular_name.yml, and a migration in db/migrate.
|
|
14
|
+
|
|
15
|
+
Examples:
|
|
16
|
+
./script/generate model account
|
|
17
|
+
|
|
18
|
+
This will create an Account model:
|
|
19
|
+
Model: app/models/account.rb
|
|
20
|
+
Test: test/unit/account_test.rb
|
|
21
|
+
Fixtures: test/fixtures/accounts.yml
|
|
22
|
+
Migration: db/migrate/XXX_add_accounts.rb
|
|
23
|
+
|
|
24
|
+
./script/generate model post title:string created_on:date body:text published:boolean
|
|
25
|
+
|
|
26
|
+
Creates post model with predefined attributes.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
class HoboModelGenerator < Rails::Generator::NamedBase
|
|
2
|
+
default_options :skip_migration => false
|
|
3
|
+
|
|
4
|
+
def manifest
|
|
5
|
+
record do |m|
|
|
6
|
+
# Check for class naming collisions.
|
|
7
|
+
m.class_collisions class_path, class_name, "#{class_name}Test"
|
|
8
|
+
|
|
9
|
+
# Model, test, and fixture directories.
|
|
10
|
+
m.directory File.join('app/models', class_path)
|
|
11
|
+
m.directory File.join('test/unit', class_path)
|
|
12
|
+
m.directory File.join('test/fixtures', class_path)
|
|
13
|
+
|
|
14
|
+
# Model class, unit test, and fixtures.
|
|
15
|
+
m.template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb")
|
|
16
|
+
m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb")
|
|
17
|
+
m.template 'fixtures.yml', File.join('test/fixtures', class_path, "#{table_name}.yml")
|
|
18
|
+
|
|
19
|
+
unless options[:skip_migration]
|
|
20
|
+
m.migration_template 'migration.rb', 'db/migrate', :assigns => {
|
|
21
|
+
:migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}"
|
|
22
|
+
}, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}"
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
protected
|
|
28
|
+
def banner
|
|
29
|
+
"Usage: #{$0} generate ModelName [field:type, field:type]"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def add_options!(opt)
|
|
33
|
+
opt.separator ''
|
|
34
|
+
opt.separator 'Options:'
|
|
35
|
+
opt.on("--skip-migration",
|
|
36
|
+
"Don't generate a migration file for this model") { |v| options[:skip_migration] = v }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
|
|
2
|
+
one:
|
|
3
|
+
id: 1
|
|
4
|
+
<% for attribute in attributes -%>
|
|
5
|
+
<%= attribute.name %>: <%= attribute.default %>
|
|
6
|
+
<% end -%>
|
|
7
|
+
two:
|
|
8
|
+
id: 2
|
|
9
|
+
<% for attribute in attributes -%>
|
|
10
|
+
<%= attribute.name %>: <%= attribute.default %>
|
|
11
|
+
<% end -%>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class <%= migration_name %> < ActiveRecord::Migration
|
|
2
|
+
def self.up
|
|
3
|
+
create_table :<%= table_name %> do |t|
|
|
4
|
+
<% for attribute in attributes -%>
|
|
5
|
+
t.column :<%= attribute.name %>, :<%= attribute.type %>
|
|
6
|
+
<% end -%>
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def self.down
|
|
11
|
+
drop_table :<%= table_name %>
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
class <%= class_name %> < ActiveRecord::Base
|
|
2
|
+
|
|
3
|
+
hobo_model
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
# --- Hobo Permissions --- #
|
|
7
|
+
|
|
8
|
+
def creatable_by?(creator)
|
|
9
|
+
false
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def updatable_by?(updater, new)
|
|
13
|
+
false
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def deletable_by?(deleter)
|
|
17
|
+
false
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def viewable_by?(viewer, field)
|
|
21
|
+
true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
The controller generator creates stubs for a new controller and its views.
|
|
3
|
+
|
|
4
|
+
The generator takes a controller name and a list of views as arguments.
|
|
5
|
+
The controller name may be given in CamelCase or under_score and should
|
|
6
|
+
not be suffixed with 'Controller'. To create a controller within a
|
|
7
|
+
module, specify the controller name as 'module/controller'.
|
|
8
|
+
|
|
9
|
+
The generator creates a controller class in app/controllers with view
|
|
10
|
+
templates in app/views/controller_name, a helper class in app/helpers,
|
|
11
|
+
and a functional test suite in test/functional.
|
|
12
|
+
|
|
13
|
+
Example:
|
|
14
|
+
./script/generate controller CreditCard open debit credit close
|
|
15
|
+
|
|
16
|
+
Credit card controller with URLs like /credit_card/debit.
|
|
17
|
+
Controller: app/controllers/credit_card_controller.rb
|
|
18
|
+
Views: app/views/credit_card/debit.rhtml [...]
|
|
19
|
+
Helper: app/helpers/credit_card_helper.rb
|
|
20
|
+
Test: test/functional/credit_card_controller_test.rb
|
|
21
|
+
|
|
22
|
+
Modules Example:
|
|
23
|
+
./script/generate controller 'admin/credit_card' suspend late_fee
|
|
24
|
+
|
|
25
|
+
Credit card admin controller with URLs /admin/credit_card/suspend.
|
|
26
|
+
Controller: app/controllers/admin/credit_card_controller.rb
|
|
27
|
+
Views: app/views/admin/credit_card/debit.rhtml [...]
|
|
28
|
+
Helper: app/helpers/admin/credit_card_helper.rb
|
|
29
|
+
Test: test/functional/admin/credit_card_controller_test.rb
|
|
30
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
class HoboModelControllerGenerator < Rails::Generator::NamedBase
|
|
2
|
+
|
|
3
|
+
def initialize(args, options)
|
|
4
|
+
args[0] = args[0].pluralize
|
|
5
|
+
super(args, options)
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def manifest
|
|
9
|
+
record do |m|
|
|
10
|
+
# Check for class naming collisions.
|
|
11
|
+
m.class_collisions class_path, "#{class_name}Controller", "#{class_name}ControllerTest", "#{class_name}Helper"
|
|
12
|
+
|
|
13
|
+
# Controller, helper, views, and test directories.
|
|
14
|
+
m.directory File.join('app/controllers', class_path)
|
|
15
|
+
m.directory File.join('app/helpers', class_path)
|
|
16
|
+
m.directory File.join('app/views', class_path, file_name)
|
|
17
|
+
m.directory File.join('test/functional', class_path)
|
|
18
|
+
|
|
19
|
+
# Controller class, functional test, and helper class.
|
|
20
|
+
m.template 'controller.rb',
|
|
21
|
+
File.join('app/controllers',
|
|
22
|
+
class_path,
|
|
23
|
+
"#{file_name}_controller.rb")
|
|
24
|
+
|
|
25
|
+
m.template 'functional_test.rb',
|
|
26
|
+
File.join('test/functional',
|
|
27
|
+
class_path,
|
|
28
|
+
"#{file_name}_controller_test.rb")
|
|
29
|
+
|
|
30
|
+
m.template 'helper.rb',
|
|
31
|
+
File.join('app/helpers',
|
|
32
|
+
class_path,
|
|
33
|
+
"#{file_name}_helper.rb")
|
|
34
|
+
|
|
35
|
+
# View template for each action.
|
|
36
|
+
actions.each do |action|
|
|
37
|
+
path = File.join('app/views', class_path, file_name, "#{action}.rhtml")
|
|
38
|
+
m.template 'view.rhtml', path,
|
|
39
|
+
:assigns => { :action => action, :path => path }
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require File.dirname(__FILE__) + '<%= '/..' * class_nesting_depth %>/../test_helper'
|
|
2
|
+
require '<%= file_path %>_controller'
|
|
3
|
+
|
|
4
|
+
# Re-raise errors caught by the controller.
|
|
5
|
+
class <%= class_name %>Controller; def rescue_action(e) raise e end; end
|
|
6
|
+
|
|
7
|
+
class <%= class_name %>ControllerTest < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@controller = <%= class_name %>Controller.new
|
|
10
|
+
@request = ActionController::TestRequest.new
|
|
11
|
+
@response = ActionController::TestResponse.new
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Replace this with your real tests.
|
|
15
|
+
def test_truth
|
|
16
|
+
assert true
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
require 'find'
|
|
2
|
+
|
|
3
|
+
class HoboRapidGenerator < Hobo::Generator
|
|
4
|
+
|
|
5
|
+
default_options :import_tags => false
|
|
6
|
+
|
|
7
|
+
def manifest
|
|
8
|
+
if options[:command] == :create
|
|
9
|
+
import_tags if options[:import_tags]
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
record do |m|
|
|
13
|
+
m.file "hobo_rapid.js", "public/javascripts/hobo_rapid.js"
|
|
14
|
+
m.file "themes/default/default_mapping.rb", "app/views/hobolib/default_mapping.rb"
|
|
15
|
+
create_all(m, "themes/default/public", "public/hobothemes/default")
|
|
16
|
+
create_all(m, "themes/default/views", "app/views/hobolib/themes/default")
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def import_tags
|
|
21
|
+
path = File.join(RAILS_ROOT, "app/views/hobolib/application.dryml")
|
|
22
|
+
|
|
23
|
+
tag = "<taglib src=\"plugins/hobo/tags/rapid\"/>\n\n<set_theme name=\"default\"/>\n"
|
|
24
|
+
|
|
25
|
+
src = File.read(path)
|
|
26
|
+
return if src.include?(tag)
|
|
27
|
+
|
|
28
|
+
# first try putting it before the first tag
|
|
29
|
+
done = src.sub!(/<(?!!)/, tag + "\n<")
|
|
30
|
+
|
|
31
|
+
# otherwise append it
|
|
32
|
+
src << tag unless done
|
|
33
|
+
|
|
34
|
+
File.open(path, 'w') {|f| f.write(src) }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
protected
|
|
39
|
+
def banner
|
|
40
|
+
"Usage: #{$0} generate [--import-tags]"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def add_options!(opt)
|
|
44
|
+
opt.separator ''
|
|
45
|
+
opt.separator 'Options:'
|
|
46
|
+
opt.on("--import-tags",
|
|
47
|
+
"Modify hobolib/application.dryml to import hobo-rapid and theme tags ") do |v|
|
|
48
|
+
options[:import_tags] = true
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
|
|
2
|
+
Object.extend = function(destination) {
|
|
3
|
+
$A(arguments).slice(1).each(function (src) {
|
|
4
|
+
for (var property in src) {
|
|
5
|
+
destination[property] = src[property];
|
|
6
|
+
}
|
|
7
|
+
})
|
|
8
|
+
return destination
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
Object.merge = function() {
|
|
12
|
+
return Object.extend.apply(this, [{}].concat($A(arguments)))
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
var Hobo = {
|
|
16
|
+
|
|
17
|
+
searchRequest: null,
|
|
18
|
+
uidCounter: 0,
|
|
19
|
+
ipeOldValues: {},
|
|
20
|
+
|
|
21
|
+
uid: function() {
|
|
22
|
+
Hobo.uidCounter += 1
|
|
23
|
+
return "uid" + Hobo.uidCounter
|
|
24
|
+
},
|
|
25
|
+
|
|
26
|
+
updatesForElement: function(el) {
|
|
27
|
+
el = $(el)
|
|
28
|
+
var updates = el.getAttribute("hobo_update")
|
|
29
|
+
return updates ? updates.split(/\s*,\s*/) : []
|
|
30
|
+
},
|
|
31
|
+
|
|
32
|
+
ajaxSetFieldForElement: function(el, val, options) {
|
|
33
|
+
var updates = Hobo.updatesForElement(el)
|
|
34
|
+
var params = Hobo.fieldSetParam(el, val)
|
|
35
|
+
var p = el.getAttribute("hobo_ajax_params")
|
|
36
|
+
if (p) params = params + "&" + p
|
|
37
|
+
|
|
38
|
+
var opts = Object.merge(options || {}, { params: params})
|
|
39
|
+
Hobo.ajaxRequest(Hobo.putUrl(el),
|
|
40
|
+
el.getAttribute("hobo_ajax_message") || "Changing...",
|
|
41
|
+
updates,
|
|
42
|
+
opts)
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
ajaxUpdateParams: function(updates, resultUpdates) {
|
|
46
|
+
var params = []
|
|
47
|
+
var i = 0
|
|
48
|
+
if (updates.length > 0) {
|
|
49
|
+
updates.each(function(dom_id) {
|
|
50
|
+
params.push("render["+i+"][part]=" + hoboParts[dom_id][0])
|
|
51
|
+
params.push("render["+i+"][id]=" + dom_id)
|
|
52
|
+
params.push("render["+i+"][object]=" + hoboParts[dom_id][1])
|
|
53
|
+
i += 1
|
|
54
|
+
})
|
|
55
|
+
params.push("part_page=" + hoboPartPage)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (resultUpdates) {
|
|
59
|
+
resultUpdates.each(function (resultUpdate) {
|
|
60
|
+
params.push("render["+i+"][id]=" + resultUpdate.id)
|
|
61
|
+
params.push("render["+i+"][result]=" + resultUpdate.result)
|
|
62
|
+
if (resultUpdate.func) {
|
|
63
|
+
params.push("render["+i+"][function]=" + resultUpdate.func)
|
|
64
|
+
}
|
|
65
|
+
i += 1
|
|
66
|
+
})
|
|
67
|
+
}
|
|
68
|
+
return params.join('&')
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
ajaxRequest: function(url_or_form, message, updates, options) {
|
|
72
|
+
options = Object.merge({ asynchronous:true,
|
|
73
|
+
evalScripts:true,
|
|
74
|
+
resetForm: true,
|
|
75
|
+
refocusForm: true
|
|
76
|
+
}, options)
|
|
77
|
+
if (typeof url_or_form == "string") {
|
|
78
|
+
var url = url_or_form
|
|
79
|
+
var form = false
|
|
80
|
+
} else {
|
|
81
|
+
var form = url_or_form
|
|
82
|
+
var url = form.action
|
|
83
|
+
}
|
|
84
|
+
var params = []
|
|
85
|
+
|
|
86
|
+
updateParams = Hobo.ajaxUpdateParams(updates, options.resultUpdate)
|
|
87
|
+
if (updateParams != "") { params.push(updateParams) }
|
|
88
|
+
|
|
89
|
+
if (options.params) {
|
|
90
|
+
params.push(options.params)
|
|
91
|
+
delete options.params
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (form) {
|
|
95
|
+
params.push(Form.serialize(form))
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
Hobo.showSpinner(message)
|
|
99
|
+
var complete = function() {
|
|
100
|
+
if (form && options.resetForm) form.reset();
|
|
101
|
+
Hobo.hideSpinner();
|
|
102
|
+
|
|
103
|
+
if (options.onComplete)
|
|
104
|
+
options.onComplete.apply(this, arguments)
|
|
105
|
+
if (form && options) Form.focusFirstElement(form)
|
|
106
|
+
}
|
|
107
|
+
if (options.method && options.method.toLowerCase() == "put") {
|
|
108
|
+
delete options.method
|
|
109
|
+
params.push("_method=PUT")
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
if (!options.onFailure) {
|
|
113
|
+
options.onFailure = function(response) {
|
|
114
|
+
alert(response.responseText)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
new Ajax.Request(url, Object.merge(options, { parameters: params.join("&"), onComplete: complete }))
|
|
119
|
+
},
|
|
120
|
+
|
|
121
|
+
hide: function() {
|
|
122
|
+
for (i = 0; i < arguments.length; i++) {
|
|
123
|
+
if ($(arguments[i])) {
|
|
124
|
+
Element.addClassName(arguments[i], 'hidden')
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
show: function() {
|
|
130
|
+
for (i = 0; i < arguments.length; i++) {
|
|
131
|
+
if ($(arguments[i])) {
|
|
132
|
+
Element.removeClassName(arguments[i], 'hidden')
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
toggle: function() {
|
|
138
|
+
for (i = 0; i < arguments.length; i++) {
|
|
139
|
+
if ($(arguments[i])) {
|
|
140
|
+
if(Element.hasClassName(arguments[i], 'hidden')) {
|
|
141
|
+
Element.removeClassName(arguments[i], 'hidden')
|
|
142
|
+
} else {
|
|
143
|
+
Element.addClassName(arguments[i], 'hidden')
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
onFieldEditComplete: function(el, newValue) {
|
|
150
|
+
el = $(el)
|
|
151
|
+
var oldValue = Hobo.ipeOldValues[el.id]
|
|
152
|
+
delete Hobo.ipeOldValues[el.id]
|
|
153
|
+
|
|
154
|
+
var blank = el.getAttribute("hobo_blank_message")
|
|
155
|
+
if (blank && newValue.strip().length == 0) {
|
|
156
|
+
el.update(blank)
|
|
157
|
+
} else {
|
|
158
|
+
el.update(newValue)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
var modelId = el.getAttribute('hobo_model_id')
|
|
162
|
+
if (oldValue) {
|
|
163
|
+
$$("*[hobo_model_id=" + modelId + "]").each(function(e) {
|
|
164
|
+
if (e != el && e.innerHTML == oldValue) e.update(newValue)
|
|
165
|
+
})
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
|
|
169
|
+
_makeInPlaceEditor: function(el, options) {
|
|
170
|
+
var old
|
|
171
|
+
var spec = Hobo.parseFieldId(el)
|
|
172
|
+
var updates = Hobo.updatesForElement(el)
|
|
173
|
+
var id = el.id
|
|
174
|
+
if (!id) { id = el.id = Hobo.uid() }
|
|
175
|
+
var updateParams = Hobo.ajaxUpdateParams(updates, [{id: id,
|
|
176
|
+
result: 'new_field_value',
|
|
177
|
+
func: "Hobo.onFieldEditComplete"}])
|
|
178
|
+
opts = {okButton: false,
|
|
179
|
+
cancelLink: false,
|
|
180
|
+
submitOnBlur: true,
|
|
181
|
+
callback: function(form, val) {
|
|
182
|
+
old = val
|
|
183
|
+
return (Hobo.fieldSetParam(el, val) + "&" + updateParams)
|
|
184
|
+
},
|
|
185
|
+
highlightcolor: '#ffffff',
|
|
186
|
+
highlightendcolor: Hobo.backgroundColor(el),
|
|
187
|
+
onFailure: function(resp) { alert(resp.responseText); el.innerHTML = old },
|
|
188
|
+
evalScripts: true
|
|
189
|
+
}
|
|
190
|
+
Object.extend(opts, options)
|
|
191
|
+
var ipe = new Ajax.InPlaceEditor(el, Hobo.putUrl(el), opts)
|
|
192
|
+
ipe.onEnterEditMode = function() {
|
|
193
|
+
var blank_message = el.getAttribute("hobo_blank_message")
|
|
194
|
+
if (el.innerHTML.gsub(" ", " ") == blank_message) {
|
|
195
|
+
el.innerHTML = ""
|
|
196
|
+
} else {
|
|
197
|
+
Hobo.ipeOldValues[el.id] = el.innerHTML
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
return ipe
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
applyEvents: function(root) {
|
|
204
|
+
root = $(root)
|
|
205
|
+
function select(p) {
|
|
206
|
+
return new Selector(p).findElements(root)
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
select(".in_place_textfield_bhv").each(function (el) {
|
|
210
|
+
ipe = Hobo._makeInPlaceEditor(el)
|
|
211
|
+
ipe.getText = function() {
|
|
212
|
+
return this.element.innerHTML.gsub(/<br\s*\/?>/, "\n").unescapeHTML()
|
|
213
|
+
}
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
select(".in_place_textarea_bhv").each(function (el) {
|
|
217
|
+
ipe = Hobo._makeInPlaceEditor(el, {rows: 2})
|
|
218
|
+
ipe.getText = function() {
|
|
219
|
+
return this.element.innerHTML.gsub(/<br\s*\/?>/, "\n").unescapeHTML()
|
|
220
|
+
}
|
|
221
|
+
})
|
|
222
|
+
|
|
223
|
+
select(".in_place_html_textarea_bhv").each(function (el) {
|
|
224
|
+
var ipe = Hobo._makeInPlaceEditor(el, {rows: 2, handleLineBreaks: false})
|
|
225
|
+
if (typeof(tinyMCE) != "undefined") {
|
|
226
|
+
ipe.afterEnterEditMode = function() {
|
|
227
|
+
var id = this.form.id = Hobo.uid()
|
|
228
|
+
|
|
229
|
+
// 'orrible 'ack
|
|
230
|
+
// What is the correct way to individually configure a tinyMCE instace?
|
|
231
|
+
var old = tinyMCE.settings.theme_advanced_buttons1
|
|
232
|
+
tinyMCE.settings.theme_advanced_buttons1 += ", separator, save"
|
|
233
|
+
tinyMCE.addMCEControl(this.editField, id);
|
|
234
|
+
tinyMCE.settings.theme_advanced_buttons1 = old
|
|
235
|
+
|
|
236
|
+
this.form.onsubmit = function() {
|
|
237
|
+
tinyMCE.removeMCEControl(ipe.form.id)
|
|
238
|
+
setTimeout(ipe.onSubmit.bind(ipe), 10)
|
|
239
|
+
return false
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
select("select.number_editor_bhv").each(function(el) {
|
|
246
|
+
el.onchange = function() {
|
|
247
|
+
Hobo.ajaxSetFieldForElement(el, el.value)
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
select(".autocomplete_bhv").each(function (el) {
|
|
252
|
+
options = {paramName: "query", minChars: 3, method: 'get' }
|
|
253
|
+
if (el.hasClassName("autosubmit")) {
|
|
254
|
+
options.afterUpdateElement = function(el, item) { el.form.onsubmit(); }
|
|
255
|
+
}
|
|
256
|
+
new Ajax.Autocompleter(el, el.id + "_completions", el.getAttribute("autocomplete_url"),
|
|
257
|
+
options);
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
select(".search_bhv").each(function(el) {
|
|
261
|
+
new Form.Element.Observer(el, 1.0, function() { Hobo.doSearch(el) })
|
|
262
|
+
});
|
|
263
|
+
},
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
doSearch: function(el) {
|
|
267
|
+
el = $(el)
|
|
268
|
+
var spinner = $(el.getAttribute("search_spinner") || "search_spinner")
|
|
269
|
+
var search_results = $(el.getAttribute("search_results") || "search_results")
|
|
270
|
+
var search_results_panel = $(el.getAttribute("search_results_panel") || "search_results_panel")
|
|
271
|
+
var url = el.getAttribute("search_url") || (urlBase + "/search")
|
|
272
|
+
|
|
273
|
+
el.focus();
|
|
274
|
+
var value = $F(el)
|
|
275
|
+
if (Hobo.searchRequest) { Hobo.searchRequest.transport.abort() }
|
|
276
|
+
if (value.length >= 3) {
|
|
277
|
+
if (spinner) Hobo.show(spinner);
|
|
278
|
+
Hobo.searchRequest = new Ajax.Updater(search_results,
|
|
279
|
+
url,
|
|
280
|
+
{ asynchronous:true,
|
|
281
|
+
evalScripts:true,
|
|
282
|
+
onSuccess:function(request) {
|
|
283
|
+
if (spinner) Hobo.hide(spinner)
|
|
284
|
+
if (search_results_panel) {
|
|
285
|
+
Hobo.show(search_results_panel)
|
|
286
|
+
}
|
|
287
|
+
},
|
|
288
|
+
parameters:"query=" + value });
|
|
289
|
+
} else {
|
|
290
|
+
Hobo.updateElement(search_results, '')
|
|
291
|
+
Hobo.hide(search_results_panel)
|
|
292
|
+
}
|
|
293
|
+
},
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
putUrl: function(el) {
|
|
297
|
+
spec = Hobo.parseFieldId(el)
|
|
298
|
+
return urlBase + "/" + controllerNames[spec.name] + "/" + spec.id + "?_method=PUT"
|
|
299
|
+
},
|
|
300
|
+
|
|
301
|
+
|
|
302
|
+
fieldSetParam: function(el, val) {
|
|
303
|
+
spec = Hobo.parseFieldId(el)
|
|
304
|
+
return spec.name + '[' + spec.field + ']=' + escape(val)
|
|
305
|
+
},
|
|
306
|
+
|
|
307
|
+
fadeObjectElement: function(el) {
|
|
308
|
+
new Effect.Fade(Hobo.objectElementFor(el),
|
|
309
|
+
{ duration: 0.5,
|
|
310
|
+
afterFinish: function (ef) { ef.element.remove() } });
|
|
311
|
+
},
|
|
312
|
+
|
|
313
|
+
removeButton: function(el, url, updates, fade) {
|
|
314
|
+
if (fade == null) { fade = true; }
|
|
315
|
+
if (confirm("Are you sure?")) {
|
|
316
|
+
objEl = Hobo.objectElementFor(el)
|
|
317
|
+
Hobo.showSpinner('Removing');
|
|
318
|
+
function complete() {
|
|
319
|
+
if (fade) { Hobo.fadeObjectElement(el) }
|
|
320
|
+
Hobo.hideSpinner()
|
|
321
|
+
}
|
|
322
|
+
if (updates && updates.length > 0) {
|
|
323
|
+
new Hobo.ajaxRequest(url, "Removing", updates, { method:'delete',
|
|
324
|
+
onComplete: complete});
|
|
325
|
+
} else {
|
|
326
|
+
new Ajax.Request(url, {asynchronous:true, evalScripts:true, method:'delete',
|
|
327
|
+
onComplete: complete});
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
},
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
parseFieldId: function(el) {
|
|
334
|
+
id = el.getAttribute("hobo_model_id")
|
|
335
|
+
if (!id) return
|
|
336
|
+
m = id.match(/^([a-z_]+)_([0-9]+)_([a-z_]+)$/)
|
|
337
|
+
if (m) return { name: m[1], id: m[2], field: m[3] }
|
|
338
|
+
},
|
|
339
|
+
|
|
340
|
+
appendRow: function(el, rowSrc) {
|
|
341
|
+
// IE friendly method to add a <tr> (from html source) to a table
|
|
342
|
+
// el should be an element that contains *only* a table
|
|
343
|
+
el = $(el);
|
|
344
|
+
el.innerHTML = el.innerHTML.replace("</table>", "") + rowSrc + "</table>";
|
|
345
|
+
Hobo.applyEvents(el)
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
objectElementFor: function(el) {
|
|
349
|
+
var m
|
|
350
|
+
while(el.getAttribute) {
|
|
351
|
+
id = el.getAttribute("hobo_model_id");
|
|
352
|
+
if (id) m = id.match(/^([a-z_]+)_([0-9]+)(_[a-z0-9_]*)?$/);
|
|
353
|
+
if (m) break;
|
|
354
|
+
el = el.parentNode;
|
|
355
|
+
}
|
|
356
|
+
if (m) return el;
|
|
357
|
+
},
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
showSpinner: function(message) {
|
|
361
|
+
if(t = $('ajax_progress_text')) Element.update(t, message);
|
|
362
|
+
if(e = $('ajax_progress')) e.style.display = "block";
|
|
363
|
+
},
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
hideSpinner: function() {
|
|
367
|
+
if(e = $('ajax_progress')) e.style.display = "none";
|
|
368
|
+
},
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
updateElement: function(id, content) {
|
|
372
|
+
Element.update(id, content)
|
|
373
|
+
Hobo.applyEvents(id)
|
|
374
|
+
},
|
|
375
|
+
|
|
376
|
+
rgbColorToHex: function(color) {
|
|
377
|
+
parts = /^rgb\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3})\)/.exec(color)
|
|
378
|
+
function hexPart(s) {
|
|
379
|
+
var res = (s * 1).toString(16)
|
|
380
|
+
return res.length == 1 ? '0' + res : res
|
|
381
|
+
}
|
|
382
|
+
if (parts) {
|
|
383
|
+
return '#' + hexPart(parts[1]) + hexPart(parts[2]) + hexPart(parts[3])
|
|
384
|
+
} else {
|
|
385
|
+
return color
|
|
386
|
+
}
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
getStyle: function(el, styleProp) {
|
|
390
|
+
if (el.currentStyle)
|
|
391
|
+
var y = el.currentStyle[styleProp];
|
|
392
|
+
else if (window.getComputedStyle)
|
|
393
|
+
var y = document.defaultView.getComputedStyle(el, null).getPropertyValue(styleProp);
|
|
394
|
+
return y;
|
|
395
|
+
},
|
|
396
|
+
|
|
397
|
+
backgroundColor: function(el) {
|
|
398
|
+
return Hobo.rgbColorToHex(Hobo.getStyle(el, 'background-color'))
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
Element.findContaining = function(el, tag) {
|
|
404
|
+
el = $(el)
|
|
405
|
+
tag = tag.toLowerCase()
|
|
406
|
+
e = el.parentNode
|
|
407
|
+
while (el) {
|
|
408
|
+
if (el.nodeName.toLowerCase() == tag) {
|
|
409
|
+
return el;
|
|
410
|
+
}
|
|
411
|
+
e = el.parentNode
|
|
412
|
+
}
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Fix scriptaculous - don't remove <p> tags please!
|
|
417
|
+
Ajax.InPlaceEditor.prototype.convertHTMLLineBreaks = function(string) {
|
|
418
|
+
return string.replace(/<br>/gi, "\n").replace(/<br\/>/gi, "\n");
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
|
|
422
|
+
origEnterEditMode = Ajax.InPlaceEditor.prototype.enterEditMode
|
|
423
|
+
Ajax.InPlaceEditor.prototype.enterEditMode = function(evt) {
|
|
424
|
+
origEnterEditMode.bind(this)(evt)
|
|
425
|
+
if (this.afterEnterEditMode) this.afterEnterEditMode()
|
|
426
|
+
return false
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
// Silence errors from IE :-(
|
|
430
|
+
Field.scrollFreeActivate = function(field) {
|
|
431
|
+
setTimeout(function() {
|
|
432
|
+
try {
|
|
433
|
+
Field.activate(field);
|
|
434
|
+
} catch(e) {}
|
|
435
|
+
}, 1);
|
|
436
|
+
}
|