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 }