package com.aptana.ide.editor.html;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.IProgressMonitor;
import com.aptana.ide.core.builder.BuildContext;
import com.aptana.ide.core.builder.IProblem;
import com.aptana.ide.core.builder.Warning;
import com.aptana.ide.editor.html.parsing.nodes.HTMLElementNode;
import com.aptana.ide.parsing.nodes.IParseNode;
import com.aptana.ide.parsing.nodes.IParseNodeAttribute;
public class RequiredAttributeHTMLBuildParticipant extends HTMLBuildParticipant
{
// TODO This varies by HTML version. I pulled this from HTML 4.01. From
// http://www.w3.org/TR/html4/index/attributes.html
private static Map<String, String[]> REQUIRED_ATTRIBUTES = new HashMap<String, String[]>();
static
{
REQUIRED_ATTRIBUTES.put("img", new String[] { "alt", "src" });
REQUIRED_ATTRIBUTES.put("basefont", new String[] { "size" });
REQUIRED_ATTRIBUTES.put("applet", new String[] { "width", "height" });
REQUIRED_ATTRIBUTES.put("style", new String[] { "type" });
REQUIRED_ATTRIBUTES.put("script", new String[] { "type" });
REQUIRED_ATTRIBUTES.put("textarea", new String[] { "rows", "cols" });
REQUIRED_ATTRIBUTES.put("area", new String[] { "alt" });
REQUIRED_ATTRIBUTES.put("param", new String[] { "name" });
REQUIRED_ATTRIBUTES.put("map", new String[] { "name" });
REQUIRED_ATTRIBUTES.put("bdo", new String[] { "dir" });
REQUIRED_ATTRIBUTES.put("meta", new String[] { "content" });
REQUIRED_ATTRIBUTES.put("optgroup", new String[] { "label" });
REQUIRED_ATTRIBUTES.put("form", new String[] { "action" });
}
@Override
public void build(BuildContext context, IProgressMonitor monitor)
{
if (!isHTMLFile(context))
return;
// ok we have an html file
IParseNode root = context.getRootNode();
List<IProblem> problems = walk(context, root);
context.recordNewProblems(problems);
}
private List<IProblem> walk(BuildContext context, IParseNode root)
{
List<IProblem> problems = new ArrayList<IProblem>();
if (root == null) {
return problems;
}
IParseNode[] children = root.getChildren();
for (IParseNode node : children)
{
if (node instanceof HTMLElementNode)
{
HTMLElementNode elementNode = (HTMLElementNode) node;
Collection<String> missingAttributes = getMissingAttributes(elementNode);
for (String attributeName : missingAttributes)
{
problems.add(new Warning(2, context.getFile().getFullPath().toPortableString(), getLineNumber(
context, elementNode), elementNode.getStartingOffset(), elementNode.getEndingOffset(),
"Missing required attribute '" + attributeName + "'"));
}
}
problems.addAll(walk(context, node));
}
return problems;
}
private Set<String> getMissingAttributes(HTMLElementNode elementNode)
{
String tagName = elementNode.getName();
if (!REQUIRED_ATTRIBUTES.containsKey(tagName))
return Collections.emptySet();
Set<String> missingAttributes = new HashSet<String>();
for (String attribute : REQUIRED_ATTRIBUTES.get(tagName))
{
if (!containsAttribute(elementNode, attribute))
missingAttributes.add(attribute);
}
return missingAttributes;
}
private boolean containsAttribute(HTMLElementNode elementNode, String attrName)
{
if (elementNode == null)
return false;
IParseNodeAttribute[] attrs = elementNode.getAttributes();
if (attrs == null)
return false;
for (IParseNodeAttribute attr : attrs)
{
String attributeName = attr.getName();
if (attributeName.equalsIgnoreCase(attrName))
return true;
}
return false;
}
}