PageRenderTime 20ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/public/chrome-frame/1.0.1/CFInstall.js

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