Ferreteria/archive/menu.php: Difference between revisions

From Woozle Writes Code
Jump to navigation Jump to search
(2010-10-07 revision)
(more reconciliation; latest version in use)
Line 1: Line 1:
<php><?php
<php><?php
/*
/*
LIBRARY: menu.php - a few classes for managing menus
  LIBRARY: menu.php - a few classes for managing menus
HISTORY:
  HISTORY:
  2009-08-09 Extracted from SpecialVbzAdmin.php
    2009-08-09 Extracted from SpecialVbzAdmin.php
  2009-11-04 clsArgs
    2009-11-04 clsArgs
  2010-02-20 clsWikiSection::SectionAdd(), ::ToggleAdd()
    2010-02-20 clsWikiSection::SectionAdd(), ::ToggleAdd()
  2010-04-06  
    2010-04-06  
    * General reconciliation with edited non-dev version
      * General reconciliation with edited non-dev version
    * Done earlier but not logged here:
      * Done earlier but not logged here:
      clsWikiSection::ArgsToAdd() (ported from other copy of menu.php)
    clsWikiSection::ArgsToAdd() (ported from other copy of menu.php)
      clsAdminTable, clsAdminData, clsAdminData_Logged, clsAdminEvents, clsAdminEvent
    clsAdminTable, clsAdminData, clsAdminData_Logged, clsAdminEvents, clsAdminEvent
  2010-10-06
    2010-06-17 StartEvent() / FinishEvent() now keep the event ID in $this->idEvent
    Reconciling with dev:
    2010-10-06
    * Minor improvements; split() is deprecated; small bugfixes
      Reconciling with dev:
  2010-10-07 reconstructed clsDataSet::_AdminLink(), which apparently got lost during reconciliation
      * Minor improvements; split() is deprecated; small bugfixes
    2010-10-07 reconstructed clsDataSet::_AdminLink(), which apparently got lost during reconciliation
  BUGS:
    2010-09-13 When there are multiple toggles, they don't preserve each other's states
      http://wiki.vbz.net/Special:VbzAdmin/page:order/id:4263/receipt -- "email" cancels out "receipt"
*/
*/
//if (!function_exists('clsMenu::WikiText')) {
//if (!function_exists('clsMenu::WikiText')) {
class clsMenu {
class clsMenu {
Line 143: Line 148:
}
}
// link-data functions
// link-data functions
/*----
  RETURNS: the part of the path *after* the specialpage name
  USED BY: SelfURL(), which is used by clsWikiSection:ActionAdd()
*/
function SelfLink_Path(array $iData) {
function SelfLink_Path(array $iData) {
     $out = '';
     $fp = '';
     foreach ($iData AS $key => $val) {
     foreach ($iData AS $key => $val) {
     if ($val !== FALSE) {
     if ($val !== FALSE) {
         if ($val === TRUE) {
         if ($val === TRUE) {
         $out .= '/'.$key;
         $fp .= '/'.$key;
         } else {
         } else {
         $out .= '/'.$key.KS_CHAR_URL_ASSIGN.$val;
         $fp .= '/'.$key.KS_CHAR_URL_ASSIGN.$val;
         }
         }
     }
     }
     }
     }
    $out = $fp;
     return $out;
     return $out;
}
}
Line 164: Line 174:
     }
     }
}
}
/* 2010-10-01 NEED TO KNOW who uses this, so I can fix it
function SelfLink_HTML(array $iData,$iShow,$iPopup=NULL) {
function SelfLink_HTML(array $iData,$iShow,$iPopup=NULL) {
     if (is_null($iShow)) {
     if (is_null($iShow)) {
Line 173: Line 184:
     }
     }
}
}
*/
//}
//}
class SpecialPageApp extends SpecialPage {
class SpecialPageApp extends SpecialPage {
Line 178: Line 190:


