From ff301d6e8ee9812b8022daccf28324fedcd349a4 Mon Sep 17 00:00:00 2001 From: klopfdreh Date: Tue, 20 Jan 2015 00:21:34 +0100 Subject: [PATCH 1/3] Wicket-5801 Responsive Images --- .../wicket/markup/html/image/Image.java | 277 +++++++++++++++--- .../wicket/markup/html/image/Picture.java | 67 +++++ .../wicket/markup/html/image/Source.java | 123 ++++++++ .../html/image/ImagePictureTestPage.html | 13 + .../html/image/ImagePictureTestPage.java | 45 +++ .../image/ImageResourceReferenceTestPage.html | 9 + .../image/ImageResourceReferenceTestPage.java | 46 +++ .../html/image/ImageSrcSetTestPage.html | 9 + .../html/image/ImageSrcSetTestPage.java | 37 +++ .../html/image/ResponsiveImageTest.java | 90 ++++++ .../apache/wicket/examples/images/Home.html | 6 + .../apache/wicket/examples/images/Home.java | 32 ++ .../wicket/examples/images/Image2_large.gif | Bin 0 -> 1562 bytes .../wicket/examples/images/Image2_medium.gif | Bin 0 -> 1276 bytes .../wicket/examples/images/Image2_small.gif | Bin 0 -> 1092 bytes 15 files changed, 718 insertions(+), 36 deletions(-) create mode 100644 wicket-core/src/main/java/org/apache/wicket/markup/html/image/Picture.java create mode 100644 wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java create mode 100644 wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.html create mode 100644 wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.java create mode 100644 wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.html create mode 100644 wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java create mode 100644 wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.html create mode 100644 wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.java create mode 100644 wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java create mode 100644 wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_large.gif create mode 100644 wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_medium.gif create mode 100644 wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_small.gif diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java index 93d447541d9..5101e80ffbe 100644 --- a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java @@ -17,6 +17,9 @@ package org.apache.wicket.markup.html.image; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import org.apache.wicket.Component; import org.apache.wicket.IResourceListener; @@ -32,22 +35,37 @@ import org.apache.wicket.request.resource.ResourceReference; /** - * An Image component displays a localizable image resource. + * An Image component displays localizable image resources. *

* For details of how Images load, generate and manage images, see {@link LocalizedImageResource}. * + * The first ResourceReference / ImageResource is used for the src attribute within the img tag, all + * following are applied to the srcset. If setXValues(String... values) is used the values are set + * behind the srcset elements in the order they are given to the setXValues(String... valus) method. + * The separated values in the sizes attribute are set with setSizes(String... sizes) + * * @see NonCachingImage * * @author Jonathan Locke + * @author Tobias Soloschenko * */ public class Image extends WebComponent implements IResourceListener { private static final long serialVersionUID = 1L; - /** The image resource this image component references */ + /** The image resource this image component references (src attribute) */ private final LocalizedImageResource localizedImageResource = new LocalizedImageResource(this); + /** The image resources this image component references (srcset attribute) */ + private final List localizedImageResources = new ArrayList(); + + /** The x values to be used within the srcset */ + private List xValues = null; + + /** The sizes of the responsive images */ + private List sizes = null; + /** * This constructor can be used if you override {@link #getImageResourceReference()} or * {@link #getImageResource()} @@ -72,11 +90,14 @@ protected Image(final String id) * @param id * See Component * @param resourceReference - * The shared image resource + * The shared image resource used in the src attribute + * @param resourceReferences + * The shared image resources used in the srcset attribute */ - public Image(final String id, final ResourceReference resourceReference) + public Image(final String id, final ResourceReference resourceReference, + final ResourceReference... resourceReferences) { - this(id, resourceReference, null); + this(id, resourceReference, null, resourceReferences); } /** @@ -92,15 +113,18 @@ public Image(final String id, final ResourceReference resourceReference) * @param id * See Component * @param resourceReference - * The shared image resource + * The shared image resource used in the src attribute * @param resourceParameters * The resource parameters + * @param resourceReferences + * The shared image resources used in the srcset attribute */ public Image(final String id, final ResourceReference resourceReference, - PageParameters resourceParameters) + PageParameters resourceParameters, final ResourceReference... resourceReferences) { super(id); - setImageResourceReference(resourceReference, resourceParameters); + this.setImageResourceReference(resourceParameters, resourceReference); + this.setImageResourceReferences(resourceParameters, resourceReferences); } /** @@ -114,12 +138,15 @@ public Image(final String id, final ResourceReference resourceReference, * See Component * * @param imageResource - * The image resource + * The image resource used in the src attribute + * @param imageResources + * The image resource used in the srcset attribute */ - public Image(final String id, final IResource imageResource) + public Image(final String id, final IResource imageResource, final IResource... imageResources) { super(id); - setImageResource(imageResource); + this.setImageResource(imageResource); + this.setImageResources(imageResources); } /** @@ -139,7 +166,7 @@ public Image(final String id, final IModel model) */ public Image(final String id, final String string) { - this(id, new Model<>(string)); + this(id, new Model(string)); } /** @@ -149,6 +176,10 @@ public Image(final String id, final String string) public void onResourceRequested() { localizedImageResource.onResourceRequested(null); + for (LocalizedImageResource localizedImageResource : this.localizedImageResources) + { + localizedImageResource.onResourceRequested(null); + } } /** @@ -157,28 +188,99 @@ public void onResourceRequested() */ public void setImageResource(final IResource imageResource) { - localizedImageResource.setResource(imageResource); + if (imageResource != null) + { + this.localizedImageResource.setResource(imageResource); + } } /** - * @param resourceReference - * The shared ImageResource to set. + * + * @param imageResources + * the new ImageResource to set. */ - public void setImageResourceReference(final ResourceReference resourceReference) + public void setImageResources(final IResource... imageResources) { - localizedImageResource.setResourceReference(resourceReference); + this.localizedImageResources.clear(); + for (IResource imageResource : imageResources) + { + LocalizedImageResource localizedImageResource = new LocalizedImageResource(this); + localizedImageResource.setResource(imageResource); + this.localizedImageResources.add(localizedImageResource); + } } /** * @param resourceReference - * The shared ImageResource to set. + * The resource reference to set. + */ + public void setImageResourceReference(final PageParameters parameters, + final ResourceReference resourceReference) + { + if (localizedImageResource != null) + { + if (parameters != null) + { + this.localizedImageResource.setResourceReference(resourceReference, parameters); + } + else + { + this.localizedImageResource.setResourceReference(resourceReference); + } + } + } + + /** * @param parameters * Set the resource parameters for the resource. + * @param resourceReferences + * The resource references to set. */ - public void setImageResourceReference(final ResourceReference resourceReference, - final PageParameters parameters) + public void setImageResourceReferences(final PageParameters parameters, + final ResourceReference... resourceReferences) { - localizedImageResource.setResourceReference(resourceReference, parameters); + this.localizedImageResources.clear(); + for (ResourceReference resourceReference : resourceReferences) + { + LocalizedImageResource localizedImageResource = new LocalizedImageResource(this); + if (parameters != null) + { + localizedImageResource.setResourceReference(resourceReference, parameters); + } + else + { + localizedImageResource.setResourceReference(resourceReference); + } + this.localizedImageResources.add(localizedImageResource); + } + } + + /** + * @param values + * the x values to be used in the srcset + */ + public void setXValues(String... values) + { + if (this.xValues == null) + { + xValues = new ArrayList(); + } + this.xValues.clear(); + this.xValues.addAll(Arrays.asList(values)); + } + + /** + * @param sizes + * the sizes to be used in the size + */ + public void setSizes(String... sizes) + { + if (this.sizes == null) + { + this.sizes = new ArrayList(); + } + this.sizes.clear(); + this.sizes.addAll(Arrays.asList(sizes)); } /** @@ -189,6 +291,11 @@ public Component setDefaultModel(IModel model) { // Null out the image resource, so we reload it (otherwise we'll be // stuck with the old model. + for (LocalizedImageResource localizedImageResource : this.localizedImageResources) + { + localizedImageResource.setResourceReference(null); + localizedImageResource.setResource(null); + } localizedImageResource.setResourceReference(null); localizedImageResource.setResource(null); return super.setDefaultModel(model); @@ -228,29 +335,116 @@ protected IModel initModel() @Override protected void onComponentTag(final ComponentTag tag) { - checkComponentTag(tag, "img"); super.onComponentTag(tag); - final IResource resource = getImageResource(); + if (tag.getName().equals("source")) + { + this.buildSrcSetAttribute(tag); + tag.remove("src"); + } + else + { + this.checkComponentTag(tag, "img"); + String srcAttribute = this.buildSrcAttribute(tag); + this.buildSrcSetAttribute(tag); + tag.put("src", srcAttribute); + } + this.buildSizesAttribute(tag); + } + + /** + * Builds the srcset attribute if multiple localizedImageResources are found as varargs + * + * @param tag + * the component tag + */ + protected void buildSrcSetAttribute(final ComponentTag tag) + { + int srcSetPosition = 0; + for (LocalizedImageResource localizedImageResource : this.localizedImageResources) + { + localizedImageResource.setSrcAttribute(tag); + + if (this.shouldAddAntiCacheParameter()) + { + this.addAntiCacheParameter(tag); + } + + String srcset = tag.getAttribute("srcset"); + String xValue = ""; + + // If there are xValues set process them in the applied order to the srcset attribute. + if (this.xValues != null) + { + xValue = this.xValues.size() > srcSetPosition && + this.xValues.get(srcSetPosition) != null ? " " + + this.xValues.get(srcSetPosition) : ""; + } + tag.put("srcset", (srcset != null ? srcset + ", " : "") + tag.getAttribute("src") + + xValue); + srcSetPosition++; + } + } + + /** + * Builds the src attribute + * + * @param tag + * the component tag + * @return the value of the src attribute + */ + protected String buildSrcAttribute(final ComponentTag tag) + { + final IResource resource = this.getImageResource(); if (resource != null) { - localizedImageResource.setResource(resource); + this.localizedImageResource.setResource(resource); } - final ResourceReference resourceReference = getImageResourceReference(); + final ResourceReference resourceReference = this.getImageResourceReference(); if (resourceReference != null) { - localizedImageResource.setResourceReference(resourceReference); + this.localizedImageResource.setResourceReference(resourceReference); } - localizedImageResource.setSrcAttribute(tag); + this.localizedImageResource.setSrcAttribute(tag); - if (shouldAddAntiCacheParameter()) + if (this.shouldAddAntiCacheParameter()) { - addAntiCacheParameter(tag); + this.addAntiCacheParameter(tag); } + return tag.getAttribute("src"); } /** - * Adding an image to {@link org.apache.wicket.ajax.AjaxRequestTarget} most of the times mean that the image has - * changes and must be re-rendered. + * builds the sizes attribute of the img tag + * + * @param tag + * the component tag + */ + protected void buildSizesAttribute(final ComponentTag tag) + { + // if no sizes have been set then don't build the attribute + if (this.sizes == null) + { + return; + } + String sizes = ""; + for (String size : this.sizes) + { + sizes += size + ","; + } + int lastIndexOf = sizes.lastIndexOf(","); + if (lastIndexOf != -1) + { + sizes = sizes.substring(0, lastIndexOf); + } + if (!"".equals(sizes)) + { + tag.put("sizes", sizes); + } + } + + /** + * Adding an image to {@link org.apache.wicket.ajax.AjaxRequestTarget} most of the times mean + * that the image has changes and must be re-rendered. *

* With this method the user may change this default behavior for some of her images. *

@@ -259,7 +453,7 @@ protected void onComponentTag(final ComponentTag tag) */ protected boolean shouldAddAntiCacheParameter() { - return getRequestCycle().find(AjaxRequestTarget.class) != null; + return this.getRequestCycle().find(AjaxRequestTarget.class) != null; } /** @@ -282,8 +476,17 @@ protected final void addAntiCacheParameter(final ComponentTag tag) @Override protected boolean getStatelessHint() { - return (getImageResource() == null || getImageResource() == localizedImageResource.getResource()) && + boolean stateless = (getImageResource() == null || getImageResource() == localizedImageResource.getResource()) && localizedImageResource.isStateless(); + boolean statelessList = false; + for (LocalizedImageResource localizedImageResource : this.localizedImageResources) + { + if (localizedImageResource.isStateless()) + { + statelessList = true; + } + } + return stateless || statelessList; } /** @@ -297,10 +500,12 @@ public void onComponentTagBody(final MarkupStream markupStream, final ComponentT @Override public boolean canCallListenerInterface(Method method) { - boolean isResource = method != null && IResourceListener.class.isAssignableFrom(method.getDeclaringClass()); - if (isResource && isVisibleInHierarchy()) + boolean isResource = method != null && + IResourceListener.class.isAssignableFrom(method.getDeclaringClass()); + if (isResource && this.isVisibleInHierarchy()) { - // when the image data is requested we do not care if this component is enabled in + // when the image data is requested we do not care if this component + // is enabled in // hierarchy or not, only that it is visible return true; } diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Picture.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Picture.java new file mode 100644 index 00000000000..82fc76cc2f7 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Picture.java @@ -0,0 +1,67 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.markup.html.image; + +import org.apache.wicket.markup.ComponentTag; +import org.apache.wicket.markup.html.WebMarkupContainer; +import org.apache.wicket.model.IModel; + +/** + * A component which displays localizable image resources within source and image elements as + * responsive image. Elements are added with addImage / addSource. + * + * @author Tobias Soloschenko + */ +public class Picture extends WebMarkupContainer +{ + + private static final long serialVersionUID = 1L; + + /** + * Creates a picture component + * + * @param id + * the id of the picture component + */ + public Picture(String id) + { + super(id); + } + + /** + * Creates a picture component + * + * @param id + * the id of the picture component + * @param model + * the component's model + */ + public Picture(String id, IModel model) + { + super(id, model); + } + + /** + * builds the component tag and checks the tag to be a picture + */ + @Override + protected void onComponentTag(ComponentTag tag) + { + this.checkComponentTag(tag, "picture"); + super.onComponentTag(tag); + } +} diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java new file mode 100644 index 00000000000..aa1d3ed0370 --- /dev/null +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.markup.html.image; + +import org.apache.wicket.markup.ComponentTag; +import org.apache.wicket.model.IModel; +import org.apache.wicket.request.mapper.parameter.PageParameters; +import org.apache.wicket.request.resource.IResource; +import org.apache.wicket.request.resource.ResourceReference; + +/** + * A component which displays localizable image resources within a picture tag. + * + * The source tag is the same as the image element, but it is also possible to set the media + * attribute with setMedia(String media). The second difference is that there is no src attribute, + * so every ResourceReference and ImageResource is added directly to the srcset attribute. + * + * @see org.apache.wicket.markup.html.image.Image + * @author Tobias Soloschenko + * + */ +public class Source extends Image +{ + + private static final long serialVersionUID = 1L; + + private String media = null; + + /** + * @see org.apache.wicket.markup.html.image.Image + */ + protected Source(final String id) + { + super(id); + } + + /** + * @see org.apache.wicket.markup.html.image.Image + */ + public Source(final String id, final ResourceReference... resourceReferences) + { + super(id, null, resourceReferences); + } + + /** + * @see org.apache.wicket.markup.html.image.Image + */ + public Source(final String id, PageParameters resourceParameters, + final ResourceReference... resourceReferences) + { + super(id, null, resourceParameters, resourceReferences); + } + + /** + * @see org.apache.wicket.markup.html.image.Image + */ + public Source(final String id, final IResource... imageResources) + { + super(id, null, imageResources); + } + + /** + * @see org.apache.wicket.Component#Component(String, IModel) + */ + public Source(final String id, final IModel model) + { + super(id, model); + } + + /** + * @see org.apache.wicket.markup.html.image.Image + */ + public Source(final String id, final String string) + { + super(id, string); + } + + @Override + protected void onComponentTag(ComponentTag tag) + { + checkComponentTag(tag, "source"); + super.onComponentTag(tag); + if (this.media != null) + { + tag.put("media", getMedia()); + } + } + + /** + * Sets the media attribute information + * + * @param media + * the media attribute information + */ + public void setMedia(String media) + { + this.media = media; + } + + /** + * Gets the media attribute information + * + * @return the media attribute information + */ + public String getMedia() + { + return media; + } +} diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.html b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.html new file mode 100644 index 00000000000..913da1e6e77 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.html @@ -0,0 +1,13 @@ + + + + de.test.testimage + + + + + + + + + \ No newline at end of file diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.java new file mode 100644 index 00000000000..9d963684a80 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImagePictureTestPage.java @@ -0,0 +1,45 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.markup.html.image; + +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.request.resource.PackageResourceReference; + +public class ImagePictureTestPage extends WebPage +{ + + private static final long serialVersionUID = 1L; + + public ImagePictureTestPage() + { + Picture picture = new Picture("picture"); + Source large = new Source("sourcelarge", new PackageResourceReference(this.getClass(), + "large.jpg")); + large.setMedia("(min-width: 650px)"); + large.setSizes("(min-width: 50em) 33vw"); + picture.add(large); + large.setOutputMarkupId(true); + Source medium = new Source("sourcemedium", new PackageResourceReference(this.getClass(), + "medium.jpg")); + medium.setMedia("(min-width: 465px)"); + picture.add(medium); + Image image3 = new Image("image3", new PackageResourceReference(this.getClass(), + "small.jpg")); + picture.add(image3); + this.add(picture); + } +} diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.html b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.html new file mode 100644 index 00000000000..a61db1da678 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.html @@ -0,0 +1,9 @@ + + + + de.test.testimage + + + + + \ No newline at end of file diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java new file mode 100644 index 00000000000..cb96f67ca67 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java @@ -0,0 +1,46 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.markup.html.image; + +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.image.Image; +import org.apache.wicket.markup.html.image.Picture; +import org.apache.wicket.markup.html.image.Source; +import org.apache.wicket.model.Model; +import org.apache.wicket.request.resource.PackageResourceReference; +import org.apache.wicket.request.resource.ResourceReference; + +public class ImageResourceReferenceTestPage extends WebPage +{ + + private static final long serialVersionUID = 1L; + + public ImageResourceReferenceTestPage() + { + Image image1 = new Image("image1", Model.of("Test")) + { + private static final long serialVersionUID = 1L; + + @Override + protected ResourceReference getImageResourceReference() + { + return new PackageResourceReference(this.getClass(), "small.jpg"); + } + }; + this.add(image1); + } +} diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.html b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.html new file mode 100644 index 00000000000..b5e7e714ecd --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.html @@ -0,0 +1,9 @@ + + + + de.test.testimage + + + + + \ No newline at end of file diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.java new file mode 100644 index 00000000000..cfa23268250 --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageSrcSetTestPage.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.markup.html.image; + +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.request.resource.PackageResourceReference; + +public class ImageSrcSetTestPage extends WebPage +{ + + private static final long serialVersionUID = 1L; + + public ImageSrcSetTestPage() + { + Image image2 = new Image("image2", new PackageResourceReference(this.getClass(), + "small.jpg"), new PackageResourceReference(this.getClass(), "small.jpg"), + new PackageResourceReference(this.getClass(), "medium.jpg"), + new PackageResourceReference(this.getClass(), "large.jpg")); + image2.setXValues("320w", "2x", "900w"); + image2.setSizes("(min-width: 50em) 33vw", "(min-width: 28em) 50vw", "100vw"); + this.add(image2); + } +} diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java new file mode 100644 index 00000000000..49fad034acc --- /dev/null +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java @@ -0,0 +1,90 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.wicket.markup.html.image; + +import org.apache.wicket.util.tester.TagTester; +import org.apache.wicket.util.tester.WicketTester; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +public class ResponsiveImageTest +{ + + private WicketTester wicketTester; + + @Before + public void setup() + { + wicketTester = new WicketTester(new PubApplication()); + } + + @Test + public void testSrcSetIsNotAvailableOnDefaultUsage() + { + wicketTester.startPage(ImageResourceReferenceTestPage.class); + String lastResponseAsString = wicketTester.getLastResponse().getDocument(); + TagTester createTagByAttribute = TagTester.createTagByAttribute(lastResponseAsString, "img"); + Assert.assertFalse(createTagByAttribute.hasAttribute("srcset")); + } + + @Test + public void testPictureTagIsRenderedRight() + { + wicketTester.startPage(ImagePictureTestPage.class); + String lastResponseAsString = wicketTester.getLastResponse().getDocument(); + TagTester pictureTagTester = TagTester.createTagByAttribute(lastResponseAsString, "picture"); + Assert.assertTrue(pictureTagTester.hasChildTag("img")); + Assert.assertTrue(pictureTagTester.hasChildTag("source")); + TagTester sourceTagTester = TagTester.createTagByAttribute(lastResponseAsString, "source"); + Assert.assertTrue(sourceTagTester.hasAttribute("media")); + Assert.assertEquals("(min-width: 650px)", sourceTagTester.getAttribute("media")); + Assert.assertEquals("(min-width: 50em) 33vw", sourceTagTester.getAttribute("sizes")); + } + + @Test + public void testImageTagIsRenderedWithXValuesAndSrcSet() + { + wicketTester.startPage(ImageSrcSetTestPage.class); + String lastResponseAsString = wicketTester.getLastResponse().getDocument(); + TagTester imgTagTester = TagTester.createTagByAttribute(lastResponseAsString, "img"); + Assert.assertTrue(imgTagTester.hasAttribute("src")); + Assert.assertTrue(imgTagTester.hasAttribute("srcset")); + String attribute = imgTagTester.getAttribute("srcset"); + String[] srcSetElements = attribute.split(","); + int i = 0; + for (String srcSetElement : srcSetElements) + { + if (i == 0) + { + Assert.assertTrue(srcSetElement.endsWith("320w")); + } + if (i == 1) + { + Assert.assertTrue(srcSetElement.endsWith("2x")); + } + if (i == 2) + { + Assert.assertTrue(srcSetElement.endsWith("900w")); + } + i++; + } + Assert.assertEquals("(min-width: 50em) 33vw,(min-width: 28em) 50vw,100vw", + imgTagTester.getAttribute("sizes")); + } + +} diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.html b/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.html index 76240899465..39ca8301a8e 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.html +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.html @@ -17,5 +17,11 @@ + + + + + + diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.java b/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.java index d21f242eaa8..0744f6e8660 100644 --- a/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.java +++ b/wicket-examples/src/main/java/org/apache/wicket/examples/images/Home.java @@ -23,6 +23,8 @@ import org.apache.wicket.examples.WicketExamplePage; import org.apache.wicket.markup.html.image.Image; +import org.apache.wicket.markup.html.image.Picture; +import org.apache.wicket.markup.html.image.Source; import org.apache.wicket.markup.html.image.resource.BufferedDynamicImageResource; import org.apache.wicket.markup.html.image.resource.DefaultButtonImageResource; import org.apache.wicket.markup.html.image.resource.RenderedDynamicImageResource; @@ -94,6 +96,36 @@ public Home() add(new Image("imageModelResource", new Model( new CircleDynamicImageResource(100, 100)))); + // responsive images (only for img tag) + // the first package resource reference is used for the src attribute all following for the + // srcset in the order they are given to the constructor + Image respImage = new Image("image6", new PackageResourceReference(this.getClass(), + "Image2_small.gif"), new PackageResourceReference(this.getClass(), "Image2_small.gif"), + new PackageResourceReference(this.getClass(), "Image2_medium.gif"), + new PackageResourceReference(this.getClass(), "Image2_large.gif")); + // the x values are applied after each given package resource reference in the order they + // are applied to the setter in the srcset attribute + respImage.setXValues("320w", "2x", "900w"); + // The sizes are applied comma separated to the sizes attribute + respImage.setSizes("(min-width: 50em) 33vw", "(min-width: 28em) 50vw", "100vw"); + this.add(respImage); + + // responsive images (to demonstrate the same picture is used for sources and img) + Picture picture = new Picture("picture"); + Source large = new Source("sourcelarge", new PackageResourceReference(this.getClass(), + "Image2_large.gif")); + large.setMedia("(min-width: 650px)"); + large.setSizes("(min-width: 50em) 33vw"); + picture.add(large); + large.setOutputMarkupId(true); + Source medium = new Source("sourcemedium", new PackageResourceReference(this.getClass(), + "image2_medium.gif")); + medium.setMedia("(min-width: 465px)"); + picture.add(medium); + Image image3 = new Image("image7", new PackageResourceReference(this.getClass(), + "image2_small.gif")); + picture.add(image3); + this.add(picture); } /** diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_large.gif b/wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_large.gif new file mode 100644 index 0000000000000000000000000000000000000000..f15d4c64602e51cf12a9e779f5be6a4ea0b3e770 GIT binary patch literal 1562 zcmb_bi&NB96uxTX1M)FhMy8~Ln(FV#5L8HT#3+@FN=~Jq5?jF`ZF8ekv|mS_bJECx29fhCo5s*D^VIG4&u=)+oMLU1ABE98O&id+gV;Uk=e z0pNvp7!9?s5`KUtreOy-K`<18HNZd`lb{72SPX1HOLZdEjWTkC#KmAF^kFSBVSmY# zul9SZqWy%*X8ToCuia?ny4^c9YPUlj!LCpt*-5LL*m)>mJ2YMgTnXku6IM+fcw>kI z`Ioq>w_5!t$jH}3j+*3?pI)|qDpCHoYdt%!G`VU3jqTEnp^i{mEw z7M`n0n7J~0T~*uJ{ScTDqp^Wd|#%7hP=mo4}vw{>{DTiVg&-42$r zo~A+U&e!*}StAWe^2Uv4PA_$u^1+KY2jxtsw>D}9 zuMbQAW$1HD^S++xp-Br*F9~g&`t~OW#(vTGQ>1zHymno4_&C2qLl4HTJ`}X4<;V7^ zJ015$m>t}5D}xu!iW#9jLY-H&Mb5J(x-5E{oS1fO;lwSqyFc#@*s{nwCh^hnk#h%{ z5&|YZijS-d3jFTNz!iy)cdUIqtoBs%D9@IYn}>I#@Srh&Fh1sc-;Hse6RJ{wHD#q+ zV%M5GQc_)?etSOc-VoRJwR1_8?4JSS~L$o z$~YadW_rf)72d%o28&N;M-BuRKL|T#shIdA_tJ`x&aAi?Ym<|H*F(1`{n4_poTyu+ zodtu_ayknGZdboeOuE-L<}atYJdIpQf*W zZr|1w*L6KN&M~;##K-mFwi-`MuI=`M7hSemuMr-- ze=T`e(|gC~!@SefL%cYWnW44$14QTNl~gSHCINqyO(MiJJZgp_zI8 W55slc{SDg<9xobqy1X-v%>NH`atcZS literal 0 HcmV?d00001 diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_medium.gif b/wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_medium.gif new file mode 100644 index 0000000000000000000000000000000000000000..62ffd72c885f9ae9e96303be89f1d104adcbda5c GIT binary patch literal 1276 zcmb_b|4-C)7=Ikjscq`kbTnk6T&I#1?yYuZHK!Z$rKKBV^9N}J_#QB8=d3)Ii>srP zNTzw)aqsvd94H5BfQOLf6hZ2Mcf)31Jo7SB?+#k4iGjHE>Gl5n4L#fKbI(1`^Lk#d z*Ymlp*_rki-}I4>;)@C4vOX^B;X>vzF)%Q|_??NZ2cGzbz;FLw2qHuz>~^hSAMt zj|nM+5<&~XW-T%)g;YXnA=$7%QAwecP+BN9q|mFS&`M}6G=n2X1xvw7uojH1U=1*k z220RF4U2&dXkcNOjUbaFl$2UZHu|s@nNm_|so2N`3lz1IT1(AP4^rrrtR!p6kOx0N z6VtE*`auE;!5Uy74VGvH4=e^Ypn=84Ia5ZC&`Pl}68f+fnbt}(e1%-FKvA()3?Jb% z3;-{*!)U05mGA>JF%3Jw34);ztN{knm;^2Gz+zwnn$3w!H_FHnjEliY=)+oM+Iq>1 zuhzXy(K?~A*}979wTw2dTi%&b%MNn{OQAusNSm8jJPfb}jn@HJf_cz{RZq^&owJbs zr8VZQHvb8l|A=_O@~rOWi|+Z4r|%4Rw+tOvvLdG;t0yr0X|gE49`0%V_E6fEn&sK2 z+eW;r@;Y~poIW;Imr*?0kR3YyUA=wp@|LZHZ>J_=q?GASphrJ?iI_3GM*!ZfVOIQ15q8l$aKl8`> z+6STXbC1@QZQhgEzIp#^8M)_sYI}ckH`}@r4^zH${675HVExP2_TBw(+BV~SJL9X{ z6F)3?P;=71XS(ul-?gn9?!ENBbL92~o;sH@J2m!Me$erH>Z?Vw_q;Riq?I46`D=Xk z*0#zc>jO=$xtX%?y(F7+$6JwqLN`i^f-76x2lB&dl}BpVW>!5+c>JEU8vo6GGY9%gPfi)wa$=;NXVIMC;+frAuhze=)~n*#H0l literal 0 HcmV?d00001 diff --git a/wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_small.gif b/wicket-examples/src/main/java/org/apache/wicket/examples/images/Image2_small.gif new file mode 100644 index 0000000000000000000000000000000000000000..78618077b066944574a18ad744d18f9c1585844e GIT binary patch literal 1092 zcmb_bO-q$w5S^e%TZ9lnkXGWNFc-x`X}ZvgN`=rcEAWPu@+7XbB7z`p7zBy6aFI_M zmR6QR_?bf8tEJ}GsE7$sW>OomsLV`7bUO3?h6XP0ojWsU&N=hmBPoaD_MOe8T$(2h zzxVNb4?i-$Mn^}7;CCVM9(dv#0>AygFhrKf5wUJUW(*li#*tw%qD5=STC$ETlNIfC zhMXnm$T2z5Q8vVu*by_aG9@u2mc)@TXe+Qn0}I3G7Tu#^jd8}XF`{dcS!=8_mW>r< zfuggz;Qy>e-=3 z@DwVNM_O;<@laq78m|Mc1oNN?t0EUyuObSg7=5etKS3eb7aE>i|KN2|$cAWNZ~ep0 zn_*F@70C@%-NluY>GaCcWue?>~ulfm-1i__zM zO*O-nNk!`-Qk$QSR4124pYCsdHd>Qjoq9jDr8e_=S9;#3+C7J2>gLM|A_m67#;)X! z=9e@aola=UA3QKu6WSeFw9s`sF!DEge|pZzKXW_7CQiM$vG&8}k5My8*}g#h%K5hM zxy`=C`1J#s-DldDCoiqsdtaINyd=DQ%hlMzsfKgMD<|UL7A6L=a<&I!v+8_r%8n)2 zy(fPEm?&tiZCf*U`9kCFs^GPujWZcT?^?f$gOF?SBtY#qjlNC!NAh| Yudf4@Y3;$~rG?pVpNHEMd;FB}4=!l{1^@s6 literal 0 HcmV?d00001 From b307e24eafd14795d558587761f04780ddceb27f Mon Sep 17 00:00:00 2001 From: klopfdreh Date: Thu, 22 Jan 2015 12:28:52 +0100 Subject: [PATCH 2/3] Wicket-5801 Responsive Images - CORS settings --- .../wicket/markup/html/image/Image.java | 60 +++++++++++++++++++ .../wicket/markup/html/image/Source.java | 16 +++++ 2 files changed, 76 insertions(+) diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java index 5101e80ffbe..78796b77324 100644 --- a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Image.java @@ -65,6 +65,11 @@ public class Image extends WebComponent implements IResourceListener /** The sizes of the responsive images */ private List sizes = null; + + /** + * Cross origin settings + */ + private Cors crossorigin = null; /** * This constructor can be used if you override {@link #getImageResourceReference()} or @@ -347,8 +352,13 @@ protected void onComponentTag(final ComponentTag tag) String srcAttribute = this.buildSrcAttribute(tag); this.buildSrcSetAttribute(tag); tag.put("src", srcAttribute); + } this.buildSizesAttribute(tag); + + if (this.crossorigin != null) { + tag.put("crossorigin", this.crossorigin.getRealName()); + } } /** @@ -514,4 +524,54 @@ public boolean canCallListenerInterface(Method method) return super.canCallListenerInterface(method); } } + + /** + * Gets the cross origin settings + * + * @see {@link #setCrossorigin(Cors)} + * + * @return the cross origins settings + */ + public Cors getCrossorigin() { + return this.crossorigin; + } + + /** + * Sets the cross origin settings
+ *
+ * + * anonymous: Cross-origin CORS requests for the element will not have the credentials flag set.
+ *
+ * use_credentials: Cross-origin CORS requests for the element will have the credentials flag set.
+ *
+ * no_cores: The empty string is also a valid keyword, and maps to the Anonymous state. The attribute's invalid value default is the + * Anonymous state. The missing value default, used when the attribute is omitted, is the No CORS state + * + * @param crossorigin + * the cross origins settings to set + */ + public void setCrossorigin(Cors crossorigin) { + this.crossorigin = crossorigin; + } + + /** + * To be used for the crossorigin attribute + * + * @see {@link #setCrossorigin(Cors)} + */ + public enum Cors { + anonymous("anonymous"), + use_credentials("user-credentials"), + no_cors(""); + + private String realName; + + private Cors(String realName) { + this.realName = realName; + } + + public String getRealName() { + return this.realName; + } + } } diff --git a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java index aa1d3ed0370..f9bb8c15275 100644 --- a/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java +++ b/wicket-core/src/main/java/org/apache/wicket/markup/html/image/Source.java @@ -120,4 +120,20 @@ public String getMedia() { return media; } + + /** + * Unsupported for source tag + */ + @Override + public void setCrossorigin(Cors crossorigin) { + throw new UnsupportedOperationException("It is not allowed to set the crossorigin attribute for source tag"); + } + + /** + * Unsupported for source tag + */ + @Override + public Cors getCrossorigin() { + throw new UnsupportedOperationException("It is not allowed to get the crossorigin attribute for source tag"); + } } From 4e0b0ebfb0556d85cecafacb84cbc3e4bc925702 Mon Sep 17 00:00:00 2001 From: klopfdreh Date: Thu, 22 Jan 2015 21:12:30 +0100 Subject: [PATCH 3/3] Wicket-5801 Responsive Images - CORS settings unit test --- .../markup/html/image/ImageResourceReferenceTestPage.java | 5 ++--- .../apache/wicket/markup/html/image/ResponsiveImageTest.java | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java index cb96f67ca67..0bca07168c0 100644 --- a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ImageResourceReferenceTestPage.java @@ -17,9 +17,7 @@ package org.apache.wicket.markup.html.image; import org.apache.wicket.markup.html.WebPage; -import org.apache.wicket.markup.html.image.Image; -import org.apache.wicket.markup.html.image.Picture; -import org.apache.wicket.markup.html.image.Source; +import org.apache.wicket.markup.html.image.Image.Cors; import org.apache.wicket.model.Model; import org.apache.wicket.request.resource.PackageResourceReference; import org.apache.wicket.request.resource.ResourceReference; @@ -41,6 +39,7 @@ protected ResourceReference getImageResourceReference() return new PackageResourceReference(this.getClass(), "small.jpg"); } }; + image1.setCrossorigin(Cors.anonymous); this.add(image1); } } diff --git a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java index 49fad034acc..4c00d4881ae 100644 --- a/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java +++ b/wicket-core/src/test/java/org/apache/wicket/markup/html/image/ResponsiveImageTest.java @@ -40,6 +40,7 @@ public void testSrcSetIsNotAvailableOnDefaultUsage() String lastResponseAsString = wicketTester.getLastResponse().getDocument(); TagTester createTagByAttribute = TagTester.createTagByAttribute(lastResponseAsString, "img"); Assert.assertFalse(createTagByAttribute.hasAttribute("srcset")); + Assert.assertEquals("anonymous", createTagByAttribute.getAttribute("crossorigin")); } @Test