Ferreteria/archive/menu.php

From Woozle Writes Code
< Ferreteria‎ | archive
Revision as of 10:07, 6 April 2010 by htyp>Woozle (reconciliation with edited non-dev version)
Jump to navigation Jump to search

<php><?php /*

LIBRARY: menu.php - a few classes for managing menus
HISTORY:
 2009-08-09 Extracted from SpecialVbzAdmin.php
 2009-11-04 clsArgs
 2010-02-20 clsWikiSection::SectionAdd(), ::ToggleAdd()
 2010-04-06 Done earlier but not logged here:
   clsWikiSection::ArgsToAdd() (ported from other copy of menu.php)
   clsAdminTable, clsAdminData, clsAdminData_Logged, clsAdminEvents, clsAdminEvent
  • /

//if (!function_exists('clsMenu::WikiText')) { class clsMenu {

   public $Page;
   private $SubNodes;
   private $AllNodes;
   protected $Action;
   protected $Selected;
   public function __construct($iWikiPage) {

$this->Page = $iWikiPage;

   }
   public function WikiText($iAction) {

$this->Action = $iAction; if (isset($this->AllNodes[$iAction])) { $this->AllNodes[$iAction]->Activate(); } $out = $this->WikiText_SubMenu($iAction); return $out;

   }
   public function WikiText_SubMenu($iAction) {

$out = NULL; foreach ($this->SubNodes as $objNode) { if (!is_null($out)) { $out .= ' | '; } $out .= $objNode->WikiText($iAction); } return $out;

   }
   public function Add(clsMenuNode $iNode) {

$this->SubNodes[$iNode->Name] = $iNode; $this->Root()->AllNodes[$iNode->Name] = $iNode; $iNode->Parent = $this;

   }
   protected function Root() {

return $this;

   }
   protected function Activate() {    }	// do nothing
   public function Execute() {

if (isset($this->Selected)) { $out = $this->Selected->DoAction(); } else { $out = NULL; } return $out;

   }

}

abstract class clsMenuNode extends clsMenu {

   public $Name;
   protected $Text;
   protected $DoSpec;
   public $Parent;
   protected $IsActive;
   public function __construct($iText, $iDo) {

$this->Name = $iDo; $this->Text = $iText; $this->DoSpec = $iDo;

   }
   public function Root() {

return $this->Parent->Root();

   }
   abstract public function DoAction();
   protected function Activate() {

$this->IsActive = TRUE; $this->Parent->Activate();

   }
   public function WikiText($iAction) {

$wtSelf = $this->Root()->Page; $wtItem = "[[$wtSelf/page".KS_CHAR_URL_ASSIGN."{$this->DoSpec}|{$this->Text}]]"; // if ($iAction == $this->DoSpec) { if ($this->IsActive) { $out = "$wtItem"; $this->Root()->Selected = $this; } else { $out = $wtItem; } return $out;

   }

}

class clsMenuRow extends clsMenuNode {

   public function DoAction() {

$out = "
{$this->Text}: "; $out .= $this->WikiText_SubMenu($this->Root()->Action); return $out;

   }

}

class clsMenuItem extends clsMenuNode {

   public function DoAction() {

// later: actually implement menu item action

   }

}

// A way of passing a variable number of options to a function // Possibly this should be in a separate library // 2010-02-20 ok, this is kind of stupid; just the usual array syntax is simple enough. Is any code using this? // Currently ruling out SpecialVbzAdmin...

class clsArgs {

   private $arArgs;
   public function __construct(array $iPairs=NULL) {

if (!is_null($iPairs)) { foreach ($iPairs as $key=>$val) { $this->Add($key,$val); } }

   }
   public function Add($iName, $iValue=NULL) {

$this->arArgs[$iName] = $iValue;

   }
   public function Value($iName, $iValue=NULL) {

if (!is_null($iValue)) { $this->arArgs[$iName] = $iValue; } if (isset($this->arArgs[$iName])) { return $this->arArgs[$iName]; } else { return NULL; }

   }

} // link-data functions function SelfLink_Path(array $iData) {

   $out = ;
   foreach ($iData AS $key => $val) {

if ($val !== FALSE) { if ($val === TRUE) { $out .= '/'.$key; } else { $out .= '/'.$key.KS_CHAR_URL_ASSIGN.$val; } }

   }
   return $out;

} function SelfLink_WT(array $iData,$iShow) {

   if (is_null($iShow)) {

return NULL;

   } else {

$strPath = SelfLink_Path($iData); return ''.$iShow.'';

   }

} function SelfLink_HTML(array $iData,$iShow,$iPopup=NULL) {

   if (is_null($iShow)) {

return NULL;

   } else {

$strPath = SelfLink_Path($iData); $htPopup = is_null($iPopup)?:(' title="'.$iPopup.'"'); return '<a href="'.$strPath.'"'.$htPopup.'>'.$iShow.'</a>';

   }

} //} class SpecialPageApp extends SpecialPage {

   protected $objRT_HTML,$objRT_Wiki;
   public function __construct($iName) {

global $wgTitle; global $vgPage;

parent::__construct($iName); $vgPage = $this; $objTitleMe = $this->getTitle(); $strFullName = $objTitleMe->getPrefixedText(); $this->objRT_HTML = new clsHTML($strFullName); $this->objRT_Wiki = new clsWikiText($strFullName);

   }
   public function UseHTML() {

global $vgOut;

$vgOut = $this->objRT_HTML;

   }
   public function UseWiki() {

global $vgOut;

$vgOut = $this->objRT_Wiki;

   }
   public function RichTextObj() {

return $vgOut;

   }
   protected function GetArgs($par) {

/*

PURPOSE: Parses variable arguments from the URL
 The URL is formatted as a series of arguments /arg=val/arg=val/..., so that we can always refer directly
   to any particular item as a wiki page title while also not worrying about hierarchy/order.
  • /

$args_raw = split('/',$par); foreach($args_raw as $arg_raw) { if (strpos($arg_raw,KS_CHAR_URL_ASSIGN) !== FALSE) { list($key,$val) = split(KS_CHAR_URL_ASSIGN,$arg_raw); $this->args[$key] = $val; } else { $this->args[$arg_raw] = TRUE; } }

   }
   public function Arg($iName) {

if (isset($this->args[$iName])) { return $this->args[$iName]; } else { return FALSE; }

   }
   /*=====
     RETURNS: Just the path after the page name, not the whole wiki title
   */
   private function SelfLink_Path(array $iAdd) {

$arData = $this->args; foreach ($iAdd AS $key => $val) { $arData[$key] = $val; // override any matching keys } return SelfLink_Path($arData);

   }
   /*=====
     RETURNS: Relative path, ready for use in an href
   */
   public function SelfURL(array $iAdd=NULL,$iClear=FALSE) {

global $wgTitle;

if (is_array($iAdd)) { if ($iClear) { $strPath = SelfLink_Path($iAdd); } else { $strPath = $this->SelfLink_Path($iAdd); } } else { $strPath = ; } return '/'.$wgTitle->getPrefixedText().$strPath;

   }
   public function SelfLink_WT(array $iAdd, $iShow) {

$arData = $this->args; foreach ($iAdd AS $key => $val) { $arData[$key] = $val; // override any matching keys } $out = SelfLink_WT($arData,$iShow); return $out;

   }
   public function SelfLink_HTML(array $iAdd, $iShow, $iClear=FALSE, $iPopup=NULL) {

$urlPath = $this->SelfURL($iAdd,$iClear); $htPopup = is_null($iPopup)?:(' title="'.$iPopup.'"'); $out = '<a href="'.$urlPath.'"'.$htPopup.'>'.$iShow.'</a>'; return $out;

   }

} /*==========

 DATA CLASSES
  • /

class clsAdminTable extends clsTable {

   public function ActionKey($iName=NULL) {

if (!is_null($iName)) { $this->ActionKey = $iName; } return $this->ActionKey;

   }

} class clsAdminData extends clsDataSet {

   public function AdminLink($iText=NULL,$iPopup=NULL) {

global $vgOut;

$txtShow = is_null($iText)?($this->ID):$iText; if (isset($this->Table->ActionKey)) { $strKey = $this->Table->ActionKey; } else { $strKey = $this->Table->Name(); }

$arLink = array( 'page' => $strKey, 'id' => $this->ID); $out = $vgOut->SelfLink($arLink,$txtShow,$iPopup); return $out;

   }

} abstract class clsAdminData_Logged extends clsAdminData {

   abstract protected function Events();		// RETURNS a clsAdminEvents object
   public function StartEvent(array $iarArgs) {

$arArgs = $iarArgs; $arArgs['type'] = $this->Table->ActionKey; // TO DO: de-couple this from URL keys $arArgs['id'] = $this->ID; return $this->Events()->StartEvent($arArgs);

   }
   public function FinishEvent($iEvent,array $iarArgs=NULL) {

$this->Events()->FinishEvent($iEvent,$iarArgs);

   }

} /*==========

EVENT LOGGING
This was written to work with FinanceFerret, but should be compatible with standard event tables.
 Any app-specific code should be moved out into descendant classes.
  • /

class clsAdminEvents extends clsAdminTable {

   public function __construct($iDB) {

assert('is_object($iDB)'); // these defaults are all overridable - must match actual event table schema parent::__construct($iDB); $this->Name('event'); $this->KeyName('ID'); $this->ClassSng('clsAdminEvent'); // override parent $this->ActionKey('event');

   }
   public function ListPage() {

global $wgOut;

$objRow = $this->GetData(NULL,NULL,'ID DESC'); if ($objRow->hasRows()) { $out = $objRow->AdminRows(); } else { $out = 'No events logged yet.'; } $wgOut->addWikiText($out,TRUE);

   }
   /*-----
     RETURNS: event arguments translated into field names for use in Insert()
   */
   private function CalcSQL($iArgs) {

if (is_null($iArgs)) { return NULL; } else { foreach ($iArgs as $key=>$val) { switch ($key) { case 'descr': $sqlKey = 'Descr'; $sqlVal = SQLValue($val); break; case 'notes': $sqlKey = 'Notes'; $sqlVal = SQLValue($val); break; case 'type': $sqlKey = 'ModType'; $sqlVal = SQLValue($val); break; case 'id': $sqlKey = 'ModIndex'; $sqlVal = SQLValue($val); // can be NULL break; case 'where': $sqlKey = 'EvWhere'; $sqlVal = SQLValue($val); break; case 'code': $sqlKey = 'Code'; $sqlVal = SQLValue($val); break; case 'error': $sqlKey = 'isError'; $sqlVal = TRUE; break; case 'severe': $sqlKey = 'isSevere'; $sqlVal = TRUE; break; } $arIns[$sqlKey] = $sqlVal; } return $arIns; }

   }
   /*-----
     ACTION: Logs an event from specs in an array
     INPUT: Array containing any of the following elements:

'descr': description of event 'type': type of event (one of the kType* class constants) 'id': ID of row in table corresponding to event type 'where': location in code where event is taking place (usually __METHOD__ will do) 'code': event code unique to type 'error' (value ignored): if present, event represents an error 'severe' (value ignored): if present, event represents a severe error

   */
   public function StartEvent(array $iArgs) {

global $vgUserName;

$arIns = $this->CalcSQL($iArgs); if (empty($arIns)) { return NULL; } else { $arIns['WhenStarted'] = 'NOW()'; $arIns['WhoNetwork'] = SQLValue($_SERVER['REMOTE_ADDR']); $arIns['WhoAdmin'] = SQLValue($vgUserName); $ok = $this->Insert($arIns); if ($ok) { return $this->objDB->NewID(__METHOD__); } else { return NULL; } }

   }
   public function FinishEvent($iEvent,array $iArgs=NULL) {

if (is_array($iArgs)) { $arUpd = $this->CalcSQL($iArgs); //$arUpd = array_merge($arUpd,$iArgs); } $arUpd['WhenFinished'] = 'NOW()'; $this->Update($arUpd,'ID='.$iEvent);

   }

} class clsAdminEvent extends clsAdminData {

   /*
     ASSUMES: there are rows (caller should check this)
   */
   public function AdminRows() {

$htUnknown = '?'; $out = "{|"; $out .= "\n|-\n! ID || Start || Finish || Who/How || Where"; // $out .= "\n|-\n! || colspan=5 | Description"; $isOdd = TRUE; $strDateLast = NULL; $objRow = $this; while ($objRow->NextRow()) { $wtStyle = $isOdd?'background:#ffffff;':'background:#eeeeee;'; $isOdd = !$isOdd;

$row = $objRow->Row;

$strSysUser = $row['WhoAdmin']; $strVbzUser = $row['WhoSystem']; $strMachine = $row['WhoNetwork']; $htSysUser = is_null($strSysUser)?$htUnknown:$strSysUser; $htMachine = is_null($strMachine)?$htUnknown:$strMachine; $htVbzUser = is_null($strVbzUser)?$htUnknown:$strVbzUser;

$ftDescr = $row['Descr']; $strNotes = $row['Notes'];

$id = $row['ID']; $strWhenSt = $row['WhenStarted']; $strWhenFi = $row['WhenFinished']; $strWhere = $row['EvWhere']; $htWho = $htVbzUser.'/'.$htSysUser.'@'.$htMachine; $strParams = $row['Params'];

$dtWhenSt = strtotime($strWhenSt); $dtWhenFi = strtotime($strWhenFi); $strDate = date('Y-m-d',empty($dtWhenSt)?$dtWhenFi:$dtWhenSt); $strTimeSt = empty($dtWhenSt)?:date('H:i',$dtWhenSt); $strTimeFi = empty($dtWhenFi)?:date('H:i',$dtWhenFi); if ($strDate != $strDateLast) { $strDateLast = $strDate; $out .= "\n|- style=\"background: #444466; color: #ffffff;\"\n| colspan=5 | $strDate"; }

$out .= "\n|- style=\"$wtStyle\""; $out .= "\n| $id || $strTimeSt || $strTimeFi || $htWho || $strWhere"; if (!empty($ftDescr)) { $out .= "\n|- style=\"$wtStyle\""; $out .= "\n| || colspan=5 | What: $ftDescr"; } if (!empty($strParams)) { $out .= "\n|- style=\"$wtStyle\""; $out .= "\n| || colspan=5 | Params: $strParams"; } if (!empty($strNotes)) { $out .= "\n|- style=\"$wtStyle\""; $out .= "\n| || colspan=5 | Notes: $strNotes"; } } $out .= "\n|}"; return $out;

   }

}

/*========== | FORM CLASSES | Trying not to be too ambitious at first, but eventually could be separate library file

  • /

class clsWikiFormatter {

   private $mwoPage;
   public function __construct(SpecialPageApp $iPage) {

$this->mwoPage = $iPage;

   }
   public function Page() {

return $this->mwoPage;

   }

} class clsWikiSection {

   // STATIC
   public static $arKeepDefault = array('page','id');
   // DYNAMIC
   private $strName;	// short name for header text
   private $strDescr;	// longer description for popups
   private $intLevel;	// level of header; defaults to 2
   private $objFmt;	// page-formatter object
   private $arMenu;	// menu entries
   private $arKeep;	// arguments to preserve (in every menu item) from the current page 
   private $arAdd;	// arguments to add to every menu item
   public function __construct(clsWikiFormatter $iFmt,$iName,$iDescr=NULL,$iLevel=2,array $iMenu=NULL) {

$this->objFmt = $iFmt; $this->strName = $iName; $this->strDescr = is_null($iDescr)?$iName:$iDescr; $this->intLevel = $iLevel; $this->arMenu = $iMenu; $this->arKeep = self::$arKeepDefault;

   }
   public function ArgsToKeep(array $iKeep) {

$this->arKeep = $iKeep;

   }
   public function ArgsToAdd(array $iAdd) {

$this->arAdd = $iAdd;

   }
   protected function ArrayCheck(array $iarCheck) {

if (is_array($this->arAdd)) { $arOut = array_unique(array_merge($iarCheck,$this->arAdd)); } else { $arOut = $iarCheck; } return $arOut;

   }
   /*-----
    PURPOSE: Add an action link to the menu
   */
   public function SelfArray() {

$objPage = $this->objFmt->Page(); if (is_array($this->arKeep)) { foreach ($this->arKeep as $key) { $arLink[$key] = $objPage->Arg($key); } } return $this->ArrayCheck($arLink);

   }
   public function SelfURL() {

$arLink = $this->SelfArray(); $objPage = $this->objFmt->Page(); $wpPath = $objPage->SelfURL($arLink,TRUE); return $wpPath;

   }
   public function ActionAdd($iDisp,$iPopup=NULL,$iActive=NULL,$iKey=NULL,$iIsDefault=FALSE) {

$strPopup = is_null($iPopup)?($iDisp.' '.$this->strDescr):$iPopup;

$objPage = $this->objFmt->Page(); $arLink = $this->ArrayCheck($this->SelfArray());

$strKey = is_null($iKey)?$iDisp:$iKey; $arLink['do'] = $strKey; $arLink = $this->ArrayCheck($arLink); $wpPath = $objPage->SelfURL($arLink,TRUE); $isActive = is_null($iActive)?($objPage->Arg('do')==$strKey):$iActive;

$arEntry = array( 'type' => 'action', 'path' => $wpPath, 'popup' => $strPopup, 'displ' => $iDisp, 'active' => $isActive, 'isdef' => $iIsDefault ); $this->arMenu[] = $arEntry;

   }
   public function SectionAdd($iDisp) {

$arEntry = array( 'type' => 'section', 'displ' => $iDisp ); $this->arMenu[] = $arEntry;

   }
   public function ToggleAdd($iDisp,$iPopup=NULL,$iKey=NULL) {

$strPopup = is_null($iPopup)?($iDisp.' '.$this->strDescr):$iPopup; $strKey = is_null($iKey)?$iDisp:$iKey;

$objPage = $this->objFmt->Page(); $arLink = $this->SelfArray();

$isActive = $objPage->Arg($strKey); // active state is indicated by presence of key $arLink[$strKey] = !$isActive; $arLink = $this->ArrayCheck($arLink); $wpPath = $objPage->SelfURL($arLink,TRUE);

$arEntry = array( 'type' => 'toggle', 'path' => $wpPath, 'popup' => $strPopup, 'displ' => $iDisp, 'active' => $isActive ); $this->arMenu[] = $arEntry;

   }
   public function Generate() {

$out = '<h'.$this->intLevel.'>'; if (is_array($this->arMenu)) { $arMenu = array_reverse($this->arMenu); // right-alignment reverses things foreach ($arMenu as $arLink) { $strType = $arLink['type']; switch ($strType) { case 'action': $htPath = $arLink['path']; $htPopup = $arLink['popup']; $htDispl = $arLink['displ']; $isActive = !empty($arLink['active']) || $arLink['isdef']; $htFmtOpen = $isActive?'':; $htFmtShut = $isActive?'':; $out .= ''; $out .= $htFmtOpen.'['; $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>'; $out .= ']'.$htFmtShut; $out .= ''; break; case 'toggle': $htPath = $arLink['path']; $htPopup = $arLink['popup']; $htDispl = $arLink['displ']; $isActive = !empty($arLink['active']); $htFmtOpen = $isActive?'':; $htFmtShut = $isActive?'':; $out .= ''; $out .= $htFmtOpen.'['; $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>'; $out .= ']'.$htFmtShut; $out .= ''; break; case 'section': $htDispl = $arLink['displ']; $out .= ''; $out .= '| '.$htDispl.':'; $out .= ''; break; } } } $out .= ''.$this->strName.'</h'.$this->intLevel.'>'; return $out;

   }
   public function FormOpen() {

$out = '<form method=post action="'.$this->SelfURL().'">'; return $out;

   }

}

// This class is DEPRECATED; replacing with clsWikiFormatter / clsWikiSection class clsWikiAdminSection {

   private $strTitle;
   private $strDescr;
   private $doEdit;
   private $arKeep;
   //private $htPath;
   public static $arKeepDefault = array('page','id');
   public function __construct($iTitle, $iDescr=NULL, array $iKeep=NULL) {

global $vgPage;

$this->strTitle = $iTitle; $this->strDescr = is_null($iDescr)?$iTitle:$iDescr; $this->arKeep = is_null($iKeep)?(self::$arKeepDefault):$iKeep; $this->doEdit = $vgPage->Arg('edit'); //$this->htPath = $vgPage->SelfURL(array('edit'=>!$this->doEdit)); $this->htPath = $vgPage->SelfURL();

   }
   public function HeaderHtml(array $iMenu=NULL) {

$out = '

'; if (is_array($iMenu)) { foreach ($iMenu as $arLink) { $htPath = $arLink['path']; $htPopup = $arLink['popup']; $htDispl = $arLink['displ']; $isActive = !empty($arLink['active']); $out .= ''; if ($isActive) { $out .= ''; } $out .= '['; if ($isActive) { $out .= ''; } $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>'; if ($isActive) { $out .= ''; } $out .= ']'; if ($isActive) { $out .= ''; } $out .= ' '; } } else { $out = ; } $out .= ''.$this->strTitle.'

';

return $out;

   }
   public function HeaderHtml_OLD() {

$out = '

'; if (!$this->doEdit) { $out .= '[<a href="'.$this->htPath.'" title="Edit '.$this->strDescr.'">edit</a>] '; } $out .= ''.$this->strTitle.'

';

return $out;

   }
   public function HeaderHtml_Edit(array $iMenu=NULL) {

global $vgPage;

if (is_array($this->arKeep)) { foreach ($this->arKeep as $key) { $arLink[$key] = $vgPage->Arg($key); } }

$arLink['edit'] = TRUE; $wpPathEd = $vgPage->SelfURL($arLink,TRUE);

$arLink['edit'] = FALSE; $wpPathVw = $vgPage->SelfURL($arLink,TRUE);

// generate standard part of menu: $arMenu = array( array( 'path' => $wpPathEd, 'popup' => 'edit '.$this->strDescr, 'displ' => 'edit', 'active' => $this->doEdit), array( 'path' => $wpPathVw, 'popup' => 'view '.$this->strDescr, 'displ' => 'view', 'active' => !$this->doEdit));

if (is_array($iMenu)) { $arMenu = array_merge($arMenu,$iMenu); // append passed menu }

return $this->HeaderHtml($arMenu);

   }
   public function FormOpen() {

if ($this->doEdit) { $out = '<form method=post action="'.$this->htPath.'">'; } else { $out = NULL; } return $out;

   }

} // TABBED CONTENTS /*

 NOTES: There's probably a better way of doing this (e.g. using the same code used by the User Preferences page), but for now
   this uses the Tabber extension.
  • /

function TabsOpen() {

   global $wgScriptPath,$wgOut;
   $path = $wgScriptPath . '/extensions/tabber/';
   $htmlHeader = '<script type="text/javascript" src="'.$path.'tabber.js"></script>'

. '<link rel="stylesheet" href="'.$path.'tabber.css" TYPE="text/css" MEDIA="screen">'

. '

';
   $wgOut->addHTML($htmlHeader);

} function TabsShut() {

   global $wgOut;
$wgOut->addHTML('

');

} function TabOpen($iName) {

   global $wgOut;

$wgOut->addHTML('

');

} function TabShut() {

   global $wgOut;
$wgOut->addHTML('

');

}</php>