filefield_sources.js 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. /**
  2. * @file
  3. * Defines Javascript behaviors for the filefield_sources module.
  4. */
  5. (function ($, Drupal) {
  6. "use strict";
  7. // Behavior to add source options to configured fields.
  8. Drupal.behaviors.fileFieldSources = {};
  9. Drupal.behaviors.fileFieldSources.attach = function(context, settings) {
  10. $('div.filefield-sources-list:not(.filefield-sources-processed)', context).each(function() {
  11. $(this).addClass('filefield-sources-processed');
  12. var $fileFieldElement = $(this).parents('div.form-managed-file:first');
  13. $(this).find('a').click(function() {
  14. // Remove the active class.
  15. $(this).parents('div.filefield-sources-list').find('a.active').removeClass('active');
  16. // Find the unique FileField Source class name.
  17. var fileFieldSourceClass = this.className.match(/filefield-source-[0-9a-z_]+/i)[0];
  18. // The default upload element is a special case.
  19. if ($(this).is('.filefield-source-upload')) {
  20. $fileFieldElement.find('div.filefield-sources-list').siblings('.form-file, .form-submit').css('display', '');
  21. $fileFieldElement.find('div.filefield-source').css('display', 'none');
  22. }
  23. else {
  24. $fileFieldElement.find('div.filefield-sources-list').siblings('.form-file, .form-submit').css('display', 'none');
  25. $fileFieldElement.find('div.filefield-source').not('div.' + fileFieldSourceClass).css('display', 'none');
  26. $fileFieldElement.find('div.' + fileFieldSourceClass).css('display', '');
  27. }
  28. // Add the active class.
  29. $(this).addClass('active');
  30. Drupal.fileFieldSources.updateHintText($fileFieldElement.get(0));
  31. }).first().triggerHandler('click');
  32. // Clipboard support.
  33. $fileFieldElement.find('.filefield-source-clipboard-capture')
  34. .bind('paste', Drupal.fileFieldSources.pasteEvent)
  35. .bind('focus', Drupal.fileFieldSources.pasteFocus)
  36. .bind('blur', Drupal.fileFieldSources.pasteBlur);
  37. // Imce support.
  38. $fileFieldElement.find('.filefield-sources-imce-browse')
  39. .bind('click', Drupal.fileFieldSources.imceBrowse);
  40. });
  41. if (context === document) {
  42. $('form').submit(function() {
  43. Drupal.fileFieldSources.removeHintText();
  44. });
  45. }
  46. };
  47. // Helper functions used by FileField Sources.
  48. Drupal.fileFieldSources = {
  49. /**
  50. * Update the hint text when clicking between source types.
  51. */
  52. updateHintText: function(fileFieldElement) {
  53. // Add default value hint text to text fields.
  54. $(fileFieldElement).find('div.filefield-source').each(function() {
  55. var matches = this.className.match(/filefield-source-([a-z]+)/);
  56. var sourceType = matches[1];
  57. var textfield = $(this).find('input.form-text:first').get(0);
  58. var defaultText = (drupalSettings.fileFieldSources && drupalSettings.fileFieldSources[sourceType]) ? drupalSettings.fileFieldSources[sourceType].hintText : '';
  59. // If the field doesn't exist, just return.
  60. if (!textfield) {
  61. return;
  62. }
  63. // If this field is not shown, remove its value and be done.
  64. if (!$(this).is(':visible') && textfield.value == defaultText) {
  65. textfield.value = '';
  66. return;
  67. }
  68. // Set a default value:
  69. if (textfield.value == '') {
  70. textfield.value = defaultText;
  71. }
  72. // Set a default class.
  73. if (textfield.value == defaultText) {
  74. $(textfield).addClass('hint');
  75. }
  76. $(textfield).focus(hideHintText);
  77. $(textfield).blur(showHintText);
  78. function showHintText() {
  79. if (this.value == '') {
  80. this.value = defaultText;
  81. $(this).addClass('hint');
  82. }
  83. }
  84. function hideHintText() {
  85. if (this.value == defaultText) {
  86. this.value = '';
  87. $(this).removeClass('hint');
  88. }
  89. }
  90. });
  91. },
  92. /**
  93. * Delete all hint text from a form before submit.
  94. */
  95. removeHintText: function() {
  96. $('div.filefield-source input.hint').val('').removeClass('hint');
  97. },
  98. /**
  99. * Clean up the default value on focus.
  100. */
  101. pasteFocus: function(e) {
  102. // Set default text.
  103. if (!this.defaultText) {
  104. this.defaultText = this.innerHTML;
  105. this.innerHTML = '';
  106. }
  107. // Remove non-text nodes.
  108. $(this).children().remove();
  109. },
  110. /**
  111. * Restore default value on blur.
  112. */
  113. pasteBlur: function(e) {
  114. if (this.defaultText && !this.innerHTML) {
  115. this.innerHTML = this.defaultText;
  116. }
  117. },
  118. pasteEvent: function(e) {
  119. var clipboardData = null;
  120. var targetElement = this;
  121. var userAgent = navigator.userAgent.toLowerCase();
  122. // Chrome.
  123. if (window.event && window.event.clipboardData && window.event.clipboardData.items) {
  124. clipboardData = window.event.clipboardData;
  125. }
  126. // All browsers in the future (hopefully).
  127. else if (e.originalEvent && e.originalEvent.clipboardData && e.originalEvent.clipboardData.items) {
  128. clipboardData = e.originalEvent.clipboardData;
  129. }
  130. // Firefox with content editable pastes as img tag with data href.
  131. else if (userAgent.match(/mozilla/) && !userAgent.match(/webkit/)) {
  132. Drupal.fileFieldSources.waitForPaste(targetElement);
  133. return true;
  134. }
  135. else {
  136. Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('Paste from clipboard not supported in this browser.'));
  137. return false;
  138. }
  139. var items = clipboardData.items;
  140. var types = clipboardData.types;
  141. var filename = targetElement.firstChild ? targetElement.firstChild.textContent : '';
  142. // Handle files and image content directly in the clipboard.
  143. var fileFound = false;
  144. for (var n = 0; n < items.length; n++) {
  145. if (items[n] && items[n].kind === 'file') {
  146. var fileBlob = items[n].getAsFile();
  147. var fileReader = new FileReader();
  148. // Define events to fire after the file is read into memory.
  149. fileReader.onload = function() {
  150. Drupal.fileFieldSources.pasteSubmit(targetElement, filename, this.result);
  151. };
  152. fileReader.onerror = function() {
  153. Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('Error reading file from clipboard.'));
  154. };
  155. // Read in the file to fire the above events.
  156. fileReader.readAsDataURL(fileBlob);
  157. fileFound = true;
  158. break;
  159. }
  160. // Handle files that a copy/pasted as a file reference.
  161. /* if (types[n] && types[n] === 'Files') {
  162. TODO: Figure out how to capture copy/paste of entire files from desktop.
  163. }*/
  164. }
  165. if (!fileFound) {
  166. Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('No file in clipboard.'));
  167. }
  168. return false;
  169. },
  170. /**
  171. * For browsers that don't support native clipboardData attributes.
  172. */
  173. waitForPaste: function(targetElement) {
  174. if (targetElement.children && targetElement.children.length > 0) {
  175. var filename = targetElement.firstChild ? targetElement.firstChild.textContent : '';
  176. var tagFound = false;
  177. $(targetElement).find('img[src^="data:image"]').each(function(n, element) {
  178. Drupal.fileFieldSources.pasteSubmit(targetElement, filename, element.src);
  179. tagFound = true;
  180. });
  181. $(targetElement).html(filename);
  182. if (!tagFound) {
  183. Drupal.fileFieldSources.pasteError(targetElement, Drupal.t('No file in clipboard.'));
  184. }
  185. }
  186. else {
  187. setTimeout(function() {
  188. Drupal.fileFieldSources.waitForPaste(targetElement);
  189. }, 200);
  190. }
  191. },
  192. /**
  193. * Set an error on the paste field temporarily then clear it.
  194. */
  195. pasteError: function(domElement, errorMessage) {
  196. var $description = $(domElement).parents('.filefield-source-clipboard:first').find('.description');
  197. if (!$description.data('originalDescription')) {
  198. $description.data('originalDescription', $description.html())
  199. }
  200. $description.html(errorMessage);
  201. var errorTimeout = setTimeout(function() {
  202. $description.html($description.data('originalDescription'));
  203. $(this).unbind('click.pasteError');
  204. }, 3000);
  205. $(domElement).bind('click.pasteError', function() {
  206. clearTimeout(errorTimeout);
  207. $description.html($description.data('originalDescription'));
  208. $(this).unbind('click.pasteError');
  209. });
  210. },
  211. /**
  212. * After retreiving a clipboard, post the results to the server.
  213. */
  214. pasteSubmit: function(targetElement, filename, contents) {
  215. var $wrapper = $(targetElement).parents('.filefield-source-clipboard');
  216. $wrapper.find('.filefield-source-clipboard-filename').val(filename);
  217. $wrapper.find('.filefield-source-clipboard-contents').val(contents);
  218. $wrapper.find('input.form-submit').trigger('mousedown');
  219. },
  220. /**
  221. * Click event for the imce browse link.
  222. */
  223. imceBrowse: function (e) {
  224. window.open(this.href, '', 'width=760,height=560,resizable=1');
  225. e.preventDefault();
  226. }
  227. };
  228. // Override triggerUploadButton method from file.js.
  229. Drupal.file.triggerUploadButton = function (event) {
  230. $(event.target).closest('.form-managed-file').find('.form-submit.upload-button').trigger('mousedown');
  231. }
  232. })(jQuery, Drupal);