/* GNU GENERAL LICENSE Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either verion 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General License for more details. You should have received a copy of the GNU General Public along with this program. If not, see <http://www.gnu.org/licenses/>. Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it */ /* * Created on Sep 3, 2005 */ package org.lobobrowser.html.domimpl; import java.awt.Color; import java.io.Reader; import java.io.StringReader; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.lobobrowser.html.FormInput; import org.lobobrowser.html.HtmlAttributeProperties; import org.lobobrowser.html.dombl.QuerySelectorImpl; import org.lobobrowser.html.dombl.UINode; import org.lobobrowser.html.parser.HtmlParser; import org.lobobrowser.html.renderstate.ColorRenderState; import org.lobobrowser.html.renderstate.RenderState; import org.lobobrowser.html.renderstate.StyleSheetRenderState; import org.lobobrowser.html.style.AbstractCSS2Properties; import org.lobobrowser.html.style.CSS2PropertiesContext; import org.lobobrowser.html.style.ComputedCSS2Properties; import org.lobobrowser.html.style.HtmlValues; import org.lobobrowser.html.style.LocalCSS2Properties; import org.lobobrowser.html.style.StyleSheetAggregator; import org.lobobrowser.html.style.selectors.SelectorMatcher; import org.lobobrowser.util.Strings; import org.lobobrowser.util.gui.LAFSettings; import org.lobobrowser.w3c.html.DOMSettableTokenList; import org.lobobrowser.w3c.html.DOMStringMap; import org.lobobrowser.w3c.html.DOMTokenList; import org.lobobrowser.w3c.html.HTMLElement; import org.lobobrowser.w3c.html.HTMLPropertiesCollection; import org.mozilla.javascript.Function; import org.w3c.css.sac.InputSource; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.w3c.dom.css.CSSStyleDeclaration; import com.steadystate.css.parser.CSSOMParser; import com.steadystate.css.parser.SACParserCSS3; /** * The Class HTMLElementImpl. */ public class HTMLElementImpl extends DOMElementImpl implements HTMLElement, CSS2PropertiesContext { /** * Instantiates a new HTML element impl. * * @param name * the name * @param noStyleSheet * the no style sheet */ public HTMLElementImpl(String name, boolean noStyleSheet) { super(name); } /** * Instantiates a new HTML element impl. * * @param name * the name */ public HTMLElementImpl(String name) { super(name); } /** The current style declaration state. */ private volatile AbstractCSS2Properties currentStyleDeclarationState; /** The local style declaration state. */ private volatile AbstractCSS2Properties localStyleDeclarationState; /** * Forget local style. */ protected final void forgetLocalStyle() { synchronized (this) { this.currentStyleDeclarationState = null; this.localStyleDeclarationState = null; this.computedStyles = null; } } /** * Forget style. * * @param deep * the deep */ protected final void forgetStyle(boolean deep) { // TODO: OPTIMIZATION: If we had a ComputedStyle map in // window (Mozilla model) the map could be cleared in one shot. synchronized (this) { this.currentStyleDeclarationState = null; this.computedStyles = null; this.isHoverStyle = null; this.hasHoverStyleByElement = null; if (deep) { java.util.ArrayList<Node> nl = this.nodeList; if (nl != null) { Iterator<Node> i = nl.iterator(); while (i.hasNext()) { Object node = i.next(); if (node instanceof HTMLElementImpl) { ((HTMLElementImpl) node).forgetStyle(deep); } } } } } } /** * Gets the current style. * * @return the current style */ public AbstractCSS2Properties getCurrentStyle() { AbstractCSS2Properties sds; synchronized (this) { sds = this.currentStyleDeclarationState; if (sds != null) { return sds; } } // Can't do the following in synchronized block (reverse locking order // with document). // First, add declarations from stylesheet sds = this.createDefaultStyleSheet(); sds = this.addStyleSheetDeclarations(sds, this.getPseudoNames()); // Now add local style if any. AbstractCSS2Properties localStyle = this.getStyle(); if (sds == null) { sds = new ComputedCSS2Properties(this); sds.setLocalStyleProperties(localStyle); } else { sds.setLocalStyleProperties(localStyle); } synchronized (this) { // Check if style properties were set while outside // the synchronized block (can happen). AbstractCSS2Properties setProps = this.currentStyleDeclarationState; if (setProps != null) { return setProps; } this.currentStyleDeclarationState = sds; return sds; } } /** * Gets the local style object associated with the element. The properties * object returned only includes properties from the local style attribute. * It may return null only if the type of element does not handle * stylesheets. * * @return the style */ @Override public AbstractCSS2Properties getStyle() { AbstractCSS2Properties sds; synchronized (this) { sds = this.localStyleDeclarationState; if (sds != null) { return sds; } sds = new LocalCSS2Properties(this); // Add any declarations in style attribute (last takes precedence). String style = this.getAttribute(HtmlAttributeProperties.STYLE); if ((style != null) && (style.length() != 0)) { CSSOMParser parser = new CSSOMParser(new SACParserCSS3()); InputSource inputSource = this.getCssInputSourceForDecl(style); try { CSSStyleDeclaration sd = parser.parseStyleDeclaration(inputSource); sd.setCssText(style); sds.addStyleDeclaration(sd); } catch (Exception err) { String id = this.getId(); String withId = id == null ? "" : " with ID '" + id + "'"; logger.error("Unable to parse style attribute value for element " + this.getTagName() + withId + " in " + this.getDocumentURL() + ".", err); } } this.localStyleDeclarationState = sds; } // Synchronization note: Make sure getStyle() does not return multiple // values. return sds; } /** * Creates the default style sheet. * * @return the abstract cs s2 properties */ protected AbstractCSS2Properties createDefaultStyleSheet() { ComputedCSS2Properties css = new ComputedCSS2Properties(this); css.internalSetLC("font-size", String.valueOf((int)LAFSettings.getInstance().getFontSize())+"px"); return css; } /** The computed styles. */ private Map<String, AbstractCSS2Properties> computedStyles; /** * Gets the computed style. * * @param pseudoElement * the pseudo element * @return the computed style */ public AbstractCSS2Properties getComputedStyle(String pseudoElement) { if (pseudoElement == null) { pseudoElement = ""; } synchronized (this) { Map<String, AbstractCSS2Properties> cs = this.computedStyles; if (cs != null) { AbstractCSS2Properties sds = cs.get(pseudoElement); if (sds != null) { return sds; } } } // Can't do the following in synchronized block (reverse locking order // with document). // First, add declarations from stylesheet Set<String> pes = pseudoElement.length() == 0 ? null : Collections.singleton(pseudoElement); AbstractCSS2Properties sds = this.createDefaultStyleSheet(); sds = this.addStyleSheetDeclarations(sds, pes); // Now add local style if any. AbstractCSS2Properties localStyle = this.getStyle(); if (sds == null) { sds = new ComputedCSS2Properties(this); sds.setLocalStyleProperties(localStyle); } else { sds.setLocalStyleProperties(localStyle); } synchronized (this) { // Check if style properties were set while outside // the synchronized block (can happen). We need to // return instance already set for consistency. Map<String, AbstractCSS2Properties> cs = this.computedStyles; if (cs == null) { cs = new HashMap<String, AbstractCSS2Properties>(2); this.computedStyles = cs; } else { AbstractCSS2Properties sds2 = cs.get(pseudoElement); if (sds2 != null) { return sds2; } } cs.put(pseudoElement, sds); } return sds; } /** * Sets the style. * * @param value * the new style */ public void setStyle(String value) { this.setAttribute(HtmlAttributeProperties.STYLE, value); } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getClassName() */ @Override public String getClassName() { String className = this.getAttribute(HtmlAttributeProperties.CLASS); return className == null ? "" : className; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#setClassName(java.lang.String) */ @Override public void setClassName(String className) { this.setAttribute(HtmlAttributeProperties.CLASS, className); } /** * Gets the charset. * * @return the charset */ public String getCharset() { return this.getAttribute(HtmlAttributeProperties.CHARSET); } /** * Sets the charset. * * @param charset * the new charset */ public void setCharset(String charset) { this.setAttribute(HtmlAttributeProperties.CHARSET, charset); } /** * Gets the attribute as int. * * @param name * the name * @param defaultValue * the default value * @return the attribute as int */ protected int getAttributeAsInt(String name, int defaultValue) { String valueText = this.getAttribute(name); return HtmlValues.getPixelSize(valueText, this.getRenderState(), 0); } /** * Gets the attribute as boolean. * * @param name * the name * @return the attribute as boolean */ public boolean getAttributeAsBoolean(String name) { return this.getAttribute(name) != null; } /* * (non-Javadoc) * * @see * org.lobobrowser.html.domimpl.DOMElementImpl#assignAttributeField(java. * lang .String, java.lang.String) */ @Override protected void assignAttributeField(String normalName, String value) { if (!this.notificationsSuspended) { this.informInvalidAttibute(normalName); } else { if ("style".equals(normalName)) { this.forgetLocalStyle(); } } super.assignAttributeField(normalName, value); } /** * Gets the css input source for decl. * * @param text * the text * @return the css input source for decl */ protected final InputSource getCssInputSourceForDecl(String text) { Reader reader = new StringReader(text); InputSource is = new InputSource(reader); return is; } /** * Adds style sheet declarations applicable to this element. A properties * object is created if necessary when the one passed is <code>null</code>. * * @param style * the style * @param pseudoNames * the pseudo names * @return the abstract cs s2 properties */ protected final AbstractCSS2Properties addStyleSheetDeclarations(AbstractCSS2Properties style, Set<String> pseudoNames) { Node pn = this.parentNode; if (pn == null) { // do later return style; } String classNames = this.getClassName(); if ((classNames != null) && (classNames.length() != 0)) { String id = this.getId(); String elementName = this.getTagName(); String[] classNameArray = Strings.split(classNames); for (int i = classNameArray.length; --i >= 0;) { String className = classNameArray[i]; Collection<CSSStyleDeclaration> sds = this.findStyleDeclarations(elementName, id, className, pseudoNames); if (sds != null) { Iterator<CSSStyleDeclaration> sdsi = sds.iterator(); while (sdsi.hasNext()) { CSSStyleDeclaration sd = sdsi.next(); if (style == null) { style = new ComputedCSS2Properties(this); } style.addStyleDeclaration(sd); } } } } else { String id = this.getId(); String elementName = this.getTagName(); Collection<CSSStyleDeclaration> sds = this.findStyleDeclarations(elementName, id, null, pseudoNames); if (sds != null) { Iterator<CSSStyleDeclaration> sdsi = sds.iterator(); while (sdsi.hasNext()) { CSSStyleDeclaration sd = sdsi.next(); if (style == null) { style = new ComputedCSS2Properties(this); } style.addStyleDeclaration(sd); } } } return style; } /** The is mouse over. */ private boolean isMouseOver = false; /** * Sets the mouse over. * * @param mouseOver * the new mouse over */ public void setMouseOver(boolean mouseOver) { if (this.isMouseOver != mouseOver) { // Change isMouseOver field before checking to invalidate. this.isMouseOver = mouseOver; // Check if descendents are affected (e.g. div:hover a {...} ) this.invalidateDescendentsForHover(); if (this.hasHoverStyle()) { // TODO: OPTIMIZATION: In some cases it should be much // better to simply invalidate the "look" of the node. this.informInvalid(); } } } /** * Invalidate descendents for hover. */ private void invalidateDescendentsForHover() { synchronized (this.getTreeLock()) { this.invalidateDescendentsForHoverImpl(this); } } /** * Invalidate descendents for hover impl. * * @param ancestor * the ancestor */ private void invalidateDescendentsForHoverImpl(HTMLElementImpl ancestor) { ArrayList<Node> nodeList = this.nodeList; if (nodeList != null) { int size = nodeList.size(); for (int i = 0; i < size; i++) { Object node = nodeList.get(i); if (node instanceof HTMLElementImpl) { HTMLElementImpl descendent = (HTMLElementImpl) node; if (descendent.hasHoverStyle(ancestor)) { descendent.informInvalid(); } descendent.invalidateDescendentsForHoverImpl(ancestor); } } } } /** The is hover style. */ private Boolean isHoverStyle = null; /** The has hover style by element. */ private Map<HTMLElementImpl, Boolean> hasHoverStyleByElement = null; /** * Checks for hover style. * * @return true, if successful */ private boolean hasHoverStyle() { Boolean ihs; synchronized (this) { ihs = this.isHoverStyle; if (ihs != null) { return ihs.booleanValue(); } } HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document; if (doc == null) { ihs = Boolean.FALSE; } else { StyleSheetAggregator ssa = doc.getStyleSheetAggregator(); String id = this.getId(); String elementName = this.getTagName(); String classNames = this.getClassName(); String[] classNameArray = null; if ((classNames != null) && (classNames.length() != 0)) { classNameArray = Strings.split(classNames); } ihs = Boolean .valueOf(ssa.affectedByPseudoNameInAncestor(this, this, elementName, id, classNameArray, "hover")); } synchronized (this) { this.isHoverStyle = ihs; } return ihs.booleanValue(); } /** * Checks for hover style. * * @param ancestor * the ancestor * @return true, if successful */ private boolean hasHoverStyle(HTMLElementImpl ancestor) { Map<HTMLElementImpl, Boolean> ihs; synchronized (this) { ihs = this.hasHoverStyleByElement; if (ihs != null) { Boolean f = ihs.get(ancestor); if (f != null) { return f.booleanValue(); } } } Boolean hhs; HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document; if (doc == null) { hhs = Boolean.FALSE; } else { StyleSheetAggregator ssa = doc.getStyleSheetAggregator(); String id = this.getId(); String elementName = this.getTagName(); String classNames = this.getClassName(); String[] classNameArray = null; if ((classNames != null) && (classNames.length() != 0)) { classNameArray = Strings.split(classNames); } hhs = Boolean.valueOf( ssa.affectedByPseudoNameInAncestor(this, ancestor, elementName, id, classNameArray, "hover")); } synchronized (this) { ihs = this.hasHoverStyleByElement; if (ihs == null) { ihs = new HashMap<HTMLElementImpl, Boolean>(2); this.hasHoverStyleByElement = ihs; } ihs.put(ancestor, hhs); } return hhs.booleanValue(); } /** * Gets the pseudo names. * * @return the pseudo names */ public Set<String> getPseudoNames() { Set<String> pnset = new HashSet<String>(); pnset.add(SelectorMatcher.LAST_CHILD); pnset.add(SelectorMatcher.LAST_OF_TYPE); pnset.add(SelectorMatcher.FIRST_CHILD); pnset.add(SelectorMatcher.FIRST_OF_TYPE); pnset.add(SelectorMatcher.ONLY_CHILD); pnset.add(SelectorMatcher.ONLY_OF_TYPE); pnset.add(SelectorMatcher.NTH_CHILD); pnset.add(SelectorMatcher.NTH_LAST_CHILD); pnset.add(SelectorMatcher.NTH_OF_TYPE); pnset.add(SelectorMatcher.NTH_LAST_OF_TYPE); pnset.add(SelectorMatcher.HOVER); pnset.add(SelectorMatcher.ROOT); pnset.add(SelectorMatcher.EMPTY); pnset.add(SelectorMatcher.LANG); return pnset; } /** * Find style declarations. * * @param elementName * the element name * @param id * the id * @param className * the class name * @param pseudoNames * the pseudo names * @return the collection */ protected final Collection<CSSStyleDeclaration> findStyleDeclarations(String elementName, String id, String className, Set<String> pseudoNames) { HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document; if (doc == null) { return null; } StyleSheetAggregator ssa = doc.getStyleSheetAggregator(); return ssa.getActiveStyleDeclarations(this, elementName, id, className, pseudoNames, getAttributes()); } /* * (non-Javadoc) * * @see org.lobobrowser.html.domimpl.DOMNodeImpl#informInvalid() */ @Override public void informInvalid() { // This is called when an attribute or child changes. this.forgetStyle(false); super.informInvalid(); } /** * Inform invalid attibute. * * @param normalName * the normal name */ public void informInvalidAttibute(String normalName) { if ("style".equals(normalName)) { this.forgetLocalStyle(); } forgetStyle(true); informInvalidRecursive(); } private void informInvalidRecursive() { super.informInvalid(); DOMNodeImpl[] nodeList = this.getChildrenArray(); if (nodeList != null) { for (DOMNodeImpl n : nodeList) { if (n instanceof HTMLElementImpl) { HTMLElementImpl htmlElementImpl = (HTMLElementImpl) n; htmlElementImpl.informInvalidRecursive(); } } } } /** * Gets the form inputs. * * @return the form inputs */ protected FormInput[] getFormInputs() { // Override in input elements return null; } /** * Class match. * * @param classTL * the class tl * @return true, if successful */ private boolean classMatch(String classTL) { String classNames = this.getClassName(); if ((classNames == null) || (classNames.length() == 0)) { return classTL == null; } StringTokenizer tok = new StringTokenizer(classNames, " \t\r\n"); while (tok.hasMoreTokens()) { String token = tok.nextToken(); if (token.toLowerCase().equals(classTL)) { return true; } } return false; } /** * Get an ancestor that matches the element tag name given and the style * class given. * * @param elementTL * An tag name in lowercase or an asterisk (*). * @param classTL * A class name in lowercase. * @return the ancestor with class */ public HTMLElementImpl getAncestorWithClass(String elementTL, String classTL) { Object nodeObj = this.getParentNode(); if (nodeObj instanceof HTMLElementImpl) { HTMLElementImpl parentElement = (HTMLElementImpl) nodeObj; String pelementTL = parentElement.getTagName().toLowerCase(); if (("*".equals(elementTL) || elementTL.equals(pelementTL)) && parentElement.classMatch(classTL)) { return parentElement; } return parentElement.getAncestorWithClass(elementTL, classTL); } else { return null; } } /** * Gets the parent with class. * * @param elementTL * the element tl * @param classTL * the class tl * @return the parent with class */ public HTMLElementImpl getParentWithClass(String elementTL, String classTL) { Object nodeObj = this.getParentNode(); if (nodeObj instanceof HTMLElementImpl) { HTMLElementImpl parentElement = (HTMLElementImpl) nodeObj; String pelementTL = parentElement.getTagName().toLowerCase(); if (("*".equals(elementTL) || elementTL.equals(pelementTL)) && parentElement.classMatch(classTL)) { return parentElement; } } return null; } /** * Gets the preceeding sibling element. * * @return the preceeding sibling element */ public HTMLElementImpl getPreceedingSiblingElement() { Node parentNode = this.getParentNode(); if (parentNode == null) { return null; } NodeList childNodes = parentNode.getChildNodes(); if (childNodes == null) { return null; } int length = childNodes.getLength(); HTMLElementImpl priorElement = null; for (int i = 0; i < length; i++) { Node child = childNodes.item(i); if (child == this) { return priorElement; } if (child instanceof HTMLElementImpl) { priorElement = (HTMLElementImpl) child; } } return null; } /** * Gets the preceeding sibling with class. * * @param elementTL * the element tl * @param classTL * the class tl * @return the preceeding sibling with class */ public HTMLElementImpl getPreceedingSiblingWithClass(String elementTL, String classTL) { HTMLElementImpl psibling = this.getPreceedingSiblingElement(); if (psibling != null) { String pelementTL = psibling.getTagName().toLowerCase(); if (("*".equals(elementTL) || elementTL.equals(pelementTL)) && psibling.classMatch(classTL)) { return psibling; } } return null; } /** * Gets the ancestor with id. * * @param elementTL * the element tl * @param idTL * the id tl * @return the ancestor with id */ public HTMLElementImpl getAncestorWithId(String elementTL, String idTL) { Object nodeObj = this.getParentNode(); if (nodeObj instanceof HTMLElementImpl) { HTMLElementImpl parentElement = (HTMLElementImpl) nodeObj; String pelementTL = parentElement.getTagName().toLowerCase(); String pid = parentElement.getId(); String pidTL = pid == null ? null : pid.toLowerCase(); if (("*".equals(elementTL) || elementTL.equals(pelementTL)) && idTL.equals(pidTL)) { return parentElement; } return parentElement.getAncestorWithId(elementTL, idTL); } else { return null; } } /** * Gets the parent with id. * * @param elementTL * the element tl * @param idTL * the id tl * @return the parent with id */ public HTMLElementImpl getParentWithId(String elementTL, String idTL) { Object nodeObj = this.getParentNode(); if (nodeObj instanceof HTMLElementImpl) { HTMLElementImpl parentElement = (HTMLElementImpl) nodeObj; String pelementTL = parentElement.getTagName().toLowerCase(); String pid = parentElement.getId(); String pidTL = pid == null ? null : pid.toLowerCase(); if (("*".equals(elementTL) || elementTL.equals(pelementTL)) && idTL.equals(pidTL)) { return parentElement; } } return null; } /** * Gets the preceeding sibling with id. * * @param elementTL * the element tl * @param idTL * the id tl * @return the preceeding sibling with id */ public HTMLElementImpl getPreceedingSiblingWithId(String elementTL, String idTL) { HTMLElementImpl psibling = this.getPreceedingSiblingElement(); if (psibling != null) { String pelementTL = psibling.getTagName().toLowerCase(); String pid = psibling.getId(); String pidTL = pid == null ? null : pid.toLowerCase(); if (("*".equals(elementTL) || elementTL.equals(pelementTL)) && idTL.equals(pidTL)) { return psibling; } } return null; } /** * Gets the ancestor. * * @param elementTL * the element tl * @return the ancestor */ public HTMLElementImpl getAncestor(String elementTL) { Object nodeObj = this.getParentNode(); if (nodeObj instanceof HTMLElementImpl) { HTMLElementImpl parentElement = (HTMLElementImpl) nodeObj; if ("*".equals(elementTL)) { return parentElement; } String pelementTL = parentElement.getTagName().toLowerCase(); if (elementTL.equals(pelementTL)) { return parentElement; } return parentElement.getAncestor(elementTL); } else { return null; } } /** * Gets the parent. * * @param elementTL * the element tl * @return the parent */ public HTMLElementImpl getParent(String elementTL) { Object nodeObj = this.getParentNode(); if (nodeObj instanceof HTMLElementImpl) { HTMLElementImpl parentElement = (HTMLElementImpl) nodeObj; if ("*".equals(elementTL)) { return parentElement; } String pelementTL = parentElement.getTagName().toLowerCase(); if (elementTL.equals(pelementTL)) { return parentElement; } } return null; } /** * Gets the preceeding sibling. * * @param elementTL * the element tl * @return the preceeding sibling */ public HTMLElementImpl getPreceedingSibling(String elementTL) { HTMLElementImpl psibling = this.getPreceedingSiblingElement(); if (psibling != null) { if ("*".equals(elementTL)) { return psibling; } String pelementTL = psibling.getTagName().toLowerCase(); if (elementTL.equals(pelementTL)) { return psibling; } } return null; } /** * Gets the ancestor for java class. * * @param javaClass * the java class * @return the ancestor for java class */ protected Object getAncestorForJavaClass(Class javaClass) { Object nodeObj = this.getParentNode(); if ((nodeObj == null) || javaClass.isInstance(nodeObj)) { return nodeObj; } else if (nodeObj instanceof HTMLElementImpl) { return ((HTMLElementImpl) nodeObj).getAncestorForJavaClass(javaClass); } else { return null; } } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#setInnerHTML(java.lang.String) */ @Override public void setInnerHTML(String newHtml) { HTMLDocumentImpl document = (HTMLDocumentImpl) this.document; if (document == null) { logger.error("setInnerHTML(): Element " + this + " does not belong to a document."); return; } HtmlParser parser = new HtmlParser(document.getUserAgentContext(), document, null, null, null); synchronized (this) { ArrayList<Node> nl = this.nodeList; if (nl != null) { nl.clear(); } } // Should not synchronize around parser probably. try { Reader reader = new StringReader(newHtml); try { parser.parse(reader, this); } finally { reader.close(); } } catch (Exception thrown) { logger.error("setInnerHTML(): Error setting inner HTML.", thrown); } } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getOuterHTML() */ @Override public String getOuterHTML() { StringBuffer buffer = new StringBuffer(); synchronized (this) { this.appendOuterHTMLImpl(buffer); } return buffer.toString(); } /** * Append outer html impl. * * @param buffer * the buffer */ public void appendOuterHTMLImpl(StringBuffer buffer) { String tagName = this.getTagName(); buffer.append('<'); buffer.append(tagName); Map<String, String> attributes = this.attributes; if (attributes != null) { Iterator i = attributes.entrySet().iterator(); while (i.hasNext()) { Map.Entry entry = (Map.Entry) i.next(); String value = (String) entry.getValue(); if (value != null) { buffer.append(' '); buffer.append(entry.getKey()); buffer.append("=\""); buffer.append(Strings.strictHtmlEncode(value, true)); buffer.append("\""); } } } ArrayList<Node> nl = this.nodeList; if ((nl == null) || (nl.size() == 0)) { buffer.append("/>"); return; } buffer.append('>'); this.appendInnerHTMLImpl(buffer); buffer.append("</"); buffer.append(tagName); buffer.append('>'); } /* * (non-Javadoc) * * @see org.lobobrowser.html.domimpl.DOMNodeImpl#createRenderState(org. * lobobrowser .html.renderstate.RenderState) */ @Override protected RenderState createRenderState(RenderState prevRenderState) { // Overrides DOMNodeImpl method // Called in synchronized block already if (prevRenderState.getColor() == null) { prevRenderState = new ColorRenderState(prevRenderState, Color.BLACK); } return new StyleSheetRenderState(prevRenderState, this); } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getOffsetTop() */ @Override public int getOffsetTop() { UINode uiNode = this.getUINode(); return uiNode == null ? 0 : uiNode.getBoundsRelativeToBlock().y; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getOffsetLeft() */ @Override public int getOffsetLeft() { UINode uiNode = this.getUINode(); return uiNode == null ? 0 : uiNode.getBoundsRelativeToBlock().x; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getOffsetWidth() */ @Override public int getOffsetWidth() { UINode uiNode = this.getUINode(); return uiNode == null ? 0 : uiNode.getBoundsRelativeToBlock().width; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getOffsetHeight() */ @Override public int getOffsetHeight() { UINode uiNode = this.getUINode(); return uiNode == null ? 0 : uiNode.getBoundsRelativeToBlock().height; } /* * (non-Javadoc) * * @see org.lobobrowser.html.style.CSS2PropertiesContext#getParentStyle() */ @Override public AbstractCSS2Properties getParentStyle() { Object parent = this.parentNode; if (parent instanceof HTMLElementImpl) { return ((HTMLElementImpl) parent).getCurrentStyle(); } return null; } /* * (non-Javadoc) * * @see * org.lobobrowser.html.style.CSS2PropertiesContext#getDocumentBaseURI() */ @Override public String getDocumentBaseURI() { HTMLDocumentImpl doc = (HTMLDocumentImpl) this.document; if (doc != null) { return doc.getBaseURI(); } else { return null; } } /* * (non-Javadoc) * * @see org.lobobrowser.html.domimpl.DOMElementImpl#toString() */ @Override public String toString() { return super.toString() + "[currentStyle=" + this.getCurrentStyle() + "]"; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#setOuterHTML(java.lang.String) */ @Override public void setOuterHTML(String outerHTML) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see * org.lobobrowser.w3c.html.HTMLElement#insertAdjacentHTML(java.lang.String, * java.lang.String) */ @Override public void insertAdjacentHTML(String position, String text) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getClassList() */ @Override public DOMTokenList getClassList() { return new DOMTokenListImpl(this, this.getClassName()); } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getDataset() */ @Override public DOMStringMap getDataset() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#click() */ @Override public void click() { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#focus() */ @Override public void focus() { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#blur() */ @Override public void blur() { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getAccessKeyLabel() */ @Override public String getAccessKeyLabel() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getCommandType() */ @Override public String getCommandType() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getLabel() */ @Override public String getLabel() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getIcon() */ @Override public String getIcon() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getOffsetParent() */ @Override public Element getOffsetParent() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getItemRef() */ @Override public DOMSettableTokenList getItemRef() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#setItemRef(java.lang.String) */ @Override public void setItemRef(String itemRef) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getItemProp() */ @Override public DOMSettableTokenList getItemProp() { return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#setItemProp(java.lang.String) */ @Override public void setItemProp(String itemProp) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getProperties() */ @Override public HTMLPropertiesCollection getProperties() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#getItemValue() */ @Override public Object getItemValue() { // TODO Auto-generated method stub return null; } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#setItemValue(java.lang.Object) */ @Override public void setItemValue(Object itemValue) { // TODO Auto-generated method stub } /* * (non-Javadoc) * * @see org.lobobrowser.w3c.html.HTMLElement#querySelector(java.lang.String) */ @Override public Element querySelector(String selectors) { QuerySelectorImpl qsel = new QuerySelectorImpl(); return qsel.documentQuerySelector(this.document, selectors); } /* * (non-Javadoc) * * @see * org.lobobrowser.w3c.html.HTMLElement#querySelectorAll(java.lang.String) */ @Override public NodeList querySelectorAll(String selectors) { QuerySelectorImpl qsel = new QuerySelectorImpl(); return qsel.documentQuerySelectorAll(this.document, selectors); } @Override public NodeList getElementsByClassName(String classNames) { // TODO Auto-generated method stub return null; } @Override public void setHidden(boolean hidden) { // TODO Auto-generated method stub } @Override public DOMSettableTokenList getDropzone() { // TODO Auto-generated method stub return null; } @Override public void setDropzone(String dropzone) { // TODO Auto-generated method stub } @Override public void setSpellcheck(boolean spellcheck) { // TODO Auto-generated method stub } @Override public Function getOnabort() { // TODO Auto-generated method stub return null; } @Override public void setOnabort(Function onabort) { // TODO Auto-generated method stub } @Override public Function getOnblur() { // TODO Auto-generated method stub return null; } @Override public void setOnblur(Function onblur) { // TODO Auto-generated method stub } @Override public Function getOncanplay() { // TODO Auto-generated method stub return null; } @Override public void setOncanplay(Function oncanplay) { // TODO Auto-generated method stub } @Override public Function getOncanplaythrough() { // TODO Auto-generated method stub return null; } @Override public void setOncanplaythrough(Function oncanplaythrough) { // TODO Auto-generated method stub } @Override public Function getOnchange() { // TODO Auto-generated method stub return null; } @Override public void setOnchange(Function onchange) { // TODO Auto-generated method stub } @Override public Function getOnclick() { // TODO Auto-generated method stub return null; } @Override public void setOnclick(Function onclick) { // TODO Auto-generated method stub } @Override public Function getOncontextmenu() { // TODO Auto-generated method stub return null; } @Override public void setOncontextmenu(Function oncontextmenu) { // TODO Auto-generated method stub } @Override public Function getOncuechange() { // TODO Auto-generated method stub return null; } @Override public void setOncuechange(Function oncuechange) { // TODO Auto-generated method stub } @Override public Function getOndblclick() { // TODO Auto-generated method stub return null; } @Override public void setOndblclick(Function ondblclick) { // TODO Auto-generated method stub } @Override public Function getOndrag() { // TODO Auto-generated method stub return null; } @Override public void setOndrag(Function ondrag) { // TODO Auto-generated method stub } @Override public Function getOndragend() { // TODO Auto-generated method stub return null; } @Override public void setOndragend(Function ondragend) { // TODO Auto-generated method stub } @Override public Function getOndragenter() { // TODO Auto-generated method stub return null; } @Override public void setOndragenter(Function ondragenter) { // TODO Auto-generated method stub } @Override public Function getOndragleave() { // TODO Auto-generated method stub return null; } @Override public void setOndragleave(Function ondragleave) { // TODO Auto-generated method stub } @Override public Function getOndragover() { // TODO Auto-generated method stub return null; } @Override public void setOndragover(Function ondragover) { // TODO Auto-generated method stub } @Override public Function getOndragstart() { // TODO Auto-generated method stub return null; } @Override public void setOndragstart(Function ondragstart) { // TODO Auto-generated method stub } @Override public Function getOndrop() { // TODO Auto-generated method stub return null; } @Override public void setOndrop(Function ondrop) { // TODO Auto-generated method stub } @Override public Function getOndurationchange() { // TODO Auto-generated method stub return null; } @Override public void setOndurationchange(Function ondurationchange) { // TODO Auto-generated method stub } @Override public Function getOnemptied() { // TODO Auto-generated method stub return null; } @Override public void setOnemptied(Function onemptied) { // TODO Auto-generated method stub } @Override public Function getOnended() { // TODO Auto-generated method stub return null; } @Override public void setOnended(Function onended) { // TODO Auto-generated method stub } @Override public Function getOnerror() { // TODO Auto-generated method stub return null; } @Override public void setOnerror(Function onerror) { // TODO Auto-generated method stub } @Override public Function getOnfocus() { // TODO Auto-generated method stub return null; } @Override public void setOnfocus(Function onfocus) { // TODO Auto-generated method stub } @Override public Function getOninput() { // TODO Auto-generated method stub return null; } @Override public void setOninput(Function oninput) { // TODO Auto-generated method stub } @Override public Function getOninvalid() { // TODO Auto-generated method stub return null; } @Override public void setOninvalid(Function oninvalid) { // TODO Auto-generated method stub } @Override public Function getOnkeydown() { // TODO Auto-generated method stub return null; } @Override public void setOnkeydown(Function onkeydown) { // TODO Auto-generated method stub } @Override public Function getOnkeypress() { // TODO Auto-generated method stub return null; } @Override public void setOnkeypress(Function onkeypress) { // TODO Auto-generated method stub } @Override public Function getOnkeyup() { // TODO Auto-generated method stub return null; } @Override public void setOnkeyup(Function onkeyup) { // TODO Auto-generated method stub } @Override public Function getOnload() { // TODO Auto-generated method stub return null; } @Override public void setOnload(Function onload) { // TODO Auto-generated method stub } @Override public Function getOnloadeddata() { // TODO Auto-generated method stub return null; } @Override public void setOnloadeddata(Function onloadeddata) { // TODO Auto-generated method stub } @Override public Function getOnloadedmetadata() { // TODO Auto-generated method stub return null; } @Override public void setOnloadedmetadata(Function onloadedmetadata) { // TODO Auto-generated method stub } @Override public Function getOnloadstart() { // TODO Auto-generated method stub return null; } @Override public void setOnloadstart(Function onloadstart) { // TODO Auto-generated method stub } @Override public Function getOnmousedown() { // TODO Auto-generated method stub return null; } @Override public void setOnmousedown(Function onmousedown) { // TODO Auto-generated method stub } @Override public Function getOnmousemove() { // TODO Auto-generated method stub return null; } @Override public void setOnmousemove(Function onmousemove) { // TODO Auto-generated method stub } @Override public Function getOnmouseout() { // TODO Auto-generated method stub return null; } @Override public void setOnmouseout(Function onmouseout) { // TODO Auto-generated method stub } @Override public Function getOnmouseover() { // TODO Auto-generated method stub return null; } @Override public void setOnmouseover(Function onmouseover) { // TODO Auto-generated method stub } @Override public Function getOnmouseup() { // TODO Auto-generated method stub return null; } @Override public void setOnmouseup(Function onmouseup) { // TODO Auto-generated method stub } @Override public Function getOnmousewheel() { // TODO Auto-generated method stub return null; } @Override public void setOnmousewheel(Function onmousewheel) { // TODO Auto-generated method stub } @Override public Function getOnpause() { // TODO Auto-generated method stub return null; } @Override public void setOnpause(Function onpause) { // TODO Auto-generated method stub } @Override public Function getOnplay() { // TODO Auto-generated method stub return null; } @Override public void setOnplay(Function onplay) { // TODO Auto-generated method stub } @Override public Function getOnplaying() { // TODO Auto-generated method stub return null; } @Override public void setOnplaying(Function onplaying) { // TODO Auto-generated method stub } @Override public Function getOnprogress() { // TODO Auto-generated method stub return null; } @Override public void setOnprogress(Function onprogress) { // TODO Auto-generated method stub } @Override public Function getOnratechange() { // TODO Auto-generated method stub return null; } @Override public void setOnratechange(Function onratechange) { // TODO Auto-generated method stub } @Override public Function getOnreadystatechange() { // TODO Auto-generated method stub return null; } @Override public void setOnreadystatechange(Function onreadystatechange) { // TODO Auto-generated method stub } @Override public Function getOnreset() { // TODO Auto-generated method stub return null; } @Override public void setOnreset(Function onreset) { // TODO Auto-generated method stub } @Override public Function getOnscroll() { // TODO Auto-generated method stub return null; } @Override public void setOnscroll(Function onscroll) { // TODO Auto-generated method stub } @Override public Function getOnseeked() { // TODO Auto-generated method stub return null; } @Override public void setOnseeked(Function onseeked) { // TODO Auto-generated method stub } @Override public Function getOnseeking() { // TODO Auto-generated method stub return null; } @Override public void setOnseeking(Function onseeking) { // TODO Auto-generated method stub } @Override public Function getOnselect() { // TODO Auto-generated method stub return null; } @Override public void setOnselect(Function onselect) { // TODO Auto-generated method stub } @Override public Function getOnshow() { // TODO Auto-generated method stub return null; } @Override public void setOnshow(Function onshow) { // TODO Auto-generated method stub } @Override public Function getOnstalled() { // TODO Auto-generated method stub return null; } @Override public void setOnstalled(Function onstalled) { // TODO Auto-generated method stub } @Override public Function getOnsubmit() { // TODO Auto-generated method stub return null; } @Override public void setOnsubmit(Function onsubmit) { // TODO Auto-generated method stub } @Override public Function getOnsuspend() { // TODO Auto-generated method stub return null; } @Override public void setOnsuspend(Function onsuspend) { // TODO Auto-generated method stub } @Override public Function getOntimeupdate() { // TODO Auto-generated method stub return null; } @Override public void setOntimeupdate(Function ontimeupdate) { // TODO Auto-generated method stub } @Override public Function getOnvolumechange() { // TODO Auto-generated method stub return null; } @Override public void setOnvolumechange(Function onvolumechange) { // TODO Auto-generated method stub } @Override public Function getOnwaiting() { // TODO Auto-generated method stub return null; } @Override public void setOnwaiting(Function onwaiting) { // TODO Auto-generated method stub } }