<?php

/*/
	© 2000-2018 by Locke Enterprises (iLocke.com) - All rights reserved.
	License: Authorized for use on the Windshields To Go USA website(s).
	File:  oDataManager.phi  [v0.98h]  (need full lookup capability desired before v1.0)
	Purpose:  Class with routines for the automated but extensible handling of the administration of data in m¥ standardized db table schema.
	Requirements: GLOBAL.phi, NDB.phi, oManagerInfo.phi for the main for the "info" member variable, manager.css
	Notes:
		Extensible capabilities should be based upon either 1) additions to run after the default action handler or 2) superceding routines handled beforehand.
		Access permissions handling and setup (like an ADMIN_LEVEL) must be done beforehand in the outer caller script.
		The callback system is just meant to get a Y/N answer regarding whether or not to process a certain block of code. However, references can be used to alter that functionality.
	Modification History:
		· 12/23/2003 - Nathan - got this working with the oManager.phi info storage model
		· 1/15/2004 - Nathan - packaged this into a class definition instead of just flat routines
		· 6/25/2004 - Nathan - converted to using the new GLOBALS.phi / NDB.phi
		· 7/3/2004 - Nathan - v0.94; new features for lookups, callbacks, and support for MGR_EDIT_SELECT
		· 7/7/2004 - Nathan - v0.96; added new $extraActions[] and $carryFields[] properties
		· 8/21/2004 - Nathan - v0.97; added in the context help extensibilities
		· 9/2/2004 - Nathan - v0.98; got the view routine working including DMGR_CALLBACK_VIEW and DMGR_CALLBACK_VIEW_FIELD
		· 10/15/2004 - Nathan - v0.98b; added and corrected functionality for DMGR_CALLBACK_LIST_LINK_EDIT
		· 10/22/2004 - Nathan - v0.98c; added links to the extra actions on the edit page
		· 10/29/2004 - Nathan - v0.98d; added DMGR_CALLBACK_UPDATE_ADD_COMPLETE
		· 11/27/2004 - Nathan - v0.98e; added the header/footer callbacks; named the edit form
		· 11/16/2005 - Nathan - v0.98f; some <br> fixes for FireFox
		· 06/19/2008 - Nathan - v0.98g; new DMGR_CALLBACK_EXTRA_ACTIONS callback
		· 08/26/2008 - Nathan - v0.98h; DMGR_CALLBACK_ACTION, added DMGR_CALLBACK_FOOTER into the DefaultActionHandler()
		· 11/05/2009 - Nathan - v0.98i; added the rowclass and rowactionclass extensibility
		· mm/dd/yyyy - [name] - [comment]
		
	!!! 1.) before v0.99, we still need to add a standardized search feature including a form and mods to the listing (use a listSQL concept?)
	         also, when only one item is returned from a search, a quick jump to the view/edit would be nice as well
	!!! 2.) before v1.00, there should be an attempt to support simple multi-checkboxes for a) sets and b) ref lookup join tables [like personRoles]
	!!! 3.) also before v1.00, it would be nice to have a NEXT/PREV on the EDIT page. And an option to 'Edit after Add' - for setting up lookup infos.
	!!! 4.) should also get some good DATE, TIME, & DATETIME field handling in here
	!!! 5.) should add the jump links beneath the list -- example code follows:
					/// add links so that parts pages can be jumped through
					$i = 0;
					$pages = ceil($matchingCount / $displayNum);
					$currentPage = floor($startAt / $displayNum) + 1;
					$pagingLinks = "";
					while( $pages>1 && $i<=$matchingCount ) {
						/// do some intelligent skipping to avoid too many nav links...
						$bDisplay = true;
						$thisPage++;
						if( $thisPage%10 == 0 ) {
							$testval = $currentPage - intval($thisPage/10) * 10;
							 if( $pages>200 && $thisPage%50!=0 && ($testval < -50 || $testval > 50) ) $bDisplay = false;
						} else {
							$testval = $currentPage - intval($thisPage/10) * 10;
							if( $testval < 0  ||  $testval > 10 )  {
								$bDisplay = false;
							}
						}
						/// show the page number...
						if( $bDisplay ) {
							if( $i == $startAt ) {
								$pagingLinks .= "&nbsp;&nbsp;<font style='text-decoration: underline; color: #8000C0; font-size: 12px; font-weight: bold;'>$thisPage</font> ";
							} else {
								$pagingLinks .= "&nbsp;&nbsp;<a style='font-weight: normal;' href=products.php?startAt=$i&displayNum=$displayNum&wF=$wF&wV=$wV>$thisPage</a> ";
							}
						}
						/// continue to the nexct page...
						$i = $i + $displayNum;
					}
					if( $pagingLinks != "" ) echo "<table cellspacing=0 cellpadding=0 border=0><tr><td valign=top nowrap style='vertical-align: top;'>Jump to Page: &nbsp;</td><td>$pagingLinks</td></tr></table>";
		
/*/

$DMGR_LicensedTo = "Windshields To Go USA - AutoGlassHosting.com";
if (!@isset($g_INCLUDED["GLOBAL.phi"])) {
    if (!include(dirname(dirname(__FILE__)) . "/GLOBAL.phi"))
        exit("<pre>\n\nERROR(0a) GLOBAL requirement failure.\n\n</pre>");
    if (!@isset($g_INCLUDED["GLOBAL.phi"]))
        exit("<pre>\n\nERROR(0b) GLOBAL requirement failure.\n\n</pre>");
} require_once $g_Config->IncPath . "N.phi";
if (!isset($g_Config->ManagerPath) || $g_Config->ManagerPath == "") {
    $g_Config->ManagerPath = dirname(__FILE__) . "/";
} if (!isset($g_Config->ManagerURL) || $g_Config->ManagerURL == "")
    $g_Config->ManagerURL = $g_Config->BaseURL . "inc/Manager/";
