• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn more.

History v1.0

AndyB

Well-known member
#1
Purpose:

The purpose of this thread is to provide additional information on the History v1.0 add-on.

To download and install this add-on please visit the following XenForo Resource:

http://xenforo.com/community/resources/history.2653/

Description:

This add-on will allow members to quickly return to previously viewed threads.

Features:
  • Shows a list of last viewed threads
  • Highlights threads with new posts
  • Places History link in navigation bar for easy access
  • Fully phrased
(Example of History link)

pic001.jpg

(Example of History page)

pic002.jpg
 

AndyB

Well-known member
#2
The directory structure with the core files highlighted.

library
--Andy
----History
------ControllerPublic
--------Thread.php
----Install.php
----Listener.php
----Model.php
----Uninstall.php
 

AndyB

Well-known member
#4
library/Andy/History/ControllerPublic/Thread.php

PHP:
<?php

class Andy_History_ControllerPublic_Thread extends XFCP_Andy_History_ControllerPublic_Thread
{
	public function actionIndex()
	{
		// get parent
		$parent = parent::actionIndex();
		
		//########################################
		// update xf_history table
		//########################################

		// get $userId
		$userId = XenForo_Visitor::getUserId();
		
		// continue if member is logged in
		if ($userId > 0)
		{
			// get database
			$db = XenForo_Application::get('db');
			
			// get $threadId
			$threadId = $this->_input->filterSingle('thread_id', XenForo_Input::UINT);	
			
			// define $dateline
			$dateline = time();
			
			// insert row into xf_history
			$db->query("
				INSERT INTO xf_history
					(user_id, thread_id, thread_read_date)
				VALUES
					(?, ?, ?)
				ON DUPLICATE KEY UPDATE
					thread_read_date = VALUES(thread_read_date)
			", array($userId, $threadId, $dateline));
		}

		// return parent
		return $parent;
	}		
			
	public function actionHistory()
	{
		//########################################
		// display History page
		//########################################
				
		// get $userId
		$userId = XenForo_Visitor::getUserId();
		
		// throw error if no $userId
		if (!$userId){
			throw $this->getNoPermissionResponseException();
		}		
		
		// get $threads data from model
		$threads = $this->getModelFromCache('Andy_History_Model')->getHistoryThreads($userId);
		
		// prepare $viewParams for template
		$viewParams = array(
			'threads' => $threads,
		);		
		
		// send to template for display
		return $this->responseView('Andy_History_ViewPublic_History', 'andy_history', $viewParams);
	}
}

?>
 

AndyB

Well-known member
#5
library/Andy/History/Install.php

PHP:
<?php

class Andy_History_Install
{
    public static function install()
    {
        $db = XenForo_Application::get('db');		
		
		try
		{	
			$db->query("
				CREATE TABLE xf_history (
				user_id INT( 10 ) UNSIGNED NOT NULL , 
				thread_id INT( 10 ) UNSIGNED NOT NULL , 
				thread_read_date INT( 10 ) UNSIGNED NOT NULL
				) ENGINE = InnoDB
			");
		}
		catch (Zend_Db_Exception $e) {}
		
		try
		{	
			$db->query("
				ALTER TABLE xf_history ADD UNIQUE user_id_thread_id ( user_id , thread_id ) 
			");		
		}
		catch (Zend_Db_Exception $e) {}
    }
}

?>
 

AndyB

Well-known member
#6
library/Andy/History/Listener.php

PHP:
<?php

class Andy_History_Listener
{
	public static function Thread($class, array &$extend)
	{
		$extend[] = 'Andy_History_ControllerPublic_Thread';
	}	
}

?>
 

AndyB

Well-known member
#7
library/Andy/History/Model.php

PHP:
<?php

class Andy_History_Model extends XenForo_Model
{
	public function getHistoryThreads($userId)
	{		
		return $this->_getDb()->fetchAll('
		SELECT xf_history.thread_id, 
		xf_history.thread_read_date AS history_read_date, 
		xf_thread.title, 
		xf_thread.reply_count, 
		xf_thread.view_count, 
		xf_thread.last_post_username, 
		xf_thread.last_post_date, 
		xf_node.title AS nodeTitle, 
		xf_thread_user_post.post_count AS user_post_count, 
		xf_user.user_id, xf_user.avatar_date
		FROM xf_history
		INNER JOIN xf_thread ON xf_thread.thread_id = xf_history.thread_id
		INNER JOIN xf_node ON xf_node.node_id = xf_thread.node_id
        LEFT JOIN xf_thread_user_post AS xf_thread_user_post
            ON (xf_thread_user_post.thread_id = xf_thread.thread_id
            AND xf_thread_user_post.user_id = ' . $userId . ')			
		INNER JOIN xf_user ON xf_user.user_id = xf_thread.user_id
		WHERE xf_history.user_id = ' . $userId . '
		ORDER BY xf_history.thread_read_date DESC 
		LIMIT 50');
	}		
}

?>
 

AndyB

Well-known member
#8
library/Andy/History/Uninstall.php

PHP:
<?php

class Andy_History_Uninstall
{
    public static function uninstall()
    {
        $db = XenForo_Application::get('db');
		
		try
		{		
			$db->query("
				DROP TABLE xf_history
			");
		}
		catch (Zend_Db_Exception $e) {}
    }
}

?>
 

AndyB

Well-known member
#10
andy_history template

Code:
<xen:require css="andy_history.css" />

{xen:phrase history_last_50_threads_you_have_visited}
<br /><br />

<table class="dataTable">

    <tr class="dataRow">
        <th width="42"></th>
        <th>{xen:phrase title}</th>
        <th>{xen:phrase replies}</th>
        <th>{xen:phrase views}</th>
        <th>{xen:phrase last_reply_from}</th>
        <th>{xen:phrase forum}</th>
    </tr>
    
    <xen:foreach loop="$threads" value="$thread">
    <tr class="dataRow">
    
        <td class="history_avatarContainer">
        <xen:avatar user="$thread" size="s" img="true" class="history_avatar"/>
        <xen:if is="{$thread.user_post_count}"><xen:avatar user="$visitor" size="s" img="true" class="history_miniMe" title="{xen:phrase you_have_posted_x_messages_in_this_thread, 'count={xen:number $thread.user_post_count}'}" /></xen:if>
        </td>
        
        <xen:if is="{$thread.last_post_date} <= {$thread.history_read_date} OR {$thread.last_post_username} == {$visitor.username}">
        <td><a href="{xen:link 'threads',  $thread}" />{$thread.title}</a></td>
        </xen:if>
        
        <xen:if is="{$thread.last_post_date} > {$thread.history_read_date} AND {$thread.last_post_username} != {$visitor.username}">
        <td class="history_title_unread"><a href="{xen:link 'threads/unread',  $thread}" />{$thread.title}</a></td>
        </xen:if>  
        
        <td>{$thread.reply_count}</td>     
        <td>{$thread.view_count}</td>
        <td>{$thread.last_post_username}</td>
        <td>{$thread.nodeTitle}</td>
    
    </tr>
    </xen:foreach>
    
</table>
 

AndyB

Well-known member
#11
andy_history.css

Code:
.dataTable a:link {
    font-size: 11pt;
}

history_avatar_th {
    width:42px;
}

.history_avatarContainer {
    display: block;
    position: relative;
    padding:5px 5px 5px 5px;
    background: url("styles/default/xenforo/gradients/category-23px-light.png") repeat-x scroll center top #F0F7FC;   
}

.history_avatar img {
    display: block;
    height: 36px;
    width: 36px;
    background-color: #ffffff;
    border: 1px solid #a5cae4;
    border-radius: 4px 4px 4px 4px;
    padding: 2px;
}

.history_miniMe img {
    max-width:20px;
    max-height:20px;
    margin: 0px 0px 1px 5px;
    position: absolute;
    border:none;
    border-radius: 0px 0px 0px 0px;
    bottom: 1px;
    left: 29px;
    padding:none;
    z-index: 10;
}

.history_miniMe img {
    border: 1px none #000000;
    border-radius: 2px;
    box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.5);
    height: 20px;
    padding: 1px;
    width: 20px;
}

.history_title_unread a:link {
    font-weight:bold;
    font-size:12pt;
}
 

Slavik

XenForo moderator
Staff member
#13
You should prefix correctly to avoid any issues with potential XenForo Core updates.

Using xf_tablename is poor practice. You should use something like andyb_history or xf_andyb_history.
 

Alfa1

Well-known member
#15
Will it be possible for staff to see the browsing history of specific members? I have such functionality on vbulletin and we use it a lot when encountering problematic members.
 

Brogan

XenForo moderator
Staff member
#17