001/* 002 * flattr4j - A Java library for Flattr 003 * 004 * Copyright (C) 2011 Richard "Shred" Körber 005 * http://flattr4j.shredzone.org 006 * 007 * This program is free software: you can redistribute it and/or modify 008 * it under the terms of the GNU General Public License / GNU Lesser 009 * General Public License as published by the Free Software Foundation, 010 * either version 3 of the License, or (at your option) any later version. 011 * 012 * Licensed under the Apache License, Version 2.0 (the "License"); 013 * you may not use this file except in compliance with the License. 014 * 015 * This program is distributed in the hope that it will be useful, 016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 018 */ 019package org.shredzone.flattr4j.web.builder; 020 021import java.io.Serializable; 022import java.net.URL; 023import java.util.Map; 024import java.util.TreeMap; 025 026import org.shredzone.flattr4j.model.AutoSubmission; 027import org.shredzone.flattr4j.model.Thing; 028import org.shredzone.flattr4j.web.BadgeType; 029 030/** 031 * Builds a static Flattr button tag. A static button works without JavaScript, but does 032 * not offer enhanced features like a click counter. 033 * <p> 034 * The builder uses sensible default settings that can be changed by using its methods. 035 * All methods return a reference to the builder itself, so method calls can be 036 * daisy-chained. 037 * <p> 038 * Example: 039 * <code>String button = new StaticButtonBuilder().url(thingUrl).toString();</code> 040 * 041 * @author Richard "Shred" Körber 042 */ 043public class StaticButtonBuilder implements Serializable { 044 private static final long serialVersionUID = 3266441765264183202L; 045 046 private String url; 047 private String badgeUrl; 048 private BadgeType type; 049 private String style; 050 private String styleClass; 051 private TreeMap<String, String> attributes = new TreeMap<String, String>(); 052 053 /** 054 * Link to the Thing page at Flattr. 055 */ 056 public StaticButtonBuilder thing(String url) { 057 this.url = url; 058 return this; 059 } 060 061 /** 062 * Link to the Thing page at Flattr by {@link AutoSubmission}. If the Thing does not 063 * exist yet, it will be created on the first click. 064 */ 065 public StaticButtonBuilder thing(AutoSubmission submission) { 066 this.url = submission.toUrl(); 067 return this; 068 } 069 070 /** 071 * Link to the Thing page at Flattr. 072 */ 073 public StaticButtonBuilder thing(Thing thing) { 074 return thing(thing.getLink()); 075 } 076 077 /** 078 * Selects the badge type to be used. Optional, defaults to the default badge. 079 */ 080 public StaticButtonBuilder badge(BadgeType type) { 081 this.type = type; 082 return this; 083 } 084 085 /** 086 * A URL to a custom badge image. If this url is given, an invocation of the 087 * {@link #badge(org.shredzone.flattr4j.web.BadgeType)} method is ignored. 088 * 089 * @param url 090 * Button image URL 091 */ 092 public StaticButtonBuilder badgeUrl(String url) { 093 this.badgeUrl = url; 094 return this; 095 } 096 097 /** 098 * A URL to a custom badge image. Convenience method that takes an URL object. 099 */ 100 public StaticButtonBuilder badgeUrl(URL url) { 101 return badgeUrl(url.toString()); 102 } 103 104 /** 105 * CSS style to be used. 106 */ 107 public StaticButtonBuilder style(String style) { 108 this.style = style; 109 return this; 110 } 111 112 /** 113 * CSS class to be used. 114 */ 115 public StaticButtonBuilder styleClass(String styleClass) { 116 this.styleClass = styleClass; 117 return this; 118 } 119 120 /** 121 * Adds a custom HTML attribute to the generated link tag. If an attribute has already 122 * been added, its value will be replaced. Attributes are written to the tag in 123 * alphabetical order. 124 * <p> 125 * Attributes are added without further checks. It is your responsibility to take care 126 * for HTML compliance. 127 * 128 * @param attribute 129 * HTML attribute to be added 130 * @param value 131 * Value of that attribute. The builder takes care for proper HTML 132 * escaping. 133 */ 134 public StaticButtonBuilder attribute(String attribute, String value) { 135 String check = attribute.trim().toLowerCase(); 136 if ("class".equals(check) || "style".equals(check) || "href".equals(check)) { 137 throw new IllegalArgumentException("attribute \"" + check + "\" is reserved"); 138 } 139 140 this.attributes.put(attribute, value); 141 return this; 142 } 143 144 /** 145 * Builds a static button tag of the current setup. 146 */ 147 @Override 148 public String toString() { 149 if (url == null) { 150 throw new IllegalStateException("thing url is required, but missing"); 151 } 152 153 StringBuilder sb = new StringBuilder(); 154 sb.append("<a"); 155 156 if (styleClass != null) { 157 sb.append(" class=\"").append(escape(styleClass)).append('"'); 158 } 159 160 if (style != null) { 161 sb.append(" style=\"").append(escape(style)).append('"'); 162 } 163 164 sb.append(" href=\"").append(escape(url)).append('"'); 165 166 for (Map.Entry<String, String> entry : attributes.entrySet()) { 167 sb.append(' ').append(entry.getKey()).append("=\""); 168 sb.append(escape(entry.getValue())); 169 sb.append('"'); 170 } 171 172 sb.append('>'); 173 174 if (badgeUrl != null) { 175 sb.append("<img src=\"").append(escape(badgeUrl)).append('"') 176 .append(" alt=\"Flattr this\"") 177 .append(" title=\"Flattr this\"") 178 .append(" border=\"0\"") 179 .append(" />"); 180 181 } else { 182 BadgeType useType = (type != null ? type : BadgeType.DEFAULT); 183 sb.append("<img src=\"").append(useType.getUrl()).append('"') 184 .append(" width=\"").append(useType.getWidth()).append('"') 185 .append(" height=\"").append(useType.getHeight()).append('"') 186 .append(" alt=\"Flattr this\"") 187 .append(" title=\"Flattr this\"") 188 .append(" border=\"0\"") 189 .append(" />"); 190 } 191 192 sb.append("</a>"); 193 194 return sb.toString(); 195 } 196 197 /** 198 * Escapes a string for use in HTML attributes. 199 * 200 * @param str 201 * Attribute to be escaped 202 * @return Escaped attribute 203 */ 204 private String escape(String str) { 205 return str.replace("&", "&").replace("<", "<").replace("\"", """); 206 } 207 208}