require $g_Config->ManagerPath . "oManagerInfo.phi";
define("DMGR_MODE_ADMIN", 16);
define("DMGR_MODE_ADMIN_ALL", 23);
define("DMGR_MODE_SINGLE", 8);
define("DMGR_MODE_SINGLE_ALL", 13);
define("DMGR_MODE_ALLOW_VIEW", 0);
define("DMGR_MODE_ALLOW_EDIT", 1);
define("DMGR_MODE_ALLOW_ADD", 2);
define("DMGR_MODE_ALLOW_DELETE", 4);
define("DMGR_MODE_ALLOW_ALL", 7);
define("DMGR_ONLYID_ALL", -1);
define("DMGR_ONLYID_NONE", 0);
define("DMGR_LOOKUP_UNKNOWN", "(unknown)");
define("DMGR_VAR_ROWCLASS", "_ rowClass");
define("DMGR_VAR_ROWACTIONCLASS", "_ rowActionClass");
define("DMGR_VAR_ROWSTYLE", "_ rowStyle");
define("DMGR_VAR_ROWACTIONSTYLE", "_ rowActionStyle");
define("DMGR_CALLBACK_ACTION", 'Action');
define("DMGR_CALLBACK_HEADER", 'Header');
define("DMGR_CALLBACK_HEADER_HEAD", 'HeaderHead');
define("DMGR_CALLBACK_HEADER_DONE", 'HeaderDone');
define("DMGR_CALLBACK_FOOTER", 'Footer');
define("DMGR_CALLBACK_LIST", 'List');
define("DMGR_CALLBACK_LIST_ITEM", 'List_Item');
define("DMGR_CALLBACK_LIST_FIELD", 'List_Field');
define("DMGR_CALLBACK_LIST_LINK_EDIT", 'List_Link_Edit');
define("DMGR_CALLBACK_LIST_LINK_CUSTOM", 'List_Link_Custom');
define("DMGR_CALLBACK_LIST_LINK_DELETE", 'List_Link_Delete');
define("DMGR_CALLBACK_EDIT", 'Edit');
define("DMGR_CALLBACK_EDIT_FIELD", 'Edit_Field');
define("DMGR_CALLBACK_VIEW", 'View');
define("DMGR_CALLBACK_VIEW_FIELD", 'View_Field');
define("DMGR_CALLBACK_UPDATE_ADD", 'UpdateAdd');
define("DMGR_CALLBACK_UPDATE_ADD_FIELD", 'UpdateAdd_Field');
define("DMGR_CALLBACK_UPDATE_ADD_COMPLETE", 'UpdateAddComplete');
define("DMGR_CALLBACK_DELETE", 'Delete');
define("DMGR_CALLBACK_EXTRA_ACTIONS", 'Extra_Actions');
return true;

class DataManager {

    var $info;
    var $mode;
    var $onlyID;
    var $whereClause;
    var $carryFields = null;
    var $forceFields = null;
    var $extraActions = null;
    var $extraActionTargets = null;
    var $extraActionTitle = "Additional Actions";
    var $extraActionSingleRow = true;
    var $actionLinksClass = "";
    var $callbacks = null;
    var $showListPagination = true;
    var $bDebugging;
    var $bUseSqlQuote;
    var $maxListLength = 50;
    var $listTitle = "";
    var $showEditFormHeader = true;
    var $useRowHighlighting = true;
    var $licensedTo = "Locke Enterprises (iLocke.com)";
    var $extraHead = "";

    function DataManager($mode, $onlyID, $itemName, $table, $orderBy = "name", $infoOverrides = "", $hasID = true, $bDebugging = false, $bUseSqlQuote = false) {
        $this->mode = $mode;
        $this->onlyID = $onlyID;
        $this->bDebugging = $bDebugging;
        $this->bUseSqlQuote = $bUseSqlQuote;
        $this->extraActions = array();
        $this->extraActionTargets = array();
        $this->carryFields = array();
        $this->ID = "ID";
        global $DMGR_LicensedTo;
        $this->licensedTo = $DMGR_LicensedTo;
        $this->info = new ManagerInfo($table, $itemName, $orderBy, $infoOverrides, $hasID, $bDebugging);
    }

    function DefaultActionHandler($A, $ID, $bDebug = false) {
        $this->bDebugging = $this->bDebugging || $bDebug;
        $this->Manager_Header();
        $result = true;
        $action = trim(strtoupper($A));
        if ($this->mode & DMGR_MODE_SINGLE) {
            $ID = intval($this->onlyID);
            if (($action == "" || $action == "L"))
                $action = "E";
        } if (!($this->mode & DMGR_MODE_ALLOW_EDIT) && $action == "E")
            $action = "V";
        if ($action == "L" || $action == "") {
            $this->ListItems();
        } elseif ($action == "E") {
            $this->EditItem($ID);
        } elseif ($action == "A") {
            $this->UpdateItem($ID);
            $this->EditItem(0);
        } elseif ($action == "U") {
            $this->UpdateItem($ID);
            $this->EditItem($ID);
        } elseif ($action == "D") {
            $this->DeleteItem($ID);
            $this->ListItems();
        } elseif ($action == "V") {
            $this->ViewItem($ID);
        } else {
            if (!isset($this->callbacks[DMGR_CALLBACK_ACTION]) || $this->callbacks[DMGR_CALLBACK_ACTION] == "") {
                return false;
            } $result = $this->RunCallback(DMGR_CALLBACK_ACTION, $action, $ID);
        } if ($result) {
            $this->RunCallback(DMGR_CALLBACK_FOOTER);
        } return $result;
    }

