Index: branches/2.8.x/CHANGELOG
===================================================================
--- branches/2.8.x/CHANGELOG	(revision 2025)
+++ branches/2.8.x/CHANGELOG	(revision 2026)
@@ -11,6 +11,9 @@
 ! = Update/Change
 ===============================================================================
 
+08 Dec-2013 Build 2026 Manuela v.d.Decken(DarkViper)
+! [wblink] outputfilter now can handle ancors too
+! WbLink Interface is much more easier to use now.
 07 Dec-2013 Build 2025 Manuela v.d.Decken(DarkViper)
 # mod-MultiLingual forgotten fix in Lib.php :(
 07 Dec-2013 Build 2024 Manuela v.d.Decken(DarkViper)
Index: branches/2.8.x/wb/admin/interface/version.php
===================================================================
--- branches/2.8.x/wb/admin/interface/version.php	(revision 2025)
+++ branches/2.8.x/wb/admin/interface/version.php	(revision 2026)
@@ -51,5 +51,5 @@
 
 // check if defined to avoid errors during installation (redirect to admin panel fails if PHP error/warnings are enabled)
 if(!defined('VERSION')) define('VERSION', '2.8.3');
-if(!defined('REVISION')) define('REVISION', '2025');
+if(!defined('REVISION')) define('REVISION', '2026');
 if(!defined('SP')) define('SP', '');
