001    /* 
002        Licensed to the Apache Software Foundation (ASF) under one
003        or more contributor license agreements.  See the NOTICE file
004        distributed with this work for additional information
005        regarding copyright ownership.  The ASF licenses this file
006        to you under the Apache License, Version 2.0 (the
007        "License"); you may not use this file except in compliance
008        with the License.  You may obtain a copy of the License at
009    
010           http://www.apache.org/licenses/LICENSE-2.0
011    
012        Unless required by applicable law or agreed to in writing,
013        software distributed under the License is distributed on an
014        "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015        KIND, either express or implied.  See the License for the
016        specific language governing permissions and limitations
017        under the License.  
018     */
019    package org.apache.wiki.render;
020    
021    import java.io.IOException;
022    import java.io.StringWriter;
023    import java.util.Iterator;
024    
025    import org.jdom2.Attribute;
026    import org.jdom2.Element;
027    import org.jdom2.output.Format;
028    import org.jdom2.output.XMLOutputter;
029    
030    import org.apache.wiki.WikiContext;
031    import org.apache.wiki.htmltowiki.XHtmlToWikiConfig;
032    import org.apache.wiki.parser.WikiDocument;
033    
034    /**
035     *  Implements a WikiRendered that outputs XHTML in a format that is suitable
036     *  for use by a WYSIWYG XHTML editor.
037     *
038     *  @since  2.5
039     */
040    public class WysiwygEditingRenderer
041        extends WikiRenderer
042    {
043    
044        private static final String A_ELEMENT = "a";
045    //    private static final String PRE_ELEMENT = "pre";
046        private static final String CLASS_ATTRIBUTE = "class";
047        private static final String HREF_ATTRIBUTE = "href";
048        private static final String TITLE_ATTRIBUTE = "title";
049        private static final String EDITPAGE = "createpage";
050        private static final String WIKIPAGE = "wikipage";
051        private static final String LINEBREAK = "\n";
052        private static final String LINKS_TRANSLATION = "$1#$2";
053        private static final String LINKS_SOURCE = "(.+)#section-.+-(.+)";
054    
055        /**
056         *  Creates a WYSIWYG editing renderer.
057         *  
058         *  @param context {@inheritDoc}
059         *  @param doc {@inheritDoc}
060         */
061        public WysiwygEditingRenderer( WikiContext context, WikiDocument doc )
062        {
063            super( context, doc );
064        }
065    
066        /*
067         * Recursively walk the XHTML DOM tree and manipulate specific elements to
068         * make them better for WYSIWYG editing.
069         */
070        private void processChildren(Element baseElement)
071        {
072            for( Iterator itr = baseElement.getChildren().iterator(); itr.hasNext(); )
073            {
074                Object childElement = itr.next();
075                if( childElement instanceof Element )
076                {
077                    Element element = (Element)childElement;
078                    String elementName = element.getName().toLowerCase();
079                    Attribute classAttr = element.getAttribute( CLASS_ATTRIBUTE );
080    
081                    if( elementName.equals( A_ELEMENT ) )
082                    {
083                        if( classAttr != null )
084                        {
085                            String classValue = classAttr.getValue();
086                            Attribute hrefAttr = element.getAttribute( HREF_ATTRIBUTE );
087    
088                            XHtmlToWikiConfig wikiConfig = new XHtmlToWikiConfig( m_context );
089    
090                            // Get the url for wiki page link - it's typically "Wiki.jsp?page=MyPage"
091                            // or when using the ShortURLConstructor option, it's "wiki/MyPage" .
092                            String wikiPageLinkUrl = wikiConfig.getWikiJspPage();
093                            String editPageLinkUrl = wikiConfig.getEditJspPage();
094    
095                            if( classValue.equals( WIKIPAGE )
096                                || ( hrefAttr != null && hrefAttr.getValue().startsWith( wikiPageLinkUrl ) ) )
097                            {
098                                // Remove the leading url string so that users will only see the
099                                // wikipage's name when editing an existing wiki link.
100                                // For example, change "Wiki.jsp?page=MyPage" to just "MyPage".
101                                String newHref = hrefAttr.getValue().substring( wikiPageLinkUrl.length() );
102    
103                                // Convert "This%20Pagename%20Has%20Spaces" to "This Pagename Has Spaces"
104                                newHref = m_context.getEngine().decodeName( newHref );
105    
106                                // Handle links with section anchors.
107                                // For example, we need to translate the html string "TargetPage#section-TargetPage-Heading2"
108                                // to this wiki string: "TargetPage#Heading2".
109                                hrefAttr.setValue( newHref.replaceFirst( LINKS_SOURCE, LINKS_TRANSLATION ) );
110                            }
111                            else if( hrefAttr != null && (classValue.equals( EDITPAGE ) ||
112                                                          hrefAttr.getValue().startsWith( editPageLinkUrl ) ) )
113                            {
114                                Attribute titleAttr = element.getAttribute( TITLE_ATTRIBUTE );
115                                if( titleAttr != null )
116                                {
117                                    // remove the title since we don't want to eventually save the default undefined page title.
118                                    titleAttr.detach();
119                                }
120    
121                                String newHref = hrefAttr.getValue().substring( editPageLinkUrl.length() );
122                                newHref = m_context.getEngine().decodeName( newHref );
123    
124                                hrefAttr.setValue( newHref );
125                            }
126                        }
127                    } // end of check for "a" element
128                    
129                    processChildren( element );
130                }
131            }
132        }
133    
134        /**
135         *  {@inheritDoc}
136         */
137        public String getString()
138            throws IOException
139        {
140            Element rootElement = m_document.getRootElement();
141            processChildren( rootElement );
142    
143            m_document.setContext( m_context );
144    
145            XMLOutputter output = new XMLOutputter();
146    
147            StringWriter out = new StringWriter();
148    
149            Format fmt = Format.getRawFormat();
150            fmt.setExpandEmptyElements( false );
151            fmt.setLineSeparator( LINEBREAK );
152    
153            output.setFormat( fmt );
154            output.outputElementContent( m_document.getRootElement(), out );
155    
156            return out.toString();
157        }
158    }