card-mod-edit 0.1

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.
@@ -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