Fix prettify private scope in IE6, IE8

On IE6 or IE8 we can't abuse an IFrame quite the same way as we
do on Mozilla, WebKit and Opera.  IE requires us to initialize the
iframe by running a script that exports the iframe window back to
the parent before we can use its eval method.

Change-Id: Ia5e01a611ed9685a5fc5341a3f8a2446f7dcb9f4
Signed-off-by: Shawn O. Pearce <sop@google.com>
This commit is contained in:
Shawn O. Pearce 2010-07-14 15:31:06 -07:00
parent 077b2c5dd0
commit 56d8f8824a
4 changed files with 144 additions and 32 deletions

View File

@ -1,19 +1,27 @@
<!--
Copyright (C) 2008 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
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,
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.
-->
<module>
<replace-with class='com.google.gerrit.prettify.client.PrivateScopeImplIE6'>
<when-type-is class='com.google.gerrit.prettify.client.PrivateScopeImpl'/>
<any>
<when-property-is name="user.agent" value="ie6" />
<when-property-is name="user.agent" value="ie8" />
</any>
</replace-with>
<inherits name='com.google.gwt.resources.Resources'/>
<inherits name='com.google.gwtexpui.safehtml.SafeHtml'/>
<source path='common' />

View File

@ -16,8 +16,8 @@ package com.google.gerrit.prettify.client;
import com.google.gerrit.prettify.common.PrettyFactory;
import com.google.gerrit.prettify.common.PrettyFormatter;
import com.google.gwt.resources.client.TextResource;
import com.google.gwt.user.client.ui.NamedFrame;
import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.user.client.ui.RootPanel;
/** Evaluates prettify using the host browser's JavaScript engine. */
@ -29,45 +29,36 @@ public class ClientSideFormatter extends PrettyFormatter {
}
};
private static final PrivateScopeImpl prettify;
static {
Resources.I.prettify_css().ensureInjected();
Resources.I.gerrit_css().ensureInjected();
createFrame();
compile(Resources.I.core());
compile(Resources.I.lang_css());
compile(Resources.I.lang_hs());
compile(Resources.I.lang_lisp());
compile(Resources.I.lang_lua());
compile(Resources.I.lang_ml());
compile(Resources.I.lang_proto());
compile(Resources.I.lang_sql());
compile(Resources.I.lang_vb());
compile(Resources.I.lang_wiki());
}
prettify = GWT.create(PrivateScopeImpl.class);
RootPanel.get().add(prettify);
private static void createFrame() {
NamedFrame frame = new NamedFrame("_prettify");
frame.setUrl("javascript:");
frame.setVisible(false);
RootPanel.get().add(frame);
prettify.compile(Resources.I.core());
prettify.compile(Resources.I.lang_css());
prettify.compile(Resources.I.lang_hs());
prettify.compile(Resources.I.lang_lisp());
prettify.compile(Resources.I.lang_lua());
prettify.compile(Resources.I.lang_ml());
prettify.compile(Resources.I.lang_proto());
prettify.compile(Resources.I.lang_sql());
prettify.compile(Resources.I.lang_vb());
prettify.compile(Resources.I.lang_wiki());
}
private static void compile(TextResource core) {
eval(core.getText());
}
private static native void eval(String js)
/*-{ $wnd._prettify.eval(js); }-*/;
@Override
protected String prettify(String html, String type) {
return go(html, type, settings.getTabSize());
return go(prettify.getContext(), html, type, settings.getTabSize());
}
private static native String go(String srcText, String srcType, int tabSize)
private static native String go(JavaScriptObject ctx, String srcText,
String srcType, int tabSize)
/*-{
$wnd._prettify.PR_TAB_WIDTH = tabSize;
return $wnd._prettify.prettyPrintOne(srcText, srcType);
ctx.PR_TAB_WIDTH = tabSize;
return ctx.prettyPrintOne(srcText, srcType);
}-*/;
}

View File

@ -0,0 +1,67 @@
// Copyright (C) 2010 The Android Open Source Project
//
// 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.gerrit.prettify.client;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.resources.client.TextResource;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.NamedFrame;
/**
* Creates a private JavaScript environment, typically inside an IFrame.
* <p>
* Instances must be created through {@code GWT.create(PrivateScopeImpl.class)}.
* A scope must remain attached to the primary document for its entire life.
* Behavior is undefined if a scope is detached and attached again later. It is
* best to attach the scope with {@code RootPanel.get().add(scope)} as soon as
* it has been created.
*/
public class PrivateScopeImpl extends Composite {
private static int scopeId;
protected final String scopeName;
public PrivateScopeImpl() {
scopeName = nextScopeName();
NamedFrame frame = new NamedFrame(scopeName);
frame.setUrl("javascript:''");
initWidget(frame);
setVisible(false);
}
public void compile(TextResource js) {
eval(js.getText());
}
public void eval(String js) {
nativeEval(getContext(), js);
}
public JavaScriptObject getContext() {
return nativeGetContext(scopeName);
}
private static String nextScopeName() {
return "_PrivateScope" + (++scopeId);
}
private static native void nativeEval(JavaScriptObject ctx, String js)
/*-{ ctx.eval(js); }-*/;
private static native JavaScriptObject nativeGetContext(String scopeName)
/*-{ return $wnd[scopeName]; }-*/;
}

View File

@ -0,0 +1,46 @@
// Copyright (C) 2010 The Android Open Source Project
//
// 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.gerrit.prettify.client;
import com.google.gwt.core.client.JavaScriptObject;
/** IE6 requires us to initialize the document before we can use it. */
public class PrivateScopeImplIE6 extends PrivateScopeImpl {
private JavaScriptObject context;
@Override
protected void onAttach() {
super.onAttach();
context = nativeInitContext(scopeName);
}
@Override
public JavaScriptObject getContext() {
return context;
}
private static native JavaScriptObject nativeInitContext(String scopeName)
/*-{
var fe = $wnd[scopeName];
fe.document.write(
'<script>'
+ 'parent._PrivateScopeNewChild = this;'
+ '</' + 'script>'
);
var ctx = $wnd._PrivateScopeNewChild;
$wnd._PrivateScopeNewChild = undefined;
return ctx;
}-*/;
}