heitml Source Display
File: /usr/local/httpd/htdocs/heitml2.0/lib/formbase.hei
// Basic Form Components
// $Id: formbase.hei,v 1.87 2000/08/29 19:20:23 heitml Exp $
// Copyright (C) 1996-2000 by H.E.I. Informationssysteme GmbH and suppliers.
// This file is part of heitml. All licensing conditions of the
// heitml package apply. See the license file contained in the heitml
// distribution.
<includeonce>//
<include component.hei>//
<include std.hei>//
<include javasc.hei>//
<include browcomp.hei>//
<include panel.hei>//
// <include formfields.hei>//
//
//
// Use of globals:
// gl._curpanel current panel
// gl._curselect current select
// /Use
//
// Form environments
//
// Abstract base class for panels (sets of controls).
// A panel is either a form or a sub-panel of another panel.
// A panel may contain fields, buttons and sub-panels.
<
defclass _panelbase;
inherit component, panel;
// Attribute members:
// array buttons panel's buttons
// array fields panel's fields
// array subpanels panel's sub-panels
// object encpanel panel that has this as sub-panel, possibly null
// object form panel's form
// string panelid unique panel id (must be unique within the form)
// state panel state: display, invisible, enabled, disabled, readonly
// bool erremitted are panel's errors already emitted?
// tuple errmsg map field names to error message strings
// tuple ff map field names to current form data,
// is panel's initial actual value attribute,
// !isnull (errmsg[name]) => !isdecl (ff[name])
// tuple clvalue map field names to client values, i.e.
// string(s) sent by client
// bool isinitial is ff just the inital field values
// string onsubmit JavaScript event function
// Define context F form, T table, possibly m multipart/form-data.
defenv _evalcontext;
if (tolower (default (this._param.method, "")) == "post")
&& (tolower (default (this._param.enctype, "")) == "multipart/form-data");
context = "Fm";
else;
context = "F";
/if;
_addcontext context=context priv="T"; defbody; /_addcontext;
/defenv;
// Return control name for field name NAME.
def control_name name;
return this.panelid + '.' + name;
/def;
// Register a sub-panel.
def regsubpanel obj; arappend (this.subpanels, obj); /def;
// Register a button OBJ.
def regbutton obj; arappend (this.buttons, obj); /def;
// Register a field OBJ.
// If VALUE is not null, it overrides the field's initial value.
def regfield obj value;
if !isdecl(this.ff[obj.name]) && ! (isdecl(this.clvalue) && isdecl(this.clvalue[obj.name]));
this.ff[obj.name] = value;
/if;
this.isinitial = this.isinitial && this.ff[obj.name] == value;
arappend (this.fields, obj);
/def;
/*
// Define and return this.clvalue[NAME].
// CLFF is this.ff[NAME] transformed into internal field state.
// CLIV is this.ivalue[NAME] transformed into internal field state.
// Update this.isinitial accordingly.
def clvalue name clff cliv;
if isdecl (this.ff[name]);
this.clvalue[name] = clff;
elsif !isdecl (this.clvalue[name]);
this.clvalue[name] = cliv;
/if;
this.isinitial = this.isinitial && (this.clvalue[name] == cliv);
return this.clvalue[name];
/def;
*/
// Report error ERRMSG for field NAME, or panel if NAME is "".
def error errmsg name;
// EXTEND one name cannot have multiple errors
this.errmsg[name] = default (this.errmsg[name], errmsg);
/def;
// To be called if a field does not emit a control.
// Ensure that the association of NAME with VALUE is available for
// the processing agent.
def save_value name value;
><input type="hidden" name=<? this.control_name (name) "P"> <? value "Pn">><hei
/def;
// Return whether to perform a mandatroy check, called during processing
// MANDATORY is the field's idea.
// NOTE this is called during form processing not during form display
def field_mandatory field mandatory;
return mandatory;
/def;
// Return field state.
// STATE is the field's idea, may be null.
def field_state field state;
// ? state; ? field.state;
return default (state, this.state);
/def;
// Return BUTTON state.
// STATE is the button's idea, may be null.
def button_state button state;
return default (state, this.state);
/def;
// Update this.clvalue from MSG, return pressed button if any.
def update msg;
subbtn = null;
// update sub-panels
forin i this.subpanels;
subbtn = default (this.subpanels[i].update(msg), subbtn);
/forin;
// update panel state
if !isnull(ff[this.panelid]);
// this.clvalue = tuassign (emptytuple, ff[this.panelid]);
// search for button
forin i this.buttons;
btn = this.buttons[i];
if !isempty (ff[this.panelid][btn.name]) && (isnull (btn.value) ||
(ff[this.panelid][btn.name] == btn.value));
return btn;
/if;
/forin;
/if;
return subbtn;
/def;
def clearffenabled;
// Delete all enabled form fields
forin i this.fields;
if this.fields[i].state!="display"; tudelfield (this.ff[this.fields[i].name]); /if;
/forin;
this.errmsg = emptytuple;
/def;
// Reset this panel and its sub-panels to their initial values.
def reset;
this.ff = emptytuple;
this.clvalue = emptytuple;
forin i this.subpanels;
this.subpanels[i].reset();
/forin;
/def;
// Submit this panel's and its sub-panels' clvalue into the respective ff.
// Button BTN triggered the submission.
// Return null for success, else string.
def submit btn;
res = null; this.ok=true;
this.errmsg = emptytuple;
in = ff[this.panelid];
// clearffenabled();
// EXTEND button should be able to determine fields to check
if !isempty(in);
scratch=emptytuple;
forin i this.fields; // filter through check() into ff
field = this.fields[i];
if field.state!="display";
field.fcheck (in this.ff this.clvalue scratch);
/*
val = field.check (default (in[field.name]));
if !isdecl (this.errmsg[field.name]);
this.ff[field.name] = val; TuDelField (this.clvalue[field.name]);
else
this.clvalue[field.name]=in[field.name];/if;
TuDelField (this.ff[field.name]);
/if;
*/
/if;
/forin;
/if;
if isdecl (this.errmsg) && len (this.errmsg) != 0;
res = "Bad form fields"; this.ok = false;
/if;
forin i this.subpanels; // submit sub-panelsTuDelField (this.ff[field.name])
if !isnull (this.subpanels[i].submit (btn));
res = "Bad form fields"; this. ok = false;
/if;
/forin;
return res;
/def;
// Process this panel and its sub panels.
// Return null on success, string on failure.
// EXTEND rename to process() and add argument ff when heitml can
// EXTEND call shadowed inherited code
def process_panel;
// process sub-panels
forin i this.subpanels;
tmp = this.subpanels[i].process_panel();
if !isnull (tmp); return tmp; /if;
/forin;
// process this panel
// EXTEND field.process() necessary?
return null;
/def;
// Each panel in a form needs a unique PANELID.
// The panel edits the tuple VALUE, i.e. reads initial values from
// it and stores the edited values into it.
// STATE is a default for the panel's fields, see field_state().
// Caution: The edited tuple is sticky, i.e. it is fixed when the
// panel is created. Further calls do not switch the edited tuple.
defenv dopanel;
// this.panelid = panelid;
if !isdecl(this._bid); this._bid=stdmakeuniq("p");/if;
this.panelid = this._bid;
// this.state = state;
this.state = default (this.state, "enabled");
// this.ivalue = tuassign (emptytuple, this.ff);
// this.isinitial = true;
// leave alone this.clvalue, this.ff and this.errmsg, they are
// set by reset(), submit()
if !isempty(gl._curpanel); gl._curpanel.regsubpanel(this); /if;
this.clvalue = default (this.clvalue, emptytuple);
this.ff = default (value, this.ff, emptytuple);
this.errmsg = default (this.errmsg, emptytuple);
this.erremitted = false;
this.subpanels = array(0);
this.fields = array(0);
this.buttons = array(0);
_dopanel; defbody; /_dopanel;
this.passwdok=null;
/defenv;
/defclass
// Emit unemitted errors for panel and its subpanels delimited by DELIM
// DELIM must not contain "%" WHY ?
def panelerrors js=null html=null delim="<br>" @rest ...;
inherit component;
def jsemiterrors panel;
if !htmlbool(panel.erremitted)&& isdecl(panel.errmsg);
forin i panel.errmsg;
if !isempty(panel.errmsg[i]);
? panel.errmsg[i] "H"; ?"\n";
/if;
/forin;
forin i panel.subpanels;
this.jsemiterrors (panel.subpanels[i], false);
/forin;
/if;
/def;
def emiterrors panel delim first;
if !htmlbool(panel.erremitted) && isdecl(panel.errmsg);
forin i panel.errmsg;
if !first; ? delim "A"; /if;
? panel.errmsg[i] "H";
// EXTEND link that moves focus to bad field
first = false;
/forin;
forin i panel.subpanels;
this.emiterrors (panel.subpanels[i], delim, false);
/forin;
panel.erremitted = true;
/if;
/def;
def clearerrors panel;
forin i panel.subpanels;
this.clearerrors (panel.subpanels[i]);
/forin;
panel.errmsg=emptytuple;
/def;
_marker;
if htmlbool(js);
assign m; this.jsemiterrors (gl._curpanel); /assign;
if !isempty(trim(m)); js> alert(<? m "J">) </js; /if;
/if;
if htmlbool(html) || (!htmlbool(html) && !htmlbool(js));
if !isempty(rest) ><\font <? rest "Pn">>< /if;
emiterrors (gl._curpanel, delim, true);
if !isempty(rest) ><\/font>< /if;
/if;
this.clearerrors (gl._curpanel);
/_marker;
/def
// Abstract base class for sesform and sleform
// Adds form and field checking and processing and error handling
// Provides means to process the control data set: check() updates the
// form state and filters each field's clvalue[field.name] through
// field.check() into this.ff[field.name]. After successful check(),
// process() calls the pressed button's process().
defclass _formbase;
inherit _panelbase, simpleform;
// Attribute members:
// string _bid see control_name(), interactive
// bool success form successfully submitted?
// object btn the submit button object
// string enctype attribute for HTML form element
// string method attribute for HTML form element
// oncheck hook called after checking form fields
def oncheck msg; return null; /def;
// Check MSG sent by client and update form state.
// Return null if MSG is valid, else string.
// Implements callback interactive.check().
// Update and submit or reset panel if necessary, define this.btn.
def check msg;
this.success=false; this.passwdok=null;
this.btn = update (msg);
if !isnull(this.btn) && this.btn.type == "reset";
this.btn.panel.reset(); this.ok=false;
return null;
/if;
tmp = submit (this.btn);
ot = this.oncheck(msg);
if isnull(ot); return tmp; else this.ok=false; return ot; /if;
/def;
// Process MSG sent by client.
// Return null on success, string on failure.
// Implements callback interactive.process().
// Process panels, then button, stopping on errors.
def _formbase_process msg;
if !isnull(this.btn) && this.btn.type == "reset"; return null; /if;
tmp = process_panel();
if !isnull (tmp); return tmp; /if;
if isnull(this.btn); return null; /if; // no button, nothing to process
tmp = this.btn.process (this.btn.panel.ff);
if isnull(tmp); this.success = true; return null; /if;
if isbool (tmp); this.success = tmp; return null; /if;
error (tmp, "");
return tmp;
/def;
defenv doformbase value state method enctype action onsubmit name rest;
if state=="invisible"; return; /if;
if !isdecl(this.ok); this.ok=true; /if;
this.btn = default (this.btn, null);
this.success = default (this.success, false);
dosimpleform value state method enctype action onsubmit name rest;
defbody;
if !this.erremitted; // If error messages are not yet shown do it now
><br><panelerrors html color="red" size="+1";
/if;
/dosimpleform;
TuDelField (this.errmsg);
TuDelField (this.erremitted);
TuDelField (this.passwdok);
/defenv;
/defclass>