api/js/egw_action/egw_action_dragdrop.js   F
last analyzed

Complexity

Total Complexity 101
Complexity/F 2.89

Size

Lines of Code 701
Function Count 35

Duplication

Duplicated Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 352
dl 0
loc 701
rs 2
c 0
b 0
f 0
wmc 101
mnd 66
bc 66
fnc 35
bpm 1.8857
cpm 2.8857
noi 4

6 Functions

Rating   Name   Duplication   Size   Complexity  
A egw_action_dragdrop.js ➔ egwDragAction 0 14 3
A egw_action_dragdrop.js ➔ getDragImplementation 0 8 2
B egw_action_dragdrop.js ➔ egwDropAction 0 42 6
A egw_action_dragdrop.js ➔ getDropImplementation 0 8 2
F egw_action_dragdrop.js ➔ egwDragActionImplementation 0 391 59
F egw_action_dragdrop.js ➔ egwDropActionImplementation 0 183 29

How to fix   Complexity   

Complexity

Complex classes like api/js/egw_action/egw_action_dragdrop.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * eGroupWare egw_action framework - egw action framework
3
 *
4
 * @link http://www.egroupware.org
5
 * @author Andreas Stöckel <[email protected]>
6
 * @copyright 2011 by Andreas Stöckel
7
 * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License
8
 * @package egw_action
9
 * @version $Id$
10
 */
11
12
/*egw:uses
13
	egw_action;
14
	egw_action_common;
15
	egw_action_popup;
16
	vendor.bower-asset.jquery.dist.jquery;
17
	/vendor/bower-asset/jquery-ui/jquery-ui.js;
18
*/
19
20
/**
21
 * Register the drag and drop handlers
22
 */
23
if (typeof window._egwActionClasses == "undefined")
24
	window._egwActionClasses = {};
25
_egwActionClasses["drag"] = {
26
	"actionConstructor": egwDragAction,
27
	"implementation": getDragImplementation
28
};
29
_egwActionClasses["drop"] = {
30
	"actionConstructor": egwDropAction,
31
	"implementation": getDropImplementation
32
};
33
34
/**
35
 * The egwDragAction class overwrites the egwAction class and adds the new
36
 * "dragType" propery. The "onExecute" event of the drag action will be called
37
 * whenever dragging starts. The onExecute JS handler should return the
38
 * drag-drop helper object - otherwise an default helper will be generated.
39
 *
40
 * @param {egwAction} _id
41
 * @param {string} _handler
42
 * @param {string} _caption
43
 * @param {string} _icon
44
 * @param {(string|function)} _onExecute
45
 * @param {bool} _allowOnMultiple
46
 * @returns {egwDragAction}
47
 */
48
function egwDragAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
49
{
50
	var action = new egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple);
51
52
	action.type = "drag";
53
	action.dragType = "default";
54
	action.hideOnDisabled = true;
55
56
	action.set_dragType = function(_value) {
57
		action.dragType = _value;
58
	};
59
60
	return action;
61
}
62
63
64
var
65
	_dragActionImpl = null;
