package com.psddev.cms.db;
import java.io.IOException;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.psddev.dari.util.HtmlWriter;
import com.psddev.dari.util.ObjectUtils;
/**
* {@link ExternalContent} from providers that doesn't support the oEmbed
* specification.
*/
public interface ExternalContentProvider {
/**
* @return {@code null} if this provider doesn't support embedding
* the given {@code content}.
*/
public Map<String, Object> createResponse(ExternalContent content);
/**
* Skeletal implementation of {@link ExternalContentProvider} optimized
* for returning {@code rich} oEmbed type.
*/
public abstract static class RichExternalContentProvider implements ExternalContentProvider {
private ExternalContent content;
public ExternalContent getContent() {
return content;
}
/**
* Returns the regular expression pattern against the URL that's used
* to determined whether this provider supports embedded the external
* content.
*
* <p>The resulting matcher is passed to {@link #updateHtml}.</p>
*
* @return Never {@code null}.
*/
protected abstract Pattern getUrlPattern();
/**
* Updates the HTML that's returned in the response.
*
* @param urlMatcher Never {@code null}.
* @param html Never {@code null}.
*/
protected abstract void updateHtml(Matcher urlMatcher, HtmlWriter html) throws IOException;
/**
* Updates the given {@code response}.
*
* @param response Never {@code null}.
*/
protected void updateResponse(Map<String, Object> response) {
}
@Override
public final Map<String, Object> createResponse(ExternalContent content) {
this.content = content;
Matcher urlMatcher = getUrlPattern().matcher(content.getUrl());
if (!urlMatcher.matches()) {
return null;
}
StringWriter string = new StringWriter();
HtmlWriter html = new HtmlWriter(string);
try {
try {
updateHtml(urlMatcher, html);
} finally {
html.close();
}
} catch (IOException error) {
throw new IllegalStateException(error);
}
Map<String, Object> response = new HashMap<String, Object>();
response.put("type", "rich");
response.put("html", string.toString());
updateResponse(response);
return response;
}
}
public static class Instagram extends ExternalContentProvider.RichExternalContentProvider {
private static final Pattern URL_PATTERN = Pattern.compile("(?i)https?://instagr(?:\\.am|am\\.com)/p/([^/]+).*");
@Override
protected Pattern getUrlPattern() {
return URL_PATTERN;
}
@Override
protected void updateHtml(Matcher urlMatcher, HtmlWriter html) throws IOException {
html.writeStart("iframe",
"src", "//instagram.com/p/" + urlMatcher.group(1) + "/embed/",
"width", 640,
"height", 640,
"frameborder", 0,
"scrolling", "no");
html.writeEnd();
}
@Override
protected void updateResponse(Map<String, Object> response) {
response.put("width", 640);
response.put("height", 640);
}
}
public static class Vine extends RichExternalContentProvider {
private static final Pattern URL_PATTERN = Pattern.compile("\"(?i)https?:(//vine.co/[^/]+/[^/]+).*\"");
@Override
protected Pattern getUrlPattern() {
return URL_PATTERN;
}
@Override
protected void updateHtml(Matcher urlMatcher, HtmlWriter html) throws IOException {
html.writeStart("iframe",
"src", "https://vine.co/v/" + urlMatcher.group(1) + "/embed/simple",
"width", 600,
"height", 600,
"frameborder", 0,
"scrolling", "no");
html.writeEnd();
}
@Override
protected void updateResponse(Map<String, Object> response) {
response.put("width", 600);
response.put("height", 600);
}
}
public static class Storify extends RichExternalContentProvider {
private static final Pattern URL_PATTERN = Pattern.compile("(?i)https?:(//storify.com/[^/]+/[^/]+).*");
@Override
protected Pattern getUrlPattern() {
return URL_PATTERN;
}
@Override
protected void updateHtml(Matcher urlMatcher, HtmlWriter html) throws IOException {
html.writeStart("script",
"type", "text/javascript",
"src", urlMatcher.group(1) + ".js");
html.writeEnd();
}
}
public static class Pinterest extends RichExternalContentProvider {
private static final Pattern URL_PATTERN = Pattern.compile("(?i)https?://(?:www\\.)?pinterest.com/([^/]+)(/[^/]+)?.*");
@Override
protected Pattern getUrlPattern() {
return URL_PATTERN;
}
@Override
protected void updateHtml(Matcher urlMatcher, HtmlWriter html) throws IOException {
String pinDo;
if ("pin".equals(urlMatcher.group(1))) {
pinDo = "embedPin";
} else if (ObjectUtils.isBlank(urlMatcher.group(2))) {
pinDo = "embedUser";
} else {
pinDo = "embedBoard";
}
html.writeStart("a",
"data-pin-do", pinDo,
"href", urlMatcher.group(0));
html.writeEnd();
html.writeStart("script", "type", "text/javascript");
html.writeRaw("(function() {");
html.writeRaw("var w = window, d, f, p;");
html.writeRaw("if (w.BRIGHTSPOT_PINTEREST) { return; }");
html.writeRaw("d = w.document, f = d.getElementsByTagName('SCRIPT')[0], p = d.createElement('SCRIPT');");
html.writeRaw("p.type = 'text/javascript';");
html.writeRaw("p.async = true;");
html.writeRaw("p.src = '//assets.pinterest.com/js/pinit.js';");
html.writeRaw("f.parentNode.insertBefore(p, f);");
html.writeRaw("w.BRIGHTSPOT_PINTEREST = true;");
html.writeRaw("})()");
html.writeEnd();
}
}
public static class Facebook extends RichExternalContentProvider {
private static final Pattern URL_PATTERN = Pattern.compile("(?i)https?://(?:www\\.)?facebook.com/([^/]+)(/[^/]+)?.*");
@Override
protected Pattern getUrlPattern() {
return URL_PATTERN;
}
@Override
protected void updateHtml(Matcher matcher, HtmlWriter page) throws IOException {
page.writeStart("script");
page.writeRaw("(function(d, s, id) {\n"
+ " var js, fjs = d.getElementsByTagName(s)[0];\n"
+ " if (d.getElementById(id)) return;\n"
+ " js = d.createElement(s); js.id = id;\n"
+ " js.src = \"//connect.facebook.net/en_US/sdk.js#xfbml=1&version=v2.2\";\n"
+ " fjs.parentNode.insertBefore(js, fjs);\n"
+ "}(document, 'script', 'facebook-jssdk'));");
page.writeEnd();
page.writeStart("div",
"class", "fb-post",
"data-href", matcher.group(0));
page.writeEnd();
}
}
class Tableau extends RichExternalContentProvider {
private static final Pattern URL_PATTERN = Pattern.compile("(?i)https?://public.tableau.com/([^?]+).*");
private static final int WIDTH = 815;
private static final int HEIGHT = 690;
@Override
protected Pattern getUrlPattern() {
return URL_PATTERN;
}
@Override
protected void updateHtml(Matcher matcher, HtmlWriter html) throws IOException {
html.writeStart("iframe",
"src", "https://public.tableau.com/" + matcher.group(1) + "?:embed=y&:showVizHome=n",
"width", WIDTH,
"height", HEIGHT);
html.writeEnd();
}
@Override
protected void updateResponse(Map<String, Object> response) {
response.put("width", WIDTH);
response.put("height", HEIGHT);
}
}
}