Lots of updates for 2012-11-14 release
This commit is contained in:
parent
e1f92b54a7
commit
15aeef411c
34 changed files with 989 additions and 282 deletions
97
src/main/java/com/moandjiezana/essayist/posts/Bookmark.java
Normal file
97
src/main/java/com/moandjiezana/essayist/posts/Bookmark.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package com.moandjiezana.essayist.posts;
|
||||
|
||||
import com.moandjiezana.tent.client.posts.content.PostContent;
|
||||
|
||||
import java.net.URL;
|
||||
import java.util.Locale;
|
||||
|
||||
public class Bookmark implements PostContent {
|
||||
|
||||
public static final String URI = "http://www.beberlei.de/tent/bookmark/v0.0.1";
|
||||
|
||||
private URL url;
|
||||
private String title;
|
||||
private URL image;
|
||||
private String description;
|
||||
private Locale[] locale;
|
||||
private String siteName;
|
||||
private String[] tags;
|
||||
private String content;
|
||||
|
||||
public Bookmark(URL url, String title) {
|
||||
this.url = url;
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public Bookmark() {}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return URI;
|
||||
}
|
||||
|
||||
public URL getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(URL url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public URL getImage() {
|
||||
return image;
|
||||
}
|
||||
|
||||
public void setImage(URL image) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public Locale[] getLocale() {
|
||||
return locale;
|
||||
}
|
||||
|
||||
public void setLocale(Locale[] locale) {
|
||||
this.locale = locale;
|
||||
}
|
||||
|
||||
public String getSiteName() {
|
||||
return siteName;
|
||||
}
|
||||
|
||||
public void setSiteName(String siteName) {
|
||||
this.siteName = siteName;
|
||||
}
|
||||
|
||||
public String[] getTags() {
|
||||
return tags;
|
||||
}
|
||||
|
||||
public void setTags(String[] tags) {
|
||||
this.tags = tags;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(String content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.moandjiezana.essayist.posts;
|
||||
|
||||
import com.moandjiezana.tent.client.posts.content.PostContent;
|
||||
|
||||
public class EssayistMetadataContent implements PostContent {
|
||||
|
||||
public static final String URI = "http://moandjiezana.com/tent/essayist/types/post/metadata/v0.1.0";
|
||||
|
||||
private String format = "markdown";
|
||||
private String raw;
|
||||
private String statusId;
|
||||
|
||||
public EssayistMetadataContent(String raw) {
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public EssayistMetadataContent() {}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return URI;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public String getRaw() {
|
||||
return raw;
|
||||
}
|
||||
|
||||
public void setRaw(String raw) {
|
||||
this.raw = raw;
|
||||
}
|
||||
|
||||
public String getStatusId() {
|
||||
return statusId;
|
||||
}
|
||||
|
||||
public void setStatusId(String statusId) {
|
||||
this.statusId = statusId;
|
||||
}
|
||||
}
|
40
src/main/java/com/moandjiezana/essayist/posts/Favorite.java
Normal file
40
src/main/java/com/moandjiezana/essayist/posts/Favorite.java
Normal file
|
@ -0,0 +1,40 @@
|
|||
package com.moandjiezana.essayist.posts;
|
||||
|
||||
import com.moandjiezana.tent.client.posts.content.PostContent;
|
||||
|
||||
public class Favorite implements PostContent {
|
||||
|
||||
public static final String URI = "http://www.beberlei.de/tent/favorite/v0.0.1";
|
||||
|
||||
private String entity;
|
||||
private String post;
|
||||
|
||||
public Favorite(String entity, String post) {
|
||||
this.entity = entity;
|
||||
this.post = post;
|
||||
}
|
||||
|
||||
public Favorite() {}
|
||||
|
||||
@Override
|
||||
public String getType() {
|
||||
return URI;
|
||||
}
|
||||
|
||||
public String getEntity() {
|
||||
return entity;
|
||||
}
|
||||
|
||||
public void setEntity(String entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
|
||||
public String getPost() {
|
||||
return post;
|
||||
}
|
||||
|
||||
public void setPost(String post) {
|
||||
this.post = post;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package com.moandjiezana.essayist.posts;
|
||||
|
||||
public class UserReactions {
|
||||
|
||||
public boolean favorited;
|
||||
public boolean reposted;
|
||||
public boolean bookmarked;
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.moandjiezana.tent.client.TentClient;
|
||||
import com.moandjiezana.tent.client.posts.Mention;
|
||||
import com.moandjiezana.tent.client.posts.Post;
|
||||
import com.moandjiezana.tent.client.posts.content.StatusContent;
|
||||
import com.moandjiezana.tent.client.users.Permissions;
|
||||
import com.moandjiezana.tent.essayist.auth.Authenticated;
|
||||
import com.moandjiezana.tent.essayist.config.Routes;
|
||||
import com.moandjiezana.tent.essayist.tent.Entities;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Singleton
|
||||
@Authenticated
|
||||
public class CommentsServlet extends HttpServlet {
|
||||
|
||||
private final Provider<EssayistSession> sessions;
|
||||
private final Provider<Routes> routes;
|
||||
|
||||
@Inject
|
||||
public CommentsServlet(Provider<Routes> routes, Provider<EssayistSession> sessions) {
|
||||
this.routes = routes;
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String[] parts = req.getPathInfo().split("/essay/");
|
||||
String authorEntity = Entities.expandFromUrl(parts[0]);
|
||||
String essayId = parts[1].split("/")[0];
|
||||
|
||||
String commentText = req.getParameter("comment");
|
||||
|
||||
Post essay = new Post();
|
||||
essay.setEntity(authorEntity);
|
||||
essay.setId(essayId);
|
||||
|
||||
if (Strings.isNullOrEmpty(commentText)) {
|
||||
resp.sendRedirect(routes.get().essay(essay));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
User user = sessions.get().getUser();
|
||||
TentClient tentClient = new TentClient(user.getProfile());
|
||||
tentClient.getAsync().setAccessToken(user.getAccessToken());
|
||||
tentClient.getAsync().setRegistrationResponse(user.getRegistration());
|
||||
|
||||
Post comment = new Post();
|
||||
comment.setEntity(user.getProfile().getCore().getEntity());
|
||||
commentText = commentText.substring(0, Math.min(commentText.length(), 256));
|
||||
comment.setContent(new StatusContent(commentText));
|
||||
comment.setMentions(new Mention[] { new Mention(authorEntity, essayId) });
|
||||
Permissions permissions = new Permissions();
|
||||
permissions.setPublic(true);
|
||||
comment.setPermissions(permissions);
|
||||
comment.setLicenses(new String[] { "http://creativecommons.org/licenses/by/3.0/" });
|
||||
|
||||
tentClient.write(comment);
|
||||
|
||||
resp.sendRedirect(routes.get().essay(essay));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.moandjiezana.essayist.posts.Bookmark;
|
||||
import com.moandjiezana.essayist.posts.Favorite;
|
||||
import com.moandjiezana.essayist.posts.UserReactions;
|
||||
import com.moandjiezana.tent.client.TentClient;
|
||||
import com.moandjiezana.tent.client.posts.Mention;
|
||||
import com.moandjiezana.tent.client.posts.Post;
|
||||
import com.moandjiezana.tent.client.posts.PostQuery;
|
||||
import com.moandjiezana.tent.client.posts.content.Repost;
|
||||
import com.moandjiezana.tent.client.posts.content.StatusContent;
|
||||
import com.moandjiezana.tent.client.users.Permissions;
|
||||
import com.moandjiezana.tent.essayist.auth.Authenticated;
|
||||
import com.moandjiezana.tent.essayist.config.Routes;
|
||||
import com.moandjiezana.tent.essayist.tent.Entities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Singleton
|
||||
public class EssayActionServlet extends HttpServlet {
|
||||
|
||||
private final Provider<EssayistSession> sessions;
|
||||
private final Provider<Routes> routes;
|
||||
private Users users;
|
||||
private Templates templates;
|
||||
|
||||
@Inject
|
||||
public EssayActionServlet(Users users, Provider<Routes> routes, Provider<EssayistSession> sessions, Templates templates) {
|
||||
this.users = users;
|
||||
this.routes = routes;
|
||||
this.sessions = sessions;
|
||||
this.templates = templates;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String[] urlParts = getEntityAndIdAndAction(req);
|
||||
String authorEntity = req.getParameter("entity") != null ? req.getParameter("entity") : urlParts[0];
|
||||
String postId = urlParts[1];
|
||||
String action = urlParts[2];
|
||||
|
||||
|
||||
if ("user".equals(action)) {
|
||||
User loggedUser = sessions.get().getUser();
|
||||
String loggedEntity = loggedUser.getProfile().getCore().getEntity();
|
||||
TentClient tentClient = new TentClient(loggedUser.getProfile());
|
||||
List<Post> reactions = tentClient.getPosts(new PostQuery().mentionedPost(postId).entity(loggedEntity).postTypes(Bookmark.URI, Favorite.URI, Post.Types.repost("v0.1.0")));
|
||||
UserReactions userReactions = new UserReactions();
|
||||
for (Post reaction : reactions) {
|
||||
String reactionType = reaction.getType();
|
||||
if (Post.Types.equalsIgnoreVersion(Bookmark.URI, reactionType)) {
|
||||
userReactions.bookmarked = true;
|
||||
} else if (Post.Types.equalsIgnoreVersion(Favorite.URI, reactionType)) {
|
||||
userReactions.favorited = true;
|
||||
}
|
||||
}
|
||||
} else if ("reactions".equals(action)) {
|
||||
User user = users.getByEntityOrNull(authorEntity);
|
||||
TentClient tentClient;
|
||||
if (user != null) {
|
||||
tentClient = new TentClient(user.getProfile());
|
||||
tentClient.getAsync().setAccessToken(user.getAccessToken());
|
||||
tentClient.getAsync().setRegistrationResponse(user.getRegistration());
|
||||
} else {
|
||||
tentClient = new TentClient(authorEntity);
|
||||
tentClient.getProfile();
|
||||
}
|
||||
//.postTypes(Bookmark.URI, Favorite.URI, Post.Types.repost("v0.1.0"), Post.Types.status("v0.1.0"))
|
||||
List<Post> reactions = tentClient.getPosts(new PostQuery().mentionedPost(postId));
|
||||
templates.reactions().render(resp.getWriter(), reactions);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Authenticated
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String[] entityAndId = getEntityAndIdAndAction(req);
|
||||
String authorEntity = entityAndId[0];
|
||||
String essayId = entityAndId[1];
|
||||
String action = entityAndId[2];
|
||||
|
||||
Post essay = new Post();
|
||||
essay.setEntity(authorEntity);
|
||||
essay.setId(essayId);
|
||||
|
||||
User user = sessions.get().getUser();
|
||||
TentClient tentClient = new TentClient(user.getProfile());
|
||||
tentClient.getAsync().setAccessToken(user.getAccessToken());
|
||||
tentClient.getAsync().setRegistrationResponse(user.getRegistration());
|
||||
|
||||
Post post = new Post();
|
||||
post.setEntity(user.getProfile().getCore().getEntity());
|
||||
post.setMentions(new Mention[] { new Mention(authorEntity, essayId) });
|
||||
Permissions permissions = new Permissions();
|
||||
permissions.setPublic(true);
|
||||
post.setPermissions(permissions);
|
||||
post.setLicenses(new String[] { "http://creativecommons.org/licenses/by/3.0/" });
|
||||
|
||||
if ("status".equals(action)) {
|
||||
String commentText = req.getParameter("comment");
|
||||
|
||||
if (Strings.isNullOrEmpty(commentText)) {
|
||||
resp.sendRedirect(routes.get().essay(essay));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
commentText = commentText.substring(0, Math.min(commentText.length(), 256));
|
||||
post.setContent(new StatusContent(commentText));
|
||||
} else if ("favorite".equals(action)) {
|
||||
post.setContent(new Favorite(authorEntity, essayId));
|
||||
} else if ("bookmark".equals(action)) {
|
||||
String requestUrl = req.getRequestURL().toString();
|
||||
Bookmark bookmark = new Bookmark(new URL(requestUrl.substring(0, requestUrl.lastIndexOf('/'))), req.getParameter("title"));
|
||||
bookmark.setDescription(req.getParameter("description"));
|
||||
bookmark.setSiteName(req.getParameter("name") + " on Essayist");
|
||||
post.setContent(bookmark);
|
||||
} else if ("repost".equals(action)) {
|
||||
post.setContent(new Repost(authorEntity, essayId));
|
||||
}
|
||||
|
||||
tentClient.write(post);
|
||||
|
||||
resp.sendRedirect(routes.get().essay(essay));
|
||||
}
|
||||
|
||||
private String[] getEntityAndIdAndAction(HttpServletRequest req) {
|
||||
String[] parts = req.getPathInfo().split("/");
|
||||
String authorEntity = Entities.expandFromUrl(parts[0]);
|
||||
String essayId = parts[2];
|
||||
String action = parts[3];
|
||||
|
||||
return new String[] { authorEntity, essayId, action };
|
||||
}
|
||||
}
|
|
@ -66,16 +66,19 @@ public class EssayServlet extends HttpServlet {
|
|||
EssayistPostContent essayContent = post.getContentAs(EssayistPostContent.class);
|
||||
essayContent.setBody(csrf.stripScripts(essayContent.getBody()));
|
||||
|
||||
EssayTemplate essayPage = templates.essay();
|
||||
EssayPage essayPage = templates.essay();
|
||||
if (user.owns(post)) {
|
||||
essayPage.setActive("Written");
|
||||
}
|
||||
|
||||
if (Boolean.parseBoolean(req.getParameter("reactions"))) {
|
||||
tentClient.getAsync().setAccessToken(author.getAccessToken());
|
||||
tentClient.getAsync().setRegistrationResponse(author.getRegistration());
|
||||
List<Post> reactions = tentClient.getPosts(new PostQuery().mentionedPost(essayId));
|
||||
essayPage.setReactions(reactions);
|
||||
}
|
||||
|
||||
tentClient.getAsync().setAccessToken(author.getAccessToken());
|
||||
tentClient.getAsync().setRegistrationResponse(author.getRegistration());
|
||||
List<Post> comments = tentClient.getPosts(new PostQuery().mentionedPost(essayId));
|
||||
|
||||
essayPage.render(resp.getWriter(), post, author.getProfile(), comments);
|
||||
essayPage.render(resp.getWriter(), post, author.getProfile());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.google.common.base.Throwables;
|
||||
import com.moandjiezana.tent.client.HttpTentDataSource;
|
||||
import com.moandjiezana.tent.client.TentClient;
|
||||
import com.moandjiezana.tent.client.TentClientAsync;
|
||||
import com.moandjiezana.tent.client.posts.Post;
|
||||
import com.moandjiezana.tent.client.posts.PostQuery;
|
||||
|
||||
|
@ -10,6 +10,7 @@ import java.util.ArrayList;
|
|||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.Future;
|
||||
|
@ -25,13 +26,23 @@ public class Essays {
|
|||
CopyOnWriteArrayList<Future<List<Post>>> futurePosts = new CopyOnWriteArrayList<Future<List<Post>>>();
|
||||
|
||||
for (User user : users) {
|
||||
futurePosts.add(new TentClientAsync(user.getProfile()).getPosts(new PostQuery().entity(user.getProfile().getCore().getEntity()).postTypes(Post.Types.essay("v0.1.0"))));
|
||||
futurePosts.add(new HttpTentDataSource(user.getProfile()).getPosts(new PostQuery().entity(user.getProfile().getCore().getEntity()).postTypes(Post.Types.essay("v0.1.0"))));
|
||||
}
|
||||
|
||||
List<Post> posts = new ArrayList<Post>(futurePosts.size());
|
||||
for (Future<List<Post>> futurePost : futurePosts) {
|
||||
try {
|
||||
posts.addAll(futurePost.get());
|
||||
List<Post> post = futurePost.get();
|
||||
if (post == null) {
|
||||
continue;
|
||||
}
|
||||
Iterator<Post> iterator = post.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
if (iterator.next() == null) {
|
||||
iterator.remove();
|
||||
}
|
||||
}
|
||||
posts.addAll(post);
|
||||
} catch (Exception e) {
|
||||
LOGGER.error("Could not load Post", Throwables.getRootCause(e));
|
||||
}
|
||||
|
@ -55,6 +66,10 @@ public class Essays {
|
|||
return tentClient.getPosts(new PostQuery().postTypes(Post.Types.essay("v0.1.0")));
|
||||
}
|
||||
|
||||
public List<Post> getReactions(User user, String postId) {
|
||||
return new TentClient(user.getProfile()).getPosts(new PostQuery().mentionedPost(postId));
|
||||
}
|
||||
|
||||
public Post get(String essayId) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.moandjiezana.essayist.posts.Bookmark;
|
||||
import com.moandjiezana.essayist.posts.EssayistMetadataContent;
|
||||
import com.moandjiezana.essayist.posts.Favorite;
|
||||
import com.moandjiezana.tent.client.TentClient;
|
||||
import com.moandjiezana.tent.client.apps.AuthorizationRequest;
|
||||
import com.moandjiezana.tent.client.apps.RegistrationRequest;
|
||||
|
@ -107,7 +110,8 @@ public class LoginServlet extends HttpServlet {
|
|||
tentClient.getProfile();
|
||||
|
||||
Map<String, String> scopes = new HashMap<String, String>();
|
||||
scopes.put("write_posts", "Will post Essays and optionally Statuses to announce or comment on Essays.");
|
||||
scopes.put("write_posts", "Allows you to write Essays and re-post, bookmark or favorite other people's Essays.");
|
||||
scopes.put("read_posts", "Read Essays and your reactions to Essays.");
|
||||
|
||||
URL url = new URL(req.getRequestURL().toString());
|
||||
String baseUrl = url.getProtocol() + "://" + url.getAuthority() + req.getContextPath();
|
||||
|
@ -122,7 +126,7 @@ public class LoginServlet extends HttpServlet {
|
|||
private String authorize(TentClient tentClient, RegistrationResponse registrationResponse, String redirectUri, HttpServletRequest req) {
|
||||
AuthorizationRequest authorizationRequest = new AuthorizationRequest(registrationResponse.getMacKeyId(), redirectUri);
|
||||
authorizationRequest.setScope("write_posts", "read_posts");
|
||||
authorizationRequest.setTentPostTypes(Post.Types.essay("v0.1.0"), Post.Types.status("v0.1.0"), Post.Types.photo("v0.1.0"));
|
||||
authorizationRequest.setTentPostTypes(Post.Types.essay("v0.1.0"), Post.Types.status("v0.1.0"), Post.Types.photo("v0.1.0"), Post.Types.repost("v0.1.0"), EssayistMetadataContent.URI, Bookmark.URI, Favorite.URI);
|
||||
authorizationRequest.setState(UUID.randomUUID().toString());
|
||||
String authorizationUrl = tentClient.buildAuthorizationUrl(authorizationRequest);
|
||||
|
||||
|
@ -131,6 +135,7 @@ public class LoginServlet extends HttpServlet {
|
|||
authResult.registrationResponse = registrationResponse;
|
||||
req.getSession().setAttribute(authorizationRequest.getState(), authResult);
|
||||
req.getSession().setAttribute("entity", tentClient.getProfile().getCore().getEntity());
|
||||
|
||||
return authorizationUrl;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.moandjiezana.tent.client.TentClient;
|
||||
import com.moandjiezana.tent.client.posts.Post;
|
||||
import com.moandjiezana.tent.client.users.Permissions;
|
||||
import com.moandjiezana.tent.essayist.auth.Authenticated;
|
||||
import com.moandjiezana.tent.essayist.tent.Entities;
|
||||
import com.moandjiezana.tent.essayist.tent.EssayistPostContent;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.pegdown.PegDownProcessor;
|
||||
|
||||
@Singleton
|
||||
@Authenticated
|
||||
public class NewEssayServlet extends HttpServlet {
|
||||
|
||||
private Templates templates;
|
||||
private Provider<EssayistSession> sessions;
|
||||
|
||||
@Inject
|
||||
public NewEssayServlet(Provider<EssayistSession> sessions, Templates templates) {
|
||||
this.sessions = sessions;
|
||||
this.templates = templates;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
templates.newEssay().render(resp.getWriter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
TentClient tentClient = tentClient(req);
|
||||
|
||||
Post post = new Post();
|
||||
post.setPublishedAt(System.currentTimeMillis() / 1000);
|
||||
Permissions permissions = new Permissions();
|
||||
permissions.setPublic(true);
|
||||
post.setPermissions(permissions);
|
||||
post.setLicenses(new String[] { "http://creativecommons.org/licenses/by/3.0/" });
|
||||
EssayistPostContent essay = new EssayistPostContent();
|
||||
essay.setTitle(req.getParameter("title"));
|
||||
essay.setBody(new PegDownProcessor().markdownToHtml(req.getParameter("body")));
|
||||
essay.setRaw(req.getParameter("body"));
|
||||
essay.setType("markdown");
|
||||
essay.setExcerpt(req.getParameter("excerpt"));
|
||||
post.setContent(essay);
|
||||
|
||||
Post newPost = tentClient.write(post);
|
||||
|
||||
resp.sendRedirect(req.getContextPath() + "/" + Entities.getForUrl(tentClient.getProfile().getCore().getEntity()) + "/essay/" + newPost.getId());
|
||||
}
|
||||
|
||||
private TentClient tentClient(HttpServletRequest req) {
|
||||
User user = sessions.get().getUser();
|
||||
|
||||
TentClient tentClient = new TentClient(user.getProfile());
|
||||
tentClient.getAsync().setAccessToken(user.getAccessToken());
|
||||
|
||||
return tentClient;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.google.common.io.CharStreams;
|
||||
import com.moandjiezana.tent.essayist.auth.Authenticated;
|
||||
import com.moandjiezana.tent.essayist.security.Csrf;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.pegdown.PegDownProcessor;
|
||||
|
||||
@Singleton
|
||||
@Authenticated
|
||||
public class PreviewServlet extends HttpServlet {
|
||||
|
||||
private final Csrf csrf;
|
||||
|
||||
@Inject
|
||||
public PreviewServlet(Csrf csrf) {
|
||||
this.csrf = csrf;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
String body = CharStreams.toString(req.getReader());
|
||||
String html = new PegDownProcessor().markdownToHtml(body);
|
||||
String sanitized = csrf.stripScripts(html);
|
||||
|
||||
resp.getWriter().write(sanitized);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.moandjiezana.tent.essayist.config.JamonContext;
|
||||
import com.moandjiezana.tent.essayist.partials.ReactionList;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
|
@ -20,12 +21,12 @@ public class Templates {
|
|||
return new LoginTemplate().setJamonContext(jamonContext.get());
|
||||
}
|
||||
|
||||
public EssaysTemplate essays(String active) {
|
||||
return new EssaysTemplate().setActive(active).setJamonContext(jamonContext.get());
|
||||
public EssaysPage essays(String active) {
|
||||
return new EssaysPage().setActive(active).setJamonContext(jamonContext.get());
|
||||
}
|
||||
|
||||
public EssayTemplate essay() {
|
||||
return new EssayTemplate().setJamonContext(jamonContext.get());
|
||||
public EssayPage essay() {
|
||||
return new EssayPage().setJamonContext(jamonContext.get());
|
||||
}
|
||||
|
||||
public NewEssayTemplate newEssay() {
|
||||
|
@ -35,4 +36,12 @@ public class Templates {
|
|||
public ReadPage read() {
|
||||
return new ReadPage().setJamonContext(jamonContext.get());
|
||||
}
|
||||
|
||||
public ReactionList reactions() {
|
||||
return new ReactionList().setJamonContext(jamonContext.get());
|
||||
}
|
||||
|
||||
public NonEditableEssayPage nonEditableEssay() {
|
||||
return new NonEditableEssayPage().setJamonContext(jamonContext.get());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,12 @@ public class User {
|
|||
|
||||
public User() {}
|
||||
|
||||
public User(String entity) {
|
||||
this.profile = new Profile();
|
||||
this.profile.setCore(new Profile.Core());
|
||||
this.profile.getCore().setEntity(entity);
|
||||
}
|
||||
|
||||
public User(Profile profile) {
|
||||
this(null, profile, null, null);
|
||||
}
|
||||
|
|
157
src/main/java/com/moandjiezana/tent/essayist/WriteServlet.java
Normal file
157
src/main/java/com/moandjiezana/tent/essayist/WriteServlet.java
Normal file
|
@ -0,0 +1,157 @@
|
|||
package com.moandjiezana.tent.essayist;
|
||||
|
||||
import com.moandjiezana.essayist.posts.EssayistMetadataContent;
|
||||
import com.moandjiezana.essayist.utils.Tasks;
|
||||
import com.moandjiezana.tent.client.TentClient;
|
||||
import com.moandjiezana.tent.client.posts.Mention;
|
||||
import com.moandjiezana.tent.client.posts.Post;
|
||||
import com.moandjiezana.tent.client.posts.PostQuery;
|
||||
import com.moandjiezana.tent.client.posts.content.EssayContent;
|
||||
import com.moandjiezana.tent.client.users.Permissions;
|
||||
import com.moandjiezana.tent.essayist.auth.Authenticated;
|
||||
import com.moandjiezana.tent.essayist.config.Routes;
|
||||
import com.moandjiezana.tent.essayist.tent.Entities;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Provider;
|
||||
import javax.inject.Singleton;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.pegdown.PegDownProcessor;
|
||||
|
||||
@Singleton
|
||||
@Authenticated
|
||||
public class WriteServlet extends HttpServlet {
|
||||
|
||||
private Templates templates;
|
||||
private Provider<EssayistSession> sessions;
|
||||
private Tasks tasks;
|
||||
private Provider<Routes> routes;
|
||||
|
||||
@Inject
|
||||
public WriteServlet(Provider<EssayistSession> sessions, Templates templates, Provider<Routes> routes, Tasks tasks) {
|
||||
this.sessions = sessions;
|
||||
this.templates = templates;
|
||||
this.routes = routes;
|
||||
this.tasks = tasks;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
if (req.getRequestURI().endsWith("/write")) {
|
||||
templates.newEssay().render(resp.getWriter());
|
||||
return;
|
||||
}
|
||||
|
||||
String essayId = req.getPathInfo().substring(1);
|
||||
TentClient tentClient = newTentClient();
|
||||
List<Post> metadataPosts = tentClient.getPosts(new PostQuery().mentionedPost(essayId).postTypes(EssayistMetadataContent.URI));
|
||||
if (metadataPosts.isEmpty()) {
|
||||
templates.nonEditableEssay().render(resp.getWriter());
|
||||
return;
|
||||
}
|
||||
|
||||
Post essay = tentClient.getPost(essayId);
|
||||
Post metadata = metadataPosts.get(0);
|
||||
|
||||
templates.newEssay().setMetadata(metadata).setEssay(essay).setMetadata(metadata).render(resp.getWriter());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
final TentClient tentClient = newTentClient();
|
||||
|
||||
final Post post = newPost();
|
||||
EssayContent essay = new EssayContent();
|
||||
essay.setTitle(req.getParameter("title"));
|
||||
final String body = req.getParameter("body");
|
||||
essay.setBody(new PegDownProcessor().markdownToHtml(body));
|
||||
essay.setExcerpt(req.getParameter("excerpt"));
|
||||
post.setContent(essay);
|
||||
|
||||
final Post newPost = tentClient.write(post);
|
||||
final String newPostId = newPost.getId();
|
||||
final User user = sessions.get().getUser();
|
||||
|
||||
Post metadataPost = newPost();
|
||||
metadataPost.getPermissions().setPublic(false);
|
||||
EssayistMetadataContent metadata = new EssayistMetadataContent(body);
|
||||
metadataPost.setContent(metadata);
|
||||
String essayId = newPostId;
|
||||
metadataPost.setMentions(new Mention[] { new Mention(user.getProfile().getCore().getEntity(), essayId) });
|
||||
|
||||
tentClient.write(metadataPost);
|
||||
|
||||
resp.sendRedirect(req.getContextPath() + "/" + Entities.getForUrl(tentClient.getProfile().getCore().getEntity()) + "/essay/" + newPost.getId());
|
||||
|
||||
// tasks.run(new Runnable() {
|
||||
// @Override
|
||||
// public void run() {
|
||||
// } else {
|
||||
// Post originalPost = posts.get(0);
|
||||
//
|
||||
// Post newPost = newPost();
|
||||
//
|
||||
// EssayistMetadataContent content = originalPost.getContentAs(EssayistMetadataContent.class);
|
||||
// content.setRaw(body);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
|
||||
TentClient tentClient = newTentClient();
|
||||
// List<Post> posts = tentClient.getPosts(new PostQuery().mentionedPost(essayId).postTypes(EssayistMetadataContent.URI));
|
||||
|
||||
String essayId = req.getPathInfo().substring(1);
|
||||
Post post = newPost();
|
||||
post.setId(essayId);
|
||||
post.setEntity(sessions.get().getUser().getProfile().getCore().getEntity());
|
||||
EssayContent essay = new EssayContent();
|
||||
essay.setTitle(req.getParameter("title"));
|
||||
final String body = req.getParameter("body");
|
||||
essay.setBody(new PegDownProcessor().markdownToHtml(body));
|
||||
essay.setExcerpt(req.getParameter("excerpt"));
|
||||
post.setContent(essay);
|
||||
|
||||
tentClient.put(post);
|
||||
|
||||
List<Post> posts = tentClient.getPosts(new PostQuery().mentionedPost(essayId).postTypes(EssayistMetadataContent.URI));
|
||||
|
||||
Post metadataPost = posts.get(0);
|
||||
EssayistMetadataContent metadata = metadataPost.getContentAs(EssayistMetadataContent.class);
|
||||
metadata.setRaw(body);
|
||||
metadataPost.setContent(metadata);
|
||||
|
||||
tentClient.put(metadataPost);
|
||||
|
||||
resp.sendRedirect(routes.get().essay(post));
|
||||
}
|
||||
|
||||
private Post newPost() {
|
||||
Post post = new Post();
|
||||
post.setPublishedAt(System.currentTimeMillis() / 1000);
|
||||
Permissions permissions = new Permissions();
|
||||
permissions.setPublic(true);
|
||||
post.setPermissions(permissions);
|
||||
post.setLicenses(new String[] { "http://creativecommons.org/licenses/by/3.0/" });
|
||||
return post;
|
||||
}
|
||||
|
||||
private TentClient newTentClient() {
|
||||
User user = sessions.get().getUser();
|
||||
|
||||
TentClient tentClient = new TentClient(user.getProfile());
|
||||
tentClient.getAsync().setAccessToken(user.getAccessToken());
|
||||
|
||||
return tentClient;
|
||||
}
|
||||
}
|
|
@ -11,14 +11,15 @@ import com.google.inject.servlet.GuiceServletContextListener;
|
|||
import com.google.inject.servlet.ServletModule;
|
||||
import com.moandjiezana.tent.client.internal.com.google.common.base.Throwables;
|
||||
import com.moandjiezana.tent.essayist.AccessTokenServlet;
|
||||
import com.moandjiezana.tent.essayist.CommentsServlet;
|
||||
import com.moandjiezana.tent.essayist.EssayActionServlet;
|
||||
import com.moandjiezana.tent.essayist.EssayServlet;
|
||||
import com.moandjiezana.tent.essayist.EssaysServlet;
|
||||
import com.moandjiezana.tent.essayist.GlobalFeedServlet;
|
||||
import com.moandjiezana.tent.essayist.LoginServlet;
|
||||
import com.moandjiezana.tent.essayist.LogoutServlet;
|
||||
import com.moandjiezana.tent.essayist.MyFeedServlet;
|
||||
import com.moandjiezana.tent.essayist.NewEssayServlet;
|
||||
import com.moandjiezana.tent.essayist.PreviewServlet;
|
||||
import com.moandjiezana.tent.essayist.WriteServlet;
|
||||
import com.moandjiezana.tent.essayist.auth.Authenticated;
|
||||
import com.moandjiezana.tent.essayist.auth.AuthenticationInterceptor;
|
||||
import com.moandjiezana.tent.essayist.db.migrations.Migration_1;
|
||||
|
@ -66,6 +67,9 @@ public class EssayistServletContextListener extends GuiceServletContextListener
|
|||
poolProperties.setUrl(properties.getProperty("db.url"));
|
||||
poolProperties.setDriverClassName(properties.getProperty("db.driverClassName"));
|
||||
poolProperties.setInitialSize(Integer.parseInt(properties.getProperty("db.initialSize")));
|
||||
poolProperties.setTestWhileIdle(true);
|
||||
poolProperties.setTestOnBorrow(true);
|
||||
poolProperties.setValidationQuery("SELECT 1");
|
||||
|
||||
dataSource = new DataSource(poolProperties);
|
||||
|
||||
|
@ -96,9 +100,10 @@ public class EssayistServletContextListener extends GuiceServletContextListener
|
|||
serve("/accessToken").with(AccessTokenServlet.class);
|
||||
serve("/read").with(MyFeedServlet.class);
|
||||
serve("/global").with(GlobalFeedServlet.class);
|
||||
serve("/write").with(NewEssayServlet.class);
|
||||
serve("/write", "/write/*").with(WriteServlet.class);
|
||||
serve("/preview").with(PreviewServlet.class);
|
||||
serveRegex("/(.*)/essays").with(EssaysServlet.class);
|
||||
serveRegex("/(.*)/essay/(.*)/comment").with(CommentsServlet.class);
|
||||
serveRegex("/(.*)/essay/(.*)/(status|favorite|bookmark|repost|reactions|user)").with(EssayActionServlet.class);
|
||||
serveRegex("/(.*)/essay/(.*)").with(EssayServlet.class);
|
||||
filter("/*").through(Utf8Filter.class);
|
||||
filter("/*").through(HttpMethodFilter.class);
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
package com.moandjiezana.tent.essayist.config;
|
||||
|
||||
import com.google.common.base.Joiner;
|
||||
import com.google.inject.servlet.RequestScoped;
|
||||
import com.moandjiezana.tent.client.posts.Post;
|
||||
import com.moandjiezana.tent.essayist.tent.Entities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
@ -17,8 +21,26 @@ public class Routes {
|
|||
this.req = req;
|
||||
}
|
||||
|
||||
public String assets(String asset) {
|
||||
return req.getContextPath() + "/assets/" + asset;
|
||||
public String asset(String asset) {
|
||||
String url = req.getContextPath() + "/assets/" + asset;
|
||||
|
||||
if (asset.endsWith(".css")) {
|
||||
return "<link rel=\"stylesheet\" href=\"" + url + "\" />";
|
||||
} else if (asset.endsWith(".js")) {
|
||||
return "<script src=\"" + url + "\"></script>";
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown asset type: " + asset);
|
||||
}
|
||||
|
||||
public String assets(String name, String asset, String... assets) {
|
||||
List<String> tags = new ArrayList<String>(assets.length);
|
||||
tags.add(asset(asset));
|
||||
for (String asset2 : assets) {
|
||||
tags.add(asset(asset2));
|
||||
}
|
||||
|
||||
return Joiner.on('\n').join(tags);
|
||||
}
|
||||
|
||||
public String essay(Post essay) {
|
||||
|
@ -26,6 +48,6 @@ public class Routes {
|
|||
}
|
||||
|
||||
public String comment(Post essay) {
|
||||
return essay(essay) + "/comment";
|
||||
return essay(essay) + "/status";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ public class Csrf {
|
|||
.allowCommonInlineFormattingElements()
|
||||
.allowStandardUrlProtocols()
|
||||
.allowStyling()
|
||||
.allowElements("iframe", "img", "a", "table", "thead", "tbody", "tr", "th", "td")
|
||||
.allowElements("iframe", "img", "a", "table", "thead", "tbody", "tr", "th", "td", "em")
|
||||
.allowAttributes("width", "height", "title").globally()
|
||||
.allowAttributes("src", "frameborder", "webkitAllowFullScreen", "mozallowfullscreen", "allowFullScreen").onElements("iframe")
|
||||
.allowAttributes("src", "alt").onElements("img")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package com.moandjiezana.tent.essayist.tent;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.moandjiezana.tent.client.posts.content.EssayContent;
|
||||
import com.moandjiezana.tent.client.users.Profile;
|
||||
|
||||
public class Entities {
|
||||
|
@ -41,4 +42,18 @@ public class Entities {
|
|||
public static String getName(Profile profile, String fallback) {
|
||||
return profile != null && profile.getBasic() != null && !Strings.isNullOrEmpty(profile.getBasic().getName()) ? profile.getBasic().getName() : fallback;
|
||||
}
|
||||
|
||||
public static String essayTitle(EssayContent essay) {
|
||||
if (!Strings.isNullOrEmpty(essay.getTitle())) {
|
||||
return essay.getTitle();
|
||||
}
|
||||
|
||||
String title = Strings.nullToEmpty(!Strings.isNullOrEmpty(essay.getExcerpt()) ? essay.getExcerpt() : essay.getBody());
|
||||
String shortTitle = title.substring(0, Math.min(40, title.length()));
|
||||
if (title.length() > 40) {
|
||||
shortTitle += "...";
|
||||
}
|
||||
|
||||
return shortTitle;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<%import>
|
||||
com.moandjiezana.tent.client.users.Profile;
|
||||
com.moandjiezana.tent.client.posts.*;
|
||||
com.moandjiezana.tent.client.posts.content.EssayContent;
|
||||
com.moandjiezana.tent.client.posts.content.StatusContent;
|
||||
com.moandjiezana.tent.essayist.tent.*;
|
||||
com.moandjiezana.essayist.posts.*;
|
||||
java.text.SimpleDateFormat;
|
||||
java.util.*;
|
||||
</%import>
|
||||
<%args>
|
||||
Post essay;
|
||||
Profile profile;
|
||||
String active = "My Feed";
|
||||
List<Post> reactions = null;
|
||||
</%args>
|
||||
<%java>
|
||||
final EssayContent content = essay.getContentAs(EssayContent.class);
|
||||
final SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||
final SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd MMMM yyyy HH:mm ZZZZ");
|
||||
</%java>
|
||||
<&| Layout; active = active &>
|
||||
<& partials/Essay; essay=essay; entityForUrl=Entities.getForUrl(essay.getEntity()); entityName=Entities.getName(profile); essayId=essay.getId(); formattedPublicationDate=dateFormat.format(new Date(essay.getPublishedAt() * 1000)); display=true; &>
|
||||
|
||||
<& partials/Reactions; reactions=reactions; essay=essay; autoLoad=true; &>
|
||||
</&>
|
|
@ -1,61 +0,0 @@
|
|||
<%import>
|
||||
com.moandjiezana.tent.client.users.Profile;
|
||||
com.moandjiezana.tent.client.posts.*;
|
||||
com.moandjiezana.tent.client.posts.content.EssayContent;
|
||||
com.moandjiezana.tent.client.posts.content.StatusContent;
|
||||
com.moandjiezana.tent.essayist.tent.*;
|
||||
java.text.SimpleDateFormat;
|
||||
java.util.*;
|
||||
</%import>
|
||||
<%args>
|
||||
Post essay;
|
||||
Profile profile;
|
||||
String active = "My Feed";
|
||||
List<Post> comments;
|
||||
</%args>
|
||||
<%java>
|
||||
final EssayContent content = essay.getContentAs(EssayContent.class);
|
||||
final SimpleDateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy");
|
||||
final SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd MMMM yyyy 'at' HH:mm ZZZZ");
|
||||
</%java>
|
||||
<&| Layout; active = active &>
|
||||
<h1><% content.getTitle() %> <small><a href="<% jamonContext.currentUrl %>" style="text-decoration: none"><% Character.valueOf('\u2693') %></a></small></h1>
|
||||
<h3><small>by</small> <a href="<% jamonContext.contextPath %>/<% Entities.getForUrl(essay.getEntity()) %>/essays"><% Entities.getName(profile) %></a> <small><% dateFormat.format(new Date(essay.getPublishedAt() * 1000)) %></small></h3>
|
||||
<div class="bodyText">
|
||||
<% content.getBody() #n %>
|
||||
</div>
|
||||
<%if jamonContext.isLoggedIn() || !comments.isEmpty() %>
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<h3>Comments</h3>
|
||||
</div>
|
||||
</div>
|
||||
</%if>
|
||||
<%if jamonContext.isLoggedIn() %>
|
||||
<form action="<% jamonContext.routes.comment(essay) %>" method="post">
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<textarea name="comment" rows="3" required="required" class="span6"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span6">
|
||||
<input type="submit" value="Comment" class="btn pull-right" />
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</%if>
|
||||
|
||||
<%if !comments.isEmpty() %>
|
||||
<div class="row">
|
||||
<%for Post comment : comments %>
|
||||
<div class="span12">
|
||||
<strong><% Entities.stripScheme(comment.getEntity()) %></strong> <% dateTimeFormat.format(new Date(comment.getPublishedAt() * 1000)) %><br/>
|
||||
<p>
|
||||
<% comment.getContentAs(StatusContent.class).getText() %>
|
||||
</p>
|
||||
</div>
|
||||
</%for>
|
||||
</div>
|
||||
</%if>
|
||||
</&>
|
|
@ -25,9 +25,9 @@ String url;
|
|||
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<link rel="stylesheet" href="<% jamonContext.contextPath %>/assets/bootstrap-2.1.1/css/bootstrap.min.css" />
|
||||
<link href='http://fonts.googleapis.com/css?family=Alegreya:400italic,400,700' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=Alegreya+SC:700' rel='stylesheet' type='text/css'>
|
||||
<% jamonContext.routes.assets("application.css", "bootstrap-2.1.1/css/bootstrap.min.css") #n %>
|
||||
<link href='http://fonts.googleapis.com/css?family=PT+Serif' rel='stylesheet' type='text/css'>
|
||||
<link href='http://fonts.googleapis.com/css?family=PT+Sans' rel='stylesheet' type='text/css'>
|
||||
<style type="text/css">
|
||||
body {
|
||||
padding-top: 60px;
|
||||
|
@ -38,29 +38,40 @@ String url;
|
|||
}
|
||||
|
||||
h1, h2, h3, h4 {
|
||||
font-family: 'Alegreya SC', Georgia, serif;
|
||||
font-family: 'PT Sans', Georgia, serif;
|
||||
}
|
||||
|
||||
h3 small {
|
||||
font-size: 15px;
|
||||
font-size: 0.6em;
|
||||
}
|
||||
|
||||
.bodyText {
|
||||
font-family: 'Alegreya', Georgia, serif; font-size: 1.5em;
|
||||
font-family: 'PT Serif', Georgia, serif; font-size: 1.1em; line-height: 1.5;
|
||||
}
|
||||
|
||||
.separator {
|
||||
border-bottom: 1px solid #eee;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.form-inline {
|
||||
display: inline;
|
||||
}
|
||||
</style>
|
||||
<link rel="stylesheet" href="<% jamonContext.contextPath %>/assets/bootstrap-2.1.1/css/bootstrap-responsive.min.css" />
|
||||
<% jamonContext.routes.asset("bootstrap-2.1.1/css/bootstrap-responsive.min.css") #n %>
|
||||
<script>
|
||||
var E = {
|
||||
contextPath: "<% jamonContext.contextPath %>"
|
||||
};
|
||||
</script>
|
||||
<% jamonContext.routes.assets("application.js", "underscore-1.4.2/underscore.min.js", "spin/spin.min.js", "essayist.js") #n %>
|
||||
|
||||
<!--[if lt IE 9]>
|
||||
<script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script>
|
||||
<![endif]-->
|
||||
|
||||
<!--script src="<% jamonContext.contextPath %>/assets/bootstrap-2.1.1/js/bootstrap.min.js"></script-->
|
||||
<script src="<% jamonContext.routes.assets("essayist.js") %>"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
@ -87,7 +98,6 @@ String url;
|
|||
<ul class="nav">
|
||||
<& navItem: "Site Feed"; "global" &>
|
||||
</ul>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -96,7 +106,11 @@ String url;
|
|||
<& body &>
|
||||
</div>
|
||||
<div class="container">
|
||||
<small>Version: 20121030</small>
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<small class="muted">Version: 20121114</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -3,36 +3,65 @@ java.util.*;
|
|||
com.moandjiezana.tent.client.posts.*;
|
||||
com.moandjiezana.tent.client.posts.content.*;
|
||||
com.moandjiezana.tent.essayist.tent.*;
|
||||
com.moandjiezana.essayist.posts.*;
|
||||
</%import>
|
||||
<%args>
|
||||
Post essay = null;
|
||||
Post metadata = null;
|
||||
</%args>
|
||||
<%java>
|
||||
final EssayContent content = essay != null ? essay.getContentAs(EssayContent.class) : null;
|
||||
final EssayistMetadataContent metadataContent;
|
||||
final String raw;
|
||||
if (metadata != null) {
|
||||
metadataContent = metadata.getContentAs(EssayistMetadataContent.class);
|
||||
raw = metadataContent.getRaw();
|
||||
} else {
|
||||
metadataContent = null;
|
||||
raw = "";
|
||||
}
|
||||
</%java>
|
||||
|
||||
<&| Layout &>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Title
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="title" class="span8" />
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span12">
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Title
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="title" value="<%if content != null %><% content.getTitle() %></%if>" class="span8" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Excerpt
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="excerpt" value="<%if content != null %><% content.getExcerpt() %></%if>" class="span8" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Body (use <a href="http://daringfireball.net/projects/markdown/syntax">Markdown</a>)
|
||||
</label>
|
||||
<div class="controls">
|
||||
<textarea name="body" required="required" rows="15" class="span8"><% raw %></textarea><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<%if essay != null %>
|
||||
<input type="hidden" name="_method" value="PUT" />
|
||||
</%if>
|
||||
<button id="newEssayPreviewTrigger" type="button" class="btn" style="display: none">Preview</button>
|
||||
<button type="submit" class="btn btn-success"><i class="icon-globe icon-white"></i> Publish</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Excerpt
|
||||
</label>
|
||||
<div class="controls">
|
||||
<input type="text" name="excerpt" class="span8" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-group">
|
||||
<label class="control-label">
|
||||
Body (as <a href="http://daringfireball.net/projects/markdown/syntax">Markdown</a>)
|
||||
</label>
|
||||
<div class="controls">
|
||||
<textarea name="body" required="required" rows="15" class="span8"></textarea><br/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-actions">
|
||||
<button type="submit" value="Publish" class="btn btn-success"><i class="icon-globe icon-white"></i> Publish</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="row">
|
||||
<div id="preview" class="span7 offset3"></div>
|
||||
</div>
|
||||
</&>
|
|
@ -0,0 +1,3 @@
|
|||
<&| Layout &>
|
||||
Sorry, this essay cannot be edited.
|
||||
</&>
|
|
@ -0,0 +1,14 @@
|
|||
<%import>
|
||||
com.moandjiezana.tent.client.posts.*;
|
||||
</%import>
|
||||
<%args>
|
||||
Post essay;
|
||||
</%args>
|
||||
<form action="<% jamonContext.routes.comment(essay) %>" method="post">
|
||||
<div>
|
||||
<textarea name="comment" rows="3" required="required" placeholder="Comment on this essay" class="span7"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<input type="submit" value="Comment" class="btn pull-right" />
|
||||
</div>
|
||||
</form>
|
|
@ -0,0 +1,50 @@
|
|||
<%import>
|
||||
com.moandjiezana.tent.client.posts.*;
|
||||
com.moandjiezana.tent.client.posts.content.*;
|
||||
com.moandjiezana.tent.essayist.tent.Entities;
|
||||
</%import>
|
||||
<%args>
|
||||
Post essay;
|
||||
String entityForUrl;
|
||||
String entityName;
|
||||
String essayId;
|
||||
String formattedPublicationDate;
|
||||
boolean display = false;
|
||||
</%args>
|
||||
<%java>
|
||||
EssayContent essayContent = essay.getContentAs(EssayContent.class);
|
||||
String essayUrl = jamonContext.routes.essay(essay);
|
||||
</%java>
|
||||
<div class="row">
|
||||
<div class="span7">
|
||||
<h1><% Entities.essayTitle(essayContent) %> <a href="<% essayUrl %>" style="text-decoration: none"><% Character.valueOf('\u2693') %></a></h1>
|
||||
<h3><small>by</small> <a href="<% jamonContext.contextPath %>/<% entityForUrl %>/essays"><% entityName %></a> <small><% formattedPublicationDate %></small></h3>
|
||||
<p class="muted"><% essayContent.getExcerpt() %></p>
|
||||
<div class="bodyText">
|
||||
<% jamonContext.csrf.stripScripts(essayContent.getBody()) #n %>
|
||||
</div>
|
||||
<%if jamonContext.isLoggedIn() %>
|
||||
<div>
|
||||
<form action="<% essayUrl %>/favorite" method="post" class="form-inline" data-essay-action="favorite">
|
||||
<button type="submit" class="btn" title="Favourite"><i class="icon-star-empty"></i></button>
|
||||
</form>
|
||||
<form action="<% essayUrl %>/bookmark" method="post" class="form-inline" data-essay-action="bookmark">
|
||||
<input type="hidden" name="title" value="<% essayContent.getTitle() %>" />
|
||||
<input type="hidden" name="name" value="<% entityName %>" />
|
||||
<input type="hidden" name="description" value="<% essayContent.getExcerpt() %>" />
|
||||
<button type="submit" class="btn" title="Bookmark"><i class="icon-map-marker"></i></button>
|
||||
</form>
|
||||
<form action="<% essayUrl %>/repost" method="post" class="form-inline" data-essay-action="repost">
|
||||
<button type="submit" class="btn" title="Repost"><i class="icon-retweet"></i></button>
|
||||
</form>
|
||||
<%if jamonContext.getCurrentUser().owns(essay) %>
|
||||
<a href="<% jamonContext.contextPath %>/write/<% essay.getId() %>" class="btn btn-primary"><i class="icon-pencil icon-white"></i></a>
|
||||
<form action="<% jamonContext.routes.essay(essay) %>" method="post" class="form-inline">
|
||||
<button class="btn btn-danger"><i class="icon-trash icon-white"></i></button>
|
||||
<input type="hidden" name="_method" value="DELETE" />
|
||||
</form>
|
||||
</%if>
|
||||
</div>
|
||||
</%if>
|
||||
</div>
|
||||
</div>
|
|
@ -4,6 +4,7 @@ com.moandjiezana.tent.client.users.Profile;
|
|||
com.moandjiezana.tent.client.posts.content.*;
|
||||
com.moandjiezana.tent.essayist.tent.*;
|
||||
java.text.SimpleDateFormat;
|
||||
com.google.common.base.Strings;
|
||||
java.util.*;
|
||||
</%import>
|
||||
<%args>
|
||||
|
@ -20,7 +21,7 @@ String authorPageUrl = jamonContext.contextPath + "/" + entityForUrl + "/essays"
|
|||
String formattedPublicationDate = dateFormat.format(new Date(essay.getPublishedAt() * 1000));
|
||||
</%java>
|
||||
<div data-essay="container" data-essay-author="<% entityForUrl %>" data-essay-id="<% essay.getId() %>">
|
||||
<div class="row" data-essay="summary" class="separator">
|
||||
<div class="row separator" data-essay="summary">
|
||||
<%if showProfile %>
|
||||
<div class="span2">
|
||||
<%if profile != null && profile.getBasic() != null && profile.getBasic().getAvatarUrl() != null %>
|
||||
|
@ -29,12 +30,13 @@ String formattedPublicationDate = dateFormat.format(new Date(essay.getPublishedA
|
|||
</div>
|
||||
</%if>
|
||||
<div class="span10">
|
||||
<h3><a href="<% jamonContext.contextPath %>/<% entityForUrl %>/essay/<% essay.getId() %>" data-essay="link"><% essayContent.getTitle() %></a></h3>
|
||||
<h3><a href="<% jamonContext.routes.essay(essay) %>" data-essay="link"><% Entities.essayTitle(essayContent) %></a></h3>
|
||||
<%if showProfile %><a href="<% jamonContext.contextPath %>/<% entityForUrl %>/essays"><% entityName %></a></%if> <% formattedPublicationDate %>
|
||||
<p class="excerpt"><% essayContent.getExcerpt() %></p>
|
||||
<%if jamonContext.getCurrentUser().owns(essay) %>
|
||||
<div>
|
||||
<form action="<% jamonContext.contextPath %>/<% entityForUrl %>/essay/<% essay.getId() %>" method="post">
|
||||
<a href="<% jamonContext.contextPath %>/write/<% essay.getId() %>" class="btn"><i class="icon-pencil"></i> Edit</a>
|
||||
<form action="<% jamonContext.routes.essay(essay) %>" method="post" style="display: inline">
|
||||
<button class="btn btn-danger"><i class="icon-trash icon-white"></i> Delete</button>
|
||||
<input type="hidden" name="_method" value="DELETE" />
|
||||
</form>
|
||||
|
@ -43,14 +45,9 @@ String formattedPublicationDate = dateFormat.format(new Date(essay.getPublishedA
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row" data-essay="full" style="display: none">
|
||||
<div class="span12">
|
||||
<h1><% essayContent.getTitle() %> <small><a href="<% jamonContext.currentUrl %>" style="text-decoration: none"><% Character.valueOf('\u2693') %></a></small></h1>
|
||||
<h3><small>by</small> <a href="<% jamonContext.contextPath %>/<% entityForUrl %>/essays"><% entityName %></a> <small><% formattedPublicationDate %></small></h3>
|
||||
<blockquote class="muted"><% essayContent.getExcerpt() %></blockquote>
|
||||
<div class="bodyText">
|
||||
<% jamonContext.csrf.stripScripts(essayContent.getBody()) #n %>
|
||||
</div>
|
||||
</div>
|
||||
<div data-essay="full" style="display: none">
|
||||
<& Essay; essay=essay; entityForUrl=entityForUrl; entityName=entityName; essayId=essay.getId(); formattedPublicationDate=formattedPublicationDate &>
|
||||
|
||||
<& Reactions; essay=essay &>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
<%import>
|
||||
com.moandjiezana.tent.client.posts.*;
|
||||
java.util.*;
|
||||
</%import>
|
||||
<%args>
|
||||
List<Post> reactions;
|
||||
</%args>
|
||||
<%for Post reaction : reactions %>
|
||||
<& ReactionTemplate; reaction=reaction &>
|
||||
</%for>
|
|
@ -0,0 +1,30 @@
|
|||
<%import>
|
||||
com.moandjiezana.tent.client.posts.*;
|
||||
com.moandjiezana.tent.client.posts.content.*;
|
||||
com.moandjiezana.essayist.posts.*;
|
||||
com.moandjiezana.tent.essayist.tent.*;
|
||||
java.util.*;
|
||||
java.text.SimpleDateFormat;
|
||||
</%import>
|
||||
<%args>
|
||||
Post reaction;
|
||||
</%args>
|
||||
<%java>
|
||||
final SimpleDateFormat dateTimeFormat = new SimpleDateFormat("dd MMMM yyyy HH:mm ZZZZ");
|
||||
String displayEntity = Entities.stripScheme(reaction.getEntity());
|
||||
String formattedDate = dateTimeFormat.format(new Date(reaction.getPublishedAt() * 1000));
|
||||
</%java>
|
||||
<div data-reaction-author="<% reaction.getEntity() %>" data-reaction-id="<% reaction.getId() %>">
|
||||
<%if Post.Types.equalsIgnoreVersion(Post.Types.status("v0.1.0"), reaction.getType()) %>
|
||||
<i class="icon-comment"></i> <a href="<% reaction.getEntity() %>"><% displayEntity %></a> commented <small class="muted"><% formattedDate %></small><br/>
|
||||
<p>
|
||||
<% reaction.getContentAs(StatusContent.class).getText() %>
|
||||
</p>
|
||||
<%elseif Post.Types.equalsIgnoreVersion(Favorite.URI, reaction.getType()) %>
|
||||
<i class="icon-star"></i> Favourited by <a href="<% reaction.getEntity() %>"><% displayEntity %></a> <small class="muted"><% formattedDate %></small>
|
||||
<%elseif Post.Types.equalsIgnoreVersion(Bookmark.URI, reaction.getType()) %>
|
||||
<i class="icon-map-marker"></i> Bookmarked by <a href="<% reaction.getEntity() %>"><% displayEntity %></a> <small class="muted"><% formattedDate %></small>
|
||||
<%elseif Post.Types.equalsIgnoreVersion(Post.Types.repost("v0.1.0"), reaction.getType()) %>
|
||||
<i class="icon-retweet"></i> Reposted by <a href="<% reaction.getEntity() %>"><% displayEntity %></a> <small class="muted"><% formattedDate %></small>
|
||||
</%if>
|
||||
</div>
|
|
@ -0,0 +1,28 @@
|
|||
<%import>
|
||||
com.moandjiezana.tent.client.posts.*;
|
||||
com.moandjiezana.tent.client.posts.content.*;
|
||||
com.moandjiezana.tent.essayist.tent.*;
|
||||
java.util.*;
|
||||
</%import>
|
||||
<%args>
|
||||
List<Post> reactions = null;
|
||||
Post essay;
|
||||
boolean autoLoad = false;
|
||||
</%args>
|
||||
<div class="row">
|
||||
<div class="span7">
|
||||
<h3>Reactions</h3>
|
||||
<%if jamonContext.isLoggedIn() %>
|
||||
<& CommentForm; essay=essay; &>
|
||||
</%if>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="span7">
|
||||
<div data-essay="reactions" data-essay-author="<% Entities.getForUrl(essay.getEntity()) %>" data-essay-id="<% essay.getId() %>" data-essay-loaded="<% reactions != null %>" data-essay-autoLoad="<% autoLoad %>">
|
||||
<%if reactions != null %>
|
||||
<& ReactionList; reactions=reactions &>
|
||||
</%if>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
function init() {
|
||||
function initNavigation() {
|
||||
var essayContainers = document.querySelectorAll("[data-essay=container]");
|
||||
var i;
|
||||
|
||||
|
@ -36,9 +36,37 @@ function init() {
|
|||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
var container = null;
|
||||
var currentTarget = event.target;
|
||||
while (container === null) {
|
||||
currentTarget = currentTarget.parentNode;
|
||||
if (currentTarget.dataset.essay === "container") {
|
||||
container = currentTarget;
|
||||
}
|
||||
}
|
||||
|
||||
var scrollPosition = document.body.scrollTop;
|
||||
displaySection("essay", event.currentTarget);
|
||||
|
||||
history.pushState({ essayId: event.currentTarget.dataset.essayId, essayAuthor: event.currentTarget.dataset.essayAuthor }, "essay title", event.target.href);
|
||||
var reactionsContainer = container.querySelector('[data-essay="reactions"]');
|
||||
fetchReactions(reactionsContainer);
|
||||
// if (reactionsContainer.dataset.essayLoaded === "false") {
|
||||
// var spinner = new Spinner().spin(container.querySelector('[data-essay="reactionsSpinner"]'));
|
||||
// var xhr = new XMLHttpRequest();
|
||||
// xhr.onreadystatechange = function () {
|
||||
// if (xhr.readyState === 4) {
|
||||
// spinner.stop();
|
||||
// reactionsContainer.innerHTML = xhr.responseText;
|
||||
// reactionsContainer.dataset.essayLoaded = "true";
|
||||
// }
|
||||
// };
|
||||
// xhr.open("GET", E.contextPath + "/" + container.dataset.essayAuthor + "/essay/" + container.dataset.essayId + "/reactions", true);
|
||||
// xhr.setRequestHeader("Accept", "text/html");
|
||||
// xhr.setRequestHeader("X-Essayist-Partial", "true");
|
||||
// xhr.send();
|
||||
// }
|
||||
|
||||
history.pushState({ essayId: event.currentTarget.dataset.essayId, essayAuthor: event.currentTarget.dataset.essayAuthor, scrollPosition: scrollPosition }, "essay title", event.target.href);
|
||||
|
||||
return false;
|
||||
};
|
||||
|
@ -47,6 +75,7 @@ function init() {
|
|||
var essayContainer;
|
||||
if (window.location.href.indexOf("/essays") > -1 || window.location.href.indexOf("/global") > -1 || window.location.href.indexOf("/read") > -1) {
|
||||
displaySection("list", document);
|
||||
window.scrollTo(0);
|
||||
} else if (event.state !== null) {
|
||||
essayContainer = document.querySelector("[data-essay-author=\"" + event.state.essayAuthor + "\"][data-essay-id=\"" + event.state.essayId + "\"]");
|
||||
displaySection("essay", essayContainer);
|
||||
|
@ -60,6 +89,62 @@ function init() {
|
|||
window.addEventListener("popstate", essayPopStateHandler, false);
|
||||
}
|
||||
|
||||
if (history.pushState !== undefined) {
|
||||
document.addEventListener("DOMContentLoaded", init, false);
|
||||
function initPreview() {
|
||||
var trigger = document.querySelector("#newEssayPreviewTrigger");
|
||||
|
||||
if (trigger === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
trigger.style.display = "inline";
|
||||
|
||||
var body = document.querySelector("textarea[name='body']");
|
||||
|
||||
var updatePreview = function () {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
document.querySelector("#preview").innerHTML = xhr.responseText;
|
||||
}
|
||||
};
|
||||
xhr.open("POST", E.contextPath + "/preview", true);
|
||||
xhr.setRequestHeader("Accept", "text/html");
|
||||
xhr.setRequestHeader("X-Essayist-Partial", "true");
|
||||
xhr.send(body.value);
|
||||
};
|
||||
|
||||
trigger.addEventListener("click", updatePreview, false);
|
||||
body.addEventListener("keyup", _.debounce(updatePreview, 2000), false);
|
||||
}
|
||||
|
||||
function initReactions() {
|
||||
var reactionsContainers = document.querySelectorAll('[data-essay="reactions"][data-essay-autoLoad="true"]');
|
||||
var i;
|
||||
for (i = 0; i < reactionsContainers.length; i++) {
|
||||
fetchReactions(reactionsContainers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchReactions(reactionsContainer) {
|
||||
if (reactionsContainer.dataset.essayLoaded === "false") {
|
||||
var spinner = new Spinner().spin(reactionsContainer);
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function () {
|
||||
if (xhr.readyState === 4) {
|
||||
spinner.stop();
|
||||
reactionsContainer.innerHTML = xhr.responseText;
|
||||
reactionsContainer.dataset.essayLoaded = "true";
|
||||
}
|
||||
};
|
||||
xhr.open("GET", E.contextPath + "/" + reactionsContainer.dataset.essayAuthor + "/essay/" + reactionsContainer.dataset.essayId + "/reactions", true);
|
||||
xhr.setRequestHeader("Accept", "text/html");
|
||||
xhr.setRequestHeader("X-Essayist-Partial", "true");
|
||||
xhr.send();
|
||||
}
|
||||
}
|
||||
|
||||
if (history.pushState !== undefined && document.querySelector !== undefined && XMLHttpRequest !== undefined) {
|
||||
document.addEventListener("DOMContentLoaded", initNavigation, false);
|
||||
document.addEventListener("DOMContentLoaded", initPreview, false);
|
||||
document.addEventListener("DOMContentLoaded", initReactions, false);
|
||||
}
|
||||
|
|
2
src/main/webapp/assets/spin/spin.min.js
vendored
Normal file
2
src/main/webapp/assets/spin/spin.min.js
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
//fgnass.github.com/spin.js#v1.2.7
|
||||
!function(e,t,n){function o(e,n){var r=t.createElement(e||"div"),i;for(i in n)r[i]=n[i];return r}function u(e){for(var t=1,n=arguments.length;t<n;t++)e.appendChild(arguments[t]);return e}function f(e,t,n,r){var o=["opacity",t,~~(e*100),n,r].join("-"),u=.01+n/r*100,f=Math.max(1-(1-e)/t*(100-u),e),l=s.substring(0,s.indexOf("Animation")).toLowerCase(),c=l&&"-"+l+"-"||"";return i[o]||(a.insertRule("@"+c+"keyframes "+o+"{"+"0%{opacity:"+f+"}"+u+"%{opacity:"+e+"}"+(u+.01)+"%{opacity:1}"+(u+t)%100+"%{opacity:"+e+"}"+"100%{opacity:"+f+"}"+"}",a.cssRules.length),i[o]=1),o}function l(e,t){var i=e.style,s,o;if(i[t]!==n)return t;t=t.charAt(0).toUpperCase()+t.slice(1);for(o=0;o<r.length;o++){s=r[o]+t;if(i[s]!==n)return s}}function c(e,t){for(var n in t)e.style[l(e,n)||n]=t[n];return e}function h(e){for(var t=1;t<arguments.length;t++){var r=arguments[t];for(var i in r)e[i]===n&&(e[i]=r[i])}return e}function p(e){var t={x:e.offsetLeft,y:e.offsetTop};while(e=e.offsetParent)t.x+=e.offsetLeft,t.y+=e.offsetTop;return t}var r=["webkit","Moz","ms","O"],i={},s,a=function(){var e=o("style",{type:"text/css"});return u(t.getElementsByTagName("head")[0],e),e.sheet||e.styleSheet}(),d={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"auto",left:"auto",position:"relative"},v=function m(e){if(!this.spin)return new m(e);this.opts=h(e||{},m.defaults,d)};v.defaults={},h(v.prototype,{spin:function(e){this.stop();var t=this,n=t.opts,r=t.el=c(o(0,{className:n.className}),{position:n.position,width:0,zIndex:n.zIndex}),i=n.radius+n.length+n.width,u,a;e&&(e.insertBefore(r,e.firstChild||null),a=p(e),u=p(r),c(r,{left:(n.left=="auto"?a.x-u.x+(e.offsetWidth>>1):parseInt(n.left,10)+i)+"px",top:(n.top=="auto"?a.y-u.y+(e.offsetHeight>>1):parseInt(n.top,10)+i)+"px"})),r.setAttribute("aria-role","progressbar"),t.lines(r,t.opts);if(!s){var f=0,l=n.fps,h=l/n.speed,d=(1-n.opacity)/(h*n.trail/100),v=h/n.lines;(function m(){f++;for(var e=n.lines;e;e--){var i=Math.max(1-(f+e*v)%h*d,n.opacity);t.opacity(r,n.lines-e,i,n)}t.timeout=t.el&&setTimeout(m,~~(1e3/l))})()}return t},stop:function(){var e=this.el;return e&&(clearTimeout(this.timeout),e.parentNode&&e.parentNode.removeChild(e),this.el=n),this},lines:function(e,t){function i(e,r){return c(o(),{position:"absolute",width:t.length+t.width+"px",height:t.width+"px",background:e,boxShadow:r,transformOrigin:"left",transform:"rotate("+~~(360/t.lines*n+t.rotate)+"deg) translate("+t.radius+"px"+",0)",borderRadius:(t.corners*t.width>>1)+"px"})}var n=0,r;for(;n<t.lines;n++)r=c(o(),{position:"absolute",top:1+~(t.width/2)+"px",transform:t.hwaccel?"translate3d(0,0,0)":"",opacity:t.opacity,animation:s&&f(t.opacity,t.trail,n,t.lines)+" "+1/t.speed+"s linear infinite"}),t.shadow&&u(r,c(i("#000","0 0 4px #000"),{top:"2px"})),u(e,u(r,i(t.color,"0 0 1px rgba(0,0,0,.1)")));return e},opacity:function(e,t,n){t<e.childNodes.length&&(e.childNodes[t].style.opacity=n)}}),function(){function e(e,t){return o("<"+e+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',t)}var t=c(o("group"),{behavior:"url(#default#VML)"});!l(t,"transform")&&t.adj?(a.addRule(".spin-vml","behavior:url(#default#VML)"),v.prototype.lines=function(t,n){function s(){return c(e("group",{coordsize:i+" "+i,coordorigin:-r+" "+ -r}),{width:i,height:i})}function l(t,i,o){u(a,u(c(s(),{rotation:360/n.lines*t+"deg",left:~~i}),u(c(e("roundrect",{arcsize:n.corners}),{width:r,height:n.width,left:n.radius,top:-n.width>>1,filter:o}),e("fill",{color:n.color,opacity:n.opacity}),e("stroke",{opacity:0}))))}var r=n.length+n.width,i=2*r,o=-(n.width+n.length)*2+"px",a=c(s(),{position:"absolute",top:o,left:o}),f;if(n.shadow)for(f=1;f<=n.lines;f++)l(f,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(f=1;f<=n.lines;f++)l(f);return u(t,a)},v.prototype.opacity=function(e,t,n,r){var i=e.firstChild;r=r.shadow&&r.lines||0,i&&t+r<i.childNodes.length&&(i=i.childNodes[t+r],i=i&&i.firstChild,i=i&&i.firstChild,i&&(i.opacity=n))}):s=l(t,"animation")}(),typeof define=="function"&&define.amd?define(function(){return v}):e.Spinner=v}(window,document);
|
5
src/main/webapp/assets/underscore-1.4.2/underscore.min.js
vendored
Normal file
5
src/main/webapp/assets/underscore-1.4.2/underscore.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
|
@ -48,4 +48,11 @@ public class CsrfTest {
|
|||
|
||||
assertEquals(table, new Csrf().stripScripts(table));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_allow_emphasis() {
|
||||
String emphasis = "<em>emphas</em>ised";
|
||||
|
||||
assertEquals(emphasis, new Csrf().stripScripts(emphasis));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue