hobo 0.6.2 → 0.6.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.
Files changed (60) hide show
  1. data/bin/hobo +21 -22
  2. data/hobo_files/plugin/CHANGES.txt +429 -4
  3. data/hobo_files/plugin/Rakefile +2 -2
  4. data/hobo_files/plugin/generators/hobo_front_controller/templates/index.dryml +6 -5
  5. data/hobo_files/plugin/generators/hobo_front_controller/templates/search.dryml +2 -2
  6. data/hobo_files/plugin/generators/hobo_migration/hobo_migration_generator.rb +20 -15
  7. data/hobo_files/plugin/generators/hobo_model/templates/model.rb +1 -0
  8. data/hobo_files/plugin/generators/hobo_model_controller/templates/controller.rb +2 -0
  9. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_base.css +1 -2
  10. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.css +4 -3
  11. data/hobo_files/plugin/generators/hobo_rapid/templates/hobo_rapid.js +94 -12
  12. data/hobo_files/plugin/generators/hobo_rapid/templates/lowpro.js +5 -183
  13. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/public/stylesheets/application.css +1 -1
  14. data/hobo_files/plugin/generators/hobo_rapid/templates/themes/default/views/application.dryml +23 -1
  15. data/hobo_files/plugin/generators/hobo_user_controller/templates/controller.rb +2 -0
  16. data/hobo_files/plugin/generators/hobo_user_model/templates/model.rb +3 -1
  17. data/hobo_files/plugin/init.rb +18 -7
  18. data/hobo_files/plugin/lib/active_record/has_many_association.rb +2 -2
  19. data/hobo_files/plugin/lib/extensions.rb +56 -12
  20. data/hobo_files/plugin/lib/hobo.rb +25 -88
  21. data/hobo_files/plugin/lib/hobo/composite_model.rb +2 -0
  22. data/hobo_files/plugin/lib/hobo/controller.rb +40 -20
  23. data/hobo_files/plugin/lib/hobo/dryml.rb +122 -106
  24. data/hobo_files/plugin/lib/hobo/dryml/dryml_builder.rb +2 -1
  25. data/hobo_files/plugin/lib/hobo/dryml/part_context.rb +3 -2
  26. data/hobo_files/plugin/lib/hobo/dryml/taglib.rb +19 -3
  27. data/hobo_files/plugin/lib/hobo/dryml/template.rb +40 -25
  28. data/hobo_files/plugin/lib/hobo/dryml/template_environment.rb +41 -20
  29. data/hobo_files/plugin/lib/hobo/email_address.rb +4 -1
  30. data/hobo_files/plugin/lib/hobo/enum_string.rb +50 -0
  31. data/hobo_files/plugin/lib/hobo/field_declaration_dsl.rb +36 -0
  32. data/hobo_files/plugin/lib/hobo/field_spec.rb +4 -7
  33. data/hobo_files/plugin/lib/hobo/hobo_helper.rb +47 -44
  34. data/hobo_files/plugin/lib/hobo/html_string.rb +2 -0
  35. data/hobo_files/plugin/lib/hobo/markdown_string.rb +2 -0
  36. data/hobo_files/plugin/lib/hobo/model.rb +158 -89
  37. data/hobo_files/plugin/lib/hobo/model_controller.rb +422 -376
  38. data/hobo_files/plugin/lib/hobo/model_queries.rb +1 -1
  39. data/hobo_files/plugin/lib/hobo/model_router.rb +174 -0
  40. data/hobo_files/plugin/lib/hobo/password_string.rb +2 -0
  41. data/hobo_files/plugin/lib/hobo/percentage.rb +14 -0
  42. data/hobo_files/plugin/lib/hobo/plugins.rb +4 -4
  43. data/hobo_files/plugin/lib/hobo/rapid_helper.rb +10 -2
  44. data/hobo_files/plugin/lib/hobo/text.rb +3 -3
  45. data/hobo_files/plugin/lib/hobo/textile_string.rb +2 -0
  46. data/hobo_files/plugin/lib/hobo/undefined.rb +3 -2
  47. data/hobo_files/plugin/lib/hobo/{authenticated_user.rb → user.rb} +10 -3
  48. data/hobo_files/plugin/lib/hobo/user_controller.rb +27 -23
  49. data/hobo_files/plugin/tags/core.dryml +8 -2
  50. data/hobo_files/plugin/tags/rapid.dryml +52 -40
  51. data/hobo_files/plugin/tags/rapid_document_tags.dryml +15 -11
  52. data/hobo_files/plugin/tags/rapid_editing.dryml +41 -9
  53. data/hobo_files/plugin/tags/rapid_forms.dryml +136 -36
  54. data/hobo_files/plugin/tags/rapid_navigation.dryml +2 -2
  55. data/hobo_files/plugin/tags/rapid_pages.dryml +204 -221
  56. data/hobo_files/plugin/tags/rapid_plus.dryml +8 -6
  57. data/hobo_files/plugin/tags/rapid_support.dryml +2 -3
  58. metadata +44 -42
  59. data/hobo_files/plugin/lib/hobo/define_tags.rb +0 -56
  60. data/hobo_files/plugin/lib/hobo/http_parameters.rb +0 -225
