preliminary support for a TAL template engine
authorzapata <zapata>
Fri, 21 Nov 2003 17:50:01 +0000 (17:50 +0000)
committerzapata <zapata>
Fri, 21 Nov 2003 17:50:01 +0000 (17:50 +0000)
20 files changed:
source/mir/generator/TALGenerator.java [new file with mode: 0755]
source/mir/generator/VelocityGenerator.java
source/mir/generator/tal/CachingFileLoader.java [new file with mode: 0755]
source/mir/generator/tal/MirExpressionParser.java [new file with mode: 0755]
source/mir/generator/tal/TALExc.java [new file with mode: 0755]
source/mir/generator/tal/TALFailure.java [new file with mode: 0755]
source/mir/generator/tal/TALTemplate.java [new file with mode: 0755]
source/mir/generator/tal/TALTemplateEngine.java [new file with mode: 0755]
source/mir/generator/tal/TALTemplateParser.java [new file with mode: 0755]
source/mir/generator/tal/TALTest.java [new file with mode: 0755]
source/mir/generator/tal/interfaces/TALExpressionParser.java [new file with mode: 0755]
source/mir/util/HTMLRoutines.java
source/mir/util/ParameterExpander.java
source/mir/util/StringRoutines.java
source/mir/util/XMLReader.java
source/mircoders/localizer/basic/MirBasicGeneratorLocalizer.java
source/tool/ConfigTool.java
templates/admin/FUNCTIONS.template
templates/admin/contentlist.template
templates/admin/start_admin.template

