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 */ 019package org.apache.wiki.ui; 020 021import java.util.Collection; 022import java.util.HashMap; 023import java.util.Iterator; 024import java.util.List; 025import java.util.Map; 026import java.util.Properties; 027import java.util.Set; 028 029import javax.servlet.jsp.PageContext; 030 031import org.apache.log4j.Logger; 032import org.apache.wiki.WikiContext; 033import org.apache.wiki.WikiEngine; 034import org.apache.wiki.api.exceptions.NoSuchVariableException; 035import org.apache.wiki.modules.ModuleManager; 036import org.apache.wiki.modules.WikiModuleInfo; 037import org.apache.wiki.preferences.Preferences; 038import org.apache.wiki.util.XmlUtil; 039import org.jdom2.Element; 040 041 042/** 043 * Defines an editor manager. An editor can be added by adding a 044 * suitable JSP file under templates/default/editors 045 * If you want your editor to include any scripts or something, you 046 * can simply request it by adding the following in your 047 * ini/jspwiki_module.xml: 048 * 049 * <pre> 050 * <modules> 051 * <editor name="myeditor"> 052 * <author>Janne Jalkanen</author> 053 * <script>foo.js</script> 054 * <stylesheet>foo.css</stylesheet> 055 * <path>editors/myeditor.jsp</path> 056 * </editor> 057 * </modules> 058 * </pre> 059 * 060 * @since 2.4 061 */ 062public class EditorManager extends ModuleManager { 063 064 /** The property name for setting the editor. Current value is "jspwiki.editor" */ 065 /* not used anymore -- replaced by defaultpref.template.editor */ 066 public static final String PROP_EDITORTYPE = "jspwiki.editor"; 067 068 /** Parameter for changing editors at run-time */ 069 public static final String PARA_EDITOR = "editor"; 070 071 /** Known name for the plain wikimarkup editor. */ 072 public static final String EDITOR_PLAIN = "plain"; 073 074 /** Known name for the preview editor component. */ 075 public static final String EDITOR_PREVIEW = "preview"; 076 077 /** Known attribute name for storing the user edited text inside a HTTP parameter. */ 078 public static final String REQ_EDITEDTEXT = "_editedtext"; 079 080 /** Known attribute name for storing the user edited text inside a session or a page context */ 081 public static final String ATTR_EDITEDTEXT = REQ_EDITEDTEXT; 082 083 private Map<String, WikiEditorInfo> m_editors; 084 085 private static Logger log = Logger.getLogger( EditorManager.class ); 086 087 public EditorManager( WikiEngine engine ) 088 { 089 super(engine); 090 } 091 092 /** 093 * Initializes the EditorManager. It also registers any editors it can find. 094 * 095 * @param props Properties for setup. 096 */ 097 public void initialize( Properties props ) 098 { 099 registerEditors(); 100 } 101 102 /** 103 * This method goes through the jspwiki_module.xml files and hunts for editors. 104 * Any editors found are put in the registry. 105 * 106 */ 107 private void registerEditors() { 108 log.info( "Registering editor modules" ); 109 m_editors = new HashMap<String, WikiEditorInfo>(); 110 111 // 112 // Register all editors which have created a resource containing its properties. 113 // 114 // Get all resources of all modules 115 // 116 List< Element > editors = XmlUtil.parse( PLUGIN_RESOURCE_LOCATION, "/modules/editor" ); 117 118 for( Iterator< Element > i = editors.iterator(); i.hasNext(); ) { 119 Element pluginEl = i.next(); 120 String name = pluginEl.getAttributeValue( "name" ); 121 WikiEditorInfo info = WikiEditorInfo.newInstance( name, pluginEl ); 122 123 if( checkCompatibility(info) ) { 124 m_editors.put( name, info ); 125 log.debug( "Registered editor " + name ); 126 } else { 127 log.info( "Editor '" + name + "' not compatible with this version of JSPWiki." ); 128 } 129 } 130 } 131 132 /** 133 * Returns an editor for the current context. The editor names are matched in 134 * a case insensitive manner. At the moment, the only place that this method 135 * looks in is the property file, but in the future this will also look at 136 * user preferences. 137 * <p> 138 * Determines the editor to use by the following order of conditions: 139 * 1. Editor set in User Preferences 140 * 2. Default Editor set in jspwiki.properties 141 * <p> 142 * For the PREVIEW context, this method returns the "preview" editor. 143 * 144 * @param context The context that is chosen. 145 * @return The name of the chosen editor. If no match could be found, will 146 * revert to the default "plain" editor. 147 */ 148 public String getEditorName( WikiContext context ) 149 { 150 if( context.getRequestContext().equals(WikiContext.PREVIEW) ) 151 return EDITOR_PREVIEW; 152 153 String editor = null; 154 155 // User has set an editor in preferences 156 editor = Preferences.getPreference( context, PARA_EDITOR ); 157 158 /* FIXME: actual default 'editor' property is read by the Preferences class */ 159 if (editor == null) 160 { 161 // or use the default editor in jspwiki.properties 162 try 163 { 164 editor = m_engine.getVariableManager().getValue( context, PROP_EDITORTYPE ); 165 } 166 catch( NoSuchVariableException e ) {} // This is fine 167 } 168 169 if (editor != null) 170 { 171 String[] editorlist = getEditorList(); 172 173 editor = editor.trim(); 174 175 for( int i = 0; i < editorlist.length; i++ ) 176 { 177 if( editorlist[i].equalsIgnoreCase(editor)) 178 { 179 return editorlist[i]; 180 } 181 } 182 } 183 184 return EDITOR_PLAIN; 185 } 186 187 /** 188 * Returns a list of editors as Strings of editor names. 189 * 190 * @return the list of available editors 191 */ 192 public String[] getEditorList() 193 { 194 String[] editors = new String[m_editors.size()]; 195 196 Set<String> keys = m_editors.keySet(); 197 198 return keys.toArray( editors ); 199 } 200 201 /** 202 * Convenience method for getting the path to the editor JSP file. 203 * 204 * @param context 205 * @return e.g. "editors/plain.jsp" 206 */ 207 public String getEditorPath( WikiContext context ) 208 { 209 String path = null; 210 211 String editor = getEditorName( context ); 212 213 WikiEditorInfo ed = m_editors.get( editor ); 214 215 if( ed != null ) 216 { 217 path = ed.getPath(); 218 } 219 else 220 { 221 path = "editors/"+editor+".jsp"; 222 } 223 224 return path; 225 } 226 227 /** 228 * Convenience function which examines the current context and attempts to figure 229 * out whether the edited text is in the HTTP request parameters or somewhere in 230 * the session. 231 * 232 * @param ctx the JSP page context 233 * @return the edited text, if present in the session page context or as a parameter 234 */ 235 public static String getEditedText( PageContext ctx ) 236 { 237 String usertext = ctx.getRequest().getParameter( REQ_EDITEDTEXT ); 238 239 if( usertext == null ) 240 { 241 usertext = (String)ctx.findAttribute( ATTR_EDITEDTEXT ); 242 } 243 244 return usertext; 245 } 246 247 /** 248 * Contains info about an editor. 249 * 250 */ 251 private static final class WikiEditorInfo 252 extends WikiModuleInfo 253 { 254 private String m_path; 255 256 protected static WikiEditorInfo newInstance( String name, Element el ) 257 { 258 if( name == null || name.length() == 0 ) return null; 259 WikiEditorInfo info = new WikiEditorInfo( name ); 260 261 info.initializeFromXML( el ); 262 return info; 263 } 264 265 protected void initializeFromXML( Element el ) 266 { 267 super.initializeFromXML( el ); 268 m_path = el.getChildText("path"); 269 } 270 271 private WikiEditorInfo( String name ) 272 { 273 super(name); 274 } 275 276 public String getPath() 277 { 278 return m_path; 279 } 280 } 281 282 /** 283 * {@inheritDoc} 284 */ 285 @Override 286 public Collection modules() { 287 return modules( m_editors.values().iterator() ); 288 } 289 290 /** 291 * {@inheritDoc} 292 */ 293 @Override 294 public WikiEditorInfo getModuleInfo(String moduleName) { 295 return m_editors.get(moduleName); 296 } 297 298}