govuk_publishing_components 21.56.2 → 21.60.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +31 -6
  3. data/app/assets/javascripts/component_guide/accessibility-test.js +21 -21
  4. data/app/assets/javascripts/component_guide/filter-components.js +19 -19
  5. data/app/assets/javascripts/component_guide/visual-regression.js +38 -37
  6. data/app/assets/javascripts/govuk_publishing_components/components/checkboxes.js +2 -2
  7. data/app/assets/javascripts/govuk_publishing_components/components/details.js +6 -4
  8. data/app/assets/javascripts/govuk_publishing_components/components/print-link.js +14 -0
  9. data/app/assets/javascripts/govuk_publishing_components/components/step-by-step-nav.js +4 -4
  10. data/app/assets/javascripts/govuk_publishing_components/lib/auto-track-event.js +31 -0
  11. data/app/assets/javascripts/govuk_publishing_components/lib/cookie-functions.js +24 -24
  12. data/app/assets/javascripts/govuk_publishing_components/lib/govspeak/youtube-link-enhancement.js +17 -17
  13. data/app/assets/stylesheets/component_guide/application.scss +15 -15
  14. data/app/assets/stylesheets/govuk_publishing_components/_all_components.scss +1 -0
  15. data/app/assets/stylesheets/govuk_publishing_components/components/_action-link.scss +9 -11
  16. data/app/assets/stylesheets/govuk_publishing_components/components/_breadcrumbs.scss +1 -1
  17. data/app/assets/stylesheets/govuk_publishing_components/components/_checkboxes.scss +4 -0
  18. data/app/assets/stylesheets/govuk_publishing_components/components/_cookie-banner.scss +5 -8
  19. data/app/assets/stylesheets/govuk_publishing_components/components/_feedback.scss +0 -1
  20. data/app/assets/stylesheets/govuk_publishing_components/components/_govspeak-html-publication.scss +4 -5
  21. data/app/assets/stylesheets/govuk_publishing_components/components/_heading.scss +3 -8
  22. data/app/assets/stylesheets/govuk_publishing_components/components/_image-card.scss +1 -1
  23. data/app/assets/stylesheets/govuk_publishing_components/components/_input.scss +1 -1
  24. data/app/assets/stylesheets/govuk_publishing_components/components/_inverse-header.scss +5 -8
  25. data/app/assets/stylesheets/govuk_publishing_components/components/_list.scss +1 -0
  26. data/app/assets/stylesheets/govuk_publishing_components/components/_print-link.scss +52 -0
  27. data/app/assets/stylesheets/govuk_publishing_components/components/_radio.scss +4 -0
  28. data/app/assets/stylesheets/govuk_publishing_components/components/_related-navigation.scss +2 -2
  29. data/app/assets/stylesheets/govuk_publishing_components/components/_search.scss +7 -3
  30. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-header.scss +0 -5
  31. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav-related.scss +1 -4
  32. data/app/assets/stylesheets/govuk_publishing_components/components/_step-by-step-nav.scss +8 -12
  33. data/app/assets/stylesheets/govuk_publishing_components/components/_table.scss +21 -24
  34. data/app/assets/stylesheets/govuk_publishing_components/components/_tabs.scss +4 -8
  35. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_attachment.scss +2 -0
  36. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_button.scss +1 -4
  37. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_charts.scss +2 -4
  38. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_contact.scss +2 -0
  39. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_footnotes.scss +2 -0
  40. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_highlight-answer.scss +2 -0
  41. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_place.scss +1 -1
  42. data/app/assets/stylesheets/govuk_publishing_components/components/govspeak/_typography.scss +2 -0
  43. data/app/assets/stylesheets/govuk_publishing_components/components/helpers/_markdown-typography.scss +1 -1
  44. data/app/assets/stylesheets/govuk_publishing_components/components/print/_govspeak.scss +7 -1
  45. data/app/assets/stylesheets/govuk_publishing_components/components/print/_step-by-step-nav-header.scss +0 -4
  46. data/app/assets/stylesheets/govuk_publishing_components/components/print/_step-by-step-nav.scss +2 -10
  47. data/app/controllers/govuk_publishing_components/audit_controller.rb +52 -0
  48. data/app/controllers/govuk_publishing_components/component_guide_controller.rb +2 -1
  49. data/app/models/govuk_publishing_components/audit_applications.rb +105 -0
  50. data/app/models/govuk_publishing_components/audit_comparer.rb +185 -0
  51. data/app/models/govuk_publishing_components/audit_components.rb +158 -0
  52. data/app/views/govuk_publishing_components/audit/show.html.erb +229 -0
  53. data/app/views/govuk_publishing_components/component_guide/index.html.erb +9 -4
  54. data/app/views/govuk_publishing_components/components/_action_link.html.erb +2 -0
  55. data/app/views/govuk_publishing_components/components/_breadcrumbs.html.erb +1 -1
  56. data/app/views/govuk_publishing_components/components/_cookie_banner.html.erb +3 -1
  57. data/app/views/govuk_publishing_components/components/_list.html.erb +26 -0
  58. data/app/views/govuk_publishing_components/components/_machine_readable_metadata.html.erb +1 -1
  59. data/app/views/govuk_publishing_components/components/_print_link.html.erb +27 -0
  60. data/app/views/govuk_publishing_components/components/_radio.html.erb +13 -5
  61. data/app/views/govuk_publishing_components/components/_step_by_step_nav_header.html.erb +2 -2
  62. data/app/views/govuk_publishing_components/components/docs/action_link.yml +5 -0
  63. data/app/views/govuk_publishing_components/components/docs/checkboxes.yml +4 -0
  64. data/app/views/govuk_publishing_components/components/docs/heading.yml +6 -3
  65. data/app/views/govuk_publishing_components/components/docs/list.yml +64 -0
  66. data/app/views/govuk_publishing_components/components/docs/print_link.yml +24 -0
  67. data/app/views/govuk_publishing_components/components/docs/radio.yml +4 -0
  68. data/config/locales/en.yml +2 -0
  69. data/config/routes.rb +1 -0
  70. data/lib/govuk_publishing_components/presenters/checkboxes_helper.rb +15 -7
  71. data/lib/govuk_publishing_components/presenters/heading_helper.rb +21 -1
  72. data/lib/govuk_publishing_components/version.rb +1 -1
  73. data/node_modules/axe-core/package.json +145 -220
  74. data/node_modules/govuk-frontend/package.json +14 -81
  75. data/node_modules/jquery/package.json +44 -116
  76. metadata +50 -66
  77. data/Rakefile +0 -32
