govuk_publishing_components 21.56.0 → 21.58.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +6 -1
  3. data/app/assets/javascripts/govuk_publishing_components/components/details.js +2 -2
  4. data/app/assets/javascripts/govuk_publishing_components/components/print-link.js +14 -0
  5. data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
  6. data/app/assets/stylesheets/govuk_publishing_components/components/_action-link.scss +11 -5
  7. data/app/assets/stylesheets/govuk_publishing_components/components/_cookie-banner.scss +4 -0
  8. data/app/assets/stylesheets/govuk_publishing_components/components/_input.scss +9 -5
  9. data/app/assets/stylesheets/govuk_publishing_components/components/_list.scss +1 -0
  10. data/app/assets/stylesheets/govuk_publishing_components/components/_print-link.scss +52 -0
  11. data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +7 -2
  12. data/app/assets/stylesheets/govuk_publishing_components/components/print/_govspeak.scss +5 -1
  13. data/app/controllers/govuk_publishing_components/component_guide_controller.rb +1 -0
  14. data/app/views/govuk_publishing_components/component_guide/index.html.erb +5 -6
  15. data/app/views/govuk_publishing_components/components/_action_link.html.erb +2 -0
  16. data/app/views/govuk_publishing_components/components/_contextual_breadcrumbs.html.erb +11 -7
  17. data/app/views/govuk_publishing_components/components/_cookie_banner.html.erb +3 -1
  18. data/app/views/govuk_publishing_components/components/_input.html.erb +3 -4
  19. data/app/views/govuk_publishing_components/components/_list.html.erb +26 -0
  20. data/app/views/govuk_publishing_components/components/_print_link.html.erb +27 -0
  21. data/app/views/govuk_publishing_components/components/docs/action_link.yml +5 -0
  22. data/app/views/govuk_publishing_components/components/docs/input.yml +9 -1
  23. data/app/views/govuk_publishing_components/components/docs/list.yml +64 -0
  24. data/app/views/govuk_publishing_components/components/docs/print_link.yml +24 -0
  25. data/config/locales/en.yml +2 -0
  26. data/lib/govuk_publishing_components.rb +2 -1
  27. data/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb +50 -42
  28. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_ancestors.rb +41 -0
  29. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_priority.rb +1 -0
  30. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_taxons.rb +4 -0
  31. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_topic.rb +38 -0
  32. data/lib/govuk_publishing_components/presenters/contextual_navigation.rb +15 -4
  33. data/lib/govuk_publishing_components/presenters/page_with_step_by_step_navigation.rb +3 -1
  34. data/lib/govuk_publishing_components/presenters/related_navigation_helper.rb +18 -17
  35. data/lib/govuk_publishing_components/version.rb +1 -1
  36. data/node_modules/axe-core/CHANGELOG.md +11 -0
  37. data/node_modules/axe-core/axe.js +36 -9
  38. data/node_modules/axe-core/axe.min.js +2 -2
  39. data/node_modules/axe-core/bower.json +1 -1
  40. data/node_modules/axe-core/lib/checks/color/color-contrast.js +2 -2
  41. data/node_modules/axe-core/lib/checks/lists/listitem.js +1 -1
  42. data/node_modules/axe-core/lib/checks/mobile/meta-viewport-scale.js +3 -0
  43. data/node_modules/axe-core/lib/commons/dom/is-visible.js +37 -19
  44. data/node_modules/axe-core/lib/core/public/configure.js +26 -0
  45. data/node_modules/axe-core/lib/rules/aria-input-field-name.json +1 -1
  46. data/node_modules/axe-core/package.json +12 -12
  47. data/node_modules/axe-core/sri-history.json +4 -0
  48. metadata +25 -3
  49. data/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_parent.rb +0 -39
