ajaxlibs 0.1.11 → 0.1.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,348 @@
1
+ // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ /**
6
+ * @fileoverview CFInstall.js provides a set of utilities for managing
7
+ * the Chrome Frame detection and installation process.
8
+ * @author slightlyoff@google.com (Alex Russell)
9
+ */
10
+
11
+ (function(scope) {
12
+ // bail if we'd be over-writing an existing CFInstall object
13
+ if (scope['CFInstall']) {
14
+ return;
15
+ }
16
+
17
+ /**
18
+ * returns an item based on DOM ID. Optionally a document may be provided to
19
+ * specify the scope to search in. If a node is passed, it's returned as-is.
20
+ * @param {string|Node} id The ID of the node to be located or a node
21
+ * @param {Node} doc Optional A document to search for id.
22
+ * @return {Node}
23
+ */
24
+ var byId = function(id, doc) {
25
+ return (typeof id == 'string') ? (doc || document).getElementById(id) : id;
26
+ };
27
+
28
+ /////////////////////////////////////////////////////////////////////////////
29
+ // Plugin Detection
30
+ /////////////////////////////////////////////////////////////////////////////
31
+
32
+ /**
33
+ * Checks to find out if ChromeFrame is available as a plugin
34
+ * @return {Boolean}
35
+ */
36
+ var isAvailable = function() {
37
+ // For testing purposes.
38
+ if (scope.CFInstall._force) {
39
+ return scope.CFInstall._forceValue;
40
+ }
41
+
42
+ // Look for CF in the User Agent before trying more expensive checks
43
+ var ua = navigator.userAgent.toLowerCase();
44
+ if (ua.indexOf("chromeframe") >= 0) {
45
+ return true;
46
+ }
47
+
48
+ if (typeof window['ActiveXObject'] != 'undefined') {
49
+ try {
50
+ var obj = new ActiveXObject('ChromeTab.ChromeFrame');
51
+ if (obj) {
52
+ return true;
53
+ }
54
+ } catch(e) {
55
+ // squelch
56
+ }
57
+ }
58
+ return false;
59
+ };
60
+
61
+ /**
62
+ * Creates a style sheet in the document containing the passed rules.
63
+ */
64
+ var injectStyleSheet = function(rules) {
65
+ try {
66
+ var ss = document.createElement('style');
67
+ ss.setAttribute('type', 'text/css');
68
+ if (ss.styleSheet) {
69
+ ss.styleSheet.cssText = rules;
70
+ } else {
71
+ ss.appendChild(document.createTextNode(rules));
72
+ }
73
+ var h = document.getElementsByTagName('head')[0];
74
+ var firstChild = h.firstChild;
75
+ h.insertBefore(ss, firstChild);
76
+ } catch (e) {
77
+ // squelch
78
+ }
79
+ };
80
+
81
+ /** @type {boolean} */
82
+ var cfStyleTagInjected = false;
83
+ /** @type {boolean} */
84
+ var cfHiddenInjected = false;
85
+
86
+ /**
87
+ * Injects style rules into the document to handle formatting of Chrome Frame
88
+ * prompt. Multiple calls have no effect.
89
+ */
90
+ var injectCFStyleTag = function() {
91
+ if (cfStyleTagInjected) {
92
+ // Once and only once
93
+ return;
94
+ }
95
+ var rules = '.chromeFrameInstallDefaultStyle {' +
96
+ 'width: 800px;' +
97
+ 'height: 600px;' +
98
+ 'position: absolute;' +
99
+ 'left: 50%;' +
100
+ 'top: 50%;' +
101
+ 'margin-left: -400px;' +
102
+ 'margin-top: -300px;' +
103
+ '}' +
104
+ '.chromeFrameOverlayContent {' +
105
+ 'position: absolute;' +
106
+ 'margin-left: -400px;' +
107
+ 'margin-top: -300px;' +
108
+ 'left: 50%;' +
109
+ 'top: 50%;' +
110
+ 'border: 1px solid #93B4D9;' +
111
+ 'background-color: white;' +
112
+ '}' +
113
+ '.chromeFrameOverlayContent iframe {' +
114
+ 'width: 800px;' +
115
+ 'height: 600px;' +
116
+ 'border: none;' +
117
+ '}' +
118
+ '.chromeFrameOverlayCloseBar {' +
119
+ 'height: 1em;' +
120
+ 'text-align: right;' +
121
+ 'background-color: #CADEF4;' +
122
+ '}' +
123
+ '.chromeFrameOverlayUnderlay {' +
124
+ 'position: absolute;' +
125
+ 'width: 100%;' +
126
+ 'height: 100%;' +
127
+ 'background-color: white;' +
128
+ 'opacity: 0.5;' +
129
+ '-moz-opacity: 0.5;' +
130
+ '-webkit-opacity: 0.5;' +
131
+ '-ms-filter: ' +
132
+ '"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";' +
133
+ 'filter: alpha(opacity=50);' +
134
+ '}';
135
+ injectStyleSheet(rules);
136
+ cfStyleTagInjected = true;
137
+ };
138
+
139
+ /**
140
+ * Injects style rules to hide the overlay version of the GCF prompt.
141
+ * Multiple calls have no effect.
142
+ */
143
+ var closeOverlay = function() {
144
+ // IE has a limit to the # of <style> tags allowed, so we avoid
145
+ // tempting the fates.
146
+ if (cfHiddenInjected) {
147
+ return;
148
+ }
149
+ var rules = '.chromeFrameOverlayContent { display: none; }' +
150
+ '.chromeFrameOverlayUnderlay { display: none; }';
151
+ injectStyleSheet(rules);
152
+ // Hide the dialog for a year (or until cookies are deleted).
153
+ var age = 365 * 24 * 60 * 60 * 1000;
154
+ document.cookie = "disableGCFCheck=1;path=/;max-age="+age;
155
+ cfHiddenInjected = true;
156
+ };
157
+
158
+ /**
159
+ * Plucks properties from the passed arguments and sets them on the passed
160
+ * DOM node
161
+ * @param {Node} node The node to set properties on
162
+ * @param {Object} args A map of user-specified properties to set
163
+ */
164
+ var setProperties = function(node, args) {
165
+
166
+ var srcNode = byId(args['node']);
167
+
168
+ node.id = args['id'] || (srcNode ? srcNode['id'] || getUid(srcNode) : '');
169
+
170
+ // TODO(slightlyoff): Opera compat? need to test there
171
+ var cssText = args['cssText'] || '';
172
+ node.style.cssText = ' ' + cssText;
173
+
174
+ var classText = args['className'] || '';
175
+ node.className = classText;
176
+
177
+ // default if the browser doesn't so we don't show sad-tab
178
+ var src = args['src'] || 'about:blank';
179
+
180
+ node.src = src;
181
+
182
+ if (srcNode) {
183
+ srcNode.parentNode.replaceChild(node, srcNode);
184
+ }
185
+ };
186
+
187
+ /**
188
+ * Creates an iframe.
189
+ * @param {Object} args A bag of configuration properties, including values
190
+ * like 'node', 'cssText', 'className', 'id', 'src', etc.
191
+ * @return {Node}
192
+ */
193
+ var makeIframe = function(args) {
194
+ var el = document.createElement('iframe');
195
+ el.setAttribute('frameborder', '0');
196
+ el.setAttribute('border', '0');
197
+ setProperties(el, args);
198
+ return el;
199
+ };
200
+
201
+ /**
202
+ * Adds an unadorned iframe into the page, taking arguments to customize it.
203
+ * @param {Object} args A map of user-specified properties to set
204
+ */
205
+ var makeInlinePrompt = function(args) {
206
+ args.className = 'chromeFrameInstallDefaultStyle ' +
207
+ (args.className || '');
208
+ var ifr = makeIframe(args);
209
+ // TODO(slightlyoff): handle placement more elegantly!
210
+ if (!ifr.parentNode) {
211
+ var firstChild = document.body.firstChild;
212
+ document.body.insertBefore(ifr, firstChild);
213
+ }
214
+ };
215
+
216
+ /**
217
+ * Adds a styled, closable iframe into the page with a background that
218
+ * emulates a modal dialog.
219
+ * @param {Object} args A map of user-specified properties to set
220
+ */
221
+ var makeOverlayPrompt = function(args) {
222
+ if (byId('chromeFrameOverlayContent')) {
223
+ return; // Was previously created. Bail.
224
+ }
225
+
226
+ var n = document.createElement('span');
227
+ n.innerHTML = '<div class="chromeFrameOverlayUnderlay"></div>' +
228
+ '<table class="chromeFrameOverlayContent"' +
229
+ 'id="chromeFrameOverlayContent"' +
230
+ 'cellpadding="0" cellspacing="0">' +
231
+ '<tr class="chromeFrameOverlayCloseBar">' +
232
+ '<td>' +
233
+ // TODO(slightlyoff): i18n
234
+ '<button id="chromeFrameCloseButton">close</button>' +
235
+ '</td>' +
236
+ '</tr>' +
237
+ '<tr>' +
238
+ '<td id="chromeFrameIframeHolder"></td>' +
239
+ '</tr>' +
240
+ '</table>';
241
+
242
+ document.body.appendChild(n);
243
+ var ifr = makeIframe(args);
244
+ byId('chromeFrameIframeHolder').appendChild(ifr);
245
+ byId('chromeFrameCloseButton').onclick = closeOverlay;
246
+ };
247
+
248
+ var CFInstall = {};
249
+
250
+ /**
251
+ * Checks to see if Chrome Frame is available, if not, prompts the user to
252
+ * install. Once installation is begun, a background timer starts,
253
+ * checkinging for a successful install every 2 seconds. Upon detection of
254
+ * successful installation, the current page is reloaded, or if a
255
+ * 'destination' parameter is passed, the page navigates there instead.
256
+ * @param {Object} args A bag of configuration properties. Respected
257
+ * properties are: 'mode', 'url', 'destination', 'node', 'onmissing',
258
+ * 'preventPrompt', 'oninstall', 'preventInstallDetection', 'cssText', and
259
+ * 'className'.
260
+ * @public
261
+ */
262
+ CFInstall.check = function(args) {
263
+ args = args || {};
264
+
265
+ // We currently only support CF in IE
266
+ // TODO(slightlyoff): Update this should we support other browsers!
267
+ var ua = navigator.userAgent;
268
+ var ieRe = /MSIE \S+; Windows NT/;
269
+ var bail = false;
270
+ if (ieRe.test(ua)) {
271
+ // We also only support Win2003/XPSP2 or better. See:
272
+ // http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx
273
+ if (parseFloat(ua.split(ieRe)[1]) < 6 &&
274
+ ua.indexOf('SV1') >= 0) {
275
+ bail = true;
276
+ }
277
+ } else {
278
+ bail = true;
279
+ }
280
+ if (bail) {
281
+ return;
282
+ }
283
+
284
+ // Inject the default styles
285
+ injectCFStyleTag();
286
+
287
+ if (document.cookie.indexOf("disableGCFCheck=1") >=0) {
288
+ // If we're supposed to hide the overlay prompt, add the rules to do it.
289
+ closeOverlay();
290
+ }
291
+
292
+ // When loaded in an alternate protocol (e.g., "file:"), still call out to
293
+ // the right location.
294
+ var currentProtocol = document.location.protocol;
295
+ var protocol = (currentProtocol == 'https:') ? 'https:' : 'http:';
296
+ // TODO(slightlyoff): Update this URL when a mini-installer page is
297
+ // available.
298
+ var installUrl = protocol + '//www.google.com/chromeframe';
299
+ if (!isAvailable()) {
300
+ if (args.onmissing) {
301
+ args.onmissing();
302
+ }
303
+
304
+ args.src = args.url || installUrl;
305
+ var mode = args.mode || 'inline';
306
+ var preventPrompt = args.preventPrompt || false;
307
+
308
+ if (!preventPrompt) {
309
+ if (mode == 'inline') {
310
+ makeInlinePrompt(args);
311
+ } else if (mode == 'overlay') {
312
+ makeOverlayPrompt(args);
313
+ } else {
314
+ window.open(args.src);
315
+ }
316
+ }
317
+
318
+ if (args.preventInstallDetection) {
319
+ return;
320
+ }
321
+
322
+ // Begin polling for install success.
323
+ var installTimer = setInterval(function() {
324
+ // every 2 seconds, look to see if CF is available, if so, proceed on
325
+ // to our destination
326
+ if (isAvailable()) {
327
+ if (args.oninstall) {
328
+ args.oninstall();
329
+ }
330
+
331
+ clearInterval(installTimer);
332
+ // TODO(slightlyoff): add a way to prevent navigation or make it
333
+ // contingent on oninstall?
334
+ window.location = args.destination || window.location;
335
+ }
336
+ }, 2000);
337
+ }
338
+ };
339
+
340
+ CFInstall._force = false;
341
+ CFInstall._forceValue = false;
342
+ CFInstall.isAvailable = isAvailable;
343
+
344
+ // expose CFInstall to the external scope. We've already checked to make
345
+ // sure we're not going to blow existing objects away.
346
+ scope.CFInstall = CFInstall;
347
+
348
+ })(this['ChromeFrameInstallScope'] || this);
@@ -0,0 +1,11 @@
1
+ // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ (function(f){if(!f.CFInstall){var g=function(a,b){return typeof a=="string"?(b||document).getElementById(a):a},h=function(){if(f.CFInstall._force)return f.CFInstall._forceValue;var a=navigator.userAgent.toLowerCase();if(a.indexOf("chromeframe")>=0)return true;if(typeof window.ActiveXObject!="undefined")try{var b=new ActiveXObject("ChromeTab.ChromeFrame");if(b)return true}catch(c){}return false},j=function(a){try{var b=document.createElement("style");b.setAttribute("type","text/css");if(b.styleSheet)b.styleSheet.cssText=
6
+ a;else b.appendChild(document.createTextNode(a));var c=document.getElementsByTagName("head")[0],d=c.firstChild;c.insertBefore(b,d)}catch(i){}},k=false,l=false,o=function(){if(!k){var a='.chromeFrameInstallDefaultStyle {width: 800px;height: 600px;position: absolute;left: 50%;top: 50%;margin-left: -400px;margin-top: -300px;}.chromeFrameOverlayContent {position: absolute;margin-left: -400px;margin-top: -300px;left: 50%;top: 50%;border: 1px solid #93B4D9;background-color: white;}.chromeFrameOverlayContent iframe {width: 800px;height: 600px;border: none;}.chromeFrameOverlayCloseBar {height: 1em;text-align: right;background-color: #CADEF4;}.chromeFrameOverlayUnderlay {position: absolute;width: 100%;height: 100%;background-color: white;opacity: 0.5;-moz-opacity: 0.5;-webkit-opacity: 0.5;-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";filter: alpha(opacity=50);}';
7
+ j(a);k=true}},m=function(){if(!l){var a=".chromeFrameOverlayContent { display: none; }.chromeFrameOverlayUnderlay { display: none; }";j(a);a=31536000000;document.cookie="disableGCFCheck=1;path=/;max-age="+a;l=true}},p=function(a,b){var c=g(b.node);a.id=b.id||(c?c.id||getUid(c):"");var d=b.cssText||"";a.style.cssText=" "+d;d=b.className||"";a.className=d;b=b.src||"about:blank";a.src=b;c&&c.parentNode.replaceChild(a,c)},n=function(a){var b=document.createElement("iframe");b.setAttribute("frameborder",
8
+ "0");b.setAttribute("border","0");p(b,a);return b},q=function(a){a.className="chromeFrameInstallDefaultStyle "+(a.className||"");a=n(a);if(!a.parentNode){var b=document.body.firstChild;document.body.insertBefore(a,b)}},r=function(a){if(!g("chromeFrameOverlayContent")){var b=document.createElement("span");b.innerHTML='<div class="chromeFrameOverlayUnderlay"></div><table class="chromeFrameOverlayContent"id="chromeFrameOverlayContent"cellpadding="0" cellspacing="0"><tr class="chromeFrameOverlayCloseBar"><td><button id="chromeFrameCloseButton">close</button></td></tr><tr><td id="chromeFrameIframeHolder"></td></tr></table>';
9
+ document.body.appendChild(b);a=n(a);g("chromeFrameIframeHolder").appendChild(a);g("chromeFrameCloseButton").onclick=m}},e={};e.check=function(a){a=a||{};var b=navigator.userAgent,c=/MSIE \S+; Windows NT/,d=false;if(c.test(b)){if(parseFloat(b.split(c)[1])<6&&b.indexOf("SV1")>=0)d=true}else d=true;if(!d){o();document.cookie.indexOf("disableGCFCheck=1")>=0&&m();b=document.location.protocol;b=b=="https:"?"https:":"http:";b=b+"//www.google.com/chromeframe";if(!h()){a.onmissing&&a.onmissing();a.src=a.url||
10
+ b;b=a.mode||"inline";c=a.preventPrompt||false;if(!c)if(b=="inline")q(a);else b=="overlay"?r(a):window.open(a.src);if(!a.preventInstallDetection)var i=setInterval(function(){if(h()){a.oninstall&&a.oninstall();clearInterval(i);window.location=a.destination||window.location}},2000)}}};e._force=false;e._forceValue=false;e.isAvailable=h;f.CFInstall=e}})(this.ChromeFrameInstallScope||this);
11
+
@@ -0,0 +1,356 @@
1
+ // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2
+ // Use of this source code is governed by a BSD-style license that can be
3
+ // found in the LICENSE file.
4
+
5
+ /**
6
+ * @fileoverview CFInstall.js provides a set of utilities for managing
7
+ * the Chrome Frame detection and installation process.
8
+ * @author slightlyoff@google.com (Alex Russell)
9
+ */
10
+
11
+ (function(scope) {
12
+ // bail if we'd be over-writing an existing CFInstall object
13
+ if (scope['CFInstall']) {
14
+ return;
15
+ }
16
+
17
+ /**
18
+ * returns an item based on DOM ID. Optionally a document may be provided to
19
+ * specify the scope to search in. If a node is passed, it's returned as-is.
20
+ * @param {string|Node} id The ID of the node to be located or a node
21
+ * @param {Node} doc Optional A document to search for id.
22
+ * @return {Node}
23
+ */
24
+ var byId = function(id, doc) {
25
+ return (typeof id == 'string') ? (doc || document).getElementById(id) : id;
26
+ };
27
+
28
+ /////////////////////////////////////////////////////////////////////////////
29
+ // Plugin Detection
30
+ /////////////////////////////////////////////////////////////////////////////
31
+
32
+ /**
33
+ * Checks to find out if ChromeFrame is available as a plugin
34
+ * @return {Boolean}
35
+ */
36
+ var isAvailable = function() {
37
+ // For testing purposes.
38
+ if (scope.CFInstall._force) {
39
+ return scope.CFInstall._forceValue;
40
+ }
41
+
42
+ // Look for CF in the User Agent before trying more expensive checks
43
+ var ua = navigator.userAgent.toLowerCase();
44
+ if (ua.indexOf("chromeframe") >= 0) {
45
+ return true;
46
+ }
47
+
48
+ if (typeof window['ActiveXObject'] != 'undefined') {
49
+ try {
50
+ var obj = new ActiveXObject('ChromeTab.ChromeFrame');
51
+ if (obj) {
52
+ return true;
53
+ }
54
+ } catch(e) {
55
+ // squelch
56
+ }
57
+ }
58
+ return false;
59
+ };
60
+
61
+ /**
62
+ * Creates a style sheet in the document containing the passed rules.
63
+ */
64
+ var injectStyleSheet = function(rules) {
65
+ try {
66
+ var ss = document.createElement('style');
67
+ ss.setAttribute('type', 'text/css');
68
+ if (ss.styleSheet) {
69
+ ss.styleSheet.cssText = rules;
70
+ } else {
71
+ ss.appendChild(document.createTextNode(rules));
72
+ }
73
+ var h = document.getElementsByTagName('head')[0];
74
+ var firstChild = h.firstChild;
75
+ h.insertBefore(ss, firstChild);
76
+ } catch (e) {
77
+ // squelch
78
+ }
79
+ };
80
+
81
+ /** @type {boolean} */
82
+ var cfStyleTagInjected = false;
83
+ /** @type {boolean} */
84
+ var cfHiddenInjected = false;
85
+
86
+ /**
87
+ * Injects style rules into the document to handle formatting of Chrome Frame
88
+ * prompt. Multiple calls have no effect.
89
+ */
90
+ var injectCFStyleTag = function() {
91
+ if (cfStyleTagInjected) {
92
+ // Once and only once
93
+ return;
94
+ }
95
+ var rules = '.chromeFrameInstallDefaultStyle {' +
96
+ 'width: 800px;' +
97
+ 'height: 600px;' +
98
+ 'position: absolute;' +
99
+ 'left: 50%;' +
100
+ 'top: 50%;' +
101
+ 'margin-left: -400px;' +
102
+ 'margin-top: -300px;' +
103
+ '}' +
104
+ '.chromeFrameOverlayContent {' +
105
+ 'position: absolute;' +
106
+ 'margin-left: -400px;' +
107
+ 'margin-top: -300px;' +
108
+ 'left: 50%;' +
109
+ 'top: 50%;' +
110
+ 'border: 1px solid #93B4D9;' +
111
+ 'background-color: white;' +
112
+ 'z-index: 2001;' +
113
+ '}' +
114
+ '.chromeFrameOverlayContent iframe {' +
115
+ 'width: 800px;' +
116
+ 'height: 600px;' +
117
+ 'border: none;' +
118
+ '}' +
119
+ '.chromeFrameOverlayCloseBar {' +
120
+ 'height: 1em;' +
121
+ 'text-align: right;' +
122
+ 'background-color: #CADEF4;' +
123
+ '}' +
124
+ '.chromeFrameOverlayUnderlay {' +
125
+ 'position: absolute;' +
126
+ 'width: 100%;' +
127
+ 'height: 100%;' +
128
+ 'background-color: white;' +
129
+ 'opacity: 0.5;' +
130
+ '-moz-opacity: 0.5;' +
131
+ '-webkit-opacity: 0.5;' +
132
+ '-ms-filter: ' +
133
+ '"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";' +
134
+ 'filter: alpha(opacity=50);' +
135
+ 'z-index: 2000;' +
136
+ '}';
137
+ injectStyleSheet(rules);
138
+ cfStyleTagInjected = true;
139
+ };
140
+
141
+ /**
142
+ * Injects style rules to hide the overlay version of the GCF prompt.
143
+ * Multiple calls have no effect.
144
+ */
145
+ var closeOverlay = function() {
146
+ // IE has a limit to the # of <style> tags allowed, so we avoid
147
+ // tempting the fates.
148
+ if (cfHiddenInjected) {
149
+ return;
150
+ }
151
+ var rules = '.chromeFrameOverlayContent { display: none; }' +
152
+ '.chromeFrameOverlayUnderlay { display: none; }';
153
+ injectStyleSheet(rules);
154
+ // Hide the dialog for a year (or until cookies are deleted).
155
+ var age = 365 * 24 * 60 * 60 * 1000;
156
+ document.cookie = "disableGCFCheck=1;path=/;max-age="+age;
157
+ cfHiddenInjected = true;
158
+ };
159
+
160
+ /**
161
+ * Plucks properties from the passed arguments and sets them on the passed
162
+ * DOM node
163
+ * @param {Node} node The node to set properties on
164
+ * @param {Object} args A map of user-specified properties to set
165
+ */
166
+ var setProperties = function(node, args) {
167
+
168
+ var srcNode = byId(args['node']);
169
+
170
+ node.id = args['id'] || (srcNode ? srcNode['id'] || getUid(srcNode) : '');
171
+
172
+ // TODO(slightlyoff): Opera compat? need to test there
173
+ var cssText = args['cssText'] || '';
174
+ node.style.cssText = ' ' + cssText;
175
+
176
+ var classText = args['className'] || '';
177
+ node.className = classText;
178
+
179
+ // default if the browser doesn't so we don't show sad-tab
180
+ var src = args['src'] || 'about:blank';
181
+
182
+ node.src = src;
183
+
184
+ if (srcNode) {
185
+ srcNode.parentNode.replaceChild(node, srcNode);
186
+ }
187
+ };
188
+
189
+ /**
190
+ * Creates an iframe.
191
+ * @param {Object} args A bag of configuration properties, including values
192
+ * like 'node', 'cssText', 'className', 'id', 'src', etc.
193
+ * @return {Node}
194
+ */
195
+ var makeIframe = function(args) {
196
+ var el = document.createElement('iframe');
197
+ el.setAttribute('frameborder', '0');
198
+ el.setAttribute('border', '0');
199
+ setProperties(el, args);
200
+ return el;
201
+ };
202
+
203
+ /**
204
+ * Adds an unadorned iframe into the page, taking arguments to customize it.
205
+ * @param {Object} args A map of user-specified properties to set
206
+ */
207
+ var makeInlinePrompt = function(args) {
208
+ args.className = 'chromeFrameInstallDefaultStyle ' +
209
+ (args.className || '');
210
+ var ifr = makeIframe(args);
211
+ // TODO(slightlyoff): handle placement more elegantly!
212
+ if (!ifr.parentNode) {
213
+ var firstChild = document.body.firstChild;
214
+ document.body.insertBefore(ifr, firstChild);
215
+ }
216
+ };
217
+
218
+ /**
219
+ * Adds a styled, closable iframe into the page with a background that
220
+ * emulates a modal dialog.
221
+ * @param {Object} args A map of user-specified properties to set
222
+ */
223
+ var makeOverlayPrompt = function(args) {
224
+ if (byId('chromeFrameOverlayContent')) {
225
+ return; // Was previously created. Bail.
226
+ }
227
+
228
+ var n = document.createElement('span');
229
+ n.innerHTML = '<div class="chromeFrameOverlayUnderlay"></div>' +
230
+ '<table class="chromeFrameOverlayContent"' +
231
+ 'id="chromeFrameOverlayContent"' +
232
+ 'cellpadding="0" cellspacing="0">' +
233
+ '<tr class="chromeFrameOverlayCloseBar">' +
234
+ '<td>' +
235
+ // TODO(slightlyoff): i18n
236
+ '<button id="chromeFrameCloseButton">close</button>' +
237
+ '</td>' +
238
+ '</tr>' +
239
+ '<tr>' +
240
+ '<td id="chromeFrameIframeHolder"></td>' +
241
+ '</tr>' +
242
+ '</table>';
243
+
244
+ var b = document.body;
245
+ // Insert underlay nodes into the document in the right order.
246
+ while (n.firstChild) {
247
+ b.insertBefore(n.lastChild, b.firstChild);
248
+ }
249
+ var ifr = makeIframe(args);
250
+ byId('chromeFrameIframeHolder').appendChild(ifr);
251
+ byId('chromeFrameCloseButton').onclick = closeOverlay;
252
+ };
253
+
254
+ var CFInstall = {};
255
+
256
+ /**
257
+ * Checks to see if Chrome Frame is available, if not, prompts the user to
258
+ * install. Once installation is begun, a background timer starts,
259
+ * checkinging for a successful install every 2 seconds. Upon detection of
260
+ * successful installation, the current page is reloaded, or if a
261
+ * 'destination' parameter is passed, the page navigates there instead.
262
+ * @param {Object} args A bag of configuration properties. Respected
263
+ * properties are: 'mode', 'url', 'destination', 'node', 'onmissing',
264
+ * 'preventPrompt', 'oninstall', 'preventInstallDetection', 'cssText', and
265
+ * 'className'.
266
+ * @public
267
+ */
268
+ CFInstall.check = function(args) {
269
+ args = args || {};
270
+
271
+ // We currently only support CF in IE
272
+ // TODO(slightlyoff): Update this should we support other browsers!
273
+ var ua = navigator.userAgent;
274
+ var ieRe = /MSIE (\S+); Windows NT/;
275
+ var bail = false;
276
+ if (ieRe.test(ua)) {
277
+ // We also only support Win2003/XPSP2 or better. See:
278
+ // http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx
279
+ if (parseFloat(ieRe.exec(ua)[1]) < 6 &&
280
+ // 'SV1' indicates SP2, only bail if not SP2 or Win2K3
281
+ ua.indexOf('SV1') < 0) {
282
+ bail = true;
283
+ }
284
+ } else {
285
+ // Not IE
286
+ bail = true;
287
+ }
288
+ if (bail) {
289
+ return;
290
+ }
291
+
292
+ // Inject the default styles
293
+ injectCFStyleTag();
294
+
295
+ if (document.cookie.indexOf("disableGCFCheck=1") >=0) {
296
+ // If we're supposed to hide the overlay prompt, add the rules to do it.
297
+ closeOverlay();
298
+ }
299
+
300
+ // When loaded in an alternate protocol (e.g., "file:"), still call out to
301
+ // the right location.
302
+ var currentProtocol = document.location.protocol;
303
+ var protocol = (currentProtocol == 'https:') ? 'https:' : 'http:';
304
+ // TODO(slightlyoff): Update this URL when a mini-installer page is
305
+ // available.
306
+ var installUrl = protocol + '//www.google.com/chromeframe';
307
+ if (!isAvailable()) {
308
+ if (args.onmissing) {
309
+ args.onmissing();
310
+ }
311
+
312
+ args.src = args.url || installUrl;
313
+ var mode = args.mode || 'inline';
314
+ var preventPrompt = args.preventPrompt || false;
315
+
316
+ if (!preventPrompt) {
317
+ if (mode == 'inline') {
318
+ makeInlinePrompt(args);
319
+ } else if (mode == 'overlay') {
320
+ makeOverlayPrompt(args);
321
+ } else {
322
+ window.open(args.src);
323
+ }
324
+ }
325
+
326
+ if (args.preventInstallDetection) {
327
+ return;
328
+ }
329
+
330
+ // Begin polling for install success.
331
+ var installTimer = setInterval(function() {
332
+ // every 2 seconds, look to see if CF is available, if so, proceed on
333
+ // to our destination
334
+ if (isAvailable()) {
335
+ if (args.oninstall) {
336
+ args.oninstall();
337
+ }
338
+
339
+ clearInterval(installTimer);
340
+ // TODO(slightlyoff): add a way to prevent navigation or make it
341
+ // contingent on oninstall?
342
+ window.location = args.destination || window.location;
343
+ }
344
+ }, 2000);
345
+ }
346
+ };
347
+
348
+ CFInstall._force = false;
349
+ CFInstall._forceValue = false;
350
+ CFInstall.isAvailable = isAvailable;
351
+
352
+ // expose CFInstall to the external scope. We've already checked to make
353
+ // sure we're not going to blow existing objects away.
354
+ scope.CFInstall = CFInstall;
355
+
356
+ })(this['ChromeFrameInstallScope'] || this);