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 |
}
|