Subversion Repositories Applications.papyrus

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dijit.Menu"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dijit.Menu"] = true;
3
dojo.provide("dijit.Menu");
4
 
5
dojo.require("dijit._Widget");
6
dojo.require("dijit._Container");
7
dojo.require("dijit._Templated");
8
 
9
dojo.declare(
10
	"dijit.Menu",
11
	[dijit._Widget, dijit._Templated, dijit._KeyNavContainer],
12
{
13
	constructor: function() {
14
		this._bindings = [];
15
	},
16
 
17
	templateString:
18
			'<table class="dijit dijitMenu dijitReset dijitMenuTable" waiRole="menu" dojoAttachEvent="onkeypress:_onKeyPress">' +
19
				'<tbody class="dijitReset" dojoAttachPoint="containerNode"></tbody>'+
20
			'</table>',
21
 
22
	// targetNodeIds: String[]
23
	//	Array of dom node ids of nodes to attach to.
24
	//	Fill this with nodeIds upon widget creation and it becomes context menu for those nodes.
25
	targetNodeIds: [],
26
 
27
	// contextMenuForWindow: Boolean
28
	//	if true, right clicking anywhere on the window will cause this context menu to open;
29
	//	if false, must specify targetNodeIds
30
	contextMenuForWindow: false,
31
 
32
	// parentMenu: Widget
33
	// pointer to menu that displayed me
34
	parentMenu: null,
35
 
36
	// popupDelay: Integer
37
	//	number of milliseconds before hovering (without clicking) causes the popup to automatically open
38
	popupDelay: 500,
39
 
40
	// _contextMenuWithMouse: Boolean
41
	//	used to record mouse and keyboard events to determine if a context
42
	//	menu is being opened with the keyboard or the mouse
43
	_contextMenuWithMouse: false,
44
 
45
	postCreate: function(){
46
		if(this.contextMenuForWindow){
47
			this.bindDomNode(dojo.body());
48
		}else{
49
			dojo.forEach(this.targetNodeIds, this.bindDomNode, this);
50
		}
51
		this.connectKeyNavHandlers([dojo.keys.UP_ARROW], [dojo.keys.DOWN_ARROW]);
52
	},
53
 
54
	startup: function(){
55
		dojo.forEach(this.getChildren(), function(child){ child.startup(); });
56
		this.startupKeyNavChildren();
57
	},
58
 
59
	onExecute: function(){
60
		// summary: attach point for notification about when a menu item has been executed
61
	},
62
 
63
	onCancel: function(/*Boolean*/ closeAll){
64
		// summary: attach point for notification about when the user cancels the current menu
65
	},
66
 
67
	_moveToPopup: function(/*Event*/ evt){
68
		if(this.focusedChild && this.focusedChild.popup && !this.focusedChild.disabled){
69
			this.focusedChild._onClick(evt);
70
		}
71
	},
72
 
73
	_onKeyPress: function(/*Event*/ evt){
74
		// summary
75
		//	Handle keyboard based menu navigation.
76
		if(evt.ctrlKey || evt.altKey){ return; }
77
 
78
		switch(evt.keyCode){
79
			case dojo.keys.RIGHT_ARROW:
80
				this._moveToPopup(evt);
81
				dojo.stopEvent(evt);
82
				break;
83
			case dojo.keys.LEFT_ARROW:
84
				if(this.parentMenu){
85
					this.onCancel(false);
86
				}else{
87
					dojo.stopEvent(evt);
88
				}
89
				break;
90
		}
91
	},
92
 
93
	onItemHover: function(/*MenuItem*/ item){
94
		this.focusChild(item);
95
 
96
		if(this.focusedChild.popup && !this.focusedChild.disabled && !this.hover_timer){
97
			this.hover_timer = setTimeout(dojo.hitch(this, "_openPopup"), this.popupDelay);
98
		}
99
	},
100
 
101
	_onChildBlur: function(item){
102
		// Close all popups that are open and descendants of this menu
103
		dijit.popup.close(item.popup);
104
		item._blur();
105
		this._stopPopupTimer();
106
	},
107
 
108
	onItemUnhover: function(/*MenuItem*/ item){
109
	},
110
 
111
	_stopPopupTimer: function(){
112
		if(this.hover_timer){
113
			clearTimeout(this.hover_timer);
114
			this.hover_timer = null;
115
		}
116
	},
117
 
118
	_getTopMenu: function(){
119
		for(var top=this; top.parentMenu; top=top.parentMenu);
120
		return top;
121
	},
122
 
123
	onItemClick: function(/*Widget*/ item){
124
		// summary: user defined function to handle clicks on an item
125
		// summary: internal function for clicks
126
		if(item.disabled){ return false; }
127
 
128
		if(item.popup){
129
			if(!this.is_open){
130
				this._openPopup();
131
			}
132
		}else{
133
			// before calling user defined handler, close hierarchy of menus
134
			// and restore focus to place it was when menu was opened
135
			this.onExecute();
136
 
137
			// user defined handler for click
138
			item.onClick();
139
		}
140
	},
141
 
142
	// thanks burstlib!
143
	_iframeContentWindow: function(/* HTMLIFrameElement */iframe_el) {
144
		//	summary
145
		//	returns the window reference of the passed iframe
146
		var win = dijit.getDocumentWindow(dijit.Menu._iframeContentDocument(iframe_el)) ||
147
			// Moz. TODO: is this available when defaultView isn't?
148
			dijit.Menu._iframeContentDocument(iframe_el)['__parent__'] ||
149
			(iframe_el.name && document.frames[iframe_el.name]) || null;
150
		return win;	//	Window
151
	},
152
 
153
	_iframeContentDocument: function(/* HTMLIFrameElement */iframe_el){
154
		//	summary
155
		//	returns a reference to the document object inside iframe_el
156
		var doc = iframe_el.contentDocument // W3
157
			|| (iframe_el.contentWindow && iframe_el.contentWindow.document) // IE
158
			|| (iframe_el.name && document.frames[iframe_el.name] && document.frames[iframe_el.name].document)
159
			|| null;
160
		return doc;	//	HTMLDocument
161
	},
162
 
163
	bindDomNode: function(/*String|DomNode*/ node){
164
		// summary: attach menu to given node
165
		node = dojo.byId(node);
166
 
167
		//TODO: this is to support context popups in Editor.  Maybe this shouldn't be in dijit.Menu
168
		var win = dijit.getDocumentWindow(node.ownerDocument);
169
		if(node.tagName.toLowerCase()=="iframe"){
170
			win = this._iframeContentWindow(node);
171
			node = dojo.withGlobal(win, dojo.body);
172
		}
173
 
174
		// to capture these events at the top level,
175
		// attach to document, not body
176
		var cn = (node == dojo.body() ? dojo.doc : node);
177
 
178
		node[this.id] = this._bindings.push([
179
			dojo.connect(cn, "oncontextmenu", this, "_openMyself"),
180
			dojo.connect(cn, "onkeydown", this, "_contextKey"),
181
			dojo.connect(cn, "onmousedown", this, "_contextMouse")
182
		]);
183
	},
184
 
185
	unBindDomNode: function(/*String|DomNode*/ nodeName){
186
		// summary: detach menu from given node
187
		var node = dojo.byId(nodeName);
188
		var bid = node[this.id]-1, b = this._bindings[bid];
189
		dojo.forEach(b, dojo.disconnect);
190
		delete this._bindings[bid];
191
	},
192
 
193
	_contextKey: function(e){
194
		this._contextMenuWithMouse = false;
195
		if (e.keyCode == dojo.keys.F10) {
196
			dojo.stopEvent(e);
197
			if (e.shiftKey && e.type=="keydown") {
198
				// FF: copying the wrong property from e will cause the system
199
				// context menu to appear in spite of stopEvent. Don't know
200
				// exactly which properties cause this effect.
201
				var _e = { target: e.target, pageX: e.pageX, pageY: e.pageY };
202
				_e.preventDefault = _e.stopPropagation = function(){};
203
				// IE: without the delay, focus work in "open" causes the system
204
				// context menu to appear in spite of stopEvent.
205
				window.setTimeout(dojo.hitch(this, function(){ this._openMyself(_e); }), 1);
206
			}
207
		}
208
	},
209
 
210
	_contextMouse: function(e){
211
		this._contextMenuWithMouse = true;
212
	},
213
 
214
	_openMyself: function(/*Event*/ e){
215
		// summary:
216
		//		Internal function for opening myself when the user
217
		//		does a right-click or something similar
218
 
219
		dojo.stopEvent(e);
220
 
221
		// Get coordinates.
222
		// if we are opening the menu with the mouse or on safari open
223
		// the menu at the mouse cursor
224
		// (Safari does not have a keyboard command to open the context menu
225
		// and we don't currently have a reliable way to determine
226
		// _contextMenuWithMouse on Safari)
227
		var x,y;
228
		if(dojo.isSafari || this._contextMenuWithMouse){
229
			x=e.pageX;
230
			y=e.pageY;
231
		}else{
232
			// otherwise open near e.target
233
			var coords = dojo.coords(e.target, true);
234
			x = coords.x + 10;
235
			y = coords.y + 10;
236
		}
237
 
238
		var self=this;
239
		var savedFocus = dijit.getFocus(this);
240
		function closeAndRestoreFocus(){
241
			// user has clicked on a menu or popup
242
			dijit.focus(savedFocus);
243
			dijit.popup.close(self);
244
		}
245
		dijit.popup.open({
246
			popup: this,
247
			x: x,
248
			y: y,
249
			onExecute: closeAndRestoreFocus,
250
			onCancel: closeAndRestoreFocus,
251
			orient: this.isLeftToRight() ? 'L' : 'R'
252
		});
253
		this.focus();
254
 
255
		this._onBlur = function(){
256
			// Usually the parent closes the child widget but if this is a context
257
			// menu then there is no parent
258
			dijit.popup.close(this);
259
			// don't try to restore focus; user has clicked another part of the screen
260
			// and set focus there
261
		}
262
	},
263
 
264
	onOpen: function(/*Event*/ e){
265
		// summary
266
		//		Open menu relative to the mouse
267
		this.isShowingNow = true;
268
	},
269
 
270
	onClose: function(){
271
		// summary: callback when this menu is closed
272
		this._stopPopupTimer();
273
		this.parentMenu = null;
274
		this.isShowingNow = false;
275
		this.currentPopup = null;
276
		if(this.focusedChild){
277
			this._onChildBlur(this.focusedChild);
278
			this.focusedChild = null;
279
		}
280
	},
281
 
282
	_openPopup: function(){
283
		// summary: open the popup to the side of the current menu item
284
		this._stopPopupTimer();
285
		var from_item = this.focusedChild;
286
		var popup = from_item.popup;
287
 
288
		if(popup.isShowingNow){ return; }
289
		popup.parentMenu = this;
290
		var self = this;
291
		dijit.popup.open({
292
			parent: this,
293
			popup: popup,
294
			around: from_item.arrowCell,
295
			orient: this.isLeftToRight() ? {'TR': 'TL', 'TL': 'TR'} : {'TL': 'TR', 'TR': 'TL'},
296
			onCancel: function(){
297
				// called when the child menu is canceled
298
				dijit.popup.close(popup);
299
				from_item.focus();	// put focus back on my node
300
				self.currentPopup = null;
301
			}
302
		});
303
 
304
		this.currentPopup = popup;
305
 
306
		if(popup.focus){
307
			popup.focus();
308
		}
309
	}
310
}
311
);
312
 
