AspectJ Browser AJBrowser presents a GUI for compiling programs with ajc and navigating crosscutting structure. The AspectJ Browser can edit program source files, compile using the AspectJ compiler ajc run a program, and graphically navigate the program's crosscutting structure. For more information on ajc, see . Launch the browser from the command line either by typing "ajbrowser" to invoke the script in {aspectj}/bin (if AspectJ is installed correctly) or by using the aspectjtools.jar directly, and specifying no arguments or some number of build configuration files (suffix .lst): java -jar aspectj1.1/lib/aspectjtools.jar aspectj1.1/doc/examples/spacewar/debug.lst Building Programs Build Configurations A build configuration is a set of files to compile for a program (and optionally some additional compile arguments). Because ajc requires all sources to be specified (at least using the -sourceroots option), most users create .lst files that list the files to compile (one argument per line, globbing permitted - for more details, see ). To work with a particular program, select the corresponding ".lst" build configuration file from the GUI using the File menu, "open" item, or by using the "Open Build Configuration" button ( ). You can populate the build list from the command line by passing any number of ".lst" paths. (However, if you pass in any non-".lst" arguments, it will run the command-line compiler directly.) To switch between build configurations, select, add, or remove them using the corresponding toolbar buttons. Global build options are stored in an .ajbrowser file in your HOME directory. Edit these from the GUI by clicking the "Options" button or selecting the Tools menu item "Options...". This is how to set classpath, aspectpath, etc. The following sections walk through a build. Compiling a Program Build Configuration To compile click the "Build" button ( ), or or use the tools menu. To build using AspectJ 1.1's incremental mode, click the incremental compile checkbox in the AspectJ Build Options tab of the Options dialog. Once in incremental mode, you can force a full rebuild by holding the shift key down when selecting the build menu item or button. You may select from different build configurations in the GUI (see label 1 in the graphic below). (If you get classpath or other errors, set up the global build options as described above.) Navigating Program Structure Select nodes in the program structure by clicking them (see label 2). If one node is related to one or more other nodes by an association the name of the association will appear below that node and will be displayed in italics. Links to other structure nodes appear in blue below the association. If there is no corresponding source for the link it will appear light-blue. Example: Exploring the "Spacewar" sample code Launch ajbrowser Choose "File -> Open" or click the "Open Build Configuration" button ( ) and select the configuration file for debugging the spacewar example, in examples/spacewar/debug.lst. Click the "Build" button ( ) to compile. The left pane should fill with a spacewar declaration tree. If there is a compiler error, the clickable error message shows up as in label 4. Note: If you did not set up your classpath, the compile will fail with a message that you need to install aspectjrt.jar on your compile classpath. To do that, select "Tools -> Options" or click the "Options" button ( ). Click the Build Options tab to view the Build Paths pane. Edit the classpath entry to use your install location. For example, if you ran from the base Aspectj directory, the classpath need only include lib/aspectjrt.jar (though the browser may populate the classpath with the bootclasspath and classpath initially.) Be sure to use the lib/aspectjrt.jar that came with the browser. Different structure views: The structure tree at the left can display different orderings and granularity for structure: The package hierarchy view shows the traditional hierarchy of package, class, and members. The inheritance view shows the hierarchy from topmost parent classes through subclasses to members. The crosscutting view shows the aspect members and the code they affect. Additional buttons in the pane can be used to change the granularity and filter out items. Whenever you select an item in the tree view, the source pane scrolls to that item. If you select a leaf item representing another program element, then the tree selection will go to the corresponding node. (See below for how to use two panes to maintain your place.) When working with aspects, it helps to be able to navigate between different program elements: When looking at a method, find the advice that affects it. When looking at a pointcut, find the advice that uses it. When looking at advice, find what it advises - e.g., method calls or executions, initializers, etc. When looking at a type, find any aspects that declare members or supertypes of the type, or vice-versa. You can view the advice on a particular method using the default, hierarchical view. Navigate to the tree item for spacewar.Registry.register(SpaceObject) in the debug.lst config file. Now, in the lower, file view, you can see and navigate to the advice using the subtree whose parent is the method affected by relation. You can also use crosscutting view to see the advice using a pointcut or the methods affected by advice. For example, to see what advice uses a particular pointcut, navigate to the tree item for the pointcut spacewar.Debug.allConstructorsCut() in the debug.lst config file. You can see and navigate to the advice that uses the pointcut using the pointcut used by relation. As an example of seeing the methods affected by advice, while still in the same view, select the first before advice in spacewar.Debug. It has relation sub-trees for both uses pointcut and affects constructions. The affects relations will list different kinds of join points - constructor or method calls, etc. Note that the AspectJ browser can only display static structure (whether hierarchical or crosscutting). That means that dynamicly-determined pointcuts (like cflow(pointcut)) will not be shown as picking out static points in source code. Displayable pointcuts roughly correspond to those that can be used in a declare error statement. Running Programs The browser supports a limited form of running compiled programs. To run programs that have been built, click the run button or select one of the run menu items in the project menu. You can run in the same VM or spawn a new process; the latter is generally better for GUI programs. Both require that any classpath you set be specified using platform-specific paths and path separators (the compiler might be more tolerant). Output and error streams will be merged into the streams of the browser (using separate threads, so it may take a few seconds for the pipe threads to gain control.) Errors should be detected and displayed in a dialog. The GUI does not support killing a running program, so if your program might hang, be sure to save your files since you may need to kill the browser itself to kill its child processes. Isolating problems running the AspectJ browser If you have problems with the browser not solved by the documentation, please try to see if you have the same problems when running ajc directly on the command line. If the problem occurs on the command line also, then the problem is not in the browser. (It may be in the compiler; please send bug reports.) If the problem does not occur on the command line, then it may lie in the parameters you are supplying in the build options. If the build options look correct and the problem only occurs when building from the browser, then please submit a bug report. Known issues with the AspectJ browser For the most up-to-date information on known problems, see the bug database for unresolved compiler bugs or IDE bugs . Memory and forking: Users email most about the browser task running out of memory. This is not a problem with the browser; some compiles take a lot of memory, often more than similar compiles using javac. The browser does not support forking, so the only solution is to edit the java command line or script that launches the browser to add memory. Editing build configuration files: this is not currently supported. The structure model is incomplete after incremental compiles. To get a complete structure model requires a full build. If you change the output directory, you must do a full build. Limitations The AJBrowser expects the package and directory structure to match. If they do not it will be unable to browse to the corresponding file. The "Run" feature launches applications in the same VM. As a result, if a Swing application is disposed the AJBrowser will be disposed as well. AspectJ Browser questions and bugs You can send email to aspectj-users@dev.eclipse.org. (Do join the list to participate!) We also welcome any bug reports, patches, and feature requests; you can submit them to the bug database at http://bugs.eclipse.org/bugs using the AspectJ product and IDE component. kport/39611/stable30 Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
aboutsummaryrefslogtreecommitdiffstats
path: root/core/js/sharedialoglinkshareview.js
blob: 29dce21486cda034669765d42c8b2d2c536aa8bf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*
 * Copyright (c) 2015
 *
 * This file is licensed under the Affero General Public License version 3
 * or later.
 *
 * See the COPYING-README file.
 *
 */

