3 * Defines Javascript behaviors for the filefield_sources module.
6 (function ($, Drupal) {
10 // Behavior to add source options to configured fields.
11 Drupal.behaviors.fileFieldSources = {};
12 Drupal.behaviors.fileFieldSources.attach = function(context, settings) {
13 $('div.filefield-sources-list:not(.filefield-sources-processed)', context).each(function() {
14 $(this).addClass('filefield-sources-processed');
15 var $fileFieldElement = $(this).parents('div.form-managed-file:first');
16 $(this).find('a').click(function() {
17 // Remove the active class.
18 $(this).parents('div.filefield-sources-list').find('a.active').removeClass('active');
20 // Find the unique FileField Source class name.
21 var fileFieldSourceClass = this.className.match(/filefield-source-[0-9a-z_]+/i)[0];
23 // The default upload element is a special case.
24 if ($(this).is('.filefield-source-upload')) {
25 $fileFieldElement.find('div.filefield-sources-list').siblings('.form-file, .form-submit').css('display', '');
26 $fileFieldElement.find('div.filefield-source').css('display', 'none');
29 $fileFieldElement.find('div.filefield-sources-list').siblings('.form-file, .form-submit').css('display', 'none');
30 $fileFieldElement.find('div.filefield-source').not('div.' + fileFieldSourceClass).css('display', 'none');
31 $fileFieldElement.find('div.' + fileFieldSourceClass).css('display', '');
34 // Add the active class.
35 $(this).addClass('active');
36 Drupal.fileFieldSources.updateHintText($fileFieldElement.get(0));
37 }).first().triggerHandler('click');
40 $fileFieldElement.find('.filefield-source-clipboard-capture')
41 .bind('paste', Drupal.fileFieldSources.pasteEvent)
42 .bind('focus', Drupal.fileFieldSources.pasteFocus)
43 .bind('blur', Drupal.fileFieldSources.pasteBlur);
46 $fileFieldElement.find('.filefield-sources-imce-browse')
47 .bind('click', Drupal.fileFieldSources.imceBrowse);
50 if (context === document) {
51 $('form').submit(function() {
52 Drupal.fileFieldSources.removeHintText();
57 // Helper functions used by FileField Sources.
58 Drupal.fileFieldSources = {
60 * Update the hint text when clicking between source types.
62 updateHintText: function(fileFieldElement) {
63 // Add default value hint text to text fields.
64 $(fileFieldElement).find('div.filefield-source').each(function() {
65 var matches = this.className.match(/filefield-source-([a-z]+)/);
66 var sourceType = matches[1];
67 var textfield = $(this).find('input.form-text:first').get(0);
68 var defaultText = (drupalSettings.fileFieldSources && drupalSettings.fileFieldSources[sourceType]) ? drupalSettings.fileFieldSources[sourceType].hintText : '';
70 // If the field doesn't exist, just return.
75 // If this field is not shown, remove its value and be done.
76 if (!$(this).is(':visible') && textfield.value == defaultText) {
81 // Set a default value:
82 if (textfield.value == '') {
83 textfield.value = defaultText;
86 // Set a default class.
87 if (textfield.value == defaultText) {
88 $(textfield).addClass('hint');
91 $(textfield).focus(hideHintText);
92 $(textfield).blur(showHintText);
94 function showHintText() {
95 if (this.value == '') {
96 this.value = defaultText;
97 $(this).addClass('hint');
101 function hideHintText() {
102 if (this.value == defaultText) {
104 $(this).removeClass('hint');
111 * Delete all hint text from a form before submit.
113 removeHintText: function() {
114 $('div.filefield-source input.hint').val('').removeClass('hint');
118 * Clean up the default value on focus.
120 pasteFocus: function(e) {
122 if (!this.defaultText) {
123 this.defaultText = this.innerHTML;
126 // Remove non-text nodes.
127 $(this).children().remove();
131 * Restore default value on blur.
133 pasteBlur: function(e) {
134 if (this.defaultText && !this.innerHTML) {
135 this.innerHTML = this.defaultText;
139 pasteEvent: function(e) {
140 var clipboardData = null;
141 var targetElement = this;
142 var userAgent = navigator.userAgent.toLowerCase();
145 if (window.event && window.event.clipboardData && window.event.clipboardData.items) {
146 clipboardData = window.event.clipboardData;
148 // All browsers in the future (hopefully).
149 else if (e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.items) {
150 clipboardData = e.originalEvent.clipboardData;
152 // Firefox with content editable pastes as img tag with data href.
153 else if (userAgent.match(/mozilla/) && !userAgent.match(/webkit/)) {
154 Drupal.fileFieldSources.waitForPaste(targetElement);
158 Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('Paste from clipboard not supported in this browser.'));
162 var items = clipboardData.items;
163 var types = clipboardData.types;
164 var filename = targetElement.firstChild ? targetElement.firstChild.textContent : '';
166 // Handle files and image content directly in the clipboard.
167 var fileFound = false;
168 for (var n = 0; n < items.length; n++) {
169 if (items[n] && items[n].kind === 'file') {
170 var fileBlob = items[n].getAsFile();
171 var fileReader = new FileReader();
172 // Define events to fire after the file is read into memory.
173 fileReader.onload = function() {
174 Drupal.fileFieldSources.pasteSubmit(targetElement, filename, this.result);
176 fileReader.onerror = function() {
177 Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('Error reading file from clipboard.'));
179 // Read in the file to fire the above events.
180 fileReader.readAsDataURL(fileBlob);
184 // Handle files that a copy/pasted as a file reference.
185 /* if (types[n] && types[n] === 'Files') {
186 TODO: Figure out how to capture copy/paste of entire files from desktop.
190 Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('No file in clipboard.'));
196 * For browsers that don't support native clipboardData attributes.
198 waitForPaste: function(targetElement) {
199 if (targetElement.children && targetElement.children.length > 0) {
200 var filename = targetElement.firstChild ? targetElement.firstChild.textContent : '';
201 var tagFound = false;
202 $(targetElement).find('img[src^="data:image"]').each(function(n, element) {
203 Drupal.fileFieldSources.pasteSubmit(targetElement, filename, element.src);
206 $(targetElement).html(filename);
208 Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('No file in clipboard.'));
212 setTimeout(function() {
213 Drupal.fileFieldSources.waitForPaste(targetElement);
219 * Set an error on the paste field temporarily then clear it.
221 pasteError: function(domElement, errorMessage) {
222 var $description = $(domElement).parents('.filefield-source-clipboard:first').find('.description');
223 if (!$description.data('originalDescription')) {
224 $description.data('originalDescription', $description.html())
226 $description.html(errorMessage);
227 var errorTimeout = setTimeout(function() {
228 $description.html($description.data('originalDescription'));
229 $(this).unbind('click.pasteError');
231 $(domElement).bind('click.pasteError', function() {
232 clearTimeout(errorTimeout);
233 $description.html($description.data('originalDescription'));
234 $(this).unbind('click.pasteError');
239 * After retreiving a clipboard, post the results to the server.
241 pasteSubmit: function(targetElement, filename, contents) {
242 var $wrapper = $(targetElement).parents('.filefield-source-clipboard');
243 $wrapper.find('.filefield-source-clipboard-filename').val(filename);
244 $wrapper.find('.filefield-source-clipboard-contents').val(contents);
245 $wrapper.find('input.form-submit').trigger('mousedown');
249 * Click event for the imce browse link.
251 imceBrowse: function (e) {
252 window.open(this.href, '', 'width=760,height=560,resizable=1');
257 // Override triggerUploadButton method from file.js.
258 Drupal.file.triggerUploadButton = function (event) {
259 $(event.target).closest('.form-managed-file').find('.form-submit.upload-button').trigger('mousedown');