@@ -0,0 +1,64 @@
1
+ name: List
2
+ description: A list - unordered or ordered, with or without counters / bullet points.
3
+ body: |
4
+ This is an ordered or unordered list, with or without visible bullets / numbers.
5
+
6
+ The `items` parameter can include HTML to display - such as links or another
7
+ list. This HTML can either be directly coded or come from another component.
8
+ accessibility_criteria: |
9
+ The list must:
10
+
11
+ - inform the user how many items are in the list
12
+ - convey the content structure
13
+ - indicate the current page when contents span different pages, and not link to itself
14
+
15
+ The list may:
16
+
17
+ - include an `aria-label` to contextualise the list if helpful
18
+ govuk_frontend_components:
19
+ - list
20
+ examples:
21
+ default:
22
+ description: "The default is an unordered list with no bullet points or numbers."
23
+ data: &default-example-data
24
+ items:
25
+ - "Tony’s Chocolonely"
26
+ - '<a href="https://en.wikipedia.org/wiki/Cherry_Ripe_(chocolate_bar)" rel="noopener" class="govuk-link">Cherry Ripe</a>'
27
+ - "Snickers"
28
+ - "Chomp"
29
+ - "Penguin"
30
+ - "Boost"
31
+ unordered_list_with_aria-label:
32
+ description: "A list with an aria-label"
33
+ data:
34
+ aria_label: "A list of delicious chocolate bars."
35
+ <<: *default-example-data
36
+ unordered_list_with_bullet_points:
37
+ description: "An unordered list with visible bullet points."
38
+ data:
39
+ visible_counters: true
40
+ <<: *default-example-data
41
+ ordered_list_without_numbers:
42
+ description: "This is an ordered list where the numbers aren't visible."
43
+ data:
44
+ list_type: "number"
45
+ <<: *default-example-data
46
+ ordered_list_with_numbers:
47
+ description: |
48
+ This is an ordered list with the numbers visible.
49
+ data:
50
+ list_type: "number"
51
+ visible_counters: true
52
+ <<: *default-example-data
53
+ with_extra_spacing:
54
+ description: |
55
+ Increases the amount of spacing between the list items.
56
+ data:
57
+ extra_spacing: true
58
+ <<: *default-example-data
59
+ with_id_attribute:
60
+ description: |
61
+ Sets the `id` on the `ul` or `ol` element.
62
+ data:
63
+ id: 'super-fantastic-chocolate-list'
64
+ <<: *default-example-data
@@ -0,0 +1,24 @@
1
+ name: Print link
2
+ description: A link with a print icon to help users print the current page
3
+ body: |
4
+ This component renders two different outputs depending on whether a `href` is specified. By default, when no `href` is given, the component renders as a button and triggers a print action via JavaScript. In this case the component is hidden in environments where JavaScript is disabled and can be used as a progressive enhancement. When a `href` is specified the component renders as an anchor tag and navigates to that `href` without JavaScript, suitable for applications which have paths that trigger a print event on load.
5
+ accessibility_criteria: |
6
+ - The print icon must be presentational and ignored by screen readers.
7
+ shared_accessibility_criteria:
8
+ - link
9
+ examples:
10
+ default:
11
+ description: This component calls `print()` via the browser's DOM API. By default it relies on JavaScript and is not shown in environments where JavaScript is disabled. The \"link\" here is actually a button tag because this is not a navigation event.
12
+ with_different_text:
13
+ data:
14
+ text: "Print this manual"
15
+ with_different_href:
16
+ description: You can specify a alternative `href` URL that will override the default behaviour. When a `href` is specified the print link will render as an anchor tag and be displayed even when JavaScript is disabled.
17
+ data:
18
+ href: "/print"
19
+ with_data_attributes:
20
+ data:
21
+ data_attributes:
22
+ track-category: "printButton"
23
+ track-action: "clicked"
24
+ track-label: "Print this page"
@@ -58,6 +58,8 @@ en:
58
58
  policies: "Policies"
59
59
  statistical_data_sets: "Statistical data sets"
