Index: /taggingreloaded/files/lib/system/event/listener/TaggingReloadedMessageFormListener.class.php
===================================================================
--- /taggingreloaded/files/lib/system/event/listener/TaggingReloadedMessageFormListener.class.php (revision 1079)
+++ /taggingreloaded/files/lib/system/event/listener/TaggingReloadedMessageFormListener.class.php (revision 1091)
@@ -2,6 +2,4 @@
 // wcf imports
 require_once(WCF_DIR.'lib/system/event/EventListener.class.php');
-require_once(WCF_DIR.'lib/data/tag/Tag.class.php');
-require_once(WCF_DIR.'lib/data/tag/TagEngine.class.php');
 
 // tagging3 imports
@@ -65,48 +63,5 @@
          */
 	protected function readFormParameters() {
-	
-		// handle reloaded input
-		if (isset($_REQUEST['taggingname']) && isset($_REQUEST['taggingval'])) {
-			if(count($_REQUEST['taggingname']) > count($_REQUEST['taggingval'])) {
-				$_REQUEST['taggingval'] = array_slice($_REQUEST['taggingval'], 0, count($_REQUEST['taggingname']));
-			} else if(count($_REQUEST['taggingname']) < count($_REQUEST['taggingval'])) {
-				$_REQUEST['taggingname'] = array_slice($_REQUEST['taggingname'], 0, count($_REQUEST['taggingval']));
-			}
-			$this->tags3 = array_combine($_REQUEST['taggingname'], $_REQUEST['taggingval']);
-		}
-
-		// handle classic input
-		if (!isset($_REQUEST['wheeltags_enabled']) || !($_REQUEST['wheeltags_enabled'])) {
-			// copy reference
-			$tags3 = $this->tags3;
-			$this->tags3 = array();
-			
-			// proceed with classic
-			if (isset($_REQUEST['tags']) && !empty($_REQUEST['tags'])) {
-				foreach(TaggingUtil::splitString($_REQUEST['tags']) as $tag) {
-					// use weights from modern input (even if hidden)
-					if(array_key_exists($tag, $tags3)) {
-						$this->tags3[$tag] = $tags3[$tag];
-					} else if(array_key_exists($tag, $this->tags3)) {
-						$this->tags3[$tag] *= 1.33; // increase with 33%
-					} else {
-						$this->tags3[$tag] = 100;
-					}
-				}
-			}
-		}
-		
-		// conversion from post to Tag
-		foreach($this->tags3 as $name => $weight) {
-			if(strlen($name) < 3) {
-				unset($this->tags3[$name]);
-				continue;
-			}
-
-			$this->tags3[$name] = new Tag(null, array(
-				'name' => $name,
-				'weight' => $weight
-			));
-		}
+		$this->tags3 = TaggingReloadedUtil::readFormParameters();
 		
 		// workaround to be called before validate from woltlab
@@ -122,115 +77,9 @@
 	}
 	
