sharedialogshareelistview.js 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692
  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="username" title="{{shareWithTitle}}">{{shareWithDisplayName}}</span>' +
  24. '<span class="sharingOptionsGroup">' +
  25. '{{#if editPermissionPossible}}' +
  26. '<span class="shareOption">' +
  27. '<input id="canEdit-{{cid}}-{{shareId}}" type="checkbox" name="edit" class="permissions checkbox" />' +
  28. '<label for="canEdit-{{cid}}-{{shareId}}">{{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}}-{{shareId}}" type="checkbox" name="share" class="permissions checkbox" {{#if hasSharePermission}}checked="checked"{{/if}} data-permissions="{{sharePermission}}" />' +
  54. '<label for="canShare-{{cid}}-{{shareId}}">{{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}}-{{shareId}}" type="checkbox" name="create" class="permissions checkbox" {{#if hasCreatePermission}}checked="checked"{{/if}} data-permissions="{{createPermission}}"/>' +
  63. '<label for="canCreate-{{cid}}-{{shareId}}">{{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}}-{{shareId}}" type="checkbox" name="update" class="permissions checkbox" {{#if hasUpdatePermission}}checked="checked"{{/if}} data-permissions="{{updatePermission}}"/>' +
  71. '<label for="canUpdate-{{cid}}-{{shareId}}">{{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}}-{{shareId}}" type="checkbox" name="delete" class="permissions checkbox" {{#if hasDeletePermission}}checked="checked"{{/if}} data-permissions="{{deletePermission}}"/>' +
  79. '<label for="canDelete-{{cid}}-{{shareId}}">{{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}}" autocomplete="new-password" />' +
  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="{{#if hasExpireDate}}{{expireDate}}{{else}}{{defaultExpireDate}}{{/if}}" />' +
  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. editPermissionState: this.model.editPermissionState(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 && shareType !== OC.Share.SHARE_TYPE_CIRCLE,
  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', 'File drop (upload only)'),
  241. expireDateLabel: t('core', 'Set expiration date'),
  242. passwordLabel: t('core', 'Password protect'),
  243. crudsLabel: t('core', 'Access control'),
  244. expirationDatePlaceholder: t('core', 'Expiration date'),
  245. defaultExpireDate: moment().add(1, 'day').format('DD-MM-YYYY'), // Can't expire today
  246. triangleSImage: OC.imagePath('core', 'actions/triangle-s'),
  247. isResharingAllowed: this.configModel.get('isResharingAllowed'),
  248. isPasswordForMailSharesRequired: this.configModel.get('isPasswordForMailSharesRequired'),
  249. sharePermissionPossible: this.model.sharePermissionPossible(),
  250. editPermissionPossible: this.model.editPermissionPossible(),
  251. createPermissionPossible: this.model.createPermissionPossible(),
  252. updatePermissionPossible: this.model.updatePermissionPossible(),
  253. deletePermissionPossible: this.model.deletePermissionPossible(),
  254. sharePermission: OC.PERMISSION_SHARE,
  255. createPermission: OC.PERMISSION_CREATE,
  256. updatePermission: OC.PERMISSION_UPDATE,
  257. deletePermission: OC.PERMISSION_DELETE,
  258. readPermission: OC.PERMISSION_READ,
  259. isFolder: this.model.isFolder()
  260. };
  261. },
  262. /**
  263. * get an array of sharees' share properties
  264. *
  265. * @returns {Array}
  266. */
  267. getShareeList: function() {
  268. var universal = this.getShareProperties();
  269. if(!this.model.hasUserShares()) {
  270. return [];
  271. }
  272. var shares = this.model.get('shares');
  273. var list = [];
  274. for(var index = 0; index < shares.length; index++) {
  275. var share = this.getShareeObject(index);
  276. if (share.shareType === OC.Share.SHARE_TYPE_LINK) {
  277. continue;
  278. }
  279. // first empty {} is necessary, otherwise we get in trouble
  280. // with references
  281. list.push(_.extend({}, universal, share));
  282. }
  283. return list;
  284. },
  285. getLinkReshares: function() {
  286. var universal = {
  287. unshareLabel: t('core', 'Unshare'),
  288. };
  289. if(!this.model.hasUserShares()) {
  290. return [];
  291. }
  292. var shares = this.model.get('shares');
  293. var list = [];
  294. for(var index = 0; index < shares.length; index++) {
  295. var share = this.getShareeObject(index);
  296. if (share.shareType !== OC.Share.SHARE_TYPE_LINK) {
  297. continue;
  298. }
  299. // first empty {} is necessary, otherwise we get in trouble
  300. // with references
  301. list.push(_.extend({}, universal, share, {
  302. shareInitiator: shares[index].uid_owner,
  303. shareInitiatorDisplayName: shares[index].displayname_owner
  304. }));
  305. }
  306. return list;
  307. },
  308. render: function() {
  309. if(!this._renderPermissionChange) {
  310. this.$el.html(this.template({
  311. cid: this.cid,
  312. sharees: this.getShareeList(),
  313. linkReshares: this.getLinkReshares()
  314. }));
  315. this.$('.avatar').each(function () {
  316. var $this = $(this);
  317. if ($this.hasClass('imageplaceholderseed')) {
  318. $this.css({width: 32, height: 32});
  319. $this.imageplaceholder($this.data('seed'));
  320. } else {
  321. // user, size, ie8fix, hidedefault, callback, displayname
  322. $this.avatar($this.data('username'), 32, undefined, undefined, undefined, $this.data('displayname'));
  323. }
  324. });
  325. this.$('.has-tooltip').tooltip({
  326. placement: 'bottom'
  327. });
  328. this.$('ul.shareWithList > li').each(function() {
  329. var $this = $(this);
  330. var shareWith = $this.data('share-with');
  331. var shareType = $this.data('share-type');
  332. $this.find('div.avatar, span.username').contactsMenu(shareWith, shareType, $this);
  333. });
  334. } else {
  335. var permissionChangeShareId = parseInt(this._renderPermissionChange, 10);
  336. var shareWithIndex = this.model.findShareWithIndex(permissionChangeShareId);
  337. var sharee = this.getShareeObject(shareWithIndex);
  338. $.extend(sharee, this.getShareProperties());
  339. var $li = this.$('li[data-share-id=' + permissionChangeShareId + ']');
  340. $li.find('.sharingOptionsGroup .popovermenu').replaceWith(this.popoverMenuTemplate(sharee));
  341. }
  342. var _this = this;
  343. this.getShareeList().forEach(function(sharee) {
  344. var $edit = _this.$('#canEdit-' + _this.cid + '-' + sharee.shareId);
  345. if($edit.length === 1) {
  346. $edit.prop('checked', sharee.editPermissionState === 'checked');
  347. $edit.prop('indeterminate', sharee.editPermissionState === 'indeterminate');
  348. }
  349. });
  350. this.$('.popovermenu').on('afterHide', function() {
  351. _this._menuOpen = false;
  352. });
  353. this.$('.popovermenu').on('beforeHide', function() {
  354. var shareId = parseInt(_this._menuOpen, 10);
  355. if(!_.isNaN(shareId)) {
  356. var datePickerClass = '.expirationDateContainer-' + _this.cid + '-' + shareId;
  357. var datePickerInput = '#expirationDatePicker-' + _this.cid + '-' + shareId;
  358. var expireDateCheckbox = '#expireDate-' + _this.cid + '-' + shareId;
  359. if ($(expireDateCheckbox).prop('checked')) {
  360. $(datePickerInput).removeClass('hidden-visually');
  361. $(datePickerClass).removeClass('hasDatepicker');
  362. $(datePickerClass + ' .ui-datepicker').hide();
  363. }
  364. }
  365. });
  366. if (this._menuOpen !== false) {
  367. // Open menu again if it was opened before
  368. var shareId = parseInt(this._menuOpen, 10);
  369. if(!_.isNaN(shareId)) {
  370. var liSelector = 'li[data-share-id=' + shareId + ']';
  371. OC.showMenu(null, this.$(liSelector + ' .sharingOptionsGroup .popovermenu'));
  372. }
  373. }
  374. this._renderPermissionChange = false;
  375. this.delegateEvents();
  376. return this;
  377. },
  378. /**
  379. * @returns {Function} from Handlebars
  380. * @private
  381. */
  382. template: function (data) {
  383. if (!this._template) {
  384. this._template = Handlebars.compile(TEMPLATE);
  385. }
  386. var sharees = data.sharees;
  387. if(_.isArray(sharees)) {
  388. for (var i = 0; i < sharees.length; i++) {
  389. data.sharees[i].popoverMenu = this.popoverMenuTemplate(sharees[i]);
  390. }
  391. }
  392. return this._template(data);
  393. },
  394. /**
  395. * renders the popover template and returns the resulting HTML
  396. *
  397. * @param {Object} data
  398. * @returns {string}
  399. */
  400. popoverMenuTemplate: function(data) {
  401. if(!this._popoverMenuTemplate) {
  402. this._popoverMenuTemplate = Handlebars.compile(TEMPLATE_POPOVER_MENU);
  403. }
  404. return this._popoverMenuTemplate(data);
  405. },
  406. onUnshare: function(event) {
  407. event.preventDefault();
  408. event.stopPropagation();
  409. var self = this;
  410. var $element = $(event.target);
  411. if (!$element.is('a')) {
  412. $element = $element.closest('a');
  413. }
  414. var $loading = $element.find('.icon-loading-small').eq(0);
  415. if(!$loading.hasClass('hidden')) {
  416. // in process
  417. return false;
  418. }
  419. $loading.removeClass('hidden');
  420. var $li = $element.closest('li[data-share-id]');
  421. var shareId = $li.data('share-id');
  422. self.model.removeShare(shareId)
  423. .done(function() {
  424. $li.remove();
  425. })
  426. .fail(function() {
  427. $loading.addClass('hidden');
  428. OC.Notification.showTemporary(t('core', 'Could not unshare'));
  429. });
  430. return false;
  431. },
  432. onToggleMenu: function(event) {
  433. event.preventDefault();
  434. event.stopPropagation();
  435. var $element = $(event.target);
  436. var $li = $element.closest('li[data-share-id]');
  437. var $menu = $li.find('.sharingOptionsGroup .popovermenu');
  438. OC.showMenu(null, $menu);
  439. this._menuOpen = $li.data('share-id');
  440. },
  441. onExpireDateChange: function(event) {
  442. var element = $(event.target);
  443. var li = element.closest('li[data-share-id]');
  444. var shareId = li.data('share-id');
  445. var datePickerClass = '.expirationDateContainer-' + this.cid + '-' + shareId;
  446. var datePicker = $(datePickerClass);
  447. var state = element.prop('checked');
  448. datePicker.toggleClass('hidden', !state);
  449. if (!state) {
  450. this.setExpirationDate(shareId, '');
  451. } else {
  452. this.showDatePicker(event);
  453. }
  454. },
  455. showDatePicker: function(event) {
  456. var element = $(event.target);
  457. var li = element.closest('li[data-share-id]');
  458. var shareId = li.data('share-id');
  459. var expirationDatePicker = '#expirationDatePicker-' + this.cid + '-' + shareId;
  460. var view = this;
  461. $(expirationDatePicker).datepicker({
  462. dateFormat : 'dd-mm-yy',
  463. onSelect: function (expireDate) {
  464. view.setExpirationDate(shareId, expireDate);
  465. }
  466. });
  467. $(expirationDatePicker).focus();
  468. },
  469. setExpirationDate: function(shareId, expireDate) {
  470. this.model.updateShare(shareId, {expireDate: expireDate}, {});
  471. },
  472. onMailSharePasswordProtectChange: function(event) {
  473. var element = $(event.target);
  474. var li = element.closest('li[data-share-id]');
  475. var shareId = li.data('share-id');
  476. var passwordContainerClass = '.passwordContainer-' + this.cid + '-' + shareId;
  477. var passwordContainer = $(passwordContainerClass);
  478. var loading = this.$el.find(passwordContainerClass + ' .icon-loading-small');
  479. var inputClass = '#passwordField-' + this.cid + '-' + shareId;
  480. var passwordField = $(inputClass);
  481. var state = element.prop('checked');
  482. if (!state) {
  483. this.model.updateShare(shareId, {password: ''});
  484. passwordField.attr('value', '');
  485. passwordField.removeClass('error');
  486. passwordField.tooltip('hide');
  487. loading.addClass('hidden');
  488. passwordField.attr('placeholder', PASSWORD_PLACEHOLDER_MESSAGE);
  489. // We first need to reset the password field before we hide it
  490. passwordContainer.toggleClass('hidden', !state);
  491. } else {
  492. passwordContainer.toggleClass('hidden', !state);
  493. passwordField = '#passwordField-' + this.cid + '-' + shareId;
  494. this.$(passwordField).focus();
  495. }
  496. },
  497. onMailSharePasswordKeyUp: function(event) {
  498. if(event.keyCode === 13) {
  499. this.onMailSharePasswordEntered(event);
  500. }
  501. },
  502. onMailSharePasswordEntered: function(event) {
  503. var passwordField = $(event.target);
  504. var li = passwordField.closest('li[data-share-id]');
  505. var shareId = li.data('share-id');
  506. var passwordContainerClass = '.passwordContainer-' + this.cid + '-' + shareId;
  507. var loading = this.$el.find(passwordContainerClass + ' .icon-loading-small');
  508. if (!loading.hasClass('hidden')) {
  509. // still in process
  510. return;
  511. }
  512. passwordField.removeClass('error');
  513. var password = passwordField.val();
  514. // in IE9 the password might be the placeholder due to bugs in the placeholders polyfill
  515. if(password === '' || password === PASSWORD_PLACEHOLDER || password === PASSWORD_PLACEHOLDER_MESSAGE) {
  516. return;
  517. }
  518. loading
  519. .removeClass('hidden')
  520. .addClass('inlineblock');
  521. this.model.updateShare(shareId, {
  522. password: password
  523. }, {
  524. error: function(model, msg) {
  525. // destroy old tooltips
  526. passwordField.tooltip('destroy');
  527. loading.removeClass('inlineblock').addClass('hidden');
  528. passwordField.addClass('error');
  529. passwordField.attr('title', msg);
  530. passwordField.tooltip({placement: 'bottom', trigger: 'manual'});
  531. passwordField.tooltip('show');
  532. },
  533. success: function(model, msg) {
  534. passwordField.blur();
  535. passwordField.attr('value', '');
  536. passwordField.attr('placeholder', PASSWORD_PLACEHOLDER);
  537. loading.removeClass('inlineblock').addClass('hidden');
  538. }
  539. });
  540. },
  541. onPermissionChange: function(event) {
  542. event.preventDefault();
  543. event.stopPropagation();
  544. var $element = $(event.target);
  545. var $li = $element.closest('li[data-share-id]');
  546. var shareId = $li.data('share-id');
  547. var permissions = OC.PERMISSION_READ;
  548. if (this.model.isFolder()) {
  549. // adjust checkbox states
  550. var $checkboxes = $('.permissions', $li).not('input[name="edit"]').not('input[name="share"]');
  551. var checked;
  552. if ($element.attr('name') === 'edit') {
  553. checked = $element.is(':checked');
  554. // Check/uncheck Create, Update, and Delete checkboxes if Edit is checked/unck
  555. $($checkboxes).prop('checked', checked);
  556. if (checked) {
  557. permissions |= OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_DELETE;
  558. }
  559. } else {
  560. var numberChecked = $checkboxes.filter(':checked').length;
  561. checked = numberChecked === $checkboxes.length;
  562. var $editCb = $('input[name="edit"]', $li);
  563. $editCb.prop('checked', checked);
  564. $editCb.prop('indeterminate', !checked && numberChecked > 0);
  565. }
  566. } else {
  567. if ($element.attr('name') === 'edit' && $element.is(':checked')) {
  568. permissions |= OC.PERMISSION_UPDATE;
  569. }
  570. }
  571. $('.permissions', $li).not('input[name="edit"]').filter(':checked').each(function(index, checkbox) {
  572. permissions |= $(checkbox).data('permissions');
  573. });
  574. /** disable checkboxes during save operation to avoid race conditions **/
  575. $li.find('input[type=checkbox]').prop('disabled', true);
  576. var enableCb = function() {
  577. $li.find('input[type=checkbox]').prop('disabled', false);
  578. };
  579. var errorCb = function(elem, msg) {
  580. OC.dialogs.alert(msg, t('core', 'Error while sharing'));
  581. enableCb();
  582. };
  583. this.model.updateShare(shareId, {permissions: permissions}, {error: errorCb, success: enableCb});
  584. this._renderPermissionChange = shareId;
  585. },
  586. onSecureDropChange: function(event) {
  587. event.preventDefault();
  588. event.stopPropagation();
  589. var $element = $(event.target);
  590. var $li = $element.closest('li[data-share-id]');
  591. var shareId = $li.data('share-id');
  592. var permissions = OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_DELETE | OC.PERMISSION_READ;
  593. if ($element.is(':checked')) {
  594. permissions = OC.PERMISSION_CREATE | OC.PERMISSION_UPDATE | OC.PERMISSION_DELETE;
  595. }
  596. /** disable checkboxes during save operation to avoid race conditions **/
  597. $li.find('input[type=checkbox]').prop('disabled', true);
  598. var enableCb = function() {
  599. $li.find('input[type=checkbox]').prop('disabled', false);
  600. };
  601. var errorCb = function(elem, msg) {
  602. OC.dialogs.alert(msg, t('core', 'Error while sharing'));
  603. enableCb();
  604. };
  605. this.model.updateShare(shareId, {permissions: permissions}, {error: errorCb, success: enableCb});
  606. this._renderPermissionChange = shareId;
  607. }
  608. });
  609. OC.Share.ShareDialogShareeListView = ShareDialogShareeListView;
  610. })();