60
60
  topical_events: "Topical events"
61
+ print_link:
62
+ text: "Print this page"
61
63
  skip_link:
62
64
  text: "Skip to main content"
63
65
  step_by_step_nav:
@@ -12,9 +12,10 @@ require "govuk_publishing_components/presenters/contextual_navigation"
12
12
  require "govuk_publishing_components/presenters/related_navigation_helper"
13
13
  require "govuk_publishing_components/presenters/step_by_step_nav_helper"
14
14
  require "govuk_publishing_components/presenters/page_with_step_by_step_navigation"
15
- require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_parent"
15
+ require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_ancestors"
16
16
  require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_priority"
17
17
  require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_taxons"
18
+ require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_topic"
18
19
  require "govuk_publishing_components/presenters/checkboxes_helper"
19
20
  require "govuk_publishing_components/presenters/select"
20
21
  require "govuk_publishing_components/presenters/meta_tags"
@@ -1,10 +1,6 @@
1
1
  module GovukPublishingComponents
2
2
  module Presenters
3
3
  class BreadcrumbSelector
4
- def self.call(*args)
5
- new(*args).output
6
- end
7
-
8
4
  attr_reader :content_item, :request, :prioritise_taxon_breadcrumbs
9
5
 
10
6
  def initialize(content_item, request, prioritise_taxon_breadcrumbs)
@@ -13,47 +9,28 @@ module GovukPublishingComponents
13
9
  @prioritise_taxon_breadcrumbs = prioritise_taxon_breadcrumbs
14
10
  end
15
11
 
16
- def content_item_navigation
17
- @content_item_navigation ||= ContextualNavigation.new(content_item, request)
12
+ def breadcrumbs
13
+ best_match_option[:breadcrumbs]
18
14
  end
19
15
 
20
- def parent_item_navigation
21
- @parent_item_navigation ||= ContextualNavigation.new(parent_item, request)
16
+ def step_by_step
17
+ best_match_option[:step_by_step]
22
18
  end
23
19
 
24
- def parent_item
25
- @parent_item ||= Services.content_store.content_item(content_item_navigation.parent_api_path)
26
- rescue GdsApi::ContentStore::ItemNotFound
27
- # Do nothing
28
- end
20
+ def priority_breadcrumbs
21
+ return parent_item_navigation.priority_breadcrumbs if content_item_navigation.html_publication_with_parent?
29
22
 
30
- def parent_item_options
31
- @parent_item_options ||= options(parent_item_navigation)
23
+ content_item_navigation.priority_breadcrumbs
32
24
  end
33
25
 
34
- def content_item_options
35
- @content_item_options ||= options(content_item_navigation)
36
- end
26
+ private
37
27
 
38
- def parent_breadcrumbs
39
- breadcrumbs = [parent_item_options[:breadcrumbs]].flatten # to ensure breadcrumbs always an array
40
- breadcrumbs.last[:is_page_parent] = false
41
- breadcrumbs << {
42
- title: parent_item["title"],
43
- url: parent_item["base_path"],
44
- is_page_parent: true,
45
- }
46
- end
47
-
48
- def output
28
+ def best_match_option
49
29
  return content_item_options unless content_item_navigation.html_publication_with_parent?
50
- return parent_item_options if parent_item_navigation.priority_breadcrumbs
51
-
52
- step_by_step_header = parent_item_options[:step_by_step]
53
30
 
54
31
  {
55
- step_by_step: step_by_step_header,
56
- breadcrumbs: step_by_step_header ? parent_breadcrumbs.first : parent_breadcrumbs,
32
+ step_by_step: parent_is_step_by_step?,
33
+ breadcrumbs: parent_is_step_by_step? ? parent_breadcrumbs.first : parent_breadcrumbs,
57
34
  }
58
35
  end
59
36
 
@@ -61,18 +38,13 @@ module GovukPublishingComponents
61
38
  if navigation.content_tagged_to_a_finder?