Index: branches/2.8.x/wb/framework/WbLinkAbstract.php
===================================================================
--- branches/2.8.x/wb/framework/WbLinkAbstract.php	(revision 2025)
+++ branches/2.8.x/wb/framework/WbLinkAbstract.php	(revision 2026)
@@ -35,65 +35,68 @@
  */
 abstract class WbLinkAbstract {
 
-	protected $oDb  = null;
-	protected $oReg = null;
-
+/**
+ * @var object $oDb the active instance of WbDatabase 
+ */
+	protected $oDb    = null;
+/**
+ * @var object $oReg the active instance of WbAdaptor
+ */
+	protected $oReg   = null;
+/**
+ * @var string $sAddon the name of the addon, which extends this class
+ */
+	protected $sAddon = '';
+/**
+ * protected constructor
+ */
 	final public function __construct()
 	{
-		$this->oDb  = WbDatabase::getInstance();
-		$this->oReg = WbAdaptor::getInstance();
+		$this->oDb    = WbDatabase::getInstance();
+		$this->oReg   = WbAdaptor::getInstance();
+		$this->sAddon = preg_replace('/^.*?_([^_]+)_[^_]*?$/', '\1', get_class($this));
 	}
 
+
 	abstract public function makeLinkFromTag(array $aReplacement);
 	abstract public function &generateOptionsList();
 
 /**
- *
- * @param string $sAddonName
- * @param string $sAddonTableName
- * @param string $sPageIdName
- * @param string $sSectionIdName
- * @param string $sItemIdName
- * @param string $sDateTimeName
- * @param string $sTitleName
- * @param string $sActivatedName
+ * executeListGeneration
  * @return array by reference
  */
-	final protected function &_executeListGeneration(
-	                                                  $sAddonName      = 'news',
-	                                                  $sAddonTableName = 'mod_news_posts',
-	                                                  $sPageIdName     = 'page_id',
-	                                                  $sSectionIdName  = 'section_id',
-	                                                  $sItemIdName     = 'post_id',
-	                                                  $sDateTimeName   = 'created_when',
-	                                                  $sTitleName      = 'title',
-	                                                  $sActivatedName  = 'active'
-	                                                )
+	final protected function &_executeListGeneration()
 	{
 		$aAddonItems = array();
 		//generate news lists
-		$sql = 'SELECT `p`.`'.$sItemIdName.'` `ItemId`, `p`.`'.$sPageIdName.'` `PageId`, '
-		     .        '`s`.`section_id` `SectionId`, `p`.`'.$sTitleName.'` `Title` '
+		$sql = 'SELECT `p`.`'.$this::FIELDNAME_ITEM_ID.'` `ItemId`, `p`.`'.$this::FIELDNAME_PAGE_ID.'` `PageId`, '
+		     .        '`s`.`section_id` `SectionId`, `p`.`'.$this::FIELDNAME_TITLE.'` `Title` '
 		     . 'FROM `'.$this->oDb->TablePrefix.'sections` `s` '
-			 . 'LEFT JOIN `'.$this->oDb->TablePrefix.$sAddonTableName.'` `p` ON `s`.`section_id`= `p`.`'.$sSectionIdName.'` '
-			 . 'WHERE `p`.`'.$sActivatedName.'`>0 AND `s`.`module`=\''.$sAddonName.'\' '
-			 . 'ORDER BY `s`.`page_id`, `s`.`section_id`, `p`.`'.$sDateTimeName.'` DESC';
+			 . 'LEFT JOIN `'.$this->oDb->TablePrefix.$this::TABLE_NAME.'` `p` ON `s`.`section_id`= `p`.`'.$this::FIELDNAME_SECTION_ID.'` '
+			 . 'WHERE `s`.`module`=\''.$this->sAddon.'\' '
+		     . ($this->FIELDNAME_ACTIVE != '' ? 'AND `p`.`'.$this::FIELDNAME_ACTIVE.'`>0 ' : '')
+			 . 'ORDER BY `s`.`page_id`, `s`.`section_id`'.($this::FIELDNAME_TIMESTAMP != '' ? ', `p`.`'.$this::FIELDNAME_TIMESTAMP.'` DESC' : '');
 		if (( $oRes = $this->oDb->doQuery($sql))) {
+		// preset group changer flags
 			$iCurrentPage    = 0;
 			$iCurrentSection = 0;
 			$iSectionCounter = 0;
 			while ($aItem = $oRes->fetchRow(MYSQL_ASSOC)) {
+			// iterate all matches
 				if ($iCurrentPage != $aItem['PageId']) {
+				// change group by PageId
 					$iCurrentPage = $aItem['PageId'];
 					$aAddonItems[$iCurrentPage.'P'] = array();
 				}
 				if ($iCurrentSection != $aItem['SectionId']) {
+				// change group by SectionId
 					$iCurrentSection = $aItem['SectionId'];
 					$aAddonItems[$iCurrentPage.'P'][] = array();
 					$iSectionCounter = sizeof($aAddonItems[$iCurrentPage.'P'])-1;
 				}
+				// save current record
 				$aAddonItems[$iCurrentPage.'P'][$iSectionCounter][] = array(
-				    'wblink' => '[wblink'.$aItem['PageId'].'?addon='.$sAddonName.'&item='.$aItem['ItemId'].']',
+				    'wblink' => '[wblink'.$aItem['PageId'].'?addon='.$sAddon.'&item='.$aItem['ItemId'].']',
 				    'title'  => preg_replace("/\r?\n/", "\\n", $this->oDb->escapeString($aItem['Title']))
 				);
 			}
@@ -100,6 +103,30 @@
 		}
 		return $aAddonItems;
 	}
-
-
+/**
+ * makeLinkFromTag
+ * @param string $sBasePath
+ * @param array $aReplacement
+ * @return string a valid URL or '#' on error
+ */
+	protected function _makeLinkFromTag($sBasePath, array $aReplacement)
+	{
+	// set link on failure ('#' means, still stay on current page)
+		$sRetval = '#';
+	// search `link` from posts table and create absolute URL
+		$sql = 'SELECT `'.$this::FIELDNAME_LINK.'` '
+			 . 'FROM `'.$this->oDb->TablePrefix.$this::TABLE_NAME.'` '
+			 . 'WHERE `'.$this::FIELDNAME_ITEM_ID.'`='.$aReplacement['item'];
+		if (($sLink = $this->oDb->get_one($sql))) {
+			$sLink     = trim(str_replace('\\', '/', $sLink), '/');
+			$sBasePath = trim(str_replace('\\', '/', $sBasePath), '/').'/';
+		// test if valid accessfile is available
+			$sFilePath = $sBasePath.$sLink.$this->oReg->PageExtension;
+			if (is_readable($sFilePath)) {
+				$sRelPath = preg_replace('/^'.preg_quote($this->oReg->AppPath, '/').'/', '', $sFilePath);
+				$sRetval = $this->oReg->AppUrl.$sRelPath.$aReplacement['ancor'];
+			}
+		}
+		return $sRetval;
+	}
 } // end of class WbLinkAbstract
Index: branches/2.8.x/wb/modules/output_filter/filters/filterWbLink.php
===================================================================
--- branches/2.8.x/wb/modules/output_filter/filters/filterWbLink.php	(revision 2025)
+++ branches/2.8.x/wb/modules/output_filter/filters/filterWbLink.php	(revision 2026)
@@ -1,4 +1,33 @@
 <?php