    function ListItems() {
        if ($this->mode & DMGR_MODE_SINGLE)
            $this->ExitMessage("[Error] Ths instance of DataManager->ListItems() is restricted to a single item. (" . $this->mode . ":" . (DMGR_MODE_SINGLE) . ")");
        $bEdit = $this->mode & DMGR_MODE_ALLOW_EDIT;
        $bView = !$bEdit;
        $bDelete = $this->mode & DMGR_MODE_ALLOW_DELETE;
        global $PHP_SELF, $g_oNDB;
        global $B, $N, $S;
        if ($B < 1)
            $B = 0;
        if ($N < 1)
            $N = 25;
        $listParams = QueryString(array('B', 'O', 'N', 'S', 'F', 'M'));
        $extraParams = QueryString($this->carryFields);
        $listParams .= $extraParams;
        $where = $this->whereClause;
        $total = $g_oNDB->getCount($this->info->table, $where);
        if ($total < 1) {
            $msg = "Error(0) No matching " . $this->info->itemName . " items found !\n<!--" . $where . "-->\n</p><br>\n";
            if (!($this->mode & DMGR_MODE_SINGLE) && ($this->mode & DMGR_MODE_ALLOW_ADD)) {
                $msg .= "<a href=\"" . $PHP_SELF . "?A=E&ID=0" . $listParams . "\">ADD</a> a " . $this->info->itemName . " item.<br><br>";
            } $this->ExitMessage($msg);
        } if ($where != "")
            $where = " WHERE " . $where . " ";
        $orderBy = $this->info->orderBy != "" ? "ORDER BY " . $this->info->orderBy : "";
        $SQL = "SELECT * FROM " . $this->info->table . " " . $where . " " . $orderBy;
        if ($this->showListPagination)
            $SQL .= " LIMIT " . $B . ", " . $N;
        if ($this->bDebugging)
            echo "\n<br>\n\n" . $SQL . "\n\n<br>\n";
        $oNRS = new nRS();
        if (!($oNRS->open($SQL))) {
            $this->ExitMessage("Error(1) No items found!<!--\n\n" . $oNRS->message . "\n\n-->");
        } if (!$this->RunCallback(DMGR_CALLBACK_LIST, $oNRS, $this->extraActions)) {
            $this->ExitMessage("<p class=alert>Error(2) Unable to list the items.</p>");
        } echo "<table border=0 cellpadding=0 cellspacing=0><tr><td>";
        echo $this->Manager_HelpLink($this->info->helpInfo['List_ContextID'], $this->info->helpInfo['List_JumpTo']);
        echo "<nobr><u><font size=4>" . ($this->listTitle != "" ? $this->listTitle : $this->info->itemName . " Manager") . "</u> &nbsp; &nbsp; &nbsp;</font></nobr><br>&nbsp;\n";
        echo "</td></tr></table>";
        echo "Listing items " . ($B + 1) . " through " . ( $B + 1 + $N > $total ? $total : $B + $N ) . " of " . $total . ".<br>\n";
        echo "<script language=JavaScript> var mOldColorTR = ''; var mOldColorTD = ''; function setBG( row, color ) { var OldColor = ''; OldColor = row.style.backgroundColor; row.style.backgroundColor = color; return OldColor; } </script>";
        echo "<table border=0 bordercolor=red cellspacing=0 cellpadding=0><tr valign=top><td colspan=1 align=left valign=top class=managerListBg><table cellspacing=1 cellpadding=2 bgcolor=#808080 border=0>\n";
        echo "<tr>\n";
        foreach ($this->info->fields as $fieldInfo) {
            if ($fieldInfo->bInListing)
                echo "\t<td class=managerHeaderList nowrap>" . $fieldInfo->nomen . "</td>\n";
        } echo "\t<td class=actionHeader colspan=" . ( ($bEdit || $bView) && $bDelete ? count($this->extraActions) + 2 : count($this->extraActions) + 1) . "><b>Action</td>\n";
        echo "</tr>\n";
        $linkClass = $this->actionLinksClass != "" ? "class=\"" . $this->actionLinksClass . "\" " : "";
        while ($rData = $oNRS->read()) {
            if (++$i % 2 == 1) {
                $rData[DMGR_VAR_ROWCLASS] = "managerRow";
                $rData[DMGR_VAR_ROWACTIONCLASS] = "action";
            } else {
                $rData[DMGR_VAR_ROWCLASS] = "managerRow2";
                $rData[DMGR_VAR_ROWACTIONCLASS] = "action2";
            } $rData[DMGR_VAR_ROWSTYLE] = "";
            $rData[DMGR_VAR_ROWACTIONSTYLE] = "";
            if (!$this->RunCallback(DMGR_CALLBACK_LIST_ITEM, $rData)) {
                --$i;
                continue;
            } if ($i % 2 == 1) {
                if (!isset($rData[DMGR_VAR_ROWCLASS]))
                    $rData[DMGR_VAR_ROWCLASS] = "managerRow";
                if (!isset($rData[DMGR_VAR_ROWACTIONCLASS]))
                    $rData[DMGR_VAR_ROWACTIONCLASS] = "action";
            } else {
                if (!isset($rData[DMGR_VAR_ROWCLASS]))
                    $rData[DMGR_VAR_ROWCLASS] = "managerRow2";
                if (!isset($rData[DMGR_VAR_ROWACTIONCLASS]))
                    $rData[DMGR_VAR_ROWACTIONCLASS] = "action2";
            } if (!isset($rData[DMGR_VAR_ROWSTYLE]))
                $rData[DMGR_VAR_ROWSTYLE] = "";
            if (!isset($rData[DMGR_VAR_ROWACTIONSTYLE]))
                $rData[DMGR_VAR_ROWACTIONSTYLE] = "";
            $highlightingScriptTR = !$this->useRowHighlighting ? "" : "onMouseOver=\"mOldColorTR = setBG(this, '#F8F8E0'); return true;\" onMouseOut=\"setBG(this, mOldColorTR); return true;\"";
            echo '<tr class="' . htmlspecialChars($rData[DMGR_VAR_ROWCLASS]) . '" style="' . htmlspecialChars($rData[DMGR_VAR_ROWSTYLE]) . '" ' . $highlightingScriptTR . '>';
            foreach ($this->info->fields as $fieldInfo) {
                $bEditThisField = $bEdit;
                $bViewThisField = $bView;
                $bEditOrViewThisField = $this->RunCallback(DMGR_CALLBACK_LIST_LINK_EDIT, $rData, $bEditThisField, $bViewThisField);
                if ($fieldInfo->bInListing) {
                    $fieldValue = str_replace("\n", " ", str_replace("\r", " ", strip_tags($rData[$fieldInfo->name])));
                    if ($fieldInfo->type == MGR_TYPE_LOOKUP) {
                        if (isset($fieldInfo->lookups) && is_array($fieldInfo->lookups) && count($fieldInfo->lookups) == 3) {
                            if ($fieldInfo->bEmptyOption && $fieldValue == 0) {
                                $fieldValue = "";
                            } else {
                                $fieldValue = $g_oNDB->getField(0, "SELECT " . $fieldInfo->lookups[2] . " FROM " . $fieldInfo->lookups[0] . " WHERE " . $fieldInfo->lookups[1] . "='" . $fieldValue . "'", DMGR_LOOKUP_UNKNOWN);
                            }
                        }
                    } if (strlen($fieldValue) > $this->maxListLength) {
                        $fieldValue = htmlspecialchars(substr($fieldValue, 0, $this->maxListLength)) . "...";
                        if (!($fieldInfo->bIsListingEditLink && $bEditOrViewThisField))
                            $fieldValue = "<a class=text title=\"" . htmlspecialchars($fieldValue) . "\">" . $fieldValue . "</a>";
                    } else {
                        $fieldValue = htmlspecialchars($fieldValue);
                    } if ($fieldValue == "")
                        $fieldValue = "&nbsp;";
                    if (!$this->RunCallback(DMGR_CALLBACK_LIST_FIELD, $fieldInfo, $rData, $fieldValue)) {
                        echo "<td align=center><font color=#C0C0C0>&middot;</font></td>";
                        continue;
                    } if ($fieldInfo->bIsListingEditLink && $bEditOrViewThisField) {
                        if ($fieldInfo->hoverTipField != "")
                            $tip = htmlspecialchars(substr(str_replace("\n", " ", str_replace("\r", " ", strip_tags($rData[$fieldInfo->hoverTipField]))), 0, 200));
                        else
                            $tip = "Click here to " . ($bEditThisField ? "edit" : "view") . " this item. ID # " . $rData[$this->ID];
                        echo "<td nowrap align=right><a title=\"" . $tip . "\" href=\"" . $PHP_SELF . "?A=" . ($bEditThisField ? "E" : "V") . "&ID=" . $rData[$this->ID] . $listParams . "\">" . $fieldValue . "</a></td>";
                    } else {
                        echo "<td nowrap>" . $fieldValue . "</td>";
                    }
                }
            } $highlightingScriptTD = !$this->useRowHighlighting ? "" : "onMouseOver=\"mOldColorTD = setBG(this, '#E8ECF0'); return true;\" onMouseOut=\"setBG(this, mOldColorTD); return true;\"";
            if ($bEditOrViewThisField) {
                echo "<td nowrap class=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONCLASS]) . "\" style=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONSTYLE]) . "\" $highlightingScriptTD>&nbsp;<a " . $linkClass . "title='Click here to " . ($bEditThisField ? "edit" : "view") . " this item.' href=\"" . $PHP_SELF . "?A=" . ($bEditThisField ? "E" : "V") . "&ID=" . $rData[$this->ID] . $listParams . "\">" . ($bEditThisField ? "Edit" : "View") . "</a>&nbsp;</td>";
            } else {
                "<td class=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONCLASS]) . "\" style=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONSTYLE]) . "\" nowrap>&nbsp &nbsp &nbsp &nbsp;</td>";
            } foreach ($this->extraActions as $actionName => $actionLink) {
                if ($this->RunCallback(DMGR_CALLBACK_LIST_LINK_CUSTOM, $actionName, $rData)) {
                    $actionTarget = "";
                    if (ereg("^(\{[^\}]+\})(.*)$", $actionLink, $rMatches)) {
                        $actionTarget = substr($rMatches[1], 1, strlen($rMatches[1]) - 2);
                        $actionLink = $rMatches[2];
                    } else {
                        $actionTarget = $this->extraActionTargets[$actionName];
                    } echo "<td nowrap class=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONCLASS]) . "\" style=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONSTYLE]) . "\" $highlightingScriptTD>&nbsp;<a " . $linkClass . "title='Click here to perform the (" . $actionName . ") action on this item.' href=\"" . str_replace("\$listParams", $listParams, str_replace("\$ID", $rData['ID'], $actionLink)) . "\" target=\"" . $actionTarget . "\">" . $actionName . "</a>&nbsp;</td>\n";
                }
            } if ($bDelete) {
                if ($this->RunCallback(DMGR_CALLBACK_LIST_LINK_DELETE, $rData)) {
                    echo "<td nowrap class=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONCLASS]) . "\" style=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONSTYLE]) . "\" $highlightingScriptTD>&nbsp;<a class='alert' title='Click here to delete this item.' onClick=\"return confirm('Really delete this " . $this->info->itemName . " item? ');\" href=\"" . $PHP_SELF . "?A=D&ID=" . $rData[$this->ID] . $listParams . "\">Delete</a>&nbsp;</td>";
                } else {
                    echo "<td class=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONCLASS]) . "\" style=\"" . htmlspecialchars($rData[DMGR_VAR_ROWACTIONSTYLE]) . "\" nowrap>&nbsp &nbsp &nbsp &nbsp;</td>";
                }
            } echo "</tr>";
        } echo "</table></td></tr></table><span style='font-size: 4px;'>&nbsp;<br></span>";
        if ($this->showListPagination) {
            $bLinked = false;
            $listParams = "&N=" . $N . "&S=" . $S . "&F=" . $F . "&M=" . $M . $extraParams;
            if ($B > 0) {
                $bLinked = true;
                $newB = $B - $N;
                if ($newB < 0)
                    $newB = 0;
                echo "<a href=\"" . $PHP_SELF . "?A=L&B=" . $newB . $listParams . "\">&lt; &lt;&nbsp; Previous</a> &nbsp;&nbsp; ";
            } if ($B + $N + 1 < $total) {
                $bLinked = true;
                $newB = $B + $N;
                echo "<a href=\"" . $PHP_SELF . "?A=L&B=" . $newB . $listParams . "\">Next &nbsp;&gt; &gt;</a>\n";
            } $listParams = "&B=" . $B . "&S=" . $S . "&F=" . $F . "&M=" . $M . $extraParams;
            if ($bLinked)
                echo "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ";
            echo "List Items: &nbsp;<a href=\"" . $PHP_SELF . "?A=L&N=10" . $listParams . "\">10</a> &middot; <a href=\"" . $PHP_SELF . "?A=L&N=25" . $listParams . "\">25</a> &middot; <a href=\"" . $PHP_SELF . "?A=L&N=50" . $listParams . "\">50</a> &middot; <a href=\"" . $PHP_SELF . "?A=L&N=100" . $listParams . "\">100</a> &middot; <a href=\"" . $PHP_SELF . "?A=L&N=500" . $listParams . "\">500</a>&nbsp; at a time<br>\n";
            $listParams = "&N=" . $N . "&B=" . $B . "&S=" . $S . "&F=" . $F . "&M=" . $M . $extraParams;
        } if (!($this->mode & DMGR_MODE_SINGLE) && ($this->mode & DMGR_MODE_ALLOW_ADD)) {
            if ($bEdit)
                echo "<br><a href=\"" . $PHP_SELF . "?A=E&ID=0" . $listParams . "\">ADD</a> a " . $this->info->itemName . " item.<br><br>";
        }
    }

