<modelVersion>4.0.0</modelVersion>
<groupId>net.pterodactylus</groupId>
<artifactId>sone</artifactId>
- <version>0.8.1</version>
+ <version>0.8.2</version>
<dependencies>
<dependency>
<groupId>net.pterodactylus</groupId>
<artifactId>utils</artifactId>
- <version>0.12-SNAPSHOT</version>
+ <version>0.12</version>
</dependency>
<dependency>
<groupId>junit</groupId>
import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
import net.pterodactylus.sone.data.Sone.SoneStatus;
import net.pterodactylus.sone.data.TemporaryImage;
+import net.pterodactylus.sone.data.impl.PostImpl;
import net.pterodactylus.sone.database.Database;
import net.pterodactylus.sone.fcp.FcpInterface;
import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired;
import net.pterodactylus.sone.freenet.wot.IdentityListener;
import net.pterodactylus.sone.freenet.wot.IdentityManager;
import net.pterodactylus.sone.freenet.wot.OwnIdentity;
-import net.pterodactylus.sone.freenet.wot.Trust;
-import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
import net.pterodactylus.sone.main.SonePlugin;
import net.pterodactylus.util.config.Configuration;
import net.pterodactylus.util.config.ConfigurationException;
/** The update checker. */
private final UpdateChecker updateChecker;
+ /** The trust updater. */
+ private final WebOfTrustUpdater webOfTrustUpdater;
+
/** The FCP interface. */
private volatile FcpInterface fcpInterface;
* The freenet interface
* @param identityManager
* The identity manager
+ * @param webOfTrustUpdater
+ * The WebOfTrust updater
*/
- public Core(Configuration configuration, Database database, FreenetInterface freenetInterface, IdentityManager identityManager) {
+ public Core(Configuration configuration, Database database, FreenetInterface freenetInterface, IdentityManager identityManager, WebOfTrustUpdater webOfTrustUpdater) {
super("Sone Core");
this.configuration = configuration;
this.database = database;
this.soneDownloader = new SoneDownloader(this, freenetInterface);
this.imageInserter = new ImageInserter(this, freenetInterface);
this.updateChecker = new UpdateChecker(freenetInterface);
+ this.webOfTrustUpdater = webOfTrustUpdater;
}
//
synchronized (posts) {
Post post = posts.get(postId);
if ((post == null) && create) {
- post = new Post(postId);
+ post = new PostImpl(postId);
posts.put(postId, post);
}
return post;
}
/**
-<<<<<<< HEAD
-=======
- * Adds a local Sone from the given ID which has to be the ID of an own
- * identity.
- *
- * @param id
- * The ID of an own identity to add a Sone for
- * @return The added (or already existing) Sone
- */
- public Sone addLocalSone(String id) {
- if (database.getLocalSone(id, false) != null) {
- logger.log(Level.FINE, "Tried to add known local Sone: %s", id);
- return database.getLocalSone(id, false);
- }
- OwnIdentity ownIdentity = identityManager.getOwnIdentity(id);
- if (ownIdentity == null) {
- logger.log(Level.INFO, "Invalid Sone ID: %s", id);
- return null;
- }
- return addLocalSone(ownIdentity);
- }
-
- /**
->>>>>>> 4f36598... Store locality of a Sone in the Sone itself, remove related methods from Database.
* Adds a local Sone from the given own identity.
*
* @param ownIdentity
* @return The created Sone
*/
public Sone createSone(OwnIdentity ownIdentity) {
- try {
- ownIdentity.addContext("Sone");
- } catch (WebOfTrustException wote1) {
- logger.log(Level.SEVERE, String.format("Could not add “Sone” context to own identity: %s", ownIdentity), wote1);
+ if (!webOfTrustUpdater.addContextWait(ownIdentity, "Sone")) {
+ logger.log(Level.SEVERE, String.format("Could not add “Sone” context to own identity: %s", ownIdentity));
return null;
}
Sone sone = addLocalSone(ownIdentity);
}
/**
- * Retrieves the trust relationship from the origin to the target. If the
- * trust relationship can not be retrieved, {@code null} is returned.
- *
- * @see Identity#getTrust(OwnIdentity)
- * @param origin
- * The origin of the trust tree
- * @param target
- * The target of the trust
- * @return The trust relationship
- */
- public Trust getTrust(Sone origin, Sone target) {
- if (!origin.isLocal()) {
- logger.log(Level.WARNING, String.format("Tried to get trust from remote Sone: %s", origin));
- return null;
- }
- return target.getIdentity().getTrust((OwnIdentity) origin.getIdentity());
- }
-
- /**
- * Sets the trust value of the given origin Sone for the target Sone.
+ * Sets the trust value of the given origin Sone for
+ * the target Sone.
*
* @param origin
* The origin Sone
*/
public void setTrust(Sone origin, Sone target, int trustValue) {
Validation.begin().isNotNull("Trust Origin", origin).check().isInstanceOf("Trust Origin", origin.getIdentity(), OwnIdentity.class).isNotNull("Trust Target", target).isLessOrEqual("Trust Value", trustValue, 100).isGreaterOrEqual("Trust Value", trustValue, -100).check();
- try {
- ((OwnIdentity) origin.getIdentity()).setTrust(target.getIdentity(), trustValue, preferences.getTrustComment());
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not set trust for Sone: %s", target), wote1);
- }
+ webOfTrustUpdater.setTrust((OwnIdentity) origin.getIdentity(), target.getIdentity(), trustValue, preferences.getTrustComment());
}
/**
*/
public void removeTrust(Sone origin, Sone target) {
Validation.begin().isNotNull("Trust Origin", origin).isNotNull("Trust Target", target).check().isInstanceOf("Trust Origin Identity", origin.getIdentity(), OwnIdentity.class).check();
- try {
- ((OwnIdentity) origin.getIdentity()).removeTrust(target.getIdentity());
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not remove trust for Sone: %s", target), wote1);
- }
+ webOfTrustUpdater.setTrust((OwnIdentity) origin.getIdentity(), target.getIdentity(), null, null);
}
/**
SoneInserter soneInserter = soneInserters.remove(sone);
soneInserter.removeSoneInsertListener(this);
soneInserter.stop();
- try {
- ((OwnIdentity) sone.getIdentity()).removeContext("Sone");
- ((OwnIdentity) sone.getIdentity()).removeProperty("Sone.LatestEdition");
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not remove context and properties from Sone: %s", sone), wote1);
- }
+ webOfTrustUpdater.removeContext((OwnIdentity) sone.getIdentity(), "Sone");
+ webOfTrustUpdater.removeProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition");
try {
configuration.getLongValue("Sone/" + sone.getId() + "/Time").setValue(null);
} catch (ConfigurationException ce1) {
logger.log(Level.FINE, String.format("Tried to create post for non-local Sone: %s", sone));
return null;
}
- final Post post = new Post(sone, time, text);
+ final Post post = new PostImpl(sone, time, text);
if (recipient != null) {
post.setRecipient(recipient);
}
synchronized (albums) {
albums.remove(album.getId());
}
- saveSone(album.getSone());
+ touchConfiguration();
}
/**
synchronized (images) {
images.remove(image.getId());
}
- saveSone(image.getSone());
+ touchConfiguration();
}
/**
loadConfiguration();
updateChecker.addUpdateListener(this);
updateChecker.start();
+ webOfTrustUpdater.start();
}
/**
*/
@Override
public void serviceStop() {
- for (SoneInserter soneInserter : soneInserters.values()) {
- soneInserter.removeSoneInsertListener(this);
- soneInserter.stop();
+ for (Entry<Sone, SoneInserter> soneInserter : soneInserters.entrySet()) {
+ soneInserter.getValue().removeSoneInsertListener(this);
+ soneInserter.getValue().stop();
+ saveSone(soneInserter.getKey());
}
+ saveConfiguration();
+ webOfTrustUpdater.stop();
updateChecker.stop();
updateChecker.removeUpdateListener(this);
soneDownloader.stop();
configuration.save();
- ((OwnIdentity) sone.getIdentity()).setProperty("Sone.LatestEdition", String.valueOf(sone.getLatestEdition()));
+ webOfTrustUpdater.setProperty((OwnIdentity) sone.getIdentity(), "Sone.LatestEdition", String.valueOf(sone.getLatestEdition()));
logger.log(Level.INFO, String.format("Sone %s saved.", sone));
} catch (ConfigurationException ce1) {
logger.log(Level.WARNING, String.format("Could not save Sone: %s", sone), ce1);
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, String.format("Could not set WoT property for Sone: %s", sone), wote1);
}
}
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/ImagesPerPage").setValue(options.getIntegerOption("ImagesPerPage").getReal());
configuration.getIntValue("Option/CharactersPerPost").setValue(options.getIntegerOption("CharactersPerPost").getReal());
configuration.getIntValue("Option/PostCutOffLength").setValue(options.getIntegerOption("PostCutOffLength").getReal());
configuration.getBooleanValue("Option/RequireFullAccess").setValue(options.getBooleanOption("RequireFullAccess").getReal());
configuration.getStringValue("Option/TrustComment").setValue(options.getStringOption("TrustComment").getReal());
configuration.getBooleanValue("Option/ActivateFcpInterface").setValue(options.getBooleanOption("ActivateFcpInterface").getReal());
configuration.getIntValue("Option/FcpFullAccessRequired").setValue(options.getIntegerOption("FcpFullAccessRequired").getReal());
- configuration.getBooleanValue("Option/SoneRescueMode").setValue(options.getBooleanOption("SoneRescueMode").getReal());
- configuration.getBooleanValue("Option/ClearOnNextRestart").setValue(options.getBooleanOption("ClearOnNextRestart").getReal());
- configuration.getBooleanValue("Option/ReallyClearOnNextRestart").setValue(options.getBooleanOption("ReallyClearOnNextRestart").getReal());
/* save known Sones. */
int soneCounter = 0;
}));
options.addIntegerOption("PostsPerPage", new DefaultOption<Integer>(10, new IntegerRangeValidator(1, Integer.MAX_VALUE)));
+ options.addIntegerOption("ImagesPerPage", new DefaultOption<Integer>(9, new IntegerRangeValidator(1, Integer.MAX_VALUE)));
options.addIntegerOption("CharactersPerPost", new DefaultOption<Integer>(400, new OrValidator<Integer>(new IntegerRangeValidator(50, Integer.MAX_VALUE), new EqualityValidator<Integer>(-1))));
options.addIntegerOption("PostCutOffLength", 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.addBooleanOption("SoneRescueMode", new DefaultOption<Boolean>(false));
- options.addBooleanOption("ClearOnNextRestart", new DefaultOption<Boolean>(false));
- options.addBooleanOption("ReallyClearOnNextRestart", new DefaultOption<Boolean>(false));
-
- /* read options from configuration. */
- options.getBooleanOption("ClearOnNextRestart").set(configuration.getBooleanValue("Option/ClearOnNextRestart").getValue(null));
- options.getBooleanOption("ReallyClearOnNextRestart").set(configuration.getBooleanValue("Option/ReallyClearOnNextRestart").getValue(null));
- boolean clearConfiguration = options.getBooleanOption("ClearOnNextRestart").get() && options.getBooleanOption("ReallyClearOnNextRestart").get();
- options.getBooleanOption("ClearOnNextRestart").set(null);
- options.getBooleanOption("ReallyClearOnNextRestart").set(null);
- if (clearConfiguration) {
- /* stop loading the configuration. */
- return;
- }
loadConfigurationValue("InsertionDelay");
loadConfigurationValue("PostsPerPage");
+ loadConfigurationValue("ImagesPerPage");
loadConfigurationValue("CharactersPerPost");
loadConfigurationValue("PostCutOffLength");
options.getBooleanOption("RequireFullAccess").set(configuration.getBooleanValue("Option/RequireFullAccess").getValue(null));
options.getStringOption("TrustComment").set(configuration.getStringValue("Option/TrustComment").getValue(null));
options.getBooleanOption("ActivateFcpInterface").set(configuration.getBooleanValue("Option/ActivateFcpInterface").getValue(null));
options.getIntegerOption("FcpFullAccessRequired").set(configuration.getIntValue("Option/FcpFullAccessRequired").getValue(null));
- options.getBooleanOption("SoneRescueMode").set(configuration.getBooleanValue("Option/SoneRescueMode").getValue(null));
/* load known Sones. */
int soneCounter = 0;
* The URI to derive the Sone URI from
* @return The derived URI
*/
- private FreenetURI getSoneUri(String uriString) {
+ private static FreenetURI getSoneUri(String uriString) {
try {
FreenetURI uri = new FreenetURI(uriString).setDocName("Sone").setMetaString(new String[0]);
return uri;
} catch (MalformedURLException mue1) {
- logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString, mue1));
+ logger.log(Level.WARNING, String.format("Could not create Sone URI from URI: %s", uriString), mue1);
return null;
}
}
logger.log(Level.WARNING, String.format("Image insert finished for %s: %s", image, key));
image.setKey(key.toString());
deleteTemporaryImage(image.getId());
- saveSone(image.getSone());
+ touchConfiguration();
coreListenerManager.fireImageInsertFinished(image);
}
}
/**
+ * Returns the number of images to show per page.
+ *
+ * @return The number of images to show per page
+ */
+ public int getImagesPerPage() {
+ return options.getIntegerOption("ImagesPerPage").get();
+ }
+
+ /**
+ * Validates the number of images per page.
+ *
+ * @param imagesPerPage
+ * The number of images per page
+ * @return {@code true} if the number of images per page was valid,
+ * {@code false} otherwise
+ */
+ public boolean validateImagesPerPage(Integer imagesPerPage) {
+ return options.getIntegerOption("ImagesPerPage").validate(imagesPerPage);
+ }
+
+ /**
+ * Sets the number of images per page.
+ *
+ * @param imagesPerPage
+ * The number of images per page
+ * @return This preferences object
+ */
+ public Preferences setImagesPerPage(Integer imagesPerPage) {
+ options.getIntegerOption("ImagesPerPage").set(imagesPerPage);
+ return this;
+ }
+
+ /**
* Returns the number of characters per post, or <code>-1</code> if the
* posts should not be cut off.
*
return this;
}
- /**
- * Returns whether Sone should clear its settings on the next restart.
- * In order to be effective, {@link #isReallyClearOnNextRestart()} needs
- * to return {@code true} as well!
- *
- * @return {@code true} if Sone should clear its settings on the next
- * restart, {@code false} otherwise
- */
- public boolean isClearOnNextRestart() {
- return options.getBooleanOption("ClearOnNextRestart").get();
- }
-
- /**
- * Sets whether Sone will clear its settings on the next restart.
- *
- * @param clearOnNextRestart
- * {@code true} if Sone should clear its settings on the next
- * restart, {@code false} otherwise
- * @return This preferences
- */
- public Preferences setClearOnNextRestart(Boolean clearOnNextRestart) {
- options.getBooleanOption("ClearOnNextRestart").set(clearOnNextRestart);
- return this;
- }
-
- /**
- * Returns whether Sone should really clear its settings on next
- * restart. This is a confirmation option that needs to be set in
- * addition to {@link #isClearOnNextRestart()} in order to clear Sone’s
- * settings on the next restart.
- *
- * @return {@code true} if Sone should really clear its settings on the
- * next restart, {@code false} otherwise
- */
- public boolean isReallyClearOnNextRestart() {
- return options.getBooleanOption("ReallyClearOnNextRestart").get();
- }
-
- /**
- * Sets whether Sone should really clear its settings on the next
- * restart.
- *
- * @param reallyClearOnNextRestart
- * {@code true} if Sone should really clear its settings on
- * the next restart, {@code false} otherwise
- * @return This preferences
- */
- public Preferences setReallyClearOnNextRestart(Boolean reallyClearOnNextRestart) {
- options.getBooleanOption("ReallyClearOnNextRestart").set(reallyClearOnNextRestart);
- return this;
- }
-
}
}
/**
* Adds an {@link Enum} {@link Option}.
*
+ * @param <T>
+ * The enum type
* @param name
* The name of the option
* @param enumOption
* options.<SomeEnum> getEnumOption("SomeEnumOption").get();
* </pre>
*
+ * @param <T>
+ * The enum type
* @param name
* The name of the option
* @return The enum option, or {@code null} if there is no enum option with
--- /dev/null
+/*
+ * Sone - WebOfTrustUpdater.java - Copyright © 2012 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.core;
+
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import net.pterodactylus.sone.freenet.plugin.PluginException;
+import net.pterodactylus.sone.freenet.wot.DefaultIdentity;
+import net.pterodactylus.sone.freenet.wot.Identity;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
+import net.pterodactylus.sone.freenet.wot.Trust;
+import net.pterodactylus.sone.freenet.wot.WebOfTrustConnector;
+import net.pterodactylus.sone.freenet.wot.WebOfTrustException;
+import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.service.AbstractService;
+import net.pterodactylus.util.validation.Validation;
+
+/**
+ * Updates WebOfTrust identity data in a background thread because communicating
+ * with the WebOfTrust plugin can potentially last quite long.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class WebOfTrustUpdater extends AbstractService {
+
+ /** The logger. */
+ private static final Logger logger = Logging.getLogger(WebOfTrustUpdater.class);
+
+ /** Stop job. */
+ @SuppressWarnings("synthetic-access")
+ private final WebOfTrustUpdateJob stopJob = new WebOfTrustUpdateJob();
+
+ /** The web of trust connector. */
+ private final WebOfTrustConnector webOfTrustConnector;
+
+ /** The queue for jobs. */
+ private final BlockingQueue<WebOfTrustUpdateJob> updateJobs = new LinkedBlockingQueue<WebOfTrustUpdateJob>();
+
+ /**
+ * Creates a new trust updater.
+ *
+ * @param webOfTrustConnector
+ * The web of trust connector
+ */
+ public WebOfTrustUpdater(WebOfTrustConnector webOfTrustConnector) {
+ super("Trust Updater");
+ this.webOfTrustConnector = webOfTrustConnector;
+ }
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Updates the trust relation between the truster and the trustee. This
+ * method will return immediately and perform a trust update in the
+ * background.
+ *
+ * @param truster
+ * The identity giving the trust
+ * @param trustee
+ * The identity receiving the trust
+ * @param score
+ * The new level of trust (from -100 to 100, may be {@code null}
+ * to remove the trust completely)
+ * @param comment
+ * The comment of the trust relation
+ */
+ public void setTrust(OwnIdentity truster, Identity trustee, Integer score, String comment) {
+ SetTrustJob setTrustJob = new SetTrustJob(truster, trustee, score, comment);
+ if (updateJobs.contains(setTrustJob)) {
+ updateJobs.remove(setTrustJob);
+ }
+ logger.log(Level.FINER, "Adding Trust Update Job: " + setTrustJob);
+ try {
+ updateJobs.put(setTrustJob);
+ } catch (InterruptedException e) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+
+ /**
+ * Adds the given context to the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to add the context to
+ * @param context
+ * The context to add
+ */
+ public void addContext(OwnIdentity ownIdentity, String context) {
+ addContextWait(ownIdentity, context, false);
+ }
+
+ /**
+ * Adds the given context to the given own identity, waiting for completion
+ * of the operation.
+ *
+ * @param ownIdentity
+ * The own identity to add the context to
+ * @param context
+ * The context to add
+ * @return {@code true} if the context was added successfully, {@code false}
+ * otherwise
+ */
+ public boolean addContextWait(OwnIdentity ownIdentity, String context) {
+ return addContextWait(ownIdentity, context, true);
+ }
+
+ /**
+ * Adds the given context to the given own identity, waiting for completion
+ * of the operation.
+ *
+ * @param ownIdentity
+ * The own identity to add the context to
+ * @param context
+ * The context to add
+ * @param wait
+ * {@code true} to wait for the end of the operation,
+ * {@code false} to return immediately
+ * @return {@code true} if the context was added successfully, {@code false}
+ * if the context was not added successfully, or if the job should
+ * not wait for completion
+ */
+ private boolean addContextWait(OwnIdentity ownIdentity, String context, boolean wait) {
+ AddContextJob addContextJob = new AddContextJob(ownIdentity, context);
+ if (!updateJobs.contains(addContextJob)) {
+ logger.log(Level.FINER, "Adding Context Job: " + addContextJob);
+ try {
+ updateJobs.put(addContextJob);
+ } catch (InterruptedException ie1) {
+ /* the queue is unbounded so it should never block. */
+ }
+ if (wait) {
+ return addContextJob.waitForCompletion();
+ }
+ } else if (wait) {
+ for (WebOfTrustUpdateJob updateJob : updateJobs) {
+ if (updateJob.equals(addContextJob)) {
+ return updateJob.waitForCompletion();
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Removes the given context from the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to remove the context from
+ * @param context
+ * The context to remove
+ */
+ public void removeContext(OwnIdentity ownIdentity, String context) {
+ RemoveContextJob removeContextJob = new RemoveContextJob(ownIdentity, context);
+ if (!updateJobs.contains(removeContextJob)) {
+ logger.log(Level.FINER, "Adding Context Job: " + removeContextJob);
+ try {
+ updateJobs.put(removeContextJob);
+ } catch (InterruptedException ie1) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+ }
+
+ /**
+ * Sets a property on the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to set the property on
+ * @param propertyName
+ * The name of the property to set
+ * @param propertyValue
+ * The value of the property to set
+ */
+ public void setProperty(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
+ SetPropertyJob setPropertyJob = new SetPropertyJob(ownIdentity, propertyName, propertyValue);
+ if (updateJobs.contains(setPropertyJob)) {
+ updateJobs.remove(setPropertyJob);
+ }
+ logger.log(Level.FINER, "Adding Property Job: " + setPropertyJob);
+ try {
+ updateJobs.put(setPropertyJob);
+ } catch (InterruptedException e) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+
+ /**
+ * Removes a property from the given own identity.
+ *
+ * @param ownIdentity
+ * The own identity to remove the property from
+ * @param propertyName
+ * The name of the property to remove
+ */
+ public void removeProperty(OwnIdentity ownIdentity, String propertyName) {
+ setProperty(ownIdentity, propertyName, null);
+ }
+
+ //
+ // SERVICE METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void serviceRun() {
+ while (!shouldStop()) {
+ try {
+ WebOfTrustUpdateJob updateJob = updateJobs.take();
+ if (shouldStop() || (updateJob == stopJob)) {
+ break;
+ }
+ logger.log(Level.FINE, "Running Trust Update Job: " + updateJob);
+ long startTime = System.currentTimeMillis();
+ updateJob.run();
+ long endTime = System.currentTimeMillis();
+ logger.log(Level.FINE, "Trust Update Job finished, took " + (endTime - startTime) + " ms.");
+ } catch (InterruptedException ie1) {
+ /* happens, ignore, loop. */
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void serviceStop() {
+ try {
+ updateJobs.put(stopJob);
+ } catch (InterruptedException ie1) {
+ /* the queue is unbounded so it should never block. */
+ }
+ }
+
+ /**
+ * Base class for WebOfTrust update jobs.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustUpdateJob {
+
+ /** Object for synchronization. */
+ @SuppressWarnings("hiding")
+ private final Object syncObject = new Object();
+
+ /** Whether the job has finished. */
+ private boolean finished;
+
+ /** Whether the job was successful. */
+ private boolean success;
+
+ //
+ // ACTIONS
+ //
+
+ /**
+ * Performs the actual update operation.
+ * <p>
+ * The implementation of this class does nothing.
+ */
+ public void run() {
+ /* does nothing. */
+ }
+
+ /**
+ * Waits for completion of this job or stopping of the WebOfTrust
+ * updater.
+ *
+ * @return {@code true} if this job finished successfully, {@code false}
+ * otherwise
+ *
+ * @see WebOfTrustUpdater#stop()
+ */
+ @SuppressWarnings("synthetic-access")
+ public boolean waitForCompletion() {
+ synchronized (syncObject) {
+ while (!finished && !shouldStop()) {
+ try {
+ syncObject.wait();
+ } catch (InterruptedException ie1) {
+ /* we’re looping, ignore. */
+ }
+ }
+ return success;
+ }
+ }
+
+ //
+ // PROTECTED METHODS
+ //
+
+ /**
+ * Signals that this job has finished.
+ *
+ * @param success
+ * {@code true} if this job finished successfully,
+ * {@code false} otherwise
+ */
+ protected void finish(boolean success) {
+ synchronized (syncObject) {
+ finished = true;
+ this.success = success;
+ syncObject.notifyAll();
+ }
+ }
+
+ }
+
+ /**
+ * Base class for WebOfTrust trust update jobs.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustTrustUpdateJob extends WebOfTrustUpdateJob {
+
+ /** The identity giving the trust. */
+ protected final OwnIdentity truster;
+
+ /** The identity receiving the trust. */
+ protected final Identity trustee;
+
+ /**
+ * Creates a new trust update job.
+ *
+ * @param truster
+ * The identity giving the trust
+ * @param trustee
+ * The identity receiving the trust
+ */
+ @SuppressWarnings("synthetic-access")
+ public WebOfTrustTrustUpdateJob(OwnIdentity truster, Identity trustee) {
+ this.truster = truster;
+ this.trustee = trustee;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if ((object == null) || !object.getClass().equals(getClass())) {
+ return false;
+ }
+ WebOfTrustTrustUpdateJob updateJob = (WebOfTrustTrustUpdateJob) object;
+ return ((truster == null) ? (updateJob.truster == null) : updateJob.truster.equals(truster)) && ((trustee == null) ? (updateJob.trustee == null) : updateJob.trustee.equals(trustee));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return getClass().hashCode() ^ ((truster == null) ? 0 : truster.hashCode()) ^ ((trustee == null) ? 0 : trustee.hashCode());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[truster=%s,trustee=%s]", getClass().getSimpleName(), (truster == null) ? null : truster.getId(), (trustee == null) ? null : trustee.getId());
+ }
+
+ }
+
+ /**
+ * Update job that sets the trust relation between two identities.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class SetTrustJob extends WebOfTrustTrustUpdateJob {
+
+ /** The score of the relation. */
+ private final Integer score;
+
+ /** The comment of the relation. */
+ private final String comment;
+
+ /**
+ * Creates a new set trust job.
+ *
+ * @param truster
+ * The identity giving the trust
+ * @param trustee
+ * The identity receiving the trust
+ * @param score
+ * The score of the trust (from -100 to 100, may be
+ * {@code null} to remote the trust relation completely)
+ * @param comment
+ * The comment of the trust relation
+ */
+ public SetTrustJob(OwnIdentity truster, Identity trustee, Integer score, String comment) {
+ super(truster, trustee);
+ this.score = score;
+ this.comment = comment;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ if (score != null) {
+ if (trustee instanceof DefaultIdentity) {
+ ((DefaultIdentity) trustee).setTrust(truster, new Trust(score, null, 0));
+ }
+ webOfTrustConnector.setTrust(truster, trustee, score, comment);
+ } else {
+ if (trustee instanceof DefaultIdentity) {
+ ((DefaultIdentity) trustee).setTrust(truster, null);
+ }
+ webOfTrustConnector.removeTrust(truster, trustee);
+ }
+ finish(true);
+ } catch (WebOfTrustException wote1) {
+ logger.log(Level.WARNING, "Could not set Trust value for " + truster + " -> " + trustee + " to " + score + " (" + comment + ")!", wote1);
+ finish(false);
+ }
+ }
+
+ }
+
+ /**
+ * Base class for context updates of an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustContextUpdateJob extends WebOfTrustUpdateJob {
+
+ /** The own identity whose contexts to manage. */
+ protected final OwnIdentity ownIdentity;
+
+ /** The context to update. */
+ protected final String context;
+
+ /**
+ * Creates a new context update job.
+ *
+ * @param ownIdentity
+ * The own identity to update
+ * @param context
+ * The context to update
+ */
+ @SuppressWarnings("synthetic-access")
+ public WebOfTrustContextUpdateJob(OwnIdentity ownIdentity, String context) {
+ Validation.begin().isNotNull("OwnIdentity", ownIdentity).isNotNull("Context", context).check();
+ this.ownIdentity = ownIdentity;
+ this.context = context;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if ((object == null) || !object.getClass().equals(getClass())) {
+ return false;
+ }
+ WebOfTrustContextUpdateJob updateJob = (WebOfTrustContextUpdateJob) object;
+ return updateJob.ownIdentity.equals(ownIdentity) && updateJob.context.equals(context);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return getClass().hashCode() ^ ownIdentity.hashCode() ^ context.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[ownIdentity=%s,context=%s]", getClass().getSimpleName(), ownIdentity, context);
+ }
+
+ }
+
+ /**
+ * Job that adds a context to an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class AddContextJob extends WebOfTrustContextUpdateJob {
+
+ /**
+ * Creates a new add-context job.
+ *
+ * @param ownIdentity
+ * The own identity whose contexts to manage
+ * @param context
+ * The context to add
+ */
+ public AddContextJob(OwnIdentity ownIdentity, String context) {
+ super(ownIdentity, context);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ webOfTrustConnector.addContext(ownIdentity, context);
+ ownIdentity.addContext(context);
+ finish(true);
+ } catch (PluginException pe1) {
+ logger.log(Level.WARNING, String.format("Could not add Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);
+ finish(false);
+ }
+ }
+
+ }
+
+ /**
+ * Job that removes a context from an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class RemoveContextJob extends WebOfTrustContextUpdateJob {
+
+ /**
+ * Creates a new remove-context job.
+ *
+ * @param ownIdentity
+ * The own identity whose contexts to manage
+ * @param context
+ * The context to remove
+ */
+ public RemoveContextJob(OwnIdentity ownIdentity, String context) {
+ super(ownIdentity, context);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ webOfTrustConnector.removeContext(ownIdentity, context);
+ ownIdentity.removeContext(context);
+ finish(true);
+ } catch (PluginException pe1) {
+ logger.log(Level.WARNING, String.format("Could not remove Context “%2$s” to Own Identity %1$s!", ownIdentity, context), pe1);
+ finish(false);
+ }
+ }
+
+ }
+
+ /**
+ * Base class for update jobs that deal with properties.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class WebOfTrustPropertyUpdateJob extends WebOfTrustUpdateJob {
+
+ /** The own identity to update properties on. */
+ protected final OwnIdentity ownIdentity;
+
+ /** The name of the property to update. */
+ protected final String propertyName;
+
+ /**
+ * Creates a new property update job.
+ *
+ * @param ownIdentity
+ * The own identity to update the property on
+ * @param propertyName
+ * The name of the property to update
+ */
+ @SuppressWarnings("synthetic-access")
+ public WebOfTrustPropertyUpdateJob(OwnIdentity ownIdentity, String propertyName) {
+ this.ownIdentity = ownIdentity;
+ this.propertyName = propertyName;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if ((object == null) || !object.getClass().equals(getClass())) {
+ return false;
+ }
+ WebOfTrustPropertyUpdateJob updateJob = (WebOfTrustPropertyUpdateJob) object;
+ return updateJob.ownIdentity.equals(ownIdentity) && updateJob.propertyName.equals(propertyName);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return getClass().hashCode() ^ ownIdentity.hashCode() ^ propertyName.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return String.format("%s[ownIdentity=%s,propertyName=%s]", getClass().getSimpleName(), ownIdentity, propertyName);
+ }
+
+ }
+
+ /**
+ * WebOfTrust update job that sets a property on an {@link OwnIdentity}.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+ private class SetPropertyJob extends WebOfTrustPropertyUpdateJob {
+
+ /** The value of the property to set. */
+ private final String propertyValue;
+
+ /**
+ * Creates a new set-property job.
+ *
+ * @param ownIdentity
+ * The own identity to set the property on
+ * @param propertyName
+ * The name of the property to set
+ * @param propertyValue
+ * The value of the property to set
+ */
+ public SetPropertyJob(OwnIdentity ownIdentity, String propertyName, String propertyValue) {
+ super(ownIdentity, propertyName);
+ this.propertyValue = propertyValue;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void run() {
+ try {
+ if (propertyValue == null) {
+ webOfTrustConnector.removeProperty(ownIdentity, propertyName);
+ ownIdentity.removeProperty(propertyName);
+ } else {
+ webOfTrustConnector.setProperty(ownIdentity, propertyName, propertyValue);
+ ownIdentity.setProperty(propertyName, propertyValue);
+ }
+ finish(true);
+ } catch (PluginException pe1) {
+ logger.log(Level.WARNING, String.format("Could not set Property “%2$s” to “%3$s” on Own Identity %1$s!", ownIdentity, propertyName, propertyValue), pe1);
+ finish(false);
+ }
+ }
+
+ }
+
+}
package net.pterodactylus.sone.data;
import java.util.Comparator;
-import java.util.UUID;
import net.pterodactylus.util.collection.filter.Filter;
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class Post {
+public interface Post {
/** Comparator for posts, sorts descending by time. */
public static final Comparator<Post> TIME_COMPARATOR = new Comparator<Post>() {
};
- /** The GUID of the post. */
- private final UUID id;
-
- /** The Sone this post belongs to. */
- private volatile Sone sone;
-
- /** The Sone of the recipient. */
- private volatile Sone recipient;
-
- /** The time of the post (in milliseconds since Jan 1, 1970 UTC). */
- private volatile long time;
-
- /** The text of the post. */
- private volatile String text;
-
- /** Whether the post is known. */
- private volatile boolean known;
-
- /**
- * Creates a new post.
- *
- * @param id
- * The ID of the post
- */
- public Post(String id) {
- this(id, null, 0, null);
- }
-
- /**
- * Creates a new post.
- *
- * @param sone
- * The Sone this post belongs to
- * @param text
- * The text of the post
- */
- public Post(Sone sone, String text) {
- this(sone, System.currentTimeMillis(), text);
- }
-
- /**
- * Creates a new post.
- *
- * @param sone
- * The Sone this post belongs to
- * @param time
- * The time of the post (in milliseconds since Jan 1, 1970 UTC)
- * @param text
- * The text of the post
- */
- public Post(Sone sone, long time, String text) {
- this(UUID.randomUUID().toString(), sone, time, text);
- }
-
- /**
- * Creates a new post.
- *
- * @param id
- * The ID of the post
- * @param sone
- * The Sone this post belongs to
- * @param time
- * The time of the post (in milliseconds since Jan 1, 1970 UTC)
- * @param text
- * The text of the post
- */
- public Post(String id, Sone sone, long time, String text) {
- this.id = UUID.fromString(id);
- this.sone = sone;
- this.time = time;
- this.text = text;
- }
-
//
// ACCESSORS
//
*
* @return The ID of the post
*/
- public String getId() {
- return id.toString();
- }
+ public String getId();
/**
* Returns the Sone this post belongs to.
*
* @return The Sone of this post
*/
- public Sone getSone() {
- return sone;
- }
+ public Sone getSone();
/**
* Sets the Sone of this post.
* The Sone of this post
* @return This post (for method chaining)
*/
- public Post setSone(Sone sone) {
- this.sone = sone;
- return this;
- }
+ public Post setSone(Sone sone);
/**
* Returns the recipient of this post, if any.
*
* @return The recipient of this post, or {@code null}
*/
- public Sone getRecipient() {
- return recipient;
- }
+ public Sone getRecipient();
/**
* Sets the recipient of this post.
* The recipient of this post, or {@code null}
* @return This post (for method chaining)
*/
- public Post setRecipient(Sone recipient) {
- if (!sone.equals(recipient)) {
- this.recipient = recipient;
- }
- return this;
- }
+ public Post setRecipient(Sone recipient);
/**
* Returns the time of the post.
*
* @return The time of the post (in milliseconds since Jan 1, 1970 UTC)
*/
- public long getTime() {
- return time;
- }
+ public long getTime();
/**
* Sets the time of this post.
* The time of this post (in milliseconds since Jan 1, 1970 UTC)
* @return This post (for method chaining)
*/
- public Post setTime(long time) {
- this.time = time;
- return this;
- }
+ public Post setTime(long time);
/**
* Returns the text of the post.
*
* @return The text of the post
*/
- public String getText() {
- return text;
- }
+ public String getText();
/**
* Sets the text of this post.
* The text of this post
* @return This post (for method chaining)
*/
- public Post setText(String text) {
- this.text = text;
- return this;
- }
+ public Post setText(String text);
/**
* Returns whether this post is known.
*
* @return {@code true} if this post is known, {@code false} otherwise
*/
- public boolean isKnown() {
- return known;
- }
+ public boolean isKnown();
/**
* Sets whether this post is known.
* {@code true} if this post is known, {@code false} otherwise
* @return This post
*/
- public Post setKnown(boolean known) {
- this.known = known;
- return this;
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- return id.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- if (!(object instanceof Post)) {
- return false;
- }
- Post post = (Post) object;
- return post.id.equals(id);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public String toString() {
- return getClass().getName() + "[id=" + id + ",sone=" + sone + ",time=" + time + ",text=" + text + "]";
- }
+ public Post setKnown(boolean known);
}
--- /dev/null
+/*
+ * Sone - PostImpl.java - Copyright © 2010–2012 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.data.impl;
+
+import java.util.UUID;
+
+import net.pterodactylus.sone.data.Post;
+import net.pterodactylus.sone.data.Sone;
+
+/**
+ * A post is a short message that a user writes in his Sone to let other users
+ * know what is going on.
+ *
+ * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
+ */
+public class PostImpl implements Post {
+
+ /** The GUID of the post. */
+ private final UUID id;
+
+ /** The Sone this post belongs to. */
+ private volatile Sone sone;
+
+ /** The Sone of the recipient. */
+ private volatile Sone recipient;
+
+ /** The time of the post (in milliseconds since Jan 1, 1970 UTC). */
+ private volatile long time;
+
+ /** The text of the post. */
+ private volatile String text;
+
+ /** Whether the post is known. */
+ private volatile boolean known;
+
+ /**
+ * Creates a new post.
+ *
+ * @param id
+ * The ID of the post
+ */
+ public PostImpl(String id) {
+ this(id, null, 0, null);
+ }
+
+ /**
+ * Creates a new post.
+ *
+ * @param sone
+ * The Sone this post belongs to
+ * @param text
+ * The text of the post
+ */
+ public PostImpl(Sone sone, String text) {
+ this(sone, System.currentTimeMillis(), text);
+ }
+
+ /**
+ * Creates a new post.
+ *
+ * @param sone
+ * The Sone this post belongs to
+ * @param time
+ * The time of the post (in milliseconds since Jan 1, 1970 UTC)
+ * @param text
+ * The text of the post
+ */
+ public PostImpl(Sone sone, long time, String text) {
+ this(UUID.randomUUID().toString(), sone, time, text);
+ }
+
+ /**
+ * Creates a new post.
+ *
+ * @param id
+ * The ID of the post
+ * @param sone
+ * The Sone this post belongs to
+ * @param time
+ * The time of the post (in milliseconds since Jan 1, 1970 UTC)
+ * @param text
+ * The text of the post
+ */
+ public PostImpl(String id, Sone sone, long time, String text) {
+ this.id = UUID.fromString(id);
+ this.sone = sone;
+ this.time = time;
+ this.text = text;
+ }
+
+ //
+ // ACCESSORS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getId() {
+ return id.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone getSone() {
+ return sone;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostImpl setSone(Sone sone) {
+ this.sone = sone;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Sone getRecipient() {
+ return recipient;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostImpl setRecipient(Sone recipient) {
+ if (!sone.equals(recipient)) {
+ this.recipient = recipient;
+ }
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public long getTime() {
+ return time;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostImpl setTime(long time) {
+ this.time = time;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ return text;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostImpl setText(String text) {
+ this.text = text;
+ return this;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isKnown() {
+ return known;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PostImpl setKnown(boolean known) {
+ this.known = known;
+ return this;
+ }
+
+ //
+ // OBJECT METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof PostImpl)) {
+ return false;
+ }
+ PostImpl post = (PostImpl) object;
+ return post.id.equals(id);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String toString() {
+ return getClass().getName() + "[id=" + id + ",sone=" + sone + ",time=" + time + ",text=" + text + "]";
+ }
+
+}
@Override
public void addAlbum(Album album) {
Validation.begin().isNotNull("Album", album).check().isEqual("Album Owner", album.getSone(), this).check();
- albums.add(album);
+ if (!albums.contains(album)) {
+ albums.add(album);
+ }
}
/**
* The text to encode
* @return The encoded text
*/
- protected String encodeString(String text) {
+ protected static String encodeString(String text) {
return text.replaceAll("\\\\", "\\\\").replaceAll("\n", "\\\\n").replaceAll("\r", "\\\\r");
}
* such as if the Sone is followed by the local Sone
* @return The simple field set containing the given Sone
*/
- protected SimpleFieldSet encodeSone(Sone sone, String prefix, Sone localSone) {
+ protected static SimpleFieldSet encodeSone(Sone sone, String prefix, Sone localSone) {
SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder();
soneBuilder.put(prefix + "Name", sone.getName());
* {@code null})
* @return The simple field set containing the given Sones
*/
- protected SimpleFieldSet encodeSones(Collection<? extends Sone> sones, String prefix) {
+ protected static SimpleFieldSet encodeSones(Collection<? extends Sone> sones, String prefix) {
SimpleFieldSetBuilder soneBuilder = new SimpleFieldSetBuilder();
int soneIndex = 0;
* {@code null})
* @return The simple field set containing the replies
*/
- protected SimpleFieldSet encodeReplies(Collection<? extends PostReply> replies, String prefix) {
+ protected static SimpleFieldSet encodeReplies(Collection<? extends PostReply> replies, String prefix) {
SimpleFieldSetBuilder replyBuilder = new SimpleFieldSetBuilder();
int replyIndex = 0;
* {@code null})
* @return The simple field set containing the likes
*/
- protected SimpleFieldSet encodeLikes(Collection<? extends Sone> likes, String prefix) {
+ protected static SimpleFieldSet encodeLikes(Collection<? extends Sone> likes, String prefix) {
SimpleFieldSetBuilder likesBuilder = new SimpleFieldSetBuilder();
int likeIndex = 0;
* @throws PluginNotFoundException
* if the plugin can not be found
*/
- private void sendReply(PluginReplySender pluginReplySender, String identifier, Response response) throws PluginNotFoundException {
+ private static void sendReply(PluginReplySender pluginReplySender, String identifier, Response response) throws PluginNotFoundException {
SimpleFieldSet replyParameters = response.getReplyParameters();
if (identifier != null) {
replyParameters.putOverwrite("Identifier", identifier);
* {@inheritDoc}
*/
@Override
- public String format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public String format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
if (parameters.isEmpty()) {
return webInterface.getL10n().getString(String.valueOf(data));
}
int parameterIndex = 0;
while (parameters.containsKey(String.valueOf(parameterIndex))) {
Object value = parameters.get(String.valueOf(parameterIndex));
- if (((String) value).startsWith("=")) {
- value = ((String) value).substring(1);
- } else {
- value = templateContext.get((String) value);
- }
parameterValues.add(value);
++parameterIndex;
}
* if there is no value for the given key in the simple field
* set, or the value can not be converted to a String
*/
- protected String getString(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
+ protected static String getString(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
try {
return simpleFieldSet.getString(key);
} catch (FSParseException fspe1) {
* if there is no value for the given key in the simple field
* set, or the value can not be converted to an int
*/
- protected int getInt(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
+ protected static int getInt(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
try {
return simpleFieldSet.getInt(key);
} catch (FSParseException fspe1) {
* The default value
* @return The int value
*/
- protected int getInt(SimpleFieldSet simpleFieldSet, String key, int defaultValue) {
+ protected static int getInt(SimpleFieldSet simpleFieldSet, String key, int defaultValue) {
return simpleFieldSet.getInt(key, defaultValue);
}
* if there is no value for the given key in the simple field
* set, or the value can not be converted to a boolean
*/
- protected boolean getBoolean(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
+ protected static boolean getBoolean(SimpleFieldSet simpleFieldSet, String key) throws FcpException {
try {
return simpleFieldSet.getBoolean(key);
} catch (FSParseException fspe1) {
* The default value
* @return The boolean value
*/
- protected boolean getBoolean(SimpleFieldSet simpleFieldSet, String key, boolean defaultValue) {
+ protected static boolean getBoolean(SimpleFieldSet simpleFieldSet, String key, boolean defaultValue) {
return simpleFieldSet.getBoolean(key, defaultValue);
}
package net.pterodactylus.sone.freenet.wot;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-
-import net.pterodactylus.sone.freenet.plugin.PluginException;
-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.cache.WritableCache;
-import net.pterodactylus.util.collection.TimedMap;
-import net.pterodactylus.util.logging.Logging;
/**
* A Web of Trust identity.
*/
public class DefaultIdentity implements Identity {
- /** The logger. */
- private static final Logger logger = Logging.getLogger(DefaultIdentity.class);
-
- /** The web of trust connector. */
- private final WebOfTrustConnector webOfTrustConnector;
-
/** The ID of the identity. */
private final String id;
private final Map<String, String> properties = Collections.synchronizedMap(new HashMap<String, String>());
/** Cached trust. */
- /* synchronize on itself. */
- private final WritableCache<OwnIdentity, Trust> trustCache = new MemoryCache<OwnIdentity, Trust>(new ValueRetriever<OwnIdentity, Trust>() {
-
- @Override
- @SuppressWarnings("synthetic-access")
- public CacheItem<Trust> retrieve(OwnIdentity ownIdentity) throws CacheException {
- try {
- return new DefaultCacheItem<Trust>(webOfTrustConnector.getTrust(ownIdentity, DefaultIdentity.this));
- } catch (PluginException pe1) {
- throw new CacheException("Could not retrieve trust for OwnIdentity: " + ownIdentity, pe1);
- }
- }
-
- }, new TimedMap<OwnIdentity, CacheItem<Trust>>(60 * 60 * 1000));
+ private final Map<OwnIdentity, Trust> trustCache = Collections.synchronizedMap(new HashMap<OwnIdentity, Trust>());
/**
* Creates a new identity.
*
- * @param webOfTrustConnector
- * The web of trust connector
* @param id
* The ID of the identity
* @param nickname
* @param requestUri
* The request URI of the identity
*/
- public DefaultIdentity(WebOfTrustConnector webOfTrustConnector, String id, String nickname, String requestUri) {
- this.webOfTrustConnector = webOfTrustConnector;
+ public DefaultIdentity(String id, String nickname, String requestUri) {
this.id = id;
this.nickname = nickname;
this.requestUri = requestUri;
}
/**
- * Sets the contexts of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param contexts
- * The contexts to set
+ * {@inheritDoc}
*/
- void setContextsPrivate(Set<String> contexts) {
- this.contexts.clear();
- this.contexts.addAll(contexts);
+ @Override
+ public boolean hasContext(String context) {
+ return contexts.contains(context);
}
/**
* {@inheritDoc}
*/
@Override
- public boolean hasContext(String context) {
- return contexts.contains(context);
+ public void setContexts(Collection<String> contexts) {
+ this.contexts.clear();
+ this.contexts.addAll(contexts);
}
/**
- * Adds the given context to this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to add
+ * {@inheritDoc}
*/
- void addContextPrivate(String context) {
+ @Override
+ public void addContext(String context) {
contexts.add(context);
}
/**
- * Removes the given context from this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to remove
+ * {@inheritDoc}
*/
- public void removeContextPrivate(String context) {
+ @Override
+ public void removeContext(String context) {
contexts.remove(context);
}
*/
@Override
public Map<String, String> getProperties() {
- synchronized (properties) {
- return Collections.unmodifiableMap(properties);
- }
+ return Collections.unmodifiableMap(properties);
}
/**
- * Sets all properties of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param properties
- * The new properties of this identity
+ * {@inheritDoc}
*/
- void setPropertiesPrivate(Map<String, String> properties) {
- synchronized (this.properties) {
- this.properties.clear();
- this.properties.putAll(properties);
- }
+ @Override
+ public void setProperties(Map<String, String> properties) {
+ this.properties.clear();
+ this.properties.putAll(properties);
}
/**
- * Sets the property with the given name to the given value.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param name
- * The name of the property
- * @param value
- * The value of the property
+ * {@inheritDoc}
*/
- void setPropertyPrivate(String name, String value) {
- synchronized (properties) {
- properties.put(name, value);
- }
+ @Override
+ public String getProperty(String name) {
+ return properties.get(name);
}
/**
* {@inheritDoc}
*/
@Override
- public String getProperty(String name) {
- synchronized (properties) {
- return properties.get(name);
- }
+ public void setProperty(String name, String value) {
+ properties.put(name, value);
}
/**
- * Removes the property with the given name.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param name
- * The name of the property to remove
+ * {@inheritDoc}
*/
- void removePropertyPrivate(String name) {
- synchronized (properties) {
- properties.remove(name);
- }
+ @Override
+ public void removeProperty(String name) {
+ properties.remove(name);
}
/**
*/
@Override
public Trust getTrust(OwnIdentity ownIdentity) {
- try {
- synchronized (trustCache) {
- return trustCache.get(ownIdentity);
- }
- } catch (CacheException ce1) {
- logger.log(Level.WARNING, String.format("Could not get trust for OwnIdentity: %s", ownIdentity), ce1);
- return null;
- }
+ return trustCache.get(ownIdentity);
}
/**
- * Sets the trust received for this identity by the given own identity.
- *
- * @param ownIdentity
- * The own identity that gives the trust
- * @param trust
- * The trust received for this identity
+ * {@inheritDoc}
*/
- void setTrustPrivate(OwnIdentity ownIdentity, Trust trust) {
- synchronized (trustCache) {
- trustCache.put(ownIdentity, trust);
- }
+ @Override
+ public void setTrust(OwnIdentity ownIdentity, Trust trust) {
+ trustCache.put(ownIdentity, trust);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removeTrust(OwnIdentity ownIdentity) {
+ trustCache.remove(ownIdentity);
}
//
package net.pterodactylus.sone.freenet.wot;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
-import net.pterodactylus.util.validation.Validation;
-
/**
* An own identity is an identity that the owner of the node has full control
* over.
*/
public class DefaultOwnIdentity extends DefaultIdentity implements OwnIdentity {
- /** The identity manager. */
- private final WebOfTrustConnector webOfTrustConnector;
-
/** The insert URI of the identity. */
private final String insertUri;
/**
* Creates a new own identity.
*
- * @param webOfTrustConnector
- * The identity manager
* @param id
* The ID of the identity
* @param nickname
* @param insertUri
* The insert URI of the identity
*/
- public DefaultOwnIdentity(WebOfTrustConnector webOfTrustConnector, String id, String nickname, String requestUri, String insertUri) {
- super(webOfTrustConnector, id, nickname, requestUri);
- this.webOfTrustConnector = webOfTrustConnector;
+ public DefaultOwnIdentity(String id, String nickname, String requestUri, String insertUri) {
+ super(id, nickname, requestUri);
this.insertUri = insertUri;
}
/**
* Copy constructor for an own identity.
*
- * @param webOfTrustConnector
- * The web of trust connector
* @param ownIdentity
* The own identity to copy
*/
- public DefaultOwnIdentity(WebOfTrustConnector webOfTrustConnector, OwnIdentity ownIdentity) {
- super(webOfTrustConnector, ownIdentity.getId(), ownIdentity.getNickname(), ownIdentity.getRequestUri());
- this.webOfTrustConnector = webOfTrustConnector;
+ public DefaultOwnIdentity(OwnIdentity ownIdentity) {
+ super(ownIdentity.getId(), ownIdentity.getNickname(), ownIdentity.getRequestUri());
this.insertUri = ownIdentity.getInsertUri();
- setContextsPrivate(ownIdentity.getContexts());
- setPropertiesPrivate(ownIdentity.getProperties());
+ setContexts(ownIdentity.getContexts());
+ setProperties(ownIdentity.getProperties());
}
//
return insertUri;
}
- /**
- * {@inheritDoc}
- */
- @Override
- public void addContext(String context) throws WebOfTrustException {
- webOfTrustConnector.addContext(this, context);
- addContextPrivate(context);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeContext(String context) throws WebOfTrustException {
- webOfTrustConnector.removeContext(this, context);
- removeContextPrivate(context);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setContexts(Set<String> contexts) throws WebOfTrustException {
- for (String context : getContexts()) {
- if (!contexts.contains(context)) {
- webOfTrustConnector.removeContext(this, context);
- }
- }
- for (String context : contexts) {
- if (!getContexts().contains(context)) {
- webOfTrustConnector.addContext(this, context);
- }
- }
- setContextsPrivate(contexts);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setProperty(String name, String value) throws WebOfTrustException {
- webOfTrustConnector.setProperty(this, name, value);
- setPropertyPrivate(name, value);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeProperty(String name) throws WebOfTrustException {
- webOfTrustConnector.removeProperty(this, name);
- removePropertyPrivate(name);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setProperties(Map<String, String> properties) throws WebOfTrustException {
- for (Entry<String, String> oldProperty : getProperties().entrySet()) {
- if (!properties.containsKey(oldProperty.getKey())) {
- webOfTrustConnector.removeProperty(this, oldProperty.getKey());
- } else {
- webOfTrustConnector.setProperty(this, oldProperty.getKey(), properties.get(oldProperty.getKey()));
- }
- }
- for (Entry<String, String> newProperty : properties.entrySet()) {
- if (!getProperties().containsKey(newProperty.getKey())) {
- webOfTrustConnector.setProperty(this, newProperty.getKey(), newProperty.getValue());
- }
- }
- setPropertiesPrivate(properties);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void setTrust(Identity target, int trustValue, String comment) throws WebOfTrustException {
- Validation.begin().isNotNull("Trust Target", target).isNotNull("Trust Comment", comment).isLessOrEqual("Trust Value", trustValue, 100).isGreaterOrEqual("Trust Value", trustValue, -100).check();
- webOfTrustConnector.setTrust(this, target, trustValue, comment);
- if (target instanceof DefaultIdentity) {
- ((DefaultIdentity) target).setTrustPrivate(this, new Trust(trustValue, trustValue, 0));
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void removeTrust(Identity target) throws WebOfTrustException {
- Validation.begin().isNotNull("Trust Target", target).check();
- webOfTrustConnector.removeTrust(this, target);
- if (target instanceof DefaultIdentity) {
- ((DefaultIdentity) target).setTrustPrivate(this, new Trust(null, null, null));
- }
- }
-
- //
- // OBJECT METHODS
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public int hashCode() {
- /* The hash of DefaultIdentity is fine. */
- return super.hashCode();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean equals(Object object) {
- /* The ID of the superclass is still enough. */
- return super.equals(object);
- }
-
}
package net.pterodactylus.sone.freenet.wot;
+import java.util.Collection;
import java.util.Map;
import java.util.Set;
/**
* Interface for web of trust identities, defining all functions that can be
- * performed on an identity. The identity is the main entry point for identity
- * management.
+ * performed on an identity. An identity is only a container for identity data
+ * and will not perform any updating in the WebOfTrust plugin itself.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
public boolean hasContext(String context);
/**
+ * Adds the given context to this identity.
+ *
+ * @param context
+ * The context to add
+ */
+ public void addContext(String context);
+
+ /**
+ * Sets all contexts of this identity.
+ *
+ * @param contexts
+ * All contexts of the identity
+ */
+ public void setContexts(Collection<String> contexts);
+
+ /**
+ * Removes the given context from this identity.
+ *
+ * @param context
+ * The context to remove
+ */
+ public void removeContext(String context);
+
+ /**
* Returns all properties of this identity.
*
* @return All properties of this identity
public String getProperty(String name);
/**
+ * Sets the property with the given name to the given value.
+ *
+ * @param name
+ * The name of the property
+ * @param value
+ * The value of the property
+ */
+ public void setProperty(String name, String value);
+
+ /**
+ * Sets all properties of this identity.
+ *
+ * @param properties
+ * The new properties of this identity
+ */
+ public void setProperties(Map<String, String> properties);
+
+ /**
+ * Removes the property with the given name.
+ *
+ * @param name
+ * The name of the property to remove
+ */
+ public void removeProperty(String name);
+
+ /**
* Retrieves the trust that this identity receives from the given own
* identity. If this identity is not in the own identity’s trust tree, a
* {@link Trust} is returned that has all its elements set to {@code null}.
*/
public Trust getTrust(OwnIdentity ownIdentity);
+ /**
+ * Sets the trust given by an own identity to this identity.
+ *
+ * @param ownIdentity
+ * The own identity that gave trust to this identity
+ * @param trust
+ * The trust given by the given own identity
+ */
+ public void setTrust(OwnIdentity ownIdentity, Trust trust);
+
+ /**
+ * Removes trust assignment from the given own identity for this identity.
+ *
+ * @param ownIdentity
+ * The own identity that removed the trust assignment for this
+ * identity
+ */
+ public void removeTrust(OwnIdentity ownIdentity);
+
}
import java.util.Collections;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
import net.pterodactylus.sone.freenet.plugin.PluginException;
-import net.pterodactylus.util.collection.mapper.Mapper;
-import net.pterodactylus.util.collection.mapper.Mappers;
import net.pterodactylus.util.logging.Logging;
import net.pterodactylus.util.service.AbstractService;
Set<OwnIdentity> allOwnIdentities = getAllOwnIdentities();
for (OwnIdentity ownIdentity : allOwnIdentities) {
if (ownIdentity.getId().equals(id)) {
- return new DefaultOwnIdentity(webOfTrustConnector, ownIdentity);
+ return new DefaultOwnIdentity(ownIdentity);
}
}
return null;
* @return All own identities
*/
public Set<OwnIdentity> getAllOwnIdentities() {
- try {
- Set<OwnIdentity> ownIdentities = webOfTrustConnector.loadAllOwnIdentities();
- Map<String, OwnIdentity> newOwnIdentities = new HashMap<String, OwnIdentity>();
- for (OwnIdentity ownIdentity : ownIdentities) {
- newOwnIdentities.put(ownIdentity.getId(), ownIdentity);
- }
- checkOwnIdentities(newOwnIdentities);
- return Mappers.mappedSet(ownIdentities, new Mapper<OwnIdentity, OwnIdentity>() {
-
- /**
- * {@inheritDoc}
- */
- @Override
- @SuppressWarnings("synthetic-access")
- public OwnIdentity map(OwnIdentity input) {
- return new DefaultOwnIdentity(webOfTrustConnector, input);
- }
- });
- } catch (WebOfTrustException wote1) {
- logger.log(Level.WARNING, "Could not load all own identities!", wote1);
- return Collections.emptySet();
- }
+ return new HashSet<OwnIdentity>(currentOwnIdentities.values());
}
//
for (OwnIdentity oldOwnIdentity : currentOwnIdentities.values()) {
OwnIdentity newOwnIdentity = newOwnIdentities.get(oldOwnIdentity.getId());
if ((newOwnIdentity == null) || ((context != null) && oldOwnIdentity.hasContext(context) && !newOwnIdentity.hasContext(context))) {
- identityListenerManager.fireOwnIdentityRemoved(new DefaultOwnIdentity(webOfTrustConnector, oldOwnIdentity));
+ identityListenerManager.fireOwnIdentityRemoved(new DefaultOwnIdentity(oldOwnIdentity));
}
}
for (OwnIdentity currentOwnIdentity : newOwnIdentities.values()) {
OwnIdentity oldOwnIdentity = currentOwnIdentities.get(currentOwnIdentity.getId());
if (((oldOwnIdentity == null) && ((context == null) || currentOwnIdentity.hasContext(context))) || ((oldOwnIdentity != null) && (context != null) && (!oldOwnIdentity.hasContext(context) && currentOwnIdentity.hasContext(context)))) {
- identityListenerManager.fireOwnIdentityAdded(new DefaultOwnIdentity(webOfTrustConnector, currentOwnIdentity));
+ identityListenerManager.fireOwnIdentityAdded(new DefaultOwnIdentity(currentOwnIdentity));
}
}
package net.pterodactylus.sone.freenet.wot;
-import java.util.Map;
-import java.util.Set;
/**
* Defines a local identity, an own identity.
*/
public String getInsertUri();
- /**
- * Adds the given context to this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to add
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void addContext(String context) throws WebOfTrustException;
-
- /**
- * Sets all contexts of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param contexts
- * All contexts of the identity
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setContexts(Set<String> contexts) throws WebOfTrustException;
-
- /**
- * Removes the given context from this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param context
- * The context to remove
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void removeContext(String context) throws WebOfTrustException;
-
- /**
- * Sets the property with the given name to the given value.
- *
- * @param name
- * The name of the property
- * @param value
- * The value of the property
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setProperty(String name, String value) throws WebOfTrustException;
-
- /**
- * Sets all properties of this identity.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param properties
- * The new properties of this identity
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setProperties(Map<String, String> properties) throws WebOfTrustException;
-
- /**
- * Removes the property with the given name.
- * <p>
- * This method is only called by the {@link IdentityManager}.
- *
- * @param name
- * The name of the property to remove
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void removeProperty(String name) throws WebOfTrustException;
-
- /**
- * Sets the trust for the given target identity.
- *
- * @param target
- * The target to set the trust for
- * @param trustValue
- * The new trust value (from {@code -100} or {@code 100})
- * @param comment
- * The comment for the trust assignment
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void setTrust(Identity target, int trustValue, String comment) throws WebOfTrustException;
-
- /**
- * Removes any trust assignment for the given target identity.
- *
- * @param target
- * The targe to remove the trust assignment for
- * @throws WebOfTrustException
- * if an error occurs
- */
- public void removeTrust(Identity target) throws WebOfTrustException;
-
}
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
import java.util.logging.Level;
import java.util.logging.Logger;
import net.pterodactylus.sone.freenet.plugin.PluginConnector;
import net.pterodactylus.sone.freenet.plugin.PluginException;
import net.pterodactylus.util.logging.Logging;
+import net.pterodactylus.util.number.Numbers;
import freenet.support.SimpleFieldSet;
import freenet.support.api.Bucket;
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
-public class WebOfTrustConnector implements ConnectorListener {
+public class WebOfTrustConnector {
/** The logger. */
private static final Logger logger = Logging.getLogger(WebOfTrustConnector.class);
/** The name of the WoT plugin. */
private static final String WOT_PLUGIN_NAME = "plugins.WebOfTrust.WebOfTrust";
- /** A random connection identifier. */
- private static final String PLUGIN_CONNECTION_IDENTIFIER = "Sone-WoT-Connector-" + Math.abs(Math.random());
-
- /** The current reply. */
- private Reply reply;
+ /** Counter for connection identifiers. */
+ private final AtomicLong counter = new AtomicLong();
/** The plugin connector. */
private final PluginConnector pluginConnector;
*/
public WebOfTrustConnector(PluginConnector pluginConnector) {
this.pluginConnector = pluginConnector;
- pluginConnector.addConnectorListener(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, this);
}
//
* Stops the web of trust connector.
*/
public void stop() {
- pluginConnector.removeConnectorListener(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, this);
- synchronized (reply) {
- reply.notifyAll();
- }
+ /* does nothing. */
}
/**
String requestUri = fields.get("RequestURI" + ownIdentityCounter);
String insertUri = fields.get("InsertURI" + ownIdentityCounter);
String nickname = fields.get("Nickname" + ownIdentityCounter);
- DefaultOwnIdentity ownIdentity = new DefaultOwnIdentity(this, id, nickname, requestUri, insertUri);
- ownIdentity.setContextsPrivate(parseContexts("Contexts" + ownIdentityCounter + ".", fields));
- ownIdentity.setPropertiesPrivate(parseProperties("Properties" + ownIdentityCounter + ".", fields));
+ DefaultOwnIdentity ownIdentity = new DefaultOwnIdentity(id, nickname, requestUri, insertUri);
+ ownIdentity.setContexts(parseContexts("Contexts" + ownIdentityCounter + ".", fields));
+ ownIdentity.setProperties(parseProperties("Properties" + ownIdentityCounter + ".", fields));
ownIdentities.add(ownIdentity);
}
return ownIdentities;
* if an error occured talking to the Web of Trust plugin
*/
public Set<Identity> loadTrustedIdentities(OwnIdentity ownIdentity, String context) throws PluginException {
- Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("Truster", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).get());
+ Reply reply = performRequest(SimpleFieldSetConstructor.create().put("Message", "GetIdentitiesByScore").put("Truster", ownIdentity.getId()).put("Selection", "+").put("Context", (context == null) ? "" : context).put("WantTrustValues", "true").get());
SimpleFieldSet fields = reply.getFields();
Set<Identity> identities = new HashSet<Identity>();
int identityCounter = -1;
}
String nickname = fields.get("Nickname" + identityCounter);
String requestUri = fields.get("RequestURI" + identityCounter);
- DefaultIdentity identity = new DefaultIdentity(this, id, nickname, requestUri);
- identity.setContextsPrivate(parseContexts("Contexts" + identityCounter + ".", fields));
- identity.setPropertiesPrivate(parseProperties("Properties" + identityCounter + ".", fields));
+ DefaultIdentity identity = new DefaultIdentity(id, nickname, requestUri);
+ identity.setContexts(parseContexts("Contexts" + identityCounter + ".", fields));
+ identity.setProperties(parseProperties("Properties" + identityCounter + ".", fields));
+ Integer trust = Numbers.safeParseInteger(fields.get("Trust" + identityCounter), null);
+ int score = Numbers.safeParseInteger(fields.get("Score" + identityCounter));
+ int rank = Numbers.safeParseInteger(fields.get("Rank" + identityCounter));
+ identity.setTrust(ownIdentity, new Trust(trust, score, rank));
identities.add(identity);
}
return identities;
* The fields to parse the contexts from
* @return The parsed contexts
*/
- private Set<String> parseContexts(String prefix, SimpleFieldSet fields) {
+ private static Set<String> parseContexts(String prefix, SimpleFieldSet fields) {
Set<String> contexts = new HashSet<String>();
int contextCounter = -1;
while (true) {
* The fields to parse the properties from
* @return The parsed properties
*/
- private Map<String, String> parseProperties(String prefix, SimpleFieldSet fields) {
+ private static Map<String, String> parseProperties(String prefix, SimpleFieldSet fields) {
Map<String, String> properties = new HashMap<String, String>();
int propertiesCounter = -1;
while (true) {
* @throws PluginException
* if the request could not be sent
*/
- private synchronized Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException {
- reply = new Reply();
+ private Reply performRequest(SimpleFieldSet fields, Bucket data) throws PluginException {
+ final String identifier = "FCP-Command-" + System.currentTimeMillis() + "-" + counter.getAndIncrement();
+ final Reply reply = new Reply();
logger.log(Level.FINE, String.format("Sending FCP Request: %s", fields.get("Message")));
+ ConnectorListener connectorListener = new ConnectorListener() {
+
+ @Override
+ @SuppressWarnings("synthetic-access")
+ public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) {
+ String messageName = fields.get("Message");
+ logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", messageName));
+ synchronized (reply) {
+ reply.setFields(fields);
+ reply.setData(data);
+ reply.notify();
+ }
+ }
+ };
+ pluginConnector.addConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener);
synchronized (reply) {
- pluginConnector.sendRequest(WOT_PLUGIN_NAME, PLUGIN_CONNECTION_IDENTIFIER, fields, data);
try {
- reply.wait();
- } catch (InterruptedException ie1) {
- logger.log(Level.WARNING, String.format("Got interrupted while waiting for reply on %s.", fields.get("Message")), ie1);
+ pluginConnector.sendRequest(WOT_PLUGIN_NAME, identifier, fields, data);
+ while (reply.getFields() == null) {
+ try {
+ reply.wait();
+ } catch (InterruptedException ie1) {
+ logger.log(Level.WARNING, String.format("Got interrupted while waiting for reply on %s.", fields.get("Message")), ie1);
+ }
+ }
+ } finally {
+ pluginConnector.removeConnectorListener(WOT_PLUGIN_NAME, identifier, connectorListener);
}
}
logger.log(Level.FINEST, String.format("Received FCP Response for %s: %s", fields.get("Message"), (reply.getFields() != null) ? reply.getFields().get("Message") : null));
return reply;
}
- //
- // INTERFACE ConnectorListener
- //
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void receivedReply(PluginConnector pluginConnector, SimpleFieldSet fields, Bucket data) {
- String messageName = fields.get("Message");
- logger.log(Level.FINEST, String.format("Received Reply from Plugin: %s", messageName));
- synchronized (reply) {
- reply.setFields(fields);
- reply.setData(data);
- reply.notify();
- }
- }
-
/**
* Container for the data of the reply from a plugin.
*
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.core.FreenetInterface;
+import net.pterodactylus.sone.core.WebOfTrustUpdater;
import net.pterodactylus.sone.database.Database;
import net.pterodactylus.sone.database.memory.MemoryDatabase;
import net.pterodactylus.sone.fcp.FcpInterface;
}
/** The version. */
- public static final Version VERSION = new Version(0, 8, 1);
+ public static final Version VERSION = new Version(0, 8, 2);
/** The logger. */
private static final Logger logger = Logging.getLogger(SonePlugin.class);
/* create Sone database. */
Database soneDatabase = new MemoryDatabase();
+ /* create trust updater. */
+ WebOfTrustUpdater trustUpdater = new WebOfTrustUpdater(webOfTrustConnector);
+ trustUpdater.init();
+
/* create core. */
- core = new Core(oldConfiguration, soneDatabase, freenetInterface, identityManager);
+ core = new Core(oldConfiguration, soneDatabase, freenetInterface, identityManager, trustUpdater);
/* create the web interface. */
webInterface = new WebInterface(this);
return false;
}
} else {
- return false;
+ /*
+ * a null trust means that the trust updater has not yet
+ * received a trust value for this relation. if we return false,
+ * the post feed will stay empty until the trust updater has
+ * received trust values. to prevent this we simply assume that
+ * posts are visible if there is no trust.
+ */
+ return true;
}
if ((!postSone.equals(sone)) && !sone.hasFriend(postSone.getId()) && !sone.equals(post.getRecipient())) {
return false;
* The name of the link
* @return The created map containing the mappings
*/
- private Map<String, String> createLink(String target, String name) {
+ private static Map<String, String> createLink(String target, String name) {
Map<String, String> link = new HashMap<String, String>();
link.put("target", target);
link.put("name", name);
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
return String.valueOf(data).replaceAll("[^a-zA-Z0-9-]", "_");
}
* append to the nickname
* @return The nickname with optional ID appendage
*/
- private String getAbbreviatedNickname(Identity identity, int length) {
+ private static String getAbbreviatedNickname(Identity identity, int length) {
return identity.getNickname() + ((length > 0) ? "@" + identity.getId().substring(0, length) : "");
}
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
Image image = null;
if (data instanceof String) {
image = core.getImage((String) data, false);
if (image == null) {
return null;
}
- String imageClass = parameters.get("class");
+ String imageClass = String.valueOf(parameters.get("class"));
int maxWidth = Numbers.safeParseInteger(parameters.get("max-width"), Integer.MAX_VALUE);
int maxHeight = Numbers.safeParseInteger(parameters.get("max-height"), Integer.MAX_VALUE);
String mode = String.valueOf(parameters.get("mode"));
- String title = parameters.get("title");
- if ((title != null) && title.startsWith("=")) {
- title = String.valueOf(templateContext.get(title.substring(1)));
- }
+ String title = String.valueOf(parameters.get("title"));
TemplateContext linkTemplateContext = templateContextFactory.createTemplateContext();
linkTemplateContext.set("class", imageClass);
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
StringBuilder javascriptString = new StringBuilder();
javascriptString.append('"');
for (char c : String.valueOf(data).toCharArray()) {
private final TemplateContextFactory templateContextFactory;
/** The template for {@link PlainTextPart}s. */
- private final Template plainTextTemplate = TemplateParser.parse(new StringReader("<%text|html>"));
+ private static final Template plainTextTemplate = TemplateParser.parse(new StringReader("<%text|html>"));
/** The template for {@link FreenetLinkPart}s. */
- private final Template linkTemplate = TemplateParser.parse(new StringReader("<a class=\"<%cssClass|html>\" href=\"<%link|html>\" title=\"<%title|html>\"><%text|html></a>"));
+ private static final Template linkTemplate = TemplateParser.parse(new StringReader("<a class=\"<%cssClass|html>\" href=\"<%link|html>\" title=\"<%title|html>\"><%text|html></a>"));
/**
* Creates a new filter that runs its input through a {@link SoneTextParser}
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
String text = String.valueOf(data);
- int length = Numbers.safeParseInteger(parameters.get("length"), Numbers.safeParseInteger(templateContext.get(parameters.get("length")), -1));
- int cutOffLength = Numbers.safeParseInteger(parameters.get("cut-off-length"), Numbers.safeParseInteger(templateContext.get(parameters.get("cut-off-length")), length));
- String soneKey = parameters.get("sone");
- if (soneKey == null) {
- soneKey = "sone";
- }
- Sone sone = (Sone) templateContext.get(soneKey);
- if (sone == null) {
- sone = core.getSone(soneKey, false);
+ int length = Numbers.safeParseInteger(parameters.get("length"), Numbers.safeParseInteger(templateContext.get(String.valueOf(parameters.get("length"))), -1));
+ int cutOffLength = Numbers.safeParseInteger(parameters.get("cut-off-length"), Numbers.safeParseInteger(templateContext.get(String.valueOf(parameters.get("cut-off-length"))), length));
+ Object sone = parameters.get("sone");
+ if (sone instanceof String) {
+ sone = core.getSone((String) sone, false);
}
FreenetRequest request = (FreenetRequest) templateContext.get("request");
- SoneTextParserContext context = new SoneTextParserContext(request, sone);
+ SoneTextParserContext context = new SoneTextParserContext(request, (Sone) sone);
StringWriter parsedTextWriter = new StringWriter();
try {
Iterable<Part> parts = soneTextParser.parse(context, new StringReader(text));
* The part to render
*/
private void render(Writer writer, PostPart postPart) {
- renderLink(writer, "viewPost.html?post=" + postPart.getPost().getId(), getExcerpt(postPart.getPost().getText(), 20), SoneAccessor.getNiceName(postPart.getPost().getSone()), "in-sone");
+ SoneTextParser parser = new SoneTextParser(core, core);
+ SoneTextParserContext parserContext = new SoneTextParserContext(null, postPart.getPost().getSone());
+ try {
+ Iterable<Part> parts = parser.parse(parserContext, new StringReader(postPart.getPost().getText()));
+ StringBuilder excerpt = new StringBuilder();
+ for (Part part : parts) {
+ excerpt.append(part.getText());
+ if (excerpt.length() > 20) {
+ excerpt.setLength(20);
+ break;
+ }
+ }
+ renderLink(writer, "viewPost.html?post=" + postPart.getPost().getId(), excerpt.toString(), SoneAccessor.getNiceName(postPart.getPost().getSone()), "in-sone");
+ } catch (IOException ioe1) {
+ /* StringReader shouldn’t throw. */
+ }
}
/**
linkTemplate.render(templateContext, writer);
}
- //
- // STATIC METHODS
- //
-
- /**
- * Returns up to {@code length} characters from the given text, appending
- * “…” if the text is longer.
- *
- * @param text
- * The text to get an excerpt from
- * @param length
- * The maximum length of the excerpt (without the ellipsis)
- * @return The excerpt of the text
- */
- private static String getExcerpt(String text, int length) {
- String filteredText = text.replaceAll("(\r\n)+", "\r\n").replaceAll("\n+", "\n").replace("\r\n", " ").replace('\n', ' ');
- if (filteredText.length() > length) {
- return filteredText.substring(0, length) + "…";
- }
- return filteredText;
- }
-
}
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.ShowCustomAvatars;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.util.template.Accessor;
import net.pterodactylus.util.template.ReflectionAccessor;
if (showCustomAvatars == ShowCustomAvatars.FOLLOWED) {
return currentSone.hasFriend(remoteSone.getId()) ? avatarId : null;
}
- Trust trust = core.getTrust(currentSone, remoteSone);
+ Trust trust = remoteSone.getIdentity().getTrust((OwnIdentity) currentSone.getIdentity());
if (trust == null) {
return null;
}
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
@SuppressWarnings("unchecked")
List<PostReply> allReplies = (List<PostReply>) data;
Map<Post, Set<Sone>> postSones = new HashMap<Post, Set<Sone>>();
/**
* This filter expects a {@link FreenetRequest} as input and outputs a
* {@link URI} that is modified by the parameters. The name of the parameter is
- * handed in as “name”, the value may either be stored in “value”, or in a
- * template variable whose key is stored in “key”.
+ * handed in as “name”, the new value is stored in “value”.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
FreenetRequest request = (FreenetRequest) data;
- String name = parameters.get("name");
- String nameKey = parameters.get("nameKey");
- if (nameKey != null) {
- name = String.valueOf(templateContext.get(nameKey));
- }
- String key = parameters.get("key");
- String value = null;
- if (key != null) {
- value = String.valueOf(templateContext.get(key));
- }
- if (value == null) {
- value = parameters.get("value");
- }
- if (value == null) {
- return request.getUri();
- }
+ String name = String.valueOf(parameters.get("name"));
+ String value = String.valueOf(parameters.get("value"));
Map<String, String> values = new HashMap<String, String>();
Collection<String> parameterNames = request.getHttpRequest().getParameterNames();
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.data.Sone.SoneStatus;
+import net.pterodactylus.sone.freenet.wot.OwnIdentity;
import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.ajax.GetTimesAjaxPage;
if (currentSone == null) {
return null;
}
- Trust trust = core.getTrust(currentSone, sone);
+ Trust trust = sone.getIdentity().getTrust((OwnIdentity) currentSone.getIdentity());
logger.log(Level.FINEST, String.format("Trust for %s by %s: %s", sone, currentSone, trust));
if (trust == null) {
return new Trust(null, null, null);
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
- String startString = parameters.get("start");
- String lengthString = parameters.get("length");
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
+ String startString = String.valueOf(parameters.get("start"));
+ String lengthString = String.valueOf(parameters.get("length"));
int start = 0;
try {
start = Integer.parseInt(startString);
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
if (!(data instanceof Collection<?>)) {
return data;
}
* {@inheritDoc}
*/
@Override
- public Object format(TemplateContext templateContext, Object data, Map<String, String> parameters) {
+ public Object format(TemplateContext templateContext, Object data, Map<String, Object> parameters) {
if (data instanceof Long) {
if ((Long) data == 0) {
return l10nHandler.getString(unknownKey);
}
/**
- * Returns the text of this part.
+ * Returns the title of this part.
*
- * @return The text of this part
+ * @return The title of this part
*/
- public String getText() {
- return text;
+ public String getTitle() {
+ return title;
}
+ //
+ // PART METHODS
+ //
+
/**
- * Returns the title of this part.
+ * Returns the text of this part.
*
- * @return The title of this part
+ * @return The text of this part
*/
- public String getTitle() {
- return title;
+ @Override
+ public String getText() {
+ return text;
}
}
*/
public interface Part {
- /* no methods. */
+ /**
+ * Returns the text contained in this part. This should return plain text
+ * without any format information.
+ *
+ * @return The plain text of this part
+ */
+ public String getText();
}
}
//
+ // PART METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ StringBuilder partText = new StringBuilder();
+ for (Part part : parts) {
+ partText.append(part.getText());
+ }
+ return partText.toString();
+ }
+
+ //
// ITERABLE METHODS
//
}
//
- // ACCESSORS
+ // PART METHODS
//
/**
*
* @return The text of this part
*/
+ @Override
public String getText() {
return text;
}
return post;
}
+ //
+ // PART METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ return post.getText();
+ }
+
}
package net.pterodactylus.sone.text;
import net.pterodactylus.sone.data.Sone;
+import net.pterodactylus.sone.template.SoneAccessor;
/**
* {@link Part} implementation that stores a reference to a {@link Sone}.
return sone;
}
+ //
+ // PART METHODS
+ //
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getText() {
+ return SoneAccessor.getNiceName(sone);
+ }
+
}
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.database.memory.MemorySone;
+import net.pterodactylus.util.io.Closer;
import net.pterodactylus.util.logging.Logging;
import freenet.keys.FreenetURI;
public Iterable<Part> parse(SoneTextParserContext context, Reader source) throws IOException {
PartContainer parts = new PartContainer();
BufferedReader bufferedReader = (source instanceof BufferedReader) ? (BufferedReader) source : new BufferedReader(source);
- String line;
- boolean lastLineEmpty = true;
- int emptyLines = 0;
- while ((line = bufferedReader.readLine()) != null) {
- if (line.trim().length() == 0) {
- if (lastLineEmpty) {
+ try {
+ String line;
+ boolean lastLineEmpty = true;
+ int emptyLines = 0;
+ while ((line = bufferedReader.readLine()) != null) {
+ if (line.trim().length() == 0) {
+ if (lastLineEmpty) {
+ continue;
+ }
+ parts.add(new PlainTextPart("\n"));
+ ++emptyLines;
+ lastLineEmpty = emptyLines == 2;
continue;
}
- parts.add(new PlainTextPart("\n"));
- ++emptyLines;
- lastLineEmpty = emptyLines == 2;
- continue;
- }
- emptyLines = 0;
- /*
- * lineComplete tracks whether the block you are parsing is the
- * first block of the line. this is important because sometimes you
- * have to add an additional line break.
- */
- boolean lineComplete = true;
- while (line.length() > 0) {
- int nextKsk = line.indexOf("KSK@");
- int nextChk = line.indexOf("CHK@");
- int nextSsk = line.indexOf("SSK@");
- int nextUsk = line.indexOf("USK@");
- int nextHttp = line.indexOf("http://");
- int nextHttps = line.indexOf("https://");
- int nextSone = line.indexOf("sone://");
- int nextPost = line.indexOf("post://");
- if ((nextKsk == -1) && (nextChk == -1) && (nextSsk == -1) && (nextUsk == -1) && (nextHttp == -1) && (nextHttps == -1) && (nextSone == -1) && (nextPost == -1)) {
- if (lineComplete && !lastLineEmpty) {
- parts.add(new PlainTextPart("\n" + line));
- } else {
- parts.add(new PlainTextPart(line));
+ emptyLines = 0;
+ /*
+ * lineComplete tracks whether the block you are parsing is the
+ * first block of the line. this is important because sometimes
+ * you have to add an additional line break.
+ */
+ boolean lineComplete = true;
+ while (line.length() > 0) {
+ int nextKsk = line.indexOf("KSK@");
+ int nextChk = line.indexOf("CHK@");
+ int nextSsk = line.indexOf("SSK@");
+ int nextUsk = line.indexOf("USK@");
+ int nextHttp = line.indexOf("http://");
+ int nextHttps = line.indexOf("https://");
+ int nextSone = line.indexOf("sone://");
+ int nextPost = line.indexOf("post://");
+ if ((nextKsk == -1) && (nextChk == -1) && (nextSsk == -1) && (nextUsk == -1) && (nextHttp == -1) && (nextHttps == -1) && (nextSone == -1) && (nextPost == -1)) {
+ if (lineComplete && !lastLineEmpty) {
+ parts.add(new PlainTextPart("\n" + line));
+ } else {
+ parts.add(new PlainTextPart(line));
+ }
+ break;
+ }
+ int next = Integer.MAX_VALUE;
+ LinkType linkType = null;
+ if ((nextKsk > -1) && (nextKsk < next)) {
+ next = nextKsk;
+ linkType = LinkType.KSK;
+ }
+ if ((nextChk > -1) && (nextChk < next)) {
+ next = nextChk;
+ linkType = LinkType.CHK;
+ }
+ if ((nextSsk > -1) && (nextSsk < next)) {
+ next = nextSsk;
+ linkType = LinkType.SSK;
+ }
+ if ((nextUsk > -1) && (nextUsk < next)) {
+ next = nextUsk;
+ linkType = LinkType.USK;
+ }
+ if ((nextHttp > -1) && (nextHttp < next)) {
+ next = nextHttp;
+ linkType = LinkType.HTTP;
+ }
+ if ((nextHttps > -1) && (nextHttps < next)) {
+ next = nextHttps;
+ linkType = LinkType.HTTPS;
+ }
+ if ((nextSone > -1) && (nextSone < next)) {
+ next = nextSone;
+ linkType = LinkType.SONE;
+ }
+ if ((nextPost > -1) && (nextPost < next)) {
+ next = nextPost;
+ linkType = LinkType.POST;
}
- break;
- }
- int next = Integer.MAX_VALUE;
- LinkType linkType = null;
- if ((nextKsk > -1) && (nextKsk < next)) {
- next = nextKsk;
- linkType = LinkType.KSK;
- }
- if ((nextChk > -1) && (nextChk < next)) {
- next = nextChk;
- linkType = LinkType.CHK;
- }
- if ((nextSsk > -1) && (nextSsk < next)) {
- next = nextSsk;
- linkType = LinkType.SSK;
- }
- if ((nextUsk > -1) && (nextUsk < next)) {
- next = nextUsk;
- linkType = LinkType.USK;
- }
- if ((nextHttp > -1) && (nextHttp < next)) {
- next = nextHttp;
- linkType = LinkType.HTTP;
- }
- if ((nextHttps > -1) && (nextHttps < next)) {
- next = nextHttps;
- linkType = LinkType.HTTPS;
- }
- if ((nextSone > -1) && (nextSone < next)) {
- next = nextSone;
- linkType = LinkType.SONE;
- }
- if ((nextPost > -1) && (nextPost < next)) {
- next = nextPost;
- linkType = LinkType.POST;
- }
- /* cut off “freenet:” from before keys. */
- if (((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (next >= 8) && (line.substring(next - 8, next).equals("freenet:"))) {
- next -= 8;
- line = line.substring(0, next) + line.substring(next + 8);
- }
+ /* cut off “freenet:” from before keys. */
+ if (((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (next >= 8) && (line.substring(next - 8, next).equals("freenet:"))) {
+ next -= 8;
+ line = line.substring(0, next) + line.substring(next + 8);
+ }
- /* if there is text before the next item, write it out. */
- if (lineComplete && !lastLineEmpty) {
- parts.add(new PlainTextPart("\n"));
- }
- if (next > 0) {
- parts.add(new PlainTextPart(line.substring(0, next)));
- line = line.substring(next);
- next = 0;
- }
- lineComplete = false;
+ /* if there is text before the next item, write it out. */
+ if (lineComplete && !lastLineEmpty) {
+ parts.add(new PlainTextPart("\n"));
+ }
+ if (next > 0) {
+ parts.add(new PlainTextPart(line.substring(0, next)));
+ line = line.substring(next);
+ next = 0;
+ }
+ lineComplete = false;
- if (linkType == LinkType.SONE) {
- if (line.length() >= (7 + 43)) {
- String soneId = line.substring(7, 50);
- Sone sone = soneProvider.getSone(soneId, false);
- if (sone == null) {
- /*
- * don’t use create=true above, we don’t want the
- * empty shell.
- */
- sone = new MemorySone(soneId, false);
+ if (linkType == LinkType.SONE) {
+ if (line.length() >= (7 + 43)) {
+ String soneId = line.substring(7, 50);
+ Sone sone = soneProvider.getSone(soneId, false);
+ if (sone == null) {
+ /*
+ * don’t use create=true above, we don’t want
+ * the empty shell.
+ */
+ sone = new MemorySone(soneId, false);
+ }
+ parts.add(new SonePart(sone));
+ line = line.substring(50);
+ } else {
+ parts.add(new PlainTextPart(line));
+ line = "";
}
- parts.add(new SonePart(sone));
- line = line.substring(50);
- } else {
- parts.add(new PlainTextPart(line));
- line = "";
+ continue;
}
- continue;
- }
- if (linkType == LinkType.POST) {
- if (line.length() >= (7 + 36)) {
- String postId = line.substring(7, 43);
- Post post = postProvider.getPost(postId, false);
- if ((post != null) && (post.getSone() != null)) {
- parts.add(new PostPart(post));
+ if (linkType == LinkType.POST) {
+ if (line.length() >= (7 + 36)) {
+ String postId = line.substring(7, 43);
+ Post post = postProvider.getPost(postId, false);
+ if ((post != null) && (post.getSone() != null)) {
+ parts.add(new PostPart(post));
+ } else {
+ parts.add(new PlainTextPart(line.substring(0, 43)));
+ }
+ line = line.substring(43);
} else {
- parts.add(new PlainTextPart(line.substring(0, 43)));
+ parts.add(new PlainTextPart(line));
+ line = "";
}
- line = line.substring(43);
- } else {
- parts.add(new PlainTextPart(line));
- line = "";
+ continue;
}
- continue;
- }
- Matcher matcher = whitespacePattern.matcher(line);
- int nextSpace = matcher.find(0) ? matcher.start() : line.length();
- String link = line.substring(0, nextSpace);
- String name = link;
- logger.log(Level.FINER, String.format("Found link: %s", link));
- logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk));
+ Matcher matcher = whitespacePattern.matcher(line);
+ int nextSpace = matcher.find(0) ? matcher.start() : line.length();
+ String link = line.substring(0, nextSpace);
+ String name = link;
+ logger.log(Level.FINER, String.format("Found link: %s", link));
+ logger.log(Level.FINEST, String.format("CHK: %d, SSK: %d, USK: %d", nextChk, nextSsk, nextUsk));
- if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) {
- FreenetURI uri;
- if (name.indexOf('?') > -1) {
- name = name.substring(0, name.indexOf('?'));
- }
- if (name.endsWith("/")) {
- name = name.substring(0, name.length() - 1);
- }
- try {
- uri = new FreenetURI(name);
- name = uri.lastMetaString();
- if (name == null) {
- name = uri.getDocName();
+ if ((linkType == LinkType.KSK) || (linkType == LinkType.CHK) || (linkType == LinkType.SSK) || (linkType == LinkType.USK)) {
+ FreenetURI uri;
+ if (name.indexOf('?') > -1) {
+ name = name.substring(0, name.indexOf('?'));
}
- if (name == null) {
- name = link.substring(0, Math.min(9, link.length()));
+ if (name.endsWith("/")) {
+ name = name.substring(0, name.length() - 1);
}
- boolean fromPostingSone = ((linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (context != null) && (context.getPostingSone() != null) && link.substring(4, Math.min(link.length(), 47)).equals(context.getPostingSone().getId());
- parts.add(new FreenetLinkPart(link, name, fromPostingSone));
- } catch (MalformedURLException mue1) {
- /* not a valid link, insert as plain text. */
- parts.add(new PlainTextPart(link));
- } catch (NullPointerException npe1) {
- /* FreenetURI sometimes throws these, too. */
- parts.add(new PlainTextPart(link));
- } catch (ArrayIndexOutOfBoundsException aioobe1) {
- /* oh, and these, too. */
- parts.add(new PlainTextPart(link));
- }
- } else if ((linkType == LinkType.HTTP) || (linkType == LinkType.HTTPS)) {
- name = link.substring(linkType == LinkType.HTTP ? 7 : 8);
- int firstSlash = name.indexOf('/');
- int lastSlash = name.lastIndexOf('/');
- if ((lastSlash - firstSlash) > 3) {
- name = name.substring(0, firstSlash + 1) + "…" + name.substring(lastSlash);
- }
- if (name.endsWith("/")) {
- name = name.substring(0, name.length() - 1);
- }
- if (((name.indexOf('/') > -1) && (name.indexOf('.') < name.lastIndexOf('.', name.indexOf('/'))) || ((name.indexOf('/') == -1) && (name.indexOf('.') < name.lastIndexOf('.')))) && name.startsWith("www.")) {
- name = name.substring(4);
- }
- if (name.indexOf('?') > -1) {
- name = name.substring(0, name.indexOf('?'));
+ try {
+ uri = new FreenetURI(name);
+ name = uri.lastMetaString();
+ if (name == null) {
+ name = uri.getDocName();
+ }
+ if (name == null) {
+ name = link.substring(0, Math.min(9, link.length()));
+ }
+ boolean fromPostingSone = ((linkType == LinkType.SSK) || (linkType == LinkType.USK)) && (context != null) && (context.getPostingSone() != null) && link.substring(4, Math.min(link.length(), 47)).equals(context.getPostingSone().getId());
+ parts.add(new FreenetLinkPart(link, name, fromPostingSone));
+ } catch (MalformedURLException mue1) {
+ /* not a valid link, insert as plain text. */
+ parts.add(new PlainTextPart(link));
+ } catch (NullPointerException npe1) {
+ /* FreenetURI sometimes throws these, too. */
+ parts.add(new PlainTextPart(link));
+ } catch (ArrayIndexOutOfBoundsException aioobe1) {
+ /* oh, and these, too. */
+ parts.add(new PlainTextPart(link));
+ }
+ } else if ((linkType == LinkType.HTTP) || (linkType == LinkType.HTTPS)) {
+ name = link.substring(linkType == LinkType.HTTP ? 7 : 8);
+ int firstSlash = name.indexOf('/');
+ int lastSlash = name.lastIndexOf('/');
+ if ((lastSlash - firstSlash) > 3) {
+ name = name.substring(0, firstSlash + 1) + "…" + name.substring(lastSlash);
+ }
+ if (name.endsWith("/")) {
+ name = name.substring(0, name.length() - 1);
+ }
+ if (((name.indexOf('/') > -1) && (name.indexOf('.') < name.lastIndexOf('.', name.indexOf('/'))) || ((name.indexOf('/') == -1) && (name.indexOf('.') < name.lastIndexOf('.')))) && name.startsWith("www.")) {
+ name = name.substring(4);
+ }
+ if (name.indexOf('?') > -1) {
+ name = name.substring(0, name.indexOf('?'));
+ }
+ parts.add(new LinkPart(link, name));
}
- parts.add(new LinkPart(link, name));
+ line = line.substring(nextSpace);
}
- line = line.substring(nextSpace);
+ lastLineEmpty = false;
+ }
+ } finally {
+ if (bufferedReader != source) {
+ Closer.close(bufferedReader);
}
- lastLineEmpty = false;
}
for (int partIndex = parts.size() - 1; partIndex >= 0; --partIndex) {
Part part = parts.getPart(partIndex);
* @return The parsed ID, or {@code null} if there was no part matching the
* given string
*/
- private String getFieldId(FreenetRequest request, String partNameStart) {
+ private static String getFieldId(FreenetRequest request, String partNameStart) {
for (String partName : request.getHttpRequest().getParts()) {
if (partName.startsWith(partNameStart)) {
return partName.substring(partNameStart.length());
import net.pterodactylus.sone.data.Image;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.web.page.FreenetRequest;
+import net.pterodactylus.util.collection.Pagination;
+import net.pterodactylus.util.number.Numbers;
import net.pterodactylus.util.template.Template;
import net.pterodactylus.util.template.TemplateContext;
Album album = webInterface.getCore().getAlbum(albumId, false);
templateContext.set("albumRequested", true);
templateContext.set("album", album);
+ templateContext.set("page", request.getHttpRequest().getParam("page"));
return;
}
String imageId = request.getHttpRequest().getParam("image", null);
albums.addAll(sone.getAllAlbums());
}
Collections.sort(albums, Album.TITLE_COMPARATOR);
- templateContext.set("albums", albums);
+ Pagination<Album> albumPagination = new Pagination<Album>(albums, 12).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0));
+ templateContext.set("albumPagination", albumPagination);
+ templateContext.set("albums", albumPagination.getItems());
return;
}
Sone sone = getCurrentSone(request.getToadletContext(), false);
} else {
preferences.setPostsPerPage(postsPerPage);
}
+ Integer imagesPerPage = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("images-per-page", 4), null);
+ if (!preferences.validateImagesPerPage(imagesPerPage)) {
+ fieldErrors.add("images-per-page");
+ } else {
+ preferences.setImagesPerPage(imagesPerPage);
+ }
Integer charactersPerPost = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("characters-per-post", 10), null);
if (!preferences.validateCharactersPerPost(charactersPerPost)) {
fieldErrors.add("characters-per-post");
Integer fcpFullAccessRequiredInteger = Numbers.safeParseInteger(request.getHttpRequest().getPartAsStringFailsafe("fcp-full-access-required", 1), preferences.getFcpFullAccessRequired().ordinal());
FullAccessRequired fcpFullAccessRequired = FullAccessRequired.values()[fcpFullAccessRequiredInteger];
preferences.setFcpFullAccessRequired(fcpFullAccessRequired);
- boolean clearOnNextRestart = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("clear-on-next-restart", 5));
- preferences.setClearOnNextRestart(clearOnNextRestart);
- boolean reallyClearOnNextRestart = Boolean.parseBoolean(request.getHttpRequest().getPartAsStringFailsafe("really-clear-on-next-restart", 5));
- preferences.setReallyClearOnNextRestart(reallyClearOnNextRestart);
webInterface.getCore().touchConfiguration();
if (fieldErrors.isEmpty()) {
throw new RedirectException(getPath());
}
templateContext.set("insertion-delay", preferences.getInsertionDelay());
templateContext.set("posts-per-page", preferences.getPostsPerPage());
+ templateContext.set("images-per-page", preferences.getImagesPerPage());
templateContext.set("characters-per-post", preferences.getCharactersPerPost());
templateContext.set("post-cut-off-length", preferences.getPostCutOffLength());
templateContext.set("require-full-access", preferences.isRequireFullAccess());
templateContext.set("trust-comment", preferences.getTrustComment());
templateContext.set("fcp-interface-active", preferences.isFcpInterfaceActive());
templateContext.set("fcp-full-access-required", preferences.getFcpFullAccessRequired().ordinal());
- templateContext.set("clear-on-next-restart", preferences.isClearOnNextRestart());
- templateContext.set("really-clear-on-next-restart", preferences.isReallyClearOnNextRestart());
}
}
* The string generator for the objects
* @return The hits for the given phrases
*/
- private <T> Set<Hit<T>> getHits(Collection<T> objects, List<Phrase> phrases, StringGenerator<T> stringGenerator) {
+ private static <T> Set<Hit<T>> getHits(Collection<T> objects, List<Phrase> phrases, StringGenerator<T> stringGenerator) {
Set<Hit<T>> hits = new HashSet<Hit<T>>();
for (T object : objects) {
String objectString = stringGenerator.generateString(object);
* The query to parse
* @return The parsed phrases
*/
- private List<Phrase> parseSearchPhrases(String query) {
+ private static List<Phrase> parseSearchPhrases(String query) {
List<String> parsedPhrases = null;
try {
parsedPhrases = StringEscaper.parseLine(query);
* The expression to search
* @return The score of the expression
*/
- private double calculateScore(List<Phrase> phrases, String expression) {
+ private static double calculateScore(List<Phrase> phrases, String expression) {
logger.log(Level.FINEST, String.format("Calculating Score for “%s”…", expression));
double optionalHits = 0;
double requiredHits = 0;
* @return The MIME type of the image, or “application/octet-stream” if the
* image type could not be detected
*/
- private String getMimeType(byte[] imageData) {
+ private static String getMimeType(byte[] imageData) {
ByteArrayInputStream imageDataInputStream = new ByteArrayInputStream(imageData);
try {
ImageInputStream imageInputStream = ImageIO.createImageInputStream(imageDataInputStream);
import net.pterodactylus.util.template.HtmlFilter;
import net.pterodactylus.util.template.MatchFilter;
import net.pterodactylus.util.template.ModFilter;
+import net.pterodactylus.util.template.PaginationFilter;
import net.pterodactylus.util.template.Provider;
import net.pterodactylus.util.template.ReflectionAccessor;
import net.pterodactylus.util.template.ReplaceFilter;
templateContextFactory.addFilter("in", new ContainsFilter());
templateContextFactory.addFilter("unique", new UniqueElementFilter());
templateContextFactory.addFilter("mod", new ModFilter());
+ templateContextFactory.addFilter("paginate", new PaginationFilter());
templateContextFactory.addProvider(Provider.TEMPLATE_CONTEXT_PROVIDER);
templateContextFactory.addProvider(new ClassPathTemplateProvider());
templateContextFactory.addTemplateObject("webInterface", this);
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
return createErrorJsonObject("invalid-sone-id");
}
webInterface.getCore().distrustSone(currentSone, sone);
- Trust trust = webInterface.getCore().getTrust(currentSone, sone);
- if (trust == null) {
- return createErrorJsonObject("wot-plugin");
- }
- return createSuccessJsonObject().put("trustValue", trust.getExplicit());
+ return createSuccessJsonObject().put("trustValue", webInterface.getCore().getPreferences().getNegativeTrust());
}
}
String description = request.getHttpRequest().getParam("description").trim();
image.setTitle(title).setDescription(TextFilter.filter(request.getHttpRequest().getHeader("host"), description));
webInterface.getCore().touchConfiguration();
- return createSuccessJsonObject().put("imageId", image.getId()).put("title", image.getTitle()).put("description", image.getDescription()).put("parsedDescription", (String) parserFilter.format(new TemplateContext(), image.getDescription(), new MapBuilder<String, String>().put("sone", image.getSone().getId()).get()));
+ return createSuccessJsonObject().put("imageId", image.getId()).put("title", image.getTitle()).put("description", image.getDescription()).put("parsedDescription", (String) parserFilter.format(new TemplateContext(), image.getDescription(), new MapBuilder<String, Object>().put("sone", image.getSone()).get()));
}
}
* The Sones to convert to an array
* @return The Sones, sorted by name
*/
- private JsonArray getSones(Set<Sone> sones) {
+ private static JsonArray getSones(Set<Sone> sones) {
JsonArray soneArray = new JsonArray();
List<Sone> sortedSones = new ArrayList<Sone>(sones);
Collections.sort(sortedSones, Sone.NICE_NAME_COMPARATOR);
* The current Sone (may be {@code null})
* @return The current options
*/
- private JsonObject createJsonOptions(Sone currentSone) {
+ private static JsonObject createJsonOptions(Sone currentSone) {
JsonObject options = new JsonObject();
if (currentSone != null) {
options.put("ShowNotification/NewSones", currentSone.getOptions().getBooleanOption("ShowNotification/NewSones").get());
@Override
protected JsonObject createJsonObject(FreenetRequest request) {
final Sone currentSone = getCurrentSone(request.getToadletContext(), false);
- /* load Sones. */
- boolean loadAllSones = Boolean.parseBoolean(request.getHttpRequest().getParam("loadAllSones", "false"));
+ /* load Sones. always return the status of the current Sone. */
Set<Sone> sones = new HashSet<Sone>(Collections.singleton(getCurrentSone(request.getToadletContext(), false)));
- if (loadAllSones) {
- sones.addAll(webInterface.getCore().getSones());
- } else {
- String loadSoneIds = request.getHttpRequest().getParam("soneIds");
- if (loadSoneIds.length() > 0) {
- String[] soneIds = loadSoneIds.split(",");
- for (String soneId : soneIds) {
- /* just add it, we skip null further down. */
- sones.add(webInterface.getCore().getSone(soneId, false));
- }
+ String loadSoneIds = request.getHttpRequest().getParam("soneIds");
+ if (loadSoneIds.length() > 0) {
+ String[] soneIds = loadSoneIds.split(",");
+ for (String soneId : soneIds) {
+ /* just add it, we skip null further down. */
+ sones.add(webInterface.getCore().getSone(soneId, false));
}
}
JsonArray jsonSones = new JsonArray();
* The current Sone (may be {@code null})
* @return The current options
*/
- private JsonObject createJsonOptions(Sone currentSone) {
+ private static JsonObject createJsonOptions(Sone currentSone) {
JsonObject options = new JsonObject();
if (currentSone != null) {
options.put("ShowNotification/NewSones", currentSone.getOptions().getBooleanOption("ShowNotification/NewSones").get());
Time time = getTime(post.getTime());
postTime.put("timeText", time.getText());
postTime.put("refreshTime", time.getRefresh() / Time.SECOND);
- postTime.put("tooltip", dateFormat.format(new Date(post.getTime())));
+ synchronized (dateFormat) {
+ postTime.put("tooltip", dateFormat.format(new Date(post.getTime())));
+ }
postTimes.put(id, postTime);
}
}
Time time = getTime(reply.getTime());
replyTime.put("timeText", time.getText());
replyTime.put("refreshTime", time.getRefresh() / Time.SECOND);
- replyTime.put("tooltip", dateFormat.format(new Date(reply.getTime())));
+ synchronized (dateFormat) {
+ replyTime.put("tooltip", dateFormat.format(new Date(reply.getTime())));
+ }
replyTimes.put(id, replyTime);
}
}
* @return {@code true} if the form password (given as “formPassword”) is
* required, {@code false} otherwise
*/
+ @SuppressWarnings("static-method")
protected boolean needsFormPassword() {
return true;
}
* @return {@code true} if the user needs to be logged in to use this page,
* {@code false} otherwise
*/
+ @SuppressWarnings("static-method")
protected boolean requiresLogin() {
return true;
}
*
* @return A reply signaling success
*/
- protected JsonObject createSuccessJsonObject() {
+ protected static JsonObject createSuccessJsonObject() {
return new JsonObject().put("success", true);
}
* The error that has occured
* @return The JSON object, signalling failure and the error code
*/
- protected JsonObject createErrorJsonObject(String error) {
+ protected static JsonObject createErrorJsonObject(String error) {
return new JsonObject().put("success", false).put("error", error);
}
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
return createErrorJsonObject("invalid-sone-id");
}
webInterface.getCore().trustSone(currentSone, sone);
- Trust trust = webInterface.getCore().getTrust(currentSone, sone);
- if (trust == null) {
- return createErrorJsonObject("wot-plugin");
- }
- return createSuccessJsonObject().put("trustValue", trust.getExplicit());
+ return createSuccessJsonObject().put("trustValue", webInterface.getCore().getPreferences().getPositiveTrust());
}
}
import net.pterodactylus.sone.core.Core;
import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.freenet.wot.Trust;
import net.pterodactylus.sone.web.WebInterface;
import net.pterodactylus.sone.web.page.FreenetRequest;
import net.pterodactylus.util.json.JsonObject;
return createErrorJsonObject("invalid-sone-id");
}
webInterface.getCore().untrustSone(currentSone, sone);
- Trust trust = webInterface.getCore().getTrust(currentSone, sone);
- if (trust == null) {
- return createErrorJsonObject("wot-plugin");
- }
- return createSuccessJsonObject().put("trustValue", trust.getExplicit());
+ return createSuccessJsonObject().put("trustValue", (String) null);
}
}
* The request to serve
* @return The title of the page
*/
+ @SuppressWarnings("static-method")
protected String getPageTitle(FreenetRequest request) {
return null;
}
*
* @return Additional style sheets to load
*/
+ @SuppressWarnings("static-method")
protected Collection<String> getStyleSheets() {
return Collections.emptySet();
}
*
* @return The URL of the shortcut icon, or {@code null} for no icon
*/
+ @SuppressWarnings("static-method")
protected String getShortcutIcon() {
return null;
}
* The request that is processed
* @return The URL to redirect to, or {@code null} to not redirect
*/
+ @SuppressWarnings("static-method")
protected String getRedirectTarget(FreenetRequest request) {
return null;
}
* The request for which to return the link nodes
* @return All link nodes that should be added to the HTML head
*/
+ @SuppressWarnings("static-method")
protected List<Map<String, String>> getAdditionalLinkNodes(FreenetRequest request) {
return Collections.emptyList();
}
* @return {@code true} if this page should only be allowed for hosts with
* full access, {@code false} to allow this page for any host
*/
+ @SuppressWarnings("static-method")
protected boolean isFullAccessOnly() {
return false;
}
Page.Options.Option.ShowAvatars.Followed.Description=Nur benutzerdefinierte Avatare von Sones, denen Sie folgen, anzeigen.
Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Nur benutzerdefinierte Avatare von Sones, denen Sie manuell einen Vertrauenswert von mehr als 0 zugewiesen haben, anzeigen.
Page.Options.Option.ShowAvatars.Trusted.Description=Nur benutzerdefinierte Avatare von Sones, die einen berechneten Vertrauenswert von mehr als 0 haben, anzeigen.
-Page.Options.Option.ShowAvatars.Always.Description=Immer benutzerdefinierte Avatare anzeigen. Warnung: Benutzerdefinierte Avatare können beliebiges Bildmaterial enthalten!
+Page.Options.Option.ShowAvatars.Always.Description=Immer benutzerdefinierte Avatare anzeigen. Warnung: Benutzerdefinierte Avatare können beliebiges Bildmaterial enthalten!
Page.Options.Section.RuntimeOptions.Title=Laufzeitverhalten
Page.Options.Option.InsertionDelay.Description=Anzahl der Sekunden, die vor dem Hochladen einer Sone nach einer Änderung gewartet wird.
Page.Options.Option.PostsPerPage.Description=Anzahl der Nachrichten pro Seite.
+Page.Options.Option.ImagesPerPage.Description=Anzahl der Bilder pro Seite.
Page.Options.Option.CharactersPerPost.Description=Die Anzahl der Zeichen, die eine Nachricht enthalten muss, damit sie gekürzt angezeigt wird (-1 für „nie kürzen“). Die Anzahl der tatsächlich angezeigten Zeichen wird in der nächsten Option konfiguriert.
Page.Options.Option.PostCutOffLength.Description=Die Anzahl der Zeichen, die von einer gekürzten Nachricht sichtbar sind (siehe Option hierüber).
Page.Options.Option.RequireFullAccess.Description=Zugriff auf Sone für alle Rechner, die keinen vollen Zugriff haben, unterbinden.
Page.Index.Button.Post=Abschicken!
Page.Index.PostList.Title=Nachrichtenliste
Page.Index.PostList.Text.NoPostYet=Bisher hat noch niemand etwas geschrieben. Sie sollten sofort damit anfangen!
+Page.Index.PostList.Text.FollowSomeSones=Oder vielleicht folgen Sie gar keinen Sones? Werfen Sie doch mal einen Blick auf {link}bekannte Sones{/link} und folgen Sie Sones, die interessant aussehen!
Page.New.Title=Neue Nachrichten und Antworten - Sone
Page.New.Page.Title=Neue Nachrichten und Antworten
WebInterface.DefaultText.EditImage.Title=Bildtitel
WebInterface.DefaultText.EditImage.Description=Bildbeschreibung
WebInterface.DefaultText.Option.PostsPerPage=Anzahl der Nachrichten pro Seite
+WebInterface.DefaultText.Option.ImagesPerPage=Anzahl der Bilder pro Seite
WebInterface.DefaultText.Option.CharactersPerPost=Anzahl der Zeichen, die eine Nachricht haben muss, damit er gekürzt wird
-WebInterface.DefaultText.Option.PostCutOffLength=Anzahl der Zeichen, die von einer gekürzten Nachricht angezeigt werden
+WebInterface.DefaultText.Option.PostCutOffLength=Anzahl der Zeichen, die von einer gekürzten Nachricht angezeigt werden
WebInterface.DefaultText.Option.PositiveTrust=Der positive Vertrauenswert
WebInterface.DefaultText.Option.NegativeTrust=Der negative Vertrauenswert
WebInterface.DefaultText.Option.TrustComment=Der Kommentar für die Vertrauenszuweisung
WebInterface.ClickToShow.Replies=Hier klicken, um ausgeblendete Antworten zu zeigen.
WebInterface.VersionInformation.CurrentVersion=Aktuelle Version:
WebInterface.VersionInformation.LatestVersion=Neueste Version:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Hier klicken, um den vollen Text der Benachrichtigung zu lesen.
Notification.FirstStart.Text=Es scheint, als wäre dies das erste Mal, dass Sie Sone starten. Legen Sie eine neue Sone an und folgen Sie anderen Sones!
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.ImagesPerPage.Description=The number of images 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). The actual length of the snippet is determined by the option below.
Page.Options.Option.PostCutOffLength.Description=The number of characters that are displayed if a post is deemed to long (see option above).
Page.Options.Option.RequireFullAccess.Description=Whether to deny access to Sone to any host that has not been granted full access.
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.Index.PostList.Text.FollowSomeSones=Or maybe you are not following any Sones? Take a look at the list of {link}known Sones{/link} and follow whoever looks interesting!
Page.New.Title=New Posts and Replies - Sone
Page.New.Page.Title=New Posts and Replies
WebInterface.DefaultText.EditImage.Title=Image title
WebInterface.DefaultText.EditImage.Description=Image description
WebInterface.DefaultText.Option.PostsPerPage=Number of posts to show on a page
+WebInterface.DefaultText.Option.ImagesPerPage=Number of images to show on a page
WebInterface.DefaultText.Option.CharactersPerPost=Number of characters a post must have to be shortened
WebInterface.DefaultText.Option.PostCutOffLength=Number of characters for the snippet of the shortened post
WebInterface.DefaultText.Option.PositiveTrust=The positive trust to assign
WebInterface.ClickToShow.Replies=Click here to show hidden replies.
WebInterface.VersionInformation.CurrentVersion=Current Version:
WebInterface.VersionInformation.LatestVersion=Latest Version:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Click here to read the full text of the notification.
Notification.FirstStart.Text=This seems to be the first time you start Sone. To start, create a new Sone from a web of trust identity and start following other Sones.
Page.Options.Section.RuntimeOptions.Title=Comportement runtime
Page.Options.Option.InsertionDelay.Description=Le nombre de secondes que l'inserteur de Sone attends après une modification d'un Sone avant qu'elle soit insérée.
Page.Options.Option.PostsPerPage.Description=Le nombre de message à afficher par page avant que les boutons de contrôle de page sont affichés.
+Page.Options.Option.ImagesPerPage.Description=The number of images to display on a page before pagination controls are being shown.
Page.Options.Option.CharactersPerPost.Description=Le nombre de caractères à afficher par message avant que le lien proposant de voir l'intégralité ne soit proposé (-1 pour désactiver). La taille du composant est determinée par l'option ci-desssous.
Page.Options.Option.PostCutOffLength.Description=Le nombre de charactère à afficher avant que le message ne soit considéré comme trops long. (voir option du dessus)
Page.Options.Option.RequireFullAccess.Description=Que ce soit pour refuser l'accès à Sone à tout hôte à qui un accès complet n'a pas été accordé.
Page.Index.Button.Post=Envoyer!
Page.Index.PostList.Title=Envoyer du contenu
Page.Index.PostList.Text.NoPostYet=Personne n'a encore écrit de message. vous devriez probablement commencer maintenant!
+Page.Index.PostList.Text.FollowSomeSones=Or maybe you are not following any Sones? Take a look at the list of {link}known Sones{/link} and follow whoever looks interesting!
Page.New.Title=Nouveaux messages et réponses - Sone
Page.New.Page.Title=Nouveaux messages et réponses
WebInterface.DefaultText.EditImage.Title=Image title
WebInterface.DefaultText.EditImage.Description=Image description
WebInterface.DefaultText.Option.PostsPerPage=Nombre de messages à afficher par page
+WebInterface.DefaultText.Option.ImagesPerPage=Number of images to show on a page
WebInterface.DefaultText.Option.CharactersPerPost=Number of characters a post must have to be shortened
WebInterface.DefaultText.Option.PostCutOffLength=Number of characters for the snippet of the shortened post
WebInterface.DefaultText.Option.PositiveTrust=La note de confiance positive à assigner
WebInterface.ClickToShow.Replies=Cliquer ici pour afficher les réponses cachées.
WebInterface.VersionInformation.CurrentVersion=Version actuelle:
WebInterface.VersionInformation.LatestVersion=Dernière version:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Cliquer ici pour lire le texte entier de la notification.
Notification.FirstStart.Text=Il semble que ce soit la première fois que vous démarrez Sone. Pour démarrer, créez un nouveau Sone depuis une identité Web of Trust et commencez à suivre d'autres Sones.
Notification.Mention.ShortText=Vous avez été mentionné.
Notification.Mention.Text=Vous avez été mentionné dans les messages suivants:
Notification.SoneInsert.Duration={0,number} {0,choice,0#seconds|1#second|1<seconds}
+#to update: 58, 99, 232 (?), 239, 241, 404-411, 413-415, 428, 452 (?)
\ No newline at end of file
Page.Options.Section.RuntimeOptions.Title=Oppførsel ved kjøretid
Page.Options.Option.InsertionDelay.Description=Antall sekunder Sone-innsetteren skal vente etter en endring av en Sone før den blir innsatt.
Page.Options.Option.PostsPerPage.Description=Antallet innlegg å vise pr side før side-kontroller blir vist.
+Page.Options.Option.ImagesPerPage.Description=The number of images to display on a page before pagination controls are being shown.
Page.Options.Option.CharactersPerPost.Description=Antall tegn å vise fra et innlegg før resten blir skjult og en link blir vist for å utvide til hele innlegget (-1 for å deaktivere). Lengden på den viste teksten kan endres under.
Page.Options.Option.PostCutOffLength.Description=Antallet tegn som blir vist hvis et innlegg er for langt (Se innstilling over).
Page.Options.Option.RequireFullAccess.Description=For å avslå tilgang til Sone fra enhver host som ikke har blitt gitt full tilgang.
Page.Index.Button.Post=Publiser!
Page.Index.PostList.Title=Innleggsstrøm
Page.Index.PostList.Text.NoPostYet=Ingen har skrevet noen innlegg enda. Du burde starte med en gang!
+Page.Index.PostList.Text.FollowSomeSones=Or maybe you are not following any Sones? Take a look at the list of {link}known Sones{/link} and follow whoever looks interesting!
Page.New.Title=Nye innlegg og svar - Sone
Page.New.Page.Title=Nye innlegg og svar
WebInterface.DefaultText.EditImage.Description=Bildebeskrivelse
WebInterface.DefaultText.EditImage.Title=Bildetittel
WebInterface.DefaultText.Option.PostsPerPage=Antall innlegg å vise på en side
+WebInterface.DefaultText.Option.ImagesPerPage=Number of images to show on a page
WebInterface.DefaultText.Option.CharactersPerPost=Antall tegn et innlegg må ha for å bli skjult.
WebInterface.DefaultText.Option.PostCutOffLength=Antall tegn som vises når et innlegg blir skjult
WebInterface.DefaultText.Option.PositiveTrust=Positiv tillit å gi
WebInterface.ClickToShow.Replies=Klikk her for å vise skjulte svar.
WebInterface.VersionInformation.CurrentVersion=Gjeldende utgave:
WebInterface.VersionInformation.LatestVersion=Siste utgave:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Klikk her for å lese hele varslingen.
Notification.FirstStart.Text=Dette ser ut til å være første gang du starter Sone. For å starte, lag en ny Sone fra et 'Web Of Trust'-pseudonym og start å følge andre Soner.
Notification.Mention.ShortText=Du har blitt nevnt:
Notification.Mention.Text=Du har blitt nevnt i følgende innlegg:
Notification.SoneInsert.Duration={0,number} {0,choice,0#sekund|1#sekund|1<sekunder}
+# to update: 58, 99, 413, 428
\ No newline at end of file
Page.Options.Page.Description=Te opcje wpływaja na pracę wtyczki Sone.
Page.Options.Section.SoneSpecificOptions.Title=Sone-Konkretne Opcje
Page.Options.Section.SoneSpecificOptions.NotLoggedIn=Opcje dostępne po zalogowaniu {link}zalogowany{/link}.
-Page.Options.Section.SoneSpecificOptions.LoggedIn=Opcje dostępne po zalogowaniu dla aktualnie używanego profilu Sone.
+Page.Options.Section.SoneSpecificOptions.LoggedIn=Opcje dostępne po zalogowaniu dla aktualnie używanego profilu Sone.
Page.Options.Option.AutoFollow.Description=Śledź automatycznie nowych uzytkowników Sone. Śledzeni będą tylko użytkownicy Sone odnalezieni po uruchomieniu tej opcji!
Page.Options.Option.EnableSoneInsertNotifications.Description=Włączenie tej opcji uruchamia powiadomienia o tym, że twój Sone jest wysyłany lub zakończył wysyłanie na serwer.
Page.Options.Option.ShowNotificationNewSones.Description=Pokaż powiadomienie o nowych użytkownikach Sone.
Page.Options.Option.ShowAvatars.Never.Description=Nigdy nie pokazuj niestandardowych avatarów.
Page.Options.Option.ShowAvatars.Followed.Description=Pokazuj avatary tylko śledzonych użytkowników Sone.
Page.Options.Option.ShowAvatars.ManuallyTrusted.Description=Pokazuj avatary tylko tych użytkowników Sone, którym ręcznie przyznałeś ilość punktów zaufania przekraczającą 0.
-Page.Options.Option.ShowAvatars.Trusted.Description=Pokazuj avatary tylko tych użytkowników Sone, którzy mają ilość punktów zaufania większą niż 0.
-Page.Options.Option.ShowAvatars.Always.Description=Zawsze pokazuj niestandardowe avatary. Uwaga: niektóre avatary mogą zawierać obraźliwe treści.
+Page.Options.Option.ShowAvatars.Trusted.Description=Pokazuj avatary tylko tych użytkowników Sone, którzy mają ilość punktów zaufania większą niż 0.
+Page.Options.Option.ShowAvatars.Always.Description=Zawsze pokazuj niestandardowe avatary. Uwaga: niektóre avatary mogą zawierać obraźliwe treści.
Page.Options.Section.RuntimeOptions.Title=Tryb pracy
-Page.Options.Option.InsertionDelay.Description=Czas oczekiwania użytkownika Sone na modifikację profilu Sone przed jego załadowaniem.
+Page.Options.Option.InsertionDelay.Description=Czas oczekiwania użytkownika Sone na modifikację profilu Sone przed jego załadowaniem.
Page.Options.Option.PostsPerPage.Description=Ilość postów wyświetlanych na stronie przed pojawieniem się znaków paginacji.
-Page.Options.Option.CharactersPerPost.Description=Ilość znaków pokazywanych w poście zanim zostanie on obcięty i pojawi się link do jego rozszerzenia (-1 powoduje wyłączenie). Długość fragmentu zależy od poniższej opcji.
+Page.Options.Option.ImagesPerPage.Description=The number of images to display on a page before pagination controls are being shown.
+Page.Options.Option.CharactersPerPost.Description=Ilość znaków pokazywanych w poście zanim zostanie on obcięty i pojawi się link do jego rozszerzenia (-1 powoduje wyłączenie). Długość fragmentu zależy od poniższej opcji.
Page.Options.Option.PostCutOffLength.Description=Ilość znaków wyświetlanych w przypadku za długiego postu (zobacz opcję powyżej).
-Page.Options.Option.RequireFullAccess.Description=Opcja odmowy dostępu do Sone hostom bez przyznanego pełnego dostępu.
+Page.Options.Option.RequireFullAccess.Description=Opcja odmowy dostępu do Sone hostom bez przyznanego pełnego dostępu.
Page.Options.Section.TrustOptions.Title=Ustawienia Zaufania
-Page.Options.Option.PositiveTrust.Description=Punkty pozytywnego zaufania, które chcesz przyznać innym użytkownikom Sone klikając na ikonę pod postem lub odpowiedzią.
-Page.Options.Option.NegativeTrust.Description=Punkty zaufania, które chcesz przyznać innym użytkownikom Sone klikając na czerwony krzyżyk pod postem lub odpowiedzią. Wartosć powinna być negatywna.
-Page.Options.Option.TrustComment.Description=Komentarz, który wyświetli się w sieci zaufania w momencie przyznawania punktów zaufania w obrębie Sone.
-Page.Options.Section.FcpOptions.Title=Ustawienia Interfejsu FCP
-Page.Options.Option.FcpInterfaceActive.Description=Uruchom interfejs FCP, aby umożliwić innym wtyczkom i klientom zdalnym dostęp do twojej wtyczki Sone.
+Page.Options.Option.PositiveTrust.Description=Punkty pozytywnego zaufania, które chcesz przyznać innym użytkownikom Sone klikając na ikonę pod postem lub odpowiedzią.
+Page.Options.Option.NegativeTrust.Description=Punkty zaufania, które chcesz przyznać innym użytkownikom Sone klikając na czerwony krzyżyk pod postem lub odpowiedzią. Wartosć powinna być negatywna.
+Page.Options.Option.TrustComment.Description=Komentarz, który wyświetli się w sieci zaufania w momencie przyznawania punktów zaufania w obrębie Sone.
+Page.Options.Section.FcpOptions.Title=Ustawienia Interfejsu FCP
+Page.Options.Option.FcpInterfaceActive.Description=Uruchom interfejs FCP, aby umożliwić innym wtyczkom i klientom zdalnym dostęp do twojej wtyczki Sone.
Page.Options.Option.FcpFullAccessRequired.Description=Wymagane połączenie FCP dla hostów z dostępem (patrz twoja {link}konfiguracja Freenet, sekcja “FCP”{/link})
Page.Options.Option.FcpFullAccessRequired.Value.No=Nie
Page.Options.Option.FcpFullAccessRequired.Value.Writing=Dostęp z zapisem
Page.Options.Section.Cleaning.Title=Wyczyść
Page.Options.Option.ClearOnNextRestart.Description=Przy kolejnym uruchomieniu zresetuj ustawienia wtyczki Sone. Uwaga!{strong}Wszystkie twoje profile Sone zostaną zniszczone{/strong}upewnij się, że wykonano kopie zapasowe wszystkich niezbędnych danych! Wymagane wybranie odpowiedzi "tak" w następnej opcji.
Page.Options.Option.ReallyClearOnNextRestart.Description=Wymagane wybranie opcji"tak"jeśli {strong}naprawdę{/strong} jesteś zdecydowany zresetować ustawienia wtyczki konfiguracyjnej przy kolejnym uruchomieniu.
-Page.Options.Warnings.ValueNotChanged=Opcja nie została zmieniona, ponieważ wprowadzono błędną wartość.
+Page.Options.Warnings.ValueNotChanged=Opcja nie została zmieniona, ponieważ wprowadzono błędną wartość.
Page.Options.Button.Save=Zapisz
Page.Login.Title=Login - Sone
Page.Index.Label.Sender=Autor:
Page.Index.Button.Post=Napisz!
Page.Index.PostList.Title=Wątek
-Page.Index.PostList.Text.NoPostYet=Nie ma jeszcze żądnych postów. Można rozpocząć pisanie wątku!
+Page.Index.PostList.Text.NoPostYet=Nie ma jeszcze żądnych postów. Można rozpocząć pisanie wątku!
+Page.Index.PostList.Text.FollowSomeSones=Or maybe you are not following any Sones? Take a look at the list of {link}known Sones{/link} and follow whoever looks interesting!
Page.New.Title=Nowe Posty i Odpowiedzi - Sone
Page.New.Page.Title=Nowe Posty i Odpowiedzi
Page.KnownSones.Filter.NotNew=Ukryj nowe Sone
Page.KnownSones.Button.Apply=Zastosuj
Page.KnownSones.Button.FollowAllSones=Śledź wszystkie Sone na tej stronie
-Page.KnownSones.Button.UnfollowAllSones=Przestań śledzić wszystkie Sone na tej stronie
+Page.KnownSones.Button.UnfollowAllSones=Przestań śledzić wszystkie Sone na tej stronie
Page.EditProfile.Title=Edytuj Profil - Sone
-Page.EditProfile.Page.Title=Edytuj Profil
+Page.EditProfile.Page.Title=Edytuj Profil
Page.EditProfile.Page.Description=Na tej stronie uzyskasz dostęp do swoich danych profilowych.
Page.EditProfile.Page.Hint.Optionality=Pamiętaj, każde pole w profilu jest opcjonalne! Nie musisz nic wpisywać! Wszystko co wpiszesz będzie bardzo długo przechowywane na Freenet!
Page.EditProfile.Label.FirstName=Imię:
Page.EditProfile.Avatar.Description=Możesz ustawić jako avatar jedno z załadowanych zdjęć. Nie może być większe niż 64×64 pikseli, poniważ jest to największy rozmiar zdjęć wyświetlanych u innych osób (80×80 pikseli jest stosowany jako nagłówek strony).
Page.EditProfile.Avatar.Delete=Brak avataru
Page.EditProfile.Fields.Title=Pola niestandardowe
-Page.EditProfile.Fields.Description=Tutaj możesz wprowadzać pola nistandardowe do profilu. Pola mogą zawierać dowolne treści oraz dowolą ilość tekstu. Należy pamiętać, że ze względu na anonimowość często mniej znaczy więcej.
+Page.EditProfile.Fields.Description=Tutaj możesz wprowadzać pola nistandardowe do profilu. Pola mogą zawierać dowolne treści oraz dowolą ilość tekstu. Należy pamiętać, że ze względu na anonimowość często mniej znaczy więcej.
Page.EditProfile.Fields.Button.Edit=Edytuj
Page.EditProfile.Fields.Button.MoveUp=Idź do góry
Page.EditProfile.Fields.Button.MoveDown=Idź na dół
Page.EditProfileField.Title=Edytuj profil - Sone
Page.EditProfileField.Page.Title=Edytuj profil
-Page.EditProfileField.Text=Wprowadź nową nazwę dla tego profilu
+Page.EditProfileField.Text=Wprowadź nową nazwę dla tego profilu
Page.EditProfileField.Error.DuplicateFieldName=Wprowadzona nazwa pola już istnieje.
Page.EditProfileField.Button.Save=Zmień
Page.EditProfileField.Button.Reset=Wróć do poprzedniej nazwy
Page.DeleteProfileField.Title=Usuń profil - Sone
Page.DeleteProfileField.Page.Title=Usuń profil
-Page.DeleteProfileField.Text=Czy naprawdę chcesz usunąć ten profil?
-Page.DeleteProfileField.Button.Yes=Tak, usuń.
+Page.DeleteProfileField.Text=Czy naprawdę chcesz usunąć ten profil?
+Page.DeleteProfileField.Button.Yes=Tak, usuń.
Page.DeleteProfileField.Button.No=Nie, nie usuwaj.
Page.CreatePost.Title=Napisz post - Sone
Page.ViewSone.Title=Zobacz Sone - Sone
Page.ViewSone.Page.TitleWithoutSone=Zobacz nieznany Sone
-Page.ViewSone.NoSone.Description= Nie ma obecnie Sone z tym ID {sone}. Jesli szukasz konkretnego użytkownika to upewnij się, że jest widoczny w twojej sieci zaufania.
-Page.ViewSone.UnknownSone.Description=Ten Sone nie został jeszcze odzyskany. Proszę sprawdzić za chwilę.
-Page.ViewSone.UnknownSone.LinkToWebOfTrust=Ten Sone nie jest jeszcze znany, ale jego profil w Sieci Zaufania może być już dostępny.
+Page.ViewSone.NoSone.Description= Nie ma obecnie Sone z tym ID {sone}. Jesli szukasz konkretnego użytkownika to upewnij się, że jest widoczny w twojej sieci zaufania.
+Page.ViewSone.UnknownSone.Description=Ten Sone nie został jeszcze odzyskany. Proszę sprawdzić za chwilę.
+Page.ViewSone.UnknownSone.LinkToWebOfTrust=Ten Sone nie jest jeszcze znany, ale jego profil w Sieci Zaufania może być już dostępny.
Page.ViewSone.WriteAMessage=Tu możesz napisać wiadomość do tego Sone. Każdy będzie mógł zobaczyć tą wiadomość!
Page.ViewSone.PostList.Title=Posty {sone}
Page.ViewSone.PostList.Text.NoPostYet=Ten Sone nie ma jeszcze żadnych postów.
Page.ViewSone.Profile.Label.Name=Nazwa
Page.ViewSone.Profile.Label.Albums=Album
Page.ViewSone.Profile.Albums.Text.All=Wszystkie albumy
-Page.ViewSone.Profile.Name.WoTLink=Profil
+Page.ViewSone.Profile.Name.WoTLink=Profil
Page.ViewSone.Replies.Title=Posty, na które odpowiedział {sone}
Page.ViewPost.Title=Zobacz Post - Sone
Page.DeletePost.Title=Usuń Sone - Sone
Page.DeletePost.Page.Title=Usuń Sone
-Page.DeletePost.Text.PostWillBeGone=Usunięty post nie będzie widoczny na twoim Sone. Nie zostanie jednak usunięty z Freenetu, ponieważ nie ma takiej możliwości. Starsze wersje twojego Sone będą zawsze zawierały usunięte posty.
+Page.DeletePost.Text.PostWillBeGone=Usunięty post nie będzie widoczny na twoim Sone. Nie zostanie jednak usunięty z Freenetu, ponieważ nie ma takiej możliwości. Starsze wersje twojego Sone będą zawsze zawierały usunięte posty.
Page.DeletePost.Button.Yes=Tak, usuń.
Page.DeletePost.Button.No=Nie, nie usuwaj.
Page.DeleteReply.Title=Usuń odpowiedź - Sone
Page.DeleteReply.Page.Title=Usuń odpowiedź
-Page.DeleteReply.Text.PostWillBeGone= Usunięta odpowiedź nie będzie widoczna na twoim Sone. Nie zostanie jednak usunięta z Freenet, ponieważ nie ma takiej możlowość. Starsze wersje twojego Sone zawsze będa zawierały usunięte odpowiedzi.
+Page.DeleteReply.Text.PostWillBeGone= Usunięta odpowiedź nie będzie widoczna na twoim Sone. Nie zostanie jednak usunięta z Freenet, ponieważ nie ma takiej możlowość. Starsze wersje twojego Sone zawsze będa zawierały usunięte odpowiedzi.
Page.DeleteReply.Button.Yes=Tak, usuń.
Page.DeleteReply.Button.No=Nie, nie usuwaj.
Page.ImageBrowser.Title=Wyszukiwarka Obrazów - Sone
Page.ImageBrowser.Album.Title=Album “{album}”
-Page.ImageBrowser.Album.Error.NotFound.Text=Nie można znaleźć żądanego albumu. Prawdopodobnie nie został jeszcze ściagnięty, albo został usunięty.
+Page.ImageBrowser.Album.Error.NotFound.Text=Nie można znaleźć żądanego albumu. Prawdopodobnie nie został jeszcze ściagnięty, albo został usunięty.
Page.ImageBrowser.Sone.Title=Albumy {sone}
-Page.ImageBrowser.Sone.Error.NotFound.Text=Nie można znaleźć żądanego Sone. Prawdopodobnie nie został jeszcze ściągnięty.
+Page.ImageBrowser.Sone.Error.NotFound.Text=Nie można znaleźć żądanego Sone. Prawdopodobnie nie został jeszcze ściągnięty.
Page.ImageBrowser.Header.Albums=Albumy
Page.ImageBrowser.Header.Images=Obrazy
Page.ImageBrowser.Link.All=Wszystkie Sone
Page.ImageBrowser.Image.Button.MoveLeft=◀
Page.ImageBrowser.Image.Button.Save=Zapisz Obraz
Page.ImageBrowser.Image.Button.MoveRight=►
-Page.ImageBrowser.Image.Delete.Title=Usuń Obraz
+Page.ImageBrowser.Image.Delete.Title=Usuń Obraz
Page.ImageBrowser.Image.Button.Delete=Usuń Obraz
Page.CreateAlbum.Title=Utwórz Album - Sone
Page.DeleteImage.Page.Title=Usuń Obraz
Page.DeleteImage.Text.ImageWillBeGone=Obraz “{image}” zostanie usunięty z twojego albumu “{album}”. Jeśli został już umieszczony na Freenet to nie bedzie można go usunąć. Czy chcesz usunąć obraz?
Page.DeleteImage.Button.Yes=Tak, usuń obraz.
-Page.DeleteImage.Button.No=Nie, nie usuwaj obrazu.
+Page.DeleteImage.Button.No=Nie, nie usuwaj obrazu.
Page.EditAlbum.Title=Edytuj Album
Page.Unbookmark.Title=Usuń zakładkę - Sone
Page.Bookmarks.Title=Zakładka - Sone
Page.Bookmarks.Page.Title=Zakładki
-Page.Bookmarks.Text.NoBookmarks= Nie masz obecnie żadnych zakładek. Możesz dodać posty do zakładek klikając gwiazdkę poniżej postu.
+Page.Bookmarks.Text.NoBookmarks= Nie masz obecnie żadnych zakładek. Możesz dodać posty do zakładek klikając gwiazdkę poniżej postu.
Page.Bookmarks.Text.PostsNotLoaded=Niektóre z zaznaczonych przez ciebie postów nie zostały wyświetlone, ponieważ wystąpił problem z ich załadowaniem. Dzieje się tak, jeśli Sone było niedawno restartowane, lub gdy posty zostały usunięte. Jeśli jesteś pewien, że posty zostały usunięte, to możesz je {link}odznaczyć{/link}.
Page.Search.Title=Szukaj - Sone
-Page.Search.Page.Title=Szukaj
-Page.Search.Text.SoneHits=Następujące Sone pasuja do twoich wyników wyszukiwania.
-Page.Search.Text.PostHits=Następujące posty pasują do twoich wyników wyszukiwania.
-Page.Search.Text.NoHits=Nie znaleziono żadnych Sone ani postów pasujących do twoich wyników wyszukiwania.
+Page.Search.Page.Title=Szukaj
+Page.Search.Text.SoneHits=Następujące Sone pasuja do twoich wyników wyszukiwania.
+Page.Search.Text.PostHits=Następujące posty pasują do twoich wyników wyszukiwania.
+Page.Search.Text.NoHits=Nie znaleziono żadnych Sone ani postów pasujących do twoich wyników wyszukiwania.
Page.Rescue.Title=Ratuj Sone
Page.Rescue.Page.Title=Ratuj Sone “{0}”
-Page.Rescue.Text.Description=Tryb Ratunkowy pozwala przywrócić poprzednią wersję twojego Sone. Może to okazać się niezbędne, jeśli twoje ustawienia zostaną utracone.
+Page.Rescue.Text.Description=Tryb Ratunkowy pozwala przywrócić poprzednią wersję twojego Sone. Może to okazać się niezbędne, jeśli twoje ustawienia zostaną utracone.
Page.Rescue.Text.Procedure=Tryb Rarunkowy polega na pobraniu ostatniej wprowadzonej edycji twojego Sone. Jeśli edycja zostanie poprawnie pobrana wówczas zostanie załadowana na twój Sone, co umożliwi zarządzanie twoimi postami, profilem oraz innymi ustawieniami (można to zrobić w nowej zakładce lub oknie przegladarki). Jeśli pobrana edycja różni się od tej, którą chcesz przywrócić, wówczas ustaw Tryb Ratunkowy tak, aby poprał jeszcze wcześniejszą edycję.
-Page.Rescue.Text.Fetching=Tryb Ratunkowy Sone pobiera właśnie edycję {0} twojego Sone.
-Page.Rescue.Text.Fetched=Tryb Ratunkowy Sone pobrał edycję {0} twojego Sone. Sprawdź swoje posty, odpowiedzi oraz profil. Jeśli podoba ci się zawartość aktualnego Sone, to mozesz go odblokować.
+Page.Rescue.Text.Fetching=Tryb Ratunkowy Sone pobiera właśnie edycję {0} twojego Sone.
+Page.Rescue.Text.Fetched=Tryb Ratunkowy Sone pobrał edycję {0} twojego Sone. Sprawdź swoje posty, odpowiedzi oraz profil. Jeśli podoba ci się zawartość aktualnego Sone, to mozesz go odblokować.
Page.Rescue.Text.FetchedLast= Tryb Ratunkowy Sone pobrał ostatnią dostępną edycję. Jeśli nie udało się przywrócić twojego Sone, to nie masz teraz szczęścia.
Page.Rescue.Text.NotFetched=Tryb Ratunkowy Sone nie mógł sćiągnąć edycji {0} twojego Sone. Spróbuj pobrać ponownie edycję {0}, albo pobierz kolejną starszą edycję.
Page.Rescue.Label.NextEdition=Następna edycja:
Page.NoPermission.Title=Nieupoważniony dostęp- Sone
Page.NoPermission.Page.Title=Nieupoważniony dostęp
-Page.NoPermission.Text.NoPermission=Próbowałeś zrobić coś do czego nie masz wystarczającej autoryzacji. Na przyszłość nie podejmuj tego typu działań, albo będziemy zmuszeni podjać odpowiednie kroki.
+Page.NoPermission.Text.NoPermission=Próbowałeś zrobić coś do czego nie masz wystarczającej autoryzacji. Na przyszłość nie podejmuj tego typu działań, albo będziemy zmuszeni podjać odpowiednie kroki.
Page.DismissNotification.Title=Odrzuć powiadomienie - Sone
-Page.WotPluginMissing.Text.WotRequired=Sieć Zaufania jest integralną częścią Sone. Należy załądować wtyczkę Sieci Zaufania, aby móc korzystać z Sone.
+Page.WotPluginMissing.Text.WotRequired=Sieć Zaufania jest integralną częścią Sone. Należy załądować wtyczkę Sieci Zaufania, aby móc korzystać z Sone.
Page.WotPluginMissing.Text.LoadPlugin=Załaduj wtyczkę Sieci Zaufania w {link}menadżerze wtyczek{/link}.
Page.Logout.Title=Wyloguj - Sone
Page.Invalid.Title=Niepoprawne działanie
Page.Invalid.Page.Title=Niepoprawne działanie
-Page.Invalid.Text=Podjęto niepoprawne działanie, lub też działanie było poprawne, ale parametry nie. Wróć do{link}strony głównej{/link} i spróbuj ponownie. Jeśli problem będzie się utrzymywać to najprawdopodobniej znalazłeś błąd.
+Page.Invalid.Text=Podjęto niepoprawne działanie, lub też działanie było poprawne, ale parametry nie. Wróć do{link}strony głównej{/link} i spróbuj ponownie. Jeśli problem będzie się utrzymywać to najprawdopodobniej znalazłeś błąd.
View.Search.Button.Search=Szukaj
View.Sone.Button.UnlockSone=odblokuj
View.Sone.Button.UnlockSone.Tooltip=Pozwala na załadowanie Sone
View.Sone.Button.LockSone=zablokuj
-View.Sone.Button.LockSone.Tooltip=Uniemożliwia załadowanie Sone
+View.Sone.Button.LockSone.Tooltip=Uniemożliwia załadowanie Sone
View.Sone.Button.UnfollowSone=przestań śledzić
View.Sone.Button.FollowSone=śledź
View.Sone.Status.Modified=Ten Sone został zmodyfikowany i czeka na załadowanie
-View.Sone.Status.Unknown=Ten Sone nie został jeszcze odzyskany
+View.Sone.Status.Unknown=Ten Sone nie został jeszcze odzyskany
View.Sone.Status.Idle=Ten Sone nie jest używany, t.j. nie jest ani ładowany ani ściągany.
View.Sone.Status.Downloading=Ten Sone jest właśnie ściągany.
View.Sone.Status.Inserting=Ten Sone jest właśnie ładowany.
View.Post.WebOfTrustLink=Profil sieci zaufania
View.Post.Permalink=linkuj post
View.Post.PermalinkAuthor=linkuj autora
-View.Post.Bookmarks.PostIsBookmarked=Post został oznaczony, kliknij, żeby odznaczyć
-View.Post.Bookmarks.PostIsNotBookmarked=Post nie jest oznaczony, kliknij, żeby dodać do zakładek
+View.Post.Bookmarks.PostIsBookmarked=Post został oznaczony, kliknij, żeby odznaczyć
+View.Post.Bookmarks.PostIsNotBookmarked=Post nie jest oznaczony, kliknij, żeby dodać do zakładek
View.Post.DeleteLink=Usuń
View.Post.SendReply=Wyślij Odpowiedź!
View.Post.Reply.DeleteLink=Usuń
View.Post.LikeLink=Lubię
View.Post.UnlikeLink=Nie lubię
View.Post.ShowSource=Parsowanie
-View.Post.NotDownloaded=Ten post albo nie został jeszcze ściągnięty albo został usunięty.
+View.Post.NotDownloaded=Ten post albo nie został jeszcze ściągnięty albo został usunięty.
View.Post.ShowMore=pokaż więcej
View.Post.ShowLess=pokaż mniej
-View.UpdateStatus.Text.ChooseSenderIdentity=Wybierz tożsamość nadawcy
+View.UpdateStatus.Text.ChooseSenderIdentity=Wybierz tożsamość nadawcy
View.Trust.Tooltip.Trust=Zaufaj tej osobie
View.Trust.Tooltip.Distrust=Przypisz tej osobie nagatywny poziom zaufania
View.UploadImage.Title=Załaduj Obraz
View.UploadImage.Label.Title=Tytuł:
View.UploadImage.Label.Description=Opis:
-View.UploadImage.Button.UploadImage=Załaduj Obraz
+View.UploadImage.Button.UploadImage=Załaduj Obraz
View.Time.InTheFuture=potem
View.Time.AFewSecondsAgo=kilka sekund temu
WebInterface.DefaultText.Message=Napisz Wiadomość…
WebInterface.DefaultText.Reply=Napisz Odpowiedź…
WebInterface.DefaultText.FirstName=Imię
-WebInterface.DefaultText.MiddleName=Drugie imię
+WebInterface.DefaultText.MiddleName=Drugie imię
WebInterface.DefaultText.LastName=Nazwisko
WebInterface.DefaultText.BirthDay=Dzień
WebInterface.DefaultText.BirthMonth=Miesiąc
WebInterface.DefaultText.BirthYear=Rok
WebInterface.DefaultText.FieldName=Nazwa Pola
-WebInterface.DefaultText.Option.InsertionDelay=Czas potrzebny na załadowanie Sone po modyfikacji (w sekundach)
+WebInterface.DefaultText.Option.InsertionDelay=Czas potrzebny na załadowanie Sone po modyfikacji (w sekundach)
WebInterface.DefaultText.Search=Czego szukasz?
WebInterface.DefaultText.CreateAlbum.Name=Tytuł Albumu
WebInterface.DefaultText.CreateAlbum.Description=Opis Albumu
WebInterface.DefaultText.EditImage.Title=Tytuł Obrazka
WebInterface.DefaultText.EditImage.Description=Opis Obrazka
WebInterface.DefaultText.Option.PostsPerPage=Ilość postów wyświetlanych na jednej stronie
-WebInterface.DefaultText.Option.CharactersPerPost=Ilość znaków, które ma zawierać post, aby zostać skrócony
+WebInterface.DefaultText.Option.ImagesPerPage=Number of images to show on a page
+WebInterface.DefaultText.Option.CharactersPerPost=Ilość znaków, które ma zawierać post, aby zostać skrócony
WebInterface.DefaultText.Option.PostCutOffLength=Ilość znaków w skróconym poście
-WebInterface.DefaultText.Option.PositiveTrust=Pozytywny poziom zaufania
+WebInterface.DefaultText.Option.PositiveTrust=Pozytywny poziom zaufania
WebInterface.DefaultText.Option.NegativeTrust=Negatywny poziom zaufania
WebInterface.DefaultText.Option.TrustComment=Komentarz, który zostanie ustawiony w Sieci Zaufania
WebInterface.Button.Comment=Komentuj
WebInterface.SelectBox.Choose=Wybierz…
WebInterface.SelectBox.Yes=Tak
WebInterface.SelectBox.No=Nie
-WebInterface.ClickToShow.Replies=Kliknij, żeby pokazać ukryte odpowiedzi.
+WebInterface.ClickToShow.Replies=Kliknij, żeby pokazać ukryte odpowiedzi.
WebInterface.VersionInformation.CurrentVersion=Aktualna wersja:
WebInterface.VersionInformation.LatestVersion=Najnowsza wersja:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Kliknij tutaj, żeby przeczytać cały tekst powiadomienia.
-Notification.FirstStart.Text=Po raz pierwszy korzystasz z Sone. Zacznij od wybrania nowego Sone z tożsamości z Sieci Zaufania i zacznij śledzić inne Sone.
-Notification.Startup.Text=Sone właśnie się włącza. Należy chwilę poczekać zanim wszystkie tożsamości i Sone z sieci zaufania zostaną odzyskane. Jeśli brakuje jakichś elementów, należy być cierpliwym, najprawdopodobniej wkrótce się pojawią.
-Notification.ConfigNotRead.Text=Plik konfiguracyjny “sone.properties” nie mógł zostać odczytany, prawdopodobnie dlatego, że nie został poprawnie zapisany. Dotyczy to wersji wcześniejszych niż Sone 0.3.3 i nie można nic z tym zrobić.
+Notification.FirstStart.Text=Po raz pierwszy korzystasz z Sone. Zacznij od wybrania nowego Sone z tożsamości z Sieci Zaufania i zacznij śledzić inne Sone.
+Notification.Startup.Text=Sone właśnie się włącza. Należy chwilę poczekać zanim wszystkie tożsamości i Sone z sieci zaufania zostaną odzyskane. Jeśli brakuje jakichś elementów, należy być cierpliwym, najprawdopodobniej wkrótce się pojawią.
+Notification.ConfigNotRead.Text=Plik konfiguracyjny “sone.properties” nie mógł zostać odczytany, prawdopodobnie dlatego, że nie został poprawnie zapisany. Dotyczy to wersji wcześniejszych niż Sone 0.3.3 i nie można nic z tym zrobić.
Notification.Button.Dismiss=Odrzuć
Notification.NewSone.ShortText=Znaleziono nowe Sone:
Notification.NewSone.Text=Znaleziono nowe Sone:
Notification.NewPost.Button.MarkRead=Oznacz jako przeczytane
Notification.NewReply.ShortText=Znaleziono nowe odpowiedzi.
Notification.NewReply.Text=Znaleziono nowe odpowiedzi napisane przez poniższych użytkowników Sone:
-Notification.SoneIsBeingRescued.Text=Następujące Sone są aktualnie odzyskiwane:
+Notification.SoneIsBeingRescued.Text=Następujące Sone są aktualnie odzyskiwane:
Notification.SoneRescued.Text=Odzyskano następujące Sone:
Notification.SoneRescued.Text.RememberToUnlock=Należy pamiętać o zarządzaniu napisanymi postami i odpowiedziami oraz nie zapomnieć o odblokowaniu swoich Sone!
-Notification.LockedSones.Text=Następujące Sone są zablokowane od ponad 5 minut. Sprawdź czy chcesz, żeby pozostały zablokowane.
+Notification.LockedSones.Text=Następujące Sone są zablokowane od ponad 5 minut. Sprawdź czy chcesz, żeby pozostały zablokowane.
Notification.NewVersion.Text=Znaleziono wersję {version}wtyczki Sone. Ściągnij ją z USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/{edition}!
Notification.InsertingImages.Text=Ładowane są następujące obrazy:
Notification.InsertedImages.Text=Załadowano nastepujące obrazy:
Notification.Mention.ShortText=Zostałeś oznaczony.
Notification.Mention.Text=Zostałeś oznaczony w następujących postach:
Notification.SoneInsert.Duration={0,number} {0,choice,0#seconds|1#second|1<seconds}
+# to update: 58, 99, 413, 428
Page.Options.Section.RuntimeOptions.Title=Поведение во время работы.
Page.Options.Option.InsertionDelay.Description=Количество секунд, в течение которых выгрузчик Sone ожидает после изменения Sone до того, как он будет выгружен.
Page.Options.Option.PostsPerPage.Description=Количество сообщений, которое должно быть показно на странице до того, как будут показаны кнопки переключения страниц.
+Page.Options.Option.ImagesPerPage.Description=The number of images to display on a page before pagination controls are being shown.
Page.Options.Option.CharactersPerPost.Description=Количество символов сообщения, которые должны быть показаны до того, как оно будет обрезано и будет показана ссылка для его раскрытия (-1 для отключения). Фактическая длина обрезанного сообщения задается нижеследующей настройкой.
Page.Options.Option.PostCutOffLength.Description=Количество символов, которые показываются, если сообщение посчитано слишком длинным (см. настройку выше).
Page.Options.Option.RequireFullAccess.Description=Запрещать доступ к Sone любому хосту, которому не был дан полный доступ.
Page.Index.Button.Post=Отправить!
Page.Index.PostList.Title=Лента сообщений
Page.Index.PostList.Text.NoPostYet=Никто еще не написал ни одного сообщения. Вам, наверное, следует начать это прямо сейчас!
+Page.Index.PostList.Text.FollowSomeSones=Or maybe you are not following any Sones? Take a look at the list of {link}known Sones{/link} and follow whoever looks interesting!
Page.New.Title=Новые сообщения и ответы - Sone
Page.New.Page.Title=Новые сообщения и ответы
WebInterface.DefaultText.EditImage.Title=Название изображения
WebInterface.DefaultText.EditImage.Description=Описание изображения
WebInterface.DefaultText.Option.PostsPerPage=Количество сообщений, показываемых на странице
+WebInterface.DefaultText.Option.ImagesPerPage=Number of images to show on a page
WebInterface.DefaultText.Option.CharactersPerPost=Количество символов, которое должно быть у сообщения, чтобы оно было сокращено
WebInterface.DefaultText.Option.PostCutOffLength=Количество символов в сокращенном варианте сообщения
WebInterface.DefaultText.Option.PositiveTrust=Положительное доверие для назначения
WebInterface.ClickToShow.Replies=Нажмите, чтобы показать скрытые ответы.
WebInterface.VersionInformation.CurrentVersion=Текущая версия:
WebInterface.VersionInformation.LatestVersion=Последняя версия:
+WebInterface.VersionInformation.Homepage=Homepage
Notification.ClickHereToRead=Нажмите здесь, чтобы прочитать полный текст уведомления.
Notification.FirstStart.Text=Видимо, вы запустили Sone в первый раз. Чтобы начать, создайте новый Sone из личность web of trust и начните подписываться на другие Sone.
Notification.Mention.ShortText=Вас упомянули.
Notification.Mention.Text=Вас упомянули в следующих сообщениях:
Notification.SoneInsert.Duration={0,number} {0,choice,0#секунд|1#секунда|2#секунды|4<секунд}
+# to update: 58, 99, 413, 428
\ No newline at end of file
float: right;
}
+#sone .clear {
+ clear: both;
+}
+
#sone h1 {
font-family: inherit;
font-size: 200%;
}
function getStatus() {
- ajaxGet("getStatus.ajax", isViewSonePage() ? {"soneIds": getShownSoneId() } : {"loadAllSones": isKnownSonesPage()}, function(data, textStatus) {
+ ajaxGet("getStatus.ajax", isViewSonePage() ? {"soneIds": getShownSoneId() } : isKnownSonesPage() ? {"soneIds": getShownSoneIds() } : {}, function(data, textStatus) {
if ((data != null) && data.success) {
/* process Sone information. */
$.each(data.sones, function(index, value) {
}
/**
+ * Returns the ID of all currently visible Sones. This is mainly used on the
+ * “Known Sones” page.
+ *
+ * @returns The ID of the currently shown Sones
+ */
+function getShownSoneIds() {
+ var soneIds = new Array();
+ $("#sone #known-sones .sone .id").each(function() {
+ soneIds.push($(this).text());
+ });
+ return soneIds.join(",");
+}
+
+/**
* Returns whether the current page is a “view post” page.
*
* @returns {Boolean} <code>true</code> if the current page is a “view post”
<p>Sone – The Freenet Social Network Plugin, Version <% version|html>, © 2010–2012 by David ‘Bombe’ Roden.</p>
<p>
- <%= Page.About.Flattr.Description|l10n|html|replace needle="{link}" replacement='<a href="/?_CHECKED_HTTP_=https://www.flattr.com/" title="Flattr Homepage" target="_blank">'|replace needle="{/link}" replacement='</a>'>
+ <%= Page.About.Flattr.Description|l10n|html|replace needle=="{link}" replacement=='<a href="/?_CHECKED_HTTP_=https://www.flattr.com/" title="Flattr Homepage" target="_blank">'|replace needle=="{/link}" replacement=='</a>'>
</p>
<h2><%= Page.About.Homepage.Title|l10n|html></h2>
<p>
- <%= Page.About.Homepage.Description|l10n|html|replace needle="{link}" replacement='<a href="/USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/49/">'|replace needle="{/link}" replacement='</a>'>
+ <%= Page.About.Homepage.Description|l10n|html|replace needle=="{link}" replacement=='<a href="/USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/49/">'|replace needle=="{/link}" replacement=='</a>'>
</p>
<h2><%= Page.About.License.Title|l10n|html></h2>
<h1><%= Page.Bookmarks.Page.Title|l10n|html></h1>
<div id="posts">
- <%= page|store key=pageParameter>
- <%include include/pagination.html>
+ <%include include/pagination.html pageParameter==page>
<%foreach posts post>
<%include include/viewPost.html>
<%/foreach>
- <%include include/pagination.html>
+ <%include include/pagination.html pageParameter==page>
<%if postsNotLoaded>
- <p><%= Page.Bookmarks.Text.PostsNotLoaded|l10n|html|replace needle='{link}' replacement='<a href="unbookmark.html?post=allNotLoaded">'|replace needle='{/link}' replacement='</a>'></p>
+ <p><%= Page.Bookmarks.Text.PostsNotLoaded|l10n|html|replace needle=='{link}' replacement=='<a href="unbookmark.html?post=allNotLoaded">'|replace needle=='{/link}' replacement=='</a>'></p>
<%elseif posts.empty>
<p><%= Page.Bookmarks.Text.NoBookmarks|l10n|html></p>
<%/if>
<h1><%= Page.DeleteAlbum.Page.Title|l10n|html></h1>
- <p><%= Page.DeleteAlbum.Text.AlbumWillBeGone|l10n|replace needle="{title}" replacementKey=album.title|html></p>
+ <p><%= Page.DeleteAlbum.Text.AlbumWillBeGone|l10n|replace needle=="{title}" replacementKey==album.title|html></p>
<form method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<h1><%= Page.DeleteImage.Page.Title|l10n|html></h1>
- <p><%= Page.DeleteImage.Text.ImageWillBeGone|l10n|replace needle="{image}" replacementKey=image.title|replace needle="{album}" replacementKey=image.album.title|html></p>
+ <p><%= Page.DeleteImage.Text.ImageWillBeGone|l10n|replace needle=="{image}" replacement=image.title|replace needle=="{album}" replacement=image.album.title|html></p>
<form method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
<%include include/head.html>
- <h1><%= Page.DeleteSone.Page.Title|l10n|replace needle="{sone}" replacementKey=currentSone.name|html></h1>
+ <h1><%= Page.DeleteSone.Page.Title|l10n|replace needle=="{sone}" replacement=currentSone.name|html></h1>
<p><%= Page.DeleteSone.Page.Description|l10n|html></p>
<ul id="avatar-selection">
<li id="no-avatar">
- <input type="radio" name="avatar-id" value="none"<%ifnull avatar-image> checked="checked"<%/if>/>
+ <input type="radio" name="avatar-id" value="none"<%ifnull avatar-id> checked="checked"<%/if>/>
<%= Page.EditProfile.Avatar.Delete|l10n|html>
</li>
<%foreach currentSone.allImages image>
<li>
<input type="radio" name="avatar-id" value="<%image.id|html>"<%if avatar-id|match key=image.id> checked="checked"<%/if>/>
- <div class="post-avatar"><% image|image-link max-width=48 max-height=48 mode=enlarge title==image.title></div>
+ <div class="post-avatar"><% image|image-link max-width==48 max-height==48 mode==enlarge title=image.title></div>
</li>
<%/foreach>
</ul>
<h2><%= Page.EditProfile.Fields.AddField.Title|l10n|html></h2>
<%if duplicateFieldName>
- <p><%= Page.EditProfile.Error.DuplicateFieldName|l10n|replace needle="{fieldName}" replacementKey="fieldName"|html></p>
+ <p><%= Page.EditProfile.Error.DuplicateFieldName|l10n|replace needle=="{fieldName}" replacement=fieldName|html></p>
<%/if>
<div id="new-field">
</script>
<%/if>
- <h1 class="backlink"><%= Page.ImageBrowser.Album.Title|l10n|replace needle='{album}' replacementKey=album.title|html></h1>
+ <h1 class="backlink"><%= Page.ImageBrowser.Album.Title|l10n|replace needle=='{album}' replacement=album.title|html></h1>
<div class="backlinks">
<div class="backlink"><a href="imageBrowser.html?mode=gallery"><%= Page.ImageBrowser.Link.All|l10n|html></a></div>
<select name="album-image">
<option disabled="disabled"><%= Page.ImageBrowser.Album.AlbumImage.Choose|l10n|html></option>
<%foreach album.images image>
- <option value="<% image.id|html>"<%if album.albumImage.id|match key=image.id> selected="selected"<%/if>><% image.title|html></option>
+ <option value="<% image.id|html>"<%if album.albumImage.id|match value=image.id> selected="selected"<%/if>><% image.title|html></option>
<%/foreach>
</select>
</div>
</div>
<%/if>
- <%foreach album.images image>
- <%first><h2><%= Page.ImageBrowser.Header.Images|l10n|html></h2><%/first>
- <%if loop.count|mod divisor=3><div class="image-row"><%/if>
+ <%foreach album.images image|paginate pageSize=core.preferences.imagesPerPage page=page>
+ <%first>
+ <h2><%= Page.ImageBrowser.Header.Images|l10n|html></h2>
+ <%include include/pagination.html pageParameter=="page">
+ <%/first>
+ <%if loop.count|mod divisor==3><div class="image-row"><%/if>
<div id="image-<% image.id|html>" class="image">
<div class="image-id hidden"><% image.id|html></div>
<div class="image-container">
- <a href="imageBrowser.html?image=<%image.id|html>"><% image|image-link max-width=250 max-height=250 mode=enlarge title==image.title></a>
+ <a href="imageBrowser.html?image=<%image.id|html>"><% image|image-link max-width==250 max-height==250 mode==enlarge title=image.title></a>
</div>
<div class="show-data">
<div class="image-title"><% image.title|html></div>
</form>
<%/if>
</div>
- <%= false|store key=endRow>
- <%if loop.count|mod divisor=3 offset=1><%= true|store key=endRow><%/if>
- <%last><%= true|store key=endRow><%/last>
- <%if endRow></div><%/if>
+ <%= false|store key==endRow>
+ <%if loop.count|mod divisor==3 offset==1><%= true|store key==endRow><%/if>
+ <%last><%= true|store key==endRow><%/last>
+ <%if endRow>
+ </div>
+ <%include include/pagination.html pageParameter=="page">
+ <%/if>
<%/foreach>
<%if album.sone.local>
- <div class="show-upload-image hidden toggle-link"><a class="small-link">» <%= View.UploadImage.Title|l10n|html></a></div>
- <div class="hide-upload-image hidden toggle-link"><a class="small-link">« <%= View.UploadImage.Title|l10n|html></a></div>
+ <div class="clear show-upload-image hidden toggle-link"><a class="small-link">» <%= View.UploadImage.Title|l10n|html></a></div>
+ <div class="clear hide-upload-image hidden toggle-link"><a class="small-link">« <%= View.UploadImage.Title|l10n|html></a></div>
<div class="upload-image">
<%include include/uploadImage.html>
</div>
<div class="single-image">
<%ifnull !image.key>
- <a href="/<%image.key|html>"><% image|image-link max-width=640 max-height=480></a>
+ <a href="/<%image.key|html>"><% image|image-link max-width==640 max-height==480></a>
<%else>
- <a href="imageBrowser.html?image=<%image.id|html>"><% image|image-link max-width=640 max-height=480></a>
+ <a href="imageBrowser.html?image=<%image.id|html>"><% image|image-link max-width==640 max-height==480></a>
<%/if>
</div>
<%else>
- <h1><%= Page.ImageBrowser.Sone.Title|l10n|replace needle='{sone}' replacementKey=sone.niceName|html></h1>
+ <h1><%= Page.ImageBrowser.Sone.Title|l10n|replace needle=='{sone}' replacement=sone.niceName|html></h1>
<div class="backlinks">
<div class="backlink"><a href="imageBrowser.html?mode=gallery"><%= Page.ImageBrowser.Link.All|l10n|html></a></div>
<%elseif galleryRequested>
- <%foreach albums album>
- <%first><h2><%= Page.ImageBrowser.Header.Albums|l10n|html></h2><%/first>
- <%if loop.count|mod divisor=3><div class="album-row"><%/if>
+ <%foreach albums album|paginate pageSize=core.preferences.imagesPerPage pageParameter=request.page pagination=albumPagination>
+ <%first>
+ <h2><%= Page.ImageBrowser.Header.Albums|l10n|html></h2>
+ <%include include/pagination.html pagination=albumPagination pageParameter=="page">
+ <%/first>
+ <%if loop.count|mod divisor==3><div class="album-row"><%/if>
<div id="album-<% album.id|html>" class="album">
<div class="album-id hidden"><% album.id|html></div>
<div class="album-container">
<%ifnull album.albumImage>
<img src="images/unknown-image-0.png" width="333" height="250" alt="<% album.title|html> (<%album.sone.niceName|html>)" title="<% album.title|html> (<%album.sone.niceName|html>)" style="position: relative; top: 0px; left: -41px;" />
<%else><!-- TODO -->
- <% album.albumImage|image-link max-width=250 max-height=250 mode=enlarge title==album.title>
+ <% album.albumImage|image-link max-width==250 max-height==250 mode==enlarge title=album.title>
<%/if>
</a>
</div>
<div class="album-description"><% album.description|parse sone=album.sone></div>
</div>
</div>
- <%= false|store key=endRow>
- <%if loop.count|mod divisor=3 offset=1><%= true|store key=endRow><%/if>
- <%last><%= true|store key=endRow><%/last>
- <%if endRow></div><%/if>
+ <%= false|store key==endRow>
+ <%if loop.count|mod divisor==3 offset==1><%= true|store key==endRow><%/if>
+ <%last><%= true|store key==endRow><%/last>
+ <%if endRow>
+ </div>
+ <%/if>
+ <%last>
+ <%include include/pagination.html pagination=albumPagination pageParameter=="page">
+ <%/last>
<%/foreach>
<%/if>
<%foreach albums album>
<%first><h2><%= Page.ImageBrowser.Header.Albums|l10n|html></h2><%/first>
- <%if loop.count|mod divisor=3><div class="album-row"><%/if>
+ <%if loop.count|mod divisor==3><div class="album-row"><%/if>
<div id="album-<% album.id|html>" class="album">
<div class="album-id hidden"><% album.id|html></div>
<div class="album-container">
<%ifnull album.albumImage>
<img src="images/unknown-image-0.png" width="333" height="250" alt="<% album.title|html>" title="<% album.title|html>" style="position: relative; top: 0px; left: -41px;" />
<%else><!-- TODO -->
- <% album.albumImage|image-link max-width=250 max-height=250 mode=enlarge title==album.title>
+ <% album.albumImage|image-link max-width==250 max-height==250 mode==enlarge title=album.title>
<%/if>
</a>
</div>
</form>
<%/if>
</div>
- <%= false|store key=endRow>
- <%if loop.count|mod divisor=3 offset=1><%= true|store key=endRow><%/if>
- <%last><%= true|store key=endRow><%/last>
+ <%= false|store key==endRow>
+ <%if loop.count|mod divisor==3 offset==1><%= true|store key==endRow><%/if>
+ <%last><%= true|store key==endRow><%/last>
<%if endRow></div><%/if>
<%/foreach>
<%if !identitiesWithoutSone.empty>
<h1><%= Page.Login.CreateSone.Title|l10n|html></h1>
- <p><%= View.CreateSone.Text.WotIdentityRequired|l10n|html|replace needle="{link}" replacement='<a href="/WebOfTrust/">'|replace needle="{/link}" replacement='</a>'></p>
+ <p><%= View.CreateSone.Text.WotIdentityRequired|l10n|html|replace needle=="{link}" replacement=='<a href="/WebOfTrust/">'|replace needle=="{/link}" replacement=='</a>'></p>
<form id="create-sone" action="createSone.html" method="post">
<input type="hidden" name="formPassword" value="<% formPassword|html>" />
</form>
<%else>
<%if !sones.empty>
- <p><%= View.CreateSone.Text.NoNonSoneIdentities|l10n|html|replace needle="{link}" replacement='<a href="/WebOfTrust/OwnIdentities">'|replace needle="{/link}" replacement="</a>"></p>
+ <p><%= View.CreateSone.Text.NoNonSoneIdentities|l10n|html|replace needle=="{link}" replacement=='<a href="/WebOfTrust/OwnIdentities">'|replace needle=="{/link}" replacement=="</a>"></p>
<%else>
- <p><%= View.CreateSone.Text.NoIdentities|l10n|html|replace needle="{link}" replacement='<a href="/WebOfTrust/OwnIdentities">'|replace needle="{/link}" replacement="</a>"></p>
+ <p><%= View.CreateSone.Text.NoIdentities|l10n|html|replace needle=="{link}" replacement=='<a href="/WebOfTrust/OwnIdentities">'|replace needle=="{/link}" replacement=="</a>"></p>
<%/if>
<%/if>
<a class="picture" href="index.html">
<%ifnull !currentSone>
<%ifnull !currentSone.profile.avatar>
- <%currentSone.profile.avatar|image-link max-width=80 max-height=80 mode=enlarge title="Profile Avatar">
+ <%currentSone.profile.avatar|image-link max-width==80 max-height==80 mode==enlarge title=="Profile Avatar">
<%else>
<img src="/WebOfTrust/GetIdenticon?identity=<% currentSone.id|html>&width=80&height=80" width="80" height="80" alt="Profile Avatar" />
<%/if>
</div>
<%ifnull ! currentSone>
<div id="home-sone">
- <% currentSone|store key=sone>
- <%include include/viewSone.html>
+ <%include include/viewSone.html sone=currentSone>
</div>
<%/if>
<form id="search" action="search.html" method="get">
<%if pagination.necessary>
<div class="navigation <%paginationName|html>">
- <div class="first"><%if ! pagination.first><a href="<% request|change nameKey=pageParameter value=0>">«</a><%else><span>«</span><%/if></div>
- <div class="previous"><%if ! pagination.first><a href="<% request|change nameKey=pageParameter key=pagination.previousPage>">‹</a><%else><span>‹</span><%/if></div>
+ <div class="first"><%if ! pagination.first><a href="<% request|change name=pageParameter value==0>">«</a><%else><span>«</span><%/if></div>
+ <div class="previous"><%if ! pagination.first><a href="<% request|change name=pageParameter value=pagination.previousPage>">‹</a><%else><span>‹</span><%/if></div>
<div class="current-page"><% pagination.pageNumber></div>
<div class="total-pages"><% pagination.pageCount></div>
- <div class="last"><%if ! pagination.last><a href="<% request|change nameKey=pageParameter key=pagination.lastPage>">»</a><%else><span>»</span><%/if></div>
- <div class="next"><%if ! pagination.last><a href="<% request|change nameKey=pageParameter key=pagination.nextPage>">›</a><%else><span>›</span><%/if></div>
+ <div class="last"><%if ! pagination.last><a href="<% request|change name=pageParameter value=pagination.lastPage>">»</a><%else><span>»</span><%/if></div>
+ <div class="next"><%if ! pagination.last><a href="<% request|change name=pageParameter value=pagination.nextPage>">›</a><%else><span>›</span><%/if></div>
</div>
<%/if>
<div class="sone-menu-id hidden"><%sone.id|html></div>
<div class="avatar menu-avatar">
<%ifnull !sone.profile.avatar>
- <%sone.profile.avatar|image-link max-width=64 max-height=64 mode=enlarge title==sone.niceName>
+ <%sone.profile.avatar|image-link max-width==64 max-height==64 mode==enlarge title=sone.niceName>
<%else>
<img src="/WebOfTrust/GetIdenticon?identity=<%sone.id|html>&width=64&height=64" width="64" height="64" alt="Avatar Image" />
<%/if>
<div class="inner-menu">
<div>
<a class="author" href="viewSone.html?sone=<%sone.id|html>"><%sone.niceName|html></a>
- (<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size><%if ! sone.allImages.size|match value=0>, <%= View.Sone.Stats.Images|l10n 0=sone.allImages.size><%/if>)
+ (<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size><%if ! sone.allImages.size|match value==0>, <%= View.Sone.Stats.Images|l10n 0=sone.allImages.size><%/if>)
</div>
<div><a href="/WebOfTrust/ShowIdentity?id=<%sone.id|html>">» <% =View.Post.WebOfTrustLink|l10n|html></a></div>
<%foreach sone.albums album>
<%if hasLatestVersion>
<div class="latest-version"><%= WebInterface.VersionInformation.LatestVersion|l10n|html> <b><% latestVersion|html></b></div>
<%/if>
+ <div class="homepage"><a href="/USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/<%latestEdition|html>/"><%=WebInterface.VersionInformation.Homepage|l10n|html></a></div>
</div>
</div>
<div class="avatar post-avatar" >
<%if post.loaded>
<%ifnull !post.sone.profile.avatar>
- <%post.sone.profile.avatar|image-link max-width=48 max-height=48 mode=enlarge title="Avatar Image">
+ <%post.sone.profile.avatar|image-link max-width==48 max-height==48 mode==enlarge title=="Avatar Image">
<%else>
- <img src="/WebOfTrust/GetIdenticon?identity=<% post.sone.id|html>&width=48&height=48" width="48" height="48" alt="Avatar Image" />
+ <img src="/WebOfTrust/GetIdenticon?identity=<% post.sone.id|html>&width=48&height=48" width="48" height="48" alt="Avatar Image" />
<%/if>
<%else>
<img src="images/sone-avatar.png" width="48" height="48" alt="Avatar Image" />
<div class="recipient profile-link"><a href="viewSone.html?sone=<% post.recipient.id|html>"><% post.recipient.niceName|html></a></div>
<%/if>
<%/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 cut-off-length=core.preferences.postCutOffLength|store key=shortText text=true>
+ <% 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 cut-off-length=core.preferences.postCutOffLength|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><%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>
+ <%if !shortText|match value=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 value=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">
</form>
</div>
<span class='separator'>·</span>
- <div class="time"><a href="viewPost.html?post=<% post.id|html>"><% post.time|date format="MMM d, yyyy, HH:mm:ss"></a></div>
+ <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="permalink permalink-post"><a href="post://<%post.id|html>">[<%= View.Post.Permalink|l10n|html>]</a></div>
<span class='separator'>·</span>
<div class="permalink permalink-author"><a href="sone://<%post.sone.id|html>">[<%= View.Post.PermalinkAuthor|l10n|html>]</a></div>
- <%if ! originalText|match key=parsedText>
+ <%if ! originalText|match value=parsedText>
<span class='separator'>·</span>
<div class="show-source"><a href="viewPost.html?post=<% post.id|html>&raw=<%if raw>false<%else>true<%/if>"><%= View.Post.ShowSource|l10n|html></a></div>
<%/if>
- <div class="likes<%if post.likes.size|match value=0> hidden<%/if>">
+ <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>
<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>
+ <%ifnull !post.sone.trust>
+ <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>
<%if post.sone.local>
<%include include/soneMenu.html class=="sone-reply-menu" sone=reply.sone>
<div class="avatar reply-avatar">
<%ifnull !reply.sone.profile.avatar>
- <% reply.sone.profile.avatar|image-link max-width=36 max-height=36 mode=enlarge title="Avatar Image">
+ <% reply.sone.profile.avatar|image-link max-width==36 max-height==36 mode==enlarge title=="Avatar Image">
<%else>
<img src="/WebOfTrust/GetIdenticon?identity=<% reply.sone.id|html>&width=36&height=36" width="36" height="36" alt="Avatar Image" />
<%/if>
<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>
- <% 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 cut-off-length=core.preferences.postCutOffLength|store key=shortText text=true>
+ <% 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 cut-off-length=core.preferences.postCutOffLength|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><%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>
+ <%if !shortText|match value=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 value=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>
+ <div class="time"><% reply.time|date format=="MMM d, yyyy, HH:mm:ss"></div>
<span class='separator'>·</span>
<div class="permalink permalink-author"><a href="sone://<%reply.sone.id|html>">[<%= View.Post.PermalinkAuthor|l10n|html>]</a></div>
- <%if ! originalText|match key=parsedText>
+ <%if ! originalText|match value=parsedText>
<span class='separator'>·</span>
<div class="show-reply-source"><a href="viewPost.html?post=<% post.id|html>&raw=<%if raw>false<%else>true<%/if>"><%= View.Post.ShowSource|l10n|html></a></div>
<%/if>
- <div class="likes<%if reply.likes.size|match value=0> hidden<%/if>">
+ <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>
<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>
+ <%ifnull !reply.sone.trust>
+ <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>
<%if reply.sone.local>
<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" title="<% sone.time|unknown|date format="MMM d, yyyy, HH:mm:ss">"><%sone.lastUpdatedText|html></span></div>
+ <div class="last-update"><%= View.Sone.Label.LastUpdate|l10n|html> <span class="time" title="<% sone.time|unknown|date format=="MMM d, yyyy, HH:mm:ss">"><%sone.lastUpdatedText|html></span></div>
<div>
<div class="profile-link"><a href="viewSone.html?sone=<% sone.id|html>" title="<% sone.requestUri|html>"><% sone.niceName|html></a></div>
- <div class="sone-stats">(<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size><%if ! sone.allImages.size|match value=0>, <%= View.Sone.Stats.Images|l10n 0=sone.allImages.size><%/if>)</div>
+ <div class="sone-stats">(<%= View.Sone.Stats.Posts|l10n 0=sone.posts.size>, <%= View.Sone.Stats.Replies|l10n 0=sone.replies.size><%if ! sone.allImages.size|match value==0>, <%= View.Sone.Stats.Images|l10n 0=sone.allImages.size><%/if>)</div>
</div>
- <div class="short-request-uri"><% sone.requestUri|substring start=4 length=43|html></div>
+ <div class="short-request-uri"><% sone.requestUri|substring start==4 length==43|html></div>
<div class="hidden"><% sone.blacklisted></div>
<%if sone.local>
<form class="lock<%if sone.locked> hidden<%/if>" action="lockSone.html" method="post">
<%include include/updateStatus.html>
<div id="posts">
- <%= page|store key=pageParameter>
- <%include include/pagination.html paginationName==pagination-index>
+ <%include include/pagination.html pageParameter==page paginationName==pagination-index>
<%foreach pagination.items post>
<%include include/viewPost.html>
<%foreachelse>
- <div><%= Page.Index.PostList.Text.NoPostYet|l10n|html></div>
+ <p><%= Page.Index.PostList.Text.NoPostYet|l10n|html></p>
+ <p><%= Page.Index.PostList.Text.FollowSomeSones|l10n|html|replace needle=='{link}' replacement=='<a href="knownSones.html">'|replace needle=='{/link}' replacement=='</a>'></p>
<%/foreach>
- <%include include/pagination.html>
+ <%include include/pagination.html pageParameter==page>
</div>
<%include include/tail.html>
<h1><%= Page.Invalid.Page.Title|l10n|html></h1>
<%foreach messages message>
- <%if message|substring start=0 length=1|match value='!'>
- <p class="error"><% message|substring start=1|parse></p>
+ <%if message|substring start==0 length==1|match value=='!'>
+ <p class="error"><% message|substring start==1|parse></p>
<%else>
<p><% message|parse></p>
<%/if>
<%foreachelse>
- <p><%= Page.Invalid.Text|l10n|html|replace needle="{link}" replacement='<a href="index.html">'|replace needle="{/link}" replacement='</a>'></p>
+ <p><%= Page.Invalid.Text|l10n|html|replace needle=="{link}" replacement=='<a href="index.html">'|replace needle=="{/link}" replacement=='</a>'></p>
<%/foreach>
<%include include/tail.html>
<div>
<%= Page.KnownSones.Label.Sort|l10n|html>
<select name="sort">
- <option value="name"<%if sort|match value="name"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.Name|l10n|html></option>
- <option value="activity"<%if sort|match value="activity"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.LastActivity|l10n|html></option>
- <option value="posts"<%if sort|match value="posts"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.Posts|l10n|html></option>
- <option value="images"<%if sort|match value="images"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.Images|l10n|html></option>
+ <option value="name"<%if sort|match value=="name"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.Name|l10n|html></option>
+ <option value="activity"<%if sort|match value=="activity"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.LastActivity|l10n|html></option>
+ <option value="posts"<%if sort|match value=="posts"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.Posts|l10n|html></option>
+ <option value="images"<%if sort|match value=="images"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Field.Images|l10n|html></option>
</select>
<select name="order">
- <option value="asc"<%if order|match value="asc"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Order.Ascending|l10n|html></option>
- <option value="desc"<%if order|match value="desc"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Order.Descending|l10n|html></option>
+ <option value="asc"<%if order|match value=="asc"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Order.Ascending|l10n|html></option>
+ <option value="desc"<%if order|match value=="desc"> selected="selected"<%/if>><%= Page.KnownSones.Sort.Order.Descending|l10n|html></option>
</select>
</div>
<%ifnull !currentSone>
<select name="filter">
<option value="none"></option>
<%ifnull !currentSone>
- <option value="followed"<%if filter|match value="followed"> selected="selected"<%/if>><%= Page.KnownSones.Filter.Followed|l10n|html></option>
- <option value="not-followed"<%if filter|match value="not-followed"> selected="selected"<%/if>><%= Page.KnownSones.Filter.NotFollowed|l10n|html></option>
+ <option value="followed"<%if filter|match value=="followed"> selected="selected"<%/if>><%= Page.KnownSones.Filter.Followed|l10n|html></option>
+ <option value="not-followed"<%if filter|match value=="not-followed"> selected="selected"<%/if>><%= Page.KnownSones.Filter.NotFollowed|l10n|html></option>
<%/if>
- <option value="new"<%if filter|match value="new"> selected="selected"<%/if>><%= Page.KnownSones.Filter.New|l10n|html></option>
- <option value="not-new"<%if filter|match value="not-new"> selected="selected"<%/if>><%= Page.KnownSones.Filter.NotNew|l10n|html></option>
+ <option value="new"<%if filter|match value=="new"> selected="selected"<%/if>><%= Page.KnownSones.Filter.New|l10n|html></option>
+ <option value="not-new"<%if filter|match value=="not-new"> selected="selected"<%/if>><%= Page.KnownSones.Filter.NotNew|l10n|html></option>
</select>
</div>
<%/if>
<%/if>
<div id="known-sones">
- <%= page|store key=pageParameter>
- <%include include/pagination.html>
+ <%include include/pagination.html pageParameter==page>
<%foreach pagination.items sone>
<%include include/viewSone.html>
<%foreachelse>
<div><%= Page.KnownSones.Text.NoKnownSones|l10n|html></div>
<%/foreach>
- <%include include/pagination.html>
+ <%include include/pagination.html pageParameter==page>
</div>
<%include include/tail.html>
<%include include/updateStatus.html>
<div id="posts">
- <%= page|store key=pageParameter>
- <%include include/pagination.html paginationName==pagination-index>
+ <%include include/pagination.html pageParameter==page paginationName==pagination-index>
<%foreach pagination.items post>
<%include include/viewPost.html>
<%foreachelse>
<div><%= Page.New.NothingNew|l10n|html></div>
<%/foreach>
- <%include include/pagination.html>
+ <%include include/pagination.html pageParameter==page>
</div>
<%include include/tail.html>
-<div class="text"><%= Notification.NewVersion.Text|l10n|replace needle="{version}" replacementKey=latestVersion|replace needle="{edition}" replacementKey=latestEdition|parse sone="nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"></div>
+<div class="text"><%= Notification.NewVersion.Text|l10n|replace needle=="{version}" replacement=latestVersion|replace needle=="{edition}" replacement=latestEdition|parse sone=="nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI"></div>
-<%if soneStatus|match value="inserting">
+<%if soneStatus|match value=="inserting">
Your Sone <a href="viewSone.html?sone=<%insertSone.id|html>"><%insertSone.niceName|html></a> is now being inserted.
-<%elseif soneStatus|match value="inserted">
+<%elseif soneStatus|match value=="inserted">
Your Sone <a href="viewSone.html?sone=<%insertSone.id|html>"><%insertSone.niceName|html></a> has been inserted in <%= Notification.SoneInsert.Duration|l10n 0=insertDuration>.
-<%elseif soneStatus|match value="insert-aborted">
+<%elseif soneStatus|match value=="insert-aborted">
Inserting your Sone <a href="viewSone.html?sone=<%insertSone.id|html>"><%insertSone.niceName|html></a> has failed.
<%/if>
\ No newline at end of file
<div class="text">
<%= Page.WotPluginMissing.Text.WotRequired|l10n|html>
- <%= Page.WotPluginMissing.Text.LoadPlugin|l10n|html|replace needle="{link}" replacement='<a href="/plugins/">'|replace needle="{/link}" replacement='</a>'>
+ <%= Page.WotPluginMissing.Text.LoadPlugin|l10n|html|replace needle=="{link}" replacement=='<a href="/plugins/">'|replace needle=="{/link}" replacement=='</a>'>
</div>
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.ImagesPerPage", function(imagesPerPageText) {
+ registerInputTextareaSwap("#sone #options input[name=images-per-page]", imagesPerPageText, "images-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);
});
<h2><%= Page.Options.Section.SoneSpecificOptions.Title|l10n|html></h2>
<%ifnull currentSone>
- <p><%= Page.Options.Section.SoneSpecificOptions.NotLoggedIn|l10n|html|replace needle="{link}" replacement='<a href="login.html">'|replace needle="{/link}" replacement='</a>'></p>
+ <p><%= Page.Options.Section.SoneSpecificOptions.NotLoggedIn|l10n|html|replace needle=="{link}" replacement=='<a href="login.html">'|replace needle=="{/link}" replacement=='</a>'></p>
<%else>
<p><%= Page.Options.Section.SoneSpecificOptions.LoggedIn|l10n|html></p>
<%/if>
<h2><%= Page.Options.Section.AvatarOptions.Title|l10n|html></h2>
<p><%= Page.Options.Option.ShowAvatars.Description|l10n|html></p>
-
+
<ul>
<li>
- <input type="radio" name="show-custom-avatars" value="NEVER"<%if show-custom-avatars|match value=NEVER> checked="checked"<%/if>/>
+ <input type="radio" name="show-custom-avatars" value="NEVER"<%if show-custom-avatars|match value==NEVER> checked="checked"<%/if>/>
<%=Page.Options.Option.ShowAvatars.Never.Description|l10n|html>
</li>
<li>
- <input type="radio" name="show-custom-avatars" value="FOLLOWED"<%if show-custom-avatars|match value=FOLLOWED> checked="checked"<%/if>/>
+ <input type="radio" name="show-custom-avatars" value="FOLLOWED"<%if show-custom-avatars|match value==FOLLOWED> checked="checked"<%/if>/>
<%=Page.Options.Option.ShowAvatars.Followed.Description|l10n|html>
</li>
<li>
- <input type="radio" name="show-custom-avatars" value="MANUALLY_TRUSTED"<%if show-custom-avatars|match value=MANUALLY_TRUSTED> checked="checked"<%/if>/>
+ <input type="radio" name="show-custom-avatars" value="MANUALLY_TRUSTED"<%if show-custom-avatars|match value==MANUALLY_TRUSTED> checked="checked"<%/if>/>
<%=Page.Options.Option.ShowAvatars.ManuallyTrusted.Description|l10n|html>
</li>
<li>
- <input type="radio" name="show-custom-avatars" value="TRUSTED"<%if show-custom-avatars|match value=TRUSTED> checked="checked"<%/if>/>
+ <input type="radio" name="show-custom-avatars" value="TRUSTED"<%if show-custom-avatars|match value==TRUSTED> checked="checked"<%/if>/>
<%=Page.Options.Option.ShowAvatars.Trusted.Description|l10n|html>
</li>
<li>
- <input type="radio" name="show-custom-avatars" value="ALWAYS"<%if show-custom-avatars|match value=ALWAYS> checked="checked"<%/if>/>
+ <input type="radio" name="show-custom-avatars" value="ALWAYS"<%if show-custom-avatars|match value==ALWAYS> checked="checked"<%/if>/>
<%=Page.Options.Option.ShowAvatars.Always.Description|l10n|html>
</li>
</ul>
<%/if>
<p><input type="text" name="posts-per-page" value="<% posts-per-page|html>" /></p>
+ <p><%= Page.Options.Option.ImagesPerPage.Description|l10n|html></p>
+ <%if =images-per-page|in collection=fieldErrors>
+ <p class="warning"><%= Page.Options.Warnings.ValueNotChanged|l10n|html></p>
+ <%/if>
+ <p><input type="text" name="images-per-page" value="<% images-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>
<p><input type="checkbox" name="fcp-interface-active"<%if fcp-interface-active> checked="checked"<%/if> /> <%= Page.Options.Option.FcpInterfaceActive.Description|l10n|html></p>
<p>
- <%= Page.Options.Option.FcpFullAccessRequired.Description|l10n|html|replace needle="{link}" replacement='<a href="/config/fcp">'|replace needle="{/link}" replacement='</a>'>
+ <%= Page.Options.Option.FcpFullAccessRequired.Description|l10n|html|replace needle=="{link}" replacement=='<a href="/config/fcp">'|replace needle=="{/link}" replacement=='</a>'>
<select name="fcp-full-access-required">
- <option value="0"<%if fcp-full-access-required|match value="0"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.No|l10n|html></option>
- <option value="1"<%if fcp-full-access-required|match value="1"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.Writing|l10n|html></option>
- <option value="2"<%if fcp-full-access-required|match value="2"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.Always|l10n|html></option>
+ <option value="0"<%if fcp-full-access-required|match value=="0"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.No|l10n|html></option>
+ <option value="1"<%if fcp-full-access-required|match value=="1"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.Writing|l10n|html></option>
+ <option value="2"<%if fcp-full-access-required|match value=="2"> selected="selected"<%/if>><%= Page.Options.Option.FcpFullAccessRequired.Value.Always|l10n|html></option>
</select>
</p>
- <h2><%= Page.Options.Section.Cleaning.Title|l10n|html></h2>
-
- <p><%= Page.Options.Option.ClearOnNextRestart.Description|l10n|html|replace needle="{strong}" replacement="<strong>"|replace needle="{/strong}" replacement="</strong>"></p>
- <p><select name="clear-on-next-restart"><option disabled="disabled"><%= WebInterface.SelectBox.Choose|l10n|html></option><option value="true"<%if clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.Yes|l10n|html></option><option value="false"<%if ! clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.No|l10n|html></option></select>
-
- <p><%= Page.Options.Option.ReallyClearOnNextRestart.Description|l10n|html|replace needle="{strong}" replacement="<strong>"|replace needle="{/strong}" replacement="</strong>"></p>
- <p><select name="really-clear-on-next-restart"><option disabled="disabled"><%= WebInterface.SelectBox.Choose|l10n|html></option><option value="true"<%if really-clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.Yes|l10n|html></option><option value="false"<%if ! really-clear-on-next-restart> selected="selected"<%/if>><%= WebInterface.SelectBox.No|l10n|html></option></select>
-
<p><button type="submit"><%= Page.Options.Button.Save|l10n|html></button></p>
</form>
<p><%= Page.ViewPost.Text.UnknownPost|l10n|html></p>
<%else>
- <h1><%= Page.ViewPost.Page.Title|l10n|replace needle="{sone}" replacementKey=post.sone.niceName|html></h1>
+ <h1><%= Page.ViewPost.Page.Title|l10n|replace needle=="{sone}" replacement=post.sone.niceName|html></h1>
<%include include/viewPost.html>
<%/if>
<h1><%= Page.ViewSone.Page.TitleWithoutSone|l10n|html></h1>
<p>
- <%= Page.ViewSone.NoSone.Description|l10n|replace needle="{sone}" replacementKey=soneId|html>
- <a href="/WebOfTrust/ShowIdentity?id=<% sone.id|html>"><%= Page.ViewSone.Profile.Name.WoTLink|l10n|html></a>
+ <%= Page.ViewSone.NoSone.Description|l10n|replace needle=="{sone}" replacement=soneId|html>
+ <a href="/WebOfTrust/ShowIdentity?id=<% soneId|html>"><%= Page.ViewSone.Profile.Name.WoTLink|l10n|html></a>
</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|parse></div>
+ <div class="value"><% field.value|parse sone=sone></div>
</div>
<%/foreach>
<%/if>
<%/if>
- <h1><%= Page.ViewSone.PostList.Title|l10n|replace needle="{sone}" replacementKey=sone.niceName|html></h1>
+ <h1><%= Page.ViewSone.PostList.Title|l10n|replace needle=="{sone}" replacement=sone.niceName|html></h1>
<%foreach posts post>
<%first>
<%foreach repliedPosts post>
<%first>
- <h2><%= Page.ViewSone.Replies.Title|l10n|html|replace needle="{sone}" replacementKey=sone.niceName></h2>
+ <h2><%= Page.ViewSone.Replies.Title|l10n|html|replace needle=="{sone}" replacement=sone.niceName></h2>
<div id="replied-posts">
<%include include/pagination.html pagination=repliedPostPagination pageParameter==repliedPostPage paginationName==reply-navigation>
<%/first>