Fetch template length message as user types

This commit adds some Javascript that makes AJAX requests as the users
changes the content of their template.

It then takes the content returned by the backend and inserts it in the
page.
This commit is contained in:
Chris Hill-Scott
2021-01-06 17:32:46 +00:00
parent ca50d77ac2
commit 3fdaa29f35
6 changed files with 201 additions and 1 deletions

View File

@@ -0,0 +1,41 @@
(function(window) {
"use strict";
window.GOVUK.Modules.UpdateStatus = function() {
let getRenderer = $component => response => $component.html(
response.html
);
this.start = component => {
let id = 'update-status';
this.$component = $(component);
this.$textbox = $('#' + this.$component.data('target'));
this.$textbox
.on('input', this.update)
.trigger('input');
};
this.update = () => {
$.ajax(
this.$component.data('updates-url'),
{
'method': 'post',
'data': this.$textbox.parents('form').serialize()
}
).done(
getRenderer(this.$component)
).fail(
() => {}
);
};
};
})(window);

View File

@@ -27,6 +27,10 @@
<div class="govuk-grid-column-full">
<div class="js-stick-at-bottom-when-scrolling">
{{ page_footer('Save') }}
<span class="template-content-count">
<div data-module="update-status" data-target="template_content" data-updates-url="{{ url_for('.count_content_length', service_id=current_service.id, template_type='broadcast') }}">
</div>
</span>
</div>
</div>
</div>

View File

@@ -30,6 +30,10 @@
<div class="govuk-grid-column-full">
<div class="js-stick-at-bottom-when-scrolling">
{{ page_footer('Save') }}
<span class="template-list-selected-counter">
<div data-module="update-status" data-target="template_content" data-updates-url="{{ url_for('.count_content_length', service_id=current_service.id, template_type='sms') }}">
</div>
</span>
</div>
</div>
<aside class="govuk-grid-column-full">

View File

@@ -177,6 +177,7 @@ const javascripts = () => {
paths.src + 'javascripts/templateFolderForm.js',
paths.src + 'javascripts/collapsibleCheckboxes.js',
paths.src + 'javascripts/radioSlider.js',
paths.src + 'javascripts/updateStatus.js',
paths.src + 'javascripts/main.js',
])
.pipe(plugins.prettyerror())

View File

@@ -467,10 +467,27 @@ def test_should_show_page_for_one_template(
assert page.select_one('textarea')['data-module'] == 'enhanced-textbox'
assert page.select_one('textarea')['data-highlight-placeholders'] == 'true'
assert "priority" not in str(page.select_one('main'))
assert (
page.select_one('[data-module=update-status]')['data-target']
) == (
page.select_one('textarea')['id']
) == (
'template_content'
)
assert (
page.select_one('[data-module=update-status]')['data-updates-url']
) == url_for(
'.count_content_length',
service_id=SERVICE_ONE_ID,
template_type='sms',
)
mock_get_service_template.assert_called_with(SERVICE_ONE_ID, template_id, None)
def test_broadcast_template_doesnt_highlight_placeholders(
def test_broadcast_template_doesnt_highlight_placeholders_but_does_count_characters(
client_request,
service_one,
mock_get_broadcast_template,
@@ -485,6 +502,22 @@ def test_broadcast_template_doesnt_highlight_placeholders(
assert page.select_one('textarea')['data-module'] == 'enhanced-textbox'
assert page.select_one('textarea')['data-highlight-placeholders'] == 'false'
assert (
page.select_one('[data-module=update-status]')['data-target']
) == (
page.select_one('textarea')['id']
) == (
'template_content'
)
assert (
page.select_one('[data-module=update-status]')['data-updates-url']
) == url_for(
'.count_content_length',
service_id=SERVICE_ONE_ID,
template_type='broadcast',
)
def test_caseworker_redirected_to_one_off(
client_request,

View File

@@ -0,0 +1,117 @@
const each = require('jest-each').default;
const jestDateMock = require('jest-date-mock');
const helpers = require('./support/helpers.js');
const serviceNumber = '6658542f-0cad-491f-bec8-ab8457700ead';
const updatesURL = `/services/${serviceNumber}/templates/count-sms-length`;
let responseObj = {};
let jqueryAJAXReturnObj;
beforeAll(() => {
// ensure all timers go through Jest
jest.useFakeTimers();
// mock the bits of jQuery used
jest.spyOn(window.$, 'ajax');
// set up the object returned from $.ajax so it responds with whatever responseObj is set to
jqueryAJAXReturnObj = {
done: callback => {
// For these tests the server responds immediately
callback(responseObj);
return jqueryAJAXReturnObj;
},
fail: () => {}
};
$.ajax.mockImplementation(() => jqueryAJAXReturnObj);
require('../../app/assets/javascripts/updateStatus.js');
});
afterAll(() => {
require('./support/teardown.js');
});
describe('Update content', () => {
beforeEach(() => {
document.body.innerHTML = `
<form>
<input type="hidden" name="csrf_token" value="abc123" />
<textarea name="template_content" id="template_content">Content of message</textarea>
</form>
<div data-module="update-status" data-updates-url="${updatesURL}" data-target="template_content">
Initial content
</div>
`;
});
afterEach(() => {
document.body.innerHTML = '';
// tidy up record of mocked AJAX calls
$.ajax.mockClear();
// ensure any timers set by continually starting the module are cleared
jest.clearAllTimers();
});
test("It should make requests to the URL specified in the data-updates-url attribute", () => {
window.GOVUK.modules.start();
expect($.ajax.mock.calls[0][0]).toEqual(updatesURL);
expect($.ajax.mock.calls[0]).toEqual([
updatesURL,
{
"data": "csrf_token=abc123&template_content=Content%20of%20message",
"method": "post"
}
]);
});
test("It should replace the content of the div with the returned HTML", () => {
responseObj = {'html': 'Updated content'}
expect(
document.querySelectorAll('[data-module=update-status]')[0].textContent.trim()
).toEqual(
"Initial content"
);
window.GOVUK.modules.start();
expect(
document.querySelectorAll('[data-module=update-status]')[0].textContent.trim()
).toEqual(
"Updated content"
);
});
test("It should fire when the content of the textarea changes", () => {
let textarea = document.getElementById('template_content');
// Initial update triggered
window.GOVUK.modules.start();
expect($.ajax.mock.calls.length).toEqual(1);
helpers.triggerEvent(textarea, 'input');
expect($.ajax.mock.calls.length).toEqual(2);
});
});