Mercurial > hg > Papers > 2011 > nobu-prosym
comparison presen/ui/graphic_support/fixed.js @ 54:a967ee5a0b0f
add presen
author | Nobuyasu Oshiro <dimolto@cr.ie.u-ryukyu.ac.jp> |
---|---|
date | Sat, 24 Dec 2011 18:53:34 +0900 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
53:de1f203636d1 | 54:a967ee5a0b0f |
---|---|
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 | |
4 | |
5 /*@cc_on | |
6 @if (@_win32 && @_jscript_version>4) | |
7 | |
8 var fixed_positions= new Array(); | |
9 var fixed_backgrounds= new Array(); | |
10 var fixed_viewport; | |
11 | |
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 | |
15 | |
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 } | |
28 | |
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 | |
31 | |
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; | |
38 | |
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 } | |
66 | |
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 } | |
82 | |
83 // Layout. On every window or font size change, recalculate positioning | |
84 | |
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 } | |
92 | |
93 var fixed_ARBITRARY= 200; | |
94 | |
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; | |
101 | |
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 } | |
148 | |
149 | |
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 } | |
164 | |
165 // now call scroll() to set the positions from the values just calculated | |
166 fixed_scroll(); | |
167 } | |
168 | |
169 // Scrolling. Offset fixed elements relative to viewport scrollness | |
170 | |
171 var fixed_lastX, fixed_lastY; | |
172 var fixed_PATCHDELAY= 300; | |
173 var fixed_patching= false; | |
174 | |
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(); | |
181 } | |
182 | |
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; | |
188 | |
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 } | |
201 | |
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 } | |
215 | |
216 // call back again in a tic | |
217 if (!fixed_patching) { | |
218 fixed_patching= true; | |
219 window.setTimeout(fixed_patch, fixed_PATCHDELAY); | |
220 } | |
221 } | |
222 | |
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 | |
226 | |
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); | |
235 } | |
236 | |
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 } | |
243 } | |
244 | |
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'; | |
252 } | |
253 | |
254 // Utility. General-purpose functions | |
255 | |
256 // parse url() to get value inside | |
257 | |
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; | |
264 } | |
265 | |
266 // parse length or auto or background-position keyword into number and unit | |
267 | |
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'); | |
273 | |
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)); | |
286 } | |
287 | |
288 // convert parsed (number, unit) into a number of pixels | |
289 | |
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; | |
303 } | |
304 | |
305 // convert stupid IE offsetLeft/Top to page-relative values | |
306 | |
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; | |
314 } | |
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; | |
322 } | |
323 | |
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 | |
327 | |
328 var fixed_SCANDELAY= 500; | |
329 | |
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 } } | |
340 } | |
341 | |
342 var fixed_scanner; | |
343 function fixed_stop() { | |
344 window.clearInterval(fixed_scanner); | |
345 fixed_scan(); | |
346 } | |
347 | |
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); | |
353 | |
354 @end @*/ |