card-mod-rules 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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