Ferreteria/archive/menu.php: Difference between revisions

From Woozle Writes Code
Jump to navigation Jump to search
(more reconciliation; latest version in use)
(examples; latest code)
Line 1: Line 1:
==Examples==
Shows a set of toggles. Library code currently does not properly highlight active options.
<php>
global $vgPage;
$vgPage->UseHTML();
$objPage = new clsWikiFormatter($vgPage);
$objSection = new clsWikiSection_std_page($objPage,'Orders',3);
//$objSection->ArgsToKeep(array('show','page','id'));
$objSection->PageKeys(array('page','id'));
//$objSection->ToggleAdd('edit','edit the list of groups','edit.ctg');
$objLink = $objSection->AddLink_local(new clsWikiSectionLink_keyed(array('show.pulled'=>TRUE),'pulled'));
  $objLink->Popup('show pulled orders');
$objLink = $objSection->AddLink_local(new clsWikiSectionLink_keyed(array('show.shut'=>TRUE),'shut'));
  $objLink->Popup('show orders which have been closed');
$objLink = $objSection->AddLink_local(new clsWikiSectionLink_keyed(array('show.open'=>TRUE),'open'));
  $objLink->Popup('show orders which have not been completed');
$out = $objSection->Render();
/* check the flags */
if ($vgPage->Arg('show.open')) {
// ...and so on
</php>
==Source==
<php><?php
<php><?php
/*
/*
Line 9: Line 36:
       * 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-06-17 StartEvent() / FinishEvent() now keep the event ID in $this->idEvent
     2010-06-17 StartEvent() / FinishEvent() now keep the event ID in $this->idEvent
     2010-10-06
     2010-10-06
Line 16: Line 43:
       * Minor improvements; split() is deprecated; small bugfixes
       * Minor improvements; split() is deprecated; small bugfixes
     2010-10-07 reconstructed clsDataSet::_AdminLink(), which apparently got lost during reconciliation
     2010-10-07 reconstructed clsDataSet::_AdminLink(), which apparently got lost during reconciliation
    2010-10-17 Expanded SpecialPageApp::Args() to allow returning a limited set of arguments
   BUGS:
   BUGS:
     2010-09-13 When there are multiple toggles, they don't preserve each other's states
     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"
       http://wiki.vbz.net/Special:VbzAdmin/page:order/id:4263/receipt -- "email" cancels out "receipt"
*/
*/
if (!defined('KS_CHAR_URL_ASSIGN')) {
    define('KS_CHAR_URL_ASSIGN',':'); // default
}


//if (!function_exists('clsMenu::WikiText')) {
//if (!function_exists('clsMenu::WikiText')) {
Line 28: Line 60:
     protected $Action;
     protected $Action;
     protected $Selected;
     protected $Selected;
    protected $isSubActive;


     public function __construct($iWikiPage) {
     public function __construct($iWikiPage) {
    $this->Page = $iWikiPage;
$this->Page = $iWikiPage;
$this->isSubActive = FALSE;
     }
     }
     public function WikiText($iAction) {
     public function WikiText($iAction) {
    $this->Action = $iAction;
$this->Action = $iAction;
    if (isset($this->AllNodes[$iAction])) {
if (isset($this->AllNodes[$iAction])) {
        $this->AllNodes[$iAction]->Activate();
    $this->AllNodes[$iAction]->Activate();
    }
    $this->isSubActive = TRUE;
    $out = $this->WikiText_SubMenu($iAction);
}
    return $out;
$out = $this->WikiText_SubMenu($iAction);
return $out;
     }
     }
     public function WikiText_SubMenu($iAction) {
     public function WikiText_SubMenu($iAction) {
    $out = NULL;
$out = NULL;
    foreach ($this->SubNodes as $objNode) {
foreach ($this->SubNodes as $objNode) {
        if (!is_null($out)) {
    if (!is_null($out)) {
        $out .= ' | ';
$out .= ' | ';
        }
    }
        $out .= $objNode->WikiText($iAction);
    $out .= $objNode->WikiText($iAction);
    }
}
    return $out;
return $out;
     }
     }
     public function Add(clsMenuNode $iNode) {
     public function Add(clsMenuNode $iNode) {
    $this->SubNodes[$iNode->Name] = $iNode;
$this->SubNodes[$iNode->Name] = $iNode;
    $this->Root()->AllNodes[$iNode->Name] = $iNode;
$this->Root()->AllNodes[$iNode->Name] = $iNode;
    $iNode->Parent = $this;
$iNode->Parent = $this;
     }
     }
     protected function Root() {
     protected function Root() {
    return $this;
return $this;
     }
     }
     protected function Activate() {    }   // do nothing
     protected function Activate() {    } // do nothing
     public function Execute() {
     public function Execute() {
    if (isset($this->Selected)) {
if (isset($this->Selected)) {
        $out = $this->Selected->DoAction();
    $out = $this->Selected->DoAction();
    } else {
} else {
        $out = NULL;
    $out = NULL;
}
return $out;
     }
     }
     return $out;
     /*----
      RETURNS: TRUE if the current input has activated a sub-menu
    */
    public function IsSubMenuActive() {
return $this->isSubActive;
     }
     }
}
}
Line 77: Line 118:


     public function __construct($iText, $iDo) {
     public function __construct($iText, $iDo) {
    $this->Name = $iDo;
$this->Name = $iDo;
    $this->Text = $iText;
$this->Text = $iText;
    $this->DoSpec = $iDo;
$this->DoSpec = $iDo;
     }
     }
     public function Root() {
     public function Root() {
    return $this->Parent->Root();
return $this->Parent->Root();
     }
     }
     abstract public function DoAction();
     abstract public function DoAction();
     protected function Activate() {
     protected function Activate() {
    $this->IsActive = TRUE;
$this->IsActive = TRUE;
    $this->Parent->Activate();
$this->Parent->Activate();
     }
     }
     public function WikiText($iAction) {
     public function WikiText($iAction) {
    $wtSelf = $this->Root()->Page;
$wtSelf = $this->Root()->Page;
    $wtItem = "[[$wtSelf/page".KS_CHAR_URL_ASSIGN."{$this->DoSpec}|{$this->Text}]]";
$wtItem = "[[$wtSelf/page".KS_CHAR_URL_ASSIGN."{$this->DoSpec}|{$this->Text}]]";
//   if ($iAction == $this->DoSpec) {
// if ($iAction == $this->DoSpec) {
    if ($this->IsActive) {
if ($this->IsActive) {
        $out = "'''$wtItem'''";
    $out = "'''$wtItem'''";
        $this->Root()->Selected = $this;
    $this->Root()->Selected = $this;
    } else {
} else {
        $out = $wtItem;
    $out = $wtItem;
    }
}
    return $out;
return $out;
     }
     }
}
}
Line 105: Line 146:
class clsMenuRow extends clsMenuNode {
class clsMenuRow extends clsMenuNode {
     public function DoAction() {
     public function DoAction() {
    $out = "<br>'''{$this->Text}''': ";
$out = "<br>'''{$this->Text}''': ";
    $out .= $this->WikiText_SubMenu($this->Root()->Action);
$out .= $this->WikiText_SubMenu($this->Root()->Action);
    return $out;
return $out;
     }
     }
}
}
Line 120: Line 161:
// Possibly this should be in a separate library
// 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?
// 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...
// Currently ruling out SpecialVbzAdmin...


class clsArgs {
class clsArgs {
Line 126: Line 167:


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


     public function Add($iName, $iValue=NULL) {
     public function Add($iName, $iValue=NULL) {
    $this->arArgs[$iName] = $iValue;
$this->arArgs[$iName] = $iValue;
     }
     }
     public function Value($iName, $iValue=NULL) {
     public function Value($iName, $iValue=NULL) {
    if (!is_null($iValue)) {
if (!is_null($iValue)) {
        $this->arArgs[$iName] = $iValue;
    $this->arArgs[$iName] = $iValue;
    }
}
    if (isset($this->arArgs[$iName])) {
if (isset($this->arArgs[$iName])) {
        return $this->arArgs[$iName];
    return $this->arArgs[$iName];
    } else {
} else {
        return NULL;
    return NULL;
    }
}
     }
     }
}
}
Line 155: Line 196:
     $fp = '';
     $fp = '';
     foreach ($iData AS $key => $val) {
     foreach ($iData AS $key => $val) {
    if ($val !== FALSE) {
if ($val !== FALSE) {
        if ($val === TRUE) {
    if ($val === TRUE) {
        $fp .= '/'.$key;
$fp .= '/'.$key;
        } else {
    } else {
        $fp .= '/'.$key.KS_CHAR_URL_ASSIGN.$val;
$fp .= '/'.$key.KS_CHAR_URL_ASSIGN.$val;
        }
    }
    }
}
     }
     }
     $out = $fp;
     $out = $fp;
