/*
GNU LESSER GENERAL PUBLIC LICENSE
Copyright (C) 2014 Uproot Labs India Pvt Ltd
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
*/
package org.lobobrowser.html.style;
import java.net.MalformedURLException;
import java.net.URL;
import org.lobobrowser.js.AbstractScriptableDelegate;
import org.lobobrowser.js.HideFromJS;
import org.lobobrowser.util.Urls;
import org.w3c.dom.css.CSS2Properties;
import cz.vutbr.web.css.CSSProperty;
import cz.vutbr.web.css.NodeData;
import cz.vutbr.web.css.Term;
import cz.vutbr.web.csskit.TermURIImpl;
abstract public class JStyleProperties extends AbstractScriptableDelegate implements CSS2Properties {
private String overlayColor;
final private CSS2PropertiesContext context;
// TODO: this flag can be removed when the layout can handle empty strings
// currently there is only a check for null and not for empty string
final protected boolean nullIfAbsent;
public JStyleProperties(final CSS2PropertiesContext context, final boolean nullIfAbsent) {
this.context = context;
this.nullIfAbsent = nullIfAbsent;
}
//TODO All the methods that are not implemented need more detailed understanding.
// most of them are short hand properties and they need to be constructed from the long
// forms of the respective properties
public String getAzimuth() {
return helperTryBoth("azimuth");
}
public String getBackground() {
// TODO need to implement this method. GH #143
return "";
}
public String getBackgroundAttachment() {
return helperGetProperty("background-attachment");
}
public String getBackgroundColor() {
return helperTryBoth("background-color");
}
public String getBackgroundImage() {
// TODO
// need to check if upstream can provide the absolute url of
// the image so that it can directly be passed.
String quotedUri = null;
final TermURIImpl t = (TermURIImpl) getNodeData().getValue("background-image", false);
if (t != null) {
URL finalUrl = null;
try {
finalUrl = Urls.createURL(t.getBase(), t.getValue());
} catch (final MalformedURLException e) {
e.printStackTrace();
}
quotedUri = finalUrl == null ? null : finalUrl.toString();
}
return quotedUri == null ? null : "url(" + quotedUri + ")";
}
public String getBackgroundPosition() {
return helperGetValue("background-position");
}
public String getBackgroundRepeat() {
return helperGetProperty("background-repeat");
}
public String getBorder() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBorderCollapse() {
return helperGetProperty("border-collapse");
}
public String getBorderColor() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBorderSpacing() {
return helperGetValue("border-spacing");
}
public String getBorderStyle() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBorderTop() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBorderRight() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBorderBottom() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBorderLeft() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBorderTopColor() {
return helperTryBoth("border-top-color");
}
public String getBorderRightColor() {
return helperTryBoth("border-right-color");
}
public String getBorderBottomColor() {
return helperTryBoth("border-bottom-color");
}
public String getBorderLeftColor() {
return helperTryBoth("border-left-color");
}
public String getBorderTopStyle() {
return helperGetProperty("border-top-style");
}
public String getBorderRightStyle() {
return helperGetProperty("border-right-style");
}
public String getBorderBottomStyle() {
return helperGetProperty("border-bottom-style");
}
public String getBorderLeftStyle() {
return helperGetProperty("border-left-style");
}
public String getBorderTopWidth() {
final String width = helperTryBoth("border-top-width");
// TODO
// temp hack to support border thin/medium/thick
// need to implement it at the place where it is actually being processed
return border2Pixel(width);
}
public String getBorderRightWidth() {
final String width = helperTryBoth("border-right-width");
// TODO
// temp hack to support border thin/medium/thick
// need to implement it at the place where it is actually being processed
return border2Pixel(width);
}
public String getBorderBottomWidth() {
final String width = helperTryBoth("border-bottom-width");
// TODO
// temp hack to support border thin/medium/thick
// need to implement it at the place where it is actually being processed
return border2Pixel(width);
}
public String getBorderLeftWidth() {
final String width = helperTryBoth("border-left-width");
// TODO
// temp hack to support border thin/medium/thick
// need to implement it at the place where it is actually being processed
return border2Pixel(width);
}
// TODO
// temp hack to support border thin/medium/thick
// this method should be removed once it is implemented where border is actually processed
private static String border2Pixel(final String width) {
if (width != null) {
if ("thin".equalsIgnoreCase(width)) {
return HtmlValues.BORDER_THIN_SIZE;
}
if ("medium".equalsIgnoreCase(width)) {
return HtmlValues.BORDER_MEDIUM_SIZE;
}
if ("thick".equalsIgnoreCase(width)) {
return HtmlValues.BORDER_THICK_SIZE;
}
}
return width;
}
public String getBorderWidth() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getBottom() {
return helperTryBoth("bottom");
}
public String getCaptionSide() {
return helperGetProperty("caption-side");
}
public String getClear() {
return helperGetProperty("clear");
}
public String getClip() {
return helperTryBoth("clip");
}
public String getColor() {
return helperTryBoth("color");
}
public String getContent() {
return helperTryBoth("content");
}
public String getCounterIncrement() {
return helperTryBoth("couter-increment");
}
public String getCounterReset() {
return helperTryBoth("couter-reset");
}
public String getCue() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getCueAfter() {
return helperTryBoth("cue-after");
}
public String getCueBefore() {
return helperTryBoth("cue-before");
}
public String getCursor() {
return helperGetProperty("cursor");
}
public String getDirection() {
return helperGetProperty("direction");
}
public String getDisplay() {
return helperGetProperty("display");
}
public String getElevation() {
return helperTryBoth("elevation");
}
public String getEmptyCells() {
return helperGetProperty("empty-cells");
}
public String getCssFloat() {
return this.getFloat();
}
public String getFont() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getFontFamily() {
return helperTryBoth("font-family");
}
public String getFontSize() {
return helperTryBoth("font-size");
}
public String getFontSizeAdjust() {
return helperTryBoth("font-adjust");
}
public String getFontStretch() {
return helperGetProperty("font-stretch");
}
public String getFontStyle() {
return helperGetProperty("font-style");
}
public String getFontVariant() {
return helperGetProperty("font-variant");
}
public String getFontWeight() {
return helperGetProperty("font-weight");
}
public String getHeight() {
return helperGetValue("height");
}
public String getLeft() {
return helperTryBoth("left");
}
public String getLetterSpacing() {
return helperTryBoth("letter-spacing");
}
public String getLineHeight() {
return helperTryBoth("line-height");
}
public String getListStyle() {
final String listStyleType = getListStyleType();
final String listStylePosition = getListStylePosition();
final StringBuilder listStyle = new StringBuilder();
if ((listStyleType != null) && !("null".equals(listStyleType))) {
listStyle.append(listStyleType);
}
if ((listStylePosition != null) && !("null".equals(listStylePosition))) {
listStyle.append(" " + listStylePosition);
}
final String listStyleText = listStyle.toString().trim();
return listStyleText.length() == 0 ? null : listStyleText;
}
public String getListStyleImage() {
return helperTryBoth("list-style-image");
}
public String getListStylePosition() {
return helperGetProperty("list-style-position");
}
public String getListStyleType() {
return helperGetProperty("list-style-type");
}
public String getMargin() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getMarginTop() {
return helperTryBoth("margin-top");
}
public String getMarginRight() {
return helperTryBoth("margin-right");
}
public String getMarginBottom() {
return helperTryBoth("margin-bottom");
}
public String getMarginLeft() {
return helperTryBoth("margin-left");
}
public String getMarkerOffset() {
return helperTryBoth("marker-offset");
}
public String getMarks() {
return helperGetProperty("marks");
}
public String getMaxHeight() {
return helperTryBoth("max-height");
}
public String getMaxWidth() {
return helperTryBoth("max-width");
}
public String getMinHeight() {
return helperTryBoth("min-height");
}
public String getMinWidth() {
return helperTryBoth("min-width");
}
public String getOrphans() {
return helperGetValue("orphans");
}
public String getOutline() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getOutlineColor() {
return helperTryBoth("outline-color");
}
public String getOutlineStyle() {
return helperGetProperty("outline-style");
}
//TODO add support for thick/think/medium
public String getOutlineWidth() {
final String width = helperTryBoth("outline-border");
return border2Pixel(width);
}
public String getOverflow() {
return helperGetProperty("overflow");
}
public String getPadding() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getPaddingTop() {
return helperGetValue("padding-top");
}
public String getPaddingRight() {
return helperGetValue("padding-right");
}
public String getPaddingBottom() {
return helperGetValue("padding-bottom");
}
public String getPaddingLeft() {
return helperGetValue("padding-left");
}
public String getPage() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getPageBreakAfter() {
return helperGetProperty("page-break-after");
}
public String getPageBreakBefore() {
return helperGetProperty("page-break-before");
}
public String getPageBreakInside() {
return helperGetProperty("page-break-inside");
}
public String getPause() {
return helperGetValue("pause");
}
public String getPauseAfter() {
return helperGetValue("pause-after");
}
public String getPauseBefore() {
return helperGetValue("pause-before");
}
public String getPitch() {
return helperTryBoth("pitch");
}
public String getPitchRange() {
return helperGetValue("pitchRange");
}
public String getPlayDuring() {
return helperTryBoth("play-during");
}
public String getPosition() {
return helperGetProperty("position");
}
public String getQuotes() {
return helperTryBoth("quotes");
}
public String getRichness() {
return helperGetValue("richness");
}
public String getRight() {
return helperTryBoth("right");
}
public String getSize() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getSpeak() {
return helperGetProperty("speak");
}
public String getSpeakHeader() {
return helperGetProperty("speak-header");
}
public String getSpeakNumeral() {
return helperGetProperty("speak-numeral");
}
public String getSpeakPunctuation() {
return helperGetProperty("speak-punctuation");
}
public String getSpeechRate() {
return helperTryBoth("speech-rate");
}
public String getStress() {
return helperGetValue("stress");
}
public String getTableLayout() {
return helperGetProperty("table-layout");
}
public String getTextAlign() {
return helperGetProperty("text-align");
}
public String getTextDecoration() {
return helperTryBoth("text-decoration");
}
public String getTextIndent() {
return helperGetValue("text-indent");
}
public String getTextShadow() {
// TODO need to implement this method
throw new UnsupportedOperationException();
}
public String getTextTransform() {
return helperGetProperty("text-transform");
}
public String getTop() {
return helperTryBoth("top");
}
public String getUnicodeBidi() {
return helperGetProperty("unicode-bidi");
}
public String getVerticalAlign() {
return helperGetProperty("vertical-align");
}
public String getVisibility() {
return helperGetProperty("visibility");
}
public String getVoiceFamily() {
return helperTryBoth("voice-family");
}
public String getVolume() {
return helperTryBoth("volume");
}
public String getWhiteSpace() {
return helperGetProperty("white-space");
}
public String getWidows() {
return helperGetValue("widows");
}
public String getWidth() {
return helperGetValue("width");
}
public String getWordSpacing() {
return helperTryBoth("word-spacing");
}
public String getZIndex() {
// TODO
// refer to issue #77
// According to the specs ZIndex value has to be integer but
// jStyle Parser returns an float.
// until then this is just a temp hack.
final String zIndex = helperGetValue("z-index");
float fZIndex = 0.0f;
if (zIndex != null) {
try {
fZIndex = Float.parseFloat(zIndex);
} catch (final NumberFormatException err) {
err.printStackTrace();
}
}
final int iZIndex = (int) fZIndex;
return "" + iZIndex;
}
public String getOverlayColor() {
return this.overlayColor;
}
public void setOverlayColor(final String value) {
this.overlayColor = value;
this.context.informLookInvalid();
}
// TODO references to this in internal code can use a more specific method.
// (we can implement specific methods like we have for other properties)
public String getPropertyValue(final String string) {
return helperGetProperty(string);
}
public String getFloat() {
return helperGetProperty("float");
}
abstract protected NodeData getNodeData();
private String helperGetValue(final String propertyName) {
final NodeData nodeData = getNodeData();
if (nodeData != null) {
final Term<?> value = nodeData.getValue(propertyName, true);
// The trim() is a temporary work around for #154
return value == null ? null : value.toString().trim();
} else {
return nullIfAbsent ? null : "";
}
}
private String helperGetProperty(final String propertyName) {
final NodeData nodeData = getNodeData();
if (nodeData != null) {
final CSSProperty property = nodeData.getProperty(propertyName, true);
// final CSSProperty property = nodeData.getProperty(propertyName);
return property == null ? null : property.toString();
} else {
return nullIfAbsent ? null : "";
}
}
@HideFromJS
public String helperTryBoth(final String propertyName) {
// These two implementations were deprecated after the changes in https://github.com/radkovo/jStyleParser/issues/50
/* Original
final String value = helperGetValue(propertyName);
return value == null ? helperGetProperty(propertyName) : value;
*/
/* Corrected (equivalent to below implementation, but less optimal)
final String property = helperGetProperty(propertyName);
return property == null || property.isEmpty() ? helperGetValue(propertyName) : property;
*/
final NodeData nodeData = getNodeData();
if (nodeData == null) {
return null;
}
return nodeData.getAsString(propertyName, true);
}
}