PageSourceSearch

https://www.niceforyou.com/core/modules/file/file.js?v=10.6.14

js niceforyou.com collected 2026-09-24 09:46:15 UTC 9,798 bytes, 299 lines download raw bytes

1/**
2 * @file
3 * Provides JavaScript additions to the managed file field type.
4 *
5 * This file provides progress bar support (if available), popup windows for
6 * file previews, and disabling of other file fields during Ajax uploads (which
7 * prevents separate file fields from accidentally uploading files).
8 */
9
10(function ($, Drupal) {
11  /**
12   * Attach behaviors to the file fields passed in the settings.
13   *
14   * @type {Drupal~behavior}
15   *
16   * @prop {Drupal~behaviorAttach} attach
17   *   Attaches validation for file extensions.
18   * @prop {Drupal~behaviorDetach} detach
19   *   Detaches validation for file extensions.
20   */
21  Drupal.behaviors.fileValidateAutoAttach = {
22    attach(context, settings) {
23      const $context = $(context);
24      let elements;
25
26      function initFileValidation(selector) {
27        $(once('fileValidate', $context.find(selector))).on(
28          'change.fileValidate',
29          { extensions: elements[selector] },
30          Drupal.file.validateExtension,
31        );
32      }
33
34      if (settings.file && settings.file.elements) {
35        elements = settings.file.elements;
36        Object.keys(elements).forEach(initFileValidation);
37      }
38    },
39    detach(context, settings, trigger) {
40      const $context = $(context);
41      let elements;
42
43      function removeFileValidation(selector) {
44        $(once.remove('fileValidate', $context.find(selector))).off(
45          'change.fileValidate',
46          Drupal.file.validateExtension,
47        );
48      }
49
50      if (trigger === 'unload' && settings.file && settings.file.elements) {
51        elements = settings.file.elements;
52        Object.keys(elements).forEach(removeFileValidation);
53      }
54    },
55  };
56
57  /**
58   * Attach behaviors to file element auto upload.
59   *
60   * @type {Drupal~behavior}
61   *
62   * @prop {Drupal~behaviorAttach} attach
63   *   Attaches triggers for the upload button.
64   * @prop {Drupal~behaviorDetach} detach
65   *   Detaches auto file upload trigger.
66   */
67  Drupal.behaviors.fileAutoUpload = {
68    attach(context) {
69      $(once('auto-file-upload', 'input[type="file"]', context)).on(
70        'change.autoFileUpload',
71        Drupal.file.triggerUploadButton,
72      );
73    },
74    detach(context, settings, trigger) {
75      if (trigger === 'unload') {
76        $(once.remove('auto-file-upload', 'input[type="file"]', context)).off(
77          '.autoFileUpload',
78        );
79      }
80    },
81  };
82
83  /**
84   * Attach behaviors to the file upload and remove buttons.
85   *
86   * @type {Drupal~behavior}
87   *
88   * @prop {Drupal~behaviorAttach} attach
89   *   Attaches form submit events.
90   * @prop {Drupal~behaviorDetach} detach
91   *   Detaches form submit events.
92   */
93  Drupal.behaviors.fileButtons = {
94    attach(context) {
95      const $context = $(context);
96      $context
97        .find('.js-form-submit')
98        .on('mousedown', Drupal.file.disableFields);
99      $context
100        .find('.js-form-managed-file .js-form-submit')
101        .on('mousedown', Drupal.file.progressBar);
102    },
103    detach(context, settings, trigger) {
104      if (trigger === 'unload') {
105        const $context = $(context);
106        $context
107          .find('.js-form-submit')
108          .off('mousedown', Drupal.file.disableFields);
109        $context
110          .find('.js-form-managed-file .js-form-submit')
111          .off('mousedown', Drupal.file.progressBar);
112      }
113    },
114  };
115
116  /**
117   * Attach behaviors to links within managed file elements for preview windows.
118   *
119   * @type {Drupal~behavior}
120   *
121   * @prop {Drupal~behaviorAttach} attach
122   *   Attaches triggers.
123   * @prop {Drupal~behaviorDetach} detach
124   *   Detaches triggers.
125   */
126  Drupal.behaviors.filePreviewLinks = {
127    attach(context) {
128      $(context)
129        .find('div.js-form-managed-file .file a')
130        .on('click', Drupal.file.openInNewWindow);
131    },
132    detach(context) {
133      $(context)
134        .find('div.js-form-managed-file .file a')
135        .off('click', Drupal.file.openInNewWindow);
136    },
137  };
138
139  /**
140   * File upload utility functions.
141   *
142   * @namespace
143   */
144  Drupal.file = Drupal.file || {
145    /**
146     * Client-side file input validation of file extensions.
147     *
148     * @name Drupal.file.validateExtension
149     *
150     * @param {jQuery.Event} event
151     *   The event triggered. For example `change.fileValidate`.
152     */
153    validateExtension(event) {
154      event.preventDefault();
155      // Remove any previous errors.
156      $('.file-upload-js-error').remove();
157
158      // Add client side validation for the input[type=file].
159      const extensionPattern = event.data.extensions.replace(/,\s*/g, '|');
160      if (extensionPattern.length > 1 && this.value.length > 0) {
161        const acceptableMatch = new RegExp(`\\.(${extensionPattern})$`, 'gi');
162        if (!acceptableMatch.test(this.value)) {
163          const error = Drupal.t(
164            'The selected file %filename cannot be uploaded. Only files with the following extensions are allowed: %extensions.',
165            {
166              // According to the specifications of HTML5, a file upload control
167              // should not reveal the real local path to the file that a user
168              // has selected. Some web browsers implement this restriction by
169              // replacing the local path with "C:\fakepath\", which can cause
170              // confusion by leaving the user thinking perhaps Drupal could not
171              // find the file because it messed up the file path. To avoid this
172              // confusion, therefore, we strip out the bogus fakepath string.
173              '%filename': this.value.replace('C:\\fakepath\\', ''),
174              '%extensions': extensionPattern.replace(/\|/g, ', '),
175            },
176          );
177          $(this)
178            .closest('div.js-form-managed-file')
179            .prepend(
180              `<div class="messages messages--error file-upload-js-error" aria-live="polite">${error}</div>`,
181            );
182          this.value = '';
183          // Cancel all other change event handlers.
184          event.stopImmediatePropagation();
185        }
186      }
187    },
188
189    /**
190     * Trigger the upload_button mouse event to auto-upload as a managed file.
191     *
192     * @name Drupal.file.triggerUploadButton
193     *
194     * @param {jQuery.Event} event
195     *   The event triggered. For example `change.autoFileUpload`.
196     */
197    triggerUploadButton(event) {
198      $(event.target)
199        .closest('.js-form-managed-file')
200        .find('.js-form-submit[data-drupal-selector$="upload-button"]')
201        .trigger('mousedown');
202    },
203
204    /**
205     * Prevent file uploads when using buttons not intended to upload.
206     *
207     * @name Drupal.file.disableFields
208     *
209     * @param {jQuery.Event} event
210     *   The event triggered, most likely a `mousedown` event.
211     */
212    disableFields(event) {
213      const $clickedButton = $(this);
214      $clickedButton.trigger('formUpdated');
215
216      // Check if we're working with an "Upload" button.
217      let $enabledFields = [];
218      if ($clickedButton.closest('div.js-form-managed-file').length > 0) {
219        $enabledFields = $clickedButton
220          .closest('div.js-form-managed-file')
221          .find('input.js-form-file');
222      }
223
224      // Temporarily disable upload fields other than the one we're currently
225      // working with. Filter out fields that are already disabled so that they
226      // do not get enabled when we re-enable these fields at the end of
227      // behavior processing. Re-enable in a setTimeout set to a relatively
228      // short amount of time (1 second). All the other mousedown handlers
229      // (like Drupal's Ajax behaviors) are executed before any timeout
230      // functions are called, so we don't have to worry about the fields being
231      // re-enabled too soon. @todo If the previous sentence is true, why not
232      // set the timeout to 0?
233      const $fieldsToTemporarilyDisable = $(
234        'div.js-form-managed-file input.js-form-file',
235      )
236        .not($enabledFields)
237        .not(':disabled');
238      $fieldsToTemporarilyDisable.prop('disabled', true);
239      setTimeout(() => {
240        $fieldsToTemporarilyDisable.prop('disabled', false);
241      }, 1000);
242    },
243
244    /**
245     * Add progress bar support if possible.
246     *
247     * @name Drupal.file.progressBar
248     *
249     * @param {jQuery.Event} event
250     *   The event triggered, most likely a `mousedown` event.
251     */
252    progressBar(event) {
253      const $clickedButton = $(this);
254      const $progressId = $clickedButton
255        .closest('div.js-form-managed-file')
256        .find('input.file-progress');
257      if ($progressId.length) {
258        const originalName = $progressId.attr('name');
259
260        // Replace the name with the required identifier.
261        $progressId.attr(
262          'name',
263          originalName.match(/APC_UPLOAD_PROGRESS|UPLOAD_IDENTIFIER/)[0],
264        );
265
266        // Restore the original name after the upload begins.
267        setTimeout(() => {
268          $progressId.attr('name', originalName);
269        }, 1000);
270      }
271      // Show the progress bar if the upload takes longer than half a second.
272      setTimeout(() => {
273        $clickedButton
274          .closest('div.js-form-managed-file')
275          .find('div.ajax-progress-bar')
276          .slideDown();
277      }, 500);
278      $clickedButton.trigger('fileUpload');
279    },
280
281    /**
282     * Open links to files within forms in a new window.
283     *
284     * @name Drupal.file.openInNewWindow
285     *
286     * @param {jQuery.Event} event
287     *   The event triggered, most likely a `click` event.
288     */
289    openInNewWindow(event) {
290      event.preventDefault();
291      $(this).attr('target', '_blank');
292      window.open(
293        this.href,
294        'filePreview',
295        'toolbar=0,scrollbars=1,location=1,statusbar=1,menubar=0,resizable=1,width=500,height=550',
296      );
297    },
298  };
299})(jQuery, Drupal);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.