card-mod-rules 0.11.0

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,52 @@
1
+ format :html do
2
+ #### DEPRECATED
3
+
4
+ def rule_set_selection
5
+ wrap_with :div, class: "set-list" do
6
+ [rule_set_formgroup, related_set_formgroup]
7
+ end
8
+ end
9
+
10
+ def rule_set_formgroup
11
+ tag = @rule_context.rule_user_setting_name
12
+ narrower = []
13
+ option_list "Set" do
14
+ rule_set_options.map do |set_name, state|
15
+ rule_set_radio_button set_name, tag, state, narrower
16
+ end
17
+ end
18
+ end
19
+
20
+ def related_set_formgroup
21
+ related_sets = related_sets_in_context
22
+ return "" unless related_sets&.present?
23
+
24
+ tag = @rule_context.rule_user_setting_name
25
+ option_list "related set" do
26
+ related_rule_radios related_sets, tag
27
+ end
28
+ end
29
+
30
+ def related_sets_in_context
31
+ set_context = @rule_context.rule_set_name
32
+ set_context && Card.fetch(set_context).prototype.related_sets
33
+ end
34
+
35
+ def option_list title
36
+ formgroup title, input: "set", class: "col-xs-6", help: false do
37
+ wrap_with :ul do
38
+ wrap_each_with(:li, class: "radio") { yield }
39
+ end
40
+ end
41
+ end
42
+
43
+ def related_rule_radios related_sets, tag
44
+ related_sets.map do |set_name, _label|
45
+ rule_name = "#{set_name}+#{tag}"
46
+ state = Card.exists?(rule_name) ? :exists : nil
47
+ rule_radio set_name, state do
48
+ radio_button :name, rule_name
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,20 @@
1
+ .guide-line.rule-section.mt-4
2
+ %h5
3
+ .guide-line-number 1
4
+ Define rule
5
+ -# = popover_link "Help text to explain this section"
6
+ .card-editor
7
+ = rules_type_formgroup
8
+ = rule_content_formgroup
9
+ .rule-section
10
+ %h5
11
+ .guide-line-number 2
12
+ Apply to set
13
+ = popover_link "Each rule applies to a set of cards. Rules for more specific sets override rules for more general ones."
14
+ .card-editor
15
+ = bridge_rule_set_selection
16
+ = edit_rule_buttons
17
+
18
+ -##app-5
19
+ -# %p {{ message }}
20
+ -# %button{'v-on:click': 'reverseMessage'} Reverse Message
@@ -0,0 +1,83 @@
1
+ #! no set module
2
+ class RuleSetRadio
3
+ attr_reader :format
4
+ delegate :link_to_card, :radio_button, :wrap_with, :icon_tag,
5
+ to: :format
6
+
7
+ # @param state [:current, :overwritten]
8
+ def initialize format, set_name, tag, state
9
+ @format = format
10
+ @card = format.card
11
+ @set_name = set_name
12
+ @tag = tag
13
+ @state = state
14
+ end
15
+
16
+ def html narrower
17
+ @narrower_rules = narrower
18
+
19
+ rule_radio do
20
+ radio_text = "#{@set_name}+#{@tag}"
21
+ radio_button :name, radio_text, checked: false, warning: warning
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def current?
28
+ @state == :current
29
+ end
30
+
31
+ def overwritten?
32
+ @state == :overwritten
33
+ end
34
+
35
+ def rule_radio
36
+ label_classes = ["set-label", ("current-set-label" if current?)]
37
+ icon = icon_tag "open_in_new", "link-muted"
38
+ wrap_with :label, class: label_classes.compact.join(" ") do
39
+ [yield, label, link_to_card(@set_name, icon, target: "decko_set")]
40
+ end
41
+ end
42
+
43
+ def label
44
+ label = Card.fetch(@set_name).label
45
+ label += " <em>#{extra_info}</em>".html_safe if extra_info
46
+ label
47
+ end
48
+
49
+ def extra_info
50
+ case @state
51
+ when :current
52
+ "(current)"
53
+ when :overwritten, :exists
54
+ link_to_card "#{@set_name}+#{@card.rule_user_setting_name}", "(#{@state})",
55
+ target: "_blank"
56
+ end
57
+ end
58
+
59
+ def warning
60
+ if @set_name == "*all"
61
+ "This rule will affect all cards! Are you sure?"
62
+ else
63
+ narrower_warning
64
+ end
65
+ end
66
+
67
+ # warn user if rule change won't have a effect on the current card
68
+ # because there is a narrower rule
69
+ def narrower_warning
70
+ return unless @state.in? %i[current overwritten]
71
+
72
+ @narrower_rules << Card.fetch(@set_name).uncapitalized_label
73
+ return unless @state == :overwritten
74
+
75
+ narrower_warning_message
76
+ end
77
+
78
+ def narrower_warning_message
79
+ plural = @narrower_rules.size > 1 ? "s" : ""
80
+ "This rule will not have any effect on this card unless you delete " \
81
+ "the narrower rule#{plural} for #{@narrower_rules.to_sentence}."
82
+ end
83
+ end
@@ -0,0 +1,39 @@
1
+ format :html do
2
+ def bridge_rule_set_selection
3
+ wrap_with :div, class: "set-list" do
4
+ bridge_rule_set_formgroup
5
+ end
6
+ end
7
+
8
+ def bridge_rule_set_formgroup
9
+ tag = @rule_context.rule_user_setting_name
10
+ narrower = []
11
+
12
+ bridge_option_list "Set" do
13
+ rule_set_options.map do |set_name, state|
14
+ RuleSetRadio.new(self, set_name, tag, state).html narrower
15
+ end
16
+ end
17
+ end
18
+
19
+ def bridge_option_list title
20
+ index = -1
21
+ formgroup title, input: "set", class: "col-xs-6", help: false do
22
+ yield.inject("") do |res, radio|
23
+ index += 1
24
+ # TODO
25
+ if false # index.in? [2,3]
26
+ wrap_with(:li, radio, class: "radio") + res
27
+ else
28
+ wrap_with :ul do
29
+ wrap_with(:li, (radio + res), class: "radio")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ def rule_set_options
37
+ @rule_set_options ||= @rule_context.set_options
38
+ end
39
+ end
@@ -0,0 +1,109 @@
1
+ event :save_recently_edited_settings, :integrate, on: :save, changed: %i[type content] do
2
+ if (recent = Card[:recent_settings])
3
+ recent.insert_item 0, name.right
4
+ attach_subcard recent
5
+ end
6
+ end
7
+
8
+ def rule_set_key
9
+ rule_set_name.key
10
+ end
11
+
12
+ def rule_set_name
13
+ if is_preference?
14
+ name.trunk_name.trunk_name
15
+ else
16
+ name.trunk_name
17
+ end
18
+ end
19
+
20
+ def rule_set_pattern_name
21
+ rule_set_name.tag_name
22
+ end
23
+
24
+ def rule_set
25
+ if is_preference?
26
+ self[0..-3]
27
+ else
28
+ trunk
29
+ end
30
+ end
31
+
32
+ def rule_setting
33
+ right
34
+ end
35
+
36
+ def rule_setting_name
37
+ name.tag
38
+ end
39
+
40
+ def short_help_text
41
+ Card[rule_setting_name].short_help_text
42
+ end
43
+
44
+ def rule_setting_title
45
+ rule_setting_name.tr "*", ""
46
+ end
47
+
48
+ def rule_user_setting_name
49
+ if is_preference?
50
+ "#{rule_user_name}+#{rule_setting_name}"
51
+ else
52
+ rule_setting_name
53
+ end
54
+ end
55
+
56
+ # ~~~~~~~~~~ determine the set options to which a user can apply the rule.
57
+ def set_options
58
+ @set_options ||= [].tap do |set_options|
59
+ set_option_candidates.each do |set_name|
60
+ set_options << [set_name, state_of_set(set_name)]
61
+ end
62
+ end
63
+ end
64
+
65
+ # the narrowest rule should be the one attached to the set being viewed.
66
+ # So, eg, if you're looking at the '*all plus' set, you shouldn't
67
+ # have the option to create rules based on arbitrary narrower sets, though
68
+ # narrower sets will always apply to whatever prototype we create
69
+ def first_set_option_index candidates
70
+ new_card? ? 0 : candidates.index { |c| c.to_name.key == rule_set_key }
71
+ end
72
+
73
+ def set_prototype
74
+ if is_preference?
75
+ self[0..-3].prototype
76
+ else
77
+ trunk.prototype
78
+ end
79
+ end
80
+
81
+ private
82
+
83
+ def set_option_candidates
84
+ candidates = set_prototype.set_names
85
+ first = first_set_option_index candidates
86
+ candidates[first..-1]
87
+ end
88
+
89
+ def state_of_set set_name
90
+ @sets_with_existing_rules ||= 0
91
+ if rule_for_set? set_name
92
+ @sets_with_existing_rules += 1
93
+ state_of_existing_set
94
+ else
95
+ state_of_nonexisting_set
96
+ end
97
+ end
98
+
99
+ def state_of_existing_set
100
+ @sets_with_existing_rules == 1 ? :current : :overwritten
101
+ end
102
+
103
+ def state_of_nonexisting_set
104
+ @sets_with_existing_rules == 1 ? :current : :overwritten
105
+ end
106
+
107
+ def rule_for_set? set_name
108
+ Card.exists?("#{set_name}+#{rule_user_setting_name}")
109
+ end
@@ -0,0 +1,42 @@
1
+ GROUP = {
2
+ "Text" => %w[RichText PlainText Markdown Phrase HTML],
3
+ "Data" => %w[Number Toggle Date URI],
4
+ "Upload" => %w[File Image],
5
+ "Custom" => [],
6
+ "Organize" => ["List", "Pointer", "Search", "Link list", "Nest list"],
7
+ "Template" => ["Notification template", "Email template", "Twitter template"],
8
+ "Admin" => ["Cardtype", "User", "Role", "Sign up", "Session", "Set", "Setting"],
9
+ "Styling" => ["Layout", "Skin", "Bootswatch skin", "Customized bootswatch skin",
10
+ "CSS", "SCSS"],
11
+ "Scripting" => %w[JSON JavaScript CoffeeScript]
12
+ }.freeze
13
+
14
+ # DEFAULT_RULE_GROUPS = ["Text", "Data", "Upload", "Organize - Search"]
15
+ # STRUCTURE_RULE_GROUPS = ["Text", "Organize > Search"]
16
+
17
+ # group for each cardtype: { "RichText => "Content", "Layout" => "Admin", ... }
18
+ GROUP_MAP = GROUP.each_with_object({}) do |(cat, types), h|
19
+ types.each { |t| h[t] = cat }
20
+ end
21
+
22
+ format :html do
23
+ view :grouped_list do
24
+ GROUP.keys.map do |group|
25
+ type_list = group == "Custom" ? custom_types : GROUP[group]
26
+ next if type_list.empty?
27
+
28
+ [wrap_with(:h5, group), wrap_with(:p, listing(type_list))]
29
+ end.flatten.join "\n"
30
+ end
31
+
32
+ def custom_types
33
+ custom_types = []
34
+
35
+ Card.search(type_id: Card::CardtypeID, return: "name").each do |name|
36
+ next if ::Card::Set::Self::Cardtype::GROUP_MAP[name]
37
+
38
+ custom_types << name
39
+ end
40
+ custom_types
41
+ end
42
+ end
@@ -0,0 +1,7 @@
1
+ def history?
2
+ false
3
+ end
4
+
5
+ def followable?
6
+ false
7
+ end
@@ -0,0 +1,3 @@
1
+ include_set Abstract::CodeFile
2
+
3
+ Self::ScriptMods.add_item :script_rules
@@ -0,0 +1,107 @@
1
+ include_set Type::SearchType
2
+
3
+ def anchor_name
4
+ name.left_name
5
+ end
6
+
7
+ def anchor
8
+ Card[anchor_name]
9
+ end
10
+
11
+ def pattern_name
12
+ name.tag_name
13
+ end
14
+
15
+ def pattern
16
+ tag
17
+ end
18
+
19
+ def inheritable?
20
+ junction_only? || (anchor_name&.junction? && self_set?)
21
+ end
22
+
23
+ def self_set?
24
+ pattern_name == Card::Set::Self.pattern.key
25
+ end
26
+
27
+ def subclass_for_set
28
+ current_set_pattern_code = pattern.codename
29
+ Card.set_patterns.find { |set| set.pattern_code == current_set_pattern_code }
30
+ end
31
+
32
+ def junction_only?
33
+ @junction_only.nil? ? (@junction_only = subclass_for_set.junction_only) : @junction_only
34
+ end
35
+
36
+ def label
37
+ klass = subclass_for_set
38
+ klass ? klass.label(anchor_name) : ""
39
+ end
40
+
41
+ def uncapitalized_label
42
+ label = label.to_s
43
+ return label unless label[0]
44
+
45
+ label[0] = label[0].downcase
46
+ label
47
+ end
48
+
49
+ def rule_cache_key_base
50
+ if (l = left) && (r = right)
51
+ "#{l.id}+#{Codename[r.id]}"
52
+ else
53
+ Codename[id].to_s
54
+ end
55
+ end
56
+
57
+ def all_user_ids_with_rule_for setting_code
58
+ Card::Rule.all_user_ids_with_rule_for self, setting_code
59
+ end
60
+
61
+ def setting_codenames_by_group
62
+ result = {}
63
+ Card::Setting.groups.each do |group, settings|
64
+ visible_settings =
65
+ settings.reject { |s| !s || !s.applies_to_cardtype(prototype.type_id) }
66
+ result[group] = visible_settings.map(&:codename) unless visible_settings.empty?
67
+ end
68
+ result
69
+ end
70
+
71
+ def visible_setting_codenames
72
+ @visible_setting_codenames ||= visible_settings.map(&:codename)
73
+ end
74
+
75
+ def visible_settings group=nil, cardtype_id=nil
76
+ cardtype_id ||= prototype.type_id
77
+ settings =
78
+ (group && Card::Setting.groups[group]) || Card::Setting.groups.values.flatten.compact
79
+ settings.reject do |setting|
80
+ !setting || !setting.applies_to_cardtype(cardtype_id)
81
+ end
82
+ end
83
+
84
+ def broader_sets
85
+ prototype.set_names[1..-1]
86
+ end
87
+
88
+ def prototype
89
+ opts = subclass_for_set.prototype_args anchor_name
90
+ Card.fetch opts[:name], new: opts
91
+ end
92
+
93
+ def prototype_default_type_id
94
+ prototype_default_card.type_id
95
+ end
96
+
97
+ def prototype_default_card
98
+ prototype.rule_card(:default)
99
+ end
100
+
101
+ def related_sets with_self=false
102
+ if subclass_for_set.anchorless?
103
+ prototype.related_sets with_self
104
+ else
105
+ left(new: {}).related_sets with_self
106
+ end
107
+ end