diff --git a/plugins/ktstandard/documentpreview/documentPreview.php b/plugins/ktstandard/documentpreview/documentPreview.php
new file mode 100644
index 0000000..96911d1
--- /dev/null
+++ b/plugins/ktstandard/documentpreview/documentPreview.php
@@ -0,0 +1,299 @@
+_oDocument = false;
+ return;
+ }
+ $oDocument = Document::get($iId);
+
+ if(PEAR::isError($oDocument)){
+ $this->_oDocument = false;
+ return;
+ }
+
+ $this->_oDocument = $oDocument;
+ $this->_IDocId = $iId;
+ $this->_iMimeId = $oDocument->getMimeTypeID();
+ $this->imageMimeTypes = array(10, 27, 37, 38, 39, 71);
+ }
+
+ /**
+ * Get the document title for the preview
+ *
+ * @return string The document title and mime icon
+ */
+ function getTitle(){
+ if($this->_oDocument === false){
+ return ''._kt('Error').'';
+ }
+ GLOBAL $default;
+ $sIcon = '';
+
+ $sTitle = htmlentities($this->_oDocument->getName(), ENT_NOQUOTES, 'utf-8');
+ $iLen = strlen($sTitle);
+
+ if($iLen > 60){
+ $sFull = $sTitle;
+ if($iLen >= 99){
+ $sTitle = substr($sTitle, 0, 97).'...';
+ }
+ $sTitle = '
'.$sTitle.'
';
+ }else{
+ $sTitle = ''.$sTitle.'
';
+ }
+
+ // Get the icon
+ $sIcon = $this->getMimeIcon();
+
+ $sTitle = '
+
'.$sIcon.'
+
'.$sTitle.'
+
';
+ return $sTitle;
+ }
+
+ /**
+ * Display the mime type icon.
+ *
+ * @param unknown_type $iMimeId
+ * @return unknown
+ */
+ function getMimeIcon() {
+ global $default;
+ $iMimeId = $this->_iMimeId;
+
+ $sIconPath = $this->getIconPath();
+ $sIconPath = $default->rootUrl.$sIconPath;
+ return "
";
+ }
+
+ /**
+ * If there isn't an icon for the given extension, find a generic icon for the type else return the default icon.
+ *
+ * @param string $ext
+ * @return string
+ */
+ function checkForGeneric($ext) {
+ if(in_array($ext, array('py','php'))){
+ return 'generic/source';
+ }
+ if(in_array($ext, array('odt','sxw', 'ott', 'sxt'))){
+ return 'generic/wordprocessing';
+ }
+ if(in_array($ext, array('ods','ots', 'sxc', 'stc'))){
+ return 'spreadsheet';
+ }
+ if(in_array($ext, array('odp','otp', 'sxi', 'sti'))){
+ return 'generic/pres';
+ }
+ if(in_array($ext, array('mp3','m4a'))){
+ return 'generic/sound';
+ }
+ if(in_array($ext, array('m4v'))){
+ return 'generic/video';
+ }
+ return 'default';
+ }
+
+ /**
+ * Get the path to the correct icon for the mime type
+ *
+ * @return string
+ */
+ function getIconPath() {
+
+ $sIconPath = KTMime::getIconPath($this->_iMimeId);
+
+ // Get mime type icon
+ $sIconPath = '/resources/mimetypes/big/'.$sIconPath.'.png';
+
+ if(!file_exists(KT_DIR.$sIconPath)){
+ // See if there is an icon for the extension
+ $sMimeType = KTMime::getMimeTypeName($this->_iMimeId);
+ $aMimeInfo = KTMime::getFriendlyNameAndExtension($sMimeType);
+ if(!PEAR::isError($aMimeInfo) && !empty($aMimeInfo)){
+ $sExt = $aMimeInfo[0]['filetypes'];
+ $sIconPath = '/resources/mimetypes/big/'.$sExt.'.png';
+
+ if(!file_exists(KT_DIR.$sIconPath)){
+ $generic = $this->checkForGeneric($sExt);
+ // if all else fails, use the default icon
+ $sIconPath = '/resources/mimetypes/big/'.$generic.'.png';
+ }
+ }
+ }
+ return $sIconPath;
+ }
+
+ /**
+ * Render the info box content
+ *
+ * @return string
+ */
+ function renderPreview(){
+ if($this->_oDocument === false){
+ return ''._kt('A problem occured while loading the document preview.').'
';
+ }
+
+ $sInfo = $this->getMetadata();
+
+ return ''.$sInfo.'
';
+ }
+
+ /**
+ * Create a table of the document metadata.
+ * Hard coded for the moment
+ *
+ * @return unknown
+ */
+ function getMetadata(){
+ /* Get document info */
+
+ // Filename
+ $sFilenameLb = _kt('Document Filename: ');
+ $sFilename = $this->_oDocument->getFileName();
+
+ // Mime type
+ $sMimeTypeLb = _kt('File is a: ');
+ $iMimeId = $this->_oDocument->getMimeTypeID();
+ $sMimeType = KTMime::getMimeTypeName($iMimeId);
+ $sMimeType = KTMime::getFriendlyNameForString($sMimeType);
+
+ // Version
+ $sVersionLb = _kt('Document Version: ');
+ $iVersion = $this->_oDocument->getVersion();
+
+ // Created by
+ $sCreatedByLb = _kt('Created by: ');
+ $iCreatorId = $this->_oDocument->getCreatorID();
+ $sCreated = $this->_oDocument->getCreatedDateTime();
+ $oCreator = User::get($iCreatorId);
+ $sCreatedBy = $oCreator->getName().' ('.$sCreated.')';
+
+ // Owned by
+ $sOwnedByLb = _kt('Owned by: ');
+ $iOwnedId = $this->_oDocument->getOwnerID();
+ $oOwner = User::get($iOwnedId);
+ $sOwnedBy = $oOwner->getName();
+
+ // Last update by
+ $iModifiedId = $this->_oDocument->getModifiedUserId();
+ $sLastUpdatedByLb = ''; $sLastUpdatedBy = '';
+ if(!empty($iModifiedId)){
+ $sLastUpdatedByLb = _kt('Last updated by: ');
+ $sModified = $this->_oDocument->getLastModifiedDate();
+ $oModifier = User::get($iModifiedId);
+ $sLastUpdatedBy = $oModifier->getName().' ('.$sModified.')';
+ }
+
+ // Document type
+ $sDocTypeLb = _kt('Document Type: ');
+ $iDocTypeId = $this->_oDocument->getDocumentTypeID();
+ $oDocType = DocumentType::get($iDocTypeId);
+ $sDocType = $oDocType->getName();
+
+ // Workflow
+ $iWFId = $this->_oDocument->getWorkflowId();
+ $sWF = ''; $sWFLb = '';
+ if(!empty($iWFId)){
+ $sWFLb = _kt('Workflow: ');
+ $iWFStateId = $this->_oDocument->getWorkflowStateId();
+ $oWF = KTWorkflow::get($iWFId);
+ $sWF = $oWF->getHumanName();
+ $oWFState = KTWorkflowState::get($iWFStateId);
+ $sWF .= ' ('.$oWFState->getHumanName().')';
+ }
+
+ // Checked out by
+ $sCheckedLb = ''; $sCheckedOutBy = '';
+ if($this->_oDocument->getIsCheckedOut()){
+ $sCheckedLb = _kt('Checked out by: ');
+ $iCheckedID = $this->_oDocument->getCheckedOutUserID();
+ $oCheckedUser = User::get($iCheckedID);
+ $sCheckedOutBy = $oCheckedUser->getName();
+ }
+
+ // Id
+ $sIdLb = _kt('Document ID: ');
+ $sId = $this->_IDocId;
+
+ /* Create table */
+
+ $sInfo = "
+ | {$sFilenameLb} | {$sFilename} |
+ | {$sMimeTypeLb} | {$sMimeType} |
+ | {$sVersionLb} | {$iVersion} |
+ | {$sCreatedByLb} | {$sCreatedBy} |
+ | {$sOwnedByLb} | {$sOwnedBy} |
";
+
+ if(!empty($sLastUpdatedBy)){
+ $sInfo .= "| {$sLastUpdatedByLb} | {$sLastUpdatedBy} |
";
+ }
+ $sInfo .= "| {$sDocTypeLb} | {$sDocType} |
";
+ if(!empty($sWF)){
+ $sInfo .= "| {$sWFLb} | {$sWF} |
";
+ }
+ if(!empty($sCheckedOutBy)){
+ $sInfo .= "| {$sCheckedLb} | {$sCheckedOutBy} |
";
+ }
+
+ $sInfo .= "| {$sIdLb} | {$sId} |
+
";
+
+ return $sInfo;
+ }
+}
+
+/**
+ * Get the document id and render the preview / info box
+ */
+
+$iDocumentId = $_REQUEST['fDocumentId'];
+
+$oPreview = new DocumentPreview($iDocumentId);
+
+$sTitle = $oPreview->getTitle();
+$sContent = $oPreview->renderPreview();
+
+echo $sTitle.'
'.$sContent;
+exit;
+?>
\ No newline at end of file
diff --git a/plugins/ktstandard/documentpreview/documentPreviewPlugin.php b/plugins/ktstandard/documentpreview/documentPreviewPlugin.php
new file mode 100644
index 0000000..1cd858d
--- /dev/null
+++ b/plugins/ktstandard/documentpreview/documentPreviewPlugin.php
@@ -0,0 +1,108 @@
+label = null;
+
+ $oConfig = KTConfig::getSingleton();
+ $this->sActivation = $oConfig->get('browse/previewActivation', 'onclick');
+
+ // Get file path
+ $this->sPluginPath = 'plugins/ktstandard/documentpreview';
+ }
+
+ function renderHeader($sReturnURL) {
+ // Get the yui libraries required
+ global $main;
+
+ // Get the CSS to render the pop-up
+ $main->requireCSSResource($this->sPluginPath.'/resources/container.css');
+
+ // Get the javascript to render the document preview
+ $main->requireJSResource($this->sPluginPath.'/resources/preview.js');
+
+ return ' ';
+ }
+
+ function renderData($aDataRow) {
+ // only _ever_ show this for documents.
+ if ($aDataRow["type"] === "folder") {
+ return ' ';
+ }
+
+ $sUrl = KTUtil::kt_url().'/'.$this->sPluginPath.'/documentPreview.php';
+ $sDir = KT_DIR;
+ $iDelay = 1000; // milliseconds
+
+ $iDocumentId = $aDataRow['document']->getId();
+ $sTitle = _kt('Preview Document');
+ $sLoading = _kt('Loading...');
+
+
+ $link = 'sActivation == 'mouse-over'){
+ $sJs = "javascript: this.t = setTimeout('showInfo(\'$iDocumentId\', \'$sUrl\', \'$sDir\', \'$sLoading\')', $iDelay);";
+ $link .= 'onmouseover = "'.$sJs.'" onmouseout = "clearTimeout(this.t);">';
+ }else{
+ $sJs = "javascript: showInfo('$iDocumentId', '$sUrl', '$sDir', '$sLoading');";
+ $link .= 'onclick = "'.$sJs.'" title="'.$sTitle.'">';
+ }
+
+ return $link.$sTitle.'';
+ }
+
+ function getName() { return _kt('Preview'); }
+}
+
+class DocumentPreviewPlugin extends KTPlugin {
+ var $sNamespace = 'document.preview.plugin';
+
+ function DocumentPreviewPlugin($sFilename = null) {
+ $res = parent::KTPlugin($sFilename);
+ $this->sFriendlyName = _kt('Document Preview Plugin');
+ return $res;
+ }
+
+ function setup() {
+ $this->registerColumn(_kt('Preview File'), 'ktcore.columns.preview', 'PreviewColumn', 'documentPreviewPlugin.php');
+
+ require_once(KT_LIB_DIR . '/templating/templating.inc.php');
+ $oTemplating =& KTTemplating::getSingleton();
+ $oTemplating->addLocation('documentpreview', '/plugins/ktstandard/documentpreview/templates', 'document.preview.plugin');
+ }
+}
+
+$oPluginRegistry =& KTPluginRegistry::getSingleton();
+$oPluginRegistry->registerPlugin('DocumentPreviewPlugin', 'document.preview.plugin', __FILE__);
+?>
diff --git a/plugins/ktstandard/documentpreview/resources/container.css b/plugins/ktstandard/documentpreview/resources/container.css
new file mode 100644
index 0000000..04dc39a
--- /dev/null
+++ b/plugins/ktstandard/documentpreview/resources/container.css
@@ -0,0 +1,131 @@
+
+/* The containing div's, in which the dialog window is created */
+
+.panel {
+ visibility:hidden;
+ position:relative;
+ left:0px;top:0px;
+ font:1em Arial;
+ background-color:transparent;
+ overflow:hidden;
+ line-height: 1.6em;
+}
+
+#info-preview {
+ padding: 10px;
+}
+
+#info-dlg {
+ visibility: hidden;
+ position: absolute;
+ top: 0px;
+}
+
+/* Styling for the dialog content */
+
+.preview {
+ padding-right: 10px;
+ padding-bottom: 0px;
+ cursor: pointer;
+ height: 250px;
+ overflow: hidden;
+ clear: both;
+}
+
+.previewhd {
+ padding-left: 10px;
+ padding-right: 10px;
+ overflow: hidden;
+ visibility: visible;
+}
+
+.previewhd h4 {
+ padding-top: 0;
+ margin-top: 0;
+ line-height: 110%;
+}
+
+.previewhd h2 {
+ padding-top: 0;
+ margin-top: 0;
+ font-family: "Lucida Grande", "Bitstream Vera Sans", Tahoma, sans-serif;
+ border-width: 0 0 0 0;
+ border-style: solid;
+ border-color: #eee;
+ font-size: large;
+ color: #333;
+}
+
+.previewhd img {
+ height: 40px;
+ width: 40px;
+}
+
+/* Override ExtJS CSS */
+
+.x-window-tc {
+ background: url(../../../resources/graphics/portlet_bg.png) repeat-x 0 0;
+ overflow:hidden;
+ zoom:1;
+}
+
+.x-window-tl {
+ background: url(../../../resources/graphics/portlet_corner_topleft.png) no-repeat 0 0;
+ padding-left:6px;
+ zoom:1;
+ z-index:1;
+ position:relative;
+}
+
+.x-window-tr {
+ background: url(graphics/portlet_corner_topright.png) no-repeat right 0;
+ padding-right:6px;
+}
+
+.x-window-bc {
+ background: #FFF;
+ zoom:1;
+}
+.x-window-bl {
+ border-left:1px solid #AFAFAF;
+ border-bottom:1px solid #AFAFAF;
+ background: #FFF;
+ padding-left:6px;
+ zoom:1;
+}
+.x-window-br {
+ border-right:1px solid #AFAFAF;
+ background: #FFF;
+ padding-right:6px;
+ zoom:1;
+}
+
+.x-window-ml {
+ border-left:1px solid #AFAFAF;
+ background: #FFF;
+ padding-left:6px;
+ zoom:1;
+}
+.x-window-mr {
+ border-right:1px solid #AFAFAF;
+ background: #FFF;
+ padding-right:6px;
+ zoom:1;
+}
+
+.x-window-mc {
+ border:1px solid #FFF;
+ border-top:1px solid #FFF;
+ padding:0;
+ margin:0;
+ font: normal 11px tahoma,arial,helvetica,sans-serif;
+ background:#FFF;
+}
+
+.x-window-body {
+ border-left:1px solid #FFF;
+ border-top:1px solid #FFF;
+ border-bottom:1px solid #FFF;
+ border-right:1px solid #FFF;
+ background: transparent;
+}
diff --git a/plugins/ktstandard/documentpreview/resources/graphics/portlet_corner_topright.png b/plugins/ktstandard/documentpreview/resources/graphics/portlet_corner_topright.png
new file mode 100644
index 0000000..57b9673
--- /dev/null
+++ b/plugins/ktstandard/documentpreview/resources/graphics/portlet_corner_topright.png
diff --git a/plugins/ktstandard/documentpreview/resources/preview.js b/plugins/ktstandard/documentpreview/resources/preview.js
new file mode 100644
index 0000000..f65a54c
--- /dev/null
+++ b/plugins/ktstandard/documentpreview/resources/preview.js
@@ -0,0 +1,73 @@
+/*
+ Create the preview / info box using an ExtJS Dialog window
+*/
+var showInfo = function(iDocId, sUrl, sDir, loading){
+
+ // Create the info box container div
+ createPanel();
+
+ showIcon = Ext.get('box_'+iDocId);
+ dialog = new Ext.Window({
+ el: 'info-dlg',
+ closeAction: 'destroy',
+ layout: 'fit',
+ shadow: false,
+ modal: true,
+ plain: false,
+ width: 500,
+ height: 300,
+ minWidth: 300,
+ minHeight: 250
+ });
+ dialog.show(showIcon.dom);
+
+ var info = document.getElementById('info-preview');
+ info.innerHTML = loading;
+
+ Ext.Ajax.request({
+ url: sUrl,
+ success: function(response) {
+ info.innerHTML = response.responseText;
+ },
+ failure: function(response) {
+ alert('Error. Couldn\'t create info box.');
+ },
+ params: {
+ fDocumentId: iDocId,
+ kt_dir: sDir
+ }
+ });
+}
+
+/*
+ Create the container div's in which the info box will be created.
+ Add the div's required by the ExtJS dialog box.
+*/
+var createPanel = function() {
+
+ if(document.getElementById('info-panel')){
+ destroyPanel();
+ p = document.getElementById('info-panel');
+ p.style.display = 'block';
+ }else{
+ p = document.getElementById('pageBody').appendChild(document.createElement('div'));
+ p.id = 'info-panel';
+ }
+
+ b = p.appendChild(document.createElement('div'));
+ b.id = 'info-dlg';
+ b.innerHTML = '';
+}
+
+/*
+ Set the container div to empty.
+ The display must be set to none for IE, otherwise the icons under the div aren't clickable.
+*/
+var destroyPanel = function() {
+ if(dialog){
+ dialog.destroy();
+ }
+ p = document.getElementById('info-panel');
+ p.innerHTML = '';
+ p.style.display = 'none';
+}
\ No newline at end of file