MODULE WebStd; (** AUTHOR "Luc Blaeser"; PURPOSE "Standard Active Element Library for Dynamic Webpage Generation"*) IMPORT DynamicWebpage, PrevalenceSystem, HTTPSupport, HTTPSession, GenericSort, XML, XMLObjects, DynamicStrings, Dates, Strings, TFClasses, KernelLog, WebHTTP; CONST DateTimeFormat* = "dd.mm.yyyy hh:nn:ss"; SessionContainerNamePrefix = "dxp-WebStd-sessioncontainer-"; SessionVariableNamePrefix = "dxp-WebStd-variable-"; SessionGuardNamePrefix = "dxp-WebStd-Guard-"; SessionVisitorCounterPrefix = "dxp-WebStd-VisitorCounter-"; TYPE (** normal XHTML attribute and element names should be lowercase *) (** hyperlink with implicit delegation of sessionid if target is not another webserver. * if href is not specified then the previously requested page is used as href . * usage expamle: * text or image *) Hyperlink* = OBJECT (DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(input: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR a: XML.Element; hrefString, attrName, sessionCounterStr: Strings.String; newUri: ARRAY 4096 OF CHAR; enum: XMLObjects.Enumerator; p: ANY; attr: XML.Attribute; content: XML.Content; dynStr: DynamicStrings.DynamicString; session: HTTPSession.Session; BEGIN session := HTTPSession.GetSession(request); (* session # NIL *) hrefString := input.GetAttributeValue("href"); IF ((hrefString = NIL) OR (~IsExternalHyperlink(hrefString^, request.header.host))) THEN IF (hrefString # NIL) THEN COPY(hrefString^, newUri); IF (Strings.Pos("?", hrefString^) = -1) THEN Strings.Append(newUri, "?") ELSE Strings.Append(newUri, "&") END ELSE (* href is the previous requested page *) Strings.Concat(request.shortUri, "?", newUri) END; Strings.Append(newUri, HTTPSession.HTTPVarSessionIdName); Strings.Append(newUri, "="); Strings.Append(newUri, session.sessionId); p := session.GetVariableValue(DynamicWebpage.StateCounterVariable); IF ((p # NIL) & (p IS DynamicStrings.DynamicString)) THEN dynStr := p(DynamicStrings.DynamicString); sessionCounterStr := dynStr.ToArrOfChar(); (* sessionCounterStr # NIL *) Strings.Append(newUri, "&"); Strings.Append(newUri, DynamicWebpage.StateCounterVariable); Strings.Append(newUri, "="); Strings.Append(newUri, sessionCounterStr^) END ELSE COPY(hrefString^, newUri) END; NEW(a); a.SetName("a"); a.SetAttributeValue("href", newUri); enum := input.GetAttributes(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); attr := p(XML.Attribute); attrName := attr.GetName(); IF ((attrName # NIL) & (attrName^ # "href") & (Strings.Pos("xmlns", attrName^) # 0)) THEN a.AddAttribute(attr) END END; enum := input.GetContents(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); content := p(XML.Content); a.AddContent(content) END; RETURN a END Transform; END Hyperlink; (** returns a HTTP header field value specified by name attribute and special header properties like "#ip", "#port", "#method" * *) GetHeaderField* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR fieldName : Strings.String; result : ARRAY 256 OF CHAR; BEGIN fieldName := elem.GetAttributeValue("name"); IF (fieldName # NIL) THEN WebHTTP.GetRequestPropertyValue(request.header, fieldName^, result); RETURN CreateXMLText(result) ELSE RETURN NIL END END Transform; END GetHeaderField; (** set a session global variable, usage example: * *) SetVariable* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR varName, varValue, encVarName: Strings.String; session: HTTPSession.Session; dynVarValue, dynVarName: DynamicStrings.DynamicString; BEGIN (* only DynamicString can have a type guard for PTR *) varName := elem.GetAttributeValue("name"); varValue := elem.GetAttributeValue("value"); IF ((varName # NIL) & (varValue # NIL)) THEN NEW(dynVarValue); dynVarValue.Append(varValue^); NEW(dynVarName); Concat(dynVarName, SessionVariableNamePrefix); dynVarName.Append(varName^); encVarName := dynVarName.ToArrOfChar(); session := HTTPSession.GetSession(request); session.AddVariableValue(encVarName^, dynVarValue) END; RETURN NIL END Transform; END SetVariable; (** get a session global variable, usage example: * *) GetVariable* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR varName, varValue, encVarName: Strings.String; session: HTTPSession.Session; dynVarValue, dynVarName: DynamicStrings.DynamicString; p: ANY; BEGIN varName := elem.GetAttributeValue("name"); IF (varName # NIL) THEN NEW(dynVarName); Concat(dynVarName, SessionVariableNamePrefix); dynVarName.Append(varName^); encVarName := dynVarName.ToArrOfChar(); session := HTTPSession.GetSession(request); p := session.GetVariableValue(encVarName^); IF ((p # NIL) & (p IS DynamicStrings.DynamicString)) THEN dynVarValue := p(DynamicStrings.DynamicString); IF (dynVarValue.Length() > 0) THEN varValue := dynVarValue.ToArrOfChar(); RETURN CreateXMLText(varValue^) END END END; RETURN NIL END Transform; END GetVariable; (** conditional element. If 'condition' contains exactly the text "true" then the 'Expression'-content is the result. * If 'condition' contains exactly the text 'false' then no result will be generated and active elements apearing * under the 'Expression'-element will not be transformed. * The condition value could be the result of another active element like * "WebStd:IsEqual". Usage example: * * true|false * .. * *) Guard* = OBJECT (DynamicWebpage.StateLessActiveElement) (* the 'Expression' subtree is only transformed if the condition has the value 'true'. Since the condition can have * further active element in its content, it can only be decided in the Transform()-method if the contents of * the 'Expression'-element will be used for the transformation result. * Therefore in PreTransform the 'Expression'-subtree is cut out and stored into the session using the * SessionGuardNamePrefix followed by the request.shortUri to support parallel requests of the same client * for different documents with if statements. The use of a state full active element would result in worse * performance, since each 'Guard'-occurence would have its own instances *) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR conditionElem, expressionElem: XML.Element; session: HTTPSession.Session; dynVarName: DynamicStrings.DynamicString; varName, condText: Strings.String; p: ANY; outContainer: XML.Container; BEGIN session := HTTPSession.GetSession(request); NEW(dynVarName); Concat(dynVarName, SessionGuardNamePrefix); dynVarName.Append(request.shortUri); varName := dynVarName.ToArrOfChar(); p := session.GetVariableValue(varName^); IF ((p # NIL) & (p IS XML.Element)) THEN expressionElem := p(XML.Element) ELSE expressionElem := NIL END; session.RemoveVariable(varName^); conditionElem := GetXMLSubElement(elem, "Condition"); IF (conditionElem # NIL) THEN condText := GetXMLCharContent(conditionElem); IF ((condText # NIL) & (condText^ = "true")) THEN IF (expressionElem # NIL) THEN NEW(outContainer); CopyXMLSubContents(expressionElem, outContainer); RETURN outContainer ELSE RETURN NIL END ELSIF ((condText # NIL) & (condText^ = "false")) THEN RETURN NIL ELSE NEW(outContainer); AppendXMLContent(outContainer, CreateXMLText("WebStd:Guard: Condition value must be either 'true' or 'false' but not ")); IF (condText # NIL) THEN AppendXMLContent(outContainer, CreateXMLText(condText^)) END; RETURN outContainer END ELSE RETURN CreateXMLText("No condition specified for WebStd:Guard.") END END Transform; PROCEDURE PreTransform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR expressionElem: XML.Element; session: HTTPSession.Session; dynVarName: DynamicStrings.DynamicString; varName: Strings.String; BEGIN session := HTTPSession.GetSession(request); expressionElem := GetXMLSubElement(elem, "Expression"); NEW(dynVarName); Concat(dynVarName, SessionGuardNamePrefix); dynVarName.Append(request.shortUri); varName := dynVarName.ToArrOfChar(); session.AddVariableValue(varName^, expressionElem); IF (expressionElem # NIL) THEN elem.RemoveContent(expressionElem) END; RETURN elem END PreTransform; END Guard; (** sequence over multiple requests of one page for a session. If the attribute 'circular' is set to 'true' then at the end of the * sequence the sequence will be restarted. if the sequence is non circular and has reached the last state then it stays in * the last state. Usage example: * * .. * .. * .. * * the event "SetState" with parameter "pos" can be used to set the actual state position for a sequence *) Sequence* = OBJECT (DynamicWebpage.StateFullActiveElement) VAR stateCounter: LONGINT; PROCEDURE &Init*; BEGIN stateCounter := 0 END Init; PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; BEGIN RETURN elem END Transform; PROCEDURE PreTransform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR p: ANY; enum: XMLObjects.Enumerator; counter: LONGINT; state, actState: XML.Element; stateName: Strings.String; container: XML.Container; content: XML.Content; circularVal: Strings.String; BEGIN actState:= NIL; counter := 0; enum := elem.GetContents(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); IF (p IS XML.Element) THEN state := p(XML.Element); stateName := state.GetName(); IF ((stateName # NIL) & (stateName^ = "State")) THEN IF (stateCounter = counter) THEN actState := state END; INC(counter); END END END; INC(stateCounter); circularVal := elem.GetAttributeValue("circular"); IF ((counter > 0) & (stateCounter >= counter)) THEN IF ((circularVal # NIL) & (circularVal^ = "true")) THEN stateCounter := stateCounter MOD counter ELSE stateCounter := counter-1 END END; IF (actState # NIL) THEN NEW(container); enum := actState.GetContents(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); content := p(XML.Content); container.AddContent(content) END; RETURN container ELSE (* end of the sequence was already reached *) RETURN NIL END END PreTransform; PROCEDURE SetState(request: HTTPSupport.HTTPRequest; params: DynamicWebpage.ParameterList); (* parameters "pos" *) VAR posStr: Strings.String; BEGIN posStr := params.GetParameterValueByName("pos"); IF (posStr # NIL) THEN Strings.StrToInt(posStr^, stateCounter) ELSE KernelLog.String("WebStd:Sequence - event handler 'SetState' has parameter 'pos'."); KernelLog.Ln END END SetState; PROCEDURE GetEventHandlers*() : DynamicWebpage.EventHandlerList; VAR list: DynamicWebpage.EventHandlerList; BEGIN NEW(list, 1); NEW(list[0], "SetState", SetState); RETURN list END GetEventHandlers; END Sequence; (** an equal comparison for two XML subforests in 'Arg1' and 'Arg2'. * Returns 'true' iff the subforests are equal otherwise 'false'. Usage example: * * * * *) IsEqual* = OBJECT (DynamicWebpage.StateLessActiveElement) PROCEDURE Compare(arg1, arg2: XML.Content) : BOOLEAN; VAR chars1, chars2: XML.Chars; str1, str2: Strings.String; cref1, cref2: XML.CharReference; ncont1, ncont2: XML.NameContent; attr1, attr2: XML.Attribute; cont1, cont2: XML.Container; enum1, enum2: XMLObjects.Enumerator; p1, p2: ANY; content1, content2: XML.Content; elem1, elem2: XML.Element; BEGIN IF ((arg1 = NIL) OR (arg2 = NIL)) THEN RETURN arg1 = arg2 ELSIF (arg1 IS XML.Chars) THEN IF (arg2 IS XML.Chars) THEN chars1 := arg1(XML.Chars); chars2 := arg2(XML.Chars); str1 := chars1.GetStr(); str2 := chars2.GetStr(); IF ((str1 # NIL) & (str2 # NIL)) THEN RETURN str1^ = str2^ ELSE RETURN str1 = str2 END ELSE RETURN FALSE END ELSIF (arg1 IS XML.CharReference) THEN IF (arg2 IS XML.CharReference) THEN cref1 := arg1(XML.CharReference); cref2 := arg2(XML.CharReference); RETURN cref1.GetCode() = cref2.GetCode() ELSE RETURN FALSE END ELSIF (arg1 IS XML.NameContent) THEN IF (arg2 IS XML.NameContent) THEN ncont1 := arg1(XML.NameContent); ncont2 := arg2(XML.NameContent); str1 := ncont1.GetName(); str2 := ncont2.GetName(); IF ((str1 = NIL) OR (str2 = NIL)) THEN IF (str1 # str2) THEN RETURN FALSE END ELSIF (str1^ # str2^) THEN RETURN FALSE END; IF (ncont1 IS XML.Attribute) THEN IF (ncont2 IS XML.Attribute) THEN attr1 := ncont1(XML.Attribute); attr2 := ncont2(XML.Attribute); str1 := attr1.GetValue(); str2 := attr2.GetValue(); IF ((str1 # NIL) & (str2 # NIL)) THEN RETURN str1^ = str2^ ELSE RETURN str1 = str2 END ELSE RETURN FALSE END END; RETURN TRUE ELSE RETURN FALSE END ELSIF (arg1 IS XML.Container) THEN IF (arg2 IS XML.Container) THEN cont1 := arg1(XML.Container); cont2 := arg2(XML.Container); enum1 := cont1.GetContents(); enum2 := cont2.GetContents(); WHILE ((enum1.HasMoreElements()) & (enum2.HasMoreElements())) DO p1 := enum1.GetNext(); p2 := enum2.GetNext(); content1 := p1(XML.Content); content2 := p2(XML.Content); IF (~Compare(content1, content2)) THEN RETURN FALSE END END; IF ((enum1.HasMoreElements()) OR (enum2.HasMoreElements())) THEN RETURN FALSE END; IF (cont1 IS XML.Element) THEN IF (cont2 IS XML.Element) THEN elem1 := cont1(XML.Element); elem2 := cont2(XML.Element); str1 := elem1.GetName(); str2 := elem2.GetName(); IF ((str1 # NIL) & (str2 # NIL)) THEN IF (str1^ # str2^) THEN RETURN FALSE END ELSE IF (str1 # str2) THEN RETURN FALSE END END; enum1 := elem1.GetAttributes(); enum2 := elem2.GetAttributes(); WHILE ((enum1.HasMoreElements()) & (enum2.HasMoreElements())) DO p1 := enum1.GetNext(); p2 := enum2.GetNext(); content1 := p1(XML.Content); content2 := p2(XML.Content); IF (~Compare(content1, content2)) THEN RETURN FALSE END END; IF ((enum1.HasMoreElements()) OR (enum2.HasMoreElements())) THEN RETURN FALSE END; RETURN TRUE ELSE RETURN FALSE END; END; RETURN TRUE ELSE RETURN FALSE END ELSE (* not supported *) RETURN FALSE END END Compare; PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR arg1, arg2: XML.Element; enum1, enum2: XMLObjects.Enumerator; p1, p2: ANY; content1, content2: XML.Content; BEGIN arg1 := GetXMLSubElement(elem, "Arg1"); arg2 := GetXMLSubElement(elem, "Arg2"); IF ((arg1 # NIL) & (arg2 # NIL)) THEN enum1 := arg1.GetContents(); enum2 := arg2.GetContents(); WHILE ((enum1.HasMoreElements()) & (enum2.HasMoreElements())) DO p1 := enum1.GetNext(); p2 := enum2.GetNext(); content1 := p1(XML.Content); content2 := p2(XML.Content); IF (~Compare(content1, content2)) THEN RETURN CreateXMLText("false") END END; IF ((enum1.HasMoreElements()) OR (enum2.HasMoreElements())) THEN RETURN CreateXMLText("false") END; RETURN CreateXMLText("true") ELSE RETURN CreateXMLText("WebStd:IsEqual: Missing 'Arg1' or 'Arg2' subelement") END END Transform; END IsEqual; (** returns 'true' if the content is 'false'. If the content is 'false' then it returns 'true'. Usage example * The content could be the results of active elements like 'IsEqual'. * true|false *) Not* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR str: Strings.String; BEGIN str := GetXMLCharContent(elem); IF ((str # NIL) & (str^ = "true")) THEN RETURN CreateXMLText("false") ELSIF ((str # NIL) & (str^ = "false")) THEN RETURN CreateXMLText("true") ELSE RETURN CreateXMLText("WebStd:Not - Content must be either 'true' or 'false'.") END END Transform; END Not; (** returns 'true' if both arguments 'Arg1' and 'Arg2' have content 'true'. If one of them has content 'false' the result will be * 'false'. The contents could be the results of active elements like 'IsEqual'. Usage example: * * true|false * true|false * *) And* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR arg1, arg2: XML.Element; str1, str2: Strings.String; BEGIN arg1 := GetXMLSubElement(elem, "Arg1"); arg2 := GetXMLSubElement(elem, "Arg2"); IF ((arg1 # NIL) & (arg2 # NIL)) THEN str1 := GetXMLCharContent(arg1); str2 := GetXMLCharContent(arg2); IF ((str1 # NIL) & (str1^ = "true") & (str2 # NIL) & (str2^ = "true")) THEN RETURN CreateXMLText("true") ELSIF ((str1 # NIL) & (str1^ = "true") & (str2 # NIL) & (str2^ = "false")) THEN RETURN CreateXMLText("false") ELSIF ((str1 # NIL) & (str1^ = "false") & (str2 # NIL) & (str2^ = "true")) THEN RETURN CreateXMLText("false") ELSIF ((str1 # NIL) & (str1^ = "false") & (str2 # NIL) & (str2^ = "false")) THEN RETURN CreateXMLText("false") ELSE RETURN CreateXMLText("WebStd:And - Content of 'Arg1' and 'Arg2' must be either 'true' or 'false'.") END ELSE RETURN CreateXMLText("WebStd:And - 'Arg1' or 'Arg2' subelements missing.") END END Transform; END And; (** returns 'true' if argument 'Arg1' or 'Arg2' (or both) has content 'true'. If both of them have content 'false' * the result will be 'false'. The contents could be the results of active elements like 'IsEqual'. Usage example: * * true|false * true|false * *) Or* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR arg1, arg2: XML.Element; str1, str2: Strings.String; BEGIN arg1 := GetXMLSubElement(elem, "Arg1"); arg2 := GetXMLSubElement(elem, "Arg2"); IF ((arg1 # NIL) & (arg2 # NIL)) THEN str1 := GetXMLCharContent(arg1); str2 := GetXMLCharContent(arg2); IF ((str1 # NIL) & (str1^ = "false") & (str2 # NIL) & (str2^ = "false")) THEN RETURN CreateXMLText("false") ELSIF ((str1 # NIL) & (str1^ = "true") & (str2 # NIL) & (str2^ = "false")) THEN RETURN CreateXMLText("true") ELSIF ((str1 # NIL) & (str1^ = "false") & (str2 # NIL) & (str2^ = "true")) THEN RETURN CreateXMLText("true") ELSIF ((str1 # NIL) & (str1^ = "true") & (str2 # NIL) & (str2^ = "true")) THEN RETURN CreateXMLText("true") ELSE RETURN CreateXMLText("WebStd:Or - Content of 'Arg1' and 'Arg2' must be either 'true' or 'false'.") END ELSE RETURN CreateXMLText("WebStd:Or - 'Arg1' or 'Arg2' subelements missing.") END END Transform; END Or; (** returns 'true' if argument either 'Arg1' or 'Arg2' has content 'true'. If both of them have the same content 'true' or 'false' * the result will be 'false'. The contents could be the results of active elements like 'IsEqual'. Usage example: * * true|false * true|false * *) Xor* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR arg1, arg2: XML.Element; str1, str2: Strings.String; BEGIN arg1 := GetXMLSubElement(elem, "Arg1"); arg2 := GetXMLSubElement(elem, "Arg2"); IF ((arg1 # NIL) & (arg2 # NIL)) THEN str1 := GetXMLCharContent(arg1); str2 := GetXMLCharContent(arg2); IF ((str1 # NIL) & (str1^ = "true") & (str2 # NIL) & (str2^ = "false")) THEN RETURN CreateXMLText("true") ELSIF ((str1 # NIL) & (str1^ = "false") & (str2 # NIL) & (str2^ = "true")) THEN RETURN CreateXMLText("true") ELSIF ((str1 # NIL) & (str1^ = "false") & (str2 # NIL) & (str2^ = "false")) THEN RETURN CreateXMLText("false") ELSIF ((str1 # NIL) & (str1^ = "true") & (str2 # NIL) & (str2^ = "true")) THEN RETURN CreateXMLText("false") ELSE RETURN CreateXMLText("WebStd:Xor - Content of 'Arg1' and 'Arg2' must be either 'true' or 'false'.") END ELSE RETURN CreateXMLText("WebStd:Xor - 'Arg1' or 'Arg2' subelements missing.") END END Transform; END Xor; (** a button that triggers a user event, usage example: * EventButton can optionally have an attribute 'href' to specify another target page as the current one. * If the target object is a statefull active element then 'objectid' has to used to specify the instance. * * * * ... * *) EventButton* = OBJECT (DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR labelName, methodName, objectName, objectIdName, moduleName, elemName, paramName, paramValue, hrefString, sessionCounterStr: Strings.String; form, input, param: XML.Element; enum: XMLObjects.Enumerator; p: ANY; newParamName, encStr: ARRAY 128 OF CHAR; content: XML.Content; session: HTTPSession.Session; dynStr: DynamicStrings.DynamicString; BEGIN session := HTTPSession.GetSession(request); (* session # NIL *) labelName := elem.GetAttributeValue("label"); methodName := elem.GetAttributeValue("method"); objectName := elem.GetAttributeValue("object"); objectIdName := elem.GetAttributeValue("objectid"); moduleName := elem.GetAttributeValue("module"); IF ((moduleName # NIL) & (methodName# NIL) & (objectName # NIL)) THEN NEW(form); form.SetName("form"); form.SetAttributeValue("method", "POST"); hrefString := elem.GetAttributeValue("href"); IF (hrefString # NIL) THEN form.SetAttributeValue("action", hrefString^) ELSE form.SetAttributeValue("action", request.shortUri) END; NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandModule); input.SetAttributeValue("value", moduleName^); form.AddContent(input); NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandObject); input.SetAttributeValue("value", objectName^); form.AddContent(input); NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandMethod); input.SetAttributeValue("value", methodName^); form.AddContent(input); IF (objectIdName # NIL) THEN NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandObjectId); input.SetAttributeValue("value", objectIdName^); form.AddContent(input) END; enum := elem.GetContents(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); IF (p IS XML.Element) THEN param := p(XML.Element); elemName := param.GetName(); IF ((elemName # NIL) & (elemName^ = "Param")) THEN paramName := param.GetAttributeValue("name"); paramValue := param.GetAttributeValue("value"); IF ((paramName # NIL) & (paramValue # NIL)) THEN HTTPSupport.HTTPEncode(paramName^, encStr); Strings.Concat(DynamicWebpage.HTTPVarCommandParamPrefix, encStr, newParamName); NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", newParamName); HTTPSupport.HTTPEncode(paramValue^, encStr); input.SetAttributeValue("value", encStr); form.AddContent(input) ELSE form.AddContent(param) END ELSE content := p(XML.Content); form.AddContent(content) END END END; NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", HTTPSession.HTTPVarSessionIdName); input.SetAttributeValue("value", session.sessionId); form.AddContent(input); p := session.GetVariableValue(DynamicWebpage.StateCounterVariable); IF ((p # NIL) & (p IS DynamicStrings.DynamicString)) THEN dynStr := p(DynamicStrings.DynamicString); sessionCounterStr := dynStr.ToArrOfChar(); (* sessionCounterStr # NIL *) NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.StateCounterVariable); input.SetAttributeValue("value", sessionCounterStr^); form.AddContent(input) END; NEW(input); input.SetName("input"); input.SetAttributeValue("type", "submit"); IF (labelName # NIL) THEN input.SetAttributeValue("value", labelName^) END; form.AddContent(input); RETURN form ELSE RETURN CreateXMLText("Missing module, object or method name for WebStd:EventButton") END END Transform; END EventButton; (** a hyperlink that triggers a user event. * EventLink can optionally have an attribute 'href' to specify another target page as the current one. * If the target object is a statefull active element then 'objectid' is used to specify the instance. * usage example: * * * * * ... * *) EventLink* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR a: XML.Element; newUri: ARRAY 4096 OF CHAR; enum, labelEnum: XMLObjects.Enumerator; p, labelp: ANY; attr: XML.Attribute; content, labelContent: XML.Content; methodName, objectName, objectIdName, moduleName, attrName, subElemName, paramName, paramValue, hrefString, sessionCounterStr: Strings.String; encStr: ARRAY 128 OF CHAR; subElem: XML.Element; session: HTTPSession.Session; dynStr: DynamicStrings.DynamicString; BEGIN session := HTTPSession.GetSession(request); methodName := elem.GetAttributeValue("method"); objectName := elem.GetAttributeValue("object"); objectIdName := elem.GetAttributeValue("objectid"); moduleName := elem.GetAttributeValue("module"); IF ((moduleName # NIL) & (methodName# NIL) & (objectName # NIL)) THEN hrefString := elem.GetAttributeValue("href"); IF (hrefString # NIL) THEN COPY(hrefString^, newUri); IF (Strings.Pos("?", hrefString^) = -1) THEN Strings.Append(newUri, "?") ELSE Strings.Append(newUri, "&") END ELSE Strings.Concat(request.shortUri, "?", newUri) END; Strings.Append(newUri, HTTPSession.HTTPVarSessionIdName); Strings.Append(newUri, "="); Strings.Append(newUri, session.sessionId); Strings.Append(newUri, "&"); Strings.Append(newUri, DynamicWebpage.HTTPVarCommandModule); Strings.Append(newUri, "="); Strings.Append(newUri, moduleName^); Strings.Append(newUri, "&"); Strings.Append(newUri, DynamicWebpage.HTTPVarCommandObject); Strings.Append(newUri, "="); Strings.Append(newUri, objectName^); Strings.Append(newUri, "&"); Strings.Append(newUri, DynamicWebpage.HTTPVarCommandMethod); Strings.Append(newUri, "="); Strings.Append(newUri, methodName^); IF (objectIdName # NIL) THEN Strings.Append(newUri, "&"); Strings.Append(newUri, DynamicWebpage.HTTPVarCommandObjectId); Strings.Append(newUri, "="); Strings.Append(newUri, objectIdName^) END; p := session.GetVariableValue(DynamicWebpage.StateCounterVariable); IF ((p # NIL) & (p IS DynamicStrings.DynamicString)) THEN dynStr := p(DynamicStrings.DynamicString); sessionCounterStr := dynStr.ToArrOfChar(); (* sessionCounterStr # NIL *) Strings.Append(newUri, "&"); Strings.Append(newUri, DynamicWebpage.StateCounterVariable); Strings.Append(newUri, "="); Strings.Append(newUri, sessionCounterStr^) END; NEW(a); a.SetName("a"); enum := elem.GetAttributes(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); attr := p(XML.Attribute); attrName := attr.GetName(); IF ((attrName # NIL) & (attrName^ # "href") & (attrName^ # "method") & (attrName^ # "object") & (attrName^ # "objectid") & (attrName^ # "module") & (Strings.Pos("xmlns", attrName^) # 0)) THEN a.AddAttribute(attr) END END; enum := elem.GetContents(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); content := p(XML.Content); IF (content IS XML.Element) THEN subElem := content(XML.Element); subElemName := subElem.GetName(); IF (subElemName^ = "Param") THEN paramName := subElem.GetAttributeValue("name"); paramValue := subElem.GetAttributeValue("value"); IF ((paramName # NIL) & (paramValue # NIL)) THEN Strings.Append(newUri, "&"); Strings.Append(newUri, DynamicWebpage.HTTPVarCommandParamPrefix); HTTPSupport.HTTPEncode(paramName^, encStr); Strings.Append(newUri, encStr); Strings.Append(newUri, "="); HTTPSupport.HTTPEncode(paramValue^, encStr); Strings.Append(newUri, encStr) END ELSIF ((subElemName # NIL) & (subElemName^ = "Label")) THEN labelEnum := subElem.GetContents(); WHILE (labelEnum.HasMoreElements()) DO labelp := labelEnum.GetNext(); labelContent := labelp(XML.Content); a.AddContent(labelContent) END END END END; a.SetAttributeValue("href", newUri); RETURN a ELSE RETURN CreateXMLText("Missing module, object or method name for WebStd:EventLink") END END Transform; END EventLink; (** a formular that triggers a user event with parameters if submitted. * transfer-method is HTTP POST. * Formular can have an optionally attribute 'href' to specify another target page as the current one. * If the target object is a statefull active element then 'objectid' has to used to specfiy the instance. * usage example: * * ... * * * * ... * * ... * *) Formular* = OBJECT(DynamicWebpage.StateLessActiveElement) PROCEDURE Transform*(elem: XML.Element; request: HTTPSupport.HTTPRequest) : XML.Content; VAR methodName, objectName, objectIdName, moduleName, attrName, hrefString, sessionCounterStr: Strings.String; session: HTTPSession.Session; form, input: XML.Element; enum: XMLObjects.Enumerator; p: ANY; content: XML.Content; attr: XML.Attribute; dynStr: DynamicStrings.DynamicString; BEGIN session := HTTPSession.GetSession(request); (* session # NIL *) methodName := elem.GetAttributeValue("method"); objectName := elem.GetAttributeValue("object"); objectIdName := elem.GetAttributeValue("objectid"); moduleName := elem.GetAttributeValue("module"); IF ((moduleName # NIL) & (methodName# NIL) & (objectName # NIL)) THEN NEW(form); form.SetName("form"); form.SetAttributeValue("method", "post"); hrefString := elem.GetAttributeValue("href"); IF (hrefString # NIL) THEN form.SetAttributeValue("action", hrefString^) ELSE form.SetAttributeValue("action", request.shortUri) END; enum := elem.GetAttributes(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); attr := p(XML.Attribute); attrName := attr.GetName(); IF ((attrName # NIL) & (attrName^ # "href") & (attrName^ # "method")) THEN form.AddAttribute(attr) END END; NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandModule); input.SetAttributeValue("value", moduleName^); form.AddContent(input); NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandObject); input.SetAttributeValue("value", objectName^); form.AddContent(input); NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandMethod); input.SetAttributeValue("value", methodName^); form.AddContent(input); IF (objectIdName # NIL) THEN NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.HTTPVarCommandObjectId); input.SetAttributeValue("value", objectIdName^); form.AddContent(input) END; NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", HTTPSession.HTTPVarSessionIdName); input.SetAttributeValue("value", session.sessionId); form.AddContent(input); enum := elem.GetContents(); WHILE (enum.HasMoreElements()) DO p := enum.GetNext(); content := p(XML.Content); RenameInputAttr(content); form.AddContent(content) END; p := session.GetVariableValue(DynamicWebpage.StateCounterVariable); IF ((p # NIL) & (p IS DynamicStrings.DynamicString)) THEN dynStr := p(DynamicStrings.DynamicString); sessionCounterStr := dynStr.ToArrOfChar(); (* sessionCounterStr # NIL *) NEW(input); input.SetName("input"); input.SetAttributeValue("type", "hidden"); input.SetAttributeValue("name", DynamicWebpage.StateCounterVariable); input.SetAttributeValue("value", sessionCounterStr^); form.AddContent(input) END; RETURN form ELSE RETURN CreateXMLText("Missing module, object or method name for WebStd:Formular") END END Transform; (* rename 'name' attribute for ,