hobo 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
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>