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 11(function () { 12 if (!OC.Share) { 13 OC.Share = {}; 14 } 15 16 var PASSWORD_PLACEHOLDER_STARS = '**********'; 17 var PASSWORD_PLACEHOLDER_MESSAGE = t('core', 'Choose a password'); 18 var TEMPLATE = 19 '<div class="error-message-global hidden"></div>' + 20 '<div class="public-link-modal">'+ 21 '<div class="public-link-modal--item">' + 22 '<label class="public-link-modal--label">{{linkNameLabel}}</label>' + 23 '<input class="public-link-modal--input" type="text" name="linkName" placeholder="{{namePlaceholder}}" value="{{name}}" maxlength="64" />' + 24 '</div>' + 25 '<div id="allowPublicRead-{{cid}}" class="public-link-modal--item">' + 26 '<input type="radio" value="{{publicReadValue}}" name="publicPermissions" id="sharingDialogAllowPublicRead-{{cid}}" class="checkbox publicPermissions" {{#if publicReadSelected}}checked{{/if}} />' + 27 '<label class="bold" for="sharingDialogAllowPublicRead-{{cid}}">{{publicReadLabel}}</label>' + 28 '<p><em>{{publicReadDescription}}</em></p>' + 29 '</div>' + 30 '{{#if publicUploadPossible}}' + 31 '<div id="allowPublicReadWrite-{{cid}}" class="public-link-modal--item">' + 32 '<input type="radio" value="{{publicReadWriteValue}}" name="publicPermissions" id="sharingDialogAllowPublicReadWrite-{{cid}}" class="checkbox publicPermissions" {{#if publicReadWriteSelected}}checked{{/if}} />' + 33 '<label class="bold" for="sharingDialogAllowPublicReadWrite-{{cid}}">{{publicReadWriteLabel}}</label>' + 34 '<p><em>{{publicReadWriteDescription}}</em></p>' + 35 '</div>' + 36 '<div id="allowPublicUploadWrapper-{{cid}}" class="public-link-modal--item">' + 37 '<input type="radio" value="{{publicUploadValue}}" name="publicPermissions" id="sharingDialogAllowPublicUpload-{{cid}}" class="checkbox publicPermissions" {{#if publicUploadSelected}}checked{{/if}} />' + 38 '<label class="bold" for="sharingDialogAllowPublicUpload-{{cid}}">{{publicUploadLabel}}</label>' + 39 '<p><em>{{publicUploadDescription}}</em></p>' + 40 '</div>' + 41 '{{/if}}' + 42 '<div id="linkPass-{{cid}}" class="public-link-modal--item linkPass">' + 43 '<label class="public-link-modal--label" for="linkPassText-{{cid}}">{{passwordLabel}}</label>' + 44 '<input class="public-link-modal--input linkPassText" id="linkPassText-{{cid}}" type="password" autocomplete="off" placeholder="{{passwordPlaceholder}}" />' + 45 '<span class="error-message hidden"></span>' + 46 '</div>' + 47 '<div class="expirationDateContainer"></div>' + 48 '{{#if isMailEnabled}}' + 49 '<div class="mailView"></div>' + 50 '{{/if}}' + 51 '</div>' 52 ; 53 54 /** 55 * @class OCA.Share.ShareDialogLinkShareView 56 * @member {OC.Share.ShareItemModel} model 57 * @member {jQuery} $el 58 * @memberof OCA.Sharing 59 * @classdesc 60 * 61 * Represents the GUI of the share dialogue 62 * 63 */ 64 var ShareDialogLinkShareView = OC.Backbone.View.extend({ 65 /** @type {string} **/ 66 id: 'shareDialogLinkShare', 67 68 className: 'shareDialogLinkShare', 69 70 /** @type {OC.Share.ShareConfigModel} **/ 71 configModel: undefined, 72 73 /** @type {OC.Share.ShareItemModel} **/ 74 itemModel: undefined, 75 76 /** @type {Function} **/ 77 _template: undefined, 78 79 initialize: function (options) { 80 if (!_.isUndefined(options.itemModel)) { 81 this.itemModel = options.itemModel; 82 this.configModel = this.itemModel.configModel; 83 } else { 84 throw 'missing OC.Share.ShareItemModel'; 85 } 86 87 this.expirationView = new OC.Share.ShareDialogExpirationView({ 88 model: this.model, 89 itemModel: this.itemModel 90 }); 91 92 OC.Plugins.attach('OCA.Share.ShareDialogLinkShareView', this); 93 }, 94 95 /** 96 * Returns the selected permissions as read from the checkboxes or 97 * the absence thereof. 98 * 99 * @return {int} permissions 100 */ 101 _getPermissions: function() { 102 var permissions = this.$('input[name="publicPermissions"]:checked').val(); 103 104 return (permissions) ? parseInt(permissions, 10) : OC.PERMISSION_READ; 105 }, 106 107 _shouldRequirePassword: function() { 108 // matching passwordMustBeEnforced from server side 109 var permissions = this._getPermissions(); 110 var roEnforcement = permissions === OC.PERMISSION_READ && this.configModel.get('enforceLinkPasswordReadOnly'); 111 var woEnforcement = permissions === OC.PERMISSION_CREATE && this.configModel.get('enforceLinkPasswordWriteOnly'); 112 var rwEnforcement = (permissions !== OC.PERMISSION_READ && permissions !== OC.PERMISSION_CREATE) && this.configModel.get('enforceLinkPasswordReadWrite'); 113 if (roEnforcement || woEnforcement || rwEnforcement) { 114 return true; 115 } else { 116 return false;
117 } 118 }, 119 120 _save: function () { 121 var deferred = $.Deferred(); 122 var $el = this.$el; 123 124 var $formElements = $el.find('input, textarea, select, button'), 125 $select2Elements = $el.find('.select2-search-choice-close'), 126 $password = $el.find('.linkPassText'), 127 $inputs = $el.find('.linkPassText, .expirationDate, .permission'), // all input fields combined 128 $errorMessageGlobal = $el.find('.error-message-global'), 129 $loading = $el.find('.loading'), 130 131 password = $password.val(), 132 expirationDate = this.expirationView.getValue(); 133 134 $el.find('.error-message').addClass('hidden'); 135 136 // prevent tinkering with form while loading 137 $formElements.attr('disabled', true); 138 $select2Elements.addClass('hidden'); 139 140 // remove errors 141 $inputs.removeClass('error'); 142 $errorMessageGlobal.addClass('hidden'); 143 144 // explicit attributes to be saved 145 var attributes = { 146 expireDate: expirationDate, 147 permissions: this._getPermissions(), 148 name: this.$('[name=linkName]').val(), 149 shareType: this.model.get('shareType') 150 }; 151 152 // Reset password for the time being 153 if (this.model.get("resetPassword")) { 154 attributes.password = ''; 155 } 156 157 if (password) { 158 // only set password explicitly if changed 159 attributes.password = password; 160 } 161 162 var validates = true; 163 validates &= this.expirationView.validate(); 164 165 if (!password 166 && this._shouldRequirePassword() 167 && (this.model.isNew() || !this.model.get('encryptedPassword')) 168 ) { 169 $password.addClass('error'); 170 $password.next('.error-message').removeClass('hidden').text(t('core', 'Password required')); 171 validates = false; 172 } 173 174 if (!validates) { 175 $loading.addClass('hidden'); 176 $formElements.removeAttr('disabled'); 177 $select2Elements.removeClass('hidden'); 178 return deferred.reject(this.model); 179 } 180 181 if (this.model.isNew()) { 182 // the API is inconsistent 183 attributes.path = this.itemModel.getFileInfo().getFullPath(); 184 } 185 186 var self = this; 187 188 var done = function() { 189 $loading.addClass('hidden'); 190 deferred.resolve(self.model); 191 self.trigger('saved', self.model); 192 }; 193 194 $loading.removeClass('hidden'); 195 196 // save it 197 // *** 198 this.model.save(attributes, { 199 // explicit attributes for patch-like PUT to avoid 200 // passing all attributes 201 attrs: attributes, 202 success: function() { 203 if (self.mailView) { 204 // also send out email first 205 // do not resolve on errors 206 self.mailView.sendEmails().then(done); 207 } else { 208 done(); 209 } 210 self.model.unset("resetPassword"); 211 }, 212 error: function (model, xhr) { 213 var msg = xhr.responseJSON.ocs.meta.message; 214 // destroy old tooltips 215 $loading.addClass('hidden'); 216 $formElements.removeAttr('disabled'); 217 $select2Elements.removeClass('hidden'); 218 $errorMessageGlobal.removeClass('hidden').text(msg); 219 deferred.reject(self.model); 220 } 221 }); 222 223 return deferred.promise(); 224 }, 225 226 _remove: function () { 227 this.model.destroy(); 228 }, 229 230 _isPublicUploadPossible: function() { 231 // TODO: in the future to read directly from the FileInfoModel 232 return this.itemModel.isFolder() && this.itemModel.createPermissionPossible() && this.configModel.isPublicUploadEnabled(); 233 }, 234 235 render: function () { 236 var isPasswordSet = !!this.model.get('encryptedPassword'); 237 238 // only show email field for new shares and if enabled globally 239 var showEmailField = this.configModel.isMailPublicNotificationEnabled(); 240 241 this.$el.html(this.template({ 242 cid: this.cid, 243 passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER_STARS : PASSWORD_PLACEHOLDER_MESSAGE, 244 linkNameLabel: t('core', 'Link name'), 245 namePlaceholder: t('core', 'Name'), 246 name: this.model.get('name'), 247 isPasswordSet: isPasswordSet, 248 249 fileNameLabel : t('core', 'Filename'), 250 passwordLabel : t('core', 'Password'), 251 252 publicUploadPossible : this._isPublicUploadPossible(), 253 254 publicUploadLabel : t('core', 'Upload only') + ' (File Drop)', 255 publicUploadDescription : t('core', 'Receive files from multiple recipients without reveal
255ing the contents of the folder.'), 256 publicUploadValue : OC.PERMISSION_CREATE, 257 publicUploadSelected : this.model.get('permissions') === OC.PERMISSION_CREATE, 258 259 publicReadLabel : t('core', 'Download / View'), 260 publicReadDescription : t('core', 'Recipients can view or download contents.'), 261 publicReadValue : OC.PERMISSION_READ, 262 publicReadSelected : this.model.get('permissions') === OC.PERMISSION_READ, 263 264 publicReadWriteLabel : t('core', 'Download / View / Upload'), 265 publicReadWriteDescription : t('core', 'Recipients can view, download, edit, delete and upload contents.'), 266 publicReadWriteValue : OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_DELETE, 267 publicReadWriteSelected : this.model.get('permissions') >= (OC.PERMISSION_READ | OC.PERMISSION_UPDATE | OC.PERMISSION_CREATE | OC.PERMISSION_DELETE), 268 269 isMailEnabled: showEmailField 270 })); 271 272 this.$('.datepicker').datepicker({dateFormat : 'dd-mm-yy'}); 273 274 if (showEmailField) { 275 this.mailView = new OC.Share.ShareDialogMailView({ 276 itemModel: this.itemModel, 277 configModel: this.configModel, 278 model: this.model 279 }); 280 this.mailView.render(); 281 this.$('.mailView').append(this.mailView.$el); 282 } else { 283 this.mailView = null; 284 } 285 286 this.expirationView.render(); 287 this.$('.expirationDateContainer').append(this.expirationView.$el); 288 289 this.delegateEvents(); 290 291 return this; 292 }, 293 294 _onClickReset: function () { 295 var $dialog = $('.oc-dialog:visible'), 296 $inputPassword = $dialog.find('.linkPassText'), 297 $buttonReset = $dialog.find('.removePassword'); 298 299 this.model.set("resetPassword", true); 300 301 $inputPassword 302 .val('') 303 .attr('placeholder', PASSWORD_PLACEHOLDER_MESSAGE); 304 305 $buttonReset.remove(); 306 }, 307 308 _onClickSave: function() { 309 var self = this; 310 this._save().then(function() { 311 self.$dialog.ocdialog('close'); 312 }); 313 }, 314 315 _onClickCancel: function() { 316 this.$dialog.ocdialog('close'); 317 this.model.unset("resetPassword"); 318 }, 319 /** 320 * @returns {Function} from Handlebars 321 * @private 322 */ 323 template: function (data) { 324 if (!this._template) { 325 this._template = Handlebars.compile(TEMPLATE); 326 } 327 return this._template(data); 328 }, 329 330 /** 331 * Display this view inside a popup window 332 */ 333 show: function() { 334 var self = this; 335 var title = t('core', 'Edit link share: {name}', {name: this.itemModel.getFileInfo().getFullPath()}); 336 var buttons = [{ 337 text: t('core', 'Cancel'), 338 click: _.bind(this._onClickCancel, this) 339 }]; 340 341 if (this.model.isNew()) { 342 title = t('core', 'Create link share: {name}', {name: this.itemModel.getFileInfo().getFullPath()}); 343 buttons.push({ 344 text: t('core', 'Share'), 345 click: _.bind(this._onClickSave, this), 346 defaultButton: true 347 }) 348 } 349 else { 350 buttons.push({ 351 text: t('core', 'Save'), 352 click: _.bind(this._onClickSave, this), 353 defaultButton: true 354 }) 355 } 356 357 if (this.model.get('encryptedPassword')) { 358 buttons.push({ 359 classes: 'removePassword', 360 text: t('core', 'Remove password'), 361 click: _.bind(this._onClickReset, this), 362 defaultButton: false 363 }); 364 } 365 366 // hack the dialogs 367 OC.dialogs.message( 368 '', 369 title, 370 'custom', 371 buttons, 372 null, 373 true, 374 'public-link-modal' 375 ).then(function adjustDialog() { 376 var $dialogShell = $('.oc-dialog:visible'); 377 self.render(); 378 self.$dialog = $dialogShell.find('.oc-dialog-content'); 379 self.$dialog.html(self.$el); 380 self.$el.find('input:first').focus(); 381 }); 382 } 383 384}); 385 386 OC.Share.ShareDialogLinkShareView = ShareDialogLinkShareView; 387 388})();
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.