diff --git a/.dockerignore b/.dockerignore
index edbe80040..36e53b377 100644
--- a/.dockerignore
+++ b/.dockerignore
@@ -11,9 +11,7 @@ docs
features
log
node_modules
-package.json
script
spec
test
tmp
-yarn.lock
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 488eeb079..e518dd1e5 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -1,3 +1,4 @@
+/* global pasteHtmlToGovspeak */
//= require vendor/jquery-1.11.0.min
//= require vendor/jquery-ui.min.js
@@ -6,11 +7,15 @@
//= require length_counter
//= require markdown_preview
//= require toggle_display_with_checked_input
-
+//= require paste-html-to-govspeak
jQuery(function ($) {
$('.js-length-counter').each(function () {
new GOVUK.LengthCounter({ $el: $(this) }) // eslint-disable-line no-new
})
+ $('.js-paste-html-to-govspeak').each(function () {
+ this.addEventListener('paste', pasteHtmlToGovspeak.pasteListener)
+ })
+
$('.reorderable-document-list').sortable()
})
diff --git a/app/views/manuals/_form.html.erb b/app/views/manuals/_form.html.erb
index 3d3bce8e8..42a8043d7 100644
--- a/app/views/manuals/_form.html.erb
+++ b/app/views/manuals/_form.html.erb
@@ -8,7 +8,7 @@
Summary text should be 280 characters or fewer.
- <%= f.text_area :body, rows: 20, cols: 40, class: 'form-control' %>
+ <%= f.text_area :body, rows: 20, cols: 40, class: 'form-control js-paste-html-to-govspeak' %>
diff --git a/app/views/sections/_form.html.erb b/app/views/sections/_form.html.erb
index d820af4e2..53a73cb81 100644
--- a/app/views/sections/_form.html.erb
+++ b/app/views/sections/_form.html.erb
@@ -6,7 +6,7 @@
<%= f.text_field :title, label: 'Section title', class: 'form-control' %>
<%= f.text_area :summary, rows: 20, cols: 40, label: 'Section summary', class: 'form-control short-textarea js-length-counter', data: { :"count-message-threshold" => 280, :"count-message-selector" => ".summary-length-info" } %>
Summary text should be 280 characters or fewer.
- <%= f.text_area :body, rows: 20, cols: 40, label: 'Section body', class: 'form-control' %>
+ <%= f.text_area :body, rows: 20, cols: 40, label: 'Section body', class: 'form-control js-paste-html-to-govspeak' %>
diff --git a/features/creating-and-editing-a-manual.feature b/features/creating-and-editing-a-manual.feature
index 306b94763..e3c3cf7d7 100644
--- a/features/creating-and-editing-a-manual.feature
+++ b/features/creating-and-editing-a-manual.feature
@@ -51,6 +51,12 @@ Feature: Creating and editing a manual
When I edit a manual
Then the manual's sections won't have changed
+ @javascript
+ Scenario: Pasting HTML into a manual
+ When I start creating a new manual
+ And I paste HTML into the manual body
+ Then the manual body field contains govspeak
+
Scenario: Try to create an invalid manual
When I create a manual with an empty title
Then I see errors for the title field
@@ -67,6 +73,13 @@ Feature: Creating and editing a manual
And I see the section isn't visually expanded
And the section and table of contents will have been sent to the draft publishing api
+ @javascript
+ Scenario: Pasting HTML into a section
+ Given a draft manual exists without any sections
+ When I start creating a section for the manual
+ And I paste HTML into the section body
+ Then the section body field contains govspeak
+
Scenario: Add an expanded section to a manual
Given a draft manual exists without any sections
When I create an expanded section for the manual
diff --git a/features/step_definitions/manual_steps.rb b/features/step_definitions/manual_steps.rb
index f8d5b98ca..ab286d68b 100644
--- a/features/step_definitions/manual_steps.rb
+++ b/features/step_definitions/manual_steps.rb
@@ -278,9 +278,9 @@
When(/^I add another section and publish the manual later$/) do
create_section(
@manual.title,
- section_title: "Another section so we can publish",
- section_summary: "Another section so we can publish summary",
- section_body: "Another section so we can publish body",
+ { section_title: "Another section so we can publish",
+ section_summary: "Another section so we can publish summary",
+ section_body: "Another section so we can publish body" },
)
go_to_manual_page(@manual.title)
publish_manual
@@ -667,6 +667,24 @@
create_manual(@manual_fields, save: false)
end
+When(/^I start creating a section for the manual$/) do
+ create_section(@manual_fields.fetch(:title), {}, save: false)
+end
+
+When(/^I paste HTML into the manual body$/) do
+ fill_in_field("body", "")
+ page.execute_script(javascript_to_simulate_paste("manual_body", "Benefits of following this advice
"))
+end
+
+When(/^I paste HTML into the section body$/) do
+ fill_in_field("section body", "")
+ page.execute_script(javascript_to_simulate_paste("section_body", "Benefits of following this advice
"))
+end
+
+Then(/^the (manual|section) body field contains govspeak$/) do |content_type_name|
+ expect(page).to have_field("#{content_type_name}_body", with: "## Benefits of following this advice")
+end
+
When(/^I preview the manual$/) do
click_button("Preview")
end
diff --git a/features/support/form_helpers.rb b/features/support/form_helpers.rb
index 9d1252452..0caa9cdd4 100644
--- a/features/support/form_helpers.rb
+++ b/features/support/form_helpers.rb
@@ -15,6 +15,18 @@ def fill_in_field(field_name, value)
end
end
+ def javascript_to_simulate_paste(element_id, paste_content)
+ <<~JS
+ var event = new Event('paste')
+ event.clipboardData = {
+ getData: function() {
+ return '#{paste_content}'
+ }
+ }
+ document.getElementById('#{element_id}').dispatchEvent(event)
+ JS
+ end
+
def clear_datetime(label)
base_dom_id = find(:xpath, ".//label[contains(., '#{label}')]")["for"].gsub(/(_[1-5]i)$/, "")
diff --git a/features/support/manual_helpers.rb b/features/support/manual_helpers.rb
index ca00a3010..f6be08340 100644
--- a/features/support/manual_helpers.rb
+++ b/features/support/manual_helpers.rb
@@ -30,7 +30,7 @@ def create_manual_without_ui(fields, organisation_slug: "ministry-of-tea")
Manual.find(manual.id, FactoryBot.build(:gds_editor))
end
- def create_section(manual_title, fields)
+ def create_section(manual_title, fields, save: true)
go_to_manual_page(manual_title)
click_on "Add section"
@@ -38,7 +38,7 @@ def create_section(manual_title, fields)
yield if block_given?
- save_as_draft
+ save_as_draft if save
end
def create_expanded_section(manual_title, fields)
diff --git a/lib/tasks/assets.rake b/lib/tasks/assets.rake
new file mode 100644
index 000000000..4f4f3b7a6
--- /dev/null
+++ b/lib/tasks/assets.rake
@@ -0,0 +1,2 @@
+# Maintain Rails < 7 behaviour of running yarn:install before assets:precompile
+Rake::Task["assets:precompile"].enhance(["yarn:install"])
diff --git a/package.json b/package.json
index 3f7c4be33..81a70c5fe 100644
--- a/package.json
+++ b/package.json
@@ -45,5 +45,8 @@
"resolutions": {
"stylelint/strip-ansi": "6.0.1",
"stylelint/string-width": "4.2.3"
+ },
+ "dependencies": {
+ "paste-html-to-govspeak": "^0.3.0"
}
}
diff --git a/yarn.lock b/yarn.lock
index b3c102a2a..fe22dc339 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1894,6 +1894,11 @@ parseurl@~1.3.3:
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+paste-html-to-govspeak@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/paste-html-to-govspeak/-/paste-html-to-govspeak-0.3.0.tgz#9c4717690f3d6cd290c972c9bf106ead14adb177"
+ integrity sha512-K4jcJkZLQpvpukkiSzXZcXPbV80CDSKTI3zEs0/gVG+jx5H7v2XsdIOEuCZ56cRCCuuIH3rsrJcyoleGqPj6xw==
+
path-exists@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"