-	public function deleteFromTagging3($userID, $tags, Tagged $object, $languageIDArray) {
-		if(!count($tags)) return;
-		
-		$ids = array();
-		foreach($tags as $tag) {
-			$ids[] = $tag->tagID;
-		}
-		
-		$sql = "DELETE FROM 	wcf".WCF_N."_tagging3
-			WHERE 		taggableID = ".$object->getTaggable()->getTaggableID()."
-					AND languageID IN (".implode(',', $languageIDArray).")
-					AND objectID = ".$object->getObjectID()."
-					AND tagID IN (".implode(",", $ids).")
-					AND userID = ".intval($userID);
-		WCF::getDB()->sendQuery($sql);
-		$result = WCF::getDB()->sendQuery($sql);
-	}
-	
-	/**
-	 * this is a reimplemenation of TagEngine::deleteObjectTags with a slite modification.
-	 * not all tags are deleted. just some tagIDs
-	 */
-	public function deleteFromSystem($tags, Tagged $object, $languageIDArray) {
-		if(!count($tags)) return;
-		
-		$ids = array();
-		foreach($tags as $tag) {
-			$ids[] = $tag->tagID;
-		}
-		
-		$sql = "DELETE FROM 	wcf".WCF_N."_tag_to_object
-			WHERE 		taggableID = ".$object->getTaggable()->getTaggableID()."
-					AND languageID IN (".implode(',', $languageIDArray).")
-					AND objectID = ".$object->getObjectID()."
-					AND tagID IN (".implode(",", $ids).")";
-		WCF::getDB()->sendQuery($sql);
-		$result = WCF::getDB()->sendQuery($sql);
-	}
-	
-	public function addToSystem($tags, Tagged $object, $languageID) {
-		if(!count($tags)) return;
-		
-		$tags = array_keys($tags);
-		try {
-			TagEngine::getInstance()->addTags($tags, $object, $languageID);
-		} catch(Exception $e) {
-			// please handle
-		}
-	}
-	
-	/**
-	 * this is a reimplementation of TagEngine::addTags with a slite modification to write to our table and to update existing tables with weight
-	 */
-	public function addToTagging3($userID, $tags, Tagged $object, $languageID) {
-		if(!count($tags)) return;
-		
-		// store tagging3 database
-		$tagIDs = array();
-		foreach ($tags as $tag) {
-			$tagID = $tag->tagID ? $tag->tagID : Tag::test($tag->name, $languageID);
-			if (!$tagID) $tagID = Tag::insert($tag->name, $languageID);
-			
-			if (empty($tag->userID)) $tag->userID = $userID;
-			$tagIDs[$tagID] = $tag;
-		}
-		
-		$sql = "REPLACE INTO	wcf".WCF_N."_tagging3
-					(objectID, tagID, taggableID, languageID, userID, weight)
-			VALUES ";
-		foreach ($tagIDs as $tagID => $tag) {
-			$sql .= "(" . $object->getObjectID() . ", " . $tagID . ", " . $object->getTaggable()->getTaggableID() . ", 
-				".$languageID.", ".$tag->userID.", ".$tag->weight."),";
-		}
-		$sql = StringUtil::substring($sql, 0, StringUtil::length($sql) - 1);
-		$result = WCF::getDB()->sendQuery($sql);
-	}
-	
 	/**
 	 * save
 	 */
 	protected function tagging3Save($userID, $tagged, $languageID) {
-		$languageIDArray = array($languageID);
-		
-		// remove old links
-		if(count($this->existingTagsUser) || count($this->existingTagsObject)) {
-		
-			// tagging3: remove the link to the current user
-			$deleteFromTagging3 = TaggingReloadedUtil::diff($this->existingTagsUser, $this->tags3);
-		
-			// woltlab system: when no other user has this tag, remove the link from tag to object
-			$deleteFromSystem = TaggingReloadedUtil::diff($deleteFromTagging3, $this->existingTagsObject);
-			
-			// tagging3: ids are known.. delete is easy
-			$this->deleteFromTagging3($userID, $deleteFromTagging3, $tagged, $languageIDArray);
-			
-			// woltlab system: ids are known.. delete is easy
-			$this->deleteFromSystem($deleteFromSystem, $tagged, $languageIDArray);
-		}
-		
-		// tagging3: add user specific tags
-		$addToTagging3 = TaggingReloadedUtil::diff($this->tags3, $this->existingTagsUser);
-		
-		// woltlab system: add link from tag to object
-		$addToSystem = TaggingReloadedUtil::diff($addToTagging3, $this->existingTagsObject);
-		
-		// woltlab system: save
-		$this->addToSystem($addToSystem, $tagged, $languageID);
-		
-		// tagging3: save
-		// attention: use $this->tags3 instead of the diff, because we want to update all weights
-		$this->addToTagging3($userID, $this->tags3, $tagged, $languageID);
+		return TaggingReloadedUtil::tagging3Save($userID, $tagged, $languageID, $this->tags3, $this->existingTagsUser, $this->existingTagsObject);
 	}
 	
