wagn 1.14.4 → 1.14.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (140) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/app/controllers/card_controller.rb +4 -3
  4. data/db/bootstrap/card_actions.yml +597 -583
  5. data/db/bootstrap/card_acts.yml +2 -2
  6. data/db/bootstrap/card_changes.yml +297 -248
  7. data/db/bootstrap/card_references.yml +3111 -1284
  8. data/db/bootstrap/cards.yml +1067 -1022
  9. data/db/migrate_core_cards/20141208132416_partial_reference_type.rb +7 -0
  10. data/db/migrate_core_cards/20141208162106_add_ace_script.rb +12 -0
  11. data/db/migrate_core_cards/20141230204340_uri_codename.rb +13 -0
  12. data/db/version_core_cards.txt +1 -1
  13. data/features/history.feature +2 -1
  14. data/features/layouts.feature +4 -0
  15. data/features/navbox.feature +1 -0
  16. data/features/step_definitions/wagn_steps.rb +6 -1
  17. data/features/support/env.rb +1 -1
  18. data/lib/card/env.rb +1 -1
  19. data/lib/card/format.rb +35 -48
  20. data/lib/card/loader.rb +9 -9
  21. data/lib/card/mailer.rb +0 -2
  22. data/lib/card/query.rb +8 -8
  23. data/lib/card/query/{card_spec.rb → card_clause.rb} +42 -42
  24. data/lib/card/query/{spec.rb → clause.rb} +3 -3
  25. data/lib/card/query/ref_clause.rb +47 -0
  26. data/lib/card/query/value_clause.rb +65 -0
  27. data/lib/card/reference.rb +11 -20
  28. data/lib/card/set.rb +6 -6
  29. data/lib/card/set_pattern.rb +5 -1
  30. data/lib/wagn/commands.rb +28 -14
  31. data/lib/wagn/config/environments/test.rb +3 -0
  32. data/lib/wagn/generators/wagn/templates/Gemfile +6 -0
  33. data/lib/wagn/generators/wagn/templates/Rakefile +1 -0
  34. data/lib/wagn/generators/wagn/templates/config/application.rb +1 -0
  35. data/lib/wagn/generators/wagn/templates/spec/javascripts/support/deck_jasmine.yml +56 -0
  36. data/lib/wagn/generators/wagn/templates/spec/javascripts/support/wagn_jasmine.yml +69 -0
  37. data/lib/wagn/generators/wagn/wagn_generator.rb +19 -2
  38. data/lib/wagn/migration.rb +10 -0
  39. data/lib/wagn/spec_helper.rb +2 -0
  40. data/lib/wagn/tasks/wagn.rake +9 -16
  41. data/mod/01_core/chunk/link.rb +2 -2
  42. data/mod/01_core/chunk/uri.rb +4 -4
  43. data/mod/01_core/format/html_format.rb +43 -280
  44. data/mod/01_core/set/all/active_card.rb +2 -0
  45. data/mod/01_core/set/all/collection.rb +19 -1
  46. data/mod/01_core/set/all/fetch.rb +5 -0
  47. data/mod/01_core/set/all/initialize.rb +1 -1
  48. data/mod/01_core/set/all/references.rb +25 -8
  49. data/mod/01_core/set/all/templating.rb +1 -1
  50. data/mod/01_core/set/all/tracked_attributes.rb +1 -1
  51. data/mod/01_core/set/all/type.rb +1 -1
  52. data/mod/01_core/set/all/utils.rb +1 -0
  53. data/mod/01_core/set_pattern/07_type_plus_right.rb +2 -1
  54. data/mod/01_core/spec/format/html_format_spec.rb +0 -2
  55. data/mod/01_core/spec/set/all/initialize_spec.rb +4 -4
  56. data/mod/01_core/spec/set/all/notify_spec.rb +9 -9
  57. data/mod/02_basic_types/set/type/pointer.rb +19 -8
  58. data/mod/03_machines/lib/javascript/ace.js +18204 -0
  59. data/mod/03_machines/lib/javascript/jquery-ui.js +13109 -11440
  60. data/mod/03_machines/lib/javascript/jquery.autosize.js +52 -33
  61. data/mod/03_machines/lib/javascript/jquery.fileupload.js +10 -8
  62. data/mod/03_machines/lib/javascript/jquery.iframe-transport.js +44 -16
  63. data/mod/03_machines/lib/javascript/jquery.js +4 -9473
  64. data/mod/03_machines/lib/javascript/jquery_ujs.js +156 -116
  65. data/mod/03_machines/lib/javascript/jquerymobile.js +14890 -8236
  66. data/mod/03_machines/lib/javascript/theme-textmate.js +130 -0
  67. data/mod/03_machines/lib/javascript/wagn_mod.js.coffee +50 -10
  68. data/mod/03_machines/set/self/script_ace.rb +8 -0
  69. data/mod/03_machines/set/type/coffee_script.rb +1 -1
  70. data/mod/03_machines/set/type/css.rb +0 -2
  71. data/mod/03_machines/set/type/java_script.rb +1 -1
  72. data/mod/03_machines/spec/lib/{machine_spec.rb → shared_machine_examples.rb} +0 -0
  73. data/mod/03_machines/spec/lib/{machine_input_spec.rb → shared_machine_input_examples.rb} +0 -0
  74. data/mod/03_machines/spec/set/type/scss_spec.rb +2 -2
  75. data/mod/04_settings/set/right/comment.rb +2 -2
  76. data/mod/04_settings/set/type/setting.rb +2 -2
  77. data/mod/04_settings/spec/set/right/structure_spec.rb +2 -2
  78. data/mod/04_settings/spec/set/right/style_spec.rb +1 -1
  79. data/mod/05_email/set/type/email_template.rb +3 -2
  80. data/mod/05_standard/set/all/all_css.rb +1 -1
  81. data/mod/05_standard/set/all/all_js.rb +1 -1
  82. data/mod/05_standard/set/all/attach.rb +8 -7
  83. data/mod/05_standard/set/all/base.rb +6 -34
  84. data/mod/05_standard/set/all/editing.rb +145 -0
  85. data/mod/05_standard/set/all/error.rb +203 -0
  86. data/mod/05_standard/set/all/follow.rb +2 -2
  87. data/mod/05_standard/set/all/form.rb +211 -0
  88. data/mod/05_standard/set/all/header.rb +60 -0
  89. data/mod/05_standard/set/all/history.rb +3 -3
  90. data/mod/05_standard/set/all/links.rb +101 -0
  91. data/mod/05_standard/set/all/rich_html.rb +14 -392
  92. data/mod/05_standard/set/all/wrapper.rb +74 -0
  93. data/mod/05_standard/set/right/account.rb +1 -2
  94. data/mod/05_standard/set/rstar/rules.rb +5 -5
  95. data/mod/05_standard/set/self/account_links.rb +8 -4
  96. data/mod/05_standard/set/self/head.rb +3 -3
  97. data/mod/05_standard/set/self/signin.rb +5 -3
  98. data/mod/05_standard/set/type/search_type.rb +25 -25
  99. data/mod/05_standard/set/type/set.rb +2 -2
  100. data/mod/05_standard/set/type/signup.rb +0 -2
  101. data/mod/05_standard/set/type/uri.rb +11 -0
  102. data/mod/05_standard/spec/set/all/rich_html_spec.rb +6 -6
  103. data/mod/05_standard/spec/set/all/rss_spec.rb +1 -1
  104. data/mod/05_standard/spec/set/type/signup_spec.rb +0 -1
  105. data/mod/05_standard/spec/set/type/uri_spec.rb +41 -0
  106. data/public/assets/ace/mode-coffee.js +1 -0
  107. data/public/assets/ace/mode-css.js +1 -0
  108. data/public/assets/ace/mode-html.js +1 -0
  109. data/public/assets/ace/mode-javascript.js +1 -0
  110. data/public/assets/ace/mode-json.js +1 -0
  111. data/public/assets/ace/mode-scss.js +922 -0
  112. data/public/assets/ace/theme-github.js +98 -0
  113. data/public/assets/ace/theme-textmate.js +1 -0
  114. data/public/assets/ace/worker-coffee.js +1 -0
  115. data/public/assets/ace/worker-css.js +1 -0
  116. data/public/assets/ace/worker-html.js +1 -0
  117. data/public/assets/ace/worker-javascript.js +1 -0
  118. data/public/assets/ace/worker-json.js +1 -0
  119. data/spec/controllers/card_controller_spec.rb +0 -1
  120. data/spec/controllers/location_spec.rb +0 -2
  121. data/spec/javascripts/helpers/jasmine-jquery.js +812 -0
  122. data/spec/javascripts/support/jasmine.yml +8 -6
  123. data/spec/javascripts/support/jasmine_config.rb +1 -1
  124. data/spec/javascripts/support/jasmine_runner.rb +1 -1
  125. data/spec/javascripts/wagn_spec.coffee +2 -0
  126. data/spec/lib/card/content_spec.rb +28 -6
  127. data/spec/lib/card/format_spec.rb +62 -15
  128. data/spec/lib/card/reference_spec.rb +3 -3
  129. data/spec/spec_helper.rb +2 -2
  130. data/test/fixtures/card_actions.yml +1260 -1239
  131. data/test/fixtures/card_acts.yml +347 -341
  132. data/test/fixtures/card_changes.yml +2345 -2276
  133. data/test/fixtures/card_references.yml +4098 -1606
  134. data/test/fixtures/cards.yml +1950 -1887
  135. metadata +39 -13
  136. data/lib/card/query/ref_spec.rb +0 -37
  137. data/lib/card/query/value_spec.rb +0 -65
  138. data/lib/wagn/location.rb +0 -93
  139. data/spec/javascripts/helpers/jasmine-config.js +0 -2
  140. data/spec/javascripts/helpers/jasmine-jquery-1.3.1.js +0 -295
