From: David ‘Bombe’ Roden Date: Fri, 27 Sep 2013 04:29:41 +0000 (+0200) Subject: Update French translation. X-Git-Tag: 0.8.8^2~29 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=629ddb006542df2b671e172d8f544815bbab639b;hp=54ec8c45421d5d3f88e73ba52e47383d3499feb2 Update French translation. --- diff --git a/pom.xml b/pom.xml index d2f00a4..f506a24 100644 --- a/pom.xml +++ b/pom.xml @@ -2,12 +2,12 @@ 4.0.0 net.pterodactylus sone - 0.8.6 + 0.8.7 net.pterodactylus utils - 0.12.3 + ${version.utils} junit @@ -34,11 +34,6 @@ provided - net.pterodactylus - utils.json - 0.1 - - com.google.inject guice 3.0 @@ -53,6 +48,16 @@ commons-lang 2.6 + + com.fasterxml.jackson.core + jackson-databind + 2.1.2 + + + com.google.code.findbugs + jsr305 + 2.0.1 + @@ -62,10 +67,20 @@ UTF-8 + 0.12.4 + 600000 + org.codehaus.mojo + findbugs-maven-plugin + 2.5.2 + + ${findbugs.timeout} + + + org.apache.maven.plugins maven-compiler-plugin 2.0.2 diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 7b4bc4b..5103b7d 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -1035,13 +1035,13 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, database.storePostReplies(sone, sone.getReplies()); synchronized (albums) { synchronized (images) { - for (Album album : storedSone.get().getAlbums()) { + for (Album album : storedSone.get().getRootAlbum().getAlbums()) { albums.remove(album.getId()); for (Image image : album.getImages()) { images.remove(image.getId()); } } - for (Album album : sone.getAlbums()) { + for (Album album : sone.getRootAlbum().getAlbums()) { albums.put(album.getId(), album); for (Image image : album.getImages()) { images.put(image.getId(), image); @@ -1052,6 +1052,11 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, synchronized (sones) { sone.setOptions(storedSone.get().getOptions()); sone.setKnown(storedSone.get().isKnown()); + sone.setStatus((sone.getTime() == 0) ? SoneStatus.unknown : SoneStatus.idle); + if (sone.isLocal()) { + soneInserters.get(storedSone.get()).setSone(sone); + touchConfiguration(); + } sones.put(sone.getId(), sone); } } @@ -1314,7 +1319,12 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, for (String friendId : friends) { followSone(sone, friendId); } - sone.setAlbums(topLevelAlbums); + for (Album album : sone.getRootAlbum().getAlbums()) { + sone.getRootAlbum().removeAlbum(album); + } + for (Album album : topLevelAlbums) { + sone.getRootAlbum().addAlbum(album); + } soneInserters.get(sone).setLastInsertFingerprint(lastInsertFingerprint); } synchronized (knownSones) { @@ -1579,7 +1589,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, * @return The new album */ public Album createAlbum(Sone sone) { - return createAlbum(sone, null); + return createAlbum(sone, sone.getRootAlbum()); } /** @@ -1598,11 +1608,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, albums.put(album.getId(), album); } album.setSone(sone); - if (parent != null) { - parent.addAlbum(album); - } else { - sone.addAlbum(album); - } + parent.addAlbum(album); return album; } @@ -1619,11 +1625,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, if (!album.isEmpty()) { return; } - if (album.getParent() == null) { - album.getSone().removeAlbum(album); - } else { - album.getParent().removeAlbum(album); - } + album.getParent().removeAlbum(album); synchronized (albums) { albums.remove(album.getId()); } @@ -1878,7 +1880,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, configuration.getStringValue(sonePrefix + "/Friends/" + friendCounter + "/ID").setValue(null); /* save albums. first, collect in a flat structure, top-level first. */ - List albums = FluentIterable.from(sone.getAlbums()).transformAndConcat(Album.FLATTENER).toList(); + List albums = FluentIterable.from(sone.getRootAlbum().getAlbums()).transformAndConcat(Album.FLATTENER).toList(); int albumCounter = 0; for (Album album : albums) { @@ -1886,7 +1888,7 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, configuration.getStringValue(albumPrefix + "/ID").setValue(album.getId()); configuration.getStringValue(albumPrefix + "/Title").setValue(album.getTitle()); configuration.getStringValue(albumPrefix + "/Description").setValue(album.getDescription()); - configuration.getStringValue(albumPrefix + "/Parent").setValue(album.getParent() == null ? null : album.getParent().getId()); + configuration.getStringValue(albumPrefix + "/Parent").setValue(album.getParent().equals(sone.getRootAlbum()) ? null : album.getParent().getId()); configuration.getStringValue(albumPrefix + "/AlbumImage").setValue(album.getAlbumImage() == null ? null : album.getAlbumImage().getId()); } configuration.getStringValue(sonePrefix + "/Albums/" + albumCounter + "/ID").setValue(null); diff --git a/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java b/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java index f493fdc..9af6328 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneDownloader.java @@ -239,7 +239,7 @@ public class SoneDownloader extends AbstractService { return null; } - Sone sone = new Sone(originalSone.getId(), false).setIdentity(originalSone.getIdentity()); + Sone sone = new Sone(originalSone.getId(), originalSone.isLocal()).setIdentity(originalSone.getIdentity()); SimpleXML soneXml; try { @@ -518,7 +518,9 @@ public class SoneDownloader extends AbstractService { sone.setReplies(replies); sone.setLikePostIds(likedPostIds); sone.setLikeReplyIds(likedReplyIds); - sone.setAlbums(topLevelAlbums); + for (Album album : topLevelAlbums) { + sone.getRootAlbum().addAlbum(album); + } } return sone; diff --git a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java index 8efcc73..a1bb903 100644 --- a/src/main/java/net/pterodactylus/sone/core/SoneInserter.java +++ b/src/main/java/net/pterodactylus/sone/core/SoneInserter.java @@ -17,6 +17,9 @@ package net.pterodactylus.sone.core; +import static com.google.common.base.Preconditions.checkArgument; +import static net.pterodactylus.sone.data.Album.NOT_EMPTY; + import java.io.InputStreamReader; import java.io.StringWriter; import java.nio.charset.Charset; @@ -90,7 +93,7 @@ public class SoneInserter extends AbstractService { private final FreenetInterface freenetInterface; /** The Sone to insert. */ - private final Sone sone; + private volatile Sone sone; /** Whether a modification has been detected. */ private volatile boolean modified = false; @@ -123,8 +126,21 @@ public class SoneInserter extends AbstractService { // /** - * Changes the insertion delay, i.e. the time the Sone inserter waits after - * it has noticed a Sone modification before it starts the insert. + * Sets the Sone to insert. + * + * @param sone + * The Sone to insert + * @return This Sone inserter + */ + public SoneInserter setSone(Sone sone) { + checkArgument((this.sone == null) || sone.equals(this.sone), "Sone to insert can not be set to a different Sone"); + this.sone = sone; + return this; + } + + /** + * Changes the insertion delay, i.e. the time the Sone inserter waits after it + * has noticed a Sone modification before it starts the insert. * * @param insertionDelay * The insertion delay (in seconds) @@ -175,12 +191,14 @@ public class SoneInserter extends AbstractService { long lastModificationTime = 0; String lastInsertedFingerprint = lastInsertFingerprint; String lastFingerprint = ""; + Sone sone; while (!shouldStop()) { try { /* check every seconds. */ sleep(1000); /* don’t insert locked Sones. */ + sone = this.sone; if (core.isLocked(sone)) { /* trigger redetection when the Sone is unlocked. */ synchronized (sone) { @@ -291,7 +309,7 @@ public class SoneInserter extends AbstractService { soneProperties.put("replies", Ordering.from(Reply.TIME_COMPARATOR).reverse().sortedCopy(sone.getReplies())); soneProperties.put("likedPostIds", new HashSet(sone.getLikedPostIds())); soneProperties.put("likedReplyIds", new HashSet(sone.getLikedReplyIds())); - soneProperties.put("albums", FluentIterable.from(sone.getAlbums()).transformAndConcat(Album.FLATTENER).toList()); + soneProperties.put("albums", FluentIterable.from(sone.getRootAlbum().getAlbums()).transformAndConcat(Album.FLATTENER).filter(NOT_EMPTY).toList()); } // diff --git a/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java index bb7016d..e18c6d4 100644 --- a/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java +++ b/src/main/java/net/pterodactylus/sone/core/UpdateChecker.java @@ -53,7 +53,7 @@ public class UpdateChecker { private static final String SONE_HOMEPAGE = "USK@nwa8lHa271k2QvJ8aa0Ov7IHAV-DFOCFgmDt3X6BpCI,DuQSUZiI~agF8c-6tjsFFGuZ8eICrzWCILB60nT8KKo,AQACAAE/sone/"; /** The current latest known edition. */ - private static final int LATEST_EDITION = 58; + private static final int LATEST_EDITION = 60; /** The event bus. */ private final EventBus eventBus; diff --git a/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java b/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java index d449835..dd3de58 100644 --- a/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java +++ b/src/main/java/net/pterodactylus/sone/core/WebOfTrustUpdater.java @@ -61,7 +61,7 @@ public class WebOfTrustUpdater extends AbstractService { * Creates a new trust updater. * * @param webOfTrustConnector - * The web of trust connector + * The web of trust connector */ @Inject public WebOfTrustUpdater(WebOfTrustConnector webOfTrustConnector) { @@ -74,19 +74,18 @@ public class WebOfTrustUpdater extends AbstractService { // /** - * Updates the trust relation between the truster and the trustee. This - * method will return immediately and perform a trust update in the - * background. + * 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 + * The identity giving the trust * @param trustee - * The identity receiving the trust + * 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) + * 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 + * 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); @@ -105,22 +104,22 @@ public class WebOfTrustUpdater extends AbstractService { * Adds the given context to the given own identity. * * @param ownIdentity - * The own identity to add the context to + * The own identity to add the context to * @param context - * The context to add + * 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. + * 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 + * The own identity to add the context to * @param context - * The context to add + * The context to add * @return {@code true} if the context was added successfully, {@code false} * otherwise */ @@ -129,19 +128,19 @@ public class WebOfTrustUpdater extends AbstractService { } /** - * Adds the given context to the given own identity, waiting for completion - * of the operation. + * 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 + * The own identity to add the context to * @param context - * The context to add + * 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 + * {@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); @@ -169,9 +168,9 @@ public class WebOfTrustUpdater extends AbstractService { * Removes the given context from the given own identity. * * @param ownIdentity - * The own identity to remove the context from + * The own identity to remove the context from * @param context - * The context to remove + * The context to remove */ public void removeContext(OwnIdentity ownIdentity, String context) { RemoveContextJob removeContextJob = new RemoveContextJob(ownIdentity, context); @@ -189,11 +188,11 @@ public class WebOfTrustUpdater extends AbstractService { * Sets a property on the given own identity. * * @param ownIdentity - * The own identity to set the property on + * The own identity to set the property on * @param propertyName - * The name of the property to set + * The name of the property to set * @param propertyValue - * The value of the property to set + * The value of the property to set */ public void setProperty(OwnIdentity ownIdentity, String propertyName, String propertyValue) { SetPropertyJob setPropertyJob = new SetPropertyJob(ownIdentity, propertyName, propertyValue); @@ -212,9 +211,9 @@ public class WebOfTrustUpdater extends AbstractService { * Removes a property from the given own identity. * * @param ownIdentity - * The own identity to remove the property from + * The own identity to remove the property from * @param propertyName - * The name of the property to remove + * The name of the property to remove */ public void removeProperty(OwnIdentity ownIdentity, String propertyName) { setProperty(ownIdentity, propertyName, null); @@ -224,9 +223,7 @@ public class WebOfTrustUpdater extends AbstractService { // SERVICE METHODS // - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override protected void serviceRun() { while (!shouldStop()) { @@ -246,9 +243,7 @@ public class WebOfTrustUpdater extends AbstractService { } } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override protected void serviceStop() { try { @@ -281,7 +276,7 @@ public class WebOfTrustUpdater extends AbstractService { /** * Performs the actual update operation. - *

+ *

* The implementation of this class does nothing. */ public void run() { @@ -289,8 +284,7 @@ public class WebOfTrustUpdater extends AbstractService { } /** - * Waits for completion of this job or stopping of the WebOfTrust - * updater. + * Waits for completion of this job or stopping of the WebOfTrust updater. * * @return {@code true} if this job finished successfully, {@code false} * otherwise @@ -318,8 +312,7 @@ public class WebOfTrustUpdater extends AbstractService { * Signals that this job has finished. * * @param success - * {@code true} if this job finished successfully, - * {@code false} otherwise + * {@code true} if this job finished successfully, {@code false} otherwise */ protected void finish(boolean success) { synchronized (syncObject) { @@ -332,72 +325,17 @@ public class WebOfTrustUpdater extends AbstractService { } /** - * Base class for WebOfTrust trust update jobs. + * Update job that sets the trust relation between two identities. * * @author David ‘Bombe’ Roden */ - private class WebOfTrustTrustUpdateJob extends WebOfTrustUpdateJob { + private class SetTrustJob extends WebOfTrustUpdateJob { /** The identity giving the trust. */ - protected final OwnIdentity truster; + private 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 David ‘Bombe’ Roden - */ - private class SetTrustJob extends WebOfTrustTrustUpdateJob { + private final Identity trustee; /** The score of the relation. */ private final Integer score; @@ -409,24 +347,23 @@ public class WebOfTrustUpdater extends AbstractService { * Creates a new set trust job. * * @param truster - * The identity giving the trust + * The identity giving the trust * @param trustee - * The identity receiving the trust + * 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) + * 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 + * The comment of the trust relation */ public SetTrustJob(OwnIdentity truster, Identity trustee, Integer score, String comment) { - super(truster, trustee); + this.truster = truster; + this.trustee = trustee; this.score = score; this.comment = comment; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override @SuppressWarnings("synthetic-access") public void run() { @@ -449,6 +386,32 @@ public class WebOfTrustUpdater extends AbstractService { } } + // + // OBJECT METHODS + // + + /** {@inheritDoc} */ + @Override + public boolean equals(Object object) { + if ((object == null) || !object.getClass().equals(getClass())) { + return false; + } + SetTrustJob updateJob = (SetTrustJob) 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()); + } + } /** @@ -468,9 +431,9 @@ public class WebOfTrustUpdater extends AbstractService { * Creates a new context update job. * * @param ownIdentity - * The own identity to update + * The own identity to update * @param context - * The context to update + * The context to update */ @SuppressWarnings("synthetic-access") public WebOfTrustContextUpdateJob(OwnIdentity ownIdentity, String context) { @@ -482,9 +445,7 @@ public class WebOfTrustUpdater extends AbstractService { // OBJECT METHODS // - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override public boolean equals(Object object) { if ((object == null) || !object.getClass().equals(getClass())) { @@ -494,17 +455,13 @@ public class WebOfTrustUpdater extends AbstractService { return updateJob.ownIdentity.equals(ownIdentity) && updateJob.context.equals(context); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override public int hashCode() { return getClass().hashCode() ^ ownIdentity.hashCode() ^ context.hashCode(); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override public String toString() { return String.format("%s[ownIdentity=%s,context=%s]", getClass().getSimpleName(), ownIdentity, context); @@ -523,17 +480,15 @@ public class WebOfTrustUpdater extends AbstractService { * Creates a new add-context job. * * @param ownIdentity - * The own identity whose contexts to manage + * The own identity whose contexts to manage * @param context - * The context to add + * The context to add */ public AddContextJob(OwnIdentity ownIdentity, String context) { super(ownIdentity, context); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override @SuppressWarnings("synthetic-access") public void run() { @@ -560,17 +515,15 @@ public class WebOfTrustUpdater extends AbstractService { * Creates a new remove-context job. * * @param ownIdentity - * The own identity whose contexts to manage + * The own identity whose contexts to manage * @param context - * The context to remove + * The context to remove */ public RemoveContextJob(OwnIdentity ownIdentity, String context) { super(ownIdentity, context); } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override @SuppressWarnings("synthetic-access") public void run() { @@ -587,72 +540,17 @@ public class WebOfTrustUpdater extends AbstractService { } /** - * Base class for update jobs that deal with properties. + * WebOfTrust update job that sets a property on an {@link OwnIdentity}. * * @author David ‘Bombe’ Roden */ - private class WebOfTrustPropertyUpdateJob extends WebOfTrustUpdateJob { + private class SetPropertyJob extends WebOfTrustUpdateJob { /** The own identity to update properties on. */ - protected final OwnIdentity ownIdentity; + private 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 David ‘Bombe’ Roden - */ - private class SetPropertyJob extends WebOfTrustPropertyUpdateJob { + private final String propertyName; /** The value of the property to set. */ private final String propertyValue; @@ -661,20 +559,19 @@ public class WebOfTrustUpdater extends AbstractService { * Creates a new set-property job. * * @param ownIdentity - * The own identity to set the property on + * The own identity to set the property on * @param propertyName - * The name of the property to set + * The name of the property to set * @param propertyValue - * The value of the property to set + * The value of the property to set */ public SetPropertyJob(OwnIdentity ownIdentity, String propertyName, String propertyValue) { - super(ownIdentity, propertyName); + this.ownIdentity = ownIdentity; + this.propertyName = propertyName; this.propertyValue = propertyValue; } - /** - * {@inheritDoc} - */ + /** {@inheritDoc} */ @Override @SuppressWarnings("synthetic-access") public void run() { @@ -693,6 +590,32 @@ public class WebOfTrustUpdater extends AbstractService { } } + // + // OBJECT METHODS + // + + /** {@inheritDoc} */ + @Override + public boolean equals(Object object) { + if ((object == null) || !object.getClass().equals(getClass())) { + return false; + } + SetPropertyJob updateJob = (SetPropertyJob) 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); + } + } } diff --git a/src/main/java/net/pterodactylus/sone/data/Album.java b/src/main/java/net/pterodactylus/sone/data/Album.java index cb7b4f3..70478f3 100644 --- a/src/main/java/net/pterodactylus/sone/data/Album.java +++ b/src/main/java/net/pterodactylus/sone/data/Album.java @@ -21,13 +21,16 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; import static java.util.Arrays.asList; +import static java.util.Collections.emptyList; import java.util.ArrayList; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; +import javax.annotation.Nonnull; import com.google.common.base.Function; import com.google.common.base.Optional; @@ -44,7 +47,7 @@ import com.google.common.hash.Hashing; * * @author David ‘Bombe’ Roden */ -public class Album implements Fingerprintable { +public class Album implements Identified, Fingerprintable { /** Compares two {@link Album}s by {@link #getTitle()}. */ public static final Comparator TITLE_COMPARATOR = new Comparator() { @@ -59,7 +62,11 @@ public class Album implements Fingerprintable { public static final Function> FLATTENER = new Function>() { @Override + @Nonnull public List apply(Album album) { + if (album == null) { + return emptyList(); + } List albums = new ArrayList(); albums.add(album); for (Album subAlbum : album.getAlbums()) { @@ -69,6 +76,16 @@ public class Album implements Fingerprintable { } }; + /** Function that transforms an album into the images it contains. */ + public static final Function> IMAGES = new Function>() { + + @Override + @Nonnull + public List apply(Album album) { + return (album != null) ? album.getImages() : Collections.emptyList(); + } + }; + /** * Filter that removes all albums that do not have any images in any album * below it. @@ -77,11 +94,19 @@ public class Album implements Fingerprintable { @Override public boolean apply(Album album) { + /* so, we flatten all albums below the given one and check whether at least one album… */ return FluentIterable.from(asList(album)).transformAndConcat(FLATTENER).anyMatch(new Predicate() { @Override public boolean apply(Album album) { - return !album.getImages().isEmpty(); + /* …contains any inserted images. */ + return !album.getImages().isEmpty() && FluentIterable.from(album.getImages()).allMatch(new Predicate() { + + @Override + public boolean apply(Image input) { + return input.isInserted(); + } + }); } }); } @@ -186,7 +211,6 @@ public class Album implements Fingerprintable { public void addAlbum(Album album) { checkNotNull(album, "album must not be null"); checkArgument(album.getSone().equals(sone), "album must belong to the same Sone as this album"); - checkState((this.parent == null) || (this.parent.equals(album.parent)), "album must not already be set to some other Sone"); album.setParent(this); if (!albums.contains(album)) { albums.add(album); @@ -392,6 +416,16 @@ public class Album implements Fingerprintable { } /** + * Returns whether this album is an identitiy’s root album. + * + * @return {@code true} if this album is an identity’s root album, {@code + * false} otherwise + */ + public boolean isRoot() { + return parent == null; + } + + /** * Returns the parent album of this album. * * @return The parent album of this album, or {@code null} if this album diff --git a/src/main/java/net/pterodactylus/sone/data/Identified.java b/src/main/java/net/pterodactylus/sone/data/Identified.java new file mode 100644 index 0000000..4892479 --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/data/Identified.java @@ -0,0 +1,49 @@ +/* + * Sone - Identified.java - Copyright © 2013 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 . + */ + +package net.pterodactylus.sone.data; + +import javax.annotation.Nonnull; + +import com.google.common.base.Function; +import com.google.common.base.Optional; + +/** + * Interface for all objects that expose an ID. + * + * @author David ‘Bombe’ Roden + */ +public interface Identified { + + /** Function to extract the ID from an optional. */ + public static final Function, Optional> GET_ID = new Function, Optional>() { + + @Override + @Nonnull + public Optional apply(Optional identified) { + return (identified == null) ? Optional.absent() : (identified.isPresent() ? Optional.of(identified.get().getId()) : Optional.absent()); + } + }; + + /** + * Returns the ID of this element. + * + * @return The ID of this element + */ + public String getId(); + +} diff --git a/src/main/java/net/pterodactylus/sone/data/Image.java b/src/main/java/net/pterodactylus/sone/data/Image.java index 952d540..d8a8ab1 100644 --- a/src/main/java/net/pterodactylus/sone/data/Image.java +++ b/src/main/java/net/pterodactylus/sone/data/Image.java @@ -31,7 +31,7 @@ import com.google.common.hash.Hashing; * * @author David ‘Bombe’ Roden */ -public class Image implements Fingerprintable { +public class Image implements Identified, Fingerprintable { /** The ID of the image. */ private final String id; diff --git a/src/main/java/net/pterodactylus/sone/data/Post.java b/src/main/java/net/pterodactylus/sone/data/Post.java index 6523e9b..759a8ba 100644 --- a/src/main/java/net/pterodactylus/sone/data/Post.java +++ b/src/main/java/net/pterodactylus/sone/data/Post.java @@ -28,7 +28,7 @@ import com.google.common.base.Predicate; * * @author David ‘Bombe’ Roden */ -public interface Post { +public interface Post extends Identified { /** Comparator for posts, sorts descending by time. */ public static final Comparator TIME_COMPARATOR = new Comparator() { @@ -45,7 +45,7 @@ public interface Post { @Override public boolean apply(Post post) { - return post.getTime() <= System.currentTimeMillis(); + return (post == null) ? false : post.getTime() <= System.currentTimeMillis(); } }; @@ -77,10 +77,7 @@ public interface Post { public Optional getRecipientId(); /** - * Returns the recipient of this post, if any. As this method can return - * {@link Optional#absent()} if the post has a recipient which has not yet - * been loaded, it is recommended to use {@link #hasRecipient()} to check - * for the presence of a recipient. + * Returns the recipient of this post, if any. * * @return The recipient of this post, or {@link Optional#absent()} if there * is no recipient diff --git a/src/main/java/net/pterodactylus/sone/data/PostReply.java b/src/main/java/net/pterodactylus/sone/data/PostReply.java index 1e870b9..4a1fbad 100644 --- a/src/main/java/net/pterodactylus/sone/data/PostReply.java +++ b/src/main/java/net/pterodactylus/sone/data/PostReply.java @@ -36,7 +36,7 @@ public interface PostReply extends Reply { @Override public boolean apply(PostReply postReply) { - return postReply.getPost().isPresent(); + return (postReply == null) ? false : postReply.getPost().isPresent(); } }; diff --git a/src/main/java/net/pterodactylus/sone/data/Reply.java b/src/main/java/net/pterodactylus/sone/data/Reply.java index a686023..c229d04 100644 --- a/src/main/java/net/pterodactylus/sone/data/Reply.java +++ b/src/main/java/net/pterodactylus/sone/data/Reply.java @@ -28,7 +28,7 @@ import com.google.common.base.Predicate; * The type of the reply * @author David ‘Bombe’ Roden */ -public interface Reply> { +public interface Reply> extends Identified { /** Comparator that sorts replies ascending by time. */ public static final Comparator> TIME_COMPARATOR = new Comparator>() { @@ -51,7 +51,7 @@ public interface Reply> { */ @Override public boolean apply(Reply reply) { - return reply.getTime() <= System.currentTimeMillis(); + return (reply == null) ? false : reply.getTime() <= System.currentTimeMillis(); } }; diff --git a/src/main/java/net/pterodactylus/sone/data/Sone.java b/src/main/java/net/pterodactylus/sone/data/Sone.java index 4f4fd98..31153ff 100644 --- a/src/main/java/net/pterodactylus/sone/data/Sone.java +++ b/src/main/java/net/pterodactylus/sone/data/Sone.java @@ -17,7 +17,11 @@ package net.pterodactylus.sone.data; -import static com.google.common.base.Preconditions.*; +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.FluentIterable.from; +import static java.util.Arrays.asList; +import static net.pterodactylus.sone.data.Album.FLATTENER; +import static net.pterodactylus.sone.data.Album.IMAGES; import java.util.ArrayList; import java.util.Collection; @@ -25,7 +29,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArraySet; import java.util.logging.Level; import java.util.logging.Logger; @@ -39,9 +42,9 @@ import net.pterodactylus.util.logging.Logging; import freenet.keys.FreenetURI; import com.google.common.base.Predicate; -import com.google.common.collect.FluentIterable; import com.google.common.hash.Hasher; import com.google.common.hash.Hashing; +import com.google.common.primitives.Ints; /** * A Sone defines everything about a user: her profile, her status updates, her @@ -51,7 +54,7 @@ import com.google.common.hash.Hashing; * * @author David ‘Bombe’ Roden */ -public class Sone implements Fingerprintable, Comparable { +public class Sone implements Identified, Fingerprintable, Comparable { /** * Enumeration for the possible states of a {@link Sone}. @@ -140,7 +143,10 @@ public class Sone implements Fingerprintable, Comparable { */ @Override public int compare(Sone leftSone, Sone rightSone) { - return rightSone.getAllImages().size() - leftSone.getAllImages().size(); + int rightSoneImageCount = from(asList(rightSone.getRootAlbum())).transformAndConcat(FLATTENER).transformAndConcat(IMAGES).size(); + int leftSoneImageCount = from(asList(leftSone.getRootAlbum())).transformAndConcat(FLATTENER).transformAndConcat(IMAGES).size(); + /* sort descending. */ + return Ints.compare(rightSoneImageCount, leftSoneImageCount); } }; @@ -149,7 +155,7 @@ public class Sone implements Fingerprintable, Comparable { @Override public boolean apply(Sone sone) { - return sone.getTime() != 0; + return (sone == null) ? false : sone.getTime() != 0; } }; @@ -158,7 +164,7 @@ public class Sone implements Fingerprintable, Comparable { @Override public boolean apply(Sone sone) { - return sone.getIdentity() instanceof OwnIdentity; + return (sone == null) ? false : sone.getIdentity() instanceof OwnIdentity; } }; @@ -168,7 +174,7 @@ public class Sone implements Fingerprintable, Comparable { @Override public boolean apply(Sone sone) { - return !sone.getAlbums().isEmpty(); + return (sone == null) ? false : !sone.getRootAlbum().getAlbums().isEmpty(); } }; @@ -224,8 +230,8 @@ public class Sone implements Fingerprintable, Comparable { /** The IDs of all liked replies. */ private final Set likedReplyIds = new CopyOnWriteArraySet(); - /** The albums of this Sone. */ - private final List albums = new CopyOnWriteArrayList(); + /** The root album containing all albums. */ + private final Album rootAlbum = new Album().setSone(this); /** Sone-specific options. */ private Options options = new Options(); @@ -757,110 +763,12 @@ public class Sone implements Fingerprintable, Comparable { } /** - * Returns the albums of this Sone. + * Returns the root album that contains all visible albums of this Sone. * - * @return The albums of this Sone + * @return The root album of this Sone */ - public List getAlbums() { - return Collections.unmodifiableList(albums); - } - - /** - * Returns all images of a Sone. Images of a album are inserted into this list - * before images of all child albums. - * - * @return The list of all images - */ - public List getAllImages() { - List allImages = new ArrayList(); - for (Album album : FluentIterable.from(getAlbums()).transformAndConcat(Album.FLATTENER).toList()) { - allImages.addAll(album.getImages()); - } - return allImages; - } - - /** - * Adds an album to this Sone. - * - * @param album - * The album to add - */ - public void addAlbum(Album album) { - checkNotNull(album, "album must not be null"); - checkArgument(album.getSone().equals(this), "album must belong to this Sone"); - if (!albums.contains(album)) { - albums.add(album); - } - } - - /** - * Sets the albums of this Sone. - * - * @param albums - * The albums of this Sone - */ - public void setAlbums(Collection albums) { - checkNotNull(albums, "albums must not be null"); - this.albums.clear(); - for (Album album : albums) { - addAlbum(album); - } - } - - /** - * Removes an album from this Sone. - * - * @param album - * The album to remove - */ - public void removeAlbum(Album album) { - checkNotNull(album, "album must not be null"); - checkArgument(album.getSone().equals(this), "album must belong to this Sone"); - albums.remove(album); - } - - /** - * Moves the given album up in this album’s albums. If the album is already the - * first album, nothing happens. - * - * @param album - * The album to move up - * @return The album that the given album swapped the place with, or - * null if the album did not change its place - */ - public Album moveAlbumUp(Album album) { - checkNotNull(album, "album must not be null"); - checkArgument(album.getSone().equals(this), "album must belong to this Sone"); - checkArgument(album.getParent() == null, "album must not have a parent"); - int oldIndex = albums.indexOf(album); - if (oldIndex <= 0) { - return null; - } - albums.remove(oldIndex); - albums.add(oldIndex - 1, album); - return albums.get(oldIndex); - } - - /** - * Moves the given album down in this album’s albums. If the album is already - * the last album, nothing happens. - * - * @param album - * The album to move down - * @return The album that the given album swapped the place with, or - * null if the album did not change its place - */ - public Album moveAlbumDown(Album album) { - checkNotNull(album, "album must not be null"); - checkArgument(album.getSone().equals(this), "album must belong to this Sone"); - checkArgument(album.getParent() == null, "album must not have a parent"); - int oldIndex = albums.indexOf(album); - if ((oldIndex < 0) || (oldIndex >= (albums.size() - 1))) { - return null; - } - albums.remove(oldIndex); - albums.add(oldIndex + 1, album); - return albums.get(oldIndex); + public Album getRootAlbum() { + return rootAlbum; } /** @@ -924,7 +832,10 @@ public class Sone implements Fingerprintable, Comparable { hash.putString(")"); hash.putString("Albums("); - for (Album album : albums) { + for (Album album : rootAlbum.getAlbums()) { + if (!Album.NOT_EMPTY.apply(album)) { + continue; + } hash.putString(album.getFingerprint()); } hash.putString(")"); @@ -964,7 +875,7 @@ public class Sone implements Fingerprintable, Comparable { /** {@inheritDoc} */ @Override public String toString() { - return getClass().getName() + "[identity=" + identity + ",requestUri=" + requestUri + ",insertUri(" + String.valueOf(insertUri).length() + "),friends(" + friendSones.size() + "),posts(" + posts.size() + "),replies(" + replies.size() + ")]"; + return getClass().getName() + "[identity=" + identity + ",requestUri=" + requestUri + ",insertUri(" + String.valueOf(insertUri).length() + "),friends(" + friendSones.size() + "),posts(" + posts.size() + "),replies(" + replies.size() + "),albums(" + getRootAlbum().getAlbums().size() + ")]"; } } diff --git a/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java b/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java index 36ac8cd..c8075c5 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java +++ b/src/main/java/net/pterodactylus/sone/freenet/L10nFilter.java @@ -65,4 +65,5 @@ public class L10nFilter implements Filter { } return new MessageFormat(webInterface.getL10n().getString(String.valueOf(data)), new Locale(webInterface.getL10n().getSelectedLanguage().shortCode)).format(parameterValues.toArray()); } + } diff --git a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java index 4f87b97..348cd8c 100644 --- a/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java +++ b/src/main/java/net/pterodactylus/sone/freenet/wot/DefaultOwnIdentity.java @@ -70,4 +70,18 @@ public class DefaultOwnIdentity extends DefaultIdentity implements OwnIdentity { return insertUri; } + // + // OBJECT METHODS + // + + @Override + public int hashCode() { + return super.hashCode(); + } + + @Override + public boolean equals(Object object) { + return super.equals(object); + } + } diff --git a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java index 6f2a908..e31bbf5 100644 --- a/src/main/java/net/pterodactylus/sone/main/SonePlugin.java +++ b/src/main/java/net/pterodactylus/sone/main/SonePlugin.java @@ -104,7 +104,7 @@ public class SonePlugin implements FredPlugin, FredPluginFCP, FredPluginL10n, Fr } /** The version. */ - public static final Version VERSION = new Version(0, 8, 6); + public static final Version VERSION = new Version(0, 8, 7); /** The logger. */ private static final Logger logger = Logging.getLogger(SonePlugin.class); diff --git a/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java b/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java index 96891e5..13b4d65 100644 --- a/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/AlbumAccessor.java @@ -18,9 +18,7 @@ package net.pterodactylus.sone.template; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; import net.pterodactylus.sone.data.Album; import net.pterodactylus.util.template.Accessor; @@ -43,36 +41,66 @@ public class AlbumAccessor extends ReflectionAccessor { public Object get(TemplateContext templateContext, Object object, String member) { Album album = (Album) object; if ("backlinks".equals(member)) { - List> backlinks = new ArrayList>(); + List backlinks = new ArrayList(); Album currentAlbum = album; - while (currentAlbum != null) { - backlinks.add(0, createLink("imageBrowser.html?album=" + currentAlbum.getId(), currentAlbum.getTitle())); + while (!currentAlbum.equals(album.getSone().getRootAlbum())) { + backlinks.add(0, new Link("imageBrowser.html?album=" + currentAlbum.getId(), currentAlbum.getTitle())); currentAlbum = currentAlbum.getParent(); } - backlinks.add(0, createLink("imageBrowser.html?sone=" + album.getSone().getId(), SoneAccessor.getNiceName(album.getSone()))); + backlinks.add(0, new Link("imageBrowser.html?sone=" + album.getSone().getId(), SoneAccessor.getNiceName(album.getSone()))); return backlinks; } return super.get(templateContext, object, member); } - // - // PRIVATE METHODS - // - /** - * Creates a map containing mappings for “target” and “link.” + * Container for links. * - * @param target - * The target to link to - * @param name - * The name of the link - * @return The created map containing the mappings + * @author David ‘Bombe’ Roden */ - private static Map createLink(String target, String name) { - Map link = new HashMap(); - link.put("target", target); - link.put("name", name); - return link; + private static class Link { + + /** The target of the link. */ + private final String target; + + /** The name of the link. */ + private final String name; + + /** + * Creates a new link. + * + * @param target + * The target of the link + * @param name + * The name of the link + */ + private Link(String target, String name) { + this.target = target; + this.name = name; + } + + // + // ACCESSORS + // + + /** + * Returns the target of the link. + * + * @return The target of the link + */ + public String getTarget() { + return target; + } + + /** + * Returns the name of the link. + * + * @return The name of the link + */ + public String getName() { + return name; + } + } } diff --git a/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java b/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java index bcf73d8..3d5fda1 100644 --- a/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/ReplyGroupFilter.java @@ -21,6 +21,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import net.pterodactylus.sone.data.Post; @@ -69,14 +70,14 @@ public class ReplyGroupFilter implements Filter { replies.add(reply); } Map>> result = new HashMap>>(); - for (Post post : postSones.keySet()) { - if (result.containsKey(post)) { + for (Entry> postEntry : postSones.entrySet()) { + if (result.containsKey(postEntry.getKey())) { continue; } Map> postResult = new HashMap>(); - postResult.put("sones", postSones.get(post)); - postResult.put("replies", postReplies.get(post)); - result.put(post, postResult); + postResult.put("sones", postEntry.getValue()); + postResult.put("replies", postReplies.get(postEntry.getKey())); + result.put(postEntry.getKey(), postResult); } return result; } diff --git a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java index c54fc0d..ab872d9 100644 --- a/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java +++ b/src/main/java/net/pterodactylus/sone/template/SoneAccessor.java @@ -17,6 +17,11 @@ package net.pterodactylus.sone.template; +import static com.google.common.collect.FluentIterable.from; +import static java.util.Arrays.asList; +import static net.pterodactylus.sone.data.Album.FLATTENER; +import static net.pterodactylus.sone.data.Album.IMAGES; + import java.util.logging.Level; import java.util.logging.Logger; @@ -111,6 +116,8 @@ public class SoneAccessor extends ReflectionAccessor { return new Trust(null, null, null); } return trust; + } else if (member.equals("allImages")) { + return from(asList(sone.getRootAlbum())).transformAndConcat(FLATTENER).transformAndConcat(IMAGES); } return super.get(templateContext, object, member); } diff --git a/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java b/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java index 913e058..6efc5ed 100644 --- a/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java +++ b/src/main/java/net/pterodactylus/sone/template/SubstringFilter.java @@ -48,12 +48,6 @@ public class SubstringFilter implements Filter { } String dataString = String.valueOf(data); int dataLength = dataString.length(); - if (lengthString == null) { - if (start < 0) { - return dataString.substring(dataLength + start); - } - return dataString.substring(start); - } int length = Integer.MAX_VALUE; try { length = Integer.parseInt(lengthString); diff --git a/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java b/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java index 95ca0da..9e9cd9e 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreateAlbumPage.java @@ -64,6 +64,9 @@ public class CreateAlbumPage extends SoneTemplatePage { Sone currentSone = getCurrentSone(request.getToadletContext()); String parentId = request.getHttpRequest().getPartAsStringFailsafe("parent", 36); Album parent = webInterface.getCore().getAlbum(parentId, false); + if (parentId.equals("")) { + parent = currentSone.getRootAlbum(); + } Album album = webInterface.getCore().createAlbum(currentSone, parent); album.setTitle(name).setDescription(TextFilter.filter(request.getHttpRequest().getHeader("host"), description)); webInterface.getCore().touchConfiguration(); diff --git a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java index aea76c4..fe8c32e 100644 --- a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java +++ b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java @@ -97,6 +97,9 @@ public class CreateSonePage extends SoneTemplatePage { @Override protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException { super.processTemplate(request, templateContext); + List localSones = new ArrayList(webInterface.getCore().getLocalSones()); + Collections.sort(localSones, Sone.NICE_NAME_COMPARATOR); + templateContext.set("sones", localSones); List ownIdentitiesWithoutSone = getOwnIdentitiesWithoutSone(webInterface.getCore()); templateContext.set("identitiesWithoutSone", ownIdentitiesWithoutSone); if (request.getMethod() == Method.POST) { diff --git a/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java b/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java index 3dfb8b4..391e9ff 100644 --- a/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java +++ b/src/main/java/net/pterodactylus/sone/web/DeleteAlbumPage.java @@ -62,7 +62,7 @@ public class DeleteAlbumPage extends SoneTemplatePage { } Album parentAlbum = album.getParent(); webInterface.getCore().deleteAlbum(album); - if (parentAlbum == null) { + if (parentAlbum.equals(album.getSone().getRootAlbum())) { throw new RedirectException("imageBrowser.html?sone=" + album.getSone().getId()); } throw new RedirectException("imageBrowser.html?album=" + parentAlbum.getId()); diff --git a/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java b/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java index 8ef03e3..3db14d5 100644 --- a/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java +++ b/src/main/java/net/pterodactylus/sone/web/EditAlbumPage.java @@ -51,7 +51,6 @@ public class EditAlbumPage extends SoneTemplatePage { protected void processTemplate(FreenetRequest request, TemplateContext templateContext) throws RedirectException { super.processTemplate(request, templateContext); if (request.getMethod() == Method.POST) { - Sone currentSone = getCurrentSone(request.getToadletContext()); String albumId = request.getHttpRequest().getPartAsStringFailsafe("album", 36); Album album = webInterface.getCore().getAlbum(albumId, false); if (album == null) { @@ -61,20 +60,10 @@ public class EditAlbumPage extends SoneTemplatePage { throw new RedirectException("noPermission.html"); } if ("true".equals(request.getHttpRequest().getPartAsStringFailsafe("moveLeft", 4))) { - if (album.getParent() == null) { - currentSone.moveAlbumUp(album); - webInterface.getCore().touchConfiguration(); - throw new RedirectException("imageBrowser.html?sone=" + currentSone.getId()); - } album.getParent().moveAlbumUp(album); webInterface.getCore().touchConfiguration(); throw new RedirectException("imageBrowser.html?album=" + album.getParent().getId()); } else if ("true".equals(request.getHttpRequest().getPartAsStringFailsafe("moveRight", 4))) { - if (album.getParent() == null) { - currentSone.moveAlbumDown(album); - webInterface.getCore().touchConfiguration(); - throw new RedirectException("imageBrowser.html?sone=" + currentSone.getId()); - } album.getParent().moveAlbumDown(album); webInterface.getCore().touchConfiguration(); throw new RedirectException("imageBrowser.html?album=" + album.getParent().getId()); diff --git a/src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java b/src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java index 9dec1dc..766f018 100644 --- a/src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ImageBrowserPage.java @@ -17,6 +17,7 @@ package net.pterodactylus.sone.web; +import static com.google.common.collect.FluentIterable.from; import static net.pterodactylus.sone.data.Album.FLATTENER; import static net.pterodactylus.sone.data.Album.NOT_EMPTY; import static net.pterodactylus.sone.data.Album.TITLE_COMPARATOR; @@ -27,7 +28,6 @@ import java.util.Collections; import java.util.List; import com.google.common.base.Optional; -import com.google.common.collect.FluentIterable; import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.data.Image; @@ -94,7 +94,7 @@ public class ImageBrowserPage extends SoneTemplatePage { templateContext.set("galleryRequested", true); List albums = new ArrayList(); for (Sone sone : webInterface.getCore().getSones()) { - albums.addAll(FluentIterable.from(sone.getAlbums()).transformAndConcat(FLATTENER).filter(NOT_EMPTY).toList()); + albums.addAll(from(sone.getRootAlbum().getAlbums()).transformAndConcat(FLATTENER).filter(NOT_EMPTY).toList()); } Collections.sort(albums, TITLE_COMPARATOR); Pagination albumPagination = new Pagination(albums, 12).setPage(Numbers.safeParseInteger(request.getHttpRequest().getParam("page"), 0)); diff --git a/src/main/java/net/pterodactylus/sone/web/SearchPage.java b/src/main/java/net/pterodactylus/sone/web/SearchPage.java index 6c9e15c..e9241a1 100644 --- a/src/main/java/net/pterodactylus/sone/web/SearchPage.java +++ b/src/main/java/net/pterodactylus/sone/web/SearchPage.java @@ -581,7 +581,7 @@ public class SearchPage extends SoneTemplatePage { @Override public boolean apply(Hit hit) { - return hit.getScore() > 0; + return (hit == null) ? false : hit.getScore() > 0; } }; diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.java index 1005381..acee365 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/BookmarkAjaxPage.java @@ -19,7 +19,6 @@ package net.pterodactylus.sone.web.ajax; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user bookmark a post. @@ -46,7 +45,7 @@ public class BookmarkAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String id = request.getHttpRequest().getParam("post", null); if ((id == null) || (id.length() == 0)) { return createErrorJsonObject("invalid-post-id"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.java index 4c278c6..423d2df 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/CreatePostAjaxPage.java @@ -22,7 +22,6 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.text.TextFilter; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; import com.google.common.base.Optional; @@ -47,7 +46,7 @@ public class CreatePostAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { Sone sone = getCurrentSone(request.getToadletContext()); if (sone == null) { return createErrorJsonObject("auth-required"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java index 8a35185..ea2a2c2 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/CreateReplyAjaxPage.java @@ -25,7 +25,6 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.text.TextFilter; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * This AJAX page create a reply. @@ -52,7 +51,7 @@ public class CreateReplyAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String postId = request.getHttpRequest().getParam("post"); String text = request.getHttpRequest().getParam("text").trim(); String senderId = request.getHttpRequest().getParam("sender"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.java index 71b0016..acf5f03 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/DeletePostAjaxPage.java @@ -22,7 +22,6 @@ import com.google.common.base.Optional; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * This AJAX page deletes a post. @@ -49,7 +48,7 @@ public class DeletePostAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String postId = request.getHttpRequest().getParam("post"); Optional post = webInterface.getCore().getPost(postId); if (!post.isPresent()) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.java index 7874f83..cb33fb9 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/DeleteProfileFieldAjaxPage.java @@ -17,12 +17,16 @@ package net.pterodactylus.sone.web.ajax; +import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; + import net.pterodactylus.sone.data.Profile; import net.pterodactylus.sone.data.Profile.Field; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.fasterxml.jackson.databind.node.TextNode; /** * AJAX page that lets the user delete a profile field. @@ -45,7 +49,7 @@ public class DeleteProfileFieldAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String fieldId = request.getHttpRequest().getParam("field"); Sone currentSone = getCurrentSone(request.getToadletContext()); Profile profile = currentSone.getProfile(); @@ -56,7 +60,7 @@ public class DeleteProfileFieldAjaxPage extends JsonPage { profile.removeField(field); currentSone.setProfile(profile); webInterface.getCore().touchConfiguration(); - return createSuccessJsonObject().put("field", new JsonObject().put("id", field.getId())); + return createSuccessJsonObject().put("field", new ObjectNode(instance).put("id", new TextNode(field.getId()))); } } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java index 2aa217d..3ea9f7f 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/DeleteReplyAjaxPage.java @@ -22,7 +22,6 @@ import com.google.common.base.Optional; import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * This AJAX page deletes a reply. @@ -49,7 +48,7 @@ public class DeleteReplyAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String replyId = request.getHttpRequest().getParam("reply"); Optional reply = webInterface.getCore().getPostReply(replyId); if (!reply.isPresent()) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.java index 595696f..aed9cad 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/DismissNotificationAjaxPage.java @@ -19,7 +19,6 @@ package net.pterodactylus.sone.web.ajax; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; import net.pterodactylus.util.notify.Notification; /** @@ -43,7 +42,7 @@ public class DismissNotificationAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String notificationId = request.getHttpRequest().getParam("notification"); Notification notification = webInterface.getNotifications().getNotification(notificationId); if (notification == null) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.java index 843b088..4206e8f 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/DistrustAjaxPage.java @@ -23,7 +23,6 @@ import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user distrust a Sone. @@ -47,7 +46,7 @@ public class DistrustAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { Sone currentSone = getCurrentSone(request.getToadletContext(), false); if (currentSone == null) { return createErrorJsonObject("auth-required"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.java index 8d436ea..5d587db 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/EditAlbumAjaxPage.java @@ -21,7 +21,6 @@ import net.pterodactylus.sone.data.Album; import net.pterodactylus.sone.text.TextFilter; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * Page that stores a user’s album modifications. @@ -48,7 +47,7 @@ public class EditAlbumAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String albumId = request.getHttpRequest().getParam("album"); Album album = webInterface.getCore().getAlbum(albumId, false); if (album == null) { @@ -58,12 +57,12 @@ public class EditAlbumAjaxPage extends JsonPage { return createErrorJsonObject("not-authorized"); } if ("true".equals(request.getHttpRequest().getParam("moveLeft"))) { - Album swappedAlbum = (album.getParent() != null) ? album.getParent().moveAlbumUp(album) : album.getSone().moveAlbumUp(album); + Album swappedAlbum = album.getParent().moveAlbumUp(album); webInterface.getCore().touchConfiguration(); return createSuccessJsonObject().put("sourceAlbumId", album.getId()).put("destinationAlbumId", swappedAlbum.getId()); } if ("true".equals(request.getHttpRequest().getParam("moveRight"))) { - Album swappedAlbum = (album.getParent() != null) ? album.getParent().moveAlbumDown(album) : album.getSone().moveAlbumDown(album); + Album swappedAlbum = album.getParent().moveAlbumDown(album); webInterface.getCore().touchConfiguration(); return createSuccessJsonObject().put("sourceAlbumId", album.getId()).put("destinationAlbumId", swappedAlbum.getId()); } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.java index 378b03b..08452ef 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/EditImageAjaxPage.java @@ -22,7 +22,6 @@ import net.pterodactylus.sone.template.ParserFilter; import net.pterodactylus.sone.text.TextFilter; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; import net.pterodactylus.util.template.TemplateContext; import com.google.common.collect.ImmutableMap; @@ -58,7 +57,7 @@ public class EditImageAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String imageId = request.getHttpRequest().getParam("image"); Image image = webInterface.getCore().getImage(imageId, false); if (image == null) { @@ -81,7 +80,7 @@ public class EditImageAjaxPage extends JsonPage { 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(), ImmutableMap. builder().put("sone", image.getSone()).build())); + return createSuccessJsonObject().put("imageId", image.getId()).put("title", image.getTitle()).put("description", image.getDescription()).put("parsedDescription", (String) parserFilter.format(new TemplateContext(), image.getDescription(), ImmutableMap.builder().put("sone", image.getSone()).build())); } } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.java index 8a47ffe..b4596ad 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/EditProfileFieldAjaxPage.java @@ -22,7 +22,6 @@ import net.pterodactylus.sone.data.Profile.Field; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user rename a profile field. @@ -49,7 +48,7 @@ public class EditProfileFieldAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String fieldId = request.getHttpRequest().getParam("field"); Sone currentSone = getCurrentSone(request.getToadletContext()); Profile profile = currentSone.getProfile(); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.java index 071f8e9..64c402a 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/FollowSoneAjaxPage.java @@ -22,7 +22,6 @@ import com.google.common.base.Optional; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets a Sone follow another Sone. @@ -45,7 +44,7 @@ public class FollowSoneAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String soneId = request.getHttpRequest().getParam("sone"); Optional sone = webInterface.getCore().getSone(soneId); if (!sone.isPresent()) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java index 1a5286f..ccc51dc 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetLikesAjaxPage.java @@ -17,9 +17,9 @@ package net.pterodactylus.sone.web.ajax; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; +import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; +import static net.pterodactylus.sone.data.Sone.NICE_NAME_COMPARATOR; + import java.util.Set; import net.pterodactylus.sone.data.Post; @@ -28,10 +28,12 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.template.SoneAccessor; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonArray; -import net.pterodactylus.util.json.JsonObject; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Optional; +import com.google.common.collect.FluentIterable; /** * AJAX page that retrieves the number of “likes” a {@link Post} has. @@ -58,7 +60,7 @@ public class GetLikesAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String type = request.getHttpRequest().getParam("type", null); String id = request.getHttpRequest().getParam(type, null); if ((id == null) || (id.length() == 0)) { @@ -102,12 +104,10 @@ public class GetLikesAjaxPage extends JsonPage { * The Sones to convert to an array * @return The Sones, sorted by name */ - private static JsonArray getSones(Set sones) { - JsonArray soneArray = new JsonArray(); - List sortedSones = new ArrayList(sones); - Collections.sort(sortedSones, Sone.NICE_NAME_COMPARATOR); - for (Sone sone : sortedSones) { - soneArray.add(new JsonObject().put("id", sone.getId()).put("name", SoneAccessor.getNiceName(sone))); + private static JsonNode getSones(Set sones) { + ArrayNode soneArray = new ArrayNode(instance); + for (Sone sone : FluentIterable.from(sones).toSortedList(NICE_NAME_COMPARATOR)) { + soneArray.add(new ObjectNode(instance).put("id", sone.getId()).put("name", SoneAccessor.getNiceName(sone))); } return soneArray; } diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.java index 6573dda..e8107ef 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPage.java @@ -17,6 +17,8 @@ package net.pterodactylus.sone.web.ajax; +import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; + import java.io.IOException; import java.io.StringWriter; import java.util.Collection; @@ -28,12 +30,14 @@ import net.pterodactylus.sone.main.SonePlugin; import net.pterodactylus.sone.notify.ListNotificationFilters; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonArray; -import net.pterodactylus.util.json.JsonObject; import net.pterodactylus.util.notify.Notification; import net.pterodactylus.util.notify.TemplateNotification; import net.pterodactylus.util.template.TemplateContext; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * AJAX handler to return all current notifications. * @@ -75,12 +79,12 @@ public class GetNotificationsAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { Sone currentSone = getCurrentSone(request.getToadletContext(), false); Collection notifications = webInterface.getNotifications().getNotifications(); List filteredNotifications = ListNotificationFilters.filterNotifications(notifications, currentSone); Collections.sort(filteredNotifications, Notification.CREATED_TIME_SORTER); - JsonArray jsonNotifications = new JsonArray(); + ArrayNode jsonNotifications = new ArrayNode(instance); for (Notification notification : filteredNotifications) { jsonNotifications.add(createJsonNotification(request, notification)); } @@ -100,8 +104,8 @@ public class GetNotificationsAjaxPage extends JsonPage { * The notification to create a JSON object * @return The JSON object */ - private JsonObject createJsonNotification(FreenetRequest request, Notification notification) { - JsonObject jsonNotification = new JsonObject(); + private JsonNode createJsonNotification(FreenetRequest request, Notification notification) { + ObjectNode jsonNotification = new ObjectNode(instance); jsonNotification.put("id", notification.getId()); StringWriter notificationWriter = new StringWriter(); try { @@ -140,8 +144,8 @@ public class GetNotificationsAjaxPage extends JsonPage { * The current Sone (may be {@code null}) * @return The current options */ - private static JsonObject createJsonOptions(Sone currentSone) { - JsonObject options = new JsonObject(); + private static JsonNode createJsonOptions(Sone currentSone) { + ObjectNode options = new ObjectNode(instance); if (currentSone != null) { options.put("ShowNotification/NewSones", currentSone.getOptions().getBooleanOption("ShowNotification/NewSones").get()); options.put("ShowNotification/NewPosts", currentSone.getOptions().getBooleanOption("ShowNotification/NewPosts").get()); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java index 8eeedc9..96002b3 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetPostAjaxPage.java @@ -18,6 +18,7 @@ package net.pterodactylus.sone.web.ajax; import java.io.StringWriter; +import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; import com.google.common.base.Optional; @@ -26,11 +27,13 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.io.Closer; -import net.pterodactylus.util.json.JsonObject; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; import net.pterodactylus.util.template.TemplateException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * This AJAX handler retrieves information and rendered representation of a * {@link Post}. @@ -59,7 +62,7 @@ public class GetPostAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String postId = request.getHttpRequest().getParam("post"); Optional post = webInterface.getCore().getPost(postId); if (!post.isPresent()) { @@ -92,8 +95,8 @@ public class GetPostAjaxPage extends JsonPage { * The currently logged in Sone (to store in the template) * @return The JSON representation of the post */ - private JsonObject createJsonPost(FreenetRequest request, Post post, Sone currentSone) { - JsonObject jsonPost = new JsonObject(); + private JsonNode createJsonPost(FreenetRequest request, Post post, Sone currentSone) { + ObjectNode jsonPost = new ObjectNode(instance); jsonPost.put("id", post.getId()); jsonPost.put("sone", post.getSone().getId()); jsonPost.put("recipient", post.getRecipientId().orNull()); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java index b617608..251c784 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetReplyAjaxPage.java @@ -18,6 +18,7 @@ package net.pterodactylus.sone.web.ajax; import java.io.StringWriter; +import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; import com.google.common.base.Optional; @@ -26,11 +27,13 @@ import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.io.Closer; -import net.pterodactylus.util.json.JsonObject; import net.pterodactylus.util.template.Template; import net.pterodactylus.util.template.TemplateContext; import net.pterodactylus.util.template.TemplateException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ObjectNode; + /** * This AJAX page returns the details of a reply. * @@ -62,7 +65,7 @@ public class GetReplyAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String replyId = request.getHttpRequest().getParam("reply"); Optional reply = webInterface.getCore().getPostReply(replyId); if (!reply.isPresent()) { @@ -94,8 +97,8 @@ public class GetReplyAjaxPage extends JsonPage { * The currently logged in Sone (to store in the template) * @return The JSON representation of the reply */ - private JsonObject createJsonReply(FreenetRequest request, PostReply reply, Sone currentSone) { - JsonObject jsonReply = new JsonObject(); + private JsonNode createJsonReply(FreenetRequest request, PostReply reply, Sone currentSone) { + ObjectNode jsonReply = new ObjectNode(instance); jsonReply.put("id", reply.getId()); jsonReply.put("postId", reply.getPostId()); jsonReply.put("soneId", reply.getSone().getId()); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java index 48b25d6..e43910c 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java @@ -17,6 +17,8 @@ package net.pterodactylus.sone.web.ajax; +import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; + import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Collection; @@ -33,10 +35,11 @@ import net.pterodactylus.sone.notify.ListNotificationFilters; import net.pterodactylus.sone.template.SoneAccessor; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonArray; -import net.pterodactylus.util.json.JsonObject; import net.pterodactylus.util.notify.Notification; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Predicate; import com.google.common.collect.Collections2; @@ -65,7 +68,7 @@ public class GetStatusAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { final Sone currentSone = getCurrentSone(request.getToadletContext(), false); /* load Sones. always return the status of the current Sone. */ Set sones = new HashSet(Collections.singleton(getCurrentSone(request.getToadletContext(), false))); @@ -77,13 +80,12 @@ public class GetStatusAjaxPage extends JsonPage { sones.add(webInterface.getCore().getSone(soneId).orNull()); } } - JsonArray jsonSones = new JsonArray(); + ArrayNode jsonSones = new ArrayNode(instance); for (Sone sone : sones) { if (sone == null) { continue; } - JsonObject jsonSone = createJsonSone(sone); - jsonSones.add(jsonSone); + jsonSones.add(createJsonSone(sone)); } /* load notifications. */ List notifications = ListNotificationFilters.filterNotifications(webInterface.getNotifications().getNotifications(), currentSone); @@ -100,9 +102,9 @@ public class GetStatusAjaxPage extends JsonPage { }); } - JsonArray jsonPosts = new JsonArray(); + ArrayNode jsonPosts = new ArrayNode(instance); for (Post post : newPosts) { - JsonObject jsonPost = new JsonObject(); + ObjectNode jsonPost = new ObjectNode(instance); jsonPost.put("id", post.getId()); jsonPost.put("sone", post.getSone().getId()); jsonPost.put("recipient", post.getRecipientId().orNull()); @@ -123,9 +125,9 @@ public class GetStatusAjaxPage extends JsonPage { } /* remove replies to unknown posts. */ newReplies = Collections2.filter(newReplies, PostReply.HAS_POST_FILTER); - JsonArray jsonReplies = new JsonArray(); + ArrayNode jsonReplies = new ArrayNode(instance); for (PostReply reply : newReplies) { - JsonObject jsonReply = new JsonObject(); + ObjectNode jsonReply = new ObjectNode(instance); jsonReply.put("id", reply.getId()); jsonReply.put("sone", reply.getSone().getId()); jsonReply.put("post", reply.getPostId()); @@ -162,8 +164,8 @@ public class GetStatusAjaxPage extends JsonPage { * The Sone to convert to a JSON object * @return The JSON representation of the given Sone */ - private JsonObject createJsonSone(Sone sone) { - JsonObject jsonSone = new JsonObject(); + private JsonNode createJsonSone(Sone sone) { + ObjectNode jsonSone = new ObjectNode(instance); jsonSone.put("id", sone.getId()); jsonSone.put("name", SoneAccessor.getNiceName(sone)); jsonSone.put("local", sone.getInsertUri() != null); @@ -187,8 +189,8 @@ public class GetStatusAjaxPage extends JsonPage { * The current Sone (may be {@code null}) * @return The current options */ - private static JsonObject createJsonOptions(Sone currentSone) { - JsonObject options = new JsonObject(); + private static JsonNode createJsonOptions(Sone currentSone) { + ObjectNode options = new ObjectNode(instance); if (currentSone != null) { options.put("ShowNotification/NewSones", currentSone.getOptions().getBooleanOption("ShowNotification/NewSones").get()); options.put("ShowNotification/NewPosts", currentSone.getOptions().getBooleanOption("ShowNotification/NewPosts").get()); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java index b0d9dac..0c78bb6 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetTimesAjaxPage.java @@ -17,6 +17,8 @@ package net.pterodactylus.sone.web.ajax; +import static com.fasterxml.jackson.databind.node.JsonNodeFactory.instance; + import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; @@ -26,8 +28,8 @@ import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.PostReply; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; +import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Optional; /** @@ -54,9 +56,9 @@ public class GetTimesAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String allIds = request.getHttpRequest().getParam("posts"); - JsonObject postTimes = new JsonObject(); + ObjectNode postTimes = new ObjectNode(instance); if (allIds.length() > 0) { String[] ids = allIds.split(","); for (String id : ids) { @@ -64,7 +66,7 @@ public class GetTimesAjaxPage extends JsonPage { if (!post.isPresent()) { continue; } - JsonObject postTime = new JsonObject(); + ObjectNode postTime = new ObjectNode(instance); Time time = getTime(post.get().getTime()); postTime.put("timeText", time.getText()); postTime.put("refreshTime", TimeUnit.MILLISECONDS.toSeconds(time.getRefresh())); @@ -74,7 +76,7 @@ public class GetTimesAjaxPage extends JsonPage { postTimes.put(id, postTime); } } - JsonObject replyTimes = new JsonObject(); + ObjectNode replyTimes = new ObjectNode(instance); allIds = request.getHttpRequest().getParam("replies"); if (allIds.length() > 0) { String[] ids = allIds.split(","); @@ -83,7 +85,7 @@ public class GetTimesAjaxPage extends JsonPage { if (!reply.isPresent()) { continue; } - JsonObject replyTime = new JsonObject(); + ObjectNode replyTime = new ObjectNode(instance); Time time = getTime(reply.get().getTime()); replyTime.put("timeText", time.getText()); replyTime.put("refreshTime", TimeUnit.MILLISECONDS.toSeconds(time.getRefresh())); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetTranslationPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetTranslationPage.java index 0ecfaea..5c81d95 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetTranslationPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetTranslationPage.java @@ -19,7 +19,6 @@ package net.pterodactylus.sone.web.ajax; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * Returns the translation for a given key as JSON object. @@ -46,7 +45,7 @@ public class GetTranslationPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String key = request.getHttpRequest().getParam("key"); String translation = webInterface.getL10n().getString(key); return createSuccessJsonObject().put("value", translation); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/JsonErrorReturnObject.java b/src/main/java/net/pterodactylus/sone/web/ajax/JsonErrorReturnObject.java new file mode 100644 index 0000000..4612f0c --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/ajax/JsonErrorReturnObject.java @@ -0,0 +1,46 @@ +/* + * © 2013 xplosion interactive + */ + +package net.pterodactylus.sone.web.ajax; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.annotations.VisibleForTesting; + +/** + * {@link JsonReturnObject} that signals an error has occured. + * + * @author David Roden + */ +public class JsonErrorReturnObject extends JsonReturnObject { + + /** The error that has occured. */ + @JsonProperty + private final String error; + + /** + * Creates a new error JSON return object. + * + * @param error + * The error that occured + */ + public JsonErrorReturnObject(String error) { + super(false); + this.error = error; + } + + // + // ACCESSORS + // + + /** + * Returns the error that occured. + * + * @return The error that occured + */ + @VisibleForTesting + public String getError() { + return error; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java index 994f90c..3c7f587 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/JsonPage.java @@ -30,11 +30,11 @@ import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetPage; import net.pterodactylus.sone.web.page.FreenetRequest; import net.pterodactylus.util.io.Closer; -import net.pterodactylus.util.json.JsonObject; -import net.pterodactylus.util.json.JsonUtils; import net.pterodactylus.util.logging.Logging; import net.pterodactylus.util.web.Page; import net.pterodactylus.util.web.Response; + +import com.fasterxml.jackson.databind.ObjectMapper; import freenet.clients.http.SessionManager.Session; import freenet.clients.http.ToadletContext; @@ -49,6 +49,9 @@ public abstract class JsonPage implements FreenetPage { /** The logger. */ private static final Logger logger = Logging.getLogger(JsonPage.class); + /** The JSON serializer. */ + private static final ObjectMapper objectMapper = new ObjectMapper(); + /** The path of the page. */ private final String path; @@ -140,7 +143,7 @@ public abstract class JsonPage implements FreenetPage { * The request to handle * @return The created JSON object */ - protected abstract JsonObject createJsonObject(FreenetRequest request); + protected abstract JsonReturnObject createJsonObject(FreenetRequest request); /** * Returns whether this command needs the form password for authentication @@ -174,8 +177,8 @@ public abstract class JsonPage implements FreenetPage { * * @return A reply signaling success */ - protected static JsonObject createSuccessJsonObject() { - return new JsonObject().put("success", true); + protected static JsonReturnObject createSuccessJsonObject() { + return new JsonReturnObject(true); } /** @@ -185,8 +188,8 @@ public abstract class JsonPage implements FreenetPage { * The error that has occured * @return The JSON object, signalling failure and the error code */ - protected static JsonObject createErrorJsonObject(String error) { - return new JsonObject().put("success", false).put("error", error); + protected static JsonReturnObject createErrorJsonObject(String error) { + return new JsonErrorReturnObject(error); } // @@ -215,22 +218,22 @@ public abstract class JsonPage implements FreenetPage { @Override public Response handleRequest(FreenetRequest request, Response response) throws IOException { if (webInterface.getCore().getPreferences().isRequireFullAccess() && !request.getToadletContext().isAllowedFullAccess()) { - return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(JsonUtils.format(new JsonObject().put("success", false).put("error", "auth-required"))); + return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required"))); } if (needsFormPassword()) { String formPassword = request.getHttpRequest().getParam("formPassword"); if (!webInterface.getFormPassword().equals(formPassword)) { - return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(JsonUtils.format(new JsonObject().put("success", false).put("error", "auth-required"))); + return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required"))); } } if (requiresLogin()) { if (getCurrentSone(request.getToadletContext(), false) == null) { - return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(JsonUtils.format(new JsonObject().put("success", false).put("error", "auth-required"))); + return response.setStatusCode(403).setStatusText("Forbidden").setContentType("application/json").write(objectMapper.writeValueAsString(new JsonErrorReturnObject("auth-required"))); } } try { - JsonObject jsonObject = createJsonObject(request); - return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(JsonUtils.format(jsonObject)); + JsonReturnObject jsonObject = createJsonObject(request); + return response.setStatusCode(200).setStatusText("OK").setContentType("application/json").write(objectMapper.writeValueAsString(jsonObject)); } catch (Exception e1) { logger.log(Level.WARNING, "Error executing JSON page!", e1); return response.setStatusCode(500).setStatusText(e1.getMessage()).setContentType("text/plain").write(dumpStackTrace(e1)); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/JsonReturnObject.java b/src/main/java/net/pterodactylus/sone/web/ajax/JsonReturnObject.java new file mode 100644 index 0000000..ca29f3c --- /dev/null +++ b/src/main/java/net/pterodactylus/sone/web/ajax/JsonReturnObject.java @@ -0,0 +1,136 @@ +/* + * © 2013 xplosion interactive + */ + +package net.pterodactylus.sone.web.ajax; + +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonAnyGetter; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.node.BooleanNode; +import com.fasterxml.jackson.databind.node.IntNode; +import com.fasterxml.jackson.databind.node.TextNode; +import com.google.common.annotations.VisibleForTesting; +import com.google.common.collect.Maps; + +/** + * JSON return object for AJAX requests. + * + * @author David Roden + */ +public class JsonReturnObject { + + /** Whether the request was successful. */ + @JsonProperty + private final boolean success; + + /** The returned values. */ + private final Map content = Maps.newHashMap(); + + /** + * Creates a new JSON return object. + * + * @param success + * {@code true} if the request was successful, {@code false} otherwise + */ + public JsonReturnObject(boolean success) { + this.success = success; + } + + // + // ACCESSORS + // + + /** + * Returns whether the request was successful. + * + * @return {@code true} if the request was successful, {@code false} otherwise + */ + @VisibleForTesting + public boolean isSuccess() { + return success; + } + + /** + * Returns the value stored under the given key. + * + * @param key + * The key of the value to retrieve + * @return The value of the key, or {@code null} if there is no value for the + * given key + */ + @VisibleForTesting + public JsonNode get(String key) { + return content.get(key); + } + + /** + * Returns the content of this object for serialization. + * + * @return The content of this object + */ + @JsonAnyGetter + public Map getContent() { + return content; + } + + // + // ACTIONS + // + + /** + * Stores the given value under the given key. + * + * @param key + * The key under which to store the value + * @param value + * The value to store + * @return This JSON return object + */ + public JsonReturnObject put(String key, boolean value) { + return put(key, BooleanNode.valueOf(value)); + } + + /** + * Stores the given value under the given key. + * + * @param key + * The key under which to store the value + * @param value + * The value to store + * @return This JSON return object + */ + public JsonReturnObject put(String key, int value) { + return put(key, new IntNode(value)); + } + + /** + * Stores the given value under the given key. + * + * @param key + * The key under which to store the value + * @param value + * The value to store + * @return This JSON return object + */ + public JsonReturnObject put(String key, String value) { + return put(key, new TextNode(value)); + } + + /** + * Stores the given value under the given key. + * + * @param key + * The key under which to store the value + * @param value + * The value to store + * @return This JSON return object + */ + public JsonReturnObject put(String key, JsonNode value) { + content.put(key, value); + return this; + } + +} diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java index 6787711..55a947a 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/LikeAjaxPage.java @@ -21,7 +21,6 @@ import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user like a {@link Post}. @@ -44,7 +43,7 @@ public class LikeAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String type = request.getHttpRequest().getParam("type", null); String id = request.getHttpRequest().getParam(type, null); if ((id == null) || (id.length() == 0)) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.java index af74426..68668b7 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/LockSoneAjaxPage.java @@ -21,7 +21,6 @@ import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * Lets the user {@link Core#lockSone(Sone) lock} a {@link Sone}. @@ -44,7 +43,7 @@ public class LockSoneAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String soneId = request.getHttpRequest().getParam("sone"); Sone sone = webInterface.getCore().getLocalSone(soneId, false); if (sone == null) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java index 6610971..cd026ef 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/MarkAsKnownAjaxPage.java @@ -24,7 +24,6 @@ import net.pterodactylus.sone.data.Reply; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; import com.google.common.base.Optional; @@ -50,7 +49,7 @@ public class MarkAsKnownAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String type = request.getHttpRequest().getParam("type"); if (!type.equals("sone") && !type.equals("post") && !type.equals("reply")) { return createErrorJsonObject("invalid-type"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.java index 7721aa3..d8781ba 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/MoveProfileFieldAjaxPage.java @@ -22,7 +22,6 @@ import net.pterodactylus.sone.data.Profile.Field; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user move a profile field up or down. @@ -51,7 +50,7 @@ public class MoveProfileFieldAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { Sone currentSone = getCurrentSone(request.getToadletContext()); Profile profile = currentSone.getProfile(); String fieldId = request.getHttpRequest().getParam("field"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/TrustAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/TrustAjaxPage.java index d03e030..3661cb1 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/TrustAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/TrustAjaxPage.java @@ -23,7 +23,6 @@ import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user trust a Sone. @@ -47,7 +46,7 @@ public class TrustAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { Sone currentSone = getCurrentSone(request.getToadletContext(), false); if (currentSone == null) { return createErrorJsonObject("auth-required"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.java index 8d209af..65bb14d 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/UnbookmarkAjaxPage.java @@ -19,7 +19,6 @@ package net.pterodactylus.sone.web.ajax; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user unbookmark a post. @@ -46,7 +45,7 @@ public class UnbookmarkAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String id = request.getHttpRequest().getParam("post", null); if ((id == null) || (id.length() == 0)) { return createErrorJsonObject("invalid-post-id"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.java index 3d984b9..a285d20 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/UnfollowSoneAjaxPage.java @@ -20,7 +20,6 @@ package net.pterodactylus.sone.web.ajax; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets a Sone unfollow another Sone. @@ -43,7 +42,7 @@ public class UnfollowSoneAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String soneId = request.getHttpRequest().getParam("sone"); if (!webInterface.getCore().getSone(soneId).isPresent()) { return createErrorJsonObject("invalid-sone-id"); diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java index 0633fda..17be966 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/UnlikeAjaxPage.java @@ -21,7 +21,6 @@ import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user unlike a {@link Post}. @@ -44,7 +43,7 @@ public class UnlikeAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String type = request.getHttpRequest().getParam("type", null); String id = request.getHttpRequest().getParam(type, null); if ((id == null) || (id.length() == 0)) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.java index 32bb93c..f92132d 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/UnlockSoneAjaxPage.java @@ -21,7 +21,6 @@ import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * Lets the user {@link Core#unlockSone(Sone) unlock} a {@link Sone}. @@ -44,7 +43,7 @@ public class UnlockSoneAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { String soneId = request.getHttpRequest().getParam("sone"); Sone sone = webInterface.getCore().getLocalSone(soneId, false); if (sone == null) { diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.java index 65d45c9..229f219 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/UntrustAjaxPage.java @@ -23,7 +23,6 @@ import net.pterodactylus.sone.core.Core; import net.pterodactylus.sone.data.Sone; import net.pterodactylus.sone.web.WebInterface; import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.json.JsonObject; /** * AJAX page that lets the user untrust a Sone. @@ -47,7 +46,7 @@ public class UntrustAjaxPage extends JsonPage { * {@inheritDoc} */ @Override - protected JsonObject createJsonObject(FreenetRequest request) { + protected JsonReturnObject createJsonObject(FreenetRequest request) { Sone currentSone = getCurrentSone(request.getToadletContext(), false); if (currentSone == null) { return createErrorJsonObject("auth-required"); diff --git a/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java b/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java index 2c6706f..a40a543 100644 --- a/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java +++ b/src/main/java/net/pterodactylus/sone/web/page/PageToadlet.java @@ -18,12 +18,14 @@ package net.pterodactylus.sone.web.page; import java.io.IOException; +import java.io.OutputStream; import java.net.URI; import net.pterodactylus.util.web.Header; import net.pterodactylus.util.web.Method; import net.pterodactylus.util.web.Page; import net.pterodactylus.util.web.Response; + import freenet.client.HighLevelSimpleClient; import freenet.clients.http.LinkEnabledCallback; import freenet.clients.http.LinkFilterExceptedToadlet; @@ -144,21 +146,28 @@ public class PageToadlet extends Toadlet implements LinkEnabledCallback, LinkFil */ private void handleRequest(FreenetRequest pageRequest) throws IOException, ToadletContextClosedException { Bucket pageBucket = null; + OutputStream pageBucketOutputStream = null; + Response pageResponse; try { pageBucket = pageRequest.getToadletContext().getBucketFactory().makeBucket(-1); - Response pageResponse = new Response(pageBucket.getOutputStream()); - pageResponse = page.handleRequest(pageRequest, pageResponse); - MultiValueTable headers = new MultiValueTable(); - if (pageResponse.getHeaders() != null) { - for (Header header : pageResponse.getHeaders()) { - for (String value : header) { - headers.put(header.getName(), value); - } + pageBucketOutputStream = pageBucket.getOutputStream(); + pageResponse = page.handleRequest(pageRequest, new Response(pageBucketOutputStream)); + } catch (IOException ioe1) { + Closer.close(pageBucket); + throw ioe1; + } finally { + Closer.close(pageBucketOutputStream); + } + MultiValueTable headers = new MultiValueTable(); + if (pageResponse.getHeaders() != null) { + for (Header header : pageResponse.getHeaders()) { + for (String value : header) { + headers.put(header.getName(), value); } } + } + try { writeReply(pageRequest.getToadletContext(), pageResponse.getStatusCode(), pageResponse.getContentType(), pageResponse.getStatusText(), headers, pageBucket); - } catch (Throwable t1) { - writeInternalError(t1, pageRequest.getToadletContext()); } finally { Closer.close(pageBucket); } diff --git a/src/main/resources/i18n/sone.de.properties b/src/main/resources/i18n/sone.de.properties index d0ec575..d7a4b9d 100644 --- a/src/main/resources/i18n/sone.de.properties +++ b/src/main/resources/i18n/sone.de.properties @@ -451,4 +451,6 @@ Notification.InsertedImages.Text=Diese Bilder wurden nach Freenet hoch geladen: Notification.ImageInsertFailed.Text=Diese Bilder konnten nicht nach Freenet hoch geladen werden: Notification.Mention.ShortText=Sie wurden erwähnt. Notification.Mention.Text=Sie wurden in diesen Nachrichten erwähnt: -Notification.SoneInsert.Duration={0,number} {0,choice,0#Sekunden|1#Sekunde|1" : "").blur(function() { + var textarea = $(dontUseTextarea ? "" : "").blur(function() { if ($(this).val() == "") { $(this).hide(); - inputField = $(this).data("inputField"); + var inputField = $(this).data("inputField"); inputField.show().removeAttr("disabled").addClass("default"); inputField.val(defaultText); } @@ -68,14 +68,14 @@ function addCommentLink(postId, author, element, insertAfterThisElement) { return; } (function(postId, author, insertAfterThisElement) { - separator = $(" · ").addClass("separator"); + var separator = $(" · ").addClass("separator"); getTranslation("WebInterface.Button.Comment", function(text) { - commentElement = $("

" + text + "
").addClass("show-reply-form").click(function() { - replyElement = $("#sone .post#post-" + postId + " .create-reply"); + var commentElement = $("
" + text + "
").addClass("show-reply-form").click(function() { + var replyElement = sone.find(".post#post-" + postId + " .create-reply"); replyElement.removeClass("hidden"); replyElement.removeClass("light"); (function(replyElement) { - replyElement.find("input.reply-input").blur(function() { + replyElement.find(":input.reply-input").blur(function() { if ($(this).hasClass("default")) { replyElement.addClass("light"); } @@ -83,7 +83,7 @@ function addCommentLink(postId, author, element, insertAfterThisElement) { replyElement.removeClass("light"); }); })(replyElement); - textArea = replyElement.find("input.reply-input").focus().data("textarea"); + var textArea = replyElement.find(":input.reply-input").focus().data("textarea"); if (author != getCurrentSoneId()) { textArea.val(textArea.val() + "@sone://" + author + " "); } @@ -145,22 +145,22 @@ function filterSoneId(soneId) { * The date and time of the last update (formatted for display) */ function updateSoneStatus(soneId, name, status, modified, locked, lastUpdated, lastUpdatedText) { - $("#sone .sone." + filterSoneId(soneId)). - toggleClass("unknown", status == "unknown"). + var updateSone = sone.find(".sone." + filterSoneId(soneId)); + updateSone.toggleClass("unknown", status == "unknown"). toggleClass("idle", status == "idle"). toggleClass("inserting", status == "inserting"). toggleClass("downloading", status == "downloading"). toggleClass("modified", modified); - $("#sone .sone." + filterSoneId(soneId) + " .lock").toggleClass("hidden", locked); - $("#sone .sone." + filterSoneId(soneId) + " .unlock").toggleClass("hidden", !locked); + updateSone.find(".lock").toggleClass("hidden", locked); + updateSone.find(".unlock").toggleClass("hidden", !locked); if (lastUpdated != null) { - $("#sone .sone." + filterSoneId(soneId) + " .last-update span.time").attr("title", lastUpdated).text(lastUpdatedText); + updateSone.find(".last-update span.time").attr("title", lastUpdated).text(lastUpdatedText); } else { getTranslation("View.Sone.Text.UnknownDate", function(unknown) { - $("#sone .sone." + filterSoneId(soneId) + " .last-update span.time").text(unknown); + updateSone.find(".last-update span.time").text(unknown); }); } - $("#sone .sone." + filterSoneId(soneId) + " .profile-link a").text(name); + updateSone.find(".profile-link a").text(name); } /** @@ -175,7 +175,7 @@ function updateSoneStatus(soneId, name, status, modified, locked, lastUpdated, l */ function enhanceDeleteButton(button, text, deleteCallback) { (function(button) { - newButton = $("").addClass("confirm").hide().text(text).click(function() { + var newButton = $("").addClass("confirm").hide().text(text).click(function() { $(this).fadeOut("slow"); deleteCallback(); return false; @@ -215,7 +215,7 @@ function enhanceDeletePostButton(button, postId, text) { return; } if (data.success) { - $("#sone .post#post-" + postId).slideUp(); + sone.find(".post#post-" + postId).slideUp(); } else if (data.error == "invalid-post-id") { /* pretend the post is already gone. */ getPost(postId).slideUp(); @@ -242,12 +242,12 @@ function enhanceDeletePostButton(button, postId, text) { */ function enhanceDeleteReplyButton(button, replyId, text) { enhanceDeleteButton(button, text, function() { - ajaxGet("deleteReply.ajax", { "reply": replyId, "formPassword": $("#sone #formPassword").text() }, function(data, textStatus) { + ajaxGet("deleteReply.ajax", { "reply": replyId, "formPassword": sone.find("#formPassword").text() }, function(data, textStatus) { if (data == null) { return; } if (data.success) { - $("#sone .reply#reply-" + replyId).slideUp(); + sone.find(".reply#reply-" + replyId).slideUp(); } else if (data.error == "invalid-reply-id") { /* pretend the reply is already gone. */ getReply(replyId).slideUp(); @@ -263,7 +263,7 @@ function enhanceDeleteReplyButton(button, replyId, text) { } function getFormPassword() { - return $("#sone #formPassword").text(); + return sone.find("#formPassword").text(); } /** @@ -274,7 +274,7 @@ function getFormPassword() { * @returns All Sone elements with the given ID */ function getSone(soneId) { - return $("#sone .sone").filter(function(index) { + return sone.find(".sone").filter(function(index) { return $(".id", this).text() == soneId; }); } @@ -333,7 +333,7 @@ function getSoneId(element) { * @returns The element of the post */ function getPost(postId) { - return $("#sone .post#post-" + postId); + return sone.find(".post#post-" + postId); } function getPostElement(element) { @@ -367,7 +367,7 @@ function getPostAuthor(element) { * @returns The element of the reply */ function getReply(replyId) { - return $("#sone .reply#reply-" + replyId); + return sone.find(".reply#reply-" + replyId); } function getReplyElement(element) { @@ -401,7 +401,7 @@ function getReplyAuthor(element) { * @returns The notification element */ function getNotification(notificationId) { - return $("#sone #notification-area .notification#" + notificationId); + return sone.find("#notification-area .notification#" + notificationId); } /** @@ -442,8 +442,8 @@ function likePost(postId) { if ((data == null) || !data.success) { return; } - $("#sone .post#post-" + postId + " > .inner-part > .status-line .like").addClass("hidden"); - $("#sone .post#post-" + postId + " > .inner-part > .status-line .unlike").removeClass("hidden"); + sone.find(".post#post-" + postId + " > .inner-part > .status-line .like").addClass("hidden"); + sone.find(".post#post-" + postId + " > .inner-part > .status-line .unlike").removeClass("hidden"); updatePostLikes(postId); }, function(xmlHttpRequest, textStatus, error) { /* ignore error. */ @@ -455,8 +455,8 @@ function unlikePost(postId) { if ((data == null) || !data.success) { return; } - $("#sone .post#post-" + postId + " > .inner-part > .status-line .unlike").addClass("hidden"); - $("#sone .post#post-" + postId + " > .inner-part > .status-line .like").removeClass("hidden"); + sone.find(".post#post-" + postId + " > .inner-part > .status-line .unlike").addClass("hidden"); + sone.find(".post#post-" + postId + " > .inner-part > .status-line .like").removeClass("hidden"); updatePostLikes(postId); }, function(xmlHttpRequest, textStatus, error) { /* ignore error. */ @@ -466,9 +466,9 @@ function unlikePost(postId) { function updatePostLikes(postId) { ajaxGet("getLikes.ajax", { "type": "post", "post": postId }, function(data, textStatus) { if ((data != null) && data.success) { - $("#sone .post#post-" + postId + " > .inner-part > .status-line .likes").toggleClass("hidden", data.likes == 0); - $("#sone .post#post-" + postId + " > .inner-part > .status-line .likes span.like-count").text(data.likes); - $("#sone .post#post-" + postId + " > .inner-part > .status-line .likes > span").attr("title", generateSoneList(data.sones)); + sone.find(".post#post-" + postId + " > .inner-part > .status-line .likes").toggleClass("hidden", data.likes == 0); + sone.find(".post#post-" + postId + " > .inner-part > .status-line .likes span.like-count").text(data.likes); + sone.find(".post#post-" + postId + " > .inner-part > .status-line .likes > span").attr("title", generateSoneList(data.sones)); } }, function(xmlHttpRequest, textStatus, error) { /* ignore error. */ @@ -480,8 +480,8 @@ function likeReply(replyId) { if ((data == null) || !data.success) { return; } - $("#sone .reply#reply-" + replyId + " .status-line .like").addClass("hidden"); - $("#sone .reply#reply-" + replyId + " .status-line .unlike").removeClass("hidden"); + sone.find(".reply#reply-" + replyId + " .status-line .like").addClass("hidden"); + sone.find(".reply#reply-" + replyId + " .status-line .unlike").removeClass("hidden"); updateReplyLikes(replyId); }, function(xmlHttpRequest, textStatus, error) { /* ignore error. */ @@ -493,8 +493,8 @@ function unlikeReply(replyId) { if ((data == null) || !data.success) { return; } - $("#sone .reply#reply-" + replyId + " .status-line .unlike").addClass("hidden"); - $("#sone .reply#reply-" + replyId + " .status-line .like").removeClass("hidden"); + sone.find(".reply#reply-" + replyId + " .status-line .unlike").addClass("hidden"); + sone.find(".reply#reply-" + replyId + " .status-line .like").removeClass("hidden"); updateReplyLikes(replyId); }, function(xmlHttpRequest, textStatus, error) { /* ignore error. */ @@ -553,14 +553,14 @@ function untrustSone(soneId) { * The trust value for the Sone */ function updateTrustControls(soneId, trustValue) { - $("#sone .post").each(function() { + sone.find(".post").each(function() { if (getPostAuthor(this) == soneId) { getPostElement(this).find(".post-trust").toggleClass("hidden", trustValue != null); getPostElement(this).find(".post-distrust").toggleClass("hidden", trustValue != null); getPostElement(this).find(".post-untrust").toggleClass("hidden", trustValue == null); } }); - $("#sone .reply").each(function() { + sone.find(".reply").each(function() { if (getReplyAuthor(this) == soneId) { getReplyElement(this).find(".reply-trust").toggleClass("hidden", trustValue != null); getReplyElement(this).find(".reply-distrust").toggleClass("hidden", trustValue != null); @@ -604,9 +604,9 @@ function unbookmarkPost(postId) { function updateReplyLikes(replyId) { ajaxGet("getLikes.ajax", { "type": "reply", "reply": replyId }, function(data, textStatus) { if ((data != null) && data.success) { - $("#sone .reply#reply-" + replyId + " .status-line .likes").toggleClass("hidden", data.likes == 0); - $("#sone .reply#reply-" + replyId + " .status-line .likes span.like-count").text(data.likes); - $("#sone .reply#reply-" + replyId + " .status-line .likes > span").attr("title", generateSoneList(data.sones)); + sone.find(".reply#reply-" + replyId + " .status-line .likes").toggleClass("hidden", data.likes == 0); + sone.find(".reply#reply-" + replyId + " .status-line .likes span.like-count").text(data.likes); + sone.find(".reply#reply-" + replyId + " .status-line .likes > span").attr("title", generateSoneList(data.sones)); } }, function(xmlHttpRequest, textStatus, error) { /* ignore error. */ @@ -703,21 +703,21 @@ function ajaxifyPost(postElement) { return false; }); $(postElement).find(".create-reply button:submit").click(function() { - button = $(this); + var button = $(this); button.attr("disabled", "disabled"); - sender = $(this.form).find(":input[name=sender]").val(); - inputField = $(this.form).find(":input[name=text]:enabled").get(0); - postId = getPostId(this); - text = $(inputField).val(); + var sender = $(this.form).find(":input[name=sender]").val(); + var inputField = $(this.form).find(":input[name=text]:enabled").get(0); + var postId = getPostId(this); + var text = $(inputField).val(); (function(sender, postId, text, inputField) { postReply(sender, postId, text, function(success, error, replyId, soneId) { if (success) { $(inputField).val(""); loadNewReply(replyId, soneId, postId); - $("#sone .post#post-" + postId + " .create-reply").addClass("hidden"); - $("#sone .post#post-" + postId + " .create-reply .sender").hide(); - $("#sone .post#post-" + postId + " .create-reply .select-sender").show(); - $("#sone .post#post-" + postId + " .create-reply :input[name=sender]").val(getCurrentSoneId()); + sone.find(".post#post-" + postId + " .create-reply").addClass("hidden"); + sone.find(".post#post-" + postId + " .create-reply .sender").hide(); + sone.find(".post#post-" + postId + " .create-reply .select-sender").show(); + sone.find(".post#post-" + postId + " .create-reply :input[name=sender]").val(getCurrentSoneId()); } else { alert(error); } @@ -730,7 +730,7 @@ function ajaxifyPost(postElement) { /* replace all “delete” buttons with javascript. */ (function(postElement) { getTranslation("WebInterface.Confirmation.DeletePostButton", function(deletePostText) { - postId = getPostId(postElement); + var postId = getPostId(postElement); enhanceDeletePostButton($(postElement).find(".delete-post button"), postId, deletePostText); }); })(postElement); @@ -772,8 +772,8 @@ function ajaxifyPost(postElement) { /* convert “show source” link into javascript function. */ $(postElement).find(".show-source").each(function() { $("a", this).click(function() { - post = getPostElement(this); - rawPostText = $(".post-text.raw-text", post); + var post = getPostElement(this); + var rawPostText = $(".post-text.raw-text", post); rawPostText.toggleClass("hidden"); if (rawPostText.hasClass("hidden")) { $(".post-text.short-text", post).removeClass("hidden"); @@ -813,7 +813,7 @@ function ajaxifyPost(postElement) { /* ajaxify author/post links */ $(".post-status-line .permalink a", postElement).click(function() { if (!$(".create-reply", postElement).hasClass("hidden")) { - textArea = $("input.reply-input", postElement).focus().data("textarea"); + var textArea = $(":input.reply-input", postElement).focus().data("textarea"); $(textArea).replaceSelection($(this).attr("href")); } return false; @@ -823,7 +823,7 @@ function ajaxifyPost(postElement) { addCommentLink(getPostId(postElement), getPostAuthor(postElement), postElement, $(postElement).find(".post-status-line .permalink-author")); /* process all replies. */ - replyIds = []; + var replyIds = []; $(postElement).find(".reply").each(function() { replyIds.push(getReplyId(this)); ajaxifyReply(this); @@ -832,7 +832,7 @@ function ajaxifyPost(postElement) { /* process reply input fields. */ getTranslation("WebInterface.DefaultText.Reply", function(text) { - $(postElement).find("input.reply-input").each(function() { + $(postElement).find(":input.reply-input").each(function() { registerInputTextareaSwap(this, text, "text", false, false); }); }); @@ -872,7 +872,7 @@ function ajaxifyPost(postElement) { }).fadeIn(); }, 1000); }).mouseleave(function() { - if (currentSoneMenuId = getPostId(this)) { + if (currentSoneMenuId == getPostId(this)) { clearTimeout(currentSoneMenuTimeoutHandler); } }); @@ -883,7 +883,7 @@ function ajaxifyPost(postElement) { ajaxGet("followSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() { $(followElement).addClass("hidden"); $(followElement).parent().find(".unfollow").removeClass("hidden"); - $("#sone .sone-menu").each(function() { + sone.find(".sone-menu").each(function() { if (getMenuSone(this) == soneId) { $(".follow", this).toggleClass("hidden", true); $(".unfollow", this).toggleClass("hidden", false); @@ -897,7 +897,7 @@ function ajaxifyPost(postElement) { ajaxGet("unfollowSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() { $(unfollowElement).addClass("hidden"); $(unfollowElement).parent().find(".follow").removeClass("hidden"); - $("#sone .sone-menu").each(function() { + sone.find(".sone-menu").each(function() { if (getMenuSone(this) == soneId) { $(".follow", this).toggleClass("hidden", false); $(".unfollow", this).toggleClass("hidden", true); @@ -935,7 +935,7 @@ function ajaxifyReply(replyElement) { /* ajaxify author links */ $(".reply-status-line .permalink a", replyElement).click(function() { if (!$(".create-reply", getPostElement(replyElement)).hasClass("hidden")) { - textArea = $("input.reply-input", getPostElement(replyElement)).focus().data("textarea"); + var textArea = $(":input.reply-input", getPostElement(replyElement)).focus().data("textarea"); $(textArea).replaceSelection($(this).attr("href")); } return false; @@ -946,8 +946,8 @@ function ajaxifyReply(replyElement) { /* convert “show source” link into javascript function. */ $(replyElement).find(".show-reply-source").each(function() { $("a", this).click(function() { - reply = getReplyElement(this); - rawReplyText = $(".reply-text.raw-text", reply); + var reply = getReplyElement(this); + var rawReplyText = $(".reply-text.raw-text", reply); rawReplyText.toggleClass("hidden"); if (rawReplyText.hasClass("hidden")) { $(".reply-text.short-text", reply).removeClass("hidden"); @@ -1011,7 +1011,7 @@ function ajaxifyReply(replyElement) { }).fadeIn(); }, 1000); }).mouseleave(function() { - if (currentSoneMenuId = getPostId(this) + "-" + getReplyId(this)) { + if (currentSoneMenuId == getPostId(this) + "-" + getReplyId(this)) { clearTimeout(currentSoneMenuTimeoutHandler); } }); @@ -1022,7 +1022,7 @@ function ajaxifyReply(replyElement) { ajaxGet("followSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() { $(followElement).addClass("hidden"); $(followElement).parent().find(".unfollow").removeClass("hidden"); - $("#sone .sone-menu").each(function() { + sone.find(".sone-menu").each(function() { if (getMenuSone(this) == soneId) { $(".follow", this).toggleClass("hidden", true); $(".unfollow", this).toggleClass("hidden", false); @@ -1036,7 +1036,7 @@ function ajaxifyReply(replyElement) { ajaxGet("unfollowSone.ajax", { "sone": soneId, "formPassword": getFormPassword() }, function() { $(unfollowElement).addClass("hidden"); $(unfollowElement).parent().find(".follow").removeClass("hidden"); - $("#sone .sone-menu").each(function() { + sone.find(".sone-menu").each(function() { if (getMenuSone(this) == soneId) { $(".follow", this).toggleClass("hidden", false); $(".unfollow", this).toggleClass("hidden", true); @@ -1064,16 +1064,16 @@ function ajaxifyNotification(notification) { notification.find(".text").addClass("hidden"); } notification.find("form.mark-as-read button").click(function() { - allIds = $(":input[name=id]", this.form).val().split(" "); + var allIds = $(":input[name=id]", this.form).val().split(" "); for (var index = 0; index < allIds.length; index += 16) { - ids = allIds.slice(index, index + 16).join(" "); + var ids = allIds.slice(index, index + 16).join(" "); ajaxGet("markAsKnown.ajax", {"formPassword": getFormPassword(), "type": $(":input[name=type]", this.form).val(), "id": ids}); } }); notification.find("a[class^='link-']").each(function() { - linkElement = $(this); + var linkElement = $(this); if (linkElement.is("[href^='viewPost']")) { - id = linkElement.attr("class").substr(5); + var id = linkElement.attr("class").substr(5); if (hasPost(id)) { linkElement.attr("href", "#post-" + id).addClass("in-page-link"); } @@ -1095,7 +1095,7 @@ function ajaxifyNotification(notification) { * determine whether the notifications changed and need to be reloaded. */ function getNotificationHash() { - return $("#sone #notification-area #notification-hash").text(); + return sone.find("#notification-area #notification-hash").text(); } /** @@ -1105,7 +1105,7 @@ function getNotificationHash() { * The new notification hash */ function setNotificationHash(notificationHash) { - $("#sone #notification-area #notification-hash").text(notificationHash); + sone.find("#notification-area #notification-hash").text(notificationHash); } /** @@ -1118,7 +1118,7 @@ function setNotificationHash(notificationHash) { * @returns All extracted IDs */ function getElementIds(notification, selector) { - elementIds = []; + var elementIds = []; $(selector, notification).each(function() { elementIds.push($(this).text()); }); @@ -1138,8 +1138,8 @@ function checkForRemovedSones(oldNotification, newNotification) { if (getNotificationId(oldNotification) != "new-sone-notification") { return; } - oldIds = getElementIds(oldNotification, ".new-sone-id"); - newIds = getElementIds(newNotification, ".new-sone-id"); + var oldIds = getElementIds(oldNotification, ".new-sone-id"); + var newIds = getElementIds(newNotification, ".new-sone-id"); $.each(oldIds, function(index, value) { if ($.inArray(value, newIds) == -1) { markSoneAsKnown(getSone(value), true); @@ -1160,8 +1160,8 @@ function checkForRemovedPosts(oldNotification, newNotification) { if (getNotificationId(oldNotification) != "new-post-notification") { return; } - oldIds = getElementIds(oldNotification, ".post-id"); - newIds = getElementIds(newNotification, ".post-id"); + var oldIds = getElementIds(oldNotification, ".post-id"); + var newIds = getElementIds(newNotification, ".post-id"); $.each(oldIds, function(index, value) { if ($.inArray(value, newIds) == -1) { markPostAsKnown(getPost(value), true); @@ -1183,8 +1183,8 @@ function checkForRemovedReplies(oldNotification, newNotification) { if (getNotificationId(oldNotification) != "new-reply-notification") { return; } - oldIds = getElementIds(oldNotification, ".reply-id"); - newIds = getElementIds(newNotification, ".reply-id"); + var oldIds = getElementIds(oldNotification, ".reply-id"); + var newIds = getElementIds(newNotification, ".reply-id"); $.each(oldIds, function(index, value) { if ($.inArray(value, newIds) == -1) { markReplyAsKnown(getReply(value), true); @@ -1231,9 +1231,9 @@ function requestNotifications() { ajaxGet("getNotifications.ajax", {}, function(data, textStatus) { if (data && data.success) { /* search for removed notifications. */ - $("#sone #notification-area .notification").each(function() { - notificationId = $(this).attr("id"); - foundNotification = false; + sone.find("#notification-area .notification").each(function() { + var notificationId = $(this).attr("id"); + var foundNotification = false; $.each(data.notifications, function(index, value) { if (value.id == notificationId) { foundNotification = true; @@ -1243,24 +1243,24 @@ function requestNotifications() { if (!foundNotification) { if (notificationId == "new-sone-notification" && (data.options["ShowNotification/NewSones"] == true)) { $(".new-sone-id", this).each(function(index, element) { - soneId = $(this).text(); + var soneId = $(this).text(); markSoneAsKnown(getSone(soneId), true); }); } else if (notificationId == "new-post-notification" && (data.options["ShowNotification/NewPosts"] == true)) { $(".post-id", this).each(function(index, element) { - postId = $(this).text(); + var postId = $(this).text(); markPostAsKnown(getPost(postId), true); }); } else if (notificationId == "new-reply-notification" && (data.options["ShowNotification/NewReplies"] == true)) { $(".reply-id", this).each(function(index, element) { - replyId = $(this).text(); + var replyId = $(this).text(); markReplyAsKnown(getReply(replyId), true); }); } $(this).slideUp("normal", function() { $(this).remove(); /* remove activity when no notifications are visible. */ - if ($("#sone #notification-area .notification").length == 0) { + if (sone.find("#notification-area .notification").length == 0) { resetActivity(); } }); @@ -1268,11 +1268,11 @@ function requestNotifications() { }); /* process notifications. */ $.each(data.notifications, function(index, value) { - oldNotification = getNotification(value.id); - notification = ajaxifyNotification(createNotification(value.id, value.lastUpdatedTime, value.text, value.dismissable)).hide(); + var oldNotification = getNotification(value.id); + var notification = ajaxifyNotification(createNotification(value.id, value.lastUpdatedTime, value.text, value.dismissable)).hide(); if (oldNotification.length != 0) { if ((oldNotification.find(".short-text").length > 0) && (notification.find(".short-text").length > 0)) { - opened = oldNotification.is(":visible") && oldNotification.find(".short-text").hasClass("hidden"); + var opened = oldNotification.is(":visible") && oldNotification.find(".short-text").hasClass("hidden"); notification.find(".short-text").toggleClass("hidden", opened); notification.find(".text").toggleClass("hidden", !opened); } @@ -1281,7 +1281,7 @@ function requestNotifications() { checkForRemovedReplies(oldNotification, notification); oldNotification.replaceWith(notification.show()); } else { - $("#sone #notification-area").append(notification); + sone.find("#notification-area").append(notification); if (value.id.substring(0, 5) != "local") { notification.slideDown(); setActivity(); @@ -1309,7 +1309,7 @@ function getCurrentSoneId() { * @returns The page ID */ function getPageId() { - return $("#sone .page-id").text(); + return sone.find(".page-id").text(); } /** @@ -1331,7 +1331,7 @@ function isIndexPage() { * @returns The current page of the pagination */ function getPage(paginationSelector) { - pagination = $(paginationSelector); + var pagination = $(paginationSelector); if (pagination.length > 0) { return $(".current-page", paginationSelector).text(); } @@ -1355,7 +1355,7 @@ function isViewSonePage() { * @returns The ID of the currently shown Sone */ function getShownSoneId() { - return $("#sone .sone-id").first().text(); + return sone.find(".sone-id").first().text(); } /** @@ -1365,8 +1365,8 @@ function getShownSoneId() { * @returns The ID of the currently shown Sones */ function getShownSoneIds() { - var soneIds = new Array(); - $("#sone #known-sones .sone .id").each(function() { + var soneIds = []; + sone.find("#known-sones .sone .id").each(function() { soneIds.push($(this).text()); }); return soneIds.join(","); @@ -1389,7 +1389,7 @@ function isViewPostPage() { * @returns The ID of the currently shown post */ function getShownPostId() { - return $("#sone .post-id").text(); + return sone.find(".post-id").text(); } /** @@ -1423,7 +1423,7 @@ function hasPost(postId) { * exists on the page, false otherwise */ function hasReply(replyId) { - return $("#sone .reply#reply-" + replyId).length > 0; + return sone.find(".reply#reply-" + replyId).length > 0; } function loadNewPost(postId, soneId, recipientId, time) { @@ -1437,7 +1437,7 @@ function loadNewPost(postId, soneId, recipientId, time) { } } } - if (getPostTime($("#sone .post").last()) > time) { + if (getPostTime(sone.find(".post").last()) > time) { return; } ajaxGet("getPost.ajax", { "post" : postId }, function(data, textStatus) { @@ -1449,13 +1449,13 @@ function loadNewPost(postId, soneId, recipientId, time) { return; } var firstOlderPost = null; - $("#sone .post").each(function() { + sone.find(".post").each(function() { if (getPostTime(this) < data.post.time) { firstOlderPost = $(this); return false; } }); - newPost = $(data.post.html).addClass("hidden"); + var newPost = $(data.post.html).addClass("hidden"); if ($(".post-author-local", newPost).text() == "true") { newPost.removeClass("new"); } @@ -1483,7 +1483,7 @@ function loadNewReply(replyId, soneId, postId, postSoneId) { if (hasReply(data.reply.id)) { return; } - $("#sone .post#post-" + data.reply.postId).each(function() { + sone.find(".post#post-" + data.reply.postId).each(function() { var firstNewerReply = null; $(this).find(".replies .reply").each(function() { if (getReplyTime(this) > data.reply.time) { @@ -1491,7 +1491,7 @@ function loadNewReply(replyId, soneId, postId, postSoneId) { return false; } }); - newReply = $(data.reply.html).addClass("hidden"); + var newReply = $(data.reply.html).addClass("hidden"); if ($(".reply-author-local", newReply).text() == "true") { newReply.removeClass("new"); (function(newReply) { @@ -1540,7 +1540,7 @@ function markSoneAsKnown(soneElement, skipRequest) { function markPostAsKnown(postElements, skipRequest) { $(postElements).each(function() { - postElement = this; + var postElement = this; if ($(postElement).hasClass("new") || ((typeof skipRequest != "undefined"))) { (function(postElement) { $(postElement).removeClass("new"); @@ -1557,7 +1557,7 @@ function markPostAsKnown(postElements, skipRequest) { function markReplyAsKnown(replyElements, skipRequest) { $(replyElements).each(function() { - replyElement = this; + var replyElement = this; if ($(replyElement).hasClass("new") || ((typeof skipRequest != "undefined"))) { (function(replyElement) { $(replyElement).removeClass("new"); @@ -1648,7 +1648,7 @@ function updateReplyTimes(replyIds) { } function resetActivity() { - title = document.title; + var title = document.title; if (title.indexOf('(') == 0) { setTitle(title.substr(title.indexOf(' ') + 1)); } @@ -1657,7 +1657,7 @@ function resetActivity() { function setActivity() { if (!focus) { - title = document.title; + var title = document.title; if (title.indexOf('(') != 0) { setTitle("(!) " + title); } @@ -1728,9 +1728,9 @@ function changeIcon(iconUrl) { * user */ function createNotification(id, lastUpdatedTime, text, dismissable) { - notification = $("
").addClass("notification").attr("id", id).attr("lastUpdatedTime", lastUpdatedTime); + var notification = $("
").addClass("notification").attr("id", id).attr("lastUpdatedTime", lastUpdatedTime); if (dismissable) { - dismissForm = $("#sone #notification-area #notification-dismiss-template").clone().removeClass("hidden").removeAttr("id"); + var dismissForm = sone.find("#notification-area #notification-dismiss-template").clone().removeClass("hidden").removeAttr("id"); dismissForm.find("input[name=notification]").val(id); notification.append(dismissForm); } @@ -1745,8 +1745,8 @@ function createNotification(id, lastUpdatedTime, text, dismissable) { * The ID of the notification */ function showNotificationDetails(notificationId) { - $("#sone .notification#" + notificationId + " .text").removeClass("hidden"); - $("#sone .notification#" + notificationId + " .short-text").addClass("hidden"); + sone.find(".notification#" + notificationId + " .text").removeClass("hidden"); + sone.find(".notification#" + notificationId + " .short-text").addClass("hidden"); } /** @@ -1758,7 +1758,7 @@ function showNotificationDetails(notificationId) { function deleteProfileField(fieldId) { ajaxGet("deleteProfileField.ajax", {"formPassword": getFormPassword(), "field": fieldId}, function(data, textStatus) { if (data && data.success) { - $("#sone .profile-field#" + data.field.id).slideUp(); + sone.find(".profile-field#" + data.field.id).slideUp(); } }); } @@ -1854,11 +1854,11 @@ function ajaxSuccess() { */ function showOfflineMarker(visible) { /* jQuery documentation says toggle() works the other way around?! */ - $("#sone #offline-marker").toggle(visible); + sone.find("#offline-marker").toggle(visible); if (visible) { - $("#sone #main").addClass("offline"); + sone.find("#main").addClass("offline"); } else { - $("#sone #main").removeClass("offline"); + sone.find("#main").removeClass("offline"); } } @@ -1866,9 +1866,10 @@ function showOfflineMarker(visible) { // EVERYTHING BELOW HERE IS EXECUTED AFTER LOADING THE PAGE // +var sone = $("#sone"); var focus = true; var online = true; -var initiallyLoggedIn = $("#sone #loggedIn").text() == "true"; +var initiallyLoggedIn = sone.find("#loggedIn").text() == "true"; var notLoggedIn = !initiallyLoggedIn; /** ID of the next-to-show Sone context menu. */ @@ -1880,9 +1881,9 @@ var currentSoneMenuTimeoutHandler; $(document).ready(function() { /* rip out the status update textarea. */ - $("#sone .rip-out").each(function() { + sone.find(".rip-out").each(function() { var oldElement = $(this); - newElement = $(""); + var newElement = $(""); newElement.attr("class", oldElement.attr("class")).attr("name", oldElement.attr("name")); oldElement.before(newElement).remove(); }); @@ -1890,21 +1891,21 @@ $(document).ready(function() { /* this initializes the status update input field. */ getTranslation("WebInterface.DefaultText.StatusUpdate", function(defaultText) { registerInputTextareaSwap("#sone #update-status .status-input", defaultText, "text", false, false); - $("#sone #update-status .select-sender").css("display", "inline"); - $("#sone #update-status .sender").hide(); - $("#sone #update-status .select-sender button").click(function() { - $("#sone #update-status .sender").show(); - $("#sone #update-status .select-sender").hide(); + sone.find("#update-status .select-sender").css("display", "inline"); + sone.find("#update-status .sender").hide(); + sone.find("#update-status .select-sender button").click(function() { + sone.find("#update-status .sender").show(); + sone.find("#update-status .select-sender").hide(); return false; }); - $("#sone #update-status").submit(function() { - button = $("button:submit", this); + sone.find("#update-status").submit(function() { + var button = $("button:submit", this); button.attr("disabled", "disabled"); if ($(this).find(":input.default:enabled").length > 0) { return false; } - sender = $(this).find(":input[name=sender]").val(); - text = $(this).find(":input[name=text]:enabled").val(); + var sender = $(this).find(":input[name=sender]").val(); + var text = $(this).find(":input[name=text]:enabled").val(); ajaxGet("createPost.ajax", { "formPassword": getFormPassword(), "sender": sender, "text": text }, function(data, textStatus) { button.removeAttr("disabled"); }); @@ -1924,16 +1925,16 @@ $(document).ready(function() { /* ajaxify input field on “view Sone” page. */ getTranslation("WebInterface.DefaultText.Message", function(defaultText) { registerInputTextareaSwap("#sone #post-message input[name=text]", defaultText, "text", false, false); - $("#sone #post-message .select-sender").css("display", "inline"); - $("#sone #post-message .sender").hide(); - $("#sone #post-message .select-sender button").click(function() { - $("#sone #post-message .sender").show(); - $("#sone #post-message .select-sender").hide(); + sone.find("#post-message .select-sender").css("display", "inline"); + sone.find("#post-message .sender").hide(); + sone.find("#post-message .select-sender button").click(function() { + sone.find("#post-message .sender").show(); + sone.find("#post-message .select-sender").hide(); return false; }); - $("#sone #post-message").submit(function() { - sender = $(this).find(":input[name=sender]").val(); - text = $(this).find(":input[name=text]:enabled").val(); + sone.find("#post-message").submit(function() { + var sender = $(this).find(":input[name=sender]").val(); + var text = $(this).find(":input[name=text]:enabled").val(); ajaxGet("createPost.ajax", { "formPassword": getFormPassword(), "recipient": getShownSoneId(), "sender": sender, "text": text }); $(this).find(":input[name=sender]").val(getCurrentSoneId()); $(this).find(":input[name=text]:enabled").val("").blur(); @@ -1945,11 +1946,11 @@ $(document).ready(function() { /* Ajaxifies all posts. */ /* calling getTranslation here will cache the necessary values. */ - getTranslation("WebInterface.Confirmation.DeletePostButton", function(text) { - getTranslation("WebInterface.Confirmation.DeleteReplyButton", function(text) { - getTranslation("WebInterface.DefaultText.Reply", function(text) { - getTranslation("WebInterface.Button.Comment", function(text) { - $("#sone .post").each(function() { + getTranslation("WebInterface.Confirmation.DeletePostButton", function() { + getTranslation("WebInterface.Confirmation.DeleteReplyButton", function() { + getTranslation("WebInterface.DefaultText.Reply", function() { + getTranslation("WebInterface.Button.Comment", function () { + sone.find(".post").each(function() { ajaxifyPost(this); }); }); @@ -1958,8 +1959,8 @@ $(document).ready(function() { }); /* update post times. */ - postIds = []; - $("#sone .post").each(function() { + var postIds = []; + sone.find(".post").each(function() { postIds.push(getPostId(this)); }); updatePostTimes(postIds.join(",")); @@ -1967,15 +1968,15 @@ $(document).ready(function() { /* hides all replies but the latest two. */ if (!isViewPostPage()) { getTranslation("WebInterface.ClickToShow.Replies", function(text) { - $("#sone .post .replies").each(function() { - allReplies = $(this).find(".reply"); + sone.find(".post .replies").each(function() { + var allReplies = $(this).find(".reply"); if (allReplies.length > 2) { - newHidden = false; - for (replyIndex = 0; replyIndex < (allReplies.length - 2); ++replyIndex) { + var newHidden = false; + for (var replyIndex = 0; replyIndex < (allReplies.length - 2); ++replyIndex) { $(allReplies[replyIndex]).addClass("hidden"); newHidden |= $(allReplies[replyIndex]).hasClass("new"); } - clickToShowElement = $("
").addClass("click-to-show"); + var clickToShowElement = $("
").addClass("click-to-show"); if (newHidden) { clickToShowElement.addClass("new"); } @@ -1992,12 +1993,12 @@ $(document).ready(function() { }); } - $("#sone .sone").each(function() { + sone.find(".sone").each(function() { ajaxifySone($(this)); }); /* process all existing notifications, ajaxify dismiss buttons. */ - $("#sone #notification-area .notification").each(function() { + sone.find("#notification-area .notification").each(function() { ajaxifyNotification($(this)); }); diff --git a/src/main/resources/templates/deleteAlbum.html b/src/main/resources/templates/deleteAlbum.html index ea583fc..9b31548 100644 --- a/src/main/resources/templates/deleteAlbum.html +++ b/src/main/resources/templates/deleteAlbum.html @@ -2,7 +2,7 @@

<%= Page.DeleteAlbum.Page.Title|l10n|html>

-

<%= Page.DeleteAlbum.Text.AlbumWillBeGone|l10n|replace needle=="{title}" replacementKey==album.title|html>

+

<%= Page.DeleteAlbum.Text.AlbumWillBeGone|l10n|replace needle=="{title}" replacement=album.title|html>

diff --git a/src/main/resources/templates/imageBrowser.html b/src/main/resources/templates/imageBrowser.html index a80680f..da8d032 100644 --- a/src/main/resources/templates/imageBrowser.html +++ b/src/main/resources/templates/imageBrowser.html @@ -582,7 +582,7 @@ - <%include include/browseAlbums.html albums=sone.albums> + <%include include/browseAlbums.html albums=sone.rootAlbum.albums> <%if sone.local> diff --git a/src/main/resources/templates/include/updateStatus.html b/src/main/resources/templates/include/updateStatus.html index dde0486..aa87ce8 100644 --- a/src/main/resources/templates/include/updateStatus.html +++ b/src/main/resources/templates/include/updateStatus.html @@ -1,15 +1,17 @@ - - - - -
- -
-
- - -
+<%ifnull !currentSone> +
+ + + +
+ +
+
+ + +
+<%/if> diff --git a/src/main/resources/templates/insert/sone.xml b/src/main/resources/templates/insert/sone.xml index 511cbf2..3d456d4 100644 --- a/src/main/resources/templates/insert/sone.xml +++ b/src/main/resources/templates/insert/sone.xml @@ -67,7 +67,7 @@ <%/first> <%album.id|xml> - <%ifnull !album.parent> + <%if !album.parent.root> <%album.parent.id|xml> <%/if> <%album.title|xml> diff --git a/src/main/resources/templates/notify/soneInsertNotification.html b/src/main/resources/templates/notify/soneInsertNotification.html index d760191..c15864f 100644 --- a/src/main/resources/templates/notify/soneInsertNotification.html +++ b/src/main/resources/templates/notify/soneInsertNotification.html @@ -1,7 +1,7 @@ <%if soneStatus|match value=="inserting"> - Your Sone <%insertSone.niceName|html> is now being inserted. + <%= Notification.SoneIsInserting.Text|l10n 0=insertSone.id|parse> <%elseif soneStatus|match value=="inserted"> - Your Sone <%insertSone.niceName|html> has been inserted in <%= Notification.SoneInsert.Duration|l10n 0=insertDuration>. + <%= Notification.SoneIsInserted.Text|l10n 0=insertSone.id 1=insertDuration|parse> <%elseif soneStatus|match value=="insert-aborted"> - Inserting your Sone <%insertSone.niceName|html> has failed. -<%/if> \ No newline at end of file + <%= Notification.SoneInsertAborted.Text|l10n 0=insertSone.id|parse> +<%/if> diff --git a/src/test/java/net/pterodactylus/sone/web/ajax/BookmarkAjaxPageTest.java b/src/test/java/net/pterodactylus/sone/web/ajax/BookmarkAjaxPageTest.java new file mode 100644 index 0000000..1db89d0 --- /dev/null +++ b/src/test/java/net/pterodactylus/sone/web/ajax/BookmarkAjaxPageTest.java @@ -0,0 +1,81 @@ +/* + * © 2013 xplosion interactive + */ + +package net.pterodactylus.sone.web.ajax; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.net.URI; +import java.net.URISyntaxException; + +import net.pterodactylus.sone.core.Core; +import net.pterodactylus.sone.web.WebInterface; +import net.pterodactylus.sone.web.page.FreenetRequest; + +import freenet.clients.http.HTTPRequestImpl; +import freenet.support.api.HTTPRequest; +import org.junit.Test; + +/** + * Tests for {@link BookmarkAjaxPage}. + * + * @author David Roden + */ +public class BookmarkAjaxPageTest { + + @Test + public void testBookmarkingExistingPost() throws URISyntaxException { + /* create mocks. */ + Core core = mock(Core.class); + WebInterface webInterface = mock(WebInterface.class); + when(webInterface.getCore()).thenReturn(core); + HTTPRequest httpRequest = new HTTPRequestImpl(new URI("/ajax/bookmark.ajax?post=abc"), "GET"); + FreenetRequest request = mock(FreenetRequest.class); + when(request.getHttpRequest()).thenReturn(httpRequest); + + /* create JSON page. */ + BookmarkAjaxPage bookmarkAjaxPage = new BookmarkAjaxPage(webInterface); + JsonReturnObject jsonReturnObject = bookmarkAjaxPage.createJsonObject(request); + + /* verify response. */ + assertThat(jsonReturnObject, notNullValue()); + assertThat(jsonReturnObject.isSuccess(), is(true)); + + /* verify behaviour. */ + verify(core, times(1)).bookmarkPost(anyString()); + verify(core).bookmarkPost("abc"); + } + + @Test + public void testBookmarkingMissingPost() throws URISyntaxException { + /* create mocks. */ + Core core = mock(Core.class); + WebInterface webInterface = mock(WebInterface.class); + when(webInterface.getCore()).thenReturn(core); + HTTPRequest httpRequest = new HTTPRequestImpl(new URI("/ajax/bookmark.ajax"), "GET"); + FreenetRequest request = mock(FreenetRequest.class); + when(request.getHttpRequest()).thenReturn(httpRequest); + + /* create JSON page. */ + BookmarkAjaxPage bookmarkAjaxPage = new BookmarkAjaxPage(webInterface); + JsonReturnObject jsonReturnObject = bookmarkAjaxPage.createJsonObject(request); + + /* verify response. */ + assertThat(jsonReturnObject, notNullValue()); + assertThat(jsonReturnObject.isSuccess(), is(false)); + assertThat(((JsonErrorReturnObject) jsonReturnObject).getError(), is("invalid-post-id")); + + /* verify behaviour. */ + verify(core, never()).bookmarkPost(anyString()); + } + +}