From 56d8f8824aafae43db1af03cb0f0f7c4f72d6fb5 Mon Sep 17 00:00:00 2001 From: "Shawn O. Pearce" Date: Wed, 14 Jul 2010 15:31:06 -0700 Subject: [PATCH] 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 --- .../gerrit/prettify/PrettyFormatter.gwt.xml | 12 +++- .../prettify/client/ClientSideFormatter.java | 51 ++++++-------- .../prettify/client/PrivateScopeImpl.java | 67 +++++++++++++++++++ .../prettify/client/PrivateScopeImplIE6.java | 46 +++++++++++++ 4 files changed, 144 insertions(+), 32 deletions(-) create mode 100644 gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImpl.java create mode 100644 gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE6.java diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml index 93ce272151..48591f8239 100644 --- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/PrettyFormatter.gwt.xml @@ -1,19 +1,27 @@ + + + + + + + + diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java index 49811f9e41..1b03c625b9 100644 --- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/ClientSideFormatter.java @@ -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); }-*/; } diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImpl.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImpl.java new file mode 100644 index 0000000000..65ee2127cc --- /dev/null +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImpl.java @@ -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. + *

+ * 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]; }-*/; +} diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE6.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE6.java new file mode 100644 index 0000000000..abb4e15812 --- /dev/null +++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/client/PrivateScopeImplIE6.java @@ -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( + '