You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

684 lines
24 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. /* global OC, Handlebars */
  2. /*
  3. * Copyright (c) 2015
  4. *
  5. * This file is licensed under the Affero General Public License version 3
  6. * or later.
  7. *
  8. * See the COPYING-README file.
  9. *
  10. */
  11. /* globals Handlebars */
  12. (function() {
  13. var PASSWORD_PLACEHOLDER = '**********';
  14. var PASSWORD_PLACEHOLDER_MESSAGE = t('core', 'Choose a password for the mail share');
  15. if (!OC.Share) {
  16. OC.Share = {};
  17. }
  18. var TEMPLATE =
  19. '<ul id="shareWithList" class="shareWithList">' +
  20. '{{#each sharees}}' +
  21. '<li data-share-id="{{shareId}}" data-share-type="{{shareType}}" data-share-with="{{shareWith}}">' +
  22. '<div class="avatar {{#if modSeed}}imageplaceholderseed{{/if}}" data-username="{{shareWith}}" data-displayname="{{shareWithDisplayName}}" {{#if modSeed}}data-seed="{{shareWith}} {{shareType}}"{{/if}}></div>' +
  23. '<span class="has-tooltip username" title="{{shareWithTitle}}">{{shareWithDisplayName}}</span>' +
  24. '<span class="sharingOptionsGroup">' +
  25. '{{#if editPermissionPossible}}' +
  26. '<span class="shareOption">' +
  27. '<input id="canEdit-{{cid}}-{{shareWith}}" type="checkbox" name="edit" class="permissions checkbox" {{#if hasEditPermission}}checked="checked"{{/if}} />' +
  28. '<label for="canEdit-{{cid}}-{{shareWith}}">{{canEditLabel}}</label>' +
  29. '</span>' +
  30. '{{/if}}' +
  31. '<a href="#"><span class="icon icon-more"></span></a>' +
  32. '{{{popoverMenu}}}' +
  33. '</span>' +
  34. '</li>' +
  35. '{{/each}}' +
  36. '{{#each linkReshares}}' +
  37. '<li data-share-id="{{shareId}}" data-share-type="{{shareType}}">' +
  38. '<div class="avatar" data-username="{{shareInitiator}}"></div>' +
  39. '<span class="has-tooltip username" title="{{shareInitiator}}">' + t('core', '{{shareInitiatorDisplayName}} shared via link') + '</span>' +
  40. '<span class="sharingOptionsGroup">' +
  41. '<a href="#" class="unshare"><span class="icon-loading-small hidden"></span><span class="icon icon-delete"></span><span class="hidden-visually">{{unshareLabel}}</span></a>' +
  42. '</span>' +
  43. '</li>' +
  44. '{{/each}}' +
  45. '</ul>'
  46. ;
  47. var TEMPLATE_POPOVER_MENU =
  48. '<div class="popovermenu bubble hidden menu">' +
  49. '<ul>' +
  50. '{{#if isResharingAllowed}} {{#if sharePermissionPossible}} {{#unless isMailShare}}' +
  51. '<li>' +
  52. '<span class="shareOption menuitem">' +
  53. '<input id="canShare-{{cid}}-{{shareWith}}" type="checkbox" name="share" class="permissions checkbox" {{#if hasSharePermission}}checked="checked"{{/if}} data-permissions="{{sharePermission}}" />' +
  54. '<label for="canShare-{{cid}}-{{shareWith}}">{{canShareLabel}}</label>' +
  55. '</span>' +
  56. '</li>' +
  57. '{{/unless}} {{/if}} {{/if}}' +
  58. '{{#if isFolder}}' +
  59. '{{#if createPermissionPossible}}{{#unless isMailShare}}' +
  60. '<li>' +
  61. '<span class="shareOption menuitem">' +
  62. '<input id="canCreate-{{cid}}-{{shareWith}}" type="checkbox" name="create" class="permissions checkbox" {{#if hasCreatePermission}}checked="checked"{{/if}} data-permissions="{{createPermission}}"/>' +
  63. '<label for="canCreate-{{cid}}-{{shareWith}}">{{createPermissionLabel}}</label>' +
  64. '</span>' +
  65. '</li>' +
  66. '{{/unless}}{{/if}}' +
  67. '{{#if updatePermissionPossible}}{{#unless isMailShare}}' +
  68. '<li>' +
  69. '<span class="shareOption menuitem">' +
  70. '<input id="canUpdate-{{cid}}-{{shareWith}}" type="checkbox" name="update" class="permissions checkbox" {{#if hasUpdatePermission}}checked="checked"{{/if}} data-permissions="{{updatePermission}}"/>' +
  71. '<label for="canUpdate-{{cid}}-{{shareWith}}">{{updatePermissionLabel}}</label>' +
  72. '</span>' +
  73. '</li>' +
  74. '{{/unless}}{{/if}}' +
  75. '{{#if deletePermissionPossible}}{{#unless isMailShare}}' +
  76. '<li>' +
  77. '<span class="shareOption menuitem">' +
  78. '<input id="canDelete-{{cid}}-{{shareWith}}" type="checkbox" name="delete" class="permissions checkbox" {{#if hasDeletePermission}}checked="checked"{{/if}} data-permissions="{{deletePermission}}"/>' +
  79. '<label for="canDelete-{{cid}}-{{shareWith}}">{{deletePermissionLabel}}</label>' +
  80. '</span>' +
  81. '</li>' +
  82. '{{/unless}}{{/if}}' +
  83. '{{/if}}' +
  84. '{{#if isMailShare}}' +
  85. '{{#if hasCreatePermission}}' +
  86. '<li>' +
  87. '<span class="shareOption menuitem">' +
  88. '<input id="secureDrop-{{cid}}-{{shareId}}" type="checkbox" name="secureDrop" class="checkbox secureDrop" {{#if secureDropMode}}checked="checked"{{/if}} data-permissions="{{readPermission}}"/>' +
  89. '<label for="secureDrop-{{cid}}-{{shareId}}">{{secureDropLabel}}</label>' +
  90. '</span>' +
  91. '</li>' +
  92. '{{/if}}' +
  93. '<li>' +
  94. '<span class="shareOption menuitem">' +
  95. '<input id="password-{{cid}}-{{shareId}}" type="checkbox" name="password" class="password checkbox" {{#if isPasswordSet}}checked="checked"{{/if}}{{#if isPasswordSet}}{{#if isPasswordForMailSharesRequired}}disabled=""{{/if}}{{/if}}" />' +
  96. '<label for="password-{{cid}}-{{shareId}}">{{passwordLabel}}</label>' +
  97. '<div class="passwordContainer-{{cid}}-{{shareId}} {{#unless isPasswordSet}}hidden{{/unless}}">' +
  98. ' <label for="passwordField-{{cid}}-{{shareId}}" class="hidden-visually" value="{{password}}">{{passwordLabel}}</label>' +
  99. ' <input id="passwordField-{{cid}}-{{shareId}}" class="passwordField" type="password" placeholder="{{passwordPlaceholder}}" value="{{passwordValue}}" />' +
  100. ' <span class="icon-loading-small hidden"></span>' +
  101. '</div>' +
  102. '</span>' +
  103. '</li>' +
  104. '{{/if}}' +
  105. '<li>' +
  106. '<span class="shareOption menuitem">' +
  107. '<input id="expireDate-{{cid}}-{{shareId}}" type="checkbox" name="expirationDate" class="expireDate checkbox" {{#if hasExpireDate}}checked="checked"{{/if}}" />' +
  108. '<label for="expireDate-{{cid}}-{{shareId}}">{{expireDateLabel}}</label>' +
  109. '<div class="expirationDateContainer-{{cid}}-{{shareId}} {{#unless hasExpireDate}}hidden{{/unless}}">' +
  110. ' <label for="expirationDatePicker-{{cid}}-{{shareId}}" class="hidden-visually" value="{{expirationDate}}">{{expirationLabel}}</label>' +
  111. ' <input id="expirationDatePicker-{{cid}}-{{shareId}}" class="datepicker" type="text" placeholder="{{expirationDatePlaceholder}}" value="{{expireDate}}" />' +
  112. '</div>' +
  113. '</span>' +
  114. '</li>' +
  115. '<li>' +
  116. '<a href="#" class="unshare"><span class="icon-loading-small hidden"></span><span class="icon icon-delete"></span><span>{{unshareLabel}}</span></a>' +
  117. '</li>' +
  118. '</ul>' +
  119. '</div>';
  120. /**
  121. * @class OCA.Share.ShareDialogShareeListView
  122. * @member {OC.Share.ShareItemModel} model
  123. * @member {jQuery} $el
  124. * @memberof OCA.Sharing
  125. * @classdesc
  126. *
  127. * Represents the sharee list part in the GUI of the share dialogue
  128. *
  129. */
  130. var ShareDialogShareeListView = OC.Backbone.View.extend({
  131. /** @type {string} **/
  132. id: 'shareDialogLinkShare',
  133. /** @type {OC.Share.ShareConfigModel} **/
  134. configModel: undefined,
  135. /** @type {Function} **/
  136. _template: undefined,
  137. /** @type {Function} **/
  138. _popoverMenuTemplate: undefined,
  139. _menuOpen: false,
  140. /** @type {boolean|number} **/
  141. _renderPermissionChange: false,
  142. events: {
  143. 'click .unshare': 'onUnshare',
  144. 'click .icon-more': 'onToggleMenu',
  145. 'click .permissions': 'onPermissionChange',
  146. 'click .expireDate' : 'onExpireDateChange',
  147. 'click .password' : 'onMailSharePasswordProtectChange',
  148. 'click .secureDrop' : 'onSecureDropChange',
  149. 'keyup input.passwordField': 'onMailSharePasswordKeyUp',
  150. 'focusout input.passwordField': 'onMailSharePasswordEntered',
  151. 'change .datepicker': 'onChangeExpirationDate',
  152. 'click .datepicker' : 'showDatePicker'
  153. },
  154. initialize: function(options) {
  155. if(!_.isUndefined(options.configModel)) {
  156. this.configModel = options.configModel;
  157. } else {
  158. throw 'missing OC.Share.ShareConfigModel';
  159. }
  160. var view = this;
  161. this.model.on('change:shares', function() {
  162. view.render();
  163. });
  164. },
  165. /**
  166. *
  167. * @param {OC.Share.Types.ShareInfo} shareInfo
  168. * @returns {object}
  169. */
  170. getShareeObject: function(shareIndex) {
  171. var shareWith = this.model.getShareWith(shareIndex);
  172. var shareWithDisplayName = this.model.getShareWithDisplayName(shareIndex);
  173. var shareWithTitle = '';
  174. var shareType = this.model.getShareType(shareIndex);
  175. var sharedBy = this.model.getSharedBy(shareIndex);
  176. var sharedByDisplayName = this.model.getSharedByDisplayName(shareIndex);
  177. var hasPermissionOverride = {};
  178. if (shareType === OC.Share.SHARE_TYPE_GROUP) {
  179. shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'group') + ')';
  180. } else if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
  181. shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'remote') + ')';
  182. } else if (shareType === OC.Share.SHARE_TYPE_EMAIL) {
  183. shareWithDisplayName = shareWithDisplayName + " (" + t('core', 'email') + ')';
  184. } else if (shareType === OC.Share.SHARE_TYPE_CIRCLE) {
  185. }
  186. if (shareType === OC.Share.SHARE_TYPE_GROUP) {
  187. shareWithTitle = shareWith + " (" + t('core', 'group') + ')';
  188. } else if (shareType === OC.Share.SHARE_TYPE_REMOTE) {
  189. shareWithTitle = shareWith + " (" + t('core', 'remote') + ')';
  190. } else if (shareType === OC.Share.SHARE_TYPE_EMAIL) {
  191. shareWithTitle = shareWith + " (" + t('core', 'email') + ')';
  192. } else if (shareType === OC.Share.SHARE_TYPE_CIRCLE) {
  193. shareWithTitle = shareWith;
  194. }
  195. if (sharedBy !== oc_current_user) {
  196. var empty = shareWithTitle === '';
  197. if (!empty) {
  198. shareWithTitle += ' (';
  199. }
  200. shareWithTitle += t('core', 'shared by {sharer}', {sharer: sharedByDisplayName});
  201. if (!empty) {
  202. shareWithTitle += ')';
  203. }
  204. }
  205. var share = this.model.get('shares')[shareIndex];
  206. var password = share.password;
  207. var hasPassword = password !== null && password !== '';
  208. return _.extend(hasPermissionOverride, {
  209. cid: this.cid,
  210. hasSharePermission: this.model.hasSharePermission(shareIndex),
  211. hasEditPermission: this.model.hasEditPermission(shareIndex),
  212. hasCreatePermission: this.model.hasCreatePermission(shareIndex),
  213. hasUpdatePermission: this.model.hasUpdatePermission(shareIndex),
  214. hasDeletePermission: this.model.hasDeletePermission(shareIndex),
  215. shareWith: shareWith,
  216. shareWithDisplayName: shareWithDisplayName,
  217. shareWithTitle: shareWithTitle,
  218. shareType: shareType,
  219. shareId: this.model.get('shares')[shareIndex].id,
  220. modSeed: shareType !== OC.Share.SHARE_TYPE_USER,
  221. isRemoteShare: shareType === OC.Share.SHARE_TYPE_REMOTE,
  222. isMailShare: shareType === OC.Share.SHARE_TYPE_EMAIL,
  223. isCircleShare: shareType === OC.Share.SHARE_TYPE_CIRCLE,
  224. isFileSharedByMail: shareType === OC.Share.SHARE_TYPE_EMAIL && !this.model.isFolder(),
  225. isPasswordSet: hasPassword,
  226. secureDropMode: !this.model.hasReadPermission(shareIndex),
  227. hasExpireDate: this.model.getExpireDate(shareIndex) !== null,
  228. expireDate: moment(this.model.getExpireDate(shareIndex), 'YYYY-MM-DD').format('DD-MM-YYYY'),
  229. passwordPlaceholder: hasPassword ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE,
  230. });
  231. },
  232. getShareProperties: function() {
  233. return {
  234. unshareLabel: t('core', 'Unshare'),
  235. canShareLabel: t('core', 'Can reshare'),
  236. canEditLabel: t('core', 'Can edit'),
  237. createPermissionLabel: t('core', 'Can create'),
  238. updatePermissionLabel: t('core', 'Can change'),
  239. deletePermissionLabel: t('core', 'Can delete'),
  240. secureDropLabel: t('core', 'Secure drop (upload only)'),
  241. expireDateLabel: t('core', 'Set expiration date'),
  242. passwordLabel: t('core', 'Password protect'),
  243. crudsLabel: t('core', 'Access control'),
  244. triangleSImage: OC.imagePath('core', 'actions/triangle-s'),
  245. isResharingAllowed: this.configModel.get('isResharingAllowed'),
  246. isPasswordForMailSharesRequired: this.configModel.get('isPasswordForMailSharesRequired'),
  247. sharePermissionPossible: this.model.sharePermissionPossible(),
  248. editPermissionPossible: this.model.editPermissionPossible(),
  249. createPermissionPossible: this.model.createPermissionPossible(),
  250. updatePermissionPossible: this.model.updatePermissionPossible(),
  251. deletePermissionPossible: this.model.deletePermissionPossible(),
  252. sharePermission: OC.PERMISSION_SHARE,
  253. createPermission: OC.PERMISSION_CREATE,
  254. updatePermission: OC.PERMISSION_UPDATE,
  255. deletePermission: OC.PERMISSION_DELETE,
  256. readPermission: OC.PERMISSION_READ,
  257. isFolder: this.model.isFolder()
  258. };
  259. },
  260. /**
  261. * get an array of sharees' share properties
  262. *
  263. * @returns {Array}
  264. */
  265. getShareeList: function() {
  266. var universal = this.getShareProperties();
  267. if(!this.model.hasUserShares()) {
  268. return [];
  269. }
  270. var shares = this.model.get('shares');
  271. var list = [];
  272. for(var index = 0; index < shares.length; index++) {
  273. var share = this.getShareeObject(index);
  274. if (share.shareType === OC.Share.SHARE_TYPE_LINK) {
  275. continue;
  276. }
  277. // first empty {} is necessary, otherwise we get in trouble
  278. // with references
  279. list.push(_.extend({}, universal, share));
  280. }
  281. return list;
  282. },
  283. getLinkReshares: function() {
  284. var universal = {
  285. unshareLabel: t('core', 'Unshare'),
  286. };
  287. if(!this.model.hasUserShares()) {
  288. return [];
  289. }
  290. var shares = this.model.get('shares');
  291. var list = [];
  292. for(var index = 0; index < shares.length; index++) {
  293. var share = this.getShareeObject(index);
  294. if (share.shareType !== OC.Share.SHARE_TYPE_LINK) {
  295. continue;
  296. }
  297. // first empty {} is necessary, otherwise we get in trouble
  298. // with references
  299. list.push(_.extend({}, universal, share, {
  300. shareInitiator: shares[index].uid_owner,
  301. shareInitiatorDisplayName: shares[index].displayname_owner
  302. }));
  303. }
  304. return list;
  305. },
  306. render: function() {
  307. if(!this._renderPermissionChange) {
  308. this.$el.html(this.template({
  309. cid: this.cid,
  310. sharees: this.getShareeList(),
  311. linkReshares: this.getLinkReshares()
  312. }));
  313. this.$('.avatar').each(function () {
  314. var $this = $(this);
  315. if ($this.hasClass('imageplaceholderseed')) {
  316. $this.css({width: 32, height: 32});
  317. $this.imageplaceholder($this.data('seed'));
  318. } else {
  319. // user, size, ie8fix, hidedefault, callback, displayname
  320. $this.avatar($this.data('username'), 32, undefined, undefined, undefined, $this.data('displayname'));
  321. }
  322. });
  323. this.$('.has-tooltip').tooltip({
  324. placement: 'bottom'
  325. });
  326. } else {
  327. var permissionChangeShareId = parseInt(this._renderPermissionChange, 10);
  328. var shareWithIndex = this.model.findShareWithIndex(permissionChangeShareId);
  329. var sharee = this.getShareeObject(shareWithIndex);
  330. $.extend(sharee, this.getShareProperties());
  331. var $li = this.$('li[data-share-id=' + permissionChangeShareId + ']');
  332. $li.find('.popovermenu').replaceWith(this.popoverMenuTemplate(sharee));
  333. var checkBoxId = 'canEdit-' + this.cid + '-' + sharee.shareWith;
  334. checkBoxId = '#' + checkBoxId.replace( /(:|\.|\[|\]|,|=|@)/g, "\\$1");
  335. var $edit = $li.parent().find(checkBoxId);
  336. if($edit.length === 1) {
  337. $edit.prop('checked', sharee.hasEditPermission);
  338. }
  339. }
  340. var _this = this;
  341. this.$('.popovermenu').on('afterHide', function() {
  342. _this._menuOpen = false;
  343. });
  344. this.$('.popovermenu').on('beforeHide', function() {
  345. var shareId = parseInt(_this._menuOpen, 10);
  346. if(!_.isNaN(shareId)) {
  347. var datePickerClass = '.expirationDateContainer-' + _this.cid + '-' + shareId;
  348. var datePickerInput = '#expirationDatePicker-' + _this.cid + '-' + shareId;
  349. var expireDateCheckbox = '#expireDate-' + _this.cid + '-' + shareId;
  350. if ($(expireDateCheckbox).prop('checked')) {
  351. $(datePickerInput).removeClass('hidden-visually');
  352. $(datePickerClass).removeClass('hasDatepicker');
  353. $(datePickerClass + ' .ui-datepicker').hide();
  354. }
  355. }
  356. });
  357. if (this._menuOpen != false) {
  358. // Open menu again if it was opened before
  359. var shareId = parseInt(this._menuOpen, 10);
  360. if(!_.isNaN(shareId)) {
  361. var liSelector = 'li[data-share-id=' + shareId + ']';
  362. OC.showMenu(null, this.$(liSelector + ' .popovermenu'));
  363. }
  364. }
  365. this._renderPermissionChange = false;
  366. this.delegateEvents();
  367. return this;
  368. },
  369. /**
  370. * @returns {Function} from Handlebars
  371. * @private
  372. */
  373. template: function (data) {
  374. if (!this._template) {
  375. this._template = Handlebars.compile(TEMPLATE);
  376. }
  377. var sharees = data.sharees;
  378. if(_.isArray(sharees)) {
  379. for (var i = 0; i < sharees.length; i++) {
  380. data.sharees[i].popoverMenu = this.popoverMenuTemplate(sharees[i]);
  381. }
  382. }
  383. return this._template(data);
  384. },
  385. /**
  386. * renders the popover template and returns the resulting HTML
  387. *
  388. * @param {Object} data
  389. * @returns {string}
  390. */
  391. popoverMenuTemplate: function(data) {
  392. if(!this._popoverMenuTemplate) {
  393. this._popoverMenuTemplate = Handlebars.compile(TEMPLATE_POPOVER_MENU);
  394. }
  395. return this._popoverMenuTemplate(data);
  396. },
  397. onUnshare: function(event) {
  398. event.preventDefault();
  399. event.stopPropagation();
  400. var self = this;
  401. var $element = $(event.target);
  402. if (!$element.is('a')) {
  403. $element = $element.closest('a');
  404. }
  405. var $loading = $element.find('.icon-loading-small').eq(0);
  406. if(!$loading.hasClass('hidden')) {
  407. // in process
  408. return false;
  409. }
  410. $loading.removeClass('hidden');
  411. var $li = $element.closest('li[data-share-id]');
  412. var shareId = $li.data('share-id');
  413. self.model.removeShare(shareId)
  414. .done(function() {
  415. $li.remove();
  416. })
  417. .fail(function() {
  418. $loading.addClass('hidden');
  419. OC.Notification.showTemporary(t('core', 'Could not unshare'));
  420. });
  421. return false;
  422. },
  423. onToggleMenu: function(event) {
  424. event.preventDefault();
  425. event.stopPropagation();
  426. var $element = $(event.target);
  427. var $li = $element.closest('li[data-share-id]');
  428. var $menu = $li.find('.popovermenu');
  429. OC.showMenu(null, $menu);
  430. this._menuOpen = $li.data('share-id');
  431. },
  432. onExpireDateChange: function(event) {
  433. var element = $(event.target);
  434. var li = element.closest('li[data-share-id]');
  435. var shareId = li.data('share-id');
  436. var datePickerClass = '.expirationDateContainer-' + this.cid + '-' + shareId;
  437. var datePicker = $(datePickerClass);
  438. var state = element.prop('checked');
  439. datePicker.toggleClass('hidden', !state);
  440. if (!state) {
  441. this.setExpirationDate(shareId, '');
  442. } else {
  443. this.showDatePicker(event);
  444. }
  445. },
  446. showDatePicker: function(event) {
  447. var element = $(event.target);
  448. var li = element.closest('li[data-share-id]');
  449. var shareId = li.data('share-id');
  450. var expirationDatePicker = '#expirationDatePicker-' + this.cid + '-' + shareId;
  451. var view = this;
  452. $(expirationDatePicker).closest('div').datepicker({
  453. dateFormat : 'dd-mm-yy',
  454. onSelect:
  455. function (expireDate) {
  456. view.setExpirationDate(shareId, expireDate);
  457. },
  458. onClose:
  459. function () {
  460. $(expirationDatePicker).removeClass('hidden-visually');
  461. }
  462. });
  463. $(expirationDatePicker).addClass('hidden-visually');
  464. },
  465. setExpirationDate: function(shareId, expireDate) {
  466. this.model.updateShare(shareId, {expireDate: expireDate}, {});
  467. },
  468. onMailSharePasswordProtectChange: function(event) {
  469. var element = $(event.target);
  470. var li = element.closest('li[data-share-id]');
  471. var shareId = li.data('share-id');
  472. var passwordContainerClass = '.passwordContainer-' + this.cid + '-' + shareId;
  473. var passwordContainer = $(passwordContainerClass);
  474. var loading = this.$el.find(passwordContainerClass + ' .icon-loading-small');
  475. var inputClass = '#passwordField-' + this.cid + '-' + shareId;
  476. var passwordField = $(inputClass);
  477. var state = element.prop('checked');
  478. if (!state) {
  479. this.model.updateShare(shareId, {password: ''});
  480. passwordField.attr('value', '');
  481. passwordField.removeClass('error');
  482. passwordField.tooltip('hide');
  483. loading.addClass('hidden');
  484. passwordField.attr('placeholder', PASSWORD_PLACEHOLDER_MESSAGE);
  485. // We first need to reset the password field before we hide it
  486. passwordContainer.toggleClass('hidden', !state);
  487. } else {
  488. passwordContainer.toggleClass('hidden', !state);
  489. passwordField = '#passwordField-' + this.cid + '-' + shareId;
  490. this.$(passwordField).focus();
  491. }
  492. },
  493. onMailSharePasswordKeyUp: function(event) {
  494. if(event.keyCode === 13) {
  495. this.onMailSharePasswordEntered(event);
  496. }
  497. },
  498. onMailSharePasswordEntered: function(event) {
  499. var passwordField = $(event.target);
  500. var li = passwordField.closest('li[data-share-id]');
  501. var shareId = li.data('share-id');
  502. var passwordContainerClass = '.passwordContainer-' + this.cid + '-' + shareId;
  503. var loading = this.$el.find(passwordContainerClass + ' .icon-loading-small');
  504. if (!loading.hasClass('hidden')) {
  505. // still in process
  506. return;
  507. }
  508. passwordField.removeClass('error');
  509. var password = passwordField.val();
  510. // in IE9 the password might be the placeholder due to bugs in the placeholders polyfill
  511. if(password === '' || password === PASSWORD_PLACEHOLDER || password === PASSWORD_PLACEHOLDER_MESSAGE) {
  512. return;
  513. }
  514. loading
  515. .removeClass('hidden')
  516. .addClass('inlineblock');
  517. this.model.updateShare(shareId, {
  518. password: password
  519. }, {
  520. error: function(model, msg) {
  521. // destroy old tooltips
  522. passwordField.tooltip('destroy');
  523. loading.removeClass('inlineblock').addClass('hidden');
  524. passwordField.addClass('error');
  525. passwordField.attr('title', msg);
  526. passwordField.tooltip({placement: 'bottom', trigger: 'manual'});
  527. passwordField.tooltip('show');
  528. },
  529. success: function(model, msg) {
  530. passwordField.blur();
  531. passwordField.attr('value', '');
  532. passwordField.attr('placeholder', PASSWORD_PLACEHOLDER);
  533. loading.removeClass('inlineblock').addClass('hidden');
  534. }
  535. });
  536. },
  537. onPermissionChange: function(event) {
  538. event.preventDefault();
  539. event.stopPropagation();
  540. var $element = $(event.target);
  541. var $li = $element.closest('li[data-share-id]');
  542. var shareId = $li.data('share-id');
  543. var permissions = OC.PERMISSION_READ;
  544. if (this.model.isFolder()) {
  545. // adjust checkbox states
  546. var $checkboxes = $('.permissions', $li).not('input[name="edit"]').not('input[name="share"]');
  547. var checked;
  548. if ($element.attr('name') === 'edit') {
  549. checked = $element.is(':checked');
  550. // Check/uncheck Create, Update, and Delete checkboxes if Edit is checked/unck
  551. $($checkboxes).prop('checked', checked);
  552. if (checked) {
  553. permissions |= OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_DELETE;
  554. }
  555. } else {
  556. var numberChecked = $checkboxes.filter(':checked').length;
  557. checked = numberChecked > 0;
  558. $('input[name="edit"]', $li).prop('checked', checked);
  559. }
  560. } else {
  561. if ($element.attr('name') === 'edit' && $element.is(':checked')) {
  562. permissions |= OC.PERMISSION_UPDATE;
  563. }
  564. }
  565. $('.permissions', $li).not('input[name="edit"]').filter(':checked').each(function(index, checkbox) {
  566. permissions |= $(checkbox).data('permissions');
  567. });
  568. /** disable checkboxes during save operation to avoid race conditions **/
  569. $li.find('input[type=checkbox]').prop('disabled', true);
  570. var enableCb = function() {
  571. $li.find('input[type=checkbox]').prop('disabled', false);
  572. };
  573. var errorCb = function(elem, msg) {
  574. OC.dialogs.alert(msg, t('core', 'Error while sharing'));
  575. enableCb();
  576. };
  577. this.model.updateShare(shareId, {permissions: permissions}, {error: errorCb, success: enableCb});
  578. this._renderPermissionChange = shareId;
  579. },
  580. onSecureDropChange: function(event) {
  581. event.preventDefault();
  582. event.stopPropagation();
  583. var $element = $(event.target);
  584. var $li = $element.closest('li[data-share-id]');
  585. var shareId = $li.data('share-id');
  586. var permissions = OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_DELETE | OC.PERMISSION_READ;
  587. if ($element.is(':checked')) {
  588. permissions = OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_DELETE;
  589. }
  590. /** disable checkboxes during save operation to avoid race conditions **/
  591. $li.find('input[type=checkbox]').prop('disabled', true);
  592. var enableCb = function() {
  593. $li.find('input[type=checkbox]').prop('disabled', false);
  594. };
  595. var errorCb = function(elem, msg) {
  596. OC.dialogs.alert(msg, t('core', 'Error while sharing'));
  597. enableCb();
  598. };
  599. this.model.updateShare(shareId, {permissions: permissions}, {error: errorCb, success: enableCb});
  600. this._renderPermissionChange = shareId;
  601. }
  602. });
  603. OC.Share.ShareDialogShareeListView = ShareDialogShareeListView;
  604. })();