<modelVersion>4.0.0</modelVersion>
<groupId>net.pterodactylus</groupId>
<artifactId>sone</artifactId>
- <version>0.4.1</version>
+ <version>0.4.2</version>
<dependencies>
<dependency>
<groupId>net.pterodactylus</groupId>
<artifactId>utils</artifactId>
- <version>0.7.8</version>
+ <version>0.8</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<dependency>
<groupId>org.freenetproject</groupId>
<artifactId>fred</artifactId>
- <version>0.7.5.1311</version>
+ <version>0.7.5.1336</version>
<scope>provided</scope>
</dependency>
<dependency>
if ((sone == null) && create) {
sone = new Sone(id);
localSones.put(id, sone);
+ setSoneStatus(sone, SoneStatus.unknown);
}
return sone;
}
if ((sone == null) && create) {
sone = new Sone(id);
remoteSones.put(id, sone);
+ setSoneStatus(sone, SoneStatus.unknown);
}
return sone;
}
}
/**
- * Returns whether the given Sone is a new Sone. After this check, the Sone
- * is marked as known, i.e. a second call with the same parameters will
- * always yield {@code false}.
+ * Returns whether the Sone with the given ID is a new Sone.
*
- * @param sone
- * The sone to check for
+ * @param soneId
+ * The ID of the sone to check for
* @return {@code true} if the given Sone is new, false otherwise
*/
- public boolean isNewSone(Sone sone) {
+ public boolean isNewSone(String soneId) {
synchronized (newSones) {
- boolean isNew = !knownSones.contains(sone.getId()) && newSones.remove(sone.getId());
- knownSones.add(sone.getId());
- if (isNew) {
- coreListenerManager.fireMarkSoneKnown(sone);
- }
- return isNew;
+ return !knownSones.contains(soneId) && newSones.contains(soneId);
}
}
}
/**
- * Returns whether the given post ID is new. After this method returns it is
- * marked a known post ID.
+ * Returns whether the given post ID is new.
*
* @param postId
* The post ID
* otherwise
*/
public boolean isNewPost(String postId) {
- return isNewPost(postId, true);
- }
-
- /**
- * Returns whether the given post ID is new. If {@code markAsKnown} is
- * {@code true} then after this method returns the post ID is marked a known
- * post ID.
- *
- * @param postId
- * The post ID
- * @param markAsKnown
- * {@code true} to mark the post ID as known, {@code false} to
- * not to mark it as known
- * @return {@code true} if the post is considered to be new, {@code false}
- * otherwise
- */
- public boolean isNewPost(String postId, boolean markAsKnown) {
synchronized (newPosts) {
- boolean isNew = !knownPosts.contains(postId) && newPosts.contains(postId);
- if (markAsKnown) {
- Post post = getPost(postId, false);
- if (post != null) {
- markPostKnown(post);
- }
- }
- return isNew;
+ return !knownPosts.contains(postId) && newPosts.contains(postId);
}
}
* otherwise
*/
public boolean isNewReply(String replyId) {
- return isNewReply(replyId, true);
- }
-
- /**
- * Returns whether the reply with the given ID is new.
- *
- * @param replyId
- * The ID of the reply to check
- * @param markAsKnown
- * {@code true} to mark the reply as known, {@code false} to not
- * to mark it as known
- * @return {@code true} if the reply is considered to be new, {@code false}
- * otherwise
- */
- public boolean isNewReply(String replyId, boolean markAsKnown) {
synchronized (newReplies) {
- boolean isNew = !knownReplies.contains(replyId) && newReplies.contains(replyId);
- if (markAsKnown) {
- Reply reply = getReply(replyId, false);
- if (reply != null) {
- markReplyKnown(reply);
- }
- }
- return isNew;
+ return !knownReplies.contains(replyId) && newReplies.contains(replyId);
}
}
}
}
}
+ List<Post> storedPosts = storedSone.getPosts();
synchronized (newPosts) {
for (Post post : sone.getPosts()) {
- post.setSone(getSone(post.getSone().getId()));
- if (!storedSone.getPosts().contains(post) && !knownPosts.contains(post.getId())) {
+ post.setSone(storedSone);
+ if (!storedPosts.contains(post) && !knownPosts.contains(post.getId())) {
newPosts.add(post.getId());
coreListenerManager.fireNewPostFound(post);
}
}
}
}
+ Set<Reply> storedReplies = sone.getReplies();
synchronized (newReplies) {
for (Reply reply : sone.getReplies()) {
- reply.setSone(getSone(reply.getSone().getId()));
- if (!storedSone.getReplies().contains(reply) && !knownReplies.contains(reply.getId())) {
+ reply.setSone(storedSone);
+ if (!storedReplies.contains(reply) && !knownReplies.contains(reply.getId())) {
newReplies.add(reply.getId());
coreListenerManager.fireNewReplyFound(reply);
}
}
/**
+ * Marks the given Sone as known. If the Sone was {@link #isNewPost(String)
+ * new} before, a {@link CoreListener#markSoneKnown(Sone)} event is fired.
+ *
+ * @param sone
+ * The Sone to mark as known
+ */
+ public void markSoneKnown(Sone sone) {
+ synchronized (newSones) {
+ if (newSones.remove(sone.getId())) {
+ knownSones.add(sone.getId());
+ coreListenerManager.fireMarkSoneKnown(sone);
+ saveConfiguration();
+ }
+ }
+ }
+
+ /**
* Loads and updates the given Sone from the configuration. If any error is
* encountered, loading is aborted and the given Sone is not changed.
*
@SuppressWarnings("synthetic-access")
public void onFoundEdition(long edition, USK key, ObjectContainer objectContainer, ClientContext clientContext, boolean metadata, short codec, byte[] data, boolean newKnownGood, boolean newSlotToo) {
logger.log(Level.FINE, "Found USK update for Sone “%s” at %s, new known good: %s, new slot too: %s.", new Object[] { sone, key, newKnownGood, newSlotToo });
- if (newKnownGood) {
- sone.setLatestEdition(key.suggestedEdition);
+ if (edition > sone.getLatestEdition()) {
+ sone.setLatestEdition(edition);
new Thread(new Runnable() {
@Override
if ((soneInsertUri != null) && (sone.getInsertUri() == null)) {
try {
sone.setInsertUri(new FreenetURI(soneInsertUri));
- sone.setLatestEdition(Math.max(sone.getRequestUri().getSuggestedEdition(), sone.getInsertUri().getSuggestedEdition()));
+ sone.setLatestEdition(Math.max(sone.getRequestUri().getEdition(), sone.getInsertUri().getEdition()));
} catch (MalformedURLException mue1) {
/* TODO - mark Sone as bad. */
logger.log(Level.WARNING, "Downloaded Sone " + sone + " has invalid insert URI: " + soneInsertUri, mue1);
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.service.AbstractService;
-import net.pterodactylus.util.template.DefaultTemplateFactory;
+import net.pterodactylus.util.template.HtmlFilter;
import net.pterodactylus.util.template.ReflectionAccessor;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateContextFactory;
import net.pterodactylus.util.template.TemplateException;
+import net.pterodactylus.util.template.TemplateParser;
import net.pterodactylus.util.template.XmlFilter;
import freenet.client.async.ManifestElement;
import freenet.keys.FreenetURI;
private static volatile int insertionDelay = 60;
/** The template factory used to create the templates. */
- private static final DefaultTemplateFactory templateFactory = new DefaultTemplateFactory();
+ private static final TemplateContextFactory templateContextFactory = new TemplateContextFactory();
static {
- templateFactory.addAccessor(Object.class, new ReflectionAccessor());
- templateFactory.addFilter("xml", new XmlFilter());
+ templateContextFactory.addAccessor(Object.class, new ReflectionAccessor());
+ templateContextFactory.addFilter("xml", new XmlFilter());
+ templateContextFactory.addFilter("html", new HtmlFilter());
}
/** The UTF-8 charset. */
} else {
lastModificationTime = System.currentTimeMillis();
modified = true;
- sone.setTime(lastModificationTime);
logger.log(Level.FINE, "Sone %s has been modified, waiting %d seconds before inserting.", new Object[] { sone.getName(), insertionDelay });
}
lastFingerprint = fingerprint;
boolean success = false;
try {
core.setSoneStatus(sone, SoneStatus.inserting);
+ long insertTime = System.currentTimeMillis();
+ insertInformation.setTime(insertTime);
FreenetURI finalUri = freenetInterface.insertDirectory(insertInformation.getInsertUri().setKeyType("USK").setSuggestedEdition(0), insertInformation.generateManifestEntries(), "index.html");
/* at this point we might already be stopped. */
if (shouldStop()) {
/* if so, bail out, don’t change anything. */
break;
}
+ sone.setTime(insertTime);
sone.setLatestEdition(finalUri.getEdition());
success = true;
logger.log(Level.INFO, "Inserted Sone “%s” at %s.", new Object[] { sone.getName(), finalUri });
return (FreenetURI) soneProperties.get("insertUri");
}
+ /**
+ * Sets the time of the Sone at the time of the insert.
+ *
+ * @param time
+ * The time of the Sone
+ */
+ public void setTime(long time) {
+ soneProperties.put("time", time);
+ }
+
//
// ACTIONS
//
*/
@SuppressWarnings("synthetic-access")
private ManifestElement createManifestElement(String name, String contentType, String templateName) {
- InputStreamReader templateInputStreamReader;
- Template template = templateFactory.createTemplate(templateInputStreamReader = new InputStreamReader(getClass().getResourceAsStream(templateName), utf8Charset));
+ InputStreamReader templateInputStreamReader = null;
+ Template template;
try {
- template.parse();
+ templateInputStreamReader = new InputStreamReader(getClass().getResourceAsStream(templateName), utf8Charset);
+ template = TemplateParser.parse(templateInputStreamReader);
} catch (TemplateException te1) {
logger.log(Level.SEVERE, "Could not parse template “" + templateName + "”!", te1);
return null;
Closer.close(templateInputStreamReader);
}
- template.set("currentSone", soneProperties);
- template.set("version", SonePlugin.VERSION);
+ TemplateContext templateContext = templateContextFactory.createTemplateContext();
+ templateContext.set("currentSone", soneProperties);
+ templateContext.set("version", SonePlugin.VERSION);
StringWriter writer = new StringWriter();
StringBucket bucket = null;
try {
- template.render(writer);
+ template.render(templateContext, writer);
bucket = new StringBucket(writer.toString(), utf8Charset);
return new ManifestElement(name, bucket, contentType, bucket.size());
} catch (TemplateException te1) {
import java.util.Map;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
import freenet.l10n.BaseL10n;
/**
* {@inheritDoc}
*/
@Override
- public String format(DataProvider dataProvider, Object data, Map<String, String> parameters) {
+ public String format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
return l10n.getString(String.valueOf(data));
}
}
}
- }, new TimedMap<OwnIdentity, CacheItem<Trust>>(60000));
+ }, new TimedMap<OwnIdentity, CacheItem<Trust>>(60 * 60 * 1000));
/**
* Creates a new identity.
return distance;
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[explicit=" + explicit + ",implicit=" + implicit + ",distance=" + distance + "]";
+ }
+
}
}
/** The version. */
- public static final Version VERSION = new Version(0, 4, 1);
+ public static final Version VERSION = new Version(0, 4, 2);
/** The logger. */
private static final Logger logger = Logging.getLogger(SonePlugin.class);
*/
public ListNotification(String id, String key, Template template) {
super(id, template);
- template.set(key, elements);
- template.set("notification", this);
+ template.getInitialContext().set(key, elements);
}
//
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.util.template.Accessor;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.ReflectionAccessor;
+import net.pterodactylus.util.template.TemplateContext;
/**
* {@link Accessor} for {@link Collection}s that adds a couple of specialized
* {@inheritDoc}
*/
@Override
- public Object get(DataProvider dataProvider, Object object, String member) {
+ public Object get(TemplateContext templateContext, Object object, String member) {
if (object == null) {
return null;
}
}
return soneNames.toString();
}
- return super.get(dataProvider, object, member);
+ return super.get(templateContext, object, member);
}
}
import java.util.Map;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Converts the {@link String} {@link String#valueOf(Object) representation} of
* {@inheritDoc}
*/
@Override
- public Object format(DataProvider dataProvider, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
return String.valueOf(data).replaceAll("[^a-zA-Z0-9-]", "_");
}
import java.util.Map;
import net.pterodactylus.sone.web.page.Page.Request;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Plugin;
+import net.pterodactylus.util.template.TemplateContext;
/**
- * Extracts a page number from a {@link Request}’s parameters and stores it in a
- * {@link DataProvider}.
+ * Extracts a page number from a {@link Request}’s parameters and stores it in
+ * the {@link TemplateContext}.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
* {@inheritDoc}
*/
@Override
- public void execute(DataProvider dataProvider, Map<String, String> parameters) {
+ public void execute(TemplateContext templateContext, Map<String, String> parameters) {
String requestKey = parameters.get("request");
String parameter = parameters.get("parameter");
String pageKey = parameters.get("key");
pageKey = "page";
}
- Request request = (Request) dataProvider.getData(requestKey);
+ Request request = (Request) templateContext.get(requestKey);
String pageString = request.getHttpRequest().getParam(parameter);
int page = 0;
try {
} catch (NumberFormatException nfe1) {
/* ignore. */
}
- dataProvider.setData(pageKey, page);
+ templateContext.set(pageKey, page);
}
}
import net.pterodactylus.sone.freenet.wot.Identity;
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.util.template.Accessor;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.ReflectionAccessor;
+import net.pterodactylus.util.template.TemplateContext;
/**
* {@link Accessor} implementation that adds a “uniqueNickname” member to an
* {@inheritDoc}
*/
@Override
- public Object get(DataProvider dataProvider, Object object, String member) {
+ public Object get(TemplateContext templateContext, Object object, String member) {
Identity identity = (Identity) object;
if ("uniqueNickname".equals(member)) {
int minLength = -1;
} while (!found && (minLength < 43));
return getAbbreviatedNickname(identity, minLength);
}
- return super.get(dataProvider, object, member);
+ return super.get(templateContext, object, member);
}
//
import java.util.Map;
import net.pterodactylus.util.number.Hex;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Escapes double quotes, backslashes, carriage returns and line feeds, and
* {@inheritDoc}
*/
@Override
- public Object format(DataProvider dataProvider, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
StringBuilder javascriptString = new StringBuilder();
javascriptString.append('"');
for (char c : String.valueOf(data).toCharArray()) {
import net.pterodactylus.util.notify.Notification;
import net.pterodactylus.util.notify.NotificationManager;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.ReflectionAccessor;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Adds additional properties to a {@link NotificationManager}.
* {@inheritDoc}
*/
@Override
- public Object get(DataProvider dataProvider, Object object, String member) {
+ public Object get(TemplateContext templateContext, Object object, String member) {
NotificationManager notificationManager = (NotificationManager) object;
if ("all".equals(member)) {
List<Notification> notifications = new ArrayList<Notification>(notificationManager.getNotifications());
Collections.sort(notifications, Notification.LAST_UPDATED_TIME_SORTER);
return notifications;
}
- return super.get(dataProvider, object, member);
+ return super.get(templateContext, object, member);
}
}
--- /dev/null
+/*
+ * Sone - ParserFilter.java - Copyright © 2011 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.template;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.Map;
+
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.text.FreenetLinkParser;
+import net.pterodactylus.sone.text.FreenetLinkParserContext;
+import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateContextFactory;
+
+/**
+ * Filter that filters a given text through a {@link FreenetLinkParser}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class ParserFilter implements Filter {
+
+ /** The link parser. */
+ private final FreenetLinkParser linkParser;
+
+ /**
+ * Creates a new filter that runs its input through a
+ * {@link FreenetLinkParser}.
+ *
+ * @param templateContextFactory
+ * The context factory for rendering the parts
+ */
+ public ParserFilter(TemplateContextFactory templateContextFactory) {
+ linkParser = new FreenetLinkParser(templateContextFactory);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ String text = String.valueOf(data);
+ String soneKey = parameters.get("sone");
+ if (soneKey == null) {
+ soneKey = "sone";
+ }
+ Sone sone = (Sone) templateContext.get(soneKey);
+ FreenetLinkParserContext context = new FreenetLinkParserContext(sone);
+ try {
+ return linkParser.parse(context, new StringReader(text));
+ } catch (IOException ioe1) {
+ /* no exceptions in a StringReader, ignore. */
+ }
+ return null;
+ }
+
+}
package net.pterodactylus.sone.template;
-import java.io.IOException;
-import java.io.StringReader;
-
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.text.FreenetLinkParser;
-import net.pterodactylus.sone.text.FreenetLinkParserContext;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.ReflectionAccessor;
-import net.pterodactylus.util.template.TemplateFactory;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Accessor for {@link Post} objects that adds additional properties:
*/
public class PostAccessor extends ReflectionAccessor {
- /** Parser for Freenet links. */
- private final FreenetLinkParser linkParser;
-
/** The core to get the replies from. */
private final Core core;
*
* @param core
* The core to get the replies from
- * @param templateFactory
- * The template factory for the text parser
*/
- public PostAccessor(Core core, TemplateFactory templateFactory) {
+ public PostAccessor(Core core) {
this.core = core;
- linkParser = new FreenetLinkParser(templateFactory);
}
/**
* {@inheritDoc}
*/
@Override
- public Object get(DataProvider dataProvider, Object object, String member) {
+ public Object get(TemplateContext templateContext, Object object, String member) {
Post post = (Post) object;
if ("replies".equals(member)) {
return core.getReplies(post);
} else if (member.equals("likes")) {
return core.getLikes(post);
} else if (member.equals("liked")) {
- Sone currentSone = (Sone) dataProvider.getData("currentSone");
+ Sone currentSone = (Sone) templateContext.get("currentSone");
return (currentSone != null) && (currentSone.isLikedPostId(post.getId()));
} else if (member.equals("new")) {
- return core.isNewPost(post.getId(), false);
- } else if (member.equals("text")) {
- String text = post.getText();
- if (text == null) {
- return null;
- }
- try {
- return linkParser.parse(new FreenetLinkParserContext(post.getSone()), new StringReader(text));
- } catch (IOException ioe1) {
- /* ignore. */
- }
+ return core.isNewPost(post.getId());
}
- return super.get(dataProvider, object, member);
+ return super.get(templateContext, object, member);
}
}
package net.pterodactylus.sone.template;
-import java.io.IOException;
-import java.io.StringReader;
-
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Reply;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.text.FreenetLinkParser;
-import net.pterodactylus.sone.text.FreenetLinkParserContext;
import net.pterodactylus.util.template.Accessor;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.ReflectionAccessor;
-import net.pterodactylus.util.template.TemplateFactory;
+import net.pterodactylus.util.template.TemplateContext;
/**
* {@link Accessor} implementation that adds a couple of properties to
*/
public class ReplyAccessor extends ReflectionAccessor {
- /** Parser for Freenet links. */
- private final FreenetLinkParser linkParser;
-
/** The core. */
private final Core core;
*
* @param core
* The core
- * @param templateFactory
- * The template factory for the text parser
*/
- public ReplyAccessor(Core core, TemplateFactory templateFactory) {
+ public ReplyAccessor(Core core) {
this.core = core;
- linkParser = new FreenetLinkParser(templateFactory);
}
/**
* {@inheritDoc}
*/
@Override
- public Object get(DataProvider dataProvider, Object object, String member) {
+ public Object get(TemplateContext templateContext, Object object, String member) {
Reply reply = (Reply) object;
if ("likes".equals(member)) {
return core.getLikes(reply);
} else if (member.equals("liked")) {
- Sone currentSone = (Sone) dataProvider.getData("currentSone");
+ Sone currentSone = (Sone) templateContext.get("currentSone");
return (currentSone != null) && (currentSone.isLikedReplyId(reply.getId()));
} else if (member.equals("new")) {
- return core.isNewReply(reply.getId(), false);
- } else if (member.equals("text")) {
- String text = reply.getText();
- try {
- return linkParser.parse(new FreenetLinkParserContext(reply.getSone()), new StringReader(text));
- } catch (IOException ioe1) {
- /* ignore. */
- }
+ return core.isNewReply(reply.getId());
}
- return super.get(dataProvider, object, member);
+ return super.get(templateContext, object, member);
}
}
import java.util.Map.Entry;
import net.pterodactylus.sone.web.page.Page.Request;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This filter expects a {@link Request} as input and outputs a {@link URI} that
* {@inheritDoc}
*/
@Override
- public Object format(DataProvider dataProvider, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
Request request = (Request) data;
String name = parameters.get("name");
String nameKey = parameters.get("nameKey");
if (nameKey != null) {
- name = String.valueOf(dataProvider.getData(nameKey));
+ name = String.valueOf(templateContext.get(nameKey));
}
String key = parameters.get("key");
String value = null;
if (key != null) {
- value = String.valueOf(dataProvider.getData(key));
+ value = String.valueOf(templateContext.get(key));
}
if (value == null) {
value = parameters.get("value");
package net.pterodactylus.sone.template;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.core.Core.SoneStatus;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.freenet.wot.Trust;
+import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.template.Accessor;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.ReflectionAccessor;
+import net.pterodactylus.util.template.TemplateContext;
/**
* {@link Accessor} for {@link Sone}s that adds a couple of properties to Sones.
* <dt>friend</dt>
* <dd>Will return {@code true} if the sone in question is a friend of the
* currently logged in Sone (as determined by accessing the “currentSone”
- * variable of the given {@link DataProvider}).</dd>
+ * variable of the given {@link TemplateContext}).</dd>
* <dt>current</dt>
* <dd>Will return {@code true} if the sone in question is the currently logged
* in Sone.</dd>
*/
public class SoneAccessor extends ReflectionAccessor {
+ /** The logger. */
+ private static final Logger logger = Logging.getLogger(SoneAccessor.class);
+
/** The core. */
private final Core core;
* {@inheritDoc}
*/
@Override
- public Object get(DataProvider dataProvider, Object object, String member) {
+ public Object get(TemplateContext templateContext, Object object, String member) {
Sone sone = (Sone) object;
if (member.equals("niceName")) {
return getNiceName(sone);
} else if (member.equals("local")) {
- return sone.getInsertUri() != null;
+ return core.isLocalSone(sone);
} else if (member.equals("friend")) {
- Sone currentSone = (Sone) dataProvider.getData("currentSone");
+ Sone currentSone = (Sone) templateContext.get("currentSone");
return (currentSone != null) && currentSone.hasFriend(sone.getId());
} else if (member.equals("current")) {
- Sone currentSone = (Sone) dataProvider.getData("currentSone");
+ Sone currentSone = (Sone) templateContext.get("currentSone");
return (currentSone != null) && currentSone.equals(sone);
} else if (member.equals("modified")) {
return core.isModifiedSone(sone);
} else if (member.equals("downloading")) {
return core.getSoneStatus(sone) == SoneStatus.downloading;
} else if (member.equals("new")) {
- return core.isNewSone(sone);
+ return core.isNewSone(sone.getId());
} else if (member.equals("locked")) {
return core.isLocked(sone);
} else if (member.equals("trust")) {
- Sone currentSone = (Sone) dataProvider.getData("currentSone");
+ Sone currentSone = (Sone) templateContext.get("currentSone");
+ if (currentSone == null) {
+ return null;
+ }
Trust trust = core.getTrust(currentSone, sone);
+ logger.log(Level.FINEST, "Trust for %s by %s: %s", new Object[] { sone, currentSone, trust });
if (trust == null) {
return new Trust(null, null, null);
}
+ return trust;
}
- return super.get(dataProvider, object, member);
+ return super.get(templateContext, object, member);
}
//
import java.util.Map;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
/**
* {@link Filter} implementation that executes
* {@inheritDoc}
*/
@Override
- public Object format(DataProvider dataProvider, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
String startString = parameters.get("start");
String lengthString = parameters.get("length");
int start = 0;
import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.util.template.Accessor;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.ReflectionAccessor;
+import net.pterodactylus.util.template.TemplateContext;
/**
* {@link Accessor} implementation for {@link Trust} values, adding the
* {@inheritDoc}
*/
@Override
- public Object get(DataProvider dataProvider, Object object, String member) {
+ public Object get(TemplateContext templateContext, Object object, String member) {
Trust trust = (Trust) object;
if ("assigned".equals(member)) {
return trust.getExplicit() != null;
} else if ("hasDistance".equals(member)) {
return (trust.getDistance() != null) && (trust.getDistance() != Integer.MAX_VALUE);
}
- return super.get(dataProvider, object, member);
+ return super.get(templateContext, object, member);
}
}
--- /dev/null
+/*
+ * Sone - UnknownDateFilter.java - Copyright © 2011 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.template;
+
+import java.util.Map;
+
+import net.pterodactylus.util.template.Filter;
+import net.pterodactylus.util.template.TemplateContext;
+import freenet.l10n.BaseL10n;
+
+/**
+ * {@link Filter} implementation that replaces a {@link Long} with a value of
+ * {@code 0} by a {@link String} from an {@link BaseL10n l10n handler}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class UnknownDateFilter implements Filter {
+
+ /** The l10n handler. */
+ private BaseL10n l10nHandler;
+
+ /** The key for the text to show. */
+ private final String unknownKey;
+
+ /**
+ * Creates a new unknown date filter.
+ *
+ * @param l10nHandler
+ * The l10n handler
+ * @param unknownKey
+ * The key of the text to show
+ */
+ public UnknownDateFilter(BaseL10n l10nHandler, String unknownKey) {
+ this.l10nHandler = l10nHandler;
+ this.unknownKey = unknownKey;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ if (data instanceof Long) {
+ if ((Long) data == 0) {
+ return l10nHandler.getString(unknownKey);
+ }
+ }
+ return data;
+ }
+
+}
import java.util.regex.Pattern;
import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.template.TemplateFactory;
+import net.pterodactylus.util.template.TemplateContextFactory;
+import net.pterodactylus.util.template.TemplateParser;
import freenet.keys.FreenetURI;
/**
}
/** The template factory. */
- private final TemplateFactory templateFactory;
+ private final TemplateContextFactory templateContextFactory;
/**
* Creates a new freenet link parser.
*
- * @param templateFactory
- * The template factory
+ * @param templateContextFactory
+ * The template context factory
*/
- public FreenetLinkParser(TemplateFactory templateFactory) {
- this.templateFactory = templateFactory;
+ public FreenetLinkParser(TemplateContextFactory templateContextFactory) {
+ this.templateContextFactory = templateContextFactory;
}
//
* @return The part that displays the given text
*/
private Part createPlainTextPart(String text) {
- return new TemplatePart(templateFactory.createTemplate(new StringReader("<% text|html>"))).set("text", text);
+ return new TemplatePart(templateContextFactory, TemplateParser.parse(new StringReader("<% text|html>"))).set("text", text);
}
/**
* @return The part that displays the link
*/
private Part createInternetLinkPart(String link, String name) {
- return new TemplatePart(templateFactory.createTemplate(new StringReader("<a class=\"internet\" href=\"/<% link|html>\" title=\"<% link|html>\"><% name|html></a>"))).set("link", link).set("name", name);
+ return new TemplatePart(templateContextFactory, TemplateParser.parse(new StringReader("<a class=\"internet\" href=\"/<% link|html>\" title=\"<% link|html>\"><% name|html></a>"))).set("link", link).set("name", name);
}
/**
* @return The part that displays the link
*/
private Part createFreenetLinkPart(String link, String name) {
- return new TemplatePart(templateFactory.createTemplate(new StringReader("<a class=\"freenet\" href=\"/<% link|html>\" title=\"<% link|html>\"><% name|html></a>"))).set("link", link).set("name", name);
+ return new TemplatePart(templateContextFactory, TemplateParser.parse(new StringReader("<a class=\"freenet\" href=\"/<% link|html>\" title=\"<% link|html>\"><% name|html></a>"))).set("link", link).set("name", name);
}
/**
* @return The part that displays the link
*/
private Part createTrustedFreenetLinkPart(String link, String name) {
- return new TemplatePart(templateFactory.createTemplate(new StringReader("<a class=\"freenet-trusted\" href=\"/<% link|html>\" title=\"<% link|html>\"><% name|html></a>"))).set("link", link).set("name", name);
+ return new TemplatePart(templateContextFactory, TemplateParser.parse(new StringReader("<a class=\"freenet-trusted\" href=\"/<% link|html>\" title=\"<% link|html>\"><% name|html></a>"))).set("link", link).set("name", name);
}
}
import java.io.Writer;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateContextFactory;
+import net.pterodactylus.util.template.TemplateException;
/**
* {@link Part} implementation that is rendered using a {@link Template}.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class TemplatePart implements Part {
+public class TemplatePart implements Part, net.pterodactylus.util.template.Part {
+
+ /** The template context factory. */
+ private final TemplateContextFactory templateContextFactory;
/** The template to render for this part. */
private final Template template;
/**
* Creates a new template part.
*
+ * @param templateContextFactory
+ * The template context factory
* @param template
* The template to render
*/
- public TemplatePart(Template template) {
+ public TemplatePart(TemplateContextFactory templateContextFactory, Template template) {
+ this.templateContextFactory = templateContextFactory;
this.template = template;
}
* @return This template part (for method chaining)
*/
public TemplatePart set(String key, Object value) {
- template.set(key, value);
+ template.getInitialContext().set(key, value);
return this;
}
*/
@Override
public void render(Writer writer) throws IOException {
- template.render(writer);
+ template.render(templateContextFactory.createTemplateContext().mergeContext(template.getInitialContext()), writer);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void render(TemplateContext templateContext, Writer writer) throws TemplateException {
+ template.render(templateContext.mergeContext(template.getInitialContext()), writer);
}
}
package net.pterodactylus.sone.web;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import net.pterodactylus.util.version.Version;
/**
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
- dataProvider.set("version", version);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
+ templateContext.set("version", version);
}
}
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user create a new {@link Post}.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
if (request.getMethod() == Method.POST) {
String text = request.getHttpRequest().getPartAsStringFailsafe("text", 65536).trim();
if (text.length() != 0) {
+ String senderId = request.getHttpRequest().getPartAsStringFailsafe("sender", 43);
String recipientId = request.getHttpRequest().getPartAsStringFailsafe("recipient", 43);
- Sone recipient = webInterface.getCore().getSone(recipientId, false);
Sone currentSone = getCurrentSone(request.getToadletContext());
- webInterface.getCore().createPost(currentSone, recipient, System.currentTimeMillis(), text);
+ Sone sender = webInterface.getCore().getLocalSone(senderId, false);
+ if (sender == null) {
+ sender = currentSone;
+ }
+ Sone recipient = webInterface.getCore().getSone(recipientId, false);
+ webInterface.getCore().createPost(sender, recipient, System.currentTimeMillis(), text);
throw new RedirectException(returnPage);
}
- dataProvider.set("errorTextEmpty", true);
+ templateContext.set("errorTextEmpty", true);
}
- dataProvider.set("returnPage", returnPage);
+ templateContext.set("returnPage", returnPage);
}
}
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user post a reply to a post.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String postId = request.getHttpRequest().getPartAsStringFailsafe("post", 36);
String text = request.getHttpRequest().getPartAsStringFailsafe("text", 65536).trim();
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
if (request.getMethod() == Method.POST) {
Post post = webInterface.getCore().getPost(postId);
if (text.length() > 0) {
- Sone currentSone = getCurrentSone(request.getToadletContext());
- webInterface.getCore().createReply(currentSone, post, text);
+ String senderId = request.getHttpRequest().getPartAsStringFailsafe("sender", 43);
+ Sone sender = webInterface.getCore().getLocalSone(senderId, false);
+ if (sender == null) {
+ sender = getCurrentSone(request.getToadletContext());
+ }
+ webInterface.getCore().createReply(sender, post, text);
throw new RedirectException(returnPage);
}
- dataProvider.set("errorTextEmpty", true);
+ templateContext.set("errorTextEmpty", true);
}
- dataProvider.set("postId", postId);
- dataProvider.set("text", text);
- dataProvider.set("returnPage", returnPage);
+ templateContext.set("postId", postId);
+ templateContext.set("text", text);
+ templateContext.set("returnPage", returnPage);
}
}
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.web.page.Page.Request.Method;
import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import freenet.clients.http.ToadletContext;
/**
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
List<OwnIdentity> ownIdentitiesWithoutSone = getOwnIdentitiesWithoutSone(webInterface.getCore());
- dataProvider.set("identitiesWithoutSone", ownIdentitiesWithoutSone);
+ templateContext.set("identitiesWithoutSone", ownIdentitiesWithoutSone);
if (request.getMethod() == Method.POST) {
String id = request.getHttpRequest().getPartAsStringFailsafe("identity", 44);
OwnIdentity selectedIdentity = null;
}
}
if (selectedIdentity == null) {
- dataProvider.set("errorNoIdentity", true);
+ templateContext.set("errorNoIdentity", true);
return;
}
/* create Sone. */
*/
@Override
public boolean isEnabled(ToadletContext toadletContext) {
- return getCurrentSone(toadletContext) == null;
+ return (getCurrentSone(toadletContext, false) == null) || (webInterface.getCore().getLocalSones().size() == 1);
}
}
package net.pterodactylus.sone.web;
import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Lets the user delete a post they made.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.GET) {
String postId = request.getHttpRequest().getParam("post");
String returnPage = request.getHttpRequest().getParam("returnPage");
Post post = webInterface.getCore().getPost(postId);
- dataProvider.set("post", post);
- dataProvider.set("returnPage", returnPage);
+ templateContext.set("post", post);
+ templateContext.set("returnPage", returnPage);
return;
} else if (request.getMethod() == Method.POST) {
String postId = request.getHttpRequest().getPartAsStringFailsafe("post", 36);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
Post post = webInterface.getCore().getPost(postId);
- Sone currentSone = getCurrentSone(request.getToadletContext());
- if (!post.getSone().equals(currentSone)) {
+ if (!webInterface.getCore().isLocalSone(post.getSone())) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("confirmDelete")) {
- currentSone.removePost(post);
+ webInterface.getCore().deletePost(post);
throw new RedirectException(returnPage);
} else if (request.getHttpRequest().isPartSet("abortDelete")) {
throw new RedirectException(returnPage);
}
- dataProvider.set("post", post);
- dataProvider.set("returnPage", returnPage);
+ templateContext.set("post", post);
+ templateContext.set("returnPage", returnPage);
}
}
import net.pterodactylus.sone.data.Profile.Field;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user confirm the deletion of a profile field.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
Sone currentSone = getCurrentSone(request.getToadletContext());
Profile profile = currentSone.getProfile();
}
/* set current values in template. */
- dataProvider.set("field", field);
+ templateContext.set("field", field);
}
}
package net.pterodactylus.sone.web;
import net.pterodactylus.sone.data.Reply;
-import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user delete a reply.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String replyId = request.getHttpRequest().getPartAsStringFailsafe("reply", 36);
Reply reply = webInterface.getCore().getReply(replyId);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
if (request.getMethod() == Method.POST) {
- Sone currentSone = getCurrentSone(request.getToadletContext());
- if (!reply.getSone().equals(currentSone)) {
+ if (!webInterface.getCore().isLocalSone(reply.getSone())) {
throw new RedirectException("noPermission.html");
}
if (request.getHttpRequest().isPartSet("confirmDelete")) {
throw new RedirectException(returnPage);
}
}
- dataProvider.set("reply", reply);
- dataProvider.set("returnPage", returnPage);
+ templateContext.set("reply", reply);
+ templateContext.set("returnPage", returnPage);
}
}
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Lets the user delete a Sone. Of course the Sone is not really deleted from
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
if (request.getHttpRequest().isPartSet("deleteSone")) {
Sone currentSone = getCurrentSone(request.getToadletContext());
package net.pterodactylus.sone.web;
import net.pterodactylus.util.notify.Notification;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user dismiss a notification.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String notificationId = request.getHttpRequest().getPartAsStringFailsafe("notification", 36);
Notification notification = webInterface.getNotifications().getNotification(notificationId);
if ((notification != null) && notification.isDismissable()) {
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user distrust another Sone. This will assign a
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
- String returnPath = request.getHttpRequest().getPartAsStringFailsafe("returnPath", 256);
+ String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone currentSone = getCurrentSone(request.getToadletContext());
Sone sone = webInterface.getCore().getSone(identity, false);
if (sone != null) {
webInterface.getCore().distrustSone(currentSone, sone);
}
- throw new RedirectException(returnPath);
+ throw new RedirectException(returnPage);
}
}
import net.pterodactylus.sone.data.Profile.Field;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user edit the name of a profile field.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
Sone currentSone = getCurrentSone(request.getToadletContext());
Profile profile = currentSone.getProfile();
currentSone.setProfile(profile);
throw new RedirectException("editProfile.html#profile-fields");
}
- dataProvider.set("duplicateFieldName", true);
+ templateContext.set("duplicateFieldName", true);
}
/* store current values in template. */
- dataProvider.set("field", field);
+ templateContext.set("field", field);
}
}
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
import net.pterodactylus.util.number.Numbers;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import freenet.clients.http.ToadletContext;
/**
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
ToadletContext toadletContenxt = request.getToadletContext();
Sone currentSone = getCurrentSone(toadletContenxt);
Profile profile = currentSone.getProfile();
webInterface.getCore().saveSone(currentSone);
throw new RedirectException("editProfile.html#profile-fields");
} catch (IllegalArgumentException iae1) {
- dataProvider.set("fieldName", fieldName);
- dataProvider.set("duplicateFieldName", true);
+ templateContext.set("fieldName", fieldName);
+ templateContext.set("duplicateFieldName", true);
}
} else {
String id = getFieldId(request, "delete-field-");
}
}
}
- dataProvider.set("firstName", firstName);
- dataProvider.set("middleName", middleName);
- dataProvider.set("lastName", lastName);
- dataProvider.set("birthDay", birthDay);
- dataProvider.set("birthMonth", birthMonth);
- dataProvider.set("birthYear", birthYear);
- dataProvider.set("fields", fields);
+ templateContext.set("firstName", firstName);
+ templateContext.set("middleName", middleName);
+ templateContext.set("lastName", lastName);
+ templateContext.set("birthDay", birthDay);
+ templateContext.set("birthMonth", birthMonth);
+ templateContext.set("birthYear", birthYear);
+ templateContext.set("fields", fields);
}
//
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user follow another Sone.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.util.collection.Pagination;
import net.pterodactylus.util.number.Numbers;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* The index page shows the main page of Sone. This page will contain the posts
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
Sone currentSone = getCurrentSone(request.getToadletContext());
List<Post> allPosts = new ArrayList<Post>();
allPosts.addAll(currentSone.getPosts());
}
Collections.sort(allPosts, Post.TIME_COMPARATOR);
Pagination<Post> pagination = new Pagination<Post>(allPosts, 25).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
- dataProvider.set("pagination", pagination);
- dataProvider.set("posts", pagination.getItems());
+ templateContext.set("pagination", pagination);
+ templateContext.set("posts", pagination.getItems());
}
/**
* {@inheritDoc}
*/
@Override
- protected void postProcess(Request request, DataProvider dataProvider) {
+ protected void postProcess(Request request, TemplateContext templateContext) {
@SuppressWarnings("unchecked")
- List<Post> posts = (List<Post>) dataProvider.get("posts");
+ List<Post> posts = (List<Post>) templateContext.get("posts");
for (Post post : posts) {
webInterface.getCore().markPostKnown(post);
for (Reply reply : webInterface.getCore().getReplies(post)) {
import java.util.List;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.template.DataProvider;
+import net.pterodactylus.util.collection.Pagination;
+import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page shows all known Sones.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
List<Sone> knownSones = new ArrayList<Sone>(webInterface.getCore().getSones());
Collections.sort(knownSones, Sone.NICE_NAME_COMPARATOR);
- dataProvider.set("knownSones", knownSones);
+ Pagination<Sone> sonePagination = new Pagination<Sone>(knownSones, 25).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
+ templateContext.set("pagination", sonePagination);
+ templateContext.set("knownSones", sonePagination.getItems());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void postProcess(Request request, TemplateContext templateContext) {
+ super.postProcess(request, templateContext);
+ @SuppressWarnings("unchecked")
+ List<Sone> sones = (List<Sone>) templateContext.get("knownSones");
+ for (Sone sone : sones) {
+ webInterface.getCore().markSoneKnown(sone);
+ }
}
}
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user like a {@link Post}.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
String type=request.getHttpRequest().getPartAsStringFailsafe("type", 16);
String id = request.getHttpRequest().getPartAsStringFailsafe(type, 36);
package net.pterodactylus.sone.web;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user lock a {@link Sone} to prevent it from being
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone sone = webInterface.getCore().getLocalSone(soneId, false);
if (sone != null) {
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.web.page.Page.Request.Method;
import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import freenet.clients.http.ToadletContext;
/**
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
/* get all own identities. */
List<Sone> localSones = new ArrayList<Sone>(webInterface.getCore().getLocalSones());
Collections.sort(localSones, Sone.NICE_NAME_COMPARATOR);
- dataProvider.set("sones", localSones);
+ templateContext.set("sones", localSones);
if (request.getMethod() == Method.POST) {
String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone-id", 100);
Sone selectedSone = webInterface.getCore().getLocalSone(soneId, false);
}
}
List<OwnIdentity> ownIdentitiesWithoutSone = CreateSonePage.getOwnIdentitiesWithoutSone(webInterface.getCore());
- dataProvider.set("identitiesWithoutSone", ownIdentitiesWithoutSone);
+ templateContext.set("identitiesWithoutSone", ownIdentitiesWithoutSone);
}
/**
*/
@Override
protected String getRedirectTarget(Request request) {
- if (getCurrentSone(request.getToadletContext()) != null) {
+ if (getCurrentSone(request.getToadletContext(), false) != null) {
return "index.html";
}
return null;
*/
@Override
public boolean isEnabled(ToadletContext toadletContext) {
- return getCurrentSone(toadletContext) == null;
+ return getCurrentSone(toadletContext, false) == null;
}
}
package net.pterodactylus.sone.web;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import freenet.clients.http.ToadletContext;
/**
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
setCurrentSone(request.getToadletContext(), null);
- super.processTemplate(request, dataProvider);
+ super.processTemplate(request, templateContext);
throw new RedirectException("index.html");
}
*/
@Override
public boolean isEnabled(ToadletContext toadletContext) {
- return getCurrentSone(toadletContext) != null;
+ return (getCurrentSone(toadletContext, false) != null) && (webInterface.getCore().getLocalSones().size() != 1);
}
}
--- /dev/null
+/*
+ * Sone - MarkReadPage.java - Copyright © 2011 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.web;
+
+import java.util.StringTokenizer;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Reply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+
+/**
+ * Page that lets the user mark a number of {@link Sone}s, {@link Post}s, or
+ * {@link Reply Replie}s as known.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MarkAsKnownPage extends SoneTemplatePage {
+
+ /**
+ * Creates a new “mark as known” page.
+ *
+ * @param template
+ * The template to render
+ * @param webInterface
+ * The Sone web interface
+ */
+ public MarkAsKnownPage(Template template, WebInterface webInterface) {
+ super("markAsKnown.html", template, "Page.MarkAsKnown.Title", webInterface);
+ }
+
+ //
+ // SONETEMPLATEPAGE METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
+ String type = request.getHttpRequest().getPartAsStringFailsafe("type", 5);
+ if (!type.equals("sone") && !type.equals("post") && !type.equals("reply")) {
+ throw new RedirectException("invalid.html");
+ }
+ String ids = request.getHttpRequest().getPartAsStringFailsafe("id", 65536);
+ for (StringTokenizer idTokenizer = new StringTokenizer(ids); idTokenizer.hasMoreTokens();) {
+ String id = idTokenizer.nextToken();
+ if (type.equals("post")) {
+ Post post = webInterface.getCore().getPost(id, false);
+ if (post == null) {
+ continue;
+ }
+ webInterface.getCore().markPostKnown(post);
+ } else if (type.equals("reply")) {
+ Reply reply = webInterface.getCore().getReply(id, false);
+ if (reply == null) {
+ continue;
+ }
+ webInterface.getCore().markReplyKnown(reply);
+ } else if (type.equals("sone")) {
+ Sone sone = webInterface.getCore().getSone(id, false);
+ if (sone == null) {
+ continue;
+ }
+ webInterface.getCore().markSoneKnown(sone);
+ }
+ }
+ String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
+ throw new RedirectException(returnPage);
+ }
+
+}
import net.pterodactylus.sone.core.Options;
import net.pterodactylus.sone.web.page.Page.Request.Method;
import net.pterodactylus.util.number.Numbers;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user edit the options of the Sone plugin.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
Options options = webInterface.getCore().getOptions();
if (request.getMethod() == Method.POST) {
Integer insertionDelay = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("insertion-delay", 16));
webInterface.getCore().saveConfiguration();
throw new RedirectException(getPath());
}
- dataProvider.set("insertion-delay", options.getIntegerOption("InsertionDelay").get());
- dataProvider.set("positive-trust", options.getIntegerOption("PositiveTrust").get());
- dataProvider.set("negative-trust", options.getIntegerOption("NegativeTrust").get());
- dataProvider.set("trust-comment", options.getStringOption("TrustComment").get());
- dataProvider.set("sone-rescue-mode", options.getBooleanOption("SoneRescueMode").get());
- dataProvider.set("clear-on-next-restart", options.getBooleanOption("ClearOnNextRestart").get());
- dataProvider.set("really-clear-on-next-restart", options.getBooleanOption("ReallyClearOnNextRestart").get());
+ templateContext.set("insertion-delay", options.getIntegerOption("InsertionDelay").get());
+ templateContext.set("positive-trust", options.getIntegerOption("PositiveTrust").get());
+ templateContext.set("negative-trust", options.getIntegerOption("NegativeTrust").get());
+ templateContext.set("trust-comment", options.getStringOption("TrustComment").get());
+ templateContext.set("sone-rescue-mode", options.getBooleanOption("SoneRescueMode").get());
+ templateContext.set("clear-on-next-restart", options.getBooleanOption("ClearOnNextRestart").get());
+ templateContext.set("really-clear-on-next-restart", options.getBooleanOption("ReallyClearOnNextRestart").get());
}
}
import net.pterodactylus.sone.main.SonePlugin;
import net.pterodactylus.sone.web.page.Page;
import net.pterodactylus.sone.web.page.TemplatePage;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import freenet.clients.http.SessionManager.Session;
import freenet.clients.http.ToadletContext;
* Whether this page requires a login
*/
public SoneTemplatePage(String path, Template template, String pageTitleKey, WebInterface webInterface, boolean requireLogin) {
- super(path, template, webInterface.getL10n(), pageTitleKey, "noPermission.html");
+ super(path, webInterface.getTemplateContextFactory(), template, webInterface.getL10n(), pageTitleKey, "noPermission.html");
this.webInterface = webInterface;
this.requireLogin = requireLogin;
- template.set("webInterface", webInterface);
+ template.getInitialContext().set("webInterface", webInterface);
}
//
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
- dataProvider.set("currentSone", getCurrentSone(request.getToadletContext(), false));
- dataProvider.set("request", request);
- dataProvider.set("currentVersion", SonePlugin.VERSION);
- dataProvider.set("hasLatestVersion", webInterface.getCore().getUpdateChecker().hasLatestVersion());
- dataProvider.set("latestVersion", webInterface.getCore().getUpdateChecker().getLatestVersion());
- dataProvider.set("latestVersionTime", webInterface.getCore().getUpdateChecker().getLatestVersionDate());
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
+ templateContext.set("currentSone", getCurrentSone(request.getToadletContext(), false));
+ templateContext.set("localSones", webInterface.getCore().getLocalSones());
+ templateContext.set("request", request);
+ templateContext.set("currentVersion", SonePlugin.VERSION);
+ templateContext.set("hasLatestVersion", webInterface.getCore().getUpdateChecker().hasLatestVersion());
+ templateContext.set("latestVersion", webInterface.getCore().getUpdateChecker().getLatestVersion());
+ templateContext.set("latestVersionTime", webInterface.getCore().getUpdateChecker().getLatestVersionDate());
}
/**
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user trust another Sone. This will assign a configurable
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
- String returnPath = request.getHttpRequest().getPartAsStringFailsafe("returnPath", 256);
+ String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone currentSone = getCurrentSone(request.getToadletContext());
Sone sone = webInterface.getCore().getSone(identity, false);
if (sone != null) {
webInterface.getCore().trustSone(currentSone, sone);
}
- throw new RedirectException(returnPath);
+ throw new RedirectException(returnPage);
}
}
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user unfollow another Sone.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user unlike a {@link Post}.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
String type = request.getHttpRequest().getPartAsStringFailsafe("type", 16);
String id = request.getHttpRequest().getPartAsStringFailsafe(type, 36);
package net.pterodactylus.sone.web;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user unlock a {@link Sone} to allow its insertion.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String soneId = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone sone = webInterface.getCore().getLocalSone(soneId, false);
if (sone != null) {
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.Page.Request.Method;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Page that lets the user untrust another Sone. This will remove all trust
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
if (request.getMethod() == Method.POST) {
- String returnPath = request.getHttpRequest().getPartAsStringFailsafe("returnPath", 256);
+ String returnPage = request.getHttpRequest().getPartAsStringFailsafe("returnPage", 256);
String identity = request.getHttpRequest().getPartAsStringFailsafe("sone", 44);
Sone currentSone = getCurrentSone(request.getToadletContext());
Sone sone = webInterface.getCore().getSone(identity, false);
if (sone != null) {
webInterface.getCore().untrustSone(currentSone, sone);
}
- throw new RedirectException(returnPath);
+ throw new RedirectException(returnPage);
}
}
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Reply;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* This page lets the user view a post and all its replies.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String postId = request.getHttpRequest().getParam("post");
Post post = webInterface.getCore().getPost(postId);
- dataProvider.set("post", post);
+ templateContext.set("post", post);
}
/**
* {@inheritDoc}
*/
@Override
- protected void postProcess(Request request, DataProvider dataProvider) {
- Post post = (Post) dataProvider.get("post");
+ protected void postProcess(Request request, TemplateContext templateContext) {
+ Post post = (Post) templateContext.get("post");
+ if (post == null) {
+ return;
+ }
webInterface.getCore().markPostKnown(post);
for (Reply reply : webInterface.getCore().getReplies(post)) {
webInterface.getCore().markReplyKnown(reply);
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Reply;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
/**
* Lets the user browser another Sone.
* {@inheritDoc}
*/
@Override
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
- super.processTemplate(request, dataProvider);
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
+ super.processTemplate(request, templateContext);
String soneId = request.getHttpRequest().getParam("sone");
Sone sone = webInterface.getCore().getSone(soneId, false);
- dataProvider.set("sone", sone);
+ templateContext.set("sone", sone);
}
/**
* {@inheritDoc}
*/
@Override
- protected void postProcess(Request request, DataProvider dataProvider) {
- Sone sone = (Sone) dataProvider.get("sone");
+ protected void postProcess(Request request, TemplateContext templateContext) {
+ Sone sone = (Sone) templateContext.get("sone");
if (sone == null) {
return;
}
+ webInterface.getCore().markSoneKnown(sone);
List<Post> posts = sone.getPosts();
for (Post post : posts) {
webInterface.getCore().markPostKnown(post);
import net.pterodactylus.sone.template.IdentityAccessor;
import net.pterodactylus.sone.template.JavascriptFilter;
import net.pterodactylus.sone.template.NotificationManagerAccessor;
+import net.pterodactylus.sone.template.ParserFilter;
import net.pterodactylus.sone.template.PostAccessor;
import net.pterodactylus.sone.template.ReplyAccessor;
import net.pterodactylus.sone.template.RequestChangeFilter;
import net.pterodactylus.sone.template.SoneAccessor;
import net.pterodactylus.sone.template.SubstringFilter;
import net.pterodactylus.sone.template.TrustAccessor;
+import net.pterodactylus.sone.template.UnknownDateFilter;
import net.pterodactylus.sone.web.ajax.CreatePostAjaxPage;
import net.pterodactylus.sone.web.ajax.CreateReplyAjaxPage;
import net.pterodactylus.sone.web.ajax.DeletePostAjaxPage;
import net.pterodactylus.sone.web.ajax.GetTranslationPage;
import net.pterodactylus.sone.web.ajax.LikeAjaxPage;
import net.pterodactylus.sone.web.ajax.LockSoneAjaxPage;
-import net.pterodactylus.sone.web.ajax.MarkPostAsKnownPage;
-import net.pterodactylus.sone.web.ajax.MarkReplyAsKnownPage;
+import net.pterodactylus.sone.web.ajax.MarkAsKnownAjaxPage;
import net.pterodactylus.sone.web.ajax.MoveProfileFieldAjaxPage;
import net.pterodactylus.sone.web.ajax.TrustAjaxPage;
import net.pterodactylus.sone.web.ajax.UnfollowSoneAjaxPage;
import net.pterodactylus.sone.web.page.PageToadlet;
import net.pterodactylus.sone.web.page.PageToadletFactory;
import net.pterodactylus.sone.web.page.StaticPage;
+import net.pterodactylus.util.cache.Cache;
+import net.pterodactylus.util.cache.CacheException;
+import net.pterodactylus.util.cache.CacheItem;
+import net.pterodactylus.util.cache.DefaultCacheItem;
+import net.pterodactylus.util.cache.MemoryCache;
+import net.pterodactylus.util.cache.ValueRetriever;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.notify.Notification;
import net.pterodactylus.util.notify.NotificationManager;
import net.pterodactylus.util.notify.TemplateNotification;
import net.pterodactylus.util.template.DateFilter;
-import net.pterodactylus.util.template.DefaultTemplateFactory;
+import net.pterodactylus.util.template.FormatFilter;
+import net.pterodactylus.util.template.HtmlFilter;
import net.pterodactylus.util.template.MatchFilter;
import net.pterodactylus.util.template.PaginationPlugin;
+import net.pterodactylus.util.template.Provider;
import net.pterodactylus.util.template.ReflectionAccessor;
+import net.pterodactylus.util.template.ReplaceFilter;
+import net.pterodactylus.util.template.StoreFilter;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateContextFactory;
import net.pterodactylus.util.template.TemplateException;
-import net.pterodactylus.util.template.TemplateFactory;
-import net.pterodactylus.util.template.TemplateProvider;
+import net.pterodactylus.util.template.TemplateParser;
import net.pterodactylus.util.template.XmlFilter;
import net.pterodactylus.util.thread.Ticker;
import net.pterodactylus.util.version.Version;
/** The form password. */
private final String formPassword;
- /** The template factory. */
- private DefaultTemplateFactory templateFactory;
+ /** The template context factory. */
+ private final TemplateContextFactory templateContextFactory;
/** The “new Sone” notification. */
private final ListNotification<Sone> newSoneNotification;
* @param sonePlugin
* The Sone plugin
*/
+ @SuppressWarnings("synthetic-access")
public WebInterface(SonePlugin sonePlugin) {
this.sonePlugin = sonePlugin;
formPassword = sonePlugin.pluginRespirator().getToadletContainer().getFormPassword();
- templateFactory = new DefaultTemplateFactory();
- templateFactory.addAccessor(Object.class, new ReflectionAccessor());
- templateFactory.addAccessor(Collection.class, new CollectionAccessor());
- templateFactory.addAccessor(Sone.class, new SoneAccessor(getCore()));
- templateFactory.addAccessor(Post.class, new PostAccessor(getCore(), templateFactory));
- templateFactory.addAccessor(Reply.class, new ReplyAccessor(getCore(), templateFactory));
- templateFactory.addAccessor(Identity.class, new IdentityAccessor(getCore()));
- templateFactory.addAccessor(NotificationManager.class, new NotificationManagerAccessor());
- templateFactory.addAccessor(Trust.class, new TrustAccessor());
- templateFactory.addFilter("date", new DateFilter());
- templateFactory.addFilter("l10n", new L10nFilter(getL10n()));
- templateFactory.addFilter("substring", new SubstringFilter());
- templateFactory.addFilter("xml", new XmlFilter());
- templateFactory.addFilter("change", new RequestChangeFilter());
- templateFactory.addFilter("match", new MatchFilter());
- templateFactory.addFilter("css", new CssClassNameFilter());
- templateFactory.addFilter("js", new JavascriptFilter());
- templateFactory.addPlugin("getpage", new GetPagePlugin());
- templateFactory.addPlugin("paginate", new PaginationPlugin());
- templateFactory.setTemplateProvider(new ClassPathTemplateProvider(templateFactory));
- templateFactory.addTemplateObject("formPassword", formPassword);
+ templateContextFactory = new TemplateContextFactory();
+ templateContextFactory.addAccessor(Object.class, new ReflectionAccessor());
+ templateContextFactory.addAccessor(Collection.class, new CollectionAccessor());
+ templateContextFactory.addAccessor(Sone.class, new SoneAccessor(getCore()));
+ templateContextFactory.addAccessor(Post.class, new PostAccessor(getCore()));
+ templateContextFactory.addAccessor(Reply.class, new ReplyAccessor(getCore()));
+ templateContextFactory.addAccessor(Identity.class, new IdentityAccessor(getCore()));
+ templateContextFactory.addAccessor(NotificationManager.class, new NotificationManagerAccessor());
+ templateContextFactory.addAccessor(Trust.class, new TrustAccessor());
+ templateContextFactory.addFilter("date", new DateFilter());
+ templateContextFactory.addFilter("html", new HtmlFilter());
+ templateContextFactory.addFilter("replace", new ReplaceFilter());
+ templateContextFactory.addFilter("store", new StoreFilter());
+ templateContextFactory.addFilter("l10n", new L10nFilter(getL10n()));
+ templateContextFactory.addFilter("substring", new SubstringFilter());
+ templateContextFactory.addFilter("xml", new XmlFilter());
+ templateContextFactory.addFilter("change", new RequestChangeFilter());
+ templateContextFactory.addFilter("match", new MatchFilter());
+ templateContextFactory.addFilter("css", new CssClassNameFilter());
+ templateContextFactory.addFilter("js", new JavascriptFilter());
+ templateContextFactory.addFilter("parse", new ParserFilter(templateContextFactory));
+ templateContextFactory.addFilter("unknown", new UnknownDateFilter(getL10n(), "View.Sone.Text.UnknownDate"));
+ templateContextFactory.addFilter("format", new FormatFilter());
+ templateContextFactory.addPlugin("getpage", new GetPagePlugin());
+ templateContextFactory.addPlugin("paginate", new PaginationPlugin());
+ templateContextFactory.addProvider(Provider.TEMPLATE_CONTEXT_PROVIDER);
+ templateContextFactory.addProvider(new ClassPathTemplateProvider());
+ templateContextFactory.addTemplateObject("formPassword", formPassword);
/* create notifications. */
- Template newSoneNotificationTemplate = templateFactory.createTemplate(createReader("/templates/notify/newSoneNotification.html"));
+ Template newSoneNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newSoneNotification.html"));
newSoneNotification = new ListNotification<Sone>("new-sone-notification", "sones", newSoneNotificationTemplate);
- Template newPostNotificationTemplate = templateFactory.createTemplate(createReader("/templates/notify/newPostNotification.html"));
+ Template newPostNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newPostNotification.html"));
newPostNotification = new ListNotification<Post>("new-post-notification", "posts", newPostNotificationTemplate);
- Template newReplyNotificationTemplate = templateFactory.createTemplate(createReader("/templates/notify/newReplyNotification.html"));
+ Template newReplyNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newReplyNotification.html"));
newReplyNotification = new ListNotification<Reply>("new-replies-notification", "replies", newReplyNotificationTemplate);
- Template rescuingSonesTemplate = templateFactory.createTemplate(createReader("/templates/notify/rescuingSonesNotification.html"));
+ Template rescuingSonesTemplate = TemplateParser.parse(createReader("/templates/notify/rescuingSonesNotification.html"));
rescuingSonesNotification = new ListNotification<Sone>("sones-being-rescued-notification", "sones", rescuingSonesTemplate);
- Template sonesRescuedTemplate = templateFactory.createTemplate(createReader("/templates/notify/sonesRescuedNotification.html"));
+ Template sonesRescuedTemplate = TemplateParser.parse(createReader("/templates/notify/sonesRescuedNotification.html"));
sonesRescuedNotification = new ListNotification<Sone>("sones-rescued-notification", "sones", sonesRescuedTemplate);
- Template lockedSonesTemplate = templateFactory.createTemplate(createReader("/templates/notify/lockedSonesNotification.html"));
+ Template lockedSonesTemplate = TemplateParser.parse(createReader("/templates/notify/lockedSonesNotification.html"));
lockedSonesNotification = new ListNotification<Sone>("sones-locked-notification", "sones", lockedSonesTemplate);
- Template newVersionTemplate = templateFactory.createTemplate(createReader("/templates/notify/newVersionNotification.html"));
+ Template newVersionTemplate = TemplateParser.parse(createReader("/templates/notify/newVersionNotification.html"));
newVersionNotification = new TemplateNotification("new-version-notification", newVersionTemplate);
}
}
/**
+ * Returns the template context factory of the web interface.
+ *
+ * @return The template context factory
+ */
+ public TemplateContextFactory getTemplateContextFactory() {
+ return templateContextFactory;
+ }
+
+ /**
* Returns the current session, creating a new session if there is no
* current session.
*
* currently logged in
*/
public Sone getCurrentSone(ToadletContext toadletContext, boolean create) {
+ Set<Sone> localSones = getCore().getLocalSones();
+ if (localSones.size() == 1) {
+ return localSones.iterator().next();
+ }
return getCurrentSone(getCurrentSession(toadletContext, create));
}
*/
public void setFirstStart(boolean firstStart) {
if (firstStart) {
- Template firstStartNotificationTemplate = templateFactory.createTemplate(createReader("/templates/notify/firstStartNotification.html"));
+ Template firstStartNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/firstStartNotification.html"));
Notification firstStartNotification = new TemplateNotification("first-start-notification", firstStartNotificationTemplate);
notificationManager.addNotification(firstStartNotification);
}
*/
public void setNewConfig(boolean newConfig) {
if (newConfig && !hasFirstStartNotification()) {
- Template configNotReadNotificationTemplate = templateFactory.createTemplate(createReader("/templates/notify/configNotReadNotification.html"));
+ Template configNotReadNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/configNotReadNotification.html"));
Notification configNotReadNotification = new TemplateNotification("config-not-read-notification", configNotReadNotificationTemplate);
notificationManager.addNotification(configNotReadNotification);
}
registerToadlets();
/* notification templates. */
- Template startupNotificationTemplate = templateFactory.createTemplate(createReader("/templates/notify/startupNotification.html"));
+ Template startupNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/startupNotification.html"));
final TemplateNotification startupNotification = new TemplateNotification("startup-notification", startupNotificationTemplate);
notificationManager.addNotification(startupNotification);
}
}, "Sone Startup Notification Remover");
- Template wotMissingNotificationTemplate = templateFactory.createTemplate(createReader("/templates/notify/wotMissingNotification.html"));
+ Template wotMissingNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/wotMissingNotification.html"));
final TemplateNotification wotMissingNotification = new TemplateNotification("wot-missing-notification", wotMissingNotificationTemplate);
Ticker.getInstance().registerEvent(System.currentTimeMillis() + (15 * 1000), new Runnable() {
* Register all toadlets.
*/
private void registerToadlets() {
- Template emptyTemplate = templateFactory.createTemplate(new StringReader(""));
- Template loginTemplate = templateFactory.createTemplate(createReader("/templates/login.html"));
- Template indexTemplate = templateFactory.createTemplate(createReader("/templates/index.html"));
- Template knownSonesTemplate = templateFactory.createTemplate(createReader("/templates/knownSones.html"));
- Template createSoneTemplate = templateFactory.createTemplate(createReader("/templates/createSone.html"));
- Template createPostTemplate = templateFactory.createTemplate(createReader("/templates/createPost.html"));
- Template createReplyTemplate = templateFactory.createTemplate(createReader("/templates/createReply.html"));
- Template editProfileTemplate = templateFactory.createTemplate(createReader("/templates/editProfile.html"));
- Template editProfileFieldTemplate = templateFactory.createTemplate(createReader("/templates/editProfileField.html"));
- Template deleteProfileFieldTemplate = templateFactory.createTemplate(createReader("/templates/deleteProfileField.html"));
- Template viewSoneTemplate = templateFactory.createTemplate(createReader("/templates/viewSone.html"));
- Template viewPostTemplate = templateFactory.createTemplate(createReader("/templates/viewPost.html"));
- Template deletePostTemplate = templateFactory.createTemplate(createReader("/templates/deletePost.html"));
- Template deleteReplyTemplate = templateFactory.createTemplate(createReader("/templates/deleteReply.html"));
- Template deleteSoneTemplate = templateFactory.createTemplate(createReader("/templates/deleteSone.html"));
- Template noPermissionTemplate = templateFactory.createTemplate(createReader("/templates/noPermission.html"));
- Template optionsTemplate = templateFactory.createTemplate(createReader("/templates/options.html"));
- Template aboutTemplate = templateFactory.createTemplate(createReader("/templates/about.html"));
- Template invalidTemplate = templateFactory.createTemplate(createReader("/templates/invalid.html"));
- Template postTemplate = templateFactory.createTemplate(createReader("/templates/include/viewPost.html"));
- Template replyTemplate = templateFactory.createTemplate(createReader("/templates/include/viewReply.html"));
+ Template emptyTemplate = TemplateParser.parse(new StringReader(""));
+ Template loginTemplate = TemplateParser.parse(createReader("/templates/login.html"));
+ Template indexTemplate = TemplateParser.parse(createReader("/templates/index.html"));
+ Template knownSonesTemplate = TemplateParser.parse(createReader("/templates/knownSones.html"));
+ Template createSoneTemplate = TemplateParser.parse(createReader("/templates/createSone.html"));
+ Template createPostTemplate = TemplateParser.parse(createReader("/templates/createPost.html"));
+ Template createReplyTemplate = TemplateParser.parse(createReader("/templates/createReply.html"));
+ Template editProfileTemplate = TemplateParser.parse(createReader("/templates/editProfile.html"));
+ Template editProfileFieldTemplate = TemplateParser.parse(createReader("/templates/editProfileField.html"));
+ Template deleteProfileFieldTemplate = TemplateParser.parse(createReader("/templates/deleteProfileField.html"));
+ Template viewSoneTemplate = TemplateParser.parse(createReader("/templates/viewSone.html"));
+ Template viewPostTemplate = TemplateParser.parse(createReader("/templates/viewPost.html"));
+ Template deletePostTemplate = TemplateParser.parse(createReader("/templates/deletePost.html"));
+ Template deleteReplyTemplate = TemplateParser.parse(createReader("/templates/deleteReply.html"));
+ Template deleteSoneTemplate = TemplateParser.parse(createReader("/templates/deleteSone.html"));
+ Template noPermissionTemplate = TemplateParser.parse(createReader("/templates/noPermission.html"));
+ Template optionsTemplate = TemplateParser.parse(createReader("/templates/options.html"));
+ Template aboutTemplate = TemplateParser.parse(createReader("/templates/about.html"));
+ Template invalidTemplate = TemplateParser.parse(createReader("/templates/invalid.html"));
+ Template postTemplate = TemplateParser.parse(createReader("/templates/include/viewPost.html"));
+ Template replyTemplate = TemplateParser.parse(createReader("/templates/include/viewReply.html"));
PageToadletFactory pageToadletFactory = new PageToadletFactory(sonePlugin.pluginRespirator().getHLSimpleClient(), "/Sone/");
pageToadlets.add(pageToadletFactory.createPageToadlet(new IndexPage(indexTemplate, this), "Index"));
pageToadlets.add(pageToadletFactory.createPageToadlet(new TrustPage(emptyTemplate, this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new DistrustPage(emptyTemplate, this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new UntrustPage(emptyTemplate, this)));
+ pageToadlets.add(pageToadletFactory.createPageToadlet(new MarkAsKnownPage(emptyTemplate, this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteSonePage(deleteSoneTemplate, this), "DeleteSone"));
pageToadlets.add(pageToadletFactory.createPageToadlet(new LoginPage(loginTemplate, this), "Login"));
pageToadlets.add(pageToadletFactory.createPageToadlet(new LogoutPage(emptyTemplate, this), "Logout"));
pageToadlets.add(pageToadletFactory.createPageToadlet(new CreateReplyAjaxPage(this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new GetReplyAjaxPage(this, replyTemplate)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new GetPostAjaxPage(this, postTemplate)));
- pageToadlets.add(pageToadletFactory.createPageToadlet(new MarkPostAsKnownPage(this)));
- pageToadlets.add(pageToadletFactory.createPageToadlet(new MarkReplyAsKnownPage(this)));
+ pageToadlets.add(pageToadletFactory.createPageToadlet(new MarkAsKnownAjaxPage(this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new DeletePostAjaxPage(this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new DeleteReplyAjaxPage(this)));
pageToadlets.add(pageToadletFactory.createPageToadlet(new LockSoneAjaxPage(this)));
try {
return new InputStreamReader(getClass().getResourceAsStream(resourceName), "UTF-8");
} catch (UnsupportedEncodingException uee1) {
+ System.out.println(" fail.");
return null;
}
}
*/
@Override
public void updateFound(Version version, long releaseTime) {
- newVersionNotification.set("version", version);
- newVersionNotification.set("releaseTime", releaseTime);
+ newVersionNotification.getTemplateContext().set("version", version);
+ newVersionNotification.getTemplateContext().set("releaseTime", releaseTime);
notificationManager.addNotification(newVersionNotification);
}
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
- private class ClassPathTemplateProvider implements TemplateProvider {
+ private class ClassPathTemplateProvider implements Provider {
- /** The template factory. */
- @SuppressWarnings("hiding")
- private final TemplateFactory templateFactory;
+ /** Cache for templates. */
+ private final Cache<String, Template> templateCache = new MemoryCache<String, Template>(new ValueRetriever<String, Template>() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public CacheItem<Template> retrieve(String key) throws CacheException {
+ Template template = findTemplate(key);
+ if (template != null) {
+ return new DefaultCacheItem<Template>(template);
+ }
+ return null;
+ }
+ });
/**
- * Creates a new template provider that locates templates on the
- * classpath.
- *
- * @param templateFactory
- * The template factory to create the templates
+ * {@inheritDoc}
*/
- public ClassPathTemplateProvider(TemplateFactory templateFactory) {
- this.templateFactory = templateFactory;
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public Template getTemplate(TemplateContext templateContext, String templateName) {
+ try {
+ return templateCache.get(templateName);
+ } catch (CacheException ce1) {
+ logger.log(Level.WARNING, "Could not get template for " + templateName + "!", ce1);
+ return null;
+ }
}
/**
- * {@inheritDoc}
+ * Locates a template in the class path.
+ *
+ * @param templateName
+ * The name of the template to load
+ * @return The loaded template, or {@code null} if no template could be
+ * found
*/
- @Override
@SuppressWarnings("synthetic-access")
- public Template getTemplate(String templateName) {
+ private Template findTemplate(String templateName) {
Reader templateReader = createReader("/templates/" + templateName);
if (templateReader == null) {
return null;
}
- Template template = templateFactory.createTemplate(templateReader);
+ Template template = null;
try {
- template.parse();
+ template = TemplateParser.parse(templateReader);
} catch (TemplateException te1) {
logger.log(Level.WARNING, "Could not parse template “" + templateName + "” for inclusion!", te1);
}
}
String recipientId = request.getHttpRequest().getParam("recipient");
Sone recipient = webInterface.getCore().getSone(recipientId, false);
+ String senderId = request.getHttpRequest().getParam("sender");
+ Sone sender = webInterface.getCore().getLocalSone(senderId, false);
+ if (sender == null) {
+ sender = sone;
+ }
String text = request.getHttpRequest().getParam("text");
if ((text == null) || (text.trim().length() == 0)) {
return createErrorJsonObject("text-required");
}
- Post newPost = webInterface.getCore().createPost(sone, recipient, text);
- return createSuccessJsonObject().put("postId", newPost.getId());
+ Post newPost = webInterface.getCore().createPost(sender, recipient, text);
+ return createSuccessJsonObject().put("postId", newPost.getId()).put("sone", sender.getId()).put("recipient", (newPost.getRecipient() != null) ? newPost.getRecipient().getId() : null);
}
}
protected JsonObject createJsonObject(Request request) {
String postId = request.getHttpRequest().getParam("post");
String text = request.getHttpRequest().getParam("text").trim();
- Sone currentSone = getCurrentSone(request.getToadletContext());
- if (currentSone == null) {
- return createErrorJsonObject("auth-required");
+ String senderId = request.getHttpRequest().getParam("sender");
+ Sone sender = webInterface.getCore().getLocalSone(senderId, false);
+ if (sender == null) {
+ sender = getCurrentSone(request.getToadletContext());
}
Post post = webInterface.getCore().getPost(postId);
if ((post == null) || (post.getSone() == null)) {
return createErrorJsonObject("invalid-post-id");
}
- Reply reply = webInterface.getCore().createReply(currentSone, post, text);
- return createSuccessJsonObject().put("reply", reply.getId());
+ Reply reply = webInterface.getCore().createReply(sender, post, text);
+ return createSuccessJsonObject().put("reply", reply.getId()).put("sone", sender.getId());
}
}
package net.pterodactylus.sone.web.ajax;
import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.util.json.JsonObject;
protected JsonObject createJsonObject(Request request) {
String postId = request.getHttpRequest().getParam("post");
Post post = webInterface.getCore().getPost(postId, false);
- Sone currentSone = getCurrentSone(request.getToadletContext());
if ((post == null) || (post.getSone() == null)) {
return createErrorJsonObject("invalid-post-id");
}
- if (currentSone == null) {
- return createErrorJsonObject("auth-required");
- }
- if (!post.getSone().equals(currentSone)) {
+ if (!webInterface.getCore().isLocalSone(post.getSone())) {
return createErrorJsonObject("not-authorized");
}
webInterface.getCore().deletePost(post);
package net.pterodactylus.sone.web.ajax;
import net.pterodactylus.sone.data.Reply;
-import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.util.json.JsonObject;
protected JsonObject createJsonObject(Request request) {
String replyId = request.getHttpRequest().getParam("reply");
Reply reply = webInterface.getCore().getReply(replyId);
- Sone currentSone = getCurrentSone(request.getToadletContext());
if (reply == null) {
return createErrorJsonObject("invalid-reply-id");
}
- if (currentSone == null) {
- return createErrorJsonObject("auth-required");
- }
- if (!reply.getSone().equals(currentSone)) {
+ if (!webInterface.getCore().isLocalSone(reply.getSone())) {
return createErrorJsonObject("not-authorized");
}
webInterface.getCore().deleteReply(reply);
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.json.JsonObject;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import net.pterodactylus.util.template.TemplateException;
/**
jsonPost.put("recipient", (post.getRecipient() == null) ? null : post.getRecipient().getId());
jsonPost.put("time", post.getTime());
StringWriter stringWriter = new StringWriter();
- DataProvider dataProvider = postTemplate.createDataProvider();
- dataProvider.setData("post", post);
- dataProvider.setData("currentSone", currentSone);
+ TemplateContext templateContext = webInterface.getTemplateContextFactory().createTemplateContext();
+ templateContext.set("post", post);
+ templateContext.set("currentSone", currentSone);
try {
- postTemplate.render(dataProvider, stringWriter);
+ postTemplate.render(templateContext, stringWriter);
} catch (TemplateException te1) {
/* TODO - shouldn’t happen. */
} finally {
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.json.JsonObject;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
import net.pterodactylus.util.template.TemplateException;
/**
jsonReply.put("soneId", reply.getSone().getId());
jsonReply.put("time", reply.getTime());
StringWriter stringWriter = new StringWriter();
- DataProvider dataProvider = replyTemplate.createDataProvider();
- dataProvider.setData("reply", reply);
- dataProvider.setData("currentSone", currentSone);
+ TemplateContext templateContext = webInterface.getTemplateContextFactory().createTemplateContext();
+ templateContext.set("reply", reply);
+ templateContext.set("currentSone", currentSone);
try {
- replyTemplate.render(dataProvider, stringWriter);
+ replyTemplate.render(templateContext, stringWriter);
} catch (TemplateException te1) {
/* TODO - shouldn’t happen. */
} finally {
package net.pterodactylus.sone.web.ajax;
+import java.io.IOException;
+import java.io.StringWriter;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import net.pterodactylus.util.json.JsonArray;
import net.pterodactylus.util.json.JsonObject;
import net.pterodactylus.util.notify.Notification;
+import net.pterodactylus.util.notify.TemplateNotification;
+import net.pterodactylus.util.template.TemplateContext;
/**
* The “get status” AJAX handler returns all information that is necessary to
jsonSone.put("status", webInterface.getCore().getSoneStatus(sone).name());
jsonSone.put("modified", webInterface.getCore().isModifiedSone(sone));
jsonSone.put("locked", webInterface.getCore().isLocked(sone));
+ jsonSone.put("lastUpdatedUnknown", sone.getTime() == 0);
synchronized (dateFormat) {
jsonSone.put("lastUpdated", dateFormat.format(new Date(sone.getTime())));
}
* The notification to create a JSON object
* @return The JSON object
*/
- private static JsonObject createJsonNotification(Notification notification) {
+ private JsonObject createJsonNotification(Notification notification) {
JsonObject jsonNotification = new JsonObject();
jsonNotification.put("id", notification.getId());
- jsonNotification.put("text", notification.toString());
+ StringWriter notificationWriter = new StringWriter();
+ try {
+ if (notification instanceof TemplateNotification) {
+ TemplateContext templateContext = webInterface.getTemplateContextFactory().createTemplateContext().mergeContext(((TemplateNotification) notification).getTemplateContext());
+ templateContext.set("notification", notification);
+ ((TemplateNotification) notification).render(templateContext, notificationWriter);
+ } else {
+ notification.render(notificationWriter);
+ }
+ } catch (IOException ioe1) {
+ /* StringWriter never throws, ignore. */
+ }
+ jsonNotification.put("text", notificationWriter.toString());
jsonNotification.put("createdTime", notification.getCreatedTime());
jsonNotification.put("lastUpdatedTime", notification.getLastUpdatedTime());
jsonNotification.put("dismissable", notification.isDismissable());
--- /dev/null
+/*
+ * Sone - MarkAsKnownAjaxPage.java - Copyright © 2011 David Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.web.ajax;
+
+import net.pterodactylus.sone.core.Core;
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Reply;
+import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.web.WebInterface;
+import net.pterodactylus.util.json.JsonObject;
+
+/**
+ * AJAX page that lets the user mark a number of {@link Sone}s, {@link Post}s,
+ * or {@link Reply}s as known.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class MarkAsKnownAjaxPage extends JsonPage {
+
+ /**
+ * Creates a new “mark as known” AJAX page.
+ *
+ * @param webInterface
+ * The Sone web interface
+ */
+ public MarkAsKnownAjaxPage(WebInterface webInterface) {
+ super("markAsKnown.ajax", webInterface);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected JsonObject createJsonObject(Request request) {
+ String type = request.getHttpRequest().getParam("type");
+ if (!type.equals("sone") && !type.equals("post") && !type.equals("reply")) {
+ return createErrorJsonObject("invalid-type");
+ }
+ String[] ids = request.getHttpRequest().getParam("id").split(" ");
+ Core core = webInterface.getCore();
+ for (String id : ids) {
+ if (type.equals("post")) {
+ Post post = core.getPost(id, false);
+ if (post == null) {
+ continue;
+ }
+ core.markPostKnown(post);
+ } else if (type.equals("reply")) {
+ Reply reply = core.getReply(id, false);
+ if (reply == null) {
+ continue;
+ }
+ core.markReplyKnown(reply);
+ } else if (type.equals("sone")) {
+ Sone sone = core.getSone(id, false);
+ if (sone == null) {
+ continue;
+ }
+ core.markSoneKnown(sone);
+ }
+ }
+ return createSuccessJsonObject();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected boolean requiresLogin() {
+ return false;
+ }
+
+}
+++ /dev/null
-/*
- * Sone - MarkPostAsKnownPage.java - Copyright © 2010 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.web.ajax;
-
-import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.web.WebInterface;
-import net.pterodactylus.util.json.JsonObject;
-
-/**
- * AJAX handler that marks a {@link Post} as known.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class MarkPostAsKnownPage extends JsonPage {
-
- /**
- * Creates a new “mark post as known” AJAX handler.
- *
- * @param webInterface
- * The Sone web interface
- */
- public MarkPostAsKnownPage(WebInterface webInterface) {
- super("markPostAsKnown.ajax", webInterface);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected JsonObject createJsonObject(Request request) {
- String postId = request.getHttpRequest().getParam("post");
- Post post = webInterface.getCore().getPost(postId, false);
- if (post == null) {
- return createErrorJsonObject("invalid-post-id");
- }
- webInterface.getCore().markPostKnown(post);
- return createSuccessJsonObject();
- }
-
-}
+++ /dev/null
-/*
- * Sone - MarkPostAsKnownPage.java - Copyright © 2010 David Roden
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-package net.pterodactylus.sone.web.ajax;
-
-import net.pterodactylus.sone.data.Reply;
-import net.pterodactylus.sone.web.WebInterface;
-import net.pterodactylus.util.json.JsonObject;
-
-/**
- * AJAX handler that marks a {@link Reply} as known.
- *
- * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
- */
-public class MarkReplyAsKnownPage extends JsonPage {
-
- /**
- * Creates a new “mark reply as known” AJAX handler.
- *
- * @param webInterface
- * The Sone web interface
- */
- public MarkReplyAsKnownPage(WebInterface webInterface) {
- super("markReplyAsKnown.ajax", webInterface);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- protected JsonObject createJsonObject(Request request) {
- String replyId = request.getHttpRequest().getParam("reply");
- Reply reply = webInterface.getCore().getReply(replyId, false);
- if (reply == null) {
- return createErrorJsonObject("invalid-reply-id");
- }
- webInterface.getCore().markReplyKnown(reply);
- return createSuccessJsonObject();
- }
-
-}
import net.pterodactylus.sone.web.page.Page.Request.Method;
import net.pterodactylus.util.logging.Logging;
-import net.pterodactylus.util.template.DataProvider;
import net.pterodactylus.util.template.Template;
+import net.pterodactylus.util.template.TemplateContext;
+import net.pterodactylus.util.template.TemplateContextFactory;
import freenet.clients.http.LinkEnabledCallback;
import freenet.clients.http.PageMaker;
import freenet.clients.http.PageNode;
/** The path of the page. */
private final String path;
+ /** The template context factory. */
+ private final TemplateContextFactory templateContextFactory;
+
/** The template to render. */
private final Template template;
*
* @param path
* The path of the page
+ * @param templateContextFactory
+ * The template context factory
* @param template
* The template to render
* @param l10n
* The target to redirect to if a POST request does not contain
* the correct form password
*/
- public TemplatePage(String path, Template template, BaseL10n l10n, String pageTitleKey, String invalidFormPasswordRedirectTarget) {
+ public TemplatePage(String path, TemplateContextFactory templateContextFactory, Template template, BaseL10n l10n, String pageTitleKey, String invalidFormPasswordRedirectTarget) {
this.path = path;
+ this.templateContextFactory = templateContextFactory;
this.template = template;
this.l10n = l10n;
this.pageTitleKey = pageTitleKey;
pageNode.addForwardLink("icon", shortcutIcon);
}
- DataProvider dataProvider = template.createDataProvider();
+ TemplateContext templateContext = templateContextFactory.createTemplateContext();
+ templateContext.mergeContext(template.getInitialContext());
try {
long start = System.nanoTime();
- processTemplate(request, dataProvider);
+ processTemplate(request, templateContext);
long finish = System.nanoTime();
logger.log(Level.FINEST, "Template was rendered in " + ((finish - start) / 1000) / 1000.0 + "ms.");
} catch (RedirectException re1) {
}
StringWriter stringWriter = new StringWriter();
- template.render(dataProvider, stringWriter);
+ template.render(templateContext, stringWriter);
pageNode.content.addChild("%", stringWriter.toString());
- postProcess(request, dataProvider);
+ postProcess(request, templateContext);
return new Response(200, "OK", "text/html", pageNode.outer.generate());
}
*
* @param request
* The request that is rendered
- * @param dataProvider
- * The data provider to set variables in
+ * @param templateContext
+ * The template context to set variables in
* @throws RedirectException
* if the processing page wants to redirect after processing
*/
- protected void processTemplate(Request request, DataProvider dataProvider) throws RedirectException {
+ protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
/* do nothing. */
}
/**
* This method will be called after
- * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, DataProvider)}
+ * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, TemplateContext)}
* has processed the template and the template was rendered. This method
* will not be called if
- * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, DataProvider)}
+ * {@link #processTemplate(net.pterodactylus.sone.web.page.Page.Request, TemplateContext)}
* throws a {@link RedirectException}!
*
* @param request
* The request being processed
- * @param dataProvider
- * The data provider that supplied the rendered data
+ * @param templateContext
+ * The template context that supplied the rendered data
*/
- protected void postProcess(Request request, DataProvider dataProvider) {
+ protected void postProcess(Request request, TemplateContext templateContext) {
/* do nothing. */
}
/**
* Exception that can be thrown to signal that a subclassed {@link Page}
* wants to redirect the user during the
- * {@link TemplatePage#processTemplate(net.pterodactylus.sone.web.page.Page.Request, DataProvider)}
+ * {@link TemplatePage#processTemplate(net.pterodactylus.sone.web.page.Page.Request, TemplateContext)}
* method call.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
Page.Index.Title=Your Sone - Sone
Page.Index.Label.Text=Post text:
+Page.Index.Label.Sender=Sender:
Page.Index.Button.Post=Post!
Page.Index.PostList.Title=Post Feed
Page.Index.PostList.Text.NoPostYet=Nobody has written any posts yet. You should probably start it right now!
Page.Untrust.Title=Untrust Sone - Sone
+Page.MarkAsKnown.Title=Mark as Known - Sone
+
Page.NoPermission.Title=Unauthorized Access - Sone
Page.NoPermission.Page.Title=Unauthorized Access
Page.NoPermission.Text.NoPermission=You tried to do something that you do not have sufficient authorization for. Please refrain from such actions in the future or we will be forced to take counter-measures!
View.CreateSone.Text.Error.NoIdentity=You have not selected an identity.
View.Sone.Label.LastUpdate=Last update:
+View.Sone.Text.UnknownDate=unknown
View.Sone.Button.UnlockSone=unlock
View.Sone.Button.UnlockSone.Tooltip=Allow this Sone to be inserted now
View.Sone.Button.LockSone=lock
View.Post.LikeLink=Like
View.Post.UnlikeLink=Unlike
+View.UpdateStatus.Text.ChooseSenderIdentity=Choose the sender identity
+
View.Trust.Tooltip.Trust=Trust this person
View.Trust.Tooltip.Distrust=Assign negative trust to this person
View.Trust.Tooltip.Untrust=Remove your trust assignment for this person
Notification.NewSone.Text=New Sones have been discovered:
Notification.NewPost.ShortText=New posts have been discovered.
Notification.NewPost.Text=New posts have been discovered by the following Sones:
+Notification.NewPost.Button.MarkRead=Mark as read
Notification.NewReply.ShortText=New replies have been discovered.
Notification.NewReply.Text=New replies have been discovered by the following Sones:
Notification.SoneIsBeingRescued.Text=The following Sones are currently being rescued:
margin: 0px;
}
+#sone select {
+ color: #444;
+ padding: 0.5ex 1.5ex;
+}
+
/* now for the real stuff. */
#sone {
min-height: 3.5ex;
}
+#sone #notification-area .notification button {
+ margin-left: 1ex;
+}
+
#sone #notification-area .notification .dismiss {
float: right;
}
margin-left: 1ex;
}
+#sone #notification-area .notification .mark-as-read {
+ float: right;
+}
+
#sone #plugin-warning {
border: solid 0.5em red;
padding: 0.5em;
padding-left: 1ex;
}
+#sone #update-status {
+ margin-bottom: 1em;
+}
+
#sone #update-status label {
display: none;
}
float: right;
}
+#sone #update-status .select-sender, #sone .create-reply .select-sender {
+ display: none;
+}
+
+#sone #update-status .select-sender button {
+ display: inline;
+ float: left;
+}
+
#sone .nice-name {
font-weight: bold;
}
#sone .post .create-reply input[type=text] {
margin-left: 0.5ex;
- width: 44em;
+ width: 42em;
}
#sone .post .create-reply textarea {
margin-left: 0.5ex;
- width: 44em;
+ width: 42em;
height: 4em;
}
float: right;
}
+#sone .create-reply .select-sender button {
+ display: inline;
+ float: left;
+}
+
#sone .sone {
clear: both;
background-color: #f0f0ff;
display: none;
}
-#sone .profile-field button.confirm {
+#sone .profile-field button.confirm.edit {
font-weight: bold;
color: #080;
}
#sone .profile-field .edit-field-name, #sone .profile-field .move-up-field, #sone .profile-field .move-down-field, #sone .profile-field .delete-field-name {
float: right;
margin-top: -1ex;
+ position: relative;
}
#sone #tail {
--- /dev/null
+// JQuery URL Parser
+// Written by Mark Perkins, mark@allmarkedup.com
+// License: http://unlicense.org/ (i.e. do what you want with it!)
+
+jQuery.url = function()
+{
+ var segments = {};
+
+ var parsed = {};
+
+ /**
+ * Options object. Only the URI and strictMode values can be changed via the setters below.
+ */
+ var options = {
+
+ url : window.location, // default URI is the page in which the script is running
+
+ strictMode: false, // 'loose' parsing by default
+
+ key: ["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"], // keys available to query
+
+ q: {
+ name: "queryKey",
+ parser: /(?:^|&)([^&=]*)=?([^&]*)/g
+ },
+
+ parser: {
+ strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, //less intuitive, more accurate to the specs
+ loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs
+ }
+
+ };
+
+ /**
+ * Deals with the parsing of the URI according to the regex above.
+ * Written by Steven Levithan - see credits at top.
+ */
+ var parseUri = function()
+ {
+ str = decodeURI( options.url );
+
+ var m = options.parser[ options.strictMode ? "strict" : "loose" ].exec( str );
+ var uri = {};
+ var i = 14;
+
+ while ( i-- ) {
+ uri[ options.key[i] ] = m[i] || "";
+ }
+
+ uri[ options.q.name ] = {};
+ uri[ options.key[12] ].replace( options.q.parser, function ( $0, $1, $2 ) {
+ if ($1) {
+ uri[options.q.name][$1] = $2;
+ }
+ });
+
+ return uri;
+ };
+
+ /**
+ * Returns the value of the passed in key from the parsed URI.
+ *
+ * @param string key The key whose value is required
+ */
+ var key = function( key )
+ {
+ if ( jQuery.isEmptyObject(parsed) )
+ {
+ setUp(); // if the URI has not been parsed yet then do this first...
+ }
+ if ( key == "base" )
+ {
+ if ( parsed.port !== null && parsed.port !== "" )
+ {
+ return parsed.protocol+"://"+parsed.host+":"+parsed.port+"/";
+ }
+ else
+ {
+ return parsed.protocol+"://"+parsed.host+"/";
+ }
+ }
+
+ return ( parsed[key] === "" ) ? null : parsed[key];
+ };
+
+ /**
+ * Returns the value of the required query string parameter.
+ *
+ * @param string item The parameter whose value is required
+ */
+ var param = function( item )
+ {
+ if ( jQuery.isEmptyObject(parsed) )
+ {
+ setUp(); // if the URI has not been parsed yet then do this first...
+ }
+ return ( parsed.queryKey[item] === null ) ? null : parsed.queryKey[item];
+ };
+
+ /**
+ * 'Constructor' (not really!) function.
+ * Called whenever the URI changes to kick off re-parsing of the URI and splitting it up into segments.
+ */
+ var setUp = function()
+ {
+ parsed = parseUri();
+
+ getSegments();
+ };
+
+ /**
+ * Splits up the body of the URI into segments (i.e. sections delimited by '/')
+ */
+ var getSegments = function()
+ {
+ var p = parsed.path;
+ segments = []; // clear out segments array
+ segments = parsed.path.length == 1 ? {} : ( p.charAt( p.length - 1 ) == "/" ? p.substring( 1, p.length - 1 ) : path = p.substring( 1 ) ).split("/");
+ };
+
+ return {
+
+ /**
+ * Sets the parsing mode - either strict or loose. Set to loose by default.
+ *
+ * @param string mode The mode to set the parser to. Anything apart from a value of 'strict' will set it to loose!
+ */
+ setMode : function( mode )
+ {
+ options.strictMode = mode == "strict" ? true : false;
+ return this;
+ },
+
+ /**
+ * Sets URI to parse if you don't want to to parse the current page's URI.
+ * Calling the function with no value for newUri resets it to the current page's URI.
+ *
+ * @param string newUri The URI to parse.
+ */
+ setUrl : function( newUri )
+ {
+ options.url = newUri === undefined ? window.location : newUri;
+ setUp();
+ return this;
+ },
+
+ /**
+ * Returns the value of the specified URI segment. Segments are numbered from 1 to the number of segments.
+ * For example the URI http://test.com/about/company/ segment(1) would return 'about'.
+ *
+ * If no integer is passed into the function it returns the number of segments in the URI.
+ *
+ * @param int pos The position of the segment to return. Can be empty.
+ */
+ segment : function( pos )
+ {
+ if ( jQuery.isEmptyObject(parsed) )
+ {
+ setUp(); // if the URI has not been parsed yet then do this first...
+ }
+ if ( pos === undefined )
+ {
+ return segments.length;
+ }
+ return ( segments[pos] === "" || segments[pos] === undefined ) ? null : segments[pos];
+ },
+
+ attr : key, // provides public access to private 'key' function - see above
+
+ param : param // provides public access to private 'param' function - see above
+
+ };
+
+}();
\ No newline at end of file
* The element to add a “comment” link to
*/
function addCommentLink(postId, element, insertAfterThisElement) {
- if ($(element).find(".show-reply-form").length > 0) {
+ if (($(element).find(".show-reply-form").length > 0) || (getPostElement(element).find(".create-reply").length == 0)) {
return;
}
commentElement = (function(postId) {
toggleClass("modified", modified);
$("#sone .sone." + filterSoneId(soneId) + " .lock").toggleClass("hidden", locked);
$("#sone .sone." + filterSoneId(soneId) + " .unlock").toggleClass("hidden", !locked);
- $("#sone .sone." + filterSoneId(soneId) + " .last-update span.time").text(lastUpdated);
+ if (lastUpdated != null) {
+ $("#sone .sone." + filterSoneId(soneId) + " .last-update span.time").text(lastUpdated);
+ } else {
+ getTranslation("View.Sone.Text.UnknownDate", function(unknown) {
+ $("#sone .sone." + filterSoneId(soneId) + " .last-update span.time").text(unknown);
+ });
+ }
$("#sone .sone." + filterSoneId(soneId) + " .profile-link a").text(name);
}
$("#sone .post").each(function() {
if (getPostAuthor(this) == soneId) {
getPostElement(this).find(".post-trust").toggleClass("hidden", trustValue != null);
- getPostElement(this).find(".post-distrust").toggleClass("hidden", (trustValue != null) && (trustValue < 0));
+ getPostElement(this).find(".post-distrust").toggleClass("hidden", trustValue != null);
getPostElement(this).find(".post-untrust").toggleClass("hidden", trustValue == null);
}
});
$("#sone .reply").each(function() {
if (getReplyAuthor(this) == soneId) {
getReplyElement(this).find(".reply-trust").toggleClass("hidden", trustValue != null);
- getReplyElement(this).find(".reply-distrust").toggleClass("hidden", (trustValue != null) && (trustValue < 0));
+ getReplyElement(this).find(".reply-distrust").toggleClass("hidden", trustValue != null);
getReplyElement(this).find(".reply-untrust").toggleClass("hidden", trustValue == null);
}
});
/**
* Posts a reply and calls the given callback when the request finishes.
*
+ * @param sender
+ * The ID of the sender
* @param postId
* The ID of the post the reply refers to
* @param text
* The callback function to call when the request finishes (takes 3
* parameters: success, error, replyId)
*/
-function postReply(postId, text, callbackFunction) {
- $.getJSON("createReply.ajax", { "formPassword" : getFormPassword(), "post" : postId, "text": text }, function(data, textStatus) {
+function postReply(sender, postId, text, callbackFunction) {
+ $.getJSON("createReply.ajax", { "formPassword" : getFormPassword(), "sender": sender, "post" : postId, "text": text }, function(data, textStatus) {
if (data == null) {
/* TODO - show error */
return;
}
if (data.success) {
- callbackFunction(true, null, data.reply);
+ callbackFunction(true, null, data.reply, data.sone);
} else {
callbackFunction(false, data.error);
}
}
/**
+ * Ajaxifies the given Sone by enhancing all eligible elements with AJAX.
+ *
+ * @param soneElement
+ * The Sone to ajaxify
+ */
+function ajaxifySone(soneElement) {
+ /*
+ * convert all “follow”, “unfollow”, “lock”, and “unlock” links to something
+ * nicer.
+ */
+ $(".follow", soneElement).submit(function() {
+ var followElement = this;
+ $.getJSON("followSone.ajax", { "sone": getSoneId(this), "formPassword": getFormPassword() }, function() {
+ $(followElement).addClass("hidden");
+ $(followElement).parent().find(".unfollow").removeClass("hidden");
+ });
+ return false;
+ });
+ $(".unfollow", soneElement).submit(function() {
+ var unfollowElement = this;
+ $.getJSON("unfollowSone.ajax", { "sone": getSoneId(this), "formPassword": getFormPassword() }, function() {
+ $(unfollowElement).addClass("hidden");
+ $(unfollowElement).parent().find(".follow").removeClass("hidden");
+ });
+ return false;
+ });
+ $(".lock", soneElement).submit(function() {
+ var lockElement = this;
+ $.getJSON("lockSone.ajax", { "sone" : getSoneId(this), "formPassword" : getFormPassword() }, function() {
+ $(lockElement).addClass("hidden");
+ $(lockElement).parent().find(".unlock").removeClass("hidden");
+ });
+ return false;
+ });
+ $(".unlock", soneElement).submit(function() {
+ var unlockElement = this;
+ $.getJSON("unlockSone.ajax", { "sone" : getSoneId(this), "formPassword" : getFormPassword() }, function() {
+ $(unlockElement).addClass("hidden");
+ $(unlockElement).parent().find(".lock").removeClass("hidden");
+ });
+ return false;
+ });
+
+ /* mark Sone as known when clicking it. */
+ $(soneElement).click(function() {
+ markSoneAsKnown(soneElement);
+ });
+}
+
+/**
* Ajaxifies the given post by enhancing all eligible elements with AJAX.
*
* @param postElement
return false;
});
$(postElement).find(".create-reply button:submit").click(function() {
- inputField = $(this.form).find(":input:enabled").get(0);
+ sender = $(this.form).find(":input[name=sender]").val();
+ inputField = $(this.form).find(":input[name=text]:enabled").get(0);
postId = getPostId(this);
text = $(inputField).val();
- (function(postId, text, inputField) {
- postReply(postId, text, function(success, error, replyId) {
+ (function(sender, postId, text, inputField) {
+ postReply(sender, postId, text, function(success, error, replyId, soneId) {
if (success) {
$(inputField).val("");
- loadNewReply(replyId, getCurrentSoneId(), postId);
+ loadNewReply(replyId, soneId, postId);
markPostAsKnown(getPostElement(inputField));
$("#sone .post#" + postId + " .create-reply").addClass("hidden");
+ $("#sone .post#" + postId + " .create-reply .sender").hide();
+ $("#sone .post#" + postId + " .create-reply .select-sender").show();
+ $("#sone .post#" + postId + " .create-reply :input[name=sender]").val(getCurrentSoneId());
} else {
alert(error);
}
});
- })(postId, text, inputField);
+ })(sender, postId, text, inputField);
return false;
});
});
});
+ /* process sender selection. */
+ $(".select-sender", postElement).css("display", "inline");
+ $(".sender", postElement).hide();
+ $(".select-sender button", postElement).click(function() {
+ $(".sender", postElement).show();
+ $(".select-sender", postElement).hide();
+ return false;
+ });
+
/* mark everything as known on click. */
$(postElement).click(function(event) {
if ($(event.target).hasClass("click-to-show")) {
* jQuery object representing the notification.
*/
function ajaxifyNotification(notification) {
- notification.find("form.dismiss").submit(function() {
+ notification.find("form").submit(function() {
return false;
});
+ notification.find("input[name=returnPage]").val($.url.attr("relative"));
+ if (notification.find(".short-text").length > 0) {
+ notification.find(".short-text").removeClass("hidden");
+ notification.find(".text").addClass("hidden");
+ }
+ notification.find("form.mark-as-read button").click(function() {
+ $.getJSON("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": $(":input[name=type]", this.form).val(), "id": $(":input[name=id]", this.form).val()});
+ });
notification.find("form.dismiss button").click(function() {
$.getJSON("dismissNotification.ajax", { "formPassword" : getFormPassword(), "notification" : notification.attr("id") }, function(data, textStatus) {
/* dismiss in case of error, too. */
if ((data != null) && data.success) {
/* process Sone information. */
$.each(data.sones, function(index, value) {
- updateSoneStatus(value.id, value.name, value.status, value.modified, value.locked, value.lastUpdated);
+ updateSoneStatus(value.id, value.name, value.status, value.modified, value.locked, value.lastUpdatedUnknown ? null : value.lastUpdated);
});
/* process notifications. */
$.each(data.notifications, function(index, value) {
oldNotification = $("#sone #notification-area .notification#" + value.id);
notification = ajaxifyNotification(createNotification(value.id, value.text, value.dismissable)).hide();
if (oldNotification.length != 0) {
+ if ((oldNotification.find(".short-text").length > 0) && (notification.find(".short-text").length > 0)) {
+ opened = oldNotification.is(":visible") && oldNotification.find(".short-text").hasClass("hidden");
+ notification.find(".short-text").toggleClass("hidden", opened);
+ notification.find(".text").toggleClass("hidden", !opened);
+ }
oldNotification.replaceWith(notification.show());
} else {
$("#sone #notification-area").append(notification);
});
}
+/**
+ * Marks the given Sone as known if it is still new.
+ *
+ * @param soneElement
+ * The Sone to mark as known
+ */
+function markSoneAsKnown(soneElement) {
+ if ($(".new", soneElement).length > 0) {
+ $.getJSON("maskAsKnown.ajax", {"formPassword": getFormPassword(), "type": "sone", "id": getSoneId(soneElement)}, function(data, textStatus) {
+ $(soneElement).removeClass("new");
+ });
+ }
+}
+
function markPostAsKnown(postElements) {
$(postElements).each(function() {
postElement = this;
if ($(postElement).hasClass("new")) {
(function(postElement) {
- $.getJSON("markPostAsKnown.ajax", {"formPassword": getFormPassword(), "post": getPostId(postElement)}, function(data, textStatus) {
+ $.getJSON("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": "post", "id": getPostId(postElement)}, function(data, textStatus) {
$(postElement).removeClass("new");
$(".click-to-show", postElement).removeClass("new");
});
replyElement = this;
if ($(replyElement).hasClass("new")) {
(function(replyElement) {
- $.getJSON("markReplyAsKnown.ajax", {"formPassword": getFormPassword(), "reply": getReplyId(replyElement)}, function(data, textStatus) {
+ $.getJSON("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": "reply", "id": getReplyId(replyElement)}, function(data, textStatus) {
$(replyElement).removeClass("new");
});
})(replyElement);
* The ID of the notification
*/
function showNotificationDetails(notificationId) {
- $("#sone .notification#" + notificationId + " .text").show();
- $("#sone .notification#" + notificationId + " .short-text").hide();
+ $("#sone .notification#" + notificationId + " .text").removeClass("hidden");
+ $("#sone .notification#" + notificationId + " .short-text").addClass("hidden");
}
/**
/* this initializes the status update input field. */
getTranslation("WebInterface.DefaultText.StatusUpdate", function(defaultText) {
registerInputTextareaSwap("#sone #update-status .status-input", defaultText, "text", false, false);
+ $("#sone #update-status .select-sender").css("display", "inline");
+ $("#sone #update-status .sender").hide();
+ $("#sone #update-status .select-sender button").click(function() {
+ $("#sone #update-status .sender").show();
+ $("#sone #update-status .select-sender").hide();
+ return false;
+ });
$("#sone #update-status").submit(function() {
if ($(this).find(":input.default:enabled").length > 0) {
return false;
}
- text = $(this).find(":input:enabled").val();
- $.getJSON("createPost.ajax", { "formPassword": getFormPassword(), "text": text }, function(data, textStatus) {
+ sender = $(this).find(":input[name=sender]").val();
+ text = $(this).find(":input[name=text]:enabled").val();
+ $.getJSON("createPost.ajax", { "formPassword": getFormPassword(), "sender": sender, "text": text }, function(data, textStatus) {
if ((data != null) && data.success) {
- loadNewPost(data.postId, getCurrentSoneId());
+ loadNewPost(data.postId, data.sone, data.recipient);
}
});
- $(this).find(":input:enabled").val("").blur();
+ $(this).find(":input[name=sender]").val(getCurrentSoneId());
+ $(this).find(":input[name=text]:enabled").val("").blur();
+ $(this).find(".sender").hide();
+ $(this).find(".select-sender").show();
return false;
});
});
});
}
- /*
- * convert all “follow”, “unfollow”, “lock”, and “unlock” links to something
- * nicer.
- */
- $("#sone .follow").submit(function() {
- var followElement = this;
- $.getJSON("followSone.ajax", { "sone": getSoneId(this), "formPassword": getFormPassword() }, function() {
- $(followElement).addClass("hidden");
- $(followElement).parent().find(".unfollow").removeClass("hidden");
- });
- return false;
- });
- $("#sone .unfollow").submit(function() {
- var unfollowElement = this;
- $.getJSON("unfollowSone.ajax", { "sone": getSoneId(this), "formPassword": getFormPassword() }, function() {
- $(unfollowElement).addClass("hidden");
- $(unfollowElement).parent().find(".follow").removeClass("hidden");
- });
- return false;
- });
- $("#sone .lock").submit(function() {
- var lockElement = this;
- $.getJSON("lockSone.ajax", { "sone" : getSoneId(this), "formPassword" : getFormPassword() }, function() {
- $(lockElement).addClass("hidden");
- $(lockElement).parent().find(".unlock").removeClass("hidden");
- });
- return false;
- });
- $("#sone .unlock").submit(function() {
- var unlockElement = this;
- $.getJSON("unlockSone.ajax", { "sone" : getSoneId(this), "formPassword" : getFormPassword() }, function() {
- $(unlockElement).addClass("hidden");
- $(unlockElement).parent().find(".lock").removeClass("hidden");
- });
- return false;
+ $("#sone .sone").each(function() {
+ ajaxifySone($(this));
});
/* process all existing notifications, ajaxify dismiss buttons. */
<%foreach fields field fieldLoop>
<div class="profile-field" id="<% field.id|html>">
<div class="name"><% field.name|html></div>
- <input class="short hidden" type="text"><button class="confirm hidden" type="button">✔</button><button class="cancel hidden" type="button">✘</button>
+ <input class="short hidden" type="text"><button class="edit confirm hidden" type="button">✔</button><button class="cancel hidden" type="button">✘</button>
<div class="edit-field-name"><button type="submit" name="edit-field-<% field.id|html>" value="true"><%= Page.EditProfile.Fields.Button.Edit|l10n|html></button></div>
<div class="delete-field-name"><button type="submit" name="delete-field-<% field.id|html>" value="true"><%= Page.EditProfile.Fields.Button.Delete|l10n|html></button></div>
<div class="<%if fieldLoop.last>hidden <%/if>move-down-field"><button type="submit" name="move-down-field-<% field.id|html>" value="true"><%= Page.EditProfile.Fields.Button.MoveDown|l10n|html></button></div>
<div id="currentSoneId" class="hidden"><% currentSone.id|html></div>
<script src="javascript/jquery-1.4.2.js" language="javascript"></script>
+ <script src="javascript/jquery.url.js" language="javascript"></script>
<script src="javascript/sone.js" language="javascript"></script>
<div id="main">
<button type="submit"><%= Notification.Button.Dismiss|l10n|html></button>
</form>
<%/if>
- <% notification>
+ <%include notification>
</div>
<%/foreach>
</div>
<div id="home-sone">
<% currentSone|store key=sone>
<%include include/viewSone.html>
- <%include include/updateStatus.html>
</div>
<%/if>
</div>
<form id="update-status" action="createPost.html" method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <label for="text"><%= Page.Index.Label.Text|l10n|html></label>
+ <label for="sender"><%= Page.Index.Label.Sender|l10n|html></label>
+ <div class="sender">
+ <select name="sender" title="<%= View.UpdateStatus.Text.ChooseSenderIdentity|l10n|html>">
+ <%foreach localSones localSone>
+ <option value="<% localSone.id|html>"<%if localSone.current> selected="selected"<%/if>><% localSone.niceName|html></option>
+ <%/foreach>
+ </select>
+ </div>
+ <div class="select-sender"><button type="button" title="<%= View.UpdateStatus.Text.ChooseSenderIdentity|l10n|html>">+</button></div><label for="text"><%= Page.Index.Label.Text|l10n|html></label>
<input type="text" class="status-input" name="text" value="" />
<button type="submit"><%= Page.Index.Button.Post|l10n|html></button>
</form>
<div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipient.id|html>"><% post.recipient.niceName|html></a></div>
<%/if>
<%/if>
- <div class="text"><% post.text></div>
+ <div class="text"><% post.text|parse sone=post.sone></div>
</div>
<div class="post-status-line status-line">
<div class="time"><a href="viewPost.html?post=<% post.id|html>"><% post.time|date format="MMM d, yyyy, HH:mm:ss"></a></div>
- <span class='separator'>·</span>
- <div class="likes<%if post.likes.size|match value=0> hidden<%/if>"><span title="<% post.likes.soneNames|html>">↑<span class="like-count"><% post.likes.size></span></span></div>
+ <div class="likes<%if post.likes.size|match value=0> hidden<%/if>">
+ <span class='separator'>·</span>
+ <span title="<% post.likes.soneNames|html>">↑<span class="like-count"><% post.likes.size></span></span>
+ </div>
<%ifnull ! currentSone>
+ <span class='separator'>·</span>
<form class="like like-post<%if post.liked> hidden<%/if>" action="like.html" method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<input type="hidden" name="returnPage" value="<% request.uri|html>" />
<input type="hidden" name="post" value="<% post.id|html>" />
<button type="submit" value="1"><%= View.Post.UnlikeLink|l10n|html></button>
</form>
+ <%if !post.sone.current>
+ <span class='separator'>·</span>
+ <form class="trust post-trust<%if post.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% post.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
+ </form>
+ <form class="distrust post-distrust<%if post.sone.trust.assigned> hidden<%/if>" action="distrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% post.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
+ </form>
+ <form class="untrust post-untrust<%if !post.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% post.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
+ </form>
+ <%/if>
<%/if>
- <%if !post.sone.current>
- <span class='separator'>·</span>
- <form class="trust post-trust<%if post.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% post.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
- </form>
- <form class="distrust post-distrust" action="distrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% post.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
- </form>
- <form class="untrust post-untrust<%if !post.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% post.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
- </form>
- <%/if>
- <%if post.sone.current>
+ <%if post.sone.local>
<span class='separator'>·</span>
<form class="delete delete-post" action="deletePost.html" method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<input type="hidden" name="returnPage" value="<% request.uri|html>" />
<input type="hidden" name="post" value="<% post.id|html>" />
+ <div class="sender">
+ <select name="sender" title="<%= View.UpdateStatus.Text.ChooseSenderIdentity|l10n|html>">
+ <%foreach localSones localSone>
+ <option value="<% localSone.id|html>"<%if localSone.current> selected="selected"<%/if>><% localSone.niceName|html></option>
+ <%/foreach>
+ </select>
+ </div>
+ <div class="select-sender"><button type="button" title="<%= View.UpdateStatus.Text.ChooseSenderIdentity|l10n|html>">+</button></div>
<input type="text" class="reply-input" name="text" value="" />
<button type="submit"><%= View.Post.SendReply|l10n|html></button>
</form>
<div class="inner-part">
<div>
<div class="author profile-link"><a href="viewSone.html?sone=<% reply.sone.id|html>"><% reply.sone.niceName|html></a></div>
- <div class="text"><% reply.text></div>
+ <div class="text"><% reply.text|parse sone=reply.sone></div>
</div>
<div class="reply-status-line status-line">
<div class="time"><% reply.time|date format="MMM d, yyyy, HH:mm:ss"></div>
- <span class='separator'>·</span>
- <div class="likes<%if reply.likes.size|match value=0> hidden<%/if>"><span title="<% reply.likes.soneNames|html>">↑<span class="like-count"><% reply.likes.size></span></span></div>
+ <div class="likes<%if reply.likes.size|match value=0> hidden<%/if>">
+ <span class='separator'>·</span>
+ <span title="<% reply.likes.soneNames|html>">↑<span class="like-count"><% reply.likes.size></span></span>
+ </div>
<%ifnull ! currentSone>
+ <span class='separator'>·</span>
<form class="like like-reply<%if reply.liked> hidden<%/if>" action="like.html" method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<input type="hidden" name="returnPage" value="<% request.uri|html>" />
<input type="hidden" name="reply" value="<% reply.id|html>" />
<button type="submit" value="1"><%= View.Post.UnlikeLink|l10n|html></button>
</form>
+ <%if !reply.sone.current>
+ <span class='separator'>·</span>
+ <form class="trust reply-trust<%if reply.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
+ </form>
+ <form class="distrust reply-distrust<%if reply.sone.trust.assigned> hidden<%/if>" action="distrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
+ </form>
+ <form class="untrust reply-untrust<%if !reply.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
+ <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
+ </form>
+ <%/if>
<%/if>
- <%if !reply.sone.current>
- <span class='separator'>·</span>
- <form class="trust reply-trust<%if reply.sone.trust.assigned> hidden<%/if>" action="trust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Trust|l10n|html>">✓</button>
- </form>
- <form class="distrust reply-distrust" action="distrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Distrust|l10n|html>">✗</button>
- </form>
- <form class="untrust reply-untrust<%if !reply.sone.trust.assigned> hidden<%/if>" action="untrust.html" method="post">
- <input type="hidden" name="formPassword" value="<% formPassword|html>" />
- <input type="hidden" name="returnPage" value="<% request.uri|html>" />
- <input type="hidden" name="sone" value="<% reply.sone.id|html>" />
- <button type="submit" title="<%= View.Trust.Tooltip.Untrust|l10n|html>">↶</button>
- </form>
- <%/if>
- <%if reply.sone.current>
+ <%if reply.sone.local>
<span class='separator'>·</span>
<form class="delete delete-reply" action="deleteReply.html" method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<div class="download-marker" title="<%= View.Sone.Status.Downloading|l10n|html>">⬊</div>
<div class="insert-marker" title="<%= View.Sone.Status.Inserting|l10n|html>">⬈</div>
<div class="idle-marker" title="<%= View.Sone.Status.Idle|l10n|html>">✔</div>
- <div class="last-update"><%= View.Sone.Label.LastUpdate|l10n|html> <span class="time"><% sone.time|date format="MMM d, yyyy, HH:mm:ss"></span></div>
+ <div class="last-update"><%= View.Sone.Label.LastUpdate|l10n|html> <span class="time"><% sone.time|unknown|date format="MMM d, yyyy, HH:mm:ss"></span></div>
<div class="profile-link"><a href="viewSone.html?sone=<% sone.id|html>" title="<% sone.requestUri|html>"><% sone.niceName|html></a></div>
<div class="short-request-uri"><% sone.requestUri|substring start=4 length=43|html></div>
<div class="hidden"><% sone.blacklisted></div>
<h1><%= Page.Index.PostList.Title|l10n|html></h1>
+ <%include include/updateStatus.html>
+
<div id="posts">
<%= page|store key=pageParameter>
<%include include/pagination.html>
<h1><%= Page.KnownSones.Page.Title|l10n|html></h1>
<div id="known-sones">
- <%getpage parameter=page>
- <%paginate list=knownSones pagesize=25>
<%= page|store key=pageParameter>
<%include include/pagination.html>
<%foreach pagination.items sone>
-<div class="short-text">
+<div class="short-text hidden">
<%= Notification.NewPost.ShortText|l10n|html>
<a class="link" onclick="showNotificationDetails('<%notification.id|html>'); return false;"><%= Notification.ClickHereToRead|l10n|html></a>
</div>
-<div class="text hidden">
+<div class="text">
+ <form class="mark-as-read" action="markAsKnown.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="type" value="post" />
+ <input type="hidden" name="id" value="<%foreach posts post><% post.id|html><%notlast> <%/notlast><%/foreach>" />
+ <button type="submit" name="mark-read" value="true"><%= Notification.NewPost.Button.MarkRead|l10n|html></button>
+ </form>
<%= Notification.NewPost.Text|l10n|html>
<%foreach posts post>
<a href="viewPost.html?post=<% post.id|html>"><% post.sone.niceName|html></a><%notlast>,<%/notlast><%last>.<%/last>
-<div class="short-text">
+<div class="short-text hidden">
<%= Notification.NewReply.ShortText|l10n|html>
<a class="link" onclick="showNotificationDetails('<%notification.id|html>'); return false;"><%= Notification.ClickHereToRead|l10n|html></a>
</div>
-<div class="text hidden">
+<div class="text">
+ <form class="mark-as-read" action="markAsKnown.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="type" value="reply" />
+ <input type="hidden" name="id" value="<%foreach replies reply><% reply.id|html><%notlast> <%/notlast><%/foreach>" />
+ <button type="submit" name="mark-read" value="true"><%= Notification.NewPost.Button.MarkRead|l10n|html></button>
+ </form>
<%= Notification.NewReply.Text|l10n|html>
<%foreach replies reply>
<a href="viewPost.html?post=<% reply.post.id|html>"><% reply.sone.niceName|html></a><%notlast>,<%/notlast><%last>.<%/last>
-<div class="short-text">
+<div class="short-text hidden">
<%= Notification.NewSone.ShortText|l10n|html>
<a class="link" onclick="showNotificationDetails('<%notification.id|html>'); return false;"><%= Notification.ClickHereToRead|l10n|html></a>
</div>
-<div class="text hidden">
+<div class="text">
+ <form class="mark-as-read" action="markAsKnown.html" method="post">
+ <input type="hidden" name="formPassword" value="<% formPassword|html>" />
+ <input type="hidden" name="returnPage" value="<% request.uri|html>" />
+ <input type="hidden" name="type" value="sone" />
+ <input type="hidden" name="id" value="<%foreach sones sone><% sone.id|html><%notlast> <%/notlast><%/foreach>" />
+ <button type="submit" name="mark-read" value="true"><%= Notification.NewPost.Button.MarkRead|l10n|html></button>
+ </form>
<%= Notification.NewSone.Text|l10n|html>
<%foreach sones sone>
<a href="viewSone.html?sone=<% sone.id|html>" title="<% sone.requestUri|html>"><% sone.niceName|html></a><%notlast>,<%/notlast><%last>.<%/last>
<p><%= Page.ViewPost.Text.UnknownPost|l10n|html></p>
<%else>
- <h1><%= Page.ViewPost.Page.Title|l10n|insert needle="{sone}" key=post.sone.niceName|html></h1>
+ <h1><%= Page.ViewPost.Page.Title|l10n|replace needle="{sone}" replacementKey=post.sone.niceName|html></h1>
<%include include/viewPost.html>
<%/if>
<h1><%= Page.ViewSone.Page.TitleWithoutSone|l10n|html></h1>
- <p><%= Page.ViewSone.NoSone.Description|l10n|insert needle="{sone}" key=sone.id|html></p>
+ <p><%= Page.ViewSone.NoSone.Description|l10n|replace needle="{sone}" replacementKey=sone.id|html></p>
<%elseifnull sone.name>
<%foreach sone.profile.fields field>
<div class="profile-field">
<div class="name"><% field.name|html></div>
- <div class="value"><% field.value|html></div>
+ <div class="value"><% field.value|parse></div>
</div>
<%/foreach>
</form>
<%/if>
- <h1><%= Page.ViewSone.PostList.Title|l10n|insert needle="{sone}" key=sone.niceName|html></h1>
+ <h1><%= Page.ViewSone.PostList.Title|l10n|replace needle="{sone}" replacementKey=sone.niceName|html></h1>
<div id="posts">
- <%getpage parameter=postPage>
- <%paginate list=sone.posts pagesize=25>
+ <%:getpage parameter=postPage>
+ <%:paginate list=sone.posts pagesize=25>
<%= postPage|store key=pageParameter>
<%include include/pagination.html>
<%foreach pagination.items post>