    function EditItem($ID) {
        global $PHP_SELF, $g_oNDB;
        if ($ID > 0) {
            $SQL = "SELECT * FROM " . $this->info->table . " WHERE " . $this->ID . "='$ID'";
//            die($SQL);
            if ($this->whereClause != "")
                $SQL .= " AND " . $this->whereClause;
            if ($this->bDebugging)
                echo $SQL . "<br><br>";
            $rData = $g_oNDB->getRow($SQL, "ERROR!");
            if (!@is_array($rData))
                exit("Error(1) Information not found!<br>" . ($this->bDebugging ? $g_oNDB->message() : ""));
            if (!@isset($rData[0]))
                exit("Error(2) Empty information returned!<br>" . ($this->bDebugging ? $g_oNDB->message() : ""));
            if ($rData[0] == "ERROR!")
                exit("Error(3) Data could not be retrieved!<br>" . ($this->bDebugging ? $g_oNDB->message() : ""));
            if ($this->bDebugging)
                DumpInfo($rData, "rData returned");
            $this->DisplayExtraActions("Edit_Header", $rData, $listParams, $linkClass);
            $title = "<u><font size=4>Edit " . $this->info->itemName . " Information</font></u>";
        } else {
            if (($this->mode & DMGR_MODE_SINGLE) || !($this->mode & DMGR_MODE_ALLOW_ADD))
                $this->ExitMessage("[Error] No permissions to add an item.");
            $rData = array();
            $title = "<u><font size=4>Add " . $this->info->itemName . "</font></u>";
        } echo "<table border=0 cellpadding=0 cellspacing=0><tr><td>";
        echo $this->Manager_HelpLink($this->info->helpInfo['Edit_ContextID'], $this->info->helpInfo['Edit_JumpTo']);
        echo "<nobr>" . $title . "<font size=4> &nbsp; &nbsp; &nbsp;</font></nobr>";
        echo "</td></tr></table>";
        if (!$this->RunCallback(DMGR_CALLBACK_EDIT, $rData)) {
            $this->ExitMessage("<p class=alert>Unable to edit that item.</p>");
            exit();
        } if (false && $BQ)
            echo "<blockquote style='padding: 25px; margin: 0px;'>\n";
        echo "<span style='font-size: 4px;'><br><br></span>";
        ?> 
        <table cellspacing=1 cellpadding=2 class=managerEdit> <form name=LockeManagerForm action='<? echo $PHP_SELF; ?>' method=POST> <input type=hidden name=A value=<? echo $ID>0?"U":"A"; ?>> <input type=hidden name=ID value="<? echo $rData[$this->ID]; ?>"> 
                <?php echo HiddenFields(array('B', 'O', 'N', 'S', 'F', 'M'));
                echo HiddenFields($this->carryFields);
                ?> <!-- submission area --> <?php
                if ($this->showEditFormHeader)
                    echo "<tr><td class=managerHeaderEdit>Field</td><td class=managerHeaderEdit>Value</td></tr>";
                $currentSection = "";
                foreach ($this->info->fields as $thisField) {
                    if ($this->bDebugging)
                        DumpInfo($thisField);
                    if (!$this->RunCallback(DMGR_CALLBACK_EDIT_FIELD, $thisField, $rData))
                        continue;
                    if ($thisField->section != "" && $thisField->section != $currentSection) {
                        $currentSection = $thisField->section;
                        $helpCode = $this->Manager_HelpLink($thisField->helpContextID, $thisField->helpJumpTo);
                        echo "<tr><td class=managerSectionHeader" . $thisField->extraCellClass . " colspan=2>" . $helpCode . $currentSection . "</td></tr>\n";
                    } if ($ID < 1 && !$thisField->bEditable)
                        continue;
                    echo "<tr>\n\t<td class=managerFieldName" . $thisField->extraCellClass . ">" . $thisField->nomen . " &nbsp;</td>\n";
                    if ($ID < 1 && !isset($rData[$thisField->name]))
                        $fieldValue = $thisField->defaultValue;
                    else
                        $fieldValue = $rData[$thisField->name];
                    if ($thisField->format != "")
                        $fieldValue = sprintf($thisField->format, $fieldValue);
                    if (!$thisField->bEditable) {
                        if ($thisField->type == MGR_TYPE_LOOKUP) {
                            if (isset($thisField->lookups) && is_array($thisField->lookups) && count($thisField->lookups) == 3) {
                                $fieldValue = $g_oNDB->getField(0, "SELECT " . $thisField->lookups[2] . " FROM " . $thisField->lookups[0] . " WHERE " . $thisField->lookups[1] . "='" . $fieldValue . "'", DMGR_LOOKUP_UNKNOWN);
                            }
                        } echo "\t<td class=managerFieldEdit" . $thisField->extraCellClass . ">";
                        if ($thisField->editWith == MGR_EDIT_CHECKBOX) {
                            echo "<input type=checkbox READONLY LOCKED DISABLED name=\"f_" . $thisField->name . "_x\" value=\"" . $thisField->optionValues[1] . "\"" . ($fieldValue == $thisField->optionValues[1] ? " CHECKED" : "") . ">";
                        } else {
                            echo "<span class=\"" . $thisField->css_class . "\" style=\"" . $thisField->css_style . "\">" . $fieldValue . "</span>";
                        }
                    } else {
                        echo "\t<td class=managerFieldEdit" . $thisField->extraCellClass . "><input type=hidden name=\"t_" . $thisField->name . "\" value=\"" . $thisField->type . ($thisField->type == MGR_TYPE_BOOL ? "=" . join(":", $thisField->optionValues) : "") . "\">";
                        $highlighting = "onFocus=\"this.style.color='#0000A0'; this.style.background='#FCFCE8'; return true;\" onBlur=\"this.style.color='#000060'; this.style.background='#F4F4F4'; return true;\"";
                        if ($thisField->editWith == MGR_EDIT_INPUT) {
                            echo "<input type=text name=\"f_" . $thisField->name . "\" class=\"" . $thisField->css_class . "\" style=\"" . $thisField->css_style . "\" $highlighting size=\"" . $thisField->size . "\" maxlength=\"" . $thisField->maxlength . "\" value=\"" . htmlspecialchars($fieldValue) . "\">";
                        } elseif ($thisField->editWith == MGR_EDIT_TEXTAREA) {
                            echo "<textarea name=\"f_" . $thisField->name . "\" class=\"" . $thisField->css_class . "\" style=\"" . $thisField->css_style . "\" $highlighting cols=\"" . $thisField->cols . "\" rows=\"" . $thisField->rows . "\" wrap=soft>" . htmlspecialchars($fieldValue) . "</textarea>";
                        } elseif ($thisField->editWith == MGR_EDIT_SELECT) {
                            echo "<select name=f_" . $thisField->name . " class=\"" . $thisField->css_class . "\">\n";
                            if ($thisField->type == MGR_TYPE_LOOKUP) {
                                if (isset($thisField->lookups) && is_array($thisField->lookups) && count($thisField->lookups) == 3) {
                                    $SQL = "SELECT " . $thisField->lookups[1] . " FROM " . $thisField->lookups[0] . " ORDER BY " . $thisField->lookups[2];
                                    $thisField->optionValues = $g_oNDB->getColumn(0, $SQL, "ERROR!");
                                    $thisField->optionTexts = $g_oNDB->getColumn(0, "SELECT " . $thisField->lookups[2] . " FROM " . $thisField->lookups[0] . " ORDER BY " . $thisField->lookups[2], "ERROR!");
                                }
                            } if ($thisField->bEmptyOption != "") {
                                array_unshift($thisField->optionValues, "0");
                                array_unshift($thisField->optionTexts, "&nbsp; - (please select one) - &nbsp;");
                            } for ($i = 0; $i < count($thisField->optionValues); $i++) {
                                echo "<option value=\"" . $thisField->optionValues[$i] . "\"" . ($thisField->optionValues[$i] == $fieldValue ? " SELECTED" : "") . ">" . $thisField->optionTexts[$i] . "</option>\n";
                            } echo "</select>";
                        } elseif ($thisField->editWith == MGR_EDIT_CHECKBOX) {
                            echo "<input type=checkbox name=\"f_" . $thisField->name . "\" value=\"" . $thisField->optionValues[1] . "\"" . ($fieldValue == $thisField->optionValues[1] ? " CHECKED" : "") . ">";
                        }
                    } if ($thisField->units != "")
                        echo "<span class=fieldUnits>" . $thisField->units . "</span>";
                    if ($thisField->description != "") {
                        echo $thisField->editWith == MGR_EDIT_CHECKBOX ? "<span class=none>" : "<span class=fieldDescription>&nbsp;&nbsp;";
                        echo $thisField->description . "</span>";
                    } echo "</td></tr>\n";
                } echo "</table><br>";
                if ($ID > 0) {
                    echo "<input type=submit class=button onMouseOver=\"this.style.backgroundColor = '#9090C8'; return true;\" onMouseOut=\"this.style.backgroundColor = '#8080B0'; return true;\" value='Save Changes'><br><br>";
                    if ($this->mode & DMGR_MODE_ALLOW_DELETE)
                        echo "<a class=alert onClick=\"return confirm('Really delete this " . $this->info->itemName . " item? ');\" href='" . $PHP_SELF . "?A=D&ID=" . $rData[$this->ID] . "'>DELETE</a> this " . $this->info->itemName . " item. &nbsp; (<font color=#A00000>Warning:</font> this deletion is final and CANNOT be undone.)<br><br>";
                    $this->DisplayExtraActions("Edit_Footer", $rData, $listParams, $linkClass);
                } else {
                    echo "<input type=submit class=button onMouseOver=\"this.style.backgroundColor = '#9090C8'; return true;\" onMouseOut=\"this.style.backgroundColor = '#8080B0'; return true;\" value='Add Item'><br><br>";
                } if ($this->mode & DMGR_MODE_ADMIN) {
                    echo "<a href=\"" . $PHP_SELF . "?A=L" . QueryString(array('B', 'O', 'N', 'S', 'F', 'M')) . QueryString($this->carryFields) . "\">BACK</a> to the " . $this->info->itemName . " list.";
                } if (false && $BQ)
                    echo "</blockquote>";
                echo "</form><br><br>";
            }

