1
0
Fork 0
mirror of https://github.com/Oreolek/ifhub.club.git synced 2024-06-26 03:30:48 +03:00

Plugins вынесены в корень сайта, управление файла перенесено в админпанель.

This commit is contained in:
Alexey Kachayev 2010-01-08 20:01:40 +00:00
parent 65bc1d85d9
commit 2a469a9275
36 changed files with 2004 additions and 21 deletions

View file

@ -0,0 +1,122 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
/**
* Класс обработки УРЛа вида /comments/
*
*/
class ActionAdmin extends Action {
/**
* Главное меню
*
* @var string
*/
protected $sMenuHeadItemSelect='admin';
public function Init() {
if(!$this->User_IsAuthorization() or !$oUserCurrent=$this->User_GetUserCurrent() or !$oUserCurrent->isAdministrator()) {
return parent::EventNotFound();
}
$this->oUserCurrent=$oUserCurrent;
}
protected function RegisterEvent() {
$this->AddEvent('plugins','EventPlugins');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
protected function EventPlugins() {
$this->sMenuHeadItemSelect='plugins';
/**
* Обработка удаления плагинов
*/
if (isPost('submit_plugins_del')) {
$this->Security_ValidateSendForm();
$aPluginsDelete=getRequest('plugins_del');
if (is_array($aPluginsDelete)) {
$this->Plugin_Delete(array_keys($aPluginsDelete));
}
}
if($sPlugin=getRequest('plugin',null,'get') and $sAction=getRequest('action',null,'get')) {
return $this->SubmitManagePlugin($sPlugin,$sAction);
}
/**
* Передан ли номер страницы
*/
$iPage= preg_match("/^\d+$/i",$this->GetEventMatch(2)) ? $this->GetEventMatch(2) : 1;
/**
* Получаем список блогов
*/
$aPlugins=$this->Plugin_GetList();
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign("aPlugins",$aPlugins);
$this->Viewer_AddHtmlTitle($this->Lang_Get('plugins_administartion_title'));
/**
* Устанавливаем шаблон вывода
*/
$this->SetTemplateAction('plugins');
}
/**
* Активация\деактивация плагина
*
* @param string $sPlugin
* @param string $sAction
*/
protected function SubmitManagePlugin($sPlugin,$sAction) {
if(!in_array($sAction,array('activate','deactivate'))) {
$this->Message_AddErrorSingle($this->Lang_Get('plugins_unknown_action'),$this->Lang_Get('error'),true);
Router::Location(Router::GetPath('plugins'));
}
/**
* Активируем\деактивируем плагин
*/
if($bResult=$this->Plugin_Toggle($sPlugin,$sAction)) {
$this->Message_AddNotice($this->Lang_Get('plugins_action_ok'),$this->Lang_Get('attention'),true);
} else {
$this->Message_AddErrorSingle($this->Lang_Get('system_error'),$this->Lang_Get('error'),true);
}
/**
* Возвращаем на страницу управления плагинами
*/
Router::Location(Router::GetPath('admin').'plugins/');
}
/**
* Выполняется при завершении работы экшена
*
*/
public function EventShutdown() {
/**
* Загружаем в шаблон необходимые переменные
*/
$this->Viewer_Assign('sMenuHeadItemSelect',$this->sMenuHeadItemSelect);
}
}
?>

View file

@ -1,5 +1,5 @@
{include file='header.tpl' noShowSystemMessage=false}
<script type="text/javascript" src="{cfg name='path.root.web'}/classes/plugins/profiler/templates/skin/default/js/profiler.js"></script>
<script type="text/javascript" src="{cfg name='path.root.web'}/plugins/profiler/templates/skin/default/js/profiler.js"></script>
<div class="topic people top-blogs talk-table">
<h1>{$aLang.profiler_reports_title}</h1>

View file

@ -1,5 +1,5 @@
{include file='header.tpl' noShowSystemMessage=false}
<script type="text/javascript" src="{cfg name='path.root.web'}/classes/plugins/profiler/templates/skin/new/js/profiler.js"></script>
<script type="text/javascript" src="{cfg name='path.root.web'}/plugins/profiler/templates/skin/new/js/profiler.js"></script>
<div class="topic people top-blogs talk-table">
<h1>{$aLang.profiler_reports_title}</h1>

View file

@ -287,7 +287,7 @@ $config['router']['page']['link'] = 'ActionLink';
$config['router']['page']['question'] = 'ActionQuestion';
$config['router']['page']['blogs'] = 'ActionBlogs';
$config['router']['page']['search'] = 'ActionSearch';
$config['router']['page']['plugins'] = 'ActionPlugins';
$config['router']['page']['admin'] = 'ActionAdmin';
// Глобальные настройки роутинга
$config['router']['config']['action_default'] = 'index';
$config['router']['config']['action_not_found'] = 'error';

View file

@ -127,10 +127,10 @@ if(file_exists(Config::Get('path.root.server').'/config/config.stable.php')) {
}
/**
* Загружает конфиги плагинов вида /classes/plugins/[plugin_name]/config/*.php
* и include-файлы /classes/plugins/[plugin_name]/include/*.php
* Загружает конфиги плагинов вида /plugins/[plugin_name]/config/*.php
* и include-файлы /plugins/[plugin_name]/include/*.php
*/
$sPluginsDir = Config::Get('path.root.server').'/classes/plugins';
$sPluginsDir = Config::Get('path.root.server').'/plugins';
$sPluginsListFile = $sPluginsDir.'/plugins.dat';
if($aPluginsList=@file($sPluginsListFile)) {
foreach ($aPluginsList as $sPlugin) {

View file

@ -46,11 +46,11 @@ abstract class ActionPlugin extends Action {
* Проверяем в списке шаблонов
*/
$aMatches[1]=strtolower($aMatches[1]);
$sTemplateName=in_array(Config::Get('view.skin'),array_map('basename',glob(Config::Get('path.root.server').'/classes/plugins/'.$aMatches[1].'/templates/skin/*',GLOB_ONLYDIR)))
$sTemplateName=in_array(Config::Get('view.skin'),array_map('basename',glob(Config::Get('path.root.server').'/plugins/'.$aMatches[1].'/templates/skin/*',GLOB_ONLYDIR)))
? Config::Get('view.skin')
: 'default';
$this->sTemplatePathAction=Config::Get('path.root.server')."/classes/plugins/{$aMatches[1]}/templates/skin/{$sTemplateName}";
$this->sTemplatePathAction=Config::Get('path.root.server')."/plugins/{$aMatches[1]}/templates/skin/{$sTemplateName}";
}
return $this->sTemplatePathAction;

View file

@ -174,7 +174,7 @@ class Engine extends Object {
/**
* Это модуль плагина
*/
$sModuleFile = Config::Get('path.root.server').'/classes/plugins/'.strtolower($aMatches[1]).'/classes/modules/'.strtolower($aMatches[2]).'/'.$aMatches[2].'.class.php';
$sModuleFile = Config::Get('path.root.server').'/plugins/'.strtolower($aMatches[1]).'/classes/modules/'.strtolower($aMatches[2]).'/'.$aMatches[2].'.class.php';
if($this->isFileExists($sModuleFile)) {
require_once($sModuleFile);
} else {
@ -247,9 +247,9 @@ class Engine extends Object {
*
*/
protected function InitPluginHooks() {
if($aPluginList = @file(Config::Get('path.root.server').'/classes/plugins/plugins.dat')) {
if($aPluginList = @file(Config::Get('path.root.server').'/plugins/plugins.dat')) {
$aFiles=array();
$sDirHooks=Config::Get('path.root.server').'/classes/plugins/';
$sDirHooks=Config::Get('path.root.server').'/plugins/';
foreach ($aPluginList as $sPluginName) {
$aFiles=glob($sDirHooks.$sPluginName.'/classes/hooks/Hook*.class.php');
@ -272,9 +272,9 @@ class Engine extends Object {
*
*/
protected function InitPlugins() {
if($aPluginList = @file(Config::Get('path.root.server').'/classes/plugins/plugins.dat')) {
if($aPluginList = @file(Config::Get('path.root.server').'/plugins/plugins.dat')) {
foreach ($aPluginList as $sPluginName) {
$sDirPlugins=Config::Get('path.root.server').'/classes/plugins/';
$sDirPlugins=Config::Get('path.root.server').'/plugins/';
$sFile="{$sDirPlugins}{$sPluginName}/Plugin{$sPluginName}.class.php";
if(is_file($sFile)) {
require_once($sFile);
@ -431,11 +431,11 @@ class Engine extends Object {
//$sFileClass=Config::get('path.root.server').'/classes/modules/'.strtolower($sModule).'/entity/'.$sEntity.'.entity.class.'.((self::$aEntityCustoms[$sName]=='custom')?'custom.':'').'php';
} else {
$sFileDefaultClass=isset($sPlugin)
? Config::get('path.root.server').'/classes/plugins/'.strtolower($sPlugin).'/classes/modules/'.strtolower($sModule).'/entity/'.$sEntity.'.entity.class.php'
? Config::get('path.root.server').'/plugins/'.strtolower($sPlugin).'/classes/modules/'.strtolower($sModule).'/entity/'.$sEntity.'.entity.class.php'
: Config::get('path.root.server').'/classes/modules/'.strtolower($sModule).'/entity/'.$sEntity.'.entity.class.php';
$sFileCustomClass=isset($sPlugin)
? Config::get('path.root.server').'/classes/plugins/'.strtolower($sPlugin).'/classes/modules/'.strtolower($sModule).'/entity/'.$sEntity.'.entity.class.custom.php'
? Config::get('path.root.server').'/plugins/'.strtolower($sPlugin).'/classes/modules/'.strtolower($sModule).'/entity/'.$sEntity.'.entity.class.custom.php'
: Config::get('path.root.server').'/classes/modules/'.strtolower($sModule).'/entity/'.$sEntity.'.entity.class.custom.php';
/**

View file

@ -167,7 +167,7 @@ class Router extends Object {
$sPrefixCustom='_custom';
}
} else {
require_once(Config::Get('path.root.server').'/classes/plugins/'.strtolower($aMatches[1]).'/classes/actions/Action'.ucfirst($aMatches[2]).'.class.php');
require_once(Config::Get('path.root.server').'/plugins/'.strtolower($aMatches[1]).'/classes/actions/Action'.ucfirst($aMatches[2]).'.class.php');
$sPrefixCustom='';
}

View file

@ -113,8 +113,8 @@ class LsLang extends Module {
/**
* Ищет языковые файлы актвиированных плагинов
*/
if($aPluginList = @file(Config::Get('path.root.server').'/classes/plugins/plugins.dat')) {
$sDir=Config::Get('path.root.server').'/classes/plugins/';
if($aPluginList = @file(Config::Get('path.root.server').'/plugins/plugins.dat')) {
$sDir=Config::Get('path.root.server').'/plugins/';
foreach ($aPluginList as $sPluginName) {
$aFiles=glob($sDir.$sPluginName.'/templates/language/'.$sLangName.'.php');

View file

@ -52,7 +52,7 @@ class LsPlugin extends Module {
*
*/
public function Init() {
$this->sPluginsDir=Config::Get('path.root.server').'/classes/plugins/';
$this->sPluginsDir=Config::Get('path.root.server').'/plugins/';
}
/**

View file

@ -171,7 +171,7 @@ class LsViewer extends Module {
* Создаём объект Smarty и устанавливаем необходиму параметры
*/
$this->oSmarty = new Smarty();
$this->oSmarty->template_dir=array(Config::Get('path.smarty.template'),Config::Get('path.root.server').'/classes/plugins/');
$this->oSmarty->template_dir=array(Config::Get('path.smarty.template'),Config::Get('path.root.server').'/plugins/');
/**
* Для каждого скина устанавливаем свою директорию компиляции шаблонов
*/

View file

@ -36,7 +36,7 @@ function smarty_insert_block($aParams,&$oSmarty) {
require_once(Config::Get('path.root.server').'/engine/classes/ActionPlugin.class.php');
$sBlockTemplate = rtrim($aParams['params']['dir'],'/').'/block.'.$aParams['block'].'.tpl';
$sBlockClass = Config::Get('path.root.server').'/classes/plugins/'.$aParams['params']['plugin'].'/blocks/Block'.$sBlock.'.class.php';
$sBlockClass = Config::Get('path.root.server').'/plugins/'.$aParams['params']['plugin'].'/blocks/Block'.$sBlock.'.class.php';
$sCmd='$oBlock=new Plugin'.ucfirst($aParams['params']['plugin']).'_Block'.$sBlock.'($aParamsBlock);';
} else {
$sBlockTemplate = 'block.'.$aParams['block'].'.tpl';

0
plugins/plugins.dat Normal file
View file

View file

@ -0,0 +1,28 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
class PluginProfiler extends Plugin {
/**
* Активация плагина Профайлер.
* Создание таблицы в базе данных при ее отсутствии.
*/
public function Activate() {
$this->ExportSQL(dirname(__FILE__).'/sql.sql');
return true;
}
}
?>

View file

@ -0,0 +1,267 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
/**
* Обрабатывает вывод отчетов профилирования
*
*/
class PluginProfiler_ActionProfiler extends ActionPlugin {
/**
* Текущий юзер
*
* @var UserEntity_User
*/
protected $oUserCurrent=null;
/**
* Инициализация
*
* @return null
*/
public function Init() {
/**
* Проверяем авторизован ли юзер
*/
if (!$this->User_IsAuthorization()) {
$this->Message_AddErrorSingle($this->Lang_Get('not_access'));
return Router::Action('error');
}
/**
* Получаем текущего юзера
*/
$this->oUserCurrent=$this->User_GetUserCurrent();
/**
* Проверяем является ли юзер администратором
*/
if (!$this->oUserCurrent->isAdministrator()) {
$this->Message_AddErrorSingle($this->Lang_Get('not_access'));
return Router::Action('error');
}
$this->SetDefaultEvent('report');
}
protected function RegisterEvent() {
$this->AddEvent('report','EventReport');
$this->AddEvent('ajaxloadreport','EventAjaxLoadReport');
$this->AddEvent('ajaxloadentriesbyfilter','EventAjaxLoadEntriesByFilter');
}
/**********************************************************************************
************************ РЕАЛИЗАЦИЯ ЭКШЕНА ***************************************
**********************************************************************************
*/
protected function EventReport() {
/**
* Обработка удаления отчетов профайлера
*/
if (isPost('submit_report_delete')) {
$this->Security_ValidateSendForm();
$aReportsId=getRequest('report_del');
if (is_array($aReportsId)) {
if($this->PluginProfiler_Profiler_DeleteEntryByRequestId(array_keys($aReportsId))) {
$this->Message_AddNotice($this->Lang_Get('profiler_report_delete_success'), $this->Lang_Get('attention'));
} else {
$this->Message_AddError($this->Lang_Get('profiler_report_delete_error'), $this->Lang_Get('error'));
}
}
}
/**
* Если вызвана обработка upload`а логов в базу данных
*/
if(getRequest('submit_profiler_import') and getRequest('profiler_date_import')) {
$iCount = @$this->PluginProfiler_Profiler_UploadLog(date('Y-m-d H:i:s',strtotime(getRequest('profiler_date_import'))));
if(!is_null($iCount)) {
$this->Message_AddNotice($this->Lang_Get('profiler_import_report_success',array('count'=>$iCount)), $this->Lang_Get('attention'));
} else {
$this->Message_AddError($this->Lang_Get('profiler_import_report_error'), $this->Lang_Get('error'));
}
}
/**
* Составляем фильтр для просмотра отчетов
*/
$aFilter=$this->BuildFilter();
/**
* Передан ли номер страницы
*/
$iPage=preg_match("/^page(\d+)$/i",$this->getParam(0),$aMatch) ? $aMatch[1] : 1;
/**
* Получаем список отчетов
*/
$aResult=$this->PluginProfiler_Profiler_GetReportsByFilter($aFilter,$iPage,Config::Get('plugin.profiler.per_page'));
$aReports=$aResult['collection'];
/**
* Если был использован фильтр, выводим количество найденых по фильтру
*/
if(count($aFilter)) {
$this->Message_AddNotice(
($aResult['count'])
? $this->Lang_Get('profiler_filter_result_count',array('count'=>$aResult['count']))
: $this->Lang_Get('profiler_filter_result_empty')
);
}
/**
* Формируем постраничность
*/
$aPaging=$this->Viewer_MakePaging(
$aResult['count'],$iPage,Config::Get('plugin.profiler.per_page'),4,
Router::GetPath('profiler').$this->sCurrentEvent,
array_intersect_key(
$_REQUEST,
array_fill_keys(array('start','end','request_id','time','per_page'), '')
)
);
/**
* Загружаем переменные в шаблон
*/
$this->Viewer_Assign('aPaging',$aPaging);
$this->Viewer_Assign('aReports',$aReports);
$this->Viewer_Assign('aDatabaseStat',($aData=$this->PluginProfiler_Profiler_GetDatabaseStat())?$aData:array('max_date'=>'','count'=>''));
$this->Viewer_AddBlock('right',$this->getTemplatePathAction().'/actions/ActionProfiler/sidebar.tpl');
$this->Viewer_AddHtmlTitle($this->Lang_Get('profiler_report_page_title'));
}
/**
* Формирует из REQUEST массива фильтр для отбора отчетов
*
* @return array
*/
protected function BuildFilter() {
$aFilter = array();
if($start=getRequest('start')) {
if(func_check($start,'text',6,10) && substr_count($start,'.')==2) {
list($d,$m,$y)=explode('.',$start);
if(@checkdate($m,$d,$y)) {
$aFilter['date_min']="{$y}-{$m}-{$d}";
} else {
$this->Message_AddError(
$this->Lang_Get('profiler_filter_error_date_format'),
$this->Lang_Get('profiler_filter_error')
);
unset($_REQUEST['start']);
}
} else {
$this->Message_AddError(
$this->Lang_Get('profiler_filter_error_date_format'),
$this->Lang_Get('profiler_filter_error')
);
unset($_REQUEST['start']);
}
}
if($end=getRequest('end')) {
if(func_check($end,'text',6,10) && substr_count($end,'.')==2) {
list($d,$m,$y)=explode('.',$end);
if(@checkdate($m,$d,$y)) {
$aFilter['date_max']="{$y}-{$m}-{$d} 23:59:59";
} else {
$this->Message_AddError(
$this->Lang_Get('profiler_filter_error_date_format'),
$this->Lang_Get('profiler_filter_error')
);
unset($_REQUEST['end']);
}
} else {
$this->Message_AddError(
$this->Lang_Get('profiler_filter_error_date_format'),
$this->Lang_Get('profiler_filter_error')
);
unset($_REQUEST['end']);
}
}
if($iTimeFull=getRequest('time') and $iTimeFull>0) {
$aFilter['time']=$iTimeFull;
}
if($iPerPage=getRequest('per_page',0) and $iPerPage>0) {
Config::Set('plugins.profiler.per_page',$iPerPage);
}
return $aFilter;
}
/**
* Подгрузка данных одного профиля по ajax-запросу
*
* @return
*/
protected function EventAjaxLoadReport() {
$this->Viewer_SetResponseAjax();
$sReportId=str_replace('report_','',getRequest('reportId',null,'post'));
$bTreeView=getRequest('bTreeView',false,'post');
$sParentId=getRequest('parentId',null,'post');
$oViewerLocal=$this->Viewer_GetLocalViewer();
$oViewerLocal->Assign('oReport',$this->PluginProfiler_Profiler_GetReportById($sReportId,$sParentId));
if(!$sParentId) $oViewerLocal->Assign('sAction','tree');
$sTemplateName = ($bTreeView)
? (($sParentId)
? 'level'
: 'tree')
:'report';
$this->Viewer_AssignAjax('sReportText',$oViewerLocal->Fetch($this->getTemplatePathAction()."/actions/ActionProfiler/ajax/{$sTemplateName}.tpl", 'profiler'));
}
/**
* Подгрузка данных одного профиля по ajax-запросу
*
* @return
*/
protected function EventAjaxLoadEntriesByFilter() {
$this->Viewer_SetResponseAjax();
$sAction = $this->GetParam(0);
$sReportId=str_replace('report_','',getRequest('reportId',null,'post'));
$oViewerLocal=$this->Viewer_GetLocalViewer();
$oViewerLocal->Assign('sAction',$sAction);
$oReport = $this->PluginProfiler_Profiler_GetReportById($sReportId,($sAction=='tree')?0:null);
/**
* Преобразуем report взависимости от выбранного фильтра
*/
switch ($sAction) {
case 'query':
$oReport->setAllEntries($oReport->getEntriesByName('query'));
break;
}
$oViewerLocal->Assign('oReport',$oReport);
$sTemplateName=($sAction=='tree')?'tree':'report';
$this->Viewer_AssignAjax('sReportText',$oViewerLocal->Fetch($this->getTemplatePathAction()."/actions/ActionProfiler/ajax/{$sTemplateName}.tpl", "profiler"));
}
/**
* Завершение работы Action`a
*
*/
public function EventShutdown() {
}
}
?>

View file

@ -0,0 +1,252 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
set_include_path(get_include_path().PATH_SEPARATOR.dirname(__FILE__));
require_once('mapper/Profiler.mapper.class.php');
/**
* Модуль статических страниц
*
*/
class PluginProfiler_Profiler extends Module {
/**
* Меппер для сохранения логов в базу данных и формирования выборок по данным из базы
*
* @var Mapper_Profiler
*/
protected $oMapper;
/**
* Хендлер открытого файла лога
*
* @var resource
*/
protected $hLog;
/**
* @var string
*/
protected $sDataDelimiter = "\t";
/**
* Инициализация модуля
*/
public function Init() {
$this->oMapper=new PluginProfiler_Mapper_Profiler($this->Database_GetConnect());
$this->hLog = @fopen(Config::Get('path.root.server').'/logs/'.Config::Get('sys.logs.profiler_file'),'r+');
}
/**
* Добавить новую запись в базу данных
*
* @param PluginProfiler_ProfilerEntity_Entry $oEntry
* @return bool
*/
public function AddEntry(PluginProfiler_ProfilerEntity_Entry $oEntry) {
return $this->oMapper->AddEntry($oEntry);
}
/**
* Читает из лог-файла записи
*
* @param string $sPath
* @return PluginProfiler_ProfilerEntity_Entry
*/
public function ReadEntry() {
/**
* Если хендлер не определен, или лог закончен, вовращаем null
*/
if(!$this->hLog or feof($this->hLog)) return null;
/**
* Читаем следующую строку и формируем объект Entry
*/
$sLine=fgets($this->hLog);
if(!$sLine) return null;
$aTime = array();
list(
$aTime['request_date'],$aTime['request_id'],$aTime['time_full'],
$aTime['time_start'],$aTime['time_stop'],$aTime['time_id'],
$aTime['time_pid'],$aTime['time_name'],$aTime['time_comment']
)=explode($this->sDataDelimiter,$sLine,9);
return Engine::GetEntity('PluginProfiler_Profiler_Entry',$aTime);
}
/**
* Выгружает записи из лога в базу данных
*
* @param string $sDateStart
* @param string $sPath
* @return bool|int
*/
public function UploadLog($sDateStart,$sPath=null) {
if($sPath) $this->hLog = @fopen($sPath,'r+');
if(!$this->hLog) return null;
rewind($this->hLog);
$iCount=0;
while($oEntry=$this->ReadEntry()) {
if(strtotime($oEntry->getDate())>strtotime($sDateStart)){
$this->AddEntry($oEntry);
$iCount++;
}
unset($oEntry);
}
return $iCount;
}
/**
* Получает дату последней записи профайлера в базе данных
*
* @return string
*/
public function GetDatabaseStat() {
return $this->oMapper->GetDatabaseStat();
}
/**
* Очищает файл лога
*
* @return bool
*/
public function EraseLog() {
}
/**
* Получает записи профайлера из базы данных, группированных по уровню "Report"
* TODO: Реализовать кеширование данных
*
* @param array $aFilter
* @param int $iPage
* @param int $iPerPage
* @return array
*/
public function GetReportsByFilter($aFilter,$iPage,$iPerPage) {
$data=array(
'collection'=>$this->oMapper->GetReportsByFilter($aFilter,$iCount,$iPage,$iPerPage),
'count'=>$iCount
);
return $data;
}
/**
* Получает профайл-отчет по идентификатору
* TODO: доработать система вывода записей в виде дерева
*
* @param int $sId
* @return ProfileEntity_Report
*/
public function GetReportById($sId,$sPid=null) {
$aReportRows=$this->oMapper->GetReportById($sId,$sPid);
if(count($aReportRows)) {
/**
* Если запрошена часть записей, отдельно получаем статистику общей выборки
*/
$aStat = !is_null($sPid)
? $this->GetReportStatById($sId)
: array(
'count' => 0,
'query' => 0,
'modules' => array(),
'time_full' => 0
);
$oReport = Engine::GetEntity('PluginProfiler_Profiler_Report');
$aEntries = $this->BuildEntriesRecursive($aReportRows);
foreach ($aEntries as $oEntry) {
$oReport->addEntry($oEntry);
if(is_null($sPid)) {
/**
* Заполняем статистику
*/
$aStat['count']++;
$aStat['time_full']=max($aStat['time_full'],$oEntry->getTimeFull());
if($oEntry->getName()=='query') $aStat['query']++;
}
}
$oReport->setStat($aStat);
return $oReport;
}
return null;
}
/**
* Получает статистику данного отчета
* (количество замеров, общее время, количество запросов к БД, используемые модули)
*
* @param string $sId
* @return array
*/
public function GetReportStatById($sId) {
$aStat = array(
'count' => 0,
'query' => 0,
'modules' => array(),
'time_full' => 0
);
$aReportRows=$this->oMapper->GetReportStatById($sId);
foreach ($aReportRows as $aEntry) {
$aStat['count']++;
$aStat['time_full']=max($aStat['time_full'],$aEntry['time_full']);
/**
* Является ли запросом
*/
if($aEntry['time_name']=='query') $aStat['query']++;
}
return $aStat;
}
protected function BuildEntriesRecursive($aEntries,$bBegin=true) {
static $aResultEntries;
static $iLevel;
if ($bBegin) {
$aResultEntries=array();
$iLevel=0;
}
foreach ($aEntries as $aEntry) {
$aTemp=$aEntry;
$aTemp['level']=$iLevel;
unset($aTemp['childNodes']);
$aResultEntries[]=Engine::GetEntity('PluginProfiler_Profiler_Entry',$aTemp);
if (isset($aEntry['childNodes']) and count($aEntry['childNodes'])>0) {
$iLevel++;
$this->BuildEntriesRecursive($aEntry['childNodes'],false);
}
}
$iLevel--;
return $aResultEntries;
}
/**
* Удаление отчетов из базы данных
* TODO: Добавить обработку кеша данных
*
* @param array|int $aIds
* @return bool
*/
public function DeleteEntryByRequestId($aIds) {
if(!is_array($aIds)) $aIds = array($aIds);
return $this->oMapper->DeleteEntryByRequestId($aIds);
}
}
?>

View file

@ -0,0 +1,121 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
class PluginProfiler_ProfilerEntity_Entry extends Entity
{
public function getRequestId() {
return $this->_aData['request_id'];
}
public function getDate() {
return $this->_aData['request_date'];
}
public function getTimeFull() {
return str_replace(',','.',$this->_aData['time_full']);
}
public function getTimeStart($mode=null) {
switch ($mode) {
case 'seconds':
list($iSeconds,)=explode(' ',$this->_aData['time_start'],2);
return $iSeconds;
case 'time':
list(,$iTime)=explode(' ',$this->_aData['time_start'],2);
return $iTime;
case null:
default:
return $this->_aData['time_start'];
}
}
public function getTimeStop($mode=null) {
switch ($mode) {
case 'seconds':
list($iSeconds,)=explode(' ',$this->_aData['time_stop'],2);
return $iSeconds;
case 'time':
list(,$iTime)=explode(' ',$this->_aData['time_stop'],2);
return $iTime;
case null:
default:
return $this->_aData['time_stop'];
}
}
public function getId() {
return $this->_aData['time_id'];
}
public function getPid() {
return is_null($this->_aData['time_pid']) ? 0 : $this->_aData['time_pid'];
}
public function getName() {
return $this->_aData['time_name'];
}
public function getComment() {
return $this->_aData['time_comment'];
}
public function getLevel() {
return $this->_aData['level'];
}
public function getChildCount() {
return $this->_aData['child_count'];
}
public function getParentTimeFull() {
return $this->_aData['parent_time_full'];
}
public function setRequestId($data) {
$this->_aData['request_id']=$data;
}
public function setDate($data) {
$this->_aData['request_date']=$data;
}
public function setTimeFull($data) {
$this->_aData['time_full']=$data;
}
public function setTimeStart($data) {
$this->_aData['time_start']=$data;
}
public function setTimeStop($data) {
$this->_aData['time_stop']=$data;
}
public function setId($data) {
$this->_aData['time_id']=$data;
}
public function setPid($data) {
$this->_aData['time_pid']=$data;
}
public function setName($data) {
$this->_aData['time_name']=$data;
}
public function setComment($data) {
$this->_aData['time_comment']=$data;
}
public function setLevel($data) {
$this->_aData['level']=$data;
}
public function setParentTimeFull($data) {
$this->_aData['parent_time_full']=$data;
}
}
?>

View file

@ -0,0 +1,136 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
class PluginProfiler_ProfilerEntity_Report extends Entity
{
public function getId() {
return $this->_aData['report_id'];
}
public function getDate() {
return $this->_aData['report_date'];
}
public function getAllEntries() {
return isset($this->_aData['report_entries'])?$this->_aData['report_entries']:array();
}
public function getTime() {
return isset($this->_aData['report_time_full'])?$this->_aData['report_time_full']:0;
}
public function getEntriesByName($sName=null) {
if(!$sName) return $this->getAllEntries();
$aResult=array();
foreach ($this->getAllEntries() as $oEntry) {
if($oEntry->getName()==$sName) $aResult[$oEntry->getId()]=$oEntry;
}
return $aResult;
}
public function getCountEntriesByName($sName=null) {
return count($this->getEntriesByName($sName));
}
public function getEntriesByCommentFilter($sFilter) {
$sFilter=str_replace('*','[\W]+',$sFilter);
$aResult=array();
foreach ($this->_aData['report_entries'] as $oEntry) {
if(preg_match("/{$sFilter}/Ui",$oEntry->getComment())) {
$aResult[$oEntry->getId()]=$oEntry;
}
}
return $aResult;
}
public function getCountEntriesByCommentFilter($sFilter) {
return count($this->getEntriesByCommentFilter($sFilter));
}
public function getEntriesByPid($sPid) {
$aResult=array();
foreach ($this->_aData['report_entries'] as $oEntry) {
if($oEntry->getPid()==$sPid) $aResult[]=$oEntry;
}
return $aResult;
}
public function getCountEntriesByPid($sPid) {
return $this->getEntriesByPid($sPid);
}
public function getEntryShare($sEntryId) {
if(!isset($this->_aData['report_entries'][$sEntryId])) return null;
if(!$this->_aData['report_entries'][$sEntryId]->getParentTimeFull()) return '-';
return round($this->_aData['report_entries'][$sEntryId]->getTimeFull()*100/$this->_aData['report_entries'][$sEntryId]->getParentTimeFull(), 2);
}
public function getEntryFullShare($sEntryId) {
if(!isset($this->_aData['report_entries'][$sEntryId])) return null;
return ($iTimeFull=$this->getStat('time_full'))
? round($this->_aData['report_entries'][$sEntryId]->getTimeFull()*100/$iTimeFull, 2)
: '?';
}
/**
* Получает статистику отчета
*
* @param string [$sKey default=null
* @return array|string|null
*/
public function getStat($sKey=null) {
if(!$sKey) return $this->_aData['report_stat'];
if(isset($this->_aData['report_stat'][$sKey])) return $this->_aData['report_stat'][$sKey];
return null;
}
public function setId($data) {
$this->_aData['report_id']=$data;
}
public function setDate($data) {
$this->_aData['report_date']=$data;
}
protected function setTime($data) {
$this->_aData['report_time_full']=$data;
}
public function addEntry(PluginProfiler_ProfilerEntity_Entry $data) {
if(!isset($this->_aData['report_id'])) {
$this->setId($data->getRequestId());
$this->setDate($data->getDate());
}
if($this->getId()!=$data->getRequestId()) return null;
$this->_aData['report_entries'][$data->getId()]=$data;
}
/**
* Устанавливаем все записи одним массивом
*
* @param array $data
* @return null
*/
public function setAllEntries($data) {
if(!is_array($data)) return null;
$this->_aData['report_entries']=$data;
}
public function setStat($data,$sKey=null) {
if(!$sKey) {
$this->_aData['report_stat']=$data;
return ;
}
$this->_aData[$sKey]=$data;
}
}
?>

View file

@ -0,0 +1,146 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
class PluginProfiler_Mapper_Profiler extends Mapper {
public function AddEntry(PluginProfiler_ProfilerEntity_Entry $oEntry) {
$sql = "INSERT IGNORE INTO ".Config::Get('db.table.profiler')."
(request_date,
request_id,
time_full,
time_start,
time_stop,
time_id,
time_pid,
time_name,
time_comment)
VALUES(?, ?, ?f, ?f+?f, ?f+?f, ?d, ?d, ?, ?)
";
return $this->oDb->query($sql,$oEntry->getDate(),$oEntry->getRequestId(),$oEntry->getTimeFull(),$oEntry->getTimeStart('time'),$oEntry->getTimeStart('seconds'),$oEntry->getTimeStop('time'),$oEntry->getTimeStop('seconds'),$oEntry->getId(),$oEntry->getPid(),$oEntry->getName(),$oEntry->getComment());
}
public function GetDatabaseStat() {
$sql = "
SELECT
MAX(request_date) as max_date,
COUNT(*) as count
FROM ".Config::Get('db.table.profiler') ."
";
if($aData = $this->oDb->selectRow($sql)) {
return $aData;
}
return null;
}
/**
* Возвращает список отчетов профайлера, сгруппированных по идентификатору вызова request_id
*
* @param array $aFilter
* @param int $iCount
* @param int $iCurrPage
* @param int $iPerPage
* @return array
*/
public function GetReportsByFilter($aFilter,&$iCount,$iCurrPage,$iPerPage) {
$sql = "
SELECT
DISTINCT request_id,
MAX(time_full) as time_full,
COUNT(time_id) as count_time_id,
MIN(request_date) as request_date
FROM ".Config::Get('db.table.profiler')."
WHERE
1=1
{ AND request_date >= ? }
{ AND request_date <= ? }
{ AND time_full > ? }
GROUP BY request_id
ORDER BY request_date desc
LIMIT ?d, ?d
";
if (
$aRows=$this->oDb->selectPage(
$iCount,
$sql,
isset($aFilter['date_min'])?$aFilter['date_min']:DBSIMPLE_SKIP,
isset($aFilter['date_max'])?$aFilter['date_max']:DBSIMPLE_SKIP,
isset($aFilter['time'])?$aFilter['time']:DBSIMPLE_SKIP,
($iCurrPage-1)*$iPerPage,
$iPerPage
)
) {
return $aRows;
}
return null;
}
public function GetReportById($sReportId,$sPid=null) {
$sql = "
SELECT
p.*,
p.time_id as ARRAY_KEY,
p.time_pid as PARENT_KEY,
COUNT(pc.time_id) as child_count,
pp.time_full as parent_time_full
FROM
".Config::Get('db.table.profiler')." as p
LEFT JOIN ".Config::Get('db.table.profiler')." as pc ON p.request_id=pc.request_id AND p.time_id = pc.time_pid
LEFT JOIN ".Config::Get('db.table.profiler')." AS pp ON p.request_id=pp.request_id AND p.time_pid = pp.time_id
WHERE
p.request_id=?
{ AND p.time_pid=?d }
GROUP BY p.time_id
";
if($aRows=$this->oDb->query($sql,$sReportId,is_null($sPid)?DBSIMPLE_SKIP:$sPid)) {
return $aRows;
}
return array();
}
public function GetReportStatById($sReportId) {
$sql = "
SELECT time_full, time_name, time_comment
FROM ".Config::Get('db.table.profiler')."
WHERE request_id=?
";
if($aRows=$this->oDb->query($sql,$sReportId)) {
return $aRows;
}
return array();
}
/**
* Удаление записей из базы данных по уникальному ключу отчетов
*
* @param array|int $aIds
* @return bool
*/
public function DeleteEntryByRequestId($aIds) {
$sql = "
DELETE FROM ".Config::Get('db.table.profiler')."
WHERE request_id IN(?a)
";
return $this->oDb->query($sql,$aIds);
}
}
?>

View file

@ -0,0 +1,23 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
$config['per_page'] = 15; // Число profiler-отчетов на одну страницу
Config::Set('db.table.profiler', '___db.table.prefix___profiler');
Config::Set('router.page.profiler', 'PluginProfiler_ActionProfiler');
return $config;
?>

View file

@ -0,0 +1,6 @@
Name: Livestreet Profiler Plugin
Author: LiveStreet Developers Team
Homepage: http://livestreet.ru/
Version: 1.0.0
Requires: 0.4.0
Description: Профилирование работы движка LiveStreet-движка.

12
plugins/profiler/sql.sql Normal file
View file

@ -0,0 +1,12 @@
CREATE TABLE IF NOT EXISTS `prefix_profiler` (
`request_date` DATETIME NOT NULL ,
`request_id` VARCHAR( 32 ) NOT NULL ,
`time_full` DOUBLE( 9,6 ) NOT NULL ,
`time_start` DOUBLE( 17,7 ) NOT NULL ,
`time_stop` DOUBLE( 17,7 ) NOT NULL ,
`time_id` INT NOT NULL ,
`time_pid` INT NOT NULL ,
`time_name` VARCHAR( 250 ) NOT NULL ,
`time_comment` VARCHAR( 250 ) NOT NULL,
PRIMARY KEY (`request_id` , `time_id`)
);

View file

@ -0,0 +1,65 @@
<?php
/*-------------------------------------------------------
*
* LiveStreet Engine Social Networking
* Copyright © 2008 Mzhelskiy Maxim
*
*--------------------------------------------------------
*
* Official site: www.livestreet.ru
* Contact e-mail: rus.engine@gmail.com
*
* GNU General Public License, version 2:
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
*
---------------------------------------------------------
*/
/**
* Русский языковой файл плагина Profiler
*/
return array(
'profiler_report_page_title' => 'Профилирование',
'profiler_reports_title' => 'Отчеты о профилировании',
'profiler_table_date' => 'Дата начала работы',
'profiler_table_time_full' => 'Время работы',
'profiler_table_count_id' => 'Количество профилей',
'profiler_report_delete' => 'Удалить',
'profiler_report_delete_confirm' => 'Вы уверены, что хотите удалить выбранные отчеты?',
'profiler_dbstat_title' => 'Информацию о базе данных',
'profiler_dbstat_count' => 'Всего записей',
'profiler_dbstat_max_date' => 'Последняя дата',
'profiler_import_label' => 'Импортировать начиная с',
'profiler_import_notice' => 'В любом читаемом формате, напрмиер, Y-m-d H:i',
'profiler_import_submit' => 'Импортировать в БД',
'profiler_report_delete_success' => 'Отчеты успешно удалены из базы данных',
'profiler_report_delete_error' => 'При удалении отчетов произошла ошибка',
'profiler_import_report_success' => 'Импортировано записей: %%count%%',
'profiler_import_report_error' => 'При импорте отчетов в базу данных произошла ошибка',
'profiler_entries_show_all' => 'Показать все',
'profiler_entries_show_tree' => 'Вывести дерево',
'profiler_entries_show_query' => 'Запросы к БД',
'profiler_filter_title' => 'Фильтровать',
'profiler_filter_highlight' => 'Подсветить',
'profiler_filter_seconds' => 'секунд',
'profiler_filter_erase' => 'Сбросить фильтр',
'profiler_filter_erase_form' => 'Очистить форму',
'profiler_filter_label_per_page' => 'Вывести на страницу',
'profiler_filter_label_time' => 'Общее время больше',
'profiler_filter_label_date' => 'Ограничения по дате',
'profiler_filter_notice_per_page' => '',
'profiler_filter_notice_time' => 'Минимальное количество секунд выполнения',
'profiler_filter_notice_date' => 'Дата вводиться в формате 25.12.2009',
'profiler_filter_submit' => 'Отфильтровать',
'profiler_filter_error' => 'Ошибка фильрации',
'profiler_filter_error_date_format' => 'Указан неверный формат даты',
'profiler_filter_result_count' => 'Найдено отчетов: %%count%%',
'profiler_filter_result_empty' => 'По вашим критериям отчетов не найдено'
);
?>

View file

@ -0,0 +1,14 @@
<div class="profiler-table">
<table class="profiler entries">
{foreach from=$oReport->getAllEntries() item=oEntry}
<tr class="entry_{$oReport->getId()}_all entry_{$oReport->getId()}_{$oEntry->getName()}{if $oEntry->getChildCount()!=0} has-child{/if}">
<td>{if $oEntry->getChildCount()!=0}<img src="{cfg name='path.static.skin'}/images/open.gif" alt="+" title="{$aLang.comment_collapse}/{$aLang.comment_expand}" class="folding lsProfiler_tree" id="tree_{$oReport->getId()}_{$oEntry->getId()}" style="margin-right:3px;"/>{/if}</td>
<td width="5%">{$oEntry->getId()}</td>
<td width="12%">{$oEntry->getName()}</td>
<td width="12%" class="time">{$oEntry->getTimeFull()}</td>
<td width="18%">{$oReport->getEntryFullShare($oEntry->getId())}% ({$oReport->getEntryShare($oEntry->getId())}%)</td>
<td>{$oEntry->getComment()}</td>
</tr>
{/foreach}
</table>
</div>

View file

@ -0,0 +1,22 @@
{if $oReport}
<a href="#" class="profiler tree {if $sAction=='tree'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','tree',this); return false;">{$aLang.profiler_entries_show_tree}</a>
<a href="#" class="profiler all {if $sAction=='all'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','all',this); return false;">{$aLang.profiler_entries_show_all} ({$oReport->getStat('count')})</a>
<a href="#" class="profiler query {if $sAction=='query'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','query',this); return false;">{$aLang.profiler_entries_show_query} ({$oReport->getStat('query')})</a>
<div class="profiler-table">
<table class="profiler entries">
{foreach from=$oReport->getAllEntries() item=oEntry}
<tr class="entry_{$oReport->getId()}_all entry_{$oReport->getId()}_{$oEntry->getName()}{if $oEntry->getChildCount()!=0} child{/if}">
<td></td>
<td width="5%">{$oEntry->getId()}</td>
<td width="12%">{$oEntry->getName()}</td>
<td width="12%" class="time">{$oEntry->getTimeFull()}</td>
<td width="18%">{$oReport->getEntryFullShare($oEntry->getId())}% ({$oReport->getEntryShare($oEntry->getId())}%)</td>
<td>{$oEntry->getComment()}</td>
</tr>
{/foreach}
</table>
</div>
{else}
{$aLang.error}
{/if}

View file

@ -0,0 +1,9 @@
{if $oReport}
<a href="#" class="profiler tree {if $sAction=='tree'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','tree',this); return false;">{$aLang.profiler_entries_show_tree}</a>
<a href="#" class="profiler all {if $sAction=='all'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','all',this); return false;">{$aLang.profiler_entries_show_all} ({$oReport->getStat('count')})</a>
<a href="#" class="profiler query {if $sAction=='query'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','query',this); return false;">{$aLang.profiler_entries_show_query} ({$oReport->getStat('query')})</a>
{include file='profiler/templates/skin/new/actions/ActionProfiler/ajax/level.tpl'}
{else}
{$aLang.error}
{/if}

View file

@ -0,0 +1,35 @@
{include file='header.tpl' noShowSystemMessage=false}
<script type="text/javascript" src="{cfg name='path.root.web'}/plugins/profiler/templates/skin/new/js/profiler.js"></script>
<div class="topic people top-blogs talk-table">
<h1>{$aLang.profiler_reports_title}</h1>
<form action="{router page='profiler'}" method="post" id="form_report_list">
<input type="hidden" name="security_ls_key" value="{$LIVESTREET_SECURITY_KEY}" />
<table>
<thead>
<tr>
<td width="20px"><input type="checkbox" name="" onclick="checkAllReport(this);"></td>
<td></td>
<td>{$aLang.profiler_table_date}</td>
<td align="center">{$aLang.profiler_table_time_full}</td>
<td align="center">{$aLang.profiler_table_count_id}</td>
</tr>
</thead>
<tbody>
{foreach from=$aReports item=oReport}
<tr>
<td><input type="checkbox" name="report_del[{$oReport.request_id}]" class="form_reports_checkbox"></td>
<td><img src="{cfg name='path.static.skin'}/images/open.gif" alt="+" title="{$aLang.comment_collapse}/{$aLang.comment_expand}" class="folding" id="img_{$oReport.request_id}" /></td>
<td>{date_format date=$oReport.request_date}</td>
<td align="center" class="time">{$oReport.time_full}</td>
<td align="center">{$oReport.count_time_id}</td>
</tr>
{/foreach}
</tbody>
</table>
<input type="submit" name="submit_report_delete" value="{$aLang.profiler_report_delete}" onclick="return ($$('.form_reports_checkbox').length==0)?false:confirm('{$aLang.profiler_report_delete_confirm}');">
</form>
</div>
{include file='paging.tpl' aPaging=`$aPaging`}
{include file='footer.tpl'}

View file

@ -0,0 +1,99 @@
<div class="profiler-highlight">{$aLang.profiler_filter_highlight}: <input type="text" name="profiler_filter_entries" id="profiler_filter_entries" onchange="lsProfiler.filterNode(this);" class="w50" /> {$aLang.profiler_filter_seconds}</div>
<div class="block blogs">
<div class="tl"><div class="tr"></div></div>
<div class="cl"><div class="cr">
<h1>{$aLang.profiler_dbstat_title}</h1>
<form action="{router page='profiler'}" method="POST" name="profiler_import_form">
<p>{$aLang.profiler_dbstat_count}: {$aDatabaseStat.count}<br />
{$aLang.profiler_dbstat_max_date}: {$aDatabaseStat.max_date}</p>
<p>
<label for="profiler_date_import">{$aLang.profiler_import_label}:</label><br />
<input type="text" id="profiler_date_import" name="profiler_date_import" value="{if $_aRequest.date_import}{$_aRequest.date_import}{else}{if $aDatabaseStat.max_date}{$aDatabaseStat.max_date}{else}{date_format date=$smarty.now format='Y-m-d \0\0\:\0\0\:\0\0'}{/if}{/if}" class="w100p" /><br />
<span class="form_note">{$aLang.profiler_import_notice}</span>
</p>
<p class="buttons">
<input type="submit" name="submit_profiler_import" value="{$aLang.profiler_import_submit}"/>
</p>
</form>
<br/>
</div></div>
<div class="bl"><div class="br"></div></div>
</div>
<div class="block blogs">
<div class="tl"><div class="tr"></div></div>
<div class="cl"><div class="cr">
<h1>{$aLang.profiler_filter_title}</h1>
{literal}
<script language="JavaScript" type="text/javascript">
document.addEvent('domready', function() {
new vlaDatePicker(
$('profiler_filter_start'),
{
separator: '.',
leadingZero: true,
twoDigitYear: false,
alignX: 'center',
alignY: 'top',
offset: { y: 3 },
filePath: DIR_WEB_ROOT+'/engine/lib/external/MooTools_1.2/plugs/vlaCal-v2.1/inc/',
prefillDate: false,
startMonday: true
}
);
new vlaDatePicker(
$('profiler_filter_end'),
{
separator: '.',
leadingZero: true,
twoDigitYear: false,
alignX: 'center',
alignY: 'top',
offset: { y: 3 },
filePath: DIR_WEB_ROOT+'/engine/lib/external/MooTools_1.2/plugs/vlaCal-v2.1/inc/',
prefillDate: false,
startMonday: true
}
);
});
function eraseFilterForm() {
$$("#profiler_filter_per_page, #profiler_filter_time, #profiler_filter_start, #profiler_filter_end").each(
function(item,index){
return item.set('value','');
}
);
return false;
}
</script>
{/literal}
<form action="{router page='profiler'}" method="GET" name="profiler_filter_form">
<p><label for="profiler_filter_start">{$aLang.profiler_filter_label_date}:</label><br />
<input type="text" id="profiler_filter_start" name="start" value="{$_aRequest.start}" class="w100p" style="width: 44%" readonly="readonly" /> &mdash;
<input type="text" id="profiler_filter_end" name="end" value="{$_aRequest.end}" class="w100p" style="width: 44%" readonly="readonly" /><br />
<span class="form_note">{$aLang.profiler_filter_notice_date}</span>
</p>
<p><label for="profiler_filter_time">{$aLang.profiler_filter_label_time}:</label>
<input type="text" id="profiler_filter_time" name="time" value="{$_aRequest.time}" class="w100" /><br />
<span class="form_note">{$aLang.profiler_filter_notice_time}</span>
</p>
<p><label for="profiler_filter_per_page">{$aLang.profiler_filter_label_per_page}:</label>
<input type="text" id="profiler_filter_per_page" name="per_page" value="{if $_aRequest.per_page}{$_aRequest.per_page}{else}{cfg name='module.profiler.per_page'}{/if}" class="w50" /><br />
<span class="form_note">{$aLang.profiler_filter_notice_per_page}</span>
</p>
<p class="buttons">
<input type="submit" name="submit_profiler_filter" value="{$aLang.profiler_filter_submit}"/>
</p>
</form>
<div class="right"><a href="#" onclick="return eraseFilterForm();">{$aLang.profiler_filter_erase_form}</a> | <a href="{router page='profiler'}">{$aLang.profiler_filter_erase}</a></div>
</div></div>
<div class="bl"><div class="br"></div></div>
</div>

View file

@ -0,0 +1,207 @@
var lsProfilerClass = new Class({
Implements: Options,
options: {
img : {
path: DIR_STATIC_SKIN+'/images/',
openName: 'open.gif',
closeName: 'close.gif'
},
classes: {
visible: 'lsProfiler_visible',
hidden: 'lsProfiler_hidden',
openImg: 'lsProfiler_open',
closeImg: 'lsProfiler_close',
treeNode: 'lsProfiler_tree',
filterNode: 'lsProfiler_filter'
},
prefix: {
img: 'img_',
td: 'report_',
entry: 'entry_',
tree: 'tree_',
treeNode: 'tree_node_'
},
path: {
loadReport: aRouter['profiler']+'ajaxloadreport/',
loadEntries: aRouter['profiler']+'ajaxloadentriesbyfilter/'
}
},
initialize: function(options){
this.setOptions(options);
this.make();
},
make: function(expandClass){
var thisObj = this;
var aImgFolding=(!expandClass)?$$('img.folding'):$$('img.folding.'+expandClass);
aImgFolding.each(function(img, i){thisObj.makeImg(img);});
},
makeImg: function(img) {
var thisObj = this;
img.setStyles({
'cursor' : 'pointer',
'display' : 'inline'
});
img.removeClass(this.options.classes.closeImg);
img.addClass(this.options.classes.openImg);
img.removeEvents('click');
img.addEvent('click',function(){
thisObj.toggleNode(img);
});
},
toggleNode: function(img) {
if (img.hasClass(this.options.classes.closeImg)) {
this.collapseNode(img);
} else {
this.expandNode(img);
}
},
expandNode: function(img) {
var thisObj = this;
img.setProperties({'src': this.options.img.path + this.options.img.closeName});
img.removeClass(this.options.classes.openImg);
img.addClass(this.options.classes.closeImg);
if(img.hasClass(thisObj.options.classes.treeNode)) {
// Это элемент дерева - обрабатываем его соответствующим образом
ids = img.get('id').replace(this.options.prefix.tree,'').split('_');
reportId=ids[0];
var trReportId=this.options.prefix.treeNode+ids[0]+'_'+ids[1];
var trReport=$(trReportId);
var parentId=ids[1];
} else {
reportId=img.get('id').replace(this.options.prefix.img,this.options.prefix.td);
var trReport = $(reportId);
var parentId = 0;
var trReportId = 0;
}
if(trReport){
trReport.show();
} else {
thisObj.loadReport(img.getParent('tr'),reportId,parentId,trReportId);
}
},
loadReport: function(obj,reportId,parentId,namedId) {
var thisObj=this;
var trCurrent = obj;
JsHttpRequest.query(
'POST '+thisObj.options.path.loadReport,
{
reportId: reportId,
bTreeView: true,
parentId: parentId,
security_ls_key: LIVESTREET_SECURITY_KEY
},
function(result, errors) {
if (!result) {
msgErrorBox.alert('Error','Please try again later');
}
if (result.bStateError) {
msgErrorBox.alert(result.sMsgTitle,result.sMsg);
} else {
var trReport=new Element('tr', {'id':(!namedId)?reportId:namedId});
trReport.adopt(new Element('td',{
'colspan': 6,
'html' : result.sReportText
}));
trReport.inject(trCurrent,'after');
trReport.getElements('img').each(function(img, i){thisObj.makeImg(img);});
}
},
true
);
},
collapseNode: function(img) {
var thisObj = this;
img.setProperties({'src': this.options.img.path + this.options.img.openName});
img.removeClass(this.options.classes.closeImg);
img.addClass(this.options.classes.openImg);
if(img.hasClass(thisObj.options.classes.treeNode)) {
// Это элемент дерева - обрабатываем его соответствующим образом
trReport=img.getParent('tr').getNext('tr');
} else {
reportId=img.get('id').replace(this.options.prefix.img,this.options.prefix.td);
var trReport = $(reportId);
}
trReport.hide();
},
toggleEntriesByClass: function(reportId,name,link) {
var thisObj=this;
$$('a.profiler').removeClass('active');
$$('a.profiler.'+name).addClass('active');
//var trCurrent = link.getParent('tr').getPrevious('tr');
JsHttpRequest.query(
'POST '+thisObj.options.path.loadEntries+name+'/',
{
reportId: reportId,
security_ls_key: LIVESTREET_SECURITY_KEY
},
function(result, errors) {
if (!result) {
msgErrorBox.alert('Error','Please try again later');
}
if (result.bStateError) {
msgErrorBox.alert(result.sMsgTitle,result.sMsg);
} else {
var trReport = $(thisObj.options.prefix.td+reportId).empty();
trReport.adopt(new Element('td',{
'colspan': 5,
'html' : result.sReportText
}));
trReport.getElements('img').each(function(img, i){thisObj.makeImg(img);});
}
},
true
);
},
filterNode: function(obj) {
var thisObj = this;
var iTime=obj.get('value');
if(iTime!='' && parseFloat(iTime)){ thisObj.highlightFilterNode(iTime); }
},
highlightFilterNode: function(iTime) {
var thisObj = this;
$$('.time').each(function(el,i){
el.getParent('tr').removeClass(thisObj.options.classes.filterNode);
if(el.get('text')>iTime) {
el.getParent('tr').addClass(thisObj.options.classes.filterNode);
}
});
}
});
var lsProfiler;
window.addEvent('domready', function() {
lsProfiler = new lsProfilerClass({
img: {
path: DIR_STATIC_SKIN+'/images/'
},
classes: {
openImg: 'folding-open',
closeImg: 'folding',
filterNode: 'filter'
}
});
});

View file

@ -0,0 +1,14 @@
<div class="profiler-table">
<table class="profiler entries">
{foreach from=$oReport->getAllEntries() item=oEntry}
<tr class="entry_{$oReport->getId()}_all entry_{$oReport->getId()}_{$oEntry->getName()}{if $oEntry->getChildCount()!=0} has-child{/if}">
<td>{if $oEntry->getChildCount()!=0}<img src="{cfg name='path.static.skin'}/images/open.gif" alt="+" title="{$aLang.comment_collapse}/{$aLang.comment_expand}" class="folding lsProfiler_tree" id="tree_{$oReport->getId()}_{$oEntry->getId()}" style="margin-right:3px;"/>{/if}</td>
<td width="5%">{$oEntry->getId()}</td>
<td width="12%">{$oEntry->getName()}</td>
<td width="12%" class="time">{$oEntry->getTimeFull()}</td>
<td width="18%">{$oReport->getEntryFullShare($oEntry->getId())}% ({$oReport->getEntryShare($oEntry->getId())}%)</td>
<td>{$oEntry->getComment()}</td>
</tr>
{/foreach}
</table>
</div>

View file

@ -0,0 +1,22 @@
{if $oReport}
<a href="#" class="profiler tree {if $sAction=='tree'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','tree',this); return false;">{$aLang.profiler_entries_show_tree}</a>
<a href="#" class="profiler all {if $sAction=='all'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','all',this); return false;">{$aLang.profiler_entries_show_all} ({$oReport->getStat('count')})</a>
<a href="#" class="profiler query {if $sAction=='query'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','query',this); return false;">{$aLang.profiler_entries_show_query} ({$oReport->getStat('query')})</a>
<div class="profiler-table">
<table class="profiler entries">
{foreach from=$oReport->getAllEntries() item=oEntry}
<tr class="entry_{$oReport->getId()}_all entry_{$oReport->getId()}_{$oEntry->getName()}{if $oEntry->getChildCount()!=0} child{/if}">
<td></td>
<td width="5%">{$oEntry->getId()}</td>
<td width="12%">{$oEntry->getName()}</td>
<td width="12%" class="time">{$oEntry->getTimeFull()}</td>
<td width="18%">{$oReport->getEntryFullShare($oEntry->getId())}% ({$oReport->getEntryShare($oEntry->getId())}%)</td>
<td>{$oEntry->getComment()}</td>
</tr>
{/foreach}
</table>
</div>
{else}
{$aLang.error}
{/if}

View file

@ -0,0 +1,9 @@
{if $oReport}
<a href="#" class="profiler tree {if $sAction=='tree'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','tree',this); return false;">{$aLang.profiler_entries_show_tree}</a>
<a href="#" class="profiler all {if $sAction=='all'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','all',this); return false;">{$aLang.profiler_entries_show_all} ({$oReport->getStat('count')})</a>
<a href="#" class="profiler query {if $sAction=='query'}active{/if}" onclick="lsProfiler.toggleEntriesByClass('{$oReport->getId()}','query',this); return false;">{$aLang.profiler_entries_show_query} ({$oReport->getStat('query')})</a>
{include file='profiler/templates/skin/new/actions/ActionProfiler/ajax/level.tpl'}
{else}
{$aLang.error}
{/if}

View file

@ -0,0 +1,35 @@
{include file='header.tpl' noShowSystemMessage=false}
<script type="text/javascript" src="{cfg name='path.root.web'}/plugins/profiler/templates/skin/new/js/profiler.js"></script>
<div class="topic people top-blogs talk-table">
<h1>{$aLang.profiler_reports_title}</h1>
<form action="{router page='profiler'}" method="post" id="form_report_list">
<input type="hidden" name="security_ls_key" value="{$LIVESTREET_SECURITY_KEY}" />
<table>
<thead>
<tr>
<td width="20px"><input type="checkbox" name="" onclick="checkAllReport(this);"></td>
<td></td>
<td>{$aLang.profiler_table_date}</td>
<td align="center">{$aLang.profiler_table_time_full}</td>
<td align="center">{$aLang.profiler_table_count_id}</td>
</tr>
</thead>
<tbody>
{foreach from=$aReports item=oReport}
<tr>
<td><input type="checkbox" name="report_del[{$oReport.request_id}]" class="form_reports_checkbox"></td>
<td><img src="{cfg name='path.static.skin'}/images/open.gif" alt="+" title="{$aLang.comment_collapse}/{$aLang.comment_expand}" class="folding" id="img_{$oReport.request_id}" /></td>
<td>{date_format date=$oReport.request_date}</td>
<td align="center" class="time">{$oReport.time_full}</td>
<td align="center">{$oReport.count_time_id}</td>
</tr>
{/foreach}
</tbody>
</table>
<input type="submit" name="submit_report_delete" value="{$aLang.profiler_report_delete}" onclick="return ($$('.form_reports_checkbox').length==0)?false:confirm('{$aLang.profiler_report_delete_confirm}');">
</form>
</div>
{include file='paging.tpl' aPaging=`$aPaging`}
{include file='footer.tpl'}

View file

@ -0,0 +1,99 @@
<div class="profiler-highlight">{$aLang.profiler_filter_highlight}: <input type="text" name="profiler_filter_entries" id="profiler_filter_entries" onchange="lsProfiler.filterNode(this);" class="w50" /> {$aLang.profiler_filter_seconds}</div>
<div class="block blogs">
<div class="tl"><div class="tr"></div></div>
<div class="cl"><div class="cr">
<h1>{$aLang.profiler_dbstat_title}</h1>
<form action="{router page='profiler'}" method="POST" name="profiler_import_form">
<p>{$aLang.profiler_dbstat_count}: {$aDatabaseStat.count}<br />
{$aLang.profiler_dbstat_max_date}: {$aDatabaseStat.max_date}</p>
<p>
<label for="profiler_date_import">{$aLang.profiler_import_label}:</label><br />
<input type="text" id="profiler_date_import" name="profiler_date_import" value="{if $_aRequest.date_import}{$_aRequest.date_import}{else}{if $aDatabaseStat.max_date}{$aDatabaseStat.max_date}{else}{date_format date=$smarty.now format='Y-m-d \0\0\:\0\0\:\0\0'}{/if}{/if}" class="w100p" /><br />
<span class="form_note">{$aLang.profiler_import_notice}</span>
</p>
<p class="buttons">
<input type="submit" name="submit_profiler_import" value="{$aLang.profiler_import_submit}"/>
</p>
</form>
<br/>
</div></div>
<div class="bl"><div class="br"></div></div>
</div>
<div class="block blogs">
<div class="tl"><div class="tr"></div></div>
<div class="cl"><div class="cr">
<h1>{$aLang.profiler_filter_title}</h1>
{literal}
<script language="JavaScript" type="text/javascript">
document.addEvent('domready', function() {
new vlaDatePicker(
$('profiler_filter_start'),
{
separator: '.',
leadingZero: true,
twoDigitYear: false,
alignX: 'center',
alignY: 'top',
offset: { y: 3 },
filePath: DIR_WEB_ROOT+'/engine/lib/external/MooTools_1.2/plugs/vlaCal-v2.1/inc/',
prefillDate: false,
startMonday: true
}
);
new vlaDatePicker(
$('profiler_filter_end'),
{
separator: '.',
leadingZero: true,
twoDigitYear: false,
alignX: 'center',
alignY: 'top',
offset: { y: 3 },
filePath: DIR_WEB_ROOT+'/engine/lib/external/MooTools_1.2/plugs/vlaCal-v2.1/inc/',
prefillDate: false,
startMonday: true
}
);
});
function eraseFilterForm() {
$$("#profiler_filter_per_page, #profiler_filter_time, #profiler_filter_start, #profiler_filter_end").each(
function(item,index){
return item.set('value','');
}
);
return false;
}
</script>
{/literal}
<form action="{router page='profiler'}" method="GET" name="profiler_filter_form">
<p><label for="profiler_filter_start">{$aLang.profiler_filter_label_date}:</label><br />
<input type="text" id="profiler_filter_start" name="start" value="{$_aRequest.start}" class="w100p" style="width: 44%" readonly="readonly" /> &mdash;
<input type="text" id="profiler_filter_end" name="end" value="{$_aRequest.end}" class="w100p" style="width: 44%" readonly="readonly" /><br />
<span class="form_note">{$aLang.profiler_filter_notice_date}</span>
</p>
<p><label for="profiler_filter_time">{$aLang.profiler_filter_label_time}:</label>
<input type="text" id="profiler_filter_time" name="time" value="{$_aRequest.time}" class="w100" /><br />
<span class="form_note">{$aLang.profiler_filter_notice_time}</span>
</p>
<p><label for="profiler_filter_per_page">{$aLang.profiler_filter_label_per_page}:</label>
<input type="text" id="profiler_filter_per_page" name="per_page" value="{if $_aRequest.per_page}{$_aRequest.per_page}{else}{cfg name='module.profiler.per_page'}{/if}" class="w50" /><br />
<span class="form_note">{$aLang.profiler_filter_notice_per_page}</span>
</p>
<p class="buttons">
<input type="submit" name="submit_profiler_filter" value="{$aLang.profiler_filter_submit}"/>
</p>
</form>
<div class="right"><a href="#" onclick="return eraseFilterForm();">{$aLang.profiler_filter_erase_form}</a> | <a href="{router page='profiler'}">{$aLang.profiler_filter_erase}</a></div>
</div></div>
<div class="bl"><div class="br"></div></div>
</div>

View file

@ -0,0 +1,207 @@
var lsProfilerClass = new Class({
Implements: Options,
options: {
img : {
path: DIR_STATIC_SKIN+'/images/',
openName: 'open.gif',
closeName: 'close.gif'
},
classes: {
visible: 'lsProfiler_visible',
hidden: 'lsProfiler_hidden',
openImg: 'lsProfiler_open',
closeImg: 'lsProfiler_close',
treeNode: 'lsProfiler_tree',
filterNode: 'lsProfiler_filter'
},
prefix: {
img: 'img_',
td: 'report_',
entry: 'entry_',
tree: 'tree_',
treeNode: 'tree_node_'
},
path: {
loadReport: aRouter['profiler']+'ajaxloadreport/',
loadEntries: aRouter['profiler']+'ajaxloadentriesbyfilter/'
}
},
initialize: function(options){
this.setOptions(options);
this.make();
},
make: function(expandClass){
var thisObj = this;
var aImgFolding=(!expandClass)?$$('img.folding'):$$('img.folding.'+expandClass);
aImgFolding.each(function(img, i){thisObj.makeImg(img);});
},
makeImg: function(img) {
var thisObj = this;
img.setStyles({
'cursor' : 'pointer',
'display' : 'inline'
});
img.removeClass(this.options.classes.closeImg);
img.addClass(this.options.classes.openImg);
img.removeEvents('click');
img.addEvent('click',function(){
thisObj.toggleNode(img);
});
},
toggleNode: function(img) {
if (img.hasClass(this.options.classes.closeImg)) {
this.collapseNode(img);
} else {
this.expandNode(img);
}
},
expandNode: function(img) {
var thisObj = this;
img.setProperties({'src': this.options.img.path + this.options.img.closeName});
img.removeClass(this.options.classes.openImg);
img.addClass(this.options.classes.closeImg);
if(img.hasClass(thisObj.options.classes.treeNode)) {
// Это элемент дерева - обрабатываем его соответствующим образом
ids = img.get('id').replace(this.options.prefix.tree,'').split('_');
reportId=ids[0];
var trReportId=this.options.prefix.treeNode+ids[0]+'_'+ids[1];
var trReport=$(trReportId);
var parentId=ids[1];
} else {
reportId=img.get('id').replace(this.options.prefix.img,this.options.prefix.td);
var trReport = $(reportId);
var parentId = 0;
var trReportId = 0;
}
if(trReport){
trReport.show();
} else {
thisObj.loadReport(img.getParent('tr'),reportId,parentId,trReportId);
}
},
loadReport: function(obj,reportId,parentId,namedId) {
var thisObj=this;
var trCurrent = obj;
JsHttpRequest.query(
'POST '+thisObj.options.path.loadReport,
{
reportId: reportId,
bTreeView: true,
parentId: parentId,
security_ls_key: LIVESTREET_SECURITY_KEY
},
function(result, errors) {
if (!result) {
msgErrorBox.alert('Error','Please try again later');
}
if (result.bStateError) {
msgErrorBox.alert(result.sMsgTitle,result.sMsg);
} else {
var trReport=new Element('tr', {'id':(!namedId)?reportId:namedId});
trReport.adopt(new Element('td',{
'colspan': 6,
'html' : result.sReportText
}));
trReport.inject(trCurrent,'after');
trReport.getElements('img').each(function(img, i){thisObj.makeImg(img);});
}
},
true
);
},
collapseNode: function(img) {
var thisObj = this;
img.setProperties({'src': this.options.img.path + this.options.img.openName});
img.removeClass(this.options.classes.closeImg);
img.addClass(this.options.classes.openImg);
if(img.hasClass(thisObj.options.classes.treeNode)) {
// Это элемент дерева - обрабатываем его соответствующим образом
trReport=img.getParent('tr').getNext('tr');
} else {
reportId=img.get('id').replace(this.options.prefix.img,this.options.prefix.td);
var trReport = $(reportId);
}
trReport.hide();
},
toggleEntriesByClass: function(reportId,name,link) {
var thisObj=this;
$$('a.profiler').removeClass('active');
$$('a.profiler.'+name).addClass('active');
//var trCurrent = link.getParent('tr').getPrevious('tr');
JsHttpRequest.query(
'POST '+thisObj.options.path.loadEntries+name+'/',
{
reportId: reportId,
security_ls_key: LIVESTREET_SECURITY_KEY
},
function(result, errors) {
if (!result) {
msgErrorBox.alert('Error','Please try again later');
}
if (result.bStateError) {
msgErrorBox.alert(result.sMsgTitle,result.sMsg);
} else {
var trReport = $(thisObj.options.prefix.td+reportId).empty();
trReport.adopt(new Element('td',{
'colspan': 5,
'html' : result.sReportText
}));
trReport.getElements('img').each(function(img, i){thisObj.makeImg(img);});
}
},
true
);
},
filterNode: function(obj) {
var thisObj = this;
var iTime=obj.get('value');
if(iTime!='' && parseFloat(iTime)){ thisObj.highlightFilterNode(iTime); }
},
highlightFilterNode: function(iTime) {
var thisObj = this;
$$('.time').each(function(el,i){
el.getParent('tr').removeClass(thisObj.options.classes.filterNode);
if(el.get('text')>iTime) {
el.getParent('tr').addClass(thisObj.options.classes.filterNode);
}
});
}
});
var lsProfiler;
window.addEvent('domready', function() {
lsProfiler = new lsProfilerClass({
img: {
path: DIR_STATIC_SKIN+'/images/'
},
classes: {
openImg: 'folding-open',
closeImg: 'folding',
filterNode: 'filter'
}
});
});

View file

@ -0,0 +1,33 @@
{include file='header.tpl' showWhiteBack=true}
<div class="page people top-blogs plugins">
<form action="{router page='admin'}plugins/" method="post" id="form_plugins_list">
<input type="hidden" name="security_ls_key" value="{$LIVESTREET_SECURITY_KEY}" />
<table>
<thead>
<tr>
<td width="20px"><input type="checkbox" name="" onclick="checkAllPlugins(this);"></td>
<td class="name">{$aLang.plugins_plugin_name}</td>
<td class="version">{$aLang.plugins_plugin_version}</td>
<td class="author">{$aLang.plugins_plugin_author}</td>
<td class="action">{$aLang.plugins_plugin_action}</td>
</tr>
</thead>
<tbody>
{foreach from=$aPlugins item=aPlugin}
<tr>
<td><input type="checkbox" name="plugin_del[{$aPlugin.code}]" class="form_plugins_checkbox"></td>
<td class="name"><a class="title">{$aPlugin.name}</a><br />{$aPlugin.description}<br />{$aPlugin.homepage}</td>
<td class="version">{$aPlugin.version}</td>
<td class="author">{$aPlugin.author}</td>
<td class="{if $aPlugin.is_active}deactivate{else}activate{/if}"><strong>{if $aPlugin.is_active}<a href="{router page='admin'}plugins/?plugin={$aPlugin.code}&action=deactivate">{$aLang.plugins_plugin_deactivate}</a>{else}<a href="{router page='admin'}plugins/?plugin={$aPlugin.code}&action=activate">{$aLang.plugins_plugin_activate}</a>{/if}</strong></td>
</tr>
{/foreach}
</tbody>
</table>
<input type="submit" name="submit_plugins_del" value="{$aLang.plugins_submit_delete}" onclick="return ($$('.form_plugins_checkbox:checked').length==0)?false:confirm('{$aLang.plugins_delete_confirm}');">
</form>
</div>
{include file='footer.tpl'}