(function() {
	if (!OC.Share) {
		OC.Share = {};
	}

	var PASSWORD_PLACEHOLDER = '**********';
	var PASSWORD_PLACEHOLDER_MESSAGE = t('core', 'Choose a password for the public link');

	var TEMPLATE =
			'{{#if shareAllowed}}' +
			'<span class="icon-loading-small hidden"></span>' +
			'<input type="checkbox" name="linkCheckbox" id="linkCheckbox-{{cid}}" class="checkbox linkCheckbox" value="1" {{#if isLinkShare}}checked="checked"{{/if}} />' +
			'<label for="linkCheckbox-{{cid}}">{{linkShareLabel}}</label>' +
			'<br />' +
			'<label for="linkText-{{cid}}" class="hidden-visually">{{urlLabel}}</label>' +
			'<input id="linkText-{{cid}}" class="linkText {{#unless isLinkShare}}hidden{{/unless}}" type="text" readonly="readonly" value="{{shareLinkURL}}" />' +
			'   {{#if showPasswordCheckBox}}' +
			'<input type="checkbox" name="showPassword" id="showPassword-{{cid}}" class="checkbox showPasswordCheckbox" {{#if isPasswordSet}}checked="checked"{{/if}} value="1" />' +
			'<label for="showPassword-{{cid}}">{{enablePasswordLabel}}</label>' +
			'   {{/if}}' +
			'<div id="linkPass" class="linkPass {{#unless isPasswordSet}}hidden{{/unless}}">' +
			'    <label for="linkPassText-{{cid}}" class="hidden-visually">{{passwordLabel}}</label>' +
			'    <input id="linkPassText-{{cid}}" class="linkPassText" type="password" placeholder="{{passwordPlaceholder}}" />' +
			'    <span class="icon-loading-small hidden"></span>' +
			'</div>' +
			'    {{#if publicUpload}}' +
			'<div id="allowPublicUploadWrapper">' +
			'    <span class="icon-loading-small hidden"></span>' +
			'    <input type="checkbox" value="1" name="allowPublicUpload" id="sharingDialogAllowPublicUpload-{{cid}}" class="checkbox publicUploadCheckbox" {{{publicUploadChecked}}} />' +
			'<label for="sharingDialogAllowPublicUpload-{{cid}}">{{publicUploadLabel}}</label>' +
			'</div>' +
			'    {{/if}}' +
			'    {{#if mailPublicNotificationEnabled}}' +
			'<form id="emailPrivateLink" class="emailPrivateLinkForm">' +
			'    <input id="email" class="emailField" value="" placeholder="{{mailPrivatePlaceholder}}" type="text" />' +
			'    <input id="emailButton" class="emailButton" type="submit" value="{{mailButtonText}}" />' +
			'</form>' +
			'    {{/if}}' +
			'{{else}}' +
			// FIXME: this doesn't belong in this view
			'<input id="shareWith-{{cid}}" class="shareWithField" type="text" placeholder="{{noSharingPlaceholder}}" disabled="disabled"/>' +
			'{{/if}}'
		;

	/**
	 * @class OCA.Share.ShareDialogLinkShareView
	 * @member {OC.Share.ShareItemModel} model
	 * @member {jQuery} $el
	 * @memberof OCA.Sharing
	 * @classdesc
	 *
	 * Represents the GUI of the share dialogue
	 *
	 */
	var ShareDialogLinkShareView = OC.Backbone.View.extend({
		/** @type {string} **/
		id: 'shareDialogLinkShare',

		/** @type {OC.Share.ShareConfigModel} **/
		configModel: undefined,

		/** @type {Function} **/
		_template: undefined,

		/** @type {boolean} **/
		showLink: true,

		events: {
			'submit .emailPrivateLinkForm': '_onEmailPrivateLink',
			'focusout input.linkPassText': 'onPasswordEntered',
			'keyup input.linkPassText': 'onPasswordKeyUp',
			'click .linkCheckbox': 'onLinkCheckBoxChange',
			'click .linkText': 'onLinkTextClick',
			'change .publicUploadCheckbox': 'onAllowPublicUploadChange',
			'click .showPasswordCheckbox': 'onShowPasswordClick'
		},

		initialize: function(options) {
			var view = this;

			this.model.on('change:permissions', function() {
				view.render();
			});

			this.model.on('change:itemType', function() {
				view.render();
			});

			this.model.on('change:allowPublicUploadStatus', function() {
				view.render();
			});

			this.model.on('change:linkShare', function() {
				view.render();
			});

			if(!_.isUndefined(options.configModel)) {
				this.configModel = options.configModel;
			} else {
				throw 'missing OC.Share.ShareConfigModel';
			}

			_.bindAll(
				this,
				'_onEmailPrivateLink',
				'onLinkCheckBoxChange',
				'onPasswordEntered',
				'onPasswordKeyUp',
				'onLinkTextClick',
				'onShowPasswordClick',
				'onAllowPublicUploadChange'
			);
		},

		onLinkCheckBoxChange: function() {
			var $checkBox = this.$el.find('.linkCheckbox');
			var $loading = $checkBox.siblings('.icon-loading-small');
			if(!$loading.hasClass('hidden')) {
				return false;
			}

			if($checkBox.is(':checked')) {
				if(this.configModel.get('enforcePasswordForPublicLink') === false) {
					$loading.removeClass('hidden');
					// this will create it
					this.model.saveLinkShare();
				} else {
					this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
					this.$el.find('.linkPassText').focus();
				}
			} else {
				$loading.removeClass('hidden');
				if (this.model.get('linkShare').isLinkShare) {
					this.model.removeLinkShare();
				} else {
					this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
				}
			}
		},

		onLinkTextClick: function() {
			var $el = this.$el.find('.linkText');
			$el.focus();
			$el.select();
		},

		onShowPasswordClick: function() {
			this.$el.find('.linkPass').slideToggle(OC.menuSpeed);
			if(!this.$el.find('.showPasswordCheckbox').is(':checked')) {
				this.model.setPassword('');
				this.model.saveLinkShare();
			} else {
				this.$el.find('.linkPassText').focus();
			}
		},

		onPasswordKeyUp: function(event) {
			if(event.keyCode == 13) {
				this.onPasswordEntered();
			}
		},

		onPasswordEntered: function() {
			var self = this;
			var $loading = this.$el.find('.linkPass .icon-loading-small');
			if (!$loading.hasClass('hidden')) {
				// still in process
				return;
			}
			var $input = this.$el.find('.linkPassText');
			$input.removeClass('error');
			var password = $input.val();
			// in IE9 the password might be the placeholder due to bugs in the placeholders polyfill
			if(password === '' || password === PASSWORD_PLACEHOLDER || password === PASSWORD_PLACEHOLDER_MESSAGE) {
				return;
			}

			$loading
				.removeClass('hidden')
				.addClass('inlineblock');

			this.model.setPassword(password);
			this.model.saveLinkShare({}, {
				error: function(model, msg) {
					$loading.removeClass('inlineblock').addClass('hidden');
					$input.addClass('error');
					$input.attr('title', msg);
					$input.tooltip({placement: 'bottom', trigger: 'manual'});
					$input.tooltip('show');
				}
			});
		},

		onAllowPublicUploadChange: function() {
			var $checkbox = this.$('.publicUploadCheckbox');
			$checkbox.siblings('.icon-loading-small').removeClass('hidden').addClass('inlineblock');
			this.model.setPublicUpload($checkbox.is(':checked'));
			this.model.saveLinkShare();
		},

		_onEmailPrivateLink: function(event) {
			event.preventDefault();

			var $emailField = this.$el.find('.emailField');
			var $emailButton = this.$el.find('.emailButton');
			var email = $emailField.val();
			if (email !== '') {
				$emailField.prop('disabled', true);
				$emailButton.prop('disabled', true);
				$emailField.val(t('core', 'Sending ...'));
				this.model.sendEmailPrivateLink(email).done(function() {
					$emailField.css('font-weight', 'bold').val(t('core','Email sent'));
					setTimeout(function() {
						$emailField.val('');
						$emailField.css('font-weight', 'normal');
						$emailField.prop('disabled', false);
						$emailButton.prop('disabled', false);
					}, 2000);
				}).fail(function() {
					$emailField.val(email);
					$emailField.css('font-weight', 'normal');
					$emailField.prop('disabled', false);
					$emailButton.prop('disabled', false);
				});
			}
			return false;
		},

		render: function() {
			var linkShareTemplate = this.template();

			if(    !this.model.sharePermissionPossible()
				|| !this.showLink
				|| !this.configModel.isShareWithLinkAllowed())
			{
				this.$el.html(linkShareTemplate({
					shareAllowed: false,
					noSharingPlaceholder: t('core', 'Resharing is not allowed')
				}));
				return this;
			}

			var publicUpload =
				this.model.isFolder()
				&& this.model.createPermissionPossible()
				&& this.configModel.isPublicUploadEnabled();

			var publicUploadChecked = '';
			if(this.model.isPublicUploadAllowed()) {
				publicUploadChecked = 'checked="checked"';
			}

			var isLinkShare = this.model.get('linkShare').isLinkShare;
			var isPasswordSet = !!this.model.get('linkShare').password;
			var showPasswordCheckBox = isLinkShare
				&& (   !this.configModel.get('enforcePasswordForPublicLink')
					|| !this.model.get('linkShare').password);

			this.$el.html(linkShareTemplate({
				cid: this.cid,
				shareAllowed: true,
				isLinkShare: isLinkShare,
				shareLinkURL: this.model.get('linkShare').link,
				linkShareLabel: t('core', 'Share link'),
				urlLabel: t('core', 'Link'),
				enablePasswordLabel: t('core', 'Password protect'),
				passwordLabel: t('core', 'Password'),
				passwordPlaceholder: isPasswordSet ? PASSWORD_PLACEHOLDER : PASSWORD_PLACEHOLDER_MESSAGE,
				isPasswordSet: isPasswordSet,
				showPasswordCheckBox: showPasswordCheckBox,
				publicUpload: publicUpload && isLinkShare,
				publicUploadChecked: publicUploadChecked,
				publicUploadLabel: t('core', 'Allow editing'),
				mailPublicNotificationEnabled: isLinkShare && this.configModel.isMailPublicNotificationEnabled(),
				mailPrivatePlaceholder: t('core', 'Email link to person'),
				mailButtonText: t('core', 'Send')
			}));

			var $emailField = this.$el.find('.emailField');
			if (isLinkShare && $emailField.length !== 0) {
				$emailField.autocomplete({
					minLength: 1,
					source: function (search, response) {
						$.get(
							OC.generateUrl('core/ajax/share.php'), {
								fetch: 'getShareWithEmail',
								search: search.term
							}, function(result) {
								if (result.status == 'success' && result.data.length > 0) {
									response(result.data);
								}
							});
						},
					select: function( event, item ) {
						$emailField.val(item.item.email);
						return false;
					}
				})
				.data("ui-autocomplete")._renderItem = function( ul, item ) {
					return $('<li>')
						.append('<a>' + escapeHTML(item.displayname) + "<br>" + escapeHTML(item.email) + '</a>' )
						.appendTo( ul );
				};
			}

			// TODO drop with IE8 drop
			if($('html').hasClass('ie8')) {
				this.$el.find('#linkPassText').removeAttr('placeholder');
				this.$el.find('#linkPassText').val('');
			}

			this.delegateEvents();

			return this;
		},

		/**
		 * @returns {Function} from Handlebars
		 * @private
		 */
		template: function () {
			if (!this._template) {
				this._template = Handlebars.compile(TEMPLATE);
			}
			return this._template;
		}

	});

	OC.Share.ShareDialogLinkShareView = ShareDialogLinkShareView;

})();