            function ViewItem($ID) {
                global $PHP_SELF, $g_oNDB;
                if ($ID > 0) {
                    $SQL = "SELECT * FROM " . $this->info->table . " WHERE " . $this->ID . "='$ID'";
                    if ($this->whereClause != "")
                        $SQL .= " AND " . $this->whereClause;
                    if ($this->bDebugging)
                        echo $SQL . "<br><br>";
                    $rData = $g_oNDB->getRow($SQL, "ERROR!");
                    if (!@is_array($rData))
                        exit("Error(1) Information not found!<br>" . ($this->bDebugging ? $g_oNDB->message() : ""));
                    if (!@isset($rData[0]))
                        exit("Error(2) Empty information returned!<br>" . ($this->bDebugging ? $g_oNDB->message() : ""));
                    if ($rData[0] == "ERROR!")
                        exit("Error(3) Data could not be retrieved!<br>" . ($this->bDebugging ? $g_oNDB->message() : ""));
                    if ($this->bDebugging)
                        DumpInfo($rData, "rData returned");
                    $title = "<u><font size=4>View " . $this->info->itemName . " Information</font></u>";
                } else {
                    if (($this->mode & DMGR_MODE_SINGLE) || !($this->mode & DMGR_MODE_ALLOW_ADD))
                        $this->ExitMessage("[Error] No permissions to add an item.");
                    $rData = array();
                    $title = "<u><font size=4>Add " . $this->info->itemName . "</font></u>";
                } echo "<table border=0 cellpadding=0 cellspacing=0><tr><td>";
                echo $this->Manager_HelpLink($this->info->helpInfo['Edit_ContextID'], $this->info->helpInfo['Edit_JumpTo']);
                echo "<nobr>" . $title . "<font size=4> &nbsp; &nbsp; &nbsp;</font></nobr>";
                echo "</td></tr></table>";
                if (!$this->RunCallback(DMGR_CALLBACK_VIEW, $rData)) {
                    $this->ExitMessage("<p class=alert>Unable to view that item.</p>");
                    exit();
                } if (false && $BQ)
                    echo "<blockquote style='padding: 25px; margin: 0px;'>\n";
                echo "<span style='font-size: 4px;'><br><br></span>";
                echo "<table cellspacing=1 cellpadding=2 class=managerEdit>";
                if ($this->showEditFormHeader)
                    echo "<tr><td class=managerHeaderEdit>Field</td><td class=managerHeaderEdit>Value</td></tr>";
                $currentSection = "";
                foreach ($this->info->fields as $thisField) {
                    if ($this->bDebugging)
                        DumpInfo($thisField);
                    if ($ID < 1 && !isset($rData[$thisField->name]))
                        $fieldValue = $thisField->defaultValue;
                    else
                        $fieldValue = $rData[$thisField->name];
                    $fieldValue = htmlspecialchars($fieldValue);
                    if ($thisField->format != "")
                        $fieldValue = sprintf($thisField->format, $fieldValue);
                    if (!$this->RunCallback(DMGR_CALLBACK_VIEW_FIELD, $thisField, $rData, $fieldValue))
                        continue;
                    if ($thisField->section != "" && $thisField->section != $currentSection) {
                        $currentSection = $thisField->section;
                        $helpCode = $this->Manager_HelpLink($thisField->helpContextID, $thisField->helpJumpTo);
                        echo "<tr><td class=managerSectionHeader" . $thisField->extraCellClass . " colspan=2>" . $helpCode . $currentSection . "</td></tr>\n";
                    } if ($ID < 1 && !$thisField->bEditable)
                        continue;
                    echo "<tr>\n\t<td class=managerFieldName" . $thisField->extraCellClass . ">" . $thisField->nomen . " &nbsp;</td>\n";
                    if ($thisField->type == MGR_TYPE_LOOKUP) {
                        if (isset($thisField->lookups) && is_array($thisField->lookups) && count($thisField->lookups) == 3) {
                            $fieldValue = $g_oNDB->getField(0, "SELECT " . $thisField->lookups[2] . " FROM " . $thisField->lookups[0] . " WHERE " . $thisField->lookups[1] . "='" . $fieldValue . "'", DMGR_LOOKUP_UNKNOWN);
                        }
                    } echo "\t<td class=managerFieldEdit" . $thisField->extraCellClass . "><span Zclass=\"" . $thisField->css_class . "\" style=\"" . $thisField->css_style . "\">" . $fieldValue . "</span>";
                    if ($thisField->units != "")
                        echo "<span class=fieldUnits>" . $thisField->units . "</span>";
                    if (false && $thisField->description != "") {
                        echo $thisField->editWith == MGR_EDIT_CHECKBOX ? "<span class=none>" : "<span class=fieldDescription>&nbsp;&nbsp;";
                        echo $thisField->description . "</span>";
                    } echo "</td></tr>\n";
                } echo "</table><br>";
                if ($this->mode & DMGR_MODE_ADMIN) {
                    echo "<a href=\"" . $PHP_SELF . "?A=L" . QueryString(array('B', 'O', 'N', 'S', 'F', 'M')) . QueryString($this->carryFields) . "\">BACK</a> to the " . $this->info->itemName . " list.";
                } if (false && $BQ)
                    echo "</blockquote>";
                echo "<br><br>";
            }

