card 1.19.4 → 1.19.5
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/VERSION +1 -1
- data/config/initializers/01_core_extensions/module.rb +4 -0
- data/lib/card.rb +2 -2
- data/lib/card/content/diff/lcs.rb +1 -1
- data/lib/card/model/save_helper.rb +100 -25
- data/lib/card/name.rb +8 -0
- data/lib/card/set/event.rb +22 -42
- data/lib/card/set/format.rb +1 -0
- data/lib/card/set/inheritance.rb +30 -5
- data/lib/card/set/loader.rb +24 -3
- data/mod/account/set/self/account_links.rb +45 -21
- data/mod/account/set/self/signin.rb +5 -9
- data/mod/account/set/type/signup.rb +22 -15
- data/mod/account/spec/set/all/account_spec.rb +3 -1
- data/mod/admin/set/self/admin.rb +4 -4
- data/mod/admin/set/self/admin_info.rb +3 -9
- data/mod/admin/set/self/trash.rb +21 -14
- data/mod/basic_formats/set/all/base.rb +6 -7
- data/mod/bootstrap/set/all/bootstrap/helper.rb +4 -5
- data/mod/bootstrap/set/all/bootstrap/tabs.rb +3 -4
- data/mod/bootstrap/spec/set/all/bootstrap/form_spec.rb +2 -0
- data/mod/carrierwave/set/abstract/attachment/storage_type.rb +3 -0
- data/mod/core/chunk/link.rb +3 -3
- data/mod/core/chunk/uri.rb +2 -2
- data/mod/core/set/all/actify.rb +11 -10
- data/mod/core/set/all/permissions.rb +6 -7
- data/mod/core/spec/set/all/actify_spec.rb +2 -0
- data/mod/developer/set/right/debug.rb +1 -1
- data/mod/email/set/all/follow.rb +2 -1
- data/mod/email/set/right/follow.rb +19 -22
- data/mod/email/set/type_plus_right/user/follow.rb +1 -1
- data/mod/email/spec/set/all/notify_spec.rb +17 -14
- data/mod/history/set/all/history.rb +35 -38
- data/mod/machines/spec/set/abstract/machine_spec.rb +2 -0
- data/mod/settings/set/abstract/permission.rb +6 -9
- data/mod/settings/set/type/setting.rb +4 -3
- data/mod/solid_cache/set/abstract/solid_cache.rb +41 -20
- data/mod/solid_cache/spec/set/abstract/solid_cache_spec.rb +3 -1
- data/mod/standard/set/all/error.rb +14 -19
- data/mod/standard/set/all/links.rb +149 -120
- data/mod/standard/set/all/rich_html/content.rb +9 -19
- data/mod/standard/set/all/rich_html/header.rb +3 -5
- data/mod/standard/set/all/rich_html/menu.rb +25 -23
- data/mod/standard/set/all/rich_html/modal.rb +11 -9
- data/mod/standard/set/all/rich_html/toolbar.rb +85 -84
- data/mod/standard/set/rstar/rules_editor.rb +96 -79
- data/mod/standard/set/type/cardtype.rb +2 -1
- data/mod/standard/set/type/search_type.rb +2 -1
- data/mod/standard/set/type/set.rb +15 -19
- data/mod/standard/set/type/uri.rb +2 -2
- data/mod/standard/spec/set/all/links_spec.rb +8 -5
- data/spec/config/initializers/core_extensions_spec.rb +2 -0
- data/spec/lib/card/format/nest_spec.rb +2 -0
- data/spec/lib/card/migration/import_spec.rb +2 -0
- data/spec/lib/card/set/trait_spec.rb +2 -0
- data/spec/lib/card/stage_director_spec.rb +2 -0
- data/spec/lib/card/view_cache_spec.rb +2 -0
- data/spec/spec_helper.rb +11 -139
- data/spec/support/card_spec_helper.rb +61 -0
- data/spec/support/card_spec_loader.rb +83 -0
- data/spec/support/helper/card_helper.rb +87 -0
- data/spec/support/helper/event_helper.rb +80 -0
- data/spec/support/helper/render_helper.rb +35 -0
- data/spec/support/helper/save_helper.rb +26 -0
- data/{config → spec/support}/simplecov_helper.rb +1 -1
- metadata +16 -5
- data/spec/card_spec_helper.rb +0 -137
@@ -123,8 +123,8 @@ describe Card::Set::All::Notify do
|
|
123
123
|
context "and missing permissions" do
|
124
124
|
context "for subcard" do
|
125
125
|
before do
|
126
|
-
|
127
|
-
|
126
|
+
create_or_update! "#{name}+s1+*self+*read",
|
127
|
+
type: "Pointer", content: "[[Administrator]]"
|
128
128
|
end
|
129
129
|
it "excludes subcard content" do
|
130
130
|
is_expected.not_to include sub1_content
|
@@ -142,10 +142,10 @@ describe Card::Set::All::Notify do
|
|
142
142
|
).text_part.body.raw_source
|
143
143
|
end
|
144
144
|
before do
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
145
|
+
create_or_update! "#{name}+*self+*read",
|
146
|
+
type: "Pointer", content: "[[Administrator]]"
|
147
|
+
create_or_update! "#{name}+s1+*self+*read",
|
148
|
+
type: "Pointer", content: "[[Anyone]]"
|
149
149
|
end
|
150
150
|
it "includes subcard content" do
|
151
151
|
is_expected.to include sub1_content
|
@@ -157,18 +157,18 @@ describe Card::Set::All::Notify do
|
|
157
157
|
end
|
158
158
|
context "for all parts" do
|
159
159
|
before do
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
160
|
+
create_or_update! "#{name}+s1+*self+*read",
|
161
|
+
type: "Pointer", content: "[[Administrator]]"
|
162
|
+
create_or_update! "#{name}+s2+*self+*read",
|
163
|
+
type: "Pointer", content: "[[Administrator]]"
|
164
|
+
create_or_update! "#{name}+*self+*read",
|
165
|
+
type: "Pointer", content: "[[Administrator]]"
|
166
166
|
end
|
167
167
|
it { is_expected.not_to include content }
|
168
168
|
it { is_expected.not_to include sub1_content }
|
169
169
|
it { is_expected.not_to include sub2_content }
|
170
170
|
it "will not be send" do
|
171
|
-
expect(Card["Joe User"].account.changes_visible?
|
171
|
+
expect(Card["Joe User"].account.changes_visible?(@card.acts.last))
|
172
172
|
.to be_falsey
|
173
173
|
end
|
174
174
|
end
|
@@ -204,6 +204,9 @@ describe Card::Set::All::Notify do
|
|
204
204
|
followed_set: "#{@card.name}+*self",
|
205
205
|
follow_option: "*always"
|
206
206
|
).text_part.body.raw_source
|
207
|
+
unfollow_link =
|
208
|
+
"/update/Joe_User+*follow?card%5Bsubcards%5D%5Banother+"\
|
209
|
+
"card+with+subcards%2B%2Aself%2BJoe+User%2B%2Afollow%5D=%2Anever"
|
207
210
|
expect(result)
|
208
211
|
.to eq(%("another card with subcards" was just created by Joe User.
|
209
212
|
|
@@ -230,7 +233,7 @@ See the card: /another_card_with_subcards
|
|
230
233
|
|
231
234
|
You received this email because you're following "another card with subcards".
|
232
235
|
|
233
|
-
Use this link to unfollow
|
236
|
+
Use this link to unfollow #{unfollow_link}
|
234
237
|
))
|
235
238
|
end
|
236
239
|
end
|
@@ -233,7 +233,7 @@ format :html do
|
|
233
233
|
end
|
234
234
|
|
235
235
|
view :act_header do |_args|
|
236
|
-
%(<h5 class="act-header">#{
|
236
|
+
%(<h5 class="act-header">#{link_to_card card}</h5>)
|
237
237
|
end
|
238
238
|
|
239
239
|
view :act_metadata do |args|
|
@@ -244,7 +244,7 @@ format :html do
|
|
244
244
|
= '#' + act_seq.to_s
|
245
245
|
.title
|
246
246
|
.actor
|
247
|
-
=
|
247
|
+
= link_to_card act.actor
|
248
248
|
.time.timeago
|
249
249
|
= time_ago_in_words(act.acted_at)
|
250
250
|
ago
|
@@ -306,17 +306,17 @@ format :html do
|
|
306
306
|
end
|
307
307
|
|
308
308
|
def name_diff action, hide_diff
|
309
|
+
working_name = name_changes action, hide_diff
|
309
310
|
if action.card == card
|
310
|
-
|
311
|
+
working_name
|
311
312
|
else
|
312
|
-
|
313
|
-
|
314
|
-
related: { view: "history", name: action.card.name }
|
313
|
+
link_to_view(
|
314
|
+
:related, working_name,
|
315
|
+
path: { related: { view: "history", name: action.card.name } },
|
316
|
+
remote: true,
|
317
|
+
class: "slotter label label-default",
|
318
|
+
"data-slot-selector" => ".card-slot.history-view"
|
315
319
|
)
|
316
|
-
link_to name_changes(action, hide_diff), link_path,
|
317
|
-
class: "slotter label label-default",
|
318
|
-
"data-slot-selector" => ".card-slot.history-view",
|
319
|
-
remote: true
|
320
320
|
end
|
321
321
|
end
|
322
322
|
|
@@ -370,45 +370,42 @@ format :html do
|
|
370
370
|
end
|
371
371
|
|
372
372
|
def fold_or_unfold_link args
|
373
|
-
|
374
|
-
|
375
|
-
act_seq: args[:act_seq],
|
376
|
-
hide_diff: args[:hide_diff],
|
377
|
-
act_context: args[:act_context],
|
378
|
-
action_view: (args[:action_view] == :expanded ? :summary : :expanded),
|
379
|
-
look_in_trash: true
|
380
|
-
}
|
373
|
+
act_id = args[:act].id
|
374
|
+
action_view = args[:action_view] == :expanded ? :summary : :expanded
|
381
375
|
arrow_dir = args[:action_view] == :expanded ? "arrow-down" : "arrow-right"
|
382
|
-
|
383
|
-
|
376
|
+
|
377
|
+
link_to_view :act, "", class: "slotter revision-#{act_id} #{arrow_dir}",
|
378
|
+
path: { act_id: act_id,
|
379
|
+
act_seq: args[:act_seq],
|
380
|
+
hide_diff: args[:hide_diff],
|
381
|
+
act_context: args[:act_context],
|
382
|
+
action_view: action_view,
|
383
|
+
look_in_trash: true }
|
384
384
|
end
|
385
385
|
|
386
386
|
def rollback_link actions
|
387
|
-
|
387
|
+
# @fixme -- doesn't this need to specify which action it wants?
|
388
|
+
prior = # @fixme - should be a Card::Action method
|
388
389
|
actions.select { |action| action.card.last_action_id != action.id }
|
389
|
-
return unless card.ok?(:update) &&
|
390
|
-
link_path = path action: :update, view: :open, action_ids: not_current,
|
391
|
-
look_in_trash: true
|
390
|
+
return unless card.ok?(:update) && prior.present?
|
392
391
|
link = link_to(
|
393
|
-
"Save as current",
|
394
|
-
|
395
|
-
|
392
|
+
"Save as current", class: "slotter",
|
393
|
+
"data-slot-selector" => ".card-slot.history-view",
|
394
|
+
remote: true, method: :post, rel: "nofollow",
|
395
|
+
path: { action: :update, action_ids: prior,
|
396
|
+
view: :open, look_in_trash: true }
|
396
397
|
)
|
397
398
|
%(<div class="act-link">#{link}</div>)
|
398
399
|
end
|
399
400
|
|
400
401
|
def show_or_hide_changes_link args
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
act_seq: args[:act_seq],
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
look_in_trash: true
|
409
|
-
}
|
410
|
-
link = view_link("#{toggle} changes", :act,
|
411
|
-
path_opts: path_opts, class: "slotter", remote: true)
|
402
|
+
link = link_to_view(
|
403
|
+
:act, "#{args[:hide_diff] ? 'Show' : 'Hide'} changes",
|
404
|
+
class: "slotter",
|
405
|
+
path: { act_id: args[:act].id, act_seq: args[:act_seq],
|
406
|
+
hide_diff: !args[:hide_diff], action_view: :expanded,
|
407
|
+
act_context: args[:act_context], look_in_trash: true }
|
408
|
+
)
|
412
409
|
%(<div class="act-link">#{link}</div>)
|
413
410
|
end
|
414
411
|
end
|
@@ -45,14 +45,11 @@ format :html do
|
|
45
45
|
|
46
46
|
def groups item_names
|
47
47
|
group_options.map do |option|
|
48
|
-
checked =
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
<label>#{card_link option.name, target: 'wagn_role'}</label>
|
54
|
-
</div>
|
55
|
-
)
|
48
|
+
checked = !item_names.delete(option.name).nil?
|
49
|
+
option_link = link_to_card option.name, nil, target: "wagn_role"
|
50
|
+
box = check_box_tag "#{option.key}-perm-checkbox",
|
51
|
+
option.name, checked, class: "perm-checkbox-button"
|
52
|
+
%(<div class="group-option">#{box}<label>#{option_link}</label></div>)
|
56
53
|
end * "\n"
|
57
54
|
end
|
58
55
|
|
@@ -103,7 +100,7 @@ format :html do
|
|
103
100
|
task = card.tag.codename
|
104
101
|
ancestor = Card[set_context.trunk_name.trunk_name]
|
105
102
|
links = ancestor.who_can(task.to_sym).map do |card_id|
|
106
|
-
|
103
|
+
link_to_card card_id, nil, target: args[:target]
|
107
104
|
end * ", "
|
108
105
|
"Inherit ( #{links} )"
|
109
106
|
rescue
|
@@ -58,17 +58,18 @@ format do
|
|
58
58
|
- card.set_classes_with_rules.each do |klass, rules|
|
59
59
|
%tr.klass-row
|
60
60
|
%td{class: ['setting-klass', "anchorless-#{klass.anchorless?}"]}
|
61
|
-
|
61
|
+
- kpat = klass.pattern
|
62
|
+
= klass.anchorless? ? link_to_card(kpat) : kpat
|
62
63
|
%td.rule-content-container
|
63
64
|
%span.closed-content.content
|
64
65
|
- if klass.anchorless?
|
65
66
|
= subformat(rules[0])._render_closed_content
|
66
67
|
- if !klass.anchorless?
|
67
68
|
- duplicate_check(rules) do |rule, duplicate, changeover|
|
69
|
+
- setname = rule.cardname.trunk_name
|
68
70
|
%tr{class: ('rule-changeover' if changeover)}
|
69
71
|
%td.rule-anchor
|
70
|
-
=
|
71
|
-
text: rule.cardname.trunk_name.trunk_name
|
72
|
+
= link_to_card setname, setname.trunk_name
|
72
73
|
- if duplicate
|
73
74
|
%td
|
74
75
|
- else
|
@@ -10,31 +10,36 @@
|
|
10
10
|
|
11
11
|
card_accessor :solid_cache, type: :html
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
def self.included host_class
|
14
|
+
host_class.format(host_class.try(:cached_format) || :base) do
|
15
|
+
view :core do |args|
|
16
|
+
return super(args) unless args[:solid_cache]
|
17
|
+
card.update_solid_cache if card.solid_cache_card.new?
|
18
|
+
subformat(card.solid_cache_card)._render_core args
|
19
|
+
end
|
16
20
|
end
|
21
|
+
end
|
17
22
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
subformat(card.solid_cache_card)._render_core args
|
23
|
+
format do
|
24
|
+
def default_core_args args
|
25
|
+
args[:solid_cache] = true unless args.key?(:solid_cache)
|
22
26
|
end
|
23
27
|
end
|
24
28
|
|
25
29
|
module ClassMethods
|
26
|
-
# If a card of the set given by 'set_of_changed_card' is
|
30
|
+
# If a card of the set given by 'set_of_changed_card' is changed
|
27
31
|
# the given block is executed. It is supposed to return an array of
|
28
|
-
# cards whose solid caches are expired because of the
|
32
|
+
# cards whose solid caches are expired because of the change.
|
29
33
|
# @param set_of_changed_card [set constant] a set of cards that triggers
|
30
34
|
# a cache update
|
31
35
|
# @param args [Hash]
|
32
|
-
# @option args [Symbol, Array
|
36
|
+
# @option args [Symbol, Array<Symbol>] :on the action(s)
|
33
37
|
# (:create, :update, or :delete) on which the cache update
|
34
38
|
# should be triggered. Default is all actions.
|
35
39
|
# @option args [Stage] :in_stage the stage when the update is executed.
|
36
40
|
# Default is :integrate
|
37
|
-
# @yield return an array of cards with solid cache that need to be
|
41
|
+
# @yield return a card or an array of cards with solid cache that need to be
|
42
|
+
# updated
|
38
43
|
def cache_update_trigger set_of_changed_card, args={}, &block
|
39
44
|
define_event_to_update_expired_cached_cards(
|
40
45
|
set_of_changed_card, args, :update_solid_cache, &block
|
@@ -56,37 +61,53 @@ module ClassMethods
|
|
56
61
|
stage = args[:in_stage] || :integrate
|
57
62
|
Card::Set.register_set set_of_changed_card
|
58
63
|
set_of_changed_card.event name, stage, args do
|
59
|
-
Array(yield(self)).compact.each do |expired_cache_card|
|
64
|
+
Array.wrap(yield(self)).compact.each do |expired_cache_card|
|
60
65
|
next unless expired_cache_card.solid_cache?
|
61
|
-
expired_cache_card.send method_name
|
66
|
+
expired_cache_card.send method_name, self
|
62
67
|
end
|
63
68
|
end
|
64
69
|
end
|
65
70
|
|
66
71
|
def event_name set, args
|
67
|
-
changed_card_set = set.
|
68
|
-
solid_cache_set =
|
72
|
+
changed_card_set = set.shortname.tr(":", "_").underscore
|
73
|
+
solid_cache_set = shortname.tr(":", "_").underscore + "__solid_cache"
|
69
74
|
actions = Array.wrap(args[:on]).join("_")
|
70
|
-
"
|
71
|
-
|
75
|
+
["update", solid_cache_set,
|
76
|
+
"changed_by", changed_card_set,
|
77
|
+
"on", actions].join("___").to_sym
|
72
78
|
end
|
73
79
|
end
|
74
80
|
|
75
|
-
def expire_solid_cache
|
81
|
+
def expire_solid_cache _changed_card=nil
|
76
82
|
return unless solid_cache?
|
77
83
|
Auth.as_bot do
|
78
84
|
solid_cache_card.delete!
|
79
85
|
end
|
80
86
|
end
|
81
87
|
|
82
|
-
def update_solid_cache
|
88
|
+
def update_solid_cache changed_card=nil
|
83
89
|
return unless solid_cache?
|
84
|
-
new_content =
|
90
|
+
new_content =
|
91
|
+
if solid_cache_card.new?
|
92
|
+
generate_content_for_cache changed_card
|
93
|
+
else
|
94
|
+
updated_content_for_cache changed_card
|
95
|
+
end
|
85
96
|
return unless new_content
|
86
97
|
write_to_solid_cache new_content
|
87
98
|
new_content
|
88
99
|
end
|
89
100
|
|
101
|
+
def generate_content_for_cache changed_card=nil
|
102
|
+
format_type = try(:cached_format) || :base
|
103
|
+
format(format_type)._render_core(solid_cache: false,
|
104
|
+
changed_card: changed_card)
|
105
|
+
end
|
106
|
+
|
107
|
+
def updated_content_for_cache _changed_card=nil
|
108
|
+
generate_content_for_cache
|
109
|
+
end
|
110
|
+
|
90
111
|
def write_to_solid_cache new_content
|
91
112
|
Auth.as_bot do
|
92
113
|
if solid_cache_card.new_card?
|
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- encoding : utf-8 -*-
|
1
2
|
|
2
3
|
describe Card::Set::Abstract::SolidCache do
|
3
4
|
context "render core view of a card" do
|
@@ -5,7 +6,8 @@ describe Card::Set::Abstract::SolidCache do
|
|
5
6
|
@card = Card["A"]
|
6
7
|
end
|
7
8
|
|
8
|
-
let(:core_view) { 'Alpha <a class="known-card" href="/Z">Z</a>' }
|
9
|
+
# let(:core_view) { 'Alpha <a class="known-card" href="/Z">Z</a>' }
|
10
|
+
let(:core_view) { "Alpha Z[/Z]" }
|
9
11
|
context "with solid cache" do
|
10
12
|
it "saves core view in solid cache card" do
|
11
13
|
@card.format_with_set(Card::Set::Abstract::SolidCache, &:render_core)
|
@@ -71,18 +71,16 @@ format :html do
|
|
71
71
|
end
|
72
72
|
|
73
73
|
def backtrace_link exception
|
74
|
-
|
75
|
-
|
76
|
-
alert_class: "render-error-message errors-view admin-error-message"
|
77
|
-
}
|
78
|
-
warning = alert("warning", warning_options) do
|
74
|
+
alert_class = "render-error-message errors-view admin-error-message"
|
75
|
+
warning = alert("warning", dismissible: true, alert_class: alert_class) do
|
79
76
|
%{
|
80
77
|
<h3>Error message (visible to admin only)</h3>
|
81
78
|
<p><strong>#{exception.message}</strong></p>
|
82
79
|
<div>#{exception.backtrace * "<br>\n"}</div>
|
83
80
|
}
|
84
81
|
end
|
85
|
-
|
82
|
+
link = link_to_card error_cardname, nil, class: "render-error-link"
|
83
|
+
link + warning
|
86
84
|
end
|
87
85
|
|
88
86
|
view :unsupported_view, perms: :none, tags: :unknown_ok do |args|
|
@@ -102,15 +100,11 @@ format :html do
|
|
102
100
|
|
103
101
|
view :missing do |args|
|
104
102
|
return "" unless card.ok? :create # should this be moved into ok_view?
|
105
|
-
|
106
|
-
link_opts = {
|
107
|
-
remote: true,
|
108
|
-
class: "slotter missing-#{args[:denied_view] || args[:home_view]}"
|
109
|
-
}
|
110
|
-
link_opts[:path_opts] = { type: args[:type] } if args[:type]
|
111
|
-
|
103
|
+
missing_view = args[:denied_view] || args[:home_view]
|
112
104
|
wrap args do
|
113
|
-
|
105
|
+
link_to_view :new, "Add #{fancy_title args[:title]}",
|
106
|
+
path: (args[:type] ? { type: args[:type] } : {}),
|
107
|
+
class: "slotter missing-#{missing_view}"
|
114
108
|
end
|
115
109
|
end
|
116
110
|
|
@@ -119,7 +113,7 @@ format :html do
|
|
119
113
|
end
|
120
114
|
|
121
115
|
view :conflict, error_code: 409 do |args|
|
122
|
-
actor_link =
|
116
|
+
actor_link = link_to_card card.last_action.act.actor.cardname
|
123
117
|
expanded_act = wrap(args) do
|
124
118
|
_render_act_expanded act: card.last_action.act, current_rev_nr: 0
|
125
119
|
end
|
@@ -158,8 +152,8 @@ format :html do
|
|
158
152
|
view :not_found do |args| # ug. bad name.
|
159
153
|
sign_in_or_up_links =
|
160
154
|
unless Auth.signed_in?
|
161
|
-
signin_link =
|
162
|
-
signup_link = link_to "Sign up",
|
155
|
+
signin_link = link_to_card :signin, "Sign in"
|
156
|
+
signup_link = link_to "Sign up", path: { account: :new, type: :signup }
|
163
157
|
%(<div>#{signin_link} or #{signup_link} to create it.</div>)
|
164
158
|
end
|
165
159
|
frame args.merge(title: "Not Found", optional_menu: :never) do
|
@@ -186,10 +180,11 @@ format :html do
|
|
186
180
|
when Auth.signed_in?
|
187
181
|
"You need permission #{to_task}"
|
188
182
|
else
|
189
|
-
signin_link =
|
183
|
+
signin_link = link_to_card :signin, "sign in"
|
190
184
|
or_signup_link =
|
191
185
|
if Card.new(type_id: Card::SignupID).ok? :create
|
192
|
-
"or " +
|
186
|
+
"or " +
|
187
|
+
link_to("sign up", path: { account: "new", type: :signup })
|
193
188
|
end
|
194
189
|
Env.save_interrupted_action(request.env["REQUEST_URI"])
|
195
190
|
"Please #{signin_link} #{or_signup_link} #{to_task}"
|
@@ -1,9 +1,30 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
def link_to text,
|
5
|
-
href =
|
1
|
+
RESOURCE_TYPE_REGEXP = /^([a-zA-Z][\-+\.a-zA-Z\d]*):/
|
2
|
+
|
3
|
+
format :html do
|
4
|
+
def link_to text=nil, opts={}
|
5
|
+
opts[:href] = interpret_pathish opts.delete(:path)
|
6
|
+
text = raw(text || opts[:href])
|
7
|
+
interpret_data_opts_to_link_to opts
|
8
|
+
content_tag :a, text, opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def interpret_data_opts_to_link_to opts
|
12
|
+
[:remote, :method].each do |key|
|
13
|
+
next unless (val = opts.delete key)
|
14
|
+
opts["data-#{key}"] = val
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
format :css do
|
20
|
+
def link_to _text=nil, opts={}
|
21
|
+
card_url interpret_pathish(opts.delete(:path))
|
22
|
+
end
|
23
|
+
end
|
6
24
|
|
25
|
+
format do
|
26
|
+
def link_to text=nil, opts={}
|
27
|
+
href = interpret_pathish opts.delete(:path)
|
7
28
|
if text && href != text
|
8
29
|
"#{text}[#{href}]"
|
9
30
|
else
|
@@ -11,148 +32,156 @@ format do
|
|
11
32
|
end
|
12
33
|
end
|
13
34
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
view_link link_text, view, html_args.merge(path_opts: target)
|
18
|
-
elsif (page = target.delete(:card))
|
19
|
-
card_link page, html_args.merge(path_opts: target, text: link_text)
|
20
|
-
elsif target[:related]
|
21
|
-
if target[:related].is_a? String
|
22
|
-
target[:related] = { name: "+#{target[:related]}" }
|
23
|
-
end
|
24
|
-
view_link link_text, :related, html_args.merge(path_opts: target)
|
25
|
-
elsif target[:web]
|
35
|
+
def smart_link_to text, opts={}
|
36
|
+
if (linktype = [:view, :related, :card, :resource].find { |key| opts[key] })
|
37
|
+
send "link_to_#{linktype}", opts.delete(linktype), text, opts
|
26
38
|
else
|
27
|
-
link_to
|
39
|
+
send :link_to, text, opts
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def link_to_resource resource, text=nil, opts={}
|
44
|
+
case (resource_type = resource_type resource)
|
45
|
+
when "external-link" then opts[:target] = "_blank"
|
46
|
+
when "internal-link" then resource = internal_url resource[1..-1]
|
47
|
+
end
|
48
|
+
add_class opts, resource_type
|
49
|
+
link_to text, opts.merge(path: resource)
|
50
|
+
end
|
51
|
+
|
52
|
+
def resource_type resource
|
53
|
+
case resource
|
54
|
+
when /^https?\:/ then "external-link"
|
55
|
+
when %r{^/} then "internal-link"
|
56
|
+
when /^mailto\:/ then "email-link"
|
57
|
+
when RESOURCE_TYPE_REGEXP then Regexp.last_match(1) + "-link"
|
28
58
|
end
|
29
59
|
end
|
30
60
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
"internal-link"
|
46
|
-
else
|
47
|
-
return card_link href, opts
|
48
|
-
end
|
49
|
-
add_class opts, new_class
|
50
|
-
link_to text, href, opts
|
51
|
-
end
|
52
|
-
|
53
|
-
# link to a specific card
|
54
|
-
def card_link name_or_card, opts={}
|
55
|
-
name =
|
56
|
-
case name_or_card
|
57
|
-
when Symbol then Card.fetch(name_or_card, skip_modules: true).cardname
|
58
|
-
when Card then name_or_card.cardname
|
59
|
-
else name_or_card
|
60
|
-
end
|
61
|
-
text = (opts.delete(:text) || name).to_name.to_show @context_names
|
62
|
-
|
63
|
-
path_opts = opts.delete(:path_opts) || {}
|
64
|
-
path_opts[:name] = name
|
65
|
-
path_opts[:known] =
|
66
|
-
opts[:known].nil? ? Card.known?(name) : opts.delete(:known)
|
67
|
-
add_class opts, (path_opts[:known] ? "known-card" : "wanted-card")
|
68
|
-
link_to text, path_opts, opts
|
61
|
+
def link_to_card cardish, text=nil, opts={}
|
62
|
+
opts[:path] ||= {}
|
63
|
+
name = opts[:path][:name] = Card::Name.cardish cardish
|
64
|
+
# @fixme - need smarter mark handling
|
65
|
+
|
66
|
+
text ||= name.to_name.to_show @context_names
|
67
|
+
add_known_or_wanted_class opts, name
|
68
|
+
link_to text, opts
|
69
|
+
end
|
70
|
+
|
71
|
+
def add_known_or_wanted_class opts, name
|
72
|
+
known = opts.delete :known
|
73
|
+
known = Card.known?(name) if known.nil?
|
74
|
+
add_class opts, (known ? "known-card" : "wanted-card")
|
69
75
|
end
|
70
76
|
|
71
77
|
# link to a specific view (defaults to current card)
|
72
78
|
# this is generally used for ajax calls
|
73
|
-
def
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
link_to text, path_opts, opts
|
80
|
-
end
|
81
|
-
|
82
|
-
def related_link name_or_card, opts={}
|
83
|
-
name =
|
84
|
-
case name_or_card
|
85
|
-
when Symbol then Card.fetch(name_or_card, skip_modules: true).cardname
|
86
|
-
when Card then name_or_card.cardname
|
87
|
-
else name_or_card
|
88
|
-
end
|
89
|
-
opts[:path_opts] ||= { view: :related }
|
90
|
-
opts[:path_opts][:related] = { name: "+#{name}" }
|
91
|
-
opts[:path_opts][:related].merge! opts[:related_opts] if opts[:related_opts]
|
92
|
-
view_link(opts[:text] || name, :related, opts)
|
93
|
-
end
|
94
|
-
|
95
|
-
def path opts={}
|
96
|
-
if opts[:action] == :new && opts[:type] &&
|
97
|
-
!(opts[:name] || opts[:card] || opts[:id])
|
98
|
-
opts.delete(:action)
|
99
|
-
base = "new/#{opts.delete(:type)}"
|
100
|
-
else
|
101
|
-
name = opts.delete(:name) || card.name
|
102
|
-
base = opts[:action] ? "card/#{opts.delete :action}/" : ""
|
79
|
+
def link_to_view view, text, opts={}
|
80
|
+
opts.reverse_merge! path: {}, remote: true, rel: "nofollow"
|
81
|
+
opts[:path][:view] = view unless view == :home
|
82
|
+
link_to text, opts
|
83
|
+
end
|
103
84
|
|
104
|
-
|
105
|
-
|
85
|
+
def link_to_related cardish, text=nil, opts={}
|
86
|
+
name = Card::Name.cardish cardish
|
87
|
+
opts[:path] ||= {}
|
88
|
+
opts[:path][:related] ||= {}
|
89
|
+
opts[:path][:related][:name] ||= "+#{name}"
|
90
|
+
link_to_view :related, (text || name), opts
|
91
|
+
end
|
106
92
|
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
93
|
+
# @param opts [Hash]
|
94
|
+
# @option opts [Symbol] :action card action (:create, :update, :delete)
|
95
|
+
# @option opts [Integer, String] :id
|
96
|
+
# @option opts [String, Card::Name] :name
|
97
|
+
# @option opts [String] :type
|
98
|
+
# @option opts [Hash] :card
|
99
|
+
# @param mark_type [Symbol] defaults to :id
|
100
|
+
def path opts={}, mark_type=:id
|
101
|
+
path = new_cardtype_path(opts) || standard_path(opts, mark_type)
|
102
|
+
internal_url path
|
103
|
+
end
|
111
104
|
|
112
|
-
|
113
|
-
|
105
|
+
def new_cardtype_path opts
|
106
|
+
return unless opts[:action] == :new
|
107
|
+
opts.delete :action
|
108
|
+
return unless (type_mark = opts.delete(:type))
|
109
|
+
"new/#{Card.quick_fetch(type_mark).cardname.url_key}"
|
110
|
+
end
|
114
111
|
|
115
|
-
|
116
|
-
|
112
|
+
def standard_path opts, mark_type
|
113
|
+
standardize_action! opts
|
114
|
+
base = path_action(opts[:action]) + path_mark(opts, mark_type)
|
115
|
+
base + path_query(opts)
|
117
116
|
end
|
118
117
|
|
119
|
-
def
|
120
|
-
|
118
|
+
def path_action action
|
119
|
+
case action
|
120
|
+
when :create then "card/#{action}/"
|
121
|
+
# sometimes create action has no mark,
|
122
|
+
# but /create alone would refer to a card named "create"
|
123
|
+
when nil then ""
|
124
|
+
else "#{action}/"
|
125
|
+
end
|
121
126
|
end
|
122
127
|
|
123
|
-
def
|
124
|
-
|
128
|
+
def standardize_action! opts
|
129
|
+
return if [:create, :update, :delete].member? opts[:action]
|
130
|
+
opts.delete :action
|
125
131
|
end
|
126
132
|
|
127
|
-
def
|
128
|
-
|
129
|
-
|
130
|
-
|
133
|
+
def path_mark opts, mark_type
|
134
|
+
case mark_type
|
135
|
+
when :id && (id = path_id opts) then "~#{id}"
|
136
|
+
when :codename && (codename = card.codename) then ":#{codename}"
|
137
|
+
else (opts[:name] || card.name).to_name.url_key
|
131
138
|
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def path_id opts
|
142
|
+
id = opts.delete :id
|
143
|
+
id if id.present?
|
144
|
+
end
|
145
|
+
|
146
|
+
def path_query opts
|
147
|
+
finalize_card_opts opts.delete(:card), opts
|
148
|
+
opts.delete :action
|
149
|
+
opts.empty? ? "" : "?#{opts.to_param}"
|
150
|
+
end
|
132
151
|
|
133
|
-
|
134
|
-
|
152
|
+
def finalize_card_opts card_opts, opts
|
153
|
+
card_opts ||= {}
|
154
|
+
[:name, :type].each do |field|
|
155
|
+
assign_path_card_opt card_opts, field, opts
|
135
156
|
end
|
136
|
-
opts
|
157
|
+
opts[:card] = card_opts unless card_opts.empty?
|
137
158
|
end
|
138
|
-
end
|
139
159
|
|
140
|
-
|
141
|
-
|
142
|
-
|
160
|
+
def assign_path_card_opt card_opts, field, opts
|
161
|
+
optvalue = opts.delete field
|
162
|
+
return if card_opts[field] || !optvalue.present?
|
163
|
+
new_value = send "new_#{field}_in_path_opts", optvalue.to_s, opts
|
164
|
+
return unless new_value
|
165
|
+
card_opts[field] = new_value
|
166
|
+
end
|
143
167
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
168
|
+
def new_name_in_path_opts name, opts
|
169
|
+
if opts[:action] == :update
|
170
|
+
name if name != card.name
|
171
|
+
elsif !Card.known?(name) && name != name.to_name.url_key
|
172
|
+
name
|
148
173
|
end
|
174
|
+
end
|
149
175
|
|
150
|
-
|
176
|
+
def new_type_in_path_opts opttype, _opts
|
177
|
+
opttype if Card.known?(opttype)
|
151
178
|
end
|
152
|
-
end
|
153
179
|
|
154
|
-
|
155
|
-
|
156
|
-
|
180
|
+
def internal_url relative_path
|
181
|
+
card_path relative_path
|
182
|
+
end
|
183
|
+
|
184
|
+
def interpret_pathish pathish
|
185
|
+
pathish.is_a?(Hash) ? path(pathish) : pathish
|
157
186
|
end
|
158
187
|
end
|