[Tynstep-svn] r242 - in trunk/step: step-core/src/main/java/com/tyndalehouse/step/core/data/create step-core/src/main/java/com/tyndalehouse/step/core/data/entities step-core/src/main/java/com/tyndalehouse/step/core/data/entities/aggregations step-core/src/main/java/com/tyndalehouse/step/core/guice/providers step-core/src/main/java/com/tyndalehouse/step/core/service step-core/src/main/java/com/tyndalehouse/step/core/service/impl step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline step-core/src/main/resources/com/tyndalehouse/step/core/service/impl step-core/src/test/java/com/tyndalehouse/step/core/service/impl step-parent step-web/src/main/java/com/tyndalehouse/step/models step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile step-web/src/main/java/com/tyndalehouse/step/rest/controllers step-web/src/main/webapp step-web/src/main/webapp/css step-web/src/main/webapp/js
ChrisBurrell at crosswire.org
ChrisBurrell at crosswire.org
Wed Apr 18 11:55:17 MST 2012
Author: ChrisBurrell
Date: 2012-04-18 11:55:16 -0700 (Wed, 18 Apr 2012)
New Revision: 242
Added:
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/aggregations/
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/aggregations/TimelineEventsAndDate.java
Modified:
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/Loader.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/ModuleLoader.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java
trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/index.txt
trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl
trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/interlinear.xsl
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java
trunk/step/step-parent/pom.xml
trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/UserInterfaceTranslator.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileEvent.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineImpl.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineTranslatorImpl.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java
trunk/step/step-web/src/main/webapp/css/initial-layout.css
trunk/step/step-web/src/main/webapp/index.html
trunk/step/step-web/src/main/webapp/js/init.js
trunk/step/step-web/src/main/webapp/js/setup.js
trunk/step/step-web/src/main/webapp/js/timeline.js
trunk/step/step-web/src/main/webapp/js/ui_hooks.js
trunk/step/step-web/src/main/webapp/setup.jsp
Log:
cleaning up timeline to make it one band only + timeline toolbar
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/Loader.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/Loader.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/Loader.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -54,7 +54,7 @@
// TODO
this.timelineModuleLoader.init();
this.geoModuleLoader.init();
- this.peopleLoader.init();
+ // this.peopleLoader.init();
this.ebean.commitTransaction();
} finally {
this.ebean.endTransaction();
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/ModuleLoader.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/ModuleLoader.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/ModuleLoader.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -1,6 +1,5 @@
package com.tyndalehouse.step.core.data.create;
-
/**
* A simple interface for all module loaders to implement
*
@@ -11,7 +10,6 @@
/**
* loads up the timeline data
*
- * @param scriptureReferences the scripture references that might be found as part of the loading
*/
void init();
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/create/TimelineModuleLoader.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -194,7 +194,9 @@
final List<CsvData> csvDataFiles = new ArrayList<CsvData>();
for (final String ic : indexChapters) {
- csvDataFiles.add(readTimelineDataFile(ic));
+ if (!ic.startsWith("--")) {
+ csvDataFiles.add(readTimelineDataFile(ic));
+ }
}
return csvDataFiles;
Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/aggregations/TimelineEventsAndDate.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/aggregations/TimelineEventsAndDate.java (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/aggregations/TimelineEventsAndDate.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -0,0 +1,49 @@
+package com.tyndalehouse.step.core.data.entities.aggregations;
+
+import java.util.List;
+
+import javax.persistence.Entity;
+
+import org.joda.time.LocalDateTime;
+
+import com.tyndalehouse.step.core.data.entities.TimelineEvent;
+
+/**
+ * A simple wrapper around a timeline set of events and a central date
+ *
+ * @author Chris
+ *
+ */
+ at Entity
+public class TimelineEventsAndDate {
+ private List<TimelineEvent> events;
+ private LocalDateTime dateTime;
+
+ /**
+ * @return the events
+ */
+ public List<TimelineEvent> getEvents() {
+ return this.events;
+ }
+
+ /**
+ * @param events the events to set
+ */
+ public void setEvents(final List<TimelineEvent> events) {
+ this.events = events;
+ }
+
+ /**
+ * @return the dateTime
+ */
+ public LocalDateTime getDateTime() {
+ return this.dateTime;
+ }
+
+ /**
+ * @param dateTime the dateTime to set
+ */
+ public void setDateTime(final LocalDateTime dateTime) {
+ this.dateTime = dateTime;
+ }
+}
Property changes on: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/data/entities/aggregations/TimelineEventsAndDate.java
___________________________________________________________________
Added: svn:mime-type
+ text/plain
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/guice/providers/DatabaseConfigProvider.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -19,6 +19,7 @@
import com.tyndalehouse.step.core.data.entities.Timeband;
import com.tyndalehouse.step.core.data.entities.TimelineEvent;
import com.tyndalehouse.step.core.data.entities.User;
+import com.tyndalehouse.step.core.data.entities.aggregations.TimelineEventsAndDate;
/**
* Returns a database connection server instance for use across the application
@@ -124,6 +125,7 @@
config.addClass(Bookmark.class);
config.addClass(History.class);
config.addClass(GeoPlace.class);
+ config.addClass(TimelineEventsAndDate.class);
}
}
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/TimelineService.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -6,6 +6,7 @@
import com.tyndalehouse.step.core.data.entities.Timeband;
import com.tyndalehouse.step.core.data.entities.TimelineEvent;
+import com.tyndalehouse.step.core.data.entities.aggregations.TimelineEventsAndDate;
/**
* The timeline service gives access to all the data relating to the timeline the events, the configuration,
@@ -34,4 +35,12 @@
* @return a list of timeline events contained between the two dates
*/
List<TimelineEvent> getTimelineEvents(LocalDateTime from, LocalDateTime to);
+
+ /**
+ * Given a reference to a passage, this looks up the relevant set of events
+ *
+ * @param reference the reference to look up
+ * @return a set of events and the date at which they occur
+ */
+ TimelineEventsAndDate getEventsFromScripture(String reference);
}
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImpl.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -1,15 +1,24 @@
package com.tyndalehouse.step.core.service.impl;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import org.joda.time.LocalDateTime;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.avaje.ebean.EbeanServer;
import com.avaje.ebean.Query;
import com.google.inject.Inject;
import com.google.inject.Singleton;
+import com.tyndalehouse.step.core.data.entities.ScriptureReference;
import com.tyndalehouse.step.core.data.entities.Timeband;
import com.tyndalehouse.step.core.data.entities.TimelineEvent;
+import com.tyndalehouse.step.core.data.entities.aggregations.TimelineEventsAndDate;
+import com.tyndalehouse.step.core.data.entities.reference.TargetType;
+import com.tyndalehouse.step.core.service.JSwordService;
import com.tyndalehouse.step.core.service.TimelineService;
/**
@@ -19,14 +28,19 @@
*/
@Singleton
public class TimelineServiceImpl implements TimelineService {
+ private static final Logger LOGGER = LoggerFactory.getLogger(TimelineServiceImpl.class);
+
private final EbeanServer ebean;
+ private final JSwordService jsword;
/**
* @param ebean the ebean server with which to lookup data
+ * @param jsword the jsword service
*/
@Inject
- public TimelineServiceImpl(final EbeanServer ebean) {
+ public TimelineServiceImpl(final EbeanServer ebean, final JSwordService jsword) {
this.ebean = ebean;
+ this.jsword = jsword;
}
@Override
@@ -35,6 +49,86 @@
}
@Override
+ public TimelineEventsAndDate getEventsFromScripture(final String reference) {
+ final TimelineEventsAndDate timelineEventsAndDate = new TimelineEventsAndDate();
+
+ final List<TimelineEvent> matchingTimelineEvents = lookupEventsMatchingReference(reference);
+ timelineEventsAndDate.setEvents(matchingTimelineEvents);
+
+ timelineEventsAndDate.setDateTime(getDateForEvents(matchingTimelineEvents));
+
+ return timelineEventsAndDate;
+
+ }
+
+ /**
+ * Gets the date which is most appropriate for centering around these events, i.e. the median?
+ *
+ * @param matchingTimelineEvents the number of events
+ * @return the localDateTime of the median event, if a duration, then of the start point
+ */
+ private LocalDateTime getDateForEvents(final List<TimelineEvent> matchingTimelineEvents) {
+ if (matchingTimelineEvents.isEmpty()) {
+ return null;
+ }
+
+ // copy list to new list that can be sorted
+ final ArrayList<TimelineEvent> events = new ArrayList<TimelineEvent>(matchingTimelineEvents);
+
+ // first we order events based on the start date
+ Collections.sort(events, new Comparator<TimelineEvent>() {
+
+ @Override
+ public int compare(final TimelineEvent o1, final TimelineEvent o2) {
+ return o1.getFromDate().compareTo(o2.getFromDate());
+ }
+ });
+
+ // now we simply return the median element
+ return events.get(events.size() / 2).getFromDate();
+ }
+
+ /**
+ * This method simply takes a reference, resolves it to the kjv versification, and then manages to output
+ * all events that match
+ *
+ * @param reference the reference we are looking for
+ * @return the list of events matching the reference
+ */
+ private List<TimelineEvent> lookupEventsMatchingReference(final String reference) {
+ // first get the kjv reference
+ final List<ScriptureReference> passageReferences = this.jsword.getPassageReferences(reference);
+
+ if (passageReferences.size() == 0) {
+ return new ArrayList<TimelineEvent>();
+ }
+
+ // let's assume for now we only work on one reference
+ final ScriptureReference searchingReference = passageReferences.get(0);
+
+ LOGGER.debug("Finding events overlapping [{}] and [{}]", searchingReference.getStartVerseId(),
+ searchingReference.getEndVerseId());
+
+ // find all timeline events where at least one scripture reference maps to our 1st reference
+ // overlap: if a and b are start and stop of event, then overlap formula is:
+ // search_start < b & search_end > a
+
+ final String queryText = "find timelineEvent where references.targetType = :targetType "
+ + "and :searchStart <= references.endVerseId and :searchEnd >= references.startVerseId";
+ // final String queryText = "find timelineEvent";
+
+ final Query<TimelineEvent> query = this.ebean.createQuery(TimelineEvent.class, queryText).fetch(
+ "references");
+
+ query.setParameter("targetType", TargetType.TIMELINE_EVENT);
+ query.setParameter("searchStart", searchingReference.getStartVerseId());
+ query.setParameter("searchEnd", searchingReference.getEndVerseId());
+
+ return query.findList();
+
+ }
+
+ @Override
public List<TimelineEvent> getTimelineEvents(final LocalDateTime from, final LocalDateTime to) {
// fromDate < to and toDate > from is the standard coverage method where we find the overlapping
// events
Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/index.txt
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/index.txt 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/data/create/timeline/index.txt 2012-04-18 18:55:16 UTC (rev 242)
@@ -1,16 +1,16 @@
-TL_Africa.csv
-TL_Americas.csv
-TL_ArchCult.csv
-TL_Asia.csv
-TL_EarlyChurch.csv
-TL_Egypt.csv
-TL_Europe.csv
-TL_ExileAndReturn.csv
-TL_Global.csv
-TL_Intertestamental.csv
-TL_Jesus.csv
-TL_Monarchy.csv
-TL_NTChurch.csv
-TL_OTNeighbours.csv
+--TL_Africa.csv
+--TL_Americas.csv
+--TL_ArchCult.csv
+--TL_Asia.csv
+--TL_EarlyChurch.csv
+--TL_Egypt.csv
+--TL_Europe.csv
+--TL_ExileAndReturn.csv
+--TL_Global.csv
+--TL_Intertestamental.csv
+--TL_Jesus.csv
+--TL_Monarchy.csv
+--TL_NTChurch.csv
+--TL_OTNeighbours.csv
TL_PatriarchsToJudges.csv
-TL_Rome.csv
+--TL_Rome.csv
Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl 2012-04-18 18:55:16 UTC (rev 242)
@@ -949,8 +949,8 @@
== cQuote Marks the location of a continuation quote mark, with marker containing the publishers mark.
-->
<!-- This is used by the KJV for paragraph markers. -->
- <xsl:template match="milestone[@type = 'x-p']"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
- <xsl:template match="milestone[@type = 'x-p']" mode="jesus"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
+ <xsl:template match="milestone[@type = 'x-p']"> <!-- <xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text> --></xsl:template>
+ <xsl:template match="milestone[@type = 'x-p']" mode="jesus"><!-- <xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text> --></xsl:template>
<xsl:template match="milestone[@type = 'cQuote']">
<xsl:value-of select="@marker"/>
Modified: trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/interlinear.xsl
===================================================================
--- trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/interlinear.xsl 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/interlinear.xsl 2012-04-18 18:55:16 UTC (rev 242)
@@ -1079,8 +1079,8 @@
== cQuote Marks the location of a continuation quote mark, with marker containing the publishers mark.
-->
<!-- This is used by the KJV for paragraph markers. -->
- <xsl:template match="milestone[@type = 'x-p']"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
- <xsl:template match="milestone[@type = 'x-p']" mode="jesus"><xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text></xsl:template>
+ <xsl:template match="milestone[@type = 'x-p']"> <!-- <xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text> --></xsl:template>
+ <xsl:template match="milestone[@type = 'x-p']" mode="jesus"><!-- <xsl:text> </xsl:text><xsl:value-of select="@marker"/><xsl:text> </xsl:text> --></xsl:template>
<xsl:template match="milestone[@type = 'cQuote']">
<xsl:value-of select="@marker"/>
Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImplTest.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -169,7 +169,40 @@
assertTrue(bibleBookNames.contains("Malachi"));
assertTrue(bibleBookNames.contains("Matthew"));
assertTrue(bibleBookNames.contains("Mark"));
+ }
+ /**
+ * tests that the XSLT transformation is handled correctly
+ *
+ * @throws BookException uncaught exception
+ * @throws NoSuchKeyException uncaught exception
+ * @throws IOException uncaught exception
+ * @throws JDOMException uncaught exception
+ */
+ @Test
+ public void testAbsenceOfParagraphMark() throws BookException, NoSuchKeyException, JDOMException,
+ IOException {
+ final String testReference = "Acts 1:15";
+ final String testVersion = "KJV";
+
+ final Book currentBook = Books.installed().getBook(testVersion);
+ final BookData bookData = new BookData(currentBook, currentBook.getKey(testReference));
+ final Element osisFragment = bookData.getOsisFragment();
+
+ final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
+ LOGGER.debug(xmlOutputter.outputString(osisFragment));
+
+ // do the test
+ final JSwordServiceImpl jsi = new JSwordServiceImpl(null);
+ final List<LookupOption> options = new ArrayList<LookupOption>();
+ // options.add(LookupOption.STRONG_NUMBERS);
+
+ final String osisText = jsi.getOsisText(testVersion, testReference, options, "");
+ final SAXBuilder sb = new SAXBuilder();
+ final Document d = sb.build(new StringReader(osisText));
+
+ LOGGER.debug("\n {}", xmlOutputter.outputString(d));
+ Assert.assertTrue(osisText.contains("span"));
}
/**
Modified: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/impl/TimelineServiceImplTest.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -1,13 +1,26 @@
package com.tyndalehouse.step.core.service.impl;
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.when;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.joda.time.LocalDateTime;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.tyndalehouse.step.core.data.DataDrivenTestExtension;
+import com.tyndalehouse.step.core.data.entities.ScriptureReference;
+import com.tyndalehouse.step.core.data.entities.TimelineEvent;
+import com.tyndalehouse.step.core.data.entities.aggregations.TimelineEventsAndDate;
+import com.tyndalehouse.step.core.data.entities.reference.TargetType;
import com.tyndalehouse.step.core.service.TimelineService;
/**
@@ -21,153 +34,242 @@
private static final Logger LOG = LoggerFactory.getLogger(FavouritesServiceImpl.class);
private TimelineService ts;
+ @Mock
+ private JSwordServiceImpl jsword;
+
/**
* sets up a few things to be able to test properly
*/
@Before
public void setUp() {
- this.ts = new TimelineServiceImpl(getEbean());
+
+ this.ts = new TimelineServiceImpl(getEbean(), this.jsword);
}
- // /**
- // * tests that the syntax of the query is correct
- // */
- // @Test
- // public void testGetEventsInPeriodInRangePointInTime() {
- // final TimelineEvent inRange = createEventAndPersist(1000, "A");
- // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(0),
- // new LocalDateTime(2000));
- //
- // LOG.debug("Event 1: [{}]", timelineEvents.get(0).getSummary());
- // LOG.debug("Event 2: [{}]", timelineEvents.get(1).getSummary());
- //
- // assertEquals(timelineEvents.size(), 1);
- // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
- // }
- //
- // /**
- // * tests that out of range events before/after do not get retrieved
- // */
- // @Test
- // public void testGetEventsInPeriodOutOfRangePointInTime() {
- // createEventAndPersist(1000, "A");
- // createEventAndPersist(2001, "B");
- // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1001),
- // new LocalDateTime(2000));
- //
- // assertEquals(timelineEvents.size(), 0);
- // }
- //
- // /**
- // * tests that out of range events before/after do not get retrieved
- // */
- // @Test
- // public void testGetEventsInPeriodOverlapStartDuration() {
- // final TimelineEvent inRange = createEvent(500, 1100, "A");
- // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
- // new LocalDateTime(2000));
- //
- // assertEquals(timelineEvents.size(), 1);
- // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
- // }
- //
- // /**
- // * tests that out of range events before/after do not get retrieved
- // */
- // @Test
- // public void testGetEventsInPeriodOverlapEndDuration() {
- // final TimelineEvent inRange = createEvent(1500, 2100, "A");
- // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
- // new LocalDateTime(2000));
- //
- // assertEquals(timelineEvents.size(), 1);
- // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
- // }
- //
- // /**
- // * tests that out of range events before/after do not get retrieved
- // */
- // @Test
- // public void testGetEventsInPeriodContainedDuration() {
- // final TimelineEvent inRange = createEvent(1500, 1700, "A");
- // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
- // new LocalDateTime(2000));
- //
- // assertEquals(timelineEvents.size(), 1);
- // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
- // }
- //
- // /**
- // * tests that out of range events before/after do not get retrieved
- // */
- // @Test
- // public void testGetEventsInPeriodOverflowDuration() {
- // final TimelineEvent inRange = createEvent(200, 2100, "A");
- // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
- // new LocalDateTime(2000));
- //
- // assertEquals(timelineEvents.size(), 1);
- // assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
- // }
- //
- // /**
- // * tests that out of range events before/after do not get retrieved
- // */
- // @Test
- // public void testGetEventsOutOfRangeDuration() {
- // createEvent(200, 700, "A");
- // createEvent(2200, 2700, "B");
- // final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
- // new LocalDateTime(2000));
- //
- // assertEquals(timelineEvents.size(), 0);
- //
- // }
- //
- // /**
- // * creates a duration event
- // *
- // * @param startTime start of event
- // * @param endTime end of event
- // * @param summary summary of event
- // * @return a single timeline event
- // */
- // private TimelineEvent createEvent(final int startTime, final int endTime, final String summary) {
- // final TimelineEvent te = createEvent(startTime, summary);
- // te.setToDate(new LocalDateTime(endTime));
- // getEbean().save(te);
- // return te;
- // }
- //
- // /**
- // * a helper method to create an event
- // *
- // * @param startTime the time of creation
- // * @param summary the summary
- // * @return the event that was creates and persisted
- // */
- // private TimelineEvent createEventAndPersist(final int startTime, final String summary) {
- // final TimelineEvent te = createEvent(startTime, summary);
- // getEbean().save(te);
- // return te;
- // }
- //
- // /**
- // * creates the event without persisting
- // *
- // * @param startTime the start time of the event
- // * @param summary the summary
- // * @return the event created
- // */
- // private TimelineEvent createEvent(final int startTime, final String summary) {
- // final TimelineEvent te = new TimelineEvent();
- // te.setFromDate(new LocalDateTime(startTime));
- // te.setSummary(summary);
- // return te;
- // }
+ /**
+ * tests looking up scripture from a reference
+ */
+ @Test
+ public void testGetEventsFromScriptureTimelineEvent() {
+ final List<ScriptureReference> testReferences = saveEventWithVerses(TargetType.TIMELINE_EVENT, 5, 10);
+ // ensure we return the references that we've set up
+ when(this.jsword.getPassageReferences(anyString())).thenReturn(testReferences);
+
+ final TimelineEventsAndDate eventsForPassage = this.ts.getEventsFromScripture("");
+
+ // check that we have our 1 event back
+ assertEquals(1, eventsForPassage.getEvents().size());
+ }
+
+ /**
+ * tests looking up scripture from a reference
+ */
@Test
- public void temporaryTest() {
+ public void testGetEventsFromScriptureNoPastOrFuture() {
+ final List<ScriptureReference> testReferences = saveEventWithVerses(TargetType.TIMELINE_EVENT, 5, 10);
+ saveEventWithVerses(TargetType.TIMELINE_EVENT, 1, 4);
+ saveEventWithVerses(TargetType.TIMELINE_EVENT, 11, 13);
+ // ensure we return the references that we've set up
+ when(this.jsword.getPassageReferences(anyString())).thenReturn(testReferences);
+
+ final TimelineEventsAndDate eventsForPassage = this.ts.getEventsFromScripture("");
+
+ // check that we have our 1 event back
+ assertEquals(1, eventsForPassage.getEvents().size());
}
+
+ /**
+ * tests looking up scripture from a reference
+ */
+ @Test
+ public void testGetEventsFromScriptureNotOtherTypes() {
+ final List<ScriptureReference> testReferences = saveEventWithVerses(TargetType.GEO_PLACE, 5, 10);
+
+ // ensure we return the references that we've set up
+ when(this.jsword.getPassageReferences(anyString())).thenReturn(testReferences);
+
+ final TimelineEventsAndDate eventsForPassage = this.ts.getEventsFromScripture("");
+
+ // check that we have our no events
+ assertEquals(0, eventsForPassage.getEvents().size());
+ }
+
+ /**
+ * tests that the syntax of the query is correct
+ */
+ @Test
+ public void testGetEventsInPeriodInRangePointInTime() {
+ final TimelineEvent inRange = createEventAndPersist(1000, "A");
+ final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(0),
+ new LocalDateTime(2000));
+
+ LOG.debug("Event 1: [{}]", timelineEvents.get(0).getSummary());
+
+ assertEquals(timelineEvents.size(), 1);
+ assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+ }
+
+ /**
+ * tests that out of range events before/after do not get retrieved
+ */
+ @Test
+ public void testGetEventsInPeriodOutOfRangePointInTime() {
+ createEventAndPersist(1000, "A");
+ createEventAndPersist(2001, "B");
+ final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1001),
+ new LocalDateTime(2000));
+
+ assertEquals(timelineEvents.size(), 0);
+ }
+
+ /**
+ * tests that out of range events before/after do not get retrieved
+ */
+ @Test
+ public void testGetEventsInPeriodOverlapStartDuration() {
+ final TimelineEvent inRange = createEvent(500, 1100, "A");
+ final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+ new LocalDateTime(2000));
+
+ assertEquals(timelineEvents.size(), 1);
+ assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+ }
+
+ /**
+ * tests that out of range events before/after do not get retrieved
+ */
+ @Test
+ public void testGetEventsInPeriodOverlapEndDuration() {
+ final TimelineEvent inRange = createEvent(1500, 2100, "A");
+ final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+ new LocalDateTime(2000));
+
+ assertEquals(timelineEvents.size(), 1);
+ assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+ }
+
+ /**
+ * tests that out of range events before/after do not get retrieved
+ */
+ @Test
+ public void testGetEventsInPeriodContainedDuration() {
+ final TimelineEvent inRange = createEvent(1500, 1700, "A");
+ final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+ new LocalDateTime(2000));
+
+ assertEquals(timelineEvents.size(), 1);
+ assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+ }
+
+ /**
+ * tests that out of range events before/after do not get retrieved
+ */
+ @Test
+ public void testGetEventsInPeriodOverflowDuration() {
+ final TimelineEvent inRange = createEvent(200, 2100, "A");
+ final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+ new LocalDateTime(2000));
+
+ assertEquals(timelineEvents.size(), 1);
+ assertEquals(timelineEvents.get(0).getSummary(), inRange.getSummary());
+ }
+
+ /**
+ * tests that out of range events before/after do not get retrieved
+ */
+ @Test
+ public void testGetEventsOutOfRangeDuration() {
+ createEvent(200, 700, "A");
+ createEvent(2200, 2700, "B");
+ final List<TimelineEvent> timelineEvents = this.ts.getTimelineEvents(new LocalDateTime(1000),
+ new LocalDateTime(2000));
+
+ assertEquals(timelineEvents.size(), 0);
+
+ }
+
+ /**
+ * creates a duration event
+ *
+ * @param startTime start of event
+ * @param endTime end of event
+ * @param summary summary of event
+ * @return a single timeline event
+ */
+ private TimelineEvent createEvent(final int startTime, final int endTime, final String summary) {
+ final TimelineEvent te = createEvent(startTime, summary);
+ te.setToDate(new LocalDateTime(endTime));
+ getEbean().save(te);
+ return te;
+ }
+
+ /**
+ * a helper method to create an event
+ *
+ * @param startTime the time of creation
+ * @param summary the summary
+ * @return the event that was creates and persisted
+ */
+ private TimelineEvent createEventAndPersist(final int startTime, final String summary) {
+ final TimelineEvent te = createEvent(startTime, summary);
+ getEbean().save(te);
+ return te;
+ }
+
+ /**
+ * creates the event without persisting
+ *
+ * @param startTime the start time of the event
+ * @param summary the summary
+ * @return the event created
+ */
+ private TimelineEvent createEvent(final int startTime, final String summary) {
+ final TimelineEvent te = new TimelineEvent();
+ te.setFromDate(new LocalDateTime(startTime));
+ te.setSummary(summary);
+ return te;
+ }
+
+ /**
+ * returns a list of scripture references, containing 1 reference
+ *
+ * @param targetType the type of scripture reference
+ * @param start the start
+ * @param end the end
+ * @return the list containing the one element required
+ */
+ private List<ScriptureReference> getListScriptureReferences(final TargetType targetType, final int start,
+ final int end) {
+ final List<ScriptureReference> testReferences = new ArrayList<ScriptureReference>();
+
+ final ScriptureReference sr = new ScriptureReference();
+ sr.setStartVerseId(start);
+ sr.setEndVerseId(end);
+ sr.setTargetType(targetType);
+ testReferences.add(sr);
+ return testReferences;
+ }
+
+ /**
+ * creates an event with a particular list of references
+ *
+ * @param target the type of event
+ * @param start the verse start
+ * @param end the verse end
+ * @return a timeline event
+ */
+ private List<ScriptureReference> saveEventWithVerses(final TargetType target, final int start,
+ final int end) {
+ // set up an event with references
+ final List<ScriptureReference> testReferences = getListScriptureReferences(target, start, end);
+
+ final TimelineEvent event = createEvent(100, "Some event");
+ event.setReferences(testReferences);
+ getEbean().save(event);
+
+ return testReferences;
+ }
+
}
Modified: trunk/step/step-parent/pom.xml
===================================================================
--- trunk/step/step-parent/pom.xml 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-parent/pom.xml 2012-04-18 18:55:16 UTC (rev 242)
@@ -40,6 +40,7 @@
<opencsv.version>2.1</opencsv.version>
<jetty.version>6.1.26</jetty.version>
+ <joda-time.version>2.1</joda-time.version>
<ebean.version>2.7.2</ebean.version>
<ehcache.version>2.4.2</ehcache.version>
<lucene.version>3.0.3</lucene.version>
@@ -314,7 +315,7 @@
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
- <version>1.6.2</version>
+ <version>${joda-time.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/UserInterfaceTranslator.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/UserInterfaceTranslator.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/UserInterfaceTranslator.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -2,6 +2,8 @@
import java.util.List;
+import org.joda.time.LocalDateTime;
+
/**
* A translator is able to convert timeline data into a form that is acceptable by the client
*
@@ -15,8 +17,9 @@
* translates a list of events to a digestable form of a timeline
*
* @param sourceElement the source element
+ * @param suggestedDate a date for the timeline
* @return the wrapped up form of the timeline
*/
- T toDigestableForm(final List<S> sourceElement);
+ T toDigestableForm(final List<S> sourceElement, LocalDateTime suggestedDate);
}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileEvent.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileEvent.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileEvent.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -24,6 +24,7 @@
private String title;
private String description;
private int hotSpotId;
+ private int eventId;
private String image; // ? should be url? TODO
private String link; // ? should be url
@@ -139,4 +140,18 @@
public void setHotSpotId(final int hotSpotId) {
this.hotSpotId = hotSpotId;
}
+
+ /**
+ * @return the eventId
+ */
+ public int getEventId() {
+ return this.eventId;
+ }
+
+ /**
+ * @param eventId the eventId to set
+ */
+ public void setEventId(final int eventId) {
+ this.eventId = eventId;
+ }
}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineImpl.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineImpl.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineImpl.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -32,6 +32,7 @@
public class SimileTimelineImpl implements DigestableTimeline {
private String dateTimeFormat;
private List<SimileEvent> events;
+ private String suggestedDate;
/**
* @return the dateTimeFormat
@@ -60,4 +61,18 @@
public void setEvents(final List<SimileEvent> events) {
this.events = events;
}
+
+ /**
+ * @return the suggestedDate
+ */
+ public String getSuggestedDate() {
+ return this.suggestedDate;
+ }
+
+ /**
+ * @param suggestedDate the suggestedDate to set
+ */
+ public void setSuggestedDate(final String suggestedDate) {
+ this.suggestedDate = suggestedDate;
+ }
}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineTranslatorImpl.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineTranslatorImpl.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/models/timeline/simile/SimileTimelineTranslatorImpl.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -20,7 +20,8 @@
private static final String SIMILE_DEFAULT_TIME_FORMAT = "iso8601";
@Override
- public DigestableTimeline toDigestableForm(final List<TimelineEvent> events) {
+ public DigestableTimeline toDigestableForm(final List<TimelineEvent> events,
+ final LocalDateTime suggestedDate) {
final SimileTimelineImpl timeline = new SimileTimelineImpl();
timeline.setDateTimeFormat(SIMILE_DEFAULT_TIME_FORMAT);
@@ -31,6 +32,7 @@
e.setTitle(te.getSummary());
e.setDescription(te.getSummary());
e.setStart(te.getFromDate().toString());
+ e.setEventId(e.getEventId());
if (te.getHotSpot() != null) {
e.setHotSpotId(te.getHotSpot().getId());
@@ -47,6 +49,10 @@
}
timeline.setEvents(eventList);
+
+ if (suggestedDate != null) {
+ timeline.setSuggestedDate(suggestedDate.toString());
+ }
return timeline;
}
}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/FrontController.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -120,8 +120,8 @@
final Object controllerInstance = getController(sr.getControllerName());
// resolve method
- final Method controllerMethod = getControllerMethod(sr.getMethodName(), controllerInstance, sr
- .getArgs(), sr.getCacheKey().getMethodKey());
+ final Method controllerMethod = getControllerMethod(sr.getMethodName(), controllerInstance,
+ sr.getArgs(), sr.getCacheKey().getMethodKey());
// invoke the three together
Object returnVal;
@@ -212,8 +212,7 @@
}
final String responsePackage = responseValue.getClass().getPackage().getName();
- return !responsePackage.startsWith(ENTITIES_PACKAGE)
- && !responseValue.getClass().getPackage().getName().startsWith(AVAJE_PACKAGE);
+ return !responsePackage.startsWith(ENTITIES_PACKAGE) && !responsePackage.startsWith(AVAJE_PACKAGE);
}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/TimelineController.java 2012-04-18 18:55:16 UTC (rev 242)
@@ -11,6 +11,7 @@
import com.google.inject.Singleton;
import com.tyndalehouse.step.core.data.entities.Timeband;
import com.tyndalehouse.step.core.data.entities.TimelineEvent;
+import com.tyndalehouse.step.core.data.entities.aggregations.TimelineEventsAndDate;
import com.tyndalehouse.step.core.service.TimelineService;
import com.tyndalehouse.step.models.UserInterfaceTranslator;
import com.tyndalehouse.step.models.timeline.DigestableTimeline;
@@ -68,9 +69,12 @@
* of the timeline
*/
@Cacheable(true)
- public String getEventsFromReference(final String bibleReference) {
+ public DigestableTimeline getEventsFromReference(final String bibleReference) {
+ final TimelineEventsAndDate eventsFromScripture = this.timelineService
+ .getEventsFromScripture(bibleReference);
+ return this.translator.toDigestableForm(eventsFromScripture.getEvents(),
+ eventsFromScripture.getDateTime());
- return null;
}
/**
@@ -82,12 +86,18 @@
*/
@Cacheable(true)
public DigestableTimeline getEventsInPeriod(final String from, final String to) {
- // TODO enhance FrontController to accept basic types such as long
- final long f = Long.parseLong(from);
- final long t = Long.parseLong(to);
+ return this.translator.toDigestableForm(this.timelineService.getTimelineEvents(
+ convertJavascriptDate(from), convertJavascriptDate(to)), null);
+ }
- return this.translator.toDigestableForm(this.timelineService.getTimelineEvents(new LocalDateTime(f),
- new LocalDateTime(t)));
+ /**
+ * Converts a java script date, which at the moment, just seems to have an extra Z on the end
+ *
+ * @param javascriptDate the date
+ * @return the local date time
+ */
+ private LocalDateTime convertJavascriptDate(final String javascriptDate) {
+ return LocalDateTime.parse(javascriptDate.substring(0, javascriptDate.length() - 1));
}
/**
Modified: trunk/step/step-web/src/main/webapp/css/initial-layout.css
===================================================================
--- trunk/step/step-web/src/main/webapp/css/initial-layout.css 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/webapp/css/initial-layout.css 2012-04-18 18:55:16 UTC (rev 242)
@@ -23,7 +23,7 @@
}
/**************************/
-/** INTERLINEAR PANE
+/** INTERLINEAR PANE */
/**************************/
.interlinearPopup {
display: none;
@@ -47,7 +47,7 @@
}
/**************************/
-/** BOOKMARK PANE
+/** BOOKMARK PANE */
/**************************/
.bookmarks {
border-top: 0px;
@@ -98,7 +98,7 @@
}
/**************************/
-/* TOP MENU
+/* TOP MENU */
/**************************/
#topMenu {
}
@@ -116,21 +116,20 @@
}
/**************************/
-/* COLUMNS
+/* COLUMNS */
/**************************/
.column {
border: 0px;
display: inline;
- width: 45%; /* *2 columns */
+ width: 45%; /* 2 columns */
float: left;
position: relative;
/* overflow: hidden;*/
-
}
/********************************/
-/* INNER MENUS (i.e. sub menus)
+/* INNER MENUS (i.e. sub menus) */
/********************************/
.innerMenu {
position: absolute;
@@ -139,7 +138,7 @@
/**************************/
-/* PASSAGE CONTAINERS
+/* PASSAGE CONTAINERS */
/**************************/
.passageContainer {
}
@@ -166,7 +165,7 @@
.passageContent {
position: absolute;
- /* top: 45px; */
+/* top: 45px; */
overflow: auto;
}
@@ -198,7 +197,7 @@
/*********************************************/
-/** BOTTOM COMPONENT
+/** BOTTOM COMPONENT */
/*********************************************/
#bottomSection {
height: 0px;
@@ -212,53 +211,19 @@
display: none;
}
-#bottomSection > div
-{
- width: 100%;
- background-color: #147000;
- color: #fff;
- text-align: right;
+#bottomModuleHeader {
+ height: 25px;
+ background-color: #4EB305;
}
-/* Close button */
-#bottomSection > div span
-{
- cursor: pointer;
- margin: 5px;
+.timelineContext {
+ color: #fff;
+ font-weight: bold;
}
-#bottomSection #leftArrow
-{
- height: 105px;
- width: 20px;
- background-color: #fff;
- border: 1px solid #ccc;
- position: absolute;
- top: 28px;
- left: 0px;
- z-index: 9999;
- font-size: 30px;
- color: #ccc;
- padding-top: 70px;
-}
-#bottomSection #rightArrow
-{
- height: 105px;
- width: 20px;
- background-color: #fff;
- border: 1px solid #ccc;
- position: absolute;
- top: 28px;
- right: 0px;
- z-index: 9999;
- font-size: 30px;
- color: #ccc;
- padding-top: 70px;
-}
-
.no-left-border {
- /* border-left: none; */
+/* border-left: none; */
margin-left: -1px;
}
@@ -282,9 +247,9 @@
overflow-y: auto;
}
-/* IE 6 doesn't support max-height
- * we use height instead, but this forces the menu to always be this tall
- */
+/* IE 6 doesn't support max-height
+ * we use height instead, but this forces the menu to always be this tall
+ */
* html .ui-autocomplete {
height: 500px;
}
@@ -331,7 +296,7 @@
}
/**************************/
-/* LEXICON DEFINITION
+/* LEXICON DEFINITION */
/**************************/
#lexiconDefinition {
display: none;
@@ -350,7 +315,7 @@
cursor: pointer;
}
/**************************/
-/* LOGIN POPUP
+/* LOGIN POPUP */
/**************************/
#login {
display: none;
@@ -364,4 +329,3 @@
margin-right: 0.5em;
display: block
}
-
Modified: trunk/step/step-web/src/main/webapp/index.html
===================================================================
--- trunk/step/step-web/src/main/webapp/index.html 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/webapp/index.html 2012-04-18 18:55:16 UTC (rev 242)
@@ -18,7 +18,7 @@
<link rel="stylesheet" type="text/css" href="libs/menu/ddsmoothmenu.css" />
<link rel="stylesheet" type="text/css" href="libs/menu/ddsmoothmenu-v.css" />
- <script src="js/initLib.js"></script>
+ <script src="js/initLib.js" type="text/javascript"></script>
<script src="libs/timeline_js/timeline-api.js?bundle=true" type="text/javascript"></script>
<script src="libs/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="libs/jquery-ui-1.8.5.custom.min.js" type="text/javascript"></script>
@@ -98,15 +98,13 @@
</div>
<div id="bottomSection" class="bottomModule timeline">
- <div style="height: 25px;">
- <span id="timelineContext" style="float: left;"></span>
- <span style="float: right;" onclick="hideBottomSection();">Close</span>
+ <div id="bottomModuleHeader" >
+ <span class="timelineContext" style="padding-right: 10px"></span>
+ <span class="timelineContext" style="float: right;" onclick="hideBottomSection();">Close</span>
</div>
- <div id="leftArrow" onclick="TimelineLeftArrow();" style="cursor: pointer;"><</div>
<div id="bottomSectionContent" style="clear: both;">
No modules have yet been loaded.
</div>
- <div id="rightArrow" onclick="TimelineRightArrow();" style="cursor: pointer;">></div>
</div>
</div>
Modified: trunk/step/step-web/src/main/webapp/js/init.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/init.js 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/webapp/js/init.js 2012-04-18 18:55:16 UTC (rev 242)
@@ -30,18 +30,20 @@
var topMenuHeight = $("#topMenu").height();
var headingContainerHeight = $(".headingContainer").height();
var imageAndFooterHeight = $(".northBookmark").height() + $(".logo").height();
- var bottomSectionHeight = $("#bottomSection").height() + 100;
+ var bottomSectionHeight = $("#bottomSection").height();
var windowWithoutMenuNorModule = windowHeight - topMenuHeight - bottomSectionHeight;
var columnHeight = windowWithoutMenuNorModule;
var bookmarkHeight = windowWithoutMenuNorModule - imageAndFooterHeight ;
var passageTextHeight = windowWithoutMenuNorModule - innerMenuHeight;
+ var gapBetweenMenuAndPassage = 5;
var passageContentHeight = passageTextHeight - headingContainerHeight;
+
$(".column").height(columnHeight);
$(".bookmarkPane").height(bookmarkHeight);
$(".passageText").height(passageTextHeight);
- $(".passageContent").css("top", headingContainerHeight);
- $(".passageContent").height(passageContentHeight);
+ $(".passageContent").css("top", headingContainerHeight + gapBetweenMenuAndPassage);
+ $(".passageContent").height(passageContentHeight - gapBetweenMenuAndPassage * 2);
// alert(headingContainerHeight);
// if($("#debug").text() == "") {
@@ -58,7 +60,7 @@
// "passageContent = " + $(".passageContent").height() + "\n" ;
//
// $("#debug").text(heights);
-//
+
}
/**
@@ -277,7 +279,7 @@
function initModules(passages) {
var bottomSection = $("#bottomSectionContent");
- new TimelineWidget(bottomSection);
+ new TimelineWidget(bottomSection, passages);
new GeographyWidget(bottomSection, passages);
}
Modified: trunk/step/step-web/src/main/webapp/js/setup.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/setup.js 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/webapp/js/setup.js 2012-04-18 18:55:16 UTC (rev 242)
@@ -14,7 +14,7 @@
$.getJSON(MODULE_GET_ALL_INSTALLABLE_MODULES, function(data) {
$(data).each(function() {
var toBeInstalled = "<a class='notInstalled' href=\"javascript:installVersion('" + this.initials + "','" +
- this.name.replace(/'/g,"\\'") + "')\">[" + this.initials + "] " + this.name + " - Installed</a><br />";
+ this.name.replace(/'/g,"\\'") + "')\">[" + this.initials + "] " + this.name + "</a><br />";
$("#availableModules").append(toBeInstalled);
})
});
Modified: trunk/step/step-web/src/main/webapp/js/timeline.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/timeline.js 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/webapp/js/timeline.js 2012-04-18 18:55:16 UTC (rev 242)
@@ -1,3 +1,7 @@
+//TODO DELETE???
+var tl2;
+
+
/**
* Code for showing and interacting with the timeline
*/
@@ -2,12 +6,18 @@
-function TimelineWidget(rootElement) {
+function TimelineWidget(rootElement, passages) {
this.rootElement = rootElement;
- var self = this;
-
- this.hotspots = [];
- this.timebands = [];
+ this.passages = passages;
this.initialised = false;
+ this.active = false;
+ this.currentEvents = {};
- $(rootElement).hear("show-timeline", function(selfElement) {
- //first show the bottom pane...
+ var self = this;
+
+ // register the "show-timeline" event
+ $(rootElement).hear("show-timeline", function(selfElement, data) {
+ self.passageId = data.passageId;
+ self.active = true;
+ console.log("Showing timeline on passage " + self.passageId);
+
+ // first show the bottom pane...
if(!this.initialised) {
@@ -17,164 +27,141 @@
} else {
self.onLoad();
}
-
+
$(window).resize(self.onResize);
- });
-
- $(rootElement).hear("hide-timeline", function(selfElement) {
- //first show the bottom pane...
-// mainAppLayout.close("south");
- });
+ });
}
-/**
- * @returns true if initialisation was required
- */
TimelineWidget.prototype.initAndLoad = function() {
- this.initialised = true;
- var self = this;
+ //set up the theme
+ this.theme = Timeline.ClassicTheme.create();
+ this.theme.event.bubble.width = 250;
+ this.eventSource = new Timeline.DefaultEventSource();
+
+ // let's start with 1 band for now
- if(this.config == null) {
- //we obtain the configuration from the server - this tells us about timebands -> hotspots, etc.
- $.getSafe(TIMELINE_GET_CONFIG, function(data) {
- //want hotspots -> timebands link (we sent the other way round to save space on the copper wire
- $.each(data, function(timebandIndex, timeband) {
- $.each(timeband.hotspots, function(hotspotIndex, hotspot) {
- self.hotspots[hotspot.id] = {
- timebandId: timeband.id,
- description: hotspot.description,
- scale: hotspot.scale
- };
- });
-
- self.timebands[timeband.id] = { description: timeband.description, scale: timeband.scale} ;
- });
- self.onLoad();
- });
- }
-}
+ //setup bands
+ this.bands = [
+ Timeline.createBandInfo({
+ trackGap: 100,
+ width: "100%",
+ intervalUnit: Timeline.DateTime.WEEK,
+ intervalPixels: 150,
+ eventSource: this.eventSource,
+ theme: this.theme,
+ })];
-var tl2;
+ //set up timeline
+ this.tl = Timeline.create(this.rootElement[0], this.bands, Timeline.HORIZONTAL);
+
+ this.initToolbar();
+
+ // set status as successfully intialised
+ this.initialised = true;
+ this.onLoad();
+};
-TimelineWidget.prototype.onLoad = function() {
- var zones = [];
- this.theme = Timeline.ClassicTheme.create();
- var self = this;
- this.theme.event.bubble.width = 250;
-
+/**
+ * adds an event to the timeline, the caller is required to call the refresh layout on the timeline
+ */
+TimelineWidget.prototype.addEvent = function(item) {
+ //we only add the event if it is not already on our timeline...
+
+ if(!(item.eventId in this.currentEvents)) {
+
+ var event = new Timeline.DefaultEventSource.Event({
+ 'start' : Timeline.DateTime.parseIso8601DateTime(item.start),
+ 'end' : Timeline.DateTime.parseIso8601DateTime(item.end),
+ 'description' : item.description,
+ 'text' : item.title,
+ 'instant' : !item.duration
+ });
- $.getSafe(TIMELINE_GET_EVENTS_IN_PERIOD +"-101690000000000/-101580000000000", function(json, url) {
- //work out how many bands to show first!
- var bands = self.getBands(json.events);
+ this.eventSource.add(event);
+ }
+}
- if(!self.tl) {
- self.tl = Timeline.create(self.rootElement[0], bands, Timeline.HORIZONTAL);
- tl2 = self.tl;
- }
-
-// bands[0].eventSource.loadJSON(json, TIMELINE_GET_EVENTS_IN_PERIOD +"-101690000000000/-101580000000000");
- self.loadEvents(bands, json);
- });
+TimelineWidget.prototype.addMultipleEventsAndRefresh = function(data) {
+ var self = this;
+
+ //add each event to timeline
+ $.each(data.events, function(index, item) {
+ self.addEvent(item);
+ });
+
+ this.tl.layout();
}
/**
- * Returns the bands to be created given the data from the ui
+ * Let us load stuff relevant to our passage
*/
-TimelineWidget.prototype.getBands = function(events) {
- var uiTimebands = [];
- var obtained = [];
-
+TimelineWidget.prototype.onLoad = function() {
+ var reference = this.passages[this.passageId].getReference();
var self = this;
- var date = "-1250";
- var zones = [];
-
- var i = 0;
-
- $.each(events, function(index, event) {
- //TODO this can be optmized, since we are re-creating the uiTimebands every time
- var hotspot = self.hotspots[event.hotSpotId];
- if(hotspot != null) {
- var timeband = self.timebands[hotspot.timebandId];
- var unit = self.resolveScale(timeband.scale);
-
- if(obtained[hotspot.timebandId] == null) {
- obtained[hotspot.timebandId] = true;
- var bandInfo = Timeline.createBandInfo({
- width: "180px",
- trackGap: 0.2,
- trackHeight: 0.5,
- intervalUnit: unit,
- intervalPixels: 150,
-// zones: { start: "-2000", end: "2000", /* magnify: 1, */ unit: unit },
- zones: { start: "-1252", end: "-1249", /* magnify: 1, */ unit: unit },
- eventSource: new Timeline.DefaultEventSource(),
- date: date,
- theme: self.theme,
- });
-
- bandInfo.stepTimebandId = hotspot.timebandId;
-
- if (i == 2)
- {
- uiTimebands.push( bandInfo );
- }
- }
- }
+ //load events from server
+ $.getSafe(TIMELINE_GET_EVENTS_FROM_REFERENCE + reference, function(data, url) {
+ console.log("Now have " + data.events.length + " to show.");
- i++;
+ //move timeline to different date
+ //assuming first band is main band
+ self.tl.getBand(0).scrollToCenter(Timeline.DateTime.parseIso8601DateTime(data.suggestedDate));
+ self.addMultipleEventsAndRefresh(data);
+
+
+ // now that we have repositioned the timeline, we can try and
+ // get the other events within the visible time period
+ $.getSafe(TIMELINE_GET_EVENTS_IN_PERIOD +
+ self.tl.getBand(0).getMinVisibleDate().toISOString() + "/" +
+ self.tl.getBand(0).getMaxVisibleDate().toISOString(),
+ function(data, url) {
+ self.addMultipleEventsAndRefresh(data);
+ });
});
-
- return uiTimebands;
}
+
+TimelineWidget.prototype.addToolbarIcon = function(toolbar, id, text, iconName) {
+ var html = "<a id='" + id + "'>" + text + "</a>";
+ toolbar.append(html);
+ $("#" + id, toolbar).button({ text: false, icons: { primary: iconName }});
+};
-
/**
- * loads up the events on the correct bands
- * the band has a property called stepTimebandId which we can match to hotspots[hotspotId].timebandId
+ * Creates a toolbar for the timeline component
*/
-TimelineWidget.prototype.loadEvents = function(bands, json) {
+TimelineWidget.prototype.initToolbar = function() {
var self = this;
- var events = json.events;
- $.each(bands, function(bandIndex, band) {
- var eventsOnBand = $.grep(events, function(element, eventIndex) {
- //TODO fix events without hotspot ids
- var hotspot = self.hotspots[element.hotSpotId];
- if(hotspot == null) {
- return false;
- }
-
- return band.stepTimebandId == hotspot.timebandId;
- });
+ var toolbar = $("#bottomModuleHeader")
+ this.addToolbarIcon(toolbar, "scrollTimelineLeft", "Scroll left", 'ui-icon-seek-prev');
+ this.addToolbarIcon(toolbar, "scrollTimelineRight", "Scroll right", 'ui-icon-seek-next');
+ this.addToolbarIcon(toolbar, "zoomInTimeline", "Zoom in", 'ui-icon-zoomin');
+ this.addToolbarIcon(toolbar, "zoomOutTimeline", "Zoom out", 'ui-icon-zoomout');
+ this.addToolbarIcon(toolbar, "scrollTimelineToDate", "Scroll to date", 'ui-icon-search');
+
+ $("#bottomModuleHeader #scrollTimelineLeft").click(function() {
+ var mainBand = self.tl.getBand(0);
+ mainBand.scrollToCenter(mainBand.getMinVisibleDate());
+ });
- band.eventSource.loadJSON({ dateTimeFormat: json.dateTimeFormat, events: eventsOnBand },
- TIMELINE_GET_EVENTS_IN_PERIOD +"-101690000000000/-101580000000000");
+ $("#bottomModuleHeader #scrollTimelineRight").click(function() {
+ var mainBand = self.tl.getBand(0);
+ mainBand.scrollToCenter(mainBand.getMaxVisibleDate());
});
-
};
+
/**
- * resolves and returns the timeline scale
+ * This method updates the events on the timeline
*/
-TimelineWidget.prototype.resolveScale = function(scale) {
- //TODO remove
-// return Timeline.DateTime.WEEK;
+TimelineWidget.prototype.refreshTimeline = function(passageReference) {
+
+}
- switch(scale) {
- case 'CENTURY': return Timeline.DateTime.CENTURY;
- case 'DAY': return Timeline.DateTime.DAY;
- case 'DECADE': return Timeline.DateTime.DECADE;
- case 'MILLENIUM': return Timeline.DateTime.MILLENNIUM;
- case 'MONTH': return Timeline.DateTime.MONTH;
- case 'WEEK': return Timeline.DateTime.WEEK;
- case 'YEAR': return Timeline.DateTime.YEAR;
- default: return Timeline.DateTime.MONTH;
- }
-};
+
/**
* resizes the timeline appropriately
*/
@@ -225,7 +212,7 @@
this.fillDescription(divBody);
theme.event.bubble.bodyStyler(divBody);
elmt.appendChild(divBody);
- // This is where they define the times in the bubble
+ // This is where they define the times in the bubble
var divTime = doc.createElement("div");
divTime.innerHTML = start + " - " + end;
elmt.appendChild(divTime);
@@ -235,16 +222,14 @@
elmt.appendChild(divWiki);
}
-function TimelineLeftArrow()
-{
+function timelineLeftArrow() {
var band = tl2.getBand(0);
var newDate = Timeline.DateTime.parseGregorianDateTime(band.getMinVisibleDate().getFullYear() - 300);
band.scrollToCenter(newDate);
}
-function TimelineRightArrow()
-{
+function timelineRightArrow() {
var band = tl2.getBand(0);
var newDate = Timeline.DateTime.parseGregorianDateTime(band.getMaxVisibleDate().getFullYear() + 300);
band.scrollToCenter(newDate);
-}
\ No newline at end of file
+}
Modified: trunk/step/step-web/src/main/webapp/js/ui_hooks.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/ui_hooks.js 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/webapp/js/ui_hooks.js 2012-04-18 18:55:16 UTC (rev 242)
@@ -10,38 +10,36 @@
// These are used as part of the rest-like calls
/////////////////////////////////////////////////////////////////////////
-BOOKMARKS_GET = STEP_SERVER_BASE_URL + "favourites/getBookmarks";
-BOOKMARKS_ADD = STEP_SERVER_BASE_URL + "favourites/addBookmark/";
-HISTORY_GET = STEP_SERVER_BASE_URL + "favourites/getHistory/";
-HISTORY_ADD = STEP_SERVER_BASE_URL + "favourites/addHistory/";
+BOOKMARKS_GET = STEP_SERVER_BASE_URL + "favourites/getBookmarks";
+BOOKMARKS_ADD = STEP_SERVER_BASE_URL + "favourites/addBookmark/";
+HISTORY_GET = STEP_SERVER_BASE_URL + "favourites/getHistory/";
+HISTORY_ADD = STEP_SERVER_BASE_URL + "favourites/addHistory/";
+BIBLE_GET_BIBLE_VERSIONS = STEP_SERVER_BASE_URL + "bible/getBibleVersions/";
+BIBLE_GET_BIBLE_TEXT = STEP_SERVER_BASE_URL + "bible/getBibleText/";
+BIBLE_GET_FEATURES = STEP_SERVER_BASE_URL + "bible/getFeatures/";
+BIBLE_GET_ALL_FEATURES = STEP_SERVER_BASE_URL + "bible/getAllFeatures/";
+BIBLE_GET_BIBLE_BOOK_NAMES = STEP_SERVER_BASE_URL + "bible/getBibleBookNames/"
-BIBLE_GET_BIBLE_VERSIONS = STEP_SERVER_BASE_URL + "bible/getBibleVersions/";
-BIBLE_GET_BIBLE_TEXT = STEP_SERVER_BASE_URL + "bible/getBibleText/";
-BIBLE_GET_FEATURES = STEP_SERVER_BASE_URL + "bible/getFeatures/";
-BIBLE_GET_ALL_FEATURES = STEP_SERVER_BASE_URL + "bible/getAllFeatures/";
-BIBLE_GET_BIBLE_BOOK_NAMES = STEP_SERVER_BASE_URL + "bible/getBibleBookNames/"
+MODULE_GET_ALL_MODULES = STEP_SERVER_BASE_URL + "module/getAllModules/";
+MODULE_GET_ALL_INSTALLABLE_MODULES = STEP_SERVER_BASE_URL + "module/getAllInstallableModules/";
+MODULE_GET_DEFINITION = STEP_SERVER_BASE_URL + "module/getDefinition/";
+SETUP_IS_FIRST_TIME = STEP_SERVER_BASE_URL + "setup/isFirstTime/";
+SETUP_INSTALL_DEFAULT_MODULES = STEP_SERVER_BASE_URL + "setup/installDefaultModules/";
+SETUP_INSTALL_BIBLE = STEP_SERVER_BASE_URL + "setup/installBible/";
-MODULE_GET_ALL_MODULES = STEP_SERVER_BASE_URL + "module/getAllModules/";
-MODULE_GET_ALL_INSTALLABLE_MODULES = STEP_SERVER_BASE_URL + "module/getAllModules/";
-MODULE_GET_DEFINITION = STEP_SERVER_BASE_URL + "module/getDefinition/";
+TIMELINE_GET_EVENTS = STEP_SERVER_BASE_URL + "timeline/getEvents/";
+TIMELINE_GET_EVENTS_IN_PERIOD = STEP_SERVER_BASE_URL + "timeline/getEventsInPeriod/";
+TIMELINE_GET_EVENTS_FROM_REFERENCE = STEP_SERVER_BASE_URL + "timeline/getEventsFromReference/";
+TIMELINE_GET_CONFIG = STEP_SERVER_BASE_URL + "timeline/getTimelineConfiguration";
-SETUP_IS_FIRST_TIME = STEP_SERVER_BASE_URL + "setup/isFirstTime/";
-SETUP_INSTALL_DEFAULT_MODULES = STEP_SERVER_BASE_URL + "setup/installDefaultModules/";
-SETUP_INSTALL_BIBLE = STEP_SERVER_BASE_URL + "setup/installBible/";
+USER_LOGIN = STEP_SERVER_BASE_URL + "user/login/";
+USER_LOGOUT = STEP_SERVER_BASE_URL + "user/logout/";
+USER_REGISTER = STEP_SERVER_BASE_URL + "user/register/"
+USER_GET_LOGGED_IN_USER = STEP_SERVER_BASE_URL + "user/getLoggedInUser";
-TIMELINE_GET_EVENTS = STEP_SERVER_BASE_URL + "timeline/getEvents/";
-TIMELINE_GET_EVENTS_IN_PERIOD = STEP_SERVER_BASE_URL + "timeline/getEventsInPeriod/";
-TIMELINE_GET_EVENTS_FROM_REFERENCE = STEP_SERVER_BASE_URL + "timeline/getEventsFromReference/";
-TIMELINE_GET_CONFIG = STEP_SERVER_BASE_URL + "timeline/getTimelineConfiguration";
-
-USER_LOGIN = STEP_SERVER_BASE_URL + "user/login/";
-USER_LOGOUT = STEP_SERVER_BASE_URL + "user/logout/";
-USER_REGISTER = STEP_SERVER_BASE_URL + "user/register/"
-USER_GET_LOGGED_IN_USER = STEP_SERVER_BASE_URL + "user/getLoggedInUser";
-
-GEOGRAPHY_GET_PLACES = STEP_SERVER_BASE_URL + "geography/getPlaces/"
+GEOGRAPHY_GET_PLACES = STEP_SERVER_BASE_URL + "geography/getPlaces/"
//////////////////////////
// SOME DEFAULTS
@@ -129,7 +127,7 @@
*/
function showTimelineModule(menuItem) {
showBottomSection(menuItem);
- $.shout("show-timeline");
+ $.shout("show-timeline", { passageId : + getPassageId(menuItem) });
};
/**
@@ -147,12 +145,12 @@
if (getPassageId(menuItem) == 0)
{
var verse = $('#leftPassageReference').val();
- $('#timelineContext').html(verse);
+ $('.timelineContext:first').html(verse);
}
else
{
var verse = $('#rightPassageReference').val();
- $('#timelineContext').html(verse);
+ $('.timelineContext:first').html(verse);
}
var bottomSection = $("#bottomSection");
Modified: trunk/step/step-web/src/main/webapp/setup.jsp
===================================================================
--- trunk/step/step-web/src/main/webapp/setup.jsp 2012-04-17 19:04:39 UTC (rev 241)
+++ trunk/step/step-web/src/main/webapp/setup.jsp 2012-04-18 18:55:16 UTC (rev 242)
@@ -5,15 +5,18 @@
<META http-equiv="Content-Type" content="text/html; charset=utf-8">
<TITLE>STEP :: Scripture Tools for Every Pastor</TITLE>
- <link rel="stylesheet" type="text/css" href="css/ui-layout/layout-default.css" />
<link rel="stylesheet" type="text/css" href="css/ui-lightness/jquery-ui-1.8.5.custom.css" />
<link rel="stylesheet" type="text/css" href="css/initial-layout.css" />
<link rel="stylesheet" type="text/css" href="css/initial-fonts.css" />
<link rel="stylesheet" type="text/css" href="css/setup-layout.css" />
+
+ <script src="js/initLib.js" type="text/javascript"></script>
+
+
<script src="libs/jquery-1.4.2.min.js" type="text/javascript"></script>
<script src="libs/jquery-ui-1.8.5.custom.min.js" type="text/javascript"></script>
- <script src="libs/jquery.layout-latest.js" type="text/javascript"></script>
+ <!-- <script src="libs/jquery.layout-latest.js" type="text/javascript"></script> -->
<script src="libs/jquery-shout.js" type="text/javascript"></script>
<script src="js/ui_hooks.js" type="text/javascript"></script>
More information about the Tynstep-svn
mailing list