001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.wicket.markup.html.image; 018 019import java.io.Serializable; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.Collections; 023import java.util.List; 024 025import org.apache.wicket.markup.ComponentTag; 026import org.apache.wicket.markup.html.CrossOrigin; 027import org.apache.wicket.markup.html.WebComponent; 028import org.apache.wicket.model.IModel; 029import org.apache.wicket.model.Model; 030 031/** 032 * A component to display external images. The src / srcSet information are hold in models 033 * 034 * @see org.apache.wicket.markup.html.image.Image 035 * 036 * @author Tobias Soloschenko 037 * @author Sebastien Briquet 038 * @author Sven Meier 039 * @author Martin Grigorov 040 * 041 */ 042public class ExternalImage extends WebComponent 043{ 044 045 private static final long serialVersionUID = 1L; 046 047 /** The x values to be used within the srcset */ 048 private List<String> xValues = null; 049 050 /** The sizes of the responsive images */ 051 private List<String> sizes = null; 052 053 /** 054 * Cross origin settings 055 */ 056 private CrossOrigin crossOrigin = null; 057 058 private IModel<List<Serializable>> srcSetModel; 059 060 /** 061 * Creates an external image 062 * 063 * @param id 064 * the component id 065 */ 066 public ExternalImage(String id) 067 { 068 this(id, null, Model.ofList(Collections.emptyList())); 069 } 070 071 /** 072 * Creates an external image 073 * 074 * @param id 075 * the component id 076 * @param src 077 * the source URL 078 */ 079 public ExternalImage(String id, Serializable src) 080 { 081 this(id, Model.of(src), Model.ofList(Collections.<Serializable> emptyList())); 082 } 083 084 /** 085 * Creates an external image 086 * 087 * @param id 088 * the component id 089 * @param src 090 * the source URL 091 * @param srcSet 092 * a list of URLs placed in the srcSet attribute 093 */ 094 public ExternalImage(String id, Serializable src, List<Serializable> srcSet) 095 { 096 this(id, Model.of(src), Model.ofList(srcSet)); 097 } 098 099 /** 100 * Creates an external image 101 * 102 * @param id 103 * the component id 104 * @param srcModel 105 * the model source URL 106 */ 107 public ExternalImage(String id, IModel<Serializable> srcModel) 108 { 109 this(id, srcModel, Model.ofList(Collections.emptyList())); 110 } 111 112 /** 113 * Creates an external image 114 * 115 * @param id 116 * the component id 117 * @param srcModel 118 * the model source URL 119 * @param srcSetModel 120 * a model list of URLs placed in the srcSet attribute 121 */ 122 public ExternalImage(String id, IModel<Serializable> srcModel, 123 IModel<List<Serializable>> srcSetModel) 124 { 125 super(id, srcModel); 126 this.srcSetModel = srcSetModel; 127 } 128 129 @Override 130 protected void onComponentTag(ComponentTag tag) 131 { 132 super.onComponentTag(tag); 133 134 if (!"source".equals(tag.getName())) 135 { 136 checkComponentTag(tag, "img"); 137 buildSrcAttribute(tag, getDefaultModel()); 138 } 139 buildSrcSetAttribute(tag, getSrcSetModel()); 140 141 buildSizesAttribute(tag); 142 143 CrossOrigin crossOrigin = getCrossOrigin(); 144 if (crossOrigin != null && CrossOrigin.NO_CORS != crossOrigin) 145 { 146 tag.put("crossOrigin", crossOrigin.getRealName()); 147 } 148 } 149 150 /** 151 * Builds the src attribute 152 * 153 * @param tag 154 * the component tag 155 * @param srcModel 156 * the model containing the src URL 157 */ 158 protected void buildSrcAttribute(final ComponentTag tag, IModel<?> srcModel) 159 { 160 tag.put("src", String.valueOf(srcModel.getObject())); 161 } 162 163 /** 164 * Builds the srcset attribute if multiple models are found as varargs 165 * 166 * @param tag 167 * the component tag 168 * @param srcSetModel 169 * the models containing the src set URLs 170 */ 171 protected void buildSrcSetAttribute(final ComponentTag tag, 172 IModel<List<Serializable>> srcSetModel) 173 { 174 int srcSetPosition = 0; 175 List<Serializable> srcSetItems = srcSetModel.getObject(); 176 for (Serializable srcSet : srcSetItems) 177 { 178 String srcset = tag.getAttribute("srcset"); 179 String xValue = ""; 180 181 // If there are xValues set process them in the applied order to the srcset 182 // attribute. 183 if (xValues != null) 184 { 185 xValue = xValues.size() > srcSetPosition && xValues.get(srcSetPosition) != null 186 ? " " + xValues.get(srcSetPosition) : ""; 187 } 188 tag.put("srcset", (srcset != null ? srcset + ", " : "") + srcSet + xValue); 189 srcSetPosition++; 190 } 191 } 192 193 /** 194 * builds the sizes attribute of the img tag 195 * 196 * @param tag 197 * the component tag 198 */ 199 protected void buildSizesAttribute(final ComponentTag tag) 200 { 201 // if no sizes have been set then don't build the attribute 202 if (sizes == null) 203 { 204 return; 205 } 206 String sizes = ""; 207 for (String size : this.sizes) 208 { 209 sizes += size + ","; 210 } 211 int lastIndexOf = sizes.lastIndexOf(","); 212 if (lastIndexOf != -1) 213 { 214 sizes = sizes.substring(0, lastIndexOf); 215 } 216 if (!sizes.isEmpty()) 217 { 218 tag.put("sizes", sizes); 219 } 220 } 221 222 /** 223 * @param values 224 * the x values to be used in the srcset 225 */ 226 public void setXValues(String... values) 227 { 228 if (xValues == null) 229 { 230 xValues = new ArrayList<>(); 231 } 232 else 233 { 234 xValues.clear(); 235 } 236 xValues.addAll(Arrays.asList(values)); 237 } 238 239 /** 240 * Removes all sizes values. The corresponding tag will not be rendered anymore. 241 */ 242 public void removeSizes() 243 { 244 if (sizes != null) 245 { 246 sizes.clear(); 247 } 248 } 249 250 /** 251 * @param sizes 252 * the sizes to be used in the size 253 */ 254 public void setSizes(String... sizes) 255 { 256 if (this.sizes == null) 257 { 258 this.sizes = new ArrayList<>(); 259 } 260 else 261 { 262 this.sizes.clear(); 263 } 264 this.sizes.addAll(Arrays.asList(sizes)); 265 } 266 267 /** 268 * Removes all x values from the image src set. 269 */ 270 public void removeXValues() 271 { 272 if (xValues != null) 273 { 274 xValues.clear(); 275 } 276 } 277 278 /** 279 * Gets the cross origin settings 280 * 281 * @see org.apache.wicket.markup.html.image.Image#setCrossOrigin(CrossOrigin) 282 * 283 * @return the cross origins settings 284 */ 285 public CrossOrigin getCrossOrigin() 286 { 287 return crossOrigin; 288 } 289 290 /** 291 * Sets the cross origin settings 292 * 293 * @see org.apache.wicket.markup.html.image.Image#setCrossOrigin(CrossOrigin) 294 * @param crossOrigin 295 * the cross origins settings to set 296 */ 297 public void setCrossOrigin(CrossOrigin crossOrigin) 298 { 299 this.crossOrigin = crossOrigin; 300 } 301 302 /** 303 * Gets a list of models containing the src set values 304 * 305 * @return a list of models containing the src set values 306 */ 307 public IModel<List<Serializable>> getSrcSetModel() 308 { 309 return srcSetModel; 310 } 311 312 /** 313 * Sets the source set model 314 * 315 * @param srcSetModel 316 * the model of a list of src set entries 317 */ 318 public void setSrcSetModel(IModel<List<Serializable>> srcSetModel) 319 { 320 this.srcSetModel = srcSetModel; 321 } 322 323 /** 324 * Detaches the srcSetModels 325 */ 326 @Override 327 protected void onDetach() 328 { 329 if (srcSetModel != null) 330 { 331 srcSetModel.detach(); 332 } 333 super.onDetach(); 334 } 335}