            function UpdateItem($ID) {
                global $PHP_SELF, $g_oNDB, $HTTP_POST_VARS, $HTTP_GET_VARS;
                if (!$this->RunCallback(DMGR_CALLBACK_UPDATE_ADD, $ID)) {
                    if ($this->bDebugging)
                        echo ($ID > 0 ? "Update" : "Add") . " of item '" . $ID . "' was barred by callback.<br>";
                    return false;
                } if ($ID > 0) {
                    $SQL = "UPDATE " . $this->info->table . " SET ";
                } else {
                    $SQL = "INSERT INTO " . $this->info->table . " SET ";
                } $FieldTypes = RequestFieldNames("^t_", true);
                if (count($FieldTypes) < 1)
                    $this->ExitMessage("UpdateItem() configuration error -- no fields found.<br>\n");
                foreach ($FieldTypes as $fieldName) {
                    $type = $_POST['t_' . $fieldName];
                    if (eregi("^" . MGR_TYPE_BOOL, $type)) {
                        $parms = eregi_replace("^" . MGR_TYPE_BOOL, "", $type);
                        $parms = eregi_replace("^=", "", $parms);
                        if ($parms == "")
                            $parms = "N:Y";
                        $parms = split(":", $parms);
                        if ($this->bUseSqlQuote) {
                            $fieldValue = $g_oNDB->escape($_POST['f_' . $fieldName] == $parms[1] ? $parms[1] : $parms[0], NDB_NO_QUOTES);
                        } else {
                            $fieldValue = $_POST['f_' . $fieldName] == $parms[1] ? $parms[1] : $parms[0];
                        }
                    } else {
                        if ($this->bUseSqlQuote) {
                            $fieldValue = $g_oNDB->escape($_POST['f_' . $fieldName], NDB_NO_QUOTES);
                        } else {
                            $fieldValue = $_POST['f_' . $fieldName];
                        }
                    } if (!$this->RunCallback(DMGR_CALLBACK_UPDATE_ADD_FIELD, $ID, $fieldName, $fieldValue)) {
                        if ($this->bDebugging)
                            echo ($ID > 0 ? "Update" : "Add") . " of item '" . $ID . "' was barred by callback.<br>";
                        continue;
                    } $SQL .= $fieldName . "='" . $fieldValue . "', ";
                } $SQL = substr($SQL, 0, strlen($SQL) - 2);
                if ($ID > 0)
                    $SQL .= " WHERE " . $this->ID . "=" . $ID;
                if ($this->bDebugging)
                    echo "<br>\n\n$SQL\n\n<br>";
                if (!$g_oNDB->execute($SQL))
                    $this->ExitMessage($g_oNDB->message() . "<!--\n\n" . $SQL . "\n\n-->");
                if ($ID > 0) {
                    echo "<font color=#00C040 size=4><b>&gt; &gt; Changes saved.</b></font><br><br>";
                } else {
                    echo "<font color=#00C040 size=4><b>&gt; &gt; " . $this->info->itemName . " added.</b></font><br><br>";
                    $ID = $g_oNDB->getLastInsertID($this->info->table);
                } $this->RunCallback(DMGR_CALLBACK_UPDATE_ADD_COMPLETE, $ID);
            }

