/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.cocoon.portal.transformation; import java.io.IOException; import java.util.Map; import org.apache.avalon.framework.parameters.Parameters; import org.apache.cocoon.ProcessingException; import org.apache.cocoon.environment.SourceResolver; import org.apache.cocoon.portal.coplet.CopletInstanceData; import org.apache.cocoon.xml.AttributesImpl; import org.apache.excalibur.source.SourceUtil; import org.xml.sax.Attributes; import org.xml.sax.SAXException; /** * This transformer transforms html actions into events. * The transformer listens for the element a and form. Links * that only contain an anchor are ignored. * In addition if a link has the attribute "external" with the value * "true", the link is also ignored. * * TODO: Support target attribute * * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a> * @version CVS $Id$ */ public class HTMLEventLinkTransformer extends AbstractCopletTransformer { /** The temporary attribute used to store the uri */ protected String attributeName; /** The jxpath for the attribute */ protected String jxPath; /** * @see org.apache.cocoon.sitemap.SitemapModelComponent#setup(org.apache.cocoon.environment.SourceResolver, java.util.Map, java.lang.String, org.apache.avalon.framework.parameters.Parameters) */ public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par) throws ProcessingException, SAXException, IOException { super.setup(resolver, objectModel, src, par); this.attributeName = par.getParameter("attribute-name", "application-uri"); this.jxPath = "temporaryAttributes/" + this.attributeName; } /** * @see org.xml.sax.ContentHandler#startElement(java.lang.String, java.lang.String, java.lang.String, org.xml.sax.Attributes) */ public void startElement(String uri, String name, String raw, Attributes attr) throws SAXException { boolean processed = false; if ("a".equals(name) ) { final AttributesImpl a = this.getMutableAttributes(attr); attr = a; boolean convert = false; final boolean isRemoteAnchor = this.isRemoteAnchor(attr); if ( isRemoteAnchor ) { convert = !this.isExternalLink(a); } this.stack.push(convert ? Boolean.TRUE: Boolean.FALSE); if ( convert ) { this.createAnchorEvent(attr); processed = true; } } else if ("form".equals(name) ) { final AttributesImpl a = this.getMutableAttributes(attr); attr = a; boolean convert = !this.isExternalForm(a); this.stack.push(convert ? Boolean.TRUE: Boolean.FALSE); if ( convert ) { this.createFormEvent(attr); processed = true; } } if ( !processed ) { super.startElement(uri, name, raw, attr); } } /** * @see org.xml.sax.ContentHandler#endElement(java.lang.String, java.lang.String, java.lang.String) */ public void endElement(String uri, String name, String raw) throws SAXException { boolean processed = false; if ( "a".equals(name) ) { final Boolean converted = (Boolean)this.stack.pop(); if ( converted.booleanValue() ) { this.xmlConsumer.endElement(CopletTransformer.NAMESPACE_URI, CopletTransformer.LINK_ELEM, "coplet:" + CopletTransformer.LINK_ELEM); this.xmlConsumer.endPrefixMapping("coplet"); processed = true; } } else if ( "form".equals(name) ) { final Boolean converted = (Boolean)this.stack.pop(); if ( converted.booleanValue() ) { this.xmlConsumer.endElement(CopletTransformer.NAMESPACE_URI, CopletTransformer.LINK_ELEM, "coplet:" + CopletTransformer.LINK_ELEM); this.xmlConsumer.endPrefixMapping("coplet"); processed = true; } } if ( !processed ) { super.endElement(uri, name, raw); } } protected void createAnchorEvent(Attributes attributes) throws SAXException { AttributesImpl newAttributes = new AttributesImpl(attributes); newAttributes.removeAttribute("href"); newAttributes.removeAttribute("external"); String link = attributes.getValue("href"); CopletInstanceData cid = this.getCopletInstanceData(); link = this.getLink((String)cid.getTemporaryAttribute(this.attributeName), link); newAttributes.addCDATAAttribute("path", this.jxPath); newAttributes.addCDATAAttribute("value", link); newAttributes.addCDATAAttribute("coplet", cid.getId()); newAttributes.addCDATAAttribute("format", "html-link"); this.xmlConsumer.startPrefixMapping("coplet", CopletTransformer.NAMESPACE_URI); this.xmlConsumer.startElement(CopletTransformer.NAMESPACE_URI, CopletTransformer.LINK_ELEM, "coplet:" + CopletTransformer.LINK_ELEM, newAttributes); } protected void createFormEvent(Attributes attributes) throws SAXException { AttributesImpl newAttributes = new AttributesImpl(attributes); newAttributes.removeAttribute("action"); String link = attributes.getValue("action"); CopletInstanceData cid = this.getCopletInstanceData(); link = this.getLink((String)cid.getTemporaryAttribute(this.attributeName), link); newAttributes.addCDATAAttribute("path", this.jxPath); newAttributes.addCDATAAttribute("value", link); newAttributes.addCDATAAttribute("coplet", cid.getId()); newAttributes.addCDATAAttribute("format", "html-form"); if ( newAttributes.getIndex("method") == -1 ) { newAttributes.addCDATAAttribute("method", "POST"); } this.xmlConsumer.startPrefixMapping("coplet", CopletTransformer.NAMESPACE_URI); this.xmlConsumer.startElement(CopletTransformer.NAMESPACE_URI, CopletTransformer.LINK_ELEM, "coplet:" + CopletTransformer.LINK_ELEM, newAttributes); } protected String getLink(String base, String link) { final String v = SourceUtil.absolutize(base, link); return v; } /** * Determine if the element is an url and if the url points to some * remote source. * * @param attributes the attributes of the element * @return true if the href url is an anchor pointing to a remote source */ protected boolean isRemoteAnchor(Attributes attributes) { String link = attributes.getValue("href"); // no empty link to current document if (link != null && link.trim().length() > 0) { // check reference to document fragment if (!link.trim().startsWith("#")) { return true; } } return false; } /** * Is this link an external link? * A link in an external application is not transformed * if there is an attribute external="true" in the link-element * or if the link starts with "mailto:" or "javascript:". * * @param attributes attributes of the node * @return true if the attribute 'external' is 'true' */ private boolean isExternalLink (AttributesImpl attributes) { final String external = attributes.getValue("external"); // remote attribute if ( external != null ) { attributes.removeAttribute("external"); } // links to external documents will be not transformed to portal links if (external != null && external.trim().length() > 0 && external.trim().toLowerCase().equals ("true") ) { return true; } final String link = attributes.getValue("href"); if ( link != null && (link.startsWith("mailto:") || link.startsWith("javascript:") ) ) { return true; } return false; } /** * Does this form contain an external action? * A form is not transformed if there is an attribute * external="true" in the form action or if the action * starts with "javascript:". * * @param attributes attributes of the node * @return True if the action is external. */ private boolean isExternalForm(AttributesImpl attributes) { final String external = attributes.getValue("external"); // remote attribute if ( external != null ) { attributes.removeAttribute("external"); } // links to external documents will be not transformed to portal links if (external != null && external.trim().length() > 0 && external.trim().toLowerCase().equals ("true") ) { return true; } final String link = attributes.getValue("action"); if ( link != null && link.startsWith("javascript:") ) { return true; } return false; } }