@@ -0,0 +1,145 @@
1
+ format :html do
2
+ ###---( TOP_LEVEL (used by menu) NEW / EDIT VIEWS )
3
+
4
+ view :new, :perms=>:create, :tags=>:unknown_ok do |args|
5
+ frame_and_form :create, args, 'main-success'=>'REDIRECT' do
6
+ [
7
+ _optional_render( :name_fieldset, args ),
8
+ _optional_render( :type_fieldset, args ),
9
+ _optional_render( :content_fieldsets, args ),
10
+ _optional_render( :button_fieldset, args )
11
+ ]
12
+ end
13
+ end
14
+
15
+
16
+ def default_new_args args
17
+ hidden = args[:hidden] ||= {}
18
+ hidden[:success] ||= card.rule(:thanks) || '_self'
19
+ hidden[:card ] ||={}
20
+
21
+ args[:optional_help] ||= :show
22
+
23
+ # name field / title
24
+ if !params[:name_prompt] and !card.cardname.blank?
25
+ # name is ready and will show up in title
26
+ hidden[:card][:name] ||= card.name
27
+ else
28
+ # name is not ready; need generic title
29
+ args[:title] ||= "New #{ card.type_name unless card.type_id == Card.default_type_id }" #fixme - overrides nest args
30
+ unless card.rule_card :autoname
31
+ # prompt for name
32
+ hidden[:name_prompt] = true unless hidden.has_key? :name_prompt
33
+ args[:optional_name_fieldset] ||= :show
34
+ end
35
+ end
36
+ args[:optional_name_fieldset] ||= :hide
37
+
38
+
39
+ # type field
40
+ if ( !params[:type] and !args[:type] and
41
+ ( main? || card.simple? || card.is_template? ) and
42
+ Card.new( :type_id=>card.type_id ).ok? :create #otherwise current type won't be on menu
43
+ )
44
+ args[:optional_type_fieldset] = :show
45
+ else
46
+ hidden[:card][:type_id] ||= card.type_id
47
+ args[:optional_type_fieldset] = :hide
48
+ end
49
+
50
+
51
+ cancel = if main?
52
+ { :class=>'redirecter', :href=>Card.path_setting('/*previous') }
53
+ else
54
+ { :class=>'slotter', :href=>path( :view=>:missing ) }
55
+ end
56
+
57
+ args[:buttons] ||= %{
58
+ #{ button_tag 'Submit', :class=>'create-submit-button', :disable_with=>'Submitting' }
59
+ #{ button_tag 'Cancel', :type=>'button', :class=>"create-cancel-button #{cancel[:class]}", :href=>cancel[:href] }
60
+ }
61
+
62
+ end
63
+
64
+
65
+ view :edit, :perms=>:update, :tags=>:unknown_ok do |args|
66
+ frame_and_form :update, args do
67
+ [
68
+ _optional_render( :content_fieldsets, args ),
69
+ _optional_render( :button_fieldset, args )
70
+ ]
71
+ end
72
+ end
73
+
74
+ def default_edit_args args
75
+ args[:optional_help] = :show
76
+
77
+ args[:buttons] = %{
78
+ #{ button_tag 'Submit', :class=>'submit-button', :disable_with=>'Submitting' }
79
+ #{ button_tag 'Cancel', :class=>'cancel-button slotter', :href=>path, :type=>'button' }
80
+ }
81
+ end
82
+
83
+ view :edit_name, :perms=>:update do |args|
84
+ frame_and_form( { :action=>:update, :id=>card.id }, args, 'main-success'=>'REDIRECT' ) do
85
+ [
86
+ _render_name_fieldset( args ),
87
+ _optional_render( :confirm_rename, args ),
88
+ _optional_render( :button_fieldset, args )
89
+ ]
90
+ end
91
+ end
92
+
93
+ view :confirm_rename do |args|
94
+ referers = args[:referers]
95
+ dependents = card.dependents
96
+ wrap args do
97
+ %{
98
+ <h1>Are you sure you want to rename <em>#{card.name}</em>?</h1>
99
+ #{ %{ <h2>This change will...</h2> } if referers.any? || dependents.any? }
100
+ <ul>
101
+ #{ %{<li>automatically alter #{ dependents.size } related name(s). } if dependents.any? }
102
+ #{ %{<li>affect at least #{referers.size} reference(s) to "#{card.name}".} if referers.any? }
103
+ </ul>
104
+ #{ %{<p>You may choose to <em>update or ignore</em> the references.</p>} if referers.any? }
105
+ }
106
+ end
107
+ end
108
+
109
+ def default_edit_name_args args
110
+ referers = args[:referers] = card.extended_referencers
111
+ args[:hidden] ||= {}
112
+ args[:hidden].reverse_merge!(
113
+ :success => '_self',
114
+ :old_name => card.name,
115
+ :referers => referers.size,
116
+ :card => { :update_referencers => false }
117
+ )
118
+ args[:buttons] = %{
119
+ #{ button_tag 'Rename and Update', :disable_with=>'Renaming', :class=>'renamer-updater' }
120
+ #{ button_tag 'Rename', :disable_with=>'Renaming', :class=>'renamer' }
121
+ #{ button_tag 'Cancel', :class=>'slotter', :type=>'button', :href=>path(:view=>:edit, :id=>card.id)}
122
+ }
123
+
124
+ end
125
+
126
+
127
+ view :edit_type, :perms=>:update do |args|
128
+ frame_and_form :update, args do
129
+ #'main-success'=>'REDIRECT: _self', # adding this back in would make main cards redirect on cardtype changes
130
+ [
131
+ _render_type_fieldset( args ),
132
+ optional_render( :button_fieldset, args )
133
+ ]
134
+ end
135
+ end
136
+
137
+ def default_edit_type_args args
138
+ args[:variety] = :edit #YUCK!
139
+ args[:hidden] ||= { :view=>:edit }
140
+ args[:buttons] = %{
141
+ #{ button_tag 'Submit', :disable_with=>'Submitting' }
142
+ #{ button_tag 'Cancel', :href=>path(:view=>:edit), :type=>'button', :class=>'slotter' }
143
+ }
144
+ end
145
+ end
@@ -0,0 +1,203 @@
1
+ format do
2
+ view :closed_missing, :perms=>:none do |args| '' end
3
+ view :missing, :perms=>:none do |args| '' end
4
+
5
+ view :not_found, :perms=>:none, :error_code=>404 do |args|
6
+ %{ Could not find #{card.name.present? ? %{"#{card.name}"} : 'the card requested'}. }
7
+ end
8
+
9
+ view :server_error, :perms=>:none, :error_code=>500 do |args|
10
+ %{ Wagn Hitch! Server Error. Yuck, sorry about that.\n}+
11
+ %{ To tell us more and follow the fix, add a support ticket at http://wagn.org/new/Support_Ticket }
12
+ end
13
+
14
+ view :denial, :perms=>:none, :error_code=>403 do |args|
15
+ focal? ? 'Permission Denied' : ''
16
+ end
17
+
18
+ view :bad_address, :perms=>:none, :error_code=>404 do |args|
19
+ %{ 404: Bad Address }
20
+ end
21
+
22
+ view :too_deep, :perms=>:none do |args|
23
+ %{ Man, you're too deep. (Too many levels of inclusions at a time) }
24
+ end
25
+
26
+ view :too_slow, :perms=>:none do |args|
27
+ %{ Timed out! #{ showname } took too long to load. }
28
+ end
29
+ end
30
+
31
+
32
+ format :html do
33
+ def view_for_unknown view, args
34
+ case
35
+ when focal? && ok?( :create ) ; :new
36
+ when commentable?( view, args ) ; view
37
+ else super
38
+ end
39
+ end
40
+
41
+ def commentable? view, args
42
+ self.class.tagged view, :comment and
43
+ show_view? :comment_box, args.merge( :default_visibility=>:hide ) and #developer or wagneer has overridden default
44
+ ok? :comment
45
+ end
46
+
47
+ def rendering_error exception, view
48
+ %{
49
+
50
+ <span class="render-error">
51
+ error rendering
52
+ #{
53
+ if Auth.always_ok?
54
+ %{
55
+ #{ card_link error_cardname, :class=>'render-error-link' }
56
+ <div class="render-error-message errors-view" style="display:none">
57
+ <h3>Error message (visible to admin only)</h3>
58
+ <p><strong>#{ exception.message }</strong></p>
59
+ <div>
60
+ #{exception.backtrace * "<br>\n"}
61
+ </div>
62
+ </div>
63
+ }
64
+ else
65
+ error_cardname
66
+ end
67
+ }
68
+ (#{view} view)
69
+ </span>
70
+ }
71
+ end
72
+
73
+ def unsupported_view view
74
+ "<strong>view <em>#{view}</em> not supported for <em>#{error_cardname}</em></strong>"
75
+ end
76
+
77
+ view :message, :perms=>:none, :tags=>:unknown_ok do |args|
78
+ frame args do
79
+ params[:message]
80
+ end
81
+ end
82
+
83
+
84
+ view :missing do |args|
85
+ return '' unless card.ok? :create # should this be moved into ok_view?
86
+
87
+ opts = { :remote=>true, :class=>"slotter missing-#{ args[:denied_view] || args[:home_view]}" }
88
+
89
+ wrap args do
90
+ view_link "Add #{ fancy_title args[:title] }", :new, opts
91
+ end
92
+ end
93
+
94
+ view :closed_missing, :perms=>:none do |args|
95
+ %{<span class="faint"> #{ showname } </span>}
96
+ end
97
+
98
+
99
+
100
+ view :conflict, :error_code=>409 do |args|
101
+ # FIXME: hack to get the conflicted update as a proper act for the diff view
102
+ card.current_act.save
103
+ action = card.actions.last # the unsaved action with the new changes
104
+ action.card_act_id = card.current_act.id
105
+ action.draft = true
106
+ action.save
107
+ card.store_changes # deletes action if there are no changes
108
+
109
+ # as a consequence card.current_act.actions can be empty when both users made exactly the same changes
110
+ # but an act is always supposed to have at least one action, so we have to delete the act to avoid bad things
111
+ card.current_act.reload
112
+ if card.current_act.actions.empty?
113
+ card.current_act.delete
114
+ card.current_act = nil
115
+ end
116
+
117
+ wrap args.merge( :slot_class=>'error-view' ) do #ENGLISH below
118
+ %{<strong>Conflict!</strong><span class="new-current-revision-id">#{card.last_action_id}</span>
119
+ <div>#{ card_link card.last_action.act.actor.cardname } has also been making changes.</div>
120
+ <div>Please examine below, resolve above, and re-submit.</div>
121
+ #{ wrap do |args|
122
+ if card.current_act
123
+ _render_act_expanded :act=>card.current_act, :current_rev_nr => 0
124
+ else
125
+ "No difference between your changes and #{card.last_action.act.actor.name}'s version."
126
+ end
127
+ end
128
+ }
129
+ }
130
+ end
131
+ end
132
+
133
+ view :errors, :perms=>:none do |args|
134
+ if card.errors.any?
135
+ title = %{ Problems #{%{ with #{card.name} } unless card.name.blank?} }
136
+ frame args.merge( :title=>title ) do
137
+ card.errors.map do |attrib, msg|
138
+ msg = "#{attrib.to_s.upcase}: #{msg}" unless attrib == :abort
139
+ %{ <div class="card-error-msg">#{msg}</div> }
140
+ end
141
+ end
142
+ end
143
+ end
144
+
145
+ view :not_found do |args| #ug. bad name.
146
+ sign_in_or_up_links = if !Auth.signed_in?
147
+ %{<div>
148
+ #{ card_link ':signin', :text=>'Sign in' } or
149
+ #{ link_to 'Sign up', wagn_path('new/:signup') } to create it.
150
+ </div>}
151
+ end
152
+ frame args.merge(:title=>'Not Found', :optional_menu=>:never) do
153
+ %{
154
+ <h2>Could not find #{card.name.present? ? "<em>#{card.name}</em>" : 'that'}.</h2>
155
+ #{sign_in_or_up_links}
156
+ }
157
+ end
158
+ end
159
+
160
+ view :denial do |args|
161
+ to_task = if task = args[:denied_task]
162
+ %{to #{task} this.}
163
+ else
164
+ 'to do that.'
165
+ end
166
+
167
+ if !focal?
168
+ %{<span class="denied"><!-- Sorry, you don't have permission #{to_task} --></span>}
169
+ else
170
+ frame args do #ENGLISH below
171
+ message = case
172
+ when task != :read && Wagn.config.read_only
173
+ "We are currently in read-only mode. Please try again later."
174
+ when Auth.signed_in?
175
+ "You need permission #{to_task}"
176
+ else
177
+ or_signup = if Card.new(:type_id=>Card::SignupID).ok? :create
178
+ "or #{ link_to 'sign up', wagn_url('new/:signup') }"
179
+ end
180
+ save_interrupted_action(request.env['REQUEST_URI'])
181
+ "You have to #{ link_to 'sign in', wagn_url(':signin') } #{or_signup} #{to_task}"
182
+ end
183
+
184
+ %{<h1>Sorry!</h1>\n<div>#{ message }</div>}
185
+ end
186
+ end
187
+ end
188
+
189
+
190
+ view :server_error do |args|
191
+ %{
192
+ <body>
193
+ <div class="dialog">
194
+ <h1>Wagn Hitch :(</h1>
195
+ <p>Server Error. Yuck, sorry about that.</p>
196
+ <p><a href="http://www.wagn.org/new/Support_Ticket">Add a support ticket</a>
197
+ to tell us more and follow the fix.</p>
198
+ </div>
199
+ </body>
200
+ }
201
+ end
202
+
203
+ end
@@ -29,14 +29,14 @@ format :html do
29
29
  return '' unless watched_card
30
30
 
31
31
  following = Auth.current.fetch :trait=>:following, :new=>{:type=>:pointer}
32
- path_hash = {:card=>following, :action=>:update, :toggle=>toggle,
32
+ path_hash = {:name=>following.name, :action=>:update, :toggle=>toggle,
33
33
  :success=>{:id=>card.name, :view=>:watch} }
34
34
  case toggle
35
35
  when :off then path_hash[:drop_item] = watched_card.cardname.url_key
36
36
  when :on then path_hash[:add_item] = watched_card.cardname.url_key
37
37
  end
38
38
 
39
- link_to "#{text}", path(path_hash),
39
+ link_to "#{text}", path_hash,
40
40
  {:class=>"watch-toggle watch-toggle-#{toggle} slotter", :title=>title, :remote=>true, :method=>'post'}.merge(extra)
41
41
  end
42
42
 
@@ -0,0 +1,211 @@
1
+ format :html do
2
+ def edit_slot args={}
3
+ #note: @mode should already be :edit here...
4
+ if args[:structure] || card.structure
5
+ # multi-card editing
6
+
7
+ if args[:core_edit] #need better name!
8
+ _render_core args
9
+ else
10
+ process_relative_tags args
11
+ end
12
+
13
+ else
14
+ # single-card edit mode
15
+ field = content_field form, args
16
+
17
+ if [ args[:optional_type_fieldset], args[:optional_name_fieldset] ].member? :show
18
+ # display content field in fieldset for consistency with other fields
19
+ fieldset '', field, :editor=>:content
20
+ else
21
+ editor_wrap( :content ) { field }
22
+ end
23
+ end
24
+ end
25
+
26
+
27
+ def form_for_multi
28
+ block = Proc.new {}
29
+ builder = ActionView::Base.default_form_builder
30
+ card.name = card.name.gsub(/^#{Regexp.escape(root.card.name)}\+/, '+') if root.card.new_card? ##FIXME -- need to match other relative inclusions.
31
+
32
+ builder.new("card[subcards][#{card.relative_name}]", card, template, {}, block)
33
+ end
34
+
35
+ def form
36
+ @form ||= form_for_multi
37
+ end
38
+
39
+ def card_form action, opts={}
40
+ hidden_args = opts.delete :hidden
41
+ form_for card, card_form_opts(action, opts) do |form|
42
+ @form = form
43
+ %{
44
+ #{ hidden_tags hidden_args if hidden_args }
45
+ #{ yield form }
46
+ }
47
+ end
48
+ end
49
+
50
+ def card_form_opts action, html={}
51
+ url, action = case action
52
+ when Symbol ; [ path(:action=>action) , action ]
53
+ when Hash ; [ path(action) , action[:action] ]
54
+ when String ; [ wagn_path(action) , nil ] #deprecated
55
+ else ; raise Card::Error, "unsupported card_form action class: #{action.class}"
56
+ end
57
+
58
+ klasses = Array.wrap( html[:class] )
59
+ klasses << 'card-form slotter'
60
+ klasses << 'autosave' if action == :update
61
+ html[:class] = klasses.join ' '
62
+
63
+ html[:recaptcha] ||= 'on' if card.recaptcha_on?
64
+ html.delete :recaptcha if html[:recaptcha] == :off
65
+
66
+ { :url=>url, :remote=>true, :html=>html }
67
+ end
68
+
69
+ def editor_wrap type=nil
70
+ content_tag( :div, :class=>"editor#{ " #{type}-editor" if type }" ) { yield }
71
+ end
72
+
73
+ def fieldset title, content, opts={}
74
+ if attribs = opts[:attribs]
75
+ attrib_string = attribs.keys.map do |key|
76
+ %{#{key}="#{attribs[key]}"}
77
+ end * ' '
78
+ end
79
+ help_text = case opts[:help]
80
+ when String ; _render_help :help_text=> opts[:help]
81
+ when true ; _render_help
82
+ else ; nil
83
+ end
84
+ %{
85
+ <fieldset #{ attrib_string }>
86
+ <legend>
87
+ <h2>#{ title }</h2>
88
+ #{ help_text }
89
+ </legend>
90
+ #{ editor_wrap( opts[:editor] ) { content } }
91
+ </fieldset>
92
+ }
93
+ end
94
+
95
+ def hidden_tags hash, base=nil
96
+ # convert hash into a collection of hidden tags
97
+ result = ''
98
+ hash ||= {}
99
+ hash.each do |key, val|
100
+ result += if Hash === val
101
+ hidden_tags val, key
102
+ else
103
+ name = base ? "#{base}[#{key}]" : key
104
+ hidden_field_tag name, val
105
+ end
106
+ end
107
+ result
108
+ end
109
+
110
+
111
+ # FIELDSET VIEWS
112
+
113
+ view :name_fieldset do |args|
114
+ fieldset 'name', raw( name_field form ), :editor=>'name', :help=>args[:help]
115
+ end
116
+
117
+ view :type_fieldset do |args|
118
+ field = if args[:variety] == :edit #FIXME dislike this api -ef
119
+ type_field :class=>'type-field edit-type-field'
120
+ else
121
+ type_field :class=>"type-field live-type-field", :href=>path(:view=>:new), 'data-remote'=>true
122
+ end
123
+ fieldset 'type', field, :editor => 'type', :attribs => { :class=>'type-fieldset'}
124
+ end
125
+
126
+
127
+ view :button_fieldset do |args|
128
+ %{
129
+ <fieldset>
130
+ <div class="button-area">
131
+ #{ args[:buttons] }
132
+ </div>
133
+ </fieldset>
134
+ }
135
+ end
136
+
137
+ view :content_fieldsets do |args|
138
+ raw %{
139
+ <div class="card-editor editor">
140
+ #{ edit_slot args }
141
+ </div>
142
+ }
143
+ end
144
+
145
+
146
+ def name_field form=nil, options={}
147
+ form ||= self.form
148
+ form.text_field( :name, {
149
+ :value=>card.name, #needed because otherwise gets wrong value if there are updates
150
+ :autocomplete=>'off'
151
+ }.merge(options))
152
+ end
153
+
154
+ def type_field args={}
155
+ typelist = Auth.createable_types
156
+ current_type = unless args.delete :no_current_type
157
+ unless card.new_card? || typelist.include?( card.type_name )
158
+ # current type should be an option on existing cards, regardless of create perms
159
+ typelist = (typelist << card.type_name).sort
160
+ end
161
+ Card[ card ? card.type_id : Card.default_type_id ].name
162
+ end
163
+
164
+ options = options_from_collection_for_select typelist, :to_s, :to_s, current_type
165
+ template.select_tag 'card[type]', options, args
166
+ end
167
+
168
+ def content_field form, options={}
169
+ @form = form
170
+ @nested = options[:nested]
171
+ card.last_action_id_before_edit = card.last_action_id
172
+ revision_tracking = if card && !card.new_card? && !options[:skip_rev_id]
173
+ form.hidden_field :last_action_id_before_edit, :class=>'current_revision_id'
174
+ #hidden_field_tag 'card[last_action_id_before_edit]', card.last_action_id, :class=>'current_revision_id'
175
+ end
176
+ %{
177
+ #{ revision_tracking
178
+ }
179
+ #{ _render_editor options }
180
+ }
181
+ end
182
+
183
+
184
+ # FIELD VIEWS
185
+
186
+ view :editor do |args|
187
+ form.text_area :content, :rows=>3, :class=>'tinymce-textarea card-content', :id=>unique_id
188
+ end
189
+
190
+
191
+ view :edit_in_form, :perms=>:update, :tags=>:unknown_ok do |args|
192
+ eform = form_for_multi
193
+ content = content_field eform, args.merge( :nested=>true )
194
+ opts = { :editor=>'content', :help=>true, :attribs =>
195
+ { :class=> "card-editor RIGHT-#{ card.cardname.tag_name.safe_key }" }
196
+ }
197
+ if card.new_card?
198
+ content += raw( "\n #{ eform.hidden_field :type_id }" )
199
+ else
200
+ opts[:attribs].merge! :card_id=>card.id, :card_name=>(h card.name)
201
+ end
202
+
203
+ fieldset fancy_title( args[:title] ), content, opts
204
+ end
205
+
206
+ def process_relative_tags args
207
+ _render_raw(args).scan( /\{\{\s*\+[^\}]*\}\}/ ).map do |inc| #fixme - wrong place for regexp!
208
+ process_content( inc ).strip
209
+ end.join
210
+ end
211
+ end