files.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850
  1. var uploadingFiles = {};
  2. Files={
  3. cancelUpload:function(filename) {
  4. if(uploadingFiles[filename]) {
  5. uploadingFiles[filename].abort();
  6. delete uploadingFiles[filename];
  7. return true;
  8. }
  9. return false;
  10. },
  11. cancelUploads:function() {
  12. $.each(uploadingFiles,function(index,file) {
  13. if(typeof file['abort'] === 'function') {
  14. file.abort();
  15. var filename = $('tr').filterAttr('data-file',index);
  16. filename.hide();
  17. filename.find('input[type="checkbox"]').removeAttr('checked');
  18. filename.removeClass('selected');
  19. } else {
  20. $.each(file,function(i,f) {
  21. f.abort();
  22. delete file[i];
  23. });
  24. }
  25. delete uploadingFiles[index];
  26. });
  27. procesSelection();
  28. },
  29. updateMaxUploadFilesize:function(response) {
  30. if(response == undefined) {
  31. return;
  32. }
  33. if(response.data !== undefined && response.data.uploadMaxFilesize !== undefined) {
  34. $('#max_upload').val(response.data.uploadMaxFilesize);
  35. $('#upload.button').attr('original-title', response.data.maxHumanFilesize);
  36. $('#usedSpacePercent').val(response.data.usedSpacePercent);
  37. Files.displayStorageWarnings();
  38. }
  39. if(response[0] == undefined) {
  40. return;
  41. }
  42. if(response[0].uploadMaxFilesize !== undefined) {
  43. $('#max_upload').val(response[0].uploadMaxFilesize);
  44. $('#upload.button').attr('original-title', response[0].maxHumanFilesize);
  45. $('#usedSpacePercent').val(response[0].usedSpacePercent);
  46. Files.displayStorageWarnings();
  47. }
  48. },
  49. isFileNameValid:function (name) {
  50. if (name === '.') {
  51. OC.Notification.show(t('files', '\'.\' is an invalid file name.'));
  52. return false;
  53. }
  54. if (name.length == 0) {
  55. OC.Notification.show(t('files', 'File name cannot be empty.'));
  56. return false;
  57. }
  58. // check for invalid characters
  59. var invalid_characters = ['\\', '/', '<', '>', ':', '"', '|', '?', '*'];
  60. for (var i = 0; i < invalid_characters.length; i++) {
  61. if (name.indexOf(invalid_characters[i]) != -1) {
  62. OC.Notification.show(t('files', "Invalid name, '\\', '/', '<', '>', ':', '\"', '|', '?' and '*' are not allowed."));
  63. return false;
  64. }
  65. }
  66. OC.Notification.hide();
  67. return true;
  68. },
  69. displayStorageWarnings: function() {
  70. if (!OC.Notification.isHidden()) {
  71. return;
  72. }
  73. var usedSpacePercent = $('#usedSpacePercent').val();
  74. if (usedSpacePercent > 98) {
  75. OC.Notification.show(t('files', 'Your storage is full, files can not be updated or synced anymore!'));
  76. return;
  77. }
  78. if (usedSpacePercent > 90) {
  79. OC.Notification.show(t('files', 'Your storage is almost full ({usedSpacePercent}%)', {usedSpacePercent: usedSpacePercent}));
  80. }
  81. }
  82. };
  83. $(document).ready(function() {
  84. Files.bindKeyboardShortcuts(document, jQuery);
  85. $('#fileList tr').each(function(){
  86. //little hack to set unescape filenames in attribute
  87. $(this).attr('data-file',decodeURIComponent($(this).attr('data-file')));
  88. });
  89. $('#file_action_panel').attr('activeAction', false);
  90. //drag/drop of files
  91. $('#fileList tr td.filename').each(function(i,e){
  92. if ($(e).parent().data('permissions') & OC.PERMISSION_DELETE) {
  93. $(e).draggable(dragOptions);
  94. }
  95. });
  96. $('#fileList tr[data-type="dir"] td.filename').each(function(i,e){
  97. if ($(e).parent().data('permissions') & OC.PERMISSION_CREATE){
  98. $(e).droppable(folderDropOptions);
  99. }
  100. });
  101. $('div.crumb:not(.last)').droppable(crumbDropOptions);
  102. $('ul#apps>li:first-child').data('dir','');
  103. if($('div.crumb').length){
  104. $('ul#apps>li:first-child').droppable(crumbDropOptions);
  105. }
  106. // Triggers invisible file input
  107. $('#upload a').on('click', function() {
  108. $(this).parent().children('#file_upload_start').trigger('click');
  109. return false;
  110. });
  111. // Trigger cancelling of file upload
  112. $('#uploadprogresswrapper .stop').on('click', function() {
  113. Files.cancelUploads();
  114. });
  115. // Show trash bin
  116. $('#trash').on('click', function() {
  117. window.location=OC.filePath('files_trashbin', '', 'index.php');
  118. });
  119. var lastChecked;
  120. // Sets the file link behaviour :
  121. $('#fileList').on('click','td.filename a',function(event) {
  122. if (event.ctrlKey || event.shiftKey) {
  123. event.preventDefault();
  124. if (event.shiftKey) {
  125. var last = $(lastChecked).parent().parent().prevAll().length;
  126. var first = $(this).parent().parent().prevAll().length;
  127. var start = Math.min(first, last);
  128. var end = Math.max(first, last);
  129. var rows = $(this).parent().parent().parent().children('tr');
  130. for (var i = start; i < end; i++) {
  131. $(rows).each(function(index) {
  132. if (index == i) {
  133. var checkbox = $(this).children().children('input:checkbox');
  134. $(checkbox).attr('checked', 'checked');
  135. $(checkbox).parent().parent().addClass('selected');
  136. }
  137. });
  138. }
  139. }
  140. var checkbox = $(this).parent().children('input:checkbox');
  141. lastChecked = checkbox;
  142. if ($(checkbox).attr('checked')) {
  143. $(checkbox).removeAttr('checked');
  144. $(checkbox).parent().parent().removeClass('selected');
  145. $('#select_all').removeAttr('checked');
  146. } else {
  147. $(checkbox).attr('checked', 'checked');
  148. $(checkbox).parent().parent().toggleClass('selected');
  149. var selectedCount=$('td.filename input:checkbox:checked').length;
  150. if (selectedCount == $('td.filename input:checkbox').length) {
  151. $('#select_all').attr('checked', 'checked');
  152. }
  153. }
  154. procesSelection();
  155. } else {
  156. var filename=$(this).parent().parent().attr('data-file');
  157. var tr=$('tr').filterAttr('data-file',filename);
  158. var renaming=tr.data('renaming');
  159. if(!renaming && !FileList.isLoading(filename)){
  160. FileActions.currentFile = $(this).parent();
  161. var mime=FileActions.getCurrentMimeType();
  162. var type=FileActions.getCurrentType();
  163. var permissions = FileActions.getCurrentPermissions();
  164. var action=FileActions.getDefault(mime,type, permissions);
  165. if(action){
  166. event.preventDefault();
  167. action(filename);
  168. }
  169. }
  170. }
  171. });
  172. // Sets the select_all checkbox behaviour :
  173. $('#select_all').click(function() {
  174. if($(this).attr('checked')){
  175. // Check all
  176. $('td.filename input:checkbox').attr('checked', true);
  177. $('td.filename input:checkbox').parent().parent().addClass('selected');
  178. }else{
  179. // Uncheck all
  180. $('td.filename input:checkbox').attr('checked', false);
  181. $('td.filename input:checkbox').parent().parent().removeClass('selected');
  182. }
  183. procesSelection();
  184. });
  185. $('#fileList').on('change', 'td.filename input:checkbox',function(event) {
  186. if (event.shiftKey) {
  187. var last = $(lastChecked).parent().parent().prevAll().length;
  188. var first = $(this).parent().parent().prevAll().length;
  189. var start = Math.min(first, last);
  190. var end = Math.max(first, last);
  191. var rows = $(this).parent().parent().parent().children('tr');
  192. for (var i = start; i < end; i++) {
  193. $(rows).each(function(index) {
  194. if (index == i) {
  195. var checkbox = $(this).children().children('input:checkbox');
  196. $(checkbox).attr('checked', 'checked');
  197. $(checkbox).parent().parent().addClass('selected');
  198. }
  199. });
  200. }
  201. }
  202. var selectedCount=$('td.filename input:checkbox:checked').length;
  203. $(this).parent().parent().toggleClass('selected');
  204. if(!$(this).attr('checked')){
  205. $('#select_all').attr('checked',false);
  206. }else{
  207. if(selectedCount==$('td.filename input:checkbox').length){
  208. $('#select_all').attr('checked',true);
  209. }
  210. }
  211. procesSelection();
  212. });
  213. $('.download').click('click',function(event) {
  214. var files=getSelectedFiles('name');
  215. var fileslist = JSON.stringify(files);
  216. var dir=$('#dir').val()||'/';
  217. OC.Notification.show(t('files','Your download is being prepared. This might take some time if the files are big.'));
  218. // use special download URL if provided, e.g. for public shared files
  219. if ( (downloadURL = document.getElementById("downloadURL")) ) {
  220. window.location=downloadURL.value+"&download&files="+encodeURIComponent(fileslist);
  221. } else {
  222. window.location=OC.filePath('files', 'ajax', 'download.php') + '?'+ $.param({ dir: dir, files: fileslist });
  223. }
  224. return false;
  225. });
  226. $('.delete-selected').click(function(event) {
  227. var files=getSelectedFiles('name');
  228. event.preventDefault();
  229. FileList.do_delete(files);
  230. return false;
  231. });
  232. // drag&drop support using jquery.fileupload
  233. // TODO use OC.dialogs
  234. $(document).bind('drop dragover', function (e) {
  235. e.preventDefault(); // prevent browser from doing anything, if file isn't dropped in dropZone
  236. });
  237. $.assocArraySize = function(obj) {
  238. // http://stackoverflow.com/a/6700/11236
  239. var size = 0, key;
  240. for (key in obj) {
  241. if (obj.hasOwnProperty(key)) size++;
  242. }
  243. return size;
  244. };
  245. // warn user not to leave the page while upload is in progress
  246. $(window).bind('beforeunload', function(e) {
  247. if ($.assocArraySize(uploadingFiles) > 0)
  248. return t('files','File upload is in progress. Leaving the page now will cancel the upload.');
  249. });
  250. //add multiply file upload attribute to all browsers except konqueror (which crashes when it's used)
  251. if(navigator.userAgent.search(/konqueror/i)==-1){
  252. $('#file_upload_start').attr('multiple','multiple')
  253. }
  254. //if the breadcrumb is to long, start by replacing foldernames with '...' except for the current folder
  255. var crumb=$('div.crumb').first();
  256. while($('div.controls').height()>40 && crumb.next('div.crumb').length>0){
  257. crumb.children('a').text('...');
  258. crumb=crumb.next('div.crumb');
  259. }
  260. //if that isn't enough, start removing items from the breacrumb except for the current folder and it's parent
  261. var crumb=$('div.crumb').first();
  262. var next=crumb.next('div.crumb');
  263. while($('div.controls').height()>40 && next.next('div.crumb').length>0){
  264. crumb.remove();
  265. crumb=next;
  266. next=crumb.next('div.crumb');
  267. }
  268. //still not enough, start shorting down the current folder name
  269. var crumb=$('div.crumb>a').last();
  270. while($('div.controls').height()>40 && crumb.text().length>6){
  271. var text=crumb.text()
  272. text=text.substr(0,text.length-6)+'...';
  273. crumb.text(text);
  274. }
  275. $(document).click(function(){
  276. $('#new>ul').hide();
  277. $('#new').removeClass('active');
  278. $('#new li').each(function(i,element){
  279. if($(element).children('p').length==0){
  280. $(element).children('form').remove();
  281. $(element).append('<p>'+$(element).data('text')+'</p>');
  282. }
  283. });
  284. });
  285. $('#new').click(function(event){
  286. event.stopPropagation();
  287. });
  288. $('#new>a').click(function(){
  289. $('#new>ul').toggle();
  290. $('#new').toggleClass('active');
  291. });
  292. $('#new li').click(function(){
  293. if($(this).children('p').length==0){
  294. return;
  295. }
  296. $('#new li').each(function(i,element){
  297. if($(element).children('p').length==0){
  298. $(element).children('form').remove();
  299. $(element).append('<p>'+$(element).data('text')+'</p>');
  300. }
  301. });
  302. var type=$(this).data('type');
  303. var text=$(this).children('p').text();
  304. $(this).data('text',text);
  305. $(this).children('p').remove();
  306. var form=$('<form></form>');
  307. var input=$('<input>');
  308. form.append(input);
  309. $(this).append(form);
  310. input.focus();
  311. form.submit(function(event){
  312. event.stopPropagation();
  313. event.preventDefault();
  314. var newname=input.val();
  315. if(type == 'web' && newname.length == 0) {
  316. OC.Notification.show(t('files', 'URL cannot be empty.'));
  317. return false;
  318. } else if (type != 'web' && !Files.isFileNameValid(newname)) {
  319. return false;
  320. } else if( type == 'folder' && $('#dir').val() == '/' && newname == 'Shared') {
  321. OC.Notification.show(t('files','Invalid folder name. Usage of \'Shared\' is reserved by Owncloud'));
  322. return false;
  323. }
  324. if (FileList.lastAction) {
  325. FileList.lastAction();
  326. }
  327. var name = getUniqueName(newname);
  328. if (newname != name) {
  329. FileList.checkName(name, newname, true);
  330. var hidden = true;
  331. } else {
  332. var hidden = false;
  333. }
  334. switch(type){
  335. case 'file':
  336. $.post(
  337. OC.filePath('files','ajax','newfile.php'),
  338. {dir:$('#dir').val(),filename:name},
  339. function(result){
  340. if (result.status == 'success') {
  341. var date=new Date();
  342. FileList.addFile(name,0,date,false,hidden);
  343. var tr=$('tr').filterAttr('data-file',name);
  344. tr.attr('data-mime',result.data.mime);
  345. tr.attr('data-size',result.data.size);
  346. tr.attr('data-id', result.data.id);
  347. tr.find('.filesize').text(humanFileSize(result.data.size));
  348. getMimeIcon(result.data.mime,function(path){
  349. tr.find('td.filename').attr('style','background-image:url('+path+')');
  350. });
  351. } else {
  352. OC.dialogs.alert(result.data.message, t('core', 'Error'));
  353. }
  354. }
  355. );
  356. break;
  357. case 'folder':
  358. $.post(
  359. OC.filePath('files','ajax','newfolder.php'),
  360. {dir:$('#dir').val(),foldername:name},
  361. function(result){
  362. if (result.status == 'success') {
  363. var date=new Date();
  364. FileList.addDir(name,0,date,hidden);
  365. var tr=$('tr').filterAttr('data-file',name);
  366. tr.attr('data-id', result.data.id);
  367. } else {
  368. OC.dialogs.alert(result.data.message, t('core', 'Error'));
  369. }
  370. }
  371. );
  372. break;
  373. case 'web':
  374. if(name.substr(0,8)!='https://' && name.substr(0,7)!='http://'){
  375. name='http://'+name;
  376. }
  377. var localName=name;
  378. if(localName.substr(localName.length-1,1)=='/'){//strip /
  379. localName=localName.substr(0,localName.length-1)
  380. }
  381. if(localName.indexOf('/')){//use last part of url
  382. localName=localName.split('/').pop();
  383. }else{//or the domain
  384. localName=(localName.match(/:\/\/(.[^/]+)/)[1]).replace('www.','');
  385. }
  386. localName = getUniqueName(localName);
  387. //IE < 10 does not fire the necessary events for the progress bar.
  388. if($('html.lte9').length > 0) {
  389. } else {
  390. $('#uploadprogressbar').progressbar({value:0});
  391. $('#uploadprogressbar').fadeIn();
  392. }
  393. var eventSource=new OC.EventSource(OC.filePath('files','ajax','newfile.php'),{dir:$('#dir').val(),source:name,filename:localName});
  394. eventSource.listen('progress',function(progress){
  395. //IE < 10 does not fire the necessary events for the progress bar.
  396. if($('html.lte9').length > 0) {
  397. } else {
  398. $('#uploadprogressbar').progressbar('value',progress);
  399. }
  400. });
  401. eventSource.listen('success',function(data){
  402. var mime=data.mime;
  403. var size=data.size;
  404. var id=data.id;
  405. $('#uploadprogressbar').fadeOut();
  406. var date=new Date();
  407. FileList.addFile(localName,size,date,false,hidden);
  408. var tr=$('tr').filterAttr('data-file',localName);
  409. tr.data('mime',mime).data('id',id);
  410. tr.attr('data-id', id);
  411. getMimeIcon(mime,function(path){
  412. tr.find('td.filename').attr('style','background-image:url('+path+')');
  413. });
  414. });
  415. eventSource.listen('error',function(error){
  416. $('#uploadprogressbar').fadeOut();
  417. alert(error);
  418. });
  419. break;
  420. }
  421. var li=form.parent();
  422. form.remove();
  423. li.append('<p>'+li.data('text')+'</p>');
  424. $('#new>a').click();
  425. });
  426. });
  427. //do a background scan if needed
  428. scanFiles();
  429. var lastWidth = 0;
  430. var breadcrumbs = [];
  431. var breadcrumbsWidth = 0;
  432. if ( document.getElementById("navigation") ) {
  433. breadcrumbsWidth = $('#navigation').get(0).offsetWidth;
  434. }
  435. var hiddenBreadcrumbs = 0;
  436. $.each($('.crumb'), function(index, breadcrumb) {
  437. breadcrumbs[index] = breadcrumb;
  438. breadcrumbsWidth += $(breadcrumb).get(0).offsetWidth;
  439. });
  440. $.each($('#controls .actions>div'), function(index, action) {
  441. breadcrumbsWidth += $(action).get(0).offsetWidth;
  442. });
  443. function resizeBreadcrumbs(firstRun) {
  444. var width = $(this).width();
  445. if (width != lastWidth) {
  446. if ((width < lastWidth || firstRun) && width < breadcrumbsWidth) {
  447. if (hiddenBreadcrumbs == 0) {
  448. breadcrumbsWidth -= $(breadcrumbs[1]).get(0).offsetWidth;
  449. $(breadcrumbs[1]).find('a').hide();
  450. $(breadcrumbs[1]).append('<span>...</span>');
  451. breadcrumbsWidth += $(breadcrumbs[1]).get(0).offsetWidth;
  452. hiddenBreadcrumbs = 2;
  453. }
  454. var i = hiddenBreadcrumbs;
  455. while (width < breadcrumbsWidth && i > 1 && i < breadcrumbs.length - 1) {
  456. breadcrumbsWidth -= $(breadcrumbs[i]).get(0).offsetWidth;
  457. $(breadcrumbs[i]).hide();
  458. hiddenBreadcrumbs = i;
  459. i++
  460. }
  461. } else if (width > lastWidth && hiddenBreadcrumbs > 0) {
  462. var i = hiddenBreadcrumbs;
  463. while (width > breadcrumbsWidth && i > 0) {
  464. if (hiddenBreadcrumbs == 1) {
  465. breadcrumbsWidth -= $(breadcrumbs[1]).get(0).offsetWidth;
  466. $(breadcrumbs[1]).find('span').remove();
  467. $(breadcrumbs[1]).find('a').show();
  468. breadcrumbsWidth += $(breadcrumbs[1]).get(0).offsetWidth;
  469. } else {
  470. $(breadcrumbs[i]).show();
  471. breadcrumbsWidth += $(breadcrumbs[i]).get(0).offsetWidth;
  472. if (breadcrumbsWidth > width) {
  473. breadcrumbsWidth -= $(breadcrumbs[i]).get(0).offsetWidth;
  474. $(breadcrumbs[i]).hide();
  475. break;
  476. }
  477. }
  478. i--;
  479. hiddenBreadcrumbs = i;
  480. }
  481. }
  482. lastWidth = width;
  483. }
  484. }
  485. $(window).resize(function() {
  486. resizeBreadcrumbs(false);
  487. });
  488. resizeBreadcrumbs(true);
  489. // display storage warnings
  490. setTimeout ( "Files.displayStorageWarnings()", 100 );
  491. OC.Notification.setDefault(Files.displayStorageWarnings);
  492. // file space size sync
  493. function update_storage_statistics() {
  494. $.getJSON(OC.filePath('files','ajax','getstoragestats.php'),function(response) {
  495. Files.updateMaxUploadFilesize(response);
  496. });
  497. }
  498. // start on load - we ask the server every 5 minutes
  499. var update_storage_statistics_interval = 5*60*1000;
  500. var update_storage_statistics_interval_id = setInterval(update_storage_statistics, update_storage_statistics_interval);
  501. // Use jquery-visibility to de-/re-activate file stats sync
  502. if ($.support.pageVisibility) {
  503. $(document).on({
  504. 'show.visibility': function() {
  505. if (!update_storage_statistics_interval_id) {
  506. update_storage_statistics_interval_id = setInterval(update_storage_statistics, update_storage_statistics_interval);
  507. }
  508. },
  509. 'hide.visibility': function() {
  510. clearInterval(update_storage_statistics_interval_id);
  511. update_storage_statistics_interval_id = 0;
  512. }
  513. });
  514. }
  515. });
  516. function scanFiles(force, dir, users){
  517. if (!OC.currentUser) {
  518. return;
  519. }
  520. if(!dir){
  521. dir = '';
  522. }
  523. force = !!force; //cast to bool
  524. scanFiles.scanning = true;
  525. var scannerEventSource;
  526. if (users) {
  527. var usersString;
  528. if (users === 'all') {
  529. usersString = users;
  530. } else {
  531. usersString = JSON.stringify(users);
  532. }
  533. scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force: force,dir: dir, users: usersString});
  534. } else {
  535. scannerEventSource = new OC.EventSource(OC.filePath('files','ajax','scan.php'),{force: force,dir: dir});
  536. }
  537. scanFiles.cancel = scannerEventSource.close.bind(scannerEventSource);
  538. scannerEventSource.listen('count',function(count){
  539. console.log(count + ' files scanned')
  540. });
  541. scannerEventSource.listen('folder',function(path){
  542. console.log('now scanning ' + path)
  543. });
  544. scannerEventSource.listen('done',function(count){
  545. scanFiles.scanning=false;
  546. console.log('done after ' + count + ' files');
  547. });
  548. scannerEventSource.listen('user',function(user){
  549. console.log('scanning files for ' + user);
  550. });
  551. }
  552. scanFiles.scanning=false;
  553. function boolOperationFinished(data, callback) {
  554. result = jQuery.parseJSON(data.responseText);
  555. Files.updateMaxUploadFilesize(result);
  556. if(result.status == 'success'){
  557. callback.call();
  558. } else {
  559. alert(result.data.message);
  560. }
  561. }
  562. function updateBreadcrumb(breadcrumbHtml) {
  563. $('p.nav').empty().html(breadcrumbHtml);
  564. }
  565. var createDragShadow = function(event){
  566. //select dragged file
  567. var isDragSelected = $(event.target).parents('tr').find('td input:first').prop('checked');
  568. if (!isDragSelected) {
  569. //select dragged file
  570. $(event.target).parents('tr').find('td input:first').prop('checked',true);
  571. }
  572. var selectedFiles = getSelectedFiles();
  573. if (!isDragSelected && selectedFiles.length == 1) {
  574. //revert the selection
  575. $(event.target).parents('tr').find('td input:first').prop('checked',false);
  576. }
  577. //also update class when we dragged more than one file
  578. if (selectedFiles.length > 1) {
  579. $(event.target).parents('tr').addClass('selected');
  580. }
  581. // build dragshadow
  582. var dragshadow = $('<table class="dragshadow"></table>');
  583. var tbody = $('<tbody></tbody>');
  584. dragshadow.append(tbody);
  585. var dir=$('#dir').val();
  586. $(selectedFiles).each(function(i,elem){
  587. var newtr = $('<tr/>').attr('data-dir', dir).attr('data-filename', elem.name);
  588. newtr.append($('<td/>').addClass('filename').text(elem.name));
  589. newtr.append($('<td/>').addClass('size').text(humanFileSize(elem.size)));
  590. tbody.append(newtr);
  591. if (elem.type === 'dir') {
  592. newtr.find('td.filename').attr('style','background-image:url('+OC.imagePath('core', 'filetypes/folder.png')+')');
  593. } else {
  594. getMimeIcon(elem.mime,function(path){
  595. newtr.find('td.filename').attr('style','background-image:url('+path+')');
  596. });
  597. }
  598. });
  599. return dragshadow;
  600. }
  601. //options for file drag/drop
  602. var dragOptions={
  603. revert: 'invalid', revertDuration: 300,
  604. opacity: 0.7, zIndex: 100, appendTo: 'body', cursorAt: { left: -5, top: -5 },
  605. helper: createDragShadow, cursor: 'move',
  606. stop: function(event, ui) {
  607. $('#fileList tr td.filename').addClass('ui-draggable');
  608. }
  609. }
  610. // sane browsers support using the distance option
  611. if ( $('html.ie').length === 0) {
  612. dragOptions['distance'] = 20;
  613. }
  614. var folderDropOptions={
  615. drop: function( event, ui ) {
  616. //don't allow moving a file into a selected folder
  617. if ($(event.target).parents('tr').find('td input:first').prop('checked') === true) {
  618. return false;
  619. }
  620. var target=$.trim($(this).find('.nametext').text());
  621. var files = ui.helper.find('tr');
  622. $(files).each(function(i,row){
  623. var dir = $(row).data('dir');
  624. var file = $(row).data('filename');
  625. $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: dir+'/'+target }, function(result) {
  626. if (result) {
  627. if (result.status === 'success') {
  628. //recalculate folder size
  629. var oldSize = $('#fileList tr').filterAttr('data-file',target).data('size');
  630. var newSize = oldSize + $('#fileList tr').filterAttr('data-file',file).data('size');
  631. $('#fileList tr').filterAttr('data-file',target).data('size', newSize);
  632. $('#fileList tr').filterAttr('data-file',target).find('td.filesize').text(humanFileSize(newSize));
  633. FileList.remove(file);
  634. procesSelection();
  635. $('#notification').hide();
  636. } else {
  637. $('#notification').hide();
  638. $('#notification').text(result.data.message);
  639. $('#notification').fadeIn();
  640. }
  641. } else {
  642. OC.dialogs.alert(t('Error moving file'), t('core', 'Error'));
  643. }
  644. });
  645. });
  646. },
  647. tolerance: 'pointer'
  648. }
  649. var crumbDropOptions={
  650. drop: function( event, ui ) {
  651. var target=$(this).data('dir');
  652. var dir=$('#dir').val();
  653. while(dir.substr(0,1)=='/'){//remove extra leading /'s
  654. dir=dir.substr(1);
  655. }
  656. dir='/'+dir;
  657. if(dir.substr(-1,1)!='/'){
  658. dir=dir+'/';
  659. }
  660. if(target==dir || target+'/'==dir){
  661. return;
  662. }
  663. var files = ui.helper.find('tr');
  664. $(files).each(function(i,row){
  665. var dir = $(row).data('dir');
  666. var file = $(row).data('filename');
  667. $.post(OC.filePath('files', 'ajax', 'move.php'), { dir: dir, file: file, target: target }, function(result) {
  668. if (result) {
  669. if (result.status === 'success') {
  670. FileList.remove(file);
  671. procesSelection();
  672. $('#notification').hide();
  673. } else {
  674. $('#notification').hide();
  675. $('#notification').text(result.data.message);
  676. $('#notification').fadeIn();
  677. }
  678. } else {
  679. OC.dialogs.alert(t('Error moving file'), t('core', 'Error'));
  680. }
  681. });
  682. });
  683. },
  684. tolerance: 'pointer'
  685. }
  686. function procesSelection(){
  687. var selected=getSelectedFiles();
  688. var selectedFiles=selected.filter(function(el){return el.type=='file'});
  689. var selectedFolders=selected.filter(function(el){return el.type=='dir'});
  690. if(selectedFiles.length==0 && selectedFolders.length==0) {
  691. $('#headerName>span.name').text(t('files','Name'));
  692. $('#headerSize').text(t('files','Size'));
  693. $('#modified').text(t('files','Modified'));
  694. $('table').removeClass('multiselect');
  695. $('.selectedActions').hide();
  696. }
  697. else {
  698. $('.selectedActions').show();
  699. var totalSize=0;
  700. for(var i=0;i<selectedFiles.length;i++){
  701. totalSize+=selectedFiles[i].size;
  702. };
  703. for(var i=0;i<selectedFolders.length;i++){
  704. totalSize+=selectedFolders[i].size;
  705. };
  706. $('#headerSize').text(humanFileSize(totalSize));
  707. var selection='';
  708. if(selectedFolders.length>0){
  709. selection += n('files', '%n folder', '%n folders', selectedFolders.length);
  710. if(selectedFiles.length>0){
  711. selection+=' & ';
  712. }
  713. }
  714. if(selectedFiles.length>0){
  715. selection += n('files', '%n file', '%n files', selectedFiles.length);
  716. }
  717. $('#headerName>span.name').text(selection);
  718. $('#modified').text('');
  719. $('table').addClass('multiselect');
  720. }
  721. }
  722. /**
  723. * @brief get a list of selected files
  724. * @param string property (option) the property of the file requested
  725. * @return array
  726. *
  727. * possible values for property: name, mime, size and type
  728. * if property is set, an array with that property for each file is returnd
  729. * if it's ommited an array of objects with all properties is returned
  730. */
  731. function getSelectedFiles(property){
  732. var elements=$('td.filename input:checkbox:checked').parent().parent();
  733. var files=[];
  734. elements.each(function(i,element){
  735. var file={
  736. name:$(element).attr('data-file'),
  737. mime:$(element).data('mime'),
  738. type:$(element).data('type'),
  739. size:$(element).data('size')
  740. };
  741. if(property){
  742. files.push(file[property]);
  743. }else{
  744. files.push(file);
  745. }
  746. });
  747. return files;
  748. }
  749. function getMimeIcon(mime, ready){
  750. if(getMimeIcon.cache[mime]){
  751. ready(getMimeIcon.cache[mime]);
  752. }else{
  753. $.get( OC.filePath('files','ajax','mimeicon.php'), {mime: mime}, function(path){
  754. getMimeIcon.cache[mime]=path;
  755. ready(getMimeIcon.cache[mime]);
  756. });
  757. }
  758. }
  759. getMimeIcon.cache={};
  760. function getUniqueName(name){
  761. if($('tr').filterAttr('data-file',name).length>0){
  762. var parts=name.split('.');
  763. var extension = "";
  764. if (parts.length > 1) {
  765. extension=parts.pop();
  766. }
  767. var base=parts.join('.');
  768. numMatch=base.match(/\((\d+)\)/);
  769. var num=2;
  770. if(numMatch && numMatch.length>0){
  771. num=parseInt(numMatch[numMatch.length-1])+1;
  772. base=base.split('(')
  773. base.pop();
  774. base=$.trim(base.join('('));
  775. }
  776. name=base+' ('+num+')';
  777. if (extension) {
  778. name = name+'.'+extension;
  779. }
  780. return getUniqueName(name);
  781. }
  782. return name;
  783. }
  784. function checkTrashStatus() {
  785. $.post(OC.filePath('files_trashbin', 'ajax', 'isEmpty.php'), function(result){
  786. if (result.data.isEmpty === false) {
  787. $("input[type=button][id=trash]").removeAttr("disabled");
  788. }
  789. });
  790. }