62
39
  {
63
40
  step_by_step: false,
64
- breadcrumbs: navigation.breadcrumbs,
41
+ breadcrumbs: navigation.finder_breadcrumbs,
65
42
  }
66
43
  elsif navigation.content_tagged_to_current_step_by_step?
67
44
  {
68
45
  step_by_step: true,
69
46
  breadcrumbs: navigation.step_nav_helper.header,
70
47
  }
71
- elsif navigation.priority_breadcrumbs
72
- {
73
- step_by_step: true,
74
- breadcrumbs: navigation.priority_breadcrumbs,
75
- }
76
48
  elsif navigation.content_is_tagged_to_a_live_taxon? && prioritise_taxon_breadcrumbs
77
49
  {
78
50
  step_by_step: false,
@@ -83,10 +55,10 @@ module GovukPublishingComponents
83
55
  step_by_step: false,
84
56
  breadcrumbs: navigation.breadcrumbs,
85
57
  }
86
- elsif navigation.content_has_curated_related_items?
58
+ elsif navigation.content_has_a_topic?
87
59
  {
88
60
  step_by_step: false,
89
- breadcrumbs: navigation.breadcrumbs,
61
+ breadcrumbs: navigation.topic_breadcrumbs,
90
62
  }
91
63
  elsif navigation.use_taxon_breadcrumbs?