@@ -54,7 +54,7 @@ module Hobo
54
54
 
55
55
  m, field = *name.to_s.match(/^(.*)_is$/)
56
56
  if m
57
- if (refl = model.reflections[field.to_sym]) and refl.macro == :belongs_to
57
+ if (refl = model.reflections[field.to_sym]) && refl.macro == :belongs_to
58
58
  field = refl.primary_key_name
59
59
  val = args[0] && args[0].id
60
60
  raise HoboError.new("don't use self in query blocks") if val == self
@@ -0,0 +1,174 @@
1
+ module Hobo
2
+
3
+ class ModelRouter
4
+
5
+ APP_ROOT = "#{RAILS_ROOT}/app"
6
+
7
+ class << self
8
+
9
+ def add_routes(map)
10
+ begin
11
+ ActiveRecord::Base.connection.reconnect! unless ActiveRecord::Base.connection.active?
12
+ rescue
13
+ # No database, no routes
14
+ return
15
+ end
16
+
17
+ require "#{APP_ROOT}/controllers/application" unless Object.const_defined? :ApplicationController
18
+ require "#{APP_ROOT}/assemble.rb" if File.exists? "#{APP_ROOT}/assemble.rb"
19
+
20
+ add_routes_for(map, nil)
21
+
22
+ # Any directory inside app/controllers defines a subsite
23
+ subsites = Dir["#{APP_ROOT}/controllers/*"].map { |f| File.basename(f) if File.directory?(f) }.compact
24
+ subsites.each { |subsite| add_routes_for(map, subsite) }
25
+ end
26
+
27
+
28
+ def add_routes_for(map, subsite)
29
+ module_name = subsite._?.camelize
30
+ Hobo.models.each do |model|
31
+ controller_name = "#{model.name.pluralize}Controller"
32
+ is_defined = if subsite
33
+ Object.const_defined?(module_name) && module_name.constantize.const_defined?(controller_name)
34
+ else
35
+ Object.const_defined?(controller_name)
36
+ end
37
+ controller_filename = File.join(*["#{APP_ROOT}/controllers", subsite, "#{controller_name.underscore}.rb"].compact)
38
+ if is_defined || File.exists?(controller_filename)
39
+ owner_module = subsite ? module_name.constantize : Object
40
+ controller = owner_module.const_get(controller_name)
41
+ ModelRouter.new(map, model, controller, subsite)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+
48
+ def initialize(map, model, controller, subsite)
49
+ @map = map
50
+ @model = model
51
+ @controller = controller
52
+ @subsite = subsite
53
+ add_routes
54
+ end
55
+
56
+
57
+ attr_reader :map, :model, :controller, :subsite
58
+
59
+
60
+ def plural
61
+ model.name.underscore.pluralize
62
+ end
63
+
64
+
65
+ def singular
66
+ model.name.underscore
67
+ end
68
+
69
+
70
+ def add_routes
71
+ # Simple support for composite models, we might later need a CompositeModelController
72
+ if model < Hobo::CompositeModel
73
+ map.connect "#{plural}/:id", :controller => plural, :action => 'show'
74
+
75
+ elsif controller < Hobo::ModelController
76
+ # index routes need to be first so the index names don't get
77
+ # taken as IDs
78
+ index_action_routes
79
+ resource_routes
80
+ collection_routes
81
+ web_method_routes
82
+ show_action_routes
83
+ user_routes if controller < Hobo::UserController
84
+ end
85
+ end
86
+
87
+
88
+ def resource_routes
89
+ # We re-implement resource routing - routes are not created for
90
+ # actions that the controller does not provide
91
+ named_route(plural, plural, :action => "index", :conditions => { :method => :get })
92
+
93
+ named_route("new_#{singular}", "#{plural}/new", :action => "new", :conditions => { :method => :get })
94
+ named_route("edit_#{singular}", "#{plural}/:id/edit", :action => "edit", :conditions => { :method => :get })
95
+ named_route(singular, "#{plural}/:id", :action => "show", :conditions => { :method => :get })
96
+
97
+ named_route("create_#{singular}", plural, :action => "create", :conditions => { :method => :post })
98
+ named_route("update_#{singular}", "#{plural}/:id", :action => "update", :conditions => { :method => :put })
99
+ named_route("destroy_#{singular}", "#{plural}/:id", :action => "destroy", :conditions => { :method => :delete })
100
+ end
101
+
102
+
103
+ def collection_routes
104
+ controller.collections.each do |collection|
105
+ new_method = Hobo.simple_has_many_association?(model.reflections[collection])
106
+ named_route("#{singular}_#{collection}",
107
+ "#{plural}/:id/#{collection}",
108
+ :action => "show_#{collection}",
109
+ :conditions => { :method => :get })
110
+
111
+ named_route("new_#{singular}_#{collection.to_s.singularize}",
112
+ "#{plural}/:id/#{collection}/new",
113
+ :action => "new_#{collection.to_s.singularize}",
114
+ :conditions => { :method => :get }) if new_method
115
+ end
116
+ end
117
+
118
+
119
+ def web_method_routes
120
+ controller.web_methods.each do |method|
121
+ named_route("#{plural.singularize}_#{method}", "#{plural}/:id/#{method}",
122
+ :action => method.to_s, :conditions => { :method => :post })
123
+ end
124
+ end
125
+
126
+
127
+ def index_action_routes
128
+ controller.index_actions.each do |view|
129
+ named_route("#{view}_#{plural}", "#{plural}/#{view}",
130
+ :action => view.to_s, :conditions => { :method => :get })
131
+ end
132
+ end
133
+
134
+
135
+ def show_action_routes
136
+ controller.show_actions.each do |view|
137
+ named_route("#{plural.singularize}_#{view}", "#{plural}/:id/#{view}",
138
+ :action => view.to_s, :conditions => { :method => :get })
139
+ end
140
+ end
141
+
142
+
143
+ def user_routes
144
+ prefix = plural == "users" ? "" : "#{singular}_"
145
+ named_route("#{singular}_login", "#{prefix}login", :action => 'login')
146
+ named_route("#{singular}_logout", "#{prefix}logout", :action => 'logout')
147
+ named_route("#{singular}_signup", "#{prefix}signup", :action => 'signup')
148
+ end
149
+
150
+
151
+ def named_route(name, route, options={})
152
+ if controller.public_instance_methods.include?(options[:action].to_s)
153
+ options.reverse_merge!(:controller => route_with_subsite(plural))
154
+ name = name_with_subsite(name)
155
+ route = route_with_subsite(route)
156
+ map.named_route(name, route, options)
157
+ format_route = options.delete(:format) != false
158
+ map.named_route("formatted_#{name}", "#{route}.:format", options) if format_route
159
+ end
160
+ end
161
+
162
+
163
+ def name_with_subsite(name)
164
+ subsite ? "#{subsite}_#{name}" : name
165
+ end
166
+
167
+
168
+ def route_with_subsite(route)
169
+ subsite ? "#{subsite}/#{route}" : route
170
+ end
171
+
172
+ end
173
+
174
+ end
@@ -3,3 +3,5 @@ class Hobo::PasswordString < String
3
3
  COLUMN_TYPE = :string