66
67
function getDragImplementation()
68
{
69
	if (!_dragActionImpl)
70
	{
71
		_dragActionImpl = new egwDragActionImplementation();
72
	}
73
	return _dragActionImpl;
74
}
75
76
function egwDragActionImplementation()
77
{
78
	var ai = new egwActionImplementation();
79
80
	ai.type = "drag";
81
82
	ai.helper = null;
83
	ai.ddTypes = [];
84
	ai.selected = [];
85
86
	// Define default helper DOM
87
	// default helper also can be called later in application code in order to customization
88
	ai.defaultDDHelper = function (_selected)
89
	{
90
		// Table containing clone of rows
91
		var table = jQuery(document.createElement("table")).addClass('egwGridView_grid et2_egw_action_ddHelper_row');
92
		// tr element to use as last row to show lable more ...
93
		var moreRow = jQuery(document.createElement('tr')).addClass('et2_egw_action_ddHelper_moreRow');
94
		// Main div helper container
95
		var div = jQuery(document.createElement("div")).append(table);
96
97
		var rows = [];
98
		// Maximum number of rows to show
99
		var maxRows = 3;
100
		// item label
101
		var itemLabel = egw.lang(egw.link_get_registry(egw.app_name(),_selected.length > 1?'entries':'entry')||egw.app_name());
102
103
		var index = 0;
104
105
		// Take select all into account when counting number of rows, because they may not be
106
		// in _selected object
107
		var pseudoNumRows = (_selected[0] && _selected[0]._context && _selected[0]._context._selectionMgr &&
108
				_selected[0]._context._selectionMgr._selectAll) ?
109
				_selected[0]._context._selectionMgr._total : _selected.length;
110
111
		for (var i = 0; i < _selected.length;i++)
112
		{
113
			var row = jQuery(_selected[i].iface.getDOMNode()).clone();
114
			if (row)
115
			{
116
				rows.push(row);
117
				table.append(row);
118
			}
119
			index++;
120
			if (index == maxRows)
121
			{
122
				// Lable to show number of items
123
				var spanCnt = jQuery(document.createElement('span'))
124
						.addClass('et2_egw_action_ddHelper_itemsCnt')
125
						.appendTo(div);
126
127
				spanCnt.text(pseudoNumRows +' '+ itemLabel);
128
				// Number of not shown rows
129
				var restRows = pseudoNumRows - maxRows;
130
				if (restRows)
131
				{
132
					moreRow.text((pseudoNumRows - maxRows) +' '+egw.lang('more %1 selected ...', itemLabel));
133
				}
134
				table.append(moreRow);
135
				break;
136
			}
137
		}
138
139
		var text = jQuery(document.createElement('div')).addClass('et2_egw_action_ddHelper_tip');
140
		div.append(text);
141
142
		// Add notice of Ctrl key, if supported
143
		if('draggable' in document.createElement('span') &&
144
			navigator && navigator.userAgent.indexOf('Chrome') >= 0 && egw.app_name() == 'filemanager') // currently only filemanager supports drag out
145
		{
146
			var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ?
147
				egw.lang('Alt') : egw.lang('Command ⌘');
148
			text.text(egw.lang('Hold [%1] and [%2] key to drag %3 to your desktop', key, egw.lang('Shift ⇧'), itemLabel));
149
		}
150
		// Final html DOM return as helper structor
151
		return div;
152
	};
153
154
	ai.doRegisterAction = function(_aoi, _callback, _context)
155
	{
156
		var node = _aoi.getDOMNode();
157
158
		if (node)
159
		{
160
			// Prevent selection
161
			node.onselectstart = function () {
162
				return false;
163
			};
164
			if (!(window.FileReader && 'draggable' in document.createElement('span')) )
165
			{
166
				// No DnD support
167
				return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
168
			}
169
170
			// It shouldn't be so hard to get the action...
171
			var action = null;
172
			var groups = _context.getActionImplementationGroups();
173
			if(!groups.drag) return;
0 ignored issues
show
Comprehensibility Best Practice introduced by
Are you sure this return statement is not missing an argument? If this is intended, consider adding an explicit undefined like return undefined;.
Loading history...
174
			for(var i = 0; i < groups.drag.length; i++)
175
			{
176
				// dragType 'file' says it can be dragged as a file
177
				if(groups.drag[i].link.actionObj.dragType == 'file' || groups.drag[i].link.actionObj.dragType.indexOf('file') > -1)
178
				{
179
					action = groups.drag[i].link.actionObj;
180
					break;
181
				}
182
			}
183
			if(action)
184
			{
185
				/**
186
				 * We found an action with dragType 'file', so by holding Ctrl
187
				 * key & dragging, user can drag from browser to system.
188
				 * The global data store must provide a full, absolute URL in 'download_url'
189
				 * and a mime in 'mime'.
190
				 *
191
				 * Unfortunately, Native DnD to drag the file conflicts with jQueryUI draggable,
192
				 * which handles all the other DnD actions.  We get around this by:
193
				 * 1.  Require the user indicate a file drag with Ctrl key
194
				 * 2.  Disable jQueryUI draggable, then turn on native draggable attribute
195
				 * This way we can at least toggle which one is operating, so they
196
				 * both work alternately if not together.
197
				 */
198
				// Native DnD - Doesn't play nice with jQueryUI Sortable
199
				// Tell jQuery to include this property
200
				jQuery.event.props.push('dataTransfer');
201
202
				jQuery(node).off("mousedown")
203
					.on("mousedown", function(event) {
204
							var dragOut = _context.isDragOut(event);
205
							jQuery(this).attr("draggable", dragOut? "true" : "");
206
							jQuery(node).draggable("option","disabled",dragOut);
207
							if (dragOut)
208
							{
209
								// Disabling draggable adds some UI classes, but we don't care so remove them
210
								jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled");
211
212
							}
213
							else
214
							{
215
								if (_context.isSelection(event))
216
								{
217
									jQuery(node).draggable("disable");
218
									// Disabling draggable adds some UI classes, but we don't care so remove them
219
									jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled");
220
								}
221
								else if(event.which != 3)
222
								{
223
									document.getSelection().removeAllRanges();
224
								}
225
								if(!(dragOut) || !this.addEventListener) return;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
226
							}
227
					})
228
					.on ("mouseup", function (event){
229
						if (_context.isSelection(event))
230
							jQuery(node).draggable("enable");
231
					})
232
					.on("dragstart", function(event) {
233
						if(_context.isSelection(event)) return;
234
						if(event.dataTransfer == null) {
235
							return;
236
						}
237
						event.dataTransfer.effectAllowed="copy";
238
239
						// Get all selected
240
						// Multiples aren't supported by event.dataTransfer, yet, so
241
						// select only the row they clicked on.
242
						// var selected = _context.getSelectedLinks('drag');
243
						var selected = [_context];
244
						_context.parent.setAllSelected(false);
245
						_context.setSelected(true);
246
247
						// Set file data
248
						for(var i = 0; i < selected.length; i++)
249
						{
250
							var data = selected[i].data || egw.dataGetUIDdata(selected[i].id).data || {};
251
							if(data && data.mime && data.download_url)
252
							{
253
								var url = data.download_url;
254
255
								// NEED an absolute URL
256
								if (url[0] == '/') url = egw.link(url);
257
								// egw.link adds the webserver, but that might not be an absolute URL - try again
258
								if (url[0] == '/') url = window.location.origin+url;
259
260
								// Unfortunately, dragging files is currently only supported by Chrome
261
								if(navigator && navigator.userAgent.indexOf('Chrome'))
262
								{
263
									event.dataTransfer.setData("DownloadURL", data.mime+':'+data.name+':'+url);
264
								}
265
								else
266
								{
267
									// Include URL as a fallback
268
									event.dataTransfer.setData("text/uri-list", url);
269
								}
270
							}
271
						}
272
						if(event.dataTransfer.types.length == 0)
273
						{
274
							// No file data? Abort: drag does nothing
275
							event.preventDefault();
276
							return;
277
						}
278
279
						// Create drag icon
280
						_callback.call(_context, _context, ai);
281
						// Drag icon must be visible for setDragImage() - we'll remove it on drag
282
						jQuery("body").append(ai.helper);
283
						event.dataTransfer.setDragImage(ai.helper[0],-12,-12);
284
					})
285
					.on("drag", function(e) {
286
						// Remove the helper, it has been copied into the dataTransfer object now
287
						// Hopefully user didn't notice it...
288
						if(e.dataTransfer != null)
289
						{
290
							ai.helper.remove();
291
						}
292
					});
293
			}
294
			else
295
			{
296
				// Use Ctrl key in order to select content
297
				jQuery(node).off("mousedown")
298
						.on({
299
							mousedown: function(event){
300
								if (_context.isSelection(event)){
301
									jQuery(node).draggable("disable");
302
									// Disabling draggable adds some UI classes, but we don't care so remove them
303
									jQuery(node).removeClass("ui-draggable-disabled ui-state-disabled");
304
								}
305
								else if(event.which != 3)
306
								{
307
									document.getSelection().removeAllRanges();
308
								}
309
							},
310
							mouseup: function (){
311
								jQuery(node).draggable("enable");
312
								// Set cursor back to auto. Seems FF can't handle cursor reversion
313
								jQuery('body').css({cursor:'auto'});
314
							}
315
				});
316
			}
317
			jQuery(node).draggable(
318
				{
319
					"distance": 20,
320
					"cursor": "move",
321
					"cursorAt": { top: -12, left: -12 },
322
					"helper": function(e) {
323
						// The helper function is called before the start function
324
						// is evoked. Call the given callback function. The callback
325
						// function will gather the selected elements and action links
326
						// and call the doExecuteImplementation function. This
327
						// will call the onExecute function of the first action
328
						// in order to obtain the helper object (stored in ai.helper)
329
						// and the multiple dragDropTypes (ai.ddTypes)
330
						 _callback.call(_context, false, ai);
331
332
						jQuery(node).data("ddTypes", ai.ddTypes);
333
						jQuery(node).data("selected", ai.selected);
334
335
						if (ai.helper)
336
						{
337
							// Add a basic class to the helper in order to standardize the background layout
338
							ai.helper.addClass('et2_egw_action_ddHelper');
339
340
							// Append the helper object to the body element - this
341
							// fixes a bug in IE: If the element isn't inserted into
342
							// the DOM-tree jquery appends it to the parent node.
343
							// In case this is a table it doesn't work correctly
344
							jQuery("body").append(ai.helper);
345
							return ai.helper;
346
						}
347
348
						// Return an empty div if the helper dom node is not set
349
						return ai.defaultDDHelper(ai.selected);//jQuery(document.createElement("div")).addClass('et2_egw_action_ddHelper');
350
					},
351
					"start": function(e) {
352
						return ai.helper != null;
353
					},
354
					revert: function(valid)
355
					{
356
						var dTarget = this;
357
						if (!valid)
358
						{
359
							// Tolerance value of pixels arround the draggable target
360
							// to distinguish whether the action was intended for dragging or selecting content.
361
							var tipTelorance = 10;
362
							var helperTop = ai.helper.position().top;
363
364
							if (helperTop >= dTarget.offset().top
365
									&& helperTop <= (dTarget.height() + dTarget.offset().top) + tipTelorance)
366
							{
367
								var key = ["Mac68K","MacPPC","MacIntel"].indexOf(window.navigator.platform) < 0 ?
368
									egw.lang("Ctrl") : egw.lang("Command ⌘");
369
								// We can not use Ctrl key for FF because FF has specific function
370
								// for element selection bound to ctrl key and it would confilicts
371
								// with our selection functionallity. Therefore, we use Alt key when
372
								// it comes to FF regardless of OS.
373
								if (window.navigator.userAgent.match(/firefox/i)) key = egw.lang("Alt");
374
								egw.message(egw.lang('Hold [%1] key to select text eg. to copy it', key), 'info');
375
							}
376
377
							// Invalid target
378
							return true;
379
						}
380
						else
381
						{
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
382
							// Valid target
383
							return false;
384
						}
385
					},
386
					// Solves problem with scroll position changing in the grid
387
					// component
388
					"refreshPositions": true,
389
					"scroll": false,
390
					//"containment": "document",
391
					"iframeFix": true,
392
					"delay": 300
393
				}
394
			);
395
396
397
			return true;
398
		}
399
		return false;
400
	};
401
402
	ai.doUnregisterAction = function(_aoi)
403
	{
404
		var node = _aoi.getDOMNode();
405
406
		if (node && jQuery(node).data("uiDraggable")){
407
			jQuery(node).draggable("destroy");
408
		}
409
	};
410
411
	/**
412
	 * Builds the context menu and shows it at the given position/DOM-Node.
413
	 *
414
	 * @param {string} _context
415
	 * @param {array} _selected
416
	 * @param {object} _links
417
	 */
418
	ai.doExecuteImplementation = function(_context, _selected, _links)
419
	{
420
		// Reset the helper object of the action implementation
421
		this.helper = null;
422
		var hasLink = false;
423
424
		// Store the drag-drop types
425
		this.ddTypes = [];
426
		this.selected = _selected;
427
428
		// Call the onExecute event of the first actionObject
429
		for (var k in _links)
430
		{
431
			if (_links[k].visible)
432
			{
433
				hasLink = true;
434
435
				// Only execute the following code if a JS function is registered
436
				// for the action and this is the first action link
437
				if (!this.helper && _links[k].actionObj.onExecute.hasHandler())
438
				{
439
					this.helper = _links[k].actionObj.execute(_selected);
440
				}
441
442
				// Push the dragType of the associated action object onto the
443
				// drag type list - this allows an element to support multiple
444
				// drag/drop types.
445
				var type = jQuery.isArray(_links[k].actionObj.dragType) ? _links[k].actionObj.dragType : [_links[k].actionObj.dragType];
446
				for(var i = 0; i < type.length; i++)
447
				{
448
					if (this.ddTypes.indexOf(type[i]) == -1)
449
					{
450
						this.ddTypes.push(type[i]);
451
					}
452
				}
453
			}
454
		}
455
456
		// If no helper has been defined, create an default one
457
		if (!this.helper && hasLink)
458
		{
459
			this.helper = ai.defaultDDHelper(_selected);
460
		}
461
462
		return true;
463
	};
464
465
	return ai;
466
}
467
468
469
470
/**
471
 * The egwDropAction class overwrites the egwAction class and adds the "acceptedTypes"
472
 * property. This array should contain all "dragTypes" the drop action is allowed to
473
 *
474
 * @param {egwAction} _id
475
 * @param {string} _handler
476
 * @param {string} _caption
477
 * @param {string} _icon
478
 * @param {(string|function)} _onExecute
479
 * @param {bool} _allowOnMultiple
480
 * @returns {egwDropAction}
481
 */
