oc-dialogs.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. /**
  2. * ownCloud
  3. *
  4. * @author Bartek Przybylski, Christopher Schäpers, Thomas Tanghus
  5. * @copyright 2012 Bartek Przybylski bartek@alefzero.eu
  6. *
  7. * This library is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
  9. * License as published by the Free Software Foundation; either
  10. * version 3 of the License, or any later version.
  11. *
  12. * This library is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public
  18. * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  19. *
  20. */
  21. /* global alert */
  22. /**
  23. * this class to ease the usage of jquery dialogs
  24. * @lends OC.dialogs
  25. */
  26. var OCdialogs = {
  27. // dialog button types
  28. YES_NO_BUTTONS: 70,
  29. OK_BUTTONS: 71,
  30. // used to name each dialog
  31. dialogsCounter: 0,
  32. /**
  33. * displays alert dialog
  34. * @param text content of dialog
  35. * @param title dialog title
  36. * @param callback which will be triggered when user presses OK
  37. * @param modal make the dialog modal
  38. */
  39. alert:function(text, title, callback, modal) {
  40. this.message(
  41. text,
  42. title,
  43. 'alert',
  44. OCdialogs.OK_BUTTON,
  45. callback,
  46. modal
  47. );
  48. },
  49. /**
  50. * displays info dialog
  51. * @param text content of dialog
  52. * @param title dialog title
  53. * @param callback which will be triggered when user presses OK
  54. * @param modal make the dialog modal
  55. */
  56. info:function(text, title, callback, modal) {
  57. this.message(text, title, 'info', OCdialogs.OK_BUTTON, callback, modal);
  58. },
  59. /**
  60. * displays confirmation dialog
  61. * @param text content of dialog
  62. * @param title dialog title
  63. * @param callback which will be triggered when user presses YES or NO
  64. * (true or false would be passed to callback respectively)
  65. * @param modal make the dialog modal
  66. */
  67. confirm:function(text, title, callback, modal) {
  68. return this.message(
  69. text,
  70. title,
  71. 'notice',
  72. OCdialogs.YES_NO_BUTTONS,
  73. callback,
  74. modal
  75. );
  76. },
  77. /**
  78. * displays prompt dialog
  79. * @param text content of dialog
  80. * @param title dialog title
  81. * @param callback which will be triggered when user presses YES or NO
  82. * (true or false would be passed to callback respectively)
  83. * @param modal make the dialog modal
  84. * @param name name of the input field
  85. * @param password whether the input should be a password input
  86. */
  87. prompt: function (text, title, callback, modal, name, password) {
  88. return $.when(this._getMessageTemplate()).then(function ($tmpl) {
  89. var dialogName = 'oc-dialog-' + OCdialogs.dialogsCounter + '-content';
  90. var dialogId = '#' + dialogName;
  91. var $dlg = $tmpl.octemplate({
  92. dialog_name: dialogName,
  93. title : title,
  94. message : text,
  95. type : 'notice'
  96. });
  97. var input = $('<input/>');
  98. input.attr('type', password ? 'password' : 'text').attr('id', dialogName + '-input');
  99. var label = $('<label/>').attr('for', dialogName + '-input').text(name + ': ');
  100. $dlg.append(label);
  101. $dlg.append(input);
  102. if (modal === undefined) {
  103. modal = false;
  104. }
  105. $('body').append($dlg);
  106. var buttonlist = [{
  107. text : t('core', 'No'),
  108. click: function () {
  109. if (callback !== undefined) {
  110. callback(false, input.val());
  111. }
  112. $(dialogId).ocdialog('close');
  113. }
  114. }, {
  115. text : t('core', 'Yes'),
  116. click : function () {
  117. if (callback !== undefined) {
  118. callback(true, input.val());
  119. }
  120. $(dialogId).ocdialog('close');
  121. },
  122. defaultButton: true
  123. }
  124. ];
  125. $(dialogId).ocdialog({
  126. closeOnEscape: true,
  127. modal : modal,
  128. buttons : buttonlist
  129. });
  130. OCdialogs.dialogsCounter++;
  131. });
  132. },
  133. /**
  134. * show a file picker to pick a file from
  135. * @param title dialog title
  136. * @param callback which will be triggered when user presses Choose
  137. * @param multiselect whether it should be possible to select multiple files
  138. * @param mimetypeFilter mimetype to filter by - directories will always be included
  139. * @param modal make the dialog modal
  140. */
  141. filepicker:function(title, callback, multiselect, mimetypeFilter, modal) {
  142. var self = this;
  143. // avoid opening the picker twice
  144. if (this.filepicker.loading) {
  145. return;
  146. }
  147. this.filepicker.loading = true;
  148. $.when(this._getFilePickerTemplate()).then(function($tmpl) {
  149. self.filepicker.loading = false;
  150. var dialogName = 'oc-dialog-filepicker-content';
  151. if(self.$filePicker) {
  152. self.$filePicker.ocdialog('close');
  153. }
  154. self.$filePicker = $tmpl.octemplate({
  155. dialog_name: dialogName,
  156. title: title
  157. }).data('path', '').data('multiselect', multiselect).data('mimetype', mimetypeFilter);
  158. if (modal === undefined) {
  159. modal = false;
  160. }
  161. if (multiselect === undefined) {
  162. multiselect = false;
  163. }
  164. if (mimetypeFilter === undefined) {
  165. mimetypeFilter = '';
  166. }
  167. $('body').append(self.$filePicker);
  168. self.$filePicker.ready(function() {
  169. self.$filelist = self.$filePicker.find('.filelist');
  170. self.$dirTree = self.$filePicker.find('.dirtree');
  171. self.$dirTree.on('click', 'span:not(:last-child)', self, self._handleTreeListSelect);
  172. self.$filelist.on('click', 'li', function(event) {
  173. self._handlePickerClick(event, $(this));
  174. });
  175. self._fillFilePicker('');
  176. });
  177. // build buttons
  178. var functionToCall = function() {
  179. if (callback !== undefined) {
  180. var datapath;
  181. if (multiselect === true) {
  182. datapath = [];
  183. self.$filelist.find('.filepicker_element_selected .filename').each(function(index, element) {
  184. datapath.push(self.$filePicker.data('path') + '/' + $(element).text());
  185. });
  186. } else {
  187. datapath = self.$filePicker.data('path');
  188. datapath += '/' + self.$filelist.find('.filepicker_element_selected .filename').text();
  189. }
  190. callback(datapath);
  191. self.$filePicker.ocdialog('close');
  192. }
  193. };
  194. var buttonlist = [{
  195. text: t('core', 'Choose'),
  196. click: functionToCall,
  197. defaultButton: true
  198. }];
  199. self.$filePicker.ocdialog({
  200. closeOnEscape: true,
  201. // max-width of 600
  202. width: Math.min((4/5)*$(document).width(), 600),
  203. height: 420,
  204. modal: modal,
  205. buttons: buttonlist,
  206. close: function() {
  207. try {
  208. $(this).ocdialog('destroy').remove();
  209. } catch(e) {}
  210. self.$filePicker = null;
  211. }
  212. });
  213. if (!OC.Util.hasSVGSupport()) {
  214. OC.Util.replaceSVG(self.$filePicker.parent());
  215. }
  216. })
  217. .fail(function(status, error) {
  218. // If the method is called while navigating away
  219. // from the page, it is probably not needed ;)
  220. self.filepicker.loading = false;
  221. if(status !== 0) {
  222. alert(t('core', 'Error loading file picker template: {error}', {error: error}));
  223. }
  224. });
  225. },
  226. /**
  227. * Displays raw dialog
  228. * You better use a wrapper instead ...
  229. */
  230. message:function(content, title, dialogType, buttons, callback, modal) {
  231. return $.when(this._getMessageTemplate()).then(function($tmpl) {
  232. var dialogName = 'oc-dialog-' + OCdialogs.dialogsCounter + '-content';
  233. var dialogId = '#' + dialogName;
  234. var $dlg = $tmpl.octemplate({
  235. dialog_name: dialogName,
  236. title: title,
  237. message: content,
  238. type: dialogType
  239. });
  240. if (modal === undefined) {
  241. modal = false;
  242. }
  243. $('body').append($dlg);
  244. var buttonlist = [];
  245. switch (buttons) {
  246. case OCdialogs.YES_NO_BUTTONS:
  247. buttonlist = [{
  248. text: t('core', 'No'),
  249. click: function(){
  250. if (callback !== undefined) {
  251. callback(false);
  252. }
  253. $(dialogId).ocdialog('close');
  254. }
  255. },
  256. {
  257. text: t('core', 'Yes'),
  258. click: function(){
  259. if (callback !== undefined) {
  260. callback(true);
  261. }
  262. $(dialogId).ocdialog('close');
  263. },
  264. defaultButton: true
  265. }];
  266. break;
  267. case OCdialogs.OK_BUTTON:
  268. var functionToCall = function() {
  269. $(dialogId).ocdialog('close');
  270. if(callback !== undefined) {
  271. callback();
  272. }
  273. };
  274. buttonlist[0] = {
  275. text: t('core', 'Ok'),
  276. click: functionToCall,
  277. defaultButton: true
  278. };
  279. break;
  280. }
  281. $(dialogId).ocdialog({
  282. closeOnEscape: true,
  283. modal: modal,
  284. buttons: buttonlist
  285. });
  286. OCdialogs.dialogsCounter++;
  287. })
  288. .fail(function(status, error) {
  289. // If the method is called while navigating away from
  290. // the page, we still want to deliver the message.
  291. if(status === 0) {
  292. alert(title + ': ' + content);
  293. } else {
  294. alert(t('core', 'Error loading message template: {error}', {error: error}));
  295. }
  296. });
  297. },
  298. _fileexistsshown: false,
  299. /**
  300. * Displays file exists dialog
  301. * @param {object} data upload object
  302. * @param {object} original file with name, size and mtime
  303. * @param {object} replacement file with name, size and mtime
  304. * @param {object} controller with onCancel, onSkip, onReplace and onRename methods
  305. * @return {Promise} jquery promise that resolves after the dialog template was loaded
  306. */
  307. fileexists:function(data, original, replacement, controller) {
  308. var self = this;
  309. var dialogDeferred = new $.Deferred();
  310. var getCroppedPreview = function(file) {
  311. var deferred = new $.Deferred();
  312. // Only process image files.
  313. var type = file.type && file.type.split('/').shift();
  314. if (window.FileReader && type === 'image') {
  315. var reader = new FileReader();
  316. reader.onload = function (e) {
  317. var blob = new Blob([e.target.result]);
  318. window.URL = window.URL || window.webkitURL;
  319. var originalUrl = window.URL.createObjectURL(blob);
  320. var image = new Image();
  321. image.src = originalUrl;
  322. image.onload = function () {
  323. var url = crop(image);
  324. deferred.resolve(url);
  325. };
  326. };
  327. reader.readAsArrayBuffer(file);
  328. } else {
  329. deferred.reject();
  330. }
  331. return deferred;
  332. };
  333. var crop = function(img) {
  334. var canvas = document.createElement('canvas'),
  335. targetSize = 96,
  336. width = img.width,
  337. height = img.height,
  338. x, y, size;
  339. // Calculate the width and height, constraining the proportions
  340. if (width > height) {
  341. y = 0;
  342. x = (width - height) / 2;
  343. } else {
  344. y = (height - width) / 2;
  345. x = 0;
  346. }
  347. size = Math.min(width, height);
  348. // Set canvas size to the cropped area
  349. canvas.width = size;
  350. canvas.height = size;
  351. var ctx = canvas.getContext("2d");
  352. ctx.drawImage(img, x, y, size, size, 0, 0, size, size);
  353. // Resize the canvas to match the destination (right size uses 96px)
  354. resampleHermite(canvas, size, size, targetSize, targetSize);
  355. return canvas.toDataURL("image/png", 0.7);
  356. };
  357. /**
  358. * Fast image resize/resample using Hermite filter with JavaScript.
  359. *
  360. * @author: ViliusL
  361. *
  362. * @param {*} canvas
  363. * @param {number} W
  364. * @param {number} H
  365. * @param {number} W2
  366. * @param {number} H2
  367. */
  368. var resampleHermite = function (canvas, W, H, W2, H2) {
  369. W2 = Math.round(W2);
  370. H2 = Math.round(H2);
  371. var img = canvas.getContext("2d").getImageData(0, 0, W, H);
  372. var img2 = canvas.getContext("2d").getImageData(0, 0, W2, H2);
  373. var data = img.data;
  374. var data2 = img2.data;
  375. var ratio_w = W / W2;
  376. var ratio_h = H / H2;
  377. var ratio_w_half = Math.ceil(ratio_w / 2);
  378. var ratio_h_half = Math.ceil(ratio_h / 2);
  379. for (var j = 0; j < H2; j++) {
  380. for (var i = 0; i < W2; i++) {
  381. var x2 = (i + j * W2) * 4;
  382. var weight = 0;
  383. var weights = 0;
  384. var weights_alpha = 0;
  385. var gx_r = 0;
  386. var gx_g = 0;
  387. var gx_b = 0;
  388. var gx_a = 0;
  389. var center_y = (j + 0.5) * ratio_h;
  390. for (var yy = Math.floor(j * ratio_h); yy < (j + 1) * ratio_h; yy++) {
  391. var dy = Math.abs(center_y - (yy + 0.5)) / ratio_h_half;
  392. var center_x = (i + 0.5) * ratio_w;
  393. var w0 = dy * dy; //pre-calc part of w
  394. for (var xx = Math.floor(i * ratio_w); xx < (i + 1) * ratio_w; xx++) {
  395. var dx = Math.abs(center_x - (xx + 0.5)) / ratio_w_half;
  396. var w = Math.sqrt(w0 + dx * dx);
  397. if (w >= -1 && w <= 1) {
  398. //hermite filter
  399. weight = 2 * w * w * w - 3 * w * w + 1;
  400. if (weight > 0) {
  401. dx = 4 * (xx + yy * W);
  402. //alpha
  403. gx_a += weight * data[dx + 3];
  404. weights_alpha += weight;
  405. //colors
  406. if (data[dx + 3] < 255)
  407. weight = weight * data[dx + 3] / 250;
  408. gx_r += weight * data[dx];
  409. gx_g += weight * data[dx + 1];
  410. gx_b += weight * data[dx + 2];
  411. weights += weight;
  412. }
  413. }
  414. }
  415. }
  416. data2[x2] = gx_r / weights;
  417. data2[x2 + 1] = gx_g / weights;
  418. data2[x2 + 2] = gx_b / weights;
  419. data2[x2 + 3] = gx_a / weights_alpha;
  420. }
  421. }
  422. canvas.getContext("2d").clearRect(0, 0, Math.max(W, W2), Math.max(H, H2));
  423. canvas.width = W2;
  424. canvas.height = H2;
  425. canvas.getContext("2d").putImageData(img2, 0, 0);
  426. };
  427. var addConflict = function($conflicts, original, replacement) {
  428. var $conflict = $conflicts.find('.template').clone().removeClass('template').addClass('conflict');
  429. var $originalDiv = $conflict.find('.original');
  430. var $replacementDiv = $conflict.find('.replacement');
  431. $conflict.data('data',data);
  432. $conflict.find('.filename').text(original.name);
  433. $originalDiv.find('.size').text(humanFileSize(original.size));
  434. $originalDiv.find('.mtime').text(formatDate(original.mtime));
  435. // ie sucks
  436. if (replacement.size && replacement.lastModifiedDate) {
  437. $replacementDiv.find('.size').text(humanFileSize(replacement.size));
  438. $replacementDiv.find('.mtime').text(formatDate(replacement.lastModifiedDate));
  439. }
  440. var path = original.directory + '/' +original.name;
  441. var urlSpec = {
  442. file: path,
  443. x: 96,
  444. y: 96,
  445. c: original.etag,
  446. forceIcon: 0
  447. };
  448. var previewpath = Files.generatePreviewUrl(urlSpec);
  449. // Escaping single quotes
  450. previewpath = previewpath.replace(/'/g, "%27");
  451. $originalDiv.find('.icon').css({"background-image": "url('" + previewpath + "')"});
  452. getCroppedPreview(replacement).then(
  453. function(path){
  454. $replacementDiv.find('.icon').css('background-image','url(' + path + ')');
  455. }, function(){
  456. path = OC.MimeType.getIconUrl(replacement.type);
  457. $replacementDiv.find('.icon').css('background-image','url(' + path + ')');
  458. }
  459. );
  460. // connect checkboxes with labels
  461. var checkboxId = $conflicts.find('.conflict').length;
  462. $originalDiv.find('input:checkbox').attr('id', 'checkbox_original_'+checkboxId);
  463. $replacementDiv.find('input:checkbox').attr('id', 'checkbox_replacement_'+checkboxId);
  464. $conflicts.append($conflict);
  465. //set more recent mtime bold
  466. // ie sucks
  467. if (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() > original.mtime) {
  468. $replacementDiv.find('.mtime').css('font-weight', 'bold');
  469. } else if (replacement.lastModifiedDate && replacement.lastModifiedDate.getTime() < original.mtime) {
  470. $originalDiv.find('.mtime').css('font-weight', 'bold');
  471. } else {
  472. //TODO add to same mtime collection?
  473. }
  474. // set bigger size bold
  475. if (replacement.size && replacement.size > original.size) {
  476. $replacementDiv.find('.size').css('font-weight', 'bold');
  477. } else if (replacement.size && replacement.size < original.size) {
  478. $originalDiv.find('.size').css('font-weight', 'bold');
  479. } else {
  480. //TODO add to same size collection?
  481. }
  482. //TODO show skip action for files with same size and mtime in bottom row
  483. // always keep readonly files
  484. if (original.status === 'readonly') {
  485. $originalDiv
  486. .addClass('readonly')
  487. .find('input[type="checkbox"]')
  488. .prop('checked', true)
  489. .prop('disabled', true);
  490. $originalDiv.find('.message')
  491. .text(t('core','read-only'))
  492. }
  493. };
  494. //var selection = controller.getSelection(data.originalFiles);
  495. //if (selection.defaultAction) {
  496. // controller[selection.defaultAction](data);
  497. //} else {
  498. var dialogName = 'oc-dialog-fileexists-content';
  499. var dialogId = '#' + dialogName;
  500. if (this._fileexistsshown) {
  501. // add conflict
  502. var $conflicts = $(dialogId+ ' .conflicts');
  503. addConflict($conflicts, original, replacement);
  504. var count = $(dialogId+ ' .conflict').length;
  505. var title = n('core',
  506. '{count} file conflict',
  507. '{count} file conflicts',
  508. count,
  509. {count:count}
  510. );
  511. $(dialogId).parent().children('.oc-dialog-title').text(title);
  512. //recalculate dimensions
  513. $(window).trigger('resize');
  514. dialogDeferred.resolve();
  515. } else {
  516. //create dialog
  517. this._fileexistsshown = true;
  518. $.when(this._getFileExistsTemplate()).then(function($tmpl) {
  519. var title = t('core','One file conflict');
  520. var $dlg = $tmpl.octemplate({
  521. dialog_name: dialogName,
  522. title: title,
  523. type: 'fileexists',
  524. allnewfiles: t('core','New Files'),
  525. allexistingfiles: t('core','Already existing files'),
  526. why: t('core','Which files do you want to keep?'),
  527. what: t('core','If you select both versions, the copied file will have a number added to its name.')
  528. });
  529. $('body').append($dlg);
  530. if (original && replacement) {
  531. var $conflicts = $dlg.find('.conflicts');
  532. addConflict($conflicts, original, replacement);
  533. }
  534. var buttonlist = [{
  535. text: t('core', 'Cancel'),
  536. classes: 'cancel',
  537. click: function(){
  538. if ( typeof controller.onCancel !== 'undefined') {
  539. controller.onCancel(data);
  540. }
  541. $(dialogId).ocdialog('close');
  542. }
  543. },
  544. {
  545. text: t('core', 'Continue'),
  546. classes: 'continue',
  547. click: function(){
  548. if ( typeof controller.onContinue !== 'undefined') {
  549. controller.onContinue($(dialogId + ' .conflict'));
  550. }
  551. $(dialogId).ocdialog('close');
  552. }
  553. }];
  554. $(dialogId).ocdialog({
  555. width: 500,
  556. closeOnEscape: true,
  557. modal: true,
  558. buttons: buttonlist,
  559. closeButton: null,
  560. close: function() {
  561. self._fileexistsshown = false;
  562. $(this).ocdialog('destroy').remove();
  563. }
  564. });
  565. $(dialogId).css('height','auto');
  566. var $primaryButton = $dlg.closest('.oc-dialog').find('button.continue');
  567. $primaryButton.prop('disabled', true);
  568. function updatePrimaryButton() {
  569. var checkedCount = $dlg.find('.conflicts .checkbox:checked').length;
  570. $primaryButton.prop('disabled', checkedCount === 0);
  571. }
  572. //add checkbox toggling actions
  573. $(dialogId).find('.allnewfiles').on('click', function() {
  574. var $checkboxes = $(dialogId).find('.conflict .replacement input[type="checkbox"]');
  575. $checkboxes.prop('checked', $(this).prop('checked'));
  576. });
  577. $(dialogId).find('.allexistingfiles').on('click', function() {
  578. var $checkboxes = $(dialogId).find('.conflict .original:not(.readonly) input[type="checkbox"]');
  579. $checkboxes.prop('checked', $(this).prop('checked'));
  580. });
  581. $(dialogId).find('.conflicts').on('click', '.replacement,.original:not(.readonly)', function() {
  582. var $checkbox = $(this).find('input[type="checkbox"]');
  583. $checkbox.prop('checked', !$checkbox.prop('checked'));
  584. });
  585. $(dialogId).find('.conflicts').on('click', '.replacement input[type="checkbox"],.original:not(.readonly) input[type="checkbox"]', function() {
  586. var $checkbox = $(this);
  587. $checkbox.prop('checked', !$checkbox.prop('checked'));
  588. });
  589. //update counters
  590. $(dialogId).on('click', '.replacement,.allnewfiles', function() {
  591. var count = $(dialogId).find('.conflict .replacement input[type="checkbox"]:checked').length;
  592. if (count === $(dialogId+ ' .conflict').length) {
  593. $(dialogId).find('.allnewfiles').prop('checked', true);
  594. $(dialogId).find('.allnewfiles + .count').text(t('core','(all selected)'));
  595. } else if (count > 0) {
  596. $(dialogId).find('.allnewfiles').prop('checked', false);
  597. $(dialogId).find('.allnewfiles + .count').text(t('core','({count} selected)',{count:count}));
  598. } else {
  599. $(dialogId).find('.allnewfiles').prop('checked', false);
  600. $(dialogId).find('.allnewfiles + .count').text('');
  601. }
  602. updatePrimaryButton();
  603. });
  604. $(dialogId).on('click', '.original,.allexistingfiles', function(){
  605. var count = $(dialogId).find('.conflict .original input[type="checkbox"]:checked').length;
  606. if (count === $(dialogId+ ' .conflict').length) {
  607. $(dialogId).find('.allexistingfiles').prop('checked', true);
  608. $(dialogId).find('.allexistingfiles + .count').text(t('core','(all selected)'));
  609. } else if (count > 0) {
  610. $(dialogId).find('.allexistingfiles').prop('checked', false);
  611. $(dialogId).find('.allexistingfiles + .count')
  612. .text(t('core','({count} selected)',{count:count}));
  613. } else {
  614. $(dialogId).find('.allexistingfiles').prop('checked', false);
  615. $(dialogId).find('.allexistingfiles + .count').text('');
  616. }
  617. updatePrimaryButton();
  618. });
  619. dialogDeferred.resolve();
  620. })
  621. .fail(function() {
  622. dialogDeferred.reject();
  623. alert(t('core', 'Error loading file exists template'));
  624. });
  625. }
  626. //}
  627. return dialogDeferred.promise();
  628. },
  629. _getFilePickerTemplate: function() {
  630. var defer = $.Deferred();
  631. if(!this.$filePickerTemplate) {
  632. var self = this;
  633. $.get(OC.filePath('core', 'templates', 'filepicker.html'), function(tmpl) {
  634. self.$filePickerTemplate = $(tmpl);
  635. self.$listTmpl = self.$filePickerTemplate.find('.filelist li:first-child').detach();
  636. defer.resolve(self.$filePickerTemplate);
  637. })
  638. .fail(function(jqXHR, textStatus, errorThrown) {
  639. defer.reject(jqXHR.status, errorThrown);
  640. });
  641. } else {
  642. defer.resolve(this.$filePickerTemplate);
  643. }
  644. return defer.promise();
  645. },
  646. _getMessageTemplate: function() {
  647. var defer = $.Deferred();
  648. if(!this.$messageTemplate) {
  649. var self = this;
  650. $.get(OC.filePath('core', 'templates', 'message.html'), function(tmpl) {
  651. self.$messageTemplate = $(tmpl);
  652. defer.resolve(self.$messageTemplate);
  653. })
  654. .fail(function(jqXHR, textStatus, errorThrown) {
  655. defer.reject(jqXHR.status, errorThrown);
  656. });
  657. } else {
  658. defer.resolve(this.$messageTemplate);
  659. }
  660. return defer.promise();
  661. },
  662. _getFileExistsTemplate: function () {
  663. var defer = $.Deferred();
  664. if (!this.$fileexistsTemplate) {
  665. var self = this;
  666. $.get(OC.filePath('files', 'templates', 'fileexists.html'), function (tmpl) {
  667. self.$fileexistsTemplate = $(tmpl);
  668. defer.resolve(self.$fileexistsTemplate);
  669. })
  670. .fail(function () {
  671. defer.reject();
  672. });
  673. } else {
  674. defer.resolve(this.$fileexistsTemplate);
  675. }
  676. return defer.promise();
  677. },
  678. _getFileList: function(dir, mimeType) {
  679. if (typeof(mimeType) === "string") {
  680. mimeType = [mimeType];
  681. }
  682. return $.getJSON(
  683. OC.filePath('files', 'ajax', 'list.php'),
  684. {
  685. dir: dir,
  686. mimetypes: JSON.stringify(mimeType)
  687. }
  688. );
  689. },
  690. /**
  691. * fills the filepicker with files
  692. */
  693. _fillFilePicker:function(dir) {
  694. var dirs = [];
  695. var others = [];
  696. var self = this;
  697. this.$filelist.empty().addClass('icon-loading');
  698. this.$filePicker.data('path', dir);
  699. $.when(this._getFileList(dir, this.$filePicker.data('mimetype'))).then(function(response) {
  700. $.each(response.data.files, function(index, file) {
  701. if (file.type === 'dir') {
  702. dirs.push(file);
  703. } else {
  704. others.push(file);
  705. }
  706. });
  707. self._fillSlug();
  708. var sorted = dirs.concat(others);
  709. $.each(sorted, function(idx, entry) {
  710. entry.icon = OC.MimeType.getIconUrl(entry.mimetype);
  711. var $li = self.$listTmpl.octemplate({
  712. type: entry.type,
  713. dir: dir,
  714. filename: entry.name,
  715. date: OC.Util.relativeModifiedDate(entry.mtime)
  716. });
  717. if (entry.type === 'file') {
  718. var urlSpec = {
  719. file: dir + '/' + entry.name
  720. };
  721. var previewUrl = OC.generateUrl('/core/preview.png?') + $.param(urlSpec);
  722. $li.find('img').attr('src', previewUrl);
  723. }
  724. else {
  725. $li.find('img').attr('src', OC.Util.replaceSVGIcon(entry.icon));
  726. }
  727. self.$filelist.append($li);
  728. });
  729. self.$filelist.removeClass('icon-loading');
  730. if (!OC.Util.hasSVGSupport()) {
  731. OC.Util.replaceSVG(self.$filePicker.find('.dirtree'));
  732. }
  733. });
  734. },
  735. /**
  736. * fills the tree list with directories
  737. */
  738. _fillSlug: function() {
  739. this.$dirTree.empty();
  740. var self = this;
  741. var path = this.$filePicker.data('path');
  742. var $template = $('<span data-dir="{dir}">{name}</span>');
  743. if(path) {
  744. var paths = path.split('/');
  745. $.each(paths, function(index, dir) {
  746. dir = paths.pop();
  747. if(dir === '') {
  748. return false;
  749. }
  750. self.$dirTree.prepend($template.octemplate({
  751. dir: paths.join('/') + '/' + dir,
  752. name: dir
  753. }));
  754. });
  755. }
  756. $template.octemplate({
  757. dir: '',
  758. name: '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;' // Ugly but works ;)
  759. }, {escapeFunction: null}).addClass('home svg').prependTo(this.$dirTree);
  760. },
  761. /**
  762. * handle selection made in the tree list
  763. */
  764. _handleTreeListSelect:function(event) {
  765. var self = event.data;
  766. var dir = $(event.target).data('dir');
  767. self._fillFilePicker(dir);
  768. },
  769. /**
  770. * handle clicks made in the filepicker
  771. */
  772. _handlePickerClick:function(event, $element) {
  773. if ($element.data('type') === 'file') {
  774. if (this.$filePicker.data('multiselect') !== true || !event.ctrlKey) {
  775. this.$filelist.find('.filepicker_element_selected').removeClass('filepicker_element_selected');
  776. }
  777. $element.toggleClass('filepicker_element_selected');
  778. } else if ( $element.data('type') === 'dir' ) {
  779. this._fillFilePicker(this.$filePicker.data('path') + '/' + $element.data('entryname'));
  780. }
  781. }
  782. };