card 1.16.14 → 1.16.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/db/migrate_core_cards/20150903130006_attachment_upload_cards.rb +4 -2
- data/lib/card/auth.rb +15 -10
- data/lib/card/codename.rb +25 -21
- data/lib/card/content.rb +100 -68
- data/lib/card/format.rb +158 -129
- data/lib/card/query.rb +15 -9
- data/lib/card/query/attributes.rb +41 -49
- data/lib/card/set.rb +15 -12
- data/lib/card/set_pattern.rb +4 -5
- data/lib/card/spec_helper.rb +54 -16
- data/lib/cardio.rb +43 -25
- data/mod/01_core/chunk/include.rb +1 -1
- data/mod/01_core/set/all/collection.rb +76 -73
- data/mod/01_core/set/all/content.rb +0 -4
- data/mod/01_core/set/all/fetch.rb +35 -42
- data/mod/01_core/set/all/name.rb +17 -7
- data/mod/01_core/set/all/pattern.rb +12 -11
- data/mod/01_core/set/all/permissions.rb +51 -42
- data/mod/01_core/set/all/phases.rb +2 -1
- data/mod/01_core/set/all/references.rb +2 -2
- data/mod/01_core/set/all/rules.rb +28 -35
- data/mod/01_core/set/all/subcards.rb +12 -12
- data/mod/01_core/set/all/tracked_attributes.rb +1 -1
- data/mod/01_core/set/all/type.rb +11 -11
- data/mod/01_core/set/all/utils.rb +6 -1
- data/mod/01_core/spec/set/all/fetch_spec.rb +6 -6
- data/mod/01_core/spec/set/all/permissions_spec.rb +11 -11
- data/mod/01_core/spec/set/all/tracked_attributes_spec.rb +1 -1
- data/mod/01_history/lib/card/action.rb +52 -47
- data/mod/01_history/set/all/actions.rb +20 -16
- data/mod/01_history/set/all/history.rb +18 -13
- data/mod/02_basic_types/set/all/base.rb +23 -2
- data/mod/02_basic_types/set/type/pointer.rb +45 -36
- data/mod/02_basic_types/spec/set/all/base_spec.rb +40 -24
- data/mod/02_basic_types/spec/set/type/pointer_spec.rb +87 -0
- data/mod/03_machines/set/right/machine_output.rb +10 -6
- data/mod/04_settings/set/abstract/permission.rb +10 -5
- data/mod/04_settings/set/type/setting.rb +4 -1
- data/mod/05_email/set/all/follow.rb +39 -44
- data/mod/05_email/set/all/notify.rb +4 -1
- data/mod/05_email/set/right/followers.rb +16 -14
- data/mod/05_email/set/self/follow_defaults.rb +22 -19
- data/mod/05_standard/lib/carrier_wave/cardmount.rb +1 -0
- data/mod/05_standard/set/abstract/attachment.rb +85 -58
- data/mod/05_standard/set/all/comment.rb +35 -19
- data/mod/05_standard/set/all/error.rb +124 -98
- data/mod/05_standard/set/all/list_changes.rb +27 -22
- data/mod/05_standard/set/all/rich_html/editing.rb +96 -70
- data/mod/05_standard/set/all/rich_html/form.rb +123 -81
- data/mod/05_standard/set/all/rich_html/modal.rb +15 -58
- data/mod/05_standard/set/right/account.rb +2 -2
- data/mod/05_standard/set/right/email.rb +3 -2
- data/mod/05_standard/set/rstar/rules.rb +3 -3
- data/mod/05_standard/set/self/search.rb +45 -22
- data/mod/05_standard/set/type/cardtype.rb +13 -11
- data/mod/05_standard/set/type/listed_by.rb +3 -2
- data/mod/05_standard/set/type/set.rb +17 -13
- data/mod/05_standard/set/type/signup.rb +1 -2
- data/mod/05_standard/set/type/user.rb +1 -1
- data/mod/05_standard/spec/set/all/account_spec.rb +1 -1
- data/mod/05_standard/spec/set/all/history_spec.rb +1 -1
- data/mod/05_standard/spec/set/type/email_template_spec.rb +140 -134
- data/mod/05_standard/spec/set/type/image_spec.rb +2 -1
- data/mod/05_standard/spec/set/type/signup_spec.rb +2 -2
- data/spec/models/card/trash_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -1
- metadata +2 -2
@@ -2,26 +2,29 @@ format :html do
|
|
2
2
|
def edit_slot args={}
|
3
3
|
# note: @mode should already be :edit here...
|
4
4
|
if args[:structure] || card.structure
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
process_relative_tags optional_toolbar: :hide,
|
11
|
-
structure: args[:structure]
|
12
|
-
end
|
5
|
+
multi_card_edit_slot args
|
6
|
+
else
|
7
|
+
single_card_edit_slot args
|
8
|
+
end
|
9
|
+
end
|
13
10
|
|
11
|
+
def multi_card_edit_slot args
|
12
|
+
if args[:core_edit] # need better name
|
13
|
+
_render_core args
|
14
14
|
else
|
15
|
-
|
16
|
-
|
15
|
+
process_relative_tags optional_toolbar: :hide,
|
16
|
+
structure: args[:structure]
|
17
|
+
end
|
18
|
+
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
20
|
+
def single_card_edit_slot args
|
21
|
+
field = content_field form, args
|
22
|
+
if [args[:optional_type_formgroup], args[:optional_name_formgroup]]
|
23
|
+
.member? :show
|
24
|
+
# display content field in formgroup for consistency with other fields
|
25
|
+
formgroup '', field, editor: :content
|
26
|
+
else
|
27
|
+
editor_wrap(:content) { field }
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -44,8 +47,8 @@ format :html do
|
|
44
47
|
form_for card, card_form_opts(action, opts) do |form|
|
45
48
|
@form = form
|
46
49
|
%{
|
47
|
-
#{
|
48
|
-
#{
|
50
|
+
#{hidden_tags hidden_args if hidden_args}
|
51
|
+
#{yield form}
|
49
52
|
}
|
50
53
|
end
|
51
54
|
end
|
@@ -61,14 +64,9 @@ format :html do
|
|
61
64
|
end
|
62
65
|
|
63
66
|
def card_form_opts action, html={}
|
64
|
-
url, action =
|
65
|
-
when Symbol ; [ path(action: action) , action ]
|
66
|
-
when Hash ; [ path(action) , action[:action] ]
|
67
|
-
when String ; [ card_path(action) , nil ] #deprecated
|
68
|
-
else ; raise Card::Error, "unsupported card_form action class: #{action.class}"
|
69
|
-
end
|
67
|
+
url, action = url_from_action(action)
|
70
68
|
|
71
|
-
klasses = Array.wrap(
|
69
|
+
klasses = Array.wrap(html[:class])
|
72
70
|
klasses << 'card-form slotter'
|
73
71
|
klasses << 'autosave' if action == :update
|
74
72
|
html[:class] = klasses.join ' '
|
@@ -79,33 +77,51 @@ format :html do
|
|
79
77
|
{ url: url, remote: true, html: html }
|
80
78
|
end
|
81
79
|
|
80
|
+
def url_from_action action
|
81
|
+
case action
|
82
|
+
when Symbol
|
83
|
+
[path(action: action), action]
|
84
|
+
when Hash
|
85
|
+
[path(action), action[:action]]
|
86
|
+
when String # deprecated
|
87
|
+
[card_path(action), nil]
|
88
|
+
else
|
89
|
+
raise Card::Error, "unsupported card_form action class: #{action.class}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
82
93
|
def editor_wrap type=nil
|
83
|
-
|
94
|
+
html_class = 'editor'
|
95
|
+
html_class << " #{type}-editor" if type
|
96
|
+
content_tag(:div, class: html_class) { yield.html_safe }
|
84
97
|
end
|
85
98
|
|
86
99
|
def formgroup title, content, opts={}
|
87
|
-
|
88
|
-
case opts[:help]
|
89
|
-
when String ; _render_help help_class: 'help-block', help_text: opts[:help]
|
90
|
-
when true ; _render_help help_class: 'help-block'
|
91
|
-
else ; nil
|
92
|
-
end
|
93
|
-
|
94
|
-
div_args = { class: ['form-group', opts[:class]].compact*' ' }
|
95
|
-
div_args[:card_id ] = card.id if card.real?
|
96
|
-
div_args[:card_name] = h card.name if card.name.present?
|
97
|
-
|
98
|
-
wrap_with :div, div_args do
|
100
|
+
wrap_with :div, formgroup_div_args(opts[:class]) do
|
99
101
|
%{
|
100
|
-
<label>#{
|
102
|
+
<label>#{title}</label>
|
101
103
|
<div>
|
102
|
-
#{
|
103
|
-
#{
|
104
|
+
#{editor_wrap(opts[:editor]) { content }}
|
105
|
+
#{formgroup_help_text opts[:help]}
|
104
106
|
</div>
|
105
107
|
}
|
106
108
|
end
|
107
109
|
end
|
108
110
|
|
111
|
+
def formgroup_div_args html_class
|
112
|
+
div_args = { class: ['form-group', html_class].compact.join(' ') }
|
113
|
+
div_args[:card_id] = card.id if card.real?
|
114
|
+
div_args[:card_name] = h card.name if card.name.present?
|
115
|
+
div_args
|
116
|
+
end
|
117
|
+
|
118
|
+
def formgroup_help_text text=nil
|
119
|
+
case text
|
120
|
+
when String then _render_help help_class: 'help-block', help_text: text
|
121
|
+
when true then _render_help help_class: 'help-block'
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
109
125
|
def hidden_tags hash, base=nil
|
110
126
|
# convert hash into a collection of hidden tags
|
111
127
|
result = ''
|
@@ -125,7 +141,7 @@ format :html do
|
|
125
141
|
# FIELDSET VIEWS
|
126
142
|
|
127
143
|
view :name_formgroup do |args|
|
128
|
-
formgroup 'name', raw(
|
144
|
+
formgroup 'name', raw(name_field form), editor: 'name', help: args[:help]
|
129
145
|
end
|
130
146
|
|
131
147
|
view :type_formgroup do |args|
|
@@ -150,26 +166,29 @@ format :html do
|
|
150
166
|
}
|
151
167
|
end
|
152
168
|
|
153
|
-
|
154
169
|
def name_field form=nil, options={}
|
155
170
|
form ||= self.form
|
156
|
-
text_field(
|
157
|
-
|
171
|
+
text_field(:name, {
|
172
|
+
# needed because otherwise gets wrong value if there are updates
|
173
|
+
value: card.name,
|
158
174
|
autocomplete: 'off'
|
159
175
|
}.merge(options))
|
160
176
|
end
|
161
177
|
|
162
178
|
def type_field args={}
|
163
179
|
typelist = Auth.createable_types
|
164
|
-
current_type =
|
165
|
-
|
166
|
-
|
167
|
-
|
180
|
+
current_type =
|
181
|
+
unless args.delete :no_current_type
|
182
|
+
if !card.new_card? && !typelist.include?(card.type_name)
|
183
|
+
# current type should be an option on existing cards,
|
184
|
+
# regardless of create perms
|
185
|
+
typelist.push(card.type_name).sort!
|
168
186
|
end
|
169
|
-
|
187
|
+
card.type_name_or_default
|
170
188
|
end
|
171
189
|
|
172
|
-
options = options_from_collection_for_select typelist, :to_s, :to_s,
|
190
|
+
options = options_from_collection_for_select typelist, :to_s, :to_s,
|
191
|
+
current_type
|
173
192
|
template.select_tag 'card[type]', options, args
|
174
193
|
end
|
175
194
|
|
@@ -177,34 +196,36 @@ format :html do
|
|
177
196
|
@form = form
|
178
197
|
@nested = options[:nested]
|
179
198
|
card.last_action_id_before_edit = card.last_action_id
|
180
|
-
revision_tracking =
|
181
|
-
|
182
|
-
|
183
|
-
|
199
|
+
revision_tracking =
|
200
|
+
if card && !card.new_card? && !options[:skip_rev_id]
|
201
|
+
hidden_field :last_action_id_before_edit, class: 'current_revision_id'
|
202
|
+
# hidden_field_tag 'card[last_action_id_before_edit]',
|
203
|
+
# card.last_action_id, class: 'current_revision_id'
|
204
|
+
end
|
184
205
|
%{
|
185
|
-
#{
|
186
|
-
|
187
|
-
#{ _render_editor options }
|
206
|
+
#{revision_tracking}
|
207
|
+
#{_render_editor options}
|
188
208
|
}
|
189
209
|
end
|
190
210
|
|
211
|
+
# FIELD VIEWS
|
191
212
|
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
text_area :content, rows: 3, class: 'tinymce-textarea card-content', id: unique_id
|
213
|
+
view :editor do |_args|
|
214
|
+
text_area :content, rows: 3, class: 'tinymce-textarea card-content',
|
215
|
+
id: unique_id
|
196
216
|
end
|
197
217
|
|
198
218
|
view :edit_in_form, perms: :update, tags: :unknown_ok do |args|
|
199
219
|
eform = form_for_multi
|
200
|
-
|
201
|
-
|
220
|
+
content = content_field eform, args.merge(nested: true)
|
221
|
+
if card.new_card?
|
222
|
+
content += raw("\n #{ eform.hidden_field :type_id }")
|
223
|
+
end
|
202
224
|
opts = { editor: 'content', help: true, class: 'card-editor' }
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
formgroup fancy_title( args[:title] ), content, opts
|
225
|
+
if card.cardname.junction?
|
226
|
+
opts[:class] += " RIGHT-#{ card.cardname.tag_name.safe_key }"
|
227
|
+
end
|
228
|
+
formgroup fancy_title(args[:title]), content, opts
|
208
229
|
end
|
209
230
|
|
210
231
|
def process_relative_tags args
|
@@ -212,31 +233,52 @@ format :html do
|
|
212
233
|
nested_card = fetch_nested_card chunk.options
|
213
234
|
nest nested_card, chunk.options.reverse_merge(args)
|
214
235
|
end.join "\n"
|
215
|
-
# _render_raw(args).scan( /\{\{\s*\+[^\}]*\}\}/ ).map do |inc| #fixme - wrong place for regexp!
|
216
|
-
# process_content( inc ).strip
|
217
|
-
# end.join
|
218
236
|
end
|
219
237
|
|
220
238
|
# form helpers
|
221
239
|
|
222
|
-
FIELD_HELPERS =
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
240
|
+
FIELD_HELPERS =
|
241
|
+
%w{
|
242
|
+
hidden_field color_field date_field datetime_field datetime_local_field
|
243
|
+
email_field month_field number_field password_field phone_field
|
244
|
+
range_field search_field telephone_field text_area text_field time_field
|
245
|
+
url_field week_field file_field
|
246
|
+
}
|
227
247
|
|
228
248
|
FIELD_HELPERS.each do |method_name|
|
229
|
-
define_method(method_name) do |name, options
|
249
|
+
define_method(method_name) do |name, options={}|
|
230
250
|
form.send(method_name, name, options)
|
231
251
|
end
|
232
252
|
end
|
233
253
|
|
234
|
-
def check_box method, options={}, checked_value =
|
254
|
+
def check_box method, options={}, checked_value = '1', unchecked_value = '0'
|
235
255
|
form.check_box method, options, checked_value, unchecked_value
|
236
256
|
end
|
237
257
|
|
238
|
-
def radio_button method, tag_value, options
|
258
|
+
def radio_button method, tag_value, options={}
|
239
259
|
form.radio_button method, tag_value, options
|
240
260
|
end
|
241
261
|
|
262
|
+
def submit_button args={}
|
263
|
+
args.reverse_merge!(
|
264
|
+
situation: 'primary',
|
265
|
+
data: {}
|
266
|
+
)
|
267
|
+
text = args.delete(:text) || 'Submit'
|
268
|
+
args[:data][:disable_with] ||= args.delete(:disable_with) || 'Submitting'
|
269
|
+
button_tag text, args
|
270
|
+
end
|
271
|
+
|
272
|
+
# redirect to *previous if no :href is given
|
273
|
+
def cancel_button args={}
|
274
|
+
args.reverse_merge! type: 'button'
|
275
|
+
if args[:href]
|
276
|
+
add_class args, 'slotter'
|
277
|
+
else
|
278
|
+
add_class args, 'redirecter'
|
279
|
+
args[:href] = Card.path_setting('/*previous')
|
280
|
+
end
|
281
|
+
text = args.delete(:text) || 'Cancel'
|
282
|
+
button_tag text, args
|
283
|
+
end
|
242
284
|
end
|
@@ -1,22 +1,15 @@
|
|
1
1
|
format :html do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
2
|
view :modal_link do |args|
|
7
3
|
path_opts = args[:path_opts] || {}
|
8
4
|
path_opts.merge!(layout: :modal)
|
9
5
|
html_args = args[:html_args] || {}
|
10
|
-
|
11
|
-
|
12
|
-
'data-toggle'=>'modal')
|
6
|
+
html_args.merge!('data-target' => '#modal-main-slot',
|
7
|
+
'data-toggle' => 'modal')
|
13
8
|
link_to(args[:text] || _render_title(args), path(path_opts), html_args)
|
14
9
|
end
|
15
10
|
|
16
11
|
view :modal_slot do |args|
|
17
|
-
|
18
|
-
id = "modal-"
|
19
|
-
id += (args[:modal_id] || 'main-slot')
|
12
|
+
id = "modal-#{args[:modal_id] || 'main-slot'}"
|
20
13
|
wrap_with(:div, class: 'modal fade', role: 'dialog', id: id) do
|
21
14
|
wrap_with(:div, class: 'modal-dialog') do
|
22
15
|
content_tag :div, class: 'modal-content' do
|
@@ -26,16 +19,19 @@ format :html do
|
|
26
19
|
end
|
27
20
|
end
|
28
21
|
|
29
|
-
|
30
|
-
view :modal_menu, tags: :unknown_ok do |args|
|
22
|
+
view :modal_menu, tags: :unknown_ok do
|
31
23
|
popout_params = {}
|
32
24
|
popout_params[:view] = params[:view] if params[:view]
|
33
|
-
# we probably want to pass on a lot more params than just view,
|
25
|
+
# we probably want to pass on a lot more params than just view,
|
26
|
+
# but not all of them
|
34
27
|
# (eg we don't want layout, id, controller...)
|
35
28
|
wrap_with :div, class: 'modal-menu' do
|
36
29
|
[
|
37
|
-
link_to(
|
38
|
-
|
30
|
+
link_to(glyphicon('remove'), '',
|
31
|
+
class: 'close-modal pull-right close',
|
32
|
+
'data-dismiss' => 'modal'),
|
33
|
+
link_to(glyphicon('new-window'), popout_params,
|
34
|
+
class: 'pop-out-modal pull-right close ')
|
39
35
|
]
|
40
36
|
end
|
41
37
|
end
|
@@ -45,48 +41,9 @@ format :html do
|
|
45
41
|
end
|
46
42
|
|
47
43
|
def default_modal_footer_args args
|
48
|
-
args[:buttons] ||=
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
def default_modal_content_args args
|
53
|
-
args[:buttons] ||= button_tag 'Close', 'data-dismiss'=>'modal'
|
54
|
-
end
|
55
|
-
|
56
|
-
view :modal_link_and_dialog do |args|
|
57
|
-
_render_modal_link(args) + _render_modal(args)
|
58
|
-
end
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
# use modal_content for ajax calls to fill a modal_slot with content
|
63
|
-
view :modal_content do |args|
|
64
|
-
output [
|
65
|
-
wrap_with( :div, _render_modal_header(args), class: 'modal-header' ),
|
66
|
-
wrap_with( :div, _render_modal_body(args), class: 'modal-body' ),
|
67
|
-
wrap_with( :div, _render_modal_footer(args), class: 'modal-footer' ),
|
68
|
-
]
|
44
|
+
args[:buttons] ||=
|
45
|
+
button_tag 'Close',
|
46
|
+
class: 'btn-xs close-modal pull-right',
|
47
|
+
'data-dismiss' => 'modal'
|
69
48
|
end
|
70
|
-
|
71
|
-
view :modal_header do |args|
|
72
|
-
_render_modal_title(args)
|
73
|
-
end
|
74
|
-
|
75
|
-
view :modal_body do |args|
|
76
|
-
_render_core(args)
|
77
|
-
end
|
78
|
-
|
79
|
-
view :modal_footer do |args|
|
80
|
-
args[:buttons] || ''
|
81
|
-
end
|
82
|
-
|
83
|
-
view :modal_title do |args|
|
84
|
-
"<h4>#{_render_title args.merge(title_class: 'modal-title')}</h4>"
|
85
|
-
end
|
86
|
-
|
87
|
-
view :modal do |args|
|
88
|
-
_render_modal_slot args.merge(optional_modal_content: :show)
|
89
|
-
end
|
90
|
-
=end
|
91
|
-
|
92
49
|
end
|
@@ -70,13 +70,13 @@ event :require_email, on: :create, after: :approve do
|
|
70
70
|
errors.add :email, 'required' unless subfield(:email)
|
71
71
|
end
|
72
72
|
|
73
|
-
event :set_default_salt, on: :create, before: :
|
73
|
+
event :set_default_salt, on: :create, before: :approve_subcards do
|
74
74
|
salt = Digest::SHA1.hexdigest "--#{Time.zone.now}--"
|
75
75
|
Env[:salt] = salt # HACK!!! need viable mechanism to get this to password
|
76
76
|
add_subfield :salt, content: salt
|
77
77
|
end
|
78
78
|
|
79
|
-
event :set_default_status, on: :create, before: :
|
79
|
+
event :set_default_status, on: :create, before: :approve_subcards do
|
80
80
|
default_status = Auth.needs_setup? ? 'active' : 'pending'
|
81
81
|
add_subfield :status, content: default_status
|
82
82
|
end
|
@@ -21,9 +21,10 @@ end
|
|
21
21
|
event :validate_unique_email, after: :validate_email, on: :save do
|
22
22
|
if content.present?
|
23
23
|
Auth.as_bot do
|
24
|
-
wql = { right_id: Card::EmailID, eq: content }
|
24
|
+
wql = { right_id: Card::EmailID, eq: content, return: :id }
|
25
25
|
wql[:not] = { id: id } if id
|
26
|
-
|
26
|
+
wql_comment = "email duplicate? (#{content})"
|
27
|
+
if Card.search(wql, wql_comment).first
|
27
28
|
errors.add :content, 'must be unique'
|
28
29
|
end
|
29
30
|
end
|
@@ -146,9 +146,9 @@ format :html do
|
|
146
146
|
args[:delete_button] ||= delete_button args
|
147
147
|
args[:cancel_button] ||=
|
148
148
|
begin
|
149
|
-
|
150
|
-
|
151
|
-
|
149
|
+
cancel_view = card.new_card? ? :closed_rule : :open_rule
|
150
|
+
cancel_button class: 'rule-cancel-button',
|
151
|
+
href: path(view: cancel_view, success: false)
|
152
152
|
end
|
153
153
|
end
|
154
154
|
|