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.
- checksums.yaml +7 -0
- data/lib/javascript/script_rules.js.coffee +23 -0
- data/set/right/self.rb +3 -0
- data/set/right/type_plus_right.rb +4 -0
- data/set/rstar/rule_user.rb +8 -0
- data/set/rule/bar_view.rb +92 -0
- data/set/rule/bridge_rules_editor.rb +28 -0
- data/set/rule/editor.rb +110 -0
- data/set/rule/html_views.rb +13 -0
- data/set/rule/quick_editor.rb +39 -0
- data/set/rule/quick_editor/quick_edit.haml +8 -0
- data/set/rule/quick_editor/set_info.haml +10 -0
- data/set/rule/rule_form.rb +57 -0
- data/set/rule/rule_form/buttons.rb +46 -0
- data/set/rule/rule_form/form_elements.rb +52 -0
- data/set/rule/rule_form/rule_form.haml +20 -0
- data/set/rule/rule_form/rule_set_radio.rb +83 -0
- data/set/rule/rule_form/set_selection.rb +39 -0
- data/set/rule/rules.rb +109 -0
- data/set/self/cardtype.rb +42 -0
- data/set/self/recent_settings.rb +7 -0
- data/set/self/script_rules.rb +3 -0
- data/set/type/set.rb +107 -0
- data/set/type/set/html_views.rb +51 -0
- data/set/type/set/html_views/group_panel.haml +14 -0
- data/set/type/set/html_views/rule_lists.rb +42 -0
- data/set/type/set/html_views/template.rb +12 -0
- data/set/type/set/rules_filter.rb +60 -0
- data/set/type/set/setting_lists.rb +76 -0
- data/set/type/setting.rb +79 -0
- metadata +117 -0
@@ -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
|
data/set/rule/rules.rb
ADDED
@@ -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
|
data/set/type/set.rb
ADDED
@@ -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
|