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 }