92
64
  {
@@ -102,6 +74,42 @@ module GovukPublishingComponents
102
74
  {}
103
75
  end
104
76
  end
77
+
78
+ def content_item_navigation
79
+ @content_item_navigation ||= ContextualNavigation.new(content_item, request)
80
+ end
81
+
82
+ def parent_item_navigation
83
+ @parent_item_navigation ||= ContextualNavigation.new(parent_item, request)
84
+ end
85
+
86
+ def parent_item
87
+ @parent_item ||= Services.content_store.content_item(content_item_navigation.parent_api_path)
88
+ rescue GdsApi::ContentStore::ItemNotFound
89
+ # Do nothing
90
+ end
91
+
92
+ def parent_item_options
93
+ @parent_item_options ||= options(parent_item_navigation)
94
+ end
95
+
96
+ def content_item_options
97
+ @content_item_options ||= options(content_item_navigation)
98
+ end
99
+
100
+ def parent_breadcrumbs
101
+ breadcrumbs = [parent_item_options[:breadcrumbs]].flatten # to ensure breadcrumbs always an array
102
+ breadcrumbs.last[:is_page_parent] = false
103
+ breadcrumbs << {
104
+ title: parent_item["title"],
105
+ url: parent_item["base_path"],
106
+ is_page_parent: true,
107
+ }
108
+ end
109
+
110
+ def parent_is_step_by_step?
111
+ parent_item_options[:step_by_step]
112
+ end
105
113
  end
106
114
  end
107
115
  end
@@ -0,0 +1,41 @@
1
+ module GovukPublishingComponents
2
+ module Presenters
3
+ # @private
4
+ class ContentBreadcrumbsBasedOnAncestors
5
+ def self.call(content_item)
6
+ new(content_item).breadcrumbs
7
+ end
8
+
9
+ def initialize(content_item)
10
+ @content_item = ContentItem.new(content_item)
11
+ end
12
+
13
+ def breadcrumbs
14
+ ordered_ancestors = all_ancestors.map do |ancestor|
15
+ { title: ancestor.title, url: ancestor.base_path }
16
+ end
17
+
18
+ ordered_ancestors << { title: "Home", url: "/" }
19
+ ordered_ancestors.reverse!
20
+ ordered_ancestors
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :content_item
26
+
27
+ def all_ancestors
28
+ ancestors = []
29
+
30
+ parent = content_item.parent
31
+ while parent
32
+ ancestors << parent
33
+
34
+ parent = parent.parent
35
+ end
36
+
37
+ ancestors
38
+ end
39
+ end
40
+ end
41
+ end
@@ -6,6 +6,7 @@ module GovukPublishingComponents
6
6
  # and the bottom one the lowest priority
7
7
  PRIORITY_TAXONS = {
8
8
  education_coronavirus: "272308f4-05c8-4d0d-abc7-b7c2e3ccd249",
9
+ worker_coronavirus: "b7f57213-4b16-446d-8ded-81955d782680",
9
10
  business_coronavirus: "65666cdf-b177-4d79-9687-b9c32805e450",
10
11
  }.freeze
11
12
 
@@ -2,6 +2,10 @@ module GovukPublishingComponents
2
2
  module Presenters
3
3
  # @private
4
4
  class ContentBreadcrumbsBasedOnTaxons
5
+ def self.call(content_item)
6
+ new(content_item).breadcrumbs
7
+ end
8
+
5
9
  def initialize(content_item)
6
10
  @content_item = ContentItem.new(content_item)
7
11
  end
@@ -0,0 +1,38 @@
1
+ module GovukPublishingComponents
2
+ module Presenters
3
+ class ContentBreadcrumbsBasedOnTopic
4
+ def self.call(content_item)
5
+ new(content_item).breadcrumbs
6
+ end
7
+
8
+ attr_reader :content_item
9
+
10
+ def initialize(content_item)
11
+ @content_item = content_item
12
+ end
13
+
14
+ def breadcrumbs
15
+ breadcrumbs = [{ title: "Home", url: "/" }]
16
+ return breadcrumbs unless topics.present?
17
+
18
+ breadcrumbs << topic_breadcrumb
19
+ breadcrumbs
20
+ end
21
+
22
+ def topic_breadcrumb
23
+ {
24
+ title: first_topic["title"],
25
+ url: first_topic["base_path"],
26
+ }
27
+ end
28
+
29
+ def first_topic
30
+ topics.first
31
+ end
32
+
33
+ def topics
34
+ @topics ||= content_item.dig("links", "topics")
35
+ end
36
+ end
37
+ end
38
+ end
@@ -26,15 +26,22 @@ module GovukPublishingComponents
26
26
  end
27
27
 
28
28
  def taxon_breadcrumbs
29
- @taxon_breadcrumbs ||= ContentBreadcrumbsBasedOnTaxons.new(content_item).breadcrumbs
29
+ @taxon_breadcrumbs ||= ContentBreadcrumbsBasedOnTaxons.call(content_item)
30
30
  end
31
31
 
32
32
  def priority_breadcrumbs
33
33
  @priority_breadcrumbs ||= ContentBreadcrumbsBasedOnPriority.call(content_item)
34
34
  end
35
35
 
36
+ def topic_breadcrumbs
37
+ @topic_breadcrumbs ||= ContentBreadcrumbsBasedOnTopic.call(content_item)
38
+ end
39
+
36
40
  def breadcrumbs
37
- return breadcrumbs_based_on_parent unless content_tagged_to_a_finder?
41
+ breadcrumbs_based_on_ancestors
42
+ end
43
+
44
+ def finder_breadcrumbs
38
45
  return [] unless parent_finder
39
46
 
40
47
  [
@@ -77,6 +84,10 @@ module GovukPublishingComponents
77
84
  content_item["document_type"] == "html_publication"
78
85
  end
79
86
 
87
+ def content_has_a_topic?
88
+ content_item.dig("links", "topics").present?
89
+ end
90
+
80
91
  def tagged_to_brexit?
81
92
  taxons = content_item.dig("links", "taxons").to_a
82
93
  brexit_taxon = "d6c2de5d-ef90-45d1-82d4-5f2438369eea"
@@ -119,8 +130,8 @@ module GovukPublishingComponents
119
130
  step_nav_helper.show_also_part_of_step_nav?
120
131
  end
121
132
 
122
- def breadcrumbs_based_on_parent
123
- ContentBreadcrumbsBasedOnParent.new(content_item).breadcrumbs[:breadcrumbs]
133
+ def breadcrumbs_based_on_ancestors
134
+ ContentBreadcrumbsBasedOnAncestors.call(content_item)
124
135
  end
125
136
 
126
137
  def step_nav_helper
@@ -3,6 +3,8 @@ module GovukPublishingComponents
3
3
  # @private
4
4
  # Only used by the step by step component
5
5
  class PageWithStepByStepNavigation
6
+ MAX_SECTION_LENGTH = RelatedNavigationHelper::MAX_SECTION_LENGTH
7
+
6
8
  def initialize(content_store_response, current_path, query_parameters = {})
7
9
  @content_item = content_store_response.to_h.deep_symbolize_keys
8
10
  @current_path = current_path
@@ -48,7 +50,7 @@ module GovukPublishingComponents
48
50
  end
49
51
 
50
52
  def show_also_part_of_step_nav?
51
- active_step_by_step? && also_part_of_step_nav.any? && step_navs_combined_list.count < 5
53
+ active_step_by_step? && also_part_of_step_nav.any? && step_navs_combined_list.count < MAX_SECTION_LENGTH
52
54
  end
53
55
 
54
56
  def related_links
@@ -31,7 +31,7 @@ module GovukPublishingComponents
31
31
  }
32
32
  when :footer
33
33
  {
34
- "topics" => related_topics,
34
+ "topics" => related_topics_or_taxons,
35
35
  "topical_events" => related_topical_events,
36
36
  "world_locations" => related_world_locations,
37
37
  "statistical_data_sets" => related_statistical_data_sets,
@@ -43,7 +43,7 @@ module GovukPublishingComponents
43
43
  "related_items" => related_items,
44
44
  "related_guides" => related_guides,
45
45
  "collections" => related_document_collections,
46
- "topics" => related_topics,
46
+ "topics" => related_topics_or_taxons,
47
47
  "topical_events" => related_topical_events,
48
48
  "world_locations" => related_world_locations,
49
49
  "statistical_data_sets" => related_statistical_data_sets,
@@ -162,26 +162,27 @@ module GovukPublishingComponents
162
162
  end
163
163
 
164
164
  def related_taxons
165
- content_item_links_for("taxons", only: "taxon")
165
+ @related_taxons ||= content_item_links_for("taxons", only: "taxon")
166
166
  end
167
167
 
168
- def related_topics
169
- if related_legacy_topics.any?
170
- related_legacy_topics
171
- elsif related_taxons.any?
172
- related_taxons
173
- else
174
- []
175
- end
168
+ def related_topics_or_taxons
169
+ return related_topics if related_topics.any?
170
+ return related_taxons if related_taxons.any?
171
+
172
+ []
176
173
  end
177
174
 
178
- def related_legacy_topics
179
- mainstream_browse_page_links = content_item_links_for("mainstream_browse_pages", only: "mainstream_browse_page")
180
- topic_links = content_item_links_for("topics", only: "topic")
175
+ def related_topics
176
+ @related_topics ||= begin
177
+ mainstream_browse_page_links = content_item_links_for("mainstream_browse_pages", only: "mainstream_browse_page")
178
+ topic_links = content_item_links_for("topics", only: "topic")
179
+
180
+ return topic_links if topic_links.present? && mainstream_browse_page_links.empty?
181
181
 
182
- mainstream_browse_page_links + topic_links.find_all do |topic_link|
183
- mainstream_browse_page_links.none? do |mainstream_browse_page_link|
184
- mainstream_browse_page_link[:text] == topic_link[:text]
182
+ mainstream_browse_page_links + topic_links.find_all do |topic_link|
183
+ mainstream_browse_page_links.none? do |mainstream_browse_page_link|
184
+ mainstream_browse_page_link[:text] == topic_link[:text]
185
+ end
185
186
  end
186
187
  end
187
188
  end