            function DeleteItem($ID) {
                global $PHP_SELF, $g_oNDB;
                if (!$this->RunCallback(DMGR_CALLBACK_DELETE, $ID)) {
                    if ($this->bDebugging)
                        echo "Delete of item '" . $ID . "' barred by callback.<br>";
                    return false;
                } $SQL = "DELETE FROM " . $this->info->table . " WHERE " . $this->ID . "='" . $ID . "'";
                if ($this->whereClause != "")
                    $SQL .= " AND " . $this->whereClause;
                if ($this->bDebugging)
                    echo "<!--\n" . $SQL . "\nwhereClause: " . $this->whereClause . "\n-->";
                if (!$g_oNDB->execute($SQL)) {
                    $this->ExitMessage($g_oNDB->message() . "<!--\n\n" . $SQL . "\n\n-->");
                    return true;
                } if (intval($g_oNDB->affectedRows) == 1) {
                    echo "<p class=action>&gt;&gt; " . $this->info->itemName . " item deleted.</p>";
                } else {
                    echo "<p class=error>&gt;&gt; " . intval($g_oNDB->affectedRows) . " item(s) deleted.";
                    if (intval($g_oNDB->affectedRows) < 1)
                        echo " You probably do not have permission to delete that " . $this->info->itemName . " item.";
                    echo "</p>";
                    if ($this->bDebugging)
                        echo $g_oNDB->message() . "<br>";
                } return true;
            }

