//Copyright [2011] [Barry Books]
// Licensed 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 com.trsvax.tapestry.facebook.services;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.apache.tapestry5.ComponentResources;
import org.apache.tapestry5.dom.Document;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.services.RequestGlobals;
import org.apache.tapestry5.services.javascript.JavaScriptSupport;
import org.slf4j.Logger;
import com.trsvax.tapestry.facebook.FBInit;
import com.trsvax.tapestry.facebook.opengraph.Tags;
public class FBAsyncSupportImpl implements FBAsyncSupport {
private final Logger logger;
private final RequestGlobals requestGlobals;
private final String context;
private final JavaScriptSupport javaScriptSupport;
private FBInit fbinit;
private Tags tags;
private boolean render = false;
private StringWriter initWriter = new StringWriter();
private Map<String, Set<String>> events = new HashMap<String, Set<String>>();
public FBAsyncSupportImpl(Logger logger, RequestGlobals requestGlobals, JavaScriptSupport javascriptSupport) {
this.logger = logger;
this.requestGlobals = requestGlobals;
this.javaScriptSupport = javascriptSupport;
String c = requestGlobals.getHTTPServletRequest().getContextPath();
if ( c == null ) {
c = "/";
}
if ( ! c.endsWith("/")) {
c+="/";
}
context = c;
}
public void subscribe(String event,ComponentResources resources) {
render();
String containerID = resources.getContainerResources().getCompleteId() + ":" + fb2tap(event) ;
//String url = resources.createEventLink(event).toAbsoluteURI();
String url = resources.getContainerResources().createEventLink(fb2tap(event)).toAbsoluteURI();
url = url.replace(":8080", "");
Set<String> s = events.get(event);
if ( s == null ) {
s = new HashSet<String>();
events.put(event,s);
}
//s.add(containerID);
s.add(url);
}
public void init(FBInit fbinit) {
render();
this.fbinit = fbinit;
}
public void init(String init) {
render();
initWriter.append(init);
initWriter.append("\n");
}
public void meta(Tags tags) {
render();
this.tags = tags;
}
public void render() {
render = true;
}
public void updateDocument(Document document) {
if ( !render ) {
return;
}
if ( requestGlobals.getRequest().isXHR()) {
javaScriptSupport.addScript("window.fbAsyncInit();");
return;
}
if (tags != null) {
Element head = findOrCreateElement(document.getRootElement(),
"head", false);
renderMeta(head);
}
Element body = findOrCreateElement(document.getRootElement(), "body",
false);
body.elementAt(0, "div", "id", "fb-root");
Element script = body.elementAt(1, "script");
//script.raw(script());
script(script);
}
private Element findOrCreateElement(Element root, String childElement,
boolean atTop) {
Element container = root.find(childElement);
// Create the element is it is missing.
if (container == null)
container = atTop ? root.elementAt(0, childElement) : root
.element(childElement);
return container;
}
void script(Element script) {
script.raw("window.fbAsyncInit = function() {\n");
script.raw("FB.init({" + initString() + "});\n");
script.raw(initWriter.toString());
for ( Entry<String, Set<String>> e : events.entrySet()) {
String event = e.getKey();
for ( String url : e.getValue()) {
script.raw(subscribe(event, url));
}
}
script.raw("};\n");
script.raw(
"(function() {\n"
+ "var e = document.createElement('script');\n"
+ "e.type = 'text/javascript';\n"
+ "e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js';\n"
+ "e.async = true;\n"
+ "document.getElementById('fb-root').appendChild(e);"
+ "}());\n");
}
void renderMeta(Element head) {
if (tags == null) {
return;
}
if (tags.getTitle() != null) {
head.element("meta", "property", "og:title", "content",
tags.getTitle());
}
if (tags.getType() != null) {
head.element("meta", "property", "og:type", "content",
tags.getType());
}
if (tags.getImageURL() != null) {
head.element("meta", "property", "og:image", "content",
tags.getImageURL());
}
if (tags.getUrl() != null) {
head.element("meta", "property", "og:url", "content", tags.getUrl());
}
if (tags.getSiteName() != null) {
head.element("meta", "property", "og:site_name", "content",
tags.getSiteName());
}
if (tags.getApplicationID() != null) {
head.element("meta", "property", "fb:app_id", "content",
tags.getApplicationID());
}
if (tags.getAdmins() != null) {
head.element("meta", "property", "fb:admins", "content",
tags.getAdmins());
}
}
String initString() {
String sep = "";
StringWriter s = new StringWriter();
//s.append("({");
if ( fbinit.getAppID() != null ) {
s.append(sep);
sep = ",";
s.append("appId: '");
s.append(fbinit.getAppID());
s.append("'");
}
if ( fbinit.getCookie() != null ) {
s.append(sep);
sep = ",";
s.append("cookie: " + fbinit.getCookie());
}
if ( fbinit.getLogging() != null ) {
s.append(sep);
sep = ",";
s.append("logging: " + fbinit.getLogging());
}
if ( fbinit.getStatus() != null ) {
s.append(sep);
sep = ",";
s.append("status: " + fbinit.getStatus());
}
if ( fbinit.getXfbml() != null ) {
s.append(sep);
sep = ",";
s.append("xfbml: " + fbinit.getXfbml());
}
return s.toString();
}
String fb2tap(String event) {
String t = null;
String[] n = event.split("\\.");
boolean first = true;
for ( String s : n) {
if ( first ) {
t = s;
first = false;
continue;
}
t += s.substring(0, 1).toUpperCase();
t += s.substring(1);
}
return t;
}
String subscribe(String event, String url) {
return String.format("FB.Event.subscribe('%s', function(response){" +
//"alert(response);" +
"Tapestry.ajaxRequest('%s', {" +
"method : 'get'," +
"parameters : {" +
"url : response }" +
"});" +
"});\n", event,url);
}
}