Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/htmlcss/HTMLDocumentAdapter.java')
-rw-r--r--bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/htmlcss/HTMLDocumentAdapter.java398
1 files changed, 398 insertions, 0 deletions
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/htmlcss/HTMLDocumentAdapter.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/htmlcss/HTMLDocumentAdapter.java
new file mode 100644
index 0000000000..a2ecc232dc
--- /dev/null
+++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/htmlcss/HTMLDocumentAdapter.java
@@ -0,0 +1,398 @@
+/*******************************************************************************
+ * 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 (<style> and <link>)
+ org.w3c.dom.stylesheets.StyleSheet ss = ssl.item(i);
+
+ try {
+ query.apply((ICSSNode) ss);
+ }
+ catch (ClassCastException ex) {
+ // I can handle only CSS style
+ }
+ }
+
+ return query.getDeclaration();
+ }
+
+ /**
+ */
+ public StyleSheetList getStyleSheets() {
+ if (this.styleAdapters == null) {
+ if (this.document == null)
+ return null;
+
+ this.styleAdapters = new Vector();
+ for (Node child = this.document.getFirstChild(); child != null; child = child.getNextSibling()) {
+ if (child.getNodeType() != Node.ELEMENT_NODE)
+ continue;
+ addStyleSheet((Element) child);
+ }
+
+ removeOldStyleSheets();
+ }
+ return this;
+ }
+
+ /**
+ * Allowing the INodeAdapter to compare itself against the type
+ * allows it to return true in more than one case.
+ */
+ public boolean isAdapterForType(Object type) {
+ return (type == IStyleSheetListAdapter.class);
+ }
+
+ /**
+ */
+ public StyleSheet item(int index) {
+ if (this.styleAdapters == null)
+ return null;
+
+ List validAdapters = getValidAdapters();
+
+ if (index < 0 || index >= validAdapters.size())
+ return null;
+ org.w3c.dom.stylesheets.StyleSheet sheet = ((IStyleSheetAdapter) validAdapters.get(index)).getSheet();
+ if (sheet == null) {// for LINK element whose link is broken
+ ICSSModel model = ((AbstractStyleSheetAdapter) this.styleAdapters.elementAt(index)).createModel();
+ sheet = ((model != null) ? (StyleSheet) model.getDocument() : null);
+ }
+ return sheet;
+ }
+
+ /**
+ */
+ public void notifyChanged(INodeNotifier notifier, int eventType, Object changedFeature, Object oldValue, Object newValue, int pos) {
+ Node node = null;
+ switch (eventType) {
+ case INodeNotifier.ADD :
+ node = (Node) newValue;
+ break;
+ case INodeNotifier.REMOVE :
+ node = (Node) oldValue;
+ break;
+ case INodeNotifier.CHANGE :
+ node = (Node) notifier;
+ break;
+ default :
+ break;
+ }
+ if (node == null || node.getNodeType() != Node.ELEMENT_NODE)
+ return;
+ XMLElement element = (XMLElement) node;
+ String tagName = element.getTagName();
+ if (tagName == null)
+ return;
+
+ if (eventType == INodeNotifier.CHANGE) {
+ if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.BASE)) {
+ refreshAdapters();
+ }
+ }
+ else {
+ if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.HEAD) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.STYLE) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.LINK) || tagName.equalsIgnoreCase(HTML40Namespace.ElementName.NOSCRIPT) || tagName.equalsIgnoreCase(JSP11Namespace.ElementName.ROOT) || element.isCommentTag() || (!element.isGlobalTag() && element.isContainer())) {
+ childReplaced();
+ }
+ else if (tagName.equalsIgnoreCase(HTML40Namespace.ElementName.BASE)) {
+ refreshAdapters();
+ }
+ else {
+ String localName = element.getLocalName();
+ if (localName != null && localName.equalsIgnoreCase(HTML40Namespace.ElementName.HTML)) {
+ // taglib html tag
+ childReplaced();
+ }
+ }
+ }
+ }
+
+ /**
+ * reload LINK / @import if BASE changed
+ */
+ private void refreshAdapters() {
+ Iterator iAdapter = this.styleAdapters.iterator();
+ while (iAdapter.hasNext()) {
+ Object adapter = iAdapter.next();
+ if (adapter instanceof LinkElementAdapter) {
+ ((LinkElementAdapter) adapter).refreshSheet();
+ }
+ else if (adapter instanceof StyleElementAdapter) {
+ ICSSModel model = ((StyleElementAdapter) adapter).getModel();
+ ImportRuleCollector trav = new ImportRuleCollector();
+ trav.apply(model);
+ Iterator iRule = trav.getRules().iterator();
+ while (iRule.hasNext()) {
+ ICSSImportRule rule = (ICSSImportRule) iRule.next();
+ rule.refreshStyleSheet();
+ }
+ }
+ }
+ }
+
+ /**
+ */
+ private void notifyStyleSheetsChanged(Document target) {
+ INodeNotifier notifier = (INodeNotifier) target;
+ if (notifier == null)
+ return;
+ Collection adapters = notifier.getAdapters();
+ if (adapters == null)
+ return;
+ Iterator it = adapters.iterator();
+ if (it == null)
+ return;
+ while (it.hasNext()) {
+ INodeAdapter adapter = (INodeAdapter) it.next();
+ if (adapter instanceof StyleListener) {
+ StyleListener listener = (StyleListener) adapter;
+ listener.styleChanged();
+ }
+ }
+ }
+
+ /**
+ */
+ private void releaseOldStyleSheets() {
+ if (this.oldStyleAdapters == null)
+ return;
+ Iterator it = this.oldStyleAdapters.iterator();
+ while (it.hasNext()) {
+ IStyleSheetAdapter adapter = (IStyleSheetAdapter) it.next();
+ if (adapter == null)
+ continue;
+ // if the same adapter is in the current list,
+ // do not release
+ if (this.styleAdapters != null && this.styleAdapters.contains(adapter))
+ continue;
+ adapter.released();
+ }
+ this.oldStyleAdapters = null;
+ }
+
+ /**
+ */
+ public void releaseStyleSheets() {
+ releaseOldStyleSheets();
+
+ if (this.styleAdapters == null)
+ return;
+ Iterator it = this.styleAdapters.iterator();
+ while (it.hasNext()) {
+ IStyleSheetAdapter adapter = (IStyleSheetAdapter) it.next();
+ if (adapter != null)
+ adapter.released();
+ }
+ this.styleAdapters = null;
+ }
+
+ /**
+ */
+ private void removeOldStyleSheets() {
+ if (this.oldStyleAdapters == null)
+ return;
+ Iterator it = this.oldStyleAdapters.iterator();
+ while (it.hasNext()) {
+ IStyleSheetAdapter adapter = (IStyleSheetAdapter) it.next();
+ if (adapter == null)
+ continue;
+ // if the same adapter is in the current list,
+ // do not release
+ if (this.styleAdapters != null && this.styleAdapters.contains(adapter))
+ continue;
+ adapter.removed();
+ }
+ this.oldStyleAdapters = null;
+ }
+
+ /**
+ */
+ void setDocument(Document document) {
+ this.document = document;
+ }
+} \ No newline at end of file

Back to the top