form.js 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import $ from 'jquery';
  2. /* Dependencies for checking if changes happened since load on a form
  3. import toastr from '../utils/toastr';
  4. import { translations } from 'grav-config';
  5. import { Instance as FormState } from './state';
  6. */
  7. export default class Form {
  8. constructor(form) {
  9. this.form = $(form);
  10. if (!this.form.length || this.form.prop('tagName').toLowerCase() !== 'form') { return; }
  11. /* Option for not saving while nothing in a form has changed
  12. this.form.on('submit', (event) => {
  13. if (FormState.equals()) {
  14. event.preventDefault();
  15. toastr.info(translations.PLUGIN_ADMIN.NOTHING_TO_SAVE);
  16. }
  17. }); */
  18. this._attachShortcuts();
  19. this._attachToggleables();
  20. this._attachDisabledFields();
  21. this._submitUncheckedFields();
  22. this.observer = new MutationObserver(this.addedNodes);
  23. this.form.each((index, form) => this.observer.observe(form, { subtree: true, childList: true }));
  24. }
  25. _attachShortcuts() {
  26. // CTRL + S / CMD + S - shortcut for [Save] when available
  27. let saveTask = $('#titlebar [name="task"][value="save"]');
  28. if (saveTask.length) {
  29. $(global).on('keydown', function(event) {
  30. const key = String.fromCharCode(event.which).toLowerCase();
  31. if (!event.shiftKey && ((event.ctrlKey && !event.altKey) || event.metaKey) && key === 's') {
  32. event.preventDefault();
  33. saveTask.click();
  34. }
  35. });
  36. }
  37. }
  38. _attachToggleables() {
  39. let query = '[data-grav-field="toggleable"] input[type="checkbox"]';
  40. this.form.on('change', query, (event) => {
  41. let toggle = $(event.target);
  42. let enabled = toggle.is(':checked');
  43. let parent = toggle.closest('.form-field');
  44. let label = parent.find('label.toggleable');
  45. let fields = parent.find('.form-data');
  46. let inputs = fields.find('input, select, textarea, button');
  47. label.add(fields).css('opacity', enabled ? '' : 0.7);
  48. inputs.map((index, input) => {
  49. let isSelectize = input.selectize;
  50. input = $(input);
  51. if (isSelectize) {
  52. isSelectize[enabled ? 'enable' : 'disable']();
  53. } else {
  54. input.prop('disabled', !enabled);
  55. }
  56. });
  57. });
  58. this.form.find(query).trigger('change');
  59. }
  60. _attachDisabledFields() {
  61. let prefix = '.form-field-toggleable .form-data';
  62. let query = [];
  63. ['input', 'select', 'label[for]', 'textarea', '.selectize-control'].forEach((item) => {
  64. query.push(`${prefix} ${item}`);
  65. });
  66. this.form.on('mousedown', query.join(', '), (event) => {
  67. let input = $(event.target);
  68. let isFor = input.prop('for');
  69. let isSelectize = (input.hasClass('selectize-control') || input.parents('.selectize-control')).length;
  70. if (isFor) { input = $(`[id="${isFor}"]`); }
  71. if (isSelectize) { input = input.closest('.selectize-control').siblings('select[name]'); }
  72. if (!input.prop('disabled')) { return true; }
  73. let toggle = input.closest('.form-field').find('[data-grav-field="toggleable"] input[type="checkbox"]');
  74. toggle.trigger('click');
  75. });
  76. }
  77. _submitUncheckedFields() {
  78. let submitted = false;
  79. this.form.each((index, form) => {
  80. form = $(form);
  81. form.on('submit', () => {
  82. // workaround for MS Edge, submitting multiple forms at the same time
  83. if (submitted) { return false; }
  84. let formId = form.attr('id');
  85. let unchecked = form.find('input[type="checkbox"]:not(:checked):not(:disabled)');
  86. let submit = form.find('[type="submit"]').add(`[form="${formId}"][type="submit"]`);
  87. if (!unchecked.length) { return true; }
  88. submit.addClass('pointer-events-disabled');
  89. unchecked.each((index, element) => {
  90. element = $(element);
  91. let name = element.prop('name');
  92. let fake = $(`<input type="hidden" name="${name}" value="0" />`);
  93. form.append(fake);
  94. });
  95. submitted = true;
  96. return true;
  97. });
  98. });
  99. }
  100. addedNodes(mutations) {
  101. mutations.forEach((mutation) => {
  102. if (mutation.type !== 'childList') { return; }
  103. if (mutation.addedNodes) {
  104. $('body').trigger('mutation._grav', mutation.target, mutation, this);
  105. }
  106. if (mutation.removedNodes) {
  107. $('body').trigger('mutation_removed._grav', { target: mutation.target, mutation }, this);
  108. }
  109. });
  110. }
  111. }
  112. export let Instance = new Form('form#blueprints');