metadata_presenter 2.9.0 → 2.12.1
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/app/models/metadata_presenter/branch_destinations.rb +18 -0
- data/app/models/metadata_presenter/column_number.rb +21 -0
- data/app/models/metadata_presenter/coordinates.rb +51 -0
- data/app/models/metadata_presenter/grid.rb +63 -47
- data/app/models/metadata_presenter/row_number.rb +82 -0
- data/app/models/metadata_presenter/service.rb +1 -1
- data/fixtures/branching_10.json +1271 -0
- data/fixtures/branching_10.png +0 -0
- data/fixtures/branching_7.json +0 -62
- data/fixtures/branching_9.json +1012 -0
- data/fixtures/branching_9.png +0 -0
- data/lib/metadata_presenter/version.rb +1 -1
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a349beb4173c1f6361b321a95e36a407c5f5361153403cae2fbd15ffb7b8840
|
4
|
+
data.tar.gz: 8e06745f55b04f1074a5da27b77e4f9cb720b95bfb328672c14cca059e4a3003
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 01f7f93e1b0d7a058ff856cb27ce07ec816b060e2b2299cec55be298aa046809a9e9ba82f9f770205b4fe647a8d3e046e1a0b10afad0a78fc5190e52aa28fc5f
|
7
|
+
data.tar.gz: 5cb518f2fb78f26ae06d447d0d1a7a7f2b84de9b4f24057079464bdcd77945c36430c4718c49d1bc2a04ec48ab1cfb422fbfc02c952a516ca83d7cae3e29a2ff
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
module BranchDestinations
|
3
|
+
# The frontend requires that expressions of type 'or' get there own line and
|
4
|
+
# arrow. 'and' expression types continue to be grouped together.
|
5
|
+
# Return the UUIDs of the destinations exiting a branch and allow duplicates
|
6
|
+
# if the expression type is an 'or'.
|
7
|
+
def exiting_destinations_from_branch(branch)
|
8
|
+
destination_uuids = branch.conditionals.map do |conditional|
|
9
|
+
if conditional.type == 'or'
|
10
|
+
conditional.expressions.map { |_| conditional.next }
|
11
|
+
else
|
12
|
+
conditional.next
|
13
|
+
end
|
14
|
+
end
|
15
|
+
destination_uuids.flatten.push(branch.default_next)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class ColumnNumber
|
3
|
+
def initialize(uuid:, coordinates:, new_column:)
|
4
|
+
@uuid = uuid
|
5
|
+
@coordinates = coordinates
|
6
|
+
@new_column = new_column
|
7
|
+
end
|
8
|
+
|
9
|
+
def number
|
10
|
+
[existing_column, new_column].compact.max
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
attr_reader :uuid, :coordinates, :new_column
|
16
|
+
|
17
|
+
def existing_column
|
18
|
+
@coordinates.uuid_column(uuid)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class Coordinates
|
3
|
+
def initialize(flow)
|
4
|
+
@flow = flow
|
5
|
+
@positions = setup_positions
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :positions
|
9
|
+
|
10
|
+
def set_column(uuid, number)
|
11
|
+
positions[uuid][:column] = number
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_row(uuid, number)
|
15
|
+
positions[uuid][:row] = number
|
16
|
+
end
|
17
|
+
|
18
|
+
def uuid_column(uuid)
|
19
|
+
positions[uuid][:column]
|
20
|
+
end
|
21
|
+
|
22
|
+
def uuid_row(uuid)
|
23
|
+
positions[uuid][:row]
|
24
|
+
end
|
25
|
+
|
26
|
+
def uuid_at_position(column, row)
|
27
|
+
positions.find do |uuid, position|
|
28
|
+
if position[:column] == column && position[:row] == row
|
29
|
+
return uuid
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def position(uuid)
|
35
|
+
positions[uuid]
|
36
|
+
end
|
37
|
+
|
38
|
+
def positions_in_column(column_number)
|
39
|
+
positions.select { |_, position| position[:column] == column_number }
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
attr_reader :flow
|
45
|
+
attr_writer :positions
|
46
|
+
|
47
|
+
def setup_positions
|
48
|
+
flow.keys.index_with { |_uuid| { row: nil, column: nil } }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -12,6 +12,7 @@ module MetadataPresenter
|
|
12
12
|
end
|
13
13
|
|
14
14
|
class Grid
|
15
|
+
include BranchDestinations
|
15
16
|
attr_reader :start_from
|
16
17
|
|
17
18
|
def initialize(service, start_from: nil, main_flow: [])
|
@@ -21,7 +22,7 @@ module MetadataPresenter
|
|
21
22
|
@ordered = []
|
22
23
|
@routes = []
|
23
24
|
@traversed = []
|
24
|
-
@coordinates =
|
25
|
+
@coordinates = MetadataPresenter::Coordinates.new(service.flow)
|
25
26
|
end
|
26
27
|
|
27
28
|
ROW_ZERO = 0
|
@@ -30,8 +31,8 @@ module MetadataPresenter
|
|
30
31
|
return @ordered unless @ordered.empty?
|
31
32
|
|
32
33
|
@ordered = make_grid
|
33
|
-
|
34
|
-
|
34
|
+
set_column_numbers
|
35
|
+
set_row_numbers
|
35
36
|
add_by_coordinates
|
36
37
|
insert_expression_spacers
|
37
38
|
trim_pointers unless main_flow.empty?
|
@@ -62,10 +63,6 @@ module MetadataPresenter
|
|
62
63
|
attr_reader :service, :main_flow
|
63
64
|
attr_accessor :ordered, :traversed, :routes, :coordinates
|
64
65
|
|
65
|
-
def setup_coordinates
|
66
|
-
service.flow.keys.index_with { |_uuid| { row: nil, column: nil } }
|
67
|
-
end
|
68
|
-
|
69
66
|
def route_from_start
|
70
67
|
@route_from_start ||=
|
71
68
|
MetadataPresenter::Route.new(
|
@@ -83,7 +80,12 @@ module MetadataPresenter
|
|
83
80
|
end
|
84
81
|
|
85
82
|
def max_potential_rows
|
86
|
-
@max_potential_rows ||=
|
83
|
+
@max_potential_rows ||= begin
|
84
|
+
destinations_count = service.branches.map do |branch|
|
85
|
+
exiting_destinations_from_branch(branch).count
|
86
|
+
end
|
87
|
+
destinations_count.sum
|
88
|
+
end
|
87
89
|
end
|
88
90
|
|
89
91
|
def max_potential_columns
|
@@ -121,30 +123,47 @@ module MetadataPresenter
|
|
121
123
|
end
|
122
124
|
end
|
123
125
|
|
124
|
-
def
|
126
|
+
def set_column_numbers
|
125
127
|
@routes.each do |route|
|
126
|
-
route.flow_uuids.each.with_index(route.column) do |uuid,
|
127
|
-
column_number =
|
128
|
-
|
129
|
-
|
130
|
-
|
128
|
+
route.flow_uuids.each.with_index(route.column) do |uuid, new_column|
|
129
|
+
column_number = MetadataPresenter::ColumnNumber.new(
|
130
|
+
uuid: uuid,
|
131
|
+
new_column: new_column,
|
132
|
+
coordinates: @coordinates
|
133
|
+
).number
|
134
|
+
@coordinates.set_column(uuid, column_number)
|
131
135
|
end
|
132
136
|
end
|
133
137
|
end
|
134
138
|
|
135
|
-
def
|
139
|
+
def set_row_numbers
|
136
140
|
@routes.each do |route|
|
137
|
-
route.
|
138
|
-
next if @traversed.include?(uuid)
|
141
|
+
next if @traversed.include?(route.traverse_from) && appears_later_in_flow?(route)
|
139
142
|
|
140
|
-
|
143
|
+
current_row = route.row
|
144
|
+
route.flow_uuids.each do |uuid|
|
145
|
+
row_number = MetadataPresenter::RowNumber.new(
|
146
|
+
uuid: uuid,
|
147
|
+
route: route,
|
148
|
+
current_row: current_row,
|
149
|
+
coordinates: @coordinates,
|
150
|
+
service: service
|
151
|
+
).number
|
152
|
+
@coordinates.set_row(uuid, row_number)
|
141
153
|
|
142
154
|
update_route_rows(route, uuid)
|
143
|
-
@traversed.push(uuid)
|
155
|
+
@traversed.push(uuid) unless @traversed.include?(uuid)
|
156
|
+
current_row = row_number
|
144
157
|
end
|
145
158
|
end
|
146
159
|
end
|
147
160
|
|
161
|
+
# New routes can be linked to later. We need to also traverse these to see
|
162
|
+
# if anything should be moved to a different row.
|
163
|
+
def appears_later_in_flow?(route)
|
164
|
+
@coordinates.uuid_column(route.traverse_from) > route.column
|
165
|
+
end
|
166
|
+
|
148
167
|
# Each Route object has a starting row. Each Route object has no knowledge
|
149
168
|
# of other potential routes and pages/branches that may or may not exist in
|
150
169
|
# them. The starting row may need to change dependent upon what has been
|
@@ -162,10 +181,14 @@ module MetadataPresenter
|
|
162
181
|
end
|
163
182
|
|
164
183
|
def add_by_coordinates
|
165
|
-
|
184
|
+
service.flow.each_key do |uuid|
|
185
|
+
position = coordinates.position(uuid)
|
166
186
|
next if detached?(position)
|
167
187
|
|
168
|
-
|
188
|
+
column = position[:column]
|
189
|
+
row = position[:row]
|
190
|
+
insert_spacer(column, row) if occupied?(column, row, uuid)
|
191
|
+
@ordered[column][row] = get_flow_object(uuid)
|
169
192
|
end
|
170
193
|
end
|
171
194
|
|
@@ -173,6 +196,11 @@ module MetadataPresenter
|
|
173
196
|
position[:row].nil? || position[:column].nil?
|
174
197
|
end
|
175
198
|
|
199
|
+
def occupied?(column, row, uuid)
|
200
|
+
object = @ordered[column][row]
|
201
|
+
object.is_a?(MetadataPresenter::Flow) && object.uuid != uuid
|
202
|
+
end
|
203
|
+
|
176
204
|
def get_flow_object(uuid)
|
177
205
|
# main_flow is always empty if the Grid is _actually_ building the main flow
|
178
206
|
return MetadataPresenter::Pointer.new(uuid: uuid) if main_flow.include?(uuid)
|
@@ -202,12 +230,12 @@ module MetadataPresenter
|
|
202
230
|
# Find the very last MetadataPresenter::Flow object in every column and
|
203
231
|
# remove any Spacer objects after that.
|
204
232
|
def trim_spacers
|
205
|
-
@ordered.each_with_index do |column,
|
233
|
+
@ordered.each_with_index do |column, column_number|
|
206
234
|
last_index_of = column.rindex { |item| !item.is_a?(MetadataPresenter::Spacer) }
|
207
|
-
trimmed_column = @ordered[
|
235
|
+
trimmed_column = @ordered[column_number][0..last_index_of]
|
208
236
|
|
209
237
|
# We do not need any columns that only contain Spacer objects
|
210
|
-
@ordered[
|
238
|
+
@ordered[column_number] = only_spacers?(trimmed_column) ? [] : trimmed_column
|
211
239
|
end
|
212
240
|
end
|
213
241
|
|
@@ -220,37 +248,25 @@ module MetadataPresenter
|
|
220
248
|
# the one the branch is located in.
|
221
249
|
def insert_expression_spacers
|
222
250
|
service.branches.each do |branch|
|
223
|
-
|
224
|
-
next if position[:row].nil? || position[:column].nil? # detached branch
|
225
|
-
|
226
|
-
next_column = position[:column] + 1
|
227
|
-
uuids = []
|
228
|
-
exiting_destinations_from_branch(branch).each.with_index(position[:row]) do |uuid, row|
|
229
|
-
if uuids.include?(uuid)
|
230
|
-
@ordered[next_column].insert(row, MetadataPresenter::Spacer.new)
|
231
|
-
end
|
251
|
+
next if coordinates.uuid_column(branch.uuid).nil?
|
232
252
|
|
233
|
-
|
253
|
+
previous_uuid = ''
|
254
|
+
next_column = coordinates.uuid_column(branch.uuid) + 1
|
255
|
+
exiting_destinations_from_branch(branch).each_with_index do |uuid, row|
|
256
|
+
insert_spacer(next_column, row) if uuid == previous_uuid
|
257
|
+
previous_uuid = uuid
|
234
258
|
end
|
235
259
|
end
|
236
260
|
end
|
237
261
|
|
238
|
-
|
239
|
-
|
240
|
-
# Return the UUIDs of the destinations exiting a branch and allow duplicates
|
241
|
-
# if the expression type is an 'or'.
|
242
|
-
def exiting_destinations_from_branch(branch)
|
243
|
-
destination_uuids = branch.conditionals.map do |conditional|
|
244
|
-
if conditional.type == 'or'
|
245
|
-
conditional.expressions.map(&:next)
|
246
|
-
else
|
247
|
-
conditional.next
|
248
|
-
end
|
249
|
-
end
|
250
|
-
destination_uuids.flatten
|
262
|
+
def insert_spacer(column, row)
|
263
|
+
@ordered[column].insert(row, MetadataPresenter::Spacer.new)
|
251
264
|
end
|
252
265
|
|
253
266
|
# Any destinations exiting the branch that have not already been traversed.
|
267
|
+
# This removes any branch destinations that already exist on other rows. If
|
268
|
+
# that is the case then the arrow will flow towards whatever row that object
|
269
|
+
# is located.
|
254
270
|
def routes_exiting_branch(branch)
|
255
271
|
branch.all_destination_uuids.reject { |uuid| @traversed.include?(uuid) }
|
256
272
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module MetadataPresenter
|
2
|
+
class RowNumber
|
3
|
+
include BranchDestinations
|
4
|
+
|
5
|
+
def initialize(uuid:, route:, current_row:, coordinates:, service:)
|
6
|
+
@uuid = uuid
|
7
|
+
@route = route
|
8
|
+
@current_row = current_row
|
9
|
+
@coordinates = coordinates
|
10
|
+
@service = service
|
11
|
+
end
|
12
|
+
|
13
|
+
ROW_ZERO = 0
|
14
|
+
|
15
|
+
def number
|
16
|
+
return route.row if first_row? && existing_row.nil?
|
17
|
+
|
18
|
+
return ROW_ZERO if place_on_row_zero?
|
19
|
+
|
20
|
+
[current_row, existing_row, potential_row].compact.max
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
attr_reader :uuid, :route, :current_row, :coordinates, :service
|
26
|
+
|
27
|
+
def existing_row
|
28
|
+
@existing_row ||= coordinates.uuid_row(uuid)
|
29
|
+
end
|
30
|
+
|
31
|
+
def potential_row
|
32
|
+
return unless object_above.branch? && uuid != object_above.uuid
|
33
|
+
|
34
|
+
coordinates.uuid_row(object_above.uuid) + number_of_destinations
|
35
|
+
end
|
36
|
+
|
37
|
+
def first_row?
|
38
|
+
@first_row ||= route.row.zero?
|
39
|
+
end
|
40
|
+
|
41
|
+
def object_above
|
42
|
+
@object_above ||=
|
43
|
+
service.flow_object(
|
44
|
+
coordinates.uuid_at_position(uuid_column, row_number_for_object_above)
|
45
|
+
)
|
46
|
+
end
|
47
|
+
|
48
|
+
def row_number_for_object_above
|
49
|
+
column_objects.map { |_, p| p[:row] if p[:row] < current_row }.compact.max.to_i
|
50
|
+
end
|
51
|
+
|
52
|
+
def column_objects
|
53
|
+
objects_in_column = coordinates.positions_in_column(uuid_column).reject do |u, p|
|
54
|
+
u == uuid || p[:row].nil?
|
55
|
+
end
|
56
|
+
objects_in_column.sort_by { |_, p| p[:row] }
|
57
|
+
end
|
58
|
+
|
59
|
+
# Takes into account the 'or' type of conditionals which requires an
|
60
|
+
# additional spacer
|
61
|
+
def number_of_destinations
|
62
|
+
exiting_destinations_from_branch(object_above).count
|
63
|
+
end
|
64
|
+
|
65
|
+
def uuid_column
|
66
|
+
@uuid_column ||= coordinates.uuid_column(uuid)
|
67
|
+
end
|
68
|
+
|
69
|
+
# If an object has already been positioned on row 0 then leave it there.
|
70
|
+
# If the object is a checkanswers or confirmation type then always place it
|
71
|
+
# on row 0.
|
72
|
+
def place_on_row_zero?
|
73
|
+
cya_or_confirmation_page? || coordinates.uuid_row(uuid) == ROW_ZERO
|
74
|
+
end
|
75
|
+
|
76
|
+
def cya_or_confirmation_page?
|
77
|
+
%w[page.checkanswers page.confirmation].include?(
|
78
|
+
service.find_page_by_uuid(uuid)&.type
|
79
|
+
)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|