            function Manager_Header($title = "", $showLocke = true) {
                global $g_Config;
                @session_start();
                if (!$this->RunCallback(DMGR_CALLBACK_HEADER))
                    return;
                ?> <!-- Developed and Copyrighted (c) 2000-2004 by: Locke Enterprises (www.iLocke.com) --> <html> <head> <title><?php if ($showLocke) echo "LockeMgr: "; ?>Web Content Management System<?php if ($title != "")
                        echo " | " . $title;
                    if ($showLocke)
                        echo " | by iLocke.com";
                ?></title> <meta name="Copyright" content="Copyright (c) 2000-2004 Locke Enterprises (iLocke.com) - All rights reserved."> <meta name="Owner" content="Locke Enterprises (iLocke.com)"> <meta name="License" content="<? echo $this->licensedTo; ?>"> <meta name="Author" content="Nathan"> <meta name="Creator" content="Locke Enterprises (iLocke.com)"> <meta name="Maintaned-By" content="Locke Enterprises (iLocke.com)"> <script language="JavaScript" src="/inc/nUtils.js"></script>
                        <link rel="stylesheet" type="text/css" href="<? echo $g_Config->ManagerURL; ?>manager.css"> <?php echo $this->extraHead; ?> <?php $this->RunCallback(DMGR_CALLBACK_HEADER_HEAD); ?> </head> <body bgcolor=#F8F8F8 text=#000080 marginheight=0 marginwidth=0 topmargin=0 leftmargin=0 link=#0000FF vlink=#0000FF alink=#0000FF > <blockquote style="padding: 0px; margin: 0px 25px;"><br> <?php
                    $this->RunCallback(DMGR_CALLBACK_HEADER_DONE);
                }

                function Manager_HelpLink($contextID, $jumpToRef) {
                    if (intval($contextID) < 1)
                        return "";
                    $helpLink = str_replace("\$topic", $contextID, $this->info->helpLinkURL);
                    $jumpTo = $jumpToRef;
                    if (!eregi("^HelpJump", $jumpTo))
                        $jumpTo = "HelpJump" . $jumpTo;
                    $helpLink = str_replace("\$jumpToItem", $jumpTo, $helpLink) . "#" . $jumpTo;
                    $helpCode = "<table align=right cellpadding=0 cellspacing=0><tr><td><a title='&nbsp; TopicID = " . $contextID . " &nbsp;/&nbsp; JumpID = " . eregi_replace("^HelpJump", "", $jumpTo) . " &nbsp;' class=smallLink onClick=\"winManagerHelp = window.open('" . $helpLink . "', 'winManagerHelp', '" . $this->info->helpPopupSettings . "'); if( winManagerHelp ) { if( winManagerHelp.focus ) { winManagerHelp.focus(); } } return false;\" href=\"$helpLink\">";
                    if ($this->info->helpLinkIcon != "") {
                        $helpCode .= "<img border=0 src=\"" . $this->info->helpLinkIcon . "\">";
                    } else {
                        $helpCode .= "help";
                    } $helpCode .= "</a></td></tr></table>";
                    return $helpCode;
                }

                function RegisterCallback($code, $name) {
                    $this->callbacks[$code] = $name;
                }

                function & RunCallback($CODE, &$param1 = null, &$param2 = null, &$param3 = null, &$param4 = null, &$param5 = null) {
                    $default = true;
                    if (!isset($this->callbacks[$CODE]) || $this->callbacks[$CODE] == "")
                        return $default;
                    $callbackFunction = $this->callbacks[$CODE];
                    if (isset($param5)) {
                        return $callbackFunction($param1, $param2, $param3, $param4, $param5);
                    } elseif (isset($param4)) {
                        return $callbackFunction($param1, $param2, $param3, $param4);
                    } elseif (isset($param3)) {
                        return $callbackFunction($param1, $param2, $param3);
                    } elseif (isset($param2)) {
                        return $callbackFunction($param1, $param2);
                    } elseif (isset($param1)) {
                        return $callbackFunction($param1);
                    } else {
                        return $callbackFunction();
                    }
                }

                function DisplayExtraActions($source, &$rData, $listParams = "", $linkClass = "") {
                    if (!$this->RunCallback(DMGR_CALLBACK_EXTRA_ACTIONS, $source, $rData))
                        return false;
                    if (count($this->extraActions) < 1)
                        return false;
                    echo "<table cellpadding=2 cellspacing=" . ($this->extraActionSingleRow ? 1 : 0) . " border=0 class=managerEdit style='border-top: #204890 1px solid;'><tr><td zclass=managerHeaderEdit class=actionHeader>&nbsp; " . $this->extraActionTitle . " &nbsp;</td>";
                    if (!$this->extraActionSingleRow)
                        echo "</tr>";
                    foreach ($this->extraActions as $actionName => $actionLink) {
                        if ($this->RunCallback(DMGR_CALLBACK_LIST_LINK_CUSTOM, $actionName, $rData)) {
                            if (!$this->extraActionSingleRow)
                                echo "<tr>";
                            echo "<td nowrap class=action>&nbsp; <a " . $linkClass . "title='Click here to perform the (" . $actionName . ") action on this item.' href=\"" . str_replace("\$listParams", $listParams, str_replace("\$ID", $rData[$this->ID], $actionLink)) . "\">" . $actionName . "</a> &nbsp;</td>";
                            if (!$this->extraActionSingleRow)
                                echo "</tr>";
                        }
                    } echo "</table><br>";
                    return true;
                }

                function ExitMessage($msg) {
                    echo "<br><blockquote><p class=error>" . $msg . "</p></blockquote>";
                    $this->RunCallback(DMGR_CALLBACK_FOOTER);
                    exit;
                }

            }
            
