metadata_presenter 2.10.0 → 2.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e03698bc80c7779212a57aaa9bbca97b5567025b950a6a6b7170fb635745e3e0
4
- data.tar.gz: 7c3eca3a9da18aa6001791d2c5def0abacbf95b8b9baeb2be8920df804734bdd
3
+ metadata.gz: 6cca8a3428e516ba176e5a898a1d1a76cd57fa836041f0c3fc492a8cd394e88a
4
+ data.tar.gz: 9940b709ccce5e211444fe6b7cf84dfeed78f1c13591c9291b797a3eca4ac609
5
5
  SHA512:
6
- metadata.gz: a6dedb4d4413eab6222933b8096bf45c6fef7db7d51853e1a46ecaf51f4b718362bbe00776f5adfc3b3687dcf10fb6660b289d9dc930768dadfa5dc1bfbda1b9
7
- data.tar.gz: c822f36b904e46fd6075979dd3acca19ed1e91ddcf73a5adf93ca4ad261e2da5e5507866fe890641c116ecb4695e25b16281fd5aa54304b7328b50b5a4d55b34
6
+ metadata.gz: 1b9c3ae006ca76d0386db74a2fb39d106884dc0cd285457c05be6f3d3f75e2a30cc79511112d3881c532ba7e6e3c087e5e83e4116a708cf3cd81b4ea345de813
7
+ data.tar.gz: 659da027fb5c27df2c007dfd961bfce0148879aec3833f72c53f4d195080bde041b29c53260c397430e5425383a2c7a364e1ed8fd4d22bbabdb33417ecb896ed
@@ -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,25 @@
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
+ use_new_column? ? new_column : existing_column
11
+ end
12
+
13
+ private
14
+
15
+ attr_reader :uuid, :coordinates, :new_column
16
+
17
+ def use_new_column?
18
+ existing_column.nil? || new_column > existing_column
19
+ end
20
+
21
+ def existing_column
22
+ @existing_column ||= @coordinates.uuid_column(uuid)
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
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 occupied?(column, row, new_object_uuid)
39
+ positions.any? do |uuid, position|
40
+ position[:column] == column &&
41
+ position[:row] == row &&
42
+ new_object_uuid != uuid
43
+ end
44
+ end
45
+
46
+ def positions_in_column(column_number)
47
+ positions.select { |_, position| position[:column] == column_number }
48
+ end
49
+
50
+ private
51
+
52
+ attr_reader :flow
53
+ attr_writer :positions
54
+
55
+ def setup_positions
56
+ flow.keys.index_with { |_uuid| { row: nil, column: nil } }
57
+ end
58
+ end
59
+ 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 = setup_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
- add_columns
34
- add_rows
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 ||= @routes.map(&:row).max + 1
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,29 +123,47 @@ module MetadataPresenter
121
123
  end
122
124
  end
123
125
 
124
- def add_columns
126
+ def set_column_numbers
125
127
  @routes.each do |route|
126
- route.flow_uuids.each.with_index(route.column) do |uuid, column|
127
- column_number = @coordinates[uuid][:column]
128
- if column_number.nil? || column > column_number
129
- @coordinates[uuid][:column] = column
130
- end
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 add_rows
139
+ def set_row_numbers
136
140
  @routes.each do |route|
137
- next if @traversed.include?(route.traverse_from)
141
+ next if @traversed.include?(route.traverse_from) && appears_later_in_flow?(route)
138
142
 
143
+ current_row = route.row
139
144
  route.flow_uuids.each do |uuid|
140
- @coordinates[uuid][:row] = route.row if @coordinates[uuid][:row].nil?
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)
153
+
141
154
  update_route_rows(route, uuid)
142
155
  @traversed.push(uuid) unless @traversed.include?(uuid)
156
+ current_row = row_number
143
157
  end
144
158
  end
145
159
  end
146
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
+
147
167
  # Each Route object has a starting row. Each Route object has no knowledge
148
168
  # of other potential routes and pages/branches that may or may not exist in
149
169
  # them. The starting row may need to change dependent upon what has been
@@ -161,7 +181,8 @@ module MetadataPresenter
161
181
  end
162
182
 
163
183
  def add_by_coordinates