4
4
 
5
5
  end
6
+
7
+ Hobo.field_types[:password] = Hobo::PasswordString
@@ -0,0 +1,14 @@
1
+ module Hobo
2
+
3
+ class Percentage < DelegateClass(Fixnum)
4
+
5
+ COLUMN_TYPE = :integer
6
+
7
+ def validate
8
+ "must be from 0 to 100" unless self.in?(0..100)
9
+ end
10
+
11
+ end
12
+
13
+ end
14
+ Hobo.field_types[:percentage] = Hobo::Percentage
@@ -1,8 +1,8 @@
1
1
  module ::Hobo::Plugins
2
2
  class HoboPlugin
3
3
 
4
- def initialize(opt=nil)
5
- @opt = opt || Hash.new
4
+ def initialize(opt={})
5
+ @opt = opt
6
6
  set_up_options(self.class::PLUGIN_DEFAULTS)
7
7
 
8
8
  send @opt[:setup_using] || :default
@@ -37,7 +37,7 @@ module ::Hobo::Plugins
37
37
  end
38
38
 
39
39
  def hobo_model(name, &b)
40
- make_class @opt[name], ActiveRecord::Base do
40
+ make_class(@opt ? @opt[name] : name, ActiveRecord::Base) do
41
41
  hobo_model
