/******************************************************************************* * Copyright (c) 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.html.core.htmlcss; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; import java.util.Iterator; import java.util.List; import java.util.Vector; import org.eclipse.wst.css.core.adapters.IStyleSheetAdapter; import org.eclipse.wst.css.core.adapters.IStyleSheetListAdapter; import org.eclipse.wst.css.core.document.ICSSImportRule; import org.eclipse.wst.css.core.document.ICSSModel; import org.eclipse.wst.css.core.document.ICSSNode; import org.eclipse.wst.css.core.util.CSSClassTraverser; import org.eclipse.wst.css.core.util.ImportRuleCollector; import org.eclipse.wst.html.core.HTML40Namespace; import org.eclipse.wst.html.core.contentmodel.JSP11Namespace; import org.eclipse.wst.sse.core.INodeAdapter; import org.eclipse.wst.sse.core.INodeNotifier; import org.eclipse.wst.xml.core.document.XMLElement; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.css.CSSStyleDeclaration; import org.w3c.dom.stylesheets.StyleSheet; import org.w3c.dom.stylesheets.StyleSheetList; /** */ public class HTMLDocumentAdapter implements IStyleSheetListAdapter, StyleSheetList { private Document document = null; private Vector styleAdapters = null; private Vector oldStyleAdapters = null; /** */ HTMLDocumentAdapter() { super(); } /** */ private void addStyleSheet(Element node) { XMLElement element = (XMLElement) node; String tagName = element.getTagName(); if (tagName == null) return; boolean isContainer = false; if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HEAD) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.NOSCRIPT) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.BASE) || tagName.equalsIgnoreCase(JSP11Namespace.ElementName.ROOT) || (!element.isGlobalTag() && element.isContainer())) { isContainer = true; } else if (element.isCommentTag()) { Node parent = element.getParentNode(); if (parent == element.getOwnerDocument()) { // This condition is too severe, actually do not work for JSF template. // But above (! globalTag() && isContainer()) cover JSF template + tpl template isContainer = true; } else if (parent.getNodeType() == Node.ELEMENT_NODE) { tagName = ((Element) parent).getTagName(); if (tagName != null && tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HEAD)) { isContainer = true; } } } else { String localName = element.getLocalName(); if (localName != null && localName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML)) { // taglib html tag isContainer = true; } else { INodeNotifier notifier = element; INodeAdapter adapter = notifier.getAdapterFor(IStyleSheetAdapter.class); if (adapter != null && adapter instanceof IStyleSheetAdapter) { this.styleAdapters.addElement(adapter); } } } if (isContainer) { INodeNotifier notifier = element; if (notifier.getExistingAdapter(IStyleSheetListAdapter.class) == null) { notifier.addAdapter(this); } for (Node child = element.getFirstChild(); child != null; child = child.getNextSibling()) { if (child.getNodeType() != Node.ELEMENT_NODE) continue; addStyleSheet((Element) child); } } } /** */ void childReplaced() { if (this.styleAdapters == null) return; // backup old adapters to be released on updating in getStyleSheets() this.oldStyleAdapters = this.styleAdapters; // invalidate the list this.styleAdapters = null; notifyStyleSheetsChanged(this.document); } /** */ public Enumeration getClasses() { StyleSheetList sheetList = getStyleSheets(); int nSheets = sheetList.getLength(); final ArrayList classes = new ArrayList(); CSSClassTraverser traverser = new CSSClassTraverser(); traverser.setTraverseImported(true); for (int i = 0; i < nSheets; i++) { org.w3c.dom.stylesheets.StyleSheet sheet = sheetList.item(i); if (sheet instanceof ICSSNode) { traverser.apply((ICSSNode) sheet); } } classes.addAll(traverser.getClassNames()); return new Enumeration() { int i = 0; public boolean hasMoreElements() { return i < classes.size(); } public Object nextElement() { return classes.get(i++); } }; } /** */ private List getValidAdapters() { Vector validAdapters = new Vector(); if (this.styleAdapters != null) { Iterator i = this.styleAdapters.iterator(); while (i.hasNext()) { Object obj = i.next(); if (obj instanceof AbstractStyleSheetAdapter && ((AbstractStyleSheetAdapter) obj).isValidAttribute()) { validAdapters.add(obj); } } } return validAdapters; } /** */ public int getLength() { return getValidAdapters().size(); } /** */ public CSSStyleDeclaration getOverrideStyle(Element element, String pseudoName) { StyleSheetList ssl = getStyleSheets(); int numStyles = ssl.getLength(); CSSQueryTraverser query = new CSSQueryTraverser(); query.setTraverseImported(true); query.setTraverseImportFirst(true); query.setElement(element, pseudoName); for (int i = 0; i < numStyles; i++) { // loop for styles (