/*
GNU LESSER GENERAL PUBLIC LICENSE
Copyright (C) 2006 The Lobo Project
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Contact info: lobochief@users.sourceforge.net
*/
/*
* Created on Nov 27, 2005
*/
package org.lobobrowser.html.domimpl;
import org.lobobrowser.html.style.CSSUtilities;
import org.lobobrowser.ua.UserAgentContext;
import org.w3c.dom.DOMException;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.w3c.dom.css.CSSStyleSheet;
import org.w3c.dom.html.HTMLStyleElement;
import org.w3c.dom.stylesheets.LinkStyle;
import co.uproot.css.domimpl.JStyleSheetWrapper;
import cz.vutbr.web.css.StyleSheet;
public class HTMLStyleElementImpl extends HTMLElementImpl implements HTMLStyleElement, LinkStyle {
private JStyleSheetWrapper styleSheet;
public HTMLStyleElementImpl() {
super("STYLE", true);
}
public HTMLStyleElementImpl(final String name) {
super(name, true);
}
private boolean disabled;
public boolean getDisabled() {
return this.disabled;
}
public void setDisabled(final boolean disabled) {
this.disabled = disabled;
final CSSStyleSheet sheet = this.styleSheet;
if (sheet != null) {
sheet.setDisabled(disabled);
}
}
//TODO hide from JS
public void setDisabledImpl(final boolean disabled) {
this.disabled = disabled;
}
public String getMedia() {
return this.getAttribute("media");
}
public void setMedia(final String media) {
this.setAttribute("media", media);
}
public String getType() {
return this.getAttribute("type");
}
public void setType(final String type) {
this.setAttribute("type", type);
}
// TODO: This should probably not be a nop. We should probably be handling changes to inner text.
@Override
protected void appendInnerTextImpl(final StringBuffer buffer) {
// nop
}
@Override
public void setAttribute(final String name, final String value) throws DOMException {
super.setAttribute(name, value);
if (isAttachedToDocument()) {
final String nameLowerCase = name.toLowerCase();
if ("type".equals(nameLowerCase) || "media".equals(nameLowerCase) || "title".equals(nameLowerCase)) {
this.disabled = false;
this.processStyle();
}
}
}
private String getOnlyText() {
final NodeList nl = this.getChildNodes();
final StringBuilder sb = new StringBuilder();
for (int i = 0; i < nl.getLength(); i++) {
final Node n = nl.item(i);
if (n.getNodeType() == Node.TEXT_NODE) {
final Text textNode = (Text) n;
sb.append(textNode.getTextContent());
}
}
return sb.toString();
}
private boolean isAllowedType() {
final String type = this.getType();
return ((type == null) || (type.trim().length() == 0) || (type.equalsIgnoreCase("text/css")));
}
// TODO: check if this method can be made private
protected void processStyle() {
if (isAttachedToDocument()) {
/* check if type == "text/css" or no, empty value is also allowed as well.
if it is something other than empty or "text/css" set the style sheet to null
we need not check for the media type here, jStyle parser should take care of this.
*/
if (isAllowedType()) {
final UserAgentContext uacontext = this.getUserAgentContext();
if (uacontext.isInternalCSSEnabled()) {
final HTMLDocumentImpl doc = (HTMLDocumentImpl) this.getOwnerDocument();
final JStyleSheetWrapper newStyleSheet = processStyleHelper();
newStyleSheet.setDisabled(this.disabled);
this.styleSheet = newStyleSheet;
doc.styleSheetManager.invalidateStyles();
}
} else {
this.detachStyleSheet();
}
}
}
private JStyleSheetWrapper processStyleHelper() {
final HTMLDocumentImpl doc = (HTMLDocumentImpl) this.getOwnerDocument();
// TODO a sanity check can be done for the media type while setting it to the style sheet
// as in is it a valid media type or not
try {
final String text = this.getOnlyText();
final String processedText = CSSUtilities.preProcessCss(text);
final String baseURI = doc.getBaseURI();
// TODO if the new StyleSheet contains any @import rules, then we should queue them for further processing. GH #137
final StyleSheet jSheet = CSSUtilities.jParseStyleSheet(this, baseURI, processedText, doc.getUserAgentContext());
return new JStyleSheetWrapper(jSheet, this.getMedia(), null, this.getType(), this.getTitle(), this, doc.styleSheetManager.bridge);
} catch (final Exception err) {
this.warn("Unable to parse style sheet", err);
}
return this.getEmptyStyleSheet();
}
private JStyleSheetWrapper getEmptyStyleSheet() {
final HTMLDocumentImpl doc = (HTMLDocumentImpl) this.getOwnerDocument();
return new JStyleSheetWrapper(CSSUtilities.getEmptyStyleSheet(), this.getMedia(), null, this.getType(), this.getTitle(), this,
doc.styleSheetManager.bridge);
}
private void detachStyleSheet() {
if (this.styleSheet != null) {
this.styleSheet.setOwnerNode(null);
this.styleSheet = null;
final HTMLDocumentImpl doc = (HTMLDocumentImpl) this.getOwnerDocument();
doc.styleSheetManager.invalidateStyles();
}
}
public CSSStyleSheet getSheet() {
return this.styleSheet;
}
@Override
protected void handleChildListChanged() {
this.processStyle();
}
@Override
protected void handleDocumentAttachmentChanged() {
if (isAttachedToDocument()) {
this.processStyle();
} else {
this.detachStyleSheet();
}
}
}