// Copyright (C) 2013 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.client.api; import com.google.gwt.core.client.JavaScriptObject; import com.google.gwt.dom.client.Document; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Node; import com.google.gwt.dom.client.StyleInjector; import com.google.gwt.user.client.DOM; import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder; final class HtmlTemplate { static native void init() /*-{ var ElementSet = function(r,e) { this.root = r; this.elements = e; }; ElementSet.prototype = { clear: function() { this.root = null; this.elements = null; }, }; $wnd.Gerrit.css = @com.google.gerrit.client.api.HtmlTemplate::css(Ljava/lang/String;); $wnd.Gerrit.html = function(h,r,w) { var i = {}; if (r) { h = h.replace( /\sid=['"]\{([a-z_][a-z0-9_]*)\}['"]|\{([a-z0-9._-]+)\}/gi, function(m,a,b) { if (a) return @com.google.gerrit.client.api.HtmlTemplate::id( Lcom/google/gerrit/client/api/HtmlTemplate$IdMap; Ljava/lang/String;) (i,a); return @com.google.gerrit.client.api.HtmlTemplate::html( Lcom/google/gerrit/client/api/HtmlTemplate$ReplacementMap; Ljava/lang/String;) (r,b); }); } var e = @com.google.gerrit.client.api.HtmlTemplate::parseHtml( Ljava/lang/String;Lcom/google/gerrit/client/api/HtmlTemplate$IdMap; Lcom/google/gerrit/client/api/HtmlTemplate$ReplacementMap; Z) (h,i,r,!!w); return w ? new ElementSet(e,i) : e; }; }-*/; private static final String css(String css) { String name = DOM.createUniqueId(); StyleInjector.inject("." + name + "{" + css + "}"); return name; } private static final String id(IdMap idMap, String key) { String id = DOM.createUniqueId(); idMap.put(id, key); return " id='" + id + "'"; } private static final String html(ReplacementMap opts, String id) { int d = id.indexOf('.'); if (0 < d) { String name = id.substring(0, d); String rest = id.substring(d + 1); return html(opts.map(name), rest); } return new SafeHtmlBuilder().append(opts.str(id)).asString(); } private static final Node parseHtml( String html, IdMap ids, ReplacementMap opts, boolean wantElements) { Element div = Document.get().createDivElement(); div.setInnerHTML(html); if (!ids.isEmpty()) { attachHandlers(div, ids, opts, wantElements); } if (div.getChildCount() == 1) { return div.getFirstChild(); } return div; } private static void attachHandlers( Element e, IdMap ids, ReplacementMap opts, boolean wantElements) { if (e.getId() != null) { String key = ids.get(e.getId()); if (key != null) { ids.remove(e.getId()); if (wantElements) { ids.put(key, e); } e.setId(null); opts.map(key).attachHandlers(e); } } for (Element c = e.getFirstChildElement(); c != null;) { attachHandlers(c, ids, opts, wantElements); c = c.getNextSiblingElement(); } } private static class ReplacementMap extends JavaScriptObject { final native ReplacementMap map(String n) /*-{ return this[n] }-*/; final native String str(String n) /*-{ return ''+this[n] }-*/; final native void attachHandlers(Element e) /*-{ for (var k in this) { var f = this[k]; if (k.substring(0, 2) == 'on' && typeof f == 'function') e[k] = f; } }-*/; protected ReplacementMap() { } } private static class IdMap extends JavaScriptObject { final native String get(String i) /*-{ return this[i] }-*/; final native void remove(String i) /*-{ delete this[i] }-*/; final native void put(String i, String k) /*-{ this[i] = k }-*/; final native void put(String k, Element e) /*-{ this[k] = e }-*/; final native boolean isEmpty() /*-{ for (var i in this) return false; return true; }-*/; protected IdMap() { } } private HtmlTemplate() { } }