media.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. import $ from 'jquery';
  2. import FilesField from './file';
  3. import { config, translations } from 'grav-form';
  4. import Sortable from 'sortablejs';
  5. const template = `
  6. <div class="dz-preview dz-file-preview">
  7. <div class="dz-details">
  8. <div class="dz-filename"><span data-dz-name></span></div>
  9. <div class="dz-size" data-dz-size></div>
  10. <img data-dz-thumbnail />
  11. </div>
  12. <div class="dz-progress"><span class="dz-upload" data-dz-uploadprogress></span></div>
  13. <div class="dz-success-mark"><span>✔</span></div>
  14. <div class="dz-error-mark"><span>✘</span></div>
  15. <div class="dz-error-message"><span data-dz-errormessage></span></div>
  16. <a class="dz-remove" title="${translations.PLUGIN_FORM.DELETE}" href="javascript:undefined;" data-dz-remove>${translations.PLUGIN_FORM.DELETE}</a>
  17. </div>`.trim();
  18. export default class PageMedia extends FilesField {
  19. constructor({ container = '#grav-dropzone', options = {} } = {}) {
  20. const previewTemplate = $('#dropzone-media-template').html() || template;
  21. options = Object.assign(options, { previewTemplate });
  22. super({ container, options });
  23. if (!this.container.length) { return; }
  24. this.urls = {
  25. fetch: `${this.container.data('media-url')}/task${config.param_sep}listmedia`,
  26. add: `${this.container.data('media-url')}/task${config.param_sep}addmedia`,
  27. delete: `${this.container.data('media-url')}/task${config.param_sep}delmedia`
  28. };
  29. this.dropzone.options.url = this.urls.add;
  30. if (typeof this.options.fetchMedia === 'undefined' || this.options.fetchMedia) {
  31. this.fetchMedia();
  32. }
  33. const field = $(`[name="${this.container.data('dropzone-field')}"]`);
  34. if (field.length) {
  35. this.sortable = new Sortable(this.container.get(0), {
  36. animation: 150,
  37. // forceFallback: true,
  38. setData: (dataTransfer, target) => {
  39. target = $(target);
  40. this.dropzone.disable();
  41. target.addClass('hide-backface');
  42. dataTransfer.effectAllowed = 'copy';
  43. },
  44. onSort: () => {
  45. let names = [];
  46. this.container.find('[data-dz-name]').each((index, file) => {
  47. file = $(file);
  48. const name = file.text().trim();
  49. names.push(name);
  50. });
  51. field.val(names.join(','));
  52. }
  53. });
  54. }
  55. }
  56. onDropzoneRemovedFile(file, ...extra) {
  57. if (!file.accepted || file.rejected) { return; }
  58. const form = this.container.closest('form');
  59. const unique_id = form.find('[name="__unique_form_id__"]');
  60. let url = file.removeUrl || this.urls.delete || `${location.href}.json`;
  61. let path = (url || '').match(/path:(.*)\//);
  62. let data = new FormData();
  63. data.append('filename', file.name);
  64. data.append('__form-name__', form.find('[name="__form-name__"]').val());
  65. if (unique_id.length) {
  66. data.append('__unique_form_id__', unique_id.val());
  67. }
  68. data.append('name', this.options.dotNotation);
  69. data.append('form-nonce', config.form_nonce);
  70. if (file.sessionParams) {
  71. data.append('__form-file-remover__', '1');
  72. data.append('session', file.sessionParams);
  73. }
  74. $.ajax({
  75. url,
  76. data,
  77. method: 'POST',
  78. contentType: false,
  79. processData: false,
  80. success: () => {
  81. if (!path) { return; }
  82. path = global.atob(path[1]);
  83. let input = this.container.find('[name][type="hidden"]');
  84. let data = JSON.parse(input.val() || '{}');
  85. delete data[path];
  86. input.val(JSON.stringify(data));
  87. }
  88. });
  89. }
  90. fetchMedia() {
  91. const order = this.container.closest('.form-field').find('[name="data[header][media_order]"]').val();
  92. const data = { order };
  93. let url = this.urls.fetch;
  94. $.ajax({
  95. url,
  96. method: 'POST',
  97. data,
  98. success: (response) => {
  99. if (typeof response === 'string' || response instanceof String) {
  100. return false;
  101. }
  102. response = response.results;
  103. Object.keys(response).forEach((name) => {
  104. let data = response[name];
  105. let mock = { name, size: data.size, accepted: true, extras: data };
  106. this.dropzone.files.push(mock);
  107. this.dropzone.options.addedfile.call(this.dropzone, mock);
  108. this.dropzone.options.thumbnail.call(this.dropzone, mock, data.url);
  109. });
  110. this.container.find('.dz-preview').prop('draggable', 'true');
  111. }
  112. });
  113. /*
  114. request(url, { method: 'post', body }, (response) => {
  115. let results = response.results;
  116. Object.keys(results).forEach((name) => {
  117. let data = results[name];
  118. let mock = { name, size: data.size, accepted: true, extras: data };
  119. this.dropzone.files.push(mock);
  120. this.dropzone.options.addedfile.call(this.dropzone, mock);
  121. this.dropzone.options.thumbnail.call(this.dropzone, mock, data.url);
  122. });
  123. this.container.find('.dz-preview').prop('draggable', 'true');
  124. });*/
  125. }
  126. onDropzoneSending(file, xhr, formData) {
  127. /*
  128. // Cannot call super because Safari and IE API don't implement `delete`
  129. super.onDropzoneSending(file, xhr, formData);
  130. formData.delete('task');
  131. */
  132. formData.append('name', this.options.dotNotation);
  133. formData.append('admin-nonce', config.admin_nonce);
  134. }
  135. onDropzoneComplete(file) {
  136. super.onDropzoneComplete(file);
  137. this.sortable.options.onSort();
  138. // accepted
  139. $('.dz-preview').prop('draggable', 'true');
  140. }
  141. onDropzoneRemovedFile(file, ...extra) {
  142. super.onDropzoneRemovedFile(file, ...extra);
  143. this.sortable.options.onSort();
  144. }
  145. }
  146. export let Instance = new PageMedia();