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 TEMPLATE = 17 '<span class="icon-loading-small hidden"></span>' + 18 '<ul class="link-shares">' + 19 '{{#each shares}}' + 20 '<li class="link-entry" data-id="{{id}}">' + 21 '<span class="link-entry--icon icon-public-white"></span>' + 22 '<span class="link-entry--title">{{linkTitle}}</span>' + 23 '<div class="minify"><input id="linkText-{{../cid}}-{{id}}" class="linkText" type="text" readonly="readonly" value="{{link}}" /></div>' + 24 '<div class="link-entry--icon-button clipboardButton" data-clipboard-target="#linkText-{{../cid}}-{{id}}" title="{{../copyToClipboardText}}">' + 25 ' <span class="icon icon-clippy-dark"></span>' + 26 ' <span class="hidden">{{../copyToClipboardText}}</span>' + 27 '</div>' + 28 '<div class="link-entry--icon-button editLink" title="{{../editLinkText}}">' + 29 ' <span class="icon icon-settings-dark"></span>' + 30 ' <span class="hidden">{{../editLinkText}}</span>' + 31 '</div>' + 32 '{{#if ../socialShareEnabled}}' + 33 '<div class="link-entry--icon-button shareLink" title="{{../shareText}}">' + 34 ' <span class="icon icon-shared"></span>' + 35 ' <span class="hidden">{{../shareText}}</span>' + 36 '</div>' + 37 '{{/if}}' + 38 '<div class="link-entry--icon-button removeLink" title="{{../removeLinkText}}">' + 39 ' <span class="icon icon-delete"></span>' + 40 ' <span class="hidden">{{../removeLinkText}}</span>' + 41 '</div>' + 42 '{{#if ../socialShareEnabled}}' + 43 '<div class="socialShareContainer hidden"></div>' + 44 '{{/if}}' + 45 '</li>' + 46 '{{/each}}' + 47 '</ul>' + 48 '{{#if noShares}}' + 49 '<div class="empty-message">{{noSharesMessage}}</div>' + 50 '{{/if}}' + 51 '<div class="clear-both">' + 52 ' <button class="addLink">{{addLinkText}}</button>' + 53 '</div>' + 54 '<div class="privacyWarningMessage">{{privacyWarningMessage}}</div>'; 55 56 /** 57 * @class OCA.Share.ShareDialogLinkListView 58 * @member {OC.Share.ShareItemModel} model 59 * @member {jQuery} $el 60 * @memberof OCA.Sharing 61 * @classdesc 62 * 63 * Represents the GUI of the share dialogue 64 * 65 */ 66 var ShareDialogLinkListView = OC.Backbone.View.extend({ 67 /** @type {string} **/ 68 id: 'shareDialogLinkList', 69 70 className: 'shareDialogLinkList', 71 72 /** @type {OCA.Files.FileInfoModel} **/ 73 fileInfoModel: undefined, 74 75 /** @type {OC.Share.ShareConfigModel} **/ 76 configModel: undefined, 77 78 /** @type {OC.Share.ShareItemModel} **/ 79 itemModel: undefined, 80 81 /** @type {Function} **/ 82 _template: undefined, 83 84 events: { 85 'click .addLink': 'onAddButtonClick', 86 'click .editLink': 'onEditButtonClick', 87 'click .removeLink': 'onRemoveButtonClick', 88 'click .shareLink': 'onShareButtonClick' 89 }, 90 91 initialize: function (options) { 92 var view = this; 93 94 // if any item in the list changes, render the whole thing 95 this.collection.on('change update delete', function() { 96 view.render(); 97 }); 98 99 if (!_.isUndefined(options.itemModel)) { 100 this.itemModel = options.itemModel; 101 this.fileInfoModel = this.itemModel.getFileInfo(); 102 this.configModel = this.itemModel.configModel; 103 } else { 104 throw 'missing OC.Share.ShareItemModel'; 105 } 106 }, 107 108 onRemoveButtonClick: function (ev) { 109 var $target = $(ev.target); 110 var linkId = $target.closest('.link-entry').attr('data-id'); 111 112 var linkModel = this.collection.get(linkId); 113 var linkTitle = (linkModel.attributes.name) ? linkModel.attributes.name : linkModel.attributes.token; 114 115 if (!linkModel) { 116 return; 117 } 118 119 OCdialogs.confirm( 120 t('core', 'Delete {link}', { link: linkTitle }), 121 t('core', 'Remove link'), 122 function(cb) { 123 if (cb) { 124 linkModel.destroy(); 125 } 126 }, 127 true 128 ); 129 130 }, 131 132 _generateName: function() { 133 var index = 1; 134 var baseName = OC.getCapabilities()['files_sharing']["public"]["defaultPublicLinkShareName"]; 135 var name = baseName; 136 137 while (this.collection.findWhere({name: name})) { 138 index++; 139 name = baseName + ' (' + index + ')'; 140 } 141 142 return name; 143 }, 144 145 onAddButtonClick: function () { 146 var newShare = new OC.Share.ShareModel({ 147 name: this._generateName(), 148 password: '', 149 permissions: OC.PERMISSION_READ, 150 expireDate: this.configModel.getDefaultExpirationDateString(), 151 shareType: OC.Share.SHARE_TYPE_LINK, 152 itemType: this.itemModel.get('itemType'), 153 itemSource: this.itemModel.get('itemSource') 154 }); 155 this._showPopupForShare(newShare); 156 }, 157 158 onEditButtonClick: function (ev) { 159 var $target = $(ev.target); 160 var linkId = $target.closest('.link-entry').attr('data-id'); 161 162 var linkModel = this.collection.get(linkId); 163 if (!linkModel) { 164 return; 165 } 166 167 this._showPopupForShare(linkModel); 168 }, 169 170 onShareButtonClick: function (ev) { 171 var $target = $(ev.target); 172 var $li = $target.closest('.link-entry'); 173 var linkId = $li.attr('data-id'); 174 var $container = $li.find('.socialShareContainer'); 175 176 var linkModel = this.collection.get(linkId); 177 if (!linkModel) { 178 return; 179 } 180 181 if ($container.is(':empty')) { 182 if (this.configModel.isSocialShareEnabled()) { 183 var socialView = new OC.Share.ShareDialogLinkSocialView({ 184 model: linkModel, 185 configModel: this.configModel 186 }); 187 socialView.render(); 188 $container.append(socialView.$el); 189 $container.removeClass('hidden'); 190 } 191 } else { 192 $container.toggleClass('hidden', !$container.hasClass('hidden')); 193 } 194 }, 195 196 _showPopupForShare: function(model) { 197 var self = this; 198 var popupView = new OC.Share.ShareDialogLinkShareView({ 199 model: model, 200 configModel: this.configModel, 201 // pass in legacy stuff... 202 itemModel: this.itemModel 203 }); 204 205 popupView.once('saved', function() { 206 // add/update in collection on success 207 self.collection.add(model); 208 }); 209 popupView.show(); 210 }, 211 212 _formatItem: function(model) { 213 return _.extend(model.toJSON(), { 214 linkTitle: model.get('name') || model.get('token'), 215 link: this._makeLink(model) 216 }); 217 }, 218 219 _makeLink: function(model) { 220 var link = ''; 221 if (!model.get('token')) {
222 var preTokenLink = OC.getProtocol() + '://' + OC.getHost(); 223 var fullPath = this.fileInfoModel.get('path') + '/' + 224 this.fileInfoModel.get('name'); 225 var location = '/' + OC.currentUser + '/files' + fullPath; 226 var type = this.fileInfoModel.isDirectory() ? 'folder' : 'file'; 227 link = preTokenLink + OC.linkTo('', 'public.php') + '?service=files&' + 228 type + '=' + encodeURIComponent(location); 229 } else { 230 link = model.getLink(); 231 } 232 return link; 233 }, 234 235 render: function () { 236 this.$el.html(this.template({ 237 cid: this.cid, 238 urlLabel: t('core', 'Link'), 239 addLinkText: t('core', 'Create public link'), 240 editLinkText: t('core', 'Edit'), 241 removeLinkText: t('core', 'Remove'), 242 copyToClipboardText: t('core', 'Copy to clipboard'), 243 shareText: t('core', 'Social share'), 244 socialShareEnabled: this.configModel.isSocialShareEnabled(), 245 noShares: !this.collection.length, 246 noSharesMessage: t('core', 'There are currently no link shares, you can create one'), 247 privacyWarningMessage: t('core', 'Anyone with the link has access to the file/folder'), 248 shares: this.collection.map(_.bind(this._formatItem, this)) 249 })); 250 251 this.$el.find('[title]').tooltip(); 252 253 var clipboard = new ClipboardJS('#' + this.id + ' .clipboardButton'); 254 clipboard.on('success', function (e) { 255 var $input = $(e.trigger); 256 $input.tooltip({ 257 placement: 'bottom', 258 trigger: 'manual', 259 title: t('core', 'Copied!') 260 }); 261 $input.tooltip('show'); 262 _.delay(function () { 263 $input.tooltip('hide'); 264 }, 3000); 265 }); 266 clipboard.on('error', function (e) { 267 var $input = $(e.trigger); 268 var actionMsg = ''; 269 if (bowser.ios) { 270 actionMsg = t('core', 'Not supported!'); 271 } else if (bowser.mac) { 272 actionMsg = t('core', 'Press â-C to copy.'); 273 } else { 274 actionMsg = t('core', 'Press Ctrl-C to copy.'); 275 } 276 277 $input.tooltip({ 278 placement: 'bottom', 279 trigger: 'manual', 280 title: actionMsg 281 }); 282 $input.tooltip('show'); 283 _.delay(function () { 284 $input.tooltip('hide'); 285 }, 3000); 286 }); 287 288 this.delegateEvents(); 289 290 return this; 291 }, 292 293 /** 294 * @returns {Function} from Handlebars 295 * @private 296 */ 297 template: function (data) { 298 if (!this._template) { 299 this._template = Handlebars.compile(TEMPLATE); 300 } 301 return this._template(data); 302 } 303 304 }); 305 306 OC.Share.ShareDialogLinkListView = ShareDialogLinkListView; 307 308})();
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.