blob: d0d9104472043f15d3bda7739eaf43926528110e [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.user.rebind;
import com.google.gwt.core.ext.TreeLogger;
import com.google.gwt.core.ext.linker.ConfigurationProperty;
import com.google.gwt.core.ext.linker.PropertyProviderGenerator;
import java.util.Arrays;
import java.util.List;
import java.util.SortedSet;
/**
* Generator which writes out the JavaScript for determining the value of the
* <code>user.agent</code> selection property.
*/
public class UserAgentPropertyGenerator implements PropertyProviderGenerator {
/**
* List of valid user agent selection property values, which helps ensure that
* UserAgent.gwt.xml stays in sync with the
* {@link #writeUserAgentPropertyJavaScript(SourceWriter)} method body of this
* class.
*/
private static final List<String> VALID_VALUES = Arrays.asList(new String[]{
"ie6", "ie8", "gecko1_8", "safari", "opera", "ie9"});
/**
* List of predicates to identify user agent.
* The order of evaluation is from top to bottom, i.e., the first matching
* predicate will have the associated ua token returned.
* ua is defined in an outer scope and is therefore visible in
* the predicate javascript fragment.
*/
private static UserAgentPropertyGeneratorPredicate[] predicates =
new UserAgentPropertyGeneratorPredicate[] {
// opera
new UserAgentPropertyGeneratorPredicate("opera")
.getPredicateBlock()
.println("return (ua.indexOf('opera') != -1);")
.returns("'opera'"),
// webkit family (chrome, safari and chromeframe).
new UserAgentPropertyGeneratorPredicate("safari")
.getPredicateBlock()
.println("return (")
.println("(ua.indexOf('webkit') != -1)")
.println("||")
.println("(function() {")
.println("if (ua.indexOf('chromeframe') != -1) {")
.println("return true;")
.println("}")
.println("if (typeof window['ActiveXObject'] != 'undefined') {")
.println("try {")
.println("var obj = new ActiveXObject('ChromeTab.ChromeFrame');")
.println("if (obj) {")
.println("obj.registerBhoIfNeeded();")
.println("return true;")
.println("}")
.println("} catch(e) { }")
.println("}")
.println("return false;")
.println("})()")
.println(")")
.returns("'safari'"),
// IE9
new UserAgentPropertyGeneratorPredicate("ie9")
.getPredicateBlock()
.println("return (ua.indexOf('msie') != -1 && ($doc.documentMode >= 9));")
.returns("'ie9'"),
// IE8
new UserAgentPropertyGeneratorPredicate("ie8")
.getPredicateBlock()
.println("return (ua.indexOf('msie') != -1 && ($doc.documentMode >= 8));")
.returns("'ie8'"),
// IE6
new UserAgentPropertyGeneratorPredicate("ie6")
.getPredicateBlock()
.println("var result = /msie ([0-9]+)\\.([0-9]+)/.exec(ua);")
.println("if (result && result.length == 3)")
.indent()
.println("return (makeVersion(result) >= 6000);")
.outdent()
.returns("'ie6'"),
// gecko family
new UserAgentPropertyGeneratorPredicate("gecko1_8")
.getPredicateBlock()
.println("return (ua.indexOf('gecko') != -1);")
.returns("'gecko1_8'"),
};
/**
* Writes out the JavaScript function body for determining the value of the
* <code>user.agent</code> selection property. This method is used to create
* the selection script and by {@link UserAgentGenerator} to assert at runtime
* that the correct user agent permutation is executing. The list of
* <code>user.agent</code> values listed here should be kept in sync with
* {@link #VALID_VALUES} and <code>UserAgent.gwt.xml</code>.
*/
static void writeUserAgentPropertyJavaScript(SourceWriter body,
SortedSet<String> possibleValues) {
// write preamble
body.println("var ua = navigator.userAgent.toLowerCase();");
body.println("var makeVersion = function(result) {");
body.indent();
body.println("return (parseInt(result[1]) * 1000) + parseInt(result[2]);");
body.outdent();
body.println("};");
// write only selected user agents
for (int i = 0; i < predicates.length; i++) {
if (possibleValues.contains(predicates[i].getUserAgent())) {
body.println("if ((function() { ");
body.indent();
body.print(predicates[i].toString());
body.outdent();
body.println("})()) return " + predicates[i].getReturnValue() + ";");
}
}
// default return
body.println("return 'unknown';");
}
public String generate(TreeLogger logger, SortedSet<String> possibleValues,
String fallback, SortedSet<ConfigurationProperty> configProperties) {
for (String value : possibleValues) {
if (!VALID_VALUES.contains(value)) {
logger.log(TreeLogger.WARN, "Unrecognized "
+ UserAgentGenerator.PROPERTY_USER_AGENT + " property value '"
+ value + "', possibly due to UserAgent.gwt.xml and "
+ UserAgentPropertyGenerator.class.getName()
+ " being out of sync." + " Use <set-configuration-property name=\""
+ UserAgentGenerator.PROPERTY_USER_AGENT_RUNTIME_WARNING
+ "\" value=\"false\"/> to suppress this warning message.");
}
}
// make sure that the # of ua in VALID_VALUES
// is the same of predicates. maybe should iterate
// to make sure each one has a match.
assert predicates.length == VALID_VALUES.size();
StringSourceWriter body = new StringSourceWriter();
body.println("{");
body.indent();
writeUserAgentPropertyJavaScript(body, possibleValues);
body.outdent();
body.println("}");
return body.toString();
}
}