/*
* Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores
* CA 94065 USA or visit www.oracle.com if you need additional information or
* have any questions.
*/
package com.codename1.ui.html;
import com.codename1.xml.Element;
import com.codename1.ui.Component;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Vector;
/**
* The HTMLElement class defines a single HTML element with its attributes and children.
* Due to its hierarchial nature, this class can be used for a single "leaf" Element, for more complex elements (with child elements), and up to describing the entire document.
*
* @author Ofir Leitner
*/
public class HTMLElement extends Element {
//////////////////////////////////
// Tags //
//////////////////////////////////
//HTML Tag ID codes:
public static final int TAG_CSS_ILLEGAL_SELECTOR = -3; // If this is the tag ID it means this selector was malformed and as such will never match (For example p[] or a[=] - empty/meaningless attribute selection). Note that we can't simply discard this selector for the case of descendants: for example 'h1 a[] h2' - should never be matched - if we would discard the a[] which is illegal we would get 'h1 h2' which may be matched
public static final int TAG_CSS_SELECTOR = -2;
public static final int TAG_UNSUPPORTED = -1;
//Structure Module
public static final int TAG_BODY = 0;
public static final int TAG_HEAD = 1;
public static final int TAG_HTML = 2;
public static final int TAG_TITLE = 3;
//Text Module -
public static final int TAG_ABBR = 4; // No visual effect
public static final int TAG_ACRONYM = 5; // No visual effect
public static final int TAG_ADDRESS = 6; // No visual effect
public static final int TAG_BLOCKQUOTE = 7;
public static final int TAG_BR = 8;
public static final int TAG_CITE = 9;
public static final int TAG_CODE = 10;
public static final int TAG_DFN = 11;
public static final int TAG_DIV = 12;
public static final int TAG_EM = 13;
public static final int TAG_H1 = 14;
public static final int TAG_H2 = 15;
public static final int TAG_H3 = 16;
public static final int TAG_H4 = 17;
public static final int TAG_H5 = 18;
public static final int TAG_H6 = 19;
public static final int TAG_KBD = 20;
public static final int TAG_P = 21;
public static final int TAG_PRE = 22;
public static final int TAG_Q = 23;
public static final int TAG_SAMP = 24;
public static final int TAG_SPAN = 25; // While this is not parsed, it will be kept in the DOM and as such CSS will affect its class/ID
public static final int TAG_STRONG = 26;
public static final int TAG_VAR = 27;
//Hypertext Module -
public static final int TAG_A = 28;
//List Module -
public static final int TAG_DL = 29;
public static final int TAG_DT = 30;
public static final int TAG_DD = 31;
public static final int TAG_OL = 32;
public static final int TAG_UL = 33;
public static final int TAG_LI = 34;
//Basic Forms Module -
public static final int TAG_FORM = 35;
public static final int TAG_INPUT = 36;
public static final int TAG_LABEL = 37;
public static final int TAG_SELECT = 38;
public static final int TAG_OPTION = 39;
public static final int TAG_TEXTAREA = 40;
//Basic Tables Module -
public static final int TAG_CAPTION = 41;
public static final int TAG_TABLE = 42;
public static final int TAG_TD = 43;
public static final int TAG_TH = 44;
public static final int TAG_TR = 45;
//Image Module -
public static final int TAG_IMG = 46;
//Object Module -
public static final int TAG_OBJECT = 47; // Not supported
public static final int TAG_PARAM = 48; // Not supported
//Metainformation Module
public static final int TAG_META = 49;
//Link Module -
public static final int TAG_LINK = 50;
//Base Module
public static final int TAG_BASE = 51;
//XHTML Mobile Profile additons
public static final int TAG_HR = 52;
public static final int TAG_OPTGROUP = 53; // Currently still not supported as Codename One's ComboBox can't display option groups, but will display as a regular ComboBox
public static final int TAG_STYLE = 54;
public static final int TAG_B = 55;
public static final int TAG_I = 56;
public static final int TAG_BIG = 57;
public static final int TAG_SMALL = 58;
public static final int TAG_FIELDSET = 59;
// HTML 4 tags - the following tags are not part of the XHTML MP 1.0 standard:
public static final int TAG_U = 60; // Underline
public static final int TAG_FONT = 61;
public static final int TAG_DEL = 62; // Rendered same as S
public static final int TAG_INS = 63; // Rendered same as U
public static final int TAG_TT = 64;
public static final int TAG_BASEFONT = 65;
public static final int TAG_MENU = 66; // Same as UL
public static final int TAG_S = 67; // Strike through
public static final int TAG_STRIKE = 68; // Strike through
public static final int TAG_CENTER = 69; // shorthand for DIV align=center
public static final int TAG_DIR = 70;// Same as UL
public static final int TAG_MAP = 71;
public static final int TAG_AREA = 72;
public static final int TAG_LEGEND = 73;
public static final int TAG_SUB = 74;
public static final int TAG_SUP = 75;
public static final int TAG_NOSCRIPT = 76; // Since we don't support scripts this tag will always be evaluated
public static final int TAG_NOFRAMES = 77; // Since we don't support frames this tag will always be evaluated
public static final int TAG_THEAD = 78;
public static final int TAG_TBODY = 79;
public static final int TAG_TFOOT = 80;
public static final int TAG_BUTTON = 81;
//Text nodes (not an actual tag - text segments are added by the parser as the 'text' tag
public static final int TAG_TEXT = 82;
private static int LAST_TAG_INDEX = HTMLComponent.PROCESS_HTML_MP1_ONLY?TAG_FIELDSET:TAG_BUTTON; // In any case we exclude TAG_TEXT, which is given only on text element creation
/**
* Defines the tag names, these are specified according to the tag constants numbering.
*/
static final String[] TAG_NAMES = {
"body","head","html","title"
,"abbr","acronym","address","blockquote","br","cite","code","dfn","div","em","h1","h2","h3","h4","h5","h6","kbd","p","pre","q","samp","span","strong","var"
,"a"
,"dl","dt","dd","ol","ul","li"
,"form","input","label","select","option","textarea"
,"caption","table","td","th","tr"
,"img"
,"object","param"
,"meta"
,"link"
,"base"
,"hr","optgroup","style","b","i","big","small","fieldset"
//html4 tags
,"u","font","del","ins","tt","basefont","menu","s","strike","center","dir","map","area","legend","sub","sup","noscript","noframes"
,"thead","tbody","tfoot","button"
,"text"
};
//////////////////////////////////
// Attributes //
//////////////////////////////////
//Tag attributes:
public static final int ATTR_CLASS = 0;
public static final int ATTR_ID = 1;
public static final int ATTR_STYLE = 2;
public static final int ATTR_TITLE = 3;
public static final int ATTR_XMLNS = 4;
public static final int ATTR_XMLLANG = 5;
public static final int ATTR_ALIGN = 6;
public static final int ATTR_BGCOLOR = 7;
public static final int ATTR_LINK = 8;
public static final int ATTR_TEXT = 9;
public static final int ATTR_VERSION = 10;
public static final int ATTR_CITE = 11;
public static final int ATTR_ACCESSKEY = 12;
public static final int ATTR_CHARSET = 13;
public static final int ATTR_HREF = 14;
public static final int ATTR_HREFLANG = 15;
public static final int ATTR_REL = 16;
public static final int ATTR_REV = 17;
public static final int ATTR_TABINDEX = 18;
public static final int ATTR_TYPE = 19;
public static final int ATTR_ACTION = 20;
public static final int ATTR_ENCTYPE = 21;
public static final int ATTR_METHOD = 22;
public static final int ATTR_WIDTH = 23;
public static final int ATTR_HEIGHT = 24;
public static final int ATTR_ALT = 25;
public static final int ATTR_HSPACE = 26;
public static final int ATTR_VSPACE = 27;
public static final int ATTR_LONGDESC = 28;
public static final int ATTR_LOCALSRC = 29;
public static final int ATTR_SRC = 30;
public static final int ATTR_SIZE = 31;
public static final int ATTR_CHECKED = 32;
public static final int ATTR_EMPTYOK = 33;
public static final int ATTR_FORMAT = 34;
public static final int ATTR_ISTYLE = 35;
public static final int ATTR_MAXLENGTH = 36;
public static final int ATTR_NAME = 37;
public static final int ATTR_VALUE = 38;
public static final int ATTR_FOR = 39;
public static final int ATTR_XMLSPACE = 40;
public static final int ATTR_MULTIPLE = 41;
public static final int ATTR_SELECTED = 42;
public static final int ATTR_ABBR = 43;
public static final int ATTR_AXIS = 44;
public static final int ATTR_COLSPAN = 45;
public static final int ATTR_HEADERS = 46;
public static final int ATTR_ROWSPAN = 47;
public static final int ATTR_SCOPE = 48;
public static final int ATTR_VALIGN = 49;
public static final int ATTR_START = 50;
public static final int ATTR_MEDIA = 51;
public static final int ATTR_LABEL = 52;
public static final int ATTR_SUMMARY = 53;
public static final int ATTR_CONTENT = 54;
public static final int ATTR_HTTPEQUIV = 55;
public static final int ATTR_SCHEME = 56;
public static final int ATTR_COLS = 57;
public static final int ATTR_ROWS = 58;
// Unsupported attributes in XHTML-MP that we DO support
public static final int ATTR_DIR = 59; //Currently only supported in the html tag
public static final int ATTR_BORDER = 60;
// Required by HTML4 tags we support:
public static final int ATTR_COLOR = 61;
public static final int ATTR_FACE = 62;
public static final int ATTR_SHAPE = 63;
public static final int ATTR_COORDS = 64;
public static final int ATTR_USEMAP = 65;
// HTML4 attributes
public static final int ATTR_LANG = 66;
public static final int ATTR_CELLSPACING = 67;
public static final int ATTR_CELLPADDING = 68;
public static final int ATTR_FRAME = 69;
public static final int ATTR_RULES = 70;
public static final int ATTR_DISABLED = 71;
public static final int ATTR_READONLY = 72;
public static final int ATTR_ISMAP = 73;
/**
* Defines the allowed attribute names, these are specified according to the ATTR_* constants numbering.
*/
static final String[] ATTRIBUTE_NAMES = {
"class", "id", "style", "title", "xmlns", "xml:lang", "align", "bgcolor", "link", "text", "version", "cite",
"accesskey", "charset", "href", "hreflang", "rel", "rev", "tabindex", "type", "action", "enctype", "method",
"width", "height", "alt", "hspace", "vspace", "longdesc", "localsrc", "src", "size", "checked", "emptyok",
"format", "istyle", "maxlength", "name", "value", "for", "xml:space", "multiple", "selected","abbr","axis",
"colspan","headers","rowspan","scope","valign","start","media","label","summary","content","http-equiv","scheme",
"cols","rows","dir","border",
"color","face","shape","coords","usemap",
"lang","cellspacing","cellpadding","frame","rules",
"disabled","readonly","ismap"
};
/**
* This array defines the 6 common attributes that each tag has
*/
private static final int[] COMMON_ATTRIBUTES = {ATTR_CLASS,ATTR_ID,ATTR_STYLE,ATTR_TITLE,ATTR_XMLNS,ATTR_XMLLANG,ATTR_LANG};
/**
* This array defines the allowed attributes for each tag, according to the XHTML-MP 1.0 spec
*/
private static final int[][] TAG_ATTRIBUTES = {
//Structure Module
{
ATTR_BGCOLOR, // #rrggbb | colors // Deprecated but supported
ATTR_LINK, // #rrggbb | colors // Deprecated but supported
ATTR_TEXT //#rrggbb | colors // Deprecated but supported
}, // BODY = 0;
{}, // HEAD = 1;
{
//ATTR_VERSION, // = //WAPFORUM//DTD XHTML Mobile 1.0//EN // We don't use the version attribute
ATTR_DIR
}, // HTML = 2;
{}, // TITLE = 3;
//Text Module -
{}, // ABBR = 4;
{}, // ACRONYM = 5;
{}, // ADDRESS = 6;
{
//ATTR_CITE // URL // Not supported by any of the major browsers
}, // BLOCKQUOTE = 7;
{}, // BR = 8;
{}, // CITE = 9;
{}, // CODE = 10;
{}, // DFN = 11;
{
ATTR_ALIGN // top/bottom/left/right
}, // DIV = 12;
{}, // EM = 13;
{
ATTR_ALIGN // top/bottom/left/right
}, // H1 = 14;
{
ATTR_ALIGN // top/bottom/left/right
}, // H2 = 15;
{
ATTR_ALIGN // top/bottom/left/right
}, // H3 = 16;
{
ATTR_ALIGN // top/bottom/left/right
}, // H4 = 17;
{
ATTR_ALIGN // top/bottom/left/right
}, // H5 = 18;
{
ATTR_ALIGN // top/bottom/left/right
}, // H6 = 19;
{}, // KBD = 20;
{
ATTR_ALIGN // left | center | right | justify
}, // P = 21;
{
//ATTR_XMLSPACE, // preserve // We don't use this attribute
}, // PRE = 22;
{
//ATTR_CITE // URL // The cite attribute is not supported by any of the major browsers.
}, // Q = 23;
{}, // SAMP = 24;
{}, // SPAN = 25;
{}, // STRONG = 26;
{}, // VAR = 27;
//Hypertext Module -
{
ATTR_ACCESSKEY, // character
//ATTR_CHARSET, // cdata // The charset attribute is not supported in any of the major browsers.
ATTR_HREF, // URL
//ATTR_HREFLANG, // ((?i)[A-Z]{1,8}(-[A-Z]{1,8})*)? // The hreflang attribute is not supported in any of the major browsers.
//ATTR_REL, // nmtokens // Not used by browsers
//ATTR_REV, // nmtokens // Not used by browsers
//ATTR_TABINDEX, // number
//ATTR_TYPE, // cdata // Should specify the MIME type of the document, but we don't use it anyway
ATTR_NAME // Note: Name on the a tag (anchor) is not supported on XHTML-MP 1.0, but we support it
}, // A = 28;
//List Module -
{}, // DL = 29;
{}, // DT = 30;
{}, // DD = 31;
{
ATTR_START, // number // Deprecated but supported
ATTR_TYPE // cdata // Deprecated but supported
}, // OL = 32;
{}, // UL = 33;
{
ATTR_TYPE, // cdata // Deprecated but supported
ATTR_VALUE // number // Deprecated but supported
}, // LI = 34;
//Basic Forms Module -
{
ATTR_ACTION, // URL
ATTR_ENCTYPE, // cdata
ATTR_METHOD, // get | post
}, // FORM = 35;
{
ATTR_ACCESSKEY, // character
ATTR_CHECKED, // checked
ATTR_EMPTYOK, // true | false // This attribute was said to be supported on XHTML-MP1 on various sources, but verified as not
ATTR_FORMAT, // cdata // Deprecated but still supported
//ATTR_ISTYLE, // cdata // This attribute was said to be supported on XHTML-MP1 on various sources, but verified as not
//ATTR_LOCALSRC, // cdata // This attribute was said to be supported on XHTML-MP1 on various sources, but verified as not
ATTR_MAXLENGTH, // number
ATTR_NAME, // cdata
ATTR_SIZE, // cdata
ATTR_SRC, // URL
ATTR_TABINDEX, // number
ATTR_TYPE, // text | password | checkbox | radio | submit | reset | hidden
ATTR_VALUE, // cdata
ATTR_DISABLED,
ATTR_READONLY
}, // INPUT = 36;
{
ATTR_ACCESSKEY,
ATTR_FOR
}, // LABEL = 37;
{
ATTR_MULTIPLE, // multiple
ATTR_NAME, // cdata
ATTR_SIZE, // number
ATTR_TABINDEX, // number
ATTR_DISABLED,
}, // SELECT = 38;
{
ATTR_SELECTED, // selected
ATTR_VALUE, // cdata
ATTR_DISABLED,
}, // OPTION = 39;
{
ATTR_ACCESSKEY, // character
ATTR_COLS, // number
ATTR_NAME, // cdata
ATTR_ROWS, // number
ATTR_TABINDEX, // number
ATTR_DISABLED,
ATTR_READONLY
}, // TEXTAREA = 40;
//Basic Tables Module -
{
ATTR_ALIGN // top/bottom/left/right
}, // CAPTION = 41;
{
//ATTR_SUMMARY, // cdata // The summary attribute makes no visual difference in ordinary web browsers.
ATTR_BORDER,
ATTR_CELLSPACING,
ATTR_CELLPADDING,
ATTR_FRAME,
ATTR_RULES,
}, // TABLE = 42;
{
//ATTR_ABBR, // cdata // The abbr attribute makes no visual difference in ordinary web browsers.
ATTR_ALIGN, // left | center | right
//ATTR_AXIS, // cdata // The axis attribute is not supported by any of the major browsers
ATTR_COLSPAN, // number
//ATTR_HEADERS, // IDREFS // The headers attribute makes no visual difference in ordinary web browsers.
ATTR_ROWSPAN, // number
//ATTR_SCOPE, // row | col // // The scope attribute makes no visual difference in ordinary web browsers.
ATTR_VALIGN, // top | middle | bottom
ATTR_WIDTH, // number or % - deprecated but still supported
ATTR_HEIGHT, // number or % - deprecated but still supported
}, // TD = 43;
{
//ATTR_ABBR, // cdata // The abbr attribute makes no visual difference in ordinary web browsers.
ATTR_ALIGN, // left | center | right
//ATTR_AXIS, // cdata // The axis attribute is not supported by any of the major browsers
ATTR_COLSPAN, // number
//ATTR_HEADERS, // IDREFS // The headers attribute makes no visual difference in ordinary web browsers.
ATTR_ROWSPAN, // number
//ATTR_SCOPE, // row | col // // The scope attribute makes no visual difference in ordinary web browsers.
ATTR_VALIGN, // top | middle | bottom
ATTR_WIDTH, // number or % - deprecated but still supported
ATTR_HEIGHT, // number or % - deprecated but still supported
}, // TH = 44;
{
ATTR_ALIGN, // = left | center | right
ATTR_VALIGN // top | middle | bottom
}, // TR = 45;
//Image Module -
{
ATTR_ALIGN, // top | middle | bottom | left | right
ATTR_ALT, // cdata
ATTR_HEIGHT, // number[%]
ATTR_HSPACE, // number
//ATTR_LOCALSRC, // cdata // This attribute was said to be supported on XHTML-MP1 on various sources, but verified as not
//ATTR_LONGDESC, // URL //The longdesc attribute is not supported by any of the major browsers.
ATTR_SRC, // URL
ATTR_VSPACE, // number
ATTR_WIDTH, // number[%]
ATTR_USEMAP, // for HTML4
ATTR_BORDER, // for HTML4
ATTR_ISMAP // for HTML4
}, // IMG = 46;
//Object Module -
{
/* ATTR_ARCHIVE, // &URLs
ATTR_CLASSID, // URL
ATTR_CODEBASE, // URL
ATTR_CODETYPE, // cdata
ATTR_DATA, // URL
ATTR_DECLARE, // declare
ATTR_HEIGHT, // number[%]
ATTR_NAME, // cdata
ATTR_STANDBY, // cdata
ATTR_TABINDEX, // number
ATTR_TYPE, // cdata
ATTR_WIDTH, // number[%] */
}, // OBJECT = 47;
{
/* ATTR_NAME, // cdata
ATTR_TYPE, // cdata
ATTR_VALUE, // cdata
ATTR_VALUETYPE // data | ref | object */
}, // PARAM = 48;
//Metainformation Module
{
ATTR_CONTENT, // cdata
ATTR_HTTPEQUIV, // nmtoken
ATTR_NAME, // nmtoken // We do not make any use of this attribute
//ATTR_SCHEME, // cdata // We do not make any use of this attribute
}, // META = 49;
//Link Module -
{
//ATTR_CHARSET, // cdata //The charset attribute is not supported by any of the major browsers.
ATTR_HREF, // URL
//ATTR_HREFLANG, // ((?i)[A-Z]{1,8}(-[A-Z]{1,8})*)? // The hreflang attribute is not supported in any of the major browsers.
ATTR_MEDIA, // cdata
ATTR_REL, // nmtokens
//ATTR_REV, // nmtokens // The rev attribute is not supported in any of the major browsers.
ATTR_TYPE, // cdata
}, // LINK = 50;
//Base Module -
{
ATTR_HREF // URL
}, // BASE = 51;
//XHTML-MP
{
ATTR_ALIGN, // left | center | right
ATTR_SIZE, // number // Deprecated but still supported
ATTR_WIDTH, // number[%] // Deprecated but still supported
}, // HR = 52;
{
ATTR_LABEL
}, // OPTGROUP = 53
{
ATTR_MEDIA, // cdata
ATTR_TYPE, // cdata
//ATTR_XMLSPACE, // preserve // We don't use this attribute
}, // STYLE = 54
{}, //B = 55;
{}, //I = 56;
{}, //BIG = 57;
{}, //SMALL = 58;
{}, //FIELDSET = 59;
{}, //U = 60; // Underline
{
ATTR_COLOR,
ATTR_SIZE,
ATTR_FACE,
}, //FONT = 61;
{}, //DEL = 62;
{}, //INS = 63;
{}, //TT = 64;
{
ATTR_COLOR,
ATTR_SIZE,
ATTR_FACE,
}, //BASEFONT = 65;
{}, //MENU = 66; // Same as UL
{}, //S = 67; // Strike through
{}, //STRIKE = 68; // Strike through
{}, //CENTER = 69; // shorthand for DIV align=center
{}, //DIR = 70;// Same as UL
{
ATTR_NAME
}, //MAP = 71;
{
ATTR_SHAPE,
ATTR_COORDS,
ATTR_HREF,
ATTR_ALT
}, //AREA = 72;
{}, //LEGEND = 73;
{}, //SUB = 74;
{}, //SUP = 75;
{}, //NOSCRIPT = 76;
{}, //NOFRAMES = 77;
{
ATTR_ALIGN,
ATTR_VALIGN
}, //TAG_THEAD = 78;
{
ATTR_ALIGN,
ATTR_VALIGN
}, //TAG_TBODY = 79;
{
ATTR_ALIGN,
ATTR_VALIGN
}, //TAG_TFOOT = 80;
{
ATTR_ACCESSKEY, // character
ATTR_CHECKED, // checked
ATTR_EMPTYOK, // true | false // This attribute was said to be supported on XHTML-MP1 on various sources, but verified as not
ATTR_FORMAT, // cdata // Deprecated but still supported
//ATTR_ISTYLE, // cdata // This attribute was said to be supported on XHTML-MP1 on various sources, but verified as not
//ATTR_LOCALSRC, // cdata // This attribute was said to be supported on XHTML-MP1 on various sources, but verified as not
ATTR_MAXLENGTH, // number
ATTR_NAME, // cdata
ATTR_SIZE, // cdata
ATTR_SRC, // URL
ATTR_TABINDEX, // number
ATTR_TYPE, // text | password | checkbox | radio | submit | reset | hidden
ATTR_VALUE, // cdata
ATTR_DISABLED,
ATTR_READONLY
},//BUTTON = 81;
{}, //TEXT = 82;
};
//////////////////////////////////
// Types //
//////////////////////////////////
// These are the possible types for an attribute. Types define what values are acceptable to the attribute.
static final int TYPE_NUMBER = 0;
static final int TYPE_PIXELS_OR_PERCENTAGE = 1;
static final int TYPE_COLOR = 2;
static final int TYPE_ALIGN = 3; //note: there are different types of align - TD allows only left,center,right DIV allows also justify, CAPTION allows top,bottom,left,right - however we don't get to that resolution
static final int TYPE_CHAR = 4;
static final int TYPE_URL = 5;
static final int TYPE_CDATA = 6;
static final int TYPE_NMTOKENS = 7;
static final int TYPE_ID = 8;
static final int TYPE_XMLNS = 9;
static final int TYPE_LANG_CODE = 10; // ((?i)[A-Z]{1,8}(-[A-Z]{1,8})*)?
static final int TYPE_VERSION = 11;
static final int TYPE_HTTP_METHOD = 12; // get / post
static final int TYPE_BOOLEAN = 13;
static final int TYPE_CHECKED = 14;
static final int TYPE_IDREF = 15;
static final int TYPE_PRESERVE = 16;
static final int TYPE_MULTIPLE = 17;
static final int TYPE_SELECTED = 18;
static final int TYPE_IDREFS = 19;
static final int TYPE_SCOPE = 20; // row / col
static final int TYPE_VALIGN = 21; // top/middle/bottom
static final int TYPE_NMTOKEN = 22; // top/middle/bottom
static final int TYPE_DIRECTION = 23; // ltr/rtl
static final int TYPE_CSS_LENGTH = 24; // values with CSS suffixes (px/em/ex etc.)
static final int TYPE_CSS_LENGTH_OR_PERCENTAGE = 25; // values with CSS suffixes (px/em/ex etc.) or percentages
static final int TYPE_CSS_URL = 26;
static final int TYPE_CSS_LENGTH_OR_PERCENTAGE_OR_MULTIPLIER = 27; // values with CSS suffixes (px/em/ex etc.) or percentages or a number without unit that represents multiply by (i.e. 1 is 100% of the font size, 2 is 200% and so on)
/**
* This array assigns a type to each of the attributes.
*/
private static final int[] ATTRIBUTE_TYPES = {
TYPE_NMTOKENS, //"class",
TYPE_ID, //"id",
TYPE_CDATA, //"style",
TYPE_CDATA, //"title",
TYPE_XMLNS, //"xmlns",
TYPE_LANG_CODE, //"xml:lang",
TYPE_ALIGN, //"align",
TYPE_COLOR, //"bgcolor",
TYPE_COLOR, //"link",
TYPE_COLOR, //"text",
TYPE_VERSION, //"version",
TYPE_URL, //"cite",
TYPE_CHAR, //"accesskey",
TYPE_CDATA, //"charset",
TYPE_URL, //"href",
TYPE_LANG_CODE, //"hreflang",
TYPE_NMTOKENS, //"rel",
TYPE_NMTOKENS, //"rev",
TYPE_NUMBER, //"tabindex",
TYPE_CDATA, //"type",
TYPE_URL, //"action",
TYPE_CDATA, //"enctype",
TYPE_HTTP_METHOD, //"method",
TYPE_PIXELS_OR_PERCENTAGE, //"width",
TYPE_PIXELS_OR_PERCENTAGE, //"height",
TYPE_CDATA, //"alt",
TYPE_NUMBER, //"hspace",
TYPE_NUMBER, //"vspace",
TYPE_URL, //"longdesc",
TYPE_CDATA, //"localsrc",
TYPE_URL, //"src",
TYPE_CDATA, //"size",
TYPE_CHECKED, //"checked",
TYPE_BOOLEAN, //"emptyok",
TYPE_CDATA, //"format",
TYPE_CDATA, //"istyle",
TYPE_NUMBER, //"maxlength",
TYPE_CDATA, //"name",
TYPE_CDATA, //"value",
TYPE_IDREF, //"for",
TYPE_PRESERVE, //"xml:space",
TYPE_MULTIPLE, //"multiple",
TYPE_SELECTED, //"selected",
TYPE_CDATA, //"abbr",
TYPE_CDATA, //"axis",
TYPE_NUMBER, //"colspan",
TYPE_IDREFS, //"headers",
TYPE_NUMBER, //"rowspan",
TYPE_SCOPE, //"scope",
TYPE_VALIGN, //"valign",
TYPE_NUMBER, //"start",
TYPE_CDATA, //"media",
TYPE_CDATA, //"label",
TYPE_CDATA, //"summary",
TYPE_CDATA, //"content",
TYPE_NMTOKEN, //"http-equiv",
TYPE_CDATA, //"scheme",
TYPE_NUMBER, //"cols",
TYPE_NUMBER, //"rows"
TYPE_DIRECTION, //"dir"
TYPE_NUMBER, // "border"
TYPE_COLOR, // "color"
TYPE_NMTOKEN, // "face"
TYPE_NMTOKEN, // "shape"
TYPE_NMTOKEN, // "coords"
TYPE_NMTOKEN, // "usemap"
TYPE_NMTOKEN, // "lang"
TYPE_NUMBER, // "cellspacing"
TYPE_NUMBER, // "cellpadding"
TYPE_NMTOKEN, // "frame"
TYPE_NMTOKEN, // "rules"
TYPE_NMTOKEN, //ATTR_DISABLED = 71;
TYPE_NMTOKEN, //ATTR_READONLY = 72;
TYPE_NMTOKEN, //ATTR_ISMAP = 73;
};
/**
* Some types accept only a specific set of strings. For these this array defines the allowed strings.
* If the value is null it means that the type has another rule set (for example numbers only).
* This is checked against in the DOM building process.
*/
private static String[][] ALLOWED_STRINGS = {
null, // TYPE_NUMBER = 0;
null, // TYPE_PIXELS_OR_PERCENTAGE = 1;
null, // TYPE_COLOR = 2;
{"left","right","top","bottom","center","middle","justify"}, // TYPE_ALIGN = 3;
null, // TYPE_CHAR = 4;
null, // TYPE_URL = 5;
null, // TYPE_CDATA = 6;
null, // TYPE_NMTOKENS = 7;
null, // TYPE_ID = 8;
null, // TYPE_XMLNS = 9;
null, // TYPE_LANG_CODE = 10; // ((?i)[A-Z]{1,8}(-[A-Z]{1,8})*)?
null, // TYPE_VERSION = 11;
{"get","post"}, // TYPE_HTTP_METHOD = 12; // get / post
{"true","false"}, // TYPE_BOOLEAN = 13;
{"checked"}, // TYPE_CHECKED = 14;
null, // TYPE_IDREF = 15;
{"default","preserve"}, // TYPE_PRESERVE = 16;
{"multiple"}, // TYPE_MULTIPLE = 17;
{"selected"}, // TYPE_SELECTED = 18;
null, // TYPE_IDREFS = 19;
{"row","col"}, // TYPE_SCOPE = 20; // row / col
{"top","bottom","middle"}, // TYPE_VALIGN = 21; // top/middle/bottom
null, // TYPE_NMTOKEN = 22; // top/middle/bottom
{"ltr","rtl"}, // TYPE_DIRECTION
};
/**
* The allowed values for the 'frame' attribute in the 'table' tag
* (This was not placed in the ALLOWED_STRINGS in order not to add more data types, since it is very specific for this attribute)
*/
static final String[] ALLOWED_TABLE_FRAME_STRINGS =
{"void","above","below","hsides","vsides","lhs","rhs","box","border"};
/**
* The values each string of ALLOWED_TABLE_FRAME_STRINGS represents
*/
static final int[][] ALLOWED_TABLE_FRAME_VALS =
{
{}, // void
{Component.TOP}, // above
{Component.BOTTOM}, //below
{Component.TOP, Component.BOTTOM}, //hsides
{Component.LEFT, Component.RIGHT}, //vsides
{Component.LEFT}, //lhs
{Component.RIGHT}, // rhs
{Component.LEFT,Component.RIGHT,Component.TOP,Component.BOTTOM}, //box
{Component.LEFT,Component.RIGHT,Component.TOP,Component.BOTTOM}, //border
};
/**
* The allowed values for the 'rules' attribute in the 'table' tag
* (This was not placed in the ALLOWED_STRINGS in order not to add more data types, since it is very specific for this attribute)
*/
static final String[] ALLOWED_TABLE_RULES_STRINGS =
{"none","rows","cols","all","groups"};
// Additional constants used to define allowed characters for specific types
private static final int DIGITS = 1;
private static final int HEX = 2;
private static final int ABC = 4;
//////////////////////////////////
// Colors //
//////////////////////////////////
//HTML-MP colors
public static final int COLOR_AQUA = 0x00ffff;
public static final int COLOR_BLACK = 0x000000;
public static final int COLOR_BLUE = 0x0000ff;
public static final int COLOR_FUCHSIA = 0xff00ff;
public static final int COLOR_GRAY = 0x808080;
public static final int COLOR_GREEN = 0x008000;
public static final int COLOR_LIME = 0x00ff00;
public static final int COLOR_MAROON = 0x800000;
public static final int COLOR_NAVY = 0x000080;
public static final int COLOR_OLIVE = 0x808000;
public static final int COLOR_PURPLE = 0x800080;
public static final int COLOR_RED = 0xff0000;
public static final int COLOR_SILVER = 0xc0c0c0;
public static final int COLOR_TEAL = 0x008080;
public static final int COLOR_WHITE = 0xffffff;
public static final int COLOR_YELLOW = 0xffff00;
public static final int COLOR_ORANGE = 0xffa500; // Orange is added in CSS 2.1
/**
* Defines the allowed color string that are acceptable as a value to color attributes in HTML-MP1
*/
static final String[] COLOR_STRINGS = {
"aqua","black","blue","fuchsia","gray","green","lime","maroon",
"navy","olive","purple","red","silver","teal","white","yellow",
"orange","grey"
};
/**
* Assigns a color constant to each of the colors defined in COLOR_STRINGS
*/
static final int[] COLOR_VALS = {
COLOR_AQUA,COLOR_BLACK,COLOR_BLUE,COLOR_FUCHSIA,COLOR_GRAY,COLOR_GREEN,COLOR_LIME,COLOR_MAROON,
COLOR_NAVY,COLOR_OLIVE,COLOR_PURPLE,COLOR_RED,COLOR_SILVER,COLOR_TEAL,COLOR_WHITE,COLOR_YELLOW,
COLOR_ORANGE,COLOR_GRAY
};
/**
* Defines additional allowed color string that are acceptable as a value to color attributes in HTML4
*/
static final String[] MORE_COLOR_STRINGS = {
"AliceBlue","AntiqueWhite","Aqua","Aquamarine","Azure","Beige","Bisque","Black","BlanchedAlmond","Blue","BlueViolet","Brown","BurlyWood",
"CadetBlue","Chartreuse","Chocolate","Coral","CornflowerBlue","Cornsilk","Crimson","Cyan","DarkBlue","DarkCyan","DarkGoldenRod","DarkGray",
"DarkGrey","DarkGreen","DarkKhaki","DarkMagenta","DarkOliveGreen","Darkorange","DarkOrchid","DarkRed","DarkSalmon","DarkSeaGreen",
"DarkSlateBlue","DarkSlateGray","DarkSlateGrey","DarkTurquoise","DarkViolet","DeepPink","DeepSkyBlue","DimGray","DimGrey","DodgerBlue",
"FireBrick","FloralWhite","ForestGreen","Fuchsia","Gainsboro","GhostWhite","Gold","GoldenRod","Gray","Grey","Green","GreenYellow","HoneyDew",
"HotPink","IndianRed ","Indigo ","Ivory","Khaki","Lavender","LavenderBlush","LawnGreen","LemonChiffon","LightBlue","LightCoral","LightCyan",
"LightGoldenRodYellow","LightGray","LightGrey","LightGreen","LightPink","LightSalmon","LightSeaGreen","LightSkyBlue","LightSlateGray",
"LightSlateGrey","LightSteelBlue","LightYellow","Lime","LimeGreen","Linen","Magenta","Maroon","MediumAquaMarine","MediumBlue","MediumOrchid",
"MediumPurple","MediumSeaGreen","MediumSlateBlue","MediumSpringGreen","MediumTurquoise","MediumVioletRed","MidnightBlue","MintCream",
"MistyRose","Moccasin","NavajoWhite","Navy","OldLace","Olive","OliveDrab","Orange","OrangeRed","Orchid","PaleGoldenRod","PaleGreen",
"PaleTurquoise","PaleVioletRed","PapayaWhip","PeachPuff","Peru","Pink","Plum","PowderBlue","Purple","Red","RosyBrown","RoyalBlue",
"SaddleBrown","Salmon","SandyBrown","SeaGreen","SeaShell","Sienna","Silver","SkyBlue","SlateBlue","SlateGray","SlateGrey","Snow","SpringGreen",
"SteelBlue","Tan","Teal","Thistle","Tomato","Turquoise","Violet","Wheat","White","WhiteSmoke","Yellow","YellowGreen"
};
/**
* Assigns a color constant to each of the colors defined in MORE_COLOR_STRINGS
*/
static final int[] MORE_COLOR_VALS = {
0xF0F8FF,0xFAEBD7,0x00FFFF,0x7FFFD4,0xF0FFFF,0xF5F5DC,0xFFE4C4,0x000000,0xFFEBCD,0x0000FF,0x8A2BE2,0xA52A2A,0xDEB887,0x5F9EA0,0x7FFF00,0xD2691E,
0xFF7F50,0x6495ED,0xFFF8DC,0xDC143C,0x00FFFF,0x00008B,0x008B8B,0xB8860B,0xA9A9A9,0xA9A9A9,0x006400,0xBDB76B,0x8B008B,0x556B2F,0xFF8C00,0x9932CC,
0x8B0000,0xE9967A,0x8FBC8F,0x483D8B,0x2F4F4F,0x2F4F4F,0x00CED1,0x9400D3,0xFF1493,0x00BFFF,0x696969,0x696969,0x1E90FF,0xB22222,0xFFFAF0,0x228B22,
0xFF00FF,0xDCDCDC,0xF8F8FF,0xFFD700,0xDAA520,0x808080,0x808080,0x008000,0xADFF2F,0xF0FFF0,0xFF69B4,0xCD5C5C,0x4B0082,0xFFFFF0,0xF0E68C,0xE6E6FA,
0xFFF0F5,0x7CFC00,0xFFFACD,0xADD8E6,0xF08080,0xE0FFFF,0xFAFAD2,0xD3D3D3,0xD3D3D3,0x90EE90,0xFFB6C1,0xFFA07A,0x20B2AA,0x87CEFA,0x778899,0x778899,
0xB0C4DE,0xFFFFE0,0x00FF00,0x32CD32,0xFAF0E6,0xFF00FF,0x800000,0x66CDAA,0x0000CD,0xBA55D3,0x9370D8,0x3CB371,0x7B68EE,0x00FA9A,0x48D1CC,0xC71585,
0x191970,0xF5FFFA,0xFFE4E1,0xFFE4B5,0xFFDEAD,0x000080,0xFDF5E6,0x808000,0x6B8E23,0xFFA500,0xFF4500,0xDA70D6,0xEEE8AA,0x98FB98,0xAFEEEE,0xD87093,
0xFFEFD5,0xFFDAB9,0xCD853F,0xFFC0CB,0xDDA0DD,0xB0E0E6,0x800080,0xFF0000,0xBC8F8F,0x4169E1,0x8B4513,0xFA8072,0xF4A460,0x2E8B57,0xFFF5EE,0xA0522D,
0xC0C0C0,0x87CEEB,0x6A5ACD,0x708090,0x708090,0xFFFAFA,0x00FF7F,0x4682B4,0xD2B48C,0x008080,0xD8BFD8,0xFF6347,0x40E0D0,0xEE82EE,0xF5DEB3,0xFFFFFF,
0xF5F5F5,0xFFFF00,0x9ACD32
};
/**
* Converts a color string into an int value.
* This method supports color denoted in hex (with a leading #), named colors (from the standard HTML colors) and rgb(x,y,z)
*
* @param colorStr The string representing the color
* @param defaultColor Default color if color parsing can't be done
* @return The int value of the parsed color
*/
static int getColor(String colorStr,int defaultColor) {
if ((colorStr==null) || (colorStr.equals(""))) {
return defaultColor;
}
if (colorStr.charAt(0)!='#') {
if (colorStr.startsWith("rgb(")) {
colorStr=colorStr.substring(4);
char[] tokens= {',',',',')'};
int weight=256*256;
int color=0;
for(int i=0;i<3;i++) {
int index=colorStr.indexOf(tokens[i]);
if (index==-1) {
return defaultColor; // Unparsed color
}
String channelStr=colorStr.substring(0, index).trim();
int channel=HTMLComponent.calcSize(255, channelStr, 0,true);
channel=Math.min(channel, 255); // Set to 255 if over 255
channel=Math.max(channel, 0); // Set to 0 if negative
color+=channel*weight;
colorStr=colorStr.substring(index+1);
weight/=256;
}
return color;
} else {
for(int i=0;i<COLOR_STRINGS.length;i++) {
if (colorStr.equalsIgnoreCase(COLOR_STRINGS[i])) {
return COLOR_VALS[i];
}
}
if (!HTMLComponent.PROCESS_HTML_MP1_ONLY) {
for(int i=0;i<MORE_COLOR_STRINGS.length;i++) {
if (colorStr.equalsIgnoreCase(MORE_COLOR_STRINGS[i])) {
return MORE_COLOR_VALS[i];
}
}
}
}
} else {
colorStr=colorStr.substring(1);
}
if (colorStr.length()==3) { // shortened format rgb - translated to rrggbb
String newColStr="";
for(int i=0;i<3;i++) {
newColStr+=colorStr.charAt(i)+""+colorStr.charAt(i);
}
colorStr=newColStr;
}
try {
int color=Integer.parseInt(colorStr,16);
return color;
} catch (NumberFormatException nfe) {
return defaultColor;
}
}
// Member variables:
/**
* The tag ID. Upon construction of tag with a name, a lookup is performed to assign it an ID accordign to the TAG_NAMES array.
* THe ID is used to find what are the allowed attributes, and also prevents the need for further string parsing later on.
*/
private int id=TAG_UNSUPPORTED;
/**
* A vector holding all associate components
*/
private Vector comps;
/**
* If true than the UI components where calculated automatically
*/
private boolean calculatedUi = false;
/**
* Constructs and HTMLElement without specifying a name.
* This can be used by subclasses that do not require name assigments.
*/
protected HTMLElement() {
}
/**
* Constructor for HTMLElement. This mostly sets up the element's ID.
*
* @param tagName The HTMLElement's name
*/
public HTMLElement(String tagName) {
init(tagName);
}
private void init(String tagName) {
int i=0;
int tagId=-1;
while((tagId==-1) && (i<=LAST_TAG_INDEX)) { // -1 to exclude TAG_TEXT, which is given only on text element creation
if (TAG_NAMES[i].equals(tagName)) {
tagId=i;
} else {
i++;
}
}
id=tagId;
if (id==TAG_UNSUPPORTED) {
setTagName(tagName);
}
}
/**
* Constructor for HTMLElement. This mostly sets up the element's ID.
*
* @param tagName The HTMLElement's name, or the text for text elements
* @param isTextElement true for a text element, false otherwise
*/
public HTMLElement(String tagName,boolean isTextElement) {
setTextElement(isTextElement);
if (isTextElement) {
setTagName(tagName);
id=TAG_TEXT;
} else {
init(tagName);
}
}
/**
* Sets the given component or Vector of components to be associated with this element.
* This is used internally to apply CSS styling.
*
* @param obj The component (or vector of components) representing this HTMLElement
*/
void setAssociatedComponents(Object obj) {
if (obj instanceof Vector) {
comps=(Vector)obj;
} else {
comps=new Vector();
comps.addElement(obj);
}
}
/**
* Clears the associated components object
*/
void clearAssociatedComponents() {
comps=null;
}
/**
* Adds the given component to be associated with this element.
* This is used internally to apply CSS styling.
*
* @param cmp The component to add
*/
void addAssociatedComponent(Component cmp) {
if (comps==null) {
comps=new Vector();
}
comps.addElement(cmp);
}
/**
* Adds the given component to be associated with this element.
* This is used internally to apply CSS styling.
*
* @param index The index to insert the component to
* @param cmp The component to add
*/
void addAssociatedComponentAt(int index,Component cmp) {
if (comps==null) {
comps=new Vector();
}
comps.insertElementAt(cmp, index);
}
public void addChild(Element childElement) {
//if (((HTMLElement)childElement).getId()!=TAG_UNSUPPORTED) {
super.addChild(childElement);
//}
}
/**
* Returns whether this element supports the common core attributes.
* These are attributes most HTML tags support, with a few exceptions that are checked here.
* Note that to be exact the common atributes are divided to 2 groups: core attributes (class,id,title,style) and language attributes (xmlns,xml:lang)
* The tags checked here all don't support the core attributes but in fact may support the language attributes.
* Since the language attributes are not implemented anyway, this is not critical.
* For reference, tags that do not support the language attributes in XHTML-MP1 are: param, hr, base, br
*
* @return true if core attributes are supported, false otherwise
*/
private boolean supportsCoreAttributes() {
return ((id!=TAG_STYLE) && (id!=TAG_META) && (id!=TAG_HEAD) && (id!=TAG_HTML) && (id!=TAG_TITLE) && (id!=TAG_PARAM) && (id!=TAG_BASE));
}
/**
* Adds the specified attribute and value to this Element if it is supported for the Element and has a valid value.
*
* @param attribute The attribute's name
* @param value The attribute's value
*
* @return a positive error code or -1 if attribute is supported and valid
*/
public int setAttribute(String attribute,String value) {
if (id==TAG_UNSUPPORTED) {
return -1; //No error code for this case since tag not supported error is already notified before
}
int attrId=-1;
int i=0;
if (supportsCoreAttributes()) {
while ((attrId==-1) && (i<COMMON_ATTRIBUTES.length)) {
if (ATTRIBUTE_NAMES[COMMON_ATTRIBUTES[i]].equals(attribute)) {
attrId=COMMON_ATTRIBUTES[i];
} else {
i++;
}
}
}
i=0;
while ((attrId==-1) && (i<TAG_ATTRIBUTES[id].length)) {
if (ATTRIBUTE_NAMES[TAG_ATTRIBUTES[id][i]].equals(attribute)) {
attrId=TAG_ATTRIBUTES[id][i];
} else {
i++;
}
}
if (attrId==-1) {
return HTMLCallback.ERROR_ATTRIBUTE_NOT_SUPPORTED;
} else {
if (isValid(ATTRIBUTE_TYPES[attrId], value)) {
setAttribute(new Integer(attrId), value);
} else {
return HTMLCallback.ERROR_ATTIBUTE_VALUE_INVALID;
}
}
return -1;
}
/**
* Allows setting an attribute with an attribute id
*
* @param attrId The attribute Id (One of the ATTR_ constants)
* @param value The value to set to the attribute
*/
public void setAttributeById(int attrId,String value) {
if ((attrId<0) || (attrId>=ATTRIBUTE_NAMES.length)) {
throw new IllegalArgumentException("Attribute Id must be in the range of 0-"+(ATTRIBUTE_NAMES.length-1));
}
if (isValid(ATTRIBUTE_TYPES[attrId], value)) {
setAttribute(new Integer(attrId), value);
} else {
throw new IllegalArgumentException(value+" is not a valid value for attribute "+ATTRIBUTE_NAMES[attrId]);
}
}
/**
* Removes the specified attribute
*
* @param attrId The attribute Id (One of the ATTR_ constants)
*/
public void removeAttributeById(int attrId) {
if ((attrId<0) || (attrId>=ATTRIBUTE_NAMES.length)) {
throw new IllegalArgumentException("Attribute Id must be in the range of 0-"+(ATTRIBUTE_NAMES.length-1));
}
removeAttribute(new Integer(attrId));
}
/**
* Returns a list of supported attributes for this tag. Note that the list does not include the core attributes that are supported on almost all tags
*
* @return a list of supported attributes for this tag
*/
public String getSupportedAttributesList() {
if ((id<0) || (id>=TAG_ATTRIBUTES.length)) {
return "Unknown";
}
String list="";
for (int a=0;a<TAG_ATTRIBUTES[id].length;a++) {
list+=ATTRIBUTE_NAMES[TAG_ATTRIBUTES[id][a]]+",";
}
if (supportsCoreAttributes()) {
for (int a=0;a<COMMON_ATTRIBUTES.length;a++) {
list+=ATTRIBUTE_NAMES[COMMON_ATTRIBUTES[a]]+",";
}
}
if (list.endsWith(",")) {
list=list.substring(0, list.length()-1);
}
if (list.equals("")) {
list="None";
}
return list;
}
/**
* Verifies that the specified value conforms with the attribute's type restrictions.
* This basically checks the attribute type and according to that checks the value.
*
* @param attrId The attribute ID
* @param value The value to be checked
* @return true if the value is valid for this attribute, false otherwise
*/
private boolean isValid(int type,String value) {
if (value==null) { // a null value is invalid for all attributes
return false;
}
if (ALLOWED_STRINGS[type]!=null) {
return verifyStringGroup(value, ALLOWED_STRINGS[type]);
}
switch(type) {
case TYPE_NUMBER:
return verify(value, DIGITS, null);
case TYPE_PIXELS_OR_PERCENTAGE:
if (value.endsWith("%")) { //percentage
value=value.substring(0,value.length()-1);
} else if (value.endsWith("px")) { //pixels
value=value.substring(0,value.length()-2);
}
return verify(value, DIGITS, null);
case TYPE_CHAR:
return verify(value, DIGITS|ABC, null, 1, 1);
case TYPE_COLOR:
if (value.length()==0) {
return false;
}
if (value.charAt(0)!='#') {
return verifyStringGroup(value, COLOR_STRINGS);
} else {
return verify(value.substring(1), HEX, null, 3, 6); //Color can also be #rgb which means #rrggbb (as for 4,5 chars these will also be tolerated)
}
default:
return true;
}
}
/**
* A convenience method for verifying strings with no length restrictions
*
* @param value The string to be checked
* @param allowedMask DIGITS or HEX or ABC or a combination of those
* @param allowedChars Characters that are allowed even if they don't conform to the mask
* @return true if the string is valid, false otherwise.
*/
private boolean verify(String value,int allowedMask,char[] allowedChars) {
return verify(value,allowedMask,allowedChars,-1,-1);
}
/**
* Verifies that the specified string conforms with the specified restrictions.
*
* @param value The string to be checked
* @param allowedMask DIGITS or HEX or ABC or a combination of those
* @param allowedChars Characters that are allowed even if they don't conform to the mask
* @param minLength Minimum length
* @param maxLength Maximum length
* @return true if the string is valid, false otherwise.
*/
private boolean verify(String value,int allowedMask,char[] allowedChars,int minLength,int maxLength) {
if ((minLength!=-1) && (value.length()<minLength)) {
return false;
}
if ((maxLength!=-1) && (value.length()>maxLength)) {
return false;
}
int i=0;
while (i<value.length()) {
boolean found=false;
char ch=value.charAt(i);
if ((allowedMask & HEX)!=0) {
if (((ch>='0') && (ch<='9')) ||
((ch>='A') && (ch<='F')) ||
((ch>='a') && (ch<='f'))) {
found=true;
}
}
if ((allowedMask & DIGITS)!=0) {
if (((ch>='0') && (ch<='9'))) {
found=true;
} else if ((i==0) && ((ch=='-') || (ch=='+'))) { // Sign is allowed as the first character
found=true;
}
}
if ((!found) && ((allowedMask & ABC)!=0)) {
if (((ch>='a') && (ch<='z')) ||
((ch>='A') && (ch<='Z')))
{
found=true;
}
}
if ((!found) && (allowedChars!=null)) {
int c=0;
while ((!found) && (c<allowedChars.length)) {
if (ch==allowedChars[c]) {
found=true;
} else {
c++;
}
}
}
if (!found) {
return false;
}
i++;
}
return true;
}
/**
* Verifies that the specified string equals to one of the allowed strings
*
* @param value The string to be checked
* @param allowed The list of allowed strings
* @return true if the string equals to one of the allowed, false otherwise
*/
boolean verifyStringGroup(String value,String[] allowed) {
for(int i=0;i<allowed.length;i++) {
if (value.equalsIgnoreCase(allowed[i])) {
return true;
}
}
return false;
}
/**
* Returns this HTMLElement's tag name
*
* @return the HTMLElement's tag name
*/
public String getTagName() {
String name=super.getTagName();
if (name!=null) { //unsupported tags
return name;
}
// if ((id<0) || (id>=TAG_NAMES.length)) {
// return "Unsupported";
// }
return TAG_NAMES[id];
}
/**
* Returns this HTMLElement's ID
*
* @return the HTMLELement's ID
*/
public int getTagId() {
return id;
}
/**
* Sets this HTMLElement's ID
*
* @param tagId The tag ID to set, one of the TAG_* constants (Not to be confused with the id attribute)
*/
protected void setTagId(int tagId) {
this.id=tagId;
}
/**
* Returns an HTMLElement's child by a tag ID (One of the TAG_* constants)
*
* @param tagId The child's tag ID, one of the TAG_* constants (Not to be confused with the id attribute)
* @return the first child with the specified ID, or null if not found
*/
public HTMLElement getFirstChildByTagId(int tagId) {
Vector children=getChildren();
if (children==null) {
return null;
}
int i=0;
HTMLElement found=null;
while ((found==null) && (i<children.size())) {
HTMLElement child=(HTMLElement)children.elementAt(i);
if (child.getTagId()==tagId) {
found=child;
} else {
i++;
}
}
return found;
}
/**
* Returns an HTMLElement's attribute by the attribute's ID (One of the ATTR_* constants)
*
* @param id The attribute's ID
* @return the attribute with the specified ID, or null if not found
*/
public String getAttributeById(int id) {
Hashtable attributes=getAttributes();
if (attributes==null) {
return null;
}
return (String)attributes.get(new Integer(id));
}
/**
*
* {{@inheritDoc}}
*/
public String toString() {
return toString("");
}
/**
* Returns the attribute name of the requested attribute
*
* @param attrKey The attribute key, which is typically an Integer object made of its int attrId
* @return the attribute name of the requested attribute
*/
public String getAttributeName(Integer attrKey) { // This method is not static since it needs to be overriden in CSSElement
return ATTRIBUTE_NAMES[attrKey.intValue()];
}
public String getAttribute(String name) {
Hashtable attributes=getAttributes();
if (attributes!=null) {
for(int i=0;i<ATTRIBUTE_NAMES.length;i++) {
if (name.equalsIgnoreCase(ATTRIBUTE_NAMES[i])) {
return getAttributeById(i);
}
}
}
return null;
}
/**
* A recursive method for creating a printout of a full tag with its entire hierarchy.
* This is used by the public method toString().
*
* @param spacing Increased by one in each recursion phase to provide with indentation
* @return the printout of this tag
*/
private String toString(String spacing) {
String str=spacing;
if (!isTextElement()) {
str+="<"+getTagName();
Hashtable attributes=getAttributes();
if (attributes!=null) {
for(Enumeration e=attributes.keys();e.hasMoreElements();) {
Integer attrKey=(Integer)e.nextElement();
String attrStr=getAttributeName(attrKey);
String val=(String)attributes.get(attrKey);
str+=" "+attrStr+"='"+val+"' ("+attrKey+")";
}
}
str+=">\n";
Vector children=getChildren();
if (children!=null) {
for(int i=0;i<children.size();i++) {
str+=((HTMLElement)children.elementAt(i)).toString(spacing+' ');
}
}
str+=spacing+"</"+getTagName()+">\n";
} else {
str+="'"+getText()+"'\n";
}
return str;
}
/**
* Returns a vector of Components associated with this HTMLElement
*
* @return a vector of Components associated with this HTMLElement
*/
Vector getUi() {
if (comps==null) { // If no UI exists this may be a tag with children that do have UI, such as TAG_A
comps=new Vector();
Vector children=getChildren();
if (children!=null) {
for (Enumeration e=children.elements();e.hasMoreElements();) {
HTMLElement child = (HTMLElement)e.nextElement();
Vector childUI=child.getUi();
for (Enumeration e2=childUI.elements();e2.hasMoreElements();) {
comps.addElement(e2.nextElement());
}
}
}
calculatedUi=true;
}
return comps;
}
/**
* Causes a recalculation of the UI, if the UI of this element was deduced from children components
*/
void recalcUi() {
if (calculatedUi) {
comps=null;
calculatedUi=false;
}
}
/**
* {{@inheritDoc}}
*/
public void removeChildAt(int index) { // Overiding is done to clear the associated components vector of the child
HTMLElement child=(HTMLElement)getChildAt(index);
child.clearAssociatedComponents();
super.removeChildAt(index);
}
private void getDescendantsByTagIdInternal(Vector v,int tagId,int depth) {
int i=0;
Vector children=getChildren();
if (children!=null) {
while (i<children.size()) {
HTMLElement child=(HTMLElement)children.elementAt(i);
if (depth>0) {
child.getDescendantsByTagIdInternal(v, tagId, depth-1);
}
if (child.getTagId()==tagId) {
v.addElement(child);
}
i++;
}
}
}
/**
* Returns all descendants with the specified tag id
*
* @param tagId The tag ID to look for, one of the TAG_* constants (Not to be confused with the id attribute)
* @param depth The search depth (1 - children, 2 - grandchildren .... DEPTH_INFINITE - for all descendants)
* @return A vector containing descendants with the specified tag id
*/
public Vector getDescendantsByTagId(int tagId,int depth) {
if (depth<1) {
throw new IllegalArgumentException("Depth must be 1 or higher");
}
if (isEmpty()) {
return null;
}
Vector v=new Vector();
getDescendantsByTagIdInternal(v, tagId,depth);
return v;
}
/**
* Returns all descendants with the specified tag id
*
* @param tagId The tag ID to look for, one of the TAG_* constants (Not to be confused with the id attribute)
* @return A vector containing descendants with the specified tag id
*/
public Vector getDescendantsByTagId(int tagId) {
return getDescendantsByTagId(tagId, DEPTH_INFINITE);
}
/**
* Returns true if this element is the first non-text child of its parent
* This is used internally for the :first-child pseudo class
*
* @return true if this element is the first non-text child of its parent
*/
boolean isFirstChild() {
if ((HTMLComponent.PROCESS_HTML_MP1_ONLY) || (isTextElement())) { // :first-child is not supported in HTML-MP1
return false;
}
HTMLElement parent = (HTMLElement)getParent();
if (parent!=null) {
Vector v=parent.getChildren();
for(Element e : parent) {
HTMLElement elem = (HTMLElement)e;
if (elem==this) {
return true;
}
if (!elem.isTextElement()) {
return false;
}
}
}
return false;
}
}