blob: 6b2b97e915e261359e1702b9bf3c98999130c374 [file] [log] [blame]
/*
* Copyright 2011 Google Inc.
*
* 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.
*/
package com.google.gwt.core.client.impl;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.core.client.impl.AsyncFragmentLoader.HttpDownloadFailure;
/**
* A download strategy that uses a JSONP style script tag mechanism. and is
* therefore cross site compatible. Note that if this strategy is used, the
* deferred fragments must be wrapped in a callback called runAsyncCallbackX()
* where X is the fragment number.
*
* This is the default strategy for the CrossSiteIframeLinker.
*
* TODO(unnurg): Try to use the ScriptInjector here
*/
public class ScriptTagLoadingStrategy extends LoadingStrategyBase {
/**
* Uses a JSONP style script tag mechanism to download the code.
*/
protected static class ScriptTagDownloadStrategy implements DownloadStrategy {
@Override
public void tryDownload(final RequestData request) {
int fragment = request.getFragment();
JavaScriptObject scriptTag = createScriptTag(request.getUrl());
setOnSuccess(fragment, onSuccess(fragment, scriptTag, request));
setOnFailure(scriptTag, onFailure(fragment, scriptTag, request));
installScriptTag(scriptTag);
}
}
protected static void callOnLoadError(RequestData request) {
request.onLoadError(new HttpDownloadFailure(request.getUrl(), 404,
"Script Tag Failure - no status available"), true);
}
private static native boolean clearCallbacksAndRemoveTag(
int fragment, JavaScriptObject scriptTag) /*-{
if (scriptTag.parentNode == null) {
// onSuccess or onFailure must have already been called.
return false;
}
var head = document.getElementsByTagName('head').item(0);
@com.google.gwt.core.client.impl.ScriptTagLoadingStrategy::clearOnSuccess(I)(fragment);
@com.google.gwt.core.client.impl.ScriptTagLoadingStrategy::clearOnFailure(Lcom/google/gwt/core/client/JavaScriptObject;)(
scriptTag);
head.removeChild(scriptTag);
return true;
}-*/;
private static native void clearOnFailure(JavaScriptObject scriptTag) /*-{
scriptTag.onerror = scriptTag.onload = scriptTag.onreadystatechange = function(){};
}-*/;
private static native void clearOnSuccess(int fragment) /*-{
delete __gwtModuleFunction['runAsyncCallback' + fragment];
}-*/;
private static native JavaScriptObject createScriptTag(String url) /*-{
var head = document.getElementsByTagName('head').item(0);
var scriptTag = document.createElement('script');
scriptTag.src = url;
return scriptTag;
}-*/;
private static native void installScriptTag(JavaScriptObject scriptTag) /*-{
var head = document.getElementsByTagName('head').item(0);
head.appendChild(scriptTag);
}-*/;
private static native JavaScriptObject onFailure(
int fragment, JavaScriptObject scriptTag, RequestData request) /*-{
return function() {
if (@com.google.gwt.core.client.impl.ScriptTagLoadingStrategy::clearCallbacksAndRemoveTag(ILcom/google/gwt/core/client/JavaScriptObject;)(
fragment, scriptTag)) {
@com.google.gwt.core.client.impl.ScriptTagLoadingStrategy::callOnLoadError(Lcom/google/gwt/core/client/impl/LoadingStrategyBase$RequestData;)(
request)
}
}
}-*/;
private static native JavaScriptObject onSuccess(int fragment,
JavaScriptObject scriptTag, RequestData request) /*-{
return function(code, instance) {
if (@com.google.gwt.core.client.impl.ScriptTagLoadingStrategy::clearCallbacksAndRemoveTag(ILcom/google/gwt/core/client/JavaScriptObject;)(
fragment, scriptTag)) {
request.@com.google.gwt.core.client.impl.LoadingStrategyBase.RequestData::tryInstall(Ljava/lang/String;)(
code);
}
}
}-*/;
private static native void setOnFailure(JavaScriptObject script,
JavaScriptObject callback) /*-{
script.onerror = function() {
callback();
}
script.onload = function() {
callback();
}
script.onreadystatechange = function () {
if (script.readyState == 'loaded' || script.readyState == 'complete') {
script.onreadystatechange = function () { }
callback();
}
}
}-*/;
private static native void setOnSuccess(int fragment, JavaScriptObject callback) /*-{
__gwtModuleFunction['runAsyncCallback'+fragment] = callback;
}-*/;
public ScriptTagLoadingStrategy() {
super(new ScriptTagDownloadStrategy());
}
}