482
function egwDropAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple)
483
{
484
	var action = new egwAction(_id, _handler, _caption, _icon, _onExecute, _allowOnMultiple);
485
486
	action.type = "drop";
487
	action.acceptedTypes = ["default"];
488
	action.canHaveChildren = ["drag","popup"];
489
	action["default"] = false;
490
	action.order = 0;
491
	action.group = 0;
492
493
	action.set_default = function(_value) {
494
		action["default"] = _value;
495
	};
496
497
	action.set_order = function(_value) {
498
		action.order = _value;
499
	};
500
501
	action.set_group = function(_value) {
502
		action.group = _value;
503
	};
504
505
	/**
506
	 * The acceptType property allows strings as well as arrays - strings are
507
	 * automatically included in an array.
508
	 *
509
	 * @param {(string|array)} _value
510
	 */
511
	action.set_acceptedTypes = function(_value) {
512
		if (_value instanceof Array)
513
		{
514
			action.acceptedTypes = _value;
515
		}
516
		else
517
		{
518
			action.acceptedTypes = [_value];
519
		}
520
	};
521
522
	return action;
523
}
524
525
var
526
	_dropActionImpl = null;
527
528
function getDropImplementation()
529
{
530
	if (!_dropActionImpl)
531
	{
532
		_dropActionImpl = new egwDropActionImplementation();
533
	}
534
	return _dropActionImpl;
535
}
536
537
var EGW_AI_DRAG = 0x0100; // Use the first byte as mask for event types - 01 is for events used with drag stuff
538
var EGW_AI_DRAG_OUT = EGW_AI_DRAG | 0x01;
539
var EGW_AI_DRAG_OVER = EGW_AI_DRAG | 0x02;
540
541
function egwDropActionImplementation()
542
{
543
	var ai = new egwActionImplementation();
544
545
	ai.type = "drop";
546
547
	ai.doRegisterAction = function(_aoi, _callback, _context)
548
	{
549
		var node = _aoi.getDOMNode();
550
		var self = this;
551
552
		if (node)
553
		{
554
			jQuery(node).droppable(
555
				{
556
					"accept": function(_draggable) {
557
						if (typeof _draggable.data("ddTypes") != "undefined")
558
						{
559
							var accepted = self._fetchAccepted(
560
								_callback.call(_context, "links", self, EGW_AO_EXEC_THIS));
561
562
							// Check whether all drag types of the selected objects
563
							// are accepted
564
							var ddTypes = _draggable.data("ddTypes");
565
566
							for (var i = 0; i < ddTypes.length; i++)
567
							{
568
								if (accepted.indexOf(ddTypes[i]) != -1)
569
								{
570
									return true;
571
								}
572
							}
573
574
							return false;
575
						}
576
					},
577
					"drop": function(event, ui) {
578
						var draggable = ui.draggable;
579
						var ddTypes = draggable.data("ddTypes");
580
						var selected = draggable.data("selected");
581
582
						var links = _callback.call(_context, "links", self, EGW_AO_EXEC_THIS);
583
584
						// Disable all links which only accept types which are not
585
						// inside ddTypes
586
						for (var k in links)
587
						{
588
							var accepted = links[k].actionObj.acceptedTypes;
589
590
							var enabled = false;
591
							for (var i = 0; i < ddTypes.length; i++)
592
							{
593
								if (accepted.indexOf(ddTypes[i]) != -1)
594
								{
595
									enabled = true;
596
									break;
597
								}
598
							}
599
							// Check for allowing multiple selected
600
							if(!links[k].actionObj.allowOnMultiple && selected.length > 1)
601
							{
602
								enabled = false;
603
							}
604
							if(!enabled)
605
							{
606
								links[k].enabled = false;
607
								links[k].visible = !links[k].actionObj.hideOnDisabled;
608
							}
609
						}
610
611
						// Check whether there is only one link
612
						var cnt = 0;
613
						var lnk = null;
614
						for (var k in links)
615
						{
616
							if (links[k].enabled && links[k].visible)
617
							{
618
								lnk = links[k];
619
								cnt += 1 + links[k].actionObj.children.length;
620
621
								// Add ui, so you know what happened where
622
								lnk.actionObj.ui = ui;
623
624
							}
625
						}
626
627
						if (cnt == 1)
628
						{
629
							window.setTimeout(function() {
630
								lnk.actionObj.execute(selected, _context);
631
							},0);
632
						}
633
634
						if (cnt > 1)
635
						{
636
							// More than one drop action link is associated
637
							// to the drop event - show those as a popup menu
638
							// and let the user decide which one to use.
639
							// This is possible as the popup and the popup action
640
							// object and the drop action object share same
641
							// set of properties.
642
							var popup = getPopupImplementation();
643
							var pos = popup._getPageXY(event.originalEvent);
644
645
							// Don't add paste actions, this is a drop
646
							popup.auto_paste = false;
647
648
							window.setTimeout(function() {
649
								popup.doExecuteImplementation(pos, selected, links,
650
									_context);
651
								// Reset, popup is reused
652
								popup.auto_paste = true;
653
							}, 0); // Timeout is needed to have it working in IE
654
						}
655
						// Set cursor back to auto. Seems FF can't handle cursor reversion
656
						jQuery('body').css({cursor:'auto'});
657
658
						_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
659
					},
660
					"over": function(event, ui) {
661
						_aoi.triggerEvent(EGW_AI_DRAG_OVER,{event: event,ui:ui});
662
					},
663
					"out": function(event,ui) {
664
						_aoi.triggerEvent(EGW_AI_DRAG_OUT,{event: event,ui:ui});
665
					},
666
					"tolerance": "pointer",
667
					hoverClass: "drop-hover",
668
					// Greedy is for nested droppables - children consume the action
669
					greedy: true
670
				}
671
			);
672
673
			return true;
674
		}
675
		return false;
676
	};
677
678
	ai.doUnregisterAction = function(_aoi)
679
	{
680
		var node = _aoi.getDOMNode();
681
682
		if (node && jQuery(node).data("uiDroppable")) {
683
			jQuery(node).droppable("destroy");
684
		}
685
	};
686
687
	ai._fetchAccepted = function(_links)
688
	{
689
		// Accumulate the accepted types
690
		var accepted = [];
691
		for (var k in _links)
692
		{
693
			for (var i = 0; i < _links[k].actionObj.acceptedTypes.length; i++)
694
			{
695
				var type = _links[k].actionObj.acceptedTypes[i];
696
697
				if (accepted.indexOf(type) == -1)
698
				{
699
					accepted.push(type);
700
				}
701
			}
702
		}
703
704
		return accepted;
705
	};
706
707
	/**
708
	 * Builds the context menu and shows it at the given position/DOM-Node.
709
	 *
710
	 * @param {string} _context
711
	 * @param {array} _selected
712
	 * @param {object} _links
713
	 */
714
	ai.doExecuteImplementation = function(_context, _selected, _links)
715
	{
716
		if (_context == "links")
717
		{
718
			return _links;
719
		}
720
	};
721
722
	return ai;
723
}
724