Line 168: Line 209:
function SelfLink_WT(array $iData,$iShow) {
function SelfLink_WT(array $iData,$iShow) {
     if (is_null($iShow)) {
     if (is_null($iShow)) {
    return NULL;
return NULL;
     } else {
     } else {
    $strPath = SelfLink_Path($iData);
$strPath = SelfLink_Path($iData);
    return '[[{{FULLPAGENAME}}'.$strPath.'|'.$iShow.']]';
return '[[{{FULLPAGENAME}}'.$strPath.'|'.$iShow.']]';
     }
     }
}
}
Line 177: Line 218:
function SelfLink_HTML(array $iData,$iShow,$iPopup=NULL) {
function SelfLink_HTML(array $iData,$iShow,$iPopup=NULL) {
     if (is_null($iShow)) {
     if (is_null($iShow)) {
    return NULL;
return NULL;
     } else {
     } else {
    $strPath = SelfLink_Path($iData);
$strPath = SelfLink_Path($iData);
    $htPopup = is_null($iPopup)?'':(' title="'.$iPopup.'"');
$htPopup = is_null($iPopup)?'':(' title="'.$iPopup.'"');
    return '<a href="'.$strPath.'"'.$htPopup.'>'.$iShow.'</a>';
return '<a href="'.$strPath.'"'.$htPopup.'>'.$iShow.'</a>';
     }
     }
}
}
*/
*/
//}
//}
/* ####
  FUTURE: This could eventually be split into a general page-type and one
    which uses page/id for most pages
    Also, the different RichText classes are now dependent on their creator
      (e.g. this class) to pass them the right kind of base URL. Not sure
      how to fix the conceptual model.
*/
class SpecialPageApp extends SpecialPage {
class SpecialPageApp extends SpecialPage {
    // DYNAMIC
    private $arKeep; // arguments to preserve (in every menu item) from the current page
    private $arAdd; // arguments to add to every menu item
     protected $objRT_HTML,$objRT_Wiki;
     protected $objRT_HTML,$objRT_Wiki;


