| Index: chrome_frame/CFInstall.js
|
| ===================================================================
|
| --- chrome_frame/CFInstall.js (revision 0)
|
| +++ chrome_frame/CFInstall.js (revision 0)
|
| @@ -0,0 +1,222 @@
|
| +// Copyright (c) 2009 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +/**
|
| + * @fileoverview CFInstall.js provides a set of utilities for managing
|
| + * the Chrome Frame detection and installation process.
|
| + * @author slightlyoff@google.com (Alex Russell)
|
| + */
|
| +
|
| +(function(scope) {
|
| + // bail if we'd be over-writing an existing CFInstall object
|
| + if (scope['CFInstall']) {
|
| + return;
|
| + }
|
| +
|
| + /**
|
| + * returns an item based on DOM ID. Optionally a document may be provided to
|
| + * specify the scope to search in. If a node is passed, it's returned as-is.
|
| + * @param {string|Node} id The ID of the node to be located or a node
|
| + * @param {Node} doc Optional A document to search for id.
|
| + * @return {Node}
|
| + */
|
| + var byId = function(id, doc) {
|
| + return (typeof id == 'string') ? (doc || document).getElementById(id) : id;
|
| + };
|
| +
|
| + /////////////////////////////////////////////////////////////////////////////
|
| + // Plugin Detection
|
| + /////////////////////////////////////////////////////////////////////////////
|
| +
|
| + var cachedAvailable;
|
| +
|
| + /**
|
| + * Checks to find out if ChromeFrame is available as a plugin
|
| + * @return {Boolean}
|
| + */
|
| + var isAvailable = function() {
|
| + if (typeof cachedAvailable != 'undefined') {
|
| + return cachedAvailable;
|
| + }
|
| +
|
| + cachedAvailable = false;
|
| +
|
| + // Look for CF in the User Agent before trying more expensive checks
|
| + var ua = navigator.userAgent.toLowerCase();
|
| + if (ua.indexOf("chromeframe") >= 0 || ua.indexOf("x-clock") >= 0) {
|
| + cachedAvailable = true;
|
| + return cachedAvailable;
|
| + }
|
| +
|
| + if (typeof window['ActiveXObject'] != 'undefined') {
|
| + try {
|
| + var obj = new ActiveXObject('ChromeTab.ChromeFrame');
|
| + if (obj) {
|
| + cachedAvailable = true;
|
| + }
|
| + } catch(e) {
|
| + // squelch
|
| + }
|
| + }
|
| + return cachedAvailable;
|
| + };
|
| +
|
| +
|
| + /** @type {boolean} */
|
| + var cfStyleTagInjected = false;
|
| +
|
| + /**
|
| + * Creates a style sheet in the document which provides default styling for
|
| + * ChromeFrame instances. Successive calls should have no additive effect.
|
| + */
|
| + var injectCFStyleTag = function() {
|
| + if (cfStyleTagInjected) {
|
| + // Once and only once
|
| + return;
|
| + }
|
| + try {
|
| + var rule = '.chromeFrameInstallDefaultStyle {' +
|
| + 'width: 500px;' +
|
| + 'height: 400px;' +
|
| + 'padding: 0;' +
|
| + 'border: 1px solid #0028c4;' +
|
| + 'margin: 0;' +
|
| + '}';
|
| + var ss = document.createElement('style');
|
| + ss.setAttribute('type', 'text/css');
|
| + if (ss.styleSheet) {
|
| + ss.styleSheet.cssText = rule;
|
| + } else {
|
| + ss.appendChild(document.createTextNode(rule));
|
| + }
|
| + var h = document.getElementsByTagName('head')[0];
|
| + var firstChild = h.firstChild;
|
| + h.insertBefore(ss, firstChild);
|
| + cfStyleTagInjected = true;
|
| + } catch (e) {
|
| + // squelch
|
| + }
|
| + };
|
| +
|
| +
|
| + /**
|
| + * Plucks properties from the passed arguments and sets them on the passed
|
| + * DOM node
|
| + * @param {Node} node The node to set properties on
|
| + * @param {Object} args A map of user-specified properties to set
|
| + */
|
| + var setProperties = function(node, args) {
|
| + injectCFStyleTag();
|
| +
|
| + var srcNode = byId(args['node']);
|
| +
|
| + node.id = args['id'] || (srcNode ? srcNode['id'] || getUid(srcNode) : '');
|
| +
|
| + // TODO(slightlyoff): Opera compat? need to test there
|
| + var cssText = args['cssText'] || '';
|
| + node.style.cssText = ' ' + cssText;
|
| +
|
| + var classText = args['className'] || '';
|
| + node.className = 'chromeFrameInstallDefaultStyle ' + classText;
|
| +
|
| + // default if the browser doesn't so we don't show sad-tab
|
| + var src = args['src'] || 'about:blank';
|
| +
|
| + node.src = src;
|
| +
|
| + if (srcNode) {
|
| + srcNode.parentNode.replaceChild(node, srcNode);
|
| + }
|
| + };
|
| +
|
| + /**
|
| + * Creates an iframe.
|
| + * @param {Object} args A bag of configuration properties, including values
|
| + * like 'node', 'cssText', 'className', 'id', 'src', etc.
|
| + * @return {Node}
|
| + */
|
| + var makeIframe = function(args) {
|
| + var el = document.createElement('iframe');
|
| + setProperties(el, args);
|
| + return el;
|
| + };
|
| +
|
| + var CFInstall = {};
|
| + /**
|
| + * Checks to see if Chrome Frame is available, if not, prompts the user to
|
| + * install. Once installation is begun, a background timer starts,
|
| + * checkinging for a successful install every 2 seconds. Upon detection of
|
| + * successful installation, the current page is reloaded, or if a
|
| + * 'destination' parameter is passed, the page navigates there instead.
|
| + * @param {Object} args A bag of configuration properties. Respected
|
| + * properties are: 'mode', 'url', 'destination', 'node', 'onmissing',
|
| + * 'preventPrompt', 'oninstall', 'preventInstallDetection', 'cssText', and
|
| + * 'className'.
|
| + * @public
|
| + */
|
| + CFInstall.check = function(args) {
|
| + args = args || {};
|
| +
|
| + // We currently only support CF in IE
|
| + // TODO(slightlyoff): Update this should we support other browsers!
|
| + var ieRe = /MSIE (\S+)/;
|
| + if (!ieRe.test(navigator.userAgent)) {
|
| + return;
|
| + }
|
| +
|
| +
|
| + // TODO(slightlyoff): Update this URL when a mini-installer page is
|
| + // available.
|
| + var installUrl = '//www.google.com/chromeframe';
|
| + if (!isAvailable()) {
|
| + if (args.onmissing) {
|
| + args.onmissing();
|
| + }
|
| +
|
| + args.src = args.url || installUrl;
|
| + var mode = args.mode || 'inline';
|
| + var preventPrompt = args.preventPrompt || false;
|
| +
|
| + if (!preventPrompt) {
|
| + if (mode == 'inline') {
|
| + var ifr = makeIframe(args);
|
| + // TODO(slightlyoff): handle placement more elegantly!
|
| + if (!ifr.parentNode) {
|
| + var firstChild = document.body.firstChild;
|
| + document.body.insertBefore(ifr, firstChild);
|
| + }
|
| + } else {
|
| + window.open(args.src);
|
| + }
|
| + }
|
| +
|
| + if (args.preventInstallDetection) {
|
| + return;
|
| + }
|
| +
|
| + // Begin polling for install success.
|
| + var installTimer = setInterval(function() {
|
| + // every 2 seconds, look to see if CF is available, if so, proceed on
|
| + // to our destination
|
| + if (isAvailable()) {
|
| + if (args.oninstall) {
|
| + args.oninstall();
|
| + }
|
| +
|
| + clearInterval(installTimer);
|
| + // TODO(slightlyoff): add a way to prevent navigation or make it
|
| + // contingent on oninstall?
|
| + window.location = args.destination || window.location;
|
| + }
|
| + }, 2000);
|
| + }
|
| + };
|
| +
|
| + CFInstall.isAvailable = isAvailable;
|
| +
|
| + // expose CFInstall to the external scope. We've already checked to make
|
| + // sure we're not going to blow existing objects away.
|
| + scope.CFInstall = CFInstall;
|
| +
|
| +})(this['ChromeFrameInstallScope'] || this);
|
|
|