Code

ungoogle and unamazone
[rrdtool-all.git] / website / inc / fixed.js
1 // fixed.js: fix fixed positioning and fixed backgrounds in IE/Win
2 // version 1.8, 08-Aug-2003
3 // written by Andrew Clover <and@doxdesk.com>, use freely
5 /*@cc_on
6 @if (@_win32 && @_jscript_version>4)
8 var fixed_positions= new Array();
9 var fixed_backgrounds= new Array();
10 var fixed_viewport;
12 // Initialisation. Called when the <body> tag arrives. Set up viewport so the
13 // rest of the script knows we're going, and add a measurer div, used to detect
14 // font size changes and measure image sizes for backgrounds later   
16 function fixed_init() {
17   fixed_viewport= (document.compatMode=='CSS1Compat') ?
18     document.documentElement : document.body;
19   var el= document.createElement('div');
20   el.setAttribute('id', 'fixed-measure');
21   el.style.position= 'absolute';
22   el.style.top= '0'; el.style.left= '0';
23   el.style.overflow= 'hidden'; el.style.visibility= 'hidden';
24   el.style.fontSize= 'xx-large'; el.style.height= '5em';
25   el.style.setExpression('width', 'fixed_measureFont()');
26   document.body.insertBefore(el, document.body.firstChild);
27 }
29 // Binding. Called every time an element is added to the document, check it
30 // for fixed features, if found add to our lists and set initial props   
32 function fixed_bind(el) {
33   var needLayout= false;
34   var tag= el.tagName.toLowerCase();
35   var st= el.style;
36   var cst= el.currentStyle;
37   var anc;
39   // find fixed-position elements
40   if (cst.position=='fixed') {
41     needLayout= true;
42     fixed_positions[fixed_positions.length]= el;
43     // store original positioning as we'll overwrite it
44     st.position= 'absolute';
45     st.fixedPLeft=   cst.left;
46     st.fixedPTop=    cst.top;
47     st.fixedPRight=  cst.right;
48     st.fixedPBottom= cst.bottom;
49     st.fixedPWidth=  fixed_parseLength(cst.width);
50     st.fixedPHeight= fixed_parseLength(cst.height);
51     // find element that will act as containing box, for convenience later
52     st.fixedCB= null;
53     for (anc= el; (anc= anc.parentElement).parentElement;) {
54       if (anc.currentStyle.position!='static') {
55         st.fixedCB= anc;
56         break;
57     } }
58     // detect nested fixed positioning (only ancestor need move)
59     st.fixedNest= false;
60     for (anc= el; anc= anc.parentElement;) {
61       if (anc.style.fixedNest!=null)
62         st.fixedNest= true;
63         break;
64     }
65   }
67   // find fixed-background elements (not body/html which IE already gets right)
68   if (cst.backgroundAttachment=='fixed' && tag!='body' && tag!='html') {
69     needLayout= true;
70     fixed_backgrounds[fixed_backgrounds.length]= el;
71     // get background offset, converting from keyword if necessary
72     st.fixedBLeft= fixed_parseLength(cst.backgroundPositionX);
73     st.fixedBTop=  fixed_parseLength(cst.backgroundPositionY);
74     // if it's a non-zero %age, need to know size of image for layout
75     if (st.fixedBLeft[1]=='%' || st.fixedBTop[1]=='%') {
76       st.fixedBWidth= 0; st.fixedBHeight= 0;
77       fixed_measureBack(el);
78     }
79   }
80   if (needLayout) fixed_layout();
81 }
83 // Layout. On every window or font size change, recalculate positioning   
85 // Request re-layout at next free moment
86 var fixed_delaying= false;
87 function fixed_delayout() {
88   if (fixed_delaying) return;
89   fixed_delaying= true;
90   window.setTimeout(fixed_layout, 0);
91 }
93 var fixed_ARBITRARY= 200;
95 function fixed_layout() {
96   fixed_delaying= false;
97   if (!fixed_viewport) return;
98   var i, el, st, j, pr, tmp, A= 'auto';
99   var cb, cbLeft, cbTop, cbRight, cbBottom, oLeft, oTop, oRight, oBottom;
100   var vpWidth=fixed_viewport.clientWidth, vpHeight=fixed_viewport.clientHeight;
102   // calculate initial position for fixed-position elements [black magic]
103   for (i= fixed_positions.length; i-->0;) {
104     el= fixed_positions[i]; st= el.style;
105     // find positioning of containing block
106     cb= st.fixedCB; if (!cb) cb= fixed_viewport;
107     cbLeft= fixed_pageLeft(cb); cbTop= fixed_pageTop(cb);
108     if (cb!=fixed_viewport) { cbLeft+= cb.clientLeft; cbTop+= cb.clientTop; }
109     cbRight= fixed_viewport.clientWidth-cbLeft-cb.clientWidth;
110     cbBottom= fixed_viewport.clientHeight-cbTop-cb.clientHeight;
111     // if size is in %, must recalculate relative to viewport
112     if (st.fixedPWidth[1]=='%')
113       st.width= Math.round(vpWidth*st.fixedPWidth[0]/100)+'px';
114     if (st.fixedPHeight[1]=='%')
115       st.height= Math.round(vpHeight*st.fixedPHeight[0]/100)+'px';
116     // find out offset values at max size, to account for margins
117     st.left= A; st.right= '0'; st.top= A; st.bottom= '0';
118     oRight= el.offsetLeft+el.offsetWidth; oBottom= el.offsetTop+el.offsetHeight;
119     st.left= '0'; st.right= A; st.top= '0'; st.bottom= A;
120     oLeft= el.offsetLeft; oTop= el.offsetTop;
121     // use this to convert all edges to pixels
122     st.left= A; st.right= st.fixedPRight;
123     st.top= A; st.bottom= st.fixedPBottom;
124     oRight-= el.offsetLeft+el.offsetWidth;
125     oBottom-= el.offsetTop+el.offsetHeight;
126     st.left= st.fixedPLeft; st.top= st.fixedPTop;
127     oLeft= el.offsetLeft-oLeft; oTop= el.offsetTop-oTop;
128     // edge positioning fix
129     if (st.fixedPWidth[1]==A && st.fixedPLeft!=A && st.fixedPRight!=A) {
130       tmp= el.offsetLeft; st.left= A; st.width= fixed_ARBITRARY+'px';
131       tmp= fixed_ARBITRARY+el.offsetLeft-tmp+cbLeft+cbRight;
132       st.left= st.fixedPLeft; st.width= ((tmp<1)?1:tmp)+'px';
133     }
134     if (st.fixedPHeight[1]==A && st.fixedPTop!=A && st.fixedPBottom!=A) {
135       tmp= el.offsetTop; st.top= A; st.height= fixed_ARBITRARY+'px';
136       tmp= fixed_ARBITRARY+el.offsetTop-tmp+cbTop+cbBottom;
137       st.top= st.fixedPTop; st.height= ((tmp<1)?1:tmp)+'px';
138     }
139     // move all non-auto edges relative to the viewport
140     st.fixedCLeft= (st.fixedPLeft=='auto') ? oLeft : oLeft-cbLeft;
141     st.fixedCTop= (st.fixedPTop=='auto') ? oTop : oTop-cbTop;
142     st.fixedCRight= (st.fixedPRight=='auto') ? oRight : oRight-cbRight;
143     st.fixedCBottom= (st.fixedPBottom=='auto') ? oBottom : oBottom-cbBottom;
144     // remove left-positioning of right-positioned elements
145     if (st.fixedPLeft=='auto' && st.fixedPRight!='auto') st.fixedCLeft= 'auto';
146     if (st.fixedPTop=='auto' && st.fixedPBottom!='auto') st.fixedCTop= 'auto';
147   }
150   // calculate initial positioning of fixed backgrounds
151   for (i= fixed_backgrounds.length; i-->0;) {
152     el= fixed_backgrounds[i]; st= el.style;
153     tmp= st.fixedBImage;
154     if (tmp) {
155       if (tmp.readyState!='uninitialized') {
156         st.fixedBWidth= tmp.offsetWidth;
157         st.fixedBHeight= tmp.offsetHeight;
158         st.fixedBImage= window.undefined;
159       }
160     }
161     st.fixedBX= fixed_length(el, st.fixedBLeft, vpWidth-st.fixedBWidth);
162     st.fixedBY= fixed_length(el, st.fixedBTop, vpHeight-st.fixedBHeight);
163   }
165   // now call scroll() to set the positions from the values just calculated
166   fixed_scroll();
169 // Scrolling. Offset fixed elements relative to viewport scrollness
171 var fixed_lastX, fixed_lastY;
172 var fixed_PATCHDELAY= 300;
173 var fixed_patching= false;
175 // callback function after a scroll, because incorrect scroll position is
176 // often reported first go!
177 function fixed_patch() {
178   fixed_patching= false;
179   var scrollX= fixed_viewport.scrollLeft, scrollY= fixed_viewport.scrollTop;
180   if (scrollX!=fixed_lastX && scrollY!=fixed_lastY) fixed_scroll();
183 function fixed_scroll() {
184   if (!fixed_viewport) return;
185   var i, el, st, viewportX, viewportY;
186   var scrollX= fixed_viewport.scrollLeft, scrollY= fixed_viewport.scrollTop;
187   fixed_lastX= scrollX; fixed_lastY= scrollY;
189   // move non-nested fixed-position elements
190   for (i= fixed_positions.length; i-->0;) {
191     st= fixed_positions[i].style;
192     viewportX= (st.fixedNest) ? 0 : scrollX;
193     viewportY= (st.fixedNest) ? 0 : scrollY;
194     if (st.fixedCLeft!='auto') st.left= (st.fixedCLeft+viewportX)+'px';
195     if (st.fixedCTop!='auto') st.top= (st.fixedCTop+viewportY)+'px';
196     viewportX= (st.fixedCB==null || st.fixedCB==fixed_viewport) ? 0 : viewportX;
197     viewportY= (st.fixedCB==null || st.fixedCB==fixed_viewport) ? 0 : viewportY;
198     st.right= (st.fixedCRight-viewportX+1)+'px'; st.right= (st.fixedCRight-viewportX)+'px';
199     st.bottom= (st.fixedCBottom-viewportY+1)+'px'; st.bottom= (st.fixedCBottom-viewportY)+'px';
200   }
202   // align fixed backgrounds to viewport
203   for (i= fixed_backgrounds.length; i-->0;) {
204     el= fixed_backgrounds[i]; st= el.style;
205     viewportX= scrollX;
206     viewportY= scrollY;
207     while (el.offsetParent) {
208       viewportX-= el.offsetLeft+el.clientLeft;
209       viewportY-= el.offsetTop +el.clientTop;
210       el= el.offsetParent;
211     }
212     st.backgroundPositionX= (st.fixedBX+viewportX)+'px';
213     st.backgroundPositionY= (st.fixedBY+viewportY)+'px';
214   }
216   // call back again in a tic
217   if (!fixed_patching) {
218     fixed_patching= true;
219     window.setTimeout(fixed_patch, fixed_PATCHDELAY);
220   }
223 // Measurement. Load bg-image into an invisible element on the page, when
224 // loaded write the width/height to an element's style for layout use; detect
225 // when font size changes
227 function fixed_measureBack(el) {
228   var measure= document.getElementById('fixed-measure');
229   var img= document.createElement('img');
230   img.setAttribute('src', fixed_parseURL(el.currentStyle.backgroundImage));
231   measure.appendChild(img);
232   el.style.fixedBImage= img;
233   if (img.readyState=='uninitialized')
234     img.attachEvent('onreadystatechange', fixed_measureBackImage_ready);
237 function fixed_measureBackImage_ready() {
238   var img= event.srcElement;
239   if (img && img.readyState!='uninitialized') {
240     img.detachEvent('onreadystatechange', fixed_measureBackImage_ready);
241     fixed_layout();
242   }
245 var fixed_fontsize= 0;
246 function fixed_measureFont() {
247   var fs= document.getElementById('fixed-measure').offsetHeight;
248   if (fixed_fontsize!=fs && fixed_fontsize!=0)
249     fixed_delayout();
250   fixed_fontsize= fs;
251   return '5em';
254 // Utility. General-purpose functions
256 // parse url() to get value inside
258 function fixed_parseURL(v) {
259   v= v.substring(4, v.length-1);
260   if (v.charAt(0)=='"' && v.charAt(v.length-1)=='"' ||
261       v.charAt(0)=="'" && v.charAt(v.length-1)=="'")
262     return v.substring(1, v.length-1);
263   else return v;
266 // parse length or auto or background-position keyword into number and unit
268 var fixed_numberChars= '+-0123456789.';
269 var fixed_ZERO= new Array(0, 'px');
270 var fixed_50PC= new Array(50, '%');
271 var fixed_100PC= new Array(100, '%');
272 var fixed_AUTO= new Array(0, 'auto');
274 function fixed_parseLength(v) {
275   var num, i;
276   if (v=='left'  || v=='top')    return fixed_ZERO;
277   if (v=='right' || v=='bottom') return fixed_100PC;
278   if (v=='center') return fixed_50PC;
279   if (v=='auto')   return fixed_AUTO;
280   i= 0;
281   while (i<v.length && fixed_numberChars.indexOf(v.charAt(i))!=-1)
282     i++;
283   num= parseFloat(v.substring(0, i));
284   if (num==0) return fixed_ZERO;
285   else return new Array(num, v.substring(i));
288 // convert parsed (number, unit) into a number of pixels
290 function fixed_length(el, l, full) {
291   var tmp, x;
292   if (l[1]=='px') return l[0];
293   if (l[1]=='%')  return Math.round(full*l[0]/100);
294   // other units - measure by setting position; this is rather inefficient
295   // but then these units are used for background-position so seldom...
296   tmp= el.currentStyle.left;
297   el.style.left= '0';
298   x= el.offsetLeft;
299   el.style.left= l[0]+l[1];
300   x= el.offsetLeft-x;
301   el.style.left= tmp;
302   return x;
305 // convert stupid IE offsetLeft/Top to page-relative values
307 function fixed_pageLeft(el) {
308   var v= 0;
309   while (el.offsetParent) {
310     v+= el.offsetLeft;
311     el= el.offsetParent;
312   }
313   return v;
315 function fixed_pageTop(el) {
316   var v= 0;
317   while (el.offsetParent) {
318     v+= el.offsetTop;
319     el= el.offsetParent;
320   }
321   return v;
324 // Scanning. Check document every so often until it has finished loading. Do
325 // nothing until <body> arrives, then call main init. Pass any new elements
326 // found on each scan to be bound   
328 var fixed_SCANDELAY= 500;
330 function fixed_scan() {
331   if (!document.body) return;
332   if (!fixed_viewport) fixed_init();
333   var el;
334   for (var i= 0; i<document.all.length; i++) {
335     el= document.all[i];
336     if (!el.fixed_bound) {
337       el.fixed_bound= true;
338       fixed_bind(el);
339   } }
342 var fixed_scanner;
343 function fixed_stop() {
344   window.clearInterval(fixed_scanner);
345   fixed_scan();
348 fixed_scan();
349 fixed_scanner= window.setInterval(fixed_scan, fixed_SCANDELAY);
350 window.attachEvent('onload', fixed_stop);
351 window.attachEvent('onresize', fixed_delayout);
352 window.attachEvent('onscroll', fixed_scroll);
354 @end @*/