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