@@ -83,8 +83,9 @@ module GovukPublishingComponents
83
83
  def components_in_use
84
84
  matches = []
85
85
 
86
- files = Dir["#{@application_path}/app/views/**/*.html.erb"]
86
+ files = Dir["#{@application_path}/app/views/**/*.erb"]
87
87
  files.concat Dir["#{@application_path}/app/**/*.rb"]
88
+ files.concat Dir["#{@application_path}/lib/**/*.{rb,erb}"]
88
89
 
89
90
  files.each do |file|
90
91
  data = File.read(file)
@@ -0,0 +1,105 @@
1
+ module GovukPublishingComponents
2
+ class AuditApplications
3
+ attr_reader :data
4
+
5
+ def initialize(path, name)
6
+ templates = Dir["#{path}/app/views/**/*.erb"]
7
+ stylesheets = Dir["#{path}/app/assets/stylesheets/**/*.scss"]
8
+ javascripts = Dir["#{path}/app/assets/javascripts/**/*.js"]
9
+
10
+ find_components = /(?<=govuk_publishing_components\/components\/)[\/a-zA-Z_-]+(?=['"])/
11
+
12
+ @find_all_stylesheets = /@import ["']{1}govuk_publishing_components\/all_components/
13
+ find_stylesheets = /(?<=@import ["']{1}govuk_publishing_components\/components\/)(?!print\/)+[a-zA-Z_-]+(?=['"])/
14
+
15
+ @find_all_print_stylesheets = /@import ["']{1}govuk_publishing_components\/all_components_print/
16
+ find_print_stylesheets = /(?<=@import ["']{1}govuk_publishing_components\/components\/print\/)[a-zA-Z_-]+(?=['"])/
17
+
18
+ @find_all_javascripts = /\/\/[ ]*= require govuk_publishing_components\/all_components/
19
+ find_javascripts = /(?<=require govuk_publishing_components\/components\/)[a-zA-Z_-]+/
20
+
21
+ components_in_templates = find_components(templates, find_components, "templates") || []
22
+ components_in_stylesheets = find_components(stylesheets, find_stylesheets, "stylesheets") || []
23
+ components_in_print_stylesheets = find_components(stylesheets, find_print_stylesheets, "print_stylesheets") || []
24
+ components_in_javascripts = find_components(javascripts, find_javascripts, "javascripts") || []
25
+
26
+ ruby_paths = %w[/app/helpers/ /app/presenters/ /lib/]
27
+ components_in_ruby = []
28
+ ruby_paths.each do |ruby_path|
29
+ components_in_ruby << find_components(Dir["#{path}#{ruby_path}**/*.{rb,erb}"], find_components, "ruby") || []
30
+ end
31
+ components_in_ruby = components_in_ruby.flatten.uniq
32
+
33
+ application_found = application_exists(path)
34
+ components_found = []
35
+
36
+ if application_found
37
+ components_found = [
38
+ {
39
+ location: "templates",
40
+ components: components_in_templates,
41
+ },
42
+ {
43
+ location: "stylesheets",
44
+ components: components_in_stylesheets,
45
+ },
46
+ {
47
+ location: "print_stylesheets",
48
+ components: components_in_print_stylesheets,
49
+ },
50
+ {
51
+ location: "javascripts",
52
+ components: components_in_javascripts,
53
+ },
54
+ {
55
+ location: "ruby",
56
+ components: components_in_ruby,
57
+ },
58
+ ]
59
+ end
60
+
61
+ @data = {
62
+ name: name,
63
+ application_found: application_found,
64
+ components_found: components_found,
65
+ }
66
+ end
67
+
68
+ private
69
+
70
+ def find_components(files, find, type)
71
+ components_found = []
72
+
73
+ files.each do |file|
74
+ src = File.read(file)
75
+ components_found << find_match(find, src, type)
76
+ rescue StandardError
77
+ puts "File #{file} not found"
78
+ end
79
+
80
+ components_found.flatten.uniq.sort
81
+ end
82
+
83
+ def find_match(find, src, type)
84
+ return %w[all] if src.match(@find_all_stylesheets) && type == "stylesheets"
85
+ return %w[all] if src.match(@find_all_print_stylesheets) && type == "print_stylesheets"
86
+ return %w[all] if src.match(@find_all_javascripts) && type == "javascripts"
87
+
88
+ matches = src.scan(find)
89
+ all_matches = []
90
+ matches.each do |match|
91
+ all_matches << clean_file_name(match.tr('[])\'"', ""))
92
+ end
93
+
94
+ all_matches
95
+ end
96
+
97
+ def clean_file_name(name)
98
+ name.tr("_-", " ").strip
99
+ end
100
+
101
+ def application_exists(directory)
102
+ File.directory?(directory)
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,185 @@
1
+ module GovukPublishingComponents
2
+ class AuditComparer
3
+ attr_reader :applications_data, :gem_data
4
+
5
+ def initialize(gem_data, results)
6
+ if gem_data[:gem_found]
7
+ @gem_data = gem_data
8
+ @applications_data = sort_results(results)
9
+ @gem_data[:components_by_application] = get_components_by_application || []
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def prettify_key(key)
16
+ key.to_s.gsub("_", " ").capitalize
17
+ end
18
+
19
+ def sort_results(results)
20
+ data = []
21
+
22
+ results.each do |result|
23
+ if result[:application_found]
24
+ templates = result[:components_found].find { |c| c[:location] == "templates" }
25
+ stylesheets = result[:components_found].find { |c| c[:location] == "stylesheets" }
26
+ print_stylesheets = result[:components_found].find { |c| c[:location] == "print_stylesheets" }
27
+ javascripts = result[:components_found].find { |c| c[:location] == "javascripts" }
28
+ ruby = result[:components_found].find { |c| c[:location] == "ruby" }
29
+
30
+ @all_stylesheets = true if stylesheets[:components].include?("all")
31
+ @all_print_stylesheets = true if print_stylesheets[:components].include?("all")
32
+ @all_javascripts = true if javascripts[:components].include?("all")
33
+
34
+ templates[:components] = include_any_components_within_components(templates[:components])
35
+
36
+ warnings = []
37
+ warnings << warn_about_missing_components(result[:components_found])
38
+ warnings << warn_about_missing_assets(result[:components_found])
39
+ warnings = warnings.flatten
40
+
41
+ data << {
42
+ name: result[:name],
43
+ application_found: result[:application_found],
44
+ summary: [
45
+ {
46
+ name: "Components in templates",
47
+ value: templates[:components].flatten.uniq.sort.join(", "),
48
+ },
49
+ {
50
+ name: "Components in stylesheets",
51
+ value: stylesheets[:components].join(", "),
52
+ },
53
+ {
54
+ name: "Components in print stylesheets",
55
+ value: print_stylesheets[:components].join(", "),
56
+ },
57
+ {
58
+ name: "Components in javascripts",
59
+ value: javascripts[:components].join(", "),
60
+ },
61
+ {
62
+ name: "Components in ruby",
63
+ value: ruby[:components].join(", "),
64
+ },
65
+ ],
66
+ warnings: warnings,
67
+ warning_count: warnings.length,
68
+ }
69
+ else
70
+ data << {
71
+ name: result[:name],
72
+ application_found: result[:application_found],
73
+ }
74
+ end
75
+ end
76
+
77
+ data
78
+ end
79
+
80
+ def include_any_components_within_components(components)
81
+ @gem_data[:components_containing_components].each do |component|
82
+ components << component[:sub_components] if components.include?(component[:component])
83
+ end
84
+
85
+ components.flatten.uniq.sort
86
+ end
87
+
88
+ def create_warning(component, message)
89
+ {
90
+ component: component,
91
+ message: message,
92
+ }
93
+ end
94
+
95
+ def find_missing_items(first_group, second_group)
96
+ warnings = []
97
+
98
+ first_group.each do |first|
99
+ first_location = first[:location]
100
+
101
+ second_group.each do |second|
102
+ second_location = second[:location]
103
+ second_location = "code" if %w[templates ruby].include?(second_location)
104
+ in_current = find_missing(second[:components].clone, first[:components].clone)
105
+
106
+ next if second[:components].include?("all")
107
+
108
+ in_current.each do |component|
109
+ if @gem_data.include?("component_#{second_location}".to_sym)
110
+ warnings << create_warning(component, "Included in #{first_location} but not #{second_location}") if @gem_data["component_#{second_location}".to_sym].include?(component)
111
+ end
112
+ end
113
+ end
114
+ end
115
+
116
+ warnings
117
+ end
118
+
119
+ def warn_about_missing_assets(components)
120
+ warnings = []
121
+
122
+ code = components.select { |c| c[:location] == "templates" || c[:location] == "ruby" }
123
+ code = [
124
+ {
125
+ location: "code",
126
+ components: code.map { |c| c[:components] }.flatten.uniq.sort,
127
+ },
128
+ ]
129
+ assets = components.select { |c| c[:location] == "stylesheets" || c[:location] == "print_stylesheets" || c[:location] == "javascripts" }
130
+
131
+ warnings << find_missing_items(code, assets)
132
+ warnings << find_missing_items(assets, code)
133
+ warnings.flatten
134
+ end
135
+
136
+ def warn_about_missing_components(results)
137
+ warnings = []
138
+
139
+ results.each do |result|
140
+ location = result[:location]
141
+ result[:components].each do |component|
142
+ warnings << create_warning(component, "Included in #{location} but component does not exist") if component_does_not_exist(component)
143
+ end
144
+ end
145
+
146
+ warnings
147
+ end
148
+
149
+ def component_does_not_exist(component)
150
+ !@gem_data[:component_code].include?(component) unless component == "all"
151
+ end
152
+
153
+ def find_missing(needle, haystack)
154
+ (haystack - needle).flatten.sort
155
+ end
156
+
157
+ def get_components_by_application
158
+ results = []
159
+ found_something = false
160
+
161
+ @gem_data[:component_listing].each do |component|
162
+ found_in_applications = []
163
+
164
+ @applications_data.each do |application|
165
+ next unless application[:application_found]
166
+
167
+ name = application[:name]
168
+ found_something = true
169
+
170
+ application[:summary].each do |item|
171
+ found_in_applications << name if item[:value].include?(component[:name])
172
+ end
173
+ end
174
+
175
+ results << {
176
+ component: component[:name],
177
+ count: found_in_applications.uniq.length,
178
+ list: found_in_applications.uniq.join(", "),
179
+ }
180
+ end
181
+
182
+ results if found_something
183
+ end
184
+ end
185
+ end
@@ -0,0 +1,158 @@
1
+ module GovukPublishingComponents
2
+ class AuditComponents
3
+ attr_reader :data
4
+
5
+ def initialize(path)
6
+ @data = {
7
+ gem_found: false,
8
+ }
9
+ @data = compile_data(path) if Dir.exist?(path)
10
+ end
11
+
12
+ private
13
+
14
+ def compile_data(path)
15
+ templates_path = "app/views/govuk_publishing_components/components"
16
+ stylesheets_path = "app/assets/stylesheets/govuk_publishing_components/components"
17
+ print_stylesheets_path = "app/assets/stylesheets/govuk_publishing_components/components/print"
18
+ javascripts_path = "app/assets/javascripts/govuk_publishing_components/components"
19
+ tests_path = "spec/components"
20
+ js_tests_path = "spec/javascripts/components"
21
+
22
+ templates = Dir["#{path}/#{templates_path}/*.erb"]
23
+ stylesheets = Dir["#{path}/#{stylesheets_path}/*.scss"]
24
+ print_stylesheets = Dir["#{path}/#{print_stylesheets_path}/*.scss"]
25
+ javascripts = Dir["#{path}/#{javascripts_path}/*.js"]
26
+ tests = Dir["#{path}/#{tests_path}/*.rb"]
27
+ js_tests = Dir["#{path}/#{js_tests_path}/*.js"]
28
+
29
+ @templates_full_path = "#{path}/#{templates_path}/"
30
+
31
+ @components = find_files(templates, [path, templates_path].join("/"))
32
+ @component_stylesheets = find_files(stylesheets, [path, stylesheets_path].join("/"))
33
+ @component_print_stylesheets = find_files(print_stylesheets, [path, print_stylesheets_path].join("/"))
34
+ @component_javascripts = find_files(javascripts, [path, javascripts_path].join("/"))
35
+ @component_tests = find_files(tests, [path, tests_path].join("/"))
36
+ @component_js_tests = find_files(js_tests, [path, js_tests_path].join("/"))
37
+
38
+ {
39
+ gem_found: true,
40
+ component_code: @components,
41
+ component_stylesheets: @component_stylesheets,
42
+ component_print_stylesheets: @component_print_stylesheets,
43
+ component_javascripts: @component_javascripts,
44
+ component_tests: @component_tests,
45
+ component_js_tests: @component_js_tests,
46
+ components_containing_components: find_all_partials_in(templates),
47
+ component_listing: list_all_component_details,
48
+ }
49
+ end
50
+
51
+ def find_files(files, replace)
52
+ files.map { |file| clean_file_name(file.gsub(replace, "")) }.sort
53
+ end
54
+
55
+ def clean_file_name(name)
56
+ name.tr("/_-", " ")
57
+ .gsub(".html.erb", "")
58
+ .gsub(".erb", "")
59
+ .gsub(".scss", "")
60
+ .gsub(".js", "")
61
+ .gsub("spec", "")
62
+ .gsub(".rb", "")
63
+ .strip
64
+ end
65
+
66
+ def get_component_name_from_full_path(path)
67
+ path.gsub("/_", "/")
68
+ .gsub(@templates_full_path, "")
69
+ .gsub(".html.erb", "")
70
+ .gsub(".erb", "")
71
+ .tr('\"\'', "")
72
+ end
73
+
74
+ def get_component_link(component)
75
+ "/component-guide/#{component.gsub(' ', '_')}"
76
+ end
77
+
78
+ def find_all_partials_in(templates)
79
+ components = []
80
+
81
+ templates.each do |template|
82
+ partials_found = true
83
+ components_to_search = [template]
84
+ components_found = []
85
+
86
+ while partials_found
87
+ extra_components = find_partials_in(components_to_search)
88
+
89
+ if extra_components.any?
90
+ components_found << extra_components
91
+ components_to_search = extra_components
92
+ else
93
+ partials_found = false
94
+ components_found = components_found.flatten.reject { |c| c.include?("/") }
95
+
96
+ if components_found.any?
97
+ component_name = clean_file_name(get_component_name_from_full_path(template))
98
+ components << {
99
+ component: component_name,
100
+ link: get_component_link(component_name),
101
+ sub_components: components_found.uniq.sort.map { |name| clean_file_name(name) },
102
+ }
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ components.sort_by { |c| c[:component] }
109
+ end
110
+
111
+ def find_partials_in(components)
112
+ extra_components = []
113
+ components.each do |component|
114
+ extra_components << components_within_component(component)
115
+ end
116
+
117
+ extra_components.flatten.uniq.sort
118
+ end
119
+
120
+ def components_within_component(file)
121
+ file = get_component_name_from_full_path(file)
122
+ file = "#{@templates_full_path}#{file}.html.erb".sub(/.*\K\//, "/_")
123
+ data = File.read(file)
124
+ match = data.scan(/["']{1}(govuk_publishing_components\/components\/[\/a-z_-]+["']{1})/)
125
+ match.flatten.uniq.map(&:to_s).sort.map do |m|
126
+ m.gsub("govuk_publishing_components/components/", "").tr('\"\'', "")
127
+ end
128
+ end
129
+
130
+ def list_all_component_details
131
+ all_component_information = []
132
+
133
+ @components.each do |component|
134
+ all_component_information << {
135
+ name: component,
136
+ link: get_component_link(component),
137
+ stylesheet: check_component_has("stylesheet", component),
138
+ print_stylesheet: check_component_has("print_stylesheet", component),
139
+ javascript: check_component_has("javascript", component),
140
+ tests: check_component_has("test", component),
141
+ js_tests: check_component_has("js_test", component),
142
+ }
143
+ end
144
+
145
+ all_component_information
146
+ end
147
+
148
+ def check_component_has(a_thing, component)
149
+ look_in = @component_stylesheets if a_thing == "stylesheet"
150
+ look_in = @component_print_stylesheets if a_thing == "print_stylesheet"
151
+ look_in = @component_javascripts if a_thing == "javascript"
152
+ look_in = @component_tests if a_thing == "test"
153
+ look_in = @component_js_tests if a_thing == "js_test"
154
+
155
+ true if look_in.include?(component)
156
+ end
157
+ end
158
+ end