Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dojox.widget.FisheyeList"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dojox.widget.FisheyeList"] = true;
3
dojo.provide("dojox.widget.FisheyeList");
4
 
5
dojo.require("dijit._Widget");
6
dojo.require("dijit._Templated");
7
dojo.require("dijit._Container");
8
 
9
dojo.declare("dojox.widget.FisheyeList", [dijit._Widget, dijit._Templated, dijit._Container], {
10
	// summary:
11
	//	Menu similar to the fish eye menu on the Mac OS
12
	// example:
13
	// |	<div dojoType="FisheyeList"
14
	// |		itemWidth="40" itemHeight="40"
15
	// |		itemMaxWidth="150" itemMaxHeight="150"
16
	// |		orientation="horizontal"
17
	// |		effectUnits="2"
18
	// |		itemPadding="10"
19
	// |		attachEdge="center"
20
	// |		labelEdge="bottom">
21
	// |
22
	// |		<div dojoType="FisheyeListItem"
23
	// |			id="item1"
24
	// |			onclick="alert('click on' + this.label + '(from widget id ' + this.widgetId + ')!');"
25
	// |			label="Item 1"
26
	// |			iconSrc="images/fisheye_1.png">
27
	// |		</div>
28
	// |		...
29
	// |	</div>
30
	//
31
	constructor: function(){
32
		//
33
		// TODO
34
		// fix really long labels in vertical mode
35
		//
36
 
37
		this.pos = {'x': -1, 'y': -1};	// current cursor position, relative to the grid
38
 
39
		// for conservative trigger mode, when triggered, timerScale is gradually increased from 0 to 1
40
		this.timerScale = 1.0;
41
 
42
	},
43
 
44
	EDGE: {
45
		CENTER: 0,
46
		LEFT: 1,
47
		RIGHT: 2,
48
		TOP: 3,
49
		BOTTOM: 4
50
	},
51
 
52
	templateString: '<div class="dojoxFisheyeListBar" dojoAttachPoint="containerNode"></div>',
53
 
54
	snarfChildDomOutput: true,
55
 
56
	// itemWidth: Integer
57
	//	width of menu item (in pixels) in it's dormant state (when the mouse is far away)
58
	itemWidth: 40,
59
 
60
	// itemHeight: Integer
61
	//	height of menu item (in pixels) in it's dormant state (when the mouse is far away)
62
	itemHeight: 40,
63
 
64
	// itemMaxWidth: Integer
65
	//	width of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
66
	itemMaxWidth: 150,
67
 
68
	// itemMaxHeight: Integer
69
	//	height of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it)
70
	itemMaxHeight: 150,
71
 
72
	imgNode: null,
73
 
74
	// orientation: String
75
	//	orientation of the menu, either "horizontal" or "vertical"
76
	orientation: 'horizontal',
77
 
78
	// isFixed: Boolean
79
	//	toggle to enable additional listener (window scroll) if FisheyeList is in a fixed postion
80
	isFixed: false,
81
 
82
	// conservativeTrigger: Boolean
83
	//	if true, don't start enlarging menu items until mouse is over an image;
84
	//	if false, start enlarging menu items as the mouse moves near them.
85
	conservativeTrigger: false,
86
 
87
	// effectUnits: Number
88
	//	controls how much reaction the menu makes, relative to the distance of the mouse from the menu
89
	effectUnits: 2,
90
 
91
	// itemPadding: Integer
92
	//	padding (in pixels) betweeen each menu item
93
	itemPadding: 10,
94
 
95
	// attachEdge: String
96
	//	controls the border that the menu items don't expand past;
97
	//	for example, if set to "top", then the menu items will drop downwards as they expand.
98
	// values
99
	//	"center", "left", "right", "top", "bottom".
100
	attachEdge: 'center',
101
 
102
	// labelEdge: String
103
	//	controls were the labels show up in relation to the menu item icons
104
	// values
105
	//	"center", "left", "right", "top", "bottom".
106
	labelEdge: 'bottom',
107
 
108
	postCreate: function(){
109
		var e = this.EDGE;
110
		dojo.setSelectable(this.domNode, false);
111
 
112
		var isHorizontal = this.isHorizontal = (this.orientation == 'horizontal');
113
		this.selectedNode = -1;
114
 
115
		this.isOver = false;
116
		this.hitX1 = -1;
117
		this.hitY1 = -1;
118
		this.hitX2 = -1;
119
		this.hitY2 = -1;
120
 
121
		//
122
		// only some edges make sense...
123
		//
124
		this.anchorEdge = this._toEdge(this.attachEdge, e.CENTER);
125
		this.labelEdge  = this._toEdge(this.labelEdge,  e.TOP);
126
 
127
		if(this.labelEdge == e.CENTER){ this.labelEdge = e.TOP; }
128
 
129
		if(isHorizontal){
130
			if(this.anchorEdge == e.LEFT){ this.anchorEdge = e.CENTER; }
131
			if(this.anchorEdge == e.RIGHT){ this.anchorEdge = e.CENTER; }
132
			if(this.labelEdge == e.LEFT){ this.labelEdge = e.TOP; }
133
			if(this.labelEdge == e.RIGHT){ this.labelEdge = e.TOP; }
134
		}else{
135
			if(this.anchorEdge == e.TOP){ this.anchorEdge = e.CENTER; }
136
			if(this.anchorEdge == e.BOTTOM){ this.anchorEdge = e.CENTER; }
137
			if(this.labelEdge == e.TOP){ this.labelEdge = e.LEFT; }
138
			if(this.labelEdge == e.BOTTOM){ this.labelEdge = e.LEFT; }
139
		}
140
 
141
		//
142
		// figure out the proximity size
143
		//
144
		var effectUnits = this.effectUnits;
145
		this.proximityLeft   = this.itemWidth  * (effectUnits - 0.5);
146
		this.proximityRight  = this.itemWidth  * (effectUnits - 0.5);
147
		this.proximityTop    = this.itemHeight * (effectUnits - 0.5);
148
		this.proximityBottom = this.itemHeight * (effectUnits - 0.5);
149
 
150
		if(this.anchorEdge == e.LEFT){
151
			this.proximityLeft = 0;
152
		}
153
		if(this.anchorEdge == e.RIGHT){
154
			this.proximityRight = 0;
155
		}
156
		if(this.anchorEdge == e.TOP){
157
			this.proximityTop = 0;
158
		}
159
		if(this.anchorEdge == e.BOTTOM){
160
			this.proximityBottom = 0;
161
		}
162
		if(this.anchorEdge == e.CENTER){
163
			this.proximityLeft   /= 2;
164
			this.proximityRight  /= 2;
165
			this.proximityTop    /= 2;
166
			this.proximityBottom /= 2;
167
		}
168
	},
169
 
170
	startup: function(){
171
		// summary: create our connections and setup our FisheyeList
172
		this.children = this.getChildren();
173
		//original postCreate() --tk
174
		this._initializePositioning();
175
 
176
		//
177
		// in liberal trigger mode, activate menu whenever mouse is close
178
		//
179
		if(!this.conservativeTrigger){
180
			this._onMouseMoveHandle = dojo.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
181
		}
182
		if (this.isFixed){
183
			this._onScrollHandle = dojo.connect(document,"onscroll",this,"_onScroll");
184
		}
185
 
186
		// Deactivate the menu if mouse is moved off screen (doesn't work for FF?)
187
		this._onMouseOutHandle = dojo.connect(document.documentElement, "onmouseout", this, "_onBodyOut");
188
		this._addChildHandle = dojo.connect(this, "addChild", this, "_initializePositioning");
189
		this._onResizeHandle = dojo.connect(window,"onresize", this, "_initializePositioning");
190
	},
191
 
192
	_initializePositioning: function(){
193
		this.itemCount = this.children.length;
194
 
195
		this.barWidth  = (this.isHorizontal ? this.itemCount : 1) * this.itemWidth;
196
		this.barHeight = (this.isHorizontal ? 1 : this.itemCount) * this.itemHeight;
197
 
198
		this.totalWidth  = this.proximityLeft + this.proximityRight  + this.barWidth;
199
		this.totalHeight = this.proximityTop  + this.proximityBottom + this.barHeight;
200
 
201
		//
202
		// calculate effect ranges for each item
203
		//
204
 
205
		for(var i=0; i<this.children.length; i++){
206
 
207
			this.children[i].posX = this.itemWidth  * (this.isHorizontal ? i : 0);
208
			this.children[i].posY = this.itemHeight * (this.isHorizontal ? 0 : i);
209
 
210
			this.children[i].cenX = this.children[i].posX + (this.itemWidth  / 2);
211
			this.children[i].cenY = this.children[i].posY + (this.itemHeight / 2);
212
 
213
			var isz = this.isHorizontal ? this.itemWidth : this.itemHeight;
214
			var r = this.effectUnits * isz;
215
			var c = this.isHorizontal ? this.children[i].cenX : this.children[i].cenY;
216
			var lhs = this.isHorizontal ? this.proximityLeft : this.proximityTop;
217
			var rhs = this.isHorizontal ? this.proximityRight : this.proximityBottom;
218
			var siz = this.isHorizontal ? this.barWidth : this.barHeight;
219
 
220
			var range_lhs = r;
221
			var range_rhs = r;
222
 
223
			if(range_lhs > c+lhs){ range_lhs = c+lhs; }
224
			if(range_rhs > (siz-c+rhs)){ range_rhs = siz-c+rhs; }
225
 
226
			this.children[i].effectRangeLeft = range_lhs / isz;
227
			this.children[i].effectRangeRght = range_rhs / isz;
228
 
229
			//dojo.debug('effect range for '+i+' is '+range_lhs+'/'+range_rhs);
230
		}
231
 
232
		//
233
		// create the bar
234
		//
235
		this.domNode.style.width = this.barWidth + 'px';
236
		this.domNode.style.height = this.barHeight + 'px';
237
 
238
		//
239
		// position the items
240
		//
241
		for(var i=0; i<this.children.length; i++){
242
			var itm = this.children[i];
243
			var elm = itm.domNode;
244
			elm.style.left   = itm.posX + 'px';
245
			elm.style.top    = itm.posY + 'px';
246
			elm.style.width  = this.itemWidth + 'px';
247
			elm.style.height = this.itemHeight + 'px';
248
 
249
			itm.imgNode.style.left = this.itemPadding+'%';
250
			itm.imgNode.style.top = this.itemPadding+'%';
251
			itm.imgNode.style.width = (100 - 2 * this.itemPadding) + '%';
252
			itm.imgNode.style.height = (100 - 2 * this.itemPadding) + '%';
253
		}
254
 
255
		//
256
		// calc the grid
257
		//
258
		this._calcHitGrid();
259
	},
260
 
261
	_overElement: function(/* DomNode|String */node, /* Event */e){
262
		// summary:
263
		//	Returns whether the mouse is over the passed element.
264
		// Node: Must must be display:block (ie, not a <span>)
265
		node = dojo.byId(node);
266
		var mouse = {x: e.pageX, y: e.pageY};
267
		var bb = dojo._getBorderBox(node);
268
		var absolute = dojo.coords(node, true);
269
		var top = absolute.y;
270
		var bottom = top + bb.h;
271
		var left = absolute.x;
272
		var right = left + bb.w;
273
 
274
		return (mouse.x >= left
275
			&& mouse.x <= right
276
			&& mouse.y >= top
277
			&& mouse.y <= bottom
278
		);	//	boolean
279
	},
280
 
281
	_onBodyOut: function(/*Event*/ e){
282
		// clicking over an object inside of body causes this event to fire; ignore that case
283
		if( this._overElement(dojo.body(), e) ){
284
			return;
285
		}
286
		this._setDormant(e);
287
	},
288
 
289
	_setDormant: function(/*Event*/ e){
290
		// summary: called when mouse moves out of menu's range
291
 
292
		if(!this.isOver){ return; }	// already dormant?
293
		this.isOver = false;
294
 
295
		if(this.conservativeTrigger){
296
			// user can't re-trigger the menu expansion
297
			// until he mouses over a icon again
298
			dojo.disconnect(this._onMouseMoveHandle);
299
		}
300
		this._onGridMouseMove(-1, -1);
301
	},
302
 
303
	_setActive: function(/*Event*/ e){
304
		// summary: called when mouse is moved into menu's range
305
 
306
		if(this.isOver){ return; }	// already activated?
307
		this.isOver = true;
308
 
309
		if(this.conservativeTrigger){
310
			// switch event handlers so that we handle mouse events from anywhere near
311
			// the menu
312
			this._onMouseMoveHandle = dojo.connect(document.documentElement, "onmousemove", this, "_onMouseMove");
313
 
314
			this.timerScale=0.0;
315
 
316
			// call mouse handler to do some initial necessary calculations/positioning
317
			this._onMouseMove(e);
318
 
319
			// slowly expand the icon size so it isn't jumpy
320
			this._expandSlowly();
321
		}
322
	},
323
 
324
	_onMouseMove: function(/*Event*/ e){
325
		// summary: called when mouse is moved
326
		if(	(e.pageX >= this.hitX1) && (e.pageX <= this.hitX2) &&
327
			(e.pageY >= this.hitY1) && (e.pageY <= this.hitY2)	){
328
			if(!this.isOver){
329
				this._setActive(e);
330
			}
331
			this._onGridMouseMove(e.pageX-this.hitX1, e.pageY-this.hitY1);
332
		}else{
333
			if(this.isOver){
334
				this._setDormant(e);
335
			}
336
		}
337
	},
338
 
339
	_onScroll: function(){
340
		this._calcHitGrid();
341
	},
342
 
343
	onResized: function(){
344
		this._calcHitGrid();
345
	},
346
 
347
	_onGridMouseMove: function(x, y){
348
		// summary: called when mouse is moved in the vicinity of the menu
349
		this.pos = {x:x, y:y};
350
		this._paint();
351
	},
352
 
353
	_paint: function(){
354
		var x=this.pos.x;
355
		var y=this.pos.y;
356
 
357
		if(this.itemCount <= 0){ return; }
358
 
359
		//
360
		// figure out our main index
361
		//
362
		var pos = this.isHorizontal ? x : y;
363
		var prx = this.isHorizontal ? this.proximityLeft : this.proximityTop;
364
		var siz = this.isHorizontal ? this.itemWidth : this.itemHeight;
365
		var sim = this.isHorizontal ?
366
			(1.0-this.timerScale)*this.itemWidth + this.timerScale*this.itemMaxWidth :
367
			(1.0-this.timerScale)*this.itemHeight + this.timerScale*this.itemMaxHeight ;
368
 
369
		var cen = ((pos - prx) / siz) - 0.5;
370
		var max_off_cen = (sim / siz) - 0.5;
371
 
372
		if(max_off_cen > this.effectUnits){ max_off_cen = this.effectUnits; }
373
 
374
		//
375
		// figure out our off-axis weighting
376
		//
377
		var off_weight = 0;
378
 
379
		if(this.anchorEdge == this.EDGE.BOTTOM){
380
			var cen2 = (y - this.proximityTop) / this.itemHeight;
381
			off_weight = (cen2 > 0.5) ? 1 : y / (this.proximityTop + (this.itemHeight / 2));
382
		}
383
		if(this.anchorEdge == this.EDGE.TOP){
384
			var cen2 = (y - this.proximityTop) / this.itemHeight;
385
			off_weight = (cen2 < 0.5) ? 1 : (this.totalHeight - y) / (this.proximityBottom + (this.itemHeight / 2));
386
		}
387
		if(this.anchorEdge == this.EDGE.RIGHT){
388
			var cen2 = (x - this.proximityLeft) / this.itemWidth;
389
			off_weight = (cen2 > 0.5) ? 1 : x / (this.proximityLeft + (this.itemWidth / 2));
390
		}
391
		if(this.anchorEdge == this.EDGE.LEFT){
392
			var cen2 = (x - this.proximityLeft) / this.itemWidth;
393
			off_weight = (cen2 < 0.5) ? 1 : (this.totalWidth - x) / (this.proximityRight + (this.itemWidth / 2));
394
		}
395
		if(this.anchorEdge == this.EDGE.CENTER){
396
			if(this.isHorizontal){
397
				off_weight = y / (this.totalHeight);
398
			}else{
399
				off_weight = x / (this.totalWidth);
400
			}
401
 
402
			if(off_weight > 0.5){
403
				off_weight = 1 - off_weight;
404
			}
405
 
406
			off_weight *= 2;
407
		}
408
 
409
		//
410
		// set the sizes
411
		//
412
		for(var i=0; i<this.itemCount; i++){
413
			var weight = this._weighAt(cen, i);
414
			if(weight < 0){weight = 0;}
415
			this._setItemSize(i, weight * off_weight);
416
		}
417
 
418
		//
419
		// set the positions
420
		//
421
 
422
		var main_p = Math.round(cen);
423
		var offset = 0;
424
 
425
		if(cen < 0){
426
 
427
			main_p = 0;
428
 
429
		}else if(cen > this.itemCount - 1){
430
 
431
			main_p = this.itemCount -1;
432
 
433
		}else{
434
 
435
			offset = (cen - main_p) * ((this.isHorizontal ? this.itemWidth : this.itemHeight) - this.children[main_p].sizeMain);
436
		}
437
 
438
		this._positionElementsFrom(main_p, offset);
439
	},
440
 
441
	_weighAt: function(/*Integer*/ cen, /*Integer*/ i){
442
		var dist = Math.abs(cen - i);
443
		var limit = ((cen - i) > 0) ? this.children[i].effectRangeRght : this.children[i].effectRangeLeft;
444
		return (dist > limit) ? 0 : (1 - dist / limit); // Integer
445
	},
446
 
447
	_setItemSize: function(p, scale){
448
		scale *= this.timerScale;
449
		var w = Math.round(this.itemWidth  + ((this.itemMaxWidth  - this.itemWidth ) * scale));
450
		var h = Math.round(this.itemHeight + ((this.itemMaxHeight - this.itemHeight) * scale));
451
 
452
		if(this.isHorizontal){
453
 
454
			this.children[p].sizeW = w;
455
			this.children[p].sizeH = h;
456
 
457
			this.children[p].sizeMain = w;
458
			this.children[p].sizeOff  = h;
459
 
460
			var y = 0;
461
			if(this.anchorEdge == this.EDGE.TOP){
462
				y = (this.children[p].cenY - (this.itemHeight / 2));
463
			}else if(this.anchorEdge == this.EDGE.BOTTOM){
464
				y = (this.children[p].cenY - (h - (this.itemHeight / 2)));
465
			}else{
466
				y = (this.children[p].cenY - (h / 2));
467
			}
468
 
469
			this.children[p].usualX = Math.round(this.children[p].cenX - (w / 2));
470
			this.children[p].domNode.style.top  = y + 'px';
471
			this.children[p].domNode.style.left  = this.children[p].usualX + 'px';
472
 
473
		}else{
474
 
475
			this.children[p].sizeW = w;
476
			this.children[p].sizeH = h;
477
 
478
			this.children[p].sizeOff  = w;
479
			this.children[p].sizeMain = h;
480
 
481
			var x = 0;
482
			if(this.anchorEdge == this.EDGE.LEFT){
483
				x = this.children[p].cenX - (this.itemWidth / 2);
484
			}else if (this.anchorEdge == this.EDGE.RIGHT){
485
				x = this.children[p].cenX - (w - (this.itemWidth / 2));
486
			}else{
487
				x = this.children[p].cenX - (w / 2);
488
			}
489
 
490
			this.children[p].domNode.style.left = x + 'px';
491
			this.children[p].usualY = Math.round(this.children[p].cenY - (h / 2));
492
 
493
			this.children[p].domNode.style.top  = this.children[p].usualY + 'px';
494
		}
495
 
496
		this.children[p].domNode.style.width  = w + 'px';
497
		this.children[p].domNode.style.height = h + 'px';
498
 
499
		if(this.children[p].svgNode){
500
			this.children[p].svgNode.setSize(w, h);
501
		}
502
	},
503
 
504
	_positionElementsFrom: function(p, offset){
505
		var pos = 0;
506
 
507
		if(this.isHorizontal){
508
			pos = Math.round(this.children[p].usualX + offset);
509
			this.children[p].domNode.style.left = pos + 'px';
510
		}else{
511
			pos = Math.round(this.children[p].usualY + offset);
512
			this.children[p].domNode.style.top = pos + 'px';
513
		}
514
		this._positionLabel(this.children[p]);
515
 
516
		// position before
517
		var bpos = pos;
518
		for(var i=p-1; i>=0; i--){
519
			bpos -= this.children[i].sizeMain;
520
 
521
			if (this.isHorizontal){
522
				this.children[i].domNode.style.left = bpos + 'px';
523
			}else{
524
				this.children[i].domNode.style.top = bpos + 'px';
525
			}
526
			this._positionLabel(this.children[i]);
527
		}
528
 
529
		// position after
530
		var apos = pos;
531
		for(var i=p+1; i<this.itemCount; i++){
532
			apos += this.children[i-1].sizeMain;
533
			if(this.isHorizontal){
534
				this.children[i].domNode.style.left = apos + 'px';
535
			}else{
536
				this.children[i].domNode.style.top = apos + 'px';
537
			}
538
			this._positionLabel(this.children[i]);
539
		}
540
 
541
	},
542
 
543
	_positionLabel: function(itm){
544
		var x = 0;
545
		var y = 0;
546
 
547
		var mb = dojo.marginBox(itm.lblNode);
548
 
549
		if(this.labelEdge == this.EDGE.TOP){
550
			x = Math.round((itm.sizeW / 2) - (mb.w / 2));
551
			y = -mb.h;
552
		}
553
 
554
		if(this.labelEdge == this.EDGE.BOTTOM){
555
			x = Math.round((itm.sizeW / 2) - (mb.w / 2));
556
			y = itm.sizeH;
557
		}
558
 
559
		if(this.labelEdge == this.EDGE.LEFT){
560
			x = -mb.w;
561
			y = Math.round((itm.sizeH / 2) - (mb.h / 2));
562
		}
563
 
564
		if(this.labelEdge == this.EDGE.RIGHT){
565
			x = itm.sizeW;
566
			y = Math.round((itm.sizeH / 2) - (mb.h / 2));
567
		}
568
 
569
		itm.lblNode.style.left = x + 'px';
570
		itm.lblNode.style.top  = y + 'px';
571
	},
572
 
573
	_calcHitGrid: function(){
574
 
575
		var pos = dojo.coords(this.domNode, true);
576
 
577
		this.hitX1 = pos.x - this.proximityLeft;
578
		this.hitY1 = pos.y - this.proximityTop;
579
		this.hitX2 = this.hitX1 + this.totalWidth;
580
		this.hitY2 = this.hitY1 + this.totalHeight;
581
 
582
	},
583
 
584
	_toEdge: function(inp, def){
585
		return this.EDGE[inp.toUpperCase()] || def;
586
	},
587
 
588
	_expandSlowly: function(){
589
		// summary: slowly expand the image to user specified max size
590
		if(!this.isOver){ return; }
591
		this.timerScale += 0.2;
592
		this._paint();
593
		if(this.timerScale<1.0){
594
			setTimeout(dojo.hitch(this, "_expandSlowly"), 10);
595
		}
596
	},
597
 
598
	destroyRecursive: function(){
599
		// need to disconnect when we destroy
600
		dojo.disconnect(this._onMouseOutHandle);
601
		dojo.disconnect(this._onMouseMoveHandle);
602
		dojo.disconnect(this._addChildHandle);
603
		if (this.isFixed) { dojo.disconnect(this._onScrollHandle); }
604
		dojo.disconnect(this._onResizeHandle);
605
		this.inherited("destroyRecursive",arguments);
606
	}
607
});
608
 