164
- @coordinates.each do |uuid, position|
184
+ service.flow.each_key do |uuid|
185
+ position = coordinates.position(uuid)
165
186
  next if detached?(position)
166
187
 
167
188
  @ordered[position[:column]][position[:row]] = get_flow_object(uuid)
@@ -219,37 +240,23 @@ module MetadataPresenter
219
240
  # the one the branch is located in.
220
241
  def insert_expression_spacers
221
242
  service.branches.each do |branch|
222
- position = @coordinates[branch.uuid]
223
- next if position[:row].nil? || position[:column].nil? # detached branch
243
+ next if coordinates.uuid_column(branch.uuid).nil?
224
244
 
225
- next_column = position[:column] + 1
226
- uuids = []
227
- exiting_destinations_from_branch(branch).each.with_index(position[:row]) do |uuid, row|
228
- if uuids.include?(uuid)
245
+ previous_uuid = ''
246
+ next_column = coordinates.uuid_column(branch.uuid) + 1
247
+ exiting_destinations_from_branch(branch).each_with_index do |uuid, row|
248
+ if uuid == previous_uuid
229
249
  @ordered[next_column].insert(row, MetadataPresenter::Spacer.new)
230
250
  end
231
-
232
- uuids.push(uuid) unless uuids.include?(uuid)
233
- end
234
- end
235
- end
236
-
237
- # The frontend requires that expressions of type 'or' get there own line and
238
- # arrow. 'and' expression types continue to be grouped together.
239
- # Return the UUIDs of the destinations exiting a branch and allow duplicates
240
- # if the expression type is an 'or'.
241
- def exiting_destinations_from_branch(branch)
242
- destination_uuids = branch.conditionals.map do |conditional|
243
- if conditional.type == 'or'
244
- conditional.expressions.map(&:next)
245
- else
246
- conditional.next
251
+ previous_uuid = uuid
247
252
  end
248
253
  end
249
- destination_uuids.flatten
250
254
  end
251
255
 
252
256
  # Any destinations exiting the branch that have not already been traversed.
257
+ # This removes any branch destinations that already exist on other rows. If
258
+ # that is the case then the arrow will flow towards whatever row that object
259
+ # is located.
253
260
  def routes_exiting_branch(branch)
254
261
  branch.all_destination_uuids.reject { |uuid| @traversed.include?(uuid) }
255
262
  end
@@ -0,0 +1,71 @@
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
+ if object_above.branch? && uuid != object_above.uuid
21
+ coordinates.uuid_row(object_above.uuid) + number_of_destinations
22
+ else
23
+ existing_row.nil? ? current_row : [current_row, existing_row].max
24
+ end
25
+ end
26
+
27
+ private
28
+
29
+ attr_reader :uuid, :route, :current_row, :coordinates, :service
30
+
31
+ def existing_row
32
+ @existing_row ||= coordinates.uuid_row(uuid)
33
+ end
34
+
35
+ def first_row?
36
+ @first_row ||= route.row.zero?
37
+ end
38
+
39
+ def object_above
40
+ @object_above ||=
41
+ service.flow_object(coordinates.uuid_at_position(uuid_column, row_above))
42
+ end
43
+
44
+ # Takes into account the 'or' type of conditionals which requires an
45
+ # additional spacer
46
+ def number_of_destinations
47
+ exiting_destinations_from_branch(object_above).count
48
+ end
49
+
50
+ def uuid_column
51
+ @uuid_column ||= coordinates.uuid_column(uuid)
52
+ end
53
+
54
+ def row_above
55
+ @row_above ||= route.row - 1
56
+ end
57
+
58
+ # If an object has already been positioned on row 0 then leave it there.
59
+ # If the object is a checkanswers or confirmation type then always place it
60
+ # on row 0.
61
+ def place_on_row_zero?
62
+ cya_or_confirmation_page? || coordinates.uuid_row(uuid) == ROW_ZERO
63
+ end
64
+
65
+ def cya_or_confirmation_page?
66
+ %w[page.checkanswers page.confirmation].include?(
67
+ service.find_page_by_uuid(uuid)&.type
68
+ )
69
+ end
70
+ end
71
+ end