sharedialoglinkshareview.js 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  1. /*
  2. * Copyright (c) 2015
  3. *
  4. * This file is licensed under the Affero General Public License version 3
  5. * or later.
  6. *
  7. * See the COPYING-README file.
  8. *
  9. */
  10. /* globals Clipboard, Handlebars */
  11. (function() {
  12. if (!OC.Share) {
  13. OC.Share = {};
  14. }
  15. var PASSWORD_PLACEHOLDER = '**********';
  16. var PASSWORD_PLACEHOLDER_MESSAGE = t('core', 'Choose a password for the public link');
  17. var PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL = t('core', 'Choose a password for the public link or press the "Enter" key');
  18. var TEMPLATE =
  19. '{{#if shareAllowed}}' +
  20. '<ul id="shareLink" class="shareWithList">' +
  21. ' <li data-share-id="{{cid}}">' +
  22. ' <div class="avatar icon-public-white"></div><span class="username" title="{{linkShareLabel}}">{{linkShareLabel}}</span>' +
  23. ' <span class="sharingOptionsGroup">' +
  24. ' <span class="shareOption"> ' +
  25. ' <span class="icon-loading-small hidden"></span>' +
  26. ' <input id="linkCheckbox-{{cid}}" {{#if isLinkShare}}checked="checked"{{/if}} type="checkbox" name="linkCheckbox" class="linkCheckbox permissions checkbox">' +
  27. ' <label for="linkCheckbox-{{cid}}">{{linkShareEnableLabel}}</label>' +
  28. ' </span>' +
  29. ' {{#if showMenu}}' +
  30. ' <div class="share-menu" tabindex="0"><span class="icon icon-more"></span>' +
  31. ' {{#if showPending}}' +
  32. ' {{{pendingPopoverMenu}}}' +
  33. ' {{else}}' +
  34. ' {{{popoverMenu}}}' +
  35. ' {{/if}}' +
  36. ' </div>' +
  37. ' {{/if}}' +
  38. ' </span>' +
  39. ' </li>' +
  40. '</ul>' +
  41. '{{else}}' +
  42. // FIXME: this doesn't belong in this view
  43. '{{#if noSharingPlaceholder}}<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>{{/if}}' +
  44. '{{/if}}'
  45. ;
  46. var TEMPLATE_POPOVER_MENU =
  47. '<div class="popovermenu menu">' +
  48. '<ul>' +
  49. '<li>' +
  50. '<a href="#" class="menuitem clipboardButton" data-clipboard-text="{{shareLinkURL}}">' +
  51. '<span class="icon icon-clippy" ></span>' +
  52. '<span>{{copyLabel}}</span>' +
  53. '</a>' +
  54. '</li>' +
  55. '<li class="hidden linkTextMenu">' +
  56. '<span class="menuitem icon-link-text">' +
  57. '<input id="linkText-{{cid}}" class="linkText" type="text" readonly="readonly" value="{{shareLinkURL}}" />' +
  58. '</span>' +
  59. '</li>' +
  60. '{{#if publicUpload}}' +
  61. '<li><span class="shareOption menuitem">' +
  62. '<span class="icon-loading-small hidden"></span>' +
  63. '<input type="radio" name="publicUpload" value="{{publicUploadRValue}}" id="sharingDialogAllowPublicUpload-r-{{cid}}" class="radio publicUploadRadio" {{{publicUploadRChecked}}} />' +
  64. '<label for="sharingDialogAllowPublicUpload-r-{{cid}}">{{publicUploadRLabel}}</label>' +
  65. '</span></li>' +
  66. '<li><span class="shareOption menuitem">' +
  67. '<span class="icon-loading-small hidden"></span>' +
  68. '<input type="radio" name="publicUpload" value="{{publicUploadRWValue}}" id="sharingDialogAllowPublicUpload-rw-{{cid}}" class="radio publicUploadRadio" {{{publicUploadRWChecked}}} />' +
  69. '<label for="sharingDialogAllowPublicUpload-rw-{{cid}}">{{publicUploadRWLabel}}</label>' +
  70. '</span></li>' +
  71. '<li><span class="shareOption menuitem">' +
  72. '<span class="icon-loading-small hidden"></span>' +
  73. '<input type="radio" name="publicUpload" value="{{publicUploadWValue}}" id="sharingDialogAllowPublicUpload-w-{{cid}}" class="radio publicUploadRadio" {{{publicUploadWChecked}}} />' +
  74. '<label for="sharingDialogAllowPublicUpload-w-{{cid}}">{{publicUploadWLabel}}</label>' +
  75. '</span></li>' +
  76. '{{/if}}' +
  77. '{{#if publicEditing}}' +
  78. ' <li id="allowPublicEditingWrapper"><span class="shareOption menuitem">' +
  79. ' <span class="icon-loading-small hidden"></span>' +
  80. ' <input type="checkbox" name="allowPublicEditing" id="sharingDialogAllowPublicEditing-{{cid}}" class="checkbox publicEditingCheckbox" {{{publicEditingChecked}}} />' +
  81. ' <label for="sharingDialogAllowPublicEditing-{{cid}}">{{publicEditingLabel}}</label>' +
  82. ' </span></li>' +
  83. '{{/if}}' +
  84. '{{#if showPasswordCheckBox}}' +
  85. ' <li><span class="shareOption menuitem">' +
  86. ' <input type="checkbox" name="showPassword" id="showPassword-{{cid}}" class="checkbox showPasswordCheckbox"' +
  87. ' {{#if isPasswordSet}}checked="checked"{{/if}} {{#if isPasswordEnforced}}disabled="disabled"{{/if}} value="1" />' +
  88. ' <label for="showPassword-{{cid}}">{{enablePasswordLabel}}</label>' +
  89. ' </span></li>' +
  90. ' <li class="{{#unless isPasswordSet}}hidden{{/unless}} linkPassMenu"><span class="shareOption menuitem icon-share-pass">' +
  91. ' <input id="linkPassText-{{cid}}" class="linkPassText" type="password" placeholder="{{passwordPlaceholder}}" autocomplete="new-password" />' +
  92. ' <span class="icon icon-loading-small hidden"></span>' +
  93. ' </span></li>' +
  94. '{{/if}}' +
  95. '<li>' +
  96. ' <span class="shareOption menuitem">' +
  97. ' <input id="expireDate-{{cid}}" type="checkbox" name="expirationDate" class="expireDate checkbox"' +
  98. ' {{#if hasExpireDate}}checked="checked"{{/if}} {{#if isExpirationEnforced}}disabled="disabled"{{/if}}" />' +
  99. ' <label for="expireDate-{{cid}}">{{expireDateLabel}}</label>' +
  100. ' </span>' +
  101. '</li>' +
  102. '<li class="{{#unless hasExpireDate}}hidden{{/unless}}">' +
  103. ' <span class="menuitem icon-expiredate expirationDateContainer-{{cid}}">' +
  104. ' <label for="expirationDatePicker-{{cid}}" class="hidden-visually" value="{{expirationDate}}">{{expirationLabel}}</label>' +
  105. ' <input id="expirationDatePicker-{{cid}}" class="datepicker" type="text" placeholder="{{expirationDatePlaceholder}}" value="{{#if hasExpireDate}}{{expireDate}}{{else}}{{defaultExpireDate}}{{/if}}" />' +
  106. ' </span>' +
  107. '</li>' +
  108. '<li>' +
  109. '<a href="#" class="share-add"><span class="icon-loading-small hidden"></span>' +
  110. ' <span class="icon icon-edit"></span>' +
  111. ' <span>{{addNoteLabel}}</span>' +
  112. ' <input type="button" class="share-note-delete icon-delete">' +
  113. '</a>' +
  114. '</li>' +
  115. '<li class="share-note-form share-note-link hidden">' +
  116. '<span class="menuitem icon-note">' +
  117. ' <textarea class="share-note">{{shareNote}}</textarea>' +
  118. ' <input type="submit" class="icon-confirm share-note-submit" value="" id="add-note-{{shareId}}" />' +
  119. '</span>' +
  120. '</li>' +
  121. '{{#each social}}' +
  122. '<li>' +
  123. '<a href="#" class="shareOption menuitem pop-up" data-url="{{url}}" data-window="{{newWindow}}">' +
  124. '<span class="icon {{iconClass}}"' +
  125. '></span><span>{{label}}' +
  126. '</span>' +
  127. '</a>' +
  128. '</li>' +
  129. '{{/each}}' +
  130. '</ul>' +
  131. '</div>';
  132. // popovermenu waiting for password or expiration date before saving the share
  133. var TEMPLATE_POPOVER_MENU_PENDING =
  134. '<div class="popovermenu pendingpopover menu">' +
  135. '<ul>' +
  136. '{{#if isPasswordEnforced}}' +
  137. ' <li><span class="shareOption menuitem">' +
  138. ' <input type="checkbox" name="showPassword" id="showPassword-{{cid}}" checked="checked" disabled class="checkbox showPasswordCheckbox" value="1" />' +
  139. ' <label for="showPassword-{{cid}}">{{enablePasswordLabel}}</label>' +
  140. ' </span></li>' +
  141. ' <li class="linkPassMenu"><span class="shareOption menuitem icon-share-pass">' +
  142. ' <input id="linkPassText-{{cid}}" class="linkPassText" type="password" placeholder="{{passwordPlaceholder}}" autocomplete="new-password" />' +
  143. ' <span class="icon icon-loading-small hidden"></span>' +
  144. ' </span></li>' +
  145. '{{/if}}' +
  146. '</ul>' +
  147. '</div>';
  148. /**
  149. * @class OCA.Share.ShareDialogLinkShareView
  150. * @member {OC.Share.ShareItemModel} model
  151. * @member {jQuery} $el
  152. * @memberof OCA.Sharing
  153. * @classdesc
  154. *
  155. * Represents the GUI of the share dialogue
  156. *
  157. */
  158. var ShareDialogLinkShareView = OC.Backbone.View.extend({
  159. /** @type {string} **/
  160. id: 'shareDialogLinkShare',
  161. /** @type {OC.Share.ShareConfigModel} **/
  162. configModel: undefined,
  163. /** @type {Function} **/
  164. _template: undefined,
  165. /** @type {Function} **/
  166. _popoverMenuTemplate: undefined,
  167. /** @type {Function} **/
  168. _pendingPopoverMenuTemplate: undefined,
  169. /** @type {boolean} **/
  170. showLink: true,
  171. /** @type {boolean} **/
  172. showPending: false,
  173. events: {
  174. // enable/disable
  175. 'change .linkCheckbox': 'onLinkCheckBoxChange',
  176. // open menu
  177. 'click .share-menu .icon-more': 'onToggleMenu',
  178. // password
  179. 'focusout input.linkPassText': 'onPasswordEntered',
  180. 'keyup input.linkPassText': 'onPasswordKeyUp',
  181. 'change .showPasswordCheckbox': 'onShowPasswordClick',
  182. 'change .publicEditingCheckbox': 'onAllowPublicEditingChange',
  183. // copy link url
  184. 'click .linkText': 'onLinkTextClick',
  185. // social
  186. 'click .pop-up': 'onPopUpClick',
  187. // permission change
  188. 'change .publicUploadRadio': 'onPublicUploadChange',
  189. // expire date
  190. 'click .expireDate' : 'onExpireDateChange',
  191. 'change .datepicker': 'onChangeExpirationDate',
  192. 'click .datepicker' : 'showDatePicker',
  193. // note
  194. 'click .share-add': 'showNoteForm',
  195. 'click .share-note-delete': 'deleteNote',
  196. 'click .share-note-submit': 'updateNote'
  197. },
  198. initialize: function(options) {
  199. var view = this;
  200. this.model.on('change:permissions', function() {
  201. view.render();
  202. });
  203. this.model.on('change:itemType', function() {
  204. view.render();
  205. });
  206. this.model.on('change:allowPublicUploadStatus', function() {
  207. view.render();
  208. });
  209. this.model.on('change:hideFileListStatus', function() {
  210. view.render();
  211. });
  212. this.model.on('change:linkShare', function() {
  213. view.render();
  214. });
  215. if(!_.isUndefined(options.configModel)) {
  216. this.configModel = options.configModel;
  217. } else {
  218. throw 'missing OC.Share.ShareConfigModel';
  219. }
  220. var clipboard = new Clipboard('.clipboardButton');
  221. clipboard.on('success', function(e) {
  222. var $menu = $(e.trigger);
  223. var $linkTextMenu = $menu.parent().next('li.linkTextMenu')
  224. $menu.tooltip('hide')
  225. .attr('data-original-title', t('core', 'Copied!'))
  226. .tooltip('fixTitle')
  227. .tooltip({placement: 'bottom', trigger: 'manual'})
  228. .tooltip('show');
  229. _.delay(function() {
  230. $menu.tooltip('hide');
  231. $menu.tooltip('destroy');
  232. }, 3000);
  233. });
  234. clipboard.on('error', function (e) {
  235. var $menu = $(e.trigger);
  236. var $linkTextMenu = $menu.parent().next('li.linkTextMenu')
  237. var $input = $linkTextMenu.find('.linkText');
  238. var actionMsg = '';
  239. if (/iPhone|iPad/i.test(navigator.userAgent)) {
  240. actionMsg = t('core', 'Not supported!');
  241. } else if (/Mac/i.test(navigator.userAgent)) {
  242. actionMsg = t('core', 'Press ⌘-C to copy.');
  243. } else {
  244. actionMsg = t('core', 'Press Ctrl-C to copy.');
  245. }
  246. $linkTextMenu.removeClass('hidden');
  247. $input.select();
  248. $input.tooltip('hide')
  249. .attr('data-original-title', actionMsg)
  250. .tooltip('fixTitle')
  251. .tooltip({placement: 'bottom', trigger: 'manual'})
  252. .tooltip('show');
  253. _.delay(function () {
  254. $input.tooltip('hide');
  255. $input.attr('data-original-title', t('core', 'Copy'))
  256. .tooltip('fixTitle');
  257. }, 3000);
  258. });
  259. },
  260. onLinkCheckBoxChange: function() {
  261. var $checkBox = this.$el.find('.linkCheckbox');
  262. var $loading = $checkBox.siblings('.icon-loading-small');
  263. if(!$loading.hasClass('hidden')) {
  264. return false;
  265. }
  266. if($checkBox.is(':checked')) {
  267. if(this.configModel.get('enforcePasswordForPublicLink') === false) {
  268. $loading.removeClass('hidden');
  269. // this will create it
  270. this.model.saveLinkShare();
  271. $('.share-menu .icon-more').click();
  272. $('.share-menu .icon-more + .popovermenu .clipboardButton').click();
  273. } else {
  274. // force the rendering of the menu
  275. this.showPending = true;
  276. this.render()
  277. $('.share-menu .icon-more').click();
  278. $('.share-menu .icon-more + .popovermenu input:eq(1)').focus()
  279. }
  280. } else {
  281. if (this.model.get('linkShare').isLinkShare) {
  282. $loading.removeClass('hidden');
  283. this.model.removeLinkShare();
  284. } else {
  285. this.showPending = false;
  286. this.render()
  287. }
  288. }
  289. },
  290. onLinkTextClick: function() {
  291. var $el = this.$el.find('.linkText');
  292. $el.focus();
  293. $el.select();
  294. },
  295. onShowPasswordClick: function() {
  296. this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
  297. this.$el.find('.linkPassMenu').toggleClass('hidden');
  298. if(!this.$el.find('.showPasswordCheckbox').is(':checked')) {
  299. this.model.saveLinkShare({
  300. password: ''
  301. });
  302. } else {
  303. if (!OC.Util.isIE()) {
  304. this.$el.find('.linkPassText').focus();
  305. }
  306. }
  307. },
  308. onPasswordKeyUp: function(event) {
  309. if(event.keyCode === 13) {
  310. this.onPasswordEntered();
  311. }
  312. },
  313. onPasswordEntered: function() {
  314. var $loading = this.$el.find('.linkPassMenu .icon-loading-small');
  315. if (!$loading.hasClass('hidden')) {
  316. // still in process
  317. return;
  318. }
  319. var $input = this.$el.find('.linkPassText');
  320. $input.removeClass('error');
  321. var password = $input.val();
  322. if (this.$el.find('.linkPassText').attr('placeholder') === PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL) {
  323. // in IE9 the password might be the placeholder due to bugs in the placeholders polyfill
  324. if(password === PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL) {
  325. password = '';
  326. }
  327. } else {
  328. // in IE9 the password might be the placeholder due to bugs in the placeholders polyfill
  329. if(password === '' || password === PASSWORD_PLACEHOLDER || password === PASSWORD_PLACEHOLDER_MESSAGE) {
  330. return;
  331. }
  332. }
  333. $loading
  334. .removeClass('hidden')
  335. .addClass('inlineblock');
  336. this.model.saveLinkShare({
  337. password: password
  338. }, {
  339. complete: function(model) {
  340. $loading.removeClass('inlineblock').addClass('hidden');
  341. },
  342. error: function(model, msg) {
  343. // destroy old tooltips
  344. $input.tooltip('destroy');
  345. $input.addClass('error');
  346. $input.attr('title', msg);
  347. $input.tooltip({placement: 'bottom', trigger: 'manual'});
  348. $input.tooltip('show');
  349. }
  350. });
  351. },
  352. onAllowPublicEditingChange: function() {
  353. var $checkbox = this.$('.publicEditingCheckbox');
  354. $checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock');
  355. var permissions = OC.PERMISSION_READ;
  356. if($checkbox.is(':checked')) {
  357. permissions = OC.PERMISSION_UPDATE | OC.PERMISSION_READ;
  358. }
  359. this.model.saveLinkShare({
  360. permissions: permissions
  361. });
  362. },
  363. onPublicUploadChange: function(e) {
  364. var permissions = e.currentTarget.value;
  365. this.model.saveLinkShare({
  366. permissions: permissions
  367. });
  368. },
  369. showNoteForm: function(event) {
  370. event.preventDefault();
  371. event.stopPropagation();
  372. var self = this;
  373. var $element = $(event.target);
  374. var $li = $element.closest('li[data-share-id]');
  375. var $menu = $element.closest('li');
  376. var $form = $menu.next('li.share-note-form');
  377. // show elements
  378. $menu.find('.share-note-delete').toggle();
  379. $form.toggleClass('hidden');
  380. $form.find('textarea').focus();
  381. },
  382. deleteNote: function(event) {
  383. event.preventDefault();
  384. event.stopPropagation();
  385. var self = this;
  386. var $element = $(event.target);
  387. var $li = $element.closest('li[data-share-id]');
  388. var shareId = $li.data('share-id');
  389. var $menu = $element.closest('li');
  390. var $form = $menu.next('li.share-note-form');
  391. $form.find('.share-note').val('');
  392. $form.addClass('hidden');
  393. $menu.find('.share-note-delete').hide();
  394. self.sendNote('', shareId, $menu);
  395. },
  396. updateNote: function(event) {
  397. event.preventDefault();
  398. event.stopPropagation();
  399. var self = this;
  400. var $element = $(event.target);
  401. var $li = $element.closest('li[data-share-id]');
  402. var shareId = $li.data('share-id');
  403. var $form = $element.closest('li.share-note-form');
  404. var $menu = $form.prev('li');
  405. var message = $form.find('.share-note').val().trim();
  406. if (message.length < 1) {
  407. return;
  408. }
  409. self.sendNote(message, shareId, $menu);
  410. },
  411. sendNote: function(note, shareId, $menu) {
  412. var $form = $menu.next('li.share-note-form');
  413. var $submit = $form.find('input.share-note-submit');
  414. var $error = $form.find('input.share-note-error');
  415. $submit.prop('disabled', true);
  416. $menu.find('.icon-loading-small').removeClass('hidden');
  417. $menu.find('.icon-edit').hide();
  418. var complete = function() {
  419. $submit.prop('disabled', false);
  420. $menu.find('.icon-loading-small').addClass('hidden');
  421. $menu.find('.icon-edit').show();
  422. };
  423. var error = function() {
  424. $error.show();
  425. setTimeout(function() {
  426. $error.hide();
  427. }, 3000);
  428. };
  429. // send data
  430. $.ajax({
  431. method: 'PUT',
  432. url: OC.linkToOCS('apps/files_sharing/api/v1/shares',2) + shareId + '?' + OC.buildQueryString({format: 'json'}),
  433. data: { note: note },
  434. complete : complete,
  435. error: error
  436. });
  437. },
  438. render: function() {
  439. var linkShareTemplate = this.template();
  440. var resharingAllowed = this.model.sharePermissionPossible();
  441. if(!resharingAllowed
  442. || !this.showLink
  443. || !this.configModel.isShareWithLinkAllowed())
  444. {
  445. var templateData = {shareAllowed: false};
  446. if (!resharingAllowed) {
  447. // add message
  448. templateData.noSharingPlaceholder = t('core', 'Resharing is not allowed');
  449. }
  450. this.$el.html(linkShareTemplate(templateData));
  451. return this;
  452. }
  453. var publicUpload =
  454. this.model.isFolder()
  455. && this.model.createPermissionPossible()
  456. && this.configModel.isPublicUploadEnabled();
  457. var publicUploadRWChecked = '';
  458. var publicUploadRChecked = '';
  459. var publicUploadWChecked = '';
  460. switch (this.model.linkSharePermissions()) {
  461. case OC.PERMISSION_READ:
  462. publicUploadRChecked = 'checked';
  463. break;
  464. case OC.PERMISSION_CREATE:
  465. publicUploadWChecked = 'checked';
  466. break;
  467. case OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ | OC.PERMISSION_DELETE:
  468. publicUploadRWChecked = 'checked';
  469. break;
  470. }
  471. var publicEditingChecked = '';
  472. if(this.model.isPublicEditingAllowed()) {
  473. publicEditingChecked = 'checked="checked"';
  474. }
  475. var isLinkShare = this.model.get('linkShare').isLinkShare;
  476. var isPasswordSet = !!this.model.get('linkShare').password;
  477. var isPasswordEnforced = this.configModel.get('enforcePasswordForPublicLink')
  478. var isPasswordEnabledByDefault = this.configModel.get('enableLinkPasswordByDefault') === true
  479. var showPasswordCheckBox = isLinkShare
  480. && ( !this.configModel.get('enforcePasswordForPublicLink')
  481. || !this.model.get('linkShare').password);
  482. var passwordPlaceholderInitial = this.configModel.get('enforcePasswordForPublicLink')
  483. ? PASSWORD_PLACEHOLDER_MESSAGE : PASSWORD_PLACEHOLDER_MESSAGE_OPTIONAL;
  484. var publicEditable =
  485. !this.model.isFolder()
  486. && isLinkShare
  487. && this.model.updatePermissionPossible();
  488. var link = this.model.get('linkShare').link;
  489. var social = [];
  490. OC.Share.Social.Collection.each(function(model) {
  491. var url = model.get('url');
  492. url = url.replace('{{reference}}', link);
  493. social.push({
  494. url: url,
  495. label: t('core', 'Share to {name}', {name: model.get('name')}),
  496. name: model.get('name'),
  497. iconClass: model.get('iconClass'),
  498. newWindow: model.get('newWindow')
  499. });
  500. });
  501. var defaultExpireDays = this.configModel.get('defaultExpireDate');
  502. var isExpirationEnforced = this.configModel.get('isDefaultExpireDateEnforced');
  503. var hasExpireDate = !!this.model.get('linkShare').expiration || isExpirationEnforced;
  504. var expireDate;
  505. if (hasExpireDate) {
  506. expireDate = moment(this.model.get('linkShare').expiration, 'YYYY-MM-DD').format('DD-MM-YYYY');
  507. }
  508. // what if there is another date picker on that page?
  509. var minDate = new Date();
  510. var maxDate = null;
  511. // min date should always be the next day
  512. minDate.setDate(minDate.getDate()+1);
  513. if(hasExpireDate) {
  514. if(isExpirationEnforced) {
  515. // TODO: hack: backend returns string instead of integer
  516. var shareTime = this.model.get('linkShare').stime;
  517. if (_.isNumber(shareTime)) {
  518. shareTime = new Date(shareTime * 1000);
  519. }
  520. if (!shareTime) {
  521. shareTime = new Date(); // now
  522. }
  523. shareTime = OC.Util.stripTime(shareTime).getTime();
  524. maxDate = new Date(shareTime + defaultExpireDays * 24 * 3600 * 1000);
  525. }
  526. }
  527. $.datepicker.setDefaults({
  528. minDate: minDate,
  529. maxDate: maxDate
  530. });
  531. this.$el.find('.datepicker').datepicker({dateFormat : 'dd-mm-yy'});
  532. var popover = this.popoverMenuTemplate({
  533. cid: this.model.get('linkShare').id,
  534. copyLabel: t('core', 'Copy URL'),
  535. social: social,
  536. shareLinkURL: this.model.get('linkShare').link,
  537. urlLabel: t('core', 'Link'),
  538. enablePasswordLabel: t('core', 'Password protect'),
  539. passwordLabel: t('core', 'Password'),
  540. passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE,
  541. passwordPlaceholderInitial: passwordPlaceholderInitial,
  542. isPasswordSet: isPasswordSet || isPasswordEnabledByDefault || isPasswordEnforced,
  543. showPasswordCheckBox: showPasswordCheckBox,
  544. publicUpload: publicUpload && isLinkShare,
  545. publicEditing: publicEditable,
  546. publicEditingChecked: publicEditingChecked,
  547. publicEditingLabel: t('core', 'Allow editing'),
  548. mailPrivatePlaceholder: t('core', 'Email link to person'),
  549. mailButtonText: t('core', 'Send'),
  550. publicUploadRWLabel: t('core', 'Allow upload and editing'),
  551. publicUploadRLabel: t('core', 'Read only'),
  552. publicUploadWLabel: t('core', 'File drop (upload only)'),
  553. publicUploadRWValue: OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ | OC.PERMISSION_DELETE,
  554. publicUploadRValue: OC.PERMISSION_READ,
  555. publicUploadWValue: OC.PERMISSION_CREATE,
  556. publicUploadRWChecked: publicUploadRWChecked,
  557. publicUploadRChecked: publicUploadRChecked,
  558. publicUploadWChecked: publicUploadWChecked,
  559. expireDateLabel: t('core', 'Set expiration date'),
  560. expirationLabel: t('core', 'Expiration'),
  561. expirationDatePlaceholder: t('core', 'Expiration date'),
  562. hasExpireDate: hasExpireDate,
  563. isExpirationEnforced: isExpirationEnforced,
  564. isPasswordEnforced: isPasswordEnforced,
  565. expireDate: expireDate,
  566. defaultExpireDate: moment().add(1, 'day').format('DD-MM-YYYY'), // Can't expire today
  567. shareNote: this.model.get('linkShare').note,
  568. addNoteLabel: t('core', 'Note to recipient'),
  569. });
  570. var pendingPopover = this.pendingPopoverMenuTemplate({
  571. cid: this.model.get('linkShare').id,
  572. enablePasswordLabel: t('core', 'Password protect'),
  573. passwordLabel: t('core', 'Password'),
  574. passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE,
  575. passwordPlaceholderInitial: passwordPlaceholderInitial,
  576. showPasswordCheckBox: showPasswordCheckBox,
  577. isPasswordEnforced: isPasswordEnforced,
  578. });
  579. this.$el.html(linkShareTemplate({
  580. cid: this.model.get('linkShare').id,
  581. shareAllowed: true,
  582. isLinkShare: isLinkShare,
  583. linkShareLabel: t('core', 'Share link'),
  584. linkShareEnableLabel: t('core', 'Enable'),
  585. popoverMenu: popover,
  586. pendingPopoverMenu: pendingPopover,
  587. showMenu: isLinkShare || this.showPending,
  588. showPending: this.showPending && !isLinkShare
  589. }));
  590. this.delegateEvents();
  591. // new note autosize
  592. autosize(this.$el.find('.share-note-form .share-note'));
  593. return this;
  594. },
  595. onToggleMenu: function(event) {
  596. event.preventDefault();
  597. event.stopPropagation();
  598. var $element = $(event.target);
  599. var $li = $element.closest('li[data-share-id]');
  600. var $menu = $li.find('.sharingOptionsGroup .popovermenu');
  601. OC.showMenu(null, $menu);
  602. this._menuOpen = $li.data('share-id');
  603. },
  604. /**
  605. * @returns {Function} from Handlebars
  606. * @private
  607. */
  608. template: function () {
  609. if (!this._template) {
  610. this._template = Handlebars.compile(TEMPLATE);
  611. }
  612. return this._template;
  613. },
  614. /**
  615. * renders the popover template and returns the resulting HTML
  616. *
  617. * @param {Object} data
  618. * @returns {string}
  619. */
  620. popoverMenuTemplate: function(data) {
  621. if(!this._popoverMenuTemplate) {
  622. this._popoverMenuTemplate = Handlebars.compile(TEMPLATE_POPOVER_MENU);
  623. }
  624. return this._popoverMenuTemplate(data);
  625. },
  626. /**
  627. * renders the pending popover template and returns the resulting HTML
  628. *
  629. * @param {Object} data
  630. * @returns {string}
  631. */
  632. pendingPopoverMenuTemplate: function(data) {
  633. if(!this._pendingPopoverMenuTemplate) {
  634. this._pendingPopoverMenuTemplate = Handlebars.compile(TEMPLATE_POPOVER_MENU_PENDING);
  635. }
  636. return this._pendingPopoverMenuTemplate(data);
  637. },
  638. onPopUpClick: function(event) {
  639. event.preventDefault();
  640. event.stopPropagation();
  641. var url = $(event.currentTarget).data('url');
  642. var newWindow = $(event.currentTarget).data('window');
  643. $(event.currentTarget).tooltip('hide');
  644. if (url) {
  645. if (newWindow === true) {
  646. var width = 600;
  647. var height = 400;
  648. var left = (screen.width / 2) - (width / 2);
  649. var top = (screen.height / 2) - (height / 2);
  650. window.open(url, 'name', 'width=' + width + ', height=' + height + ', top=' + top + ', left=' + left);
  651. } else {
  652. window.location.href = url;
  653. }
  654. }
  655. },
  656. onExpireDateChange: function(event) {
  657. var $element = $(event.target);
  658. var li = $element.closest('li[data-share-id]');
  659. var shareId = li.data('share-id');
  660. var expirationDatePicker = '#expirationDateContainer-' + shareId;
  661. var datePicker = $(expirationDatePicker);
  662. var state = $element.prop('checked');
  663. datePicker.toggleClass('hidden', !state);
  664. if (!state) {
  665. // disabled, let's hide the input and
  666. // set the expireDate to nothing
  667. $element.closest('li').next('li').addClass('hidden');
  668. this.setExpirationDate('');
  669. } else {
  670. // enabled, show the input and the datepicker
  671. $element.closest('li').next('li').removeClass('hidden');
  672. this.showDatePicker(event);
  673. }
  674. },
  675. showDatePicker: function(event) {
  676. var $element = $(event.target);
  677. var li = $element.closest('li[data-share-id]');
  678. var shareId = li.data('share-id');
  679. var expirationDatePicker = '#expirationDatePicker-' + shareId;
  680. var self = this;
  681. $(expirationDatePicker).datepicker({
  682. dateFormat : 'dd-mm-yy',
  683. onSelect: function (expireDate) {
  684. self.setExpirationDate(expireDate);
  685. }
  686. });
  687. $(expirationDatePicker).datepicker('show');
  688. $(expirationDatePicker).focus();
  689. },
  690. setExpirationDate: function(expireDate) {
  691. this.model.saveLinkShare({expireDate: expireDate});
  692. },
  693. });
  694. OC.Share.ShareDialogLinkShareView = ShareDialogLinkShareView;
  695. })();