     public function __construct($iName) {
     public function __construct($iName='') {
    //global $wgScriptPath;
//global $wgScriptPath;
    global $vgMWLibPfx;
global $vgMWLibPfx;
    global $wgTitle,$wgUser;
global $wgTitle,$wgUser;
    global $vgPage,$vgUserName;
global $vgPage,$vgUserName;
 
parent::__construct($iName);
$vgPage = $this;
$vgUserName = $wgUser->getName();
$mwoTitleMe = $this->getTitle();
$wpBase = $this->BaseURL();
$wkBase = $mwoTitleMe->getPrefixedText();


    parent::__construct($iName);
$this->objRT_HTML = new clsHTML($wpBase);
    $vgPage = $this;
// $this->objRT_HTML = new clsHTML();
    $vgUserName = $wgUser->getName();
$this->objRT_Wiki = new clsWikiText($wkBase); // OMGkluge
    $objTitleMe = $this->getTitle();
$this->InitArKeep();
//   $vgMWLibPfx = empty($wgScriptPath)?'':($wgScriptPath.'/');
    }
//    $strFullName = $vgMWLibPfx.$objTitleMe->getPrefixedText();
    /*----
    $strFullName = $objTitleMe->getPrefixedText();
      RETURNS: URL of basic Special page with no URL arguments
     $this->objRT_HTML = new clsHTML($strFullName);
    */
    $this->objRT_Wiki = new clsWikiText($strFullName);
    public function BaseURL() {
$mwoTitle = $this->getTitle();
$wp = $mwoTitle->getFullURL();
return $wp;
    }
     protected function InitArKeep() {
$this->arKeep = array('page','id');
     }
     }
     public function UseHTML() {
     public function UseHTML() {
    global $vgOut;
global $vgOut;


    $vgOut = $this->objRT_HTML;
$vgOut = $this->objRT_HTML;
     }
     }
     public function UseWiki() {
     public function UseWiki() {
    global $vgOut;
global $vgOut;


    $vgOut = $this->objRT_Wiki;
$vgOut = $this->objRT_Wiki;
     }
     }
/*
/*
     public function RichTextObj() {
     public function RichTextObj() {
    return $vgOut;
return $vgOut;
     }
     }
*/
*/
    /*----
    ACTION: 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.
    */
     protected function GetArgs($par) {
     protected function GetArgs($par) {
 
// $args_raw = split('/',$par); // split() is deprecated
/*
$args_raw = preg_split('/\//',$par);
PURPOSE: Parses variable arguments from the URL
foreach($args_raw as $arg_raw) {
  The URL is formatted as a series of arguments /arg=val/arg=val/..., so that we can always refer directly
    if (strpos($arg_raw,KS_CHAR_URL_ASSIGN) !== FALSE) {
    to any particular item as a wiki page title while also not worrying about hierarchy/order.
// list($key,$val) = split(KS_CHAR_URL_ASSIGN,$arg_raw); // split() is deprecated
*/
list($key,$val) = preg_split('/'.KS_CHAR_URL_ASSIGN.'/',$arg_raw);
//   $args_raw = split('/',$par);   // split() is deprecated
$this->args[$key] = $val;
    $args_raw = preg_split('/\//',$par);
    } else {
    foreach($args_raw as $arg_raw) {
$this->args[$arg_raw] = TRUE;
        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
       RETURNS: array of all arguments found in URL,
or just the arguments listed in $iList
     */
     */
     public function Args() {
     public function Args(array $iList=NULL) {
    return $this->args;
if (is_array($iList)) {
    foreach ($iList as $name) {
$arOut[$name] = $this->Arg($name);
    }
    return $arOut;
} else {
    return $this->args;
}
     }
     }
     /*----
     /*----
       RETURNS: value of single specified argument from URL
       RETURNS: value of single specified argument from URL
      HISTORY:
2012-02-26 changed default return from FALSE to NULL
  NULL is easier to test for.
     */
     */
     public function Arg($iName) {
     public function Arg($iName) {
    if (isset($this->args[$iName])) {
if (isset($this->args[$iName])) {
        return $this->args[$iName];
    return $this->args[$iName];
     } else {
} else {
        return FALSE;
    return NULL;
}
    }
 
    /*====
      SECTION: link generation
      HISTORY:
2011-03-30 adapted from clsWikiSection to SpecialPageApp
    */
    public function ArgsToKeep(array $iKeep) {
$this->arKeep = $iKeep;
    }
    public function ArgsToAdd(array $iAdd) {
$this->arAdd = $iAdd;
     }
    public 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() {
$arLink = array();
if (is_array($this->arKeep)) {
    foreach ($this->arKeep as $key) {
$arLink[$key] = $this->Arg($key);
    }
}
return $this->ArrayCheck($arLink);
     }
     }
     /*=====
     /*----
       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()
       USED BY: $this->SelfURL()
     */
     */
     private function SelfLink_Path(array $iAdd) {
     private function SelfLink_Path(array $iAdd) {
    $arData = $this->args;
$arData = $this->args;
    foreach ($iAdd AS $key => $val) {
foreach ($iAdd AS $key => $val) {
        $arData[$key] = $val;   // override any matching keys
    $arData[$key] = $val; // override any matching keys
}
echo 'ARDATA:<pre>'.print_r($arData,TRUE).'</pre>';
return SelfLink_Path($arData);
    }
    /*----
      USED BY: clsWikiSection::ActionAdd
    */
    public function SelfURL(array $iAdd=NULL,$iClear=TRUE) {
$arAddSave = $this->arAdd;
$this->arAdd = $iAdd;
$arLink = $this->SelfArray();
// this looks OK
//echo 'ARLINK:<pre>'.print_r($arLink,TRUE).'</pre>';
$wpPath = $this->SelfURL_calc($arLink,$iClear);
// problem happens there ^
//echo 'WPPATH=['.$wpPath.']';
$this->arAdd = $arAddSave;
return $wpPath;
     }
     }
     return SelfLink_Path($arData);
     /*----
      NOTE: This has only been tested with SpecialPages; in theory it could be used on regular pages
    */
    static public function URL_fromArray(array $iArgs) {
global $wgTitle;
global $wgScriptPath;
 
$strPath = SelfLink_Path($iArgs); // the part after the page name
return $wgScriptPath.'/'.$wgTitle->getPrefixedText().$strPath;
     }
     }
     /*=====
     /*----
       RETURNS: Relative path, ready for use in an href
       RETURNS: Relative path, ready for use in an href
       USED BY: clsWikiSection:ActionAdd()
       USED BY: clsWikiSection:ActionAdd()
      HISTORY:
2011-03-30 renamed from SelfURL() to SelfURL_calc()
2012-02-24 dropped use of $wgScriptPath, because it doesn't work with MW1.18; rewrote path calculation.
     */
     */
     public function SelfURL(array $iAdd=NULL,$iClear=FALSE) {
     protected function SelfURL_calc(array $iAdd=NULL,$iClear=FALSE) {
    global $wgTitle;
global $wgTitle;
    global $wgScriptPath;


    if (is_array($iAdd)) {
if (is_array($iAdd)) {
        if ($iClear) {
    if ($iClear) {
        $strPath = SelfLink_Path($iAdd);
$strPath = SelfLink_Path($iAdd);
        } else {
    } else {
        $strPath = $this->SelfLink_Path($iAdd);
$strPath = $this->SelfLink_Path($iAdd);
        }
    }
    } else {
} else {
        $strPath = '';
    $strPath = '';
    }
}
    return $wgScriptPath.'/'.$wgTitle->getPrefixedText().$strPath;
//$wpPrefix = $wgTitle->getPrefixedText();
//$wpPrefix = $this->getName();
$mwoTitle = $this->getTitle();
$wpPrefix = $mwoTitle->getFullURL();
return $wpPrefix.$strPath;
     }
     }
    // DEPRECATED
     public function SelfLink_WT(array $iAdd, $iShow) {
     public function SelfLink_WT(array $iAdd, $iShow) {
    $arData = $this->args;
$arData = $this->args;
    foreach ($iAdd AS $key => $val) {
foreach ($iAdd AS $key => $val) {
        $arData[$key] = $val;   // override any matching keys
    $arData[$key] = $val; // override any matching keys
    }
}
    $out = SelfLink_WT($arData,$iShow);
$out = SelfLink_WT($arData,$iShow);
    return $out;
return $out;
     }
     }
/* 2010-10-01 NEED TO KNOW who uses this, so I can fix it
/* 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;
return $out;
     }
     }
*/
*/
Line 304: Line 440:
       USED BY: VbzAdminOrder.DoSetup()
       USED BY: VbzAdminOrder.DoSetup()
     */
     */
     public function SelfLink(array $iAdd, $iShow) {
     public function SelfLink(array $iAdd, $iShow, $iPopup=NULL) {
    global $vgOut;
global $vgOut;


    $arData = $this->args;
$arData = $this->args;
    foreach ($iAdd AS $key => $val) {
foreach ($iAdd AS $key => $val) {
        $arData[$key] = $val;   // override any matching keys
    $arData[$key] = $val; // override any matching keys
}
$out = $vgOut->SelfLink($arData,$iShow,$iPopup);
return $out;
     }
     }
     $out = $vgOut->SelfLink($arData,$iShow);
     /*----
    return $out;
      ACTION: Displays a mini-menu from a list of possible values
      INPUT:
$iArgName: name of argument whose value changes with each choice
$iValues: array containing prefix-delimited list of data for each choice:
  iValue[URL value] = "\display value\popup text"
    */
    public function SelfLinkMenu($iArgName,array $iValues,$iCur=NULL) {
global $vgOut;
 
$strCur = (is_null($iCur))?$this->Arg($iArgName):$iCur;
 
$objStr = new xtString;
$strArg = $iArgName;
$out = '';
foreach ($iValues as $strURL => $xtData) {
    $objStr->Value = $xtData;
    $arVal = $objStr->Xplode();
    $strDisp = $arVal[0];
    $strPop = $arVal[1];
    $arAdd[$strArg] = $strURL;
    $isSel = ($strURL == $strCur);
    $out .= $vgOut->Selected($isSel,'[ '.$this->SelfLink($arAdd,$strDisp,$strPop).' ]');
}
return $out;
    }
    /*----
      INPUT:
iarClassNames: array of names of classes to load
    */
    public function RegObjs(array $iarClassNames) {
foreach ($iarClassNames as $strCls) {
    $tbl = $this->DB()->Make($strCls);
    $strAct = $tbl->ActionKey();
    $arTbls[$strAct] = $tbl;
}
$this->arTbls = $arTbls;
     }
     }
}
/*==========
  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()
       ACTION: handles arguments embedded in the URL
      REQUIRES: classes must be registered in $this->arTbls (use $this->RegObjs())
       HISTORY:
       HISTORY:
    Extricated from VbzAdmin::VbzAdminItems
2011-10-15 moved here from SpecialVbzAdmin.php and renamed from doAdminLookup() to HandlePageArgs()
     */
     */
     public static function AdminLink($iID,$iShow=NULL,$iPopup=NULL) {
     protected function HandlePageArgs() {
    global $vgOut;
if (isset($this->args['page'])) {
    $page = $this->args['page'];
} else {
    $page = NULL;
}


    $id = $iID;
$idObj = NULL;
$doObj = FALSE;
$doNew = FALSE;
if (!is_null($page)) {
    if (isset($this->args['id'])) {
$doObj = TRUE;
$idObj = $this->args['id'];
if ($idObj == 'new') {
// an ID of NULL tells GetItem() to create a new object rather than loading an existing record
    $idObj = NULL;
    $doNew = TRUE;
}
    }
}
$this->page = $page;
$this->doObj = $doObj;
$this->idObj = $idObj;


    $arLink = array(
$tbl = NULL;
      'page'    => 'item',
$obj = NULL;
      'id'       => $id);
if (array_key_exists($page,$this->arTbls)) {
    $strShow = is_null($iShow)?($id):$iShow;
    $tbl = $this->arTbls[$page];
    $strPopup = is_null($iPopup)?('view item ID '.$id):$iPopup;
    if ($doObj) {
    $out = $vgOut->SelfLink($arLink,$strShow,$strPopup);
$obj = $tbl->GetItem($idObj);
    return $out;
if (!$doNew && $obj->IsNew()) {
    $out = '<b>Internal Error</b>: Record was expected, but none found. Check the URL.';
    $out .= '<ul>';
    $out .= '<li><b>requested ID</b>: '.$idObj;
    global $sql;
    $out .= '<li><b>SQL used</b>: '.$sql;
    $out .= '<li><b>Table class</b>: '.get_class($tbl);
    $out .= '<li><b>Record class</b>: '.get_class($obj);
    $out .= '</ul>';
 
    echo $out; $out=NULL;
    throw new exception('Expected record was not found.');
}
 
if (method_exists($obj,'PageTitle')) {
    $this->SetTitle($obj->PageTitle());
}
    } else {
if (method_exists($tbl,'PageTitle')) {
    $this->SetTitle($tbl->PageTitle());
}
    }
}
$this->tbl = $tbl;
$this->obj = $obj;
     }
     }
/*
}
     public function ActionKey($iName=NULL) {
 
     if (!is_null($iName)) {
/*==========
        $this->ActionKey = $iName;
| 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;
     }
     }
     return $this->ActionKey;
     public function Page() {
return $this->mwoPage;
     }
     }
}
/*%%%%
  PURPOSE: revised clsWikiSection, taking into account usability lessons learned
    and implementing a more flexible link design.
*/
*/
}
class clsWikiSection2 {
class clsAdminData extends clsDataSet {
     private $objFmt; // page-formatter object
     /*====
    private $arMenu; // array of menu objects
       SECTION: static versions of dynamic functions
    private $arPage; // page keys array
      PURPOSE: for classes which inherit from non-Admin classes (fake multiple inheritance)
    private $strTitle; // title of section - for display
    private $intLevel; // indentation level of section
 
    public function __construct(clsWikiFormatter $iFmt,$iTitle,$iLevel=2) {
$this->objFmt = $iFmt;
$this->strTitle = $iTitle;
$this->intLevel = $iLevel;
$this->arMenu = NULL;
$this->arPage = NULL;
    }
    /*----
       ACTION: set the list of keys that represent the current page spec.
Preserving these keys will keep the user on the current page even if other data changes.
     */
     */
    public function PageKeys(array $arKeys=NULL) {
if (!is_null($arKeys)) {
    $this->arPage = $arKeys;
}
return $this->arPage;
    }
     /*----
     /*----
       USED BY: VbzAdmin::clsAdminTopic::AdminLink()
       RETURNS: array representing page-defining data (but not all URL values)
      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) {
     public function PageData($iKey=NULL) {
    global $vgOut;
$arArgs = $this->PageVals();


    $txtShow = is_null($iText)?($iObj->ID):$iText;
if (is_null($iKey)) {
    if (isset($iObj->Table->ActionKey)) {
    // return array of values for all the keys that identify the page
        $strKey = $iObj->Table->ActionKey;
    foreach ($this->arPage as $idx => $key) {
    } else {
if (array_key_exists($key,$arArgs)) {
        $strKey = $iObj->Table->Name();
    // 2012-05-27 this seems to happen when a key is defined but not used in some circumstance
    $arOut[$key] = $arArgs[$key];
}
    }
    return $arOut;
} else {
    return NzArray($arArgs,$iKey);
}
     }
     }
 
     public function PageVals() {
     $arLink = array(
$objPage = $this->objFmt->Page();
      'page'    => $strKey,
return $objPage->Args();
      '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);
     }
     }
 
    public function AddLink(clsWikiSectionLink $iLink) {
    $out = $vgOut->SelfLink($arLink,$txtShow,$iPopup);
$this->arMenu[] = $iLink; // add Link to list of Links
    return $out;
$iLink->Section($this); // pass Link a pointer back to $this
return $iLink;
     }
     }
     /*====
     /*----
       SECTION: normal dynamic functions
       PURPOSE: add a link to do something on the current page -- preserve page-significant data
     */
     */
    public function AddLink_local(clsWikiSectionLink $iLink) {
$this->AddPageDefaults_toLink($iLink);
$this->AddLink($iLink);
return $iLink;
    }
     /*----
     /*----
       USED BY: VbzAdmin::VbzAdminStkItems::Listing_forItem()
       PURPOSE: add a link that preserves all other URL data (preserves the state of the page)
      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) {
     public function AddLink_state(clsWikiSectionLink $iLink) {
     return self::_AdminLink($this,$iText,$iPopup,$iarArgs);
$this->AddPageValues_toLink($iLink);
$this->AddLink($iLink);
return $iLink;
    }
     public function AddPageDefaults_toLink(clsWikiSectionLink $iLink) {
$iLink->Values_default($this->PageData());
     }
     }
    public function AddPageValues_toLink(clsWikiSectionLink $iLink) {
$iLink->Values_default($this->PageVals());
    }
    public function Render() {
$tag = 'h'.$this->intLevel;
$title = $this->strTitle;
$out = "\n<$tag>$title";
if (is_array($this->arMenu)) {
    $arMenu = array_reverse($this->arMenu); // right-alignment reverses things
    foreach ($arMenu as $objLink) {
$out .= $objLink->Render();
    }
}
$out .= "\n</$tag>";
return $out;
    }
   
}
}
abstract class clsAdminData_Logged extends clsAdminData {
class clsWikiSection_std_page extends clsWikiSection2 {
     protected $idEvent;
    public function __construct(clsWikiFormatter $iFmt,$iTitle,$iLevel=2) {
parent::__construct($iFmt,$iTitle,$iLevel);
$this->PageKeys(array('page','id'));
    }
}
/*%%%%
  PURPOSE: handles a single action-link (e.g. [edit]) on a section header
*/
abstract class clsWikiSectionLink {
     protected $objSect; // section object
    protected $arData; // key:value pairs for link
    private $strDisp; // text to display (defaults to $strKey)
    private $strPopup; // popup text (if any)
//    private $isSelected; // entry is shown as selected


    abstract protected function Events();        // RETURNS a clsAdminEvents object
     public function __construct(array $iarData,$iDisp) {
    /*=====
$this->arData = $iarData;
      INPUT: Array containing any of the following elements:
$this->strDisp = $iDisp;
    'descr': description of event
$this->objSect = NULL;
    'where': location in code where event is taking place (usually __METHOD__ will do)
$this->strPopup = NULL;
    'code': event code unique to type
$this->isActive = FALSE;
    '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) {
     public function Section(clsWikiSection2 $iSection=NULL) {
    $this->Events()->FinishEvent($this->idEvent,$iarArgs);
if (!is_null($iSection)) {
    unset($this->idEvent);
    $this->objSect = $iSection;
}
return $this->objSect;
     }
     }
}
     public function Popup($iPopup=NULL) {
/*==========
$this->strPopup = $iPopup;
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() {
     public function Values(array $iValues=NULL) {
    global $wgOut;
if (!is_null($iValues)) {
 
    $this->arData = $iValues;
    $objRow = $this->GetData(NULL,NULL,'ID DESC');
}
    if ($objRow->hasRows()) {
return $this->arData;
        $out = $objRow->AdminRows();
    } else {
        $out = 'No events logged yet.';
     }
     }
     $wgOut->addWikiText($out,TRUE);
     public function Value($iKey,$iVal=NULL) {
if (!is_null($iVal)) {
    $this->arData[$iKey] = $iVal;
}
return $this->arData[$iKey];
     }
     }
     /*-----
     /*----
       RETURNS: event arguments translated into field names for use in Insert()
       ACTION: sets a bunch of values to be used as defaults
      NOTE: Shouldn't this method be static?
if there is not already a value for each key.
     */
     */
     private function CalcSQL($iArgs) {
     public function Values_default(array $iarValues) {
    if (is_null($iArgs)) {
foreach ($iarValues as $key => $val) {
        return NULL;
    $this->arData[$key] = NzArray($this->arData,$key,$val);
    } 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;
     }
     }
    /*----
      RETURNS: TRUE if the current URL causes this link to be selected
May also return a value rather than TRUE/FALSE.
    */
    abstract public function Selected();
    /*----
      RETURNS: array of link's values, adjusted as needed for link behavior
      VERSION: removes key from link if it is currently active
This originally just returned $this->Values()
It may be that this class should do that, and we need
  a clsWikiSectionLink_toggle to do what this one does now.
    */
    protected function Values_forLink() {
$ar = $this->Values();
if ($this->Selected()) {
    // already selected, so toggle off the key
    $key = $this->Key();
    $ar[$key] = FALSE;
}
return $ar;
     }
     }
     /*-----
     /*----
       ACTION: Logs an event from specs in an array
       RETURNS: URL for this link
      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) {
     public function SelfURL() {
    global $vgUserName;
global $vgOut;


    $arIns = $this->CalcSQL($iArgs);
$ar = $this->Values_forLink();
    if (empty($arIns)) {
return $vgOut->SelfURL($ar);
        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) {
      ACTION: render the link
    if (is_array($iArgs)) {
      INPUT:
        $arUpd = $this->CalcSQL($iArgs);
$iPath - base URL for the link
        //$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() {
     public function Render() {
    $htUnknown = '<span style="color: #888888;">?</span>';
    $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;
$ftURL = $this->SelfURL();


        $strSysUser    = $row['WhoAdmin'];
$htPopup = htmlspecialchars($this->strPopup);
        $strVbzUser    = $row['WhoSystem'];
$htDispl = htmlspecialchars($this->strDisp);
        $strMachine    = $row['WhoNetwork'];
$isActive = $this->Selected();
        $htSysUser    = is_null($strSysUser)?$htUnknown:$strSysUser;
$htFmtOpen = $isActive?'<b>':'';
        $htMachine    = is_null($strMachine)?$htUnknown:$strMachine;
$htFmtShut = $isActive?'</b>':'';
        $htVbzUser    = is_null($strVbzUser)?$htUnknown:$strVbzUser;


        $ftDescr    = $row['Descr'];
$out = '<span class="editsection">';
        $strNotes    = $row['Notes'];
$out .= $htFmtOpen.'[';
$out .= '<a href="'.$ftURL.'" title="'.$htPopup.'">'.$htDispl.'</a>';
$out .= ']'.$htFmtShut;
$out .= '</span>';


        $id        = $row['ID'];
return $out;
        $strWhenSt    = $row['WhenStarted'];
    }
        $strWhenFi    = $row['WhenFinished'];
}
        $strWhere    = $row['EvWhere'];
/*%%%%
        $htWho        = $htVbzUser.'/'.$htSysUser.'@'.$htMachine;
  PURPOSE: handles links that have a "key", i.e. a particular identifying piece of data.
        $strParams    = $row['Params'];
    Default behavior is to treat this like a toggle.
*/
class clsWikiSectionLink_keyed extends clsWikiSectionLink {
    protected $strKey;


        $dtWhenSt    = strtotime($strWhenSt);
    public function __construct(array $iarData,$iDisp,$iKey=NULL) {
        $dtWhenFi    = strtotime($strWhenFi);
parent::__construct($iarData,$iDisp);
        $strDate    = date('Y-m-d',empty($dtWhenSt)?$dtWhenFi:$dtWhenSt);
$this->strKey = is_null($iKey)?$iDisp:$iKey;
        $strTimeSt = empty($dtWhenSt)?'':date('H:i',$dtWhenSt);
$this->isSelected = NULL;
        $strTimeFi = empty($dtWhenFi)?'':date('H:i',$dtWhenFi);
    }
        if ($strDate != $strDateLast) {
    public function Key($iKey=NULL) {
        $strDateLast = $strDate;
if (!is_null($iKey)) {
        $out .= "\n|- style=\"background: #444466; color: #ffffff;\"\n| colspan=5 | '''$strDate'''";
    $this->strKey = $iKey;
        }
}
       
return $this->strKey;
        $out .= "\n|- style=\"$wtStyle\"";
        $out .= "\n| $id || $strTimeSt || $strTimeFi || $htWho || <small>$strWhere</small>";
        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|}";
     public function Selected() {
    return $out;
$key = $this->Key();
$val = $this->objSect->PageData($key);
return $val;
     }
     }
}
}
 
/*%%%%
/*==========
  PURPOSE: handles links that express possible values of a single key
| FORM CLASSES
| Trying not to be too ambitious at first, but eventually could be separate library file
*/
*/
class clsWikiFormatter {
class clsWikiSectionLink_choice extends clsWikiSectionLink_keyed {
     private $mwoPage;
     public function Selected() {
 
$key = $this->Key();
    public function __construct(SpecialPageApp $iPage) {
$valPage = parent::Selected();
    $this->mwoPage = $iPage;
$valLink = $this->Value($key);
return $valPage == $valLink;
     }
     }
     public function Page() {
}
     return $this->mwoPage;
/*
class clsWikiSectionLink_bool {
     public function __construct(array $iarData,$iDisp=NULL,$iPopup=NULL,$iKey=NULL) {
     public function Selected($iOn=NULL) {
if (!is_null($iOn)) {
    $isActive = !empty($arLink['active']) || $arLink['isdef'];
}
return NzArray($this->arData,'active');
     }
     }
}
}
*/
class clsWikiSection {
class clsWikiSection {
     // STATIC
     // STATIC
Line 619: Line 819:


     // DYNAMIC
     // DYNAMIC
     private $strName;   // short name for header text
     private $strName; // short name for header text
     private $strDescr;   // longer description for popups
     private $strDescr; // longer description for popups
     private $intLevel;   // level of header; defaults to 2
     private $intLevel; // level of header; defaults to 2
     private $objFmt;   // page-formatter object
     private $objFmt; // page-formatter object
     private $arMenu;   // menu entries
     private $arMenu; // menu entries
     private $arKeep;   // arguments to preserve (in every menu item) from the current page  
     private $arKeep; // arguments to preserve (in every menu item) from the current page  
     private $arAdd;   // arguments to add to every menu item
     private $arAdd; // arguments to add to every menu item


     public function __construct(clsWikiFormatter $iFmt,$iName,$iDescr=NULL,$iLevel=2,array $iMenu=NULL) {
     public function __construct(clsWikiFormatter $iFmt,$iName,$iDescr=NULL,$iLevel=2,array $iMenu=NULL) {
    $this->objFmt = $iFmt;
$this->objFmt = $iFmt;
    $this->strName = $iName;
$this->strName = $iName;
    $this->strDescr = is_null($iDescr)?$iName:$iDescr;
$this->strDescr = is_null($iDescr)?$iName:$iDescr;
    $this->intLevel = $iLevel;
$this->intLevel = $iLevel;
    $this->arMenu = $iMenu;
$this->arMenu = $iMenu;
    $this->arKeep = self::$arKeepDefault;
$this->arKeep = self::$arKeepDefault;
     }
     }
/*
2011-03-30 who is using these?
2011-10-17 ArgsToKeep() and ArgsToAdd() were being used by SpecialWorkFerret clsWFSession.SectionHdr(); checking to see if actually needed...
  no, they aren't -- DEPRECATED -- use $vgPage-> functions instead.
     public function ArgsToKeep(array $iKeep) {
     public function ArgsToKeep(array $iKeep) {
    $this->arKeep = $iKeep;  
$this->arKeep = $iKeep;
     }
     }
     public function ArgsToAdd(array $iAdd) {
     public function ArgsToAdd(array $iAdd) {
    $this->arAdd = $iAdd;
$this->arAdd = $iAdd;
     }
     }
     protected function ArrayCheck(array $iarCheck) {
     protected function ArrayCheck(array $iarCheck) {
    if (is_array($this->arAdd)) {
if (is_array($this->arAdd)) {
        $arOut = array_unique(array_merge($iarCheck,$this->arAdd));
    $arOut = array_unique(array_merge($iarCheck,$this->arAdd));
    } else {
} else {
        $arOut = $iarCheck;
    $arOut = $iarCheck;
}
return $arOut;
     }
     }
     return $arOut;
     public function SelfURL() {
$arLink = $this->SelfArray();
$objPage = $this->objFmt->Page();
$wpPath = $objPage->SelfURL($arLink,TRUE);
return $wpPath;
     }
     }
     public function SelfArray() {
     public function SelfArray() {
    $objPage = $this->objFmt->Page();
$objPage = $this->objFmt->Page();
    if (is_array($this->arKeep)) {
if (is_array($this->arKeep)) {
        foreach ($this->arKeep as $key) {
    foreach ($this->arKeep as $key) {
        $arLink[$key] = $objPage->Arg($key);
$arLink[$key] = $objPage->Arg($key);
        }
    }
    }
}
    return $this->ArrayCheck($arLink);
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
      PURPOSE: Add an action link to the menu
      USED BY: any admin page that adds an action link to a section (e.g. "edit")
      INPUT;
iDisp = text to display (usually short, preferably one word)
iActive = TRUE shows the item as selected, FALSE shows it normally; default is to attempt to detect the state
iKey = key to use in URL. If this is an array, then it is passed directly to SelfURL(), overriding any existing values.
      HISTORY:
2010-11-07 added array option for iKey
     */
     */
     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;


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


    $strKey = is_null($iKey)?$iDisp:$iKey;
if (is_array($iKey)) {
    $arLink['do'] = $strKey;
    $wpPath = $objPage->SelfURL($iKey,TRUE);
    $arLink = $this->ArrayCheck($arLink);
    $isActive = is_null($iActive)?FALSE:$iActive;
//    $wpPath = 'BLARG!'.$objPage->SelfURL($arLink,TRUE);
} else {
    $isActive = is_null($iActive)?($objPage->Arg('do')==$strKey):$iActive;
    $strKey = is_null($iKey)?$iDisp:$iKey;
    $arLink['do'] = $strKey;
    $arLink = $objPage->ArrayCheck($arLink);
    $wpPath = $objPage->SelfURL($arLink,TRUE);
    $isActive = is_null($iActive)?($objPage->Arg('do')==$strKey):$iActive;
}


    $arEntry = array(
$arEntry = array(
      'type'   => 'action',
  'type' => 'action',
      'path'   => 'BLARG!', // was; $wpPath -- WHAT USES THIS?
  'path' => $wpPath,
      'popup'   => $strPopup,
  'popup' => $strPopup,
      'displ'   => $iDisp,
  'displ' => $iDisp,
      'active'   => $isActive,
  'active' => $isActive,
      'isdef'   => $iIsDefault
  'isdef' => $iIsDefault
      );
  );
    $this->arMenu[] = $arEntry;
$this->arMenu[] = $arEntry;
     }
     }
    /*----
      ACTION: adds a static-text separator to the section menu
      FUTURE: Rename this to SepAdd or DividerAdd
    */
     public function SectionAdd($iDisp) {
     public function SectionAdd($iDisp) {
    $arEntry = array(
$arEntry = array(
      'type'   => 'section',
  'type' => 'section',
      'displ'   => $iDisp
  'displ' => $iDisp
      );
  );
    $this->arMenu[] = $arEntry;
$this->arMenu[] = $arEntry;
     }
     }
     public function ToggleAdd($iDisp,$iPopup=NULL,$iKey=NULL) {
     public function ToggleAdd($iDisp,$iPopup=NULL,$iKey=NULL) {
    $strPopup = is_null($iPopup)?($iDisp.' '.$this->strDescr):$iPopup;
$strPopup = is_null($iPopup)?($iDisp.' '.$this->strDescr):$iPopup;
    $strKey = is_null($iKey)?$iDisp:$iKey;
$strKey = is_null($iKey)?$iDisp:$iKey;


    $objPage = $this->objFmt->Page();
$objPage = $this->objFmt->Page();
    $arLink = $this->SelfArray();
$arLink = $objPage->SelfArray();
$isActive = $objPage->Arg($strKey); // active state is indicated by presence of key
$arLink[$strKey] = !$isActive;


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


    $arEntry = array(
$arEntry = array(
      'type'   => 'toggle',
  'type' => 'toggle',
      'path'   => $wpPath,
  'path' => $wpPath,
      'popup'   => $strPopup,
  'popup' => $strPopup,
      'displ'   => $iDisp,
  'displ' => $iDisp,
      'active'   => $isActive
  'active' => $isActive
       );
  );
    $this->arMenu[] = $arEntry;
$this->arMenu[] = $arEntry;
    }
    /*----
      PURPOSE: More flexible section link type
      INPUT:
$iDisp = text to display
$iArgs = arguments for link
$iPopup = text for tooltip (optional)
       HISTORY:
2011-01-02 Created to allow section commands to link to new-record-creation pages
    */
    public function CommandAdd($iDisp,array $iArgs,$iPopup=NULL) {
$objPage = $this->objFmt->Page();
$wpPath = $objPage->SelfURL($iArgs);
$arEntry = array(
  'type' => 'action',
  'path' => $wpPath,
  'popup' => $iPopup,
  'displ' => $iDisp,
  'isdef' => FALSE // I've forgotten what this does, but there's a warning if it's not set
  );
$this->arMenu[] = $arEntry;
     }
     }
     public function Generate() {
     public function Generate() {
    $out = '<h'.$this->intLevel.'>';
$out = '<h'.$this->intLevel.'>';
    if (is_array($this->arMenu)) {
if (is_array($this->arMenu)) {
        $arMenu = array_reverse($this->arMenu);   // right-alignment reverses things
    $arMenu = array_reverse($this->arMenu); // right-alignment reverses things
        foreach ($arMenu as $arLink) {
    foreach ($arMenu as $arLink) {
        $strType = $arLink['type'];
$strType = $arLink['type'];
        switch ($strType) {
switch ($strType) {
          case 'action':
  case 'action':
            $htPath = $arLink['path'];
    $htPath = $arLink['path'];
            $htPopup = $arLink['popup'];
    $htPopup = $arLink['popup'];
            $htDispl = $arLink['displ'];
    $htDispl = $arLink['displ'];
            $isActive = !empty($arLink['active']) || $arLink['isdef'];
    $isActive = !empty($arLink['active']) || $arLink['isdef'];
            $htFmtOpen = $isActive?'<b>':'';
    $htFmtOpen = $isActive?'<b>':'';
            $htFmtShut = $isActive?'</b>':'';
    $htFmtShut = $isActive?'</b>':'';
            $out .= '<span class="editsection">';
    $out .= '<span class="editsection">';
            $out .= $htFmtOpen.'[';
    $out .= $htFmtOpen.'[';
            $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>';
    $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>';
            $out .= ']'.$htFmtShut;
    $out .= ']'.$htFmtShut;
            $out .= '</span>';
    $out .= '</span>';
            break;
    break;
          case 'toggle':
  case 'toggle':
            $htPath = $arLink['path'];
    $htPath = $arLink['path'];
            $htPopup = $arLink['popup'];
    $htPopup = $arLink['popup'];
            $htDispl = $arLink['displ'];
    $htDispl = $arLink['displ'];
            $isActive = !empty($arLink['active']);
    $isActive = !empty($arLink['active']);
            $htFmtOpen = $isActive?'<b>':'';
    $htFmtOpen = $isActive?'<b>':'';
            $htFmtShut = $isActive?'</b>':'';
    $htFmtShut = $isActive?'</b>':'';
            $out .= '<span class="editsection">';
    $out .= '<span class="editsection">';
            $out .= $htFmtOpen.'[';
    $out .= $htFmtOpen.'[';
            $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>';
    $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>';
            $out .= ']'.$htFmtShut;
    $out .= ']'.$htFmtShut;
            $out .= '</span>';
    $out .= '</span>';
            break;
    break;
          case 'section':
  case 'section':
            $htDispl = $arLink['displ'];
    $htDispl = $arLink['displ'];
            $out .= '<span class="editsection">';
    $out .= '<span class="editsection">';
            $out .= '| <b>'.$htDispl.'</b>:';
    $out .= '| <b>'.$htDispl.'</b>:';
            $out .= '</span>';
    $out .= '</span>';
            break;
    break;
        }
}
        }
    }
    }
}
    $out .= '<span class="mw-headline">'.$this->strName.'</span></h'.$this->intLevel.'>';
$out .= '<span class="mw-headline">'.$this->strName.'</span></h'.$this->intLevel.'>';
    return $out;
return $out;
     }
     }
     public function FormOpen() {
     public function FormOpen() {
    $out = '<form method=post action="'.$this->SelfURL().'">';
$objPage = $this->objFmt->Page();
    return $out;
$url = $objPage->SelfURL();
$out = '<form method=post action="'.$url.'">';
return $out;
     }
     }
}
}
 
class clsWikiAdminSection { // DEPRECATED; use clsWikiFormatter / clsWikiSection
// This class is DEPRECATED; replacing with clsWikiFormatter / clsWikiSection
class clsWikiAdminSection {
     private $strTitle;
     private $strTitle;
     private $strDescr;
     private $strDescr;
Line 778: Line 1,023:


     public function __construct($iTitle, $iDescr=NULL, array $iKeep=NULL) {
     public function __construct($iTitle, $iDescr=NULL, array $iKeep=NULL) {
    global $vgPage;
global $vgPage;


    $this->strTitle = $iTitle;
$this->strTitle = $iTitle;
    $this->strDescr = is_null($iDescr)?$iTitle:$iDescr;
$this->strDescr = is_null($iDescr)?$iTitle:$iDescr;
    $this->arKeep = is_null($iKeep)?(self::$arKeepDefault):$iKeep;
$this->arKeep = is_null($iKeep)?(self::$arKeepDefault):$iKeep;
    $this->doEdit = $vgPage->Arg('edit');
$this->doEdit = $vgPage->Arg('edit');
    //$this->htPath = $vgPage->SelfURL(array('edit'=>!$this->doEdit));
//$this->htPath = $vgPage->SelfURL(array('edit'=>!$this->doEdit));
    $this->htPath = $vgPage->SelfURL();
$this->htPath = $vgPage->SelfURL();
     }
     }
     public function HeaderHtml(array $iMenu=NULL) {
     public function HeaderHtml(array $iMenu=NULL) {
    $out = '<h2>';
$out = '<h2>';
    if (is_array($iMenu)) {
if (is_array($iMenu)) {
        foreach ($iMenu as $arLink) {
    foreach ($iMenu as $arLink) {
        $htPath = $arLink['path'];
$htPath = $arLink['path'];
        $htPopup = $arLink['popup'];
$htPopup = $arLink['popup'];
        $htDispl = $arLink['displ'];
$htDispl = $arLink['displ'];
        $isActive = !empty($arLink['active']);
$isActive = !empty($arLink['active']);
        $out .= '<span class="editsection">';
$out .= '<span class="editsection">';
        if ($isActive) {  $out .= '<b>'; }
if ($isActive) {  $out .= '<b>'; }
        $out .= '[';
$out .= '[';
        if ($isActive) {  $out .= '</b>'; }
if ($isActive) {  $out .= '</b>'; }
        $out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>';
$out .= '<a href="'.$htPath.'" title="'.$htPopup.'">'.$htDispl.'</a>';
        if ($isActive) {  $out .= '<b>'; }
if ($isActive) {  $out .= '<b>'; }
        $out .= ']';
$out .= ']';
        if ($isActive) {  $out .= '</b>'; }
if ($isActive) {  $out .= '</b>'; }
        $out .= '</span> ';
$out .= '</span> ';
        }
    }
    } else {
} else {
        $out = '';
    $out = '';
    }
}
    $out .= '<span class="mw-headline">'.$this->strTitle.'</span></h2>';
$out .= '<span class="mw-headline">'.$this->strTitle.'</span></h2>';
    return $out;
return $out;
     }
     }
     public function HeaderHtml_OLD() {
     public function HeaderHtml_OLD() {
    $out = '<h2>';
$out = '<h2>';
    if (!$this->doEdit) {
if (!$this->doEdit) {
      $out .= '<span class="editsection">[<a href="'.$this->htPath.'" title="Edit '.$this->strDescr.'">edit</a>]</span> ';
  $out .= '<span class="editsection">[<a href="'.$this->htPath.'" title="Edit '.$this->strDescr.'">edit</a>]</span> ';
    }
}
    $out .= '<span class="mw-headline">'.$this->strTitle.'</span></h2>';
$out .= '<span class="mw-headline">'.$this->strTitle.'</span></h2>';
    return $out;
return $out;
     }
     }
     public function HeaderHtml_Edit(array $iMenu=NULL) {
     public function HeaderHtml_Edit(array $iMenu=NULL) {
    global $vgPage;
global $vgPage;


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


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


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


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


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


    return $this->HeaderHtml($arMenu);
return $this->HeaderHtml($arMenu);
     }
     }
     public function FormOpen() {
     public function FormOpen() {
    if ($this->doEdit) {
if ($this->doEdit) {
        $out = '<form method=post action="'.$this->htPath.'">';
    $out = '<form method=post action="'.$this->htPath.'">';
    } else {
} else {
        $out = NULL;
    $out = NULL;
    }
}
    return $out;
return $out;
     }
     }
}
}
Line 872: Line 1,117:
     $path = $wgScriptPath . '/extensions/tabber/';
     $path = $wgScriptPath . '/extensions/tabber/';
     $htmlHeader = '<script type="text/javascript" src="'.$path.'tabber.js"></script>'
     $htmlHeader = '<script type="text/javascript" src="'.$path.'tabber.js"></script>'
        . '<link rel="stylesheet" href="'.$path.'tabber.css" TYPE="text/css" MEDIA="screen">'
    . '<link rel="stylesheet" href="'.$path.'tabber.css" TYPE="text/css" MEDIA="screen">'
        . '<div class="tabber">';
    . '<div class="tabber">';
     $wgOut->addHTML($htmlHeader);
     $wgOut->addHTML($htmlHeader);
}
}

Revision as of 17:27, 27 May 2012

Examples

Shows a set of toggles. Library code currently does not properly highlight active options. <php> global $vgPage;

$vgPage->UseHTML();

$objPage = new clsWikiFormatter($vgPage);

$objSection = new clsWikiSection_std_page($objPage,'Orders',3); //$objSection->ArgsToKeep(array('show','page','id')); $objSection->PageKeys(array('page','id')); //$objSection->ToggleAdd('edit','edit the list of groups','edit.ctg'); $objLink = $objSection->AddLink_local(new clsWikiSectionLink_keyed(array('show.pulled'=>TRUE),'pulled')); $objLink->Popup('show pulled orders'); $objLink = $objSection->AddLink_local(new clsWikiSectionLink_keyed(array('show.shut'=>TRUE),'shut')); $objLink->Popup('show orders which have been closed'); $objLink = $objSection->AddLink_local(new clsWikiSectionLink_keyed(array('show.open'=>TRUE),'open')); $objLink->Popup('show orders which have not been completed'); $out = $objSection->Render();


/* check the flags */ if ($vgPage->Arg('show.open')) { // ...and so on </php>

Source

<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
   2010-10-17 Expanded SpecialPageApp::Args() to allow returning a limited set of arguments
 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 (!defined('KS_CHAR_URL_ASSIGN')) {

   define('KS_CHAR_URL_ASSIGN',':');	// default

}

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

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

$this->Page = $iWikiPage; $this->isSubActive = FALSE;

   }
   public function WikiText($iAction) {

$this->Action = $iAction; if (isset($this->AllNodes[$iAction])) { $this->AllNodes[$iAction]->Activate(); $this->isSubActive = TRUE; } $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;

   }
   /*----
     RETURNS: TRUE if the current input has activated a sub-menu
   */
   public function IsSubMenuActive() {

return $this->isSubActive;

   }

}

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>';

   }

}