@@ -248,29 +97,5 @@
 	 */
 	protected function getTagsByObject($userID, Tagged $tagged, $languageID, $even = true) {
-		$taggableID = $tagged->getTaggable()->getTaggableID();
-		$objectID = $tagged->getObjectID();
-		$sign = $even ? '=' : '!=';
-	
-		$sql = "SELECT		tag.*,
-					userID,
-					weight
-			FROM (
-				SELECT		tagID,
-						userID,
-						weight
-				FROM		wcf".WCF_N."_tagging3
-				WHERE		taggableID = ".intval($taggableID)."
-				AND		languageID = ".intval($languageID)."
-				AND		objectID = ".intval($objectID)."
-				AND 		userID $sign ".intval($userID)."
-			) x
-			INNER JOIN	wcf".WCF_N."_tag tag USING(tagID)
-			";
-		$result = WCF::getDB()->sendQuery($sql);
-		$tags = array();
-		while ($row = WCF::getDB()->fetchArray($result)) {
-			$tags[$row['name']] = new Tag(null, $row);
-		}
-		return $tags;
+		return TaggingReloadedUtil::getTagsByObject($userID, $tagged, $languageID, $even);
 	}
 }
Index: /taggingreloaded/files/lib/action/TaggingReloadedSaveAction.class.php
===================================================================
--- /taggingreloaded/files/lib/action/TaggingReloadedSaveAction.class.php (revision 1087)
+++ /taggingreloaded/files/lib/action/TaggingReloadedSaveAction.class.php (revision 1091)
@@ -12,8 +12,9 @@
  */
 class TaggingReloadedSaveAction extends AbstractAction {
-	protected $taggableID = 0;
+	protected $taggable = '';
 	protected $className = '';
+	protected $classPath = '';
 	protected $entryKey = 'entryID';
-	protected $entryID = 0;
+	protected $objectID = 0;
 	protected $languageID = 0;
 
@@ -24,10 +25,13 @@
 		parent::readParameters();
 		
-		$this->taggableID = intval($_REQUEST['taggableID']);
 		$this->className = $_REQUEST['className'];
-		$this->entryID = intval($_REQUEST['entryID']);
+		$this->classPath = $_REQUEST['classPath'];
+		$this->objectID = intval($_REQUEST['objectID']);
 		
-		if(isset($_REQUEST['entryKey']) $this->entryKey = $_REQUEST['entryKey'];
-		if(isset($_REQUEST['languageID']) $this->languageID = intval($_REQUEST['languageID']);
+		if(isset($_REQUEST['entryKey'])) $this->entryKey = $_REQUEST['entryKey'];
+		if(isset($_REQUEST['languageID'])) $this->languageID = intval($_REQUEST['languageID']);
+		if(isset($_REQUEST['taggable'])) $this->taggable = $_REQUEST['taggable'];
+		
+		$this->tags3 = TaggingReloadedUtil::readFormParameters();
 	}
 	
@@ -38,6 +42,18 @@
 		parent::execute();
 		
-		$tagged = new $this->className(array(
-			$this->entryKey => $this->entryID,
+		if(!preg_match('/^Tagged/', $this->className) || preg_match('/\./', $this->className)) {
+			throw new PermissionDeniedException();
+		}
+		
+		$classPath = WCF_DIR.'lib/data/'.$this->classPath.'/'.$this->className.'.class.php';
+		
+		if(preg_match('/\./', $this->classPath) || !file_exists($classPath)) {
+			throw new PermissionDeniedException();
+		}
+		
+		require_once $classPath;
+		
+		$tagged = new $this->className(null, array(
+			$this->entryKey => $this->objectID,
 			'taggable' => TagEngine::getInstance()->getTaggable($this->taggable)
 		));
@@ -47,5 +63,9 @@
 		}
 		
-		TaggingUtil::save($userid. $tags, $tagged, $this->languageID);
+		$userID = WCF::getUser()->userID;
+		
+		$existingTagsUser = TaggingReloadedUtil::getTagsByObject($userID, $tagged, $this->languageID, true);
+		$existingTagsObject = TaggingReloadedUtil::getTagsByObject($userID, $tagged, $this->languageID, false);
+		TaggingReloadedUtil::tagging3save($userID, $tagged, $this->languageID, $this->tags3, $existingTagsUser, $existingTagsObject);
 		
 		$this->executed();
Index: /taggingreloaded/files/lib/util/TaggingReloadedUtil.class.php
===================================================================
--- /taggingreloaded/files/lib/util/TaggingReloadedUtil.class.php (revision 1080)
+++ /taggingreloaded/files/lib/util/TaggingReloadedUtil.class.php (revision 1091)
@@ -3,4 +3,7 @@
 require_once(WCF_DIR.'/lib/util/ArrayUtil.class.php');
 require_once(WCF_DIR.'/lib/util/StringUtil.class.php');
+require_once(WCF_DIR.'lib/data/tag/Tag.class.php');
+require_once(WCF_DIR.'lib/data/tag/TagCloudWrapper.class.php');
+require_once(WCF_DIR.'lib/data/tag/TagEngine.class.php');
 
 /**
@@ -12,4 +15,199 @@
  */
 class TaggingReloadedUtil {
+	public static function readFormParameters() {
+		$tags3 = array();
+
+		// handle reloaded input
+		if (isset($_REQUEST['taggingname']) && isset($_REQUEST['taggingval'])) {
+			if(count($_REQUEST['taggingname']) > count($_REQUEST['taggingval'])) {
+				$_REQUEST['taggingval'] = array_slice($_REQUEST['taggingval'], 0, count($_REQUEST['taggingname']));
+			} else if(count($_REQUEST['taggingname']) < count($_REQUEST['taggingval'])) {
+				$_REQUEST['taggingname'] = array_slice($_REQUEST['taggingname'], 0, count($_REQUEST['taggingval']));
+			}
+			$tags3 = array_combine($_REQUEST['taggingname'], $_REQUEST['taggingval']);
+		}
+
+		// handle classic input
+		if (!isset($_REQUEST['wheeltags_enabled']) || !($_REQUEST['wheeltags_enabled'])) {
+			// copy reference
+			$tags = $tags3;
+			$tags3 = array();
+			
+			// proceed with classic
+			if (isset($_REQUEST['tags']) && !empty($_REQUEST['tags'])) {
+				foreach(TaggingUtil::splitString($_REQUEST['tags']) as $tag) {
+					// use weights from modern input (even if hidden)
+					if(array_key_exists($tag, $tags)) {
+						$tags3[$tag] = $tags[$tag];
+					} else if(array_key_exists($tag, $tags3)) {
+						$tags3[$tag] *= 1.33; // increase with 33%
+					} else {
+						$tags3[$tag] = 100;
+					}
+				}
+			}
+		}
+		
+		// conversion from post to Tag
+		foreach($tags3 as $name => $weight) {
+			if(strlen($name) < 3) {
+				unset($tags3[$name]);
+				continue;
+			}
+
+			$tags3[$name] = new Tag(null, array(
+				'name' => $name,
+				'weight' => $weight
+			));
+		}
+		
+		return $tags3;
+	}
+	
+	protected static function deleteFromTagging3($userID, $tags, Tagged $object, $languageIDArray) {
+		if(!count($tags)) return;
+		
+		$ids = array();
+		foreach($tags as $tag) {
+			$ids[] = $tag->tagID;
+		}
+		
+		$sql = "DELETE FROM 	wcf".WCF_N."_tagging3
+			WHERE 		taggableID = ".$object->getTaggable()->getTaggableID()."
+					AND languageID IN (".implode(',', $languageIDArray).")
+					AND objectID = ".$object->getObjectID()."
+					AND tagID IN (".implode(",", $ids).")
+					AND userID = ".intval($userID);
+		WCF::getDB()->sendQuery($sql);
+		$result = WCF::getDB()->sendQuery($sql);
+	}
+	
+	/**
+	 * this is a reimplemenation of TagEngine::deleteObjectTags with a slite modification.
+	 * not all tags are deleted. just some tagIDs
+	 */
+	protected static function deleteFromSystem($tags, Tagged $object, $languageIDArray) {
+		if(!count($tags)) return;
+		
+		$ids = array();
+		foreach($tags as $tag) {
+			$ids[] = $tag->tagID;
+		}
+		
+		$sql = "DELETE FROM 	wcf".WCF_N."_tag_to_object
+			WHERE 		taggableID = ".$object->getTaggable()->getTaggableID()."
+					AND languageID IN (".implode(',', $languageIDArray).")
+					AND objectID = ".$object->getObjectID()."
+					AND tagID IN (".implode(",", $ids).")";
+		WCF::getDB()->sendQuery($sql);
+		$result = WCF::getDB()->sendQuery($sql);
+	}
+	
+	protected static function addToSystem($tags, Tagged $object, $languageID) {
+		if(!count($tags)) return;
+		
+		$tags = array_keys($tags);
+		try {
+			TagEngine::getInstance()->addTags($tags, $object, $languageID);
+		} catch(Exception $e) {
+			// please handle
+		}
+	}
+	
+	/**
+	 * this is a reimplementation of TagEngine::addTags with a slite modification to write to our table and to update existing tables with weight
+	 */
+	protected static function addToTagging3($userID, $tags, Tagged $object, $languageID) {
+		if(!count($tags)) return;
+		
+		// store tagging3 database
+		$tagIDs = array();
+		foreach ($tags as $tag) {
+			$tagID = $tag->tagID ? $tag->tagID : Tag::test($tag->name, $languageID);
+			if (!$tagID) $tagID = Tag::insert($tag->name, $languageID);
+			
+			if (empty($tag->userID)) $tag->userID = $userID;
+			$tagIDs[$tagID] = $tag;
+		}
+		
+		$sql = "REPLACE INTO	wcf".WCF_N."_tagging3
+					(objectID, tagID, taggableID, languageID, userID, weight)
+			VALUES ";
+		foreach ($tagIDs as $tagID => $tag) {
+			$sql .= "(" . $object->getObjectID() . ", " . $tagID . ", " . $object->getTaggable()->getTaggableID() . ", 
+				".$languageID.", ".$tag->userID.", ".$tag->weight."),";
+		}
+		$sql = StringUtil::substring($sql, 0, StringUtil::length($sql) - 1);
+		$result = WCF::getDB()->sendQuery($sql);
+	}
+	
+	/**
+	 * save
+	 */
+	public static function tagging3Save($userID, $tagged, $languageID, array $tags3, array $existingTagsUser = array(), array $existingTagsObject = array()) {
+		$languageIDArray = array($languageID);
+		
+		// remove old links
+		if(count($existingTagsUser) || count($existingTagsObject)) {
+		
+			// tagging3: remove the link to the current user
+			$deleteFromTagging3 = TaggingReloadedUtil::diff($existingTagsUser, $tags3);
+		
+			// woltlab system: when no other user has this tag, remove the link from tag to object
+			$deleteFromSystem = TaggingReloadedUtil::diff($deleteFromTagging3, $existingTagsObject);
+			
+			// tagging3: ids are known.. delete is easy
+			self::deleteFromTagging3($userID, $deleteFromTagging3, $tagged, $languageIDArray);
+			
+			// woltlab system: ids are known.. delete is easy
+			self::deleteFromSystem($deleteFromSystem, $tagged, $languageIDArray);
+		}
+		
+		// tagging3: add user specific tags
+		$addToTagging3 = TaggingReloadedUtil::diff($tags3, $existingTagsUser);
+		
+		// woltlab system: add link from tag to object
+		$addToSystem = TaggingReloadedUtil::diff($addToTagging3, $existingTagsObject);
+		
+		// woltlab system: save
+		self::addToSystem($addToSystem, $tagged, $languageID);
+		
+		// tagging3: save
+		// attention: use $tags3 instead of the diff, because we want to update all weights
+		self::addToTagging3($userID, $tags3, $tagged, $languageID);
+	}
+
+	/**
+	 * @return Tag[]
+	 */
+	public static function getTagsByObject($userID, Tagged $tagged, $languageID, $even = true) {
+		$taggableID = $tagged->getTaggable()->getTaggableID();
+		$objectID = $tagged->getObjectID();
+		
+		$sign = $even ? '=' : '!=';
+		$signline = $even === null ? '' : "AND userID $sign ".intval($userID);
+	
+		$sql = "SELECT		tag.*,
+					userID,
+					weight
+			FROM (
+				SELECT		tagID,
+						userID,
+						weight
+				FROM		wcf".WCF_N."_tagging3
+				WHERE		taggableID = ".intval($taggableID)."
+				AND		languageID = ".intval($languageID)."
+				AND		objectID = ".intval($objectID)."
+				".$signline."
+			) x
+			INNER JOIN	wcf".WCF_N."_tag tag USING(tagID)
+			";
+		$result = WCF::getDB()->sendQuery($sql);
+		$tags = array();
+		while ($row = WCF::getDB()->fetchArray($result)) {
+			$tags[$row['name']] = new Tag(null, $row);
+		}
+		return $tags;
+	}
 
 	/**
Index: /taggingreloaded/optionals/de.easy-coding.wbb.taggingreloaded/files/lib/system/event/listener/TaggingReloadedWBBPageListener.class.php
===================================================================
--- /taggingreloaded/optionals/de.easy-coding.wbb.taggingreloaded/files/lib/system/event/listener/TaggingReloadedWBBPageListener.class.php (revision 1078)
+++ /taggingreloaded/optionals/de.easy-coding.wbb.taggingreloaded/files/lib/system/event/listener/TaggingReloadedWBBPageListener.class.php (revision 1091)
@@ -41,4 +41,5 @@
 			INNER JOIN	wcf".WCF_N."_tag tag USING(tagID)
 			LIMIT		".intval($limit);
+			echo $sql;
 		return $sql;
 	}
Index: /taggingreloaded/templates/taggingReloadedSidebar.tpl
===================================================================
--- /taggingreloaded/templates/taggingReloadedSidebar.tpl (revision 1087)
+++ /taggingreloaded/templates/taggingReloadedSidebar.tpl (revision 1091)
@@ -5,5 +5,7 @@
 		<input type="hidden" name="taggable" value="{$taggable}" />
 		<input type="hidden" name="languageID" value="{$languageID}" />
-		<input type="hidden" name="entryID" value="{$entry->entryID}" />
+		<input type="hidden" name="objectID" value="{$objectID}" />
+		<input type="hidden" name="className" value="{$className}" />
+		<input type="hidden" name="classPath" value="{$classPath}" />
 		<div class="containerHead"> 
 			<h3>{lang}wcf.taggingreloaded.tags{/lang}</h3> 
@@ -15,5 +17,5 @@
 			</div>
 			<div class="containerContent">
-				<input type="text" id="tags" name="tags" size="45" style="margin-right:10px" />
+				<input type="text" id="tags" name="tags" value="{$tags}" size="45" style="margin-right:10px" />
 				<input type="button" value="{lang}Tags bearbeiten{/lang}" onclick="return taggingReloadedToggle(this)" />
 			</div>
