app/javascript/blacklight/checkbox_submit.js in blacklight-7.40.0 vs app/javascript/blacklight/checkbox_submit.js in blacklight-8.0.0.beta1
- old
+ new
@@ -1,135 +1,80 @@
-/* A JQuery plugin (should this be implemented as a widget instead? not sure)
- that will convert a "toggle" form, with single submit button to add/remove
+/* Converts a "toggle" form, with single submit button to add/remove
something, like used for Bookmarks, into an AJAXy checkbox instead.
-
Apply to a form. Does require certain assumption about the form:
1) The same form 'action' href must be used for both ADD and REMOVE
actions, with the different being the hidden input name="_method"
being set to "put" or "delete" -- that's the Rails method to pretend
to be doing a certain HTTP verb. So same URL, PUT to add, DELETE
to remove. This plugin assumes that.
-
Plus, the form this is applied to should provide a data-doc-id
attribute (HTML5-style doc-*) that contains the id/primary key
of the object in question -- used by plugin for a unique value for
DOM id's.
-
- Uses HTML for a checkbox compatible with Bootstrap 3.
-
- Pass in options for your class name and labels:
- $("form.something").blCheckboxSubmit({
- //cssClass is added to elements added, plus used for id base
- cssClass: "toggle_my_kinda_form",
- error: function() {
- #optional callback
- },
- success: function(after_success_check_state) {
- #optional callback
- }
- });
+ Uses HTML for a checkbox compatible with Bootstrap 4.
+ new CheckboxSubmit(document.querySelector('form.something')).render()
*/
-(function($) {
- $.fn.blCheckboxSubmit = function(argOpts) {
- this.each(function() {
- var options = $.extend({}, $.fn.blCheckboxSubmit.defaults, argOpts);
+export default class CheckboxSubmit {
+ constructor(form) {
+ this.form = form
+ }
+ async clicked(evt) {
+ this.spanTarget.innerHTML = this.form.getAttribute('data-inprogress')
+ this.labelTarget.setAttribute('disabled', 'disabled');
+ this.checkboxTarget.setAttribute('disabled', 'disabled');
+ const response = await fetch(this.formTarget.getAttribute('action'), {
+ body: new FormData(this.formTarget),
+ method: this.formTarget.getAttribute('method').toUpperCase(),
+ headers: {
+ 'Accept': 'application/json',
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-CSRF-Token': document.querySelector('meta[name=csrf-token]')?.content
+ }
+ })
+ this.labelTarget.removeAttribute('disabled')
+ this.checkboxTarget.removeAttribute('disabled')
+ if (response.ok) {
+ const json = await response.json()
+ this.updateStateFor(!this.checked)
+ document.querySelector('[data-role=bookmark-counter]').innerHTML = json.bookmarks.count
+ } else {
+ alert('Error')
+ }
+ }
- var form = $(this);
- form.children().hide();
- //We're going to use the existing form to actually send our add/removes
- //This works conveneintly because the exact same action href is used
- //for both bookmarks/$doc_id. But let's take out the irrelevant parts
- //of the form to avoid any future confusion.
- form.find('input[type=submit]').remove();
+ get checked() {
+ return (this.form.querySelectorAll('input[name=_method][value=delete]').length != 0)
+ }
- //View needs to set data-doc-id so we know a unique value
- //for making DOM id
- var uniqueId = form.attr('data-doc-id') || Math.random();
- // if form is currently using method delete to change state,
- // then checkbox is currently checked
- var checked = (form.find('input[name=_method][value=delete]').length != 0);
+ get formTarget() {
+ return this.form
+ }
- var checkbox = $('<input type="checkbox">')
- .addClass( options.cssClass )
- .attr('id', options.cssClass + '_' + uniqueId);
- var label = $('<label>')
- .addClass( options.cssClass )
- .attr('for', options.cssClass + '_' + uniqueId)
- .attr('title', form.attr('title') || '');
- var span = $('<span>');
+ get labelTarget() {
+ return this.form.querySelector('[data-checkboxsubmit-target="label"]')
+ }
- label.append(checkbox);
- label.append(' ');
- label.append(span);
+ get checkboxTarget() {
+ return this.form.querySelector('[data-checkboxsubmit-target="checkbox"]')
+ }
- var checkboxDiv = $('<div class="checkbox" />')
- .addClass(options.cssClass)
- .append(label);
+ get spanTarget() {
+ return this.form.querySelector('[data-checkboxsubmit-target="span"]')
+ }
- function updateStateFor(state) {
- checkbox.prop('checked', state);
- label.toggleClass('checked', state);
- if (state) {
- //Set the Rails hidden field that fakes an HTTP verb
- //properly for current state action.
- form.find('input[name=_method]').val('delete');
- span.html(form.attr('data-present'));
- } else {
- form.find('input[name=_method]').val('put');
- span.html(form.attr('data-absent'));
- }
- }
+ updateStateFor(state) {
+ this.checkboxTarget.checked = state
- form.append(checkboxDiv);
- updateStateFor(checked);
-
- checkbox.click(function() {
- span.html(form.attr('data-inprogress'));
- label.attr('disabled', 'disabled');
- checkbox.attr('disabled', 'disabled');
-
- $.ajax({
- url: form.attr('action'),
- beforeSend: function(xhr) { xhr.setRequestHeader('X-CSRF-Token', Blacklight.csrfToken()) },
- dataType: 'json',
- type: form.attr('method').toUpperCase(),
- data: form.serialize(),
- error: function() {
- label.removeAttr('disabled');
- checkbox.removeAttr('disabled');
- options.error.call();
- },
- success: function(data, status, xhr) {
- //if app isn't running at all, xhr annoyingly
- //reports success with status 0.
- if (xhr.status != 0) {
- checked = ! checked;
- updateStateFor(checked);
- label.removeAttr('disabled');
- checkbox.removeAttr('disabled');
- options.success.call(form, checked, xhr.responseJSON);
- } else {
- label.removeAttr('disabled');
- checkbox.removeAttr('disabled');
- options.error.call();
- }
- }
- });
-
- return false;
- }); //checkbox.click
-
-
- }); //this.each
- return this;
- };
-
- $.fn.blCheckboxSubmit.defaults = {
- //cssClass is added to elements added, plus used for id base
- cssClass: 'blCheckboxSubmit',
- error: function() {
- alert("Error");
- },
- success: function() {} //callback
- };
-})(jQuery);
+ if (state) {
+ this.labelTarget.classList.add('checked')
+ //Set the Rails hidden field that fakes an HTTP verb
+ //properly for current state action.
+ this.formTarget.querySelector('input[name=_method]').value = 'delete'
+ this.spanTarget.innerHTML = this.form.getAttribute('data-present')
+ } else {
+ this.labelTarget.classList.remove('checked')
+ this.formTarget.querySelector('input[name=_method]').value = 'put'
+ this.spanTarget.innerHTML = this.form.getAttribute('data-absent')
+ }
+ }
+}