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