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["dojo._base.html"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dojo._base.html"] = true;
3
dojo.require("dojo._base.lang");
4
dojo.provide("dojo._base.html");
5
 
6
// FIXME: need to add unit tests for all the semi-public methods
7
 
8
try{
9
	document.execCommand("BackgroundImageCache", false, true);
10
}catch(e){
11
	// sane browsers don't have cache "issues"
12
}
13
 
14
// =============================
15
// DOM Functions
16
// =============================
17
 
18
/*=====
19
dojo.byId = function(id, doc){
20
	//	summary:
21
	//		similar to other library's "$" function, takes a
22
	//		string representing a DOM id or a DomNode
23
	//		and returns the corresponding DomNode. If a Node is
24
	//		passed, this function is a no-op. Returns a
25
	//		single DOM node or null, working around several
26
	//		browser-specific bugs to do so.
27
	//	id: String|DOMNode
28
	//	 	DOM id or DOM Node
29
	//	doc: DocumentElement
30
	//		Document to work in. Defaults to the current value of
31
	//		dojo.doc.  Can be used to retreive
32
	//		node references from other documents.
33
=====*/
34
if(dojo.isIE || dojo.isOpera){
35
	dojo.byId = function(id, doc){
36
		if(dojo.isString(id)){
37
			var _d = doc || dojo.doc;
38
			var te = _d.getElementById(id);
39
			// attributes.id.value is better than just id in case the
40
			// user has a name=id inside a form
41
			if(te && te.attributes.id.value == id){
42
				return te;
43
			}else{
44
				var eles = _d.all[id];
45
				if(!eles){ return; }
46
				if(!eles.length){ return eles; }
47
				// if more than 1, choose first with the correct id
48
				var i=0;
49
				while((te=eles[i++])){
50
					if(te.attributes.id.value == id){ return te; }
51
				}
52
			}
53
		}else{
54
			return id; // DomNode
55
		}
56
	}
57
}else{
58
	dojo.byId = function(id, doc){
59
		if(dojo.isString(id)){
60
			return (doc || dojo.doc).getElementById(id);
61
		}else{
62
			return id; // DomNode
63
		}
64
	}
65
}
66
/*=====
67
}
68
=====*/
69
 
70
(function(){
71
	/*
72
	dojo.createElement = function(obj, parent, position){
73
		// TODO: need to finish this!
74
	}
75
	*/
76
 
77
	var _destroyContainer = null;
78
	dojo._destroyElement = function(/*String||DomNode*/node){
79
		// summary:
80
		//		removes node from its parent, clobbers it and all of its
81
		//		children.
82
		//	node:
83
		//		the element to be destroyed, either as an ID or a reference
84
 
85
		node = dojo.byId(node);
86
		try{
87
			if(!_destroyContainer){
88
				_destroyContainer = document.createElement("div");
89
			}
90
			_destroyContainer.appendChild(node.parentNode ? node.parentNode.removeChild(node) : node);
91
			// NOTE: see http://trac.dojotoolkit.org/ticket/2931. This may be a bug and not a feature
92
			_destroyContainer.innerHTML = "";
93
		}catch(e){
94
			/* squelch */
95
		}
96
	};
97
 
98
	dojo.isDescendant = function(/*DomNode|String*/node, /*DomNode|String*/ancestor){
99
		//	summary:
100
		//		Returns true if node is a descendant of ancestor
101
		//	node: id or node reference to test
102
		//	ancestor: id or node reference of potential parent to test against
103
		try{
104
			node = dojo.byId(node);
105
			ancestor = dojo.byId(ancestor);
106
			while(node){
107
				if(node === ancestor){
108
					return true; // Boolean
109
				}
110
				node = node.parentNode;
111
			}
112
		}catch(e){ return -1; /* squelch */ }
113
		return false; // Boolean
114
	};
115
 
116
	dojo.setSelectable = function(/*DomNode|String*/node, /*Boolean*/selectable){
117
		//	summary: enable or disable selection on a node
118
		//	node:
119
		//		id or reference to node
120
		//	selectable:
121
		node = dojo.byId(node);
122
		if(dojo.isMozilla){
123
			node.style.MozUserSelect = selectable ? "" : "none";
124
		}else if(dojo.isKhtml){
125
			node.style.KhtmlUserSelect = selectable ? "auto" : "none";
126
		}else if(dojo.isIE){
127
			node.unselectable = selectable ? "" : "on";
128
			dojo.query("*", node).forEach(function(descendant){
129
				descendant.unselectable = selectable ? "" : "on";
130
			});
131
		}
132
		//FIXME: else?  Opera?
133
	};
134
 
135
	var _insertBefore = function(/*Node*/node, /*Node*/ref){
136
		ref.parentNode.insertBefore(node, ref);
137
		return true;	//	boolean
138
	}
139
 
140
	var _insertAfter = function(/*Node*/node, /*Node*/ref){
141
		//	summary:
142
		//		Try to insert node after ref
143
		var pn = ref.parentNode;
144
		if(ref == pn.lastChild){
145
			pn.appendChild(node);
146
		}else{
147
			return _insertBefore(node, ref.nextSibling);	//	boolean
148
		}
149
		return true;	//	boolean
150
	}
151
 
152
	dojo.place = function(/*String|DomNode*/node, /*String|DomNode*/refNode, /*String|Number*/position){
153
		//	summary:
154
		//		attempt to insert node in relation to ref based on position
155
		//	node:
156
		//		id or reference to node to place relative to refNode
157
		//	refNode:
158
		//		id or reference of node to use as basis for placement
159
		//	position:
160
		//		string noting the position of node relative to refNode or a
161
		//		number indicating the location in the childNodes collection of
162
		//		refNode. Accepted string values are:
163
		//			* before
164
		//			* after
165
		//			* first
166
		//			* last
167
		//		"first" and "last" indicate positions as children of refNode.
168
 
169
		// FIXME: need to write tests for this!!!!
170
		if(!node || !refNode || position === undefined){
171
			return false;	//	boolean
172
		}
173
		node = dojo.byId(node);
174
		refNode = dojo.byId(refNode);
175
		if(typeof position == "number"){
176
			var cn = refNode.childNodes;
177
			if((position == 0 && cn.length == 0) ||
178
				cn.length == position){
179
				refNode.appendChild(node); return true;
180
			}
181
			if(position == 0){
182
				return _insertBefore(node, refNode.firstChild);
183
			}
184
			return _insertAfter(node, cn[position-1]);
185
		}
186
		switch(position.toLowerCase()){
187
			case "before":
188
				return _insertBefore(node, refNode);	//	boolean
189
			case "after":
190
				return _insertAfter(node, refNode);		//	boolean
191
			case "first":
192
				if(refNode.firstChild){
193
					return _insertBefore(node, refNode.firstChild);	//	boolean
194
				}else{
195
					refNode.appendChild(node);
196
					return true;	//	boolean
197
				}
198
				break;
199
			default: // aka: last
200
				refNode.appendChild(node);
201
				return true;	//	boolean
202
		}
203
	}
204
 
205
	// Box functions will assume this model.
206
	// On IE/Opera, BORDER_BOX will be set if the primary document is in quirks mode.
207
	// Can be set to change behavior of box setters.
208
 
209
	// can be either:
210
	//	"border-box"
211
	//	"content-box" (default)
212
	dojo.boxModel = "content-box";
213
 
214
	// We punt per-node box mode testing completely.
215
	// If anybody cares, we can provide an additional (optional) unit
216
	// that overrides existing code to include per-node box sensitivity.
217
 
218
	// Opera documentation claims that Opera 9 uses border-box in BackCompat mode.
219
	// but experiments (Opera 9.10.8679 on Windows Vista) indicate that it actually continues to use content-box.
220
	// IIRC, earlier versions of Opera did in fact use border-box.
221
	// Opera guys, this is really confusing. Opera being broken in quirks mode is not our fault.
222
 
223
	if(dojo.isIE /*|| dojo.isOpera*/){
224
		var _dcm = document.compatMode;
225
		// client code may have to adjust if compatMode varies across iframes
226
		dojo.boxModel = (_dcm=="BackCompat")||(_dcm=="QuirksMode")||(dojo.isIE<6) ? "border-box" : "content-box";
227
	}
228
 
229
	// =============================
230
	// Style Functions
231
	// =============================
232
 
233
	// getComputedStyle drives most of the style code.
234
	// Wherever possible, reuse the returned object.
235
	//
236
	// API functions below that need to access computed styles accept an
237
	// optional computedStyle parameter.
238
	//
239
	// If this parameter is omitted, the functions will call getComputedStyle themselves.
240
	//
241
	// This way, calling code can access computedStyle once, and then pass the reference to
242
	// multiple API functions.
243
	//
244
	// This is a faux declaration to take pity on the doc tool
245
 
246
/*=====
247
	dojo.getComputedStyle = function(node){
248
		//	summary:
249
		//		Returns a "computed style" object.
250
		//	description:
251
		//		get "computed style" object which can be used to gather
252
		//		information about the current state of the rendered node.
253
		//
254
		//		Note that this may behave differently on different browsers.
255
		//		Values may have different formats and value encodings across
256
		//		browsers.
257
		//
258
		//		Use the dojo.style() method for more consistent (pixelized)
259
		//		return values.
260
		//	node: DOMNode
261
		//		a reference to a DOM node. Does NOT support taking an
262
		//		ID string for speed reasons.
263
		//	example:
264
		//	|	dojo.getComputedStyle(dojo.byId('foo')).borderWidth;
265
		return; // CSS2Properties
266
	}
267
=====*/
268
 
269
	var gcs, dv = document.defaultView;
270
	if(dojo.isSafari){
271
		gcs = function(/*DomNode*/node){
272
			var s = dv.getComputedStyle(node, null);
273
			if(!s && node.style){
274
				node.style.display = "";
275
				s = dv.getComputedStyle(node, null);
276
			}
277
			return s || {};
278
		};
279
	}else if(dojo.isIE){
280
		gcs = function(node){
281
			return node.currentStyle;
282
		};
283
	}else{
284
		gcs = function(node){
285
			return dv.getComputedStyle(node, null);
286
		};
287
	}
288
	dojo.getComputedStyle = gcs;
289
 
290
	if(!dojo.isIE){
291
		dojo._toPixelValue = function(element, value){
292
			// style values can be floats, client code may want
293
			// to round for integer pixels.
294
			return parseFloat(value) || 0;
295
		}
296
	}else{
297
		dojo._toPixelValue = function(element, avalue){
298
			if(!avalue){ return 0; }
299
			// on IE7, medium is usually 4 pixels
300
			if(avalue=="medium"){ return 4; }
301
			// style values can be floats, client code may
302
			// want to round this value for integer pixels.
303
			if(avalue.slice && (avalue.slice(-2)=='px')){ return parseFloat(avalue); }
304
			with(element){
305
				var sLeft = style.left;
306
				var rsLeft = runtimeStyle.left;
307
				runtimeStyle.left = currentStyle.left;
308
				try{
309
					// 'avalue' may be incompatible with style.left, which can cause IE to throw
310
					// this has been observed for border widths using "thin", "medium", "thick" constants
311
					// those particular constants could be trapped by a lookup
312
					// but perhaps there are more
313
					style.left = avalue;
314
					avalue = style.pixelLeft;
315
				}catch(e){
316
					avalue = 0;
317
				}
318
				style.left = sLeft;
319
				runtimeStyle.left = rsLeft;
320
			}
321
			return avalue;
322
		}
323
	}
324
 
325
	// FIXME: there opacity quirks on FF that we haven't ported over. Hrm.
326
	/*=====
327
	dojo._getOpacity = function(node){
328
			//	summary:
329
			//		Returns the current opacity of the passed node as a
330
			//		floating-point value between 0 and 1.
331
			//	node: DomNode
332
			//		a reference to a DOM node. Does NOT support taking an
333
			//		ID string for speed reasons.
334
			//	return: Number between 0 and 1
335
	}
336
	=====*/
337
 
338
	dojo._getOpacity = (dojo.isIE ? function(node){
339
			try{
340
				return (node.filters.alpha.opacity / 100); // Number
341
			}catch(e){
342
				return 1; // Number
343
			}
344
		} : function(node){
345
			return dojo.getComputedStyle(node).opacity;
346
		}
347
	);
348
 
349
	/*=====
350
	dojo._setOpacity = function(node, opacity){
351
			//	summary:
352
			//		set the opacity of the passed node portably. Returns the
353
			//		new opacity of the node.
354
			//	node: DOMNode
355
			//		a reference to a DOM node. Does NOT support taking an
356
			//		ID string for performance reasons.
357
			//	opacity: Number
358
			//		A Number between 0 and 1. 0 specifies transparent.
359
			//	return: Number between 0 and 1
360
	}
361
	=====*/
362
 
363
	dojo._setOpacity = (dojo.isIE ? function(/*DomNode*/node, /*Number*/opacity){
364
			if(opacity == 1){
365
				// on IE7 Alpha(Filter opacity=100) makes text look fuzzy so remove it altogether (bug #2661)
366
				node.style.cssText = node.style.cssText.replace(/FILTER:[^;]*;/i, "");
367
				if(node.nodeName.toLowerCase() == "tr"){
368
					dojo.query("> td", node).forEach(function(i){
369
						i.style.cssText = i.style.cssText.replace(/FILTER:[^;]*;/i, "");
370
					});
371
				}
372
			}else{
373
				var o = "Alpha(Opacity="+(opacity*100)+")";
374
				node.style.filter = o;
375
			}
376
			if(node.nodeName.toLowerCase() == "tr"){
377
				dojo.query("> td", node).forEach(function(i){
378
					i.style.filter = o;
379
				});
380
			}
381
			return opacity;
382
		} : function(node, opacity){
383
			return node.style.opacity = opacity;
384
		}
385
	);
386
 
387
	var _pixelNamesCache = {
388
		width: true, height: true, left: true, top: true
389
	};
390
	var _toStyleValue = function(node, type, value){
391
		type = type.toLowerCase();
392
		if(_pixelNamesCache[type] === true){
393
			return dojo._toPixelValue(node, value)
394
		}else if(_pixelNamesCache[type] === false){
395
			return value;
396
		}else{
397
			if(dojo.isOpera && type == "cssText"){
398
				// FIXME: add workaround for #2855 here
399
			}
400
			if(
401
				(type.indexOf("margin") >= 0) ||
402
				// (type.indexOf("border") >= 0) ||
403
				(type.indexOf("padding") >= 0) ||
404
				(type.indexOf("width") >= 0) ||
405
				(type.indexOf("height") >= 0) ||
406
				(type.indexOf("max") >= 0) ||
407
				(type.indexOf("min") >= 0) ||
408
				(type.indexOf("offset") >= 0)
409
			){
410
				_pixelNamesCache[type] = true;
411
				return dojo._toPixelValue(node, value)
412
			}else{
413
				_pixelNamesCache[type] = false;
414
				return value;
415
			}
416
		}
417
	}
418
 
419
	// public API
420
 
421
	dojo.style = function(/*DomNode|String*/ node, /*String*/style, /*String?*/value){
422
		//	summary:
423
		//		gets or sets a style property on node. If 2 arguments are
424
		//		passed, acts as a getter. If value is passed, acts as a setter
425
		//		for the property.
426
		//	node:
427
		//		id or reference to node to get/set style for
428
		//	style:
429
		//		the style property to set in DOM-accessor format
430
		//		("borderWidth", not "border-width").
431
		//	value:
432
		//		optional. If passed, sets value on the node for style, handling
433
		//		cross-browser concerns.
434
		var n=dojo.byId(node), args=arguments.length, op=(style=="opacity");
435
		if(args==3){
436
			return op ? dojo._setOpacity(n, value) : n.style[style] = value; /*Number*/
437
		}
438
		if(args==2 && op){
439
			return dojo._getOpacity(n);
440
		}
441
		var s = dojo.getComputedStyle(n);
442
		return (args == 1) ? s : _toStyleValue(n, style, s[style]); /* CSS2Properties||String||Number */
443
	}
444
 
445
	// =============================
446
	// Box Functions
447
	// =============================
448
 
449
	dojo._getPadExtents = function(/*DomNode*/n, /*Object*/computedStyle){
450
		//	summary:
451
		// 		Returns object with special values specifically useful for node
452
		// 		fitting.
453
		// 			l/t = left/top padding (respectively)
454
		// 			w = the total of the left and right padding
455
		// 			h = the total of the top and bottom padding
456
		//		If 'node' has position, l/t forms the origin for child nodes.
457
		//		The w/h are used for calculating boxes.
458
		//		Normally application code will not need to invoke this
459
		//		directly, and will use the ...box... functions instead.
460
		var
461
			s=computedStyle||gcs(n),
462
			px=dojo._toPixelValue,
463
			l=px(n, s.paddingLeft),
464
			t=px(n, s.paddingTop);
465
		return {
466
			l: l,
467
			t: t,
468
			w: l+px(n, s.paddingRight),
469
			h: t+px(n, s.paddingBottom)
470
		};
471
	}
472
 
473
	dojo._getBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
474
		//	summary:
475
		//		returns an object with properties useful for noting the border
476
		//		dimensions.
477
		// 			l/t = the sum of left/top border (respectively)
478
		//			w = the sum of the left and right border
479
		//			h = the sum of the top and bottom border
480
		//		The w/h are used for calculating boxes.
481
		//		Normally application code will not need to invoke this
482
		//		directly, and will use the ...box... functions instead.
483
		var
484
			ne='none',
485
			px=dojo._toPixelValue,
486
			s=computedStyle||gcs(n),
487
			bl=(s.borderLeftStyle!=ne ? px(n, s.borderLeftWidth) : 0),
488
			bt=(s.borderTopStyle!=ne ? px(n, s.borderTopWidth) : 0);
489
		return {
490
			l: bl,
491
			t: bt,
492
			w: bl + (s.borderRightStyle!=ne ? px(n, s.borderRightWidth) : 0),
493
			h: bt + (s.borderBottomStyle!=ne ? px(n, s.borderBottomWidth) : 0)
494
		};
495
	}
496
 
497
	dojo._getPadBorderExtents = function(/*DomNode*/n, /*Object*/computedStyle){
498
		//	summary:
499
		//		returns object with properties useful for box fitting with
500
		//		regards to padding.
501
		//			l/t = the sum of left/top padding and left/top border (respectively)
502
		//			w = the sum of the left and right padding and border
503
		//			h = the sum of the top and bottom padding and border
504
		//		The w/h are used for calculating boxes.
505
		//		Normally application code will not need to invoke this
506
		//		directly, and will use the ...box... functions instead.
507
		var
508
			s=computedStyle||gcs(n),
509
			p=dojo._getPadExtents(n, s),
510
			b=dojo._getBorderExtents(n, s);
511
		return {
512
			l: p.l + b.l,
513
			t: p.t + b.t,
514
			w: p.w + b.w,
515
			h: p.h + b.h
516
		};
517
	}
518
 
519
	dojo._getMarginExtents = function(n, computedStyle){
520
		//	summary:
521
		//		returns object with properties useful for box fitting with
522
		//		regards to box margins (i.e., the outer-box).
523
		//			l/t = marginLeft, marginTop, respectively
524
		//			w = total width, margin inclusive
525
		//			h = total height, margin inclusive
526
		//		The w/h are used for calculating boxes.
527
		//		Normally application code will not need to invoke this
528
		//		directly, and will use the ...box... functions instead.
529
		var
530
			s=computedStyle||gcs(n),
531
			px=dojo._toPixelValue,
532
			l=px(n, s.marginLeft),
533
			t=px(n, s.marginTop),
534
			r=px(n, s.marginRight),
535
			b=px(n, s.marginBottom);
536
		if (dojo.isSafari && (s.position != "absolute")){
537
			// FIXME: Safari's version of the computed right margin
538
			// is the space between our right edge and the right edge
539
			// of our offsetParent.
540
			// What we are looking for is the actual margin value as
541
			// determined by CSS.
542
			// Hack solution is to assume left/right margins are the same.
543
			r = l;
544
		}
545
		return {
546
			l: l,
547
			t: t,
548
			w: l+r,
549
			h: t+b
550
		};
551
	}
552
 
553
	// Box getters work in any box context because offsetWidth/clientWidth
554
	// are invariant wrt box context
555
	//
556
	// They do *not* work for display: inline objects that have padding styles
557
	// because the user agent ignores padding (it's bogus styling in any case)
558
	//
559
	// Be careful with IMGs because they are inline or block depending on
560
	// browser and browser mode.
561
 
562
	// Although it would be easier to read, there are not separate versions of
563
	// _getMarginBox for each browser because:
564
	// 1. the branching is not expensive
565
	// 2. factoring the shared code wastes cycles (function call overhead)
566
	// 3. duplicating the shared code wastes bytes
567
 
568
	dojo._getMarginBox = function(/*DomNode*/node, /*Object*/computedStyle){
569
		// summary:
570
		//		returns an object that encodes the width, height, left and top
571
		//		positions of the node's margin box.
572
		var s = computedStyle||gcs(node), me = dojo._getMarginExtents(node, s);
573
		var	l = node.offsetLeft - me.l,	t = node.offsetTop - me.t;
574
		if(dojo.isMoz){
575
			// Mozilla:
576
			// If offsetParent has a computed overflow != visible, the offsetLeft is decreased
577
			// by the parent's border.
578
			// We don't want to compute the parent's style, so instead we examine node's
579
			// computed left/top which is more stable.
580
			var sl = parseFloat(s.left), st = parseFloat(s.top);
581
			if(!isNaN(sl) && !isNaN(st)){
582
				l = sl, t = st;
583
			}else{
584
				// If child's computed left/top are not parseable as a number (e.g. "auto"), we
585
				// have no choice but to examine the parent's computed style.
586
				var p = node.parentNode;
587
				if(p && p.style){
588
					var pcs = gcs(p);
589
					if(pcs.overflow != "visible"){
590
						var be = dojo._getBorderExtents(p, pcs);
591
						l += be.l, t += be.t;
592
					}
593
				}
594
			}
595
		}else if(dojo.isOpera){
596
			// On Opera, offsetLeft includes the parent's border
597
			var p = node.parentNode;
598
			if(p){
599
				var be = dojo._getBorderExtents(p);
600
				l -= be.l, t -= be.t;
601
			}
602
		}
603
		return {
604
			l: l,
605
			t: t,
606
			w: node.offsetWidth + me.w,
607
			h: node.offsetHeight + me.h
608
		};
609
	}
610
 
611
	dojo._getContentBox = function(node, computedStyle){
612
		// summary:
613
		//		Returns an object that encodes the width, height, left and top
614
		//		positions of the node's content box, irrespective of the
615
		//		current box model.
616
 
617
		// clientWidth/Height are important since the automatically account for scrollbars
618
		// fallback to offsetWidth/Height for special cases (see #3378)
619
		var s=computedStyle||gcs(node), pe=dojo._getPadExtents(node, s), be=dojo._getBorderExtents(node, s), w=node.clientWidth, h;
620
		if(!w){
621
			w=node.offsetWidth, h=node.offsetHeight;
622
		}else{
623
			h=node.clientHeight, be.w = be.h = 0;
624
		}
625
		// On Opera, offsetLeft includes the parent's border
626
		if(dojo.isOpera){ pe.l += be.l; pe.t += be.t; };
627
		return {
628
			l: pe.l,
629
			t: pe.t,
630
			w: w - pe.w - be.w,
631
			h: h - pe.h - be.h
632
		};
633
	}
634
 
635
	dojo._getBorderBox = function(node, computedStyle){
636
		var s=computedStyle||gcs(node), pe=dojo._getPadExtents(node, s), cb=dojo._getContentBox(node, s);
637
		return {
638
			l: cb.l - pe.l,
639
			t: cb.t - pe.t,
640
			w: cb.w + pe.w,
641
			h: cb.h + pe.h
642
		};
643
	}
644
 
645
	// Box setters depend on box context because interpretation of width/height styles
646
	// vary wrt box context.
647
	//
648
	// The value of dojo.boxModel is used to determine box context.
649
	// dojo.boxModel can be set directly to change behavior.
650
	//
651
	// Beware of display: inline objects that have padding styles
652
	// because the user agent ignores padding (it's a bogus setup anyway)
653
	//
654
	// Be careful with IMGs because they are inline or block depending on
655
	// browser and browser mode.
656
	//
657
	// Elements other than DIV may have special quirks, like built-in
658
	// margins or padding, or values not detectable via computedStyle.
659
	// In particular, margins on TABLE do not seems to appear
660
	// at all in computedStyle on Mozilla.
661
 
662
	dojo._setBox = function(/*DomNode*/node, /*Number?*/l, /*Number?*/t, /*Number?*/w, /*Number?*/h, /*String?*/u){
663
		//	summary:
664
		//		sets width/height/left/top in the current (native) box-model
665
		//		dimentions. Uses the unit passed in u.
666
		//	node: DOM Node reference. Id string not supported for performance reasons.
667
		//	l: optional. left offset from parent.
668
		//	t: optional. top offset from parent.
669
		//	w: optional. width in current box model.
670
		//	h: optional. width in current box model.
671
		//	u: optional. unit measure to use for other measures. Defaults to "px".
672
		u = u || "px";
673
		with(node.style){
674
			if(!isNaN(l)){ left = l+u; }
675
			if(!isNaN(t)){ top = t+u; }
676
			if(w>=0){ width = w+u; }
677
			if(h>=0){ height = h+u; }
678
		}
679
	}
680
 
681
	dojo._usesBorderBox = function(/*DomNode*/node){
682
		//	summary:
683
		//		True if the node uses border-box layout.
684
 
685
		// We could test the computed style of node to see if a particular box
686
		// has been specified, but there are details and we choose not to bother.
687
		var n = node.tagName;
688
		// For whatever reason, TABLE and BUTTON are always border-box by default.
689
		// If you have assigned a different box to either one via CSS then
690
		// box functions will break.
691
		return dojo.boxModel=="border-box" || n=="TABLE" || n=="BUTTON"; // boolean
692
	}
693
 
694
	dojo._setContentSize = function(/*DomNode*/node, /*Number*/widthPx, /*Number*/heightPx, /*Object*/computedStyle){
695
		//	summary:
696
		//		Sets the size of the node's contents, irrespective of margins,
697
		//		padding, or borders.
698
		var bb = dojo._usesBorderBox(node);
699
		if(bb){
700
			var pb = dojo._getPadBorderExtents(node, computedStyle);
701
			if(widthPx>=0){ widthPx += pb.w; }
702
			if(heightPx>=0){ heightPx += pb.h; }
703
		}
704
		dojo._setBox(node, NaN, NaN, widthPx, heightPx);
705
	}
706
 
707
	dojo._setMarginBox = function(/*DomNode*/node, 	/*Number?*/leftPx, /*Number?*/topPx,
708
													/*Number?*/widthPx, /*Number?*/heightPx,
709
													/*Object*/computedStyle){
710
		//	summary:
711
		//		sets the size of the node's margin box and palcement
712
		//		(left/top), irrespective of box model. Think of it as a
713
		//		passthrough to dojo._setBox that handles box-model vagaries for
714
		//		you.
715
 
716
		var s = computedStyle || dojo.getComputedStyle(node);
717
		// Some elements have special padding, margin, and box-model settings.
718
		// To use box functions you may need to set padding, margin explicitly.
719
		// Controlling box-model is harder, in a pinch you might set dojo.boxModel.
720
		var bb=dojo._usesBorderBox(node),
721
				pb=bb ? _nilExtents : dojo._getPadBorderExtents(node, s),
722
				mb=dojo._getMarginExtents(node, s);
723
		if(widthPx>=0){	widthPx = Math.max(widthPx - pb.w - mb.w, 0); }
724
		if(heightPx>=0){ heightPx = Math.max(heightPx - pb.h - mb.h, 0); }
725
		dojo._setBox(node, leftPx, topPx, widthPx, heightPx);
726
	}
727
 
728
	var _nilExtents = { l:0, t:0, w:0, h:0 };
729
 
730
	// public API
731
 
732
	dojo.marginBox = function(/*DomNode|String*/node, /*Object?*/box){
733
		//	summary:
734
		//		getter/setter for the margin-box of node.
735
		//	description:
736
		//		Returns an object in the expected format of box (regardless
737
		//		if box is passed). The object might look like:
738
		//			{ l: 50, t: 200, w: 300: h: 150 }
739
		//		for a node offset from its parent 50px to the left, 200px from
740
		//		the top with a margin width of 300px and a margin-height of
741
		//		150px.
742
		//	node:
743
		//		id or reference to DOM Node to get/set box for
744
		//	box:
745
		//		optional. If passed, denotes that dojo.marginBox() should
746
		//		update/set the margin box for node. Box is an object in the
747
		//		above format. All properties are optional if passed.
748
		var n=dojo.byId(node), s=gcs(n), b=box;
749
		return !b ? dojo._getMarginBox(n, s) : dojo._setMarginBox(n, b.l, b.t, b.w, b.h, s); // Object
750
	}
751
 
752
	dojo.contentBox = function(/*DomNode|String*/node, /*Object?*/box){
753
		//	summary:
754
		//		getter/setter for the content-box of node.
755
		//	description:
756
		//		Returns an object in the expected format of box (regardless if box is passed).
757
		//		The object might look like:
758
		//			{ l: 50, t: 200, w: 300: h: 150 }
759
		//		for a node offset from its parent 50px to the left, 200px from
760
		//		the top with a content width of 300px and a content-height of
761
		//		150px. Note that the content box may have a much larger border
762
		//		or margin box, depending on the box model currently in use and
763
		//		CSS values set/inherited for node.
764
		//	node:
765
		//		id or reference to DOM Node to get/set box for
766
		//	box:
767
		//		optional. If passed, denotes that dojo.contentBox() should
768
		//		update/set the content box for node. Box is an object in the
769
		//		above format. All properties are optional if passed.
770
		var n=dojo.byId(node), s=gcs(n), b=box;
771
		return !b ? dojo._getContentBox(n, s) : dojo._setContentSize(n, b.w, b.h, s); // Object
772
	}
773
 
774
	// =============================
775
	// Positioning
776
	// =============================
777
 
778
	var _sumAncestorProperties = function(node, prop){
779
		if(!(node = (node||0).parentNode)){return 0};
780
		var val, retVal = 0, _b = dojo.body();
781
		while(node && node.style){
782
			if(gcs(node).position == "fixed"){
783
				return 0;
784
			}
785
			val = node[prop];
786
			if(val){
787
				retVal += val - 0;
788
				// opera and khtml #body & #html has the same values, we only
789
				// need one value
790
				if(node == _b){ break; }
791
			}
792
			node = node.parentNode;
793
		}
794
		return retVal;	//	integer
795
	}
796
 
797
	dojo._docScroll = function(){
798
		var _b = dojo.body();
799
		var _w = dojo.global;
800
		var de = dojo.doc.documentElement;
801
		return {
802
			y: (_w.pageYOffset || de.scrollTop || _b.scrollTop || 0),
803
			x: (_w.pageXOffset || dojo._fixIeBiDiScrollLeft(de.scrollLeft) || _b.scrollLeft || 0)
804
		};
805
	};
806
 
807
	dojo._isBodyLtr = function(){
808
		//FIXME: could check html and body tags directly instead of computed style?  need to ignore case, accept empty values
809
		return !("_bodyLtr" in dojo) ?
810
			dojo._bodyLtr = dojo.getComputedStyle(dojo.body()).direction == "ltr" :
811
			dojo._bodyLtr; // Boolean
812
	}
813
 
814
	dojo._getIeDocumentElementOffset = function(){
815
		// summary
816
		// The following values in IE contain an offset:
817
		//     event.clientX
818
		//     event.clientY
819
		//     node.getBoundingClientRect().left
820
		//     node.getBoundingClientRect().top
821
		// But other position related values do not contain this offset, such as
822
		// node.offsetLeft, node.offsetTop, node.style.left and node.style.top.
823
		// The offset is always (2, 2) in LTR direction. When the body is in RTL
824
		// direction, the offset counts the width of left scroll bar's width.
825
		// This function computes the actual offset.
826
 
827
		//NOTE: assumes we're being called in an IE browser
828
 
829
		var de = dojo.doc.documentElement;
830
		if(dojo.isIE >= 7){
831
			return {x: de.getBoundingClientRect().left, y: de.getBoundingClientRect().top}; // Object
832
		}else{
833
			// IE 6.0
834
			return {x: dojo._isBodyLtr() || window.parent == window ?
835
				de.clientLeft : de.offsetWidth - de.clientWidth - de.clientLeft,
836
				y: de.clientTop}; // Object
837
		}
838
	};
839
 
840
	dojo._fixIeBiDiScrollLeft = function(/*Integer*/ scrollLeft){
841
		// In RTL direction, scrollLeft should be a negative value, but IE
842
		// returns a positive one. All codes using documentElement.scrollLeft
843
		// must call this function to fix this error, otherwise the position
844
		// will offset to right when there is a horizonal scrollbar.
845
		if(dojo.isIE && !dojo._isBodyLtr()){
846
			var de = dojo.doc.documentElement;
847
			return scrollLeft + de.clientWidth - de.scrollWidth; // Integer
848
		}
849
		return scrollLeft; // Integer
850
	}
851
 
852
	dojo._abs = function(/*DomNode*/node, /*Boolean?*/includeScroll){
853
		//	summary:
854
		//		Gets the absolute position of the passed element based on the
855
		//		document itself. Returns an object of the form:
856
		//			{ x: 100, y: 300 }
857
		//		if includeScroll is passed, the x and y values will include any
858
		//		document offsets that may affect the position relative to the
859
		//		viewport.
860
 
861
		// FIXME: need to decide in the brave-new-world if we're going to be
862
		// margin-box or border-box.
863
		var ownerDocument = node.ownerDocument;
864
		var ret = {
865
			x: 0,
866
			y: 0
867
		};
868
		var hasScroll = false;
869
 
870
		// targetBoxType == "border-box"
871
		var db = dojo.body();
872
		if(dojo.isIE){
873
			var client = node.getBoundingClientRect();
874
			var offset = dojo._getIeDocumentElementOffset();
875
			ret.x = client.left - offset.x;
876
			ret.y = client.top - offset.y;
877
		}else if(ownerDocument["getBoxObjectFor"]){
878
			// mozilla
879
			var bo = ownerDocument.getBoxObjectFor(node);
880
			ret.x = bo.x - _sumAncestorProperties(node, "scrollLeft");
881
			ret.y = bo.y - _sumAncestorProperties(node, "scrollTop");
882
		}else{
883
			if(node["offsetParent"]){
884
				hasScroll = true;
885
				var endNode;
886
				// in Safari, if the node is an absolutely positioned child of
887
				// the body and the body has a margin the offset of the child
888
				// and the body contain the body's margins, so we need to end
889
				// at the body
890
				// FIXME: getting contrary results to the above in latest WebKit.
891
				if(dojo.isSafari &&
892
					//(node.style.getPropertyValue("position") == "absolute") &&
893
					(gcs(node).position == "absolute") &&
894
					(node.parentNode == db)){
895
					endNode = db;
896
				}else{
897
					endNode = db.parentNode;
898
				}
899
				if(node.parentNode != db){
900
					var nd = node;
901
					if(dojo.isOpera || (dojo.isSafari >= 3)){ nd = db; }
902
					ret.x -= _sumAncestorProperties(nd, "scrollLeft");
903
					ret.y -= _sumAncestorProperties(nd, "scrollTop");
904
				}
905
				var curnode = node;
906
				do{
907
					var n = curnode["offsetLeft"];
908
					//FIXME: ugly hack to workaround the submenu in
909
					//popupmenu2 does not shown up correctly in opera.
910
					//Someone have a better workaround?
911
					if(!dojo.isOpera || n>0){
912
						ret.x += isNaN(n) ? 0 : n;
913
					}
914
					var m = curnode["offsetTop"];
915
					ret.y += isNaN(m) ? 0 : m;
916
					curnode = curnode.offsetParent;
917
				}while((curnode != endNode)&&curnode);
918
			}else if(node["x"]&&node["y"]){
919
				ret.x += isNaN(node.x) ? 0 : node.x;
920
				ret.y += isNaN(node.y) ? 0 : node.y;
921
			}
922
		}
923
		// account for document scrolling
924
		// if offsetParent is used, ret value already includes scroll position
925
		// so we may have to actually remove that value if !includeScroll
926
		if(hasScroll || includeScroll){
927
			var scroll = dojo._docScroll();
928
			var m = hasScroll ? (!includeScroll ? -1 : 0) : 1;
929
			ret.y += m*scroll.y;
930
			ret.x += m*scroll.x;
931
		}
932
 
933
		return ret; // object
934
	}
935
 
936
	// FIXME: need a setter for coords or a moveTo!!
937
	dojo.coords = function(/*DomNode|String*/node, /*Boolean?*/includeScroll){
938
		//	summary:
939
		//		Returns an object that measures margin box width/height and
940
		//		absolute positioning data from dojo._abs(). Return value will
941
		//		be in the form:
942
		//			{ l: 50, t: 200, w: 300: h: 150, x: 100, y: 300 }
943
		//		does not act as a setter. If includeScroll is passed, the x and
944
		//		y params are affected as one would expect in dojo._abs().
945
		var n=dojo.byId(node), s=gcs(n), mb=dojo._getMarginBox(n, s);
946
		var abs = dojo._abs(n, includeScroll);
947
		mb.x = abs.x;
948
		mb.y = abs.y;
949
		return mb;
950
	}
951
})();
952
 