313
dojo.declare(
314
	"dijit.MenuItem",
315
	[dijit._Widget, dijit._Templated, dijit._Contained],
316
{
317
	// summary
318
	//	A line item in a Menu2
319
 
320
	// Make 3 columns
321
	//   icon, label, and expand arrow (BiDi-dependent) indicating sub-menu
322
	templateString:
323
		 '<tr class="dijitReset dijitMenuItem"'
324
		+'dojoAttachEvent="onmouseenter:_onHover,onmouseleave:_onUnhover,ondijitclick:_onClick">'
325
		+'<td class="dijitReset"><div class="dijitMenuItemIcon ${iconClass}" dojoAttachPoint="iconNode" ></div></td>'
326
		+'<td tabIndex="-1" class="dijitReset dijitMenuItemLabel" dojoAttachPoint="containerNode" waiRole="menuitem"></td>'
327
		+'<td class="dijitReset" dojoAttachPoint="arrowCell">'
328
			+'<div class="dijitMenuExpand" dojoAttachPoint="expand" style="display:none">'
329
			+'<span class="dijitInline dijitArrowNode dijitMenuExpandInner">+</span>'
330
			+'</div>'
331
		+'</td>'
332
		+'</tr>',
333
 
334
	// label: String
335
	//	menu text
336
	label: '',
337
 
338
	// iconClass: String
339
	//	class to apply to div in button to make it display an icon
340
	iconClass: "",
341
 
342
	// disabled: Boolean
343
	//  if true, the menu item is disabled
344
	//  if false, the menu item is enabled
345
	disabled: false,
346
 
347
	postCreate: function(){
348
		dojo.setSelectable(this.domNode, false);
349
		this.setDisabled(this.disabled);
350
		if(this.label){
351
			this.containerNode.innerHTML=this.label;
352
		}
353
	},
354
 
355
	_onHover: function(){
356
		// summary: callback when mouse is moved onto menu item
357
		this.getParent().onItemHover(this);
358
	},
359
 
360
	_onUnhover: function(){
361
		// summary: callback when mouse is moved off of menu item
362
		// if we are unhovering the currently selected item
363
		// then unselect it
364
		this.getParent().onItemUnhover(this);
365
	},
366
 
367
	_onClick: function(evt){
368
		this.getParent().onItemClick(this);
369
		dojo.stopEvent(evt);
370
	},
371
 
372
	onClick: function() {
373
		// summary
374
		//	User defined function to handle clicks
375
	},
376
 
377
	focus: function(){
378
		dojo.addClass(this.domNode, 'dijitMenuItemHover');
379
		try{
380
			dijit.focus(this.containerNode);
381
		}catch(e){
382
			// this throws on IE (at least) in some scenarios
383
		}
384
	},
385
 
386
	_blur: function(){
387
		dojo.removeClass(this.domNode, 'dijitMenuItemHover');
388
	},
389
 
390
	setDisabled: function(/*Boolean*/ value){
391
		// summary: enable or disable this menu item
392
		this.disabled = value;
393
		dojo[value ? "addClass" : "removeClass"](this.domNode, 'dijitMenuItemDisabled');
394
		dijit.setWaiState(this.containerNode, 'disabled', value ? 'true' : 'false');
395
	}
396
});
397
 
