diff --git a/app/assets/javascripts/apiKey.js b/app/assets/javascripts/copyToClipboard.js similarity index 55% rename from app/assets/javascripts/apiKey.js rename to app/assets/javascripts/copyToClipboard.js index 4d8658a7c..03d5325d4 100644 --- a/app/assets/javascripts/apiKey.js +++ b/app/assets/javascripts/copyToClipboard.js @@ -3,33 +3,33 @@ if (!document.queryCommandSupported('copy')) return; - Modules.ApiKey = function() { + Modules.CopyToClipboard = function() { const states = { - 'keyVisible': (options) => ` - - ${options.keyLabel ? '' + options.thing + ': ' : ''}${options.key} + 'valueVisible': (options) => ` + + ${options.valueLabel ? '' + options.thing + ': ' : ''}${options.value} - + ${options.onload ? '' : options.thing + ' returned to page, press button to copy to clipboard'} - `, - 'keyCopied': (options) => ` - + 'valueCopied': (options) => ` + ${options.thing} Copied to clipboard, press button to show in page - ` }; - this.getRangeFromElement = function (keyElement) { + this.getRangeFromElement = function (copyableElement) { const range = document.createRange(); - const childNodes = Array.prototype.slice.call(keyElement.childNodes); + const childNodes = Array.prototype.slice.call(copyableElement.childNodes); let prefixIndex = -1; childNodes.forEach((el, idx) => { @@ -38,15 +38,15 @@ } }); - range.selectNodeContents(keyElement); - if (prefixIndex !== -1) { range.setStart(keyElement, prefixIndex + 1); } + range.selectNodeContents(copyableElement); + if (prefixIndex !== -1) { range.setStart(copyableElement, prefixIndex + 1); } return range; }; - this.copyKey = function(keyElement, callback) { + this.copyValueToClipboard = function(copyableElement, callback) { var selection = window.getSelection ? window.getSelection() : document.selection, - range = this.getRangeFromElement(keyElement); + range = this.getRangeFromElement(copyableElement); selection.removeAllRanges(); selection.addRange(range); @@ -59,36 +59,36 @@ const $component = $(component), stateOptions = { - key: $component.data('key'), + value: $component.data('value'), thing: $component.data('thing') }, name = $component.data('name'); // if the name is distinct from the thing: // - it will be used in the rendering - // - the key won't be identified by a heading so needs its own label + // - the value won't be identified by a heading so needs its own label if (name !== stateOptions.thing) { stateOptions.name = name; - stateOptions.keyLabel = true; + stateOptions.valueLabel = true; } $component - .addClass('api-key') + .addClass('copy-to-clipboard') .css('min-height', $component.height()) - .html(states.keyVisible($.extend({ 'onload': true }, stateOptions))) + .html(states.valueVisible($.extend({ 'onload': true }, stateOptions))) .on( - 'click', '.api-key__button--copy', () => - this.copyKey( - $('.api-key__key', component)[0], () => + 'click', '.copy-to-clipboard__button--copy', () => + this.copyValueToClipboard( + $('.copy-to-clipboard__value', component)[0], () => $component - .html(states.keyCopied(stateOptions)) + .html(states.valueCopied(stateOptions)) .find('.govuk-button').focus() ) ) .on( - 'click', '.api-key__button--show', () => + 'click', '.copy-to-clipboard__button--show', () => $component - .html(states.keyVisible(stateOptions)) + .html(states.valueVisible(stateOptions)) .find('.govuk-button').focus() ); diff --git a/app/assets/stylesheets/components/api-key.scss b/app/assets/stylesheets/components/copy-to-clipboard.scss similarity index 95% rename from app/assets/stylesheets/components/api-key.scss rename to app/assets/stylesheets/components/copy-to-clipboard.scss index 8ea44a3f1..694df01d5 100644 --- a/app/assets/stylesheets/components/api-key.scss +++ b/app/assets/stylesheets/components/copy-to-clipboard.scss @@ -1,4 +1,4 @@ -.api-key { +.copy-to-clipboard { position: relative; padding-bottom: 38px; // height of button diff --git a/app/assets/stylesheets/main.scss b/app/assets/stylesheets/main.scss index 4331c416f..270558240 100644 --- a/app/assets/stylesheets/main.scss +++ b/app/assets/stylesheets/main.scss @@ -50,7 +50,7 @@ $path: '/static/images/'; @import 'components/file-upload'; @import 'components/browse-list'; @import 'components/email-message'; -@import 'components/api-key'; +@import 'components/copy-to-clipboard'; @import 'components/vendor/previous-next-navigation'; @import 'components/radios'; @import 'components/checkboxes'; diff --git a/app/templates/components/api-key.html b/app/templates/components/api-key.html deleted file mode 100644 index bc432b452..000000000 --- a/app/templates/components/api-key.html +++ /dev/null @@ -1,13 +0,0 @@ -{% macro api_key(key, name, thing="API key") %} - {% if name|lower == thing|lower %} -

- {{ name }} -

- {% endif %} -
- - {% if name|lower != thing|lower %}{{ thing }}: {% endif %}{{ key }} - - -
-{% endmacro %} diff --git a/app/templates/components/copy-to-clipboard.html b/app/templates/components/copy-to-clipboard.html new file mode 100644 index 000000000..8f67c1cfa --- /dev/null +++ b/app/templates/components/copy-to-clipboard.html @@ -0,0 +1,13 @@ +{% macro copy_to_clipboard(value, name, thing) %} + {% if name|lower == thing|lower %} +

+ {{ name }} +

+ {% endif %} +
+ + {% if name|lower != thing|lower %}{{ thing }}: {% endif %}{{ value }} + + +
+{% endmacro %} diff --git a/app/templates/views/api/keys/show.html b/app/templates/views/api/keys/show.html index 44765a387..890d68e84 100644 --- a/app/templates/views/api/keys/show.html +++ b/app/templates/views/api/keys/show.html @@ -1,6 +1,6 @@ {% extends "withnav_template.html" %} {% from "components/page-footer.html" import page_footer %} -{% from "components/api-key.html" import api_key %} +{% from "components/copy-to-clipboard.html" import copy_to_clipboard %} {% block service_page_title %} New API key @@ -22,7 +22,7 @@
- {{ api_key( + {{ copy_to_clipboard( '{}-{}-{}'.format(key_name, service_id, secret), name='API key', thing='API key' diff --git a/app/templates/views/service-settings/email_reply_to.html b/app/templates/views/service-settings/email_reply_to.html index f60152fbd..b45b97d84 100644 --- a/app/templates/views/service-settings/email_reply_to.html +++ b/app/templates/views/service-settings/email_reply_to.html @@ -1,5 +1,5 @@ {% extends "withnav_template.html" %} -{% from "components/api-key.html" import api_key %} +{% from "components/copy-to-clipboard.html" import copy_to_clipboard %} {% from "components/page-header.html" import page_header %} {% from "components/table.html" import row_group, row, text_field, edit_field, field, boolean_field, list_table with context %} {% from "components/button/macro.njk" import govukButton %} @@ -46,7 +46,7 @@
{% if current_service.count_email_reply_to_addresses > 1 %} - {{ api_key(item.id, name=item.email_address, thing="ID") }} + {{ copy_to_clipboard(item.id, name=item.email_address, thing="ID") }} {% endif %}
diff --git a/app/templates/views/service-settings/letter-contact-details.html b/app/templates/views/service-settings/letter-contact-details.html index 677b66410..3ae2021c3 100644 --- a/app/templates/views/service-settings/letter-contact-details.html +++ b/app/templates/views/service-settings/letter-contact-details.html @@ -1,5 +1,5 @@ {% extends "withnav_template.html" %} -{% from "components/api-key.html" import api_key %} +{% from "components/copy-to-clipboard.html" import copy_to_clipboard %} {% from "components/page-header.html" import page_header %} {% from "components/table.html" import row_group, row, text_field, edit_field, field, boolean_field, list_table with context %} {% from "components/button/macro.njk" import govukButton %} @@ -59,7 +59,7 @@
{% if letter_contact_details|length > 1 %} {% set first_line_of_contact_block = item.contact_block|normalise_lines|first %} - {{ api_key(item.id, name=first_line_of_contact_block, thing="ID") }} + {{ copy_to_clipboard(item.id, name=first_line_of_contact_block, thing="ID") }} {% endif %} {% endfor %} diff --git a/app/templates/views/service-settings/sms-senders.html b/app/templates/views/service-settings/sms-senders.html index 507f7aef2..25158fa86 100644 --- a/app/templates/views/service-settings/sms-senders.html +++ b/app/templates/views/service-settings/sms-senders.html @@ -1,5 +1,5 @@ {% extends "withnav_template.html" %} -{% from "components/api-key.html" import api_key %} +{% from "components/copy-to-clipboard.html" import copy_to_clipboard %} {% from "components/page-header.html" import page_header %} {% from "components/table.html" import row_group, row, text_field, edit_field, field, boolean_field, list_table with context%} {% from "components/button/macro.njk" import govukButton %} @@ -46,7 +46,7 @@ {% if current_service.count_sms_senders > 1 %} - {{ api_key(item.id, name=item.sms_sender, thing="ID") }} + {{ copy_to_clipboard(item.id, name=item.sms_sender, thing="ID") }} {% endif %} {% endfor %} diff --git a/app/templates/views/templates/template.html b/app/templates/views/templates/template.html index 5baf3e2e2..5e05a9761 100644 --- a/app/templates/views/templates/template.html +++ b/app/templates/views/templates/template.html @@ -2,7 +2,7 @@ {% from "components/banner.html" import banner_wrapper %} {% from "components/folder-path.html" import folder_path, page_title_folder_path %} {% from "components/page-footer.html" import page_footer %} -{% from "components/api-key.html" import api_key %} +{% from "components/copy-to-clipboard.html" import copy_to_clipboard %} {% from "components/button/macro.njk" import govukButton %} {% block service_page_title %} @@ -47,7 +47,7 @@ {% if template.template_type != 'broadcast' %}
- {{ api_key(template.id, name="Template ID", thing='template ID') }} + {{ copy_to_clipboard(template.id, name="Template ID", thing='template ID') }}
{% endif %} diff --git a/gulpfile.js b/gulpfile.js index 9dbd998ee..e1dc3a5b9 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -163,7 +163,7 @@ const javascripts = () => { paths.src + 'javascripts/cookieMessage.js', paths.src + 'javascripts/cookieSettings.js', paths.src + 'javascripts/stick-to-window-when-scrolling.js', - paths.src + 'javascripts/apiKey.js', + paths.src + 'javascripts/copyToClipboard.js', paths.src + 'javascripts/autofocus.js', paths.src + 'javascripts/enhancedTextbox.js', paths.src + 'javascripts/fileUpload.js', diff --git a/tests/app/main/views/test_api_integration.py b/tests/app/main/views/test_api_integration.py index dd405b920..521c52ce5 100644 --- a/tests/app/main/views/test_api_integration.py +++ b/tests/app/main/views/test_api_integration.py @@ -283,7 +283,7 @@ def test_should_create_api_key_with_type_normal( _expected_status=200, ) - assert page.select_one('span.api-key__key').text.strip() == ( + assert page.select_one('span.copy-to-clipboard__value').text.strip() == ( 'some_default_key_name_12-{}-{}'.format(SERVICE_ONE_ID, fake_uuid) ) diff --git a/tests/app/main/views/test_templates.py b/tests/app/main/views/test_templates.py index b178a2c65..a686b1997 100644 --- a/tests/app/main/views/test_templates.py +++ b/tests/app/main/views/test_templates.py @@ -975,7 +975,7 @@ def test_should_show_template_id_on_template_page( template_id=fake_uuid, _test_page_title=False, ) - assert fake_uuid in page.select('.api-key__key')[0].text + assert fake_uuid in page.select('.copy-to-clipboard__value')[0].text def test_should_hide_template_id_for_broadcast_templates( @@ -990,7 +990,7 @@ def test_should_hide_template_id_for_broadcast_templates( template_id=fake_uuid, _test_page_title=False, ) - assert not page.select('.api-key__key') + assert not page.select('.copy-to-clipboard__value') def test_should_show_sms_template_with_downgraded_unicode_characters( diff --git a/tests/javascripts/apiKey.test.js b/tests/javascripts/copyToClipboard.test.js similarity index 75% rename from tests/javascripts/apiKey.test.js rename to tests/javascripts/copyToClipboard.test.js index 08f974928..3757a7dfd 100644 --- a/tests/javascripts/apiKey.test.js +++ b/tests/javascripts/copyToClipboard.test.js @@ -9,7 +9,7 @@ afterAll(() => { }); -describe('API key', () => { +describe('copy to clipboard', () => { let apiKey = '00000000-0000-0000-0000-000000000000'; let thing; @@ -21,14 +21,14 @@ describe('API key', () => { // set up DOM document.body.innerHTML =` -

+

${options.thing}

-
- +
+ ${(options.name === options.thing) ? '' + options.thing + ': ' : ''}${apiKey} - +
`; }; @@ -58,11 +58,11 @@ describe('API key', () => { // fake support for the copy command not being available document.queryCommandSupported = jest.fn(command => false); - require('../../app/assets/javascripts/apiKey.js'); + require('../../app/assets/javascripts/copyToClipboard.js'); - setUpDOM({ 'thing': 'API key', 'name': 'API key' }); + setUpDOM({ 'thing': 'Some Thing', 'name': 'Some Thing' }); - component = document.querySelector('[data-module=api-key]'); + component = document.querySelector('[data-module=copy-to-clipboard]'); // start the module window.GOVUK.modules.start(); @@ -83,7 +83,7 @@ describe('API key', () => { // force module require to not come from cache jest.resetModules(); - require('../../app/assets/javascripts/apiKey.js'); + require('../../app/assets/javascripts/copyToClipboard.js'); }); @@ -97,13 +97,13 @@ describe('API key', () => { beforeEach(() => { - setUpDOM({ 'thing': 'API key', 'name': 'API key' }); + setUpDOM({ 'thing': 'Some Thing', 'name': 'Some Thing' }); - component = document.querySelector('[data-module=api-key]'); + component = document.querySelector('[data-module=copy-to-clipboard]'); // set default style for component height (queried by jQuery before checking DOM APIs) const stylesheet = document.createElement('style'); - stylesheet.innerHTML = '[data-module=api-key] { height: auto; }'; // set to browser default + stylesheet.innerHTML = '[data-module=copy-to-clipboard] { height: auto; }'; // set to browser default document.getElementsByTagName('head')[0].appendChild(stylesheet); componentHeightOnLoad = 50; @@ -126,15 +126,15 @@ describe('API key', () => { }); - test("It should add a button for copying the key to the clipboard", () => { + test("It should add a button for copying the thing to the clipboard", () => { expect(component.querySelector('button')).not.toBeNull(); }); - test("It should add the 'api-key' class", () => { + test("It should add the 'copy-to-clipboard' class", () => { - expect(component.classList.contains('api-key')).toBe(true); + expect(component.classList.contains('copy-to-clipboard')).toBe(true); }); @@ -162,7 +162,7 @@ describe('API key', () => { // different, it will be one of others called the same 'thing'. setUpDOM({ 'thing': 'ID', 'name': 'Default' }); - component = document.querySelector('[data-module=api-key]'); + component = document.querySelector('[data-module=copy-to-clipboard]'); // start the module window.GOVUK.modules.start(); @@ -173,9 +173,9 @@ describe('API key', () => { // and so needs some prefix text to label it test("The id should have a hidden prefix to label what it is", () => { - const keyPrefix = component.querySelector('.api-key__key .govuk-visually-hidden'); - expect(keyPrefix).not.toBeNull(); - expect(keyPrefix.textContent).toEqual('ID: '); + const value = component.querySelector('.copy-to-clipboard__value .govuk-visually-hidden'); + expect(value).not.toBeNull(); + expect(value.textContent).toEqual('ID: '); }); @@ -196,9 +196,9 @@ describe('API key', () => { // The heading is added if 'thing' (what the id is) has the same value as 'name' // (its specific identifier on the page) because this means it can assume it is // the only one of its type there - setUpDOM({ 'thing': 'API key', 'name': 'API key' }); + setUpDOM({ 'thing': 'Some Thing', 'name': 'Some Thing' }); - component = document.querySelector('[data-module=api-key]'); + component = document.querySelector('[data-module=copy-to-clipboard]'); // start the module window.GOVUK.modules.start(); @@ -207,9 +207,9 @@ describe('API key', () => { test("Its button and id shouldn't have extra hidden text to identify them", () => { - const keyPrefix = component.querySelector('.api-key__key .govuk-visually-hidden'); + const value = component.querySelector('.copy-to-clipboard__value .govuk-visually-hidden'); const buttonSuffix = component.querySelector('button .govuk-visually-hidden'); - expect(keyPrefix).toBeNull(); + expect(value).toBeNull(); expect(buttonSuffix).toBeNull(); }) @@ -218,7 +218,7 @@ describe('API key', () => { }); - describe("If you click the 'Copy API key to clipboard' button", () => { + describe("If you click the 'Copy Some Thing to clipboard' button", () => { describe("For all variations of the initial HTML", () => { @@ -226,13 +226,13 @@ describe('API key', () => { beforeEach(() => { - setUpDOM({ 'thing': 'API key', 'name': 'API key' }); + setUpDOM({ 'thing': 'Some Thing', 'name': 'Some Thing' }); // start the module window.GOVUK.modules.start(); - component = document.querySelector('[data-module=api-key]'); - keyEl = component.querySelector('.api-key__key'); + component = document.querySelector('[data-module=copy-to-clipboard]'); + keyEl = component.querySelector('.copy-to-clipboard__value'); helpers.triggerEvent(component.querySelector('button'), 'click'); @@ -240,7 +240,7 @@ describe('API key', () => { test("The live-region should be shown and its text should confirm the copy action", () => { - const liveRegion = component.querySelector('.api-key__notice'); + const liveRegion = component.querySelector('.copy-to-clipboard__notice'); expect(liveRegion.classList.contains('govuk-visually-hidden')).toBe(false); expect(liveRegion.textContent.trim()).toEqual( @@ -253,31 +253,31 @@ describe('API key', () => { // lower priority than the live-region test("The live-region should contain some hidden text giving context to the statement shown", () => { - const liveRegionHiddenText = component.querySelectorAll('.api-key__notice .govuk-visually-hidden'); + const liveRegionHiddenText = component.querySelectorAll('.copy-to-clipboard__notice .govuk-visually-hidden'); expect(liveRegionHiddenText.length).toEqual(2); - expect(liveRegionHiddenText[0].textContent).toEqual('API key '); + expect(liveRegionHiddenText[0].textContent).toEqual('Some Thing '); expect(liveRegionHiddenText[1].textContent).toEqual(', press button to show in page'); }); - test("It should swap the button for one to show the API key", () => { + test("It should swap the button for one to show the Some Thing", () => { expect(component.querySelector('button').textContent.trim()).toEqual( - expect.stringContaining('Show API key') + expect.stringContaining('Show Some Thing') ); }); test("It should remove the id from the page", () => { - expect(component.querySelector('.api-key__key')).toBeNull(); + expect(component.querySelector('.copy-to-clipboard__value')).toBeNull(); }); - test("It should copy the key to the clipboard", () => { + test("It should copy the thing to the clipboard", () => { - // it should make a selection (a range) from the contents of the element containing the API key + // it should make a selection (a range) from the contents of the element containing the Some Thing expect(rangeMock.selectNodeContents.mock.calls[0]).toEqual([keyEl]); // that selection (a range) should be added to that for the page (a selection) @@ -293,7 +293,7 @@ describe('API key', () => { }); - describe("If you then click the 'Show API key'", () => { + describe("If you then click the 'Show Some Thing'", () => { beforeEach(() => { @@ -301,16 +301,16 @@ describe('API key', () => { }); - test("It should change the text to show the API key", () => { + test("It should change the text to show the Some Thing", () => { - expect(component.querySelector('.api-key__key')).not.toBeNull(); + expect(component.querySelector('.copy-to-clipboard__value')).not.toBeNull(); }); - test("It should swap the button for one to copy the key to the clipboard", () => { + test("It should swap the button for one to copy the thing to the clipboard", () => { expect(component.querySelector('button').textContent.trim()).toEqual( - expect.stringContaining('Copy API key to clipboard') + expect.stringContaining('Copy Some Thing to clipboard') ); }) @@ -330,7 +330,7 @@ describe('API key', () => { // start the module window.GOVUK.modules.start(); - component = document.querySelector('[data-module=api-key]'); + component = document.querySelector('[data-module=copy-to-clipboard]'); helpers.triggerEvent(component.querySelector('button'), 'click'); @@ -368,12 +368,12 @@ describe('API key', () => { // The heading is added if 'thing' (what the id is) has the same value as 'name' // (its specific identifier on the page) because this means it can assume it is // the only one of its type there - setUpDOM({ 'thing': 'API key', 'name': 'API key' }); + setUpDOM({ 'thing': 'Some Thing', 'name': 'Some Thing' }); // start the module window.GOVUK.modules.start(); - component = document.querySelector('[data-module=api-key]'); + component = document.querySelector('[data-module=copy-to-clipboard]'); helpers.triggerEvent(component.querySelector('button'), 'click'); @@ -381,9 +381,9 @@ describe('API key', () => { test("Its button and id shouldn't have extra hidden text to identify them", () => { - const keyPrefix = component.querySelector('.api-key__key .govuk-visually-hidden'); + const prefix = component.querySelector('.copy-to-clipboard__value .govuk-visually-hidden'); const buttonSuffix = component.querySelector('button .govuk-visually-hidden'); - expect(keyPrefix).toBeNull(); + expect(prefix).toBeNull(); expect(buttonSuffix).toBeNull(); })