42
42
  class_eval &b if b
43
43
  end
@@ -61,7 +61,7 @@ module ::Hobo::Plugins
61
61
  @plugin_opt
62
62
  end
63
63
  def self.has_feature(name)
64
- !@plugin_opt[name].nil? && @plugin_opt[name] != false
64
+ @plugin_opt[name]
65
65
  end
66
66
  def sym
67
67
  self.class.sym
@@ -19,7 +19,14 @@ module Hobo::RapidHelper
19
19
  def js_updates(updates)
20
20
  return '[]' unless updates
21
21
  updates = [updates] unless updates.is_a? Array
22
- '[' + comma_split(updates).map{|u| js_str(u)}.join(', ') + ']'
22
+ updates = comma_split(updates).map do |u|
23
+ if u.to_s == "self"
24
+ "Hobo.partFor(this)"
25
+ else
26
+ js_str(u)
27
+ end
28
+ end
29
+ "[#{updates * ', '}]"
23
30
  end
24
31
 
25
32
 
@@ -77,7 +84,8 @@ module Hobo::RapidHelper
77
84
  attributes = add_classes(attributes, behaviour_class)
78
85
  attributes.update(:hobo_model_id => this_field_dom_id,
79
86
  :hobo_blank_message => blank_message,
80
- :if_blank => blank_message)
87
+ :if_blank => blank_message,
88
+ :no_wrapper => false)
81
89
 
82
90
  update = attributes.delete(:update)
83
91
  attributes[:hobo_update] = update if update
