sharedialoglinkshareview.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  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. (function() {
  11. if (!OC.Share) {
  12. OC.Share = {};
  13. }
  14. var PASSWORD_PLACEHOLDER = '**********';
  15. var PASSWORD_PLACEHOLDER_MESSAGE = t('core', 'Choose a password for the public link');
  16. var TEMPLATE =
  17. '{{#if shareAllowed}}' +
  18. '<span class="icon-loading-small hidden"></span>' +
  19. '<input type="checkbox" name="linkCheckbox" id="linkCheckbox-{{cid}}" class="checkbox linkCheckbox" value="1" {{#if isLinkShare}}checked="checked"{{/if}} />' +
  20. '<label for="linkCheckbox-{{cid}}">{{linkShareLabel}}</label>' +
  21. '<br />' +
  22. '<label for="linkText-{{cid}}" class="hidden-visually">{{urlLabel}}</label>' +
  23. '<input id="linkText-{{cid}}" class="linkText {{#unless isLinkShare}}hidden{{/unless}}" type="text" readonly="readonly" value="{{shareLinkURL}}" />' +
  24. ' {{#if showPasswordCheckBox}}' +
  25. '<input type="checkbox" name="showPassword" id="showPassword-{{cid}}" class="checkbox showPasswordCheckbox" {{#if isPasswordSet}}checked="checked"{{/if}} value="1" />' +
  26. '<label for="showPassword-{{cid}}">{{enablePasswordLabel}}</label>' +
  27. ' {{/if}}' +
  28. '<div id="linkPass" class="linkPass {{#unless isPasswordSet}}hidden{{/unless}}">' +
  29. ' <label for="linkPassText-{{cid}}" class="hidden-visually">{{passwordLabel}}</label>' +
  30. ' <input id="linkPassText-{{cid}}" class="linkPassText" type="password" placeholder="{{passwordPlaceholder}}" />' +
  31. ' <span class="icon-loading-small hidden"></span>' +
  32. '</div>' +
  33. ' {{#if publicUpload}}' +
  34. '<div id="allowPublicUploadWrapper">' +
  35. ' <span class="icon-loading-small hidden"></span>' +
  36. ' <input type="checkbox" value="1" name="allowPublicUpload" id="sharingDialogAllowPublicUpload-{{cid}}" class="checkbox publicUploadCheckbox" {{{publicUploadChecked}}} />' +
  37. '<label for="sharingDialogAllowPublicUpload-{{cid}}">{{publicUploadLabel}}</label>' +
  38. '</div>' +
  39. ' {{/if}}' +
  40. ' {{#if mailPublicNotificationEnabled}}' +
  41. '<form id="emailPrivateLink" class="emailPrivateLinkForm">' +
  42. ' <input id="email" class="emailField" value="" placeholder="{{mailPrivatePlaceholder}}" type="text" />' +
  43. ' <input id="emailButton" class="emailButton" type="submit" value="{{mailButtonText}}" />' +
  44. '</form>' +
  45. ' {{/if}}' +
  46. '{{else}}' +
  47. // FIXME: this doesn't belong in this view
  48. '{{#if noSharingPlaceholder}}<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>{{/if}}' +
  49. '{{/if}}'
  50. ;
  51. /**
  52. * @class OCA.Share.ShareDialogLinkShareView
  53. * @member {OC.Share.ShareItemModel} model
  54. * @member {jQuery} $el
  55. * @memberof OCA.Sharing
  56. * @classdesc
  57. *
  58. * Represents the GUI of the share dialogue
  59. *
  60. */
  61. var ShareDialogLinkShareView = OC.Backbone.View.extend({
  62. /** @type {string} **/
  63. id: 'shareDialogLinkShare',
  64. /** @type {OC.Share.ShareConfigModel} **/
  65. configModel: undefined,
  66. /** @type {Function} **/
  67. _template: undefined,
  68. /** @type {boolean} **/
  69. showLink: true,
  70. events: {
  71. 'submit .emailPrivateLinkForm': '_onEmailPrivateLink',
  72. 'focusout input.linkPassText': 'onPasswordEntered',
  73. 'keyup input.linkPassText': 'onPasswordKeyUp',
  74. 'click .linkCheckbox': 'onLinkCheckBoxChange',
  75. 'click .linkText': 'onLinkTextClick',
  76. 'change .publicUploadCheckbox': 'onAllowPublicUploadChange',
  77. 'click .showPasswordCheckbox': 'onShowPasswordClick'
  78. },
  79. initialize: function(options) {
  80. var view = this;
  81. this.model.on('change:permissions', function() {
  82. view.render();
  83. });
  84. this.model.on('change:itemType', function() {
  85. view.render();
  86. });
  87. this.model.on('change:allowPublicUploadStatus', function() {
  88. view.render();
  89. });
  90. this.model.on('change:linkShare', function() {
  91. view.render();
  92. });
  93. if(!_.isUndefined(options.configModel)) {
  94. this.configModel = options.configModel;
  95. } else {
  96. throw 'missing OC.Share.ShareConfigModel';
  97. }
  98. _.bindAll(
  99. this,
  100. '_onEmailPrivateLink',
  101. 'onLinkCheckBoxChange',
  102. 'onPasswordEntered',
  103. 'onPasswordKeyUp',
  104. 'onLinkTextClick',
  105. 'onShowPasswordClick',
  106. 'onAllowPublicUploadChange'
  107. );
  108. },
  109. onLinkCheckBoxChange: function() {
  110. var $checkBox = this.$el.find('.linkCheckbox');
  111. var $loading = $checkBox.siblings('.icon-loading-small');
  112. if(!$loading.hasClass('hidden')) {
  113. return false;
  114. }
  115. if($checkBox.is(':checked')) {
  116. if(this.configModel.get('enforcePasswordForPublicLink') === false) {
  117. $loading.removeClass('hidden');
  118. // this will create it
  119. this.model.saveLinkShare();
  120. } else {
  121. this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
  122. this.$el.find('.linkPassText').focus();
  123. }
  124. } else {
  125. if (this.model.get('linkShare').isLinkShare) {
  126. $loading.removeClass('hidden');
  127. this.model.removeLinkShare();
  128. } else {
  129. this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
  130. }
  131. }
  132. },
  133. onLinkTextClick: function() {
  134. var $el = this.$el.find('.linkText');
  135. $el.focus();
  136. $el.select();
  137. },
  138. onShowPasswordClick: function() {
  139. this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
  140. if(!this.$el.find('.showPasswordCheckbox').is(':checked')) {
  141. this.model.saveLinkShare({
  142. password: ''
  143. });
  144. } else {
  145. this.$el.find('.linkPassText').focus();
  146. }
  147. },
  148. onPasswordKeyUp: function(event) {
  149. if(event.keyCode == 13) {
  150. this.onPasswordEntered();
  151. }
  152. },
  153. onPasswordEntered: function() {
  154. var $loading = this.$el.find('.linkPass .icon-loading-small');
  155. if (!$loading.hasClass('hidden')) {
  156. // still in process
  157. return;
  158. }
  159. var $input = this.$el.find('.linkPassText');
  160. $input.removeClass('error');
  161. var password = $input.val();
  162. // in IE9 the password might be the placeholder due to bugs in the placeholders polyfill
  163. if(password === '' || password === PASSWORD_PLACEHOLDER || password === PASSWORD_PLACEHOLDER_MESSAGE) {
  164. return;
  165. }
  166. $loading
  167. .removeClass('hidden')
  168. .addClass('inlineblock');
  169. this.model.saveLinkShare({
  170. password: password
  171. }, {
  172. error: function(model, msg) {
  173. $loading.removeClass('inlineblock').addClass('hidden');
  174. $input.addClass('error');
  175. $input.attr('title', msg);
  176. $input.tooltip({placement: 'bottom', trigger: 'manual'});
  177. $input.tooltip('show');
  178. }
  179. });
  180. },
  181. onAllowPublicUploadChange: function() {
  182. var $checkbox = this.$('.publicUploadCheckbox');
  183. $checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock');
  184. var permissions = OC.PERMISSION_READ;
  185. if($checkbox.is(':checked')) {
  186. permissions = OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_READ;
  187. }
  188. this.model.saveLinkShare({
  189. permissions: permissions
  190. });
  191. },
  192. _onEmailPrivateLink: function(event) {
  193. event.preventDefault();
  194. var $emailField = this.$el.find('.emailField');
  195. var $emailButton = this.$el.find('.emailButton');
  196. var email = $emailField.val();
  197. if (email !== '') {
  198. $emailField.prop('disabled', true);
  199. $emailButton.prop('disabled', true);
  200. $emailField.val(t('core', 'Sending ...'));
  201. this.model.sendEmailPrivateLink(email).done(function() {
  202. $emailField.css('font-weight', 'bold').val(t('core','Email sent'));
  203. setTimeout(function() {
  204. $emailField.val('');
  205. $emailField.css('font-weight', 'normal');
  206. $emailField.prop('disabled', false);
  207. $emailButton.prop('disabled', false);
  208. }, 2000);
  209. }).fail(function() {
  210. $emailField.val(email);
  211. $emailField.css('font-weight', 'normal');
  212. $emailField.prop('disabled', false);
  213. $emailButton.prop('disabled', false);
  214. });
  215. }
  216. return false;
  217. },
  218. render: function() {
  219. var linkShareTemplate = this.template();
  220. var resharingAllowed = this.model.sharePermissionPossible();
  221. if(!resharingAllowed
  222. || !this.showLink
  223. || !this.configModel.isShareWithLinkAllowed())
  224. {
  225. var templateData = {shareAllowed: false};
  226. if (!resharingAllowed) {
  227. // add message
  228. templateData.noSharingPlaceholder = t('core', 'Resharing is not allowed');
  229. }
  230. this.$el.html(linkShareTemplate(templateData));
  231. return this;
  232. }
  233. var publicUpload =
  234. this.model.isFolder()
  235. && this.model.createPermissionPossible()
  236. && this.configModel.isPublicUploadEnabled();
  237. var publicUploadChecked = '';
  238. if(this.model.isPublicUploadAllowed()) {
  239. publicUploadChecked = 'checked="checked"';
  240. }
  241. var isLinkShare = this.model.get('linkShare').isLinkShare;
  242. var isPasswordSet = !!this.model.get('linkShare').password;
  243. var showPasswordCheckBox = isLinkShare
  244. && ( !this.configModel.get('enforcePasswordForPublicLink')
  245. || !this.model.get('linkShare').password);
  246. this.$el.html(linkShareTemplate({
  247. cid: this.cid,
  248. shareAllowed: true,
  249. isLinkShare: isLinkShare,
  250. shareLinkURL: this.model.get('linkShare').link,
  251. linkShareLabel: t('core', 'Share link'),
  252. urlLabel: t('core', 'Link'),
  253. enablePasswordLabel: t('core', 'Password protect'),
  254. passwordLabel: t('core', 'Password'),
  255. passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE,
  256. isPasswordSet: isPasswordSet,
  257. showPasswordCheckBox: showPasswordCheckBox,
  258. publicUpload: publicUpload && isLinkShare,
  259. publicUploadChecked: publicUploadChecked,
  260. publicUploadLabel: t('core', 'Allow editing'),
  261. mailPublicNotificationEnabled: isLinkShare && this.configModel.isMailPublicNotificationEnabled(),
  262. mailPrivatePlaceholder: t('core', 'Email link to person'),
  263. mailButtonText: t('core', 'Send')
  264. }));
  265. var $emailField = this.$el.find('.emailField');
  266. if (isLinkShare && $emailField.length !== 0) {
  267. $emailField.autocomplete({
  268. minLength: 1,
  269. source: function (search, response) {
  270. $.get(
  271. OC.generateUrl('core/ajax/share.php'), {
  272. fetch: 'getShareWithEmail',
  273. search: search.term
  274. }, function(result) {
  275. if (result.status == 'success' && result.data.length > 0) {
  276. response(result.data);
  277. }
  278. });
  279. },
  280. select: function( event, item ) {
  281. $emailField.val(item.item.email);
  282. return false;
  283. }
  284. })
  285. .data("ui-autocomplete")._renderItem = function( ul, item ) {
  286. return $('<li>')
  287. .append('<a>' + escapeHTML(item.displayname) + "<br>" + escapeHTML(item.email) + '</a>' )
  288. .appendTo( ul );
  289. };
  290. }
  291. // TODO drop with IE8 drop
  292. if($('html').hasClass('ie8')) {
  293. this.$el.find('#linkPassText').removeAttr('placeholder');
  294. this.$el.find('#linkPassText').val('');
  295. }
  296. this.delegateEvents();
  297. return this;
  298. },
  299. /**
  300. * @returns {Function} from Handlebars
  301. * @private
  302. */
  303. template: function () {
  304. if (!this._template) {
  305. this._template = Handlebars.compile(TEMPLATE);
  306. }
  307. return this._template;
  308. }
  309. });
  310. OC.Share.ShareDialogLinkShareView = ShareDialogLinkShareView;
  311. })();