Adding float-no-zero branch hosted build
This commit is contained in:
@@ -0,0 +1,394 @@
|
||||
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS-IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
/**
|
||||
* @fileoverview Contains the iframe relay tranport.
|
||||
*/
|
||||
|
||||
|
||||
goog.provide('goog.net.xpc.IframeRelayTransport');
|
||||
|
||||
goog.require('goog.dom');
|
||||
goog.require('goog.events');
|
||||
goog.require('goog.net.xpc');
|
||||
goog.require('goog.net.xpc.Transport');
|
||||
goog.require('goog.userAgent');
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Iframe relay transport. Creates hidden iframes containing a document
|
||||
* from the peer's origin. Data is transferred in the fragment identifier.
|
||||
* Therefore the document loaded in the iframes can be served from the
|
||||
* browser's cache.
|
||||
*
|
||||
* @param {goog.net.xpc.CrossPageChannel} channel The channel this
|
||||
* transport belongs to.
|
||||
* @param {goog.dom.DomHelper=} opt_domHelper The dom helper to use for finding
|
||||
* the correct window.
|
||||
* @constructor
|
||||
* @extends {goog.net.xpc.Transport}
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport = function(channel, opt_domHelper) {
|
||||
goog.base(this, opt_domHelper);
|
||||
|
||||
/**
|
||||
* The channel this transport belongs to.
|
||||
* @type {goog.net.xpc.CrossPageChannel}
|
||||
* @private
|
||||
*/
|
||||
this.channel_ = channel;
|
||||
|
||||
/**
|
||||
* The URI used to relay data to the peer.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.peerRelayUri_ =
|
||||
this.channel_.getConfig()[goog.net.xpc.CfgFields.PEER_RELAY_URI];
|
||||
|
||||
/**
|
||||
* The id of the iframe the peer page lives in.
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
this.peerIframeId_ =
|
||||
this.channel_.getConfig()[goog.net.xpc.CfgFields.IFRAME_ID];
|
||||
|
||||
if (goog.userAgent.WEBKIT) {
|
||||
goog.net.xpc.IframeRelayTransport.startCleanupTimer_();
|
||||
}
|
||||
};
|
||||
goog.inherits(goog.net.xpc.IframeRelayTransport, goog.net.xpc.Transport);
|
||||
|
||||
|
||||
if (goog.userAgent.WEBKIT) {
|
||||
/**
|
||||
* Array to keep references to the relay-iframes. Used only if
|
||||
* there is no way to detect when the iframes are loaded. In that
|
||||
* case the relay-iframes are removed after a timeout.
|
||||
* @type {Array.<Object>}
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.iframeRefs_ = [];
|
||||
|
||||
|
||||
/**
|
||||
* Interval at which iframes are destroyed.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.CLEANUP_INTERVAL_ = 1000;
|
||||
|
||||
|
||||
/**
|
||||
* Time after which a relay-iframe is destroyed.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.IFRAME_MAX_AGE_ = 3000;
|
||||
|
||||
|
||||
/**
|
||||
* The cleanup timer id.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.cleanupTimer_ = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Starts the cleanup timer.
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.startCleanupTimer_ = function() {
|
||||
if (!goog.net.xpc.IframeRelayTransport.cleanupTimer_) {
|
||||
goog.net.xpc.IframeRelayTransport.cleanupTimer_ = window.setTimeout(
|
||||
function() { goog.net.xpc.IframeRelayTransport.cleanup_(); },
|
||||
goog.net.xpc.IframeRelayTransport.CLEANUP_INTERVAL_);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Remove all relay-iframes which are older than the maximal age.
|
||||
* @param {number=} opt_maxAge The maximal age in milliseconds.
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.cleanup_ = function(opt_maxAge) {
|
||||
var now = goog.now();
|
||||
var maxAge =
|
||||
opt_maxAge || goog.net.xpc.IframeRelayTransport.IFRAME_MAX_AGE_;
|
||||
|
||||
while (goog.net.xpc.IframeRelayTransport.iframeRefs_.length &&
|
||||
now - goog.net.xpc.IframeRelayTransport.iframeRefs_[0].timestamp >=
|
||||
maxAge) {
|
||||
var ifr = goog.net.xpc.IframeRelayTransport.iframeRefs_.
|
||||
shift().iframeElement;
|
||||
goog.dom.removeNode(ifr);
|
||||
goog.log.log(goog.net.xpc.logger, goog.log.Level.FINEST,
|
||||
'iframe removed');
|
||||
}
|
||||
|
||||
goog.net.xpc.IframeRelayTransport.cleanupTimer_ = window.setTimeout(
|
||||
goog.net.xpc.IframeRelayTransport.cleanupCb_,
|
||||
goog.net.xpc.IframeRelayTransport.CLEANUP_INTERVAL_);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Function which wraps cleanup_().
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.cleanupCb_ = function() {
|
||||
goog.net.xpc.IframeRelayTransport.cleanup_();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Maximum sendable size of a payload via a single iframe in IE.
|
||||
* @type {number}
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.IE_PAYLOAD_MAX_SIZE_ = 1800;
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {{fragments: !Array.<string>, received: number, expected: number}}
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.FragmentInfo;
|
||||
|
||||
|
||||
/**
|
||||
* Used to track incoming payload fragments. The implementation can process
|
||||
* incoming fragments from several channels at a time, even if data is
|
||||
* out-of-order or interleaved.
|
||||
*
|
||||
* @type {!Object.<string, !goog.net.xpc.IframeRelayTransport.FragmentInfo>}
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.fragmentMap_ = {};
|
||||
|
||||
|
||||
/**
|
||||
* The transport type.
|
||||
* @type {number}
|
||||
* @override
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.prototype.transportType =
|
||||
goog.net.xpc.TransportTypes.IFRAME_RELAY;
|
||||
|
||||
|
||||
/**
|
||||
* Connects this transport.
|
||||
* @override
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.prototype.connect = function() {
|
||||
if (!this.getWindow()['xpcRelay']) {
|
||||
this.getWindow()['xpcRelay'] =
|
||||
goog.net.xpc.IframeRelayTransport.receiveMessage_;
|
||||
}
|
||||
|
||||
this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Processes an incoming message.
|
||||
*
|
||||
* @param {string} channelName The name of the channel.
|
||||
* @param {string} frame The raw frame content.
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.receiveMessage_ =
|
||||
function(channelName, frame) {
|
||||
var pos = frame.indexOf(':');
|
||||
var header = frame.substr(0, pos);
|
||||
var payload = frame.substr(pos + 1);
|
||||
|
||||
if (!goog.userAgent.IE || (pos = header.indexOf('|')) == -1) {
|
||||
// First, the easy case.
|
||||
var service = header;
|
||||
} else {
|
||||
// There was a fragment id in the header, so this is a message
|
||||
// fragment, not a whole message.
|
||||
var service = header.substr(0, pos);
|
||||
var fragmentIdStr = header.substr(pos + 1);
|
||||
|
||||
// Separate the message id string and the fragment number. Note that
|
||||
// there may be a single leading + in the argument to parseInt, but
|
||||
// this is harmless.
|
||||
pos = fragmentIdStr.indexOf('+');
|
||||
var messageIdStr = fragmentIdStr.substr(0, pos);
|
||||
var fragmentNum = parseInt(fragmentIdStr.substr(pos + 1), 10);
|
||||
var fragmentInfo =
|
||||
goog.net.xpc.IframeRelayTransport.fragmentMap_[messageIdStr];
|
||||
if (!fragmentInfo) {
|
||||
fragmentInfo =
|
||||
goog.net.xpc.IframeRelayTransport.fragmentMap_[messageIdStr] =
|
||||
{fragments: [], received: 0, expected: 0};
|
||||
}
|
||||
|
||||
if (goog.string.contains(fragmentIdStr, '++')) {
|
||||
fragmentInfo.expected = fragmentNum + 1;
|
||||
}
|
||||
fragmentInfo.fragments[fragmentNum] = payload;
|
||||
fragmentInfo.received++;
|
||||
|
||||
if (fragmentInfo.received != fragmentInfo.expected) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We've received all outstanding fragments; combine what we've received
|
||||
// into payload and fall out to the call to xpcDeliver.
|
||||
payload = fragmentInfo.fragments.join('');
|
||||
delete goog.net.xpc.IframeRelayTransport.fragmentMap_[messageIdStr];
|
||||
}
|
||||
|
||||
goog.net.xpc.channels[channelName].
|
||||
xpcDeliver(service, decodeURIComponent(payload));
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handles transport service messages (internal signalling).
|
||||
* @param {string} payload The message content.
|
||||
* @override
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.prototype.transportServiceHandler =
|
||||
function(payload) {
|
||||
if (payload == goog.net.xpc.SETUP) {
|
||||
// TODO(user) Safari swallows the SETUP_ACK from the iframe to the
|
||||
// container after hitting reload.
|
||||
this.send(goog.net.xpc.TRANSPORT_SERVICE_, goog.net.xpc.SETUP_ACK_);
|
||||
this.channel_.notifyConnected();
|
||||
}
|
||||
else if (payload == goog.net.xpc.SETUP_ACK_) {
|
||||
this.channel_.notifyConnected();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sends a message.
|
||||
*
|
||||
* @param {string} service Name of service this the message has to be delivered.
|
||||
* @param {string} payload The message content.
|
||||
* @override
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.prototype.send = function(service, payload) {
|
||||
// If we're on IE and the post-encoding payload is large, split it
|
||||
// into multiple payloads and send each one separately. Otherwise,
|
||||
// just send the whole thing.
|
||||
var encodedPayload = encodeURIComponent(payload);
|
||||
var encodedLen = encodedPayload.length;
|
||||
var maxSize = goog.net.xpc.IframeRelayTransport.IE_PAYLOAD_MAX_SIZE_;
|
||||
|
||||
if (goog.userAgent.IE && encodedLen > maxSize) {
|
||||
// A probabilistically-unique string used to link together all fragments
|
||||
// in this message.
|
||||
var messageIdStr = goog.string.getRandomString();
|
||||
|
||||
for (var startIndex = 0, fragmentNum = 0; startIndex < encodedLen;
|
||||
fragmentNum++) {
|
||||
var payloadFragment = encodedPayload.substr(startIndex, maxSize);
|
||||
startIndex += maxSize;
|
||||
var fragmentIdStr =
|
||||
messageIdStr + (startIndex >= encodedLen ? '++' : '+') + fragmentNum;
|
||||
this.send_(service, payloadFragment, fragmentIdStr);
|
||||
}
|
||||
} else {
|
||||
this.send_(service, encodedPayload);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sends an encoded message or message fragment.
|
||||
* @param {string} service Name of service this the message has to be delivered.
|
||||
* @param {string} encodedPayload The message content, URI encoded.
|
||||
* @param {string=} opt_fragmentIdStr If sending a fragment, a string that
|
||||
* identifies the fragment.
|
||||
* @private
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.prototype.send_ =
|
||||
function(service, encodedPayload, opt_fragmentIdStr) {
|
||||
// IE requires that we create the onload attribute inline, otherwise the
|
||||
// handler is not triggered
|
||||
if (goog.userAgent.IE) {
|
||||
var div = this.getWindow().document.createElement('div');
|
||||
div.innerHTML = '<iframe onload="this.xpcOnload()"></iframe>';
|
||||
var ifr = div.childNodes[0];
|
||||
div = null;
|
||||
ifr['xpcOnload'] = goog.net.xpc.IframeRelayTransport.iframeLoadHandler_;
|
||||
} else {
|
||||
var ifr = this.getWindow().document.createElement('iframe');
|
||||
|
||||
if (goog.userAgent.WEBKIT) {
|
||||
// safari doesn't fire load-events on iframes.
|
||||
// keep a reference and remove after a timeout.
|
||||
goog.net.xpc.IframeRelayTransport.iframeRefs_.push({
|
||||
timestamp: goog.now(),
|
||||
iframeElement: ifr
|
||||
});
|
||||
} else {
|
||||
goog.events.listen(ifr, 'load',
|
||||
goog.net.xpc.IframeRelayTransport.iframeLoadHandler_);
|
||||
}
|
||||
}
|
||||
|
||||
var style = ifr.style;
|
||||
style.visibility = 'hidden';
|
||||
style.width = ifr.style.height = '0px';
|
||||
style.position = 'absolute';
|
||||
|
||||
var url = this.peerRelayUri_;
|
||||
url += '#' + this.channel_.name;
|
||||
if (this.peerIframeId_) {
|
||||
url += ',' + this.peerIframeId_;
|
||||
}
|
||||
url += '|' + service;
|
||||
if (opt_fragmentIdStr) {
|
||||
url += '|' + opt_fragmentIdStr;
|
||||
}
|
||||
url += ':' + encodedPayload;
|
||||
|
||||
ifr.src = url;
|
||||
|
||||
this.getWindow().document.body.appendChild(ifr);
|
||||
|
||||
goog.log.log(goog.net.xpc.logger, goog.log.Level.FINEST, 'msg sent: ' + url);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* The iframe load handler. Gets called as method on the iframe element.
|
||||
* @private
|
||||
* @this Element
|
||||
*/
|
||||
goog.net.xpc.IframeRelayTransport.iframeLoadHandler_ = function() {
|
||||
goog.log.log(goog.net.xpc.logger, goog.log.Level.FINEST, 'iframe-load');
|
||||
goog.dom.removeNode(this);
|
||||
this.xpcOnload = null;
|
||||
};
|
||||
|
||||
|
||||
/** @override */
|
||||
goog.net.xpc.IframeRelayTransport.prototype.disposeInternal = function() {
|
||||
goog.base(this, 'disposeInternal');
|
||||
if (goog.userAgent.WEBKIT) {
|
||||
goog.net.xpc.IframeRelayTransport.cleanup_(0);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user