953
// =============================
954
// (CSS) Class Functions
955
// =============================
956
 
957
dojo.hasClass = function(/*DomNode|String*/node, /*String*/classStr){
958
	//	summary:
959
	//		Returns whether or not the specified classes are a portion of the
960
	//		class list currently applied to the node.
961
	return ((" "+dojo.byId(node).className+" ").indexOf(" "+classStr+" ") >= 0);  // Boolean
962
};
963
 
964
dojo.addClass = function(/*DomNode|String*/node, /*String*/classStr){
965
	//	summary:
966
	//		Adds the specified classes to the end of the class list on the
967
	//		passed node.
968
	node = dojo.byId(node);
969
	var cls = node.className;
970
	if((" "+cls+" ").indexOf(" "+classStr+" ") < 0){
971
		node.className = cls + (cls ? ' ' : '') + classStr;
972
	}
973
};
974
 
975
dojo.removeClass = function(/*DomNode|String*/node, /*String*/classStr){
976
	// summary: Removes the specified classes from node.
977
	node = dojo.byId(node);
978
	var t = dojo.trim((" " + node.className + " ").replace(" " + classStr + " ", " "));
979
	if(node.className != t){ node.className = t; }
980
};
981
 
982
dojo.toggleClass = function(/*DomNode|String*/node, /*String*/classStr, /*Boolean?*/condition){
983
	//	summary:
984
	//		Adds a class to node if not present, or removes if present.
985
	//		Pass a boolean condition if you want to explicitly add or remove.
986
	//	condition:
987
	//		If passed, true means to add the class, false means to remove.
988
	if(condition === undefined){
989
		condition = !dojo.hasClass(node, classStr);
990
	}
991
	dojo[condition ? "addClass" : "removeClass"](node, classStr);
992
};
993
 
994
}