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.plugin;
020
021import java.util.Map;
022
023import org.apache.wiki.WikiContext;
024import org.apache.wiki.WikiEngine;
025import org.apache.wiki.api.exceptions.PluginException;
026import org.apache.wiki.api.exceptions.ProviderException;
027import org.apache.wiki.api.plugin.WikiPlugin;
028import org.apache.wiki.attachment.Attachment;
029import org.apache.wiki.attachment.AttachmentManager;
030import org.apache.wiki.util.TextUtil;
031
032/**
033 *  Provides an image plugin for better control than is possible with a simple image inclusion.
034 *  <br> Most parameters are equivalents of the html image attributes.
035 *
036 *  <p>Parameters : </p>
037 *  <ul>
038 *  <li><b>src</b> - the source (a URL) of the image (required parameter)</li>
039 *  <li><b>align</b> - the alignment of the image</li>
040 *  <li><b>height</b> - the height of the image</li>
041 *  <li><b>width</b> - the width of the image</li>
042 *  <li><b>alt</b> - alternate text</li>
043 *  <li><b>caption</b> - the caption for the image</li>
044 *  <li><b>link</b> - the hyperlink for the image</li>
045 *  <li><b>target</b> - the target (frame) to be used for opening the image</li>
046 *  <li><b>style</b> - the style attribute of the image</li>
047 *  <li><b>class</b> - the associated class for the image</li>
048 *  <li><b>border</b> - the border for the image</li>
049 *  <li><b>title</b> - the title for the image, can be presented as a tooltip to the user</li>
050 *  </ul>
051 *
052 *  @since 2.1.4.
053 */
054// FIXME: It is not yet possible to do wiki internal links.  In order to
055//        do this cleanly, a TranslatorReader revamp is needed.
056
057public class Image
058    implements WikiPlugin
059{
060    /** The parameter name for setting the src.  Value is <tt>{@value}</tt>. */
061    public static final String PARAM_SRC      = "src";
062    /** The parameter name for setting the align.  Value is <tt>{@value}</tt>. */
063    public static final String PARAM_ALIGN    = "align";
064    /** The parameter name for setting the height.  Value is <tt>{@value}</tt>. */
065    public static final String PARAM_HEIGHT   = "height";
066    /** The parameter name for setting the width.  Value is <tt>{@value}</tt>. */
067    public static final String PARAM_WIDTH    = "width";
068    /** The parameter name for setting the alt.  Value is <tt>{@value}</tt>. */
069    public static final String PARAM_ALT      = "alt";
070    /** The parameter name for setting the caption.  Value is <tt>{@value}</tt>. */
071    public static final String PARAM_CAPTION  = "caption";
072    /** The parameter name for setting the link.  Value is <tt>{@value}</tt>. */
073    public static final String PARAM_LINK     = "link";
074    /** The parameter name for setting the target.  Value is <tt>{@value}</tt>. */
075    public static final String PARAM_TARGET   = "target";
076    /** The parameter name for setting the style.  Value is <tt>{@value}</tt>. */
077    public static final String PARAM_STYLE    = "style";
078    /** The parameter name for setting the class.  Value is <tt>{@value}</tt>. */
079    public static final String PARAM_CLASS    = "class";
080    //    public static final String PARAM_MAP      = "map";
081    /** The parameter name for setting the border.  Value is <tt>{@value}</tt>. */
082    public static final String PARAM_BORDER   = "border";
083    /** The parameter name for setting the title.  Value is <tt>{@value}</tt>. */
084    public static final String PARAM_TITLE   = "title";
085
086    /**
087     *  This method is used to clean away things like quotation marks which
088     *  a malicious user could use to stop processing and insert javascript.
089     */
090    private static String getCleanParameter( Map<String, String> params, String paramId )
091    {
092        return TextUtil.replaceEntities( params.get( paramId ) );
093    }
094
095    /**
096     *  {@inheritDoc}
097     */
098    public String execute( WikiContext context, Map<String, String> params )
099        throws PluginException
100    {
101        WikiEngine engine = context.getEngine();
102        String src     = getCleanParameter( params, PARAM_SRC );
103        String align   = getCleanParameter( params, PARAM_ALIGN );
104        String ht      = getCleanParameter( params, PARAM_HEIGHT );
105        String wt      = getCleanParameter( params, PARAM_WIDTH );
106        String alt     = getCleanParameter( params, PARAM_ALT );
107        String caption = getCleanParameter( params, PARAM_CAPTION );
108        String link    = getCleanParameter( params, PARAM_LINK );
109        String target  = getCleanParameter( params, PARAM_TARGET );
110        String style   = getCleanParameter( params, PARAM_STYLE );
111        String cssclass= getCleanParameter( params, PARAM_CLASS );
112        // String map     = getCleanParameter( params, PARAM_MAP );
113        String border  = getCleanParameter( params, PARAM_BORDER );
114        String title   = getCleanParameter( params, PARAM_TITLE );
115
116        if( src == null )
117        {
118            throw new PluginException("Parameter 'src' is required for Image plugin");
119        }
120
121        //if( cssclass == null ) cssclass = "imageplugin";
122
123        if( target != null && !validTargetValue(target) )
124        {
125            target = null; // not a valid value so ignore
126        }
127
128        try
129        {
130            AttachmentManager mgr = engine.getAttachmentManager();
131            Attachment        att = mgr.getAttachmentInfo( context, src );
132
133            if( att != null )
134            {
135                src = context.getURL( WikiContext.ATTACH, att.getName() );
136            }
137        }
138        catch( ProviderException e )
139        {
140            throw new PluginException( "Attachment info failed: "+e.getMessage() );
141        }
142
143        StringBuilder result = new StringBuilder();
144
145        result.append( "<table border=\"0\" class=\"imageplugin\"" );
146
147        if( title != null )
148        {
149            result.append(" title=\""+title+"\"");
150        }
151
152        if( align != null )
153        {
154            if( align.equals("center") )
155            {
156                result.append(" style=\"margin-left: auto; margin-right: auto; text-align:center; vertical-align:middle;\"");
157            }
158            else
159            {
160                result.append(" style=\"float:" + align + ";\"");
161            }
162        }
163
164        result.append( ">\n" );
165
166        if( caption != null )
167        {
168            result.append("<caption>"+caption+"</caption>\n");
169        }
170
171        //move css class and style to the container of the image,
172        //so it doesn't affect the caption
173        result.append( "<tr><td" );
174
175        if( cssclass != null )
176        {
177            result.append(" class=\""+cssclass+"\"");
178        }
179
180        if( style != null )
181        {
182            result.append(" style=\""+style);
183
184            // Make sure that we add a ";" to the end of the style string
185            if( result.charAt( result.length()-1 ) != ';' ) result.append(";");
186
187            result.append("\"");
188        }
189
190        result.append( ">" );
191
192        if( link != null )
193        {
194            result.append("<a href=\""+link+"\"");
195            if( target != null )
196            {
197                result.append(" target=\""+target+"\"");
198            }
199            result.append(">");
200        }
201
202        result.append( "<img src=\""+src+"\"" );
203
204        if( ht != null )     result.append(" height=\""+ht+"\"");
205        if( wt != null )     result.append(" width=\""+wt+"\"");
206        if( alt != null )    result.append(" alt=\""+alt+"\"");
207        if( border != null ) result.append(" border=\""+border+"\"");
208        // if( map != null )    result.append(" map=\""+map+"\"");
209
210        result.append(" />");
211        if( link != null )  result.append("</a>");
212        result.append("</td></tr>\n");
213
214        result.append("</table>\n");
215
216        return result.toString();
217    }
218
219    private boolean validTargetValue( String s )
220    {
221        if( s.equals("_blank")
222                || s.equals("_self")
223                || s.equals("_parent")
224                || s.equals("_top") )
225        {
226            return true;
227        }
228        else if( s.length() > 0 ) // check [a-zA-z]
229        {
230            char c = s.charAt(0);
231            return Character.isLowerCase(c) || Character.isUpperCase(c);
232        }
233        return false;
234    }
235
236}