@@ -1,3 +1,3 @@
1
- class Hobo::Text < String
2
-
3
- end
1
+ class Hobo::Text < String; end
2
+
3
+ Hobo.field_types[:text] = Hobo::Text
@@ -21,3 +21,5 @@ class RedCloth
21
21
  text.gsub!( /(.)\n(?!\n|\Z| *([#*=]+(\s|$)|[{|]))/, "\\1<br />" ) if hard_breaks && RedCloth::VERSION == "3.0.4"
22
22
  end
23
23
  end
24
+
25
+ Hobo.field_types[:textile] = Hobo::TextileString
@@ -2,8 +2,9 @@ module Hobo
2
2
 
3
3
  class Undefined
4
4
 
5
- def initialize(klass=Object)
6
- @klass = klass
5
+ def initialize(*args)
6
+ options = args.extract_options!
7
+ @klass = args.first || Object
7
8
  end
8
9
 
9
10
  def hobo_undefined?
@@ -2,7 +2,9 @@ require 'digest/sha1'
2
2
 
3
3
  module Hobo
4
4
 
5
- module AuthenticatedUser
5
+ module User
6
+
7
+ AUTHENTICATION_FIELDS = [:salt, :crypted_password, :remember_token, :remember_token_expires_at]
6
8
 
7
9
  # Extend the base class with AuthenticatedUser functionality
8
10
  # This includes:
@@ -29,7 +31,9 @@ module Hobo
29
31
 
30
32
  before_save :encrypt_password
31
33
 
32
- never_show :salt, :crypted_password, :remember_token, :remember_token_expires_at
34
+ never_show *AUTHENTICATION_FIELDS
35
+
36
+ attr_protected *AUTHENTICATION_FIELDS
33
37
 
34
38
  set_field_type :password => :password, :password_confirmation => :password
35
39
 
@@ -47,7 +51,10 @@ module Hobo
47
51
 
48
52
  def set_login_attr(attr)
49
53
  @login_attr = attr = attr.to_sym
50
- alias_attribute(:login, attr) unless attr == :login
54
+ unless attr == :login
55
+ alias_attribute(:login, attr)
56
+ set_field_type :login => field_type(attr)
57
+ end
51
58
 
52
59
  if block_given?
53
60
  yield
@@ -21,11 +21,10 @@ module Hobo
21
21
  def logout; hobo_logout; end
22
22
 
23
23
  def hobo_login(options={})
24
- @user_model = model
25
24
  options = LazyHash.new(options)
26
25
  options.reverse_merge!(:success_notice => "You have logged in.",
27
- :failure_notice => "You did not provide a valid login and password.",
28
- :redirect_to => {:action => "index"})
26
+ :failure_notice => "You did not provide a valid #{model.login_attr.to_s.titleize.downcase} and password.",
27
+ :disabled_notice => "You account is not currently available.")
29
28
 
30
29
  if request.post?
31
30
  user = model.authenticate(params[:login], params[:password])
@@ -40,50 +39,55 @@ module Hobo
40
39
  if block_given? && !yield
41
40
  # block returned false - cancel this login
42
41
  self.current_user = old_user
42
+ flash[:notice] ||= options[:disabled_notice]
43
43
  else
44
44
  if params[:remember_me] == "1"
45
45
  current_user.remember_me
46
46
  create_auth_cookie
47
47
  end
48
48
  flash[:notice] ||= options[:success_notice]
49
- redirect_back_or_default(options[:redirect_to]) unless performed?
49
+ redirect_back_or_default(options[:redirect_to] || home_page) unless performed?
50
50
  end
51
51
  end
52
+ else
53
+ hobo_render unless performed?
52
54
  end
53
- hobo_render unless performed?
54
55
  end
55
56
 
56
57
 
57
- def hobo_signup(options={})
58
- options = LazyHash.new(options)
59
- options.reverse_merge!(:notice => "Thanks for signing up!",
60
- :redirect_to => {:action => "index"})
58
+ def hobo_signup(&b)
61
59
  if request.post?
62
- begin
63
- @user = model.new(params[:user])
64
- @this = @user
65
- @user.save!
66
- self.current_user = @user
67
- redirect_back_or_default(options[:redirect_to])
68
- flash[:notice] = options[:notice]
69
- rescue ActiveRecord::RecordInvalid
70
- hobo_render
71
- end
60
+ @user = model.new(params[model.name.underscore])
61
+ @this = @user
62
+ save_and_set_status!(@user)
63
+ self.current_user = @user if valid?
64
+ response_block(&b) or
65
+ if valid?
66
+ flash[:notice] ||= "Thanks for signing up!"
67
+ redirect_back_or_default(home_page)
68
+ elsif invalid?
69
+ hobo_render
70
+ elsif not_allowed?
71
+ permission_denied
72
+ end
72
73
  else
73
- hobo_render
74
+ @this = @user = model.new
75
+ yield if block_given?
76
+ hobo_render unless performed?
74
77
  end
75
78
  end
76
79
 
77
80
 
78
81
  def hobo_logout(options={})
79
82
  options = options.reverse_merge(:notice => "You have been logged out.",
80
- :redirect_to => {:action => "index"})
83
+ :redirect_to => base_url)
81
84
 
82
85
  current_user.forget_me if logged_in?
83
86
  cookies.delete :auth_token
84
87
  reset_session
85
- flash[:notice] = options[:notice]
86
- redirect_back_or_default(options[:redirect_to])
88
+ yield if block_given?
89
+ flash[:notice] ||= options[:notice]
90
+ redirect_back_or_default(options[:redirect_to]) unless performed?
87
91
  end
88
92
 
89
93
  end
@@ -1,5 +1,5 @@
1
1
  <def tag="call_tag" attrs="tag">
2
- <%= send(tag, attributes) %>
2
+ <%= send(tag, attributes, &tagbody) %>
3
3
  </def>
4
4
 
5
5
 
@@ -7,6 +7,12 @@
7
7
  <%= send(template, attributes, all_parameters) %>
8
8
  </def>
9
9
 
10
+
11
+ <def tag="wrap" attrs="tag, when">
12
+ <% body = tagbody.call %>
13
+ <%= when_ ? call_tag(tag, attributes, &proc { body }) : body %>
14
+ </def>
15
+
10
16
 
11
17
  <def tag="partial" attrs="as">
12
18
  <%= render(:partial => find_partial(this, as), :locals => { :this => this }) %>
@@ -53,7 +59,7 @@
53
59
 
54
60
  <def tag="unless" attrs="test"><%=
55
61
  test = all_attributes.fetch(:test, this)
56
- res = (cond = test.blank?) ? "" : tagbody.call
62
+ res = (cond = test.blank?) ? tagbody.call : ""
57
63
  Hobo::Dryml.last_if = cond
58
64
  res
59
65
  %></def>
@@ -13,8 +13,12 @@
13
13
  <field_list merge_attrs="&attributes - attrs_for(:with_fields)">
14
14
  <with_fields merge_attrs="&attributes & attrs_for(:with_fields)">
15
15
  <field_list_item>
16
- <item_label param="#{this_field.to_s.sub('?', '')}_label"><%= this_field.to_s.titleize %></item_label>
17
- <item_value param="#{this_field.to_s.sub('?', '')}_view"><call_tag tag="&tag" /></item_value>
16
+ <item_label param="#{this_field.to_s.sub('?', '')}_label">
17
+ <do param="label"><%= this_field.to_s.titleize %></do>
18
+ </item_label>
19
+ <item_value param="#{this_field.to_s.sub('?', '')}_view">
20
+ <do param="view"><call_tag tag="&tag" param="#{this_field.to_s.sub('?', '')}_tag"/></do>
21
+ </item_value>
18
22
  </field_list_item>
19
23
  </with_fields>
20
24
  </field_list>
@@ -23,12 +27,13 @@
23
27
 
24
28
  <def tag="item"><% scope.items << tagbody.call %></def>
25
29
 
30
+ <def tag="nil_view"><%= scope.nil_view || "(Not Available)" %></def>
26
31
 
27
32
  <def tag="UL">
28
33
  <ul merge_attrs unless="&this.empty?">
29
34
  <repeat>
30
35
  <li param if="&can_view?" class="#{scope.even_odd} #{this_type.name.underscore}"
31
- hobo_model_id="#{dom_id this}">
36
+ merge_attrs="&{:hobo_model_id => dom_id(this)} if this.respond_to?(:typed_id)">
32
37
  <tagbody><a/></tagbody>
33
38
  </li>
34
39
  </repeat>
@@ -36,9 +41,9 @@
36
41
  </def>
37
42
 
38
43
 
39
- <def tag="Table" attrs="fields, field_tag">
44
+ <def tag="Table" attrs="fields, field_tag, empty">
40
45
  <% field_tag ||= "view" %>
41
- <table merge_attrs="&attributes - attrs_for(:with_fields)" unless="&this.empty?">
46
+ <table merge_attrs="&attributes - attrs_for(:with_fields)" unless="&this.empty? && !empty">
42
47
  <thead if="&all_parameters[:thead] || fields" param>
43
48
  <tr param="field_heading_row">
44
49
  <with_field_names merge_attrs="&all_attributes & attrs_for(:with_fields)">
@@ -91,14 +96,16 @@
91
96
 
92
97
 
93
98
  <def tag="hobo_rapid_javascripts" attrs="tiny_mce"><%=
94
- res = javascript_include_tag("hobo_rapid")
95
- res += '<script type="text/javascript">'
96
- unless Hobo.all_controllers.empty?
97
- res += "var controllerNames = {" +
98
- Hobo.all_controllers.map {|c| "#{c.singularize}: '#{c}'"}.join(', ') +
99
- "}; "
99
+ res = '<script type="text/javascript">var hoboParts = {};'
100
+ unless Hobo.all_models.empty?
101
+ # Tell JS code how to pluralize names, unless they follow the simple rule
102
+ names = Hobo.all_models.map do |m|
103
+ "#{m}: '#{m.pluralize}'" unless m.pluralize == m + 's'
104
+ end.compact
105
+ res += "var pluralisations = {#{names * ', '}}; "
100
106
  end
101
- res += "urlBase = '#{base_url}'; hoboPartPage = '#{view_name}'</script>"
107
+ base = [base_url, subsite].compact.join("/")
108
+ res += "urlBase = '#{base}'; hoboPagePath = '#{view_name}'</script>"
102
109
 
103
110
  if tiny_mce
104
111
  res += javascript_include_tag("tiny_mce/tiny_mce_src") + %{
@@ -119,7 +126,7 @@
119
126
 
120
127
  <def tag="name"><%=
121
128
  if this.nil?
122
- "(not available)"
129
+ nil_view
123
130
  else
124
131
  name_tag = find_polymorphic_tag("name")
125
132
  if name_tag != "name"
@@ -132,7 +139,7 @@
132
139
  view(merge_attrs(attributes, {:field => 'name'}))
133
140
  elsif this.respond_to?(:title) && can_view?(this, :title)
134
141
  view(merge_attrs(attributes, {:field => 'title'}))
135
- else
142
+ elsif can_view?(this)
136
143
  this.to_s
137
144
  end
138
145
  end
@@ -152,18 +159,22 @@
152
159
  name
153
160
  %></def>
154
161
 
155
- <def tag="a" attrs="action, to, params, resource_type, href"><%=
162
+
163
+ <def tag="a" attrs="action, to, params, query_params, href, format, subsite"><%=
156
164
  content = tagbody.call if tagbody
165
+
166
+ params = self.query_params.merge(params || HashWithIndifferentAccess.new) if query_params
157
167
 
158
168
  if href || attributes[:name]
159
169
  # Regular link
170
+ href += "?" + params.map { |n, v| "#{n}=#{v}" }.join('&') if params
160
171
  content_tag(:a, content, attributes.update(:href => href))
161
172
  else
162
173
  target = to || this
163
174
 
164
175
  if target.nil?
165
176
  Hobo::Dryml.last_if = false
166
- "(Not Available)"
177
+ nil_view
167
178
  elsif action == "new"
168
179
  # Link to a new object form
169
180
  new_record = target.new
@@ -176,9 +187,9 @@
176
187
  target.name
177
188
  end
178
189
 
179
- href = object_url(target, "new")
190
+ href = object_url(target, "new", params._?.merge(:subsite => subsite))
180
191
  add_classes!(attributes, "new_#{new_class_name.underscore}_link")
181
- content ||= "New #{new_class_name.titleize}"
192
+ content = "New #{new_class_name.titleize}" if content.blank?
182
193
  content_tag(:a, content, attributes.update(:href => href))
183
194
  else
184
195
  Hobo::Dryml.last_if = false
@@ -186,29 +197,31 @@
186
197
  end
187
198
  else
188
199
  # Link to an existing object
200
+
201
+ if target.is_a?(Array) && !target.respond_to?(:proxy_reflection) && target.respond_to?(:member_class)
202
+ # Not much to go on here - last guess is that this is an index page
203
+ target = target.member_class
204
+ end
189
205
 
190
- href = if resource_type
191
- send("formatted_#{model.to_s.downcase}_url", this, resource_type.downcase)
192
- else
193
- object_url(target, action, params)
194
- end
206
+ href = object_url(target, action, params._?.merge(:subsite => subsite))
195
207
  add_classes!(attributes, "#{target.class.name.underscore}_link")
196
208
 
209
+ href.sub!(/\?|$/, ".#{format}\\0") unless format.blank?
210
+
197
211
  # Set default link text if none given
198
- content ||= name
212
+ content = name if content.blank?
199
213
  content_tag(:a, content, attributes.update(:href => href))
200
214
  end
201
215
  end
202
216
  %></def>
203
217
 
204
-
205
218
 
206
219
  <def tag="view" attrs="inline, block, if_blank, no_wrapper, truncate"><%=
207
220
  raise HoboError, "view of non-viewable field '#{this_field}' of #{this_parent.typed_id rescue this_parent}" unless
208
221
  can_view?
209
222
 
210
223
  res = if this.nil? && if_blank.nil?
211
- this_type.is_a?(Class) && this_type <= String ? "" : "(Not Available)"
224
+ this_type.is_a?(Class) && this_type <= String ? "" : nil_view
212
225
  elsif this_type.respond_to?(:macro)
213
226
  if this_type.macro == :belongs_to
214
227
  belongs_to_view(attributes)
@@ -231,6 +244,7 @@
231
244
 
232
245
  truncate = 30 if truncate == true
233
246
  the_view = self.truncate(the_view, truncate.to_i) if truncate
247
+ the_view = the_view.strip
234
248
 
235
249
  if no_wrapper
236
250
  the_view
@@ -275,7 +289,8 @@
275
289
 
276
290
  <def tag="view" for="TrueClass"><%= this ? 'Yes' : 'No' %></def>
277
291
 
278
- <def tag="count" attrs="label, prefix, unless_none"><%=
292
+ <def tag="count" attrs="label, prefix, unless_none, if_any"><%=
293
+ if_any = unless_none if if_any.nil?
279
294
  raise Exception.new("asked for count of a string") if this.is_a?(String)
280
295
 
281
296
  if this.is_a?(Class) and this < ActiveRecord::Base
@@ -292,7 +307,7 @@
292
307
  end
293
308
  end
294
309
 
295
- Dryml.last_if = c > 0 if unless_none
310
+ Hobo::Dryml.last_if = c > 0 if unless_none
296
311
  if unless_none && c == 0
297
312
  ""
298
313
  else
@@ -361,17 +376,14 @@ in the future - use at your own risk. -->
361
376
  </with>
362
377
  </def>
363
378
 
364
- <def tag="restricted_page" attrs="require_login,error_message"><%
365
- allowed = if require_login == false
366
- true
367
- elsif require_login == true
368
- logged_in?
369
- else
370
- models = comma_split(require_login).map &it.titleize.constantize
371
- current_user.is_a?(*models)
372
- end
373
- raise Hobo::ModelController::UserPermissionError.new(models), (error_message || "Permission Denied") unless allowed
374
- -%><tagbody/></def>
379
+
380
+ <def tag="you" attrs="have, are">
381
+ <if test="&this == current_user">you <%= if have then 'have' elsif are then 'are' end %></if>
382
+ <else><tagbody><name/> <%= if have then 'has' elsif are then 'is' end %></tagbody></else>
383
+ </def>
375
384
 
376
385
 
377
- <def tag="you_have"><if test="&this == current_user">You have</if><else><name/> has</else></def>
386
+ <def tag="You" attrs="have, are">
387
+ <if test="&this == current_user">You <%= if have then 'have' elsif are then 'are' end %></if>
388
+ <else><tagbody><name/> <%= if have then 'has' elsif are then 'is' end %></tagbody></else>
389
+ </def>