card 1.93.13 → 1.94.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 +4 -4
- data/VERSION +1 -1
- data/config/initializers/01_core_extensions/persistent_identifiers.rb +8 -0
- data/config/locales/de.yml +1 -0
- data/config/locales/en.yml +1 -0
- data/lib/card.rb +2 -1
- data/lib/card/cache.rb +1 -1
- data/lib/card/content/clean.rb +6 -4
- data/lib/card/format/error.rb +1 -1
- data/lib/card/format/render.rb +1 -1
- data/lib/card/mod.rb +6 -1
- data/lib/card/mod/loader.rb +2 -0
- data/lib/card/name.rb +25 -5
- data/lib/card/query/attributes.rb +13 -8
- data/lib/card/set/event.rb +1 -1
- data/lib/card/tasks/card.rake +12 -0
- data/lib/card/tasks/card/migrate.rake +2 -0
- data/lib/card/view/options.rb +2 -1
- data/lib/cardio.rb +6 -6
- data/lib/cardio/utils.rb +30 -0
- data/mod/account/set/self/signin.rb +3 -13
- data/mod/account/set/type/signup.rb +1 -1
- data/mod/account/spec/set/self/signin_spec.rb +1 -1
- data/mod/basic_formats/set/all/base.rb +11 -3
- data/mod/basic_formats/set/all/json.rb +1 -0
- data/mod/basic_formats/set/self/head.rb +2 -3
- data/mod/bootstrap/db/migrate_core_cards/20170719163733_update_bootswatch_themes_to_4_beta.rb +2 -95
- data/mod/bootstrap/db/migrate_core_cards/lib/skin.rb +94 -0
- data/mod/bootstrap/script/update_skin_thumbnails.rb +9 -0
- data/mod/carrierwave/set/type/image.rb +1 -1
- data/mod/core/chunk/query_reference.rb +9 -2
- data/mod/core/set/all/event_conditions.rb +18 -8
- data/mod/core/set/all/fetch_helper.rb +11 -11
- data/mod/core/set/all/utils.rb +0 -12
- data/mod/core/spec/format/html_format_spec.rb +3 -3
- data/mod/core/spec/set/all/event_conditions_spec.rb +15 -0
- data/mod/core/spec/set/all/name_spec.rb +7 -0
- data/mod/core/spec/set/all/name_validations_spec.rb +0 -10
- data/mod/core/spec/set/all/rename_spec.rb +2 -2
- data/mod/pointer/set/abstract/02_pointer.rb +4 -0
- data/mod/search/set/abstract/00_filter_helper.rb +1 -1
- data/mod/search/set/abstract/02_search_params.rb +18 -0
- data/mod/search/set/abstract/search.rb +1 -1
- data/mod/search/set/self/navbox.rb +2 -2
- data/mod/search/set/self/search.rb +1 -19
- data/mod/search/spec/set/self/search_spec.rb +1 -1
- data/mod/standard/set/all/error.rb +6 -6
- data/mod/standard/set/all/rich_html/content.rb +2 -27
- data/mod/standard/set/all/rich_html/editing.rb +1 -1
- data/mod/standard/set/all/rich_html/title.rb +39 -0
- data/mod/standard/set/all/rich_html/toolbar.rb +1 -1
- data/mod/standard/set/type/cardtype.rb +8 -2
- data/mod/standard/spec/{chunk → content/chunk}/include_spec.rb +5 -5
- data/mod/standard/spec/{chunk → content/chunk}/link_spec.rb +1 -1
- data/mod/standard/spec/{chunk → content/chunk}/query_reference_spec.rb +0 -0
- metadata +11 -7
@@ -23,10 +23,9 @@ format :html do
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def head_title
|
26
|
-
title = root.
|
27
|
-
title = nil if title.blank?
|
26
|
+
title = root.safe_name
|
28
27
|
title = params[:action] if title == "*placeholder"
|
29
|
-
%(<title>#{title ? "#{title} - " : ''}#{Card.global_setting :title}</title>)
|
28
|
+
%(<title>#{title.present? ? "#{title} - " : ''}#{Card.global_setting :title}</title>)
|
30
29
|
end
|
31
30
|
|
32
31
|
def head_buttons
|
data/mod/bootstrap/db/migrate_core_cards/20170719163733_update_bootswatch_themes_to_4_beta.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# -*- encoding : utf-8 -*-
|
2
2
|
|
3
|
+
require_relative "lib/skin"
|
4
|
+
|
3
5
|
class UpdateBootswatchThemesTo4Beta < Card::Migration::Core
|
4
6
|
def up
|
5
7
|
remove_old_stuff
|
@@ -49,101 +51,6 @@ class UpdateBootswatchThemesTo4Beta < Card::Migration::Core
|
|
49
51
|
Card["themeless bootstrap skin"].add_item! name.tr("_", " ")
|
50
52
|
end
|
51
53
|
end
|
52
|
-
|
53
|
-
class Skin
|
54
|
-
include ::Card::Model::SaveHelper
|
55
|
-
|
56
|
-
class << self
|
57
|
-
def vendor_path
|
58
|
-
File.expand_path "../../../vendor", __FILE__
|
59
|
-
end
|
60
|
-
|
61
|
-
def bootstrap_scss_path filename
|
62
|
-
File.join vendor_path, "bootstrap", "scss", "_#{filename}.scss"
|
63
|
-
end
|
64
|
-
|
65
|
-
def themes
|
66
|
-
json = File.read File.join(vendor_path, "bootswatch", "docs", "api", "4.json")
|
67
|
-
JSON.parse(json)["themes"].map { |theme| theme["name"] }
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def initialize theme_name
|
72
|
-
@theme_name = theme_name.downcase
|
73
|
-
@skin_name = "#{theme_name} skin"
|
74
|
-
@skin_codename = @skin_name.downcase.tr(" ", "_")
|
75
|
-
end
|
76
|
-
|
77
|
-
def create_or_update
|
78
|
-
Card.exists?(@skin_name) ? update_skin : create_skin
|
79
|
-
end
|
80
|
-
|
81
|
-
def create_skin
|
82
|
-
Card.create! name: @skin_name,
|
83
|
-
codename: @skin_codename,
|
84
|
-
type_id: Card::SkinID,
|
85
|
-
content: "[[themeless bootstrap skin]]\n[[+bootswatch theme]]",
|
86
|
-
subcards: create_subcard_args
|
87
|
-
end
|
88
|
-
|
89
|
-
def update_skin
|
90
|
-
update_css file_name: "bootstrap.css", field_name: "bootswatch theme"
|
91
|
-
update_tumbnail
|
92
|
-
end
|
93
|
-
|
94
|
-
def update_scss file_name:, field_name: file_name
|
95
|
-
update_card "#{@skin_name}+#{field_name}", style_args(file_name)
|
96
|
-
end
|
97
|
-
|
98
|
-
def update_css file_name:, field_name: file_name
|
99
|
-
ensure_card "#{@skin_name}+#{field_name}", style_args(file_name, Card::CssID)
|
100
|
-
end
|
101
|
-
|
102
|
-
def update_tumbnail
|
103
|
-
update_card "#{@skin_name}+Image", thumbnail_args
|
104
|
-
end
|
105
|
-
|
106
|
-
private
|
107
|
-
|
108
|
-
def create_subcard_args
|
109
|
-
{
|
110
|
-
"+bootswatch theme" => style_args("bootstrap.css", Card::CssID),
|
111
|
-
"+Image" => thumbnail_args
|
112
|
-
}
|
113
|
-
end
|
114
|
-
|
115
|
-
def style_args file_name, type_id=Card::ScssID
|
116
|
-
paths = Array.wrap(file_name).map { |fn| resource_path(fn) }
|
117
|
-
content = paths.map { |p| File.read(p) }.join "\n"
|
118
|
-
{ type_id: type_id, content: content }
|
119
|
-
end
|
120
|
-
|
121
|
-
def thumbnail_args
|
122
|
-
{
|
123
|
-
codename: "#{@skin_codename}_image",
|
124
|
-
type_id: Card::ImageID,
|
125
|
-
mod: :bootstrap, storage_type: :coded,
|
126
|
-
image: File.open(thumbnail_path)
|
127
|
-
}
|
128
|
-
end
|
129
|
-
|
130
|
-
def resource_path resource
|
131
|
-
resource = "_#{resource}.scss" unless resource.include? "."
|
132
|
-
if resource.include? File::SEPARATOR
|
133
|
-
resource
|
134
|
-
else
|
135
|
-
File.join base_resource_dir, resource
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
def thumbnail_path
|
140
|
-
File.join Skin.vendor_path, "bootswatch", "docs", @theme_name, "thumbnail.png"
|
141
|
-
end
|
142
|
-
|
143
|
-
def base_resource_dir
|
144
|
-
File.join Skin.vendor_path, "bootswatch", "dist", @theme_name
|
145
|
-
end
|
146
|
-
end
|
147
54
|
end
|
148
55
|
|
149
56
|
|
@@ -0,0 +1,94 @@
|
|
1
|
+
# Update or create a bootstrap skin
|
2
|
+
class Skin
|
3
|
+
include ::Card::Model::SaveHelper
|
4
|
+
|
5
|
+
class << self
|
6
|
+
def vendor_path
|
7
|
+
File.expand_path "../../../../vendor", __FILE__
|
8
|
+
end
|
9
|
+
|
10
|
+
def bootstrap_scss_path filename
|
11
|
+
File.join vendor_path, "bootstrap", "scss", "_#{filename}.scss"
|
12
|
+
end
|
13
|
+
|
14
|
+
def themes
|
15
|
+
json = File.read File.join(vendor_path, "bootswatch", "docs", "api", "4.json")
|
16
|
+
JSON.parse(json)["themes"].map { |theme| theme["name"] }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize theme_name
|
21
|
+
@theme_name = theme_name.downcase
|
22
|
+
@skin_name = "#{theme_name} skin"
|
23
|
+
@skin_codename = @skin_name.downcase.tr(" ", "_")
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_or_update
|
27
|
+
Card.exists?(@skin_name) ? update_skin : create_skin
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_skin
|
31
|
+
Card.create! name: @skin_name,
|
32
|
+
codename: @skin_codename,
|
33
|
+
type_id: Card::SkinID,
|
34
|
+
content: "[[themeless bootstrap skin]]\n[[+bootswatch theme]]",
|
35
|
+
subcards: create_subcard_args
|
36
|
+
end
|
37
|
+
|
38
|
+
def update_skin
|
39
|
+
update_css file_name: "bootstrap.css", field_name: "bootswatch theme"
|
40
|
+
# don't update thumbnails since they are stored as coded files in the gem
|
41
|
+
# there's a script for doing that
|
42
|
+
# update_tumbnail
|
43
|
+
end
|
44
|
+
|
45
|
+
def update_scss file_name:, field_name: file_name
|
46
|
+
update_card "#{@skin_name}+#{field_name}", style_args(file_name)
|
47
|
+
end
|
48
|
+
|
49
|
+
def update_css file_name:, field_name: file_name
|
50
|
+
ensure_card "#{@skin_name}+#{field_name}", style_args(file_name, Card::CssID)
|
51
|
+
end
|
52
|
+
|
53
|
+
def update_thumbnail
|
54
|
+
update_card "#{@skin_name}+Image", thumbnail_args
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def create_subcard_args
|
60
|
+
{ "+bootswatch theme" => style_args("bootstrap.css", Card::CssID) }
|
61
|
+
end
|
62
|
+
|
63
|
+
def style_args file_name, type_id=Card::ScssID
|
64
|
+
paths = Array.wrap(file_name).map { |fn| resource_path(fn) }
|
65
|
+
content = paths.map { |p| File.read(p) }.join "\n"
|
66
|
+
{ type_id: type_id, content: content }
|
67
|
+
end
|
68
|
+
|
69
|
+
def thumbnail_args
|
70
|
+
{
|
71
|
+
codename: "#{@skin_codename}_image",
|
72
|
+
type_id: Card::ImageID,
|
73
|
+
mod: :bootstrap, storage_type: :coded,
|
74
|
+
image: File.open(thumbnail_path)
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def resource_path resource
|
79
|
+
resource = "_#{resource}.scss" unless resource.include? "."
|
80
|
+
if resource.include? File::SEPARATOR
|
81
|
+
resource
|
82
|
+
else
|
83
|
+
File.join base_resource_dir, resource
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def thumbnail_path
|
88
|
+
File.join Skin.vendor_path, "bootswatch", "docs", @theme_name, "thumbnail.png"
|
89
|
+
end
|
90
|
+
|
91
|
+
def base_resource_dir
|
92
|
+
File.join Skin.vendor_path, "bootswatch", "dist", @theme_name
|
93
|
+
end
|
94
|
+
end
|
@@ -63,7 +63,7 @@ format :html do
|
|
63
63
|
if source.blank? || source == "missing"
|
64
64
|
# FIXME - these images should be "broken", not "missing"
|
65
65
|
# ("missing" is the view for "unknown" now, so we shouldn't further confuse things)
|
66
|
-
"<!-- image missing #{
|
66
|
+
"<!-- image missing #{safe_name} -->"
|
67
67
|
else
|
68
68
|
image_tag source
|
69
69
|
end
|
@@ -23,7 +23,7 @@ module Card::Content::Chunk
|
|
23
23
|
Card::Query::ATTRIBUTES.keys +
|
24
24
|
Card::Query::CONJUNCTIONS.keys +
|
25
25
|
%w[desc asc count]
|
26
|
-
).map(&:
|
26
|
+
).map(&:to_s)
|
27
27
|
)
|
28
28
|
|
29
29
|
Card::Content::Chunk.register_class(
|
@@ -53,10 +53,17 @@ module Card::Content::Chunk
|
|
53
53
|
|
54
54
|
class << self
|
55
55
|
def full_match content, prefix
|
56
|
+
# matches cardnames that are not keywords
|
57
|
+
# FIXME: would not match cardnames that are keywords
|
56
58
|
match, offset = super(content, prefix)
|
57
|
-
return
|
59
|
+
return if !match || keyword?(match[1])
|
58
60
|
[match, offset]
|
59
61
|
end
|
62
|
+
|
63
|
+
def keyword? str
|
64
|
+
return unless str
|
65
|
+
QUERY_KEYWORDS.include?(str.tr(" ", "_").downcase)
|
66
|
+
end
|
60
67
|
end
|
61
68
|
|
62
69
|
def interpret match, _content
|
@@ -1,30 +1,30 @@
|
|
1
|
-
EVENT_CONDITIONS = %i[set on changed when].freeze
|
1
|
+
EVENT_CONDITIONS = %i[set on changed when optional].freeze
|
2
2
|
|
3
|
-
def event_applies? opts
|
3
|
+
def event_applies? event, opts
|
4
4
|
EVENT_CONDITIONS.all? do |key|
|
5
|
-
send "#{key}_condition_applies?", opts[key]
|
5
|
+
send "#{key}_condition_applies?", event, opts[key]
|
6
6
|
end
|
7
7
|
end
|
8
8
|
|
9
9
|
private
|
10
10
|
|
11
|
-
def set_condition_applies? set_module
|
11
|
+
def set_condition_applies? _event, set_module
|
12
12
|
singleton_class.include?(set_module)
|
13
13
|
end
|
14
14
|
|
15
|
-
def on_condition_applies? actions
|
15
|
+
def on_condition_applies? _event, actions
|
16
16
|
actions = Array(actions).compact
|
17
17
|
return true if actions.empty?
|
18
18
|
actions.include? @action
|
19
19
|
end
|
20
20
|
|
21
|
-
def changed_condition_applies? db_columns
|
21
|
+
def changed_condition_applies? _event, db_columns
|
22
22
|
db_columns = Array(db_columns).compact
|
23
23
|
return true if db_columns.empty?
|
24
24
|
db_columns.any? { |col| single_changed_condition_applies? col }
|
25
25
|
end
|
26
26
|
|
27
|
-
def when_condition_applies? block
|
27
|
+
def when_condition_applies? _event, block
|
28
28
|
case block
|
29
29
|
when Proc then block.call(self)
|
30
30
|
when Symbol then send block
|
@@ -32,6 +32,11 @@ def when_condition_applies? block
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
+
def optional_condition_applies? event, optional
|
36
|
+
return true unless optional
|
37
|
+
skip_event? event
|
38
|
+
end
|
39
|
+
|
35
40
|
def single_changed_condition_applies? db_column
|
36
41
|
return true unless db_column
|
37
42
|
db_column =
|
@@ -53,6 +58,11 @@ def wrong_stage opts
|
|
53
58
|
end
|
54
59
|
|
55
60
|
def wrong_action action
|
56
|
-
return false if on_condition_applies? action
|
61
|
+
return false if on_condition_applies?(nil, action)
|
57
62
|
"on: #{action} method #{method} called on #{@action}"
|
58
63
|
end
|
64
|
+
|
65
|
+
def skip_event? event
|
66
|
+
@names_of_skipped_events ||= ::Set.new(Array.wrap(skip_event).map(&:to_sym))
|
67
|
+
!@names_of_skipped_events.include? event
|
68
|
+
end
|
@@ -13,6 +13,16 @@ module ClassMethods
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
def safe_param param
|
17
|
+
if param.respond_to? :to_unsafe_h
|
18
|
+
# clone doesn't work for Parameters
|
19
|
+
param.to_unsafe_h
|
20
|
+
else
|
21
|
+
# clone so that original params remain unaltered. need deeper clone?
|
22
|
+
(param || {}).clone
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
16
26
|
private
|
17
27
|
|
18
28
|
def standard_controller_fetch args, card_opts
|
@@ -23,23 +33,13 @@ module ClassMethods
|
|
23
33
|
end
|
24
34
|
|
25
35
|
def controller_fetch_opts args
|
26
|
-
opts =
|
36
|
+
opts = safe_param args[:card]
|
27
37
|
opts[:type] ||= args[:type] if args[:type]
|
28
38
|
# for /new/:type shortcut. we should handle in routing and deprecate this
|
29
39
|
opts[:name] ||= Card::Name.url_key_to_standard(args[:id])
|
30
40
|
opts
|
31
41
|
end
|
32
42
|
|
33
|
-
def safe_card_opts card_opts
|
34
|
-
if card_opts.respond_to? :to_unsafe_h
|
35
|
-
# clone doesn't work for Parameters
|
36
|
-
card_opts.to_unsafe_h
|
37
|
-
else
|
38
|
-
# clone so that original params remain unaltered. need deeper clone?
|
39
|
-
(card_opts || {}).clone
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
43
|
def validate_fetch_opts! opts
|
44
44
|
return unless opts[:new] && opts[:skip_virtual]
|
45
45
|
raise Card::Error, "fetch called with new args and skip_virtual"
|
data/mod/core/set/all/utils.rb
CHANGED
@@ -1,12 +1,4 @@
|
|
1
1
|
module ClassMethods
|
2
|
-
def delete_tmp_files id=nil
|
3
|
-
dir = Cardio.paths["files"].existent.first + "/tmp"
|
4
|
-
dir += "/#{id}" if id
|
5
|
-
FileUtils.rm_rf dir, secure: true
|
6
|
-
rescue
|
7
|
-
Rails.logger.info "failed to remove tmp files"
|
8
|
-
end
|
9
|
-
|
10
2
|
def merge_list attribs, opts={}
|
11
3
|
unmerged = []
|
12
4
|
attribs.each do |row|
|
@@ -49,8 +41,4 @@ module ClassMethods
|
|
49
41
|
card.update_attributes! attribs
|
50
42
|
end
|
51
43
|
end
|
52
|
-
|
53
|
-
def seed_test_db
|
54
|
-
system "env RAILS_ENV=test bundle exec rake db:fixtures:load"
|
55
|
-
end
|
56
44
|
end
|
@@ -32,10 +32,10 @@ RSpec.describe Card::Format::HtmlFormat do
|
|
32
32
|
|
33
33
|
it "renders top menu" do
|
34
34
|
is_expected.to have_tag "header" do
|
35
|
-
with_tag 'a.nav-link.internal-link[href="
|
36
|
-
with_tag 'a.nav-link.internal-link[href="
|
35
|
+
with_tag 'a.nav-link.internal-link[href=""]', text: "Home"
|
36
|
+
with_tag 'a.nav-link.internal-link[href=":recent"]', text: "Recent"
|
37
37
|
with_tag 'form.navbox-form[action="/*search"]' do
|
38
|
-
with_tag 'input[name="
|
38
|
+
with_tag 'input[name="query[keyword]"]'
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
@@ -50,5 +50,20 @@ describe Card::Set::All::EventConditions, "event" do
|
|
50
50
|
expect(@log).to contain_exactly(*content_before_change)
|
51
51
|
end
|
52
52
|
end
|
53
|
+
|
54
|
+
specify "skip event condition" do
|
55
|
+
with_test_events do
|
56
|
+
test_event :validate, on: :update, optional: true, for: "A" do
|
57
|
+
add_to_log "not skipped"
|
58
|
+
end
|
59
|
+
Card["A"].update_attributes! content: "changed content", skip_event: :test_event_0
|
60
|
+
|
61
|
+
aggregate_failures do
|
62
|
+
expect(@log).to be_empty
|
63
|
+
Card["A"].update_attributes! content: "changed content"
|
64
|
+
expect(@log).to contain_exactly "not skipped"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
53
68
|
end
|
54
69
|
end
|
@@ -57,6 +57,13 @@ describe Card::Set::All::Name do
|
|
57
57
|
end
|
58
58
|
end
|
59
59
|
|
60
|
+
describe "event: escape_name" do
|
61
|
+
it "escapes invalid characters" do
|
62
|
+
c = Card.create! name: "8 / 5 <script>"
|
63
|
+
expect(c.name).to eq("8 / 5 <script>")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
60
67
|
describe "codename" do
|
61
68
|
before do
|
62
69
|
@card = Card["a"]
|