This fixes #191.
<modelVersion>4.0.0</modelVersion>
<groupId>net.pterodactylus</groupId>
<artifactId>sone</artifactId>
- <version>0.6.4</version>
+ <version>0.6.5</version>
<dependencies>
<dependency>
<groupId>net.pterodactylus</groupId>
<artifactId>utils</artifactId>
- <version>0.9.6-SNAPSHOT</version>
+ <version>0.9.7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.thread.Ticker;
+import net.pterodactylus.util.validation.EqualityValidator;
import net.pterodactylus.util.validation.IntegerRangeValidator;
+import net.pterodactylus.util.validation.OrValidator;
import net.pterodactylus.util.validation.Validation;
import net.pterodactylus.util.version.Version;
import freenet.client.FetchResult;
configuration.getIntValue("Option/ConfigurationVersion").setValue(0);
configuration.getIntValue("Option/InsertionDelay").setValue(options.getIntegerOption("InsertionDelay").getReal());
configuration.getIntValue("Option/PostsPerPage").setValue(options.getIntegerOption("PostsPerPage").getReal());
+ configuration.getIntValue("Option/CharactersPerPost").setValue(options.getIntegerOption("CharactersPerPost").getReal());
configuration.getBooleanValue("Option/RequireFullAccess").setValue(options.getBooleanOption("RequireFullAccess").getReal());
configuration.getIntValue("Option/PositiveTrust").setValue(options.getIntegerOption("PositiveTrust").getReal());
configuration.getIntValue("Option/NegativeTrust").setValue(options.getIntegerOption("NegativeTrust").getReal());
}));
options.addIntegerOption("PostsPerPage", new DefaultOption<Integer>(10, new IntegerRangeValidator(1, Integer.MAX_VALUE)));
+ options.addIntegerOption("CharactersPerPost", new DefaultOption<Integer>(200, new OrValidator<Integer>(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator<Integer>(-1))));
options.addBooleanOption("RequireFullAccess", new DefaultOption<Boolean>(false));
options.addIntegerOption("PositiveTrust", new DefaultOption<Integer>(75, new IntegerRangeValidator(0, 100)));
options.addIntegerOption("NegativeTrust", new DefaultOption<Integer>(-25, new IntegerRangeValidator(-100, 100)));
loadConfigurationValue("InsertionDelay");
loadConfigurationValue("PostsPerPage");
+ loadConfigurationValue("CharactersPerPost");
options.getBooleanOption("RequireFullAccess").set(configuration.getBooleanValue("Option/RequireFullAccess").getValue(null));
loadConfigurationValue("PositiveTrust");
loadConfigurationValue("NegativeTrust");
}
/**
+ * Returns the number of characters per post, or <code>-1</code> if the
+ * posts should not be cut off.
+ *
+ * @return The numbers of characters per post
+ */
+ public int getCharactersPerPost() {
+ return options.getIntegerOption("CharactersPerPost").get();
+ }
+
+ /**
+ * Validates the number of characters per post.
+ *
+ * @param charactersPerPost
+ * The number of characters per post
+ * @return {@code true} if the number of characters per post was valid,
+ * {@code false} otherwise
+ */
+ public boolean validateCharactersPerPost(Integer charactersPerPost) {
+ return options.getIntegerOption("CharactersPerPost").validate(charactersPerPost);
+ }
+
+ /**
+ * Sets the number of characters per post.
+ *
+ * @param charactersPerPost
+ * The number of characters per post, or <code>-1</code> to
+ * not cut off the posts
+ * @return This preferences objects
+ */
+ public Preferences setCharactersPerPost(Integer charactersPerPost) {
+ options.getIntegerOption("CharactersPerPost").set(charactersPerPost);
+ return this;
+ }
+
+ /**
* Returns whether Sone requires full access to be even visible.
*
* @return {@code true} if Sone requires full access, {@code false}
}
TemplateContext templateContext = templateContextFactory.createTemplateContext();
+ templateContext.set("core", core);
templateContext.set("currentSone", soneProperties);
templateContext.set("currentEdition", core.getUpdateChecker().getLatestEdition());
templateContext.set("version", SonePlugin.VERSION);
};
+ /**
+ * Comparator that sorts Sones by last activity (least recent active first).
+ */
+ public static final Comparator<Sone> LAST_ACTIVITY_COMPARATOR = new Comparator<Sone>() {
+
+ @Override
+ public int compare(Sone firstSone, Sone secondSone) {
+ return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, secondSone.getTime() - firstSone.getTime()));
+ }
+ };
+
/** Filter to remove Sones that have not been downloaded. */
public static final Filter<Sone> EMPTY_SONE_FILTER = new Filter<Sone>() {
}
/** The version. */
- public static final Version VERSION = new Version(0, 6, 4);
+ public static final Version VERSION = new Version(0, 6, 5);
/** The logger. */
private static final Logger logger = Logging.getLogger(SonePlugin.class);
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import net.pterodactylus.sone.core.Core;
@Override
public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
String text = String.valueOf(data);
+ int length = -1;
+ try {
+ length = Integer.parseInt(parameters.get("length"));
+ } catch (NumberFormatException nfe1) {
+ /* ignore. */
+ }
+ if ((length == -1) && (parameters.get("length") != null)) {
+ try {
+ length = Integer.parseInt(String.valueOf(templateContext.get(parameters.get("length"))));
+ } catch (NumberFormatException nfe1) {
+ /* ignore. */
+ }
+ }
String soneKey = parameters.get("sone");
if (soneKey == null) {
soneKey = "sone";
SoneTextParserContext context = new SoneTextParserContext(request, sone);
StringWriter parsedTextWriter = new StringWriter();
try {
- render(parsedTextWriter, soneTextParser.parse(context, new StringReader(text)));
+ Iterable<Part> parts = soneTextParser.parse(context, new StringReader(text));
+ if (length > -1) {
+ List<Part> shortenedParts = new ArrayList<Part>();
+ for (Part part : parts) {
+ if (part instanceof PlainTextPart) {
+ String longText = ((PlainTextPart) part).getText();
+ if (length >= longText.length()) {
+ shortenedParts.add(part);
+ } else {
+ shortenedParts.add(new PlainTextPart(longText.substring(0, length) + "…"));
+ }
+ length -= longText.length();
+ } else if (part instanceof LinkPart) {
+ shortenedParts.add(part);
+ length -= ((LinkPart) part).getText().length();
+ } else {
+ shortenedParts.add(part);
+ }
+ if (length <= 0) {
+ break;
+ }
+ }
+ parts = shortenedParts;
+ }
+ render(parsedTextWriter, parts);
} catch (IOException ioe1) {
/* no exceptions in a StringReader or StringWriter, ignore. */
}
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.util.collection.Pagination;
+import net.pterodactylus.util.collection.ReverseComparator;
+import net.pterodactylus.util.filter.Filter;
import net.pterodactylus.util.filter.Filters;
import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.template.Template;
@Override
protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
+ String sortField = request.getHttpRequest().getParam("sort");
+ String sortOrder = request.getHttpRequest().getParam("order");
+ String followedSones = request.getHttpRequest().getParam("followedSones");
+ templateContext.set("sort", (sortField != null) ? sortField : "name");
+ templateContext.set("order", (sortOrder != null) ? sortOrder : "asc");
+ templateContext.set("followedSones", followedSones);
+ final Sone currentSone = getCurrentSone(request.getToadletContext(), false);
List<Sone> knownSones = Filters.filteredList(new ArrayList<Sone>(webInterface.getCore().getSones()), Sone.EMPTY_SONE_FILTER);
- Collections.sort(knownSones, Sone.NICE_NAME_COMPARATOR);
+ if ((currentSone != null) && "show-only".equals(followedSones)) {
+ knownSones = Filters.filteredList(knownSones, new Filter<Sone>() {
+
+ @Override
+ public boolean filterObject(Sone sone) {
+ return currentSone.hasFriend(sone.getId());
+ }
+ });
+ } else if ((currentSone != null) && "hide".equals(followedSones)) {
+ knownSones = Filters.filteredList(knownSones, new Filter<Sone>() {
+
+ @Override
+ public boolean filterObject(Sone sone) {
+ return !currentSone.hasFriend(sone.getId());
+ }
+ });
+ }
+ if ("activity".equals(sortField)) {
+ if ("asc".equals(sortOrder)) {
+ Collections.sort(knownSones, new ReverseComparator<Sone>(Sone.LAST_ACTIVITY_COMPARATOR));
+ } else {
+ Collections.sort(knownSones, Sone.LAST_ACTIVITY_COMPARATOR);
+ }
+ } else {
+ if ("desc".equals(sortOrder)) {
+ Collections.sort(knownSones, new ReverseComparator<Sone>(Sone.NICE_NAME_COMPARATOR));
+ } else {
+ Collections.sort(knownSones, Sone.NICE_NAME_COMPARATOR);
+ }
+ }
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());
}
-
}
} else {
preferences.setPostsPerPage(postsPerPage);
}
+ Integer charactersPerPost = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("characters-per-post", 10), null);
+ if (!preferences.validateCharactersPerPost(charactersPerPost)) {
+ fieldErrors.add("characters-per-post");
+ } else {
+ preferences.setCharactersPerPost(charactersPerPost);
+ }
boolean requireFullAccess = request.getHttpRequest().isPartSet("require-full-access");
preferences.setRequireFullAccess(requireFullAccess);
Integer positiveTrust = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("positive-trust", 3));
}
templateContext.set("insertion-delay", preferences.getInsertionDelay());
templateContext.set("posts-per-page", preferences.getPostsPerPage());
+ templateContext.set("characters-per-post", preferences.getCharactersPerPost());
templateContext.set("require-full-access", preferences.isRequireFullAccess());
templateContext.set("positive-trust", preferences.getPositiveTrust());
templateContext.set("negative-trust", preferences.getNegativeTrust());
protected void processTemplate(Request request, TemplateContext templateContext) throws RedirectException {
super.processTemplate(request, templateContext);
Sone currentSone = getCurrentSone(request.getToadletContext(), false);
+ templateContext.set("core", webInterface.getCore());
templateContext.set("currentSone", currentSone);
templateContext.set("localSones", webInterface.getCore().getLocalSones());
templateContext.set("request", request);
Template newPostNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newPostNotification.html"));
newPostNotification = new ListNotification<Post>("new-post-notification", "posts", newPostNotificationTemplate, false);
- localPostNotification = new ListNotification<Post>("local-post-notification", "posts", newPostNotificationTemplate, false);
+
+ Template localPostNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newPostNotification.html"));
+ localPostNotification = new ListNotification<Post>("local-post-notification", "posts", localPostNotificationTemplate, false);
Template newReplyNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newReplyNotification.html"));
newReplyNotification = new ListNotification<Reply>("new-reply-notification", "replies", newReplyNotificationTemplate, false);
- localReplyNotification = new ListNotification<Reply>("local-reply-notification", "replies", newReplyNotificationTemplate, false);
+
+ Template localReplyNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/newReplyNotification.html"));
+ localReplyNotification = new ListNotification<Reply>("local-reply-notification", "replies", localReplyNotificationTemplate, false);
Template mentionNotificationTemplate = TemplateParser.parse(createReader("/templates/notify/mentionNotification.html"));
mentionNotification = new ListNotification<Post>("mention-notification", "posts", mentionNotificationTemplate, false);
try {
if (notification instanceof TemplateNotification) {
TemplateContext templateContext = webInterface.getTemplateContextFactory().createTemplateContext().mergeContext(((TemplateNotification) notification).getTemplateContext());
+ templateContext.set("core", webInterface.getCore());
templateContext.set("currentSone", webInterface.getCurrentSone(request.getToadletContext(), false));
templateContext.set("localSones", webInterface.getCore().getLocalSones());
templateContext.set("request", request);
jsonPost.put("time", post.getTime());
StringWriter stringWriter = new StringWriter();
TemplateContext templateContext = webInterface.getTemplateContextFactory().createTemplateContext();
+ templateContext.set("core", webInterface.getCore());
templateContext.set("request", request);
templateContext.set("post", post);
templateContext.set("currentSone", currentSone);
jsonReply.put("time", reply.getTime());
StringWriter stringWriter = new StringWriter();
TemplateContext templateContext = webInterface.getTemplateContextFactory().createTemplateContext();
+ templateContext.set("core", webInterface.getCore());
templateContext.set("request", request);
templateContext.set("reply", reply);
templateContext.set("currentSone", currentSone);
Page.Options.Section.RuntimeOptions.Title=Runtime Behaviour
Page.Options.Option.InsertionDelay.Description=The number of seconds the Sone inserter waits after a modification of a Sone before it is being inserted.
Page.Options.Option.PostsPerPage.Description=The number of posts to display on a page before pagination controls are being shown.
+Page.Options.Option.CharactersPerPost.Description=The number of characters to display from a post before cutting it off and showing a link to expand it (-1 to disable).
Page.Options.Option.RequireFullAccess.Description=Whether to deny access to Sone to any host that has not been granted full access.
Page.Options.Section.TrustOptions.Title=Trust Settings
Page.Options.Option.PositiveTrust.Description=The amount of positive trust you want to assign to other Sones by clicking the checkmark below a post or reply.
View.Post.UnlikeLink=Unlike
View.Post.ShowSource=Toggle Parser
View.Post.NotDownloaded=This post has not yet been downloaded, or it has been deleted.
+View.Post.ShowMore=show more
+View.Post.ShowLess=show less
View.UpdateStatus.Text.ChooseSenderIdentity=Choose the sender identity
WebInterface.DefaultText.FieldName=Field name
WebInterface.DefaultText.Option.InsertionDelay=Time to wait after a Sone is modified before insert (in seconds)
WebInterface.DefaultText.Option.PostsPerPage=Number of posts to show on a page
+WebInterface.DefaultText.Option.CharactersPerPost=Number of characters per post after which to cut the post off
WebInterface.DefaultText.Option.PositiveTrust=The positive trust to assign
WebInterface.DefaultText.Option.NegativeTrust=The negative trust to assign
WebInterface.DefaultText.Option.TrustComment=The comment to set in the web of trust
#sone #notification-area #local-post-notification, #sone #notification-area #local-reply-notification {
display: none;
-}
+}
#sone #plugin-warning {
border: solid 0.5em red;
font-size: 90%;
}
-#sone .post .text, #sone .post .raw-text {
+#sone .post .text, #sone .post .raw-text, #sone .post .short-text {
display: inline;
white-space: pre-wrap;
+ word-wrap: break-word;
}
-#sone .post .text.hidden, #sone .post .raw-text.hidden {
+#sone .post .text.hidden, #sone .post .raw-text.hidden, #sone .post .short-text.hidden {
display: none;
}
+#sone .post .expand-post-text:before, #sone .post .expand-reply-text:before {
+ content: "» ";
+}
+
+#sone .post .shrink-post-text:before, #sone .post .shrink-reply-text:before {
+ content: "« ";
+}
+
+#sone .post .shrink-post-text {
+ cursor: pointer;
+}
+
#sone .post .status-line {
margin-top: 0.5ex;
font-size: 85%;
color: red;
font-style: italic;
}
+
+#sone #sort-options {
+ margin-bottom: 1em;
+}
/* convert “show source” link into javascript function. */
$(postElement).find(".show-source").each(function() {
$("a", this).click(function() {
+ post = getPostElement(this);
+ rawPostText = $(".post-text.raw-text", post);
+ rawPostText.toggleClass("hidden");
+ if (rawPostText.hasClass("hidden")) {
+ $(".post-text.short-text", post).removeClass("hidden");
+ $(".post-text.text", post).addClass("hidden");
+ $(".expand-post-text", post).removeClass("hidden");
+ $(".shrink-post-text", post).addClass("hidden");
+ } else {
+ $(".post-text.short-text", post).addClass("hidden");
+ $(".post-text.text", post).addClass("hidden");
+ $(".expand-post-text", post).addClass("hidden");
+ $(".shrink-post-text", post).addClass("hidden");
+ }
+ return false;
+ });
+ });
+
+ /* convert “show more” link into javascript function. */
+ $(postElement).find(".expand-post-text").each(function() {
+ $(this).click(function() {
$(".post-text.text", getPostElement(this)).toggleClass("hidden");
- $(".post-text.raw-text", getPostElement(this)).toggleClass("hidden");
+ $(".post-text.short-text", getPostElement(this)).toggleClass("hidden");
+ $(".expand-post-text", getPostElement(this)).toggleClass("hidden");
+ $(".shrink-post-text", getPostElement(this)).toggleClass("hidden");
return false;
});
});
+ $(postElement).find(".shrink-post-text").each(function() {
+ $(this).click(function() {
+ $(".post-text.text", getPostElement(this)).toggleClass("hidden");
+ $(".post-text.short-text", getPostElement(this)).toggleClass("hidden");
+ $(".expand-post-text", getPostElement(this)).toggleClass("hidden");
+ $(".shrink-post-text", getPostElement(this)).toggleClass("hidden");
+ return false;
+ })
+ });
/* add “comment” link. */
addCommentLink(getPostId(postElement), getPostAuthor(postElement), postElement, $(postElement).find(".post-status-line .permalink-author"));
/* convert “show source” link into javascript function. */
$(replyElement).find(".show-reply-source").each(function() {
$("a", this).click(function() {
+ reply = getReplyElement(this);
+ rawReplyText = $(".reply-text.raw-text", reply);
+ rawReplyText.toggleClass("hidden");
+ if (rawReplyText.hasClass("hidden")) {
+ $(".reply-text.short-text", reply).removeClass("hidden");
+ $(".reply-text.text", reply).addClass("hidden");
+ $(".expand-reply-text", reply).removeClass("hidden");
+ $(".shrink-reply-text", reply).addClass("hidden");
+ } else {
+ $(".reply-text.short-text", reply).addClass("hidden");
+ $(".reply-text.text", reply).addClass("hidden");
+ $(".expand-reply-text", reply).addClass("hidden");
+ $(".shrink-reply-text", reply).addClass("hidden");
+ }
+ return false;
+ });
+ });
+
+ /* convert “show more” link into javascript function. */
+ $(replyElement).find(".expand-reply-text").each(function() {
+ $(this).click(function() {
+ $(".reply-text.text", getReplyElement(this)).toggleClass("hidden");
+ $(".reply-text.short-text", getReplyElement(this)).toggleClass("hidden");
+ $(".expand-reply-text", getReplyElement(this)).toggleClass("hidden");
+ $(".shrink-reply-text", getReplyElement(this)).toggleClass("hidden");
+ return false;
+ });
+ });
+ $(replyElement).find(".shrink-reply-text").each(function() {
+ $(this).click(function() {
$(".reply-text.text", getReplyElement(this)).toggleClass("hidden");
- $(".reply-text.raw-text", getReplyElement(this)).toggleClass("hidden");
+ $(".reply-text.short-text", getReplyElement(this)).toggleClass("hidden");
+ $(".expand-reply-text", getReplyElement(this)).toggleClass("hidden");
+ $(".shrink-reply-text", getReplyElement(this)).toggleClass("hidden");
return false;
});
});
<%/if>
<% post.text|html|store key=originalText text=true>
<% post.text|parse sone=post.sone|store key=parsedText text=true>
+ <% post.text|parse sone=post.sone length=core.preferences.charactersPerPost|store key=shortText text=true>
<div class="post-text raw-text<%if !raw> hidden<%/if>"><% originalText></div>
- <div class="post-text text<%if raw> hidden<%/if>"><% parsedText></div>
+ <div class="post-text text<%if raw> hidden<%/if><%if !shortText|match key=parsedText> hidden<%/if>"><% parsedText></div>
+ <div class="post-text short-text<%if raw> hidden<%/if><%if shortText|match key=parsedText> hidden<%/if>"><% shortText></div>
+ <%if !shortText|match key=parsedText><%if !raw><a class="expand-post-text" href="viewPost.html?post=<% post.id|html>&raw=true"><%= View.Post.ShowMore|l10n|html></a><%/if><%/if>
+ <%if !shortText|match key=parsedText><%if !raw><a class="shrink-post-text hidden"><%= View.Post.ShowLess|l10n|html></a><%/if><%/if>
</div>
<div class="post-status-line status-line<%if !post.loaded> hidden<%/if>">
<div class="bookmarks">
<div class="author profile-link"><a href="viewSone.html?sone=<% reply.sone.id|html>"><% reply.sone.niceName|html></a></div>
<% reply.text|html|store key=originalText text=true>
<% reply.text|parse sone=reply.sone|store key=parsedText text=true>
+ <% reply.text|parse sone=reply.sone length=core.preferences.charactersPerPost|store key=shortText text=true>
<div class="reply-text raw-text<%if !raw> hidden<%/if>"><% originalText></div>
- <div class="reply-text text<%if raw> hidden<%/if>"><% parsedText></div>
+ <div class="reply-text text<%if raw> hidden<%/if><%if !shortText|match key=parsedText> hidden<%/if>"><% parsedText></div>
+ <div class="reply-text short-text<%if raw> hidden<%/if><%if shortText|match key=parsedText> hidden<%/if>"><% shortText></div>
+ <%if !shortText|match key=parsedText><%if !raw><a class="expand-reply-text" href="viewPost.html?post=<% reply.post.id|html>&raw=true"><%= View.Post.ShowMore|l10n|html></a><%/if><%/if>
+ <%if !shortText|match key=parsedText><%if !raw><a class="shrink-reply-text hidden"><%= View.Post.ShowLess|l10n|html></a><%/if><%/if>
</div>
<div class="reply-status-line status-line">
<div class="time"><% reply.time|date format="MMM d, yyyy, HH:mm:ss"></div>
<%include include/head.html>
<div class="page-id hidden">known-sones</div>
+
+ <script language="javascript">
+
+ $(document).ready(function() {
+ $("select[name=sort]").change(function() {
+ value = $(this).val();
+ if (value == "activity") {
+ $("select[name=order]").val("desc");
+ } else if (value == "name") {
+ $("select[name=order]").val("asc");
+ }
+ });
+ $("#sort-options select").change(function() {
+ this.form.submit();
+ });
+ });
+
+ </script>
<h1><%= Page.KnownSones.Page.Title|l10n|html></h1>
+
+ <div id="sort-options">
+ <form action="knownSones.html" method="get">
+ <div>
+ Sort:
+ <select name="sort">
+ <option value="name"<%if sort|match value="name"> selected="selected"<%/if>>Name</option>
+ <option value="activity"<%if sort|match value="activity"> selected="selected"<%/if>>Last activity</option>
+ </select>
+ <select name="order">
+ <option value="asc"<%if order|match value="asc"> selected="selected"<%/if>>Ascending</option>
+ <option value="desc"<%if order|match value="desc"> selected="selected"<%/if>>Descending</option>
+ </select>
+ </div>
+ <%ifnull !currentSone>
+ <div>
+ Followed Sones:
+ <select name="followedSones">
+ <option value="none"></option>
+ <option value="show-only"<%if followedSones|match value="show-only"> selected="selected"<%/if>>Show only followed Sones</option>
+ <option value="hide"<%if followedSones|match value="hide"> selected="selected"<%/if>>Hide followed Sones</option>
+ </select>
+ </div>
+ <%/if>
+ <div>
+ <button type="submit">Apply</button>
+ </div>
+ </form>
+ </div>
<div id="known-sones">
<%= page|store key=pageParameter>
getTranslation("WebInterface.DefaultText.Option.PostsPerPage", function(postsPerPageText) {
registerInputTextareaSwap("#sone #options input[name=posts-per-page]", postsPerPageText, "posts-per-page", true, true);
});
+ getTranslation("WebInterface.DefaultText.Option.CharactersPerPost", function(postsPerPageText) {
+ registerInputTextareaSwap("#sone #options input[name=characters-per-post]", postsPerPageText, "characters-per-post", true, true);
+ });
getTranslation("WebInterface.DefaultText.Option.PositiveTrust", function(positiveTrustText) {
registerInputTextareaSwap("#sone #options input[name=positive-trust]", positiveTrustText, "positive-trust", true, true);
});
<%/if>
<p><input type="text" name="posts-per-page" value="<% posts-per-page|html>" /></p>
+ <p><%= Page.Options.Option.CharactersPerPost.Description|l10n|html></p>
+ <%if =characters-per-post|in collection=fieldErrors>
+ <p class="warning"><%= Page.Options.Warnings.ValueNotChanged|l10n|html></p>
+ <%/if>
+ <p><input type="text" name="characters-per-post" value="<% characters-per-post|html>" /></p>
+
<p>
<input type="checkbox" name="require-full-access"<%if require-full-access> checked="checked"<%/if> />
<%= Page.Options.Option.RequireFullAccess.Description|l10n|html></p>