update signutare
[CPE_learningsite] / CPE / CPE.App / CPE.App.Web / static / js / detect-zoom.js
1 // detect-zoom is dual-licensed under the WTFPL and MIT license,
2 // at the recipient's choice.
3 // https://github.com/yonran/detect-zoom/
4 var DetectZoom = {
5     mediaQueryBinarySearch: function (
6       property, unit, a, b, maxIter, epsilon) {
7         var matchMedia;
8         var head, style, div
9         if (window.matchMedia) {
10             matchMedia = window.matchMedia;
11         } else {
12             head = document.getElementsByTagName('head')[0];
13             style = document.createElement('style');
14             div = document.createElement('div');
15             div.className = 'mediaQueryBinarySearch';
16             head.appendChild(style);
17             div.style.display = 'none';
18             document.body.appendChild(div);
19             matchMedia = function (query) {
20                 style.sheet.insertRule('@media ' + query +
21                                '{.mediaQueryBinarySearch ' +
22                                '{text-decoration: underline} }', 0);
23                 var matched = getComputedStyle(div, null).textDecoration
24             == 'underline';
25                 style.sheet.deleteRule(0);
26                 return { matches: matched };
27             }
28         }
29         var r = binarySearch(a, b, maxIter);
30         if (div) {
31             head.removeChild(style);
32             document.body.removeChild(div);
33         }
34         return r;
35
36         function binarySearch(a, b, maxIter) {
37             var mid = (a + b) / 2;
38             if (maxIter == 0 || b - a < epsilon) return mid;
39             var query = "(" + property + ":" + mid + unit + ")";
40             if (matchMedia(query).matches) {
41                 return binarySearch(mid, b, maxIter - 1);
42             } else {
43                 return binarySearch(a, mid, maxIter - 1);
44             }
45         }
46     },
47     _zoomIe7: function () {
48         // the trick: body's offsetWidth was in CSS pixels, while
49         // getBoundingClientRect() was in system pixels in IE7.
50         // Thanks to http://help.dottoro.com/ljgshbne.php
51         var rect = document.body.getBoundingClientRect();
52         var z = (rect.right - rect.left) / document.body.offsetWidth;
53         z = Math.round(z * 100) / 100;
54         return { zoom: z, devicePxPerCssPx: z };
55     },
56     _zoomIe8: function () {
57         // IE 8+: no trick needed!
58         // TODO: MSDN says that logicalXDPI and deviceXDPI existed since IE6
59         // (which didn't even have whole-page zoom). Check to see whether
60         // this method would also work in IE7.
61         var zoom = screen.deviceXDPI / screen.logicalXDPI;
62         return {
63             zoom: zoom,
64             devicePxPerCssPx: zoom
65         };
66     },
67     _zoomWebkitMobile: function () {
68         // the trick: window.innerWIdth is in CSS pixels, while
69         // screen.width and screen.height are in system pixels.
70         // And there are no scrollbars to mess up the measurement.
71         var devicePixelRatio = window.devicePixelRatio != null ? window.devicePixelRatio : 1
72       , deviceWidth;
73         if (Math.abs(window.orientation) == 90) {
74             deviceWidth = screen.height;
75         } else {
76             deviceWidth = screen.width;
77         }
78         var z = deviceWidth / window.innerWidth;
79         // return immediately; don't round at the end.
80         return { zoom: z, devicePxPerCssPx: z * devicePixelRatio };
81     },
82     _zoomWebkit: function () {
83         // the trick: an element's clientHeight is in CSS pixels, while you can
84         // set its line-height in system pixels using font-size and
85         // -webkit-text-size-adjust:none.
86         // device-pixel-ratio: http://www.webkit.org/blog/55/high-dpi-web-sites/
87
88         // Previous trick (used before http://trac.webkit.org/changeset/100847):
89         // documentElement.scrollWidth is in CSS pixels, while
90         // document.width was in system pixels. Note that this is the
91         // layout width of the document, which is slightly different from viewport
92         // because document width does not include scrollbars and might be wider
93         // due to big elements.
94
95         var devicePixelRatio = window.devicePixelRatio != null ? window.devicePixelRatio : 1;
96
97         // The container exists so that the div will be laid out in its own flow
98         // while not impacting the layout, viewport size, or display of the
99         // webpage as a whole.
100         var container = document.createElement('div')
101       , div = document.createElement('div');
102
103         // Add !important and relevant CSS rule resets
104         // so that other rules cannot affect the results.
105         var important = function (str) { return str.replace(/;/g, " !important;"); };
106
107         container.setAttribute('style', important('width:0; height:0; overflow:hidden; visibility:hidden; position: absolute;'));
108         div.innerHTML = "1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>0";
109         div.setAttribute('style', important('font: 100px/1em sans-serif; -webkit-text-size-adjust: none; height: auto; width: 1em; padding: 0; overflow: visible;'));
110
111         container.appendChild(div);
112         document.body.appendChild(container);
113         var z = 1000 / div.clientHeight;
114         z = Math.round(z * 100) / 100;
115         var r = {
116             zoom: z,
117             devicePxPerCssPx: devicePixelRatio * z
118         };
119         document.body.removeChild(container);
120         return r;
121     },
122     _zoomFF35: function () {
123         // the trick for FF3.5 ONLY: device-width gives CSS pixels, while
124         // screen.width gave system pixels. Thanks to QuirksMode's widths table,
125         // which called it a bug. http://www.quirksmode.org/m/widths.html
126         var z = screen.width /
127       this.mediaQueryBinarySearch('min-device-width', 'px', 0, 6000, 20, .0001);
128         z = Math.round(z * 100) / 100;
129         return { zoom: z, devicePxPerCssPx: z };
130     },
131     _zoomFF36: function () {
132         // the hack for FF3.6: you can measure scrollbar's width in CSS pixels,
133         // while in system pixels it's 15px (verified in Ubuntu).
134
135         // TODO: verify for every platform that a scrollbar is exactly 15px wide.
136         var container = document.createElement('div')
137       , outerDiv = document.createElement('div');
138         // The container exists so that the div will be laid out in its own flow
139         // while not impacting the layout, viewport size, or display of the
140         // webpage as a whole.
141         container.setAttribute('style', 'width:0; height:0; overflow:hidden;' +
142         'visibility:hidden; position: absolute');
143         outerDiv.style.width = outerDiv.style.height = '500px';  // enough for all the scrollbars
144         var div = outerDiv;
145         for (var i = 0; i < 10; ++i) {
146             var child = document.createElement('div');
147             child.style.overflowY = 'scroll';
148             div.appendChild(child);
149             div = child;
150         }
151         container.appendChild(outerDiv);
152         document.body.appendChild(container);
153         var outerDivWidth = outerDiv.clientWidth;
154         var innerDivWidth = div.clientWidth;
155         var scrollbarWidthCss = (outerDivWidth - innerDivWidth) / 10;
156         document.body.removeChild(container);
157         var scrollbarWidthDevice = 15;  // Mac and Linux: scrollbars are 15px wide
158         if (-1 != navigator.platform.indexOf('Win')) {
159             scrollbarWidthDevice = 17;
160         }
161         var z = scrollbarWidthDevice / scrollbarWidthCss;
162         z = Math.round(z * 100) / 100;
163         return { zoom: z, devicePxPerCssPx: z };
164     },
165     _zoomFF4: function () {
166         // no real trick; device-pixel-ratio is the ratio of device dpi / css dpi.
167         // (Note that this is a different interpretation than Webkit's device
168         // pixel ratio, which is the ratio device dpi / system dpi).
169         // TODO: is mozmm vs. mm promising?
170         var z = this.mediaQueryBinarySearch(
171             'min--moz-device-pixel-ratio',
172             '', 0, 10, 20, .0001);
173         z = Math.round(z * 100) / 100;
174         return { zoom: z, devicePxPerCssPx: z };
175     },
176     _zoomOperaOlder: function () {
177         // 10.00 (or before) to 11.01:
178         // the trick: a div with position:fixed;width:100%'s offsetWidth is the
179         // viewport width in CSS pixels, while window.innerWidth was in system
180         // pixels. Thanks to:
181         // http://virtuelvis.com/2005/05/how-to-detect-zoom-level-in-opera/
182         // TODO: fix bug: when there is a scrollbar, fixed div does NOT
183         // include the scrollbar, while window.outerWidth DOES. This causes the
184         // calculation to be off by a few percent.
185         var fixedDiv = document.createElement('div');
186         fixedDiv.style.position = 'fixed';
187         fixedDiv.style.width = '100%';
188         fixedDiv.style.height = '100%';
189         fixedDiv.style.top = fixedDiv.style.left = '0';
190         fixedDiv.style.visibility = 'hidden';
191         document.body.appendChild(fixedDiv);
192         var z = window.innerWidth / fixedDiv.offsetWidth;
193         document.body.removeChild(fixedDiv);
194         return { zoom: z, devicePxPerCssPx: z };
195     },
196     _zoomOpera11: function () {
197         // works starting Opera 11.11
198         // the trick: outerWidth is the viewport width including scrollbars in
199         // system px, while innerWidth is the viewport width including scrollbars
200         // in CSS px; 
201         var z = window.outerWidth / window.innerWidth;
202         z = Math.round(z * 100) / 100;
203         return { zoom: z, devicePxPerCssPx: z };
204     },
205     ratios: function () {
206         var r;
207         if (!isNaN(screen.logicalXDPI) && !isNaN(screen.systemXDPI)) {
208             return this._zoomIe8();
209         } else if ('ontouchstart' in window && document.body.style.webkitTextSizeAdjust != null) {
210             return this._zoomWebkitMobile();
211         } else if (document.body.style.webkitTextSizeAdjust != null) {  // webkit
212             return this._zoomWebkit();
213         } else if (-1 != navigator.userAgent.indexOf('Firefox/3.5')) {
214             return this._zoomFF35();
215         } else if (-1 != navigator.userAgent.indexOf('Firefox/3.6')) {
216             return this._zoomFF36();
217         } else if (-1 != navigator.appVersion.indexOf("MSIE 7.")) {
218             return this._zoomIe7();
219         } else if (-1 != navigator.userAgent.indexOf('Opera')) {
220             var versionIdx = navigator.userAgent.indexOf('Version/');
221             if (11.01 < parseFloat(navigator.userAgent.substr(versionIdx + 8)))
222                 return this._zoomOpera11();
223             else
224                 return this._zoomOperaOlder();
225         } else if (0.001 < (r = this._zoomFF4()).zoom) {
226             return r;
227         } else {
228             return { zoom: 1, devicePxPerCssPx: 1 }
229         }
230     },
231     zoom: function () {
232         return this.ratios().zoom;
233     },
234     device: function () {
235         return this.ratios().devicePxPerCssPx;
236     }
237 };