heitml Source Display
File: /usr/local/httpd/htdocs/heitml2.0/lib/formfields.hei
// heitml Form Fields
// Copyright (C) 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>//
<
//
// Buttons
// The INPUT element uses the value attribute to render the button.
// The BUTTON element uses its contents, which is more flexible.
// Unfortunately, current browsers don't grok the BUTTON element correctly. To
// faciliate future use of BUTTON, heitml buttons are environments.
// Their attribute value is usable as button label.
// The content is ignored.
// If value is null, contents is used as value for INPUT; it
// should not contain markup. Caution, this submits an unintended
// value for the button.
// Frontend for button element that currently uses INPUT instead.
defenv _allbrowserbutton type=null name=null value=null state=null rest=null contents=null;
type=default(type,"submit");
if state!="display";
assign contents; defbody; /assign;
// if isempty(contents);
><input type=<? type "P"> <? name "Pn"> <? value "Pn"> <? rest "Pn">><hei
// else
// button element does not work properly in all browsers
// ><button <? type "Pn"> <? name "Pn"> <? value "Pn"> <? state "Pn"> <? rest "Pn"> ><
// ? contents "A";
// ><input type=<? type "P"> <? name "Pn"> <? value "Pn"> <? rest "Pn">><hei
// ></button><hei
// /if;
/if;
/defenv;
defenv _heitmlbutton layout type name value form onsubmit rest;
type=default(type,"submit");
l = gl._complevel; if gl._complevel > 15; gl._complevel = 15; /if; /* suppress handles inside */
if layout=="input" || layout=="button" && gl.bc_dynhtml!="M";
><input type=<? type "P"> <? name "Pn"> <? value "Pn"> <? rest "Pn">><hei
elsif layout=="button";
><button type=<? type "P"> <? name "Pn"> <? rest "Pn">><defbody></button><
elsif layout=="link" || layout=="compatlink" || layout=="hidden";
if tolower(type)!="reset"><input type="hidden" <?name "Pn"> value=""></if;
js;
let namejs=substall(name,".","_");
>function yysubmit_<?namejs>() {<
if tolower(type)!="reset"><?form>[<?name "J">].value="t"; window.yybtn=<?name "J">; if (<?onsubmit>(<?form>)) <?form>.submit();<else
><?form>.reset();</if>}<
if layout!="hidden";
if gl._complevel<15;
><jswrite stmt="document.write"><\a href="javascript:yysubmit_<?namejs>();"><defbody><\/a></jswrite><
/if;
/if;
/js;
if layout!="hidden" && 15<=gl._complevel;
><\a href="javascript:yysubmit_<?namejs>();"><defbody><\/a><
/if;
if layout=="compatlink";
><NOSCRIPT><input <? type "Pn"> <?name "Pn"> <? value "Pn"> <? rest "Pn">></NOSCRIPT><
/if;
/if;
gl._complevel=l;
/defenv;
// Form button component.
// NAME is the button name, VALUE its value.
// Contents or VALUE is used to label the button.
// If TYPE is "reset" this is a reset button, else a submit button.
// Optional STATE asks the panel to disable/enable the button.
// We need to know which button was pressed, which is only possible if
// buttons are always successful controls. Therefore, attribute name
// is mandatory. If VALUE is null, the button's NAME must be unique
// within its form nest, else the pair NAME, VALUE must be unique.
// EXTEND mandatory name really necessary only for sleform, a sesform
// EXTEND could use stdmakeuniq()
defenv formbutton name layout=null value=null type=null state=null panel=null @rest ...;
inherit InlineComponent; definpara; defnowysiwyg; definpara;
// Define context H HTML
defenv _evalcontext;
_setcontext "H"; defbody; /_setcontext;
/defenv;
// Process this button.
// PFF is this.panel.ff for convenience
// Precondition: all fields have been submitted successfully.
// Return string on failure, else whether form has been successfully
// submitted (bool).
def process pff; return true; /def;
defenv jsonsubmit;
assign this.panel.onsubmit
// control = form["<? this.panel.control_name (this.name)>"];
>if (window.yybtn==<?this.name "P">){
< defbody>}
< ? this.panel.onsubmit;
/assign;
/defenv;
// EXTEND need doit because subclasses cannot call inherited body but
defenv doit layout panel name value type state rest;
layout=default(layout,"input");
this.panel = default(panel,gl._curpanel);
this.name = name;
// if isempty(value); value = name; /if;
// this.value=value;
rest.onclick="window.yybtn='"+name+"';"+default(rest.onclick,"");
if isnull(type); this.type = null; else this.type = tolower (type); /if;
this.state = this.panel.button_state (this, state);
this.panel.regbutton (this);
// Map all formbutton types except null, "submit" and in the
// outermost panel "reset" to HTML button type null.
if !isnull(this.type) && (this.type != "submit") && (this.type != "image")
&& ( (this.type != "reset")
|| !isnull (this.panel.encpanel)
|| !this.panel.isinitial);
if isempty(value);
// Client's default button label for type==null is something
// like "Submit", no good.
// tocapital() would be nice
value = toupper (substring(type,0,1)) + substring(type,1);
/if;
type = null;
/if;
if this.state!="display";
_heitmlbutton layout type this.panel.control_name(name) value
"window.document."+this.panel.form.name this.panel.form.name+"_onsubmit" rest;
defbody;
/_heitmlbutton;
// _allbrowserbutton type this.panel.control_name(name) value this.state rest;
// defbody;
// /_allbrowserbutton;
/if;
/defenv;
doit layout panel name value type state rest;
defbody;
/doit;
/defenv
// Button to change input of field FNAME to NEWVALUE.
// Works only if client groks intrinsic events and JavaScript.
defenv fieldchangebutton value=null state=null fname newvalue @rest ...;
inherit InlineComponent; definpara; defnowysiwyg;
panel = gl._curpanel;
rest.onclick = default (rest.onclick, "")
+ "this.form['"+panel.control_name (fname)+"'].value='"+newvalue+"';";
_allbrowserbutton "button" null value state rest; defbody; /_allbrowserbutton;
/defenv
//
// Fields
// Restriction: you cannot have multiple fields with a common name,
// except fieldcheckbox.
// EXTEND object controls?
// EXTEND label, legend
// EXTEND document attributes
// Abstract base class for fields.
// Use like this:
// inherit _fieldbase;
// regfield (...)
// clvalue();
// Override check() and toclvalue() to convert between program and
// client representation of the field value. If your check() can
// fail, you may want to override jscheck(), too.
defclass _fieldbase;
inherit object;
// Attribute members:
// object panel panel that contains this field
// string name field name
// string format format string for field value,
// may contain options and format only
// bool mandatory is field mandatory?
// string descr description of acceptable field values
// state field state: display, disabled, enabled, readonly
// Initialize common field attributes and register the field with its form.
// String NAME is the field name.
// String DESCR describes accepted field values, may be null.
// If VALUE is not null, it defines the field's initial value.
// If FORMAT is not null, it is the `?' format for converting VALUE.
// If MANDATORY, entering something into the field is mandatory.
// Return the field's initial value.
def regfield panel name value format mandatory descr errmsg state;
this.panel = default(panel,gl._curpanel);
this.name = name;
this.format = format;
this.descr = descr; this.errmsg=errmsg;
this.mandatory = htmlbool(mandatory);
this.state = this.panel.field_state (this, state);
this.jscheck();
this.panel.regfield (this,value);
/def;
// Define and return field's clvalue.
def clvalue;
if isdecl (this.panel.ff[this.name]);
clff = this.toclvalue (this.panel.ff[this.name]);
else
clff = this.panel.clvalue [this.name];
/if;
return clff;
// return this.panel.clvalue (this.name, clff, this.toclvalue (default(this.panel.ivalue[this.name])));
/def;
// Return string that asks user to fix this field's value.
def errormsg;
// EXTEND hook to change this per page, and perhaps per form or panel.
if !isempty(this.errmsg); return this.errmsg; /if;
return "Please enter " + default (this.descr, "something")
+ " into field `" + this.name+"'.";
/def;
// Report bad field value.
def error;
this.panel.error (errormsg(), this.name);
/def;
// Register JavaScript contents to run in the onsubmit event handler.
// The contents may access the control object in local variable
// `control' and may assign an error message to local variable
// `error'. Executing `break' skips any remaning registered
// code.
defenv regonsubmit;
callenv this.panel.form.regonsubmit();
>control = form["<? this.panel.control_name (this.name)>"];<hei
defbody;
/callenv;
/defenv;
// JavaScript to ensure that submitted value is not empty or not mandatory.
// To be run inside of regonsubmit.
def js_ensure_mandatory;
if this.mandatory>
if (checkmand && (control.value == "")) {
error = "<? errormsg()>\n";
}
</if;
/def;
// Register JavaScript field value check.
// Caution: your check() MUST NOT RELY on jscheck(), because it only
// runs if the user submits with JavaScript enabled.
def jscheck;
if this.mandatory; // only to avoid empty regonsubmit
regonsubmit;
js_ensure_mandatory();
/regonsubmit;
/if;
/def;
// Ensure that VALUE is not empty or not mandatory.
// Report error if mandatory value is missing.
// Handy utility for check().
def ensure_mandatory value;
if this.panel.field_mandatory(this,this.mandatory) && isempty(value);
error();
return null;
/if;
return value;
/def;
// Callback to check and transform the submitted VALUE.
// If VALUE is bad, report a field error.
// Return the transformed value.
// Note: for most fields VALUE is a string, but for some,
// e.g. fieldcheckbox, it is an array of strings.
def check value;
return ensure_mandatory (value);
/def;
// main check interface with form.
// fields can overwrite fcheck in special sitations,
// normally they overwrite check
def fcheck in out clvalue scratch;
val = check (default (in[this.name]));
if !isdecl (this.panel.errmsg[this.name]);
out[this.name] = val; TuDelField (clvalue[this.name]);
else
clvalue[this.name]=in[this.name];
TuDelField (out[this.name]);
/if;
/def;
// Return VALUE transformed into internal field state.
// Caution: the result is just a string, so don't do funny escapes
// for HTML; use format context "A"!
def toclvalue value;
assign res;
if isnull(this.format); ? value "A"; else; ? value "A"+this.format; /if;
/assign;
return res;
/def;
/defclass
// Emit a hidden field in the case of a sleform and display fields.
// Contents displays the field's value.
// Call panel.save_value(FIELD.name, VALUE) if SAVE.
defenv _emit_state field value save rest;
if save; field.panel.save_value (field.name, value); /if;
defbody;
/defenv
// Text Area Field, like HTML textarea control.
defenv fieldtextarea name rows=5 cols=60 wrap=null mandatory=false descr=null errmsg=null
state=null panel=null trim=false empty=false env=null format="" maxlength=null @rest ...;
inherit InlineComponent, _fieldbase; defnowysiwyg; defautoclose;
def errmsg_content_too_long;
return "Content of field "+this.name+" too long";
/def
def check value;
if this.trim && !isnull(value); value = trim(value); /if;
if !this.empty && value==""; value=null; /if;
if !isnull(this.maxlength) && len(default(value,"")) > this.maxlength;
this.panel.error(this.errmsg_content_too_long(), this.name);
/if;
return ensure_mandatory (value);
/def;
def jscheck;
regonsubmit;
js_ensure_mandatory();
if !isnull(this.maxlength);
>
if (control.value != "") {
if (control.value.length > <? this.maxlength>) {
error = "<? errmsg_content_too_long()>\n";
}
}
< /if;
/regonsubmit;
/def;
assign value;
defbody;
/assign;
if isempty (value); value = null; /if; // don't override with ""
this.maxlength = maxlength;
regfield (panel, name, value, null, mandatory, descr, errmsg, state);
value = clvalue();
this.trim = htmlbool(trim);
this.empty = htmlbool(empty);
if this.state=="display";
if !isempty(env)><\<?env>></if;
? default (value) format;
if !isempty(env)><\/<?env>></if;
this.panel.save_value (name, value);
else;
><textarea name=<? this.panel.control_name (name) "P"> <? rows "Pn"> <? cols "Pn"> <? wrap "Pn"> <? maxlength "Pn"> <? rest "Pn"> <if this.state!="enabled"><?this.state></if>><? value></textarea><hei
/if;
/defenv
// Text Field, like HTML text input control.
// If PASSWORD, hide the text using a HTML password input control.
def fieldtext name size=null maxlength=null value=null mandatory=false
trim=false empty=false descr=null errmsg=null state=null panel=null password=false @rest ...;
inherit InlineComponent,_fieldbase; definpara;
// EXTEND jscheck() that trims, mandatory fields that contains spaces are detected on the server
def check value;
if this.trim && !isnull(value); value = trim(value); /if;
if !this.empty && value==""; value=null; /if;
return ensure_mandatory (value);
/def;
regfield (panel, name, value, null, mandatory, descr, errmsg, state);
this.trim = htmlbool(trim); this.empty = htmlbool(empty);
value = clvalue();
if this.state=="display";
_emit_state this value true rest;
if !htmlbool(password); ? value; /if; // EXTEND print stars?
/_emit_state;
else;
><\input <if htmlbool(password)>type="password"</if> <hei
> name=<? this.panel.control_name (name) "P"> <? size "Pn"> <hei
> <? maxlength "Pn"> <? value "Pn"> <? rest "Pn"><hei
> <if this.state!="enabled"><?this.state></if>><hei
/if;
/def
// Hidden Field, like HTML hidden input control.
def fieldhidden name value=null panel=null @rest ...;
inherit InlineComponent, _fieldbase;
regfield (panel, name, value, null, false, null, null, null);
value = clvalue();
><input type="hidden" name=<? this.panel.control_name (name) "P"> <? value "Pn"> <? rest "Pn">><hei
/def
// Integer Field.
def fieldint name size=null value=null format=null mandatory=false min=null max=null
descr=null errmsg=null state=null panel=null @rest ...;
inherit InlineComponent, _fieldbase; definpara;
def jscheck;
regonsubmit>
<js_ensure_mandatory>
if (control.value != "") {
value = parseInt (control.value, 10);
// In JavaScript 1.0, parseInt() may return 0 instead of
// NaN, and isNaN() may be missing. Code for 1.1:
// if (isNaN (value)
// <if !isnull (this.min)>|| (value < <? this.min>)</if>
// <if !isnull (this.max)>|| (value > <? this.min>)</if>) {
// error = "<? errormsg()>\n";
// }
// once Javascript 1.0 is totally dead this code can be replaced
if ((parseInt ("foo") == 0) && (value == 0)) {
// broken parseInt(), can't tell 0 from NaN, have to skip range check
break;
}
if ((value != value)< // look ma, it's NaN
if !isnull (this.min)>|| (value <\ <? this.min>)</if;
if !isnull (this.max)>|| (value > <? this.max>)</if>) {
error = "<? errormsg()>\n";
}
}
</regonsubmit;
/def;
def check value;
value = ensure_mandatory (value);
if isempty(value); return null; /if;
res = integer (value);
if isnull (res)
|| !isnull (this.min) && res < this.min
|| !isnull (this.max) && this.max < res;
error();
/if;
return res;
/def;
if isnull (descr);
descr = "an integral number";
if isnull(min);
if !isnull(max);
descr = descr + " less than " + max;
/if;
elsif isnull(max);
descr = descr + " greater than " + min;
else;
descr = descr + " between " + min + " and " + max;
/if;
/if;
this.min = integer(min); this.max = integer(max); value=integer(value);
regfield (panel, name, value, format, mandatory, descr, errmsg, state);
value = clvalue();
if this.state=="display";
_emit_state this value true rest; ? value; /_emit_state;
else;
><input name=<? this.panel.control_name (name) "P"> <? size "Pn"> <? value "Pn"> <? rest "Pn"> <if this.state!="enabled"><?this.state></if>><hei
/if;
/def
// Real number field.
def fieldreal name size=null value=null format=null mandatory=false min=null max=null
prec=null descr=null errmsg=null state=null panel=null @rest ...;
inherit InlineComponent, _fieldbase; definpara;
def jscheck;
regonsubmit>
<js_ensure_mandatory>
if (control.value != "") {
value = parseFloat (control.value);
// In JavaScript 1.0, parseFloat() may return 0 instead of
// NaN, and isNaN() may be missing. Code for 1.1:
// if (isNaN (value)
// <if !isnull (this.min)>|| (value < <? this.min>)</if>
// <if !isnull (this.max)>|| (value > <? this.min>)</if>) {
// error = "<? errormsg()>\n";
// }
// When Javascript 1.0 is totally dead this code can be replaced
if ((parseFloat ("foo") == 0) && (value == 0)) {
// broken parseFloat(), can't tell 0 from NaN, have to skip range check
break;
}
if ((value != value)< // look ma, it's NaN
if !isnull (this.min)>|| (value <\ <? this.min>)</if;
if !isnull (this.max)>|| (value > <? this.max>)</if>) {
error = "<? errormsg()>\n";
}
}
</regonsubmit;
/def;
def check value;
value = ensure_mandatory (value);
if isempty(value); return null; /if;
res = real (value);
if isnull (res)
|| !isnull (this.min) && res < this.min
|| !isnull (this.max) && this.max < res;
error();
/if;
return res;
// EXTEND obey prec
/def;
if isnull(descr);
descr = "a real number";
if isnull(min);
if !isnull(max);
descr = descr + " less than " + max;
/if;
elsif isnull(max);
descr = descr + " greater than " + min;
else;
descr = descr + " between " + min + " and " + max;
/if;
/if;
this.min = real(min);
this.max = real(max);
this.prec = prec;
value = real(value);
regfield (panel, name, value, format, mandatory, descr, errmsg, state);
value = clvalue();
// EXTEND obey prec
if this.state=="display";
_emit_state this value true rest; ? value; /_emit_state;
else;
><input name=<? this.panel.control_name (name) "P"> <? size "Pn"> <? value "Pn"> <? rest "Pn"> <if this.state!="enabled"><? this.state></if>><hei
/if;
/def
// Emit a checkbox or radio control for FIELD.
// TYPE is either "checkbox" or "radio".
// VALUE, CHECKED, and STATE are as in HTML.
def _emit_checkbox_or_radio field type value checked multiple state rest;
if state=="display";
_emit_state field value checked rest;
if checked; ? "x"; /if;
/_emit_state;
else
n=field.panel.control_name (field.name);
if multiple; n=n+".";/if;
><input <? type "Pn"> name=<? n "P"> <? value "Pn"> <? checked "Pn"> <? rest "Pn"> <if state!="enabled"><?state></if>><
/if;
/def
// Field with two values.
def fieldcheckbox name onvalue="t" offvalue="" checked=null state=null panel=null multiple=null
multisep="" @rest ...;
inherit InlineComponent, _fieldbase; definpara;
def check value;
if isnull (value); return this.offvalue; /if;
return this.onvalue;
/def;
def fcheck in out clvalue scratch;
v=in[this.name];
if !this.multiple;
if v==this.clval;out [this.name] = this.onvalue; else
out [this.name] = this.offvalue; /if;
else
if isempty(scratch[this.name]);
out[this.name]= ""; scratch[this.name]=true;
/if;
if (istuple(v) && !isnull (arsearch (v, this.clval)));
// This one checked?
if !isempty(out [this.name]);
out [this.name] = out [this.name] + this.multisep + this.onvalue; // Yes, add
else
out [this.name] = this.onvalue; // Yes, return its value.
/if;
/if;
/if;
/def;
def toclvalue value;
if htmlbool(this.multiple);
if contains(value,this.onvalue+this.multisep) ||
contains(value,this.multisep+this.onvalue); return "t"; /if;
/if;
if value == this.onvalue; return "t"; /if;
return null;
/def;
if isnull (checked);
value = null;
elsif htmlbool(checked);
value = onvalue;
else;
value = offvalue;
/if;
this.multiple = htmlbool(multiple); this.multisep = multisep;
if this.multiple; onvalue=onvalue+""; /if;
this.onvalue = onvalue;
this.offvalue = offvalue;
regfield (panel, name, value, null, false, null, null, state);
value = clvalue();
if isstring (onvalue); this.clval=onvalue; else this.clval="t"; /if;
_emit_checkbox_or_radio (this, "checkbox", this.clval, !isnull (value), htmlbool(multiple), this.state, rest);
/def
defenv condenabled negate=null; inherit component; deftranspara;
_marker;
if ((gl._curpanel.state=="display")&&htmlbool(negate) ||
(gl._curpanel.state!="display")&&!htmlbool(negate));
defbody;
/if;
/_marker;
/defenv
>