Worked on skin support

This commit is contained in:
hns 2001-01-10 19:31:05 +00:00
parent 30f539b396
commit b0d134b811
5 changed files with 149 additions and 52 deletions

View file

@ -37,14 +37,12 @@ public class ResponseTrans implements Serializable {
// the buffers used to build the single body parts - // the buffers used to build the single body parts -
// transient, response must be constructed before this is serialized // transient, response must be constructed before this is serialized
public transient String title; public transient String title, head, body, message;
public transient String body;
public transient String message;
public ResponseTrans () { public ResponseTrans () {
super (); super ();
title = body = message = ""; title = head = body = message = "";
} }
public void reset () { public void reset () {

View file

@ -12,16 +12,16 @@ import helma.objectmodel.INode;
/** /**
* An EcmaScript object to access the form data sent with a HTTP request * An EcmaScript object that makes stuff in a hashtable accessible as its properties
*/ */
public class ESRequestData extends ESWrapper { public class ESRequestData extends ESObject {
private Hashtable data; private Hashtable data;
private RequestEvaluator reval; private RequestEvaluator reval;
public ESRequestData (ESObject prototype, Evaluator evaluator, RequestEvaluator reval) { public ESRequestData (RequestEvaluator reval) {
super (prototype, evaluator); super (null, reval.evaluator);
this.reval = reval; this.reval = reval;
} }
@ -33,11 +33,11 @@ public class ESRequestData extends ESWrapper {
* Overridden to make the object read-only * Overridden to make the object read-only
*/ */
public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException { public void putProperty(String propertyName, ESValue propertyValue, int hash) throws EcmaScriptException {
throw new EcmaScriptException ("Can't set property, req.data is read-only"); throw new EcmaScriptException ("Can't set property, object is read-only");
} }
public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException { public boolean deleteProperty(String propertyName, int hash) throws EcmaScriptException {
throw new EcmaScriptException ("Can't delete property, req.data is read-only"); throw new EcmaScriptException ("Can't delete property, object is read-only");
} }
public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException { public ESValue getProperty(String propertyName, int hash) throws EcmaScriptException {

View file

@ -77,6 +77,8 @@ public class HopExtension {
reval.esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp)); reval.esNodePrototype.putHiddenProperty ("href", new NodeHref ("href", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp)); reval.esNodePrototype.putHiddenProperty ("setParent", new NodeSetParent ("setParent", evaluator, fp));
reval.esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp)); reval.esNodePrototype.putHiddenProperty ("invalidate", new NodeInvalidate ("invalidate", evaluator, fp));
reval.esNodePrototype.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, reval, false, false));
reval.esNodePrototype.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, false, true));
// methods that give access to properties and global user lists // methods that give access to properties and global user lists
go.putHiddenProperty("Node", node); // register the constructor for a plain Node object. go.putHiddenProperty("Node", node); // register the constructor for a plain Node object.
@ -97,7 +99,10 @@ public class HopExtension {
go.putHiddenProperty("getXmlDocument", new GlobalGetXmlDocument ("getXmlDocument", evaluator, fp)); go.putHiddenProperty("getXmlDocument", new GlobalGetXmlDocument ("getXmlDocument", evaluator, fp));
go.putHiddenProperty("getHtmlDocument", new GlobalGetHtmlDocument ("getHtmlDocument", evaluator, fp)); go.putHiddenProperty("getHtmlDocument", new GlobalGetHtmlDocument ("getHtmlDocument", evaluator, fp));
go.putHiddenProperty("jdomize", new GlobalJDOM ("jdomize", evaluator, fp)); go.putHiddenProperty("jdomize", new GlobalJDOM ("jdomize", evaluator, fp));
go.putHiddenProperty("getSkin", new GlobalGetSkin ("getSkin", evaluator, fp, reval)); go.putHiddenProperty("getSkin", new GlobalGetSkin ("getSkin", evaluator, fp));
go.putHiddenProperty("createSkin", new GlobalCreateSkin ("createSkin", evaluator, fp));
go.putHiddenProperty("renderSkin", new RenderSkin ("renderSkin", evaluator, fp, reval, true, false));
go.putHiddenProperty("renderSkin_as_string", new RenderSkin ("renderSkin_as_string", evaluator, fp, reval, true, true));
go.deleteProperty("exit", "exit".hashCode()); go.deleteProperty("exit", "exit".hashCode());
// and some methods for session management from JS... // and some methods for session management from JS...
@ -548,19 +553,66 @@ public class HopExtension {
} }
} }
/**
* Get a parsed Skin from the central skin repository
*/
class GlobalGetSkin extends BuiltinFunctionObject { class GlobalGetSkin extends BuiltinFunctionObject {
RequestEvaluator reval; GlobalGetSkin (String name, Evaluator evaluator, FunctionPrototype fp) {
GlobalGetSkin (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) { super (fp, evaluator, name, 1);
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
throw new EcmaScriptException ("getSkin() is not implemented yet, use createSkin() instead");
}
}
/**
* Get a parsed Skin from an app-managed skin text
*/
class GlobalCreateSkin extends BuiltinFunctionObject {
GlobalCreateSkin (String name, Evaluator evaluator, FunctionPrototype fp) {
super (fp, evaluator, name, 1); super (fp, evaluator, name, 1);
this.reval = reval;
} }
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException { public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length != 1 || ESNull.theNull.equals (arguments[0])) if (arguments.length != 1 || ESNull.theNull.equals (arguments[0]))
throw new EcmaScriptException ("getSkin must be called with one String argument!"); throw new EcmaScriptException ("getSkin must be called with one String argument!");
return new ESWrapper (new Skin (arguments[0].toString(), reval), evaluator); return new ESWrapper (new Skin (arguments[0].toString()), evaluator);
} }
} }
/**
* Render a skin
*/
class RenderSkin extends BuiltinFunctionObject {
RequestEvaluator reval;
boolean global;
boolean asString;
RenderSkin (String name, Evaluator evaluator, FunctionPrototype fp,
RequestEvaluator reval, boolean global, boolean asString) {
super (fp, evaluator, name, 1);
this.reval = reval;
this.global = global;
this.asString = asString;
}
public ESValue callFunction (ESObject thisObject, ESValue[] arguments) throws EcmaScriptException {
if (arguments.length != 1 || !(arguments[0] instanceof ESWrapper))
throw new EcmaScriptException ("renderSkin must be called with one Skin argument!");
try {
Skin skin = (Skin) ((ESWrapper) arguments[0]).toJavaObject ();
ESNode handlerNode = global ? null : (ESNode) thisObject;
if (asString)
reval.res.pushStringBuffer ();
skin.render (reval, handlerNode);
if (asString)
return new ESString (reval.res.popStringBuffer ());
} catch (ClassCastException x) {
throw new EcmaScriptException ("renderSkin must be called with one Skin argument!");
}
return ESNull.theNull;
}
}
class GlobalGetUser extends BuiltinFunctionObject { class GlobalGetUser extends BuiltinFunctionObject {
RequestEvaluator reval; RequestEvaluator reval;
GlobalGetUser (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) { GlobalGetUser (String name, Evaluator evaluator, FunctionPrototype fp, RequestEvaluator reval) {

View file

@ -108,7 +108,7 @@ public class RequestEvaluator implements Runnable {
appnode = new ESAppNode (app.appnode, this); appnode = new ESAppNode (app.appnode, this);
global.putHiddenProperty ("app", appnode); global.putHiddenProperty ("app", appnode);
reqPath = new ArrayPrototype (evaluator.getArrayPrototype(), evaluator); reqPath = new ArrayPrototype (evaluator.getArrayPrototype(), evaluator);
reqData = new ESRequestData (evaluator.getObjectPrototype(), evaluator, this); reqData = new ESRequestData (this);
} catch (Exception e) { } catch (Exception e) {
System.err.println("Cannot initialize interpreter"); System.err.println("Cannot initialize interpreter");

View file

@ -8,6 +8,8 @@ import java.io.*;
import helma.framework.*; import helma.framework.*;
import FESI.Data.*; import FESI.Data.*;
import FESI.Exceptions.*; import FESI.Exceptions.*;
import helma.objectmodel.INode;
import helma.objectmodel.IServer;
/** /**
@ -18,10 +20,8 @@ import FESI.Exceptions.*;
public class Skin { public class Skin {
Object[] parts; Object[] parts;
RequestEvaluator reval;
public Skin (String content, RequestEvaluator reval) { public Skin (String content) {
this.reval = reval;
parse (content); parse (content);
} }
@ -55,13 +55,15 @@ public class Skin {
parts = partBuffer.toArray (); parts = partBuffer.toArray ();
} }
public String toString () { public void render (RequestEvaluator reval, ESNode handlerNode) {
if (parts == null) if (parts == null)
return ""; return;
StringBuffer b = new StringBuffer (); for (int i=0; i<parts.length; i++) {
for (int i=0; i<parts.length; i++) if (parts[i] instanceof Macro)
b.append (parts[i]); ((Macro) parts[i]).render (reval, handlerNode);
return b.toString (); else
reval.res.write (parts[i]);
}
} }
static final int HANDLER = 0; static final int HANDLER = 0;
@ -73,11 +75,11 @@ public class Skin {
String handler; String handler;
String name; String name;
ESObject parameters; Hashtable parameters;
public Macro (String str) { public Macro (String str) {
parameters = new ObjectPrototype (null, reval.evaluator); parameters = new Hashtable ();
int l = str.length (); int l = str.length ();
char cnt[] = new char[l]; char cnt[] = new char[l];
@ -108,9 +110,7 @@ public class Skin {
case '\'': case '\'':
if (!escape && state == PARAMVALUE) { if (!escape && state == PARAMVALUE) {
if (quotechar == cnt[i]) { if (quotechar == cnt[i]) {
try { parameters.put (lastParamName, b.toString());
parameters.putHiddenProperty (lastParamName, new ESString (b.toString()));
} catch (EcmaScriptException badluck) {}
b.setLength (0); b.setLength (0);
state = PARAMNAME; state = PARAMNAME;
quotechar = '\u0000'; quotechar = '\u0000';
@ -133,9 +133,7 @@ public class Skin {
b.setLength (0); b.setLength (0);
state = PARAMNAME; state = PARAMNAME;
} else if (state == PARAMVALUE && quotechar == '\u0000') { } else if (state == PARAMVALUE && quotechar == '\u0000') {
try { parameters.put (lastParamName, b.toString());
parameters.putHiddenProperty (lastParamName, new ESString (b.toString()));
} catch (EcmaScriptException badluck) {}
b.setLength (0); b.setLength (0);
state = PARAMNAME; state = PARAMNAME;
} else if (state == PARAMVALUE) } else if (state == PARAMVALUE)
@ -156,43 +154,92 @@ public class Skin {
escape = false; escape = false;
} }
} }
if (lastParamName != null && b.length() > 0) try { if (lastParamName != null && b.length() > 0)
parameters.putHiddenProperty (lastParamName, new ESString (b.toString())); parameters.put (lastParamName, b.toString());
} catch (EcmaScriptException noluck) {}
} }
public String toString () { public void render (RequestEvaluator reval, ESNode handlerNode) {
if ("response".equalsIgnoreCase (handler)) {
renderFromResponse (reval);
return;
}
try { try {
ESValue[] arguments = new ESValue[2]; ESObject handlerObject = null;
arguments[0] = new ESString (name);
arguments[1] = parameters; ESValue[] arguments = new ESValue[1];
ESNode handlerNode = null; ESRequestData par = new ESRequestData (reval);
par.setData (parameters);
arguments[0] = par;
if (handler != null) { if (handler != null) {
int l = reval.reqPath.size(); // not a macro handled by global - check handler object
for (int i=l-1; i>=0; i--) { if (handlerNode != null) {
if (handler.equalsIgnoreCase (((ESNode) reval.reqPath.getProperty(i)).getPrototypeName())) { // was called with this object - check it or its parents for matching prototype
handlerNode = (ESNode) reval.reqPath.getProperty(i); if (!handler.equalsIgnoreCase (handlerNode.getPrototypeName ())) {
break; // the handler object is not what we want
INode n = handlerNode.getNode();
while (n != null) {
if (handler.equalsIgnoreCase (n.getPrototype())) {
handlerObject = reval.getNodeWrapper (n);
break;
}
n = n.getParent ();
}
} else {
// we already have the right handler object
handlerObject = handlerNode;
} }
} }
} else {
handlerNode = (ESNode) reval.reqPath.getProperty(0); if (handlerObject == null) {
// eiter because handlerNode == null or the right object wasn't found in the targetNode path
// go check request path for an object with matching prototype
int l = reval.reqPath.size();
for (int i=l-1; i>=0; i--) {
if (handler.equalsIgnoreCase (((ESNode) reval.reqPath.getProperty(i)).getPrototypeName())) {
handlerObject = (ESNode) reval.reqPath.getProperty(i);
break;
}
}
}
} else {
// this is a global macro with no handler specified
handlerObject = reval.global;
} }
if (handlerNode != null) { if (handlerObject != null) {
return handlerNode.doIndirectCall (reval.evaluator, handlerNode, "handleMacro", arguments).toString(); handlerObject.doIndirectCall (reval.evaluator, handlerObject, name+"_macro", arguments);
} else { } else {
return "[HopMacro unhandled: "+handler+"."+name+"]"; String msg = "[HopMacro unhandled: "+handler+"."+name+"]";
reval.res.write (" "+msg+" ");
IServer.getLogger().log (msg);
} }
} catch (Exception x) { } catch (Exception x) {
return "[HopMacro error: "+x.getMessage()+"]"; String msg = "[HopMacro error: "+x+"]";
reval.res.write (" "+msg+" ");
IServer.getLogger().log (msg);
} }
} }
private void renderFromResponse (RequestEvaluator reval) {
if ("title".equals (name))
reval.res.write (reval.res.title);
else if ("head".equals (name))
reval.res.write (reval.res.head);
else if ("body".equals (name))
reval.res.write (reval.res.body);
else if ("message".equals (name))
reval.res.write (reval.res.message);
}
public String toString () {
return "[HopMacro: "+handler+","+name+"]";
}
} }