diff --git a/source/mir/generator/TALGenerator.java b/source/mir/generator/TALGenerator.java
new file mode 100755 (executable)
index 0000000..3744b1f
--- /dev/null
@@ -0,0 +1,88 @@
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator;\r
+\r
+import java.io.PrintWriter;\r
+import java.util.Map;\r
+\r
+import mir.generator.tal.MirExpressionParser;\r
+import mir.generator.tal.TALTemplate;\r
+import mir.generator.tal.TALTemplateEngine;\r
+import mir.log.LoggerWrapper;\r
+\r
+public class TALGenerator implements Generator {\r
+  private String templateIdentifier;\r
+  private TALGeneratorLibrary library;\r
+  private static LoggerWrapper logger = new LoggerWrapper("Generator.velocity");\r
+\r
+  public TALGenerator(String aTemplate, TALGeneratorLibrary aLibrary) {\r
+    templateIdentifier = aTemplate;\r
+    library = aLibrary;\r
+  }\r
+\r
+  public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {\r
+    TALTemplate template;\r
+\r
+    try {\r
+      template = library.engine.loadTemplate(templateIdentifier);\r
+      if (template == null) {\r
+        throw new GeneratorExc("TALGeneratorLibrary: Can't find template " + templateIdentifier);\r
+      }\r
+      template.processTemplate(aValues, (PrintWriter) anOutputWriter);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new GeneratorFailure(t);\r
+    }\r
+  }\r
+\r
+  public static class TALGeneratorLibrary implements GeneratorLibrary {\r
+    private TALTemplateEngine engine;\r
+\r
+    public TALGeneratorLibrary(String aTemplateRoot) throws GeneratorExc, GeneratorFailure {\r
+      engine = new TALTemplateEngine(new MirExpressionParser(), aTemplateRoot);\r
+    }\r
+\r
+    public Generator makeGenerator(String anIdentifier) throws GeneratorExc, GeneratorFailure {\r
+      return new TALGenerator(anIdentifier, this);\r
+    }\r
+  }\r
+\r
+  public static class TALGeneratorLibraryFactory implements GeneratorLibraryFactory {\r
+    private String basePath;\r
+\r
+    public TALGeneratorLibraryFactory(String aBasePath) {\r
+      basePath = aBasePath;\r
+    }\r
+\r
+    public GeneratorLibrary makeLibrary(String anInitializationString) throws GeneratorExc, GeneratorFailure {\r
+      return new TALGeneratorLibrary(basePath+anInitializationString);\r
+    };\r
+  }\r
+}\r
index 730b7d2..e827cc5 100755 (executable)
@@ -58,11 +58,25 @@ public class VelocityGenerator implements Generator {
   private VelocityGeneratorLibrary library;\r
   private static LoggerWrapper logger = new LoggerWrapper("Generator.velocity");\r
 \r
+  /**\r
+   *\r
+   * @param aTemplate\r
+   * @param aLibrary\r
+   */\r
+\r
   public VelocityGenerator(String aTemplate, VelocityGeneratorLibrary aLibrary) {\r
     templateIdentifier = aTemplate;\r
     library = aLibrary;\r
   }\r
 \r
+  /**\r
+   *\r
+   * @param anOutputWriter\r
+   * @param aValues\r
+   * @param aLogger\r
+   * @throws GeneratorExc\r
+   * @throws GeneratorFailure\r
+   */\r
   public void generate(Object anOutputWriter, Map aValues, LoggerWrapper aLogger) throws GeneratorExc, GeneratorFailure {\r
     Template template;\r
     Context context = makeMapAdapter(aValues);\r
@@ -89,6 +103,15 @@ public class VelocityGenerator implements Generator {
 \r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   private static class ContextAdapter implements Context {\r
     public boolean containsKey(java.lang.Object key) {\r
       return false;\r
@@ -111,31 +134,69 @@ public class VelocityGenerator implements Generator {
     }\r
   }\r
 \r
+  /**\r
+   *\r
+   * @param aMap\r
+   * @return\r
+   */\r
   private static Context makeMapAdapter(Map aMap)  {\r
     return new MapAdapter(aMap);\r
   }\r
 \r
+  /**\r
+   *\r
+   * @param anIterator\r
+   * @return\r
+   */\r
   private static List makeIteratorAdapter(Iterator anIterator) {\r
     return new IteratorAdapter(anIterator);\r
   }\r
 \r
+  /**\r
+   *\r
+   * @param aList\r
+   * @return\r
+   */\r
   private static List makeListAdapter(List aList) {\r
     return new ListAdapter(aList);\r
   }\r
 \r
-\r
+  /**\r
+   *\r
+   * @param aFunction\r
+   * @return\r
+   */\r
   private static Object makeFunctionAdapter(Generator.GeneratorFunction aFunction) {\r
     return new FunctionAdapter(aFunction);\r
   }\r
 \r
+  /**\r
+   *\r
+   * @param anObject\r
+   * @return\r
+   */\r
   private static Object makeBeanAdapter(Object anObject)  {\r
     return new BeanAdapter(anObject);\r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   private interface VelocityAdapter {\r
     public Object getOriginal();\r
   }\r
 \r
+  /**\r
+   *\r
+   * @param anObject\r
+   * @return\r
+   */\r
   public static Object unmakeAdapter(Object anObject) {\r
     if (anObject instanceof VelocityAdapter) {\r
       return ((VelocityAdapter) anObject).getOriginal();\r
@@ -144,6 +205,11 @@ public class VelocityGenerator implements Generator {
       return anObject;\r
   }\r
 \r
+  /**\r
+   *\r
+   * @param anObject\r
+   * @return\r
+   */\r
   public static Object makeAdapter(Object anObject) {\r
     if (anObject == null)\r
       return null;\r
@@ -173,6 +239,15 @@ public class VelocityGenerator implements Generator {
       return makeBeanAdapter(anObject);\r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   public static class FunctionAdapter implements VelocityAdapter {\r
     private GeneratorFunction function;\r
 \r
@@ -216,6 +291,15 @@ public class VelocityGenerator implements Generator {
   }\r
 \r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   private static class MapAdapter implements Context, VelocityAdapter  {\r
     private Map map;\r
     private Map valuesCache;\r
@@ -268,6 +352,15 @@ public class VelocityGenerator implements Generator {
     }\r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   private static class IteratorAdapter extends AbstractList implements VelocityAdapter  {\r
     private Iterator iterator;\r
     private List valuesCache;\r
@@ -318,6 +411,15 @@ public class VelocityGenerator implements Generator {
 \r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   private static class ListAdapter extends AbstractList implements VelocityAdapter  {\r
     private List list;\r
     private List valuesCache;\r
@@ -362,31 +464,15 @@ public class VelocityGenerator implements Generator {
 \r
   }\r
 \r
-/*\r
-  private static class FunctionAdapter implements TemplateMethodModel {\r
-    private Generator.GeneratorFunction function;\r
-\r
-    public FunctionAdapter(Generator.GeneratorFunction aFunction) {\r
-      function = aFunction;\r
-    }\r
-\r
-    public TemplateModel exec(List anArguments) throws TemplateModelException {\r
-      try {\r
-        return makeAdapter(function.perform(anArguments));\r
-      }\r
-      catch (Throwable t) {\r
-        throw new TemplateModelException(t.getMessage());\r
-      }\r
-    }\r
-\r
-    public boolean isEmpty() {\r
-      return false;\r
-    }\r
-\r
-  }\r
-\r
-*/\r
-\r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   private static class BeanAdapter implements Context, VelocityAdapter {\r
     private Object object;\r
 \r
@@ -437,6 +523,15 @@ public class VelocityGenerator implements Generator {
     }\r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   private static class VelocityLoggerWrapper implements LogSystem {\r
     private LoggerWrapper logger;\r
 \r
@@ -465,6 +560,15 @@ public class VelocityGenerator implements Generator {
     }\r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   public static class VelocityGeneratorLibrary implements GeneratorLibrary {\r
     private VelocityEngine engine;\r
 \r
@@ -514,15 +618,6 @@ public class VelocityGenerator implements Generator {
           logger.error(VelocityEngine.RUNTIME_LOG_LOGSYSTEM);\r
 \r
         }\r
-/*        try {\r
-          engine.setProperty(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS, null);\r
-        }\r
-        catch (Throwable t) {\r
-          logger.error(VelocityEngine.RUNTIME_LOG_LOGSYSTEM_CLASS);\r
-\r
-        }\r
-*/\r
-\r
         engine.init();\r
       }\r
       catch (Throwable t) {\r
@@ -538,6 +633,15 @@ public class VelocityGenerator implements Generator {
     }\r
   }\r
 \r
+  /**\r
+   *\r
+   * <p>Title: </p>\r
+   * <p>Description: </p>\r
+   * <p>Copyright: Copyright (c) 2003</p>\r
+   * <p>Company: </p>\r
+   * @author not attributable\r
+   * @version 1.0\r
+   */\r
   public static class VelocityGeneratorLibraryFactory implements GeneratorLibraryFactory {\r
     private String basePath;\r
 \r
diff --git a/source/mir/generator/tal/CachingFileLoader.java b/source/mir/generator/tal/CachingFileLoader.java
new file mode 100755 (executable)
index 0000000..41256ab
--- /dev/null
@@ -0,0 +1,135 @@
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.InputStream;\r
+import java.util.HashMap;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Vector;\r
+\r
+public class CachingFileLoader {\r
+  private Map cachedObjects;\r
+  private List history;\r
+  private int capacity;\r
+  private CachedFileObjectFactory factory;\r
+\r
+  public CachingFileLoader(int aCapacity, CachedFileObjectFactory aFactory) {\r
+    capacity = aCapacity;\r
+    cachedObjects = new HashMap();\r
+    history = new Vector();\r
+    factory = aFactory;\r
+  }\r
+\r
+  private void cacheObject(String aFilename, long aLastModified, Object anObject) {\r
+    synchronized (this) {\r
+      history.remove(aFilename);\r
+      history.add(aFilename);\r
+      while (history.size()>capacity && history.size()>0) {\r
+        history.remove(0);\r
+      }\r
+      cachedObjects.put(aFilename, new CachedObject(aFilename, aLastModified, anObject));\r
+    }\r
+  }\r
+\r
+  private Object constructObject(String aFilename) throws FileNotFoundException {\r
+    File file = new File(aFilename);\r
+    FileInputStream inputStream = new FileInputStream(file);\r
+    try {\r
+      Object result = factory.constructObject(inputStream);\r
+      cacheObject(aFilename, file.lastModified(), result);\r
+\r
+      return result;\r
+    }\r
+    finally {\r
+      try {\r
+        inputStream.close();\r
+      }\r
+      catch (Throwable t) {\r
+      }\r
+    }\r
+  }\r
+\r
+  private void revatilize(String aFilename) {\r
+    synchronized (this) {\r
+      history.remove(aFilename);\r
+      history.add(aFilename);\r
+    }\r
+  }\r
+\r
+  private class CachedObject {\r
+    private String filename;\r
+    private long lastModified;\r
+    private Object object;\r
+\r
+    public CachedObject(String aFilename, long aLastModified, Object anObject) {\r
+      filename = aFilename;\r
+      lastModified = aLastModified;\r
+      object = anObject;\r
+    }\r
+\r
+    public Object getObject() {\r
+      return object;\r
+    }\r
+\r
+    public String getFilename() {\r
+      return filename;\r
+    }\r
+\r
+    public long getLastModified() {\r
+      return lastModified;\r
+    }\r
+  }\r
+\r
+  public Object retrieveFile(String aFilename) throws FileNotFoundException {\r
+    synchronized (this) {\r
+      if (!cachedObjects.containsKey(aFilename)) {\r
+        return constructObject(aFilename);\r
+      }\r
+\r
+      CachedObject cachedObject = (CachedObject) cachedObjects.get(aFilename);\r
+      File file = new File(aFilename);\r
+      if (file.lastModified() != cachedObject.getLastModified()) {\r
+        return constructObject(aFilename);\r
+      }\r
+\r
+      revatilize(aFilename);\r
+\r
+      return cachedObject.getObject();\r
+    }\r
+  }\r
+\r
+  public interface CachedFileObjectFactory {\r
+    Object constructObject(InputStream aStream);\r
+  }\r
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/MirExpressionParser.java b/source/mir/generator/tal/MirExpressionParser.java
new file mode 100755 (executable)
index 0000000..ef608fc
--- /dev/null
@@ -0,0 +1,146 @@
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+\r
+package mir.generator.tal;\r
+\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.util.ParameterExpander;\r
+import mir.util.RewindableIterator;\r
+\r
+public class MirExpressionParser implements TALExpressionParser {\r
+  public Object preparseExpression(String anExpression) {\r
+    return anExpression;\r
+  }\r
+  public Object preparseStringExpression(String anExpression)  {\r
+    return anExpression;\r
+  }\r
+\r
+  public Object preparseBooleanExpression(String anExpression) {\r
+    return anExpression;\r
+  }\r
+\r
+  public Object preparseReferenceExpression(String anExpression) {\r
+    return anExpression;\r
+  }\r
+\r
+  public Object preparseListExpression(String anExpression) {\r
+    return anExpression;\r
+  }\r
+\r
+  public Object preparseTRUE() {\r
+    return "1==1";\r
+  }\r
+\r
+  public Object preparseFALSE() {\r
+    return "0==1";\r
+  }\r
+\r
+  public Object evaluateExpression(Object aContext, Object aPreparsedExpression) {\r
+    try {\r
+      return ParameterExpander.evaluateExpression(aContext, (String) aPreparsedExpression);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  public String evaluateStringExpression(Object aContext, Object aPreparsedExpression) {\r
+    try {\r
+      return ParameterExpander.evaluateStringExpression(aContext, (String) aPreparsedExpression);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  public boolean evaluateBooleanExpression(Object aContext, Object aPreparsedExpression) {\r
+    try {\r
+      return ParameterExpander.evaluateBooleanExpression(aContext, (String) aPreparsedExpression);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  public Iterator evaluateListExpression(Object aContext, Object aPreparsedExpression) {\r
+    try {\r
+      Object list = ParameterExpander.evaluateExpression(aContext, (String) aPreparsedExpression);\r
+\r
+      if (list instanceof List)\r
+        return ((List) list).iterator();\r
+\r
+      if (list instanceof RewindableIterator) {\r
+        ((RewindableIterator) list).rewind();\r
+        return (RewindableIterator) list;\r
+      }\r
+\r
+      if (list instanceof Iterator) {\r
+        return (Iterator) list;\r
+      }\r
+\r
+      throw new TALExc("Not a list: " + list);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  public void processAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aPreparsedExpression) {\r
+    try {\r
+      ParameterExpander.setValueForKey( (Map) aContext, (String) aPreparsedReferenceExpression, ParameterExpander.evaluateExpression(aContext, (String) aPreparsedExpression));\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  public void processDirectAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aValue) {\r
+    try {\r
+      ParameterExpander.setValueForKey( (Map) aContext, (String) aPreparsedReferenceExpression, aValue);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  public void processPseudoAssignment(Object aContext, String aName, Object aValue) {\r
+    try {\r
+      ParameterExpander.setValueForKey( (Map) aContext, aName, aValue);\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/TALExc.java b/source/mir/generator/tal/TALExc.java
new file mode 100755 (executable)
index 0000000..f722d2c
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2001, 2002 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * and distribute linked combinations including the two.  You must obey the
+ * GNU General Public License in all respects for all of the code used other than
+ * the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
+package mir.generator.tal;
+
+import multex.Exc;
+
+public class TALExc extends Exc {
+  public TALExc(String aMessage) {
+    super(aMessage);
+  }
+}
diff --git a/source/mir/generator/tal/TALFailure.java b/source/mir/generator/tal/TALFailure.java
new file mode 100755 (executable)
index 0000000..d15ebf5
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2001, 2002 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * and distribute linked combinations including the two.  You must obey the
+ * GNU General Public License in all respects for all of the code used other than
+ * the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
+package mir.generator.tal;
+
+import multex.Failure;
+
+public class TALFailure extends Failure {
+  public TALFailure(String msg,Throwable cause) {
+    super(msg,cause);
+  }
+
+  public TALFailure(Throwable aCause) {
+    this (aCause.getMessage(), aCause);
+  }
+}
diff --git a/source/mir/generator/tal/TALTemplate.java b/source/mir/generator/tal/TALTemplate.java
new file mode 100755 (executable)
index 0000000..2b03189
--- /dev/null
@@ -0,0 +1,333 @@
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal;\r
+\r
+import java.io.PrintWriter;\r
+import java.util.HashMap;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+import java.util.Vector;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.util.HTMLRoutines;\r
+\r
+/**\r
+ * {@link http://dev.zope.org/Wikis/DevSite/Projects/ZPT/TAL%20Specification%201.4}\r
+ *\r
+ * <p>Title: </p>\r
+ * <p>Description: </p>\r
+ * <p>Copyright: Copyright (c) 2003</p>\r
+ * <p>Company: </p>\r
+ * @author not attributable\r
+ * @version 1.0\r
+ */\r
+\r
+public class TALTemplate {\r
+  private TemplateNode rootNode;\r
+  private TALExpressionParser parser;\r
+\r
+  public TALTemplate(TALExpressionParser aParser, TemplateNode aRootNode) {\r
+    rootNode = aRootNode;\r
+    parser = aParser;\r
+  }\r
+\r
+  public void processTemplate(Object aContext, PrintWriter aDestination) {\r
+    StringBuffer output = new StringBuffer();\r
+\r
+    rootNode.process(parser, aContext, output);\r
+    aDestination.print(output);\r
+  }\r
+\r
+  public interface TemplateNode {\r
+    public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination);\r
+  }\r
+\r
+  public static class CompositeTemplateNode\r
+      implements TemplateNode {\r
+    private List parts;\r
+\r
+    public CompositeTemplateNode() {\r
+      parts = new Vector();\r
+    }\r
+\r
+    public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
+      Iterator i = parts.iterator();\r
+\r
+      while (i.hasNext()) {\r
+        ((TemplateNode) i.next()).process(aParser, aContext, aDestination);\r
+      }\r
+    }\r
+\r
+    public void appendSubNode(TemplateNode aNode) {\r
+      if (aNode instanceof CompositeTemplateNode) {\r
+        Iterator i = ((CompositeTemplateNode) aNode).parts.iterator();\r
+        while (i.hasNext()) {\r
+          appendSubNode((TemplateNode) i.next());\r
+        }\r
+      }\r
+      else if (aNode instanceof PlainTextTemplateNode && parts.size()>0 &&\r
+               (parts.get(parts.size()-1) instanceof PlainTextTemplateNode)) {\r
+\r
+        ((PlainTextTemplateNode) parts.get(parts.size()-1)).appendText(((PlainTextTemplateNode) aNode).getText());\r
+      }\r
+      else {\r
+        parts.add(aNode);\r
+      }\r
+    }\r
+  }\r
+\r
+  public static class PlainTextTemplateNode\r
+      implements TemplateNode {\r
+    private String text;\r
+\r
+    public PlainTextTemplateNode() {\r
+      this("");\r
+    }\r
+\r
+    public PlainTextTemplateNode(String aText) {\r
+      text = aText;\r
+    }\r
+\r
+    public void appendText(String aText) {\r
+      text = text + aText;\r
+    }\r
+\r
+    protected String getText() {\r
+      return text;\r
+    }\r
+\r
+    public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
+      aDestination.append(text);\r
+    }\r
+  }\r
+\r
+  public static class SmartTemplateNode implements TemplateNode {\r
+    private String tag;\r
+    private Map fixedAttributes;\r
+    private Map attributeModifiers;\r
+\r
+    private List definitions;\r
+    private Object condition;\r
+\r
+    private Object repeatVariable;\r
+    private Object repeatExpression;\r
+    private Object contentExpression;\r
+    private Object omitTagExpression;\r
+    private Object errorExpression;\r
+\r
+    private TemplateNode body;\r
+\r
+    public SmartTemplateNode(String aTag) {\r
+      tag = aTag;\r
+\r
+      fixedAttributes = new HashMap();\r
+      attributeModifiers = new HashMap();\r
+\r
+      definitions = new Vector();\r
+      condition = null;\r
+\r
+      repeatVariable = null;\r
+      repeatExpression = null;\r
+      contentExpression = null;\r
+      omitTagExpression = null;\r
+\r
+      body = null;\r
+    }\r
+\r
+    public void setBody(TemplateNode aBody) {\r
+      body = aBody;\r
+    }\r
+\r
+    public void addFixedAttribute(String aKey, String aValue) {\r
+      fixedAttributes.put(aKey, aValue);\r
+    }\r
+\r
+    public void addModifiedAttribute(String aKey, Object aValue) {\r
+      attributeModifiers.put(aKey, aValue);\r
+    }\r
+\r
+    public void addDefinition(Object aKey, Object aValue) {\r
+      definitions.add(new Definition(aKey, aValue));\r
+    }\r
+\r
+    public void setCondition(Object aCondition) {\r
+      condition = aCondition;\r
+    }\r
+\r
+    public void setRepeat(Object aRepeatVariable, Object aRepeatExpression) {\r
+      repeatVariable = aRepeatVariable;\r
+      repeatExpression = aRepeatExpression;\r
+    }\r
+\r
+    public void setContent(Object aContentExpression) {\r
+      contentExpression = aContentExpression;\r
+    }\r
+\r
+    public void setOmitTag(Object anOmitTagExpression) {\r
+      omitTagExpression = anOmitTagExpression;\r
+    }\r
+\r
+    public void setError(Object anErrorExpression) {\r
+      errorExpression = anErrorExpression;\r
+    }\r
+\r
+    public static class Definition {\r
+      private Object variable;\r
+      private Object expression;\r
+\r
+      public Definition(Object aVariable, Object anExpression) {\r
+        variable = aVariable;\r
+        expression = anExpression;\r
+      }\r
+\r
+      public Object getVariable() {\r
+        return variable;\r
+      }\r
+\r
+      public Object getExpression() {\r
+        return expression;\r
+      }\r
+    }\r
+\r
+    public void process(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
+      Iterator i;\r
+\r
+        i = definitions.iterator();\r
+        while (i.hasNext()) {\r
+          Definition d = (Definition) i.next();\r
+          aParser.processAssignment(aContext, d.getVariable(), d.getExpression());\r
+        }\r
+\r
+        if (condition == null || aParser.evaluateBooleanExpression(aContext, condition)) {\r
+          if (repeatExpression != null) {\r
+            i = aParser.evaluateListExpression(aContext, repeatExpression);\r
+\r
+            while (i.hasNext()) {\r
+              aParser.processDirectAssignment(aContext, repeatVariable, i.next());\r
+              innerProcess(aParser, aContext, aDestination);\r
+            }\r
+          }\r
+          else {\r
+            innerProcess(aParser, aContext, aDestination);\r
+          }\r
+\r
+          /*\r
+               define\r
+               condition\r
+               repeat\r
+                   attributes\r
+                   content\r
+               OR\r
+                   replace\r
+               OR\r
+                   omit-tag\r
+                   content\r
+           * define\r
+           * condition\r
+           * repeat\r
+           * content\r
+           * attributes\r
+           * omit-tag\r
+           */\r
+        }\r
+    };\r
+\r
+    private void innerProcess(TALExpressionParser aParser, Object aContext, StringBuffer aDestination) {\r
+      boolean omitTag = false;\r
+      if (omitTagExpression != null)\r
+        omitTag = aParser.evaluateBooleanExpression(aContext, omitTagExpression);\r
+\r
+      if (!omitTag) {\r
+        Map generatedAttributes = new HashMap(fixedAttributes);\r
+\r
+        Iterator i = attributeModifiers.keySet().iterator();\r
+        while (i.hasNext()) {\r
+          Map.Entry entry = (Map.Entry) i.next();\r
+\r
+          generatedAttributes.put(entry.getKey(), aParser.evaluateStringExpression(aContext, entry.getValue()));\r
+        }\r
+\r
+        aDestination.append("<");\r
+        aDestination.append(tag);\r
+\r
+        i = generatedAttributes.keySet().iterator();\r
+        while (i.hasNext()) {\r
+          Map.Entry entry = (Map.Entry) i.next();\r
+          aDestination.append(" ");\r
+          aDestination.append(entry.getKey());\r
+          aDestination.append("=");\r
+          aDestination.append("\"");\r
+          aDestination.append(HTMLRoutines.encodeHTML( (String) entry.getValue()));\r
+          aDestination.append("\"");\r
+        }\r
+        aDestination.append(">");\r
+      }\r
+\r
+      StringBuffer destination = aDestination;\r
+      if (errorExpression != null) {\r
+        destination = new StringBuffer();\r
+      }\r
+      try {\r
+        if (contentExpression != null) {\r
+          destination.append(aParser.evaluateStringExpression(aContext, contentExpression));\r
+        }\r
+        else {\r
+          if (body != null)\r
+            body.process(aParser, aContext, destination);\r
+        }\r
+      }\r
+      catch (RuntimeException t) {\r
+        if (errorExpression != null) {\r
+          try {\r
+            destination.delete(0, destination.length());\r
+\r
+            aParser.processPseudoAssignment(aContext, "exception", t);\r
+            destination.append(aParser.evaluateStringExpression(aContext, errorExpression));\r
+          }\r
+          catch (Throwable s) {\r
+          }\r
+        }\r
+        else\r
+          throw t;\r
+      }\r
+      finally {\r
+        if (errorExpression != null) {\r
+          aDestination.append(destination);\r
+        }\r
+      }\r
+      if (!omitTag) {\r
+        aDestination.append("</");\r
+        aDestination.append(tag);\r
+        aDestination.append(">");\r
+      }\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/TALTemplateEngine.java b/source/mir/generator/tal/TALTemplateEngine.java
new file mode 100755 (executable)
index 0000000..74b4b37
--- /dev/null
@@ -0,0 +1,65 @@
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+\r
+package mir.generator.tal;\r
+\r
+import java.io.File;\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+\r
+public class TALTemplateEngine {\r
+  private TALExpressionParser expressionParser;\r
+  private String basePath;\r
+  private CachingFileLoader loader;\r
+\r
+  public TALTemplateEngine(TALExpressionParser anExpressionParser, String aBasePath) {\r
+    expressionParser = anExpressionParser;\r
+    basePath = aBasePath;\r
+    loader = new CachingFileLoader(100, new TemplateFactory());\r
+  }\r
+\r
+  public TALTemplate loadTemplate(String aName) throws IOException {\r
+    File location = new File(basePath, aName);\r
+    return (TALTemplate) loader.retrieveFile(location.getCanonicalPath());\r
+  }\r
+\r
+  private class TemplateFactory implements CachingFileLoader.CachedFileObjectFactory {\r
+    public Object constructObject(InputStream aStream) {\r
+      try {\r
+        return TALTemplateParser.parseInputStream(aStream, expressionParser);\r
+      }\r
+      catch (Throwable t) {\r
+        throw new TALFailure(t);\r
+      }\r
+    }\r
+  }\r
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/TALTemplateParser.java b/source/mir/generator/tal/TALTemplateParser.java
new file mode 100755 (executable)
index 0000000..ba73919
--- /dev/null
@@ -0,0 +1,244 @@
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal;\r
+\r
+import java.io.InputStream;\r
+import java.util.Iterator;\r
+import java.util.List;\r
+import java.util.Map;\r
+\r
+import mir.generator.tal.interfaces.TALExpressionParser;\r
+import mir.util.HTMLRoutines;\r
+import mir.util.StringRoutines;\r
+import mir.util.XMLReader;\r
+import mir.util.XMLReader.AbstractSectionHandler;\r
+\r
+public class TALTemplateParser {\r
+  private int bal;\r
+  private static final String TAL_PREFIX = "tal";\r
+\r
+  public static TALTemplate parseString(String aData, TALExpressionParser aParser) throws TALExc, TALFailure {\r
+    try {\r
+      TALHandler handler = new TALHandler(aParser);\r
+      XMLReader reader = new XMLReader(false);\r
+\r
+      reader.parseString(aData, handler);\r
+\r
+      return new TALTemplate(aParser, handler.getNode());\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  public static TALTemplate parseInputStream(InputStream anInputStream, TALExpressionParser aParser) throws TALExc, TALFailure {\r
+    try {\r
+      TALHandler handler = new TALHandler(aParser);\r
+      XMLReader reader = new XMLReader(false);\r
+\r
+      reader.parseInputStream(anInputStream, handler);\r
+\r
+      return new TALTemplate(aParser, handler.getNode());\r
+    }\r
+    catch (Throwable t) {\r
+      throw new TALFailure(t);\r
+    }\r
+  }\r
+\r
+  private static final String CONDITION_ATTRIBUTE = "tal:condition";\r
+  private static final String REPEAT_ATTRIBUTE = "tal:repeat";\r
+  private static final String CONTENT_ATTRIBUTE = "tal:content";\r
+  private static final String ERROR_ATTRIBUTE = "tal:on-error";\r
+  private static final String REPLACE_ATTRIBUTE = "tal:replace";\r
+  private static final String DEFINITION_ATTRIBUTE = "tal:define";\r
+  private static final String ONERROR_ATTRIBUTE = "tal:onerror";\r
+  private static final String OMITTAG_ATTRIBUTE = "tal:omit-tag";\r
+  private static final String ATTRIBUTE_ATTRIBUTE = "tal:attributes";\r
+\r
+\r
+  protected static class TALHandler extends XMLReader.AbstractSectionHandler {\r
+    private TALTemplate.CompositeTemplateNode compositeNode;\r
+    private StringBuffer data;\r
+    private TALExpressionParser parser;\r
+    private TALTemplate.SmartTemplateNode smartNode;\r
+    private boolean smartTag;\r
+    private String currentTag;\r
+\r
+    public TALHandler(TALExpressionParser aParser) {\r
+      parser = aParser;\r
+      data = new StringBuffer();\r
+      compositeNode = new TALTemplate.CompositeTemplateNode();\r
+    }\r
+\r
+    private void flushData() {\r
+      if (data.length()!=0) {\r
+        compositeNode.appendSubNode(new TALTemplate.PlainTextTemplateNode(data.toString()));\r
+        data.delete(0, data.length());\r
+      }\r
+    }\r
+\r
+    public XMLReader.SectionHandler startElement(XMLReader.XMLName aTag, Map anAttributes) throws XMLReader.XMLReaderExc {\r
+      smartTag = false;\r
+\r
+      currentTag = aTag.getLocalName();\r
+      if (aTag.getPrefix().length()>0)\r
+        currentTag = aTag.getPrefix() + ":" + currentTag;\r
+\r
+      smartTag = (aTag.getPrefix().equals(TAL_PREFIX));\r
+\r
+      Iterator i = anAttributes.keySet().iterator();\r
+\r
+      while (!smartTag && i.hasNext()) {\r
+        XMLReader.XMLName name = (XMLReader.XMLName) i.next();\r
+        smartTag = smartTag || (name.getPrefix().equals(TAL_PREFIX));\r
+      }\r
+\r
+      if (!smartTag) {\r
+        appendCode("<"+currentTag);\r
+        i = anAttributes.entrySet().iterator();\r
+\r
+        while (i.hasNext()) {\r
+          Map.Entry entry = (Map.Entry) i.next();\r
+\r
+          appendCode(" "+ (String) entry.getKey());\r
+          appendCode("=\"");\r
+          appendText((String) entry.getValue());\r
+          appendCode("\"");\r
+        }\r
+        appendCode(">");\r
+      }\r
+      else {\r
+        smartNode = new TALTemplate.SmartTemplateNode(currentTag);\r
+        if (aTag.getPrefix().equals(TAL_PREFIX))\r
+          smartNode.setOmitTag(parser.preparseTRUE());\r
+\r
+        i = anAttributes.entrySet().iterator();\r
+        while (i.hasNext()) {\r
+          Map.Entry entry = (Map.Entry) i.next();\r
+          XMLReader.XMLName name = (XMLReader.XMLName) entry.getKey();\r
+\r
+          if (!name.getPrefix().equals(TAL_PREFIX)) {\r
+            smartNode.addFixedAttribute(name.getLocalName(), (String) entry.getValue());\r
+          }\r
+          else {\r
+            if (name.getLocalName().equalsIgnoreCase(DEFINITION_ATTRIBUTE)) {\r
+              List definitions = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
+\r
+              Iterator j = definitions.iterator(); {\r
+                List parts = StringRoutines.separateString((String) i.next(), " ");\r
+\r
+                if (parts.size()==2) {\r
+                  smartNode.addDefinition(parser.preparseReferenceExpression((String) parts.get(0)), parser.preparseExpression((String) parts.get(1)));\r
+                }\r
+              }\r
+            }\r
+            else if (name.getLocalName().equalsIgnoreCase(CONDITION_ATTRIBUTE)) {\r
+              smartNode.setCondition(parser.preparseBooleanExpression((String) entry.getValue()));\r
+            }\r
+            else if (name.getLocalName().equalsIgnoreCase(CONTENT_ATTRIBUTE)) {\r
+              smartNode.setContent(parser.preparseStringExpression((String) entry.getValue()));\r
+            }\r
+            else if (name.getLocalName().equalsIgnoreCase(ERROR_ATTRIBUTE)) {\r
+              smartNode.setError(parser.preparseStringExpression((String) entry.getValue()));\r
+            }\r
+            else if (name.getLocalName().equalsIgnoreCase(OMITTAG_ATTRIBUTE)) {\r
+              if (((String) entry.getValue()).trim().length()==0)\r
+                smartNode.setOmitTag(parser.preparseTRUE());\r
+              else\r
+                smartNode.setOmitTag(parser.preparseBooleanExpression((String) entry.getValue()));\r
+            }\r
+            else if (name.getLocalName().equalsIgnoreCase(REPLACE_ATTRIBUTE)) {\r
+              smartNode.setOmitTag(parser.preparseTRUE());\r
+              smartNode.setContent(parser.preparseStringExpression((String) entry.getValue()));\r
+            }\r
+            else if (name.getLocalName().equalsIgnoreCase(REPEAT_ATTRIBUTE)) {\r
+              List parts = StringRoutines.separateString((String) entry.getValue(), " ");\r
+\r
+              if (parts.size()==2) {\r
+                smartNode.setRepeat(parser.preparseReferenceExpression((String) parts.get(0)), parser.preparseExpression((String) parts.get(1)));\r
+              }\r
+            }\r
+            else if (name.getLocalName().equalsIgnoreCase(ATTRIBUTE_ATTRIBUTE)) {\r
+              List attributes = StringRoutines.splitStringWithEscape((String) entry.getValue(), ';', '\\');\r
+\r
+              Iterator j = attributes.iterator(); {\r
+                List parts = StringRoutines.separateString((String) i.next(), " ");\r
+\r
+                if (parts.size()==2) {\r
+                  smartNode.addModifiedAttribute((String) parts.get(0), parser.preparseExpression((String) parts.get(1)));\r
+                }\r
+              }\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      flushData();\r
+\r
+      return new TALHandler(parser);\r
+    };\r
+\r
+    public void endElement(XMLReader.SectionHandler aHandler) throws XMLReader.XMLReaderExc {\r
+      if (!smartTag) {\r
+        appendSubNode(((TALHandler) aHandler).getNode());\r
+        appendCode("</"+currentTag+">");\r
+      }\r
+      else {\r
+        smartNode.setBody(((TALHandler) aHandler).getNode());\r
+        appendSubNode(smartNode);\r
+        smartNode=null;\r
+      }\r
+    };\r
+\r
+    protected void appendSubNode(TALTemplate.TemplateNode aNode) {\r
+      compositeNode.appendSubNode(aNode);\r
+    }\r
+\r
+    protected void appendCode(String aCode) {\r
+      data.append(aCode);\r
+    }\r
+\r
+    protected void appendText(String aText) {\r
+      data.append(HTMLRoutines.encodeHTML(aText));\r
+    }\r
+\r
+    public void finishSection() throws XMLReader.XMLReaderExc {\r
+      flushData();\r
+    }\r
+\r
+    public TALTemplate.TemplateNode getNode() {\r
+      return compositeNode;\r
+    }\r
+\r
+    public void characters(String aCharacters) throws XMLReader.XMLReaderExc {\r
+      appendText(aCharacters);\r
+    }\r
+  }\r
+}\r
diff --git a/source/mir/generator/tal/TALTest.java b/source/mir/generator/tal/TALTest.java
new file mode 100755 (executable)
index 0000000..02e63f8
--- /dev/null
@@ -0,0 +1,64 @@
+/*\r
+ * Copyright (C) 2001, 2002 The Mir-coders group\r
+ *\r
+ * This file is part of Mir.\r
+ *\r
+ * Mir is free software; you can redistribute it and/or modify\r
+ * it under the terms of the GNU General Public License as published by\r
+ * the Free Software Foundation; either version 2 of the License, or\r
+ * (at your option) any later version.\r
+ *\r
+ * Mir is distributed in the hope that it will be useful,\r
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+ * GNU General Public License for more details.\r
+ *\r
+ * You should have received a copy of the GNU General Public License\r
+ * along with Mir; if not, write to the Free Software\r
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
+ *\r
+ * In addition, as a special exception, The Mir-coders gives permission to link\r
+ * the code of this program with  any library licensed under the Apache Software License,\r
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library\r
+ * (or with modified versions of the above that use the same license as the above),\r
+ * and distribute linked combinations including the two.  You must obey the\r
+ * GNU General Public License in all respects for all of the code used other than\r
+ * the above mentioned libraries.  If you modify this file, you may extend this\r
+ * exception to your version of the file, but you are not obligated to do so.\r
+ * If you do not wish to do so, delete this exception statement from your version.\r
+ */\r
+package mir.generator.tal;\r
+\r
+/**\r
+ * <p>Title: </p>\r
+ * <p>Description: </p>\r
+ * <p>Copyright: Copyright (c) 2003</p>\r
+ * <p>Company: </p>\r
+ * @author not attributable\r
+ * @version 1.0\r
+ */\r
+\r
+import java.io.PrintWriter;\r
+import java.util.HashMap;\r
+import java.util.Map;\r
+\r
+public class TALTest {\r
+  public static void main(String args[]) {\r
+    try {\r
+      TALTemplateParser parser = new TALTemplateParser();\r
+      MirExpressionParser expressionParser = new MirExpressionParser();\r
+      Map test = new HashMap();\r
+      test.put("name", "zapata");\r
+\r
+      TALTemplate template = parser.parseString("<html tal:on-error='exception.message'><head></head><body><tal:test tal:content='name'></tal:test><h1 tal:content=\"name.bla\">test</h1></body></html>", expressionParser);\r
+      PrintWriter o = new PrintWriter(System.out);\r
+      template.processTemplate(test, o);\r
+      o.close();\r
+    }\r
+    catch (Throwable t) {\r
+      System.out.println("Exception: " + t.toString());\r
+      t.printStackTrace(System.out);\r
+    }\r
+\r
+  }\r
+}
\ No newline at end of file
diff --git a/source/mir/generator/tal/interfaces/TALExpressionParser.java b/source/mir/generator/tal/interfaces/TALExpressionParser.java
new file mode 100755 (executable)
index 0000000..66b8262
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2001, 2002 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * and distribute linked combinations including the two.  You must obey the
+ * GNU General Public License in all respects for all of the code used other than
+ * the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
+package mir.generator.tal.interfaces;
+
+import java.util.Iterator;
+
+public interface TALExpressionParser {
+  public Object preparseExpression(String anExpression);
+  public Object preparseStringExpression(String anExpression);
+  public Object preparseBooleanExpression(String anExpression);
+  public Object preparseReferenceExpression(String anExpression);
+  public Object preparseListExpression(String anExpression);
+  public Object preparseTRUE();
+  public Object preparseFALSE();
+
+  public Object evaluateExpression(Object aContext, Object aPreparsedExpression);
+  public String evaluateStringExpression(Object aContext, Object aPreparsedExpression);
+  public boolean evaluateBooleanExpression(Object aContext, Object aPreparsedExpression);
+  public Iterator evaluateListExpression(Object aContext, Object aPreparsedExpression);
+  public void processAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aPreparsedExpression);
+
+  /**
+   * process a direct assignment of an object to a preparsed reference expression
+   *
+   * @param aContext
+   * @param aPreparsedReferenceExpression
+   * @param aValue
+   */
+  public void processDirectAssignment(Object aContext, Object aPreparsedReferenceExpression, Object aValue);
+
+
+  /**
+   * process an assigment to a pseudo variable. The pseudo variable will have a java
+   *   identifier-like name.
+   *
+   * @param aContext
+   * @param aPreparsedReferenceExpression
+   * @param aValue
+   */
+  public void processPseudoAssignment(Object aContext, String aName, Object aValue);
+}
\ No newline at end of file
index 53a4cda..4ed503b 100755 (executable)
@@ -56,7 +56,7 @@ public class HTMLRoutines {
     }
   }
 
-  public static String encodeHTML(String aText) throws UtilExc {
+  public static String encodeHTML(String aText) {
     final char[] CHARACTERS_TO_ESCAPE = { '&', '<', '>', '"' };
     final String[] ESCAPE_CODES = { "&amp;", "&lt;", "&gt;", "&quot;" };
 
index 71e154a..75f92a7 100755 (executable)
@@ -590,7 +590,7 @@ public class ParameterExpander {
           return MethodUtils.invokeExactMethod(anObject, "get", aField);
         }
         catch (Throwable t) {
-          throw new RuntimeException("Invalid reference of " + aField + "into " + anObject);
+          throw new RuntimeException("Invalid reference of " + aField + " into " + anObject);
         }
       }
     }
index bd6f274..0627dbc 100755 (executable)
@@ -277,6 +277,16 @@ public class StringRoutines {
     return result;
   }
 
+  /**
+   * Separates a string based on a separator, taking into account an escape character:
+   *     <code>seperateString("a:/::b", ":", "/");</code> will lead to
+   *     a List with 3 Strings: <code>"a"</code>, <code>":"</code> and <code>"b"</code>
+   *
+   * @param aString     The string to split
+   * @param aSeparator
+   * @return
+   */
+
   public static List splitStringWithEscape(String aString, char aSeparator, char anEscape) {
     List result= new Vector();
     int previousPosition = 0;
index 954b2e7..a1be97c 100755 (executable)
@@ -29,7 +29,7 @@
  */
 package mir.util;
 
-import java.io.FileInputStream;
+import java.io.*;
 import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
@@ -63,6 +63,15 @@ public class XMLReader {
     filename="";
   }
 
+  public void parseString(String aString, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
+    try {
+      parseInputSource(new InputSource(new StringReader(aString)), aRootHandler);
+    }
+    catch (Throwable t) {
+      throw new XMLReaderFailure(t);
+    }
+  }
+
   public void parseFile(String aFileName, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
     filename= aFileName;
     try {
@@ -74,6 +83,10 @@ public class XMLReader {
   }
 
   public void parseInputStream(InputStream anInputStream, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
+    parseInputSource(new InputSource(anInputStream), aRootHandler);
+  }
+
+  public void parseInputSource(InputSource anInputSource, SectionHandler aRootHandler) throws XMLReaderFailure, XMLReaderExc {
     try {
       SAXParserFactory parserFactory = SAXParserFactory.newInstance();
 
@@ -82,7 +95,7 @@ public class XMLReader {
 
       XMLReaderHandler handler = new XMLReaderHandler(parserFactory, aRootHandler);
 
-      handler.processInputStream(anInputStream);
+      handler.processInputSource(anInputSource);
     }
     catch (Throwable e) {
       Throwable t = ExceptionFunctions.traceCauseException(e);
@@ -98,11 +111,9 @@ public class XMLReader {
       throw new XMLReaderFailure(t);
     }
   }
-
   private class XMLReaderHandler extends DefaultHandler {
     private SAXParserFactory parserFactory;
     private SectionsManager manager;
-    private InputSource inputSource;
 
     public XMLReaderHandler(SAXParserFactory aParserFactory, SectionHandler aRootHandler) {
       super();
@@ -116,12 +127,11 @@ public class XMLReader {
       locator=aLocator;
     }
 
-    private void processInputStream(InputStream anInputStream) throws XMLReaderExc, XMLReaderFailure {
+    private void processInputSource(InputSource anInputSource) throws XMLReaderExc, XMLReaderFailure {
       try {
         SAXParser parser=parserFactory.newSAXParser();
 
-        inputSource = new InputSource(anInputStream);
-        parser.parse(inputSource, this);
+        parser.parse(anInputSource, this);
       }
       catch (Throwable e) {
         Throwable t = ExceptionFunctions.traceCauseException(e);
@@ -160,14 +170,15 @@ public class XMLReader {
       try {
         attributesMap = new HashMap();
 
-        if (namespaceAware)
+//        if (namespaceAware)
           for (i=0; i<anAttributes.getLength(); i++)
-            attributesMap.put(new XMLName(anAttributes.getURI(i), anAttributes.getLocalName(i)), anAttributes.getValue(i));
-        else
+            attributesMap.put(new XMLName(anAttributes.getURI(i), XMLReaderTool.getNameSpaceFromQualifiedName(anAttributes.getQName(i)), anAttributes.getLocalName(i)), anAttributes.getValue(i));
+/*        else
           for (i=0; i<anAttributes.getLength(); i++)
             attributesMap.put(anAttributes.getLocalName(i), anAttributes.getValue(i));
+*/
 
-        SectionHandler handler = manager.currentHandler().startElement(new XMLName(aUri, aLocalName), attributesMap);
+        SectionHandler handler = manager.currentHandler().startElement(new XMLName(aUri, XMLReaderTool.getNameSpaceFromQualifiedName(aQualifiedName), aLocalName), attributesMap);
 
         manager.pushHandler( handler );
       }
@@ -319,14 +330,27 @@ public class XMLReader {
   public static class XMLName {
     private String namespaceURI;
     private String localName;
+    private String prefix;
 
     public XMLName(String aLocalName) {
-      this(aLocalName, null);
+      this(null, null, aLocalName);
+    }
+
+    public XMLName(String aNamespaceURI, String aPrefix, String aLocalName) {
+      localName="";
+      prefix="";
+      namespaceURI="";
+
+      if (aLocalName!=null)
+        localName = aLocalName;
+      if (aPrefix!=null)
+        prefix = aPrefix;
+      if (aNamespaceURI!=null)
+        namespaceURI = aNamespaceURI;
     }
 
     public XMLName(String aNamespaceURI, String aLocalName) {
-      namespaceURI = aNamespaceURI;
-      localName = aLocalName;
+      this (aNamespaceURI, null, aLocalName);
     }
 
     public String getNamespaceURI() {
@@ -337,21 +361,26 @@ public class XMLReader {
       return localName;
     }
 
+    public String getPrefix() {
+      return prefix;
+    }
+
     public int hashCode() {
       if (namespaceURI == null)
-        return localName.hashCode();
+        return localName.hashCode() + 3*prefix.hashCode();
       else
         return localName.hashCode() + 3*namespaceURI.hashCode();
     }
 
     public String toString() {
-      return namespaceURI+":"+localName;
+      return ((namespaceURI.length()>0)? "["+namespaceURI+"]":"")+((prefix.length()>0)?prefix+":":"")+localName;
     }
 
     public boolean equals(Object anObject) {
       if (anObject instanceof XMLName) {
         if (namespaceURI==null)
           return (((XMLName) anObject).namespaceURI == null) &&
+                 prefix.equals(((XMLName) anObject).prefix) &&
                  localName.equals(((XMLName) anObject).localName);
         else
           return namespaceURI.equals(((XMLName) anObject).namespaceURI) &&
index 478e20b..d9b4407 100755 (executable)
@@ -31,6 +31,7 @@ package mircoders.localizer.basic;
 
 import mir.generator.FreemarkerGenerator;
 import mir.generator.VelocityGenerator;
+import mir.generator.TALGenerator;
 import mir.generator.Generator;
 import mir.generator.GeneratorLibraryRepository;
 import mir.generator.WriterEngine;
@@ -58,6 +59,9 @@ public class MirBasicGeneratorLocalizer implements MirGeneratorLocalizer {
     aRepository.registerLibraryFactory(
         "velocity",
         new VelocityGenerator.VelocityGeneratorLibraryFactory(MirGlobal.config().getString("Home") ) );
+    aRepository.registerLibraryFactory(
+        "tal",
+        new TALGenerator.TALGeneratorLibraryFactory(MirGlobal.config().getString("Home") ) );
   }
 
   public Generator.GeneratorLibrary makeProducerGeneratorLibrary() throws MirLocalizerExc, MirLocalizerFailure {
index 351274e..d7e8993 100755 (executable)
@@ -1,3 +1,32 @@
+/*
+ * Copyright (C) 2001, 2002 The Mir-coders group
+ *
+ * This file is part of Mir.
+ *
+ * Mir is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Mir is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Mir; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * In addition, as a special exception, The Mir-coders gives permission to link
+ * the code of this program with  any library licensed under the Apache Software License,
+ * The Sun (tm) Java Advanced Imaging library (JAI), The Sun JIMI library
+ * (or with modified versions of the above that use the same license as the above),
+ * and distribute linked combinations including the two.  You must obey the
+ * GNU General Public License in all respects for all of the code used other than
+ * the above mentioned libraries.  If you modify this file, you may extend this
+ * exception to your version of the file, but you are not obligated to do so.
+ * If you do not wish to do so, delete this exception statement from your version.
+ */
 package tool;
 
 import gnu.regexp.RE;
index 5ef9efe..e2b84e2 100755 (executable)
 </function>
 
 <comment>complete search-form for contenentries, not sure if it works from everywhere</comment>
-<function ContentSearch (layout)>
+<function ContentSearch (aLayout)>
 
       <form method="GET" action="${config.actionRoot}">
         <input type="hidden" name="module" value="Content">
         <input type="hidden" name="do" value="search">
-        <input type="hidden" name="selectarticleurl" value="${utility.encodeHTML(selectarticleurl)}">
+        <if selectarticleurl>
+          <input type="hidden" name="selectarticleurl" value="${utility.encodeHTML(selectarticleurl)}">
+        </if>
          
         <table border="0" cellpadding="2" cellspacing="3">
-          <tr <if !layout>class="bg-neutral"</if>>
-            <td <if layout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.value")}</td>
-            <td <if layout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.field")}</td>
-            <td <if layout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.publishedstate")}</td>
-            <td <if layout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.articletype")}</td>
-            <td <if layout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.order")}</td>
-      <td <if layout>class="table_head"<else>class="small bg_neutral"</if> valign="bottom"> &nbsp;</td>
+          <tr <if !aLayout>class="bg-neutral"</if>>
+            <td <if aLayout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.value")}</td>
+            <td <if aLayout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.field")}</td>
+            <td <if aLayout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.publishedstate")}</td>
+            <td <if aLayout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.articletype")}</td>
+            <td <if aLayout>class="table-head"<else>class="small bg-neutral"</if> valign="bottom"> ${lang("contentsearch.order")}</td>
+      <td <if aLayout>class="table_head"<else>class="small bg_neutral"</if> valign="bottom"> &nbsp;</td>
           </tr>
           <tr>
-            <td <if layout>class="listrow2"</if>><input type="text" size="10" maxlength="20" name="searchvalue" value="${searchvalue}"></td>
-            <td <if layout>class="listrow2"</if>>
+            <td <if aLayout>class="listrow2"</if>><input type="text" size="10" maxlength="20" name="searchvalue" value="${searchvalue}"></td>
+            <td <if aLayout>class="listrow2"</if>>
                 <select name="searchfield">
-                  <option value="title"<if searchfield=="title"> selected</if>>${lang("contentsearch.field.title")}</option>
-                  <option value="creator"<if searchfield=="creator"> selected</if>>${lang("contentsearch.field.creator")}</option>
-                  <option value="contents"<if searchfield=="content"> selected</if>>${lang("contentsearch.field.contents")}</option>
-                  <option value="creator_main_url"<if searchfield=="creator_main_url"> selected</if>>${lang("contentsearch.field.creator_main_url")}</option>
-                  <option value="creator_email"<if searchfield=="creator_email"> selected</if>>${lang("contentsearch.field.creator_email")}</option>
+                  <option value="title"<if searchfield && searchfield=="title"> selected</if>>${lang("contentsearch.field.title")}</option>
+                  <option value="creator"<if searchfield && searchfield=="creator"> selected</if>>${lang("contentsearch.field.creator")}</option>
+                  <option value="contents"<if searchfield && searchfield=="content"> selected</if>>${lang("contentsearch.field.contents")}</option>
+                  <option value="creator_main_url"<if searchfield && searchfield=="creator_main_url"> selected</if>>${lang("contentsearch.field.creator_main_url")}</option>
+                  <option value="creator_email"<if searchfield && searchfield=="creator_email"> selected</if>>${lang("contentsearch.field.creator_email")}</option>
                 </select>
             </td>
-            <td <if layout>class="listrow2"</if>>
+            <td <if aLayout>class="listrow2"</if>>
                 <select name="searchispublished">
                   <option value="">--</option>
-                  <option value="0" <if searchispublished=="0"> selected</if>>${lang("contentsearch.publishedstate.hidden")}</option>
-                  <option value="1" <if searchispublished=="1"> selected</if>>${lang("contentsearch.publishedstate.published")}</option>
+                  <option value="0" <if searchispublished && searchispublished=="0"> selected</if>>${lang("contentsearch.publishedstate.hidden")}</option>
+                  <option value="1" <if searchispublished && searchispublished=="1"> selected</if>>${lang("contentsearch.publishedstate.published")}</option>
                 </select>
             </td>
-            <td <if layout>class="listrow2"</if>>
+            <td <if aLayout>class="listrow2"</if>>
                 <select name="searcharticletype">
                   <option value="">--</option>
                   <list articletypes as at>
-                    <option value="${at.id}" <if searcharticletype==at.id> selected</if>>${lang("articletypes."+at.name)}</option>
+                    <option value="${at.id}" <if searcharticletype && searcharticletype==at.id> selected</if>>${lang("articletypes."+at.name)}</option>
                   </list>
                 </select>
             </td>
-            <td <if layout>class="listrow2"</if>>
+            <td <if aLayout>class="listrow2"</if>>
                 <select name="searchorder">
-                  <option value="datedesc" <if searchorder=="datedesc"> selected</if>>${lang("contentsearch.order.datedesc")}</option>
-                  <option value="dateasc" <if searchorder=="dateasc"> selected</if>>${lang("contentsearch.order.dateasc")}</option>
-                  <option value="title" <if searchorder=="title"> selected</if>>${lang("contentsearch.order.title")}</option>
-                  <option value="creator" <if searchorder=="creator"> selected</if>>${lang("contentsearch.order.creator")}</option>
+                  <option value="datedesc" <if searchorder && searchorder=="datedesc"> selected</if>>${lang("contentsearch.order.datedesc")}</option>
+                  <option value="dateasc" <if searchorder && searchorder=="dateasc"> selected</if>>${lang("contentsearch.order.dateasc")}</option>
+                  <option value="title" <if searchorder && searchorder=="title"> selected</if>>${lang("contentsearch.order.title")}</option>
+                  <option value="creator" <if searchorder && searchorder=="creator"> selected</if>>${lang("contentsearch.order.creator")}</option>
                 </select>
             </td>
-            <td <if layout>class="listrow2"</if>>
+            <td <if aLayout>class="listrow2"</if>>
                 <input class="majorbutton" type="submit" name="search" value="${lang("contentsearch.searchbutton")}">
             </td>
           </tr>
index 2752dc3..107a4c4 100755 (executable)
@@ -2,7 +2,7 @@
   if selectarticleurl is set, this list is used to select an article
 </comment>
 
-<if selectarticleurl!="">
+<if selectarticleurl && selectarticleurl!="">
   <assign showsearch="1">
   <assign showactions="0">
 <else>
index 538f9a2..5e5a86f 100755 (executable)
     <td colspan="3" valign="top">
       <p class="box-head"><b>${lang("start.search.title")}</b></p>
       <div class="box">
-        <call ContentSearch ("")>
+        <call ContentSearch("")>
       </div>
 
 <comment>