card-mod-edit 0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,101 @@
1
+ format :html do
2
+ view :edit_type, cache: :never, perms: :update do
3
+ frame do
4
+ _render_edit_type_form
5
+ end
6
+ end
7
+
8
+ view :edit_type_form, cache: :never, perms: :update, wrap: :slot do
9
+ card_form :update, success: edit_type_success do
10
+ [type_formgroup, render_new_buttons]
11
+ end
12
+ end
13
+
14
+ def edit_type_success
15
+ { view: :core }
16
+ end
17
+
18
+ view :edit_type_row do
19
+ return _render_bridge_type_formgroup if voo.visible?(:type_form) { false }
20
+
21
+ edit_row_fixed_width "Type", link_to_card(card.type), :bridge_type_formgroup
22
+ end
23
+
24
+ view :bridge_type_formgroup, unknown: true, wrap: :slot do
25
+ type_formgroup href: path(mark: card.id,
26
+ view: :edit_form,
27
+ assign: true,
28
+ slot: { show: :type_form }),
29
+ class: "live-type-field slotter",
30
+ 'data-remote': true,
31
+ 'data-slot-selector': ".card-slot.edit_form-view"
32
+ end
33
+
34
+ view :type_formgroup do
35
+ type_formgroup
36
+ end
37
+
38
+ def type_formgroup args={}
39
+ add_class args, "type-field"
40
+ wrap_type_formgroup do
41
+ type_field args
42
+ end
43
+ end
44
+
45
+ def wrap_type_formgroup
46
+ formgroup "Type", input: "type", class: "type-formgroup", help: false do
47
+ output [yield, hidden_field_tag(:assign, true)]
48
+ end
49
+ end
50
+
51
+ def type_field args={}
52
+ typelist = Auth.createable_types
53
+ current_type = type_field_current_value args, typelist
54
+ template.select_tag "card[type]", type_field_options(current_type),
55
+ args.merge("data-select2-id": "#{unique_id}-#{Time.now.to_i}")
56
+ end
57
+
58
+ def type_field_options current_type
59
+ types = grouped_types(current_type)
60
+
61
+ if types.size == 1
62
+ options_for_select types.flatten[1], current_type
63
+ else
64
+ grouped_options_for_select types, current_type
65
+ end
66
+ end
67
+
68
+ def grouped_types current_type
69
+ groups = Hash.new { |h, k| h[k] = [] }
70
+ allowed = ::Set.new Auth.createable_types
71
+ allowed << current_type if current_type
72
+
73
+ visible_cardtype_groups.each_pair do |name, items|
74
+ if name == "Custom"
75
+ Auth.createable_types.each do |type|
76
+ groups["Custom"] << type unless ::Card::Set::Self::Cardtype::GROUP_MAP[type]
77
+ end
78
+ else
79
+ items.each do |i|
80
+ groups[name] << i if allowed.include?(i)
81
+ end
82
+ end
83
+ end
84
+ groups
85
+ end
86
+
87
+ def visible_cardtype_groups
88
+ ::Card::Set::Self::Cardtype::GROUP
89
+ end
90
+
91
+ def type_field_current_value args, typelist
92
+ return if args.delete :no_current_type
93
+
94
+ if !card.new_card? && !typelist.include?(card.type_name)
95
+ # current type should be an option on existing cards,
96
+ # regardless of create perms
97
+ typelist.push(card.type_name).sort!
98
+ end
99
+ card.type_name_or_default
100
+ end
101
+ end
@@ -0,0 +1,91 @@
1
+ format :html do
2
+ ###---( TOP_LEVEL (used by menu) NEW / EDIT VIEWS )
3
+ view :bridge, perms: :update, unknown: true, cache: :never, wrap: :bridge do
4
+ with_nest_mode :edit do
5
+ add_name_context
6
+ voo.show :help
7
+ wrap true, breadcrumb_data("Editing", "edit") do
8
+ bridge_parts
9
+ end
10
+ end
11
+ end
12
+
13
+ view :cardboard, :bridge
14
+
15
+ def bridge_parts
16
+ voo.show! :edit_type_row
17
+
18
+ [
19
+ frame_help,
20
+ _render_edit_name_row(home_view: :edit_name_row),
21
+ # home_view is necessary for cancel to work correctly.
22
+ # it seems a little strange to have to think about home_view here,
23
+ # but the issue is that something currently has to happen prior to the
24
+ # render to get voo.slot_options to have the write home view in
25
+ # the slot wrap. I think this would probably best be handled as an
26
+ # option to #wrap that triggers a new heir voo
27
+ _render_edit_form
28
+ ]
29
+ end
30
+
31
+ def edit_success
32
+ # for override
33
+ end
34
+
35
+ def edit_view_hidden
36
+ # for override
37
+ end
38
+
39
+ view :edit_buttons do
40
+ button_formgroup do
41
+ wrap_with "div", class: "d-flex" do
42
+ [standard_submit_button, edit_cancel_button, delete_button]
43
+ end
44
+ end
45
+ end
46
+
47
+ # TODO: add undo functionality
48
+ view :just_deleted, unknown: true do
49
+ wrap { "#{render_title} deleted" }
50
+ end
51
+
52
+ view :edit_rules, cache: :never, unknown: true do
53
+ nest current_set_card, view: :bridge_rules_tab
54
+ end
55
+
56
+ view :edit_structure, cache: :never do
57
+ return unless card.structure
58
+
59
+ nest card.structure_rule_card, view: :edit
60
+ # FIXME: this stuff:
61
+ # slot: {
62
+ # cancel_slot_selector: ".card-slot.related-view",
63
+ # cancel_path: card.format.path(view: :edit), hide: :edit_toolbar,
64
+ # hidden: { success: { view: :open, "slot[subframe]" => true } }
65
+ # }
66
+ # }
67
+ end
68
+
69
+ view :edit_nests, cache: :never do
70
+ frame do
71
+ with_nest_mode :edit do
72
+ multi_card_edit
73
+ end
74
+ end
75
+ end
76
+
77
+ # FIXME: - view can recurse. temporarily turned off
78
+ #
79
+ # view :edit_nest_rules, cache: :never do
80
+ # return ""#
81
+ # view = args[:rule_view] || :field_related_rules
82
+ # frame do
83
+ # # with_nest_mode :edit do
84
+ # nested_fields.map do |name, _options|
85
+ # nest Card.fetch(name.to_name.trait(:self)),
86
+ # view: :titled, title: name, rule_view: view,
87
+ # hide: :set_label, show: :rule_navbar
88
+ # end
89
+ # end
90
+ # end
91
+ end
@@ -0,0 +1,56 @@
1
+
2
+ Self::InputOptions.add_to_basket :options, "text area"
3
+ Self::InputOptions.add_to_basket :options, "text field"
4
+
5
+ format :html do
6
+ def input_type
7
+ voo.input_type.present? ? voo.input_type : input_type_from_rule
8
+ end
9
+
10
+ def input_type_from_rule
11
+ card.rule(:input_type)&.gsub(/[\[\]]/, "")&.tr(" ", "_")
12
+ end
13
+
14
+ def input_method input_type
15
+ "#{input_type}_input"
16
+ end
17
+
18
+ # core view of card is input
19
+ def input_defined_by_card
20
+ with_card input_type do |input_card|
21
+ nest input_card, view: :core
22
+ end
23
+ end
24
+
25
+ # move somewhere more accessible?
26
+ def with_card mark
27
+ return nil unless (card = Card[mark])
28
+
29
+ yield card
30
+ rescue Card::Error::CodenameNotFound
31
+ nil
32
+ end
33
+
34
+ view :input, unknown: true do
35
+ try(input_method(input_type)) ||
36
+ input_defined_by_card ||
37
+ send(input_method(default_input_type))
38
+ end
39
+
40
+ def default_input_type
41
+ :rich_text
42
+ end
43
+
44
+ def rich_text_input
45
+ send "#{Cardio.config.rich_text_editor || :text_area}_editor_input"
46
+ end
47
+
48
+ def text_area_input
49
+ text_area :content, rows: 5, class: "d0-card-content",
50
+ "data-card-type-code" => card.type_code
51
+ end
52
+
53
+ def text_field_input
54
+ text_field :content, class: classy("d0-card-content")
55
+ end
56
+ end
@@ -0,0 +1,245 @@
1
+ format :html do
2
+ # FIELDSET VIEWS
3
+
4
+ # sometimes multiple card formgroups, sometimes just one
5
+ view :content_formgroups, cache: :never do
6
+ wrap_with :fieldset, edit_slot, class: classy("card-editor", "editor")
7
+ end
8
+
9
+ view :name_formgroup do
10
+ formgroup "Name", input: "name", help: false do
11
+ raw name_field
12
+ end
13
+ end
14
+
15
+ # single card content formgroup, labeled with "Content"
16
+ view :content_formgroup, unknown: true, cache: :never do
17
+ wrap_content_formgroup { content_field }
18
+ end
19
+
20
+ view :edit_in_form, cache: :never, perms: :update, unknown: true do
21
+ reset_form
22
+ @in_multi_card_editor = true
23
+ edit_slot
24
+ end
25
+
26
+ view :conflict_tracker, cache: :never, unknown: true do
27
+ return unless card&.real?
28
+
29
+ card.last_action_id_before_edit = card.last_action_id
30
+ hidden_field :last_action_id_before_edit, class: "current_revision_id"
31
+ end
32
+
33
+ def wrap_content_formgroup
34
+ formgroup("Content", input: :content, help: false,
35
+ class: classy("card-editor")) { yield }
36
+ end
37
+
38
+ def button_formgroup
39
+ wrap_with :div, class: classy("form-group") do
40
+ wrap_with :div, yield
41
+ end
42
+ end
43
+
44
+ def name_field
45
+ # value needed because otherwise gets wrong value if there are updates
46
+ text_field :name, value: card.name, autocomplete: "off"
47
+ end
48
+
49
+ def content_field
50
+ with_nest_mode :normal do
51
+ # by changing nest mode to normal, we ensure that editors (eg image
52
+ # previews) can render core views.
53
+ output [_render_conflict_tracker, _render_input]
54
+ end
55
+ end
56
+
57
+ # SAMPLE editor view for override
58
+ # view :input do
59
+ # text_area :content, rows: 5, class: "d0-card-content"
60
+ # end
61
+
62
+ def edit_slot
63
+ case
64
+ when inline_nests_editor? then _render_core
65
+ when multi_card_editor? then multi_card_edit(true)
66
+ when in_multi_card_editor? then editor_in_multi_card
67
+ else single_card_edit_field
68
+ end
69
+ end
70
+
71
+ # test: render nests within a normal rendering of the card's content?
72
+ # (as opposed to a standardized form)
73
+ def inline_nests_editor?
74
+ voo.input_type == :inline_nests
75
+ end
76
+
77
+ # test: are we opening a new multi-card form?
78
+ def multi_card_editor?
79
+ voo.structure || voo.edit_structure || # structure configured in voo
80
+ card.structure || # structure in card rule
81
+ edit_fields? # list of fields in card rule
82
+ end
83
+
84
+ # override and return true to optimize
85
+ def edit_fields?
86
+ edit_fields.present?
87
+ end
88
+
89
+ # test: are we already within a multi-card form?
90
+ def in_multi_card_editor?
91
+ @in_multi_card_editor.present?
92
+ end
93
+
94
+ def single_card_edit_field
95
+ if voo.show?(:type_formgroup) || voo.show?(:name_formgroup)
96
+ _render_content_formgroup # use formgroup for consistency
97
+ else
98
+ editor_wrap(:content) { content_field }
99
+ end
100
+ end
101
+
102
+ def editor_in_multi_card
103
+ add_junction_class
104
+ formgroup render_title,
105
+ input: "content", help: true, class: classy("card-editor") do
106
+ [content_field, (form.hidden_field(:type_id) if card.new_card?)]
107
+ end
108
+ end
109
+
110
+ def multi_card_edit fields_only=false
111
+ field_configs = edit_field_configs fields_only
112
+ return structure_link if field_configs.empty?
113
+
114
+ field_configs.map do |name, options|
115
+ nest name, options || {}
116
+ end.join "\n"
117
+ end
118
+
119
+ def structure_link
120
+ # LOCALIZE
121
+ structured = link_to_card card.structure_rule_card, "structured"
122
+ "<label>Content</label>"\
123
+ "<p><em>Uneditable; content is #{structured} without nests</em></p>"
124
+ end
125
+
126
+ # @param [Hash|Array] fields either an array with field names and/or field
127
+ # cards or a hash with the fields as keys and a hash with nest options as
128
+ # values
129
+ def process_edit_fields fields
130
+ fields.map do |field, opts|
131
+ field_nest field, opts
132
+ end.join "\n"
133
+ end
134
+ ###
135
+
136
+ # If you use subfield cards to render a form for a new card
137
+ # then the subfield cards should be created on the new card not the existing
138
+ # card that build the form
139
+
140
+ def form
141
+ @form ||= inherit(:form) || new_form
142
+ end
143
+
144
+ def new_form
145
+ @form_root = true unless parent&.form_root
146
+ instantiate_builder(form_prefix, card, {})
147
+ end
148
+
149
+ def reset_form
150
+ @form = new_form
151
+ end
152
+
153
+ def form_prefix
154
+ case
155
+ when explicit_form_prefix then explicit_form_prefix # configured
156
+ when simple_form? then "card" # simple form
157
+ when parent.card.name == card.name then parent.form_prefix # card nests self
158
+ else edit_in_form_prefix
159
+ end
160
+ end
161
+
162
+ def simple_form?
163
+ form_root? || !form_root || !parent
164
+ end
165
+
166
+ def edit_in_form_prefix
167
+ "#{parent.form_prefix}[subcards][#{card.name.from form_context.card.name}]"
168
+ end
169
+
170
+ def explicit_form_prefix
171
+ inherit :explicit_form_prefix
172
+ end
173
+
174
+ def form_context
175
+ form_root? || !form_root ? self : parent
176
+ end
177
+
178
+ def form_root?
179
+ @form_root == true
180
+ end
181
+
182
+ def form_root
183
+ return self if @form_root
184
+
185
+ parent ? parent.form_root : nil
186
+ end
187
+
188
+ def card_form action, opts={}
189
+ @form_root = true
190
+ hidden = hidden_form_tags action, opts
191
+ form_for card, card_form_opts(action, opts) do |cform|
192
+ @form = cform
193
+ hidden + output(yield(cform))
194
+ end
195
+ end
196
+
197
+ def hidden_form_tags _action, opts
198
+ success = opts.delete :success
199
+ success_tags success
200
+ end
201
+
202
+ # @param action [Symbol] :create or :update
203
+ # @param opts [Hash] html options
204
+ # @option opts [Boolean] :redirect (false) if true form is no "slotter"
205
+ def card_form_opts action, opts={}
206
+ url, action = card_form_url_and_action action
207
+ html_opts = card_form_html_opts action, opts
208
+ form_opts = { url: url, html: html_opts }
209
+ form_opts[:remote] = true unless html_opts.delete(:redirect)
210
+ form_opts
211
+ end
212
+
213
+ def card_form_html_opts action, opts={}
214
+ add_class opts, "card-form"
215
+ add_class opts, "slotter" unless opts[:redirect] || opts[:no_slotter]
216
+ add_class opts, "autosave" if action == :update
217
+ opts
218
+ end
219
+
220
+ def card_form_url_and_action action
221
+ case action
222
+ when Symbol then [path(action: action), action]
223
+ when Hash then [path(action), action[:action]]
224
+ # for when non-action path args are required
225
+ else
226
+ raise Card::Error, "unsupported #card_form_url action: #{action}"
227
+ end
228
+ end
229
+
230
+ def editor_wrap type=nil
231
+ html_class = "editor"
232
+ html_class << " #{type}-editor" if type
233
+ wrap_with :div, class: html_class do
234
+ yield
235
+ end
236
+ end
237
+
238
+ # FIELD VIEWS
239
+
240
+ def add_junction_class
241
+ return unless card.name.junction?
242
+
243
+ class_up "card-editor", "RIGHT-#{card.name.tag_name.safe_key}"
244
+ end
245
+ end