forked from extern/egroupware
1091 lines
33 KiB
PHP
1091 lines
33 KiB
PHP
<?php
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// xajax version 0.1 beta4
|
|
// copyright (c) 2005 by J. Max Wilson
|
|
// http://xajax.sourceforge.net
|
|
//
|
|
//
|
|
// xajax is an open source PHP class library for easily creating powerful
|
|
// PHP-driven, web-based AJAX Applications. Using xajax, you can asynchronously
|
|
// call PHP functions and update the content of your your webpage without
|
|
// reloading the page.
|
|
//
|
|
// xajax is released under the terms of the LGPL license
|
|
// http://www.gnu.org/copyleft/lesser.html#SEC3
|
|
//
|
|
// This library is free software; you can redistribute it and/or
|
|
// modify it under the terms of the GNU Lesser General Public
|
|
// License as published by the Free Software Foundation; either
|
|
// version 2.1 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
|
|
// Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public
|
|
// License along with this library; if not, write to the Free Software
|
|
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// The xajaxResponse class is used to created responses to be sent back to your
|
|
// webpage. A response contains one or more command messages for updating your page.
|
|
// Currently xajax supports five kinds of command messages:
|
|
// * Assign - sets the specified attribute of an element in your page
|
|
// * Append - appends data to the end of the specified attribute of an element in your page
|
|
// * Prepend - prepends data to teh beginning of the specified attribute of an element in your page
|
|
// * Replace - searches for and replaces data in the specified attribute of an element in your page
|
|
// * Script - runs JavaScript
|
|
// * Alert - shows an alert box with the suplied message text
|
|
// elements are identified by their HTML id
|
|
class xajaxResponse
|
|
{
|
|
var $xml;
|
|
|
|
// Constructor
|
|
function xajaxResponse()
|
|
{
|
|
$this->charset = is_object($GLOBALS['egw']->translation) ? $GLOBALS['egw']->translation->charset() : 'UTF-8';
|
|
//error_log("xajaxResponse: charset=$this->charset");
|
|
$this->xml = "<?xml version=\"1.0\" encoding=\"$this->charset\"?>";
|
|
$this->xml .= "<xajax>";
|
|
}
|
|
|
|
// addAssign() adds an assign command message to your xml response
|
|
// $sTarget is a string containing the id of an HTML element
|
|
// $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.)
|
|
// $sData is the data you want to set the attribute to
|
|
// usage: $objResponse->addAssign("contentDiv","innerHTML","Some Text");
|
|
function addAssign($sTarget,$sAttribute,$sData)
|
|
{
|
|
$this->xml .= "<update action=\"assign\">";
|
|
$this->xml .= "<target attribute=\"$sAttribute\">$sTarget</target>";
|
|
$this->xml .= "<data><![CDATA[$sData]]></data>";
|
|
$this->xml .= "</update>";
|
|
}
|
|
|
|
// addAppend() adds an append command message to your xml response
|
|
// $sTarget is a string containing the id of an HTML element
|
|
// $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.)
|
|
// $sData is the data you want to append to the end of the attribute
|
|
// usage: $objResponse->addAppend("contentDiv","innerHTML","Some Text");
|
|
function addAppend($sTarget,$sAttribute,$sData)
|
|
{
|
|
$this->xml .= "<update action=\"append\">";
|
|
$this->xml .= "<target attribute=\"$sAttribute\">$sTarget</target>";
|
|
$this->xml .= "<data><![CDATA[$sData]]></data>";
|
|
$this->xml .= "</update>";
|
|
}
|
|
|
|
// addPrepend() adds an prepend command message to your xml response
|
|
// $sTarget is a string containing the id of an HTML element
|
|
// $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.)
|
|
// $sData is the data you want to prepend to the beginning of the attribute
|
|
// usage: $objResponse->addPrepend("contentDiv","innerHTML","Some Text");
|
|
function addPrepend($sTarget,$sAttribute,$sData)
|
|
{
|
|
$this->xml .= "<update action=\"prepend\">";
|
|
$this->xml .= "<target attribute=\"$sAttribute\">$sTarget</target>";
|
|
$this->xml .= "<data><![CDATA[$sData]]></data>";
|
|
$this->xml .= "</update>";
|
|
}
|
|
|
|
// addReplace() adds an replace command message to your xml response
|
|
// $sTarget is a string containing the id of an HTML element
|
|
// $sAttribute is the part of the element you wish to modify ("innerHTML", "value", etc.)
|
|
// $sSearch is a string to search for
|
|
// $sData is a string to replace the search string when found in the attribute
|
|
// usage: $objResponse->addReplace("contentDiv","innerHTML","text","<b>text</b>");
|
|
function addReplace($sTarget,$sAttribute,$sSearch,$sData)
|
|
{
|
|
$this->xml .= "<update action=\"replace\">";
|
|
$this->xml .= "<target attribute=\"$sAttribute\">$sTarget</target>";
|
|
$this->xml .= "<search><![CDATA[$sSearch]]></search>";
|
|
$this->xml .= "<data><![CDATA[$sData]]></data>";
|
|
$this->xml .= "</update>";
|
|
}
|
|
|
|
// addClear() adds an clear command message to your xml response
|
|
// $sTarget is a string containing the id of an HTML element
|
|
// $sAttribute is the part of the element you wish to clear ("innerHTML", "value", etc.)
|
|
// usage: $objResponse->addClear("contentDiv","innerHTML");
|
|
function addClear($sTarget,$sAttribute)
|
|
{
|
|
$this->xml .= "<update action=\"clear\">";
|
|
$this->xml .= "<target attribute=\"$sAttribute\">$sTarget</target>";
|
|
$this->xml .= "</update>";
|
|
}
|
|
|
|
// addAlert() adds an alert command message to your xml response
|
|
// $sMsg is a text to be displayed in the alert box
|
|
// usage: $objResponse->addAlert("This is some text");
|
|
function addAlert($sMsg)
|
|
{
|
|
$this->xml .= "<alert><![CDATA[$sMsg]]></alert>";
|
|
}
|
|
|
|
// addScript() adds a jscript command message to your xml response
|
|
// $sJS is a string containing javascript code to be executed
|
|
// usage: $objResponse->addAlert("var x = prompt('get some text');");
|
|
function addScript($sJS)
|
|
{
|
|
$this->xml .= "<jscript><![CDATA[$sJS]]></jscript>";
|
|
}
|
|
|
|
// addRemove() adds a Remove Element command message to your xml response
|
|
// $sTarget is a string containing the id of an HTML element to be removed
|
|
// from your page
|
|
// usage: $objResponse->addRemove("Div2");
|
|
function addRemove($sTarget)
|
|
{
|
|
$this->xml .= "<update action=\"remove\">";
|
|
$this->xml .= "<target>$sTarget</target>";
|
|
$this->xml .= "</update>";
|
|
}
|
|
|
|
function addCreate($sParent, $sTag, $sId, $sType="")
|
|
{
|
|
$this->xml .= "<update action=\"create\">";
|
|
$this->xml .= "<target attribute=\"$sTag\">$sParent</target>";
|
|
$this->xml .= "<data><![CDATA[$sId]]></data>";
|
|
if ($sType != "")
|
|
$this->xml .= "<type><![CDATA[$sType]]></type>";
|
|
$this->xml .= "</update>";
|
|
}
|
|
|
|
// getXML() returns the xml to be returned from your function to the xajax
|
|
// processor on your page
|
|
// usage: $objResponse->getXML();
|
|
function getXML()
|
|
{
|
|
if (strstr($this->xml,"</xajax>") == false)
|
|
$this->xml .= "</xajax>";
|
|
|
|
return $this->xml;
|
|
}
|
|
}// end class xajaxResponse
|
|
|
|
// Communication Method Defines
|
|
if (!defined ('GET'))
|
|
{
|
|
define ('GET', 0);
|
|
}
|
|
if (!defined ('POST'))
|
|
{
|
|
define ('POST', 1);
|
|
}
|
|
|
|
// the xajax class generates the xajax javascript for your page including the
|
|
// javascript wrappers for the PHP functions that you want to call from your page.
|
|
// It also handles processing and executing the command messages in the xml responses
|
|
// sent back to your page from your PHP functions.
|
|
class xajax
|
|
{
|
|
var $aFunctions; // Array of PHP functions that will be callable through javascript wrappers
|
|
var $aFunctionRequestTypes; // Array of RequestTypes to be used with each function (key=function name)
|
|
var $sRequestURI; // The URI for making requests to the xajax object
|
|
var $bDebug; // Show debug messages true/false
|
|
var $sWrapperPrefix; // The prefix to prepend to the javascript wraper function name
|
|
var $bStatusMessages; // Show debug messages true/false
|
|
var $aObjArray; // Array for parsing complex objects
|
|
var $iPos; // Position in $aObjArray
|
|
|
|
// Contructor
|
|
// $sRequestURI - defaults to the current page
|
|
// $bDebug Mode - defaults to false
|
|
// $sWrapperPrefix - defaults to "xajax_";
|
|
// usage: $xajax = new xajax();
|
|
function xajax($sRequestURI="",$sWrapperPrefix="xajax_",$bDebug=false)
|
|
{
|
|
$this->aFunctions = array();
|
|
$this->sRequestURI = $sRequestURI;
|
|
if ($this->sRequestURI == "")
|
|
$this->sRequestURI = $this->detectURI();
|
|
$this->sWrapperPrefix = $sWrapperPrefix;
|
|
$this->bDebug = $bDebug;
|
|
}
|
|
|
|
// detectURL() returns the current URL based upon the SERVER vars
|
|
// used internally
|
|
function detectURI()
|
|
{
|
|
$aUri = array();
|
|
|
|
if (!empty($_SERVER['REQUEST_URI']))
|
|
{
|
|
$aUri = parse_url($_SERVER['REQUEST_URI']);
|
|
}
|
|
|
|
if (empty($aUri['scheme']))
|
|
{
|
|
if (!empty($_SERVER['HTTP_SCHEME']))
|
|
{
|
|
$aUri['scheme'] = $_SERVER['HTTP_SCHEME'];
|
|
}
|
|
else
|
|
{
|
|
$aUri['scheme'] = (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) != 'off') ? 'https' : 'http';
|
|
}
|
|
|
|
if (!empty($_SERVER['HTTP_HOST']))
|
|
{
|
|
if (strpos($_SERVER['HTTP_HOST'], ':') > 0)
|
|
{
|
|
list($aUri['host'], $aUri['port']) = explode(':', $_SERVER['HTTP_HOST']);
|
|
}
|
|
else
|
|
{
|
|
$aUri['host'] = $_SERVER['HTTP_HOST'];
|
|
}
|
|
}
|
|
else if (!empty($_SERVER['SERVER_NAME']))
|
|
{
|
|
$aUri['host'] = $_SERVER['SERVER_NAME'];
|
|
}
|
|
else
|
|
{
|
|
print "xajax Error: xajax failed to automatically identify your Request URI.";
|
|
print "Please set the Request URI explicitly when you instantiate the xajax object.";
|
|
exit();
|
|
}
|
|
|
|
if (empty($aUri['port']) && !empty($_SERVER['SERVER_PORT']))
|
|
{
|
|
$aUri['port'] = $_SERVER['SERVER_PORT'];
|
|
}
|
|
|
|
if (empty($aUri['path']))
|
|
{
|
|
if (!empty($_SERVER['PATH_INFO']))
|
|
{
|
|
$path = parse_url($_SERVER['PATH_INFO']);
|
|
}
|
|
else
|
|
{
|
|
$path = parse_url($_SERVER['PHP_SELF']);
|
|
}
|
|
$aUri['path'] = $path['path'];
|
|
unset($path);
|
|
}
|
|
}
|
|
|
|
$sUri = $aUri['scheme'] . '://';
|
|
if (!empty($aUri['user']))
|
|
{
|
|
$sUri .= $aUri['user'];
|
|
if (!empty($aUri['pass']))
|
|
{
|
|
$sUri .= ':' . $aUri['pass'];
|
|
}
|
|
$sUri .= '@';
|
|
}
|
|
|
|
$sUri .= $aUri['host'];
|
|
|
|
if (!empty($aUri['port']) && (($aUri['scheme'] == 'http' && $aUri['port'] != 80) || ($aUri['scheme'] == 'https' && $aUri['port'] != 443)))
|
|
{
|
|
$sUri .= ':'.$aUri['port'];
|
|
}
|
|
// And finally path, without script name
|
|
$sUri .= substr($aUri['path'], 0, strrpos($aUri['path'], '/') + 1);
|
|
|
|
unset($aUri);
|
|
|
|
return $sUri.basename($_SERVER['SCRIPT_NAME']);
|
|
}
|
|
|
|
// setRequestURI() sets the URI to which requests will be made
|
|
// usage: $xajax->setRequestURI("http://xajax.sourceforge.net");
|
|
function setRequestURI($sRequestURI)
|
|
{
|
|
$this->sRequestURI = $sRequestURI;
|
|
}
|
|
|
|
// debugOn() enables debug messages for xajax
|
|
// usage: $xajax->debugOn();
|
|
function debugOn()
|
|
{
|
|
$this->bDebug = true;
|
|
}
|
|
|
|
// debugOff() disables debug messages for xajax
|
|
// usage: $xajax->debugOff();
|
|
function debugOff()
|
|
{
|
|
$this->bDebug = false;
|
|
}
|
|
|
|
// statusMessagesOn() enables messages in the statusbar for xajax
|
|
// usage: $xajax->statusMessagesOn();
|
|
function statusMessagesOn()
|
|
{
|
|
$this->bStatusMessages = true;
|
|
}
|
|
|
|
// statusMessagesOff() disables messages in the statusbar for xajax
|
|
// usage: $xajax->statusMessagesOff();
|
|
function statusMessagesOff()
|
|
{
|
|
$this->bStatusMessages = false;
|
|
}
|
|
|
|
// setWrapperPrefix() sets the prefix that will be appended to the javascript
|
|
// wraper functions.
|
|
function setWrapperPrefix($sPrefix)
|
|
{
|
|
$this->sWrapperPrefix = $sPrefix;
|
|
}
|
|
|
|
//Dpericated. Use registerFunction();
|
|
function addFunction($sFunction,$sRequestType=POST)
|
|
{
|
|
trigger_error("xajax: the <b>addFunction()</b> method has been renamed <b>registerFunction()</b>. <br />Please use ->registerFunction('$sFunction'".($sRequestType==GET?",GET":"")."); instead.",E_USER_WARNING);
|
|
$this->registerFunction($sFunction,$sRequestType);
|
|
}
|
|
|
|
// registerFunction() registers a PHP function to be callable through xajax
|
|
// $sFunction is a string containing the function name
|
|
// $sRequestType is the RequestType (GET/POST) that should be used
|
|
// for this function. Defaults to POST.
|
|
// usage: $xajax->registerFunction("myfunction",POST);
|
|
function registerFunction($sFunction,$sRequestType=POST)
|
|
{
|
|
$this->aFunctions[] = $sFunction;
|
|
$this->aFunctionRequestTypes[$sFunction] = $sRequestType;
|
|
}
|
|
|
|
// generates the javascript wrapper for the specified PHP function
|
|
// used internally
|
|
function wrap($sFunction,$sRequestType=POST)
|
|
{
|
|
$js = "function ".$this->sWrapperPrefix."$sFunction(){xajax.call(\"$sFunction\", arguments, ".$sRequestType.");}\n";
|
|
return $js;
|
|
}
|
|
|
|
// processRequests() is the main communications engine of xajax
|
|
// The engine handles all incoming xajax requests, calls the apporiate PHP functions
|
|
// and passes the xml responses back to the javascript response handler
|
|
// if your RequestURI is the same as your web page then this function should
|
|
// be called before any headers or html has been sent.
|
|
// usage: $xajax->processRequests()
|
|
function processRequests()
|
|
{
|
|
if (!empty($_GET['xajaxjs']))
|
|
{
|
|
header("Content-type: text/javascript");
|
|
print $this->generateJavascript();
|
|
exit();
|
|
return;
|
|
}
|
|
|
|
$requestMode = -1;
|
|
$sFunctionName = "";
|
|
$aArgs = array();
|
|
$sResponse = "";
|
|
|
|
if (!empty($_GET["xajax"]))
|
|
$requestMode = GET;
|
|
|
|
if (!empty($_POST["xajax"]))
|
|
$requestMode = POST;
|
|
|
|
if ($requestMode == -1)
|
|
return;
|
|
|
|
if ($requestMode == POST)
|
|
{
|
|
$sFunctionName = $_POST["xajax"];
|
|
|
|
if (!empty($_POST["xajaxargs"]))
|
|
$aArgs = $_POST["xajaxargs"];
|
|
}
|
|
else
|
|
{
|
|
header ("Expires: Mon, 26 Jul 1997 05:00:00 GMT");
|
|
header ("Last-Modified: " . gmdate("D, d M Y H:i:s") . " GMT");
|
|
header ("Cache-Control: no-cache, must-revalidate");
|
|
header ("Pragma: no-cache");
|
|
header("Content-type: text/xml");
|
|
|
|
$sFunctionName = $_GET["xajax"];
|
|
|
|
if (!empty($_GET["xajaxargs"]))
|
|
$aArgs = $_GET["xajaxargs"];
|
|
}
|
|
|
|
if (!in_array($sFunctionName, $this->aFunctions))
|
|
{
|
|
$objResponse = new xajaxResponse();
|
|
$objResponse->addAlert("Unknown Function $sFunctionName.");
|
|
$sResponse = $objResponse->getXML();
|
|
}
|
|
else if ($this->aFunctionRequestTypes[$sFunctionName] != $requestMode)
|
|
{
|
|
$objResponse = new xajaxResponse();
|
|
$objResponse->addAlert("Incorrect Request Type.");
|
|
$sResponse = $objResponse->getXML();
|
|
}
|
|
else
|
|
{
|
|
for ($i = 0; $i < sizeof($aArgs); $i++)
|
|
{
|
|
if (stristr($aArgs[$i],"<xjxobj>") != false)
|
|
{
|
|
$aArgs[$i] = $this->xmlToArray("xjxobj",$aArgs[$i]);
|
|
}
|
|
else if (stristr($aArgs[$i],"<xjxquery>") != false)
|
|
{
|
|
$aArgs[$i] = $this->xmlToArray("xjxquery",$aArgs[$i]);
|
|
}
|
|
}
|
|
$sResponse = call_user_func_array($sFunctionName, $aArgs);
|
|
}
|
|
|
|
header("Content-type: text/xml; charset=$this->charset");
|
|
print $sResponse;
|
|
|
|
exit();
|
|
}
|
|
|
|
// xmlToArray() takes a string containing xajax xjxobj xml or xjxquery xml
|
|
// and builds an array representation of it to pass as an argument to
|
|
// the php function being called. Returns an array.
|
|
// used internally
|
|
function xmlToArray($rootTag, $sXml)
|
|
{
|
|
$aArray = array();
|
|
$sXml = str_replace("<$rootTag>","<$rootTag>|~|",$sXml);
|
|
$sXml = str_replace("</$rootTag>","</$rootTag>|~|",$sXml);
|
|
$sXml = str_replace("<e>","<e>|~|",$sXml);
|
|
$sXml = str_replace("</e>","</e>|~|",$sXml);
|
|
$sXml = str_replace("<k>","<k>|~|",$sXml);
|
|
$sXml = str_replace("</k>","|~|</k>|~|",$sXml);
|
|
$sXml = str_replace("<v>","<v>|~|",$sXml);
|
|
$sXml = str_replace("</v>","|~|</v>|~|",$sXml);
|
|
$sXml = str_replace("<q>","<q>|~|",$sXml);
|
|
$sXml = str_replace("</q>","|~|</q>|~|",$sXml);
|
|
|
|
$this->aObjArray = explode("|~|",$sXml);
|
|
|
|
$this->iPos = 0;
|
|
$aArray = $this->parseObjXml($rootTag);
|
|
|
|
return $aArray;
|
|
}
|
|
|
|
// parseObjXml() is a recursive function that generates an array from the
|
|
// contents of $this->aObjArray. Returns an array.
|
|
// used internally
|
|
function parseObjXml($rootTag)
|
|
{
|
|
$aArray = array();
|
|
|
|
if ($rootTag == "xjxobj")
|
|
{
|
|
while(!stristr($this->aObjArray[$this->iPos],"</xjxobj>"))
|
|
{
|
|
$this->iPos++;
|
|
if(stristr($this->aObjArray[$this->iPos],"<e>"))
|
|
{
|
|
$key = "";
|
|
$value = null;
|
|
|
|
$this->iPos++;
|
|
while(!stristr($this->aObjArray[$this->iPos],"</e>"))
|
|
{
|
|
if(stristr($this->aObjArray[$this->iPos],"<k>"))
|
|
{
|
|
$this->iPos++;
|
|
while(!stristr($this->aObjArray[$this->iPos],"</k>"))
|
|
{
|
|
$key .= $this->aObjArray[$this->iPos];
|
|
$this->iPos++;
|
|
}
|
|
}
|
|
if(stristr($this->aObjArray[$this->iPos],"<v>"))
|
|
{
|
|
$this->iPos++;
|
|
while(!stristr($this->aObjArray[$this->iPos],"</v>"))
|
|
{
|
|
if(stristr($this->aObjArray[$this->iPos],"<xjxobj>"))
|
|
{
|
|
$value = $this->parseObjXml("xjxobj");
|
|
$this->iPos++;
|
|
}
|
|
else
|
|
{
|
|
$value .= $this->aObjArray[$this->iPos];
|
|
}
|
|
$this->iPos++;
|
|
}
|
|
}
|
|
$this->iPos++;
|
|
}
|
|
$aArray[$key]=$value;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ($rootTag == "xjxquery")
|
|
{
|
|
$sQuery = "";
|
|
$this->iPos++;
|
|
while(!stristr($this->aObjArray[$this->iPos],"</xjxquery>"))
|
|
{
|
|
if (stristr($this->aObjArray[$this->iPos],"<q>") || stristr($this->aObjArray[$this->iPos],"</q>"))
|
|
{
|
|
$this->iPos++;
|
|
continue;
|
|
}
|
|
$sQuery .= $this->aObjArray[$this->iPos];
|
|
$this->iPos++;
|
|
}
|
|
parse_str($sQuery, $aArray);
|
|
}
|
|
|
|
return $aArray;
|
|
}
|
|
|
|
// Depricated. Use printJavascript();
|
|
function javascript($sJsURI="")
|
|
{
|
|
trigger_error("xajax: the <b>javascript()</b> method has been renamed <b>printJavascript()</b>. <br />Please use ->printJavascript(".($sJsURI==""?"":"'$sJsURI'")."); instead.",E_USER_WARNING);
|
|
$this->printJavascript($sJsURI);
|
|
}
|
|
|
|
// printJavascript() prints the xajax javascript code into your page
|
|
// it should only be called between the <head> </head> tags
|
|
// usage:
|
|
// <head>
|
|
// ...
|
|
// <?php $xajax->printJavascript();
|
|
function printJavascript($sJsURI="")
|
|
{
|
|
print $this->getJavascript($sJsURI);
|
|
}
|
|
|
|
// getJavascript() returns the xajax javascript code that should be added to
|
|
// your page between the <head> </head> tags
|
|
// usage:
|
|
// <head>
|
|
// ...
|
|
// <?php $xajax->getJavascript();
|
|
function getJavascript($sJsURI="")
|
|
{
|
|
if ($sJsURI == "")
|
|
$sJsURI = $this->sRequestURI;
|
|
|
|
$separator=strpos($sJsURI,'?')==false?'?':'&';
|
|
|
|
$html = "<script type=\"text/javascript\">var xajaxRequestUri=\"".$this->sRequestURI."\";</script>\n";
|
|
$html .= "\t<script type=\"text/javascript\" src=\"".$sJsURI.$separator."xajaxjs=xajaxjs\"></script>\n";
|
|
|
|
return $html;
|
|
}
|
|
|
|
// compressJavascript() compresses the javascript code for more efficient delivery
|
|
// used internally
|
|
// $sJS is a string containing the javascript code to compress
|
|
function compressJavascript($sJS)
|
|
{
|
|
//remove windows cariage returns
|
|
$sJS = str_replace("\r","",$sJS);
|
|
|
|
//array to store replaced literal strings
|
|
$literal_strings = array();
|
|
|
|
//explode the string into lines
|
|
$lines = explode("\n",$sJS);
|
|
//loop through all the lines, building a new string at the same time as removing literal strings
|
|
$clean = "";
|
|
$inComment = false;
|
|
$literal = "";
|
|
$inQuote = false;
|
|
$escaped = false;
|
|
$quoteChar = "";
|
|
|
|
for($i=0;$i<count($lines);$i++)
|
|
{
|
|
$line = $lines[$i];
|
|
$inNormalComment = false;
|
|
|
|
//loop through line's characters and take out any literal strings, replace them with ___i___ where i is the index of this string
|
|
for($j=0;$j<strlen($line);$j++)
|
|
{
|
|
$c = substr($line,$j,1);
|
|
$d = substr($line,$j,2);
|
|
|
|
//look for start of quote
|
|
if(!$inQuote && !$inComment)
|
|
{
|
|
//is this character a quote or a comment
|
|
if(($c=="\"" || $c=="'") && !$inComment && !$inNormalComment)
|
|
{
|
|
$inQuote = true;
|
|
$inComment = false;
|
|
$escaped = false;
|
|
$quoteChar = $c;
|
|
$literal = $c;
|
|
}
|
|
else if($d=="/*" && !$inNormalComment)
|
|
{
|
|
$inQuote = false;
|
|
$inComment = true;
|
|
$escaped = false;
|
|
$quoteChar = $d;
|
|
$literal = $d;
|
|
$j++;
|
|
}
|
|
else if($d=="//") //ignore string markers that are found inside comments
|
|
{
|
|
$inNormalComment = true;
|
|
$clean .= $c;
|
|
}
|
|
else
|
|
{
|
|
$clean .= $c;
|
|
}
|
|
}
|
|
else //allready in a string so find end quote
|
|
{
|
|
if($c == $quoteChar && !$escaped && !$inComment)
|
|
{
|
|
$inQuote = false;
|
|
$literal .= $c;
|
|
|
|
//subsitute in a marker for the string
|
|
$clean .= "___" . count($literal_strings) . "___";
|
|
|
|
//push the string onto our array
|
|
array_push($literal_strings,$literal);
|
|
|
|
}
|
|
else if($inComment && $d=="*/")
|
|
{
|
|
$inComment = false;
|
|
$literal .= $d;
|
|
|
|
//subsitute in a marker for the string
|
|
$clean .= "___" . count($literal_strings) . "___";
|
|
|
|
//push the string onto our array
|
|
array_push($literal_strings,$literal);
|
|
|
|
$j++;
|
|
}
|
|
else if($c == "\\" && !$escaped)
|
|
$escaped = true;
|
|
else
|
|
$escaped = false;
|
|
|
|
$literal .= $c;
|
|
}
|
|
}
|
|
if($inComment) $literal .= "\n";
|
|
$clean .= "\n";
|
|
}
|
|
//explode the clean string into lines again
|
|
$lines = explode("\n",$clean);
|
|
|
|
//now process each line at a time
|
|
for($i=0;$i<count($lines);$i++)
|
|
{
|
|
$line = $lines[$i];
|
|
|
|
//remove comments
|
|
$line = preg_replace("/\/\/(.*)/","",$line);
|
|
|
|
//strip leading and trailing whitespace
|
|
$line = trim($line);
|
|
|
|
//remove all whitespace with a single space
|
|
$line = preg_replace("/\s+/"," ",$line);
|
|
|
|
//remove any whitespace that occurs after/before an operator
|
|
$line = preg_replace("/\s*([!\}\{;,&=\|\-\+\*\/\)\(:])\s*/","\\1",$line);
|
|
|
|
$lines[$i] = $line;
|
|
}
|
|
|
|
//implode the lines
|
|
$sJS = implode("\n",$lines);
|
|
|
|
//make sure there is a max of 1 \n after each line
|
|
$sJS = preg_replace("/[\n]+/","\n",$sJS);
|
|
|
|
//strip out line breaks that immediately follow a semi-colon
|
|
$sJS = preg_replace("/;\n/",";",$sJS);
|
|
|
|
//curly brackets aren't on their own
|
|
$sJS = preg_replace("/[\n]*\{[\n]*/","{",$sJS);
|
|
|
|
//finally loop through and replace all the literal strings:
|
|
for($i=0;$i<count($literal_strings);$i++)
|
|
$sJS = str_replace("___".$i."___",$literal_strings[$i],$sJS);
|
|
|
|
return $sJS;
|
|
}
|
|
|
|
// generateJavascript() generates all of the xajax javascript code including the javascript
|
|
// wrappers for the PHP functions specified by the registerFunction() method and the response
|
|
// xml parser
|
|
// used internally
|
|
function generateJavascript()
|
|
{
|
|
$js = "";
|
|
if ($this->bDebug){ $js .= "var xajaxDebug=".($this->bDebug?"true":"false").";\n"; }
|
|
|
|
ob_start();
|
|
?>
|
|
function Xajax()
|
|
{
|
|
<?php if ($this->bDebug){ ?>this.DebugMessage = function(text){if (xajaxDebug) alert("Xajax Debug:\n " + text)}<?php } ?>
|
|
|
|
this.workId = 'xajaxWork'+ new Date().getTime();
|
|
this.depth = 0;
|
|
|
|
//Get the XMLHttpRequest Object
|
|
this.getRequestObject = function()
|
|
{
|
|
<?php if ($this->bDebug){ ?>this.DebugMessage("Initializing Request Object..");<?php } ?>
|
|
var req;
|
|
try
|
|
{
|
|
req=new ActiveXObject("Msxml2.XMLHTTP");
|
|
}
|
|
catch (e)
|
|
{
|
|
try
|
|
{
|
|
req=new ActiveXObject("Microsoft.XMLHTTP");
|
|
}
|
|
catch (e2)
|
|
{
|
|
req=null;
|
|
}
|
|
}
|
|
if(!req && typeof XMLHttpRequest != "undefined")
|
|
req = new XMLHttpRequest();
|
|
|
|
<?php if ($this->bDebug){ ?>if (!req) this.DebugMessage("Request Object Instantiation failed.");<?php } ?>
|
|
|
|
return req;
|
|
}
|
|
|
|
// xajax.$() is shorthand for document.getElementById()
|
|
this.$ = function(sId)
|
|
{
|
|
return document.getElementById(sId);
|
|
}
|
|
|
|
// xajax.getFormValues() builds a query string XML message from the elements of a form object
|
|
this.getFormValues = function(frm)
|
|
{
|
|
var objForm;
|
|
if (typeof(frm) == "string")
|
|
objForm = this.$(frm);
|
|
else
|
|
objForm = frm;
|
|
var sXml = "<xjxquery><q>";
|
|
if (objForm && objForm.tagName == 'FORM')
|
|
{
|
|
var formElements = objForm.elements;
|
|
for( var i=0; i < formElements.length; i++)
|
|
{
|
|
if ((formElements[i].type == 'radio' || formElements[i].type == 'checkbox') && formElements[i].checked == false)
|
|
continue;
|
|
var name = formElements[i].name;
|
|
if (name)
|
|
{
|
|
if (sXml != '<xjxquery><q>')
|
|
sXml += '&';
|
|
sXml += name+"="+encodeURIComponent(formElements[i].value);
|
|
}
|
|
}
|
|
}
|
|
|
|
sXml +="</q></xjxquery>";
|
|
|
|
return sXml;
|
|
}
|
|
|
|
// Generates an XML message that xajax can understand from a javascript object
|
|
this.objectToXML = function(obj)
|
|
{
|
|
var sXml = "<xjxobj>";
|
|
for (i in obj)
|
|
{
|
|
try
|
|
{
|
|
if (i == 'constructor')
|
|
continue;
|
|
if (obj[i] && typeof(obj[i]) == 'function')
|
|
continue;
|
|
|
|
var key = i;
|
|
var value = obj[i];
|
|
if (value && typeof(value)=="object" &&
|
|
(value.constructor == Array
|
|
) && this.depth <= 50)
|
|
{
|
|
this.depth++;
|
|
value = this.objectToXML(value);
|
|
this.depth--;
|
|
}
|
|
|
|
sXml += "<e><k>"+key+"</k><v>"+value+"</v></e>";
|
|
|
|
}
|
|
catch(e)
|
|
{
|
|
<?php if ($this->bDebug){ ?>this.DebugMessage(e);<?php } ?>
|
|
}
|
|
}
|
|
sXml += "</xjxobj>";
|
|
|
|
return sXml;
|
|
}
|
|
|
|
// Sends a XMLHttpRequest to call the specified PHP function on the server
|
|
this.call = function(sFunction, aArgs, sRequestType)
|
|
{
|
|
var i,r,postData;
|
|
if (document.body)
|
|
document.body.style.cursor = 'wait';
|
|
<?php if ($this->bStatusMessages == true){?>window.status = 'Sending Request...';<?php } ?>
|
|
<?php if ($this->bDebug){ ?>this.DebugMessage("Starting xajax...");<?php } ?>
|
|
var xajaxRequestType = sRequestType;
|
|
var uri = xajaxRequestUri;
|
|
var value;
|
|
switch(xajaxRequestType)
|
|
{
|
|
case <?php print GET; ?>:{
|
|
var uriGet = uri.indexOf("?")==-1?"?xajax="+encodeURIComponent(sFunction):"&xajax="+encodeURIComponent(sFunction);
|
|
for (i = 0; i<aArgs.length; i++)
|
|
{
|
|
value = aArgs[i];
|
|
if (typeof(value)=="object")
|
|
value = this.objectToXML(value);
|
|
uriGet += "&xajaxargs[]="+encodeURIComponent(value);
|
|
}
|
|
uriGet += "&xajaxr=" + new Date().getTime();
|
|
uri += uriGet;
|
|
postData = null;
|
|
} break;
|
|
case <?php print POST; ?>:{
|
|
postData = "xajax="+encodeURIComponent(sFunction);
|
|
postData += "&xajaxr="+new Date().getTime();
|
|
for (i = 0; i <aArgs.length; i++)
|
|
{
|
|
value = aArgs[i];
|
|
if (typeof(value)=="object")
|
|
value = this.objectToXML(value);
|
|
postData = postData+"&xajaxargs[]="+encodeURIComponent(value);
|
|
}
|
|
} break;
|
|
default:
|
|
alert("Illegal request type: " + xajaxRequestType); return false; break;
|
|
}
|
|
r = this.getRequestObject();
|
|
r.open(xajaxRequestType==<?php print GET; ?>?"GET":"POST", uri, true);
|
|
if (xajaxRequestType == <?php print POST; ?>)
|
|
{
|
|
try
|
|
{
|
|
r.setRequestHeader("Method", "POST " + uri + " HTTP/1.1");
|
|
r.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
|
|
}
|
|
catch(e)
|
|
{
|
|
alert("Your browser does not appear to support asynchronous requests using POST.");
|
|
return false;
|
|
}
|
|
}
|
|
r.onreadystatechange = function()
|
|
{
|
|
if (r.readyState != 4)
|
|
return;
|
|
|
|
if (r.status==200)
|
|
{
|
|
<?php if ($this->bDebug){ ?>xajax.DebugMessage("Received:\n" + r.responseText);<?php } ?>
|
|
var data = r.responseXML;
|
|
if (data)
|
|
xajax.processResponse(data);
|
|
}
|
|
}
|
|
<?php if ($this->bDebug){ ?>this.DebugMessage("Calling "+sFunction +" uri="+uri+" (post:"+ postData +")");<?php } ?>
|
|
r.send(postData);
|
|
<?php if ($this->bStatusMessages == true){?>window.status = 'Waiting for data...';<?php } ?>
|
|
<?php if ($this->bDebug){ ?>this.DebugMessage(sFunction + " waiting..");<?php } ?>
|
|
delete r;
|
|
return true;
|
|
}
|
|
|
|
// Tests if the new Data is the same as the extant data
|
|
this.willChange = function(element, attribute, newData)
|
|
{
|
|
var oldData;
|
|
if (attribute == "innerHTML")
|
|
{
|
|
tmpXajax = this.$(this.workId);
|
|
if (tmpXajax == null)
|
|
{
|
|
tmpXajax = document.createElement("div");
|
|
tmpXajax.setAttribute('id',this.workId);
|
|
tmpXajax.style.display = "none";
|
|
tmpXajax.style.visibility = "hidden";
|
|
document.body.appendChild(tmpXajax);
|
|
}
|
|
tmpXajax.innerHTML = newData;
|
|
newData = tmpXajax.innerHTML;
|
|
}
|
|
eval("oldData=document.getElementById('"+element+"')."+attribute);
|
|
if (newData != oldData)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
//Process XML xajaxResponses returned from the request
|
|
this.processResponse = function(xml)
|
|
{
|
|
<?php if ($this->bStatusMessages == true){?> window.status = 'Recieving data...'; <?php } ?>
|
|
var tmpXajax = null;
|
|
xml = xml.documentElement;
|
|
for (i=0; i<xml.childNodes.length; i++)
|
|
{
|
|
if (xml.childNodes[i].nodeName == "alert")
|
|
{
|
|
if (xml.childNodes[i].firstChild)
|
|
alert(xml.childNodes[i].firstChild.nodeValue);
|
|
}
|
|
if (xml.childNodes[i].nodeName == "jscript")
|
|
{
|
|
if (xml.childNodes[i].firstChild)
|
|
eval(xml.childNodes[i].firstChild.nodeValue);
|
|
}
|
|
if (xml.childNodes[i].nodeName == "update")
|
|
{
|
|
var action;
|
|
var element;
|
|
var attribute;
|
|
var search;
|
|
var data;
|
|
var type;
|
|
var objElement;
|
|
|
|
for (j=0; j<xml.childNodes[i].attributes.length; j++)
|
|
{
|
|
if (xml.childNodes[i].attributes[j].name == "action")
|
|
{
|
|
action = xml.childNodes[i].attributes[j].value;
|
|
}
|
|
}
|
|
|
|
var node = xml.childNodes[i];
|
|
for (j=0;j<node.childNodes.length;j++)
|
|
{
|
|
if (node.childNodes[j].nodeName == "target")
|
|
{
|
|
for (k=0; k<node.childNodes[j].attributes.length; k++)
|
|
{
|
|
if (node.childNodes[j].attributes[k].name == "attribute")
|
|
{
|
|
attribute = node.childNodes[j].attributes[k].value;
|
|
}
|
|
}
|
|
element = node.childNodes[j].firstChild.nodeValue;
|
|
}
|
|
if (node.childNodes[j].nodeName == "search")
|
|
{
|
|
if (node.childNodes[j].firstChild)
|
|
search = node.childNodes[j].firstChild.nodeValue;
|
|
else
|
|
search = "";
|
|
}
|
|
if (node.childNodes[j].nodeName == "data")
|
|
{
|
|
if (node.childNodes[j].firstChild)
|
|
data = node.childNodes[j].firstChild.nodeValue;
|
|
else
|
|
data = "";
|
|
}
|
|
|
|
if (node.childNodes[j].nodeName == "type")
|
|
{
|
|
if (node.childNodes[j].firstChild)
|
|
type = node.childNodes[j].firstChild.nodeValue;
|
|
else
|
|
type = "";
|
|
}
|
|
}
|
|
if (action=="assign")
|
|
{
|
|
if (this.willChange(element,attribute,data))
|
|
{
|
|
eval("document.getElementById('"+element+"')."+attribute+"=data;");
|
|
}
|
|
}
|
|
if (action=="append")
|
|
eval("document.getElementById('"+element+"')."+attribute+"+=data;");
|
|
if (action=="prepend")
|
|
eval("document.getElementById('"+element+"')."+attribute+"=data+document.getElementById('"+element+"')."+attribute);
|
|
if (action=="replace")
|
|
{
|
|
eval("var v=document.getElementById('"+element+"')."+attribute);
|
|
var v2 = v.indexOf(search)==-1?v:"";
|
|
while (v.indexOf(search) > -1)
|
|
{
|
|
x = v.indexOf(search)+search.length+1;
|
|
v2 += v.substr(0,x).replace(search,data);
|
|
v = v.substr(x,v.length-x);
|
|
}
|
|
if (this.willChange(element,attribute,v2))
|
|
eval('document.getElementById("'+element+'").'+attribute+'=v2;');
|
|
}
|
|
if (action=="clear")
|
|
eval("document.getElementById('"+element+"')."+attribute+"='';");
|
|
if (action=="remove")
|
|
{
|
|
objElement = this.$(element);
|
|
if (objElement.parentNode && objElement.parentNode.removeChild)
|
|
{
|
|
objElement.parentNode.removeChild(objElement);
|
|
}
|
|
}
|
|
if (action=="create")
|
|
{
|
|
var objParent = this.$(element);
|
|
objElement = document.createElement(attribute);
|
|
objElement.setAttribute('id',data);
|
|
if (type && type != '')
|
|
objElement.setAttribute('type',type);
|
|
objParent.appendChild(objElement);
|
|
if (objParent.tagName == "FORM")
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
document.body.style.cursor = 'default';
|
|
<?php if ($this->bStatusMessages == true){?> window.status = 'Done'; <?php } ?>
|
|
}
|
|
}
|
|
|
|
var xajax = new Xajax();
|
|
<?php
|
|
$js .= ob_get_contents()."\n";
|
|
ob_end_clean();
|
|
foreach($this->aFunctions as $sFunction)
|
|
$js .= $this->wrap($sFunction,$this->aFunctionRequestTypes[$sFunction]);
|
|
|
|
if ($this->bDebug == false)
|
|
$js = $this->compressJavascript($js);
|
|
|
|
print $js;
|
|
}
|
|
}// end class xajax
|
|
?>
|