609
dojo.declare("dojox.widget.FisheyeListItem", [dijit._Widget, dijit._Templated, dijit._Contained], {
610
	/*
611
	 * summary
612
	 *	Menu item inside of a FisheyeList.
613
	 *	See FisheyeList documentation for details on usage.
614
	 */
615
 
616
	// iconSrc: String
617
	//	pathname to image file (jpg, gif, png, etc.) of icon for this menu item
618
	iconSrc: "",
619
 
620
	// label: String
621
	//	label to print next to the icon, when it is moused-over
622
	label: "",
623
 
624
	// id: String
625
	//	will be set to the id of the orginal div element
626
	id: "",
627
 
628
	_blankImgPath: dojo.moduleUrl("dojox.widget", "FisheyeList/blank.gif"),
629
 
630
	templateString:
631
		'<div class="dojoxFisheyeListItem">' +
632
		'  <img class="dojoxFisheyeListItemImage" dojoAttachPoint="imgNode" dojoAttachEvent="onmouseover:onMouseOver,onmouseout:onMouseOut,onclick:onClick">' +
633
		'  <div class="dojoxFisheyeListItemLabel" dojoAttachPoint="lblNode"></div>' +
634
		'</div>',
635
 
636
	_isNode: function(/* object */wh){
637
		//	summary:
638
		//		checks to see if wh is actually a node.
639
		if(typeof Element == "function") {
640
			try{
641
				return wh instanceof Element;	//	boolean
642
			}catch(e){}
643
		}else{
644
			// best-guess
645
			return wh && !isNaN(wh.nodeType);	//	boolean
646
		}
647
	},
648
 
649
	_hasParent: function(/*Node*/node){
650
		//	summary:
651
		//		returns whether or not node is a child of another node.
652
		return Boolean(node && node.parentNode && this._isNode(node.parentNode));	//	boolean
653
	},
654
 
655
	postCreate: function() {
656
 
657
		// set image
658
		if((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4)==".png")&&(dojo.isIE)&&(dojo.isIE<7)){
659
			/* we set the id of the new fisheyeListItem to the id of the div defined in the HTML */
660
			if(this._hasParent(this.imgNode) && this.id != ""){
661
				var parent = this.imgNode.parentNode;
662
				parent.setAttribute("id", this.id);
663
			}
664
			this.imgNode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='scale')";
665
			this.imgNode.src = this._blankImgPath.toString();
666
		}else{
667
			if(this._hasParent(this.imgNode) && this.id != ""){
668
				var parent = this.imgNode.parentNode;
669
				parent.setAttribute("id", this.id);
670
			}
671
			this.imgNode.src = this.iconSrc;
672
		}
673
 
674
		// Label
675
		if(this.lblNode){
676
			this.lblNode.appendChild(document.createTextNode(this.label));
677
		}
678
		dojo.setSelectable(this.domNode, false);
679
		this.startup();
680
	},
681
 
682
	startup: function(){
683
		this.parent = this.getParent();
684
	},
685
 
686
	onMouseOver: function(/*Event*/ e){
687
		// summary: callback when user moves mouse over this menu item
688
		// in conservative mode, don't activate the menu until user mouses over an icon
689
		if(!this.parent.isOver){
690
			this.parent._setActive(e);
691
		}
692
		if(this.label != "" ){
693
			dojo.addClass(this.lblNode, "dojoxFishSelected");
694
			this.parent._positionLabel(this);
695
		}
696
	},
697
 
698
	onMouseOut: function(/*Event*/ e){
699
		// summary: callback when user moves mouse off of this menu item
700
		dojo.removeClass(this.lblNode, "dojoxFishSelected");
701
	},
702
 
703
	onClick: function(/*Event*/ e){
704
		// summary: user overridable callback when user clicks this menu item
705
	}
706
});
707
 
708
}