file-upload.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718
  1. /*
  2. * Copyright (c) 2014
  3. *
  4. * This file is licensed under the Affero General Public License version 3
  5. * or later.
  6. *
  7. * See the COPYING-README file.
  8. *
  9. */
  10. /**
  11. * The file upload code uses several hooks to interact with blueimps jQuery file upload library:
  12. * 1. the core upload handling hooks are added when initializing the plugin,
  13. * 2. if the browser supports progress events they are added in a separate set after the initialization
  14. * 3. every app can add it's own triggers for fileupload
  15. * - files adds d'n'd handlers and also reacts to done events to add new rows to the filelist
  16. * - TODO pictures upload button
  17. * - TODO music upload button
  18. */
  19. /* global Files, FileList, jQuery, oc_requesttoken, humanFileSize, getUniqueName */
  20. /**
  21. * Function that will allow us to know if Ajax uploads are supported
  22. * @link https://github.com/New-Bamboo/example-ajax-upload/blob/master/public/index.html
  23. * also see article @link http://blog.new-bamboo.co.uk/2012/01/10/ridiculously-simple-ajax-uploads-with-formdata
  24. */
  25. function supportAjaxUploadWithProgress() {
  26. return supportFileAPI() && supportAjaxUploadProgressEvents() && supportFormData();
  27. // Is the File API supported?
  28. function supportFileAPI() {
  29. var fi = document.createElement('INPUT');
  30. fi.type = 'file';
  31. return 'files' in fi;
  32. }
  33. // Are progress events supported?
  34. function supportAjaxUploadProgressEvents() {
  35. var xhr = new XMLHttpRequest();
  36. return !! (xhr && ('upload' in xhr) && ('onprogress' in xhr.upload));
  37. }
  38. // Is FormData supported?
  39. function supportFormData() {
  40. return !! window.FormData;
  41. }
  42. }
  43. /**
  44. * keeps track of uploads in progress and implements callbacks for the conflicts dialog
  45. * @namespace
  46. */
  47. OC.Upload = {
  48. _uploads: [],
  49. /**
  50. * deletes the jqHXR object from a data selection
  51. * @param {object} data
  52. */
  53. deleteUpload:function(data) {
  54. delete data.jqXHR;
  55. },
  56. /**
  57. * cancels all uploads
  58. */
  59. cancelUploads:function() {
  60. this.log('canceling uploads');
  61. jQuery.each(this._uploads, function(i, jqXHR) {
  62. jqXHR.abort();
  63. });
  64. this._uploads = [];
  65. },
  66. rememberUpload:function(jqXHR) {
  67. if (jqXHR) {
  68. this._uploads.push(jqXHR);
  69. }
  70. },
  71. /**
  72. * Checks the currently known uploads.
  73. * returns true if any hxr has the state 'pending'
  74. * @returns {boolean}
  75. */
  76. isProcessing:function() {
  77. var count = 0;
  78. jQuery.each(this._uploads, function(i, data) {
  79. if (data.state() === 'pending') {
  80. count++;
  81. }
  82. });
  83. return count > 0;
  84. },
  85. /**
  86. * callback for the conflicts dialog
  87. * @param {object} data
  88. */
  89. onCancel:function(data) {
  90. this.cancelUploads();
  91. },
  92. /**
  93. * callback for the conflicts dialog
  94. * calls onSkip, onReplace or onAutorename for each conflict
  95. * @param {object} conflicts - list of conflict elements
  96. */
  97. onContinue:function(conflicts) {
  98. var self = this;
  99. //iterate over all conflicts
  100. jQuery.each(conflicts, function (i, conflict) {
  101. conflict = $(conflict);
  102. var keepOriginal = conflict.find('.original input[type="checkbox"]:checked').length === 1;
  103. var keepReplacement = conflict.find('.replacement input[type="checkbox"]:checked').length === 1;
  104. if (keepOriginal && keepReplacement) {
  105. // when both selected -> autorename
  106. self.onAutorename(conflict.data('data'));
  107. } else if (keepReplacement) {
  108. // when only replacement selected -> overwrite
  109. self.onReplace(conflict.data('data'));
  110. } else {
  111. // when only original seleted -> skip
  112. // when none selected -> skip
  113. self.onSkip(conflict.data('data'));
  114. }
  115. });
  116. },
  117. /**
  118. * handle skipping an upload
  119. * @param {object} data
  120. */
  121. onSkip:function(data) {
  122. this.log('skip', null, data);
  123. this.deleteUpload(data);
  124. },
  125. /**
  126. * handle replacing a file on the server with an uploaded file
  127. * @param {object} data
  128. */
  129. onReplace:function(data) {
  130. this.log('replace', null, data);
  131. if (data.data) {
  132. data.data.append('resolution', 'replace');
  133. } else {
  134. data.formData.push({name:'resolution', value:'replace'}); //hack for ie8
  135. }
  136. data.submit();
  137. },
  138. /**
  139. * handle uploading a file and letting the server decide a new name
  140. * @param {object} data
  141. */
  142. onAutorename:function(data) {
  143. this.log('autorename', null, data);
  144. if (data.data) {
  145. data.data.append('resolution', 'autorename');
  146. } else {
  147. data.formData.push({name:'resolution', value:'autorename'}); //hack for ie8
  148. }
  149. data.submit();
  150. },
  151. _trace:false, //TODO implement log handler for JS per class?
  152. log:function(caption, e, data) {
  153. if (this._trace) {
  154. console.log(caption);
  155. console.log(data);
  156. }
  157. },
  158. /**
  159. * TODO checks the list of existing files prior to uploading and shows a simple dialog to choose
  160. * skip all, replace all or choose which files to keep
  161. * @param {array} selection of files to upload
  162. * @param {object} callbacks - object with several callback methods
  163. * @param {function} callbacks.onNoConflicts
  164. * @param {function} callbacks.onSkipConflicts
  165. * @param {function} callbacks.onReplaceConflicts
  166. * @param {function} callbacks.onChooseConflicts
  167. * @param {function} callbacks.onCancel
  168. */
  169. checkExistingFiles: function (selection, callbacks) {
  170. /*
  171. $.each(selection.uploads, function(i, upload) {
  172. var $row = OCA.Files.App.fileList.findFileEl(upload.files[0].name);
  173. if ($row) {
  174. // TODO check filelist before uploading and show dialog on conflicts, use callbacks
  175. }
  176. });
  177. */
  178. callbacks.onNoConflicts(selection);
  179. },
  180. _hideProgressBar: function() {
  181. $('#uploadprogresswrapper .stop').fadeOut();
  182. $('#uploadprogressbar').fadeOut(function() {
  183. $('#file_upload_start').trigger(new $.Event('resized'));
  184. });
  185. },
  186. _showProgressBar: function() {
  187. $('#uploadprogressbar').fadeIn();
  188. $('#file_upload_start').trigger(new $.Event('resized'));
  189. },
  190. init: function() {
  191. if ( $('#file_upload_start').exists() ) {
  192. var file_upload_param = {
  193. dropZone: $('#content'), // restrict dropZone to content div
  194. autoUpload: false,
  195. sequentialUploads: true,
  196. //singleFileUploads is on by default, so the data.files array will always have length 1
  197. /**
  198. * on first add of every selection
  199. * - check all files of originalFiles array with files in dir
  200. * - on conflict show dialog
  201. * - skip all -> remember as single skip action for all conflicting files
  202. * - replace all -> remember as single replace action for all conflicting files
  203. * - choose -> show choose dialog
  204. * - mark files to keep
  205. * - when only existing -> remember as single skip action
  206. * - when only new -> remember as single replace action
  207. * - when both -> remember as single autorename action
  208. * - start uploading selection
  209. * @param {object} e
  210. * @param {object} data
  211. * @returns {boolean}
  212. */
  213. add: function(e, data) {
  214. OC.Upload.log('add', e, data);
  215. var that = $(this), freeSpace;
  216. // we need to collect all data upload objects before
  217. // starting the upload so we can check their existence
  218. // and set individual conflict actions. Unfortunately,
  219. // there is only one variable that we can use to identify
  220. // the selection a data upload is part of, so we have to
  221. // collect them in data.originalFiles turning
  222. // singleFileUploads off is not an option because we want
  223. // to gracefully handle server errors like 'already exists'
  224. // create a container where we can store the data objects
  225. if ( ! data.originalFiles.selection ) {
  226. // initialize selection and remember number of files to upload
  227. data.originalFiles.selection = {
  228. uploads: [],
  229. filesToUpload: data.originalFiles.length,
  230. totalBytes: 0,
  231. biggestFileBytes: 0
  232. };
  233. }
  234. var selection = data.originalFiles.selection;
  235. // add uploads
  236. if ( selection.uploads.length < selection.filesToUpload ) {
  237. // remember upload
  238. selection.uploads.push(data);
  239. }
  240. //examine file
  241. var file = data.files[0];
  242. try {
  243. // FIXME: not so elegant... need to refactor that method to return a value
  244. Files.isFileNameValid(file.name);
  245. }
  246. catch (errorMessage) {
  247. data.textStatus = 'invalidcharacters';
  248. data.errorThrown = errorMessage;
  249. }
  250. // in case folder drag and drop is not supported file will point to a directory
  251. // http://stackoverflow.com/a/20448357
  252. if ( ! file.type && file.size%4096 === 0 && file.size <= 102400) {
  253. var dirUploadFailure = false;
  254. try {
  255. var reader = new FileReader();
  256. reader.readAsBinaryString(file);
  257. } catch (NS_ERROR_FILE_ACCESS_DENIED) {
  258. //file is a directory
  259. dirUploadFailure = true;
  260. }
  261. if (file.size === 0) {
  262. // file is empty or a directory
  263. dirUploadFailure = true;
  264. }
  265. if (dirUploadFailure) {
  266. data.textStatus = 'dirorzero';
  267. data.errorThrown = t('files',
  268. 'Unable to upload {filename} as it is a directory or has 0 bytes',
  269. {filename: file.name}
  270. );
  271. }
  272. }
  273. // add size
  274. selection.totalBytes += file.size;
  275. // update size of biggest file
  276. selection.biggestFileBytes = Math.max(selection.biggestFileBytes, file.size);
  277. // check PHP upload limit against biggest file
  278. if (selection.biggestFileBytes > $('#upload_limit').val()) {
  279. data.textStatus = 'sizeexceedlimit';
  280. data.errorThrown = t('files',
  281. 'Total file size {size1} exceeds upload limit {size2}', {
  282. 'size1': humanFileSize(selection.biggestFileBytes),
  283. 'size2': humanFileSize($('#upload_limit').val())
  284. });
  285. }
  286. // check free space
  287. freeSpace = $('#free_space').val();
  288. if (freeSpace >= 0 && selection.totalBytes > freeSpace) {
  289. data.textStatus = 'notenoughspace';
  290. data.errorThrown = t('files',
  291. 'Not enough free space, you are uploading {size1} but only {size2} is left', {
  292. 'size1': humanFileSize(selection.totalBytes),
  293. 'size2': humanFileSize($('#free_space').val())
  294. });
  295. }
  296. // end upload for whole selection on error
  297. if (data.errorThrown) {
  298. // trigger fileupload fail
  299. var fu = that.data('blueimp-fileupload') || that.data('fileupload');
  300. fu._trigger('fail', e, data);
  301. return false; //don't upload anything
  302. }
  303. // check existing files when all is collected
  304. if ( selection.uploads.length >= selection.filesToUpload ) {
  305. //remove our selection hack:
  306. delete data.originalFiles.selection;
  307. var callbacks = {
  308. onNoConflicts: function (selection) {
  309. $.each(selection.uploads, function(i, upload) {
  310. upload.submit();
  311. });
  312. },
  313. onSkipConflicts: function (selection) {
  314. //TODO mark conflicting files as toskip
  315. },
  316. onReplaceConflicts: function (selection) {
  317. //TODO mark conflicting files as toreplace
  318. },
  319. onChooseConflicts: function (selection) {
  320. //TODO mark conflicting files as chosen
  321. },
  322. onCancel: function (selection) {
  323. $.each(selection.uploads, function(i, upload) {
  324. upload.abort();
  325. });
  326. }
  327. };
  328. OC.Upload.checkExistingFiles(selection, callbacks);
  329. }
  330. return true; // continue adding files
  331. },
  332. /**
  333. * called after the first add, does NOT have the data param
  334. * @param {object} e
  335. */
  336. start: function(e) {
  337. OC.Upload.log('start', e, null);
  338. //hide the tooltip otherwise it covers the progress bar
  339. $('#upload').tipsy('hide');
  340. },
  341. submit: function(e, data) {
  342. OC.Upload.rememberUpload(data);
  343. if ( ! data.formData ) {
  344. var fileDirectory = '';
  345. if(typeof data.files[0].relativePath !== 'undefined') {
  346. fileDirectory = data.files[0].relativePath;
  347. }
  348. // noone set update parameters, we set the minimum
  349. data.formData = {
  350. requesttoken: oc_requesttoken,
  351. dir: data.targetDir || FileList.getCurrentDirectory(),
  352. file_directory: fileDirectory
  353. };
  354. }
  355. },
  356. fail: function(e, data) {
  357. OC.Upload.log('fail', e, data);
  358. if (typeof data.textStatus !== 'undefined' && data.textStatus !== 'success' ) {
  359. if (data.textStatus === 'abort') {
  360. OC.Notification.show(t('files', 'Upload cancelled.'));
  361. } else {
  362. // HTTP connection problem
  363. OC.Notification.show(data.errorThrown);
  364. if (data.result) {
  365. var result = JSON.parse(data.result);
  366. if (result && result[0] && result[0].data && result[0].data.code === 'targetnotfound') {
  367. // abort upload of next files if any
  368. OC.Upload.cancelUploads();
  369. }
  370. }
  371. }
  372. //hide notification after 10 sec
  373. setTimeout(function() {
  374. OC.Notification.hide();
  375. }, 10000);
  376. }
  377. OC.Upload.deleteUpload(data);
  378. },
  379. /**
  380. * called for every successful upload
  381. * @param {object} e
  382. * @param {object} data
  383. */
  384. done:function(e, data) {
  385. OC.Upload.log('done', e, data);
  386. // handle different responses (json or body from iframe for ie)
  387. var response;
  388. if (typeof data.result === 'string') {
  389. response = data.result;
  390. } else {
  391. //fetch response from iframe
  392. response = data.result[0].body.innerText;
  393. }
  394. var result = $.parseJSON(response);
  395. delete data.jqXHR;
  396. var fu = $(this).data('blueimp-fileupload') || $(this).data('fileupload');
  397. if (result.status === 'error' && result.data && result.data.message){
  398. data.textStatus = 'servererror';
  399. data.errorThrown = result.data.message;
  400. fu._trigger('fail', e, data);
  401. } else if (typeof result[0] === 'undefined') {
  402. data.textStatus = 'servererror';
  403. data.errorThrown = t('files', 'Could not get result from server.');
  404. fu._trigger('fail', e, data);
  405. } else if (result[0].status === 'readonly') {
  406. var original = result[0];
  407. var replacement = data.files[0];
  408. OC.dialogs.fileexists(data, original, replacement, OC.Upload);
  409. } else if (result[0].status === 'existserror') {
  410. //show "file already exists" dialog
  411. var original = result[0];
  412. var replacement = data.files[0];
  413. OC.dialogs.fileexists(data, original, replacement, OC.Upload);
  414. } else if (result[0].status !== 'success') {
  415. //delete data.jqXHR;
  416. data.textStatus = 'servererror';
  417. data.errorThrown = result[0].data.message; // error message has been translated on server
  418. fu._trigger('fail', e, data);
  419. } else { // Successful upload
  420. // Checking that the uploaded file is the last one and contained in the current directory
  421. if (data.files[0] === data.originalFiles[data.originalFiles.length - 1] &&
  422. result[0].directory === FileList.getCurrentDirectory()) {
  423. // Scroll to the last uploaded file and highlight all of them
  424. var fileList = _.pluck(data.originalFiles, 'name');
  425. FileList.highlightFiles(fileList);
  426. }
  427. }
  428. },
  429. /**
  430. * called after last upload
  431. * @param {object} e
  432. * @param {object} data
  433. */
  434. stop: function(e, data) {
  435. OC.Upload.log('stop', e, data);
  436. }
  437. };
  438. // initialize jquery fileupload (blueimp)
  439. var fileupload = $('#file_upload_start').fileupload(file_upload_param);
  440. window.file_upload_param = fileupload;
  441. if (supportAjaxUploadWithProgress()) {
  442. // add progress handlers
  443. fileupload.on('fileuploadadd', function(e, data) {
  444. OC.Upload.log('progress handle fileuploadadd', e, data);
  445. //show cancel button
  446. //if (data.dataType !== 'iframe') { //FIXME when is iframe used? only for ie?
  447. // $('#uploadprogresswrapper .stop').show();
  448. //}
  449. });
  450. // add progress handlers
  451. fileupload.on('fileuploadstart', function(e, data) {
  452. OC.Upload.log('progress handle fileuploadstart', e, data);
  453. $('#uploadprogresswrapper .stop').show();
  454. $('#uploadprogressbar').progressbar({value: 0});
  455. OC.Upload._showProgressBar();
  456. });
  457. fileupload.on('fileuploadprogress', function(e, data) {
  458. OC.Upload.log('progress handle fileuploadprogress', e, data);
  459. //TODO progressbar in row
  460. });
  461. fileupload.on('fileuploadprogressall', function(e, data) {
  462. OC.Upload.log('progress handle fileuploadprogressall', e, data);
  463. var progress = (data.loaded / data.total) * 100;
  464. $('#uploadprogressbar').progressbar('value', progress);
  465. });
  466. fileupload.on('fileuploadstop', function(e, data) {
  467. OC.Upload.log('progress handle fileuploadstop', e, data);
  468. OC.Upload._hideProgressBar();
  469. });
  470. fileupload.on('fileuploadfail', function(e, data) {
  471. OC.Upload.log('progress handle fileuploadfail', e, data);
  472. //if user pressed cancel hide upload progress bar and cancel button
  473. if (data.errorThrown === 'abort') {
  474. OC.Upload._hideProgressBar();
  475. }
  476. });
  477. } else {
  478. // for all browsers that don't support the progress bar
  479. // IE 8 & 9
  480. // show a spinner
  481. fileupload.on('fileuploadstart', function() {
  482. $('#upload').addClass('icon-loading');
  483. $('#upload .icon-upload').hide();
  484. });
  485. // hide a spinner
  486. fileupload.on('fileuploadstop fileuploadfail', function() {
  487. $('#upload').removeClass('icon-loading');
  488. $('#upload .icon-upload').show();
  489. });
  490. }
  491. }
  492. $.assocArraySize = function(obj) {
  493. // http://stackoverflow.com/a/6700/11236
  494. var size = 0, key;
  495. for (key in obj) {
  496. if (obj.hasOwnProperty(key)) {
  497. size++;
  498. }
  499. }
  500. return size;
  501. };
  502. // warn user not to leave the page while upload is in progress
  503. $(window).on('beforeunload', function(e) {
  504. if (OC.Upload.isProcessing()) {
  505. return t('files', 'File upload is in progress. Leaving the page now will cancel the upload.');
  506. }
  507. });
  508. //add multiply file upload attribute to all browsers except konqueror (which crashes when it's used)
  509. if (navigator.userAgent.search(/konqueror/i) === -1) {
  510. $('#file_upload_start').attr('multiple', 'multiple');
  511. }
  512. $(document).click(function(ev) {
  513. // do not close when clicking in the dropdown
  514. if ($(ev.target).closest('#new').length){
  515. return;
  516. }
  517. $('#new>ul').hide();
  518. $('#new').removeClass('active');
  519. if ($('#new .error').length > 0) {
  520. $('#new .error').tipsy('hide');
  521. }
  522. $('#new li').each(function(i,element) {
  523. if ($(element).children('p').length === 0) {
  524. $(element).children('form').remove();
  525. $(element).append('<p>' + $(element).data('text') + '</p>');
  526. }
  527. });
  528. });
  529. $('#new').click(function(event) {
  530. event.stopPropagation();
  531. });
  532. $('#new>a').click(function() {
  533. $('#new>ul').toggle();
  534. $('#new').toggleClass('active');
  535. });
  536. $('#new li').click(function() {
  537. if ($(this).children('p').length === 0) {
  538. return;
  539. }
  540. $('#new .error').tipsy('hide');
  541. $('#new li').each(function(i, element) {
  542. if ($(element).children('p').length === 0) {
  543. $(element).children('form').remove();
  544. $(element).append('<p>' + $(element).data('text') + '</p>');
  545. }
  546. });
  547. var type = $(this).data('type');
  548. var text = $(this).children('p').text();
  549. $(this).data('text', text);
  550. $(this).children('p').remove();
  551. // add input field
  552. var form = $('<form></form>');
  553. var input = $('<input type="text">');
  554. var newName = $(this).attr('data-newname') || '';
  555. var fileType = 'input-' + $(this).attr('data-type');
  556. if (newName) {
  557. input.val(newName);
  558. input.attr('id', fileType);
  559. }
  560. var label = $('<label class="hidden-visually" for="">' + escapeHTML(newName) + '</label>');
  561. label.attr('for', fileType);
  562. form.append(label).append(input);
  563. $(this).append(form);
  564. var lastPos;
  565. var checkInput = function () {
  566. var filename = input.val();
  567. if (Files.isFileNameValid(filename)) {
  568. // Files.isFileNameValid(filename) throws an exception itself
  569. } else if (FileList.inList(filename)) {
  570. throw t('files', '{new_name} already exists', {new_name: filename});
  571. } else {
  572. return true;
  573. }
  574. };
  575. // verify filename on typing
  576. input.keyup(function(event) {
  577. try {
  578. checkInput();
  579. input.tipsy('hide');
  580. input.removeClass('error');
  581. } catch (error) {
  582. input.attr('title', error);
  583. input.tipsy({gravity: 'w', trigger: 'manual'});
  584. input.tipsy('show');
  585. input.addClass('error');
  586. }
  587. });
  588. input.focus();
  589. // pre select name up to the extension
  590. lastPos = newName.lastIndexOf('.');
  591. if (lastPos === -1) {
  592. lastPos = newName.length;
  593. }
  594. input.selectRange(0, lastPos);
  595. form.submit(function(event) {
  596. event.stopPropagation();
  597. event.preventDefault();
  598. try {
  599. checkInput();
  600. var newname = input.val();
  601. if (FileList.lastAction) {
  602. FileList.lastAction();
  603. }
  604. var name = FileList.getUniqueName(newname);
  605. if (newname !== name) {
  606. FileList.checkName(name, newname, true);
  607. var hidden = true;
  608. } else {
  609. var hidden = false;
  610. }
  611. switch(type) {
  612. case 'file':
  613. $.post(
  614. OC.filePath('files', 'ajax', 'newfile.php'),
  615. {
  616. dir: FileList.getCurrentDirectory(),
  617. filename: name
  618. },
  619. function(result) {
  620. if (result.status === 'success') {
  621. FileList.add(result.data, {hidden: hidden, animate: true, scrollTo: true});
  622. } else {
  623. OC.dialogs.alert(result.data.message, t('core', 'Could not create file'));
  624. }
  625. }
  626. );
  627. break;
  628. case 'folder':
  629. $.post(
  630. OC.filePath('files','ajax','newfolder.php'),
  631. {
  632. dir: FileList.getCurrentDirectory(),
  633. foldername: name
  634. },
  635. function(result) {
  636. if (result.status === 'success') {
  637. FileList.add(result.data, {hidden: hidden, animate: true, scrollTo: true});
  638. } else {
  639. OC.dialogs.alert(result.data.message, t('core', 'Could not create folder'));
  640. }
  641. }
  642. );
  643. break;
  644. }
  645. var li = form.parent();
  646. form.remove();
  647. /* workaround for IE 9&10 click event trap, 2 lines: */
  648. $('input').first().focus();
  649. $('#content').focus();
  650. li.append('<p>' + li.data('text') + '</p>');
  651. $('#new>a').click();
  652. } catch (error) {
  653. input.attr('title', error);
  654. input.tipsy({gravity: 'w', trigger: 'manual'});
  655. input.tipsy('show');
  656. input.addClass('error');
  657. }
  658. });
  659. });
  660. window.file_upload_param = file_upload_param;
  661. return file_upload_param;
  662. }
  663. };
  664. $(document).ready(function() {
  665. OC.Upload.init();
  666. });