OLD | NEW |
(Empty) | |
| 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 var cachedAvailable; |
| 33 |
| 34 /** |
| 35 * Checks to find out if ChromeFrame is available as a plugin |
| 36 * @return {Boolean} |
| 37 */ |
| 38 var isAvailable = function() { |
| 39 if (typeof cachedAvailable != 'undefined') { |
| 40 return cachedAvailable; |
| 41 } |
| 42 |
| 43 cachedAvailable = false; |
| 44 |
| 45 // Look for CF in the User Agent before trying more expensive checks |
| 46 var ua = navigator.userAgent.toLowerCase(); |
| 47 if (ua.indexOf("chromeframe") >= 0 || ua.indexOf("x-clock") >= 0) { |
| 48 cachedAvailable = true; |
| 49 return cachedAvailable; |
| 50 } |
| 51 |
| 52 if (typeof window['ActiveXObject'] != 'undefined') { |
| 53 try { |
| 54 var obj = new ActiveXObject('ChromeTab.ChromeFrame'); |
| 55 if (obj) { |
| 56 cachedAvailable = true; |
| 57 } |
| 58 } catch(e) { |
| 59 // squelch |
| 60 } |
| 61 } |
| 62 return cachedAvailable; |
| 63 }; |
| 64 |
| 65 |
| 66 /** @type {boolean} */ |
| 67 var cfStyleTagInjected = false; |
| 68 |
| 69 /** |
| 70 * Creates a style sheet in the document which provides default styling for |
| 71 * ChromeFrame instances. Successive calls should have no additive effect. |
| 72 */ |
| 73 var injectCFStyleTag = function() { |
| 74 if (cfStyleTagInjected) { |
| 75 // Once and only once |
| 76 return; |
| 77 } |
| 78 try { |
| 79 var rule = '.chromeFrameInstallDefaultStyle {' + |
| 80 'width: 500px;' + |
| 81 'height: 400px;' + |
| 82 'padding: 0;' + |
| 83 'border: 1px solid #0028c4;' + |
| 84 'margin: 0;' + |
| 85 '}'; |
| 86 var ss = document.createElement('style'); |
| 87 ss.setAttribute('type', 'text/css'); |
| 88 if (ss.styleSheet) { |
| 89 ss.styleSheet.cssText = rule; |
| 90 } else { |
| 91 ss.appendChild(document.createTextNode(rule)); |
| 92 } |
| 93 var h = document.getElementsByTagName('head')[0]; |
| 94 var firstChild = h.firstChild; |
| 95 h.insertBefore(ss, firstChild); |
| 96 cfStyleTagInjected = true; |
| 97 } catch (e) { |
| 98 // squelch |
| 99 } |
| 100 }; |
| 101 |
| 102 |
| 103 /** |
| 104 * Plucks properties from the passed arguments and sets them on the passed |
| 105 * DOM node |
| 106 * @param {Node} node The node to set properties on |
| 107 * @param {Object} args A map of user-specified properties to set |
| 108 */ |
| 109 var setProperties = function(node, args) { |
| 110 injectCFStyleTag(); |
| 111 |
| 112 var srcNode = byId(args['node']); |
| 113 |
| 114 node.id = args['id'] || (srcNode ? srcNode['id'] || getUid(srcNode) : ''); |
| 115 |
| 116 // TODO(slightlyoff): Opera compat? need to test there |
| 117 var cssText = args['cssText'] || ''; |
| 118 node.style.cssText = ' ' + cssText; |
| 119 |
| 120 var classText = args['className'] || ''; |
| 121 node.className = 'chromeFrameInstallDefaultStyle ' + classText; |
| 122 |
| 123 // default if the browser doesn't so we don't show sad-tab |
| 124 var src = args['src'] || 'about:blank'; |
| 125 |
| 126 node.src = src; |
| 127 |
| 128 if (srcNode) { |
| 129 srcNode.parentNode.replaceChild(node, srcNode); |
| 130 } |
| 131 }; |
| 132 |
| 133 /** |
| 134 * Creates an iframe. |
| 135 * @param {Object} args A bag of configuration properties, including values |
| 136 * like 'node', 'cssText', 'className', 'id', 'src', etc. |
| 137 * @return {Node} |
| 138 */ |
| 139 var makeIframe = function(args) { |
| 140 var el = document.createElement('iframe'); |
| 141 setProperties(el, args); |
| 142 return el; |
| 143 }; |
| 144 |
| 145 var CFInstall = {}; |
| 146 /** |
| 147 * Checks to see if Chrome Frame is available, if not, prompts the user to |
| 148 * install. Once installation is begun, a background timer starts, |
| 149 * checkinging for a successful install every 2 seconds. Upon detection of |
| 150 * successful installation, the current page is reloaded, or if a |
| 151 * 'destination' parameter is passed, the page navigates there instead. |
| 152 * @param {Object} args A bag of configuration properties. Respected |
| 153 * properties are: 'mode', 'url', 'destination', 'node', 'onmissing', |
| 154 * 'preventPrompt', 'oninstall', 'preventInstallDetection', 'cssText', and |
| 155 * 'className'. |
| 156 * @public |
| 157 */ |
| 158 CFInstall.check = function(args) { |
| 159 args = args || {}; |
| 160 |
| 161 // We currently only support CF in IE |
| 162 // TODO(slightlyoff): Update this should we support other browsers! |
| 163 var ieRe = /MSIE (\S+)/; |
| 164 if (!ieRe.test(navigator.userAgent)) { |
| 165 return; |
| 166 } |
| 167 |
| 168 |
| 169 // TODO(slightlyoff): Update this URL when a mini-installer page is |
| 170 // available. |
| 171 var installUrl = '//www.google.com/chromeframe'; |
| 172 if (!isAvailable()) { |
| 173 if (args.onmissing) { |
| 174 args.onmissing(); |
| 175 } |
| 176 |
| 177 args.src = args.url || installUrl; |
| 178 var mode = args.mode || 'inline'; |
| 179 var preventPrompt = args.preventPrompt || false; |
| 180 |
| 181 if (!preventPrompt) { |
| 182 if (mode == 'inline') { |
| 183 var ifr = makeIframe(args); |
| 184 // TODO(slightlyoff): handle placement more elegantly! |
| 185 if (!ifr.parentNode) { |
| 186 var firstChild = document.body.firstChild; |
| 187 document.body.insertBefore(ifr, firstChild); |
| 188 } |
| 189 } else { |
| 190 window.open(args.src); |
| 191 } |
| 192 } |
| 193 |
| 194 if (args.preventInstallDetection) { |
| 195 return; |
| 196 } |
| 197 |
| 198 // Begin polling for install success. |
| 199 var installTimer = setInterval(function() { |
| 200 // every 2 seconds, look to see if CF is available, if so, proceed on |
| 201 // to our destination |
| 202 if (isAvailable()) { |
| 203 if (args.oninstall) { |
| 204 args.oninstall(); |
| 205 } |
| 206 |
| 207 clearInterval(installTimer); |
| 208 // TODO(slightlyoff): add a way to prevent navigation or make it |
| 209 // contingent on oninstall? |
| 210 window.location = args.destination || window.location; |
| 211 } |
| 212 }, 2000); |
| 213 } |
| 214 }; |
| 215 |
| 216 CFInstall.isAvailable = isAvailable; |
| 217 |
| 218 // expose CFInstall to the external scope. We've already checked to make |
| 219 // sure we're not going to blow existing objects away. |
| 220 scope.CFInstall = CFInstall; |
| 221 |
| 222 })(this['ChromeFrameInstallScope'] || this); |
OLD | NEW |