<?php
/*
*******************************************************************************
FiForms -- A collection of PHP classes designed
to facilitate rapid development of web-database software
Copyright (C) 2003-2008 Daniel McFeeters
This library 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.
This library 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 this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
The original author of this library can be contacted at the following
address:
Daniel McFeeters
182 Baker Rd.
Faubush, KY 42544-6526
email:databases [at] fiforms [dot] org
http://www.fiforms.org/
iInput class
Project Started May 4, 2003
*******************************************************************************
FiForms_iInput.inc.php
iInput Definition File
This file contains the definitions for the top-level iInput
*******************************************************************************
*/
require_once("FiForms_genericIcons.inc.php");
/* ?><code><?php */
include_once($GLOBALS['FIFORMS_CONFIG']['SCRIPT_PATH']."themes/".$FIFORMS_CONFIG['ICON_SET']."/iconset.php");
class iInput
// a generic data bound input class from which other inputs are derived
{
// NOTE about formatStr and FormatStrRO:
// In the early days of FiForms, these two properties of iInput
// fromed the basis of FiForms. Each was a string "template" containing
// attribute names enclosed in %% symbols, which was then passed through
// the fillVars function. FiForms version 0.9.3 worked this way.
// As the framework became more complex, these were re-purposed as
// functions to be eval'ed (to improve performance), although they have
// now been deprecated (as of version 1.1) in favor of custom code in
// the formatOutput function
protected $formatStr; // the string "template" for the output of the
// controls. Variable names enclosed in %% symbols
// will be replaced by class variables of the same
// name.
protected $formatStrRO;// used as $formatStr if $readOnly==TRUE
public $otherTags; // Place to insert additional property tags
public $caption; // caption displayed on form
public $value; // value retreived from database
public $dbField; // database field control is bound to, or other for
// a non data-bound control
public $valueToSave;
// Value retreived from POST to be committed to
// database, if matching %dbField% is found in table
// if valueToSave === false, then save a null value to field
public $functionToSave; // Function to save to database instead of value
public $readOnly; // Specifies whether this control should be updateable
//var $validateFunction; // name of function to execute to validate
// data
public $error; // Set to true if an error resulted in validating
// data
public $errorMsg; // error message resulting in this iInput
public $useHex; // If true, save this to the database using hexadecimal
// rather than a quoted string.
public $allowUserSort; // Allow users to sort on this field
public $visible; // if false, the control is not created in HTML
public $rowReport;
public $rowExpression;
public $dynamicUpdateOthers; // Boolean flag to dynamically
// update other fields on an AJAX update?
public $depends;
public $autoReload;
public $isBin; // true to treat value as binary
public $autoFilter; // true to show autoFilter symbol in sheetView
public $transform; // transform content to upper or lowercase
public $formatexp; // regular expression that data must match, or else an error is thrown
public $formaterror; // error message to be displayed on non-matching formatexp
public $displaymatch; // "search" part of preg_replace for display formatting
// (matching database data)
public $displayformat; // "replace" part of preg_replace for display formatting
public $inputmatch; // "search" part of preg_replace for parsing user input
// (note: this MUST be able to match displayformat and parse
// back into the original data. Otherwise data will be lost)
public $inputformat; // "replace" part of preg_replace for parsing user input
private $freshData; // true if data is fresh
private $ajaxLoad; // true if allowed to load data by AJAX
static function buildMyURL($excludeTerms)
// build the base URL for the links using the URL of the current page
{
$myURL = $GLOBALS['FIFORMS_CONFIG']['SERVER_ADDRESS'].
$_SERVER["PHP_SELF"]."?";
foreach($_GET as $getName => $getValue)
{
if(array_search(substr($getName,0,11),$excludeTerms) === false)
{
if(get_magic_quotes_gpc())
{
$getValue = stripslashes($getValue);
}
$myURL .= $getName."=".
htmlspecialchars($getValue);
$myURL .= "&";
}
} // foreach
return($myURL);
} // function buildMyURL
function iInput($theArgs)
// generic constructor. designed to be called by child classes with a
// single argument retured by func_get_args()
{
$this->visible = true;
$this->dbField = $theArgs[0];
$this->caption = $theArgs[1];
if($this->caption == "")
{
$this->caption = $this->dbField;
}
$this->error = FALSE;
$this->useHex = FALSE;
$this->functionToSave = FALSE;
$this->isBin = false;
$this->getValueToSave();
$this->allowUserSort = TRUE; //default to allow sorting on all fields
$this->autoReload = TRUE;
$this->dynamicUpdateOthers = FALSE;
$this->autoFilter = FALSE;
$this->transform = $_GLOBAL['FIFORMS_CONFIG']['DEFAULT_TRANSFORM'];
$this->formatexp = "";
$this->formaterror = "";
$this->freshData = false;
$this->ajaxLoad = false;
$this->displaymatch = "";
$this->displayformat = "";
$this->inputmatch = "";
$this->inputformat = "";
} // function iInput
function setValue($value)
{
$this->value =
preg_replace("/\&\;\#(\d+)\;/","&#\$1;",htmlentities($value));
$this->freshData = true;
}
function throwError($errorMessage)
{
$this->error = TRUE;
$this->errorMsg .= $errorMessage."<br />";
}
function getValueToSave()
// Retreives a value from _POST with the key matching dbField. This
// can be overridden in child classes to do any processing necessary
// before the value is committed to the database.
{
if(!isset($this->dbField))
{
$this->valueToSave = FALSE;
return(TRUE);
}
if(array_key_exists($this->dbField,$_POST))
{
$this->valueToSave = $_POST[$this->dbField];
if($this->transform == "uppercase")
{
$this->valueToSave = strtoupper($this->valueToSave);
}
elseif($this->transform == "lowercase")
{
$this->valueToSave = strtolower($this->valueToSave);
}
if($this->inputmatch)
{
$this->valueToSave = @preg_replace(substr($this->inputmatch,0,1) == '/' ? $this->inputmatch : '/'.$this->inputmatch.'/',$this->inputformat,$this->valueToSave);
if($this->valueToSave === NULL)
{
$this->throwError('Error in inputmatch regular expression.');
}
}
$this->validateBeforeSave();
return(TRUE);
} // if key exists
else
{
$this->valueToSave = FALSE;
}
} // function getValueToSave
function validateBeforeSave()
{
if(!$this->error && $this->formatexp &&
!@preg_match(substr($this->formatexp,0,1) == '/' ? $this->formatexp : '/'.$this->formatexp.'/',$this->valueToSave))
{
$this->throwError($this->formaterror);
}
} // function validateBeforeSave
function checkRO()
// Checks if $readOnly is true, and sets the formatStr accordingly
{
if ($this->formatStrRO == "")
{
$this->formatStrRO = $this->formatStr;
}
} //function checkRO
function preProcess()
// Do any more processing or error checking
// after data retreived from DB
{
}
function drawInput()
// returns the HTML representation of this iInput
{
$this->checkRO();
if($this->displaymatch)
{
$this->value = @preg_replace(substr($this->displaymatch,0,1) == '/' ? $this->displaymatch : '/'.$this->displaymatch.'/',$this->displayformat,$this->value);
if($this->value === NULL)
{
$this->throwError('Error in displaymatch regular expression.');
}
}
return($this->formatOutput().$this->getAJAXScript());
} // function drawInput
function formatOutput()
{
if ($this->readOnly == TRUE)
{
return(fillVars($this,$this->formatStrRO));
}
else
{
return(fillVars($this,$this->formatStr));
}
}
function getRefreshLink()
{
if(($this->rowReport || $this->rowExpression) && $this->autoReload !== "always")
{
$icons = new iconset();
$link = "<a href=\"javascript:reloadSelectRows('".$this->dbField."',false);\">".$icons->refresh."</a>";
}
else
{
$link = "";
}
return $link;
} // function getRefreshLink
function getAJAXScript()
{
$str_End = "";
if($this->rowReport || $this->rowExpression)
{
$str_End .= "<script type=\"text/javascript\">\n\n";
if($this->rowReport)
{
$app = htmlentities($_GET['app']);
$str_End .= "setSelectElementRowSrc(\"".$this->dbField."\",\"'generate.php?filename=".
$this->rowReport.
"&app=$app".
"&_TYPE=_xml&ajax_operation=fill_select&ajax_select_id=".
$this->dbField."'";
if($this->depends)
{
foreach($this->depends as $dkey => $depend)
{
$str_End .= "+'&$dkey='+document.forms[0].$depend.value";
}
}
$str_End .= "\",".($this->autoReload ? 'true':'false').",".
($this->dynamicUpdateOthers ? 'true':'false').");\n";
}
else
{
$str_End .= "setSelectElementRowFunction(\"".$this->dbField."\",\"".
$this->rowExpression."\",".
($this->autoReload ? 'true':'false').");\n";
}
if($this->depends)
{
foreach($this->depends as $depend)
{
$str_End .= "setSelectDepends('".$this->dbField."','$depend');\n";
}
}
$str_End .= "\n</script>";
}
return $str_End;
} // function getAJAXScript
function drawCaption()
// returns the HTML representation of a caption for this iInput
{
if($this->allowUserSort && $_GET['sheetView'] == 'YES')
{
$url = $this->buildMyURL(array('sort','st'));
if($_GET['st'] != 'DESC' && $_GET['sort'] == $this->dbField && $this->dbField)
{
$st = 'DESC';
}
else
{
$st = 'ASC';
}
if($this->dbField && $_GET['sort'] == $this->dbField)
{
$ico = new iconset();
if($_GET['st'] != 'DESC')
{
$img = $ico->ascSort;
}
else
{
$img = $ico->descSort;
}
}
if($_GET['st'] == 'DESC' && $_GET['sort'] == $this->dbField && $this->dbField)
{
$link = "<a href=\"$url\">$this->caption $img</a>";
}
else
{
$link = "<a href=\"$url&sort=$this->dbField&st=$st\">$this->caption $img</a>";
}
}
else
{
$link = $this->caption;
}
if($this->autoFilter && $_GET['sheetView'] == 'YES')
{
$ico = new iconset();
if(array_key_exists($this->dbField,$_GET))
{
$fimg = $ico->filterActive;
}
else
{
$fimg = $ico->filter;
}
$url = $this->buildMyURL($_GET);
$divID = $this->dbField."_filter_div";
$formID = $this->dbField."_filter_form";
$link .= <<<EOD
<a href="$url" onclick="buildFiFormFilter('$this->dbField');return false;">$fimg</a>
<div class="filter" style="display: none;" id="$divID">
<form action="$url" method="get" id="$formID" name="$formID" onsubmit="enableInheritedFields('$formID');">
<fieldset>
<legend>Filter On</legend>
EOD;
foreach($_GET as $name => $value)
{
if(get_magic_quotes_gpc())
{
$value = stripslashes($value);
}
$value = htmlentities($value);
if(!strpos($name,'_display') && $name != $this->dbField)
{
$link .= "<input type=\"hidden\" name=\"$name\" id=\"$name"."_$formID\" value=\"$value\" />\n";
}
}
$this->readOnly = FALSE;
$tmpOTags = $this->otherTags;
$this->otherTags = "";
$link .= $this->drawInput();
$this->otherTags = $tmpOTags;
$this->readOnly = TRUE;
//<input type="text" name="$this->dbField" id="$this->dbField" /><br />
$link .= <<<EOD
<br />
<input type="submit" value="Filter" />
<input type="button" value="Un-Filter" onclick="removeFiFormFilter('$this->dbField');" />
<input type="button" value="Cancel" onclick="cancelFiFormFilter('$this->dbField');" />
</fieldset>
</form>
</div>
EOD;
}
return $link;
}
function hide()
{
$this->formatStr = "";
$this->formatStrRO = "";
$this->caption = "";
}
function disableIn()
{
$this->otherTags .= " readonly=\"readonly\" ";
}
function addInputTagFromXML(&$input,$tag)
{
if($input->attributes->getNamedItem($tag))
{
$this->otherTags .= " $tag=\"".
$input->attributes->getNamedItem($tag)->nodeValue."\" ";
}
} // addTag
function buildFromXML($input)
{
// Load input configuration from XML element $input
if($input->attributes->getNamedItem('default'))
{
if($input->attributes->getNamedItem('default')->nodeValue ==
"_username")
{
// FIXME: get auth username
//$this->value = $this->auth->username;
}
else
{
$this->value =
$input->attributes->getNamedItem('default')->nodeValue;
}
}
$this->addInputTagFromXML($input,'onchange');
$windowToggles =
array('menubar','toolbar','scrollbars','resizable','location');
$this->windowopts = "";
$reload = false;
foreach($input->attributes as $attr)
{
$name = $attr->nodeName;
switch($name)
{
case "size":
$this->size = $attr->nodeValue;
break;
case "width":
$this->width = $attr->nodeValue;
$this->windowOpts .= "width=".$attr->nodeValue.",";
break;
case "height":
$this->height = $attr->nodeValue;
$this->windowOpts .= "height=".$attr->nodeValue.",";
break;
case "cols":
$this->cols = $attr->nodeValue;
break;
case "rows":
$this->rows = $attr->nodeValue;
break;
case "rowQuery":
$this->rowQuery = $attr->nodeValue;
break;
case "extended":
if($attr->nodeValue == 'attributes')
{
$this->extendedAtt = true;
}
break;
case "digits":
$this->digits = $attr->nodeValue;
break;
case "decimals":
$this->decimals = $attr->nodeValue;
break;
case "collapse":
$this->collapse = $attr->nodeValue;
break;
case "prefix":
$this->prefix = $attr->nodeValue;
break;
case "suffix":
$this->suffix = $attr->nodeValue;
break;
case "transform":
$this->transform = $attr->nodeValue;
$reload=true;
break;
case "displaymatch":
$this->displaymatch = $attr->nodeValue;
break;
case "displayformat":
$this->displayformat = $attr->nodeValue;
break;
case "inputmatch":
$this->inputmatch = $attr->nodeValue;
$reload=true;
break;
case "inputformat":
$this->inputformat = $attr->nodeValue;
$reload=true;
break;
case "formatexp":
$this->formatexp = $attr->nodeValue;
$reload=true;
break;
case "formaterror":
$this->formaterror = $attr->nodeValue;
$reload=true;
break;
case "thseperator":
$this->thseperator = $attr->nodeValue;
$reload=true;
break;
case "decpoint":
$this->decpoint = $attr->nodeValue;
$reload=true;
break;
case "style":
if($attr->nodeValue == 'radio')
{
$this->radioStyle = TRUE;
}
else if($attr->nodeValue == 'dynamic')
{
$this->dynamic = TRUE;
}
break;
case "linktext":
$this->contents = $attr->nodeValue;
break;
case "window":
$this->openIn = $attr->nodeValue;
break;
case "menubar":
$this->windowOpts .= 'menubar='.
($attr->nodeValue == 'no' ? 'no' : 'yes').',';
break;
case "toolbar":
$this->windowOpts .= 'toolbar='.
($attr->nodeValue == 'no' ? 'no' : 'yes').',';
break;
case "scrollbars":
$this->windowOpts .= 'scrollbars='.
($attr->nodeValue == 'no' ? 'no' : 'yes').',';
break;
case "resizable":
$this->windowOpts .= 'resizable='.
($attr->nodeValue == 'no' ? 'no' : 'yes').',';
break;
case "location":
$this->windowOpts .= 'location='.
($attr->nodeValue == 'no' ? 'no' : 'yes').',';
break;
case "params":
$this->params = $attr->nodeValue;
break;
case "readonly":
$this->disableIn();
break;
case "displayField":
$this->displayField = $attr->nodeValue;
case "viewmode":
// for iSubform
if(is_a($this,'iSubform'))
{
$this->sheetView = ($attr->nodeValue != "form");
}
else
{
// for iFile
if($attr->nodeValue == 'image')
{
$this->showAsImage = true;
}
}
break;
case "view":
if($attr->nodeValue == 'sheet')
$this->params .= '&sheetView=YES';
else if($attr->nodeValue == 'new')
$this->params .= '¤tRec=new';
break;
case "type":
case "field":
case "caption":
break;
default:
if(in_array($name,$windowToggles))
{
$this->windowOpts .= $name.'='.
($attr->nodeValue == 'no' ? 'no' : 'yes').',';
}
break;
} // switch
} // for each property
if($reload)
{
$this->getValueToSave();
}
if(property_exists($this,'windowOpts'))
{
foreach($windowToggles as $toggle)
{
if(!strpos($this->windowOpts, $toggle))
{
$this->windowOpts .= $toggle.'=yes,';
} // if set
} // foreach windowToggles
} // if windowOpts
//if($this->ajaxLoad)
{
$this->getAjaxParams($input);
}
} // function buildFromXML
function getAjaxParams($input)
// called from buildFromXML function. Gets the ajax parameters for element
{
$child = $input->firstChild;
// Load the "expression" and "loaddata" elements for dynamic
// data loading properties
while($child)
{
if($child->localName == "expression"
|| $child->localName == "loaddata")
{
if($child->localName == "loaddata")
{
$this->rowReport = $child->nodeValue;
}
else
{
$this->rowExpression = $child->nodeValue;
}
if($child->attributes &&
$child->attributes->getNamedItem('auto') &&
$child->attributes->getNamedItem('auto')->nodeValue
== 'always')
{
$this->autoReload = "always";
}
else if($child->attributes &&
($child->attributes->getNamedItem('auto') &&
($child->attributes->getNamedItem('auto')->nodeValue
== 'noauto' ||
($child->attributes->getNamedItem('auto')->nodeValue
== 'onlynew')
&& $this->currentRec != 'new')))
{
$this->autoReload = FALSE;
}
else
{
$this->autoReload = TRUE;
}
if($child->attributes &&
$child->attributes->getNamedItem('update') &&
$child->attributes->getNamedItem('update')->nodeValue
== 'all')
{
$this->dynamicUpdateOthers = TRUE;
}
} // if expression or loaddata element
if($child->localName == "depends")
{
$depend = $child->nodeValue;
if(($child->attributes) &&
($child->attributes->getNamedItem('param')))
{
$param =
$child->attributes->getNamedItem('param')->nodeValue;
}
else
{
$param = "";
}
if(!trim($param))
{
$param = $depend;
}
$this->depends[$param] = $depend;
} // if depends
$child = $child->nextSibling;
} // while child
} // function getAjaxParams
function drawHead()
{
return(fillVars($this,$this->formatStr->head));
}
function drawFoot()
{
return(fillVars($this,$this->formatStr->foot));
}
function drawBody($type)
{
return(fillVars($this,$this->formatStr->body));
}
} // class iInput
/* ?></code><?php */
?>