diff options
author | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-04 17:22:10 +0000 |
---|---|---|
committer | erikwright@chromium.org <erikwright@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-11-04 17:22:10 +0000 |
commit | cdaf67c70b346fa9fa8bab1973d96e0d495aba4b (patch) | |
tree | c15a8dd9b6cc42789d0f7d3bef0ab807d3422dcc /chrome_frame | |
parent | beb288919aa2ebf9908b4d161705a90417485212 (diff) | |
download | chromium_src-cdaf67c70b346fa9fa8bab1973d96e0d495aba4b.zip chromium_src-cdaf67c70b346fa9fa8bab1973d96e0d495aba4b.tar.gz chromium_src-cdaf67c70b346fa9fa8bab1973d96e0d495aba4b.tar.bz2 |
Publish the source for CFInstall.min.js .
BUG=None
TEST=./build.sh and then load file:///path/to/local_testing.html in IE (without CF). Click the "This site requires Chrome Frame" link and observe the dialog that pops up.
Review URL: http://codereview.chromium.org/8467005
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@108675 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome_frame')
20 files changed, 1411 insertions, 0 deletions
diff --git a/chrome_frame/cfinstall/.gitignore b/chrome_frame/cfinstall/.gitignore new file mode 100644 index 0000000..f92e804 --- /dev/null +++ b/chrome_frame/cfinstall/.gitignore @@ -0,0 +1,2 @@ +/deps/ +/out/ diff --git a/chrome_frame/cfinstall/README b/chrome_frame/cfinstall/README new file mode 100644 index 0000000..622ebb1 --- /dev/null +++ b/chrome_frame/cfinstall/README @@ -0,0 +1,7 @@ +This directory contains the source code for CFInstall.min.js, a useful site for +prompting web site visitors to install Chrome Frame. + +Please visit the following page for further information about compiling and +using these scripts: + +https://sites.google.com/a/chromium.org/dev/developers/how-tos/chrome-frame-cfinstall
\ No newline at end of file diff --git a/chrome_frame/cfinstall/build.sh b/chrome_frame/cfinstall/build.sh new file mode 100755 index 0000000..354262c --- /dev/null +++ b/chrome_frame/cfinstall/build.sh @@ -0,0 +1,62 @@ +#!/bin/sh +# Copyright (c) 2011 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. + +OPTIMIZATION_LEVEL="ADVANCED_OPTIMIZATIONS" +EXTRA_FLAGS="" + +while getopts l:d o +do case "$o" in + l) EXTRA_FLAGS="$EXTRA_FLAGS -f --define=google.cf.installer.Prompt.\ +DEFAULT_IMPLEMENTATION_URL='${OPTARG}cf-xd-install-impl.js'";; + d) OPTIMIZATION_LEVEL="SIMPLE_OPTIMIZATIONS" + EXTRA_FLAGS="$EXTRA_FLAGS -f --formatting=PRETTY_PRINT";; + [?]) echo >&2 "Usage: $0 [-l //host.com/path/to/scripts/dir/] [-p] [-d]" + echo >&2 " -l <URL> The path under which the generated" + echo >&2 " scripts will be deployed." + echo >&2 " -d Disable obfuscating optimizations." + exit 1;; + esac +done + +DEPS_DIR=deps +OUT_DIR=out +SRC_DIR=src +CLOSURE_LIBRARY_DIR=$DEPS_DIR/closure_library +CLOSURE_BUILDER=$CLOSURE_LIBRARY_DIR/closure/bin/build/closurebuilder.py +CLOSURE_COMPILER_ZIP=$DEPS_DIR/compiler-latest.zip +CLOSURE_COMPILER_JAR_ZIP_RELATIVE=compiler.jar +CLOSURE_COMPILER_JAR=$DEPS_DIR/$CLOSURE_COMPILER_JAR_ZIP_RELATIVE + +mkdir -p $DEPS_DIR && +mkdir -p $OUT_DIR && +{ [[ -e $CLOSURE_LIBRARY_DIR ]] || \ + svn checkout http://closure-library.googlecode.com/svn/trunk/ \ + $CLOSURE_LIBRARY_DIR; } && \ +{ [[ -e $CLOSURE_COMPILER_JAR ]] || + { wget http://closure-compiler.googlecode.com/files/compiler-latest.zip \ + -O $CLOSURE_COMPILER_ZIP && \ + unzip -d $DEPS_DIR $CLOSURE_COMPILER_ZIP \ + $CLOSURE_COMPILER_JAR_ZIP_RELATIVE >/dev/null; }; } && +$CLOSURE_BUILDER \ + --root=$CLOSURE_LIBRARY_DIR --root=src/common/ \ + --root=src/implementation/ \ + --namespace="google.cf.installer.CrossDomainInstall" \ + --output_mode=compiled --compiler_jar=$CLOSURE_COMPILER_JAR \ + $EXTRA_FLAGS \ + -f "--compilation_level=$OPTIMIZATION_LEVEL" \ + -f "--output_wrapper='(function (scope){ %output% })(window)'" \ + -f "--externs=src/common/cf-interactiondelegate-externs.js" \ + --output_file=out/cf-xd-install-impl.js && \ +$CLOSURE_BUILDER \ + --root=src/miniclosure/ --root=src/common/ \ + --root=src/stub/ \ + --namespace="google.cf.installer.CFInstall" \ + --output_mode=compiled --compiler_jar=$CLOSURE_COMPILER_JAR \ + $EXTRA_FLAGS \ + -f "--compilation_level=$OPTIMIZATION_LEVEL" \ + -f "--output_wrapper='(function (scope){ %output% })(window)'" \ + -f "--externs=src/stub/cf-activex-externs.js" \ + -f "--externs=src/common/cf-interactiondelegate-externs.js" \ + --output_file=out/CFInstall.min.js diff --git a/chrome_frame/cfinstall/examples/jquery.html b/chrome_frame/cfinstall/examples/jquery.html new file mode 100644 index 0000000..ef2e4d6 --- /dev/null +++ b/chrome_frame/cfinstall/examples/jquery.html @@ -0,0 +1,71 @@ +<!-- + Copyright 2011 Google Inc. All rights reserved. +--> +<html> + <head> + <meta http-equiv="X-UA-Compatible" content="chrome=1" /> + <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css" + rel="stylesheet" type="text/css"/> + <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5/jquery.min.js"> + </script> + <script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/jquery-ui.min.js"> + </script> + + <script src='//google.com/tools/dlpage/res/chromeframe/script/CFInstall.min.js'> </script> + <script> + $(document).ready(function() { + var interactionDelegate = { + dialog: null, + getIFrameContainer: function() { + var self = this; + this.dialog = $("#dialog").dialog( + {modal: true, + width: 'auto', + height: 'auto', + resizable: false, + close: function() { + var el = document.getElementById('dialog'); + if (el.firstChild) + el.removeChild(el.firstChild); + } + }); + var widget = this.dialog.dialog('widget')[0]; + widget.style.left = -5000; + widget.style.top = -5000; + return document.getElementById('dialog'); + }, + show: function() { + var dialogEl = $("#dialog"); + dialogEl.width($("#dialog iframe").outerWidth(true) + + dialogEl.innerWidth() - dialogEl.width()); + var widgetEl = this.dialog.dialog('widget'); + widgetEl.width(dialogEl.outerWidth(true) + + widgetEl.innerWidth() - widgetEl.width()); + dialogEl.height('auto'); + this.dialog.dialog('option', 'position', 'center') + }, + customizeIFrame: function(iframe) {}, + reset: function() { + this.dialog.dialog('close'); + } + }; + CFInstall.setInteractionDelegate(interactionDelegate); + }); + </script> + </head> + <body> + <b>Chrome Renderer Active?:</b> + <span class="labeled" id="ChromeActive"></span><br /> + <script> + var ua = navigator.userAgent.toLowerCase(); + document.getElementById('ChromeActive').innerHTML = + ua.indexOf('chrome/') >= 0 ? "Yes" : "No"; + </script> + <p> + <a href="javascript:CFInstall.require()"> + This site requires Google Chrome Frame. Click here to install it now. + </a> + </p> + <div id="dialog" style="padding:0px; height:auto;"></div> + </body> +</html> diff --git a/chrome_frame/cfinstall/examples/local_testing.html b/chrome_frame/cfinstall/examples/local_testing.html new file mode 100644 index 0000000..89bf7327 --- /dev/null +++ b/chrome_frame/cfinstall/examples/local_testing.html @@ -0,0 +1,38 @@ +<!-- + Copyright 2011 Google Inc. All rights reserved. +--> +<html> + <head> + <script src='../out/CFInstall.min.js'> </script> + <script> + // This is only required if you are hosting your own copy of the + // implementation script and have not set the implementation path during + // compilation. (See build.sh -l 'PATH'). + CFInstall.setImplementationUrl('../out/cf-xd-install-impl.js'); + + // The following are only required when running this example from a local + // file. The default behaviour is to use the same scheme as this page, + // which is file://, and thus wrong. + CFInstall.setDownloadPageUrl('http://google.com/chromeframe/eula.html'); + CFInstall.setSameDomainResourceUri('http://example.com/robots.txt'); + </script> + </head> + <body> + <b>Chrome Frame Installed?:</b> + <span class="labeled" id="ChromeInstalled"></span><br /> + <p> + Note that Chrome Frame will never render local pages (i.e., from 'file://' + URLs). The above message will, however, tell you whether Chrome Frame is + installed. + </p> + <script> + document.getElementById('ChromeInstalled').innerHTML = + CFInstall.isAvailable() ? "Yes" : "No"; + </script> + <p> + <a href="javascript:CFInstall.require()"> + This site requires Google Chrome Frame. Click here to install it now. + </a> + </p> + </body> +</html> diff --git a/chrome_frame/cfinstall/examples/simple.html b/chrome_frame/cfinstall/examples/simple.html new file mode 100644 index 0000000..812a717 --- /dev/null +++ b/chrome_frame/cfinstall/examples/simple.html @@ -0,0 +1,25 @@ +<!-- + Copyright 2011 Google Inc. All rights reserved. +--> +<html> + <head> + <meta http-equiv="X-UA-Compatible" content="chrome=1" /> + <script + src='//google.com/tools/dlpage/res/chromeframe/script/CFInstall.min.js'> + </script> + </head> + <body> + <b>Chrome Renderer Active?:</b> + <span class="labeled" id="ChromeActive"></span><br /> + <script> + var ua = navigator.userAgent.toLowerCase(); + document.getElementById('ChromeActive').innerHTML = + ua.indexOf('chrome/') >= 0 ? "Yes" : "No"; + </script> + <p> + <a href="javascript:CFInstall.require()"> + This site requires Google Chrome Frame. Click here to install it now. + </a> + </p> + </body> +</html> diff --git a/chrome_frame/cfinstall/src/common/cf-interactiondelegate-externs.js b/chrome_frame/cfinstall/src/common/cf-interactiondelegate-externs.js new file mode 100644 index 0000000..805c1ee --- /dev/null +++ b/chrome_frame/cfinstall/src/common/cf-interactiondelegate-externs.js @@ -0,0 +1,13 @@ +// Copyright (c) 2011 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 Defines an interface whose properties should be immune from + * renaming (as it may be implemented by uncompiled client code). + **/ + +google.cf.installer.InteractionDelegate.prototype.getIFrameContainer; +google.cf.installer.InteractionDelegate.prototype.reset; +google.cf.installer.InteractionDelegate.prototype.show; +google.cf.installer.InteractionDelegate.prototype.customizeIFrame; diff --git a/chrome_frame/cfinstall/src/common/interactiondelegate.js b/chrome_frame/cfinstall/src/common/interactiondelegate.js new file mode 100644 index 0000000..b9cb8c6 --- /dev/null +++ b/chrome_frame/cfinstall/src/common/interactiondelegate.js @@ -0,0 +1,49 @@ +// Copyright (c) 2011 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 Describes an interface clients may implement to customize the + * look and feel of the Chrome Frame installation flow on their site. + * + */ + +goog.provide('google.cf.installer.InteractionDelegate'); + +/** + * Allows clients to customize the display of the IFrame holding the Chrome + * Frame installation flow. + * @interface + */ +google.cf.installer.InteractionDelegate = function() {}; + +/** + * Returns the element under which the IFrame should be located. Note that the + * IFrame must remain in the DOM for the duration of the connection. + * Re-parenting the IFrame or any ancestor will cause undefined behaviour. + * @return {!HTMLElement} The element that should be the parent of the IFrame. + */ +google.cf.installer.InteractionDelegate.prototype.getIFrameContainer = + function() {}; + +/** + * Receives a reference to the newly created IFrame. May optionally modify the + * element's attributes, style, etc. The InteractionDelegate is not responsible + * for inserting the IFrame in the DOM (this will occur later). + * @param {!HTMLIFrameElement} iframe The newly created IFrame element. + */ +google.cf.installer.InteractionDelegate.prototype.customizeIFrame = + function(iframe) {}; + +/** + * Make the IFrame and its decoration (if any) visible. Its dimensions will + * already have been adjusted to those of the contained content. + */ +google.cf.installer.InteractionDelegate.prototype.show = function() {}; + + +/** + * Receives notification that the installation flow is complete and that the + * IFrame and its decoration (if any) should be hidden and resources freed. + */ +google.cf.installer.InteractionDelegate.prototype.reset = function() {}; diff --git a/chrome_frame/cfinstall/src/implementation/crossdomaininstall.js b/chrome_frame/cfinstall/src/implementation/crossdomaininstall.js new file mode 100755 index 0000000..38a1670 --- /dev/null +++ b/chrome_frame/cfinstall/src/implementation/crossdomaininstall.js @@ -0,0 +1,111 @@ +// Copyright (c) 2011 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 Implements the in-line Google Chrome Frame installation flow. + * Displays a dialog containing the download page. Upon completion, registers + * the Google Chrome Frame components in the current browser process. + * + **/ +goog.provide('google.cf.installer.CrossDomainInstall'); + +goog.require('goog.net.xpc.CrossPageChannel'); +goog.require('goog.style'); +goog.require('goog.Uri'); + +goog.require('google.cf.installer.InteractionDelegate'); +goog.require('google.cf.installer.DialogInteractionDelegate'); + +/** + * @type {Object} + **/ +google.cf.installer.CrossDomainInstall = {}; + +/** + * @define {string} Defines the default download page URL. + **/ +google.cf.installer.CrossDomainInstall.DEFAULT_DOWNLOAD_PAGE_URL = + '//www.google.com/chromeframe/eula.html'; + +/** + * Executes the in-line installation flow. + * @param {function()} successHandler Invoked upon installation success. When + * invoked, Google Chrome Frame will be active in the current and all + * future-launched browser processes. + * @param {function()=} opt_failureHandler Invoked upon installation failure or + * cancellation. + * @param {string=} opt_url An alternative URL for the download page. + * @param {google.cf.installer.InteractionDelegate=} opt_interactionDelegate An + * alternative UI implementation for the modal dialog. + * @param {string=} opt_dummyResourceUri A manually-specified dummy resource URI + * that will be used to carry cross-domain responses. + */ +google.cf.installer.CrossDomainInstall.execute = function( + successHandler, opt_failureHandler, opt_url, opt_interactionDelegate, + opt_dummyResourceUri) { + var url = new goog.Uri( + opt_url || + google.cf.installer.CrossDomainInstall.DEFAULT_DOWNLOAD_PAGE_URL); + + if (!url.hasScheme()) + url = new goog.Uri(window.location.href).resolve(url); + + var interactionDelegate = opt_interactionDelegate || + new google.cf.installer.DialogInteractionDelegate(); + + var cfg = {}; + + // TODO(user): Probably need to import some of the link/image url + // detection stuff from XDRPC. + if (opt_dummyResourceUri) { + var dummyUrl = new goog.Uri(opt_dummyResourceUri); + if (!dummyUrl.hasScheme()) + dummyUrl = new goog.Uri(window.location.href).resolve(dummyUrl); + + cfg[goog.net.xpc.CfgFields.LOCAL_POLL_URI] = dummyUrl.toString(); + } + + cfg[goog.net.xpc.CfgFields.PEER_URI] = url.toString(); + + var channel = new goog.net.xpc.CrossPageChannel(cfg); + var iframe = channel.createPeerIframe( + interactionDelegate.getIFrameContainer(), + function(newIFrame) { + newIFrame.setAttribute('frameBorder', '0'); + newIFrame.setAttribute('border', '0'); + interactionDelegate.customizeIFrame(newIFrame); + }); + channel.registerService('dimensions', function(size) { + goog.style.setContentBoxSize(iframe, new goog.math.Size(size['width'], + size['height'])); + interactionDelegate.show(); + }, true); // true => deserialize messages into objects + channel.registerService('result', function(obj) { + channel.close(); + interactionDelegate.reset(); + var result = obj['result']; + if (result) + successHandler(); + else if (opt_failureHandler) + opt_failureHandler(); + }, true); // true => deserialize messages into objects + // TODO(user): Perhaps listen to onload and set a timeout for connect. + channel.connect(); +}; + +// In compiled mode, this binary is wrapped in an anonymous function which +// receives the outer scope as its only parameter. In non-compiled mode, the +// outer scope is window. +// Look in the outer scope for the stub, and pass it the implementation. +try { + if (arguments[0]['CF_google_cf_xd_install_stub']) { + arguments[0]['CF_google_cf_xd_install_stub']( + google.cf.installer.CrossDomainInstall.execute); + } +} catch (e) { + if (window['CF_google_cf_xd_install_stub']) { + window['CF_google_cf_xd_install_stub']( + google.cf.installer.CrossDomainInstall.execute); + } +} diff --git a/chrome_frame/cfinstall/src/implementation/dialoginteractiondelegate.js b/chrome_frame/cfinstall/src/implementation/dialoginteractiondelegate.js new file mode 100755 index 0000000..9782dc9 --- /dev/null +++ b/chrome_frame/cfinstall/src/implementation/dialoginteractiondelegate.js @@ -0,0 +1,161 @@ +// Copyright (c) 2011 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 Displays the Chrome Frame installation flow in a Closure + * dialog component. + */ + +goog.provide('google.cf.installer.DialogInteractionDelegate'); + +goog.require('goog.math.Size'); +goog.require('goog.style'); +goog.require('goog.ui.Dialog'); +goog.require('goog.userAgent'); + +goog.require('google.cf.installer.InteractionDelegate'); + +/** + * An implementation of google.cf.installer.InteractionDelegate that decorates + * the installation flow using a goog.ui.Dialog . + * @constructor + * @implements {google.cf.installer.InteractionDelegate} + */ +google.cf.installer.DialogInteractionDelegate = function() { +}; + +/** + * Whether we have already injected the dialog styles into the page. + * @type {boolean} + * @private + **/ +google.cf.installer.DialogInteractionDelegate.injectedCss_ = false; + +/** + * Injects the dialog styles into the page. + * @private + **/ +google.cf.installer.DialogInteractionDelegate.injectCss_ = function() { + if (google.cf.installer.DialogInteractionDelegate.injectedCss_) + return; + + google.cf.installer.DialogInteractionDelegate.injectedCss_ = true; + + goog.style.installStyles( + '.xdgcfinstall-dlg {' + + 'background: #c1d9ff;' + + 'border: 1px solid #3a5774;' + + 'color: #000;' + + 'padding: 4px;' + + 'position: absolute;' + + '}' + + + '.xdgcfinstall-dlg-bg {' + + 'background: #666;' + + 'left: 0;' + + 'position: absolute;' + + 'top: 0;' + + '}' + + + '.xdgcfinstall-dlg-title {' + + 'background: #e0edfe;' + + 'color: #000;' + + 'cursor: pointer;' + + 'font-size: 120%;' + + 'font-weight: bold;' + + + 'padding: 0px;' + + 'height: 17px;' + + 'position: relative;' + + '_zoom: 1; /* Ensures proper width in IE6 RTL. */' + + '}' + + + '.xdgcfinstall-dlg-title-close {' + + /* Client apps may override the URL at which they serve the sprite. */ + 'background: #e0edfe' + + 'url(//ssl.gstatic.com/editor/editortoolbar.png)' + + 'no-repeat -528px 0;' + + 'cursor: default;' + + 'font-size: 0%;' + + 'height: 15px;' + + 'position: absolute;' + + 'top: 1px;' + + 'right: 1px;' + + 'width: 15px;' + + 'padding: 0px 0px 0px 0px;' + + 'align: right;' + + '}' + + + '.xdgcfinstall-dlg-content {' + + 'background-color: #fff;' + + 'padding: 0px;' + + '}' + ); +}; + +/** + * The active dialog. + * @type {goog.ui.Dialog} + * @private + */ +google.cf.installer.DialogInteractionDelegate.prototype.dialog_ = null; + +/** + * @inheritDoc + */ +google.cf.installer.DialogInteractionDelegate.prototype.getIFrameContainer = + function() { + google.cf.installer.DialogInteractionDelegate.injectCss_(); + + this.dialog_ = new goog.ui.Dialog('xdgcfinstall-dlg', true); + this.dialog_.setButtonSet(null); + // TODO(user): The IFrame must be 'visible' or else calculation of its + // contents' dimensions is incorrect on IE, yet the following line also + // disables interaction with and dims the page contents. It would be best to + // only do that when show() is called. Best way is probably to push the mask + // elements offscreen. + this.dialog_.setVisible(true); + goog.style.setPosition(this.dialog_.getDialogElement(), -5000, -5000); + return /** @type {!HTMLElement} */(this.dialog_.getContentElement()); +}; + +/** + * @inheritDoc + */ +google.cf.installer.DialogInteractionDelegate.prototype.customizeIFrame = + function(iframe) { +}; + +/** + * @inheritDoc + */ +google.cf.installer.DialogInteractionDelegate.prototype.show = + function() { + if (goog.userAgent.IE) { + // By default, in IE, the dialog does not respect the width of its contents. + // So we set its dimensions here. We need to specifically add some space for + // the title bar. + var iframeSize = goog.style.getBorderBoxSize( + this.dialog_.getContentElement().getElementsByTagName('iframe')[0]); + var titleSize = goog.style.getBorderBoxSize(this.dialog_.getTitleElement()); + goog.style.setContentBoxSize(this.dialog_.getDialogElement(), + new goog.math.Size( + iframeSize.width, + iframeSize.height + titleSize.height)); + } + // Ask the dialog to re-center itself based on the new dimensions. + this.dialog_.reposition(); +}; + + +/** + * @inheritDoc + */ +google.cf.installer.DialogInteractionDelegate.prototype.reset = function() { + if (this.dialog_) { + this.dialog_.setVisible(false); + this.dialog_.dispose(); + this.dialog_ = null; + } +}; diff --git a/chrome_frame/cfinstall/src/miniclosure/base.js b/chrome_frame/cfinstall/src/miniclosure/base.js new file mode 100644 index 0000000..b64847d --- /dev/null +++ b/chrome_frame/cfinstall/src/miniclosure/base.js @@ -0,0 +1,77 @@ +// Copyright (c) 2011 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 Implements a shim so that the CFInstall scripts can be compiled + * with or without Closure. In particular, chromeframe.js is used by the stub, + * the implementation, and the download site, so we need to provide an + * implementation of goog.provide. + **/ + +var goog = {}; +goog.global = this; + +/** + * From closure/base.js:goog.exportPath_ . + * @param {string} name + * @param {Object=} opt_object + */ +goog.provide = function(name, opt_object) { + var parts = name.split('.'); + var cur = goog.global; + + // Internet Explorer exhibits strange behavior when throwing errors from + // methods externed in this manner. See the testExportSymbolExceptions in + // base_test.html for an example. + if (!(parts[0] in cur) && cur.execScript) + cur.execScript('var ' + parts[0]); + + // Certain browsers cannot parse code in the form for((a in b); c;); + // This pattern is produced by the JSCompiler when it collapses the + // statement above into the conditional loop below. To prevent this from + // happening, use a for-loop and reserve the init logic as below. + + // Parentheses added to eliminate strict JS warning in Firefox. + for (var part; parts.length && (part = parts.shift());) { + if (!parts.length && opt_object !== undefined) { + // last part and we have an object; use it + cur[part] = opt_object; + } else if (cur[part]) { + cur = cur[part]; + } else { + cur = cur[part] = {}; + } + } +}; + +// The following line causes the closureBuilder script to recognize this as +// base.js . +goog.provide('goog'); + +/** + * From closure/base.js:goog.exportPath_ . + * @param {string} name + * @param {Object=} opt_object + */ +goog.exportSymbol = goog.provide; + +/** + * NO-OP + * @param {string} name + */ +goog.require = function(name) {}; + +/** + * A simple form that supports only bound 'this', not arguments. + * @param {Function} fn A function to partially apply. + * @param {Object|undefined} selfObj Specifies the object which |this| should + * point to when the function is run. + * @return {!Function} A partially-applied form of the function bind() was + * invoked as a method of. + */ +goog.bind = function(fn, selfObj) { + return function() { + return fn.apply(selfObj, arguments); + }; +}; diff --git a/chrome_frame/cfinstall/src/miniclosure/style.js b/chrome_frame/cfinstall/src/miniclosure/style.js new file mode 100644 index 0000000..59905d7 --- /dev/null +++ b/chrome_frame/cfinstall/src/miniclosure/style.js @@ -0,0 +1,29 @@ +// Copyright (c) 2011 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. + +// A drop-in replacement for one method that we could use from Closure. + +goog.provide('goog.style'); + +/** + * Creates a style sheet in the document containing the passed rules. + * A simplified version that does not take an optional node parameter. + * @param {string} rules + */ +goog.style.installStyles = function(rules) { + try { + var ss = document.createElement('style'); + ss.setAttribute('type', 'text/css'); + if (ss.styleSheet) { + ss.styleSheet.cssText = rules; + } else { + ss.appendChild(document.createTextNode(rules)); + } + var h = document.getElementsByTagName('head')[0]; + var firstChild = h.firstChild; + h.insertBefore(ss, firstChild); + } catch (e) { + // squelch + } +}; diff --git a/chrome_frame/cfinstall/src/stub/cf-activex-externs.js b/chrome_frame/cfinstall/src/stub/cf-activex-externs.js new file mode 100755 index 0000000..76c6418 --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/cf-activex-externs.js @@ -0,0 +1,16 @@ +// Copyright (c) 2011 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 Describes the Chrome Frame ActiveX control. + **/ + +// Defined by chrome_tab.idl +var ChromeTab; +/** + * @constructor + * @extends ActiveXObject + */ +ChromeTab.ChromeFrame; +ChromeTab.ChromeFrame.prototype.registerBhoIfNeeded; diff --git a/chrome_frame/cfinstall/src/stub/cfinstall.js b/chrome_frame/cfinstall/src/stub/cfinstall.js new file mode 100644 index 0000000..1bf4e77 --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/cfinstall.js @@ -0,0 +1,118 @@ +// Copyright (c) 2011 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 Implements CFInstall.check and isAvailable in a way that is + * compatible with previous versions. Also supports a more streamlined + * method, 'require'. + * + **/ + +goog.provide('google.cf.installer.CFInstall'); + +goog.require('google.cf.ChromeFrame'); +goog.require('google.cf.installer.InlineDelegate'); +goog.require('google.cf.installer.Installer'); +goog.require('google.cf.installer.OverlayDelegate'); +goog.require('google.cf.installer.Prompt'); + +/** + * Instantiates the CFInstall object. Normally there will be only one, at + * Window.CFInstall . + * @constructor + */ +google.cf.installer.CFInstall = function() { + this.prompt_ = new google.cf.installer.Prompt(); + this.chromeFrame_ = new google.cf.ChromeFrame(); + this.installer_ = new google.cf.installer.Installer( + this.prompt_, this.chromeFrame_); + this['setDownloadPageUrl'] = + goog.bind(this.prompt_.setDownloadPageUrl, this.prompt_); + this['setImplementationUrl'] = + goog.bind(this.prompt_.setImplementationUrl, this.prompt_); + this['setSameDomainResourceUri'] = + goog.bind(this.prompt_.setSameDomainResourceUri, this.prompt_); + this['setInteractionDelegate'] = + goog.bind(this.prompt_.setInteractionDelegate, this.prompt_); + this['require'] = goog.bind(this.installer_.require, this.installer_); + this['isAvailable'] = + goog.bind(this.chromeFrame_.activate, this.chromeFrame_); +}; + +/** + * TODO(user): This cookie is not currently set anywhere. + * @return {boolean} Whether the user has previously declined Chrome Frame. + * @private + */ +google.cf.installer.CFInstall.isDeclined_ = function() { + return document.cookie.indexOf("disableGCFCheck=1") >=0; +}; + +/** + * 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'. + */ +google.cf.installer.CFInstall.prototype['check'] = function(args) { + args = args || {}; + + if (!this.chromeFrame_.isPlatformSupported()) + return; + + if (this.chromeFrame_.activate()) + return; + + if (args['onmissing']) + args['onmissing'](); + + if (google.cf.installer.CFInstall.isDeclined_() || args['preventPrompt']) + return; + + // NOTE: @slightlyoff, I'm doing away with the window.open option here. Sites + // that were using it will now use the popup. + + // In the case of legacy installation parameters, supply a compatible + // InteractionDelegate. + if (args['mode'] == 'inline' || args['node'] || args['id'] || + args['cssText'] || args['className']) { + if (!args['mode'] || args['mode'] == 'inline') { + this.prompt_.setInteractionDelegate( + new google.cf.installer.InlineDelegate(args)); + } else { + this.prompt_.setInteractionDelegate( + new google.cf.installer.OverlayDelegate(args)); + } + } + + if (args['src']) + this.prompt_.setDownloadPageUrl(args['src']); + + var onSuccess = function() { + if (this.chromeFrame_.activate() && !args['preventInstallDetection']) { + if (args['oninstall']) + args['oninstall'](); + window.location.assign(args['destination'] || window.location); + } + }; + + this.prompt_.open(onSuccess, undefined); +}; + +// In compiled mode, this binary is wrapped in an anonymous function which +// receives the outer scope as its only parameter. In non-compiled mode, the +// outer scope is window. + +// Create a single instance of CFInstall and place it in the outer scope +// (presumably the global window object). +try { + arguments[0]['CFInstall'] = new google.cf.installer.CFInstall(); +} catch (e) { + window['CFInstall'] = new google.cf.installer.CFInstall(); +} diff --git a/chrome_frame/cfinstall/src/stub/chromeframe.js b/chrome_frame/cfinstall/src/stub/chromeframe.js new file mode 100755 index 0000000..1c00ccd --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/chromeframe.js @@ -0,0 +1,90 @@ +// Copyright (c) 2011 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 Logic for interrogating / manipulating the local Chrome Frame + * installation. + * + **/ +goog.provide('google.cf.ChromeFrame'); + +/** + * Constructs an object for interacting with Chrome Frame through the provided + * Window instance. + * @constructor + * @param {Window=} opt_windowInstance The browser window through which to + * interact with Chrome Frame. Defaults to the global window object. + **/ +google.cf.ChromeFrame = function(opt_windowInstance) { + /** + * @private + * @const + * @type {!Window} + **/ + this.window_ = opt_windowInstance || window; +}; + +/** + * The name of the Chrome Frame ActiveX control. + * @const + * @type {string} + **/ +google.cf.ChromeFrame.CONTROL_NAME = 'ChromeTab.ChromeFrame'; + +/** + * Determines whether ChromeFrame is supported on the current platform. + * @return {boolean} Whether Chrome Frame is supported on the current platform. + */ +google.cf.ChromeFrame.prototype.isPlatformSupported = function() { + var ua = this.window_.navigator.userAgent; + var ieRe = /MSIE (\S+); Windows NT/; + + if (!ieRe.test(ua)) + return false; + + // We also only support Win2003/XPSP2 or better. See: + // http://msdn.microsoft.com/en-us/library/ms537503%28VS.85%29.aspx . + // 'SV1' indicates SP2, only bail if not SP2 or Win2K3 + if (parseFloat(ieRe.exec(ua)[1]) < 6 && ua.indexOf('SV1') < 0) + return false; + + return true; +}; + +/** + * Determines whether Chrome Frame is the currently active renderer. + * @return {boolean} Whether Chrome Frame is rendering the current page. + */ +google.cf.ChromeFrame.prototype.isActiveRenderer = function () { + return this.window_.externalHost ? true : false; +}; + +/** + * Determines if Google Chrome Frame is activated or locally available for + * activation in the current browser instance. In the latter case, will trigger + * its activation. + * @return {boolean} True if Google Chrome Frame already was active or was + * locally available (and now active). False otherwise. + */ +google.cf.ChromeFrame.prototype.activate = function() { + // Look for CF in the User Agent before trying more expensive checks + var ua = this.window_.navigator.userAgent.toLowerCase(); + if (ua.indexOf('chromeframe') >= 0) + return true; + + if (typeof this.window_['ActiveXObject'] != 'undefined') { + try { + var chromeFrame = /** @type {ChromeTab.ChromeFrame} */( + new this.window_.ActiveXObject(google.cf.ChromeFrame.CONTROL_NAME)); + if (chromeFrame) { + // Register the BHO if it hasn't happened already. + chromeFrame.registerBhoIfNeeded(); + return true; + } + } catch (e) { + // Squelch + } + } + return false; +}; diff --git a/chrome_frame/cfinstall/src/stub/frame.js b/chrome_frame/cfinstall/src/stub/frame.js new file mode 100644 index 0000000..6d23984 --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/frame.js @@ -0,0 +1,46 @@ +// Copyright (c) 2011 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 Implements some utilities for the legacy 'inline' and 'overlay' + * UI modes. + **/ + +goog.provide('google.cf.installer.frame'); + +/** + * 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 + */ +google.cf.installer.frame.setProperties = function(node, args) { + var cssText = args['cssText'] || ''; + node.style.cssText = ' ' + cssText; + + var classText = args['className'] || ''; + node.className = classText; + + var srcNode = args['node']; + if (typeof srcNode == 'string') + srcNode = document.getElementById(srcNode); + return args['id'] || (srcNode ? srcNode['id'] || '' : ''); +}; + +/** + * Determines the parent node to create the IFrame in, based on the provided + * arguments. Note that this should only be called once. + * @param {Object} args A map of user-specified properties. + */ +google.cf.installer.frame.getParentNode = function(args) { + var srcNode = args['node']; + if (typeof srcNode == 'string') + srcNode = document.getElementById(srcNode); + if (srcNode) { + var parentNode = srcNode.parentNode; + parentNode.removeChild(srcNode); + return parentNode; + } + return document.body; +};
\ No newline at end of file diff --git a/chrome_frame/cfinstall/src/stub/inlinedelegate.js b/chrome_frame/cfinstall/src/stub/inlinedelegate.js new file mode 100644 index 0000000..2489d60 --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/inlinedelegate.js @@ -0,0 +1,87 @@ +// Copyright (c) 2011 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 Implements a compatibility layer for older versions of + * CFInstall.js . + **/ + +goog.provide('google.cf.installer.InlineDelegate'); + +goog.require('goog.style'); + +goog.require('google.cf.installer.InteractionDelegate'); +goog.require('google.cf.installer.frame'); + +/** + * Adds an unadorned iframe into the page, taking arguments to customize it. + * @param {Object} args A map of user-specified properties to set + * @constructor + * @implements {google.cf.installer.InteractionDelegate} + */ +google.cf.installer.InlineDelegate = function(args) { + this.args_ = args; + this.args_.className = 'chromeFrameInstallDefaultStyle ' + + (this.args_.className || ''); +}; + +/** + * Indicates whether the overlay CSS has already been injected. + * @type {boolean} + * @private + */ +google.cf.installer.InlineDelegate.styleInjected_ = false; + +/** + * Generates the CSS for the overlay. + * @private + */ +google.cf.installer.InlineDelegate.injectCss_ = function() { + if (google.cf.installer.InlineDelegate.styleInjected_) + return; + + goog.style.installStyles('.chromeFrameInstallDefaultStyle {' + + 'width: 800px;' + + 'height: 600px;' + + 'position: absolute;' + + 'left: 50%;' + + 'top: 50%;' + + 'margin-left: -400px;' + + 'margin-top: -300px;' + + '}'); + google.cf.installer.InlineDelegate.styleInjected_ = true; +}; + +/** + * @inheritDoc + */ +google.cf.installer.InlineDelegate.prototype.getIFrameContainer = function() { + // TODO(user): This will append to the end of the container, whereas + // prior behaviour was beginning... + google.cf.installer.InlineDelegate.injectCss_(); + return google.cf.installer.frame.getParentNode(this.args_); +}; + +/** + * @inheritDoc + */ +google.cf.installer.InlineDelegate.prototype.customizeIFrame = + function(iframe) { + google.cf.installer.frame.setProperties(iframe, this.args_); +}; + +/** + * @inheritDoc + */ +google.cf.installer.InlineDelegate.prototype.show = function() { + // TODO(user): Should start it out hidden and reveal/resize here. +}; + +/** + * @inheritDoc + */ +google.cf.installer.InlineDelegate.prototype.reset = + function() { + // TODO(user): Should hide it here. +}; diff --git a/chrome_frame/cfinstall/src/stub/installer.js b/chrome_frame/cfinstall/src/stub/installer.js new file mode 100644 index 0000000..5416ade --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/installer.js @@ -0,0 +1,43 @@ +// Copyright (c) 2011 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 + **/ + +goog.provide('google.cf.installer.Installer'); + +goog.require('google.cf.ChromeFrame'); +goog.require('google.cf.installer.Prompt'); + +/** + * @constructor + */ +google.cf.installer.Installer = function(prompt, chromeFrame) { + this.prompt_ = prompt; + this.chromeFrame_ = chromeFrame; +}; + +google.cf.installer.Installer.prototype.require = + function(opt_onInstall, opt_onFailure) { + if (this.chromeFrame_.isActiveRenderer()) + return; + + if (!this.chromeFrame_.isPlatformSupported()) { + if (opt_onFailure) + opt_onFailure(); + return; + } + + var successHandler = opt_onInstall || function() { + window.location.assign(window.location.href); + }; + + if (this.chromeFrame_.activate()) { + successHandler(); + return; + } + + this.prompt_.open(successHandler, opt_onFailure); +}; diff --git a/chrome_frame/cfinstall/src/stub/overlaydelegate.js b/chrome_frame/cfinstall/src/stub/overlaydelegate.js new file mode 100644 index 0000000..bb87b6f --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/overlaydelegate.js @@ -0,0 +1,156 @@ +// Copyright (c) 2011 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 Implements a compatibility layer for older versions of + * CFInstall.js . + **/ + +goog.provide('google.cf.installer.OverlayDelegate'); + +goog.require('google.cf.installer.InteractionDelegate'); +goog.require('google.cf.installer.frame'); + +/** + * Constructs an InteractionDelegate compatible with previous versions of + * CFInstall.js . + * @constructor + * @implements {google.cf.installer.InteractionDelegate} + */ +google.cf.installer.OverlayDelegate = function(args) { + this.args_ = args; +}; + +/** + * Indicates whether the overlay CSS has already been injected. + * @type {boolean} + * @private + */ +google.cf.installer.OverlayDelegate.styleInjected_ = false; + +/** + * Generates the CSS for the overlay. + * @private + */ +google.cf.installer.OverlayDelegate.injectCss_ = function() { + if (google.cf.installer.OverlayDelegate.styleInjected_) + return; + goog.style.installStyles('.chromeFrameOverlayContent {' + + 'position: absolute;' + + 'margin-left: -400px;' + + 'margin-top: -300px;' + + 'left: 50%;' + + 'top: 50%;' + + 'border: 1px solid #93B4D9;' + + 'background-color: white;' + + 'z-index: 2001;' + + '}' + + '.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);' + + 'z-index: 2000;' + + '}'); + google.cf.installer.OverlayDelegate.styleInjected_ = true; +}; + +/** + * Generates the HTML for the overlay. + * @private + */ +google.cf.installer.OverlayDelegate.injectHtml_ = function() { + google.cf.installer.OverlayDelegate.injectCss_(); + if (document.getElementById('chromeFrameOverlayContent')) { + return; // Was previously created. Bail. + } + + var n = document.createElement('span'); + n.innerHTML = '<div class="chromeFrameOverlayUnderlay"></div>' + + '<table class="chromeFrameOverlayContent"' + + 'id="chromeFrameOverlayContent"' + + 'cellpadding="0" cellspacing="0">' + + '<tr class="chromeFrameOverlayCloseBar">' + + '<td>' + + // TODO(user): i18n + '<button id="chromeFrameCloseButton">close</button>' + + '</td>' + + '</tr>' + + '<tr>' + + '<td id="chromeFrameIframeHolder"></td>' + + '</tr>' + + '</table>'; + + var b = document.body; + // Insert underlay nodes into the document in the right order. + while (n.firstChild) { + b.insertBefore(n.lastChild, b.firstChild); + } +}; + +/** + * @inheritDoc + */ +google.cf.installer.OverlayDelegate.prototype.getIFrameContainer = + function() { + google.cf.installer.OverlayDelegate.injectHtml_(); + document.getElementById('chromeFrameCloseButton').onclick = + goog.bind(this.reset, this); + return /** @type {!HTMLElement} */( + document.getElementById('chromeFrameIframeHolder')); +}; + +/** + * @inheritDoc + */ +google.cf.installer.OverlayDelegate.prototype.customizeIFrame = + function(iframe) { + google.cf.installer.frame.setProperties(iframe, this.args_); +}; + +/** + * @inheritDoc + */ +google.cf.installer.OverlayDelegate.prototype.show = function() { + // Should start it out hidden and reveal/resize here. +}; + +/** + * @inheritDoc + */ +google.cf.installer.OverlayDelegate.prototype.reset = function() { + // IE has a limit to the # of <style> tags allowed, so we avoid + // tempting the fates. + if (google.cf.installer.OverlayDelegate.hideInjected_) + return; + + goog.style.installStyles( + '.chromeFrameOverlayContent { display: none; } ' + + '.chromeFrameOverlayUnderlay { display: none; }'); + document.getElementById('chromeFrameIframeHolder').removeChild( + document.getElementById('chromeFrameIframeHolder').firstChild); + + document.getElementById('chromeFrameCloseButton').onclick = null; + +// TODO(user): put this in somewhere. +// // Hide the dialog for a year (or until cookies are deleted). +// var age = 365 * 24 * 60 * 60 * 1000; +// document.cookie = "disableGCFCheck=1;path=/;max-age="+age; + google.cf.installer.OverlayDelegate.hideInjected_ = true; +}; diff --git a/chrome_frame/cfinstall/src/stub/prompt.js b/chrome_frame/cfinstall/src/stub/prompt.js new file mode 100644 index 0000000..bf5ccee --- /dev/null +++ b/chrome_frame/cfinstall/src/stub/prompt.js @@ -0,0 +1,210 @@ +// Copyright (c) 2011 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 Implements an in-site integration of the Chrome Frame + * installation flow by loading its implementation on demand. + **/ + +goog.provide('google.cf.installer.Prompt'); + +goog.require('google.cf.installer.InteractionDelegate'); + +/** + * Constructs a prompt flow that loads its implementation from an external + * Javascript file. + * @constructor + * @param {Window=} opt_windowInstance The window in which to load the external + * script. Defaults to the global window object. + */ +google.cf.installer.Prompt = function(opt_windowInstance) { + this.window_ = opt_windowInstance || window; +}; + +/** + * An optional adapter to customize the display of the installation flow. + * @type {!google.cf.installer.InteractionDelegate|undefined} + * @private + */ +google.cf.installer.Prompt.prototype.customInteractionDelegate_ = undefined; + +/** + * An optional URL to a resource in the same domain as the calling site that + * will be used to transport installation results back to the client. + */ +google.cf.installer.Prompt.prototype. + manuallySpecifiedSameDomainResourceUri_ = undefined; + +/** + * Customizes the display of the prompt via the given adapter. + * @param {!google.cf.installer.InteractionDelegate} interactionDelegate The + * adapter. + */ +google.cf.installer.Prompt.prototype.setInteractionDelegate = + function(interactionDelegate) { + this.customInteractionDelegate_ = interactionDelegate; +}; + +/** + * Specifies a resource in the same domain as the calling site that will be used + * to carry installation results across domain boundaries. + * @param {string} uri The resource URI to use. + */ +google.cf.installer.Prompt.prototype.setSameDomainResourceUri = function(uri) { + this.manuallySpecifiedSameDomainResourceUri_ = uri; +}; + +/** + * Holds the loaded installation flow execution method. See + * CrossDomainInstall.execute (crossdomaininstall.js). + * @type {?function(function(), function()=, string=, + * google.cf.installer.InteractionDelegate=, string=)} + * @private + **/ +google.cf.installer.Prompt.prototype.installProc_ = null; + +/** + * @define {string} Defines the default implementation location. + **/ +google.cf.installer.Prompt.DEFAULT_IMPLEMENTATION_URL = + '//ajax.googleapis.com/ajax/libs/chrome-frame/2/CFInstall.impl.min.js'; + +/** + * Defines the URL from which the full prompting logic will be retrieved. + * @type {string} + * @private + **/ +google.cf.installer.Prompt.prototype.implementationUrl_ = + google.cf.installer.Prompt.DEFAULT_IMPLEMENTATION_URL; + +/** + * Defines a custom URL for the Chrome Frame download page. + * @type {string|undefined} + * @private + */ +google.cf.installer.Prompt.prototype.downloadPageUrl_ = undefined; + +/** + * Overrides the default URL for loading the implementation. + * @param {string} url The custom URL. + */ +google.cf.installer.Prompt.prototype.setImplementationUrl = function(url) { + this.implementationUrl_ = url; +}; + +/** + * Overrides the default URL for the download page. + * @param {string} url The custom URL. + */ +google.cf.installer.Prompt.prototype.setDownloadPageUrl = function(url) { + this.downloadPageUrl_ = url; +}; + +/** + * Initiates loading of the full implementation if not already initiated. + * @param {function()=} opt_loadCompleteHandler A callback that will be notified + * when the loading of the script has completed, possibly unsuccessfully. + **/ +google.cf.installer.Prompt.prototype.loadInstallProc_ = + function(opt_loadCompleteHandler) { + var scriptParent = this.window_.document.getElementsByTagName('head')[0] || + this.window_.document.documentElement; + var scriptEl = this.window_.document.createElement('script'); + scriptEl.src = this.implementationUrl_; + scriptEl.type = 'text/javascript'; + + if (opt_loadCompleteHandler) { + var loadHandler = goog.bind(function() { + scriptEl.onreadystatechange = null; + scriptEl.onerror = null; + scriptEl.onload = null; + loadHandler = function(){}; + opt_loadCompleteHandler(); + }, this); + + scriptEl.onload = loadHandler; + scriptEl.onerror = loadHandler; + scriptEl.onreadystatechange = function() { + if (scriptEl.readyState == 'loaded') + loadHandler(); + }; + } + + scriptParent.appendChild(scriptEl); +}; + +/** + * Invokes the installation procedure with our configured parameters and + * the provided callbacks. + * @param {function()} successHandler The method to invoke upon installation + * success. + * @param {function()} opt_failureHandler The method to invoke upon installation + * failure. + */ +google.cf.installer.Prompt.prototype.invokeProc_ = + function(successHandler, opt_failureHandler) { + this.installProc_(successHandler, + opt_failureHandler, + this.downloadPageUrl_, + this.customInteractionDelegate_, + this.manuallySpecifiedSameDomainResourceUri_); +} + +/** + * Receives a handle to the flow implementation method and invokes it. + * @param {function(function(), function()=, string=, + * google.cf.installer.InteractionDelegate=, string=)} + * installProc The install execution method. See + * CrossDomainInstall.execute(). + * @param {function()} successHandler The method to invoke upon installation + * success. + * @param {function()} opt_failureHandler The method to invoke upon installation + * failure. + */ +google.cf.installer.Prompt.prototype.onProcLoaded_ = + function(installProc, successHandler, opt_failureHandler) { + this.window_['CF_google_cf_xd_install_stub'] = undefined; + this.installProc_ = installProc; + this.invokeProc_(successHandler, opt_failureHandler); +}; + +/** + * Loads and executes the in-line Google Chrome Frame installation flow. + * Will typically execute asynchronously (as the flow behaviour is not yet + * loaded). + * + * @param {function()} successHandler A function to invoke once Google + * Chrome Frame is successfully installed. Overrides the default + * behaviour, which is to reload the current page. + * @param {function()=} opt_failureHandler A function to invoke if the + * installation fails. The default behaviour is to do nothing. + */ +google.cf.installer.Prompt.prototype.open = function(successHandler, + opt_failureHandler) { + if (this.installProc_) { + this.invokeProc_(successHandler, opt_failureHandler); + return; + } + + if (this.window_['CF_google_cf_xd_install_stub']) { + if (opt_failureHandler) + opt_failureHandler(); + return; + } + + this.window_['CF_google_cf_xd_install_stub'] = goog.bind( + function(installProc) { + this.onProcLoaded_(installProc, successHandler, opt_failureHandler); + }, this); + + var loadCompleteHandler = undefined; + if (opt_failureHandler) { + loadCompleteHandler = goog.bind(function() { + if (!this.installProc_) + opt_failureHandler(); + }, this); + } + + this.loadInstallProc_(loadCompleteHandler); +}; |