     public function __construct($iName) {
     public function __construct($iName) {
    //global $wgScriptPath;
    global $vgMWLibPfx;
     global $wgTitle,$wgUser;
     global $wgTitle,$wgUser;
     global $vgPage,$vgUserName;
     global $vgPage,$vgUserName;
Line 185: Line 199:
     $vgUserName = $wgUser->getName();
     $vgUserName = $wgUser->getName();
     $objTitleMe = $this->getTitle();
     $objTitleMe = $this->getTitle();
//    $vgMWLibPfx = empty($wgScriptPath)?'':($wgScriptPath.'/');
//    $strFullName = $vgMWLibPfx.$objTitleMe->getPrefixedText();
     $strFullName = $objTitleMe->getPrefixedText();
     $strFullName = $objTitleMe->getPrefixedText();
     $this->objRT_HTML = new clsHTML($strFullName);
     $this->objRT_HTML = new clsHTML($strFullName);
Line 199: Line 215:
     $vgOut = $this->objRT_Wiki;
     $vgOut = $this->objRT_Wiki;
     }
     }
/*
     public function RichTextObj() {
     public function RichTextObj() {
     return $vgOut;
     return $vgOut;
     }
     }
*/
     protected function GetArgs($par) {
     protected function GetArgs($par) {


Line 213: Line 231:
     foreach($args_raw as $arg_raw) {
     foreach($args_raw as $arg_raw) {
         if (strpos($arg_raw,KS_CHAR_URL_ASSIGN) !== FALSE) {
         if (strpos($arg_raw,KS_CHAR_URL_ASSIGN) !== FALSE) {
      //        list($key,$val) = split(KS_CHAR_URL_ASSIGN,$arg_raw);    // split() is deprecated
//        list($key,$val) = split(KS_CHAR_URL_ASSIGN,$arg_raw);    // split() is deprecated
         list($key,$val) = preg_split('/'.KS_CHAR_URL_ASSIGN.'/',$arg_raw);
         list($key,$val) = preg_split('/'.KS_CHAR_URL_ASSIGN.'/',$arg_raw);
         $this->args[$key] = $val;
         $this->args[$key] = $val;
Line 222: Line 240:
     }
     }
     /*----
     /*----
       RETURNS: Value of a single argument passed to this page in its URL
       RETURNS: array of all arguments found in URL
    */
    public function Args() {
    return $this->args;
    }
    /*----
      RETURNS: value of single specified argument from URL
     */
     */
     public function Arg($iName) {
     public function Arg($iName) {
Line 230: Line 254:
         return FALSE;
         return FALSE;
     }
     }
    }
    /*----
      RETURNS: Array of all the arguments passed to the current page in its URL
    */
    public function Args() {
    return $this->args;
     }
     }
     /*=====
     /*=====
       RETURNS: Just the path after the page name, not the whole wiki title
       RETURNS: Just the path after the page name, not the whole wiki title
      USED BY: $this->SelfURL()
     */
     */
     private function SelfLink_Path(array $iAdd) {
     private function SelfLink_Path(array $iAdd) {
Line 249: Line 268:
     /*=====
     /*=====
       RETURNS: Relative path, ready for use in an href
       RETURNS: Relative path, ready for use in an href
      USED BY: clsWikiSection:ActionAdd()
     */
     */
     public function SelfURL(array $iAdd=NULL,$iClear=FALSE) {
     public function SelfURL(array $iAdd=NULL,$iClear=FALSE) {
     global $wgTitle, $wgScriptPath;
     global $wgTitle;
    global $wgScriptPath;


     if (is_array($iAdd)) {
     if (is_array($iAdd)) {
Line 272: Line 293:
     return $out;
     return $out;
     }
     }
/* 2010-10-01 NEED TO KNOW who uses this, so I can fix it
     public function SelfLink_HTML(array $iAdd, $iShow, $iClear=FALSE, $iPopup=NULL) {
     public function SelfLink_HTML(array $iAdd, $iShow, $iClear=FALSE, $iPopup=NULL) {
     $urlPath = $this->SelfURL($iAdd,$iClear);
     $urlPath = $this->SelfURL($iAdd,$iClear);
     $htPopup = is_null($iPopup)?'':(' title="'.$iPopup.'"');
     $htPopup = is_null($iPopup)?'':(' title="'.$iPopup.'"');
     $out = '<a href="'.$urlPath.'"'.$htPopup.'>'.$iShow.'</a>';
     $out = '<a href="'.$urlPath.'"'.$htPopup.'>'.$iShow.'</a>';
    return $out;
    }
*/
    /*----
      USED BY: VbzAdminOrder.DoSetup()
    */
    public function SelfLink(array $iAdd, $iShow) {
    global $vgOut;
    $arData = $this->args;
    foreach ($iAdd AS $key => $val) {
        $arData[$key] = $val;    // override any matching keys
    }
    $out = $vgOut->SelfLink($arData,$iShow);
     return $out;
     return $out;
     }
     }
Line 281: Line 317:
/*==========
/*==========
   DATA CLASSES
   DATA CLASSES
    2010-10-04 Moved ActionKey() back into data.php, because it's useful for logging.
      No more need for this class; deprecated now.
*/
*/
class clsAdminTable extends clsTable {
class clsAdminTable extends clsTable {
    /*----
      USED BY: VbzAdmin::VbzAdminItems::AdminLink()
      HISTORY:
    Extricated from VbzAdmin::VbzAdminItems
    */
    public static function AdminLink($iID,$iShow=NULL,$iPopup=NULL) {
    global $vgOut;
    $id = $iID;
    $arLink = array(
      'page'    => 'item',
      'id'        => $id);
    $strShow = is_null($iShow)?($id):$iShow;
    $strPopup = is_null($iPopup)?('view item ID '.$id):$iPopup;
    $out = $vgOut->SelfLink($arLink,$strShow,$strPopup);
    return $out;
    }
/*
     public function ActionKey($iName=NULL) {
     public function ActionKey($iName=NULL) {
     if (!is_null($iName)) {
     if (!is_null($iName)) {
Line 289: Line 346:
     return $this->ActionKey;
     return $this->ActionKey;
     }
     }
*/
}
}
class clsAdminData extends clsDataSet {
class clsAdminData extends clsDataSet {
//=====
    /*====
// STATIC section
      SECTION: static versions of dynamic functions
     public static function _AdminLink(clsDataSet $iThis,$iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
      PURPOSE: for classes which inherit from non-Admin classes (fake multiple inheritance)
    */
    /*----
      USED BY: VbzAdmin::clsAdminTopic::AdminLink()
      HISTORY:
    2010-10-06 Wasn't sure who is using this, so commented it out (not WorkFerret or AudioFerret)
      VbzAdmin didn't *seem* to be using it...
    2010-10-13 Found that VbzAdmin uses it
    */
     static public function _AdminLink(clsDataSet $iObj, $iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
     global $vgOut;
     global $vgOut;


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


    $arLink = $iarArgs;
     $arLink = array(
     $arLink = array(
       'page'    => $strKey,
       'page'    => $strKey,
       'id'        => $iThis->KeyValue());
       'id'        => $iObj->KeyValue());
    $out = $vgOut->SelfLink($arLink,$txtShow,$iPopup);
    return $out;
    }
//=====
// DYNAMIC section
    public function AdminLink($iText=NULL,$iPopup=NULL,$iArArgs=NULL) {
    $out = self::_AdminLink($this,$iText,$iPopup,$iArArgs);
    return $out;
/*
    global $vgOut;


    $txtShow = is_null($iText)?($this->ID):$iText;
     if (is_array($iarArgs)) {   // 2010-06-25 This has not been tested -- maybe it's not useful?
     if (isset($this->Table->ActionKey)) {
         $arLink = array_merge($arLink,$iarArgs);
        $strKey = $this->Table->ActionKey;
    } else {
         $strKey = $this->Table->Name();
     }
     }


    $arLink = array(
      'page'    => $strKey,
      'id'        => $this->KeyValue());
     $out = $vgOut->SelfLink($arLink,$txtShow,$iPopup);
     $out = $vgOut->SelfLink($arLink,$txtShow,$iPopup);
     return $out;
     return $out;
*/
    }
    /*====
      SECTION: normal dynamic functions
    */
    /*----
      USED BY: VbzAdmin::VbzAdminStkItems::Listing_forItem()
      HISTORY:
    2010-10-06 Disabled, because it wasn't clear if anyone was using it.
      Thought I checked VbzAdmin, WorkFerret, and AudioFerret
    2010-10-13 VbzAdmin::VbzAdminStkItems::Listing_forItem() calls it
    */
    public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
    return self::_AdminLink($this,$iText,$iPopup,$iarArgs);
     }
     }
}
}
abstract class clsAdminData_Logged extends clsAdminData {
abstract class clsAdminData_Logged extends clsAdminData {
    protected $idEvent;
     abstract protected function Events();        // RETURNS a clsAdminEvents object
     abstract protected function Events();        // RETURNS a clsAdminEvents object
    /*=====
      INPUT: Array containing any of the following elements:
    'descr': description of event
    '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 $iarArgs) {
     public function StartEvent(array $iarArgs) {
     $arArgs = $iarArgs;
     $arArgs = $iarArgs;
     $arArgs['type'] = $this->Table->ActionKey;
     $arArgs['type'] = $this->Table->ActionKey;   // TO DO: de-couple this from URL keys
     $arArgs['id'] = $this->KeyValue();       // was: $this->ID
     $arArgs['id'] = $this->KeyValue();
    return $this->Events()->StartEvent($arArgs);
    $this->idEvent = $this->Events()->StartEvent($arArgs);
    return $this->idEvent;
     }
     }
     public function FinishEvent($iEvent,array $iarArgs=NULL) {
     public function FinishEvent(array $iarArgs=NULL) {
     $this->Events()->FinishEvent($iEvent,$iarArgs);
     $this->Events()->FinishEvent($this->idEvent,$iarArgs);
    unset($this->idEvent);
     }
     }
}
}
Line 349: Line 423:
  This was written to work with FinanceFerret, but should be compatible with standard event tables.
  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.
   Any app-specific code should be moved out into descendant classes.
*/
/*=====
  CLASS: clsAdminEvents
  PURPOSE: Event log table
*/
*/
class clsAdminEvents extends clsAdminTable {
class clsAdminEvents extends clsAdminTable {
Line 440: Line 518:
         $arIns['WhoNetwork'] = SQLValue($_SERVER['REMOTE_ADDR']);
         $arIns['WhoNetwork'] = SQLValue($_SERVER['REMOTE_ADDR']);
         $arIns['WhoAdmin'] = SQLValue($vgUserName);
         $arIns['WhoAdmin'] = SQLValue($vgUserName);
    //echo '<pre>'.print_r($arIns,TRUE).'</pre>'; die();
         $ok = $this->Insert($arIns);
         $ok = $this->Insert($arIns);
         if ($ok) {
         if ($ok) {
Line 459: Line 536:
}
}
class clsAdminEvent extends clsAdminData {
class clsAdminEvent extends clsAdminData {
     /*----
     /*
       ASSUMES: there are rows (caller should check this)
       ASSUMES: there are rows (caller should check this)
     */
     */
Line 572: Line 649:
     return $arOut;
     return $arOut;
     }
     }
    /*-----
    PURPOSE: Add an action link to the menu
    */
     public function SelfArray() {
     public function SelfArray() {
     $objPage = $this->objFmt->Page();
     $objPage = $this->objFmt->Page();
Line 590: Line 664:
     return $wpPath;
     return $wpPath;
     }
     }
    /*-----
    PURPOSE: Add an action link to the menu
    */
     public function ActionAdd($iDisp,$iPopup=NULL,$iActive=NULL,$iKey=NULL,$iIsDefault=FALSE) {
     public function ActionAdd($iDisp,$iPopup=NULL,$iActive=NULL,$iKey=NULL,$iIsDefault=FALSE) {
     $strPopup = is_null($iPopup)?($iDisp.' '.$this->strDescr):$iPopup;
     $strPopup = is_null($iPopup)?($iDisp.' '.$this->strDescr):$iPopup;
Line 599: Line 676:
     $arLink['do'] = $strKey;
     $arLink['do'] = $strKey;
     $arLink = $this->ArrayCheck($arLink);
     $arLink = $this->ArrayCheck($arLink);
    $wpPath = $objPage->SelfURL($arLink,TRUE);
//    $wpPath = 'BLARG!'.$objPage->SelfURL($arLink,TRUE);
     $isActive = is_null($iActive)?($objPage->Arg('do')==$strKey):$iActive;
     $isActive = is_null($iActive)?($objPage->Arg('do')==$strKey):$iActive;


     $arEntry = array(
     $arEntry = array(
       'type'    => 'action',
       'type'    => 'action',
       'path'    => $wpPath,
       'path'    => 'BLARG!', // was; $wpPath -- WHAT USES THIS?
       'popup'    => $strPopup,
       'popup'    => $strPopup,
       'displ'    => $iDisp,
       'displ'    => $iDisp,

Revision as of 11:52, 14 October 2010

<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 
     * General reconciliation with edited non-dev version
     * Done earlier but not logged here:
   clsWikiSection::ArgsToAdd() (ported from other copy of menu.php)
   clsAdminTable, clsAdminData, clsAdminData_Logged, clsAdminEvents, clsAdminEvent
   2010-06-17 StartEvent() / FinishEvent() now keep the event ID in $this->idEvent
   2010-10-06
     Reconciling with dev:
     * Minor improvements; split() is deprecated; small bugfixes
   2010-10-07 reconstructed clsDataSet::_AdminLink(), which apparently got lost during reconciliation
 BUGS:
   2010-09-13 When there are multiple toggles, they don't preserve each other's states
     http://wiki.vbz.net/Special:VbzAdmin/page:order/id:4263/receipt -- "email" cancels out "receipt"
  • /

//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 /*----

 RETURNS: the part of the path *after* the specialpage name
 USED BY: SelfURL(), which is used by clsWikiSection:ActionAdd()
  • /

function SelfLink_Path(array $iData) {

   $fp = ;
   foreach ($iData AS $key => $val) {
   if ($val !== FALSE) {
       if ($val === TRUE) {
       $fp .= '/'.$key;
       } else {
       $fp .= '/'.$key.KS_CHAR_URL_ASSIGN.$val;
       }
   }
   }
   $out = $fp;
   return $out;

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

   if (is_null($iShow)) {
   return NULL;
   } else {
   $strPath = SelfLink_Path($iData);
   return ''.$iShow.'';
   }

} /* 2010-10-01 NEED TO KNOW who uses this, so I can fix it 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 $wgScriptPath;
   global $vgMWLibPfx;
   global $wgTitle,$wgUser;
   global $vgPage,$vgUserName;
   parent::__construct($iName);
   $vgPage = $this;
   $vgUserName = $wgUser->getName();
   $objTitleMe = $this->getTitle();

// $vgMWLibPfx = empty($wgScriptPath)?:($wgScriptPath.'/'); // $strFullName = $vgMWLibPfx.$objTitleMe->getPrefixedText();

   $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); // split() is deprecated

   $args_raw = preg_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); // split() is deprecated

       list($key,$val) = preg_split('/'.KS_CHAR_URL_ASSIGN.'/',$arg_raw);
       $this->args[$key] = $val;
       } else {
       $this->args[$arg_raw] = TRUE;
       }
   }
   }
   /*----
     RETURNS: array of all arguments found in URL
   */
   public function Args() {
   return $this->args;
   }
   /*----
     RETURNS: value of single specified argument from URL
   */
   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
     USED BY: $this->SelfURL()
   */
   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
     USED BY: clsWikiSection:ActionAdd()
   */
   public function SelfURL(array $iAdd=NULL,$iClear=FALSE) {
   global $wgTitle;
   global $wgScriptPath;
   if (is_array($iAdd)) {
       if ($iClear) {
       $strPath = SelfLink_Path($iAdd);
       } else {
       $strPath = $this->SelfLink_Path($iAdd);
       }
   } else {
       $strPath = ;
   }
   return $wgScriptPath.'/'.$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;
   }

/* 2010-10-01 NEED TO KNOW who uses this, so I can fix it

   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;
   }
  • /
   /*----
     USED BY: VbzAdminOrder.DoSetup()
   */
   public function SelfLink(array $iAdd, $iShow) {
   global $vgOut;
   $arData = $this->args;
   foreach ($iAdd AS $key => $val) {
       $arData[$key] = $val;    // override any matching keys
   }
   $out = $vgOut->SelfLink($arData,$iShow);
   return $out;
   }

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

 DATA CLASSES
   2010-10-04 Moved ActionKey() back into data.php, because it's useful for logging.
     No more need for this class; deprecated now.
  • /

class clsAdminTable extends clsTable {

   /*----
     USED BY: VbzAdmin::VbzAdminItems::AdminLink()
     HISTORY:
   Extricated from VbzAdmin::VbzAdminItems
   */
   public static function AdminLink($iID,$iShow=NULL,$iPopup=NULL) {
   global $vgOut;
   $id = $iID;
   $arLink = array(
     'page'    => 'item',
     'id'        => $id);
   $strShow = is_null($iShow)?($id):$iShow;
   $strPopup = is_null($iPopup)?('view item ID '.$id):$iPopup;
   $out = $vgOut->SelfLink($arLink,$strShow,$strPopup);
   return $out;
   }

/*

   public function ActionKey($iName=NULL) {
   if (!is_null($iName)) {
       $this->ActionKey = $iName;
   }
   return $this->ActionKey;
   }
  • /

} class clsAdminData extends clsDataSet {

   /*====
     SECTION: static versions of dynamic functions
     PURPOSE: for classes which inherit from non-Admin classes (fake multiple inheritance)
   */
   /*----
     USED BY: VbzAdmin::clsAdminTopic::AdminLink()
     HISTORY:
   2010-10-06 Wasn't sure who is using this, so commented it out (not WorkFerret or AudioFerret)
     VbzAdmin didn't *seem* to be using it...
   2010-10-13 Found that VbzAdmin uses it
   */
   static public function _AdminLink(clsDataSet $iObj, $iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
   global $vgOut;
   $txtShow = is_null($iText)?($iObj->ID):$iText;
   if (isset($iObj->Table->ActionKey)) {
       $strKey = $iObj->Table->ActionKey;
   } else {
       $strKey = $iObj->Table->Name();
   }
   $arLink = array(
     'page'    => $strKey,
     'id'        => $iObj->KeyValue());
   if (is_array($iarArgs)) {    // 2010-06-25 This has not been tested -- maybe it's not useful?
       $arLink = array_merge($arLink,$iarArgs);
   }
   $out = $vgOut->SelfLink($arLink,$txtShow,$iPopup);
   return $out;
   }
   /*====
     SECTION: normal dynamic functions
   */
   /*----
     USED BY: VbzAdmin::VbzAdminStkItems::Listing_forItem()
     HISTORY:
   2010-10-06 Disabled, because it wasn't clear if anyone was using it.
     Thought I checked VbzAdmin, WorkFerret, and AudioFerret
   2010-10-13 VbzAdmin::VbzAdminStkItems::Listing_forItem() calls it
   */
   public function AdminLink($iText=NULL,$iPopup=NULL,array $iarArgs=NULL) {
   return self::_AdminLink($this,$iText,$iPopup,$iarArgs);
   }

} abstract class clsAdminData_Logged extends clsAdminData {

   protected $idEvent;
   abstract protected function Events();        // RETURNS a clsAdminEvents object
   /*=====
     INPUT: Array containing any of the following elements:
   'descr': description of event
   '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 $iarArgs) {
   $arArgs = $iarArgs;
   $arArgs['type'] = $this->Table->ActionKey;    // TO DO: de-couple this from URL keys
   $arArgs['id'] = $this->KeyValue();
   $this->idEvent = $this->Events()->StartEvent($arArgs);
   return $this->idEvent;
   }
   public function FinishEvent(array $iarArgs=NULL) {
   $this->Events()->FinishEvent($this->idEvent,$iarArgs);
   unset($this->idEvent);
   }

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

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
 PURPOSE: Event log table
  • /

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()
     NOTE: Shouldn't this method be static?
   */
   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 = SQLValue($val);
           break;
         case 'severe':
           $sqlKey = 'isSevere';
           $sqlVal = SQLValue($val);
           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;
   }
   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;
   }
   /*-----
    PURPOSE: Add an action link to the menu
   */
   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 = 'BLARG!'.$objPage->SelfURL($arLink,TRUE);

   $isActive = is_null($iActive)?($objPage->Arg('do')==$strKey):$iActive;
   $arEntry = array(
     'type'    => 'action',
     'path'    => 'BLARG!', // was; $wpPath -- WHAT USES THIS?
     '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>