mirror of
https://github.com/GSA/notifications-admin.git
synced 2026-08-24 00:07:02 -04:00
Compare commits
3 Commits
04-15-2025
...
f55d47e3d1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f55d47e3d1 | ||
|
|
7813ce7914 | ||
|
|
d79ece2d01 |
@@ -5,27 +5,42 @@
|
||||
|
||||
this.submit = () => this.$form.trigger('submit');
|
||||
|
||||
this.showCancelButton = () => $('.file-upload-button', this.$form).replaceWith(`
|
||||
<a href="" class='usa-button usa-button--secondary'>Cancel upload</a>
|
||||
`);
|
||||
this.showCancelButton = () => {
|
||||
$('.file-upload-button', this.$form).replaceWith(`
|
||||
<button class='usa-button uploading-button' aria-disabled="true" tabindex="0">
|
||||
Uploading<span class="dot-anim" aria-hidden="true"></span>
|
||||
</button>
|
||||
`);
|
||||
|
||||
const $srStatus = $('#upload-status-live');
|
||||
if ($srStatus.length) {
|
||||
// Clear and re-set the content to ensure it's treated as a change
|
||||
$srStatus.html('');
|
||||
setTimeout(() => {
|
||||
$srStatus.html('<span>File is uploading</span>');
|
||||
}, 50);
|
||||
}
|
||||
};
|
||||
|
||||
this.start = function(component) {
|
||||
|
||||
this.$form = $(component);
|
||||
|
||||
// The label gets styled like a button and is used to hide the native file upload control. This is so that
|
||||
// users see a button that looks like the others on the site.
|
||||
// Handle "Upload your file" button click — CSP-safe version
|
||||
this.$form.on('click', '[data-module="upload-trigger"]', function () {
|
||||
const inputId = $(this).data('file-input-id');
|
||||
const fileInput = document.getElementById(inputId);
|
||||
if (fileInput) fileInput.click();
|
||||
});
|
||||
|
||||
this.$form.find('label.file-upload-button').addClass('usa-button margin-bottom-1').attr( {role: 'button', tabindex: '0'} );
|
||||
|
||||
// Clear the form if the user navigates back to the page
|
||||
$(window).on("pageshow", () => this.$form[0].reset());
|
||||
|
||||
// Need to put the event on the container, not the input for it to work properly
|
||||
this.$form.on(
|
||||
'change', '.file-upload-field',
|
||||
() => this.submit() && this.showCancelButton()
|
||||
);
|
||||
// Watch for file input changes
|
||||
this.$form.on('change', '.file-upload-field', () => {
|
||||
this.submit();
|
||||
this.showCancelButton();
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -344,3 +344,17 @@ h2.recipient-list {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Button ellipses loading
|
||||
|
||||
.dot-anim::after {
|
||||
content: '.';
|
||||
animation: dotPulse 1.5s steps(3, end) infinite;
|
||||
}
|
||||
|
||||
@keyframes dotPulse {
|
||||
0% { content: ''; }
|
||||
33% { content: '.'; }
|
||||
66% { content: '..'; }
|
||||
100% { content: '...'; }
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
@forward "uswds-theme";
|
||||
@forward "uswds";
|
||||
@forward "uswds-theme-custom-styles";
|
||||
@forward "legacy-styles";
|
||||
@forward "main";
|
||||
@forward "data-visualization";
|
||||
|
||||
@@ -27,17 +27,21 @@
|
||||
</label>
|
||||
{{ field(**{
|
||||
'class': 'file-upload-field',
|
||||
'id': field.name,
|
||||
'accept': allowed_file_extensions|format_list_items('.{item}')|join(',')|e
|
||||
}) }}
|
||||
<label class="file-upload-button" for="{{ field.name }}">
|
||||
{{ button_text }}
|
||||
</label>
|
||||
<button type="button"
|
||||
class="usa-button file-upload-button"
|
||||
data-module="upload-trigger"
|
||||
data-file-input-id="{{ field.name }}">
|
||||
{{ button_text }}
|
||||
</button>
|
||||
{% if alternate_link and alternate_link_text %}
|
||||
<span class="file-upload-alternate-link">
|
||||
or <a class="usa-link" href="{{ alternate_link }}">{{ alternate_link_text }}</a>
|
||||
</span>
|
||||
{% endif %}
|
||||
<label class="file-upload-filename" for="{{ field.name }}"></label>
|
||||
<span class="file-upload-filename" aria-live="polite"></span>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
{{ usaButton({ "text": "Submit", "classes": "file-upload-submit" }) }}
|
||||
</form>
|
||||
|
||||
@@ -150,7 +150,7 @@ Error
|
||||
) }}
|
||||
{% endif %}
|
||||
</div>
|
||||
<a href="#content" class="usa-link back-to-top-link">Back to top</a>
|
||||
<a href="#content" class="usa-link back-to-top-link display-block margin-top-2">Back to top</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
show_errors=False
|
||||
)}}
|
||||
</div>
|
||||
<span id="upload-status-live" class="usa-sr-only" role="status" aria-live="polite" aria-atomic="true"></span>
|
||||
|
||||
<h2 class="font-body-lg">Your file needs to look like this example</h2>
|
||||
|
||||
|
||||
@@ -72,10 +72,11 @@ describe('File upload', () => {
|
||||
|
||||
});
|
||||
|
||||
test("It should add a link to cancel the upload by reloading the page", () => {
|
||||
|
||||
expect(form.querySelector("a[href='']")).not.toBeNull();
|
||||
|
||||
test("It should display a disabled Uploading button", () => {
|
||||
const uploadingButton = form.querySelector("button.uploading-button");
|
||||
expect(uploadingButton).not.toBeNull();
|
||||
expect(uploadingButton.textContent).toMatch(/Uploading/);
|
||||
expect(uploadingButton.getAttribute('aria-disabled')).toBe("true");
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user