swfupload_widget.js 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952
  1. // $Id: jw_player.js, v 0.1, 2009/07/28 12:11:24, skilip Exp $;
  2. (function ($) {
  3. /**
  4. *
  5. */
  6. function SWFU(id, settings) {
  7. var ref = {};
  8. ref.settings = {};
  9. ref.ajax_settings = {};
  10. ref.queue = {};
  11. ref.stats = {};
  12. ref.instance = {};
  13. ref.upload_stack_length = 0;
  14. ref.max_queue_size = 0;
  15. ref.upload_stack = {};
  16. ref.upload_stack_obj;
  17. ref.upload_button_obj;
  18. ref.upload_stack_size = 0;
  19. ref.wrapper_obj;
  20. ref.wrapper_id;
  21. ref.num_elements;
  22. ref.key_pressed;
  23. ref.message_wrapper_obj;
  24. ref.messages_timeout;
  25. /**
  26. *
  27. */
  28. ref.init = function() {
  29. ref.settings = settings;
  30. ref.upload_button_obj = $('#' + ref.settings.upload_button_id);
  31. ref.instance = {name:settings.file_post_name};
  32. ref.ajax_settings = {
  33. type:"post",
  34. url:ref.settings.upload_url,
  35. data:{
  36. op:'init',
  37. file_path:ref.settings.post_params.file_path,
  38. instance:ref.toJson(ref.instance),
  39. instance_settings:ref.settings.post_params.instance_settings
  40. },
  41. success:function(result) {
  42. ref.ajaxResponse(result);
  43. }
  44. };
  45. ref.prepareSWFButton();
  46. // Get the instance data by an AJAX request in order to let other modules change the callbacks and elements for this instance (using hook_swfupload);
  47. $.ajax(ref.ajax_settings);
  48. };
  49. /**
  50. * Prepares the swfupload button.
  51. */
  52. ref.prepareSWFButton = function() {
  53. // Create a copy of the button to get it's dimensions.
  54. // If we'd use the original button, we could end up with dimensions equal to 0px when the button is inside a hidden fieldset.
  55. var tmp_button = ref.upload_button_obj.clone().css({'position':'absolute'}).prependTo('body');
  56. // Set the dimensions of the swf so it matches exactly the dimensions of the upload button
  57. // swfupload.swf will be placed exactly over the upload button
  58. ref.settings.button_width = (tmp_button.find('.left').width() + tmp_button.find('.center').width() + tmp_button.find('.right').width());
  59. ref.settings.button_height = tmp_button.find('.center').height();
  60. tmp_button.remove();
  61. // Add the other button settings to the settings object
  62. ref.settings.button_placeholder_id = ref.settings.file_post_name + '-swfwrapper';
  63. ref.settings.button_window_mode = SWFUpload.WINDOW_MODE.TRANSPARENT;
  64. ref.settings.button_cursor = SWFUpload.CURSOR.HAND;
  65. };
  66. /**
  67. * Creates a hidden input field which will contain a JSON formatted string containing all uploaded files
  68. */
  69. ref.createStackObj = function() {
  70. var upload_stack_value = settings.custom_settings.upload_stack_value;
  71. ref.max_queue_size = settings.custom_settings.max_queue_size;
  72. ref.upload_stack_obj = $('<input type="hidden" />').attr('name', ref.instance.name).val(upload_stack_value).prependTo(ref.upload_button_obj);
  73. ref.upload_stack = jQuery.parseJSON(upload_stack_value);
  74. ref.upload_stack_length = ref.objectLength(ref.upload_stack);
  75. };
  76. /**
  77. *
  78. */
  79. ref.newSWFUpload = function() {
  80. ref.swfu = new SWFUpload(ref.settings);
  81. };
  82. /**
  83. *
  84. */
  85. ref.ajaxResponse = function(result) {
  86. var result = jQuery.parseJSON(result);
  87. switch (result.op) {
  88. case 'init':
  89. ref.instance = result.instance;
  90. ref.num_elements = ref.objectLength(ref.instance.elements);
  91. $.each(result.instance.callbacks, function(setting, callback) {
  92. ref.settings[setting] = eval(callback);
  93. });
  94. ref.newSWFUpload();
  95. ref.settings.init_complete_handler(result);
  96. break;
  97. };
  98. ref.addEventHandlers(result.op);
  99. };
  100. /**
  101. * Custom function for when the initialization is complete
  102. * This event handler is defined in swfupload.module as an instance callback function
  103. */
  104. ref.initComplete = function(result) {
  105. ref.createWrapper(result.instance.name);
  106. ref.createStackObj();
  107. ref.addStoredFiles();
  108. // Enable the upload button if the current stack is smaller than the allowed stack size,
  109. // or when there's no limit at all.
  110. if ((ref.settings.file_upload_limit && (ref.upload_stack_length < ref.settings.file_upload_limit)) || ref.settings.file_upload_limit === 0) {
  111. ref.upload_button_obj.removeClass('disabled').css({opacity:1});
  112. }
  113. else {
  114. ref.upload_button_obj.addClass('disabled').css({opacity:0.4});
  115. };
  116. };
  117. /**
  118. * This will process all file elements stored in the upload stack.
  119. * The upload represents all files submitted in the upload form.
  120. * For all files in the stack, a file element will be added to the wrapper using ref.addFileItem().
  121. */
  122. ref.addStoredFiles = function() {
  123. for(var i in ref.upload_stack) {
  124. if (ref.upload_stack[i] == 0) {
  125. break;
  126. };
  127. ref.upload_stack[i].id = i;
  128. ref.upload_stack[i].fid = i;
  129. ref.upload_stack[i].extension = ref.getExtension(ref.upload_stack[i].filename);
  130. ref.addFileItem(ref.upload_stack[i]);
  131. // Adjust the bytes in the stack.
  132. ref.upload_stack_size += parseInt(ref.upload_stack[i].filesize);
  133. };
  134. ref.addEventHandlers('drag_enable');
  135. };
  136. /**
  137. * Places the wrapper markup above the upload button
  138. * Depending on what type isset by the instance, a table or a list element is created.
  139. */
  140. ref.createWrapper = function(field_name) {
  141. var use_header = false;
  142. var element;
  143. if (ref.num_elements > 1 && ref.instance.type == 'table') {
  144. // First we'll check if we need to create a header
  145. for (var name in ref.instance.elements) {
  146. if (ref.instance.elements[name].title) {
  147. use_header = true;
  148. };
  149. };
  150. ref.wrapper_id = 'swfupload_file_wrapper-' + field_name.replace(/[\[\]]/g, '-');
  151. ref.wrapper_obj = $('<table />').attr({'id': ref.wrapper_id, 'class':'swfupload'});
  152. if (use_header) {
  153. ref.wrapper_obj.append($('<thead />').append(ref.tableRow(true)));
  154. };
  155. ref.wrapper_obj.append($('<tbody />').append(ref.tableRow()));
  156. ref.upload_button_obj.before(ref.wrapper_obj);
  157. if (!Drupal.settings.tableDrag) {
  158. Drupal.settings.tableDrag = {};
  159. };
  160. Drupal.settings.tableDrag[ref.wrapper_id] = {};
  161. };
  162. };
  163. /**
  164. * Creates or changes a tablerow
  165. * @param header Boolean Wheter or not the tablerow should contain th's. If sety to false, td's will be generated.
  166. * @param file Object A completed file object
  167. * - If this is not set, a row is created including the progressbar, which replaces the td's with contains_progressbar set to true.
  168. * - If file is set, the progressbar will be replaced with the appropriate td's
  169. */
  170. ref.tableRow = function(header, file) {
  171. var counter = 0;
  172. var colspan = 0;
  173. var fid = (file) ? file.fid : 0;
  174. var progress_td_counter = 0;
  175. var element, colum, content, input, progress_td, elem_value, value;
  176. var tr = (file) ? $('#' + file.fid) : $('<tr />');
  177. var wrapper = $('<div />').addClass('wrapper');
  178. var left_span = $('<div />').addClass('left').html('&nbsp;');
  179. var center_span = $('<div />').addClass('center');
  180. var right_span = $('<div />').addClass('right').html('&nbsp;');
  181. // A tablerow will be created containing all elements defined in ref.instance.elements.
  182. // If file is set, all elements will be skipped exept the ones with 'contains_progressbar'
  183. // If file isn't set, this tablerow will be hidden.
  184. for (var name in ref.instance.elements) {
  185. counter++;
  186. element = ref.instance.elements[name];
  187. if (file) {
  188. if(!element.contains_progressbar) {
  189. // The current td doesn't have to be replaced.
  190. // We only need to replace fid of the id and name of the input field
  191. tr.find('#edit-' + name + '_0').attr({'name':name +'_' + fid, 'id':'edit-' + name + '_' + fid});
  192. continue;
  193. };
  194. }
  195. else {
  196. if (!header && element.contains_progressbar) {
  197. if (!progress_td) {
  198. progress_td = $('<td />').addClass('progress').append($('<div />').addClass('sfwupload-list-progressbar').append($('<div />').addClass('sfwupload-list-progressbar-status')).append($('<div />').addClass('sfwupload-list-progressbar-glow'))).appendTo(tr);
  199. };
  200. progress_td_counter++;
  201. continue;
  202. };
  203. };
  204. column = $((header ? '<th />' : '<td />'));
  205. content = wrapper.clone().appendTo(column);
  206. input = $((element.type == 'textarea' ? '<textarea />' : '<input type="' + element.type + '" />')).attr({'name':name +'_' + fid, 'id':'edit-' + name + '_' + fid}).addClass('form-' + element.type);
  207. if (header) {
  208. // Keep track of colspans
  209. if (colspan > 0) colspan--;
  210. if (element.colspan) {
  211. colspan = element.colspan;
  212. }
  213. else if (colspan !== 0) {
  214. continue;
  215. };
  216. // Add the colspan if set.
  217. if (element.colspan) {
  218. column.attr({'colSpan':element.colspan});
  219. };
  220. // Add a separator only if we're not dealing with the first or last column
  221. if (counter !== ref.num_elements && (counter + (colspan - 1) !== ref.num_elements) && element.add_separator) {
  222. content.append(left_span.clone()).append(right_span.clone());
  223. };
  224. content.append(center_span.clone().html((element.title ? element.title : '&nbsp;')));
  225. }
  226. else {
  227. elem_value = (element.value) || element.default_value;
  228. // Create the content for this td
  229. // Depending on the type the appropriate input field is appended to store the values of this type
  230. switch (element.type) {
  231. case 'icon':
  232. case 'cancel':
  233. content.append($('<div />').addClass('sfwupload-list-' + (element.type == 'icon' ? 'mime' : element.type)));
  234. break;
  235. case 'textfield':
  236. case 'textarea':
  237. value = (file ? ref.replaceMacros(elem_value, file) : elem_value);
  238. content.append($('<span />').html((value !== '' ? value : '&nbsp;'))).append(input.css({'display':'none'}).val((value ? value : '')));
  239. break;
  240. case 'checkbox':
  241. value = (file[name] !== undefined) ? (typeof(file[name]) == 'string' ? (file[name] == '1') : file[name]) : elem_value;
  242. // For IE we need to check the checkbox after the content has been added to the tr.
  243. // We'll temporarily store it's value in a classname
  244. content.append(input.addClass('checkbox ' + (value ? 'checked' : '')));
  245. break;
  246. case 'markup':
  247. value = (file) ? (file[name] !== undefined) ? file[name] : ref.replaceMacros(elem_value, file) : elem_value;
  248. content.append($('<div />').addClass('swfupload-markup').attr('id', 'swfupload-markup-' + name).html(value));
  249. break;
  250. default:
  251. break;
  252. };
  253. };
  254. // Add a classname if set.
  255. if (element.classname) {
  256. column.addClass(element.classname);
  257. };
  258. if (file && element.contains_progressbar) {
  259. column.insertBefore(tr.find('td.progress'));
  260. }
  261. else {
  262. tr.append(column);
  263. };
  264. };
  265. if (!header && !file) {
  266. // Hide the tablerow
  267. tr.addClass('hidden');
  268. };
  269. if (progress_td) {
  270. progress_td.attr({'colSpan':progress_td_counter});
  271. };
  272. // Update the checked value of all added checkboxes
  273. tr.find('input.checkbox').each(function() {
  274. $(this).attr('checked', $(this).hasClass('checked'));
  275. });
  276. if (file) {
  277. tr.addClass('processed').find('td.progress').remove();
  278. }
  279. else {
  280. // Create borders
  281. var border = $(header ? '<th />' : '<td />').addClass('border').append($('<img />').attr({'src':Drupal.settings.basePath + ref.settings.module_path + '/images/spacer.gif'}).css({'width':'1px'}));
  282. tr.prepend(border.clone()).append(border);
  283. return tr;
  284. };
  285. };
  286. /**
  287. * A file has been selected. This function creates the markup referring to the new file object
  288. */
  289. ref.addFileItem = function(file) {
  290. // Create the markup for the new file by copying the hidden template
  291. var new_file_obj = ref.wrapper_obj.find('.hidden').clone().attr({'id':file.id}).appendTo(ref.wrapper_obj);
  292. var dom_obj, value, elem_value;
  293. // Remove tabledrag elements
  294. new_file_obj.find('a.tabledrag-handle').remove();
  295. // If it is a file earlier stored (a file in the upload_stack), remove it's progressbar.
  296. if (file.filestatus !== -1) {
  297. ref.tableRow(false, file);
  298. };
  299. // Replace macro's
  300. for (var name in ref.instance.elements) {
  301. dom_obj = new_file_obj.find('#edit-' + name + '_' + (file.fid || '0') + ', #swfupload-markup-' + name);
  302. if (dom_obj.size() > 0) {
  303. elem_value = (ref.instance.elements[name].value) || ref.instance.elements[name].default_value;
  304. value = (file[name] !== undefined) ? file[name] : ref.replaceMacros(elem_value, file);
  305. if (dom_obj[0].tagName.toLowerCase() == 'input' || dom_obj[0].tagName.toLowerCase() == 'textarea') {
  306. dom_obj.val(value);
  307. }
  308. else {
  309. dom_obj.html(value).show();
  310. };
  311. // If the inputfield is hidden, we're dealing with a string.
  312. // Look if there is a span of which the text can be replaced
  313. if (dom_obj.css('display') == 'none') {
  314. dom_obj.parent().find('span').text(value);
  315. };
  316. };
  317. };
  318. if (file.thumb) {
  319. // Attach the thumbnail image
  320. new_file_obj.find('.sfwupload-list-mime').css({'background-image': 'url(' + file.thumb + ')'});
  321. }
  322. else {
  323. // Add the extension to the mime icon
  324. new_file_obj.find('.sfwupload-list-mime').addClass(file.extension);
  325. };
  326. // Fix transparency for IE6
  327. if ($.cssPNGFix) {
  328. new_file_obj.find('.sfwupload-list-mime').cssPNGFix();
  329. };
  330. new_file_obj.removeClass('hidden').addClass('draggable');
  331. ref.addEventHandlers((file.filestatus == -1 ? 'file_queued' : 'file_added'), file);
  332. };
  333. /**
  334. * Attaches all event handlers to the loaded markup
  335. */
  336. ref.addEventHandlers = function(op, file) {
  337. switch (op) {
  338. case 'flash_loaded':
  339. ref.upload_button_obj.find('.swfupload-wrapper .swfupload').mousedown(function() {
  340. $(this).parent().parent().addClass('active');
  341. }).mouseup(function() {
  342. $(this).parent().parent().removeClass('active');
  343. });
  344. break;
  345. case 'file_queued':
  346. $('#' + file.id).find('.sfwupload-list-cancel').click(function() {
  347. ref.cancelUpload(file);
  348. });
  349. break;
  350. case 'file_added':
  351. var file_element_obj = $('#' + file.fid);
  352. file_element_obj.find('.sfwupload-list-cancel').unbind('click').click(function() {
  353. ref.removeFileItem(file);
  354. }).disableTextSelect();
  355. file_element_obj.find('input:checkbox').bind('click', function() {
  356. ref.updateStack(file);
  357. });
  358. file_element_obj.find('input:text, textarea').blur(function() {
  359. ref.toggleInput($(this), false, file);
  360. }).keydown(function(e) {
  361. ref.key_pressed = e.keyCode;
  362. if ((e.keyCode == 27) || (e.keyCode == 13 && $(this).get(0).tagName.toLowerCase() !== 'textarea')) {
  363. $(this).blur();
  364. return false;
  365. };
  366. }).parents('td').dblclick(function() {
  367. ref.toggleInput($(this).find('span'), true, file);
  368. }).find('.wrapper').append($('<a href="#" />').text(Drupal.t('edit')).addClass('toggle-editable').click(function() {
  369. ref.toggleInput($(this).parent().find('span'), true, file);
  370. return false;
  371. }));
  372. break;
  373. case 'drag_enable':
  374. // Attach the tabledrag behavior
  375. // This will we only executed once.
  376. Drupal.attachBehaviors(ref.wrapper_obj.parent());
  377. $('.tabledrag-toggle-weight-wrapper', ref.wrapper_obj.parent()).hide();
  378. $('tbody tr', ref.wrapper_obj).not('.hidden, .tabledrag-handle-swfupload-moved').each(function() {
  379. if (!$('a.tabledrag-handle', $(this)).size()) {
  380. Drupal.tableDrag[ref.wrapper_id].makeDraggable(this);
  381. };
  382. $('a.tabledrag-handle', $(this)).not('.tabledrag-handle-swfupload-moved').each(function() {
  383. $(this).appendTo($(this).parents('tr').addClass('tabledrag-handle-swfupload-moved').find('td.drag div.wrapper')).bind('mousedown', function() {
  384. $(this).parents('tr').addClass('dragging');
  385. });
  386. });
  387. });
  388. $(document).unbind('mouseup', ref.tableDragStop).bind('mouseup', ref.tableDragStop);
  389. break;
  390. default:
  391. break;
  392. };
  393. };
  394. /**
  395. * Triggered when the user has stopped dragging a tablerow.
  396. */
  397. ref.tableDragStop = function() {
  398. $('tr', ref.wrapper_obj).removeClass('dragging');
  399. $(ref.wrapper_obj).parent().children('.warning').css({'visibility':'hidden'}).remove();
  400. ref.updateStack();
  401. };
  402. /**
  403. * Toggles editability of text spans inside tablerows
  404. */
  405. ref.toggleInput = function(obj, start, file) {
  406. obj.hide().parent().toggleClass('editable-enabled');
  407. if (start) {
  408. obj.hide().parent().find('input:text, textarea').show().focus().select();
  409. }
  410. else {
  411. if (ref.key_pressed == 27) {
  412. obj.val(obj.parent().find('span').html()).hide().parent().find('span').show();
  413. return;
  414. };
  415. var value = obj.val();
  416. if (value == '') {
  417. obj.hide().parent().find('span').html('&nbsp;').show();
  418. }
  419. else {
  420. obj.hide().parent().find('span').text((value == '&nbsp;' ? '' : value)).show();
  421. };
  422. };
  423. ref.updateStack(file);
  424. };
  425. /**
  426. * Launched when the swf has been loaded.
  427. */
  428. ref.swfUploadLoaded = function() {
  429. // Update the stats object in order to let SWFUpload know we've already got some files stored
  430. ref.swfu.setStats({successful_uploads: ref.upload_stack_length});
  431. ref.addEventHandlers('flash_loaded');
  432. };
  433. /**
  434. * The file(s) have been selected.
  435. */
  436. ref.dialogComplete = function(files_selected, files_queued) {
  437. if (ref.settings.file_upload_limit && ref.settings.file_upload_limit !== 0 && (files_selected > ref.settings.file_upload_limit)) {
  438. ref.displayMessage(Drupal.t('You can upload only !num !file!', {'!num':ref.settings.file_upload_limit, '!file': Drupal.formatPlural(ref.settings.file_upload_limit, 'file', 'files')}), 'error');
  439. }
  440. else {
  441. ref.uploadNextInQueue();
  442. };
  443. };
  444. /**
  445. * The file(s) have been selected by the user and added to the upload queue
  446. */
  447. ref.fileQueued = function(file) {
  448. if (ref.settings.file_upload_limit && ref.settings.file_upload_limit !== 0) {
  449. // Check if the queued file(s) do not exceed the max number of files
  450. var stats = ref.swfu.getStats();
  451. if ((ref.upload_stack_length + stats.files_queued) > ref.settings.file_upload_limit) {
  452. ref.swfu.cancelUpload(file.id);
  453. var queue_space = (ref.settings.file_upload_limit - ref.upload_stack_length);
  454. if (queue_space == 0) {
  455. ref.displayMessage(Drupal.t('You are not allowed to add more than !num !file!', {'!num':ref.settings.file_upload_limit, '!file': Drupal.formatPlural(ref.settings.file_upload_limit, 'file', 'files')}), 'error');
  456. }
  457. else {
  458. ref.displayMessage(Drupal.t('You can upload only !num more !file!', {'!num':queue_space, '!file':Drupal.formatPlural(queue_space, 'file', 'files')}), 'error');
  459. };
  460. return;
  461. };
  462. };
  463. if (ref.max_queue_size && ref.max_queue_size !== 0) {
  464. // Check if the new file does not exceed the max queue size
  465. if ((ref.upload_stack_size + file.size) > ref.max_queue_size) {
  466. var max_queue_mbs = ref.getMbs(ref.max_queue_size);
  467. var file_mbs = ((file.size / 1024) / 1024);
  468. ref.swfu.cancelUpload(file.id);
  469. ref.displayMessage(Drupal.t('The file size (!num1 MB) exceeds the upload size (!num2 MB) for this page!', {'!num1':file_mbs.toFixed(2), '!num2':max_queue_mbs.toFixed(2)}), 'error');
  470. return;
  471. };
  472. };
  473. // No problems found, add the new file to the stack.
  474. file.extension = ref.getExtension(file.name);
  475. ref.queue[file.id] = file;
  476. ref.addFileItem(file);
  477. };
  478. /**
  479. * Responds on file queue errors
  480. */
  481. ref.fileQueueError = function(file, code, message) {
  482. switch (code) {
  483. case -110: // The file selected is too large
  484. var max_file_mbs = ref.getMbs(ref.settings.file_size_limit);
  485. var file_mbs = ((file.size / 1024) / 1024);
  486. ref.displayMessage(Drupal.t('The file size (!num1 MB) exceeds the file size limit (!num2 MB)!', {'!num1':file_mbs.toFixed(2), '!num2':max_file_mbs.toFixed(2)}), 'error');
  487. break;
  488. default:
  489. break;
  490. };
  491. };
  492. /**
  493. * Calculates the MB's from a given string
  494. */
  495. ref.getMbs = function(size) {
  496. // B, KB, MB and GB
  497. if (size.indexOf('MB') > -1) {
  498. return parseInt(size);
  499. }
  500. else if (size.indexOf('GB') > -1) {
  501. return (parseInt(size) * 1024);
  502. }
  503. else if (size.indexOf('KB') > -1) {
  504. return (parseInt(size) / 1024);
  505. }
  506. else if (size.indexOf('B') > -1) {
  507. return ((parseInt(size) / 1024) / 1024);
  508. };
  509. return false;
  510. };
  511. /**
  512. * Displays messages
  513. */
  514. ref.displayMessage = function(messages, type) {
  515. if (typeof(messages) == 'object') {
  516. var multiple = (messages.length > 1);
  517. var messages_tmp = (multiple ? '<ul>' : '');
  518. for (var i in messages) {
  519. messages_tmp += (multiple ? '<li>' + messages[i] + '</li>' : messages[i]);
  520. };
  521. messages = (multiple ? messages_tmp + '</ul>' : messages_tmp);
  522. };
  523. if (!ref.message_wrapper_obj) {
  524. ref.message_wrapper_obj = $('<div />').addClass('swfupload-messages').insertAfter(ref.wrapper_obj);
  525. ref.messages_timeout = setTimeout(function() {ref.hideMessages();}, 5000);
  526. };
  527. if (!$('div.' + type, ref.message_wrapper_obj).size()) {
  528. ref.message_wrapper_obj.append($('<div />').css({'height':'auto', 'opacity':1}).addClass('messages ' + type).html(messages));
  529. }
  530. else {
  531. // The messagewrapper already exists. Add the new message to the wrapper and reset the timeout.
  532. // Check if the message isn't already displayed
  533. if (ref.message_wrapper_obj.html().indexOf(messages) > -1) {
  534. return;
  535. };
  536. // If the new type differs from the current type, we'll remove the old message.
  537. if ((ref.message_wrapper_obj.hasClass('status') && type !== 'status') || (ref.message_wrapper_obj.hasClass('error') && type !== 'error')) {
  538. ref.message_wrapper_obj.removeClass('status error').addClass(type).html(messages);
  539. }
  540. else {
  541. ref.message_wrapper_obj.append('<br />' + messages);
  542. };
  543. clearInterval(ref.messages_timeout);
  544. ref.messages_timeout = setTimeout(function() {ref.hideMessages();}, 5000);
  545. };
  546. };
  547. /**
  548. * Slowly hides the messages wrapper
  549. */
  550. ref.hideMessages = function() {
  551. ref.message_wrapper_obj.animate({'height':'0px', 'opacity':0}, 'slow', function() {
  552. ref.message_wrapper_obj.remove();
  553. ref.message_wrapper_obj = false;
  554. });
  555. };
  556. /**
  557. * Triggers a new upload.
  558. */
  559. ref.uploadNextInQueue = function() {
  560. try {
  561. ref.swfu.startUpload();
  562. }
  563. catch (err) {
  564. ref.swfu.debug(err);
  565. };
  566. };
  567. /**
  568. * Adjusts the progress indicator.
  569. */
  570. ref.uploadProgress = function(file, complete, total) {
  571. // We don't want this one to end up to 100% when all bytes are loaded. The progressbar will have an width of 100% on uploadFileComplete
  572. var done = Math.round((96 / total) * complete);
  573. $('#' + file.id + ' .sfwupload-list-progressbar-status').css({'width': done + '%'});
  574. };
  575. /**
  576. * Handles upload errors
  577. */
  578. ref.uploadError = function(file, code, message) {
  579. // Check for messages which can be handled as 'status' messages
  580. switch (code) {
  581. case -240:
  582. ref.displayMessage(Drupal.t('The upload limit (!num) has been reached!', {'!num': ref.settings.file_upload_limit}), 'status');
  583. return;
  584. case -200:
  585. message = Drupal.t('Server error!');
  586. };
  587. // Give the user some visual indicators of the event
  588. $('#' + file.id + ' .sfwupload-list-progressbar').addClass('stopped').find('.sfwupload-list-progressbar-status').css({'width':'100%'});
  589. $('#' + file.id + ' .sfwupload-list-progressbar-glow').append((typeof(message) == 'object' ? message[0] : message));
  590. // If a file is set, we need to remove the added file DOM element
  591. if (file) {
  592. setTimeout(function() {
  593. ref.removeFileItem(file);
  594. }, 2000);
  595. };
  596. };
  597. /**
  598. * Triggered after the upload is succesfully completed.
  599. */
  600. ref.uploadComplete = function(file) {
  601. if (ref.queue[file.id] && !ref.queue[file.id].cancelled) {
  602. setTimeout(function() {
  603. $('#' + ref.queue[file.id].fid).find('.sfwupload-list-progressbar').animate({'opacity':0}, "slow", function() {
  604. file.fid = ref.queue[file.id].fid;
  605. ref.tableRow(false, file);
  606. ref.updateStack(file);
  607. ref.addEventHandlers('file_added', file);
  608. if (ref.queue[file.id].thumb) {
  609. $('.sfwupload-list-mime', $('#' + ref.queue[file.id].fid)).css({'background-image': 'url(' + ref.queue[file.id].thumb + ')'});
  610. };
  611. ref.upload_button_obj.removeClass('swfupload-error');
  612. });
  613. }, 1000);
  614. };
  615. ref.uploadNextInQueue();
  616. };
  617. /**
  618. * Retrieves the data returned by the server
  619. */
  620. ref.uploadSuccess = function(file, server_data) {
  621. var server_data = jQuery.parseJSON(server_data);
  622. // Check for messages returned by the server.
  623. if (server_data.messages) {
  624. // Check if the server returned status messages
  625. if (server_data.messages) {
  626. for (var type in server_data.messages) {
  627. if (type !== 'swfupload_error') {
  628. ref.displayMessage(server_data.messages[type], type);
  629. };
  630. };
  631. };
  632. // Check if the server returned an error
  633. if (server_data.messages.swfupload_error) {
  634. ref.uploadError(file, null, server_data.messages.swfupload_error);
  635. ref.queue[file.id].cancelled = true;
  636. return;
  637. };
  638. };
  639. // No errors. Complete the fileupload.
  640. ref.queue[file.id].fid = server_data.file.fid;
  641. $('#' + file.id).attr({'id':server_data.file.fid}).find('.sfwupload-list-progressbar-status').css({'width':'100%'}).parent().addClass('complete');
  642. if (server_data.file.thumb) {
  643. ref.queue[file.id].thumb = server_data.file.thumb;
  644. };
  645. };
  646. /**
  647. * Updates the value of the hidden input field which stores all uploaded files
  648. */
  649. ref.updateStack = function(file) {
  650. var fid, input_field, element;
  651. var old_upload_stack = ref.upload_stack;
  652. var total_size = 0;
  653. ref.upload_stack = {};
  654. ref.wrapper_obj.find('.processed').each(function() {
  655. fid = $(this).attr('id');
  656. // If no file is secified, the function is called after sorting
  657. // There are no new values so the file object is not needed
  658. // We only need to change the order of the stack
  659. if (!file) {
  660. ref.upload_stack[fid] = old_upload_stack[fid];
  661. }
  662. else {
  663. ref.upload_stack[fid] = {filename:file.filename || file.name, fid:fid};
  664. total_size += parseInt(file.size);
  665. for (var name in ref.instance.elements) {
  666. input_field = $('#edit-' + name + '_' + fid);
  667. if (input_field.size() !== 0) {
  668. ref.upload_stack[fid][name] = (input_field.attr('type') == 'checkbox') ? input_field.attr('checked') : input_field.val();
  669. };
  670. };
  671. };
  672. });
  673. ref.upload_stack_size = total_size;
  674. ref.upload_stack_length = ref.objectLength(ref.upload_stack);
  675. ref.upload_stack_obj.val(ref.toJson(ref.upload_stack));
  676. ref.addEventHandlers('drag_enable');
  677. if ((ref.settings.file_upload_limit > ref.upload_stack_length) || ref.settings.file_upload_limit === 0) {
  678. ref.upload_button_obj.removeClass('disabled').css({opacity:1});
  679. }
  680. else {
  681. ref.upload_button_obj.addClass('disabled').css({opacity:0.4});
  682. };
  683. };
  684. /**
  685. * Aborts a file upload
  686. */
  687. ref.cancelUpload = function(file) {
  688. // Check if the file is still being uploaded.
  689. if (ref.swfu.getFile(file.id)) {
  690. // Abort the upload
  691. ref.swfu.cancelUpload(file.id);
  692. ref.queue[file.id].cancelled = true;
  693. setTimeout(function() {
  694. ref.removeFileItem(file);
  695. }, 1000);
  696. };
  697. };
  698. /**
  699. * Removes a file form the list
  700. */
  701. ref.removeFileItem = function(file) {
  702. var file_tr = $('#' + (file.fid ? file.fid : file.id)).removeClass('processed');
  703. var file_tds = file_tr.find('td');
  704. var current_height = file_tr.height();
  705. var cleared = false;
  706. // Delete the file from the queue
  707. delete(ref.queue[file.id]);
  708. // Animate the deletion of the file's table row
  709. // First fade out the contents of the td's
  710. file_tds.find('div, input').animate({opacity:0}, 'fast', function() {
  711. file_tds.each(function() {
  712. // The contents are not visible anymore, so we can remove it.
  713. $(this).html('');
  714. });
  715. // Since animate({height:0}) does not work for tr and td's, we need to declare our own interval
  716. var intv = setInterval(function() {
  717. current_height -= 5;
  718. file_tds.height(current_height);
  719. file_tr.css({opacity: current_height * 4});
  720. // The animation is complete
  721. if (current_height <= 5) {
  722. if (!cleared) {
  723. cleared = true;
  724. file_tr.remove();
  725. clearInterval(intv);
  726. // Reset the successfull upload queue
  727. var stats = ref.swfu.getStats();
  728. stats.successful_uploads--;
  729. ref.swfu.setStats(stats);
  730. if (file_tr) {
  731. // Update the hidden input field
  732. ref.updateStack(file);
  733. };
  734. };
  735. };
  736. }, 50);
  737. });
  738. };
  739. /**
  740. * Retrieve the number of elements in an object
  741. */
  742. ref.objectLength = function(obj) {
  743. if (obj.status !== undefined && obj.status == 0) return 0;
  744. var count = 0;
  745. for (var i in obj)
  746. count++;
  747. return count;
  748. };
  749. /**
  750. * Parses an object to a json formatted string
  751. */
  752. ref.toJson = function(v) {
  753. switch (typeof v) {
  754. case 'boolean':
  755. return v == true ? 'true' : 'false';
  756. case 'number':
  757. return v;
  758. case 'string':
  759. return '"'+ v.replace(/\n/g, '\\n') +'"';
  760. case 'object':
  761. var output = '';
  762. for(i in v) {
  763. output += (output ? ',' : '') + '"' + i + '":' + ref.toJson(v[i]);
  764. }
  765. return '{' + output + '}';
  766. default:
  767. return 'null';
  768. };
  769. };
  770. /**
  771. *
  772. */
  773. ref.getExtension = function(file_name) {
  774. return file_name.substring(file_name.lastIndexOf('.') + 1).toLowerCase();
  775. };
  776. /**
  777. * Replaces default values from ref.instance.elements to file values
  778. * @see ref.uploadComplete
  779. */
  780. ref.replaceMacros = function(value, file) {
  781. if (!value || value == 0) {
  782. return false;
  783. }
  784. else if (value == 1) {
  785. return true;
  786. }
  787. else {
  788. var macros = {'[filename]':file.name, '{fid}':file.fid};
  789. for (var i in macros) {
  790. value = value.replace(i, macros[i]);
  791. };
  792. return value;
  793. };
  794. };
  795. /**
  796. * Reverses the order of an object
  797. */
  798. ref.objReverse = function(obj) {
  799. var temp_arr = [];
  800. var temp_obj = {};
  801. for (var i in obj) {
  802. temp_arr.push({key:i, data:obj[i]});
  803. };
  804. temp_arr = temp_arr.reverse();
  805. for (var i in temp_arr) {
  806. temp_obj[temp_arr[i].key] = temp_arr[i].data;
  807. };
  808. return temp_obj;
  809. };
  810. return ref;
  811. };
  812. /**
  813. * Overwrite for the TableDrag markChanged function
  814. * Allows to place the marker in an other table drawer than the first one.
  815. */
  816. Drupal.tableDrag.prototype.row.prototype.markChanged = function() {
  817. var marker = Drupal.theme('tableDragChangedMarker');
  818. var cell = ($('td.drag .wrapper', this.element)) || $('td:first', this.element);
  819. if ($('span.tabledrag-changed', cell).length == 0) {
  820. cell.append(marker);
  821. };
  822. };
  823. /**
  824. * Disables text selection on the DOM element the behavior is attached to.
  825. */
  826. jQuery.fn.disableTextSelect = function() {
  827. return this.each(function() {
  828. $(this).css({
  829. 'MozUserSelect' : 'none'
  830. }).bind('selectstart', function() {
  831. return false;
  832. }).mousedown(function() {
  833. return false;
  834. });
  835. });
  836. };
  837. $(function() {
  838. if (Drupal.settings.swfupload_settings) {
  839. Drupal.swfu = {};
  840. var settings = Drupal.settings.swfupload_settings;
  841. for (var id in settings) {
  842. Drupal.swfu[id] = new SWFU(id, settings[id]);
  843. Drupal.swfu[id].init();
  844. };
  845. };
  846. });
  847. })(jQuery);