+
+
+/**
+ * ParseWbLink
+ * @param string $sContent
+ * @return array details of all found Wblink-Tags
+ * @description parse 
+ */
+	function _parseWbLink(&$sContent)
+	{
+		$aResults = array();
+		$aMatches = array();
+		$sPattern = '/\[wblink([0-9]+)(\#([^\?]+))?(\?([^\]]+))?\]/is';
+		if (preg_match_all($sPattern, $sContent, $aMatches, PREG_SET_ORDER)) {
+			foreach ($aMatches as $aTag) {
+				$aResults[$aTag[0]] = array();
+				$aResults[$aTag[0]]['pageid'] = $aTag[1];
+				$aResults[$aTag[0]]['ancor']  = (isset($aTag[3]) ? $aTag[3] : '');
+				$aResults[$aTag[0]]['params'] = array();
+				$aTag[5] = (isset($aTag[5]) ? $aTag[5] : '');
+				$aTmpArgs = preg_split('/&amp;|&/i', $aTag[5], -1, PREG_SPLIT_NO_EMPTY);
+				foreach ($aTmpArgs as $sArgument) {
+					$aArgs = explode('=', $sArgument);
+					$aResults[$aTag[0]]['params'][$aArgs[0]] = $aArgs[1];
+				}
+			}
+		}
+		return $aResults;
+	}
 /*
  * @param  string $content : contains the full content of the current page
  * @return string
@@ -10,73 +39,125 @@
 		$oDb  = WbDatabase::getInstance();
 		$oReg = WbAdaptor::getInstance();
 		$aReplaceList = array();
-		$sPattern = '/\[wblink([0-9]+)\??([^\]]*)\]/is';
-		if(preg_match_all($sPattern,$sContent,$aMatches))
-		{
-		// iterate through all found matches
-			foreach($aMatches[0] as $iKey => $sKeyString )
-			{
-				$aReplaceList[$sKeyString] = array();
-			// use original Tag to save PageId
-				$aReplaceList[$sKeyString]['PageId'] = $aMatches[1][$iKey];
-			// if there are additional arguments given
-				if($aMatches[2][$iKey])
+		$aTagList = _parseWblink($sContent);
+		// iterate list if replacements are available
+		foreach ($aTagList as $sKey=>$aTag) {
+		// set link on failure ('#' means, still stay on current page)
+			$aReplaceList[$sKey] = '#';
+		// sanitize possible ancor
+			$aTag['ancor'] = ($aTag['ancor'] == '' ? '' : '#'.$aTag['ancor']);
+		// handle normal pages links
+			if (sizeof($aTag['params']) == 0) {
+				$sql = 'SELECT `link` FROM `'.$oDb->TablePrefix.'pages` WHERE `page_id` = '.(int)$aTag['pageid'];
+				if(($sLink = $oDb->get_one($sql)))
 				{
-					$aReplaceList[$sKeyString]['Args'] = array();
-					$aArgs = preg_split('/&amp;|&/i', $aMatches[2][$iKey], -1, PREG_SPLIT_NO_EMPTY);
-					foreach($aArgs as $sArgument)
+					$sLink = trim(str_replace('\\', '/', $sLink), '/');
+				// test if valid accessfile is available
+					if(is_readable($oReg->AppPath.$oReg->PagesDir.$sLink.$oReg->PageExtension))
 					{
-						$aTmp = explode('=', $sArgument);
-						$aReplaceList[$sKeyString]['Args'][$aTmp[0]] = $aTmp[1];
+					// create absolute URL
+						$aReplaceList[$sKey] = $oReg->AppUrl.$oReg->PagesDir.$sLink.$oReg->PageExtension.$aTag['ancor'];
 					}
 				}
-			}
-			if(sizeof($aReplaceList) > 0)
-			{ // iterate list if replacements are available
-				foreach($aReplaceList as $sKey => $aReplacement)
+		// handle links of modules
+			} else { 
+			// build name of the needed class
+				$sClass = 'm_'.$aTag['params']['addon'].'_WbLink';
+			// remove addon name from replacement array
+//				unset($aReplacement['Args']['addon']);
+				if(class_exists($sClass))
 				{
-				// set link on failure ('#' means, still stay on current page)
-					$aReplaceList[$sKey] = '#';
-				// handle normal pages links
-					if(!isset($aReplacement['Args'])) 
+				// instantiate class
+					$oWbLink = new $sClass();
+				// the class must implement the interface
+					if($oWbLink instanceof WbLinkAbstract)
 					{
-					// read corresponding link from table 'pages'
-						$sql = 'SELECT `link` FROM `'.$oDb->TablePrefix.'pages` WHERE `page_id` = '.(int)$aReplacement['PageId'];
-						if(($sLink = $oDb->get_one($sql)))
-						{
-							$sLink = trim(str_replace('\\', '/', $sLink), '/');
-						// test if valid accessfile is available
-							if(is_readable($oReg->AppPath.$oReg->PagesDir.$sLink.$oReg->PageExtension))
-							{
-							// create absolute URL
-								$aReplaceList[$sKey] = $oReg->AppUrl.$oReg->PagesDir.$sLink.$oReg->PageExtension;
-							}
-						}
-					// handle links of modules
-					}else 
-					{
-					// build name of the needed class
-						$sClass = 'm_'.$aReplacement['Args']['addon'].'_WbLink';
-					// remove addon name from replacement array
-						unset($aReplacement['Args']['addon']);
-						if(class_exists($sClass))
-						{
-						// instantiate class
-							$oWbLink = new $sClass();
-						// the class must implement the interface
-							if($oWbLink instanceof WbLinkAbstract)
-							{
-							// create real link from replacement data
-								$aReplaceList[$sKey] = $oWbLink->makeLinkFromTag($aReplacement['Args']);
-							}
-						}
+						$aTag['params']['pageid'] = $aTag['pageid'];
+						$aTag['params']['ancor']  = $aTag['ancor'];
+					// create real link from replacement data
+						$aReplaceList[$sKey] = $oWbLink->makeLinkFromTag($aTag['params']);
 					}
 				}
-			// extract indexes into a new array
-				$aSearchList = array_keys($aReplaceList);
-			// replace all identified wblink-tags in content
-				$sContent = str_replace($aSearchList, $aReplaceList, $sContent);
 			}
+		// extract indexes into a new array
+			$aSearchList = array_keys($aReplaceList);
+		// replace all identified wblink-tags in content
+			$sContent = str_replace($aSearchList, $aReplaceList, $sContent);
 		}
 		return $sContent;
 	}
+
+
+//		$oDb  = WbDatabase::getInstance();
+//		$oReg = WbAdaptor::getInstance();
+//		$aReplaceList = array();
+//		$sPattern = '/\[wblink([0-9]+)\??([^\]]*)\]/is';
+//		if(preg_match_all($sPattern,$sContent,$aMatches))
+//		{
+//		// iterate through all found matches
+//			foreach($aMatches[0] as $iKey => $sKeyString )
+//			{
+//				$aReplaceList[$sKeyString] = array();
+//			// use original Tag to save PageId
+//				$aReplaceList[$sKeyString]['PageId'] = $aMatches[1][$iKey];
+//			// if there are additional arguments given
+//				if($aMatches[2][$iKey])
+//				{
+//					$aReplaceList[$sKeyString]['Args'] = array();
+//					$aArgs = preg_split('/&amp;|&/i', $aMatches[2][$iKey], -1, PREG_SPLIT_NO_EMPTY);
+//					foreach($aArgs as $sArgument)
+//					{
+//						$aTmp = explode('=', $sArgument);
+//						$aReplaceList[$sKeyString]['Args'][$aTmp[0]] = $aTmp[1];
+//					}
+//				}
+//			}
+//			if(sizeof($aReplaceList) > 0)
+//			{ // iterate list if replacements are available
+//				foreach($aReplaceList as $sKey => $aReplacement)
+//				{
+//				// set link on failure ('#' means, still stay on current page)
+//					$aReplaceList[$sKey] = '#';
+//				// handle normal pages links
+//					if(!isset($aReplacement['Args']))
+//					{
+//					// read corresponding link from table 'pages'
+//						$sql = 'SELECT `link` FROM `'.$oDb->TablePrefix.'pages` WHERE `page_id` = '.(int)$aReplacement['PageId'];
+//						if(($sLink = $oDb->get_one($sql)))
+//						{
+//							$sLink = trim(str_replace('\\', '/', $sLink), '/');
+//						// test if valid accessfile is available
+//							if(is_readable($oReg->AppPath.$oReg->PagesDir.$sLink.$oReg->PageExtension))
+//							{
+//							// create absolute URL
+//								$aReplaceList[$sKey] = $oReg->AppUrl.$oReg->PagesDir.$sLink.$oReg->PageExtension;
+//							}
+//						}
+//					// handle links of modules
+//					}else
+//					{
+//					// build name of the needed class
+//						$sClass = 'm_'.$aReplacement['Args']['addon'].'_WbLink';
+//					// remove addon name from replacement array
+//						unset($aReplacement['Args']['addon']);
+//						if(class_exists($sClass))
+//						{
+//						// instantiate class
+//							$oWbLink = new $sClass();
+//						// the class must implement the interface
+//							if($oWbLink instanceof WbLinkAbstract)
+//							{
+//							// create real link from replacement data
+//								$aReplaceList[$sKey] = $oWbLink->makeLinkFromTag($aReplacement['Args']);
+//							}
+//						}
+//					}
+//				}
+//			// extract indexes into a new array
+//				$aSearchList = array_keys($aReplaceList);
+//			// replace all identified wblink-tags in content
+//				$sContent = str_replace($aSearchList, $aReplaceList, $sContent);
+//			}
+//		}
+//		return $sContent;
+//	}
Index: branches/2.8.x/wb/modules/news/WbLink.php
===================================================================
--- branches/2.8.x/wb/modules/news/WbLink.php	(revision 2025)
+++ branches/2.8.x/wb/modules/news/WbLink.php	(revision 2026)
@@ -30,7 +30,7 @@
  * @link         $HeadURL: $
  * @lastmodified $Date: $
  * @since        File available since 04.11.2013
- * @description  This class implements an interface for the wblink-outputfilter
+ * @description  This class implements an interface for i.e. the wblink-outputfilter
  *
  * @inherited WbDatabase $oDb
  * @inherited WbAdaptor  $oReg
@@ -39,49 +39,75 @@
 
 class m_news_WbLink extends WbLinkAbstract
 {
+/* *** BEGIN define the environment of your addon! ************************************ */
+/* (this section is a MUST and it MUST have all 8 consts defined!!)                     */
 /**
+ * name of the needed table
+ * @description do NOT use the TablePrefix in this name!
+ */
+	const TABLE_NAME           = 'mod_news_posts';
+
+/**
+ * name of the field with the PageId
+ */
+	const FIELDNAME_PAGE_ID    = 'page_id';
+
+/**
+ * name of the field with the SectionId
+ */
+	const FIELDNAME_SECTION_ID = 'section_id';
+
+/**
+ * name of the field with the ItemId
+ */
+	const FIELDNAME_ITEM_ID    = 'post_id';
+
+/**
+ * name of the field with the needed link
+ */
+	const FIELDNAME_LINK       = 'link';
+
+/**
+ * name of the field with the needed title
+ */
+	const FIELDNAME_TITLE      = 'title';
+
+/**
+ * name of the field with the timestamp
+ * @description define an empty string if no 'timestamp'-field is available or it's not needed!
+ */
+	const FIELDNAME_TIMESTAMP  = 'created_when';
+
+/** name of the field with the active-flag
+ * @description define an empty string if no 'active'-field is available or it's not needed!
+ */
+	const FIELDNAME_ACTIVE     = 'active';
+/* *** END define the environment of your addon! ************************************** */
+
+/**
  * makeLinkFromTag
  * @param type $aReplacement
  * @return string
- * @description
+ * @description this method is used by the output filter
  */
 	public function makeLinkFromTag(array $aReplacement)
 	{
-	// set link on failure ('#' means, still stay on current page)
-		$sRetval = '#';
-	// search `link` from posts table and create absolute URL
-		$sql = 'SELECT `link` '
-			 . 'FROM `'.$this->oDb->TablePrefix.'mod_news_posts` '
-			 . 'WHERE `post_id`='.$aReplacement['item'];
-		if(($sLink = $this->oDb->get_one($sql)))
-		{
-			$sLink = trim(str_replace('\\', '/', $sLink), '/');
-		// test if valid accessfile is available
-			if(is_readable($this->oReg->AppPath.$this->oReg->PagesDir.$sLink.$this->oReg->PageExtension))
-			{
-				$sRetval = $this->oReg->AppUrl.$this->oReg->PagesDir.$sLink.$this->oReg->PageExtension;
-			}
-		}
-		return $sRetval;
+/* *** Define here the full path where your links are based on! *********************** */
+
+		$sBaseDir = $this->oReg->AppPath.$this->oReg->PagesDir;
+
+/* *** Do NOT change the following request! ******************************************* */
+		$sBaseDir = rtrim(str_replace('\\', '/', $sBaseDir), '/').'/';
+		return $this->_makeLinkFromTag($sBaseDir, $aReplacement);
 	}
 /**
  * generateOptionsList
- * @param  string $sObjectName name of the array to create (default: 'AddonItemsSelectBox')
- * @return &array complete definition of a SelectBox
- * @description Bild a mulitdimensional Array with complete Option definitions for use in a Select Box
+ * @return &array definition of a SelectBox
+ * @description build a mulitdimensional Array with complete Option definitions for use in a Select Box
  */
 	public function &generateOptionsList()
 	{
-		$aAddonItems =& $this->_executeListGeneration(
-	                                           'news',
-	                                           'mod_news_posts',
-	                                           'page_id',
-	                                           'section_id',
-	                                           'post_id',
-	                                           'created_when',
-	                                           'title',
-	                                           'active'
-	                                          );
+		$aAddonItems =& $this->_executeListGeneration();
 		return $aAddonItems;
 	}
 } // end of class m_news_WbLink