398
dojo.declare(
399
	"dijit.PopupMenuItem",
400
	dijit.MenuItem,
401
{
402
	_fillContent: function(){
403
		// my inner HTML contains both the menu item text and a popup widget, like
404
		// <div dojoType="dijit.PopupMenuItem">
405
		//		<span>pick me</span>
406
		//		<popup> ... </popup>
407
		// </div>
408
		// the first part holds the menu item text and the second part is the popup
409
		if(this.srcNodeRef){
410
			var nodes = dojo.query("*", this.srcNodeRef);
411
			dijit.PopupMenuItem.superclass._fillContent.call(this, nodes[0]);
412
 
413
			// save pointer to srcNode so we can grab the drop down widget after it's instantiated
414
			this.dropDownContainer = this.srcNodeRef;
415
		}
416
	},
417
 
418
	startup: function(){
419
		// we didn't copy the dropdown widget from the this.srcNodeRef, so it's in no-man's
420
		// land now.  move it to document.body.
421
		if(!this.popup){
422
			var node = dojo.query("[widgetId]", this.dropDownContainer)[0];
423
			this.popup = dijit.byNode(node);
424
		}
425
		dojo.body().appendChild(this.popup.domNode);
426
 
427
		this.popup.domNode.style.display="none";
428
		dojo.addClass(this.expand, "dijitMenuExpandEnabled");
429
		dojo.style(this.expand, "display", "");
430
		dijit.setWaiState(this.containerNode, "haspopup", "true");
431
	}
432
});
433
 
434
dojo.declare(
435
	"dijit.MenuSeparator",
436
	[dijit._Widget, dijit._Templated, dijit._Contained],
437
{
438
	// summary
439
	//	A line between two menu items
440
 
441
	templateString: '<tr class="dijitMenuSeparator"><td colspan=3>'
442
			+'<div class="dijitMenuSeparatorTop"></div>'
443
			+'<div class="dijitMenuSeparatorBottom"></div>'
444
			+'</td></tr>',
445
 
446
	postCreate: function(){
447
		dojo.setSelectable(this.domNode, false);
448
	},
449
 
450
	isFocusable: function(){
451
		// summary:
452
		//		over ride to always return false
453
		return false;
454
	}
455
});
456
 
457
}