  • /

//} /* ####

 FUTURE: This could eventually be split into a general page-type and one
   which uses page/id for most pages
   Also, the different RichText classes are now dependent on their creator
     (e.g. this class) to pass them the right kind of base URL. Not sure
     how to fix the conceptual model.
  • /

class SpecialPageApp extends SpecialPage {

   // DYNAMIC
   private $arKeep;	// arguments to preserve (in every menu item) from the current page 
   private $arAdd;	// arguments to add to every menu item
   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(); $mwoTitleMe = $this->getTitle(); $wpBase = $this->BaseURL(); $wkBase = $mwoTitleMe->getPrefixedText();

$this->objRT_HTML = new clsHTML($wpBase); // $this->objRT_HTML = new clsHTML(); $this->objRT_Wiki = new clsWikiText($wkBase); // OMGkluge $this->InitArKeep();

   }
   /*----
     RETURNS: URL of basic Special page with no URL arguments
   */
   public function BaseURL() {

$mwoTitle = $this->getTitle(); $wp = $mwoTitle->getFullURL(); return $wp;

   }
   protected function InitArKeep() {

$this->arKeep = array('page','id');

   }
   public function UseHTML() {

global $vgOut;

$vgOut = $this->objRT_HTML;

   }
   public function UseWiki() {

global $vgOut;

$vgOut = $this->objRT_Wiki;

   }

/*

   public function RichTextObj() {

return $vgOut;

   }
  • /
   /*----
   ACTION: 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.

   */
   protected function GetArgs($par) {

// $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,

or just the arguments listed in $iList

   */
   public function Args(array $iList=NULL) {

if (is_array($iList)) { foreach ($iList as $name) { $arOut[$name] = $this->Arg($name); } return $arOut; } else { return $this->args; }

   }
   /*----
     RETURNS: value of single specified argument from URL
     HISTORY:

2012-02-26 changed default return from FALSE to NULL NULL is easier to test for.

   */
   public function Arg($iName) {

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

   }
   /*====
     SECTION: link generation
     HISTORY:

2011-03-30 adapted from clsWikiSection to SpecialPageApp

   */
   public function ArgsToKeep(array $iKeep) {

$this->arKeep = $iKeep;

   }
   public function ArgsToAdd(array $iAdd) {

$this->arAdd = $iAdd;

   }
   public 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() {

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

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

echo 'ARDATA:

'.print_r($arData,TRUE).'

';

return SelfLink_Path($arData);

   }
   /*----
     USED BY: clsWikiSection::ActionAdd
   */
   public function SelfURL(array $iAdd=NULL,$iClear=TRUE) {

$arAddSave = $this->arAdd; $this->arAdd = $iAdd; $arLink = $this->SelfArray(); // this looks OK

//echo 'ARLINK:

'.print_r($arLink,TRUE).'

';

$wpPath = $this->SelfURL_calc($arLink,$iClear); // problem happens there ^ //echo 'WPPATH=['.$wpPath.']'; $this->arAdd = $arAddSave; return $wpPath;

   }
   /*----
     NOTE: This has only been tested with SpecialPages; in theory it could be used on regular pages
   */
   static public function URL_fromArray(array $iArgs) {

global $wgTitle; global $wgScriptPath;

$strPath = SelfLink_Path($iArgs); // the part after the page name return $wgScriptPath.'/'.$wgTitle->getPrefixedText().$strPath;

   }
   /*----
     RETURNS: Relative path, ready for use in an href
     USED BY: clsWikiSection:ActionAdd()
     HISTORY:

2011-03-30 renamed from SelfURL() to SelfURL_calc() 2012-02-24 dropped use of $wgScriptPath, because it doesn't work with MW1.18; rewrote path calculation.

   */
   protected function SelfURL_calc(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 = ; } //$wpPrefix = $wgTitle->getPrefixedText(); //$wpPrefix = $this->getName(); $mwoTitle = $this->getTitle(); $wpPrefix = $mwoTitle->getFullURL(); return $wpPrefix.$strPath;

   }
   // DEPRECATED
   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, $iPopup=NULL) {

global $vgOut;

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

   }
   /*----
     ACTION: Displays a mini-menu from a list of possible values
     INPUT:

$iArgName: name of argument whose value changes with each choice $iValues: array containing prefix-delimited list of data for each choice: iValue[URL value] = "\display value\popup text"

   */
   public function SelfLinkMenu($iArgName,array $iValues,$iCur=NULL) {

global $vgOut;

$strCur = (is_null($iCur))?$this->Arg($iArgName):$iCur;

$objStr = new xtString; $strArg = $iArgName; $out = ; foreach ($iValues as $strURL => $xtData) { $objStr->Value = $xtData; $arVal = $objStr->Xplode(); $strDisp = $arVal[0]; $strPop = $arVal[1]; $arAdd[$strArg] = $strURL; $isSel = ($strURL == $strCur); $out .= $vgOut->Selected($isSel,'[ '.$this->SelfLink($arAdd,$strDisp,$strPop).' ]'); } return $out;

   }
   /*----
     INPUT:

iarClassNames: array of names of classes to load

   */
   public function RegObjs(array $iarClassNames) {

foreach ($iarClassNames as $strCls) { $tbl = $this->DB()->Make($strCls); $strAct = $tbl->ActionKey(); $arTbls[$strAct] = $tbl; } $this->arTbls = $arTbls;

   }
   /*----
     ACTION: handles arguments embedded in the URL
     REQUIRES: classes must be registered in $this->arTbls (use $this->RegObjs())
     HISTORY:

2011-10-15 moved here from SpecialVbzAdmin.php and renamed from doAdminLookup() to HandlePageArgs()

   */
   protected function HandlePageArgs() {

if (isset($this->args['page'])) { $page = $this->args['page']; } else { $page = NULL; }

$idObj = NULL; $doObj = FALSE; $doNew = FALSE; if (!is_null($page)) { if (isset($this->args['id'])) { $doObj = TRUE; $idObj = $this->args['id']; if ($idObj == 'new') { // an ID of NULL tells GetItem() to create a new object rather than loading an existing record $idObj = NULL; $doNew = TRUE; } } } $this->page = $page; $this->doObj = $doObj; $this->idObj = $idObj;

$tbl = NULL; $obj = NULL; if (array_key_exists($page,$this->arTbls)) { $tbl = $this->arTbls[$page]; if ($doObj) { $obj = $tbl->GetItem($idObj); if (!$doNew && $obj->IsNew()) { $out = 'Internal Error: Record was expected, but none found. Check the URL.';

$out .= '

    '; $out .= '
  • requested ID: '.$idObj; global $sql; $out .= '
  • SQL used: '.$sql; $out .= '
  • Table class: '.get_class($tbl); $out .= '
  • Record class: '.get_class($obj); $out .= '

';

echo $out; $out=NULL; throw new exception('Expected record was not found.'); }

if (method_exists($obj,'PageTitle')) { $this->SetTitle($obj->PageTitle()); } } else { if (method_exists($tbl,'PageTitle')) { $this->SetTitle($tbl->PageTitle()); } } } $this->tbl = $tbl; $this->obj = $obj;

   }

}

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

   }

} /*%%%%

 PURPOSE: revised clsWikiSection, taking into account usability lessons learned
   and implementing a more flexible link design.
  • /

class clsWikiSection2 {

   private $objFmt;	// page-formatter object
   private $arMenu;	// array of menu objects
   private $arPage;	// page keys array
   private $strTitle;	// title of section - for display
   private $intLevel;	// indentation level of section
   public function __construct(clsWikiFormatter $iFmt,$iTitle,$iLevel=2) {

$this->objFmt = $iFmt; $this->strTitle = $iTitle; $this->intLevel = $iLevel; $this->arMenu = NULL; $this->arPage = NULL;

   }
   /*----
     ACTION: set the list of keys that represent the current page spec.

Preserving these keys will keep the user on the current page even if other data changes.

   */
   public function PageKeys(array $arKeys=NULL) {

if (!is_null($arKeys)) { $this->arPage = $arKeys; } return $this->arPage;

   }
   /*----
     RETURNS: array representing page-defining data (but not all URL values)
   */
   public function PageData($iKey=NULL) {

$arArgs = $this->PageVals();

if (is_null($iKey)) { // return array of values for all the keys that identify the page foreach ($this->arPage as $idx => $key) { if (array_key_exists($key,$arArgs)) { // 2012-05-27 this seems to happen when a key is defined but not used in some circumstance $arOut[$key] = $arArgs[$key]; } } return $arOut; } else { return NzArray($arArgs,$iKey); }

   }
   public function PageVals() {

$objPage = $this->objFmt->Page(); return $objPage->Args();

   }
   public function AddLink(clsWikiSectionLink $iLink) {

$this->arMenu[] = $iLink; // add Link to list of Links $iLink->Section($this); // pass Link a pointer back to $this return $iLink;

   }
   /*----
     PURPOSE: add a link to do something on the current page -- preserve page-significant data
   */
   public function AddLink_local(clsWikiSectionLink $iLink) {

$this->AddPageDefaults_toLink($iLink); $this->AddLink($iLink); return $iLink;

   }
   /*----
     PURPOSE: add a link that preserves all other URL data (preserves the state of the page)
   */
   public function AddLink_state(clsWikiSectionLink $iLink) {

$this->AddPageValues_toLink($iLink); $this->AddLink($iLink); return $iLink;

   }
   public function AddPageDefaults_toLink(clsWikiSectionLink $iLink) {

$iLink->Values_default($this->PageData());

   }
   public function AddPageValues_toLink(clsWikiSectionLink $iLink) {

$iLink->Values_default($this->PageVals());

   }
   public function Render() {

$tag = 'h'.$this->intLevel; $title = $this->strTitle; $out = "\n<$tag>$title"; if (is_array($this->arMenu)) { $arMenu = array_reverse($this->arMenu); // right-alignment reverses things foreach ($arMenu as $objLink) { $out .= $objLink->Render(); } } $out .= "\n</$tag>"; return $out;

   }
   

} class clsWikiSection_std_page extends clsWikiSection2 {

   public function __construct(clsWikiFormatter $iFmt,$iTitle,$iLevel=2) {

parent::__construct($iFmt,$iTitle,$iLevel); $this->PageKeys(array('page','id'));

   }

} /*%%%%

 PURPOSE: handles a single action-link (e.g. [edit]) on a section header
  • /

abstract class clsWikiSectionLink {

   protected $objSect;	// section object
   protected $arData;	// key:value pairs for link
   private $strDisp;	// text to display (defaults to $strKey)
   private $strPopup;	// popup text (if any)

// private $isSelected; // entry is shown as selected

   public function __construct(array $iarData,$iDisp) {

$this->arData = $iarData; $this->strDisp = $iDisp; $this->objSect = NULL; $this->strPopup = NULL; $this->isActive = FALSE;

   }
   public function Section(clsWikiSection2 $iSection=NULL) {

if (!is_null($iSection)) { $this->objSect = $iSection; } return $this->objSect;

   }
   public function Popup($iPopup=NULL) {

$this->strPopup = $iPopup;

   }
   public function Values(array $iValues=NULL) {

if (!is_null($iValues)) { $this->arData = $iValues; } return $this->arData;

   }
   public function Value($iKey,$iVal=NULL) {

if (!is_null($iVal)) { $this->arData[$iKey] = $iVal; } return $this->arData[$iKey];

   }
   /*----
     ACTION: sets a bunch of values to be used as defaults

if there is not already a value for each key.

   */
   public function Values_default(array $iarValues) {

foreach ($iarValues as $key => $val) { $this->arData[$key] = NzArray($this->arData,$key,$val); }

   }
   /*----
     RETURNS: TRUE if the current URL causes this link to be selected

May also return a value rather than TRUE/FALSE.

   */
   abstract public function Selected();
   /*----
     RETURNS: array of link's values, adjusted as needed for link behavior
     VERSION: removes key from link if it is currently active

This originally just returned $this->Values() It may be that this class should do that, and we need a clsWikiSectionLink_toggle to do what this one does now.

   */
   protected function Values_forLink() {

$ar = $this->Values(); if ($this->Selected()) { // already selected, so toggle off the key $key = $this->Key(); $ar[$key] = FALSE; } return $ar;

   }
   /*----
     RETURNS: URL for this link
   */
   public function SelfURL() {

global $vgOut;

$ar = $this->Values_forLink(); return $vgOut->SelfURL($ar);

   }
   /*----
     ACTION: render the link
     INPUT:

$iPath - base URL for the link

   */
   public function Render() {

$ftURL = $this->SelfURL();

$htPopup = htmlspecialchars($this->strPopup); $htDispl = htmlspecialchars($this->strDisp); $isActive = $this->Selected(); $htFmtOpen = $isActive?'':; $htFmtShut = $isActive?'':;

$out = ''; $out .= $htFmtOpen.'['; $out .= '<a href="'.$ftURL.'" title="'.$htPopup.'">'.$htDispl.'</a>'; $out .= ']'.$htFmtShut; $out .= '';

return $out;

   }

} /*%%%%

 PURPOSE: handles links that have a "key", i.e. a particular identifying piece of data.
   Default behavior is to treat this like a toggle.
  • /

class clsWikiSectionLink_keyed extends clsWikiSectionLink {

   protected $strKey;
   public function __construct(array $iarData,$iDisp,$iKey=NULL) {

parent::__construct($iarData,$iDisp); $this->strKey = is_null($iKey)?$iDisp:$iKey; $this->isSelected = NULL;

   }
   public function Key($iKey=NULL) {

if (!is_null($iKey)) { $this->strKey = $iKey; } return $this->strKey;

   }
   public function Selected() {

$key = $this->Key(); $val = $this->objSect->PageData($key); return $val;

   }

} /*%%%%

 PURPOSE: handles links that express possible values of a single key
  • /

class clsWikiSectionLink_choice extends clsWikiSectionLink_keyed {

   public function Selected() {

$key = $this->Key(); $valPage = parent::Selected(); $valLink = $this->Value($key); return $valPage == $valLink;

   }

} /* class clsWikiSectionLink_bool {

   public function __construct(array $iarData,$iDisp=NULL,$iPopup=NULL,$iKey=NULL) {
   public function Selected($iOn=NULL) {

if (!is_null($iOn)) { $isActive = !empty($arLink['active']) || $arLink['isdef']; } return NzArray($this->arData,'active');

   }

}

  • /

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;

   }

/* 2011-03-30 who is using these? 2011-10-17 ArgsToKeep() and ArgsToAdd() were being used by SpecialWorkFerret clsWFSession.SectionHdr(); checking to see if actually needed...

 no, they aren't -- DEPRECATED -- use $vgPage-> functions instead.
   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 SelfURL() {

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

   }
   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);

   }
  • /
   /*-----
     PURPOSE: Add an action link to the menu
     USED BY: any admin page that adds an action link to a section (e.g. "edit")
     INPUT;

iDisp = text to display (usually short, preferably one word) iActive = TRUE shows the item as selected, FALSE shows it normally; default is to attempt to detect the state iKey = key to use in URL. If this is an array, then it is passed directly to SelfURL(), overriding any existing values.

     HISTORY:

2010-11-07 added array option for iKey

   */
   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 = $objPage->ArrayCheck($objPage->SelfArray());

if (is_array($iKey)) { $wpPath = $objPage->SelfURL($iKey,TRUE); $isActive = is_null($iActive)?FALSE:$iActive; } else { $strKey = is_null($iKey)?$iDisp:$iKey; $arLink['do'] = $strKey; $arLink = $objPage->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;

   }
   /*----
     ACTION: adds a static-text separator to the section menu
     FUTURE: Rename this to SepAdd or DividerAdd
   */
   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 = $objPage->SelfArray(); $isActive = $objPage->Arg($strKey); // active state is indicated by presence of key $arLink[$strKey] = !$isActive;

$arLink = $objPage->ArrayCheck($arLink); $wpPath = $objPage->SelfURL($arLink,TRUE);

//echo '

'.print_r($arLink,TRUE).'

';

//echo 'WPPATH=['.$wpPath.']';

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

   }
   /*----
     PURPOSE: More flexible section link type
     INPUT:

$iDisp = text to display $iArgs = arguments for link $iPopup = text for tooltip (optional)

     HISTORY:

2011-01-02 Created to allow section commands to link to new-record-creation pages

   */
   public function CommandAdd($iDisp,array $iArgs,$iPopup=NULL) {

$objPage = $this->objFmt->Page(); $wpPath = $objPage->SelfURL($iArgs); $arEntry = array( 'type' => 'action', 'path' => $wpPath, 'popup' => $iPopup, 'displ' => $iDisp, 'isdef' => FALSE // I've forgotten what this does, but there's a warning if it's not set ); $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() {

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

   }

} class clsWikiAdminSection { // DEPRECATED; use clsWikiFormatter / clsWikiSection

   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>