[Tynstep-svn] r186 - in trunk/step: step-core/src/main/java/com/tyndalehouse/step/core step-core/src/main/java/com/tyndalehouse/step/core/models 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/java/com/tyndalehouse/step/core/xsl step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl step-core/src/main/resources/com/tyndalehouse/step/core/service/impl step-core/src/test/java/com/tyndalehouse/step/core step-core/src/test/java/com/tyndalehouse/step/core/service step-core/src/test/java/com/tyndalehouse/step/core/xsl step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl step-parent step-web step-web/src/main/java/com/tyndalehouse/step/rest step-web/src/main/java/com/tyndalehouse/step/rest/controllers step-web/src/main/java/com/tyndalehouse/step/rest/wrappers step-web/src/main/webapp step-web/src/main/webapp/WEB-INF step-web/src/main/webapp/css step-web/src/main/webapp/css/ui-layout step-web/src/main/webapp/images step-web/src/main/webapp/js
ChrisBurrell at crosswire.org
ChrisBurrell at crosswire.org
Mon Nov 15 13:23:39 MST 2010
Author: ChrisBurrell
Date: 2010-11-15 13:23:39 -0700 (Mon, 15 Nov 2010)
New Revision: 186
Added:
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/IPSample.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XsltProviders.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java
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/
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/
trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java
trunk/step/step-web/src/main/webapp/images/wait16.gif
trunk/step/step-web/src/main/webapp/js/bookmark.js
Modified:
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java
trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java
trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl
trunk/step/step-parent/pom.xml
trunk/step/step-web/pom.xml
trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java
trunk/step/step-web/src/main/webapp/WEB-INF/mvc-config.xml
trunk/step/step-web/src/main/webapp/WEB-INF/web.xml
trunk/step/step-web/src/main/webapp/css/initial-layout.css
trunk/step/step-web/src/main/webapp/css/passage.css
trunk/step/step-web/src/main/webapp/css/ui-layout/layout-default.css
trunk/step/step-web/src/main/webapp/index.jsp
trunk/step/step-web/src/main/webapp/js/init.js
trunk/step/step-web/src/main/webapp/js/passage.js
trunk/step/step-web/src/main/webapp/js/passage_toolbar.js
Log:
updated with interlinear
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/BibleVersion.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -3,8 +3,7 @@
import java.io.Serializable;
/**
- * Contains information about a bible version to be displayed on the screen in
- * the UI
+ * Contains information about a bible version to be displayed on the screen in the UI
*
* @author CJBurrell
*
@@ -14,17 +13,25 @@
private String initials;
private String name;
private String language;
+ private boolean hasStrongs;
+ public boolean isHasStrongs() {
+ return this.hasStrongs;
+ }
+
+ public void setHasStrongs(final boolean hasStrongs) {
+ this.hasStrongs = hasStrongs;
+ }
+
/**
* @return the initials
*/
public String getInitials() {
- return initials;
+ return this.initials;
}
/**
- * @param initials
- * the initials to set
+ * @param initials the initials to set
*/
public void setInitials(final String initials) {
this.initials = initials;
@@ -34,12 +41,11 @@
* @return the name
*/
public String getName() {
- return name;
+ return this.name;
}
/**
- * @param name
- * the name to set
+ * @param name the name to set
*/
public void setName(final String name) {
this.name = name;
@@ -49,12 +55,11 @@
* @return the language
*/
public String getLanguage() {
- return language;
+ return this.language;
}
/**
- * @param language
- * the language to set
+ * @param language the language to set
*/
public void setLanguage(final String language) {
this.language = language;
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/models/LookupOption.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -1,5 +1,9 @@
package com.tyndalehouse.step.core.models;
+import static com.tyndalehouse.step.core.xsl.XslConversionType.DEFAULT;
+
+import com.tyndalehouse.step.core.xsl.XslConversionType;
+
/**
* Outlines a list of options available in lookup
*
@@ -8,25 +12,31 @@
*/
public enum LookupOption {
/** Strong numbers */
- STRONG_NUMBERS("StrongsNumbers", "Strongs"),
+ STRONG_NUMBERS("StrongsNumbers", "Strongs", XslConversionType.INTERLINEAR),
/** Morphology */
- MORPHOLOGY("Morph", "Morphology"),
+ MORPHOLOGY("Morph", "Morphology", XslConversionType.INTERLINEAR),
/**
* Interlinears are available when Strongs are available.
*/
- INTERLINEAR("Interlinear");
+ INTERLINEAR("Interlinear", XslConversionType.INTERLINEAR);
private final String xsltParameterName;
private final String displayName;
+ private XslConversionType stylesheet;
private LookupOption(final String xsltParameterName) {
- this(xsltParameterName, xsltParameterName);
+ this(xsltParameterName, xsltParameterName, DEFAULT);
}
- private LookupOption(final String xsltParameterName, final String displayName) {
+ private LookupOption(final String xsltParameterName, final XslConversionType stylesheet) {
+ this(xsltParameterName, xsltParameterName, stylesheet);
+ }
+
+ private LookupOption(final String xsltParameterName, final String displayName, final XslConversionType stylesheet) {
this.xsltParameterName = xsltParameterName;
this.displayName = displayName;
+ this.stylesheet = stylesheet;
}
/**
@@ -39,4 +49,8 @@
public String getDisplayName() {
return this.displayName;
}
+
+ public XslConversionType getStylesheet() {
+ return this.stylesheet;
+ }
}
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/BibleInformationService.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -29,9 +29,10 @@
* @param version the initials that identify the bible version
* @param reference the reference
* @param lookupOptions options to set for retrieval
+ * @param interlinearVersion version to use as the interlinear
* @return the HTML string passed back for consumption
*/
- String getPassageText(String version, String reference, List<LookupOption> lookupOptions);
+ String getPassageText(String version, String reference, List<LookupOption> lookupOptions, String interlinearVersion);
/**
*
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/JSwordService.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -14,55 +14,12 @@
* @param version version to lookup
* @param reference the reference to lookup
* @param options the list of options for the lookup operation
+ * @param interlinearVersion the version to add if there is an interlinear request, or blank if not
* @return the OSIS text in an HTML form
*/
- String getOsisText(String version, String reference, List<LookupOption> options);
+ String getOsisText(String version, String reference, List<LookupOption> options, String interlinearVersion);
/**
- * returns the language of the version specified
- *
- * @param version the version to lookup
- * @return the language code
- */
- String getLanguage(String version);
-
- /**
- * retrieves the short form of the key that is a human readable form
- *
- * @param version the version to be retrieved from
- * @param reference the reference to be converted
- * @return a human readable version of the key
- */
- String getReadableKey(String version, String reference);
-
- /**
- * returns the actual reference, removing the strong pattern + first initial. For e.g. removes strong:H from
- * "strong:H00002"
- *
- * @param reference reference to parse
- * @return the key in the dictionary to be used for lookup purposes
- * @throws ActionException the action exception
- */
- String getLookupKeyFromReference(String reference);
-
- /**
- * dependant on the reference, we return a different module to lookup the definition. For e.g. we use a Greek
- * dictionary to lookup a reference starting strong:Gxxxxx
- *
- * @param reference reference to be looked up
- * @return the module initials to use for the dictionary lookup
- */
- String getInitialsFromReference(String reference);
-
- /**
- * Looks up a definition given a reference in the default JSword module
- *
- * @param reference reference, for e.g. a Strong number
- * @return the definition
- */
- String lookupStrongDefinition(String reference);
-
- /**
* looks up any installed module
*
* @param bibleCategory the category of the bible to lookup
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/BibleInformationServiceImpl.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -8,6 +8,7 @@
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookCategory;
+import org.crosswire.jsword.book.FeatureType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -41,6 +42,7 @@
v.setName(b.getName());
v.setInitials(b.getInitials());
v.setLanguage(b.getLanguage().getName());
+ v.setHasStrongs(b.hasFeature(FeatureType.STRONGS_NUMBERS));
versions.add(v);
}
@@ -48,8 +50,9 @@
return versions;
}
- public String getPassageText(final String version, final String reference, final List<LookupOption> options) {
- return this.jsword.getOsisText(version, reference, options);
+ public String getPassageText(final String version, final String reference, final List<LookupOption> options,
+ final String interlinearVersion) {
+ return this.jsword.getOsisText(version, reference, options, interlinearVersion);
}
public List<EnrichedLookupOption> getAllFeatures() {
Modified: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/service/impl/JSwordServiceImpl.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -1,15 +1,16 @@
package com.tyndalehouse.step.core.service.impl;
-import static java.lang.String.format;
+import static com.tyndalehouse.step.core.xsl.XslConversionType.DEFAULT;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
import javax.xml.transform.TransformerException;
-import org.apache.commons.lang.StringUtils;
-import org.crosswire.common.util.Language;
import org.crosswire.common.xml.Converter;
import org.crosswire.common.xml.SAXEventProvider;
import org.crosswire.common.xml.TransformingSAXEventProvider;
@@ -22,8 +23,6 @@
import org.crosswire.jsword.book.Books;
import org.crosswire.jsword.book.FeatureType;
import org.crosswire.jsword.passage.NoSuchKeyException;
-import org.crosswire.jsword.versification.BibleInfo;
-import org.jdom.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.SAXException;
@@ -31,6 +30,7 @@
import com.tyndalehouse.step.core.exceptions.StepInternalException;
import com.tyndalehouse.step.core.models.LookupOption;
import com.tyndalehouse.step.core.service.JSwordService;
+import com.tyndalehouse.step.core.xsl.XslConversionType;
/**
* a service providing a wrapper around JSword
@@ -39,36 +39,8 @@
*
*/
public class JSwordServiceImpl implements JSwordService {
- /**
- * the pattern with which strong references in OSIS start
- */
- public static final String STRONG_PATTERN_START = "strong:";
-
- /**
- * a greek marker for strong numbers, e.g. strong:Gxxxx
- */
- public static final char STRONG_GREEK_MARKER = 'G';
-
- /**
- * Strong hebrew marker, for e.g. strong:Hxxxx
- */
- public static final char STRONG_HEBREW_MARKER = 'H';
-
- /**
- * Initials of default Hebrew JSword module to use for lookup of dictionary definitions
- */
- public static final String STRONG_HEBREW_DICTIONARY_INITIALS = "StrongsHebrew";
-
- /**
- * Initials of default Strong JSword greek dictionary module for lookup of dictionary definitions
- */
- public static final String STRONG_GREEK_DICTIONARY_INITIALS = "StrongsGreek";
private final Logger logger = LoggerFactory.getLogger(this.getClass());
- // TODO: autowire, or drive from properties file
- // @Autowired
- private final String xslConversionDefinition = "default.xsl";
-
@SuppressWarnings("unchecked")
public List<Book> getModules(final BookCategory bibleCategory) {
if (bibleCategory == null) {
@@ -84,25 +56,28 @@
return Books.installed().getBooks(bf);
}
- public String getOsisText(final String version, final String reference, final List<LookupOption> options) {
+ public String getOsisText(final String version, final String reference, final List<LookupOption> options,
+ final String interlinearVersion) {
this.logger.debug("Retrieving text for ({}, {})", version, reference);
try {
final Book currentBook = Books.installed().getBook(version);
final BookData bookData = new BookData(currentBook, currentBook.getKey(reference));
+ final Set<XslConversionType> requiredTransformation = identifyStyleSheet(options);
final SAXEventProvider osissep = bookData.getSAXEventProvider();
TransformingSAXEventProvider htmlsep = null;
htmlsep = (TransformingSAXEventProvider) new Converter() {
- // TODO cache XSL in memory or Transforming SAX Event Provider
public SAXEventProvider convert(final SAXEventProvider provider) throws TransformerException {
try {
+ // for now, we just assume that we'll only have one option, but this may change later
final TransformingSAXEventProvider tsep = new TransformingSAXEventProvider(getClass()
- .getResource(JSwordServiceImpl.this.xslConversionDefinition).toURI(), osissep);
+ .getResource(requiredTransformation.iterator().next().getFile()).toURI(), osissep);
// set parameters here
- setOptions(tsep, options);
+ setOptions(tsep, options, version, reference);
+ setupInterlinearOptions(tsep, interlinearVersion, reference);
// then return
return tsep;
@@ -110,6 +85,7 @@
throw new StepInternalException("Failed to load resource correctly", e);
}
}
+
}.convert(osissep);
return XMLUtil.writeToString(htmlsep);
} catch (final NoSuchKeyException e) {
@@ -124,6 +100,19 @@
}
}
+ private Set<XslConversionType> identifyStyleSheet(final List<LookupOption> options) {
+ final Set<XslConversionType> chosenOptions = new HashSet<XslConversionType>();
+
+ for (final LookupOption lo : options) {
+ chosenOptions.add(lo.getStylesheet());
+ }
+
+ if (chosenOptions.isEmpty()) {
+ chosenOptions.add(DEFAULT);
+ }
+ return chosenOptions;
+ }
+
public List<LookupOption> getFeatures(final String version) {
final Book book = Books.installed().getBook(version);
final List<LookupOption> options = new ArrayList<LookupOption>(3);
@@ -138,110 +127,33 @@
return options;
}
+ private void setupInterlinearOptions(final TransformingSAXEventProvider tsep, final String interlinearVersion,
+ final String reference) {
+ if (tsep.getParameter(LookupOption.INTERLINEAR.getXsltParameterName()) != null) {
+ tsep.setParameter("interlinearReference", reference);
+
+ if (isNotBlank(interlinearVersion)) {
+ tsep.setParameter("interlinearVersion", interlinearVersion);
+ } else {
+ // depending on OT or NT, we select a default interlinear version
+
+ }
+ }
+ }
+
/**
* This method sets up the options for the XSLT transformation
*
* @param tsep the xslt transformer
* @param options the options available
+ * @param version the version to initialise a potential interlinear with
+ * @param textScope the scope of the text to lookup
+ * @return the XSLT that will give me the correct transformation
*/
- protected void setOptions(final TransformingSAXEventProvider tsep, final List<LookupOption> options) {
+ protected void setOptions(final TransformingSAXEventProvider tsep, final List<LookupOption> options,
+ final String version, final String textScope) {
for (final LookupOption lookupOption : options) {
tsep.setParameter(lookupOption.getXsltParameterName(), true);
}
}
-
- public String getLanguage(final String version) {
- final Book currentBook = Books.installed().getBook(version);
- if (currentBook == null) {
- return null;
- }
-
- final Language language = currentBook.getLanguage();
- if (language != null) {
- return language.getCode();
- }
- return null;
- }
-
- /**
- * IMPROVEMENT NOTE that this is not thread safe, since JSword relies on statics in the background
- */
- public String getReadableKey(final String version, final String reference) {
- try {
- BibleInfo.setFullBookName(false);
- return Books.installed().getBook(version).getKey(reference).getName();
- } catch (final NoSuchKeyException e) {
- throw new StepInternalException("Unable to get readable key from OSIS reference", e);
- }
- }
-
- public String lookupStrongDefinition(final String reference) {
- if (StringUtils.isEmpty(reference)) {
- throw new StepInternalException("Reference was not provided");
- }
- this.logger.error("definition lookup command");
- final String initials = getInitialsFromReference(reference);
- final String lookupKey = getLookupKeyFromReference(reference);
-
- try {
- // TODO: ensure a lookup key exists!
- final Book currentBook = Books.installed().getBook(initials);
- final BookData data = new BookData(currentBook, currentBook.getKey(lookupKey));
- return doXslt(data, data.getOsisFragment());
- } catch (final NoSuchKeyException e) {
- throw new StepInternalException("Unable to find specified reference", e);
- } catch (final BookException e) {
- throw new StepInternalException("An error occurred looking up the passage", e);
- }
- }
-
- /**
- * does a simple xslt transformation to show the definition on the screen
- *
- * @param data data to be shown
- * @param osisFragment osisFragment to transform
- * @return the xslted definition ready to be displayed on the user's screen
- */
- private String doXslt(final BookData data, final Element osisFragment) {
- // if (data == null) {
- // return "";
- // }
- //
- // try {
- // final SAXEventProvider osissep = data.getSAXEventProvider();
- // // TODO: do some work on the XSLT definition
- // final TransformingSAXEventProvider htmlsep = (TransformingSAXEventProvider) new ConfigurableHTMLConverter()
- // .convert(osissep);
- // final String text = XMLUtil.writeToString(htmlsep);
- // return text;
- // } catch (final SAXException e) {
- // Reporter.informUser(this, e);
- // } catch (final BookException e) {
- // Reporter.informUser(this, e);
- // } catch (final TransformerException e) {
- // Reporter.informUser(this, e);
- // }
- return "";
- }
-
- public String getInitialsFromReference(final String reference) {
- if (reference.toLowerCase().startsWith(STRONG_PATTERN_START)) {
- final int charPosition = STRONG_PATTERN_START.length();
- if (reference.charAt(charPosition) == STRONG_HEBREW_MARKER) {
- return STRONG_HEBREW_DICTIONARY_INITIALS;
- } else if (reference.charAt(charPosition) == STRONG_GREEK_MARKER) {
- return STRONG_GREEK_DICTIONARY_INITIALS;
- }
- // continuing will throw exception
- }
- throw new StepInternalException(format("Dictionary reference not recognised: %s", reference));
- }
-
- public String getLookupKeyFromReference(final String reference) {
- if (reference.toLowerCase().startsWith(STRONG_PATTERN_START)) {
- // remove strong: or strong:
- return reference.substring(STRONG_PATTERN_START.length());
- }
- throw new StepInternalException(format("Lookup key not recognised: %s", reference));
- }
}
Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/IPSample.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/IPSample.java (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/IPSample.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,7 @@
+package com.tyndalehouse.step.core.xsl;
+
+public class IPSample {
+ public String getWord(final Object o) {
+ return "hello";
+ }
+}
Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/InterlinearProvider.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,13 @@
+package com.tyndalehouse.step.core.xsl;
+
+public interface InterlinearProvider {
+ /**
+ * This is the more specific method
+ *
+ * @param verseNumber helps locate the word by adding location awareness
+ * @param strong identifies the word by its root in the original language
+ * @param morph identifies the morphology of the word (i.e. the grammar)
+ * @return the word in the original language (Greek, Hebrew, etc.)
+ */
+ String getWord(String verseNumber, String strong, String morph);
+}
Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XslConversionType.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,25 @@
+package com.tyndalehouse.step.core.xsl;
+
+public enum XslConversionType {
+ /**
+ * a standard text, where only one line of text will be displayed, (i.e. normal style)
+ */
+ DEFAULT("default.xsl"),
+ /**
+ * identifies a text that requires outputs on multiple lines
+ */
+ INTERLINEAR("interlinear.xsl");
+
+ /**
+ * indicates the xsl conversion file to use for this work
+ */
+ private final String file;
+
+ private XslConversionType(final String file) {
+ this.file = file;
+ }
+
+ public String getFile() {
+ return this.file;
+ }
+}
Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XsltProviders.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XsltProviders.java (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/XsltProviders.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,15 @@
+package com.tyndalehouse.step.core.xsl;
+
+public enum XsltProviders {
+ INTERLINEAR_PROVIDER("InterlinearProvider");
+
+ private final String paramName;
+
+ XsltProviders(final String paramName) {
+ this.paramName = paramName;
+ }
+
+ public String getParamName() {
+ return this.paramName;
+ }
+}
Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/DualKey.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,45 @@
+package com.tyndalehouse.step.core.xsl.impl;
+
+import static java.lang.String.format;
+
+/**
+ * A Strong Morph Map takes two keys, and gives one word back. The following DualKey relies on hashCode. The hash
+ * function relies on toString so T and S need to have fast toString().
+ *
+ * @author Chris
+ *
+ */
+public class DualKey<T, S> {
+ private final T t;
+ private final S s;
+
+ public DualKey(final T t, final S s) {
+ this.t = t;
+ this.s = s;
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (!(obj instanceof DualKey)) {
+ return false;
+ }
+
+ final DualKey<?, ?> k = (DualKey<?, ?>) obj;
+ return this.t.equals(k.t) && this.s.equals(k.s);
+ }
+
+ @Override
+ public int hashCode() {
+ // we need to return the same hashcode based on s and t
+ return (this.t.toString().concat(this.s.toString())).hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return format("%s-%s", this.t, this.s);
+ }
+}
Added: trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java
===================================================================
--- trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java (rev 0)
+++ trunk/step/step-core/src/main/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImpl.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,311 @@
+package com.tyndalehouse.step.core.xsl.impl;
+
+import static org.apache.commons.lang.StringUtils.isBlank;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang.StringUtils.split;
+import static org.crosswire.jsword.book.OSISUtil.ATTRIBUTE_W_LEMMA;
+import static org.crosswire.jsword.book.OSISUtil.ATTRIBUTE_W_MORPH;
+import static org.crosswire.jsword.book.OSISUtil.OSIS_ATTR_OSISID;
+import static org.crosswire.jsword.book.OSISUtil.OSIS_ELEMENT_VERSE;
+import static org.crosswire.jsword.book.OSISUtil.OSIS_ELEMENT_W;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookData;
+import org.crosswire.jsword.book.BookException;
+import org.crosswire.jsword.book.Books;
+import org.crosswire.jsword.passage.NoSuchKeyException;
+import org.jdom.Content;
+import org.jdom.Element;
+
+import com.tyndalehouse.step.core.exceptions.StepInternalException;
+import com.tyndalehouse.step.core.xsl.InterlinearProvider;
+
+/**
+ * This object is not purposed to be used as a singleton. It builds up textual information on initialisation, and is
+ * specific to requests. On initialisation, the OSIS XML is retrieved and iterated through to find all strong/morph
+ * candidates
+ *
+ * @author Chris
+ *
+ */
+public class InterlinearProviderImpl implements InterlinearProvider {
+ /**
+ * set of characters used to distinguish one strong from another
+ */
+ private static final String STRONG_SEPARATORS = " []";
+
+ /**
+ * bestAccuracy gives a word by its dual key (strong,morph)
+ */
+ private final Map<DualKey<String, String>, String> bestAccuracy = new HashMap<DualKey<String, String>, String>();
+
+ /**
+ * limited accuracy tries to do a location look up by using the verse number as part of the key
+ */
+ private final Map<DualKey<String, String>, List<String>> limitedAccuracy = new HashMap<DualKey<String, String>, List<String>>();
+
+ /**
+ * finally, this is just a list of all the strongs and their mappings. Still would be fairly good as long as the
+ * same word isn't used multiple times.
+ */
+ private final Map<String, String> worstAccuracy = new HashMap<String, String>();
+
+ /**
+ * sets up the interlinear provider with the correct version and text scope.
+ *
+ * @param version the version to use to set up the interlinear
+ * @param textScope the text scope reference, defining the bounds of the lookup
+ */
+ public InterlinearProviderImpl(final String version, final String textScope) {
+ // first check whether the values passed in are correct
+ if (isBlank(version) || isBlank(textScope)) {
+ return;
+ }
+
+ final Book currentBook = Books.installed().getBook(version);
+ BookData bookData;
+
+ try {
+ bookData = new BookData(currentBook, currentBook.getKey(textScope));
+ scanForTextualInformation(bookData.getOsisFragment());
+ } catch (final NoSuchKeyException e) {
+ throw new StepInternalException(e.getMessage(), e);
+ } catch (final BookException e) {
+ throw new StepInternalException(e.getMessage(), e);
+ }
+ }
+
+ /**
+ * package private version for testing purposes
+ */
+ InterlinearProviderImpl() {
+ // exposing package private constructor
+ }
+
+ public String getWord(final String verseNumber, final String strong, final String morph) {
+ // we use a linked hashset, because we want the behaviour of a set while we add to it,
+ // but at the end, we will want to return the elements in order
+ final Set<String> results = new LinkedHashSet<String>();
+ if (isBlank(strong)) {
+ // we might as well return, as we have no information to go on
+ }
+
+ // the keys passed in may have multiple references and morphologies, therefore, we need to lookup
+ // multiple items.
+
+ // ///////////////////////////
+ // TODO we need to remove the strong:[G/H] from the string, since some versions don't have it
+ // and key things differently
+ // ////////////////////////////
+ final String[] strongs = split(strong, STRONG_SEPARATORS);
+ final String[] morphs = split(morph, STRONG_SEPARATORS);
+
+ // if we have no morphs, then might as well call getWord(verseNumber, strong) straight away
+ if (morphs == null || morphs.length == 0) {
+ results.add(getWord(verseNumber, strong));
+ return convertToString(results);
+ }
+
+ // There are at most strongs.length words, and we might have morphological data to help
+ for (final String s : strongs) {
+ boolean foundMatchForStrong = false;
+
+ // each could be using the morphs we have, so try them all
+ for (final String m : morphs) {
+ // lookup (strong,morph) -> word first
+ final DualKey<String, String> key = new DualKey<String, String>(s, m);
+ final String word = this.bestAccuracy.get(key);
+
+ if (word != null) {
+ results.add(word);
+ foundMatchForStrong = true;
+ }
+ }
+
+ // have we found a match? if not, we better try and find one using the verse
+ if (!foundMatchForStrong) {
+ results.add(getWord(verseNumber, strong));
+ }
+ }
+
+ return convertToString(results);
+ }
+
+ /**
+ * Takes a set, and outputs the strings concatenated together (and separated by a space.
+ *
+ * @param results the results that should be converted to a string
+ * @return
+ */
+ private String convertToString(final Set<String> results) {
+ final Iterator<String> iterator = results.iterator();
+ final StringBuffer sb = new StringBuffer(results.size() * 14);
+
+ // add the first word without a space
+ if (iterator.hasNext()) {
+ sb.append(iterator.next());
+ }
+
+ // add spaces between each element now
+ while (iterator.hasNext()) {
+ sb.append(' ');
+ sb.append(iterator.next());
+ }
+ return sb.toString();
+ }
+
+ /**
+ * returns words based on strong and verse number only
+ *
+ * @param verseNumber the verse number
+ * @param strong the strong reference
+ * @return a word that matches or the empty string
+ */
+ String getWord(final String verseNumber, final String strong) {
+ if (strong != null && verseNumber != null) {
+ final DualKey<String, String> key = new DualKey<String, String>(strong, verseNumber);
+
+ final List<String> list = this.limitedAccuracy.get(key);
+ if (list != null && list.size() != 0) {
+ return list.get(0);
+ }
+ }
+ // so we didn't find anything even with the verse number, now we need to look for a strong
+ // on its own
+ final String lastChance = this.worstAccuracy.get(strong);
+ if (lastChance == null) {
+ return "";
+ }
+
+ // it is important to return an empty string here
+ return lastChance;
+ }
+
+ /**
+ * retrieves context textual information from a passage
+ *
+ * @param osisFragment the fragment of XML that should be examined
+ */
+ private void scanForTextualInformation(final Element osisFragment) {
+ // redirect with null verse
+ scanForTextualInformation(osisFragment, null);
+ }
+
+ /**
+ * setups all the initial textual information for fast retrieval during XSL transformation.
+ *
+ * @param element element to start with.
+ * @param currentVerse the current verse to use as part of the key
+ */
+ @SuppressWarnings("unchecked")
+ private void scanForTextualInformation(final Element element, final String currentVerse) {
+ // check to see if we've hit a new verse, if so, we update the verse
+ final String verseToBeUsed = element.getName().equals(OSIS_ELEMENT_VERSE) ? element
+ .getAttributeValue(OSIS_ATTR_OSISID) : currentVerse;
+
+ // check to see if we've hit a node of interest
+ if (element.getName().equals(OSIS_ELEMENT_W)) {
+ extractTextualInfoFromNode(element, verseToBeUsed);
+ return;
+ }
+
+ // iterate through all children and call recursively
+ Object data = null;
+ Element ele = null;
+ final Iterator<Content> contentIter = element.getContent().iterator();
+ while (contentIter.hasNext()) {
+ data = contentIter.next();
+ if (data instanceof Element) {
+ ele = (Element) data;
+ scanForTextualInformation(ele, verseToBeUsed);
+ }
+ }
+ }
+
+ /**
+ * retrieves textual information and adds it to the provider
+ *
+ * @param element the element to extract information from
+ * @param verseReference verse reference to use for locality of keying
+ */
+ private void extractTextualInfoFromNode(final Element element, final String verseReference) {
+ final String strong = element.getAttributeValue(ATTRIBUTE_W_LEMMA);
+ final String morph = element.getAttributeValue(ATTRIBUTE_W_MORPH);
+ final String word = element.getText();
+
+ // do we need to do any manipulation? probably not because we are going to be
+ // comparing against other OSIS XML texts which should be formatted in the same way!
+ // however, some attributes may contain multiple strongs and morphs tagged to one word.
+ // therefore we do need to split the text.
+ final String[] strongs = split(strong, STRONG_SEPARATORS);
+ final String[] morphs = split(morph, STRONG_SEPARATORS);
+
+ // ///////////////////////////
+ // TODO we need to remove the strong:[G/H] from the string, since some versions don't have it
+ // and key things differently
+ // ////////////////////////////
+
+ if (strongs == null) {
+ return;
+ }
+
+ // there is no way of know which strong goes with which morph, and we only
+ // have one phrase anyway
+ for (int ii = 0; ii < strongs.length; ii++) {
+ if (morphs != null && morphs.length != 0) {
+ for (int jj = 0; jj < morphs.length; jj++) {
+ addTextualInfo(verseReference, strongs[ii], morphs[jj], word);
+ }
+ } else {
+ addTextualInfo(verseReference, strongs[ii], null, word);
+ }
+ }
+ }
+
+ /**
+ * Finally, we have some information to add to this provider. We try and add it in an efficient fashion.
+ *
+ * So, how do we store this? The most meaningful piece of data is a STRONG number, since it identifies the word that
+ * we want to retrieve. Without the strong number, we don't have any information at all. Therefore, the first level
+ * of lookup should be by Strong number.
+ *
+ * Morphology-wise, each word might have a small number of options, so a linked list will do for this
+ *
+ * One would think that strong -> morph -> word will be unique. In the case of having just strong, we should use
+ * verse locality to maximise our chance of getting the right word (strong -> verse -> word)
+ *
+ * So in summary, we use: strong -> morph -> word strong -> verse -> list(word) (not unique)
+ *
+ * @param verseReference the verse reference that specifies locality (least important factor)
+ * @param strong the strong number (identifies the root/meaning of the word)
+ * @param morph the morphology (identifies how the used is word in the sentence - i.e. grammar)
+ * @param word the word to be stored
+ */
+ void addTextualInfo(final String verseReference, final String strong, final String morph, final String word) {
+
+ if (isNotBlank(strong) && isNotBlank(morph)) {
+ final DualKey<String, String> strongMorphKey = new DualKey<String, String>(strong, morph);
+ this.bestAccuracy.put(strongMorphKey, word);
+ }
+
+ final DualKey<String, String> strongVerseKey = new DualKey<String, String>(strong, verseReference);
+
+ List<String> verseKeyedStrongs = this.limitedAccuracy.get(strongVerseKey);
+ if (verseKeyedStrongs == null) {
+ verseKeyedStrongs = new ArrayList<String>();
+ this.limitedAccuracy.put(strongVerseKey, verseKeyedStrongs);
+ }
+ verseKeyedStrongs.add(word);
+
+ // finally add it to the worst accuracy - i.e. just based on strongs (could probably refactor)
+ this.worstAccuracy.put(strong, word);
+ }
+}
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 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/default.xsl 2010-11-15 20:23:39 UTC (rev 186)
@@ -49,6 +49,7 @@
but font does not. Therefore we use font as a span.
-->
<!-- gdef and hdef refer to hebrew and greek definitions keyed by strongs -->
+ <!-- The absolute base for relative references. -->
<xsl:param name="greek.def.protocol" select="'gdef:'"/>
<xsl:param name="hebrew.def.protocol" select="'hdef:'"/>
<xsl:param name="lex.def.protocol" select="'lex:'"/>
@@ -348,10 +349,10 @@
-->
<xsl:choose>
<xsl:when test="$TinyVNum = 'true' and $Notes = 'true'">
- <span class="w"><a name="{@osisID}"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></a></span>
+ <a name="{@osisID}"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></a>
</xsl:when>
<xsl:when test="$TinyVNum = 'true' and $Notes = 'false'">
- <span class="w"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></span>
+ <span class="verseNumber"><xsl:value-of select="$versenum"/></span>
</xsl:when>
<xsl:when test="$TinyVNum = 'false' and $Notes = 'true'">
<a name="{@osisID}">(<xsl:value-of select="$versenum"/>)</a>
@@ -459,33 +460,8 @@
<!--=======================================================================-->
<xsl:template match="w">
<!-- Output the content followed by all the lemmas and then all the morphs. -->
- <xsl:variable name="innerWordText"><xsl:apply-templates/></xsl:variable>
- <xsl:variable name="isNextSiblingText" select="following-sibling::*[1]/text() = ''" />
- <xsl:variable name="nextNodeCharClass" select="''" />
- <xsl:if test="following-sibling::*[1]/text() != ''">
- <xsl:variable name="nextNodeCharClass" select="'punctuNext'" />
- </xsl:if>
- <span class="w">
- <span class="text">
- <xsl:choose>
- <xsl:when test="not(normalize-space($innerWordText))"> </xsl:when>
- <xsl:otherwise><xsl:value-of select="$innerWordText" /></xsl:otherwise>
- </xsl:choose></span>
- <xsl:if test="$StrongsNumbers = 'true' and (starts-with(@lemma, 'x-Strongs:') or starts-with(@lemma, 'strong:'))">
- <xsl:call-template name="lemma">
- <xsl:with-param name="lemma" select="@lemma"/>
- </xsl:call-template>
- </xsl:if>
- <xsl:if test="$Morph = 'true' and (starts-with(@morph, 'x-Robinson:') or starts-with(@morph, 'robinson:'))">
- <xsl:call-template name="morph">
- <xsl:with-param name="morph" select="@morph"/>
- </xsl:call-template>
- </xsl:if>
- <xsl:if test="$StrongsNumbers = 'true' and starts-with(@lemma, 'lemma.Strong:')">
- <xsl:call-template name="lemma">
- <xsl:with-param name="lemma" select="@lemma"/>
- </xsl:call-template>
- </xsl:if>
+ <xsl:apply-templates/>
+
<!--
except when followed by a text node or non-printing node.
This is true whether the href is output or not.
@@ -495,22 +471,11 @@
<xsl:if test="$siblings[$next-position] and name($siblings[$next-position]) != ''">
<xsl:text> </xsl:text>
</xsl:if>
- </span>
</xsl:template>
<xsl:template match="w" mode="jesus">
<!-- Output the content followed by all the lemmas and then all the morphs. -->
<xsl:apply-templates mode="jesus"/>
- <xsl:if test="$StrongsNumbers = 'true' and (starts-with(@lemma, 'x-Strongs:') or starts-with(@lemma, 'strong:'))">
- <xsl:call-template name="lemma">
- <xsl:with-param name="lemma" select="@lemma"/>
- </xsl:call-template>
- </xsl:if>
- <xsl:if test="$Morph = 'true' and (starts-with(@morph, 'x-Robinson:') or starts-with(@morph, 'robinson:'))">
- <xsl:call-template name="morph">
- <xsl:with-param name="morph" select="@morph"/>
- </xsl:call-template>
- </xsl:if>
<!--
except when followed by a text node or non-printing node.
This is true whether the href is output or not.
@@ -522,135 +487,6 @@
</xsl:if>
</xsl:template>
- <xsl:template name="lemma">
- <xsl:param name="lemma"/>
- <xsl:param name="part" select="0"/>
- <xsl:param name="className" />
- <xsl:param name="finalText" />
-
- <xsl:variable name="orig-lemma" select="substring-after($lemma, ':')"/>
- <xsl:variable name="protocol">
- <xsl:choose>
- <xsl:when test="substring($orig-lemma, 1, 1) = 'H'">
- <xsl:value-of select="$hebrew.def.protocol"/>
- </xsl:when>
- <xsl:when test="substring($orig-lemma, 1, 1) = 'G'">
- <xsl:value-of select="$greek.def.protocol"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$lex.def.protocol"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="separator">
- <xsl:choose>
- <xsl:when test="contains($orig-lemma, '|') ">
- <xsl:value-of select="'|'"/>
- </xsl:when>
- <xsl:when test="contains($orig-lemma, ' ')">
- <xsl:value-of select="' '"/>
- </xsl:when>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="sub">
- <xsl:choose>
- <xsl:when test="$separator != '' and $part = '0'">
- <xsl:value-of select="$part + 1"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$part"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="$protocol = $lex.def.protocol">
- <font class="lex">[<xsl:value-of select="$orig-lemma"/>]</font>
- </xsl:when>
- <xsl:when test="$separator = ''">
- <span class="strongs {$className} {$orig-lemma}"><xsl:value-of select="concat($finalText, ' ', format-number(substring($orig-lemma, 2), '#'))" />
- </span>
- </xsl:when>
- <xsl:otherwise>
- <xsl:variable name="processedLemma" select="substring-before($orig-lemma, $separator)" />
- <xsl:call-template name="lemma">
- <xsl:with-param name="lemma" select="substring-after($lemma, $separator)"/>
- <xsl:with-param name="className" select="concat($className, $processedLemma)" />
- <xsl:with-param name="finalText" select="concat($finalText, ' ', format-number(substring($processedLemma,2),'#'))" />
- <xsl:with-param name="part">
- <xsl:choose>
- <xsl:when test="$sub">
- <xsl:value-of select="$sub + 1"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="1"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-
- <xsl:template name="morph">
- <xsl:param name="morph"/>
- <xsl:param name="part" select="0"/>
- <xsl:variable name="orig-work" select="substring-before($morph, ':')"/>
- <xsl:variable name="orig-morph" select="substring-after($morph, ':')"/>
- <xsl:variable name="protocol">
- <xsl:choose>
- <xsl:when test="starts-with($orig-work, 'x-Robinson') or starts-with($orig-work, 'robinson')">
- <xsl:value-of select="$greek.morph.protocol"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$hebrew.morph.protocol"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="separator">
- <xsl:choose>
- <xsl:when test="contains($orig-morph, '|')">
- <xsl:value-of select="'|'"/>
- </xsl:when>
- <xsl:when test="contains($orig-morph, ' ')">
- <xsl:value-of select="' '"/>
- </xsl:when>
- </xsl:choose>
- </xsl:variable>
- <xsl:variable name="sub">
- <xsl:choose>
- <xsl:when test="$separator != '' and $part = '0'">
- <xsl:value-of select="$part + 1"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="$part"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:variable>
- <xsl:choose>
- <xsl:when test="$separator = ''">
- <!-- <sub class="morph"><a href="{$protocol}{$orig-morph}">M<xsl:number level="any" from="/osis//verse" format="1"/><xsl:number value="$sub" format="a"/></a></sub> -->
- <sub class="morph"><a href="{$protocol}{$orig-morph}"><xsl:value-of select="$orig-morph"/></a></sub>
- </xsl:when>
- <xsl:otherwise>
- <!-- <sub class="morph"><a href="{$protocol}{substring-before($orig-morph, $separator)}">M<xsl:number level="single" from="/osis//verse" format="1"/><xsl:number value="$sub" format="a"/></a>, </sub> -->
- <sub class="morph"><a href="{$protocol}{substring-before($orig-morph, $separator)}"><xsl:value-of select="substring-before($orig-morph, $separator)"/></a>, </sub>
- <xsl:call-template name="morph">
- <xsl:with-param name="morph" select="substring-after($morph, $separator)"/>
- <xsl:with-param name="part">
- <xsl:choose>
- <xsl:when test="$sub">
- <xsl:value-of select="$sub + 1"/>
- </xsl:when>
- <xsl:otherwise>
- <xsl:value-of select="1"/>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:with-param>
- </xsl:call-template>
- </xsl:otherwise>
- </xsl:choose>
- </xsl:template>
-
<!--=======================================================================-->
<xsl:template match="seg">
<xsl:choose>
@@ -726,11 +562,11 @@
<!--=======================================================================-->
<xsl:template match="speaker[@who = 'Jesus']">
- <font class="jesus"><xsl:apply-templates mode="jesus"/></font>
+ <span class="jesus"><xsl:apply-templates mode="jesus"/></span>
</xsl:template>
<xsl:template match="speaker">
- <font class="speech"><xsl:apply-templates/></font>
+ <span class="speech"><xsl:apply-templates/></span>
</xsl:template>
<!--=======================================================================-->
@@ -985,7 +821,7 @@
<!-- While a BR is a break, if it is immediately followed by punctuation,
indenting this rule can introduce whitespace.
-->
- <xsl:template match="lb"><br/></xsl:template>
+ <xsl:template match="lb"><br /></xsl:template>
<xsl:template match="lb" mode="jesus"><br/></xsl:template>
<xsl:template match="list">
@@ -1150,23 +986,23 @@
</xsl:template>
<xsl:template match="q[@who = 'Jesus']">
- <font class="jesus"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></font>
+ <span class="jesus"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></span>
</xsl:template>
<xsl:template match="q[@type = 'blockquote']">
- <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></blockquote>
+ <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></span>
</xsl:template>
<xsl:template match="q[@type = 'blockquote']" mode="jesus">
- <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></blockquote>
+ <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></span>
</xsl:template>
<xsl:template match="q[@type = 'citation']">
- <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></blockquote>
+ <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></span>
</xsl:template>
<xsl:template match="q[@type = 'citation']" mode="jesus">
- <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></blockquote>
+ <span class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></span>
</xsl:template>
<xsl:template match="q[@type = 'embedded']">
@@ -1335,13 +1171,13 @@
<em><xsl:apply-templates/></em>
</xsl:when>
<xsl:when test="$style = 'line-through'">
- <font class="strike"><xsl:apply-templates/></font>
+ <span class="strike"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'normal'">
- <font class="normal"><xsl:apply-templates/></font>
+ <span class="normal"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'small-caps'">
- <font class="small-caps"><xsl:apply-templates/></font>
+ <span class="small-caps"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'sub'">
<sub><xsl:apply-templates/></sub>
@@ -1350,10 +1186,10 @@
<sup><xsl:apply-templates/></sup>
</xsl:when>
<xsl:when test="$style = 'underline'">
- <u><xsl:apply-templates/></u>
+ <span class="underline"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'x-caps'">
- <font class="caps"><xsl:apply-templates/></font>
+ <span class="caps"><xsl:apply-templates/></span>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
@@ -1389,13 +1225,13 @@
<em><xsl:apply-templates/></em>
</xsl:when>
<xsl:when test="$style = 'line-through'">
- <font class="strike"><xsl:apply-templates/></font>
+ <span class="strike"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'normal'">
- <font class="normal"><xsl:apply-templates/></font>
+ <span class="normal"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'small-caps'">
- <font class="small-caps"><xsl:apply-templates/></font>
+ <span class="small-caps"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'sub'">
<sub><xsl:apply-templates/></sub>
@@ -1404,10 +1240,10 @@
<sup><xsl:apply-templates/></sup>
</xsl:when>
<xsl:when test="$style = 'underline'">
- <u><xsl:apply-templates/></u>
+ <span class="underline"><xsl:apply-templates/></span>
</xsl:when>
<xsl:when test="$style = 'x-caps'">
- <font class="caps"><xsl:apply-templates/></font>
+ <span class="caps"><xsl:apply-templates/></span>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates/>
@@ -1473,16 +1309,6 @@
</xsl:if>
</xsl:template>
- <!-- If the parent of the text is a verse then, we need to wrap in span. This applies
- to any punctuation really, since all other words should be contained in a W -->
- <xsl:template match="text()">
- <xsl:choose>
- <xsl:when test="name(..) = 'verse' and normalize-space(.) != ''"><span class="w"><span class="text"><xsl:value-of select="."/></span></span></xsl:when>
- <xsl:when test="normalize-space(.) != ''"><xsl:value-of select="."/></xsl:when>
- </xsl:choose>
- </xsl:template>
-
-
<xsl:template match="text()" mode="small-caps">
<xsl:value-of select="translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
</xsl:template>
Added: 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 (rev 0)
+++ trunk/step/step-core/src/main/resources/com/tyndalehouse/step/core/service/impl/interlinear.xsl 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,1554 @@
+<?xml version="1.0"?>
+<!--
+ * Distribution License:
+ * JSword is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License, version 2.1 as published by
+ * the Free Software Foundation. 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 Lesser General Public License for more details.
+ *
+ * The License is available on the internet at:
+ * http://www.gnu.org/copyleft/lgpl.html
+ * or by writing to:
+ * Free Software Foundation, Inc.
+ * 59 Temple Place - Suite 330
+ * Boston, MA 02111-1307, USA
+ *
+ * Copyright: 2005
+ * The copyright to this program is held by it's authors.
+ *
+ * ID: $Id: default.xsl 1943 2009-03-25 11:43:28Z dmsmith $
+ -->
+ <!--
+ * Transforms OSIS to HTML for viewing within JSword browsers.
+ * Note: There are custom protocols which the browser must handle.
+ *
+ * @see gnu.lgpl.License for license details.
+ * The copyright to this program is held by it's authors.
+ * @author Joe Walker [joe at eireneh dot com]
+ * @author DM Smith [dmsmith555 at yahoo dot com]
+ * @author Chris Burrell [chris at burrell dot me dot uk]
+ -->
+ <xsl:stylesheet
+ xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
+ version="1.0"
+ xmlns:jsword="http://xml.apache.org/xalan/java"
+ extension-element-prefixes="jsword">
+
+ <!-- Version 3.0 is necessary to get br to work correctly. -->
+ <xsl:output method="html" version="3.0" omit-xml-declaration="yes" indent="no"/>
+
+ <!-- Be very careful about introducing whitespace into the document.
+ strip-space merely remove space between one tag and another tag.
+ This may cause significant whitespace to be removed.
+
+ It is easy to have apply-templates on a line to itself which if
+ it encounters text before anything else will introduce whitespace.
+ With the browser we are using, span will introduce whitespace
+ but font does not. Therefore we use font as a span.
+ -->
+ <!-- gdef and hdef refer to hebrew and greek definitions keyed by strongs -->
+ <xsl:param name="greek.def.protocol" select="'gdef:'"/>
+ <xsl:param name="hebrew.def.protocol" select="'hdef:'"/>
+ <xsl:param name="lex.def.protocol" select="'lex:'"/>
+ <!-- currently these are not used, but they are for morphologic forms -->
+ <xsl:param name="greek.morph.protocol" select="'gmorph:'"/>
+ <xsl:param name="hebrew.morph.protocol" select="'hmorph:'"/>
+
+ <!-- The absolute base for relative references. -->
+ <xsl:param name="baseURL" select="''"/>
+
+ <!-- Whether to show Strongs or not -->
+ <xsl:param name="StrongsNumbers" select="'false'"/>
+
+ <!-- Whether to show morphologic forms or not -->
+ <xsl:param name="Morph" select="'false'"/>
+
+ <!-- Whether to start each verse on an new line or not -->
+ <xsl:param name="VLine" select="'false'"/>
+
+ <!-- Whether to show non-canonical "headings" or not -->
+ <xsl:param name="Headings" select="'true'"/>
+
+ <!-- Whether to show notes or not -->
+ <xsl:param name="Notes" select="'false'"/>
+
+ <!-- Whether to have linking cross references or not -->
+ <xsl:param name="XRef" select="'false'"/>
+
+ <!-- Whether to output no Verse numbers -->
+ <xsl:param name="NoVNum" select="'false'"/>
+
+ <!-- Whether to output Verse numbers or not -->
+ <xsl:param name="VNum" select="'true'"/>
+
+ <!-- Whether to output Chapter and Verse numbers or not -->
+ <xsl:param name="CVNum" select="'false'"/>
+
+ <!-- Whether to output Book, Chapter and Verse numbers or not -->
+ <xsl:param name="BCVNum" select="'false'"/>
+
+ <!-- Whether to output superscript verse numbers or normal size ones -->
+ <xsl:param name="TinyVNum" select="'true'"/>
+
+ <!-- The order of display. Hebrew is rtl (right to left) -->
+ <xsl:param name="direction" select="'ltr'"/>
+
+ <!-- Whether to show an interlinear and the provider helping with the lookup -->
+ <xsl:param name="Interlinear" select="'false'" />
+ <xsl:param name="interlinearVersion" select="''" />
+ <xsl:param name="interlinearReference" select="''" />
+
+ <!-- Create a global key factory from which OSIS ids will be generated -->
+ <xsl:variable name="keyf" select="jsword:org.crosswire.jsword.passage.PassageKeyFactory.instance()"/>
+ <!-- Create a global number shaper that can transform 0-9 into other number systems. -->
+ <xsl:variable name="shaper" select="jsword:org.crosswire.common.icu.NumberShaper.new()"/>
+
+ <!-- set up interlinear provider, if we have requested it -->
+ <xsl:variable name="interlinearProvider" select="jsword:com.tyndalehouse.step.core.xsl.impl.InterlinearProviderImpl.new(string($interlinearVersion), string($interlinearReference))" />
+
+ <!--=======================================================================-->
+ <xsl:template match="/">
+ <div>
+ <!-- If there are notes, output a table with notes in the 2nd column. -->
+ <!-- There is a rendering bug which prevents the notes from adhering to the right edge. -->
+ <xsl:choose>
+ <xsl:when test="$Notes = 'true' and //note[not(@type = 'x-strongsMarkup')]">
+ <xsl:choose>
+ <xsl:when test="$direction != 'rtl'">
+ <table cols="2" cellpadding="5" cellspacing="5">
+ <tr>
+ <!-- The two rows are swapped until the bug is fixed. -->
+ <td valign="top" class="notes">
+ <p> </p>
+ <xsl:apply-templates select="//verse" mode="print-notes"/>
+ </td>
+ <td valign="top" class="text">
+ <xsl:apply-templates/>
+ </td>
+ </tr>
+ </table>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- reverse the table for Right to Left languages -->
+ <table cols="2" cellpadding="5" cellspacing="5">
+ <!-- In a right to left, the alignment should be reversed too -->
+ <tr align="right">
+ <td valign="top" class="notes">
+ <p> </p>
+ <xsl:apply-templates select="//note" mode="print-notes"/>
+ </td>
+ <td valign="top" class="text">
+ <xsl:apply-templates/>
+ </td>
+ </tr>
+ </table>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </div>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <!--
+ == A proper OSIS document has osis as its root.
+ == We dig deeper for its content.
+ -->
+ <xsl:template match="osis">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <!--
+ == An OSIS document may contain more that one work.
+ == Each work is held in an osisCorpus element.
+ == If there is only one work, then this element will (should) be absent.
+ == Process each document in turn.
+ == It might be reasonable to dig into the header element of each work
+ == and get its title.
+ == Otherwise, we ignore the header and work elements and just process
+ == the osisText elements.
+ -->
+ <xsl:template match="osisCorpus">
+ <xsl:apply-templates select="osisText"/>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <!--
+ == Each work has an osisText element.
+ == We ignore the header and work elements and process its div elements.
+ == While divs can be milestoned, the osisText element requires container
+ == divs.
+ -->
+ <xsl:template match="osisText">
+ <xsl:apply-templates select="div"/>
+ </xsl:template>
+
+ <!-- Ignore headers and its elements -->
+ <xsl:template match="header"/>
+ <xsl:template match="revisionDesc"/>
+ <xsl:template match="work"/>
+ <!-- <xsl:template match="title"/> who's parent is work -->
+ <xsl:template match="contributor"/>
+ <xsl:template match="creator"/>
+ <xsl:template match="subject"/>
+ <!-- <xsl:template match="date"/> who's parent is work -->
+ <xsl:template match="description"/>
+ <xsl:template match="publisher"/>
+ <xsl:template match="type"/>
+ <xsl:template match="format"/>
+ <xsl:template match="identifier"/>
+ <xsl:template match="source"/>
+ <xsl:template match="language"/>
+ <xsl:template match="relation"/>
+ <xsl:template match="coverage"/>
+ <xsl:template match="rights"/>
+ <xsl:template match="scope"/>
+ <xsl:template match="workPrefix"/>
+ <xsl:template match="castList"/>
+ <xsl:template match="castGroup"/>
+ <xsl:template match="castItem"/>
+ <xsl:template match="actor"/>
+ <xsl:template match="role"/>
+ <xsl:template match="roleDesc"/>
+ <xsl:template match="teiHeader"/>
+ <xsl:template match="refSystem"/>
+
+
+ <!-- Ignore titlePage -->
+ <xsl:template match="titlePage"/>
+
+ <!--=======================================================================-->
+ <!--
+ == Div provides the major containers for a work.
+ == Divs are milestoneable.
+ -->
+ <xsl:template match="div[@type='x-center']">
+ <div align="center">
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="div">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="div" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <!-- Handle verses as containers and as a start verse. -->
+ <xsl:template match="verse[not(@eID)]">
+ <!-- output each preverse element in turn -->
+ <xsl:for-each select=".//*[@subType = 'x-preverse' or @subtype = 'x-preverse']">
+ <xsl:choose>
+ <xsl:when test="local-name() = 'title'">
+ <!-- Always show canonical titles or if headings is turned on -->
+ <xsl:if test="@canonical = 'true' or $Headings = 'true'">
+ <h3 class="heading"><xsl:apply-templates /></h3>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates />
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ <!-- Handle the KJV paragraph marker. -->
+ <xsl:if test="milestone[@type = 'x-p']"><br/><br/></xsl:if>
+ <!-- If the verse doesn't start on its own line and -->
+ <!-- the verse is not the first verse of a set of siblings, -->
+ <!-- output an extra space. -->
+ <xsl:if test="$VLine = 'false' and preceding-sibling::*[local-name() = 'verse']">
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ <!-- Always output the verse -->
+ <xsl:choose>
+ <xsl:when test="$VLine = 'true'">
+ <div class="l"><a name="{@osisID}"><xsl:call-template name="versenum"/></a><xsl:apply-templates/></div>
+ </xsl:when>
+ <xsl:otherwise>
+ <span class="interlinear"><xsl:call-template name="versenum"/><xsl:apply-templates/></span>
+ <!-- Follow the verse with an extra space -->
+ <!-- when they don't start on lines to themselves -->
+ <xsl:text> </xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="verse[not(@eID)]" mode="jesus">
+ <!-- If the verse doesn't start on its own line and -->
+ <!-- the verse is not the first verse of a set of siblings, -->
+ <!-- output an extra space. -->
+ <xsl:if test="$VLine = 'false' and preceding-sibling::*[local-name() = 'verse']">
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ <xsl:variable name="title" select=".//title"/>
+ <xsl:if test="string-length($title) > 0">
+ <h3 class="heading"><xsl:value-of select="$title"/></h3>
+ </xsl:if>
+ <!-- Handle the KJV paragraph marker. -->
+ <xsl:if test="milestone[@type = 'x-p']"><br/><br/></xsl:if>
+ <!-- Always output the verse -->
+ <xsl:choose>
+ <xsl:when test="$VLine = 'true'">
+ <div class="l"><a name="{@osisID}"><xsl:call-template name="versenum"/></a><xsl:apply-templates mode="jesus"/></div>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:call-template name="versenum"/><xsl:apply-templates mode="jesus"/>
+ <!-- Follow the verse with an extra space -->
+ <!-- when they don't start on lines to themselves -->
+ <xsl:text> </xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="verse" mode="print-notes">
+ <xsl:if test=".//note[not(@type) or not(@type = 'x-strongsMarkup')]">
+ <xsl:variable name="passage" select="jsword:getValidKey($keyf, @osisID)"/>
+ <a href="#{substring-before(concat(@osisID, ' '), ' ')}">
+ <xsl:value-of select="jsword:getName($passage)"/>
+ </a>
+ <xsl:apply-templates select=".//note" mode="print-notes" />
+ <div><xsl:text> </xsl:text></div>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="versenum">
+ <!-- Are verse numbers wanted? -->
+ <xsl:if test="$NoVNum = 'false'">
+ <!-- An osisID can be a space separated list of them -->
+ <xsl:variable name="firstOsisID" select="substring-before(concat(@osisID, ' '), ' ')"/>
+ <xsl:variable name="book" select="substring-before($firstOsisID, '.')"/>
+ <xsl:variable name="chapter" select="jsword:shape($shaper, substring-before(substring-after($firstOsisID, '.'), '.'))"/>
+ <!-- If n is present use it for the number -->
+ <xsl:variable name="verse">
+ <xsl:choose>
+ <xsl:when test="@n">
+ <xsl:value-of select="jsword:shape($shaper, string(@n))"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="jsword:shape($shaper, substring-after(substring-after($firstOsisID, '.'), '.'))"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="versenum">
+ <xsl:choose>
+ <xsl:when test="$BCVNum = 'true'">
+ <xsl:variable name="passage" select="jsword:getValidKey($keyf, @osisID)"/>
+ <xsl:value-of select="jsword:getName($passage)"/>
+ </xsl:when>
+ <xsl:when test="$CVNum = 'true'">
+ <xsl:value-of select="concat($chapter, ' : ', $verse)"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$verse"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <!--
+ == Surround versenum with dup
+ -->
+ <xsl:choose>
+ <xsl:when test="$TinyVNum = 'true' and $Notes = 'true'">
+ <span class="w"><a name="{@osisID}"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></a></span>
+ </xsl:when>
+ <xsl:when test="$TinyVNum = 'true' and $Notes = 'false'">
+ <span class="w"><span class="verseNumber"><xsl:value-of select="$versenum"/></span></span>
+ </xsl:when>
+ <xsl:when test="$TinyVNum = 'false' and $Notes = 'true'">
+ <a name="{@osisID}">(<xsl:value-of select="$versenum"/>)</a>
+ <xsl:text> </xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ (<xsl:value-of select="$versenum"/>)
+ <xsl:text> </xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ <xsl:if test="$VNum = 'false' and $Notes = 'true'">
+ <a name="{@osisID}"></a>
+ </xsl:if>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="a">
+ <a href="{@href}"><xsl:apply-templates/></a>
+ </xsl:template>
+
+ <xsl:template match="a" mode="jesus">
+ <a href="{@href}"><xsl:apply-templates mode="jesus"/></a>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <!-- When we encounter a note, we merely output a link to the note. -->
+ <xsl:template match="note[@type = 'x-strongsMarkup']"/>
+ <xsl:template match="note[@type = 'x-strongsMarkup']" mode="jesus"/>
+ <xsl:template match="note[@type = 'x-strongsMarkup']" mode="print-notes"/>
+
+ <xsl:template match="note">
+ <xsl:if test="$Notes = 'true'">
+ <!-- If there is a following sibling that is a note, emit a separator -->
+ <xsl:variable name="siblings" select="../child::node()"/>
+ <xsl:variable name="next-position" select="position() + 1"/>
+ <xsl:choose>
+ <xsl:when test="name($siblings[$next-position]) = 'note'">
+ <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a>, </sup>
+ </xsl:when>
+ <xsl:otherwise>
+ <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a></sup>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="note" mode="jesus">
+ <xsl:if test="$Notes = 'true'">
+ <!-- If there is a following sibling that is a note, emit a separator -->
+ <xsl:variable name="siblings" select="../child::node()"/>
+ <xsl:variable name="next-position" select="position() + 1"/>
+ <xsl:choose>
+ <xsl:when test="$siblings[$next-position] and name($siblings[$next-position]) = 'note'">
+ <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a>, </sup>
+ </xsl:when>
+ <xsl:otherwise>
+ <sup class="note"><a href="#note-{generate-id(.)}"><xsl:call-template name="generateNoteXref"/></a></sup>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="note" mode="print-notes">
+ <div class="margin">
+ <strong><xsl:call-template name="generateNoteXref"/></strong>
+ <a name="note-{generate-id(.)}">
+ <xsl:text> </xsl:text>
+ </a>
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <!--
+ == If the n attribute is present then use that for the cross ref otherwise create a letter.
+ == Note: numbering restarts with each verse.
+ -->
+ <xsl:template name="generateNoteXref">
+ <xsl:choose>
+ <xsl:when test="@n">
+ <xsl:value-of select="@n"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:number level="any" from="/osis//verse" format="a"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="p">
+ <p><xsl:apply-templates/></p>
+ </xsl:template>
+
+ <xsl:template match="p" mode="jesus">
+ <p><xsl:apply-templates mode="jesus"/></p>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="p" mode="print-notes">
+ <!-- FIXME: This ignores text in the note. -->
+ <!-- don't put para's in notes -->
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="w">
+ <!-- Output the content followed by all the lemmas and then all the morphs. -->
+ <xsl:variable name="innerWordText"><xsl:apply-templates/></xsl:variable>
+ <xsl:variable name="isNextSiblingText" select="following-sibling::*[1]/text() = ''" />
+ <xsl:variable name="nextNodeCharClass" select="''" />
+ <xsl:if test="following-sibling::*[1]/text() != ''">
+ <xsl:variable name="nextNodeCharClass" select="'punctuNext'" />
+ </xsl:if>
+ <span class="w">
+ <span class="text">
+ <xsl:choose>
+ <xsl:when test="not(normalize-space($innerWordText))"> </xsl:when>
+ <xsl:otherwise><xsl:value-of select="$innerWordText" /></xsl:otherwise>
+ </xsl:choose></span>
+ <xsl:if test="$StrongsNumbers = 'true' and (starts-with(@lemma, 'x-Strongs:') or starts-with(@lemma, 'strong:'))">
+ <xsl:call-template name="lemma">
+ <xsl:with-param name="lemma" select="@lemma"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="$Morph = 'true' and (starts-with(@morph, 'x-Robinson:') or starts-with(@morph, 'robinson:'))">
+ <xsl:call-template name="morph">
+ <xsl:with-param name="morph" select="@morph"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="$StrongsNumbers = 'true' and starts-with(@lemma, 'lemma.Strong:')">
+ <xsl:call-template name="lemma">
+ <xsl:with-param name="lemma" select="@lemma"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="$Interlinear = 'true'">
+ <xsl:call-template name="interlinear">
+ <xsl:with-param name="lemma" select="@lemma" />
+ <xsl:with-param name="morph" select="@morph" />
+ <xsl:with-param name="osisID" select="../@osisID" />
+ </xsl:call-template>
+ </xsl:if>
+
+ <!--
+ except when followed by a text node or non-printing node.
+ This is true whether the href is output or not.
+ -->
+ <xsl:variable name="siblings" select="../child::node()"/>
+ <xsl:variable name="next-position" select="position() + 1"/>
+ <xsl:if test="$siblings[$next-position] and name($siblings[$next-position]) != ''">
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </span>
+ </xsl:template>
+
+ <xsl:template match="w" mode="jesus">
+ <!-- Output the content followed by all the lemmas and then all the morphs. -->
+ <xsl:apply-templates mode="jesus"/>
+ <xsl:if test="$StrongsNumbers = 'true' and (starts-with(@lemma, 'x-Strongs:') or starts-with(@lemma, 'strong:'))">
+ <xsl:call-template name="lemma">
+ <xsl:with-param name="lemma" select="@lemma"/>
+ </xsl:call-template>
+ </xsl:if>
+ <xsl:if test="$Morph = 'true' and (starts-with(@morph, 'x-Robinson:') or starts-with(@morph, 'robinson:'))">
+ <xsl:call-template name="morph">
+ <xsl:with-param name="morph" select="@morph"/>
+ </xsl:call-template>
+ </xsl:if>
+ <!--
+ except when followed by a text node or non-printing node.
+ This is true whether the href is output or not.
+ -->
+ <xsl:variable name="siblings" select="../child::node()"/>
+ <xsl:variable name="next-position" select="position() + 1"/>
+ <xsl:if test="$siblings[$next-position] and name($siblings[$next-position]) != ''">
+ <xsl:text> </xsl:text>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template name="lemma">
+ <xsl:param name="lemma"/>
+ <xsl:param name="part" select="0"/>
+ <xsl:param name="className" />
+ <xsl:param name="finalText" />
+
+ <xsl:variable name="orig-lemma" select="substring-after($lemma, ':')"/>
+ <xsl:variable name="protocol">
+ <xsl:choose>
+ <xsl:when test="substring($orig-lemma, 1, 1) = 'H'">
+ <xsl:value-of select="$hebrew.def.protocol"/>
+ </xsl:when>
+ <xsl:when test="substring($orig-lemma, 1, 1) = 'G'">
+ <xsl:value-of select="$greek.def.protocol"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$lex.def.protocol"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="separator">
+ <xsl:choose>
+ <xsl:when test="contains($orig-lemma, '|') ">
+ <xsl:value-of select="'|'"/>
+ </xsl:when>
+ <xsl:when test="contains($orig-lemma, ' ')">
+ <xsl:value-of select="' '"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sub">
+ <xsl:choose>
+ <xsl:when test="$separator != '' and $part = '0'">
+ <xsl:value-of select="$part + 1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$part"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$protocol = $lex.def.protocol">
+ <font class="lex">[<xsl:value-of select="$orig-lemma"/>]</font>
+ </xsl:when>
+ <xsl:when test="$separator = ''">
+ <span class="strongs {$className} {$orig-lemma}"><xsl:value-of select="concat($finalText, ' ', format-number(substring($orig-lemma, 2), '#'))" />
+ </span>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:variable name="processedLemma" select="substring-before($orig-lemma, $separator)" />
+ <xsl:call-template name="lemma">
+ <xsl:with-param name="lemma" select="substring-after($lemma, $separator)"/>
+ <xsl:with-param name="className" select="concat($className, $processedLemma)" />
+ <xsl:with-param name="finalText" select="concat($finalText, ' ', format-number(substring($processedLemma,2),'#'))" />
+ <xsl:with-param name="part">
+ <xsl:choose>
+ <xsl:when test="$sub">
+ <xsl:value-of select="$sub + 1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="1"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="morph">
+ <xsl:param name="morph"/>
+ <xsl:param name="part" select="0"/>
+ <xsl:variable name="orig-work" select="substring-before($morph, ':')"/>
+ <xsl:variable name="orig-morph" select="substring-after($morph, ':')"/>
+ <xsl:variable name="protocol">
+ <xsl:choose>
+ <xsl:when test="starts-with($orig-work, 'x-Robinson') or starts-with($orig-work, 'robinson')">
+ <xsl:value-of select="$greek.morph.protocol"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$hebrew.morph.protocol"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="separator">
+ <xsl:choose>
+ <xsl:when test="contains($orig-morph, '|')">
+ <xsl:value-of select="'|'"/>
+ </xsl:when>
+ <xsl:when test="contains($orig-morph, ' ')">
+ <xsl:value-of select="' '"/>
+ </xsl:when>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="sub">
+ <xsl:choose>
+ <xsl:when test="$separator != '' and $part = '0'">
+ <xsl:value-of select="$part + 1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$part"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$separator = ''">
+ <!-- <sub class="morph"><a href="{$protocol}{$orig-morph}">M<xsl:number level="any" from="/osis//verse" format="1"/><xsl:number value="$sub" format="a"/></a></sub> -->
+ <sub class="morph"><a href="{$protocol}{$orig-morph}"><xsl:value-of select="$orig-morph"/></a></sub>
+ </xsl:when>
+ <xsl:otherwise>
+ <!-- <sub class="morph"><a href="{$protocol}{substring-before($orig-morph, $separator)}">M<xsl:number level="single" from="/osis//verse" format="1"/><xsl:number value="$sub" format="a"/></a>, </sub> -->
+ <sub class="morph"><a href="{$protocol}{substring-before($orig-morph, $separator)}"><xsl:value-of select="substring-before($orig-morph, $separator)"/></a>, </sub>
+ <xsl:call-template name="morph">
+ <xsl:with-param name="morph" select="substring-after($morph, $separator)"/>
+ <xsl:with-param name="part">
+ <xsl:choose>
+ <xsl:when test="$sub">
+ <xsl:value-of select="$sub + 1"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="1"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:with-param>
+ </xsl:call-template>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="interlinear">
+ <xsl:param name="lemma" select="''"/>
+ <xsl:param name="morph" select="''"/>
+ <xsl:param name="osisID" />
+ <xsl:variable name="interlinearWord" select="jsword:getWord($interlinearProvider, $osisID, $lemma, $morph)"/>
+ <xsl:choose>
+ <xsl:when test="normalize-space($interlinearWord) = ''" > </xsl:when>
+ <xsl:otherwise><span class="interlinearText"><xsl:value-of select="$interlinearWord"/></span></xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+
+ <!--=======================================================================-->
+ <xsl:template match="seg">
+ <xsl:choose>
+ <xsl:when test="starts-with(@type, 'color:')">
+ <font color="{substring-before(substring-after(@type, 'color: '), ';')}"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="starts-with(@type, 'font-size:')">
+ <font size="{substring-before(substring-after(@type, 'font-size: '), ';')}"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="@type = 'x-variant'">
+ <xsl:if test="@subType = 'x-class-1'">
+ <xsl:apply-templates/>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="seg" mode="jesus">
+ <xsl:choose>
+ <xsl:when test="starts-with(@type, 'color:')">
+ <font color="{substring-before(substring-after(@type, 'color: '), ';')}"><xsl:apply-templates mode="jesus"/></font>
+ </xsl:when>
+ <xsl:when test="starts-with(@type, 'font-size:')">
+ <font size="{substring-before(substring-after(@type, 'font-size: '), ';')}"><xsl:apply-templates mode="jesus"/></font>
+ </xsl:when>
+ <xsl:when test="@type = 'x-variant'">
+ <xsl:if test="@subType = 'x-class:1'">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:if>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <!-- expansion is OSIS, expan is TEI -->
+ <xsl:template match="abbr">
+ <font class="abbr">
+ <xsl:if test="@expansion">
+ <xsl:attribute name="title">
+ <xsl:value-of select="@expansion"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="@expan">
+ <xsl:attribute name="title">
+ <xsl:value-of select="@expan"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates/>
+ </font>
+ </xsl:template>
+
+ <xsl:template match="abbr" mode="jesus">
+ <font class="abbr">
+ <xsl:if test="@expansion">
+ <xsl:attribute name="title">
+ <xsl:value-of select="@expansion"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="@expan">
+ <xsl:attribute name="title">
+ <xsl:value-of select="@expan"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:apply-templates mode="jesus"/>
+ </font>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="speaker[@who = 'Jesus']">
+ <font class="jesus"><xsl:apply-templates mode="jesus"/></font>
+ </xsl:template>
+
+ <xsl:template match="speaker">
+ <font class="speech"><xsl:apply-templates/></font>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="title[@subType ='x-preverse' or @subtype = 'x-preverse']">
+ <!-- Done by a line in [verse]
+ <h3 class="heading">
+ <xsl:apply-templates/>
+ </h3>
+ -->
+ </xsl:template>
+
+ <xsl:template match="title[@subType ='x-preverse' or @subtype = 'x-preverse']" mode="jesus">
+ <!-- Done by a line in [verse]
+ <h3 class="heading">
+ <xsl:apply-templates/>
+ </h3>
+ -->
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="title[@level]">
+ <!-- Always show canonical titles or if headings is turned on -->
+ <xsl:if test="@canonical = 'true' or $Headings = 'true'">
+ <xsl:choose>
+ <xsl:when test="@level = '1'">
+ <h1 class="level"><xsl:apply-templates/></h1>
+ </xsl:when>
+ <xsl:when test="@level = '2'">
+ <h2 class="level"><xsl:apply-templates/></h2>
+ </xsl:when>
+ <xsl:when test="@level = '3'">
+ <h3 class="level"><xsl:apply-templates/></h3>
+ </xsl:when>
+ <xsl:when test="@level = '4'">
+ <h4 class="level"><xsl:apply-templates/></h4>
+ </xsl:when>
+ <xsl:when test="@level = '5'">
+ <h5 class="level"><xsl:apply-templates/></h5>
+ </xsl:when>
+ <xsl:otherwise>
+ <h6 class="level"><xsl:apply-templates/></h6>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="title[@level]" mode="jesus">
+ <!-- Always show canonical titles or if headings is turned on -->
+ <xsl:if test="@canonical = 'true' or $Headings = 'true'">
+ <xsl:choose>
+ <xsl:when test="@level = '1'">
+ <h1 class="level"><xsl:apply-templates/></h1>
+ </xsl:when>
+ <xsl:when test="@level = '2'">
+ <h2 class="level"><xsl:apply-templates/></h2>
+ </xsl:when>
+ <xsl:when test="@level = '3'">
+ <h3 class="level"><xsl:apply-templates/></h3>
+ </xsl:when>
+ <xsl:when test="@level = '4'">
+ <h4 class="level"><xsl:apply-templates/></h4>
+ </xsl:when>
+ <xsl:when test="@level = '5'">
+ <h5 class="level"><xsl:apply-templates/></h5>
+ </xsl:when>
+ <xsl:otherwise>
+ <h6 class="level"><xsl:apply-templates/></h6>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:if>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="title">
+ <!-- Always show canonical titles or if headings is turned on -->
+ <xsl:if test="@canonical = 'true' or $Headings = 'true'">
+ <h2 class="heading"><xsl:apply-templates/></h2>
+ </xsl:if>
+ </xsl:template>
+
+ <xsl:template match="title" mode="jesus">
+ <!-- Always show canonical titles or if headings is turned on -->
+ <xsl:if test="@canonical = 'true' or $Headings = 'true'">
+ <h2 class="heading"><xsl:apply-templates/></h2>
+ </xsl:if>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="reference">
+ <xsl:choose>
+ <xsl:when test="$XRef = 'true'">
+ <a href="bible://{@osisRef}"><xsl:apply-templates/></a>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="reference" mode="jesus">
+ <xsl:choose>
+ <xsl:when test="$XRef = 'true'">
+ <a href="bible://{@osisRef}"><xsl:apply-templates mode="jesus"/></a>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!--=======================================================================-->
+ <xsl:template match="caption">
+ <div class="caption"><xsl:apply-templates/></div>
+ </xsl:template>
+
+ <xsl:template match="caption" mode="jesus">
+ <div class="caption"><xsl:apply-templates/></div>
+ </xsl:template>
+
+ <xsl:template match="catchWord">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="catchWord" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <!--
+ <cell> is handled shortly after <table> below and thus does not appear
+ here.
+ -->
+
+ <xsl:template match="closer">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="closer" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <xsl:template match="date">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="date" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <xsl:template match="divineName">
+ <xsl:apply-templates mode="small-caps"/>
+ </xsl:template>
+
+ <xsl:template match="divineName" mode="jesus">
+ <xsl:apply-templates mode="small-caps"/>
+ </xsl:template>
+
+ <xsl:template match="figure">
+ <div class="figure">
+ <xsl:choose>
+ <xsl:when test="starts-with(@src, '/')">
+ <img src="{concat($baseURL, @src)}"/> <!-- FIXME: Not necessarily an image... -->
+ </xsl:when>
+ <xsl:otherwise>
+ <img src="{concat($baseURL, '/', @src)}"/> <!-- FIXME: Not necessarily an image... -->
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:apply-templates/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="figure" mode="jesus">
+ <div class="figure">
+ <xsl:choose>
+ <xsl:when test="starts-with(@src, '/')">
+ <img src="{concat($baseURL, @src)}"/> <!-- FIXME: Not necessarily an image... -->
+ </xsl:when>
+ <xsl:otherwise>
+ <img src="{concat($baseURL, '/', @src)}"/> <!-- FIXME: Not necessarily an image... -->
+ </xsl:otherwise>
+ </xsl:choose>
+ <xsl:apply-templates mode="jesus"/>
+ </div>
+ </xsl:template>
+
+ <xsl:template match="foreign">
+ <em class="foreign"><xsl:apply-templates/></em>
+ </xsl:template>
+
+ <xsl:template match="foreign" mode="jesus">
+ <em class="foreign"><xsl:apply-templates mode="jesus"/></em>
+ </xsl:template>
+
+ <!-- This is a subheading. -->
+ <xsl:template match="head//head">
+ <h5 class="head"><xsl:apply-templates/></h5>
+ </xsl:template>
+
+ <!-- This is a top-level heading. -->
+ <xsl:template match="head">
+ <h4 class="head"><xsl:apply-templates/></h4>
+ </xsl:template>
+
+ <xsl:template match="index">
+ <a name="index{@id}" class="index"/>
+ </xsl:template>
+
+ <xsl:template match="inscription">
+ <xsl:apply-templates mode="small-caps"/>
+ </xsl:template>
+
+ <xsl:template match="inscription" mode="jesus">
+ <xsl:apply-templates mode="small-caps"/>
+ </xsl:template>
+
+ <xsl:template match="item">
+ <li class="item"><xsl:apply-templates/></li>
+ </xsl:template>
+
+ <xsl:template match="item" mode="jesus">
+ <li class="item"><xsl:apply-templates mode="jesus"/></li>
+ </xsl:template>
+
+ <!--
+ <item> and <label> are covered by <list> below and so do not appear here.
+ -->
+
+ <xsl:template match="lg">
+ <div class="lg"><xsl:apply-templates/></div>
+ </xsl:template>
+
+ <xsl:template match="lg" mode="jesus">
+ <div class="lg"><xsl:apply-templates mode="jesus"/></div>
+ </xsl:template>
+
+ <xsl:template match="lg[@sID or @eID]"/>
+ <xsl:template match="lg[@sID or @eID]" mode="jesus"/>
+
+ <xsl:template match="l[@sID]"/>
+ <xsl:template match="l[@sID]" mode="jesus"/>
+
+ <xsl:template match="l[@eID]"><br/></xsl:template>
+ <xsl:template match="l[@eID]" mode="jesus"><br/></xsl:template>
+
+ <xsl:template match="l">
+ <xsl:apply-templates/><br/>
+ </xsl:template>
+
+ <xsl:template match="l" mode="jesus">
+ <xsl:apply-templates mode="jesus"/><br/>
+ </xsl:template>
+
+ <!-- While a BR is a break, if it is immediately followed by punctuation,
+ indenting this rule can introduce whitespace.
+ -->
+ <xsl:template match="lb"><br/></xsl:template>
+ <xsl:template match="lb" mode="jesus"><br/></xsl:template>
+
+ <xsl:template match="list">
+ <xsl:choose>
+ <xsl:when test="label">
+ <!-- If there are <label>s in the list, it's a <dl>. -->
+ <dl class="list">
+ <xsl:for-each select="node()">
+ <xsl:choose>
+ <xsl:when test="self::label">
+ <dt class="label"><xsl:apply-templates/></dt>
+ </xsl:when>
+ <xsl:when test="self::item">
+ <dd class="item"><xsl:apply-templates/></dd>
+ </xsl:when>
+ <xsl:when test="self::list">
+ <dd class="list-wrapper"><xsl:apply-templates select="."/></dd>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </dl>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- If there are no <label>s in the list, it's a plain old <ul>. -->
+ <ul class="list">
+ <xsl:for-each select="node()">
+ <xsl:choose>
+ <xsl:when test="self::item">
+ <li class="item"><xsl:apply-templates/></li>
+ </xsl:when>
+ <xsl:when test="self::list">
+ <li class="list-wrapper"><xsl:apply-templates select="."/></li>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </ul>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+
+ <xsl:template match="list" mode="jesus">
+ <xsl:choose>
+ <xsl:when test="label">
+ <!-- If there are <label>s in the list, it's a <dl>. -->
+ <dl class="list">
+ <xsl:for-each select="node()">
+ <xsl:choose>
+ <xsl:when test="self::label">
+ <dt class="label"><xsl:apply-templates mode="jesus"/></dt>
+ </xsl:when>
+ <xsl:when test="self::item">
+ <dd class="item"><xsl:apply-templates mode="jesus"/></dd>
+ </xsl:when>
+ <xsl:when test="self::list">
+ <dd class="list-wrapper"><xsl:apply-templates select="." mode="jesus"/></dd>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </dl>
+ </xsl:when>
+
+ <xsl:otherwise>
+ <!-- If there are no <label>s in the list, it's a plain old <ul>. -->
+ <ul class="list">
+ <xsl:for-each select="node()">
+ <xsl:choose>
+ <xsl:when test="self::item">
+ <li class="item"><xsl:apply-templates mode="jesus"/></li>
+ </xsl:when>
+ <xsl:when test="self::list">
+ <li class="list-wrapper"><xsl:apply-templates select="." mode="jesus"/></li>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:for-each>
+ </ul>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="mentioned">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="mentioned" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <!-- Milestones represent characteristics of the original manuscript.
+ == that are being preserved. For this reason, most are ignored.
+ ==
+ == The defined types are:
+ == column Marks the end of a column where there is a multi-column display.
+ == footer Marks the footer region of a page.
+ == halfLine Used to mark half-line units if not otherwise encoded.
+ == header Marks the header region of a page.
+ == line Marks line breaks, particularly important in recording appearance of an original text, such as a manuscript.
+ == pb Marks a page break in a text.
+ == screen Marks a preferred place for breaks in an on-screen rendering of the text.
+ == 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 = 'cQuote']">
+ <xsl:value-of select="@marker"/>
+ </xsl:template>
+
+ <xsl:template match="milestone[@type = 'cQuote']" mode="jesus">
+ <xsl:value-of select="@marker"/>
+ </xsl:template>
+
+ <xsl:template match="milestone[@type = 'line']"><br/></xsl:template>
+
+ <xsl:template match="milestone[@type = 'line']" mode="jesus"><br/></xsl:template>
+
+ <!--
+ == Milestone start and end are deprecated.
+ == At this point we expect them to not be in the document.
+ == These have been replace with milestoneable elements.
+ -->
+ <xsl:template match="milestoneStart"/>
+ <xsl:template match="milestoneEnd"/>
+
+ <xsl:template match="name">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="name" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <!-- If there is a milestoned q then just output a quotation mark -->
+ <xsl:template match="q[@sID or @eID]">
+ <xsl:choose>
+ <xsl:when test="@marker"><xsl:value-of select="@marker"/></xsl:when>
+ <!-- The chosen mark should be based on the work's author's locale. -->
+ <xsl:otherwise>"</xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="q[@sID or @eID]" mode="jesus">
+ <xsl:choose>
+ <xsl:when test="@marker"><xsl:value-of select="@marker"/></xsl:when>
+ <!-- The chosen mark should be based on the work's author's locale. -->
+ <xsl:otherwise>"</xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="q[@who = 'Jesus']">
+ <font class="jesus"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></font>
+ </xsl:template>
+
+ <xsl:template match="q[@type = 'blockquote']">
+ <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></blockquote>
+ </xsl:template>
+
+ <xsl:template match="q[@type = 'blockquote']" mode="jesus">
+ <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></blockquote>
+ </xsl:template>
+
+ <xsl:template match="q[@type = 'citation']">
+ <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/></blockquote>
+ </xsl:template>
+
+ <xsl:template match="q[@type = 'citation']" mode="jesus">
+ <blockquote class="q"><xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/></blockquote>
+ </xsl:template>
+
+ <xsl:template match="q[@type = 'embedded']">
+ <xsl:choose>
+ <xsl:when test="@marker">
+ <xsl:value-of select="@marker"/><xsl:apply-templates/><xsl:value-of select="@marker"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <quote class="q"><xsl:apply-templates/></quote>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="q[@type = 'embedded']" mode="jesus">
+ <xsl:choose>
+ <xsl:when test="@marker">
+ <xsl:value-of select="@marker"/><xsl:apply-templates mode="jesus"/><xsl:value-of select="@marker"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <quote class="q"><xsl:apply-templates/></quote>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!-- An alternate reading. -->
+ <xsl:template match="rdg">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="rdg" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <!--
+ <row> is handled near <table> below and so does not appear here.
+ -->
+
+ <xsl:template match="salute">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <!-- Avoid adding whitespace -->
+ <xsl:template match="salute" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <xsl:template match="signed">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="signed" mode="jesus">
+ <xsl:apply-templates mode="jesus"/>
+ </xsl:template>
+
+ <xsl:template match="speech">
+ <div class="speech"><xsl:apply-templates/></div>
+ </xsl:template>
+
+ <xsl:template match="speech" mode="jesus">
+ <div class="speech"><xsl:apply-templates mode="jesus"/></div>
+ </xsl:template>
+
+ <xsl:template match="table">
+ <table class="table">
+ <xsl:copy-of select="@rows|@cols"/>
+ <xsl:if test="head">
+ <thead class="head"><xsl:apply-templates select="head"/></thead>
+ </xsl:if>
+ <tbody><xsl:apply-templates select="row"/></tbody>
+ </table>
+ </xsl:template>
+
+ <xsl:template match="row">
+ <tr class="row"><xsl:apply-templates/></tr>
+ </xsl:template>
+
+ <xsl:template match="cell">
+ <xsl:variable name="element-name">
+ <xsl:choose>
+ <xsl:when test="@role = 'label'">
+ <xsl:text>th</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:text>td</xsl:text>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:variable name="cell-direction">
+ <xsl:if test="@xml:lang">
+ <xsl:call-template name="getDirection">
+ <xsl:with-param name="lang"><xsl:value-of select="@xml:lang"/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:variable>
+ <xsl:element name="{$element-name}">
+ <xsl:attribute name="class">cell</xsl:attribute>
+ <xsl:attribute name="valign">top</xsl:attribute>
+ <xsl:if test="@xml:lang">
+ <xsl:attribute name="dir">
+ <xsl:value-of select="$cell-direction"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="$cell-direction = 'rtl'">
+ <xsl:attribute name="align">
+ <xsl:value-of select="'right'"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="@rows">
+ <xsl:attribute name="rowspan">
+ <xsl:value-of select="@rows"/>
+ </xsl:attribute>
+ </xsl:if>
+ <xsl:if test="@cols">
+ <xsl:attribute name="colspan">
+ <xsl:value-of select="@cols"/>
+ </xsl:attribute>
+ </xsl:if>
+ <!-- hack alert -->
+ <xsl:choose>
+ <xsl:when test="$cell-direction = 'rtl'">
+ <xsl:text>‫</xsl:text><xsl:apply-templates/><xsl:text>‬</xsl:text>
+ </xsl:when>
+ <xsl:when test="$cell-direction = 'ltr'">
+ <xsl:text>‪</xsl:text><xsl:apply-templates/><xsl:text>‬</xsl:text>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:element>
+ </xsl:template>
+
+ <xsl:template match="transChange">
+ <span><em><xsl:apply-templates/></em></span>
+ </xsl:template>
+ <xsl:template match="transChange" mode="jesus">
+ <span class="w"><em><xsl:apply-templates/></em></span>
+ </xsl:template>
+
+ <!-- @type is OSIS, @rend is TEI -->
+ <xsl:template match="hi">
+ <xsl:variable name="style">
+ <xsl:choose>
+ <xsl:when test="@type">
+ <xsl:value-of select="@type"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@rend"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$style = 'acrostic'">
+ <xsl:apply-templates/>
+ </xsl:when>
+ <xsl:when test="$style = 'bold'">
+ <strong><xsl:apply-templates/></strong>
+ </xsl:when>
+ <xsl:when test="$style = 'emphasis'">
+ <em><xsl:apply-templates/></em>
+ </xsl:when>
+ <xsl:when test="$style = 'illuminated'">
+ <strong><em><xsl:apply-templates/></em></strong>
+ </xsl:when>
+ <xsl:when test="$style = 'italic'">
+ <em><xsl:apply-templates/></em>
+ </xsl:when>
+ <xsl:when test="$style = 'line-through'">
+ <font class="strike"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="$style = 'normal'">
+ <font class="normal"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="$style = 'small-caps'">
+ <font class="small-caps"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="$style = 'sub'">
+ <sub><xsl:apply-templates/></sub>
+ </xsl:when>
+ <xsl:when test="$style = 'super'">
+ <sup><xsl:apply-templates/></sup>
+ </xsl:when>
+ <xsl:when test="$style = 'underline'">
+ <u><xsl:apply-templates/></u>
+ </xsl:when>
+ <xsl:when test="$style = 'x-caps'">
+ <font class="caps"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template match="hi" mode="jesus">
+ <xsl:variable name="style">
+ <xsl:choose>
+ <xsl:when test="@type">
+ <xsl:value-of select="@type"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="@rend"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:variable>
+ <xsl:choose>
+ <xsl:when test="$style = 'acrostic'">
+ <xsl:apply-templates/>
+ </xsl:when>
+ <xsl:when test="$style = 'bold'">
+ <strong><xsl:apply-templates/></strong>
+ </xsl:when>
+ <xsl:when test="$style = 'emphasis'">
+ <em><xsl:apply-templates/></em>
+ </xsl:when>
+ <xsl:when test="$style = 'illuminated'">
+ <strong><em><xsl:apply-templates/></em></strong>
+ </xsl:when>
+ <xsl:when test="$style = 'italic'">
+ <em><xsl:apply-templates/></em>
+ </xsl:when>
+ <xsl:when test="$style = 'line-through'">
+ <font class="strike"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="$style = 'normal'">
+ <font class="normal"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="$style = 'small-caps'">
+ <font class="small-caps"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:when test="$style = 'sub'">
+ <sub><xsl:apply-templates/></sub>
+ </xsl:when>
+ <xsl:when test="$style = 'super'">
+ <sup><xsl:apply-templates/></sup>
+ </xsl:when>
+ <xsl:when test="$style = 'underline'">
+ <u><xsl:apply-templates/></u>
+ </xsl:when>
+ <xsl:when test="$style = 'x-caps'">
+ <font class="caps"><xsl:apply-templates/></font>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:apply-templates/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <!--
+ The following elements are actually TEI and there is some expectation
+ that these will make it into OSIS.
+ -->
+ <xsl:template match="superentry">
+ <!-- output each preverse element in turn -->
+ <xsl:for-each select="entry|entryFree">
+ <xsl:apply-templates/><br/><br/>
+ </xsl:for-each>
+ </xsl:template>
+
+ <xsl:template match="entry">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="entryFree">
+ <xsl:apply-templates/>
+ </xsl:template>
+
+ <xsl:template match="form">
+ <xsl:apply-templates/><br/>
+ </xsl:template>
+
+ <xsl:template match="orth">
+ <font class="orth"><xsl:apply-templates/></font>
+ </xsl:template>
+
+ <xsl:template match="pron">
+ <font class="pron"><xsl:apply-templates/></font>
+ </xsl:template>
+
+ <xsl:template match="etym">
+ <font class="etym"><xsl:apply-templates/></font>
+ </xsl:template>
+
+ <xsl:template match="def">
+ <font class="def"><xsl:apply-templates/></font>
+ </xsl:template>
+
+ <xsl:template match="usg">
+ <font class="usg"><xsl:apply-templates/></font>
+ </xsl:template>
+
+ <xsl:template match="@xml:lang">
+ <xsl:variable name="dir">
+ <xsl:if test="@xml:lang">
+ <xsl:call-template name="getDirection">
+ <xsl:with-param name="lang"><xsl:value-of select="@xml:lang"/></xsl:with-param>
+ </xsl:call-template>
+ </xsl:if>
+ </xsl:variable>
+ <xsl:if test="$dir">
+ <xsl:attribute name="dir">
+ <xsl:value-of select="$dir"/>
+ </xsl:attribute>
+ </xsl:if>
+ </xsl:template>
+
+ <!-- If the parent of the text is a verse then, we need to wrap in span. This applies
+ to any punctuation really, since all other words should be contained in a W -->
+ <xsl:template match="text()">
+ <xsl:choose>
+ <xsl:when test="name(..) = 'verse' and normalize-space(.) != ''"><span class="w"><span class="text"><xsl:value-of select="."/></span></span></xsl:when>
+ <xsl:when test="normalize-space(.) != ''"><xsl:value-of select="."/></xsl:when>
+ </xsl:choose>
+ </xsl:template>
+
+
+ <xsl:template match="text()" mode="small-caps">
+ <xsl:value-of select="translate(., 'abcdefghijklmnopqrstuvwxyz', 'ABCDEFGHIJKLMNOPQRSTUVWXYZ')"/>
+ </xsl:template>
+
+ <!--
+ The direction is deduced from the xml:lang attribute and is assumed to be meaningful for those elements.
+ Note: there is a bug that prevents dir=rtl from working.
+ see: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4296022 and 4866977
+ -->
+ <xsl:template name="getDirection">
+ <xsl:param name="lang"/>
+ <xsl:choose>
+ <xsl:when test="$lang = 'he' or $lang = 'ar' or $lang = 'fa' or $lang = 'ur' or $lang = 'syr'">
+ <xsl:value-of select="'rtl'"/>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="'ltr'"/>
+ </xsl:otherwise>
+ </xsl:choose>
+ </xsl:template>
+
+ <xsl:template name="string-replace-all">
+ <xsl:param name="text" />
+ <xsl:param name="replace" />
+ <xsl:param name="by" />
+ <xsl:choose>
+ <xsl:when test="contains($text, $replace)">
+ <xsl:value-of select="substring-before($text,$replace)" />
+ <xsl:value-of select="$by" />
+ <xsl:call-template name="string-replace-all">
+ <xsl:with-param name="text" select="substring-after($text,$replace)" />
+ <xsl:with-param name="replace" select="$replace" />
+ <xsl:with-param name="by" select="$by" />
+ </xsl:call-template>
+ </xsl:when>
+ <xsl:otherwise>
+ <xsl:value-of select="$text" />
+ </xsl:otherwise>
+ </xsl:choose>
+</xsl:template>
+</xsl:stylesheet>
Added: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java (rev 0)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/service/JSwordServiceImplTest.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,87 @@
+package com.tyndalehouse.step.core.service;
+
+import static com.tyndalehouse.step.core.models.LookupOption.INTERLINEAR;
+
+import java.io.StringReader;
+import java.util.ArrayList;
+
+import org.crosswire.jsword.book.Book;
+import org.crosswire.jsword.book.BookData;
+import org.crosswire.jsword.book.Books;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.Format;
+import org.jdom.output.XMLOutputter;
+import org.junit.Assert;
+import org.junit.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.tyndalehouse.step.core.models.LookupOption;
+import com.tyndalehouse.step.core.service.impl.JSwordServiceImpl;
+
+/**
+ * a service providing a wrapper around JSword
+ *
+ * @author CJBurrell
+ *
+ */
+public class JSwordServiceImplTest {
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ /**
+ * tests what happens when we select interlinear
+ *
+ * @throws Exception an uncaught exception
+ */
+ @Test
+ public void testInterlinearTransformation() throws Exception {
+ final Book currentBook = Books.installed().getBook("esv");
+ final BookData bookData = new BookData(currentBook, currentBook.getKey("Romans 1"));
+ final Element osisFragment = bookData.getOsisFragment();
+
+ final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
+ this.logger.debug(xmlOutputter.outputString(osisFragment));
+
+ // do the test
+ final JSwordServiceImpl jsi = new JSwordServiceImpl();
+ final ArrayList<LookupOption> options = new ArrayList<LookupOption>();
+ options.add(INTERLINEAR);
+
+ final String osisText = jsi.getOsisText("KJV", "Romans 1:4", options, "");
+ final SAXBuilder sb = new SAXBuilder();
+ final Document d = sb.build(new StringReader(osisText));
+
+ this.logger.debug("\n {}", xmlOutputter.outputString(d));
+ Assert.assertTrue(osisText.contains("<span>"));
+
+ }
+
+ /**
+ * tests that the XSLT transformation is handled correctly
+ *
+ * @throws Exception uncaught exception
+ */
+ @Test
+ public void testXslTransformation() throws Exception {
+ final Book currentBook = Books.installed().getBook("KJV");
+ final BookData bookData = new BookData(currentBook, currentBook.getKey("Romans 1:4"));
+ final Element osisFragment = bookData.getOsisFragment();
+
+ final XMLOutputter xmlOutputter = new XMLOutputter(Format.getPrettyFormat());
+ this.logger.debug(xmlOutputter.outputString(osisFragment));
+
+ // do the test
+ final JSwordServiceImpl jsi = new JSwordServiceImpl();
+ final ArrayList<LookupOption> options = new ArrayList<LookupOption>();
+ options.add(LookupOption.STRONG_NUMBERS);
+
+ final String osisText = jsi.getOsisText("KJV", "Romans 1:4", options, "");
+ final SAXBuilder sb = new SAXBuilder();
+ final Document d = sb.build(new StringReader(osisText));
+
+ this.logger.debug("\n {}", xmlOutputter.outputString(d));
+ Assert.assertTrue(osisText.contains("<span>"));
+ }
+}
Added: trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java
===================================================================
--- trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java (rev 0)
+++ trunk/step/step-core/src/test/java/com/tyndalehouse/step/core/xsl/impl/InterlinearProviderImplTest.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,26 @@
+package com.tyndalehouse.step.core.xsl.impl;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+
+public class InterlinearProviderImplTest {
+ /**
+ * this checks that when keyed with strong, morph and verse number, we can retrieve the word. We should be able to
+ * retrieve by (strong,morph), regardless of verse number. We should also be able to retrieve by (strong,verse
+ * number)
+ */
+ @Test
+ public void testInterlinearStrongMorphBased() {
+ final InterlinearProviderImpl interlinear = new InterlinearProviderImpl();
+
+ // add a word based on a strong,morph
+ interlinear.addTextualInfo("v1", "strong", "morph", "word");
+
+ assertEquals(interlinear.getWord("v1", "strong", "morph"), "word");
+ assertEquals(interlinear.getWord("x", "strong", "morph"), "word");
+ assertEquals(interlinear.getWord("x", "strong", ""), "word");
+ assertEquals(interlinear.getWord("x", "strong", null), "word");
+ assertEquals(interlinear.getWord("x", "strong"), "word");
+ }
+}
Modified: trunk/step/step-parent/pom.xml
===================================================================
--- trunk/step/step-parent/pom.xml 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-parent/pom.xml 2010-11-15 20:23:39 UTC (rev 186)
@@ -26,6 +26,7 @@
<servlet-api.version>2.5</servlet-api.version>
<jsp-api.version>2.1</jsp-api.version>
<jstl.version>1.2</jstl.version>
+ <pjl-comp-filter.version>1.6.4</pjl-comp-filter.version>
<!-- Commons -->
<commons-beanutils.version>1.8.3</commons-beanutils.version>
@@ -131,6 +132,11 @@
<artifactId>jstl</artifactId>
<version>${jstl.version}</version>
</dependency>
+ <dependency>
+ <groupId>net.sourceforge.pjl-comp-filter</groupId>
+ <artifactId>pjl-comp-filter</artifactId>
+ <version>${pjl-comp-filter.version}</version>
+ </dependency>
<dependency>
<groupId>commons-beanutils</groupId>
Modified: trunk/step/step-web/pom.xml
===================================================================
--- trunk/step/step-web/pom.xml 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/pom.xml 2010-11-15 20:23:39 UTC (rev 186)
@@ -64,6 +64,10 @@
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
+ <dependency>
+ <groupId>net.sourceforge.pjl-comp-filter</groupId>
+ <artifactId>pjl-comp-filter</artifactId>
+ </dependency>
<dependency>
<groupId>junit</groupId>
Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/JsonExceptionResolver.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,24 @@
+package com.tyndalehouse.step.rest;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.servlet.HandlerExceptionResolver;
+import org.springframework.web.servlet.ModelAndView;
+
+public class JsonExceptionResolver implements HandlerExceptionResolver {
+ private final Logger logger = LoggerFactory.getLogger(getClass());
+
+ public ModelAndView resolveException(final HttpServletRequest request, final HttpServletResponse response,
+ final Object handler, final Exception exception) {
+
+ this.logger.error(exception.getMessage(), exception);
+
+ final ModelAndView mav = new ModelAndView();
+ mav.setViewName("MappingJacksonJsonView");
+ mav.addObject("error", exception.getMessage());
+ return mav;
+ }
+}
Modified: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/controllers/BibleController.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -1,10 +1,13 @@
package com.tyndalehouse.step.rest.controllers;
+import static org.apache.commons.lang.StringUtils.isNotBlank;
+
import java.util.ArrayList;
import java.util.List;
-import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
@@ -16,12 +19,14 @@
import com.tyndalehouse.step.core.models.EnrichedLookupOption;
import com.tyndalehouse.step.core.models.LookupOption;
import com.tyndalehouse.step.core.service.BibleInformationService;
+import com.tyndalehouse.step.rest.wrappers.HtmlWrapper;
@RequestMapping(value = "/bible", method = RequestMethod.GET)
@Controller
public class BibleController {
@Autowired
private BibleInformationService bibleInformation;
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
/**
* a REST method that returns version of the Bible that are available
@@ -35,7 +40,7 @@
}
/**
- * a REST method that returns
+ * a REST method that returns text from the Bible
*
* @param version the initials identifying the version
* @param reference the reference to lookup
@@ -43,11 +48,25 @@
*/
@RequestMapping(value = "/text/{version}/{reference}")
public @ResponseBody
- String getBibleText(@PathVariable final String version, @PathVariable final String reference) {
- return getBibleText(version, reference, null);
+ HtmlWrapper getBibleText(@PathVariable final String version, @PathVariable final String reference) {
+ return getBibleText(version, reference, null, null);
}
/**
+ * a REST method that returns text from the Bible
+ *
+ * @param version the initials identifying the version
+ * @param reference the reference to lookup
+ * @return the text to be displayed, formatted as HTML
+ */
+ @RequestMapping(value = "/text/{version}/{reference}/{options}")
+ public @ResponseBody
+ HtmlWrapper getBibleText(@PathVariable final String version, @PathVariable final String reference,
+ @PathVariable final String options) {
+ return getBibleText(version, reference, options, null);
+ }
+
+ /**
* a REST method that returns
*
* @param version the initials identifying the version
@@ -55,15 +74,15 @@
* @param options a list of options to be passed in
* @return the text to be displayed, formatted as HTML
*/
- @RequestMapping(value = "/text/{version}/{reference}/{options}")
+ @RequestMapping(value = "/text/{version}/{reference}/{options}/{interlinearVersion}")
public @ResponseBody
- String getBibleText(@PathVariable final String version, @PathVariable final String reference,
- @PathVariable final String options) {
+ HtmlWrapper getBibleText(@PathVariable final String version, @PathVariable final String reference,
+ @PathVariable final String options, @PathVariable final String interlinearVersion) {
Validate.notEmpty(version, "You need to provide a version");
Validate.notEmpty(reference, "You need to provide a reference");
String[] userOptions = null;
- if (StringUtils.isNotBlank(options)) {
+ if (isNotBlank(options)) {
userOptions = options.split(",");
}
@@ -74,7 +93,8 @@
}
}
- return this.bibleInformation.getPassageText(version, reference, lookupOptions);
+ return new HtmlWrapper(this.bibleInformation.getPassageText(version, reference, lookupOptions,
+ interlinearVersion));
}
/**
Added: trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java
===================================================================
--- trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java (rev 0)
+++ trunk/step/step-web/src/main/java/com/tyndalehouse/step/rest/wrappers/HtmlWrapper.java 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,13 @@
+package com.tyndalehouse.step.rest.wrappers;
+
+public class HtmlWrapper {
+ final String value;
+
+ public HtmlWrapper(final String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return this.value;
+ }
+}
Modified: trunk/step/step-web/src/main/webapp/WEB-INF/mvc-config.xml
===================================================================
--- trunk/step/step-web/src/main/webapp/WEB-INF/mvc-config.xml 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/WEB-INF/mvc-config.xml 2010-11-15 20:23:39 UTC (rev 186)
@@ -21,10 +21,21 @@
<!-- Saves a locale change using a cookie -->
<bean id="localeResolver" class="org.springframework.web.servlet.i18n.CookieLocaleResolver" />
- <!-- Resolves view names to protected .jsp resources within the /WEB-INF/views directory -->
- <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
- <property name="prefix" value="/WEB-INF/views/"/>
- <property name="suffix" value=".jsp"/>
+ <!-- Handle exceptions neatly -->
+ <bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
+ <property name="mediaTypes">
+ <map>
+ <entry key="json" value="application/json" />
+ </map>
+ </property>
+ <property name="defaultContentType" value="application/json" />
+ <property name="defaultViews">
+ <list>
+ <bean name="MappingJacksonJsonView" class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />
+ </list>
+ </property>
</bean>
+
+ <bean id="exceptionResolver" class="com.tyndalehouse.step.rest.JsonExceptionResolver" />
</beans>
Modified: trunk/step/step-web/src/main/webapp/WEB-INF/web.xml
===================================================================
--- trunk/step/step-web/src/main/webapp/WEB-INF/web.xml 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/WEB-INF/web.xml 2010-11-15 20:23:39 UTC (rev 186)
@@ -5,18 +5,44 @@
<web-app>
<display-name>STEP :: Scripture Tools for Every Pastor</display-name>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath*:com/tyndalehouse/step/**/config/*-applicationContext.xml</param-value>
- </context-param>
-
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
+ <context-param>
+ <param-name>contextConfigLocation</param-name>
+ <param-value>classpath*:com/tyndalehouse/step/**/config/*-applicationContext.xml</param-value>
+ </context-param>
+ <filter>
+ <filter-name>requestEncodingFilter</filter-name>
+ <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
+ <init-param>
+ <param-name>encoding</param-name>
+ <param-value>UTF-8</param-value>
+ </init-param>
+ <init-param>
+ <param-name>forceEncoding</param-name>
+ <param-value>true</param-value>
+ </init-param>
+ </filter>
+ <filter>
+ <filter-name>CompressingFilter</filter-name>
+ <filter-class>com.planetj.servlet.filter.compression.CompressingFilter</filter-class>
+ </filter>
+ <!-- don't need to do all the time TODO -->
+ <filter-mapping>
+ <filter-name>requestEncodingFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ <filter-mapping>
+ <filter-name>CompressingFilter</filter-name>
+ <url-pattern>/*</url-pattern>
+ </filter-mapping>
+ <listener>
+ <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
+ </listener>
+
+
<!-- Spring context Configuration Begins -->
-
+
<servlet>
<servlet-name>step-rest</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
@@ -24,10 +50,11 @@
</servlet>
<servlet-mapping>
- <servlet-name>step-rest</servlet-name>
- <url-pattern>/rest/*</url-pattern>
+ <servlet-name>step-rest</servlet-name>
+ <url-pattern>/rest/*</url-pattern>
</servlet-mapping>
+
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
Modified: trunk/step/step-web/src/main/webapp/css/initial-layout.css
===================================================================
--- trunk/step/step-web/src/main/webapp/css/initial-layout.css 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/css/initial-layout.css 2010-11-15 20:23:39 UTC (rev 186)
@@ -35,6 +35,7 @@
.passageContainer {
text-align: center;
+ padding-botom: 5px;
}
.passageVersion {
@@ -59,4 +60,15 @@
color: grey;
}
+#loading {
+ margin-top: 3px;
+ display: none;
+ z-index: 9999; /** always on top */
+}
+#error {
+ padding-top: 2px;
+ padding-left: 1px;
+ margin: 0px;
+}
+
Modified: trunk/step/step-web/src/main/webapp/css/passage.css
===================================================================
--- trunk/step/step-web/src/main/webapp/css/passage.css 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/css/passage.css 2010-11-15 20:23:39 UTC (rev 186)
@@ -1,13 +1,14 @@
.passageText {
+ margin-top: 1px;
overflow: auto;
- height: 100%;
+ height: 96%;
position: relative;
text-align: left;
}
/** Some interlinear rules */
/* Define the nature of a "word" */
-span.verse span { /* Make each word follow the other */
+span.interlinear span { /* Make each word follow the other */
float: left;
/* Make sure that there is spacing between words */
/* And extra spacing between lines */
@@ -16,7 +17,7 @@
}
/* Make the different views of a word stack. */
-span.verse span span { /* Make this stack on top of each other. */
+span.interlinear span span { /* Make this stack on top of each other. */
display: block;
/* Turn off floating and padding that was added by the previous rule. */
float: none;
@@ -24,16 +25,21 @@
}
/* Allow for spans to be nested more deeply */
-span.verse span span span {
+span.interlinear span span span {
/* Turn off block display that was added by the previous rule. */
display: inline;
}
-span.verseNumber {
- text-align: super;
- font-size: x-small;
+.verseNumber {
+ vertical-align: top;
+ font-size: 6pt;
+ padding-right: 2px;
}
+br.paragraph {
+ padding-top: 2px;
+}
+
A {
text-decoration: none;
}
@@ -72,36 +78,31 @@
color: red;
}
-FONT.jesus {
+span.jesus {
color: red;
}
-FONT.speech {
+span.speech {
color: blue;
}
-FONT.strike {
+span.strike {
text-decoration: line-through;
}
-FONT.small-caps {
+span.small-caps {
font-variant: small-caps;
}
-FONT.inscription {
- font-weight: bold;
- font-variant: small-caps;
+span.underline {
+ text-decoration: underline;
}
-FONT.divineName {
- font-variant: small-caps;
-}
-
-FONT.normal {
+span.normal {
font-variant: normal;
}
-FONT.caps {
+span.caps {
text-transform: uppercase;
}
@@ -163,9 +164,9 @@
width: 80%;
}
--->
-<!--
-the following are for dictionary entries -->FONT.orth {
+
+/* the following are for dictionary entries */
+FONT.orth {
font-weight: bold;
}
@@ -179,4 +180,4 @@
FONT.usg {
font-style: plain;
-}
\ No newline at end of file
+}
Modified: trunk/step/step-web/src/main/webapp/css/ui-layout/layout-default.css
===================================================================
--- trunk/step/step-web/src/main/webapp/css/ui-layout/layout-default.css 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/css/ui-layout/layout-default.css 2010-11-15 20:23:39 UTC (rev 186)
@@ -14,20 +14,6 @@
* NOTE: For best code readability, view this with a fixed-space font and tabs equal to 4-chars
*/
/*
-* BASIC PAGE COSMETICS
-*/
-/*
-body {
- font-family: Lucida Grande, Lucida Sans, Geneva, Arial, Helvetica, sans-serif;
- font-size: 100%;
- *font-size: 80%;
- background-color: #EEE;
-}
-p {
- margin: 1em 0;
-}
-*/
-/*
* PANES
*/
.ui-layout-pane { /* all 'panes' */
@@ -129,13 +115,8 @@
display: none;
}
-/*
- * style the text we put INSIDE the east/west togglers
- */
.ui-layout-toggler .content {
- /* font-size: 12px; */
font-weight: bold;
color: #666;
padding-bottom: 0.35ex;
- /* to 'vertically center' text inside text-span */
}
Added: trunk/step/step-web/src/main/webapp/images/wait16.gif
===================================================================
(Binary files differ)
Property changes on: trunk/step/step-web/src/main/webapp/images/wait16.gif
___________________________________________________________________
Added: svn:mime-type
+ application/octet-stream
Modified: trunk/step/step-web/src/main/webapp/index.jsp
===================================================================
--- trunk/step/step-web/src/main/webapp/index.jsp 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/index.jsp 2010-11-15 20:23:39 UTC (rev 186)
@@ -54,6 +54,10 @@
<div class="passageText ui-widget"></div>
</div>
+
+<div id="loading"><img alt="Loading..." src="images/wait16.gif" />Loading...</div>
+<div id="error" class="ui-state-highlight">A placeholder for error messages</div>
+
</body>
</HTML>
Added: trunk/step/step-web/src/main/webapp/js/bookmark.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/bookmark.js (rev 0)
+++ trunk/step/step-web/src/main/webapp/js/bookmark.js 2010-11-15 20:23:39 UTC (rev 186)
@@ -0,0 +1,8 @@
+
+/**
+ * The bookmarks components record events that are happening across the application,
+ * for e.g. passage changes, but will also show related information to the passage.
+ */
+function Bookmark() {
+ //TODO
+}
\ No newline at end of file
Modified: trunk/step/step-web/src/main/webapp/js/init.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/init.js 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/js/init.js 2010-11-15 20:23:39 UTC (rev 186)
@@ -4,6 +4,7 @@
function init() {
$(document).ready(function() {
initLayout();
+ initGlobalHandlers();
initDefaultValues();
initData();
});
@@ -21,11 +22,17 @@
autoResize : true, // try to maintain pane-percentages
autoReopen : true, // auto-open panes that were previously
autoBindCustomButtons : true,
+ north__paneSelector: '#error',
west__paneSelector : '.leftPassage',
center__paneSelector : '.bookmarks',
east__paneSelector : '.rightPassage',
west__size : .45, // percentage size expresses as a decimal
east__size : .45,
+ north__minSize : 0,
+ north__size: 20,
+ north__spacing_open : 0,
+ north__spacing_closed : 0,
+ north__initClosed: true,
minSize : 130,
noRoomToOpenAction : "hide"
});
@@ -50,20 +57,24 @@
});
}
-var nonIDedInputs = 0;
function initDefaultValues() {
- $("input.defaultValue").addClass("inactive");
+ addDefaultValue($("input.defaultValue"));
+}
+var nonIDedInputs = 0;
+function addDefaultValue(inputSelector) {
var default_values = new Array();
- $("input.defaultValue").focus(function() {
+ inputSelector.each(function(index) {
+ $(this).addClass("inactive");
if(this.id == "") {
this.id = nonIDedInputs++;
}
-
if (!default_values[this.id]) {
default_values[this.id] = this.value;
}
+ });
+ inputSelector.focus(function() {
if (this.value == default_values[this.id]) {
$(this).removeClass("inactive");
this.value = '';
@@ -76,8 +87,10 @@
}
});
});
+
}
+
function initData() {
//get all supported versions
var options;
@@ -89,21 +102,33 @@
//get data for passages
// make call to server first and once, to cache all passages:
+ var strongedVersions = [];
+ var ii = 0;
+
$.getJSON("rest/bible/versions", function(data) {
var parsedResponse = $.map(data, function(item) {
+ var showingText = "[" + item.initials + "] " + item.name;
+
+ //add to strongs if applicable
+ if(item.hasStrongs) {
+ strongedVersions[ii++] = { label: showingText, value: item.initials };
+ }
+
+ //return response for dropdowns
return {
- label : "[" + item.initials + "] " + item.name,
+ label : showingText,
value : item.initials
}
});
+
//set up initial passages with reference data:
- var versions = ["KJV" ];
- var passages = ["Romans 1:1-10"];
+ var versions = ["ESV" ];
+ var passages = ["Romans 1"];
$(".passageContainer").each(
function(index) {
var passage = new Passage(this, parsedResponse);
- var toolbar = new Toolbar(passage, options);
+ var toolbar = new Toolbar(passage, options, strongedVersions);
passage.setToolbar(toolbar);
if(index < versions.length) {
@@ -113,3 +138,36 @@
});
}
+function initGlobalHandlers() {
+ $("#loading").ajaxStart(function() {
+ $(this).show();
+ });
+
+ $("#loading").ajaxComplete(function() {
+ $(this).hide();
+ });
+
+ //set always visible - should probably be its own class
+ $( "#loading" ).position({
+ of: $( "body" ),
+ my: "top",
+ at: "top",
+ collision: "fit"
+ });
+
+ $("#error").click(function() {
+ $('body').layout().close("north");
+ });
+
+ $("#error").ajaxComplete(function(ev, req, ajaxOptions) {
+ var currentResponse = $.parseJSON(req.responseText);
+ if(currentResponse.error) {
+ raiseError(currentResponse.error)
+ }
+ });
+}
+
+function raiseError(error) {
+ $("#error").text(error);
+ $('body').layout().open("north");
+}
Modified: trunk/step/step-web/src/main/webapp/js/passage.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/passage.js 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/js/passage.js 2010-11-15 20:23:39 UTC (rev 186)
@@ -31,15 +31,26 @@
this.version.autocomplete({
source : versions,
minLength : 0,
- select : function(event, ui) {
+ delay: 0,
+ select: function(event, ui) {
+ //force change?
+ $(this).val(ui.item.value);
+ self.reference.focus();
self.toolbar.refreshButtons(ui.item.value);
- self.changePassage();
- }
+
+ //we do not change the passage here, as we need to have refreshed the buttons
+ //so the refresh buttons will fire instead
+ return false;
+ },
+ }).focus(function() {
+ this.select();
});
//set up blur for textbox
- this.reference.blur(function(){
+ this.reference.change(function(){
self.changePassage();
+ }).focus(function() {
+ this.select();
});
}
@@ -48,19 +59,45 @@
* @param version the version passed in (optional - otherwise takes this.version)
* @param reference the reference to lookup (optional - otherwise takes this.reference)
*/
-Passage.prototype.changePassage = function(version, reference) {
- var newVersion = version ? version : (!this.version.hasClass("inactive") ? this.version.val() : null);
- var newReference = reference ? reference : (!this.reference.hasClass("inactive") ? this.reference.val() : null);
-
+Passage.prototype.changePassage = function(/* optional */ version, /* optional */reference) {
+ //if this was called from somewhere else, rather than as a reaction to an event,
+ //we change the values of the textboxes
+ if(version && this.version.val() != version) {
+ this.version.val(version);
+ this.version.removeClass("inactive");
+ this.toolbar.refreshButtons(version);
+ }
+
+ if(reference && this.reference.val() != reference) {
+ this.reference.val(reference);
+ this.reference.removeClass("inactive");
+ }
+
+ if(this.reference.hasClass("inactive") || this.version.hasClass("inactive")) {
+ raiseError("You need to provide both a version and a reference to lookup a passage");
+ return;
+ }
+
//now get the options from toolbar
var options = this.toolbar.getSelectedOptions();
+ var interlinearVersion = this.toolbar.getSelectedInterlinearVersion();
var self = this;
- if(newVersion && newReference && newVersion != "" && newReference != "") {
+ if(this.version.val() && this.reference.val() && this.version.val() != "" && this.reference.val() != "") {
+ var url = "rest/bible/text/" + this.version.val() + "/" + this.reference.val();
+
+ if(options && options.length != 0) {
+ url += "/" + options ;
+
+ if(interlinearVersion && interlinearVersion.length != 0) {
+ url += "/" + interlinearVersion;
+ }
+ }
+
//send to server
- $.get("rest/bible/text/" + newVersion + "/" + newReference + "/" + options, function (text) {
+ $.get(url, function (text) {
//we get html back, so we insert into passage:
- self.passage.html(text);
+ self.passage.html(text.value);
});
}
}
Modified: trunk/step/step-web/src/main/webapp/js/passage_toolbar.js
===================================================================
--- trunk/step/step-web/src/main/webapp/js/passage_toolbar.js 2010-11-07 17:30:58 UTC (rev 185)
+++ trunk/step/step-web/src/main/webapp/js/passage_toolbar.js 2010-11-15 20:23:39 UTC (rev 186)
@@ -5,7 +5,7 @@
*/
//static id
var toolbarId = 0;
-function Toolbar(passage, buttonOptions) {
+function Toolbar(passage, buttonOptions, strongedVersions) {
var self = this;
this.passage = passage;
@@ -15,6 +15,7 @@
$(passage.getPassageContainer()).prepend('<div class="toolbarContainer ui-widget-content ui-corner-all" />');
this.toolbarContainer = $(".toolbarContainer", passageContainer);
+
//create a button for each option
$.each(buttonOptions, function(index) {
self.toolbarContainer.append(
@@ -22,12 +23,47 @@
+ toolbarId + '">' + this.displayName + '</label></input>');
//find the newly created button
- $('#sb' + toolbarId, self.toolbarContainer).button().click(function() { self.passage.changePassage(); });
+ var newButton = $('#sb' + toolbarId, self.toolbarContainer);
+ newButton.button().click(function() { self.passage.changePassage(); });
+
+ //finally, if we're looking at the interlinear, then create a dropdown with potential versions
+ if (this.key == "INTERLINEAR") {
+ self.createInterlinearDropdown(toolbarId, strongedVersions, newButton);
+ }
toolbarId++;
});
}
+Toolbar.prototype.createInterlinearDropdown = function(toolbarId, strongedVersions, interlinearButton) {
+ this.toolbarContainer.append("<input id='interlinear" + toolbarId
+ + "' type='text' class='interlinearVersion' value='Interlinear version' disabled='disabled' />");
+
+ var self = this;
+ var interlinearSelector = $('#interlinear' + toolbarId);
+ interlinearSelector.autocomplete({
+ source : strongedVersions,
+ minLength : 0,
+ delay: 0,
+ select : function(event, ui) {
+ $(this).val(ui.item.value);
+ self.passage.changePassage();
+ return false;
+ }
+ });
+
+ addDefaultValue(interlinearSelector);
+
+ interlinearButton.click(function() {
+ if($(this).attr('checked')) {
+ interlinearSelector.removeAttr("disabled");
+ interlinearSelector.focus();
+ } else {
+ interlinearSelector.attr("disabled", "disabled");
+ }
+ });
+}
+
/**
* resets the buttons
*/
@@ -37,14 +73,25 @@
//query the server for features
$.getJSON("rest/bible/features/" + version, function (features) {
//for each button, if in array, then enable, otherwise disable
- $("input", self.toolbarContainer).each(function() {
- $(this).button("disable");
- for(var i = 0; i < features.length; i++) {
- if(features[i] == this.value) {
- $(this).button("enable");
+
+ //TODO: for some reason there are sometime some initialisation issues which throw an exception
+ try {
+ $("input", self.toolbarContainer).each(function() {
+ $(this).button("disable");
+ for(var i = 0; i < features.length; i++) {
+ if(features[i] == this.value) {
+ $(this).button("enable");
+ }
}
- }
- });
+
+ if($(this).button( "option", "disabled" )) {
+ $(this).removeAttr("checked");
+ }
+ $(this).button("refresh");
+ });
+ } finally {
+ self.passage.changePassage();
+ }
});
}
@@ -58,7 +105,17 @@
return options;
}
+Toolbar.prototype.getSelectedInterlinearVersion = function() {
+ var version = $(".interlinearVersion", this.toolbarContainer).val();
+
+ if(version && !$(".interlinearVersion", this.toolbarContainer).hasClass("inactive")) {
+ return version;
+ }
+
+ return "";
+}
+
/**
* Opens the toolbar
*/
More information about the Tynstep-svn
mailing list