Page MenuHomeIn-Portal Phabricator

in-portal
No OneTemporary

File Metadata

Created
Thu, Jul 24, 6:24 AM

in-portal

This file is larger than 256 KB, so syntax highlighting was skipped.
Index: branches/RC/admin/install/upgrades/inportal_upgrade_v4.3.0.sql
===================================================================
--- branches/RC/admin/install/upgrades/inportal_upgrade_v4.3.0.sql (revision 10293)
+++ branches/RC/admin/install/upgrades/inportal_upgrade_v4.3.0.sql (revision 10294)
@@ -1,25 +1,28 @@
UPDATE ConfigurationAdmin SET DisplayOrder = 10.09 WHERE VariableName = 'AllowDeleteRootCats';
UPDATE ConfigurationAdmin SET DisplayOrder = 10.10 WHERE VariableName = 'Catalog_PreselectModuleTab';
INSERT INTO ConfigurationAdmin VALUES ('RecycleBinFolder', 'la_Text_General', 'la_config_RecycleBinFolder', 'text', NULL , NULL , 10.11, 0, 0);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'RecycleBinFolder', '', 'In-Portal', 'in-portal:configure_categories');
ALTER TABLE PersistantSessionData ADD VariableId BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;
INSERT INTO ConfigurationAdmin VALUES ('u_MaxImageCount', 'la_section_ImageSettings', 'la_config_MaxImageCount', 'text', '', '', 30.01, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_ThumbnailImageWidth', 'la_section_ImageSettings', 'la_config_ThumbnailImageWidth', 'text', '', '', 30.02, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_ThumbnailImageHeight', 'la_section_ImageSettings', 'la_config_ThumbnailImageHeight', 'text', '', '', 30.03, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_FullImageWidth', 'la_section_ImageSettings', 'la_config_FullImageWidth', 'text', '', '', 30.04, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_FullImageHeight', 'la_section_ImageSettings', 'la_config_FullImageHeight', 'text', '', '', 30.05, 0, 0);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_MaxImageCount', 5, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_ThumbnailImageWidth', 120, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_ThumbnailImageHeight', 120, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_FullImageWidth', 450, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_FullImageHeight', 450, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO Counters VALUES (DEFAULT, 'members_count', 'SELECT COUNT(*) FROM <%PREFIX%>PortalUser WHERE Status = 1', NULL , NULL , '3600', '0', '|PortalUser|');
INSERT INTO Counters VALUES (DEFAULT, 'members_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSession WHERE PortalUserId > 0', NULL , NULL , '3600', '0', '|UserSession|');
INSERT INTO Counters VALUES (DEFAULT, 'guests_online', 'SELECT COUNT(*) FROM <%PREFIX%>UserSession WHERE PortalUserId <= 0', NULL , NULL , '3600', '0', '|UserSession|');
+CREATE TABLE ChangeLogs (ChangeLogId bigint(20) NOT NULL auto_increment, PortalUserId int(11) NOT NULL default '0', SessionLogId int(11) NOT NULL default '0', `Action` tinyint(4) NOT NULL default '0', OccuredOn int(11) NOT NULL default '0', Prefix varchar(255) NOT NULL default '', ItemId bigint(20) NOT NULL default '0', Changes text NOT NULL, MasterPrefix varchar(255) NOT NULL default '', MasterId bigint(20) NOT NULL default '0', PRIMARY KEY (ChangeLogId), KEY PortalUserId (PortalUserId), KEY SessionLogId (SessionLogId), KEY `Action` (`Action`), KEY OccuredOn (OccuredOn), KEY Prefix (Prefix), KEY MasterPrefix (MasterPrefix));
+CREATE TABLE SessionLogs (SessionLogId bigint(20) NOT NULL auto_increment, PortalUserId int(11) NOT NULL default '0', SessionId int(10) NOT NULL default '0', `Status` tinyint(4) NOT NULL default '1', SessionStart int(11) NOT NULL default '0', SessionEnd int(11) default NULL, IP varchar(15) NOT NULL default '', AffectedItems int(11) NOT NULL default '0', PRIMARY KEY (SessionLogId), KEY SessionId (SessionId), KEY `Status` (`Status`));
+
UPDATE Modules SET Version = '4.2.3' WHERE Name = 'Core';
UPDATE Modules SET Version = '4.3.0' WHERE Name = 'In-Portal';
\ No newline at end of file
Property changes on: branches/RC/admin/install/upgrades/inportal_upgrade_v4.3.0.sql
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1.2.4
\ No newline at end of property
+1.1.2.5
\ No newline at end of property
Index: branches/RC/core/kernel/constants.php
===================================================================
--- branches/RC/core/kernel/constants.php (revision 10293)
+++ branches/RC/core/kernel/constants.php (revision 10294)
@@ -1,66 +1,75 @@
<?php
// kDBList filter types (then, types are divided into classes)
define('HAVING_FILTER', 1);
define('WHERE_FILTER', 2);
define('AGGREGATE_FILTER', 3);
// kDBList filter classes
define('FLT_SYSTEM', 1); // System Having/Where filter [AND]
define('FLT_NORMAL', 2); // User Having/Where filter [OR]
define('FLT_SEARCH', 3); // User "Search" Having/Where filter [OR]
define('FLT_VIEW', 4); // User "View Menu" Having/Where filter [AND]
define('FLT_CUSTOM', 5); // Custom fields (above) grid columns [AND]
// kMultipleFilter types
define('FLT_TYPE_AND', 'AND');
define('FLT_TYPE_OR', 'OR');
// item statuses
safeDefine('STATUS_DISABLED', 0);
safeDefine('STATUS_ACTIVE', 1);
safeDefine('STATUS_PENDING', 2);
safeDefine('STATUS_PENDING_EDITING', -2);
// sections
define('stTREE', 1);
define('stTAB', 2);
// event statuses
define('erSUCCESS', 0); // event finished working succsessfully
define('erFAIL', -1); // event finished working, but result is unsuccsessfull
define('erFATAL', -2); // event experienced FATAL error - no hooks should continue!
define('erPERM_FAIL', -3); // event failed on internal permission checking (user has not permission)
define('erSTOP', -4); // event requested to stop processing (don't parse templates)
// permission types
define('ptCATEGORY', 0);
define('ptSYSTEM', 1);
// email event statuses & types
define('EVENT_TYPE_FRONTEND', 0);
define('EVENT_TYPE_ADMIN', 1);
define('EVENT_STATUS_DISABLED', 0);
define('EVENT_STATUS_ENABLED', 1);
define('EVENT_STATUS_FRONTEND', 2);
define('EDIT_MARK', '&|edit|&'); // replace this sequence inside filters to SID[_main_wid]
$application =& kApplication::Instance();
$spacer_url = $application->BaseURL().'core/admin_templates/img/spacer.gif';
define('SPACER_URL', $spacer_url);
if (!$application->IsAdmin()) {
// don't show debugger buttons on front (if not overrided in "debug.php")
safeDefine('DBG_TOOLBAR_BUTTONS', 0);
}
define('smDEBUG', 2); // show section in debug mode only
define('smSUPER_ADMIN', 4); // show section in super admin & debug mode
// common usage regular expressions
define('REGEX_EMAIL_USER', '[-a-zA-Z0-9!\#$%&*+\/=?^_`{|}~.]+');
define('REGEX_EMAIL_DOMAIN', '[a-zA-Z0-9]{1}[-.a-zA-Z0-9_]*\.[a-zA-Z]{2,6}');
define('ALLOW_DEFAULT_SETTINGS', '_USE_DEFAULT_USER_DATA_'); //Allow persistent vars to take data from default user's persistent data
+
+ define('XML_NO_TEXT_NODES', 1); // Normal mode for XMLHelper
+ define('XML_WITH_TEXT_NODES', 2); // Will create text nodes for every char-data (used in kPDFHelper)
+
+ // ChangeLog actions
+ define('clCREATE', 1);
+ define('clUPDATE', 2);
+ define('clDELETE', 3);
+
?>
\ No newline at end of file
Property changes on: branches/RC/core/kernel/constants.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.7.2.2
\ No newline at end of property
+1.7.2.3
\ No newline at end of property
Index: branches/RC/core/kernel/session/session.php
===================================================================
--- branches/RC/core/kernel/session/session.php (revision 10293)
+++ branches/RC/core/kernel/session/session.php (revision 10294)
@@ -1,1011 +1,1022 @@
<?php
/*
The session works the following way:
1. When a visitor loads a page from the site the script checks if cookies_on varibale has been passed to it as a cookie.
2. If it has been passed, the script tries to get Session ID (SID) from the request:
3. Depending on session mode the script is getting SID differently.
The following modes are available:
smAUTO - Automatic mode: if cookies are on at the client side, the script relays only on cookies and
ignore all other methods of passing SID.
If cookies are off at the client side, the script relays on SID passed through query string
and referal passed by the client. THIS METHOD IS NOT 100% SECURE, as long as attacker may
get SID and substitude referal to gain access to user' session. One of the faults of this method
is that the session is only created when the visitor clicks the first link on the site, so
there is NO session at the first load of the page. (Actually there is a session, but it gets lost
after the first click because we do not use SID in query string while we are not sure if we need it)
smCOOKIES_ONLY - Cookies only: in this mode the script relays solely on cookies passed from the browser
and ignores all other methods. In this mode there is no way to use sessions for clients
without cookies support or cookies support disabled. The cookies are stored with the
full domain name and path to base-directory of script installation.
smGET_ONLY - GET only: the script will not set any cookies and will use only SID passed in
query string using GET, it will also check referal. The script will set SID at the
first load of the page
smCOOKIES_AND_GET - Combined mode: the script will use both cookies and GET right from the start. If client has
cookies enabled, the script will check SID stored in cookie and passed in query string, and will
use this SID only if both cookie and query string matches. However if cookies are disabled on the
client side, the script will work the same way as in GET_ONLY mode.
4. After the script has the SID it tries to load it from the Storage (default is database)
5. If such SID is found in the database, the script checks its expiration time. If session is not expired, it updates
its expiration, and resend the cookie (if applicable to session mode)
6. Then the script loads all the data (session variables) pertaining to the SID.
Usage:
$session = new Session(smAUTO); //smAUTO is default, you could just leave the brackets empty, or provide another mode
$session->SetCookieDomain('my.domain.com');
$session->SetCookiePath('/myscript');
$session->SetCookieName('my_sid_cookie');
$session->SetGETName('sid');
$session->InitSession();
...
//link output:
echo "<a href='index.php?'". ( $session->NeedQueryString() ? 'sid='.$session->SID : '' ) .">My Link</a>";
*/
//Implements session storage in the database
class SessionStorage extends kDBBase {
var $Expiration;
var $SessionTimeout=0;
var $DirectVars = Array();
var $ChangedDirectVars = Array();
var $PersistentVars = Array ();
var $OriginalData=Array();
var $TimestampField;
var $SessionDataTable;
var $DataValueField;
var $DataVarField;
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->setTableName('sessions');
$this->setIDField('sid');
$this->TimestampField = 'expire';
$this->SessionDataTable = 'SessionData';
$this->DataValueField = 'value';
$this->DataVarField = 'var';
}
function setSessionTimeout($new_timeout)
{
$this->SessionTimeout = $new_timeout;
}
function StoreSession(&$session, $additional_fields = Array())
{
if (defined('IS_INSTALL') && IS_INSTALL && !$this->Application->TableFound($this->TableName)) {
return false;
}
$fields_hash = Array (
$this->IDField => $session->SID,
$this->TimestampField => $session->Expiration
);
$this->Conn->doInsert($fields_hash, $this->TableName);
foreach ($additional_fields as $field_name => $field_value) {
$this->SetField($session, $field_name, $field_value);
}
}
function DeleteSession(&$session)
{
$query = ' DELETE FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
$query = ' DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
$this->OriginalData = Array();
}
function UpdateSession(&$session, $timeout=0)
{
$this->SetField($session, $this->TimestampField, $session->Expiration);
$query = ' UPDATE '.$this->TableName.' SET '.$this->TimestampField.' = '.$session->Expiration.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->Conn->Query($query);
}
function LocateSession($sid)
{
$query = ' SELECT * FROM '.$this->TableName.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($sid);
$result = $this->Conn->GetRow($query);
if($result===false) return false;
$this->DirectVars = $result;
$this->Expiration = $result[$this->TimestampField];
return true;
}
function GetExpiration()
{
return $this->Expiration;
}
function LoadData(&$session)
{
$query = 'SELECT '.$this->DataValueField.','.$this->DataVarField.' FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID);
$this->OriginalData = $this->Conn->GetCol($query, $this->DataVarField);
return $this->OriginalData;
}
/**
* Enter description here...
*
* @param Session $session
* @param string $var_name
* @param mixed $default
*/
function GetField(&$session, $var_name, $default = false)
{
return isset($this->DirectVars[$var_name]) ? $this->DirectVars[$var_name] : $default;
//return $this->Conn->GetOne('SELECT '.$var_name.' FROM '.$this->TableName.' WHERE `'.$this->IDField.'` = '.$this->Conn->qstr($session->GetID()) );
}
function SetField(&$session, $var_name, $value)
{
$value_changed = !isset($this->DirectVars[$var_name]) || ($this->DirectVars[$var_name] != $value);
if ($value_changed) {
$this->DirectVars[$var_name] = $value;
$this->ChangedDirectVars[] = $var_name;
$this->ChangedDirectVars = array_unique($this->ChangedDirectVars);
}
//return $this->Conn->Query('UPDATE '.$this->TableName.' SET '.$var_name.' = '.$this->Conn->qstr($value).' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->GetID()) );
}
function SaveData(&$session)
{
if(!$session->SID) return false; // can't save without sid
$ses_data = $session->Data->GetParams();
$replace = '';
foreach ($ses_data as $key => $value)
{
if ( isset($this->OriginalData[$key]) && $this->OriginalData[$key] == $value)
{
continue; //skip unchanged session data
}
else
{
$replace .= sprintf("(%s, %s, %s),",
$this->Conn->qstr($session->SID),
$this->Conn->qstr($key),
$this->Conn->qstr($value));
}
}
$replace = rtrim($replace, ',');
if ($replace != '') {
$query = ' REPLACE INTO '.$this->SessionDataTable. ' ('.$this->IDField.', '.$this->DataVarField.', '.$this->DataValueField.') VALUES '.$replace;
$this->Conn->Query($query);
}
if ($this->ChangedDirectVars) {
$changes = array();
foreach ($this->ChangedDirectVars as $var) {
$changes[] = $var.' = '.$this->Conn->qstr($this->DirectVars[$var]);
}
$query = 'UPDATE '.$this->TableName.' SET '.implode(',', $changes).' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->GetID());
$this->Conn->Query($query);
}
}
function RemoveFromData(&$session, $var)
{
$query = 'DELETE FROM '.$this->SessionDataTable.' WHERE '.$this->IDField.' = '.$this->Conn->qstr($session->SID).
' AND '.$this->DataVarField.' = '.$this->Conn->qstr($var);
$this->Conn->Query($query);
unset($this->OriginalData[$var]);
}
function GetFromData(&$session, $var)
{
return getArrayValue($this->OriginalData, $var);
}
function GetExpiredSIDs()
{
$query = ' SELECT '.$this->IDField.' FROM '.$this->TableName.' WHERE '.$this->TimestampField.' > '.adodb_mktime();
return $this->Conn->GetCol($query);
}
function DeleteExpired()
{
$expired_sids = $this->GetExpiredSIDs();
if ($expired_sids) {
- $where_clause=' WHERE '.$this->IDField.' IN ("'.implode('","',$expired_sids).'")';
+ $sessionlog_table = $this->Application->getUnitOption('session-log', 'TableName');
+ $session_log_sql =
+ ' UPDATE '.$sessionlog_table.'
+ SET Status = 2, SessionEnd =
+ ( SELECT '.$this->TimestampField.' - '.$this->SessionTimeout.'
+ FROM '.$this->TableName.'
+ WHERE '.$this->IDField.' = '.$sessionlog_table.'.SessionId
+ )
+ WHERE Status = 0 AND SessionId IN ('.join(',', $expired_sids).')';
+ $this->Conn->Query($session_log_sql);
+
+ $where_clause = ' WHERE '.$this->IDField.' IN ("'.implode('","',$expired_sids).'")';
$sql = 'DELETE FROM '.$this->SessionDataTable.$where_clause;
$this->Conn->Query($sql);
$sql = 'DELETE FROM '.$this->TableName.$where_clause;
$this->Conn->Query($sql);
// delete debugger ouputs left of expired sessions
foreach ($expired_sids as $expired_sid) {
- $debug_file = KERNEL_PATH.'/../cache/debug_@'.$expired_sid.'@.txt';
+ $debug_file = (defined('WRITEABLE') ? WRITEABLE : FULL_PATH.'/kernel').'/cache/debug_@'.$expired_sid.'@.txt';
if (file_exists($debug_file)) {
@unlink($debug_file);
}
}
}
return $expired_sids;
}
function LoadPersistentVars(&$session)
{
$user_id = $session->RecallVar('user_id');
if ($user_id != -2) {
// root & normal users
$sql = 'SELECT VariableValue, VariableName
FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE PortalUserId = '.$user_id;
$this->PersistentVars = $this->Conn->GetCol($sql, 'VariableName');
}
else {
$this->PersistentVars = Array ();
}
}
/**
* Stores variable to persistent session
*
* @param Session $session
* @param string $var_name
* @param mixed $var_value
*/
function StorePersistentVar(&$session, $var_name, $var_value)
{
$user_id = $session->RecallVar('user_id');
if ($user_id == -2 || $user_id === false) {
// -2 (when not logged in), false (when after u:OnLogout event)
$session->StoreVar($var_name, $var_value);
return ;
}
$this->PersistentVars[$var_name] = $var_value;
$key_clause = 'PortalUserId = '.$user_id.' AND VariableName = '.$this->Conn->qstr($var_name);
$sql = 'SELECT VariableName
FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE '.$key_clause;
$record_found = $this->Conn->GetOne($sql);
$fields_hash = Array (
'PortalUserId' => $user_id,
'VariableName' => $var_name,
'VariableValue' => $var_value,
);
if ($record_found) {
$this->Conn->doUpdate($fields_hash, TABLE_PREFIX.'PersistantSessionData', $key_clause);
}
else {
$this->Conn->doInsert($fields_hash, TABLE_PREFIX.'PersistantSessionData');
}
}
/**
* Gets persistent variable
*
* @param Session $session
* @param string $var_name
* @param mixed $default
* @return mixed
*/
function RecallPersistentVar(&$session, $var_name, $default = false)
{
if ($session->RecallVar('user_id') == -2) {
if ($default == '_USE_DEFAULT_USER_DATA_') {
$default = null;
}
return $session->RecallVar($var_name, $default);
}
if (array_key_exists($var_name, $this->PersistentVars)) {
return $this->PersistentVars[$var_name];
}
elseif ($default == '_USE_DEFAULT_USER_DATA_') {
$default_user_id = $this->Application->ConfigValue('DefaultSettingsUserId');
if (!$default_user_id) {
$default_user_id = -1;
}
$sql = 'SELECT VariableValue, VariableName
FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE VariableName = '.$this->Conn->qstr($var_name).' AND PortalUserId = '.$default_user_id;
$value = $this->Conn->GetOne($sql);
$this->PersistentVars[$var_name] = $value;
if ($value !== false) {
$this->StorePersistentVar($session, $var_name, $value); //storing it, so next time we don't load default user setting
}
return $value;
}
else {
return $default;
}
}
function RemovePersistentVar(&$session, $var_name)
{
unset($this->PersistentVars[$var_name]);
$user_id = $session->RecallVar('user_id');
if ($user_id != -2) {
$sql = 'DELETE FROM '.TABLE_PREFIX.'PersistantSessionData
WHERE PortalUserId = '.$user_id.' AND VariableName = '.$this->Conn->qstr($var_name);
$this->Conn->Query($sql);
}
}
}
define('smAUTO', 1);
define('smCOOKIES_ONLY', 2);
define('smGET_ONLY', 3);
define('smCOOKIES_AND_GET', 4);
class Session extends kBase {
var $Checkers;
var $Mode;
var $OriginalMode = null;
var $GETName = 'sid';
var $CookiesEnabled = true;
var $CookieName = 'sid';
var $CookieDomain;
var $CookiePath;
var $CookieSecure = 0;
var $SessionTimeout = 3600;
var $Expiration;
var $SID;
/**
* Enter description here...
*
* @var SessionStorage
*/
var $Storage;
var $CachedNeedQueryString = null;
var $Data;
function Session($mode=smAUTO)
{
parent::kBase();
$this->SetMode($mode);
}
function SetMode($mode)
{
$this->Mode = $mode;
$this->CachedNeedQueryString = null;
$this->CachedSID = null;
}
function SetCookiePath($path)
{
$this->CookiePath = str_replace(' ', '%20', $path);
}
function SetCookieDomain($domain)
{
$this->CookieDomain = '.'.ltrim($domain, '.');
}
function SetGETName($get_name)
{
$this->GETName = $get_name;
}
function SetCookieName($cookie_name)
{
$this->CookieName = $cookie_name;
}
function InitStorage($special)
{
$this->Storage =& $this->Application->recallObject('SessionStorage.'.$special);
$this->Storage->setSessionTimeout($this->SessionTimeout);
}
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->CheckIfCookiesAreOn();
if ($this->CookiesEnabled) $_COOKIE['cookies_on'] = 1;
$this->Checkers = Array();
$this->InitStorage($special);
$this->Data = new Params();
$tmp_sid = $this->GetPassedSIDValue();
$check = $this->Check();
if( !(defined('IS_INSTALL') && IS_INSTALL) )
{
$expired_sids = $this->DeleteExpired();
if ( ( $expired_sids && in_array($tmp_sid,$expired_sids) ) || ( $tmp_sid && !$check ) ) {
$this->SetSession();
$this->Application->HandleEvent($event, 'u:OnSessionExpire');
return ;
}
}
if ($check) {
$this->SID = $this->GetPassedSIDValue();
$this->Refresh();
$this->LoadData();
}
else {
$this->SetSession();
}
if (!is_null($this->OriginalMode)) $this->SetMode($this->OriginalMode);
}
function IsHTTPSRedirect()
{
$http_referer = getArrayValue($_SERVER, 'HTTP_REFERER');
return (
( PROTOCOL == 'https://' && preg_match('#http:\/\/#', $http_referer) )
||
( PROTOCOL == 'http://' && preg_match('#https:\/\/#', $http_referer) )
);
}
function CheckReferer($for_cookies=0)
{
if (!$for_cookies) {
if ( !$this->Application->ConfigValue('SessionReferrerCheck') || $_SERVER['REQUEST_METHOD'] != 'POST') {
return true;
}
}
$path = preg_replace('/admin[\/]{0,1}$/', '', $this->CookiePath); // removing /admin for compatability with in-portal (in-link/admin/add_link.php)
$reg = '#^'.preg_quote(PROTOCOL.ltrim($this->CookieDomain, '.').$path).'#';
return preg_match($reg, getArrayValue($_SERVER, 'HTTP_REFERER') ) || (defined('IS_POPUP') && IS_POPUP);
}
/*function CheckDuplicateCookies()
{
if (isset($_SERVER['HTTP_COOKIE'])) {
$cookie_str = $_SERVER['HTTP_COOKIE'];
$cookies = explode('; ', $cookie_str);
$all_cookies = array();
foreach ($cookies as $cookie) {
list($name, $value) = explode('=', $cookie);
if (isset($all_cookies[$name])) {
//double cookie name!!!
$this->RemoveCookie($name);
}
else $all_cookies[$name] = $value;
}
}
}
function RemoveCookie($name)
{
$path = $_SERVER['PHP_SELF'];
$path_parts = explode('/', $path);
$cur_path = '';
setcookie($name, false, null, $cur_path);
foreach ($path_parts as $part) {
$cur_path .= $part;
setcookie($name, false, null, $cur_path);
$cur_path .= '/';
setcookie($name, false, null, $cur_path);
}
}*/
function CheckIfCookiesAreOn()
{
// $this->CheckDuplicateCookies();
if ($this->Mode == smGET_ONLY)
{
//we don't need to bother checking if we would not use it
$this->CookiesEnabled = false;
return;
}
$http_query =& $this->Application->recallObject('HTTPQuery');
$cookies_on = isset($http_query->Cookie['cookies_on']); // not good here
$get_sid = getArrayValue($http_query->Get, $this->GETName);
if ($this->IsHTTPSRedirect() && $get_sid) { //Redirect from http to https on different domain
$this->OriginalMode = $this->Mode;
$this->SetMode(smGET_ONLY);
}
if (!$cookies_on || $this->IsHTTPSRedirect()) {
//If referer is our server, but we don't have our cookies_on, it's definetly off
$is_install = defined('IS_INSTALL') && IS_INSTALL;
if (!$is_install && $this->CheckReferer(1) && !$this->Application->GetVar('admin') && !$this->IsHTTPSRedirect()) {
$this->CookiesEnabled = false;
}
else {
//Otherwise we still suppose cookies are on, because may be it's the first time user visits the site
//So we send cookies on to get it next time (when referal will tell us if they are realy off
$this->SetCookie('cookies_on', 1, adodb_mktime() + 31104000); //one year should be enough
}
}
else
$this->CookiesEnabled = true;
return $this->CookiesEnabled;
}
/**
* Sets cookie for current site using path and domain
*
* @param string $name
* @param mixed $value
* @param int $expires
*/
function SetCookie($name, $value, $expires = null)
{
setcookie($name, $value, $expires, $this->CookiePath, $this->CookieDomain, $this->CookieSecure);
}
function Check()
{
// we should check referer if cookies are disabled, and in combined mode
// auto mode would detect cookies, get only mode would turn it off - so we would get here
// and we don't care about referal in cookies only mode
if ( $this->Mode != smCOOKIES_ONLY && (!$this->CookiesEnabled || $this->Mode == smCOOKIES_AND_GET) ) {
if (!$this->CheckReferer())
return false;
}
$sid = $this->GetPassedSIDValue();
if (empty($sid)) return false;
//try to load session by sid, if everything is fine
$result = $this->LoadSession($sid);
return $result;
}
function LoadSession($sid)
{
if( $this->Storage->LocateSession($sid) ) {
//if we have session with such SID - get its expiration
$this->Expiration = $this->Storage->GetExpiration();
//If session has expired
if ($this->Expiration < adodb_mktime()) return false;
//Otherwise it's ok
return true;
}
else //fake or deleted due to expiration SID
return false;
}
function GetPassedSIDValue($use_cache = 1)
{
if (!empty($this->CachedSID) && $use_cache) return $this->CachedSID;
$http_query =& $this->Application->recallObject('HTTPQuery');
$get_sid = getArrayValue($http_query->Get, $this->GETName);
if ($this->Application->GetVar('admin') == 1 && $get_sid) {
$sid = $get_sid;
}
else {
switch ($this->Mode) {
case smAUTO:
//Cookies has the priority - we ignore everything else
$sid = $this->CookiesEnabled ? $this->GetSessionCookie() : $get_sid;
break;
case smCOOKIES_ONLY:
$sid = $this->GetSessionCookie();
break;
case smGET_ONLY:
$sid = $get_sid;
break;
case smCOOKIES_AND_GET:
$cookie_sid = $this->GetSessionCookie();
//both sids should match if cookies are enabled
if (!$this->CookiesEnabled || ($cookie_sid == $get_sid))
{
$sid = $get_sid; //we use get here just in case cookies are disabled
}
else
{
$sid = '';
}
break;
}
}
$this->CachedSID = $sid;
return $this->CachedSID;
}
/**
* Returns session id
*
* @return int
* @access public
*/
function GetID()
{
return $this->SID;
}
/**
* Generates new session id
*
* @return int
* @access private
*/
function GenerateSID()
{
list($usec, $sec) = explode(" ",microtime());
$sid_part_1 = substr($usec, 4, 4);
$sid_part_2 = mt_rand(1,9);
$sid_part_3 = substr($sec, 6, 4);
$digit_one = substr($sid_part_1, 0, 1);
if ($digit_one == 0) {
$digit_one = mt_rand(1,9);
$sid_part_1 = ereg_replace("^0","",$sid_part_1);
$sid_part_1=$digit_one.$sid_part_1;
}
$this->setSID($sid_part_1.$sid_part_2.$sid_part_3);
return $this->SID;
}
/**
* Set's new session id
*
* @param int $new_sid
* @access private
*/
function setSID($new_sid)
{
$this->SID=$new_sid;
$this->Application->SetVar($this->GETName,$new_sid);
}
function SetSession()
{
$this->GenerateSID();
$this->Expiration = adodb_mktime() + $this->SessionTimeout;
switch ($this->Mode) {
case smAUTO:
if ($this->CookiesEnabled) {
$this->SetSessionCookie();
}
break;
case smGET_ONLY:
break;
case smCOOKIES_ONLY:
case smCOOKIES_AND_GET:
$this->SetSessionCookie();
break;
}
$this->Storage->StoreSession($this);
if ($this->Application->IsAdmin() || $this->Special == 'admin') {
$this->StoreVar('admin', 1);
}
if ($this->Special != '') {
// front-session called from admin or otherwise, then save it's data
$this->SaveData();
}
$this->Application->resetCounters('UserSession');
}
/**
* Returns SID from cookie
*
* @return int
*/
function GetSessionCookie()
{
$keep_session_on_browser_close = $this->Application->ConfigValue('KeepSessionOnBrowserClose');
if (isset($this->Application->HttpQuery->Cookie[$this->CookieName]) &&
( $keep_session_on_browser_close ||
(
!$keep_session_on_browser_close &&
isset($this->Application->HttpQuery->Cookie[$this->CookieName.'_live'])
&&
$this->Application->HttpQuery->Cookie[$this->CookieName] == $this->Application->HttpQuery->Cookie[$this->CookieName.'_live']
)
)
) {
return $this->Application->HttpQuery->Cookie[$this->CookieName];
}
return false;
}
/**
* Updates SID in cookie with new value
*
*/
function SetSessionCookie()
{
$this->SetCookie($this->CookieName, $this->SID, $this->Expiration);
$this->SetCookie($this->CookieName.'_live', $this->SID);
$_COOKIE[$this->CookieName] = $this->SID; // for compatibility with in-portal
}
/**
* Refreshes session expiration time
*
* @access private
*/
function Refresh()
{
if ($this->CookiesEnabled) $this->SetSessionCookie(); //we need to refresh the cookie
$this->Storage->UpdateSession($this);
}
function Destroy()
{
$this->Storage->DeleteSession($this);
$this->Data = new Params();
$this->SID = '';
if ($this->CookiesEnabled) $this->SetSessionCookie(); //will remove the cookie due to value (sid) is empty
$this->SetSession(); //will create a new session
}
function NeedQueryString($use_cache = 1)
{
if ($this->CachedNeedQueryString != null && $use_cache) return $this->CachedNeedQueryString;
$result = false;
switch ($this->Mode)
{
case smAUTO:
if (!$this->CookiesEnabled) $result = true;
break;
/*case smCOOKIES_ONLY:
break;*/
case smGET_ONLY:
case smCOOKIES_AND_GET:
$result = true;
break;
}
$this->CachedNeedQueryString = $result;
return $result;
}
function LoadData()
{
$this->Data->AddParams($this->Storage->LoadData($this));
}
function PrintSession($comment='')
{
if($this->Application->isDebugMode() && constOn('DBG_SHOW_SESSIONDATA')) {
// dump session data
$this->Application->Debugger->appendHTML('SessionStorage ('.$comment.'):');
$session_data = $this->Data->GetParams();
ksort($session_data);
foreach ($session_data as $session_key => $session_value) {
if (IsSerialized($session_value)) {
$session_data[$session_key] = unserialize($session_value);
}
}
$this->Application->Debugger->dumpVars($session_data);
}
if ($this->Application->isDebugMode() && constOn('DBG_SHOW_PERSISTENTDATA')) {
// dump persistent session data
if ($this->Storage->PersistentVars) {
$this->Application->Debugger->appendHTML('Persistant Session:');
$session_data = $this->Storage->PersistentVars;
ksort($session_data);
foreach ($session_data as $session_key => $session_value) {
if (IsSerialized($session_value)) {
$session_data[$session_key] = unserialize($session_value);
}
}
$this->Application->Debugger->dumpVars($session_data);
}
}
}
function SaveData()
{
if (!$this->Application->GetVar('skip_last_template') && $this->Application->GetVar('ajax') != 'yes') {
$this->SaveLastTemplate( $this->Application->GetVar('t') );
}
$this->PrintSession('after save');
$this->Storage->SaveData($this);
}
function SaveLastTemplate($t)
{
// save last_template
$wid = $this->Application->GetVar('m_wid');
$last_env = $this->getLastTemplateENV($t, Array('m_opener' => 'u'));
$last_template = basename($_SERVER['PHP_SELF']).'|'.mb_substr($last_env, mb_strlen(ENV_VAR_NAME) + 1);
$this->StoreVar(rtrim('last_template_'.$wid, '_'), $last_template);
$last_env = $this->getLastTemplateENV($t, null, false);
$last_template = basename($_SERVER['PHP_SELF']).'|'.mb_substr($last_env, mb_strlen(ENV_VAR_NAME) + 1);
$this->StoreVar(rtrim('last_template_popup_'.$wid, '_'), $last_template);
// save other last... variables for mistical purposes (customizations may be)
$this->StoreVar('last_url', $_SERVER['REQUEST_URI']); // needed by ord:StoreContinueShoppingLink
$this->StoreVar('last_env', mb_substr($last_env, mb_strlen(ENV_VAR_NAME)+1));
// save last_template in persistant session
if (!$wid) {
if ($this->Application->IsAdmin()) {
// only for main window, not popups, not login template, not temp mode (used in adm:MainFrameLink tag)
$temp_mode = false;
$passed = explode(',', $this->Application->GetVar('passed'));
foreach ($passed as $passed_prefix) {
if ($this->Application->GetVar($passed_prefix.'_mode')) {
$temp_mode = true;
break;
}
}
if (!$temp_mode) {
if (isset($this->Application->HttpQuery->Get['section'])) {
// check directly in GET, bacause LinkVar (session -> request) used on these vars
$last_template .= '&section='.$this->Application->GetVar('section').'&module='.$this->Application->GetVar('module');
}
$this->StorePersistentVar('last_template_popup', $last_template);
}
}
elseif ($this->Application->GetVar('admin') == 1) {
$admin_session =& $this->Application->recallObject('Session.admin');
/* @var $admin_ses Session */
$admin_session->StorePersistentVar('last_template_popup', '../'.$last_template);
}
}
}
function getLastTemplateENV($t, $params = null, $encode = true)
{
if (!isset($params)) {
$params = Array ();
}
$params['__URLENCODE__'] = 1; // uses "&" instead of "&amp;" for url part concatenation + replaces "\" to "%5C" (works in HTML)
$ret = $this->Application->BuildEnv($t, $params, 'all');
if (!$encode) {
// cancels 2nd part of replacements, that URLENCODE does
$ret = str_replace('%5C', '\\', $ret);
}
return $ret;
}
function StoreVar($name, $value)
{
$this->Data->Set($name, $value);
}
function StorePersistentVar($name, $value)
{
$this->Storage->StorePersistentVar($this, $name, $value);
}
function LoadPersistentVars()
{
$this->Storage->LoadPersistentVars($this);
}
function StoreVarDefault($name, $value)
{
$tmp = $this->RecallVar($name);
if($tmp === false || $tmp == '')
{
$this->StoreVar($name, $value);
}
}
function RecallVar($name, $default = false)
{
$ret = $this->Data->Get($name);
return ($ret === false) ? $default : $ret;
}
function RecallPersistentVar($name, $default = false)
{
return $this->Storage->RecallPersistentVar($this, $name, $default);
}
function RemoveVar($name)
{
$this->Storage->RemoveFromData($this, $name);
$this->Data->Remove($name);
}
function RemovePersistentVar($name)
{
return $this->Storage->RemovePersistentVar($this, $name);
}
/**
* Ignores session varible value set before
*
* @param string $name
*/
function RestoreVar($name)
{
return $this->StoreVar($name, $this->Storage->GetFromData($this, $name));
}
function GetField($var_name, $default = false)
{
return $this->Storage->GetField($this, $var_name, $default);
}
function SetField($var_name, $value)
{
$this->Storage->SetField($this, $var_name, $value);
}
/**
* Deletes expired sessions
*
* @return Array expired sids if any
* @access private
*/
function DeleteExpired()
{
return $this->Storage->DeleteExpired();
}
/**
* Allows to check if user in this session is logged in or not
*
* @return bool
*/
function LoggedIn()
{
$user_id = $this->RecallVar('user_id');
$ret = $user_id > 0;
if ($this->RecallVar('admin') == 1 && ($user_id == -1)) {
$ret = true;
}
return $ret;
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/kernel/session/session.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.59.2.9
\ No newline at end of property
+1.59.2.10
\ No newline at end of property
Index: branches/RC/core/kernel/utility/formatters/left_formatter.php
===================================================================
--- branches/RC/core/kernel/utility/formatters/left_formatter.php (revision 10293)
+++ branches/RC/core/kernel/utility/formatters/left_formatter.php (revision 10294)
@@ -1,67 +1,68 @@
<?php
/**
* Replacement for kOptionsFormatter in case if options
* should be selected from database. Use this formatter
* only in case if formatter attached field is in edit form.
*
* For usage in grid just use LEFT JOIN clause to table
* where requested options are located.
*/
class kLEFTFormatter extends kFormatter {
function Format($value, $field_name, &$object, $format=null)
{
if ( is_null($value) ) return '';
$options = $object->GetFieldOptions($field_name);
if ( isset($format) ) $options['format'] = $format;
if( !isset($options['options'][$value]) )
{
// required option is not defined in config => query for it
$db =& $this->Application->GetADODBConnection();
$sql = sprintf($options['left_sql'],$options['left_title_field'],$options['left_key_field'],$value);
$options['options'][$value] = $db->GetOne($sql);
if ($options['options'][$value] === false) return $value;
}
return $options['options'][$value];
}
/**
* Parse value from form submit
*
* @param mixed $value
* @param string $field_name
* @param kDBItem $object
* @return mixed
*/
function Parse($value, $field_name, &$object)
{
if ($value == '') return NULL;
$options = $object->GetFieldOptions($field_name);
$found = isset($options['options']) ? array_search($value, $options['options']) : false;
if ($found !== false) {
// requested option found among field options
return $found;
}
// requested option is not found in field options -> query for it
$db =& $this->Application->GetADODBConnection();
$sql = sprintf($options['left_sql'], $options['left_key_field'], $options['left_title_field'], $value);
$found = $db->GetOne($sql);
if ($found !== false) {
// option successfully retrieved from db -> cache it
$options['options'][$found] = $value;
}
- if ($found === false) {
+ $skip_errors = array_key_exists('skip_errors', $options) && $options['skip_errors'];
+ if ($found === false && !$skip_errors) {
// option not found at all -> return not formatted value & set error
$object->SetError($field_name, 'invalid_option', 'la_error_InvalidOption');
return $value;
}
return $found;
}
}
\ No newline at end of file
Property changes on: branches/RC/core/kernel/utility/formatters/left_formatter.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.4
\ No newline at end of property
+1.4.2.1
\ No newline at end of property
Index: branches/RC/core/kernel/utility/temp_handler.php
===================================================================
--- branches/RC/core/kernel/utility/temp_handler.php (revision 10293)
+++ branches/RC/core/kernel/utility/temp_handler.php (revision 10294)
@@ -1,790 +1,814 @@
<?php
class kTempTablesHandler extends kBase {
var $Tables = Array();
/**
* Master table name for temp handler
*
* @var string
* @access private
*/
var $MasterTable = '';
/**
* IDs from master table
*
* @var Array
* @access private
*/
var $MasterIDs = Array();
var $AlreadyProcessed = Array();
var $DroppedTables = Array();
var $FinalRefs = Array();
var $CopiedTables = Array();
/**
* IDs of newly cloned items (key - prefix.special, value - array of ids)
*
* @var Array
*/
var $savedIDs = Array();
/**
* Description
*
* @var kDBConnection
* @access public
*/
var $Conn;
/**
* Window ID of current window
*
* @var mixed
*/
var $WindowID = '';
function kTempTablesHandler()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
function SetTables($tables)
{
// set tablename as key for tables array
$ret = Array();
$this->Tables = $tables;
$this->MasterTable = $tables['TableName'];
}
function saveID($prefix, $special = '', $id = null)
{
if (!isset($this->savedIDs[$prefix.($special ? '.' : '').$special])) {
$this->savedIDs[$prefix.($special ? '.' : '').$special] = array();
}
if (is_array($id)) {
foreach ($id as $tmp_id => $live_id) {
$this->savedIDs[$prefix.($special ? '.' : '').$special][$tmp_id] = $live_id;
}
}
else {
$this->savedIDs[$prefix.($special ? '.' : '').$special][] = $id;
}
}
/**
* Get temp table name
*
* @param string $table
* @return string
*/
function GetTempName($table)
{
return $this->Application->GetTempName($table, $this->WindowID);
}
function GetTempTablePrefix()
{
return $this->Application->GetTempTablePrefix($this->WindowID);
}
/**
* Return live table name based on temp table name
*
* @param string $temp_table
* @return string
*/
function GetLiveName($temp_table)
{
return $this->Application->GetLiveName($temp_table);
}
function IsTempTable($table)
{
return $this->Application->IsTempTable($table);
}
/**
* Return temporary table name for master table
*
* @return string
* @access public
*/
function GetMasterTempName()
{
return $this->GetTempName($this->MasterTable);
}
function CreateTempTable($table)
{
$query = sprintf("CREATE TABLE %s SELECT * FROM %s WHERE 0",
$this->GetTempName($table),
$table);
$this->Conn->Query($query);
}
function BuildTables($prefix, $ids)
{
$this->WindowID = $this->Application->GetVar('m_wid');
$this->TableIdCounter = 0;
$tables = Array(
'TableName' => $this->Application->getUnitOption($prefix, 'TableName'),
'IdField' => $this->Application->getUnitOption($prefix, 'IDField'),
'IDs' => $ids,
'Prefix' => $prefix,
'TableId' => $this->TableIdCounter++,
);
/*$parent_prefix = $this->Application->getUnitOption($prefix, 'ParentPrefix');
if ($parent_prefix) {
$tables['ForeignKey'] = $this->Application->getUnitOption($prefix, 'ForeignKey');
$tables['ParentPrefix'] = $parent_prefix;
$tables['ParentTableKey'] = $this->Application->getUnitOption($prefix, 'ParentTableKey');
}*/
$this->FinalRefs[ $tables['TableName'] ] = $tables['TableId']; // don't forget to add main table to FinalRefs too
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
if (is_array($SubItems)) {
foreach ($SubItems as $prefix) {
$this->AddTables($prefix, $tables);
}
}
$this->SetTables($tables);
}
/**
* Searches through TempHandler tables info for required prefix
*
* @param string $prefix
* @param Array $master
* @return mixed
*/
function SearchTable($prefix, $master = null)
{
if (is_null($master)) {
$master = $this->Tables;
}
if ($master['Prefix'] == $prefix) {
return $master;
}
if (isset($master['SubTables'])) {
foreach ($master['SubTables'] as $sub_table) {
$found = $this->SearchTable($prefix, $sub_table);
if ($found !== false) {
return $found;
}
}
}
return false;
}
function AddTables($prefix, &$tables)
{
if (!$this->Application->prefixRegistred($prefix)) {
// allows to skip subitem processing if subitem module not enabled/installed
return ;
}
$tmp = Array(
'TableName' => $this->Application->getUnitOption($prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($prefix,'ForeignKey'),
'ParentPrefix' => $this->Application->getUnitOption($prefix, 'ParentPrefix'),
'ParentTableKey' => $this->Application->getUnitOption($prefix,'ParentTableKey'),
'Prefix' => $prefix,
'AutoClone' => $this->Application->getUnitOption($prefix,'AutoClone'),
'AutoDelete' => $this->Application->getUnitOption($prefix,'AutoDelete'),
'TableId' => $this->TableIdCounter++,
);
$this->FinalRefs[ $tmp['TableName'] ] = $tmp['TableId'];
$constrain = $this->Application->getUnitOption($prefix,'Constrain');
if ($constrain)
{
$tmp['Constrain'] = $constrain;
$this->FinalRefs[ $tmp['TableName'].$tmp['Constrain'] ] = $tmp['TableId'];
}
$SubItems = $this->Application->getUnitOption($prefix,'SubItems');
$same_sub_counter = 1;
if( is_array($SubItems) )
{
foreach($SubItems as $prefix)
{
$this->AddTables($prefix, $tmp);
}
}
if ( !is_array(getArrayValue($tables, 'SubTables')) ) {
$tables['SubTables'] = array();
}
$tables['SubTables'][] = $tmp;
}
function CloneItems($prefix, $special, $ids, $master = null, $foreign_key = null, $parent_prefix = null, $skip_filenames = false)
{
if (!isset($master)) $master = $this->Tables;
// recalling by different name, because we may get kDBList, if we recall just by prefix
if (!preg_match('/(.*)-item$/', $special)) {
$special .= '-item';
}
$object =& $this->Application->recallObject($prefix.'.'.$special, $prefix, Array('skip_autoload' => true));
$object->PopulateMultiLangFields();
foreach ($ids as $id) {
$mode = 'create';
if ( $cloned_ids = getArrayValue($this->AlreadyProcessed, $master['TableName']) ) {
// if we have already cloned the id, replace it with cloned id and set mode to update
// update mode is needed to update second ForeignKey for items cloned by first ForeignKey
if ( getArrayValue($cloned_ids, $id) ) {
$id = $cloned_ids[$id];
$mode = 'update';
}
}
$object->Load($id);
$original_values = $object->FieldValues;
if (!$skip_filenames) {
$object->NameCopy($master, $foreign_key);
}
elseif ($master['TableName'] == $this->MasterTable) {
// kCatDBItem class only has this attribute
$object->useFilenames = false;
}
if (isset($foreign_key)) {
$master_foreign_key_field = is_array($master['ForeignKey']) ? $master['ForeignKey'][$parent_prefix] : $master['ForeignKey'];
$object->SetDBField($master_foreign_key_field, $foreign_key);
}
if ($mode == 'create') {
$this->RaiseEvent('OnBeforeClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key);
}
$res = $mode == 'update' ? $object->Update() : $object->Create();
if ($res)
{
if ( $mode == 'create' && is_array( getArrayValue($master, 'ForeignKey')) ) {
// remember original => clone mapping for dual ForeignKey updating
$this->AlreadyProcessed[$master['TableName']][$id] = $object->GetId();
}
if ($object->mode == 't') {
$object->setTempID();
}
if ($mode == 'create') {
$this->RaiseEvent('OnAfterClone', $master['Prefix'], $special, Array($object->GetId()), $foreign_key, array('original_id' => $id) );
$this->saveID($master['Prefix'], $special, $object->GetID());
}
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoClone')) continue;
$sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? $sub_table['ForeignKey'][$master['Prefix']] : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$sub_ids = $this->Conn->GetCol($query);
if ( is_array(getArrayValue($sub_table, 'ForeignKey')) ) {
// $sub_ids could containt newly cloned items, we need to remove it here
// to escape double cloning
$cloned_ids = getArrayValue($this->AlreadyProcessed, $sub_table['TableName']);
if ( !$cloned_ids ) $cloned_ids = Array();
$new_ids = array_values($cloned_ids);
$sub_ids = array_diff($sub_ids, $new_ids);
}
$parent_key = $object->GetDBField($parent_key_field);
$this->CloneItems($sub_table['Prefix'], $special, $sub_ids, $sub_table, $parent_key, $master['Prefix']);
}
}
}
}
if (!$ids) {
$this->savedIDs[$prefix.($special ? '.' : '').$special] = Array();
}
return $this->savedIDs[$prefix.($special ? '.' : '').$special];
}
function DeleteItems($prefix, $special, $ids, $master=null, $foreign_key=null)
{
if (!isset($master)) $master = $this->Tables;
if( strpos($prefix,'.') !== false ) list($prefix,$special) = explode('.', $prefix, 2);
$prefix_special = rtrim($prefix.'.'.$special, '.');
//recalling by different name, because we may get kDBList, if we recall just by prefix
$recall_prefix = $prefix_special.($special ? '' : '.').'-item';
$object =& $this->Application->recallObject($recall_prefix, $prefix, Array('skip_autoload' => true));
foreach ($ids as $id)
{
$object->Load($id);
$original_values = $object->FieldValues;
if( !$object->Delete($id) ) continue;
if ( is_array(getArrayValue($master, 'SubTables')) ) {
foreach($master['SubTables'] as $sub_table) {
if (!getArrayValue($sub_table, 'AutoDelete')) continue;
$sub_TableName = ($object->mode == 't') ? $this->GetTempName($sub_table['TableName']) : $sub_table['TableName'];
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
$parent_key_field = is_array($sub_table['ParentTableKey']) ? getArrayValue($sub_table, 'ParentTableKey', $master['Prefix']) : $sub_table['ParentTableKey'];
if (!$foreign_key_field || !$parent_key_field) continue;
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_TableName.'
WHERE '.$foreign_key_field.' = '.$original_values[$parent_key_field];
$sub_ids = $this->Conn->GetCol($query);
$parent_key = $object->GetDBField(is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$prefix] : $sub_table['ParentTableKey']);
$this->DeleteItems($sub_table['Prefix'], '', $sub_ids, $sub_table, $parent_key);
}
}
}
}
function DoCopyLiveToTemp($master, $ids, $parent_prefix=null)
{
// when two tables refers the same table as sub-sub-table, and ForeignKey and ParentTableKey are arrays
// the table will be first copied by first sub-table, then dropped and copied over by last ForeignKey in the array
// this should not do any problems :)
if ( !preg_match("/.*\.[0-9]+/", $master['Prefix']) ) {
if( $this->DropTempTable($master['TableName']) )
{
$this->CreateTempTable($master['TableName']);
}
}
if (is_array($ids)) {
$ids = join(',', $ids);
}
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
if ($ids != '' && !in_array($table_sig, $this->CopiedTables)) {
if ( getArrayValue($master, 'ForeignKey') ) {
if ( is_array($master['ForeignKey']) ) {
$key_field = $master['ForeignKey'][$parent_prefix];
}
else {
$key_field = $master['ForeignKey'];
}
}
else {
$key_field = $master['IdField'];
}
$query = 'INSERT INTO '.$this->GetTempName($master['TableName']).'
SELECT * FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
$query = 'SELECT '.$master['IdField'].' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->RaiseEvent( 'OnAfterCopyToTemp', $master['Prefix'], '', $this->Conn->GetCol($query) );
}
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$parent_key = is_array($sub_table['ParentTableKey']) ? $sub_table['ParentTableKey'][$master['Prefix']] : $sub_table['ParentTableKey'];
if (!$parent_key) continue;
if ( $ids != '' && $parent_key != $key_field ) {
$query = 'SELECT '.$parent_key.' FROM '.$master['TableName'].'
WHERE '.$key_field.' IN ('.$ids.')';
$sub_foreign_keys = join(',', $this->Conn->GetCol($query));
}
else {
$sub_foreign_keys = $ids;
}
$this->DoCopyLiveToTemp($sub_table, $sub_foreign_keys, $master['Prefix']);
}
}
}
function GetForeignKeys($master, $sub_table, $live_id, $temp_id=null)
{
$mode = 1; //multi
if (!is_array($live_id)) {
$live_id = Array($live_id);
$mode = 2; //single
}
if (isset($temp_id) && !is_array($temp_id)) $temp_id = Array($temp_id);
if ( isset($sub_table['ParentTableKey']) ) {
if ( is_array($sub_table['ParentTableKey']) ) {
$parent_key_field = $sub_table['ParentTableKey'][$master['Prefix']];
}
else {
$parent_key_field = $sub_table['ParentTableKey'];
}
}
else {
$parent_key_field = $master['IdField'];
}
if ( $cached = getArrayValue($this->FKeysCache, $master['TableName'].'.'.$parent_key_field) ) {
if ( array_key_exists(serialize($live_id), $cached) ) {
list($live_foreign_key, $temp_foreign_key) = $cached[serialize($live_id)];
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
}
if ($parent_key_field != $master['IdField']) {
$query = 'SELECT '.$parent_key_field.' FROM '.$master['TableName'].'
WHERE '.$master['IdField'].' IN ('.join(',', $live_id).')';
$live_foreign_key = $this->Conn->GetCol($query);
if (isset($temp_id)) {
// because DoCopyTempToOriginal resets negative IDs to 0 in temp table (one by one) before copying to live
$temp_key = $temp_id < 0 ? 0 : $temp_id;
$query = 'SELECT '.$parent_key_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' IN ('.join(',', $temp_key).')';
$temp_foreign_key = $this->Conn->GetCol($query);
}
else {
$temp_foreign_key = Array();
}
}
else {
$live_foreign_key = $live_id;
$temp_foreign_key = $temp_id;
}
$this->FKeysCache[$master['TableName'].'.'.$parent_key_field][serialize($live_id)] = Array($live_foreign_key, $temp_foreign_key);
if ($mode == 1) {
return $live_foreign_key;
}
else {
return Array($live_foreign_key[0], $temp_foreign_key[0]);
}
}
function DoCopyTempToOriginal($master, $parent_prefix = null, $current_ids = Array())
{
if (!$current_ids) {
$query = 'SELECT '.$master['IdField'].' FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$current_ids = $this->Conn->GetCol($query);
}
$table_sig = $master['TableName'].(isset($master['Constrain']) ? $master['Constrain'] : '');
if ($current_ids) {
// delete all ids from live table - for MasterTable ONLY!
// because items from Sub Tables get deteleted in CopySubTablesToLive !BY ForeignKey!
if ($master['TableName'] == $this->MasterTable) {
$this->RaiseEvent( 'OnBeforeDeleteFromLive', $master['Prefix'], '', $current_ids );
$query = 'DELETE FROM '.$master['TableName'].' WHERE '.$master['IdField'].' IN ('.join(',', $current_ids).')';
$this->Conn->Query($query);
}
if ( getArrayValue($master, 'SubTables') ) {
if( in_array($table_sig, $this->CopiedTables) || $this->FinalRefs[$table_sig] != $master['TableId'] ) return;
foreach($current_ids AS $id)
{
$this->RaiseEvent( 'OnBeforeCopyToLive', $master['Prefix'], '', Array($id) );
//reset negative ids to 0, so autoincrement in live table works fine
if($id < 0)
{
$query = 'UPDATE '.$this->GetTempName($master['TableName']).'
SET '.$master['IdField'].' = 0
WHERE '.$master['IdField'].' = '.$id;
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
$id_to_copy = 0;
}
else
{
$id_to_copy = $id;
}
//copy current id_to_copy (0 for new or real id) to live table
$query = 'INSERT INTO '.$master['TableName'].'
SELECT * FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = '.$id_to_copy;
$this->Conn->Query($query);
$insert_id = $id_to_copy == 0 ? $this->Conn->getInsertID() : $id_to_copy;
$this->saveID($master['Prefix'], '', array($id => $insert_id));
$this->RaiseEvent( 'OnAfterCopyToLive', $master['Prefix'], '', Array($insert_id), null, array('temp_id' => $id) );
$this->UpdateForeignKeys($master, $insert_id, $id);
//delete already copied record from master temp table
$query = 'DELETE FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = '.$id_to_copy;
if (isset($master['Constrain'])) $query .= ' AND '.$master['Constrain'];
$this->Conn->Query($query);
}
$this->CopiedTables[] = $table_sig;
// when all of ids in current master has been processed, copy all sub-tables data
$this->CopySubTablesToLive($master, $current_ids);
}
elseif( !in_array($table_sig, $this->CopiedTables) && ($this->FinalRefs[$table_sig] == $master['TableId']) ) { //If current master doesn't have sub-tables - we could use mass operations
// We don't need to delete items from live here, as it get deleted in the beggining of the method for MasterTable
// or in parent table processing for sub-tables
$this->RaiseEvent('OnBeforeCopyToLive', $master['Prefix'], '', $current_ids);
$live_ids = array();
foreach ($current_ids as $an_id) {
if ($an_id > 0) {
$live_ids[$an_id] = $an_id;
// positive (already live) IDs will be copied in on query all togather below,
// so we just store it here
continue;
}
else { // zero or negaitve ids should be copied one by one to get their InsertId
// reseting to 0 so it get inserted into live table with autoincrement
$query = 'UPDATE '.$this->GetTempName($master['TableName']).'
SET '.$master['IdField'].' = 0
WHERE '.$master['IdField'].' = '.$an_id;
// constrain is not needed here because ID is already unique
$this->Conn->Query($query);
// copying
$query = 'INSERT INTO '.$master['TableName'].'
SELECT * FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = 0';
$this->Conn->Query($query);
$live_ids[$an_id] = $this->Conn->getInsertID(); //storing newly created live id
//delete already copied record from master temp table
$query = 'DELETE FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$master['IdField'].' = 0';
$this->Conn->Query($query);
+ $this->UpdateChangeLogForeignKeys($master, $live_ids[$an_id], $an_id);
}
}
// copy ALL records to live table
$query = 'INSERT INTO '.$master['TableName'].'
SELECT * FROM '.$this->GetTempName($master['TableName']);
if (isset($master['Constrain'])) $query .= ' WHERE '.$master['Constrain'];
$this->Conn->Query($query);
$this->CopiedTables[] = $table_sig;
$this->RaiseEvent('OnAfterCopyToLive', $master['Prefix'], '', $live_ids);
$this->saveID($master['Prefix'], '', $live_ids);
// no need to clear temp table - it will be dropped by next statement
}
}
if ($this->FinalRefs[ $master['TableName'] ] != $master['TableId']) return;
/*if ( is_array(getArrayValue($master, 'ForeignKey')) ) { //if multiple ForeignKeys
if ( $master['ForeignKey'][$parent_prefix] != end($master['ForeignKey']) ) {
return; // Do not delete temp table if not all ForeignKeys have been processed (current is not the last)
}
}*/
$this->DropTempTable($master['TableName']);
$this->Application->resetCounters($master['TableName']);
if (!isset($this->savedIDs[ $master['Prefix'] ])) {
$this->savedIDs[ $master['Prefix'] ] = Array();
}
return $this->savedIDs[ $master['Prefix'] ];
}
+
+ function UpdateChangeLogForeignKeys($master, $live_id, $temp_id)
+ {
+ $main_prefix = $this->Application->GetTopmostPrefix($master['Prefix']);
+ $ses_var_name = $main_prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
+ $changes = $this->Application->RecallVar($ses_var_name);
+ $changes = $changes ? unserialize($changes) : array();
+
+ foreach ($changes as $key => $rec) {
+ if ($rec['Prefix'] == $master['Prefix']) {
+ if ($rec['ItemId'] == $temp_id) {
+ $changes[$key]['ItemId'] = $live_id;
+ }
+ }
+ if ($rec['MasterPrefix'] == $master['Prefix']) {
+ if ($rec['MasterId'] == $temp_id) {
+ $changes[$key]['MasterId'] = $live_id;
+ }
+ }
+ }
+ $this->Application->StoreVar($ses_var_name, serialize($changes));
+ }
function UpdateForeignKeys($master, $live_id, $temp_id) {
+ $this->UpdateChangeLogForeignKeys($master, $live_id, $temp_id);
foreach ($master['SubTables'] as $sub_table) {
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) return;
list ($live_foreign_key, $temp_foreign_key) = $this->GetForeignKeys($master, $sub_table, $live_id, $temp_id);
//Update ForeignKey in sub TEMP table
if ($live_foreign_key != $temp_foreign_key) {
$query = 'UPDATE '.$this->GetTempName($sub_table['TableName']).'
SET '.$foreign_key_field.' = '.$live_foreign_key.'
WHERE '.$foreign_key_field.' = '.$temp_foreign_key;
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
function CopySubTablesToLive($master, $current_ids) {
foreach ($master['SubTables'] as $sub_table) {
$table_sig = $sub_table['TableName'].(isset($sub_table['Constrain']) ? $sub_table['Constrain'] : '');
// delete records from live table by foreign key, so that records deleted from temp table
// get deleted from live
if (count($current_ids) > 0 && !in_array($table_sig, $this->CopiedTables) ) {
$foreign_key_field = is_array($sub_table['ForeignKey']) ? getArrayValue($sub_table, 'ForeignKey', $master['Prefix']) : $sub_table['ForeignKey'];
if (!$foreign_key_field) continue;
$foreign_keys = $this->GetForeignKeys($master, $sub_table, $current_ids);
if (count($foreign_keys) > 0) {
$query = 'SELECT '.$sub_table['IdField'].' FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
if ( $this->RaiseEvent( 'OnBeforeDeleteFromLive', $sub_table['Prefix'], '', $this->Conn->GetCol($query), $foreign_keys ) ){
$query = 'DELETE FROM '.$sub_table['TableName'].'
WHERE '.$foreign_key_field.' IN ('.join(',', $foreign_keys).')';
if (isset($sub_table['Constrain'])) $query .= ' AND '.$sub_table['Constrain'];
$this->Conn->Query($query);
}
}
}
//sub_table passed here becomes master in the method, and recursively updated and copy its sub tables
$this->DoCopyTempToOriginal($sub_table, $master['Prefix']);
}
}
function RaiseEvent($name, $prefix, $special, $ids, $foreign_key = null, $add_params = null)
{
if ( !is_array($ids) ) return ;
$event_key = $prefix.($special ? '.' : '').$special.':'.$name;
$event = new kEvent($event_key);
if (isset($foreign_key)) {
$event->setEventParam('foreign_key', $foreign_key);
}
foreach($ids as $id)
{
$event->setEventParam('id', $id);
if (is_array($add_params)) {
foreach ($add_params as $name => $val) {
$event->setEventParam($name, $val);
}
}
$this->Application->HandleEvent($event);
}
return $event->status == erSUCCESS;
}
function DropTempTable($table)
{
if( in_array($table, $this->DroppedTables) ) return false;
$query = sprintf("DROP TABLE IF EXISTS %s",
$this->GetTempName($table)
);
array_push($this->DroppedTables, $table);
$this->DroppedTables = array_unique($this->DroppedTables);
$this->Conn->Query($query);
return true;
}
function PrepareEdit()
{
$this->DoCopyLiveToTemp($this->Tables, $this->Tables['IDs']);
if ($this->Application->getUnitOption($this->Tables['Prefix'],'CheckSimulatniousEdit')) {
$this->CheckSimultaniousEdit();
}
}
function SaveEdit($master_ids = Array())
{
return $this->DoCopyTempToOriginal($this->Tables, null, $master_ids);
}
function CancelEdit($master=null)
{
if (!isset($master)) $master = $this->Tables;
$this->DropTempTable($master['TableName']);
if ( getArrayValue($master, 'SubTables') ) {
foreach ($master['SubTables'] as $sub_table) {
$this->CancelEdit($sub_table);
}
}
}
function CheckSimultaniousEdit()
{
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/'.TABLE_PREFIX.'ses_(.*)_edit_'.$this->MasterTable.'$/';
$sql='SELECT COUNT(*) FROM '.$this->TableName.' WHERE '.$this->IDField.' = \'%s\'';
$my_sid = $this->Application->GetSID();
$ids = join(',',$this->Tables['IDs']);
$sids = array();
if (!$ids) return ;
foreach($tables as $table)
{
if( preg_match($mask_edit_table,$table,$rets) )
{
$sid = preg_replace('/(.*)_(.*)/', '\\1', $rets[1]); // remove popup's wid from sid
if ($sid == $my_sid) continue;
$found = $this->Conn->GetOne("SELECT COUNT({$this->Tables['IdField']}) FROM $table WHERE {$this->Tables['IdField']} IN ($ids)");
if (!$found || in_array($sid, $sids)) continue;
$sids[] = $sid;
}
}
if ($sids) {
//detect who is it
$users = $this->Conn->GetCol(
' SELECT
CONCAT(IF (s.PortalUserId = -1, \'root\',
IF (s.PortalUserId = -2, \'Guest\',
CONCAT(FirstName, \' \', LastName, \' (\', Login, \')\')
)
), \' IP: \', s.IpAddress, \'\') FROM '.TABLE_PREFIX.'UserSession AS s
LEFT JOIN '.TABLE_PREFIX.'PortalUser AS u
ON u.PortalUserId = s.PortalUserId
WHERE s.SessionKey IN ('.join(',',$sids).')');
if ($users) {
$this->Application->SetVar('_simultanious_edit_message',
sprintf($this->Application->Phrase('la_record_being_edited_by'), join(",\n", $users))
);
}
}
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/kernel/utility/temp_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.30.2.2
\ No newline at end of property
+1.30.2.3
\ No newline at end of property
Index: branches/RC/core/kernel/db/db_event_handler.php
===================================================================
--- branches/RC/core/kernel/db/db_event_handler.php (revision 10293)
+++ branches/RC/core/kernel/db/db_event_handler.php (revision 10294)
@@ -1,2227 +1,2268 @@
<?php
define('EH_CUSTOM_PROCESSING_BEFORE',1);
define('EH_CUSTOM_PROCESSING_AFTER',2);
/**
* Note:
* 1. When adressing variables from submit containing
* Prefix_Special as part of their name use
* $event->getPrefixSpecial(true) instead of
* $event->Prefix_Special as usual. This is due PHP
* is converting "." symbols in variable names during
* submit info "_". $event->getPrefixSpecial optional
* 1st parameter returns correct corrent Prefix_Special
* for variables beeing submitted such way (e.g. variable
* name that will be converted by PHP: "users.read_only_id"
* will be submitted as "users_read_only_id".
*
* 2. When using $this->Application-LinkVar on variables submitted
* from form which contain $Prefix_Special then note 1st item. Example:
* LinkVar($event->getPrefixSpecial(true).'_varname',$event->Prefix_Special.'_varname')
*
*/
/**
* EventHandler that is used to process
* any database related events
*
*/
class kDBEventHandler extends kEventHandler {
/**
* Description
*
* @var kDBConnection
* @access public
*/
var $Conn;
/**
* Adds ability to address db connection
*
* @return kDBEventHandler
* @access public
*/
function kDBEventHandler()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
/**
* Checks permissions of user
*
* @param kEvent $event
*/
function CheckPermission(&$event)
{
if (!$this->Application->IsAdmin()) {
$allow_events = Array('OnSearch', 'OnSearchReset', 'OnNew');
if (in_array($event->Name, $allow_events)) {
// allow search on front
return true;
}
}
$section = $event->getSection();
if (!preg_match('/^CATEGORY:(.*)/', $section)) {
// only if not category item events
if ((substr($event->Name, 0, 9) == 'OnPreSave') || ($event->Name == 'OnSave')) {
if ($this->isNewItemCreate($event)) {
return $this->Application->CheckPermission($section.'.add', 1);
}
else {
return $this->Application->CheckPermission($section.'.add', 1) || $this->Application->CheckPermission($section.'.edit', 1);
}
}
}
if ($event->Name == 'OnPreCreate') {
// save category_id before item create (for item category selector not to destroy permission checking category)
$this->Application->LinkVar('m_cat_id');
}
return parent::CheckPermission($event);
}
/**
* Allows to override standart permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array(
'OnLoad' => Array('self' => 'view', 'subitem' => 'view'),
'OnItemBuild' => Array('self' => 'view', 'subitem' => 'view'),
'OnBuild' => Array('self' => true),
'OnNew' => Array('self' => 'add', 'subitem' => 'add|edit'),
'OnCreate' => Array('self' => 'add', 'subitem' => 'add|edit'),
'OnUpdate' => Array('self' => 'edit', 'subitem' => 'add|edit'),
'OnSetPrimary' => Array('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnDelete' => Array('self' => 'delete', 'subitem' => 'add|edit'),
'OnMassDelete' => Array('self' => 'delete', 'subitem' => 'add|edit'),
'OnMassClone' => Array('self' => 'add', 'subitem' => 'add|edit'),
'OnCut' => array('self'=>'edit', 'subitem' => 'edit'),
'OnCopy' => array('self'=>'edit', 'subitem' => 'edit'),
'OnPaste' => array('self'=>'edit', 'subitem' => 'edit'),
'OnSelectItems' => Array('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnProcessSelected' => Array('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnSelectUser' => Array('self' => 'add|edit', 'subitem' => 'add|edit'),
'OnMassApprove' => Array('self' => 'advanced:approve|edit', 'subitem' => 'advanced:approve|add|edit'),
'OnMassDecline' => Array('self' => 'advanced:decline|edit', 'subitem' => 'advanced:decline|add|edit'),
'OnMassMoveUp' => Array('self' => 'advanced:move_up|edit', 'subitem' => 'advanced:move_up|add|edit'),
'OnMassMoveDown' => Array('self' => 'advanced:move_down|edit', 'subitem' => 'advanced:move_down|add|edit'),
'OnPreCreate' => Array('self' => 'add|add.pending', 'subitem' => 'edit|edit.pending'),
'OnEdit' => Array('self' => 'edit|edit.pending', 'subitem' => 'edit|edit.pending'),
'OnExport' => Array('self' => 'view|advanced:export'),
'OnExportBegin' => Array('self' => 'view|advanced:export'),
'OnExportProgress' => Array('self' => 'view|advanced:export'),
// theese event do not harm, but just in case check them too :)
'OnCancelEdit' => Array('self' => true, 'subitem' => true),
'OnCancel' => Array('self' => true, 'subitem' => true),
'OnReset' => Array('self' => true, 'subitem' => true),
'OnSetSorting' => Array('self' => true, 'subitem' => true),
'OnSetSortingDirect' => Array('self' => true, 'subitem' => true),
'OnSetFilter' => Array('self' => true, 'subitem' => true),
'OnApplyFilters' => Array('self' => true, 'subitem' => true),
'OnRemoveFilters' => Array('self' => true, 'subitem' => true),
'OnSetFilterPattern' => Array('self' => true, 'subitem' => true),
'OnSetPerPage' => Array('self' => true, 'subitem' => true),
'OnSearch' => Array('self' => true, 'subitem' => true),
'OnSearchReset' => Array('self' => true, 'subitem' => true),
'OnGoBack' => Array('self' => true, 'subitem' => true),
// it checks permission itself since flash uploader does not send cookies
'OnUploadFile' => Array('self'=>true, 'subitem'=>true),
'OnViewFile' => Array('self'=>true, 'subitem'=>true),
'OnSaveWidths' => Array('self'=>true, 'subitem'=>true),
'OnValidateMInputFields' => Array('self'=>'view'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
function mapEvents()
{
$events_map = Array(
'OnRemoveFilters' => 'FilterAction',
'OnApplyFilters' => 'FilterAction',
'OnMassApprove'=>'iterateItems',
'OnMassDecline'=>'iterateItems',
'OnMassMoveUp'=>'iterateItems',
'OnMassMoveDown'=>'iterateItems',
);
$this->eventMethods = array_merge($this->eventMethods, $events_map);
}
/**
* Returns ID of current item to be edited
* by checking ID passed in get/post as prefix_id
* or by looking at first from selected ids, stored.
* Returned id is also stored in Session in case
* it was explicitly passed as get/post
*
* @param kEvent $event
* @return int
*/
function getPassedID(&$event)
{
if ($event->getEventParam('raise_warnings') === false) {
$event->setEventParam('raise_warnings', 1);
}
if (preg_match('/^auto-(.*)/', $event->Special, $regs) && $this->Application->prefixRegistred($regs[1])) {
// <inp2:lang.auto-phrase_Field name="DateFormat"/> - returns field DateFormat value from language (LanguageId is extracted from current phrase object)
$main_object =& $this->Application->recallObject($regs[1]);
/* @var $main_object kDBItem */
$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
return $main_object->GetDBField($id_field);
}
// 1. get id from post (used in admin)
$ret = $this->Application->GetVar($event->getPrefixSpecial(true).'_id');
if ($ret) {
return $ret;
}
// 2. get id from env (used in front)
$ret = $this->Application->GetVar($event->getPrefixSpecial().'_id');
if ($ret) {
return $ret;
}
// recall selected ids array and use the first one
$ids = $this->Application->GetVar($event->getPrefixSpecial().'_selected_ids');
if ($ids != '') {
$ids = explode(',',$ids);
if ($ids) {
$ret = array_shift($ids);
}
}
else { // if selected ids are not yet stored
$this->StoreSelectedIDs($event);
return $this->Application->GetVar($event->getPrefixSpecial(true).'_id'); // StoreSelectedIDs sets this variable
}
return $ret;
}
/**
* Prepares and stores selected_ids string
* in Session and Application Variables
* by getting all checked ids from grid plus
* id passed in get/post as prefix_id
*
* @param kEvent $event
* @param Array $ids
*
* @return Array ids stored
*/
function StoreSelectedIDs(&$event, $ids = null)
{
$wid = $this->Application->GetTopmostWid($event->Prefix);
$session_name = rtrim($event->getPrefixSpecial().'_selected_ids_'.$wid, '_');
if (isset($ids)) {
// save ids directly if they given
$this->Application->StoreVar($session_name, implode(',', $ids));
return $ids;
}
$ret = Array();
// May be we don't need this part: ?
$passed = $this->Application->GetVar($event->getPrefixSpecial(true).'_id');
if($passed !== false && $passed != '')
{
array_push($ret, $passed);
}
$ids = Array();
// get selected ids from post & save them to session
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
$id_field = $this->Application->getUnitOption($event->Prefix,'IDField');
foreach($items_info as $id => $field_values)
{
if( getArrayValue($field_values,$id_field) ) array_push($ids,$id);
}
//$ids=array_keys($items_info);
}
$ret = array_unique(array_merge($ret, $ids));
$this->Application->SetVar($event->getPrefixSpecial().'_selected_ids', implode(',',$ret));
$this->Application->LinkVar($event->getPrefixSpecial().'_selected_ids', $session_name);
// This is critical - otherwise getPassedID will return last ID stored in session! (not exactly true)
// this smells... needs to be refactored
$first_id = getArrayValue($ret,0);
if (($first_id === false) && ($event->getEventParam('raise_warnings') == 1)) {
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
trigger_error('Requested ID for prefix <b>'.$event->getPrefixSpecial().'</b> <span class="debug_error">not passed</span>',E_USER_NOTICE);
}
$this->Application->SetVar($event->getPrefixSpecial(true).'_id', $first_id);
return $ret;
}
/**
* Returns stored selected ids as an array
*
* @param kEvent $event
* @param bool $from_session return ids from session (written, when editing was started)
* @return array
*/
function getSelectedIDs(&$event, $from_session = false)
{
if ($from_session) {
$wid = $this->Application->GetTopmostWid($event->Prefix);
$var_name = rtrim($event->getPrefixSpecial().'_selected_ids_'.$wid, '_');
$ret = $this->Application->RecallVar($var_name);
}
else {
$ret = $this->Application->GetVar($event->getPrefixSpecial().'_selected_ids');
}
return explode(',', $ret);
}
/**
* Returs associative array of submitted fields for current item
* Could be used while creating/editing single item -
* meaning on any edit form, except grid edit
*
* @param kEvent $event
*/
function getSubmittedFields(&$event)
{
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
$field_values = $items_info ? array_shift($items_info) : Array();
return $field_values;
}
/**
* Removes any information about current/selected ids
* from Application variables and Session
*
* @param kEvent $event
*/
function clearSelectedIDs(&$event)
{
$prefix_special = $event->getPrefixSpecial();
$ids = implode(',', $this->getSelectedIDs($event, true));
$event->setEventParam('ids', $ids);
$wid = $this->Application->GetTopmostWid($event->Prefix);
$session_name = rtrim($prefix_special.'_selected_ids_'.$wid, '_');
$this->Application->RemoveVar($session_name);
$this->Application->SetVar($prefix_special.'_selected_ids', '');
$this->Application->SetVar($prefix_special.'_id', ''); // $event->getPrefixSpecial(true).'_id' too may be
}
/*function SetSaveEvent(&$event)
{
$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnUpdate');
$this->Application->LinkVar($event->Prefix_Special.'_SaveEvent');
}*/
/**
* Common builder part for Item & List
*
* @param kDBBase $object
* @param kEvent $event
* @access private
*/
function dbBuild(&$object, &$event)
{
$object->Configure( $event->getEventParam('populate_ml_fields') || $this->Application->getUnitOption($event->Prefix, 'PopulateMlFields') );
$this->PrepareObject($object, $event);
// force live table if specified or is original item
$live_table = $event->getEventParam('live_table') || $event->Special == 'original';
if( $this->UseTempTables($event) && !$live_table )
{
$object->SwitchToTemp();
}
// This strange constuction creates hidden field for storing event name in form submit
// It pass SaveEvent to next screen, otherwise after unsuccsefull create it will try to update rather than create
$current_event = $this->Application->GetVar($event->Prefix_Special.'_event');
// $this->Application->setEvent($event->Prefix_Special, $current_event);
$this->Application->setEvent($event->Prefix_Special, '');
$save_event = $this->UseTempTables($event) && $this->Application->GetTopmostPrefix($event->Prefix) == $event->Prefix ? 'OnSave' : 'OnUpdate';
$this->Application->SetVar($event->Prefix_Special.'_SaveEvent',$save_event);
}
/**
* Checks, that currently loaded item is allowed for viewing (non permission-based)
*
* @param kEvent $event
* @return bool
*/
function checkItemStatus(&$event)
{
$status_fields = $this->Application->getUnitOption($event->Prefix,'StatusField');
if (!$status_fields) {
return true;
}
$status_field = array_shift($status_fields);
if ($status_field == 'Status' || $status_field == 'Enabled') {
$object =& $event->getObject();
if (!$object->isLoaded()) {
return true;
}
return $object->GetDBField($status_field) == STATUS_ACTIVE;
}
return true;
}
/**
* Builds item (loads if needed)
*
* @param kEvent $event
* @access protected
*/
function OnItemBuild(&$event)
{
$object =& $event->getObject();
$this->dbBuild($object,$event);
$sql = $this->ItemPrepareQuery($event);
$sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
// 2. loads if allowed
$auto_load = $this->Application->getUnitOption($event->Prefix,'AutoLoad');
$skip_autload = $event->getEventParam('skip_autoload');
if ($auto_load && !$skip_autload) {
$perm_status = true;
$user_id = $this->Application->RecallVar('user_id');
$event->setEventParam('top_prefix', $this->Application->GetTopmostPrefix($event->Prefix, true));
$status_checked = false;
if ($user_id == -1 || $this->CheckPermission($event)) {
// don't autoload item, when user doesn't have view permission
$this->LoadItem($event);
$status_checked = true;
if ($user_id != -1 && !$this->Application->IsAdmin() && !$this->checkItemStatus($event)) {
$perm_status = false;
}
}
else {
$perm_status = false;
}
if (!$perm_status) {
// when no permission to view item -> redirect to no pemrission template
if ($this->Application->isDebugMode()) {
$this->Application->Debugger->appendTrace();
}
trigger_error('ItemLoad Permission Failed for prefix ['.$event->getPrefixSpecial().'] in <strong>'.($status_checked ? 'checkItemStatus' : 'CheckPermission').'</strong>', E_USER_WARNING);
$next_template = $this->Application->IsAdmin() ? 'no_permission' : $this->Application->ConfigValue('NoPermissionTemplate');
$this->Application->Redirect($next_template, Array('next_template' => $this->Application->GetVar('t')));
}
}
$actions =& $this->Application->recallObject('kActions');
$actions->Set($event->Prefix_Special.'_GoTab', '');
$actions->Set($event->Prefix_Special.'_GoId', '');
}
/**
* Build subtables array from configs
*
* @param kEvent $event
*/
function OnTempHandlerBuild(&$event)
{
$object =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
/* @var $object kTempTablesHandler */
$object->BuildTables( $event->Prefix, $this->getSelectedIDs($event) );
}
/**
* Enter description here...
*
* @param kEvent $event
* @return unknown
*/
function UseTempTables(&$event)
{
$object = &$event->getObject();
$top_prefix = $this->Application->GetTopmostPrefix($event->Prefix);
$var_names = Array (
$top_prefix,
rtrim($top_prefix.'_'.$event->Special, '_'),
rtrim($top_prefix.'.'.$event->Special, '.'),
);
$var_names = array_unique($var_names);
$temp_mode = false;
foreach ($var_names as $var_name) {
$value = $this->Application->GetVar($var_name.'_mode');
if (substr($value, 0, 1) == 't') {
$temp_mode = true;
break;
}
}
return $temp_mode;
}
/**
* Returns table prefix from event (temp or live)
*
* @param kEvent $event
* @return string
* @todo Needed? Should be refactored (by Alex)
*/
function TablePrefix(&$event)
{
return $this->UseTempTables($event) ? $this->Application->GetTempTablePrefix('prefix:'.$event->Prefix).TABLE_PREFIX : TABLE_PREFIX;
}
/**
* Load item if id is available
*
* @param kEvent $event
*/
function LoadItem(&$event)
{
$object =& $event->getObject();
$id = $this->getPassedID($event);
if ($object->Load($id)) {
$actions =& $this->Application->recallObject('kActions');
$actions->Set($event->Prefix_Special.'_id', $object->GetID() );
}
else {
$object->setID($id);
}
}
/**
* Builds list
*
* @param kEvent $event
* @access protected
*/
function OnListBuild(&$event)
{
$object =& $event->getObject();
/* @var $object kDBList */
$this->dbBuild($object,$event);
$sql = $this->ListPrepareQuery($event);
$sql = $this->Application->ReplaceLanguageTags($sql);
$object->setSelectSQL($sql);
$object->Counted = false; // when requery="1" should re-count records too!
$object->ClearOrderFields(); // prevents duplicate order fields, when using requery="1"
$object->linkToParent( $this->getMainSpecial($event) );
$this->AddFilters($event);
$this->SetCustomQuery($event); // new!, use this for dynamic queries based on specials for ex.
$this->SetPagination($event);
$this->SetSorting($event);
// $object->CalculateTotals(); // Now called in getTotals to avoid extra query
$actions =& $this->Application->recallObject('kActions');
$actions->Set('remove_specials['.$event->Prefix_Special.']', '0');
$actions->Set($event->Prefix_Special.'_GoTab', '');
}
/**
* Get's special of main item for linking with subitem
*
* @param kEvent $event
* @return string
*/
function getMainSpecial(&$event)
{
$special = $event->getEventParam('main_special');
if($special === false || $special == '$main_special')
{
$special = $event->Special;
}
return $special;
}
/**
* Apply any custom changes to list's sql query
*
* @param kEvent $event
* @access protected
* @see OnListBuild
*/
function SetCustomQuery(&$event)
{
}
/**
* Set's new perpage for grid
*
* @param kEvent $event
*/
function OnSetPerPage(&$event)
{
$per_page = $this->Application->GetVar($event->getPrefixSpecial(true).'_PerPage');
$this->Application->StoreVar($event->getPrefixSpecial().'_PerPage', $per_page);
$view_name = $this->Application->RecallVar($event->getPrefixSpecial().'_current_view');
$this->Application->StorePersistentVar($event->getPrefixSpecial().'_PerPage.'.$view_name, $per_page);
}
/**
* Set's correct page for list
* based on data provided with event
*
* @param kEvent $event
* @access private
* @see OnListBuild
*/
function SetPagination(&$event)
{
// get PerPage (forced -> session -> config -> 10)
$per_page = $this->getPerPage($event);
$object =& $event->getObject();
$object->SetPerPage($per_page);
$this->Application->StoreVarDefault($event->getPrefixSpecial().'_Page', 1);
$page = $this->Application->GetVar($event->getPrefixSpecial().'_Page');
if (!$page) {
$page = $this->Application->GetVar($event->getPrefixSpecial(true).'_Page');
}
if (!$page) {
$page = $this->Application->RecallVar($event->getPrefixSpecial().'_Page');
}
else {
$this->Application->StoreVar($event->getPrefixSpecial().'_Page', $page);
}
if( !$event->getEventParam('skip_counting') )
{
$pages = $object->GetTotalPages();
if($page > $pages)
{
$this->Application->StoreVar($event->getPrefixSpecial().'_Page', 1);
$page = 1;
}
}
/*$per_page = $event->getEventParam('per_page');
if ($per_page == 'list_next') {
$cur_page = $page;
$cur_per_page = $per_page;
$object->SetPerPage(1);
$object =& $this->Application->recallObject($event->Prefix);
$cur_item_index = $object->CurrentIndex;
$page = ($cur_page-1) * $cur_per_page + $cur_item_index + 1;
$object->SetPerPage(1);
}*/
$object->SetPage($page);
}
/**
* Returns current per-page setting for list
*
* @param kEvent $event
* @return int
*/
function getPerPage(&$event)
{
// 1. per-page is passed as tag parameter to PrintList, InitList, etc.
$per_page = $event->getEventParam('per_page');
/*if ($per_page == 'list_next') {
$per_page = '';
}*/
// 2. per-page variable name is store into config variable
$config_mapping = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
if ($config_mapping) {
switch ( $per_page ){
case 'short_list' :
$per_page = $this->Application->ConfigValue($config_mapping['ShortListPerPage']);
break;
case 'default' :
$per_page = $this->Application->ConfigValue($config_mapping['PerPage']);
break;
}
}
if (!$per_page) {
// per-page is stored to persistent session
$view_name = $this->Application->RecallVar($event->getPrefixSpecial().'_current_view');
$storage_prefix = $event->getEventParam('same_special') ? $event->Prefix : $event->getPrefixSpecial();
$per_page = $this->Application->RecallPersistentVar($storage_prefix.'_PerPage.'.$view_name, '_USE_DEFAULT_USER_DATA_');
if (!$per_page) {
// per-page is stored to current session
$per_page = $this->Application->RecallVar($storage_prefix.'_PerPage');
}
if (!$per_page) {
if ($config_mapping) {
if (!isset($config_mapping['PerPage'])) {
trigger_error('Incorrect mapping of <span class="debug_error">PerPage</span> key in config for prefix <b>'.$event->Prefix.'</b>', E_USER_WARNING);
}
$per_page = $this->Application->ConfigValue($config_mapping['PerPage']);
}
if (!$per_page) {
// none of checked above per-page locations are useful, then try default value
$per_page = 10;
}
}
}
return $per_page;
}
/**
* Set's correct sorting for list
* based on data provided with event
*
* @param kEvent $event
* @access private
* @see OnListBuild
*/
function SetSorting(&$event)
{
$event->setPseudoClass('_List');
$object =& $event->getObject();
$storage_prefix = $event->getEventParam('same_special') ? $event->Prefix : $event->Prefix_Special;
$cur_sort1 = $this->Application->RecallVar($storage_prefix.'_Sort1');
$cur_sort1_dir = $this->Application->RecallVar($storage_prefix.'_Sort1_Dir');
$cur_sort2 = $this->Application->RecallVar($storage_prefix.'_Sort2');
$cur_sort2_dir = $this->Application->RecallVar($storage_prefix.'_Sort2_Dir');
$sorting_configs = $this->Application->getUnitOption($event->Prefix, 'ConfigMapping');
$list_sortings = $this->Application->getUnitOption($event->Prefix, 'ListSortings');
$sorting_prefix = getArrayValue($list_sortings, $event->Special) ? $event->Special : '';
$tag_sort_by = $event->getEventParam('sort_by');
if ($tag_sort_by) {
if ($tag_sort_by == 'random') {
$by = 'RAND()';
$dir = '';
}
else {
list($by, $dir) = explode(',', $tag_sort_by);
}
$object->AddOrderField($by, $dir);
}
if ($sorting_configs && isset ($sorting_configs['DefaultSorting1Field'])){
$list_sortings[$sorting_prefix]['Sorting'] = Array(
$this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
$this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
);
}
// Use default if not specified
if ( !$cur_sort1 || !$cur_sort1_dir)
{
if ( $sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting') ) {
reset($sorting);
$cur_sort1 = key($sorting);
$cur_sort1_dir = current($sorting);
if (next($sorting)) {
$cur_sort2 = key($sorting);
$cur_sort2_dir = current($sorting);
}
}
}
if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
foreach ($forced_sorting as $field => $dir) {
$object->AddOrderField($field, $dir);
}
}
if($cur_sort1 != '' && $cur_sort1_dir != '')
{
$object->AddOrderField($cur_sort1, $cur_sort1_dir);
}
if($cur_sort2 != '' && $cur_sort2_dir != '')
{
$object->AddOrderField($cur_sort2, $cur_sort2_dir);
}
}
/**
* Add filters found in session
*
* @param kEvent $event
*/
function AddFilters(&$event)
{
$object =& $event->getObject();
$edit_mark = rtrim($this->Application->GetSID().'_'.$this->Application->GetTopmostWid($event->Prefix), '_');
// add search filter
$filter_data = $this->Application->RecallVar($event->getPrefixSpecial().'_search_filter');
if ($filter_data) {
$filter_data = unserialize($filter_data);
foreach ($filter_data as $filter_field => $filter_params) {
$filter_type = ($filter_params['type'] == 'having') ? HAVING_FILTER : WHERE_FILTER;
$filter_value = str_replace(EDIT_MARK, $edit_mark, $filter_params['value']);
$object->addFilter($filter_field, $filter_value, $filter_type, FLT_SEARCH);
}
}
// add custom filter
$view_name = $this->Application->RecallVar($event->getPrefixSpecial().'_current_view');
$custom_filters = $this->Application->RecallPersistentVar($event->getPrefixSpecial().'_custom_filter.'.$view_name);
if ($custom_filters) {
$grid_name = $event->getEventParam('grid');
$custom_filters = unserialize($custom_filters);
if (isset($custom_filters[$grid_name])) {
foreach ($custom_filters[$grid_name] as $field_name => $field_options) {
list ($filter_type, $field_options) = each($field_options);
if (isset($field_options['value']) && $field_options['value']) {
$filter_type = ($field_options['sql_filter_type'] == 'having') ? HAVING_FILTER : WHERE_FILTER;
$filter_value = str_replace(EDIT_MARK, $edit_mark, $field_options['value']);
$object->addFilter($field_name, $filter_value, $filter_type, FLT_CUSTOM);
}
}
}
}
$view_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_view_filter');
if($view_filter)
{
$view_filter = unserialize($view_filter);
$temp_filter =& $this->Application->makeClass('kMultipleFilter');
$filter_menu = $this->Application->getUnitOption($event->Prefix,'FilterMenu');
$group_key = 0; $group_count = count($filter_menu['Groups']);
while($group_key < $group_count)
{
$group_info = $filter_menu['Groups'][$group_key];
$temp_filter->setType( constant('FLT_TYPE_'.$group_info['mode']) );
$temp_filter->clearFilters();
foreach ($group_info['filters'] as $flt_id)
{
$sql_key = getArrayValue($view_filter,$flt_id) ? 'on_sql' : 'off_sql';
if ($filter_menu['Filters'][$flt_id][$sql_key] != '')
{
$temp_filter->addFilter('view_filter_'.$flt_id, $filter_menu['Filters'][$flt_id][$sql_key]);
}
}
$object->addFilter('view_group_'.$group_key, $temp_filter, $group_info['type'] , FLT_VIEW);
$group_key++;
}
}
}
/**
* Set's new sorting for list
*
* @param kEvent $event
* @access protected
*/
function OnSetSorting(&$event)
{
$cur_sort1 = $this->Application->RecallVar($event->Prefix_Special.'_Sort1');
$cur_sort1_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort1_Dir');
$use_double_sorting = $this->Application->ConfigValue('UseDoubleSorting') !== false ? $this->Application->ConfigValue('UseDoubleSorting') : true;
if ($use_double_sorting) {
$cur_sort2 = $this->Application->RecallVar($event->Prefix_Special.'_Sort2');
$cur_sort2_dir = $this->Application->RecallVar($event->Prefix_Special.'_Sort2_Dir');
}
$passed_sort1 = $this->Application->GetVar($event->getPrefixSpecial(true).'_Sort1');
if ($cur_sort1 == $passed_sort1) {
$cur_sort1_dir = $cur_sort1_dir == 'asc' ? 'desc' : 'asc';
}
else {
if ($use_double_sorting) {
$cur_sort2 = $cur_sort1;
$cur_sort2_dir = $cur_sort1_dir;
}
$cur_sort1 = $passed_sort1;
$cur_sort1_dir = 'asc';
}
$this->Application->StoreVar($event->Prefix_Special.'_Sort1', $cur_sort1);
$this->Application->StoreVar($event->Prefix_Special.'_Sort1_Dir', $cur_sort1_dir);
if ($use_double_sorting) {
$this->Application->StoreVar($event->Prefix_Special.'_Sort2', $cur_sort2);
$this->Application->StoreVar($event->Prefix_Special.'_Sort2_Dir', $cur_sort2_dir);
}
}
/**
* Set sorting directly to session (used for category item sorting (front-end), grid sorting (admin, view menu)
*
* @param kEvent $event
*/
function OnSetSortingDirect(&$event)
{
$combined = $this->Application->GetVar($event->Prefix.'_CombinedSorting');
if ($combined) {
list($field, $dir) = explode('|', $combined);
$this->Application->StoreVar($event->Prefix.'_Sort1', $field);
$this->Application->StoreVar($event->Prefix.'_Sort1_Dir', $dir);
return ;
}
$field_pos = $this->Application->GetVar($event->Prefix.'_SortPos');
$this->Application->LinkVar($event->Prefix.'_Sort'.$field_pos, $event->Prefix.'_Sort'.$field_pos);
$this->Application->LinkVar($event->Prefix.'_Sort'.$field_pos.'_Dir', $event->Prefix.'_Sort'.$field_pos.'_Dir');
}
/**
* Reset grid sorting to default (from config)
*
* @param kEvent $event
*/
function OnResetSorting(&$event)
{
$this->Application->RemoveVar($event->Prefix_Special.'_Sort1');
$this->Application->RemoveVar($event->Prefix_Special.'_Sort1_Dir');
$this->Application->RemoveVar($event->Prefix_Special.'_Sort2');
$this->Application->RemoveVar($event->Prefix_Special.'_Sort2_Dir');
}
/**
* Creates needed sql query to load item,
* if no query is defined in config for
* special requested, then use default
* query
*
* @param kEvent $event
* @access protected
*/
function ItemPrepareQuery(&$event)
{
$sqls = $this->Application->getUnitOption($event->Prefix, 'ItemSQLs', Array ());
$special = array_key_exists($event->Special, $sqls) ? $event->Special : '';
if (!array_key_exists($special, $sqls)) {
// preferred special not found in ItemSQLs -> use analog from ListSQLs
return $this->ListPrepareQuery($event);
}
return $sqls[$special];
}
/**
* Creates needed sql query to load list,
* if no query is defined in config for
* special requested, then use default
* query
*
* @param kEvent $event
* @access protected
*/
function ListPrepareQuery(&$event)
{
$sqls = $this->Application->getUnitOption($event->Prefix, 'ListSQLs', Array ());
return $sqls[ array_key_exists($event->Special, $sqls) ? $event->Special : '' ];
}
/**
* Apply custom processing to item
*
* @param kEvent $event
*/
function customProcessing(&$event, $type)
{
}
/* Edit Events mostly used in Admin */
/**
* Creates new kDBItem
*
* @param kEvent $event
* @access protected
*/
function OnCreate(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info) {
list($id,$field_values) = each($items_info);
$object->SetFieldsFromHash($field_values);
}
$this->customProcessing($event,'before');
//look at kDBItem' Create for ForceCreateId description, it's rarely used and is NOT set by default
if( $object->Create($event->getEventParam('ForceCreateId')) )
{
if( $object->IsTempTable() ) $object->setTempID();
$this->customProcessing($event,'after');
$event->status=erSUCCESS;
$event->redirect_params = Array('opener'=>'u');
}
else
{
$event->status = erFAIL;
$event->redirect = false;
$this->Application->SetVar($event->Prefix_Special.'_SaveEvent','OnCreate');
$object->setID($id);
}
}
/**
* Updates kDBItem
*
* @param kEvent $event
* @access protected
*/
function OnUpdate(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
foreach($items_info as $id => $field_values)
{
$object->Load($id);
$object->SetFieldsFromHash($field_values);
$this->customProcessing($event, 'before');
if( $object->Update($id) )
{
$this->customProcessing($event, 'after');
$event->status=erSUCCESS;
}
else
{
$event->status=erFAIL;
$event->redirect=false;
break;
}
}
}
$event->redirect_params = Array('opener'=>'u');
}
/**
* Delete's kDBItem object
*
* @param kEvent $event
* @access protected
*/
function OnDelete(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
/* @var $temp kTempTablesHandler */
$temp->DeleteItems($event->Prefix, $event->Special, Array($this->getPassedID($event)));
}
/**
* Prepares new kDBItem object
*
* @param kEvent $event
* @access protected
*/
function OnNew(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
$object->Clear(0);
$this->Application->SetVar($event->Prefix_Special.'_SaveEvent', 'OnCreate');
$table_info = $object->getLinkedInfo();
$object->SetDBField($table_info['ForeignKey'], $table_info['ParentId']);
$event->redirect = false;
}
/**
* Cancel's kDBItem Editing/Creation
*
* @param kEvent $event
* @access protected
*/
function OnCancel(&$event)
{
$object =& $event->getObject(Array('skip_autoload' => true));
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($items_info) {
$delete_ids = Array();
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
foreach ($items_info as $id => $field_values) {
$object->Load($id);
// record created for using with selector (e.g. Reviews->Select User), and not validated => Delete it
if ($object->isLoaded() && !$object->Validate() && ($id <= 0) ) {
$delete_ids[] = $id;
}
}
if ($delete_ids) {
$temp->DeleteItems($event->Prefix, $event->Special, $delete_ids);
}
}
$event->redirect_params = Array('opener'=>'u');
}
/**
* Deletes all selected items.
* Automatically recurse into sub-items using temp handler, and deletes sub-items
* by calling its Delete method if sub-item has AutoDelete set to true in its config file
*
* @param kEvent $event
*/
function OnMassDelete(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$event->status=erSUCCESS;
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$ids = $this->StoreSelectedIDs($event);
$event->setEventParam('ids', $ids);
$this->customProcessing($event, 'before');
$ids = $event->getEventParam('ids');
if($ids)
{
$temp->DeleteItems($event->Prefix, $event->Special, $ids);
}
$this->clearSelectedIDs($event);
}
/**
* Sets window id (of first opened edit window) to temp mark in uls
*
* @param kEvent $event
*/
function setTempWindowID(&$event)
{
$mode = $this->Application->GetVar($event->Prefix.'_mode');
if ($mode == 't') {
$wid = $this->Application->GetVar('m_wid');
$this->Application->SetVar($event->Prefix.'_mode', 't'.$wid);
}
}
/**
* Prepare temp tables and populate it
* with items selected in the grid
*
* @param kEvent $event
*/
function OnEdit(&$event)
{
$this->setTempWindowID($event);
$this->StoreSelectedIDs($event);
$var_name = $event->getPrefixSpecial().'_file_pending_actions'.$this->Application->GetVar('m_wid');
$this->Application->RemoveVar($var_name);
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
/* @var $temp kTempTablesHandler */
$temp->PrepareEdit();
$event->redirect=false;
}
/**
* Saves content of temp table into live and
* redirects to event' default redirect (normally grid template)
*
* @param kEvent $event
*/
function OnSave(&$event)
{
$event->CallSubEvent('OnPreSave');
if ($event->status == erSUCCESS) {
$skip_master = false;
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
+ $changes_var_name = $this->Prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
+
if (!$this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
$live_ids = $temp->SaveEdit($event->getEventParam('master_ids') ? $event->getEventParam('master_ids') : Array());
// Deleteing files scheduled for delete
$var_name = $event->getPrefixSpecial().'_file_pending_actions'.$this->Application->GetVar('m_wid');
$schedule = $this->Application->RecallVar($var_name);
$schedule = $schedule ? unserialize($schedule) : array();
foreach ($schedule as $data) {
if ($data['action'] == 'delete') {
unlink($data['file']);
}
}
if ($live_ids) {
// ensure, that newly created item ids are avalable as if they were selected from grid
// NOTE: only works if main item has subitems !!!
$this->StoreSelectedIDs($event, $live_ids);
}
+
+ $this->SaveLoggedChanges($changes_var_name);
+ }
+ else {
+ $this->Application->RemoveVar($changes_var_name);
}
$this->clearSelectedIDs($event);
$event->redirect_params = Array('opener' => 'u');
$this->Application->RemoveVar($event->getPrefixSpecial().'_modified');
// all temp tables are deleted here => all after hooks should think, that it's live mode now
$this->Application->SetVar($event->Prefix.'_mode', '');
}
}
+ function SaveLoggedChanges($changes_var_name)
+ {
+ $ses_log_id = $this->Application->RecallVar('_SessionLogId_');
+ if (!$ses_log_id) {
+ return ;
+ }
+
+ $changes = $this->Application->RecallVar($changes_var_name);
+ $changes = $changes ? unserialize($changes) : Array ();
+ if (!$changes) {
+ return ;
+ }
+
+ $add_fields = Array (
+ 'PortalUserId' => $this->Application->RecallVar('user_id'),
+ 'SessionLogId' => $ses_log_id,
+ );
+
+ $changelog_table = $this->Application->getUnitOption('change-log', 'TableName');
+ $sessionlog_table = $this->Application->getUnitOption('session-log', 'TableName');
+
+ foreach ($changes as $rec) {
+ $this->Conn->doInsert(array_merge($rec, $add_fields), $changelog_table);
+ }
+
+ $sql = 'UPDATE '.$sessionlog_table.'
+ SET AffectedItems = AffectedItems + '.count($changes).'
+ WHERE SessionLogId = '.$ses_log_id;
+ $this->Conn->Query($sql);
+
+ $this->Application->RemoveVar($changes_var_name);
+ }
+
+
/**
* Cancels edit
* Removes all temp tables and clears selected ids
*
* @param kEvent $event
*/
function OnCancelEdit(&$event)
{
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$temp->CancelEdit();
$this->clearSelectedIDs($event);
$event->redirect_params = Array('opener'=>'u');
$this->Application->RemoveVar($event->getPrefixSpecial().'_modified');
}
/**
* Allows to determine if we are creating new item or editing already created item
*
* @param kEvent $event
* @return bool
*/
function isNewItemCreate(&$event)
{
$event->setEventParam('raise_warnings', 0);
$object =& $event->getObject();
return !$object->IsLoaded();
// $item_id = $this->getPassedID($event);
// return ($item_id == '') ? true : false;
}
/**
* Saves edited item into temp table
* If there is no id, new item is created in temp table
*
* @param kEvent $event
*/
function OnPreSave(&$event)
{
//$event->redirect = false;
// if there is no id - it means we need to create an item
if (is_object($event->MasterEvent)) {
$event->MasterEvent->setEventParam('IsNew',false);
}
if ($this->isNewItemCreate($event)) {
$event->CallSubEvent('OnPreSaveCreated');
if (is_object($event->MasterEvent)) {
$event->MasterEvent->setEventParam('IsNew',true);
}
return;
}
$object =& $event->getObject( Array('skip_autoload' => true) );
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if ($items_info) {
foreach ($items_info as $id => $field_values) {
$object->SetDefaultValues();
$object->Load($id);
$object->SetFieldsFromHash($field_values);
$this->customProcessing($event, 'before');
if( $object->Update($id) )
{
$this->customProcessing($event, 'after');
$event->status=erSUCCESS;
}
else {
$event->status = erFAIL;
$event->redirect = false;
break;
}
}
}
}
/**
* Saves edited item in temp table and loads
* item with passed id in current template
* Used in Prev/Next buttons
*
* @param kEvent $event
*/
function OnPreSaveAndGo(&$event)
{
$event->CallSubEvent('OnPreSave');
if ($event->status == erSUCCESS) {
$event->SetRedirectParam($event->getPrefixSpecial(true).'_id', $this->Application->GetVar($event->Prefix_Special.'_GoId'));
}
}
/**
* Saves edited item in temp table and goes
* to passed tabs, by redirecting to it with OnPreSave event
*
* @param kEvent $event
*/
function OnPreSaveAndGoToTab(&$event)
{
$event->CallSubEvent('OnPreSave');
if ($event->status==erSUCCESS) {
$event->redirect=$this->Application->GetVar($event->getPrefixSpecial(true).'_GoTab');
}
}
/**
* Saves editable list and goes to passed tab,
* by redirecting to it with empty event
*
* @param kEvent $event
*/
function OnUpdateAndGoToTab(&$event)
{
$event->setPseudoClass('_List');
$event->CallSubEvent('OnUpdate');
if ($event->status==erSUCCESS) {
$event->redirect=$this->Application->GetVar($event->getPrefixSpecial(true).'_GoTab');
}
}
/**
* Prepare temp tables for creating new item
* but does not create it. Actual create is
* done in OnPreSaveCreated
*
* @param kEvent $event
*/
function OnPreCreate(&$event)
{
$this->setTempWindowID($event);
$this->clearSelectedIDs($event);
$object =& $event->getObject( Array('skip_autoload' => true) );
$temp =& $this->Application->recallObject($event->Prefix.'_TempHandler', 'kTempTablesHandler');
$temp->PrepareEdit();
$object->setID(0);
$this->Application->SetVar($event->getPrefixSpecial().'_id',0);
$this->Application->SetVar($event->getPrefixSpecial().'_PreCreate', 1);
$event->redirect=false;
}
/**
* Creates a new item in temp table and
* stores item id in App vars and Session on succsess
*
* @param kEvent $event
*/
function OnPreSaveCreated(&$event)
{
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info) $field_values = array_shift($items_info);
$object =& $event->getObject( Array('skip_autoload' => true) );
$object->SetFieldsFromHash($field_values);
$this->customProcessing($event, 'before');
if( $object->Create() )
{
$this->customProcessing($event, 'after');
$event->redirect_params[$event->getPrefixSpecial(true).'_id'] = $object->GetId();
$event->status=erSUCCESS;
}
else
{
$event->status=erFAIL;
$event->redirect=false;
$object->setID(0);
}
}
function OnReset(&$event)
{
//do nothing - should reset :)
if ($this->isNewItemCreate($event)) {
// just reset id to 0 in case it was create
$object =& $event->getObject( Array('skip_autoload' => true) );
$object->setID(0);
$this->Application->SetVar($event->getPrefixSpecial().'_id',0);
}
}
/**
* Apply same processing to each item beeing selected in grid
*
* @param kEvent $event
* @access private
*/
function iterateItems(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$object =& $event->getObject( Array('skip_autoload' => true) );
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
$status_field = array_shift( $this->Application->getUnitOption($event->Prefix,'StatusField') );
foreach ($ids as $id) {
$object->Load($id);
switch ($event->Name) {
case 'OnMassApprove':
$object->SetDBField($status_field, 1);
break;
case 'OnMassDecline':
$object->SetDBField($status_field, 0);
break;
case 'OnMassMoveUp':
$object->SetDBField('Priority', $object->GetDBField('Priority') + 1);
break;
case 'OnMassMoveDown':
$object->SetDBField('Priority', $object->GetDBField('Priority') - 1);
break;
}
if ($object->Update()) {
$event->status = erSUCCESS;
}
else {
$event->status = erFAIL;
$event->redirect = false;
break;
}
}
}
$this->clearSelectedIDs($event);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnMassClone(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$event->status = erSUCCESS;
$temp =& $this->Application->recallObject($event->getPrefixSpecial().'_TempHandler', 'kTempTablesHandler');
$ids = $this->StoreSelectedIDs($event);
if ($ids) {
$temp->CloneItems($event->Prefix, $event->Special, $ids);
}
$this->clearSelectedIDs($event);
}
function check_array($records, $field, $value)
{
foreach ($records as $record) {
if ($record[$field] == $value) {
return true;
}
}
return false;
}
function OnPreSavePopup(&$event)
{
$object =& $event->getObject();
$this->RemoveRequiredFields($object);
$event->CallSubEvent('OnPreSave');
$this->finalizePopup($event);
}
/* End of Edit events */
// III. Events that allow to put some code before and after Update,Load,Create and Delete methods of item
/**
* Occurse before loading item, 'id' parameter
* allows to get id of item beeing loaded
*
* @param kEvent $event
* @access public
*/
function OnBeforeItemLoad(&$event)
{
}
/**
* Occurse after loading item, 'id' parameter
* allows to get id of item that was loaded
*
* @param kEvent $event
* @access public
*/
function OnAfterItemLoad(&$event)
{
}
/**
* Occurse before creating item
*
* @param kEvent $event
* @access public
*/
function OnBeforeItemCreate(&$event)
{
}
/**
* Occurse after creating item
*
* @param kEvent $event
* @access public
*/
function OnAfterItemCreate(&$event)
{
}
/**
* Occurse before updating item
*
* @param kEvent $event
* @access public
*/
function OnBeforeItemUpdate(&$event)
{
}
/**
* Occurse after updating item
*
* @param kEvent $event
* @access public
*/
function OnAfterItemUpdate(&$event)
{
}
/**
* Occurse before deleting item, id of item beeing
* deleted is stored as 'id' event param
*
* @param kEvent $event
* @access public
*/
function OnBeforeItemDelete(&$event)
{
}
/**
* Occurse after deleting item, id of deleted item
* is stored as 'id' param of event
*
* @param kEvent $event
* @access public
*/
function OnAfterItemDelete(&$event)
{
}
/**
* Occurs after successful item validation
*
* @param kEvent $event
*/
function OnAfterItemValidate(&$event)
{
}
/**
* Occures after an item has been copied to temp
* Id of copied item is passed as event' 'id' param
*
* @param kEvent $event
*/
function OnAfterCopyToTemp(&$event)
{
}
/**
* Occures before an item is deleted from live table when copying from temp
* (temp handler deleted all items from live and then copy over all items from temp)
* Id of item being deleted is passed as event' 'id' param
*
* @param kEvent $event
*/
function OnBeforeDeleteFromLive(&$event)
{
}
/**
* Occures before an item is copied to live table (after all foreign keys have been updated)
* Id of item being copied is passed as event' 'id' param
*
* @param kEvent $event
*/
function OnBeforeCopyToLive(&$event)
{
}
/**
* !!! NOT FULLY IMPLEMENTED - SEE TEMP HANDLER COMMENTS (search by event name)!!!
* Occures after an item has been copied to live table
* Id of copied item is passed as event' 'id' param
*
* @param kEvent $event
*/
function OnAfterCopyToLive(&$event)
{
}
/**
* Occures before an item is cloneded
* Id of ORIGINAL item is passed as event' 'id' param
* Do not call object' Update method in this event, just set needed fields!
*
* @param kEvent $event
*/
function OnBeforeClone(&$event)
{
}
/**
* Occures after an item has been cloned
* Id of newly created item is passed as event' 'id' param
*
* @param kEvent $event
*/
function OnAfterClone(&$event)
{
}
/**
* Ensures that popup will be closed automatically
* and parent window will be refreshed with template
* passed
*
* @param kEvent $event
* @access public
*/
function finalizePopup(&$event)
{
$event->SetRedirectParam('opener', 'u');
/*return ;
// 2. substitute opener
$opener_stack = $this->Application->RecallVar('opener_stack');
$opener_stack = $opener_stack ? unserialize($opener_stack) : Array();
//array_pop($opener_stack);
$t = $this->Application->RecallVar('return_template');
$this->Application->RemoveVar('return_template');
// restore original "m" prefix all params, that have values before opening selector
$return_m = $this->Application->RecallVar('return_m');
$this->Application->RemoveVar('return_m');
$this->Application->HttpQuery->parseEnvPart($return_m);
$pass_events = $event->getEventParam('pass_events');
$redirect_params = array_merge_recursive2($event->redirect_params, Array('m_opener' => 'u', '__URLENCODE__' => 1));
$new_level = 'index.php|'.ltrim($this->Application->BuildEnv($t, $redirect_params, 'all', $pass_events), ENV_VAR_NAME.'=');
array_push($opener_stack, $new_level);
$this->Application->StoreVar('opener_stack', serialize($opener_stack));*/
}
/**
* Create search filters based on search query
*
* @param kEvent $event
* @access protected
*/
function OnSearch(&$event)
{
$event->setPseudoClass('_List');
$search_helper =& $this->Application->recallObject('SearchHelper');
$search_helper->performSearch($event);
}
/**
* Clear search keywords
*
* @param kEvent $event
* @access protected
*/
function OnSearchReset(&$event)
{
$search_helper =& $this->Application->recallObject('SearchHelper');
$search_helper->resetSearch($event);
}
/**
* Set's new filter value (filter_id meaning from config)
*
* @param kEvent $event
*/
function OnSetFilter(&$event)
{
$filter_id = $this->Application->GetVar('filter_id');
$filter_value = $this->Application->GetVar('filter_value');
$view_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_view_filter');
$view_filter = $view_filter ? unserialize($view_filter) : Array();
$view_filter[$filter_id] = $filter_value;
$this->Application->StoreVar( $event->getPrefixSpecial().'_view_filter', serialize($view_filter) );
}
function OnSetFilterPattern(&$event)
{
$filters = $this->Application->GetVar($event->getPrefixSpecial(true).'_filters');
if (!$filters) return ;
$view_filter = $this->Application->RecallVar($event->getPrefixSpecial().'_view_filter');
$view_filter = $view_filter ? unserialize($view_filter) : Array();
$filters = explode(',', $filters);
foreach ($filters as $a_filter) {
list($id, $value) = explode('=', $a_filter);
$view_filter[$id] = $value;
}
$this->Application->StoreVar( $event->getPrefixSpecial().'_view_filter', serialize($view_filter) );
$event->redirect = false;
}
/**
* Add/Remove all filters applied to list from "View" menu
*
* @param kEvent $event
*/
function FilterAction(&$event)
{
$view_filter = Array();
$filter_menu = $this->Application->getUnitOption($event->Prefix,'FilterMenu');
switch ($event->Name)
{
case 'OnRemoveFilters':
$filter_value = 1;
break;
case 'OnApplyFilters':
$filter_value = 0;
break;
}
foreach($filter_menu['Filters'] as $filter_key => $filter_params)
{
if(!$filter_params) continue;
$view_filter[$filter_key] = $filter_value;
}
$this->Application->StoreVar( $event->getPrefixSpecial().'_view_filter', serialize($view_filter) );
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnPreSaveAndOpenTranslator(&$event)
{
$this->Application->SetVar('allow_translation', true);
$object =& $event->getObject();
$this->RemoveRequiredFields($object);
$event->CallSubEvent('OnPreSave');
if ($event->status == erSUCCESS) {
$resource_id = $this->Application->GetVar('translator_resource_id');
if ($resource_id) {
$t_prefixes = explode(',', $this->Application->GetVar('translator_prefixes'));
$cdata =& $this->Application->recallObject($t_prefixes[1], null, Array('skip_autoload' => true));
$cdata->Load($resource_id, 'ResourceId');
if (!$cdata->isLoaded()) {
$cdata->SetDBField('ResourceId', $resource_id);
$cdata->Create();
}
$this->Application->SetVar($cdata->getPrefixSpecial().'_id', $cdata->GetID());
}
$event->redirect = $this->Application->GetVar('translator_t');
$event->redirect_params = Array('pass'=>'all,trans,'.$this->Application->GetVar('translator_prefixes'),
$event->getPrefixSpecial(true).'_id' => $object->GetID(),
'trans_event' => 'OnLoad',
'trans_prefix' => $this->Application->GetVar('translator_prefixes'),
'trans_field' => $this->Application->GetVar('translator_field'),
'trans_multi_line' => $this->Application->GetVar('translator_multi_line'),
);
// 1. SAVE LAST TEMPLATE TO SESSION (really needed here, because of tweaky redirect)
$last_template = $this->Application->RecallVar('last_template');
preg_match('/index4\.php\|'.$this->Application->GetSID().'-(.*):/U', $last_template, $rets);
$this->Application->StoreVar('return_template', $this->Application->GetVar('t'));
}
}
function RemoveRequiredFields(&$object)
{
// making all field non-required to achieve successful presave
foreach($object->Fields as $field => $options)
{
if(isset($options['required']))
{
unset($object->Fields[$field]['required']);
}
}
}
/**
* Saves selected user in needed field
*
* @param kEvent $event
*/
function OnSelectUser(&$event)
{
$items_info = $this->Application->GetVar('u');
if ($items_info) {
$user_id = array_shift( array_keys($items_info) );
$object =& $event->getObject();
$this->RemoveRequiredFields($object);
$is_new = !$object->isLoaded();
$is_main = substr($this->Application->GetVar($event->Prefix.'_mode'), 0, 1) == 't';
if ($is_new) {
$new_event = $is_main ? 'OnPreCreate' : 'OnNew';
$event->CallSubEvent($new_event);
$event->redirect = true;
}
$object->SetDBField($this->Application->RecallVar('dst_field'), $user_id);
if ($is_new) {
$object->Create();
if (!$is_main && $object->IsTempTable()) {
$object->setTempID();
}
}
else {
$object->Update();
}
}
$event->SetRedirectParam($event->getPrefixSpecial().'_id', $object->GetID());
$this->finalizePopup($event);
}
/** EXPORT RELATED **/
/**
* Shows export dialog
*
* @param kEvent $event
*/
function OnExport(&$event)
{
$this->StoreSelectedIDs($event);
$selected_ids = $this->getSelectedIDs($event);
if (implode(',', $selected_ids) == '') {
// K4 fix when no ids found bad selected ids array is formed
$selected_ids = false;
}
$this->Application->StoreVar($event->Prefix.'_export_ids', $selected_ids ? implode(',', $selected_ids) : '' );
$export_t = $this->Application->GetVar('export_template');
$this->Application->LinkVar('export_finish_t');
$this->Application->LinkVar('export_progress_t');
$this->Application->StoreVar('export_oroginal_special', $event->Special);
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
$event->redirect = $export_t ? $export_t : $export_helper->getModuleFolder($event).'/export';
list($index_file, $env) = explode('|', $this->Application->RecallVar('last_template'));
$finish_url = $this->Application->BaseURL('/admin').$index_file.'?'.ENV_VAR_NAME.'='.$env;
$this->Application->StoreVar('export_finish_url', $finish_url);
$redirect_params = Array(
$this->Prefix.'.export_event' => 'OnNew',
'pass' => 'all,'.$this->Prefix.'.export');
$event->setRedirectParams($redirect_params);
}
/**
* Apply some special processing to
* object beeing recalled before using
* it in other events that call prepareObject
*
* @param Object $object
* @param kEvent $event
* @access protected
*/
function prepareObject(&$object, &$event)
{
if ($event->Special == 'export' || $event->Special == 'import')
{
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
$export_helper->prepareExportColumns($event);
}
}
/**
* Returns specific to each item type columns only
*
* @param kEvent $event
* @return Array
*/
function getCustomExportColumns(&$event)
{
return Array();
}
/**
* Export form validation & processing
*
* @param kEvent $event
*/
function OnExportBegin(&$event)
{
$export_helper =& $this->Application->recallObject('CatItemExportHelper');
/* @var $export_helper kCatDBItemExportHelper */
$export_helper->OnExportBegin($event);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnExportCancel(&$event)
{
$this->OnGoBack($event);
}
/**
* Allows configuring export options
*
* @param kEvent $event
*/
function OnBeforeExportBegin(&$event)
{
}
function OnDeleteExportPreset(&$event)
{
$object =& $event->GetObject();
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
list($id,$field_values) = each($items_info);
$preset_key = $field_values['ExportPresets'];
$export_settings = $this->Application->RecallPersistentVar('export_settings');
if (!$export_settings) return ;
$export_settings = unserialize($export_settings);
if (!isset($export_settings[$event->Prefix])) return ;
$to_delete = '';
$export_presets = array(''=>'');
foreach ($export_settings[$event->Prefix] as $key => $val) {
if (implode('|', $val['ExportColumns']) == $preset_key) {
$to_delete = $key;
break;
}
}
if ($to_delete) {
unset($export_settings[$event->Prefix][$to_delete]);
$this->Application->StorePersistentVar('export_settings', serialize($export_settings));
}
}
}
/**
* Saves changes & changes language
*
* @param kEvent $event
*/
function OnPreSaveAndChangeLanguage(&$event)
{
$event->CallSubEvent('OnPreSave');
if ($event->status == erSUCCESS) {
$this->Application->SetVar('m_lang', $this->Application->GetVar('language'));
}
}
function OnUploadFile(&$event)
{
// Flash uploader does NOT send correct cookies, so we need to make our own check
$cookie_name = 'adm_'.$this->Application->ConfigValue('SessionCookieName');
$this->Application->HttpQuery->Cookie['cookies_on'] = 1;
$this->Application->HttpQuery->Cookie[$cookie_name] = $this->Application->GetVar('flashsid');
$admin_ses =& $this->Application->recallObject('Session.admin');
/* @var $admin_ses Session */
$user = $admin_ses->RecallVar('user_id');
$perm_helper =& $this->Application->recallObject('PermissionsHelper');
/* @var $perm_helper kPermissionsHelper */
$section = $event->getSection();
if (!$perm_helper->CheckUserPermission($user, $section.'.add') && !$perm_helper->CheckUserPermission($user, $section.'.edit')) {
$event->status = erPERM_FAIL;
header('HTTP/1.0 403 You don\'t have permissions to upload');
exit;
return;
}
if (!$cookie_name) $cookie_name = 'sid';
$value = $this->Application->GetVar('Filedata');
if (!$value) return ;
$tmp_path = defined('WRITEABLE') ? WRITEABLE.'/tmp/' : FULL_PATH.'/kernel/cache/';
$fname = $value['name'];
$id = $this->Application->GetVar('id');
if ($id) $fname = $id.'_'.$fname;
if (!is_writable($tmp_path)) {
header('HTTP/1.0 500 Write permissions not set on the server');
exit;
}
move_uploaded_file($value['tmp_name'], $tmp_path.$fname);
exit;
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnDeleteFile(&$event)
{
if (strpos($this->Application->GetVar('file'), '../') !== false) return ;
$object =& $event->getObject(array('skip_autoload'=>true));
$options = $object->GetFieldOptions($this->Application->GetVar('field'));
$var_name = $event->getPrefixSpecial().'_file_pending_actions'.$this->Application->GetVar('m_wid');
$schedule = $this->Application->RecallVar($var_name);
$schedule = $schedule ? unserialize($schedule) : array();
$schedule[] = array('action'=>'delete', 'file'=>$path = FULL_PATH.$options['upload_dir'].$this->Application->GetVar('file'));
$this->Application->StoreVar($var_name, serialize($schedule));
$this->Application->Session->SaveData();
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnViewFile(&$event)
{
if (strpos($this->Application->GetVar('file'), '../') !== false) return ;
if ($this->Application->GetVar('tmp')) {
$path = (defined('WRITEABLE') ? WRITEABLE.'/tmp/' : FULL_PATH.'/kernel/cache/').$this->Application->GetVar('id').'_'.$this->Application->GetVar('file');
}
else {
$object =& $event->getObject(array('skip_autoload'=>true));
$options = $object->GetFieldOptions($this->Application->GetVar('field'));
$path = FULL_PATH.$options['upload_dir'].$this->Application->GetVar('file');
}
$type = mime_content_type($path);
header('Content-Length: '.filesize($path));
header('Content-Type: '.$type);
safeDefine('DBG_SKIP_REPORTING',1);
readfile($path);
exit();
}
/**
* Validates MInput control fields
*
* @param kEvent $event
*/
function OnValidateMInputFields(&$event)
{
$minput_helper =& $this->Application->recallObject('MInputHelper');
/* @var $minput_helper MInputHelper */
$minput_helper->OnValidateMInputFields($event);
}
/**
* Returns auto-complete values for ajax-dropdown
*
* @param kEvent $event
*/
function OnSuggestValues(&$event)
{
$this->Application->XMLHeader();
$field = $this->Application->GetVar('field');
$cur_value = $this->Application->GetVar('cur_value');
if (!$field || !$cur_value) {
exit;
}
$object =& $event->getObject();
$sql = 'SELECT DISTINCT '.$field.'
FROM '.$object->TableName.'
WHERE '.$field.' LIKE '.$this->Conn->qstr($cur_value.'%').'
ORDER BY '.$field.'
LIMIT 0,20';
$data = $this->Conn->GetCol($sql);
echo '<suggestions>';
foreach ($data as $item) {
echo '<item>'.$item.'</item>';
}
echo '</suggestions>';
$event->status = erSTOP;
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnSaveWidths(&$event)
{
safeDefine('DBG_SKIP_REPORTING', 1);
$lang =& $this->Application->recallObject('lang.current');
// header('Content-type: text/xml; charset='.$lang->GetDBField('Charset'));
$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
/* @var $picker_helper kColumnPickerHelper */
$picker_helper->PreparePicker($event->getPrefixSpecial(), $this->Application->GetVar('grid_name'));
$picker_helper->SaveWidths($event->getPrefixSpecial(), $this->Application->GetVar('widths'));
exit;
}
/**
* Called from CSV import script after item fields
* are set and validated, but before actual item create/update.
* If event status is erSUCCESS, line will be imported,
* else it will not be imported but added to skipped lines
* and displayed in the end of import.
* Event status is preset from import script.
*
* @param kEvent $event
*/
function OnBeforeCSVLineImport(&$event)
{
// abstract, for hooking
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/kernel/db/db_event_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.99.2.17
\ No newline at end of property
+1.99.2.18
\ No newline at end of property
Index: branches/RC/core/kernel/db/dbitem.php
===================================================================
--- branches/RC/core/kernel/db/dbitem.php (revision 10293)
+++ branches/RC/core/kernel/db/dbitem.php (revision 10294)
@@ -1,1068 +1,1184 @@
<?php
/**
* DBItem
*
* Desciption
* @package kernel4
*/
class kDBItem extends kDBBase {
/**
* Description
*
* @var array Associative array of current item' field values
* @access public
*/
var $FieldValues;
/**
* Unformatted field values, before parse
*
* @var Array
* @access private
*/
var $DirtyFieldValues = Array();
/**
* Holds item values after loading (not affected by submit)
*
* @var Array
* @access private
*/
var $OriginalFieldValues = Array ();
var $FieldErrors;
var $ErrorMsgs = Array();
/**
* If set to true, Update will skip Validation before running
*
* @var array Associative array of current item' field values
* @access public
*/
var $IgnoreValidation = false;
var $Loaded = false;
/**
* Holds item' primary key value
*
* @var int Value of primary key field for current item
* @access public
*/
var $ID;
function kDBItem()
{
parent::kDBBase();
$this->ErrorMsgs['required'] = '!la_err_required!'; //'Field is required';
$this->ErrorMsgs['unique'] = '!la_err_unique!'; //'Field value must be unique';
$this->ErrorMsgs['value_out_of_range'] = '!la_err_value_out_of_range!'; //'Field is out of range, possible values from %s to %s';
$this->ErrorMsgs['length_out_of_range'] = '!la_err_length_out_of_range!'; //'Field is out of range';
$this->ErrorMsgs['bad_type'] = '!la_err_bad_type!'; //'Incorrect data format, please use %s';
$this->ErrorMsgs['invalid_format'] = '!la_err_invalid_format!'; //'Incorrect data format, please use %s';
$this->ErrorMsgs['bad_date_format'] = '!la_err_bad_date_format!'; //'Incorrect date format, please use (%s) ex. (%s)';
$this->ErrorMsgs['primary_lang_required'] = '!la_err_primary_lang_required!';
}
function SetDirtyField($field_name, $field_value)
{
$this->DirtyFieldValues[$field_name] = $field_value;
}
function GetDirtyField($field_name)
{
return $this->DirtyFieldValues[$field_name];
}
- function GetOriginalField($field_name)
+ function GetOriginalField($field_name, $formatted = false, $format=null)
{
- return $this->OriginalFieldValues[$field_name];
+ $value = $this->OriginalFieldValues[$field_name];
+ if (!$formatted) {
+ return $value;
+ }
+
+ $options = $this->GetFieldOptions($field_name);
+ $res = $value;
+ if (array_key_exists('formatter', $options)) {
+ $formatter =& $this->Application->recallObject($options['formatter']);
+ /* @var $formatter kFormatter */
+
+ $res = $formatter->Format($value, $field_name, $this, $format);
+ }
+ return $res;
}
/**
* Sets original field value (useful for custom virtual fields)
*
* @param string $field_name
*/
function SetOriginalField($field_name, $field_value)
{
$this->OriginalFieldValues[$field_name] = $field_value;
}
/**
* Set's default values for all fields
*
* @param bool $populate_ml_fields create all ml fields from db in config or not
*
* @access public
*/
function SetDefaultValues($populate_ml_fields = false)
{
parent::SetDefaultValues($populate_ml_fields);
if ($populate_ml_fields) {
$this->PopulateMultiLangFields();
}
foreach ($this->Fields as $field => $params) {
if ( isset($params['default']) ) {
$this->SetDBField($field, $params['default']);
}
else {
$this->SetDBField($field, NULL);
}
}
}
/**
* Sets current item field value
* (applies formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
function SetField($name,$value)
{
$options = $this->GetFieldOptions($name);
$parsed = $value;
if ($value == '') {
$parsed = NULL;
}
// kFormatter is always used, to make sure, that numeric value is converted to normal representation
// according to regional format, even when formatter is not set (try seting format to 1.234,56 to understand why)
$formatter =& $this->Application->recallObject(isset($options['formatter']) ? $options['formatter'] : 'kFormatter');
$parsed = $formatter->Parse($value, $name, $this);
$this->SetDBField($name,$parsed);
}
/**
* Sets current item field value
* (doesn't apply formatting)
*
* @access public
* @param string $name Name of the field
* @param mixed $value Value to set the field to
* @return void
*/
function SetDBField($name,$value)
{
$this->FieldValues[$name] = $value;
/*if (isset($this->Fields[$name]['formatter'])) {
$formatter =& $this->Application->recallObject($this->Fields[$name]['formatter']);
$formatter->UpdateSubFields($name, $value, $this->Fields[$name], $this);
}*/
}
/**
* Set's field error, if pseudo passed not found then create it with message text supplied.
* Don't owerrite existing pseudo translation.
*
* @param string $field
* @param string $pseudo
* @param string $error_label
*/
function SetError($field, $pseudo, $error_label = null, $error_params = null)
{
$error_field = isset($this->Fields[$field]['error_field']) ? $this->Fields[$field]['error_field'] : $field;
if (isset($this->FieldErrors[$error_field]['pseudo'])) {
// don't set more then one error on field
return ;
}
$this->FieldErrors[$error_field]['pseudo'] = $pseudo;
if (isset($error_params)) {
// additional params, that helps to determine error sources
$this->FieldErrors[$error_field]['params'] = $error_params;
}
if (isset($error_label) && !isset($this->ErrorMsgs[$pseudo])) {
// label for error (only when not already set)
$this->ErrorMsgs[$pseudo] = (substr($error_label, 0, 1) == '+') ? substr($error_label, 1) : '!'.$error_label.'!';
}
}
/**
* Return current item' field value by field name
* (doesn't apply formatter)
*
* @access public
* @param string $name field name to return
* @return mixed
*/
function GetDBField($name)
{
return $this->FieldValues[$name];
}
function HasField($name)
{
return isset($this->FieldValues[$name]);
}
function GetFieldValues()
{
return $this->FieldValues;
}
/**
* Sets item' fields corresponding to elements in passed $hash values.
*
* The function sets current item fields to values passed in $hash, by matching $hash keys with field names
* of current item. If current item' fields are unknown {@link kDBItem::PrepareFields()} is called before acutally setting the fields
*
* @access public
* @param Array $hash
* @param Array $set_fields Optional param, field names in target object to set, other fields will be skipped
* @return void
*/
function SetFieldsFromHash($hash, $set_fields=null)
{
// used in formatter which work with multiple fields together
foreach($hash as $field_name => $field_value)
{
if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue;
if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue;
$this->SetDirtyField($field_name, $field_value);
}
// formats all fields using associated formatters
foreach ($hash as $field_name => $field_value)
{
if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue;
if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue;
$this->SetField($field_name,$field_value);
}
}
function SetDBFieldsFromHash($hash, $set_fields=null)
{
foreach ($hash as $field_name => $field_value)
{
if( eregi("^[0-9]+$", $field_name) || !array_key_exists($field_name,$this->Fields) ) continue;
if ( is_array($set_fields) && !in_array($field_name, $set_fields) ) continue;
$this->SetDBField($field_name, $field_value);
}
}
/**
* Returns part of SQL WHERE clause identifing the record, ex. id = 25
*
* @access public
* @param string $method Child class may want to know who called GetKeyClause, Load(), Update(), Delete() send its names as method
* @param Array $keys_hash alternative, then item id, keys hash to load item by
* @return void
* @see kDBItem::Load()
* @see kDBItem::Update()
* @see kDBItem::Delete()
*/
function GetKeyClause($method=null, $keys_hash = null)
{
if( !isset($keys_hash) ) $keys_hash = Array($this->IDField => $this->ID);
$ret = '';
foreach($keys_hash as $field => $value)
{
if (!preg_match('/\./', $field)) {
$ret .= '(`'.$this->TableName.'`.'.$field.' = '.$this->Conn->qstr($value).') AND ';
}
else {
$ret .= '('.$field.' = '.$this->Conn->qstr($value).') AND ';
}
}
return preg_replace('/(.*) AND $/', '\\1', $ret);
}
/**
* Loads item from the database by given id
*
* @access public
* @param mixed $id item id of keys->values hash to load item by
* @param string $id_field_name Optional parameter to load item by given Id field
* @return bool True if item has been loaded, false otherwise
*/
function Load($id, $id_field_name = null)
{
if ( isset($id_field_name) ) $this->SetIDField( $id_field_name );
$keys_sql = '';
if( is_array($id) )
{
$keys_sql = $this->GetKeyClause('load', $id);
}
else
{
$this->setID($id);
$keys_sql = $this->GetKeyClause('load');
}
if ( isset($id_field_name) ) $this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') );
if( ($id === false) || !$keys_sql ) return $this->Clear();
if( !$this->raiseEvent('OnBeforeItemLoad', $id) ) return false;
$q = $this->GetSelectSQL().' WHERE '.$keys_sql;
$field_values = $this->Conn->GetRow($q);
if($field_values)
{
$this->FieldValues = array_merge_recursive2($this->FieldValues, $field_values);
$this->OriginalFieldValues = $this->FieldValues;
}
else {
return $this->Clear();
}
if( is_array($id) || isset($id_field_name) ) $this->setID( $this->FieldValues[$this->IDField] );
$this->UpdateFormattersSubFields(); // used for updating separate virtual date/time fields from DB timestamp (for example)
$this->raiseEvent('OnAfterItemLoad', $this->GetID() );
$this->Loaded = true;
return true;
}
/**
* Builds select sql, SELECT ... FROM parts only
*
* @access public
* @return string
*/
function GetSelectSQL()
{
$sql = $this->addCalculatedFields($this->SelectClause);
return parent::GetSelectSQL($sql);
}
function UpdateFormattersMasterFields()
{
foreach ($this->Fields as $field => $options) {
if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
}
}
}
function SkipField($field_name, $force_id=false)
{
$skip = false;
$skip = $skip || ( isset($this->VirtualFields[$field_name]) ); //skipping 'virtual' field
$skip = $skip || ( !getArrayValue($this->FieldValues, $field_name) && getArrayValue($this->Fields[$field_name], 'skip_empty') ); //skipping marked field with 'skip_empty'
// $skip = $skip || ($field_name == $this->IDField && !$force_id); //skipping Primary Key
// $table_name = preg_replace("/^(.*)\./", "$1", $field_name);
// $skip = $skip || ($table_name && ($table_name != $this->TableName)); //skipping field from other tables
$skip = $skip || ( !isset($this->Fields[$field_name]) ); //skipping field not in Fields (nor virtual, nor real)
return $skip;
}
/**
* Updates previously loaded record with current item' values
*
* @access public
* @param int Primery Key Id to update
* @return bool
*/
function Update($id=null, $system_update=false)
{
if( isset($id) ) $this->setID($id);
if( !$this->raiseEvent('OnBeforeItemUpdate') ) return false;
if( !isset($this->ID) ) return false;
// Validate before updating
if (!$this->Validate()) {
return false;
}
if( !$this->raiseEvent('OnAfterItemValidate') ) return false;
//Nothing to update
if(!$this->FieldValues) return true;
$sql = sprintf('UPDATE %s SET ',$this->TableName);
foreach ($this->FieldValues as $field_name => $field_value)
{
if ($this->SkipField($field_name)) continue;
$real_field_name = eregi_replace("^.*\.", '',$field_name); //removing table names from field names
//Adding part of SET clause for current field, escaping data with ADODB' qstr
if (is_null( $this->FieldValues[$field_name] )) {
if (isset($this->Fields[$field_name]['not_null']) && $this->Fields[$field_name]['not_null']) {
$sql .= '`'.$real_field_name.'` = '.$this->Conn->qstr($this->Fields[$field_name]['default']).', ';
}
else {
$sql .= '`'.$real_field_name.'` = NULL, ';
}
}
else {
$sql.= sprintf('`%s`=%s, ', $real_field_name, $this->Conn->qstr($this->FieldValues[$field_name], 0));
}
}
$sql = ereg_replace(", $", '', $sql); //Removing last comma and space
$sql.= sprintf(' WHERE %s', $this->GetKeyClause('update')); //Adding WHERE clause with Primary Key
if( $this->Conn->ChangeQuery($sql) === false ) return false;
$affected = $this->Conn->getAffectedRows();
if (!$system_update && $affected == 1){
- $this->setModifiedFlag();
+ $this->setModifiedFlag(clUPDATE);
}
$this->saveCustomFields();
$this->raiseEvent('OnAfterItemUpdate');
$this->Loaded = true;
if ($this->mode != 't') {
$this->Application->resetCounters($this->TableName);
}
return true;
}
function ValidateField($field)
{
$options = $this->Fields[$field];
/*if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$formatter->UpdateMasterFields($field, $this->GetDBField($field), $options, $this);
}*/
$error_field = isset($options['error_field']) ? $options['error_field'] : $field;
$res = !isset($this->FieldErrors[$error_field]['pseudo']) || !$this->FieldErrors[$error_field]['pseudo'];
$res = $res && $this->ValidateType($field, $options);
$res = $res && $this->ValidateRange($field, $options);
$res = $res && $this->ValidateUnique($field, $options);
$res = $res && $this->ValidateRequired($field, $options);
$res = $res && $this->CustomValidation($field, $options);
return $res;
}
/**
* Validate all item fields based on
* constraints set in each field options
* in config
*
* @return bool
* @access private
*/
function Validate()
{
$this->UpdateFormattersMasterFields(); //order is critical - should be called BEFORE checking errors
if ($this->IgnoreValidation) {
return true;
}
$global_res = true;
foreach ($this->Fields as $field => $params) {
$res = $this->ValidateField($field);
$global_res = $global_res && $res;
}
if (!$global_res && $this->Application->isDebugMode()) {
$error_msg = ' Validation failed in prefix <strong>'.$this->Prefix.'</strong>,
FieldErrors follow (look at items with <strong>"pseudo"</strong> key set)<br />
You may ignore this notice if submitted data really has a validation error';
trigger_error(trim($error_msg), E_USER_NOTICE);
$this->Application->Debugger->dumpVars($this->FieldErrors);
}
return $global_res;
}
/**
* Check field value by user-defined alghoritm
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
*/
function CustomValidation($field, $params)
{
return true;
}
/**
* Check if item has errors
*
* @param Array $skip_fields fields to skip during error checking
* @return bool
*/
function HasErrors($skip_fields)
{
$global_res = false;
foreach ($this->Fields as $field => $field_params) {
// If Formatter has set some error messages during values parsing
if ( !( in_array($field, $skip_fields) ) &&
isset($this->FieldErrors[$field]['pseudo']) && $this->FieldErrors[$field] != '') {
$global_res = true;
}
}
return $global_res;
}
/**
* Check if value in field matches field type specified in config
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
*/
function ValidateType($field, $params)
{
$res = true;
$val = $this->FieldValues[$field];
if ( $val != '' &&
isset($params['type']) &&
preg_match("#int|integer|double|float|real|numeric|string#", $params['type'])
) {
if ($params['type'] == 'numeric') {
trigger_error('Invalid field type <strong>'.$params['type'].'</strong> (in ValidateType method), please use <strong>float</strong> instead', E_USER_NOTICE);
$params['type'] = 'float';
}
$res = is_numeric($val);
if ($params['type']=='string' || $res) {
$f = 'is_'.$params['type'];
settype($val, $params['type']);
$res = $f($val) && ($val == $this->FieldValues[$field]);
}
if (!$res) {
$this->SetError($field, 'bad_type', null, $params['type']);
}
}
return $res;
}
/**
* Check if value is set for required field
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateRequired($field, $params)
{
$res = true;
if (isset($params['required']) && $params['required']) {
$check_value = $this->FieldValues[$field];
if ($this->Application->ConfigValue('TrimRequiredFields')) {
$check_value = trim($check_value);
}
$res = ((string)$check_value != '');
}
$options = $this->GetFieldOptions($field);
if (!$res && getArrayValue($options, 'formatter') != 'kUploadFormatter') {
$this->SetError($field, 'required');
}
return $res;
}
/**
* Validates that current record has unique field combination among other table records
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateUnique($field, $params)
{
$res = true;
$unique_fields = getArrayValue($params,'unique');
if($unique_fields !== false)
{
$where = Array();
array_push($unique_fields,$field);
foreach($unique_fields as $unique_field)
{
// if field is not empty or if it is required - we add where condition
if ($this->GetDBField($unique_field) != '' || (isset($this->Fields[$unique_field]['required']) && $this->Fields[$unique_field]['required'])) {
$where[] = '`'.$unique_field.'` = '.$this->Conn->qstr( $this->GetDBField($unique_field) );
}
}
// This can ONLY happen if all unique fields are empty and not required.
// In such case we return true, because if unique field is not required there may be numerous empty values
if (!$where) return true;
$sql = 'SELECT COUNT(*) FROM %s WHERE ('.implode(') AND (',$where).') AND ('.$this->IDField.' <> '.(int)$this->ID.')';
$res_temp = $this->Conn->GetOne( str_replace('%s', $this->TableName, $sql) );
$current_table_only = getArrayValue($params, 'current_table_only'); // check unique record only in current table
$res_live = $current_table_only ? 0 : $this->Conn->GetOne( str_replace('%s', $this->Application->GetLiveName($this->TableName), $sql) );
$res = ($res_temp == 0) && ($res_live == 0);
if (!$res) {
$this->SetError($field, 'unique');
}
}
return $res;
}
/**
* Check if field value is in range specified in config
*
* @param string $field field name
* @param Array $params field options from config
* @return bool
* @access private
*/
function ValidateRange($field, $params)
{
$res = true;
$val = $this->FieldValues[$field];
if ( isset($params['type']) && preg_match("#int|integer|double|float|real#", $params['type']) && strlen($val) > 0 ) {
if ( isset($params['max_value_inc'])) {
$res = $res && $val <= $params['max_value_inc'];
$max_val = $params['max_value_inc'].' (inclusive)';
}
if ( isset($params['min_value_inc'])) {
$res = $res && $val >= $params['min_value_inc'];
$min_val = $params['min_value_inc'].' (inclusive)';
}
if ( isset($params['max_value_exc'])) {
$res = $res && $val < $params['max_value_exc'];
$max_val = $params['max_value_exc'].' (exclusive)';
}
if ( isset($params['min_value_exc'])) {
$res = $res && $val > $params['min_value_exc'];
$min_val = $params['min_value_exc'].' (exclusive)';
}
}
if (!$res) {
if ( !isset($min_val) ) $min_val = '-&infin;';
if ( !isset($max_val) ) $max_val = '&infin;';
$this->SetError($field, 'value_out_of_range', null, Array ($min_val, $max_val));
return $res;
}
if ( isset($params['max_len'])) {
$res = $res && mb_strlen($val) <= $params['max_len'];
}
if ( isset($params['min_len'])) {
$res = $res && mb_strlen($val) >= $params['min_len'];
}
if (!$res) {
$error_params = Array (getArrayValue($params, 'min_len'), getArrayValue($params, 'max_len'));
$this->SetError($field, 'length_out_of_range', null, $error_params);
return $res;
}
return $res;
}
/**
* Return error message for field
*
* @param string $field
* @return string
* @access public
*/
function GetErrorMsg($field, $force_escape = null)
{
if( !isset($this->FieldErrors[$field]) ) return '';
$err = getArrayValue($this->FieldErrors[$field], 'pseudo');
if (!$err) return '';
// if special error msg defined in config
if( isset($this->Fields[$field]['error_msgs'][$err]) )
{
$msg = $this->Fields[$field]['error_msgs'][$err];
}
else //fall back to defaults
{
if( !isset($this->ErrorMsgs[$err]) ) {
trigger_error('No user message is defined for pseudo error <b>'.$err.'</b><br>', E_USER_WARNING);
return $err; //return the pseudo itself
}
$msg = $this->ErrorMsgs[$err];
}
$msg = $this->Application->ReplaceLanguageTags($msg, $force_escape);
if ( isset($this->FieldErrors[$field]['params']) )
{
return vsprintf($msg, $this->FieldErrors[$field]['params']);
}
return $msg;
}
/**
* Creates a record in the database table with current item' values
*
* @param mixed $force_id Set to TRUE to force creating of item's own ID or to value to force creating of passed id. Do not pass 1 for true, pass exactly TRUE!
* @access public
* @return bool
*/
function Create($force_id=false, $system_create=false)
{
if( !$this->raiseEvent('OnBeforeItemCreate') ) return false;
// Validating fields before attempting to create record
if (!$this->Validate()) {
return false;
}
if( !$this->raiseEvent('OnAfterItemValidate') ) return false;
if (is_int($force_id)) {
$this->FieldValues[$this->IDField] = $force_id;
}
elseif (!$force_id || !is_bool($force_id)) {
$this->FieldValues[$this->IDField] = $this->generateID();
}
$fields_sql = '';
$values_sql = '';
foreach ($this->FieldValues as $field_name => $field_value) {
if ($this->SkipField($field_name, $force_id)) continue;
//Adding field' value to Values block of Insert statement, escaping it with qstr
if (is_null( $this->FieldValues[$field_name] )) {
if (isset($this->Fields[$field_name]['not_null']) && $this->Fields[$field_name]['not_null']) {
$values_sql .= $this->Conn->qstr($this->Fields[$field_name]['default'], 0);
}
else {
$values_sql .= 'NULL';
}
}
else {
if ($field_name == $this->IDField && $this->FieldValues[$field_name] == 0) {
$values_sql .= 'DEFAULT';
}
else {
$values_sql .= $this->Conn->qstr($this->FieldValues[$field_name], 0);
}
}
$fields_sql .= '`'.$field_name.'`, '; //Adding field name to fields block of Insert statement
$values_sql .= ', ';
}
//Cutting last commas and spaces
$fields_sql = ereg_replace(", $", '', $fields_sql);
$values_sql = ereg_replace(", $", '', $values_sql);
$sql = sprintf('INSERT INTO %s (%s) VALUES (%s)', $this->TableName, $fields_sql, $values_sql); //Formatting query
//Executing the query and checking the result
if ($this->Conn->ChangeQuery($sql) === false) return false;
$insert_id = $this->Conn->getInsertID();
if ($insert_id == 0) {
// insert into temp table (id is not auto-increment field)
$insert_id = $this->FieldValues[$this->IDField];
}
$this->setID($insert_id);
if (!$system_create){
- $this->setModifiedFlag();
+ $this->setModifiedFlag(clCREATE);
}
$this->saveCustomFields();
if ($this->mode != 't') {
$this->Application->resetCounters($this->TableName);
}
$this->raiseEvent('OnAfterItemCreate');
$this->Loaded = true;
return true;
}
/**
* Deletes the record from databse
*
* @access public
* @return bool
*/
function Delete($id = null)
{
if( isset($id) ) $this->setID($id);
if( !$this->raiseEvent('OnBeforeItemDelete') ) return false;
$q = 'DELETE FROM '.$this->TableName.' WHERE '.$this->GetKeyClause('Delete');
$ret = $this->Conn->ChangeQuery($q);
- $this->setModifiedFlag();
+ $this->setModifiedFlag(clDELETE);
if ($this->Conn->getAffectedRows() > 0) {
// something was actually deleted
$this->raiseEvent('OnAfterItemDelete');
}
if ($this->mode != 't') {
$this->Application->resetCounters($this->TableName);
}
return $ret;
}
function PopulateMultiLangFields()
{
$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
/* @var $ml_helper kMultiLanguageHelper */
$lang_count = $ml_helper->getLanguageCount();
foreach ($this->Fields as $field => $options)
{
if (isset($options['formatter']) && $options['formatter'] == 'kMultiLanguage' && isset($options['master_field'])) {
if (preg_match('/^l([0-9]+)_(.*)/', $field, $regs)) {
$l = $regs[1];
$name = $regs[2];
unset($options['required']); // all non-primary language field set to non-required
for ($i=1; $i<=$lang_count; $i++) {
if ($i == $l || !$ml_helper->LanguageFound($i)) continue;
$this->Fields['l'.$i.'_'.$name] = $options;
}
}
}
}
}
/**
* Sets new name for item in case if it is beeing copied
* in same table
*
* @param array $master Table data from TempHandler
* @param int $foreign_key ForeignKey value to filter name check query by
* @param string $title_field FieldName to alter, by default - TitleField of the prefix
* @param string $format sprintf-style format of renaming pattern, by default Copy %1$s of %2$s which makes it Copy [Number] of Original Name
* @access private
*/
function NameCopy($master=null, $foreign_key=null, $title_field=null, $format='Copy %1$s of %2$s')
{
if (!isset($title_field)) {
$title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
if (!$title_field || isset($this->CalculatedFields[$title_field]) ) return;
}
$new_name = $this->GetDBField($title_field);
$original_checked = false;
do {
if ( preg_match('/'.sprintf($format, '([0-9]*) *', '(.*)').'/', $new_name, $regs) ) {
$new_name = sprintf($format, ($regs[1]+1), $regs[2]);
}
elseif ($original_checked) {
$new_name = sprintf($format, '', $new_name);
}
// if we are cloning in temp table this will look for names in temp table,
// since object' TableName contains correct TableName (for temp also!)
// if we are cloning live - look in live
$query = 'SELECT '.$title_field.' FROM '.$this->TableName.'
WHERE '.$title_field.' = '.$this->Conn->qstr($new_name);
$foreign_key_field = getArrayValue($master, 'ForeignKey');
$foreign_key_field = is_array($foreign_key_field) ? $foreign_key_field[ $master['ParentPrefix'] ] : $foreign_key_field;
if ($foreign_key_field && isset($foreign_key)) {
$query .= ' AND '.$foreign_key_field.' = '.$foreign_key;
}
$res = $this->Conn->GetOne($query);
/*// if not found in live table, check in temp table if applicable
if ($res === false && $object->Special == 'temp') {
$query = 'SELECT '.$name_field.' FROM '.$this->GetTempName($master['TableName']).'
WHERE '.$name_field.' = '.$this->Conn->qstr($new_name);
$res = $this->Conn->GetOne($query);
}*/
$original_checked = true;
} while ($res !== false);
$this->SetDBField($title_field, $new_name);
}
function raiseEvent($name, $id = null, $additional_params = Array())
{
if( !isset($id) ) $id = $this->GetID();
$event = new kEvent( Array('name'=>$name,'prefix'=>$this->Prefix,'special'=>$this->Special) );
$event->setEventParam('id', $id);
if ($additional_params) {
foreach ($additional_params as $ap_name => $ap_value) {
$event->setEventParam($ap_name, $ap_value);
}
}
$this->Application->HandleEvent($event);
return $event->status == erSUCCESS ? true : false;
}
/**
* Set's new ID for item
*
* @param int $new_id
* @access public
*/
function setID($new_id)
{
$this->ID = $new_id;
$this->SetDBField($this->IDField, $new_id);
}
/**
* Generate and set new temporary id
*
* @access private
*/
function setTempID()
{
$new_id = (int)$this->Conn->GetOne('SELECT MIN('.$this->IDField.') FROM '.$this->TableName);
if($new_id > 0) $new_id = 0;
--$new_id;
$this->Conn->Query('UPDATE '.$this->TableName.' SET `'.$this->IDField.'` = '.$new_id.' WHERE `'.$this->IDField.'` = '.$this->GetID());
+
+ if ($this->ShouldLogChanges()) {
+ // Updating TempId in ChangesLog, if changes are disabled
+ $ses_var_name = $this->Application->GetTopmostPrefix($this->Prefix).'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
+ $changes = $this->Application->RecallVar($ses_var_name);
+ $changes = $changes ? unserialize($changes) : Array ();
+ if ($changes) {
+ foreach ($changes as $key => $rec) {
+ if ($rec['Prefix'] == $this->Prefix && $rec['ItemId'] == $this->GetID()) {
+ $changes[$key]['ItemId'] = $new_id;
+ }
+ }
+ }
+ $this->Application->StoreVar($ses_var_name, serialize($changes));
+ }
+
$this->SetID($new_id);
}
/**
* Set's modification flag for main prefix of current prefix to true
*
* @access private
* @author Alexey
*/
- function setModifiedFlag()
+ function setModifiedFlag($mode = null)
{
$main_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
$this->Application->StoreVar($main_prefix.'_modified', '1');
+
+ if ($this->ShouldLogChanges()) {
+ $this->LogChanges($main_prefix, $mode);
+ if (!$this->IsTempTable()) {
+ $handler =& $this->Application->recallObject($this->Prefix.'_EventHandler');
+ $ses_var_name = $main_prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
+ $handler->SaveLoggedChanges($ses_var_name);
+ }
+ }
+ }
+
+ function ShouldLogChanges()
+ {
+ /* @todo Replace true with global LogChanges option */
+ return ($this->Application->getUnitOption($this->Prefix, 'LogChanges') || true) && !$this->Application->getUnitOption($this->Prefix, 'ForceDontLogChanges');
+ }
+
+ function LogChanges($main_prefix, $mode)
+ {
+ if (!$mode) {
+ return ;
+ }
+
+ $ses_var_name = $main_prefix.'_changes_'.$this->Application->GetTopmostWid($this->Prefix);
+ $changes = $this->Application->RecallVar($ses_var_name);
+ $changes = $changes ? unserialize($changes) : array();
+
+ $general = array(
+ 'Prefix' => $this->Prefix,
+ 'ItemId' => $this->GetID(),
+ 'OccuredOn' => adodb_mktime(),
+ 'MasterPrefix' => $main_prefix,
+ 'MasterId' => $this->Prefix == $main_prefix ? $this->GetID() : $this->Application->GetVar($main_prefix.'_id'), // is that correct (Kostja)??
+ 'Action' => $mode,
+ );
+ switch ($mode) {
+ case clUPDATE:
+ $changes[] = array_merge($general, Array(
+ 'Changes' => serialize(array_merge($this->GetTitleField(), $this->GetChangedFields())),
+ ));
+ break;
+ case clCREATE:
+ $changes[] = array_merge($general, Array(
+ 'Changes' => serialize($this->GetTitleField()),
+ ));
+ break;
+ case clDELETE:
+ $changes[] = array_merge($general, Array(
+ 'Changes' => serialize(array_merge($this->GetTitleField(), $this->GetRealFields())),
+ ));
+ }
+
+ $this->Application->StoreVar($ses_var_name, serialize($changes));
+ }
+
+ function GetTitleField()
+ {
+ $title_field = $this->Application->getUnitOption($this->Prefix, 'TitleField');
+ if ($title_field && $this->GetField($title_field)) {
+ return Array($title_field => $this->GetField($title_field));
+ }
+ }
+
+ function GetRealFields()
+ {
+ if (function_exists('array_diff_key')) {
+ $db_fields = array_diff_key($this->FieldValues, $this->VirtualFields, $this->CalculatedFields);
+ }
+ else {
+ $db_fields = array();
+ foreach ($this->FieldValues as $key => $value) {
+ if (array_key_exists($key, $this->VirtualFields) || array_key_exists($key, $this->CalculatedFields)) continue;
+ $db_fields[$key] = $value;
+ }
+ }
+ return $db_fields;
+ }
+
+ function GetChangedFields()
+ {
+ $changes = array();
+
+ $diff = array_diff_assoc($this->GetRealFields(), $this->OriginalFieldValues);
+ foreach ($diff as $field => $new_value) {
+ $changes[$field] = array('old' => $this->GetOriginalField($field, true), 'new' => $this->GetField($field));
+ }
+ return $changes;
}
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
function GetID()
{
return $this->ID;
}
/**
* Generates ID for new items before inserting into database
*
* @return int
* @access private
*/
function generateID()
{
return 0;
}
/**
* Returns true if item was loaded successfully by Load method
*
* @return bool
*/
function isLoaded()
{
return $this->Loaded;
}
/**
* Checks if field is required
*
* @param string $field
* @return bool
*/
function isRequired($field)
{
return getArrayValue( $this->Fields[$field], 'required' );
}
/**
* Sets new required flag to field
*
* @param string $field
* @param bool $is_required
*/
function setRequired($field, $is_required = true)
{
$this->Fields[$field]['required'] = $is_required;
}
function Clear($new_id = null)
{
$this->setID($new_id);
$this->Loaded = false;
$this->FieldValues = Array();
$this->OriginalFieldValues = Array ();
$this->SetDefaultValues();
$this->FieldErrors = Array();
return $this->Loaded;
}
function Query($force = false)
{
if( $this->Application->isDebugMode() )
{
$this->Application->Debugger->appendTrace();
}
trigger_error('<b>Query</b> method is called in class <b>'.get_class($this).'</b> for prefix <b>'.$this->getPrefixSpecial().'</b>', E_USER_ERROR);
}
function saveCustomFields()
{
if (!$this->customFields) {
return true;
}
$cdata_key = rtrim($this->Prefix.'-cdata.'.$this->Special, '.');
$cdata =& $this->Application->recallObject($cdata_key, null, Array('skip_autoload' => true, 'populate_ml_fields' => true));
$resource_id = $this->GetDBField('ResourceId');
$cdata->Load($resource_id, 'ResourceId');
$cdata->SetDBField('ResourceId', $resource_id);
$ml_formatter =& $this->Application->recallObject('kMultiLanguage');
/* @var $ml_formatter kMultiLanguage */
foreach ($this->customFields as $custom_id => $custom_name) {
$force_primary = isset($cdata->Fields['cust_'.$custom_id]['force_primary']) && $cdata->Fields['cust_'.$custom_id]['force_primary'];
$cdata->SetDBField($ml_formatter->LangFieldName('cust_'.$custom_id, $force_primary), $this->GetDBField('cust_'.$custom_name));
}
if ($cdata->isLoaded()) {
$ret = $cdata->Update();
}
else {
$ret = $cdata->Create();
if ($cdata->mode == 't') $cdata->setTempID();
}
return $ret;
}
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
* @return Array
*/
function GetCol($field)
{
return Array (0 => $this->GetDBField($field));
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/kernel/db/dbitem.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.44.2.9
\ No newline at end of property
+1.44.2.10
\ No newline at end of property
Index: branches/RC/core/kernel/kbase.php
===================================================================
--- branches/RC/core/kernel/kbase.php (revision 10293)
+++ branches/RC/core/kernel/kbase.php (revision 10294)
@@ -1,685 +1,697 @@
<?php
/**
* Base
*
* Desciption
* @package kernel4
*/
class kBase {
/**
* Holds reference to global KernelApplication instance
* @access public
* @var kApplication
*/
var $Application;
/**
* Prefix, that was used
* to create an object
*
* @var string
* @access public
*/
var $Prefix='';
/**
* Special, that was used
* to create an object
*
* @var string
* @access public
*/
var $Special='';
var $OriginalParams;
/**
* Set's application
*
* @return kBase
* @access public
*/
function kBase()
{
$this->Application =& kApplication::Instance();
}
/**
* Create new instance of object
*
* @return kBase
*/
function &makeClass()
{
$object = new kBase();
return $object;
}
/**
* Set's prefix and special
*
* @param string $prefix
* @param string $special
* @access public
*/
function Init($prefix,$special,$event_params=null)
{
$prefix=explode('_',$prefix,2);
$this->Prefix=$prefix[0];
$this->Special=$special;
$this->OriginalParams = $event_params;
}
/**
* Returns joined prefix
* and special if any
*
* @param bool $from_submit if true, then joins prefix & special by "_", uses "." otherwise
* @return string
* @access protected
*/
function getPrefixSpecial($from_submit = false)
{
$separator = !$from_submit ? '.' : '_';
$ret = $this->Prefix.$separator.$this->Special;
return rtrim($ret, $separator);
}
function &getProperty($property_name)
{
return $this->$property_name;
}
function setProperty($property_name, &$property_value)
{
$this->$property_name =& $property_value;
}
}
class kHelper extends kBase {
/**
* Connection to database
*
* @var kDBConnection
* @access public
*/
var $Conn;
function kHelper()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
function InitHelper()
{
}
}
class kDBBase extends kBase {
/**
* Connection to database
*
* @var kDBConnection
* @access public
*/
var $Conn;
/**
* Description
*
* @var string Name of primary key field for the item
* @access public
*/
var $IDField;
/**
* Holds SELECT, FROM, JOIN parts of SELECT query
*
* @var string
* @access public
*/
var $SelectClause;
/**
* Fields allowed to be set (from table + virtual)
*
* @var Array
* @access private
*/
var $Fields = Array();
/**
* Holds custom field names for item
*
* @var Array
*/
var $customFields = Array();
/**
* All virtual field names
*
* @var Array
* @access private
*/
var $VirtualFields = Array();
/**
* Fields that need to be queried using custom expression, e.g. IF(...) AS value
*
* @var Array
* @access private
*/
var $CalculatedFields = Array();
/**
* Calculated fields, that contain aggregated functions, e.g. COUNT, SUM, etc.
*
* @var Array
*/
var $AggregatedCalculatedFields = Array();
/**
* Description
*
* @var string Item' database table name, without prefix
* @access public
*/
var $TableName;
/**
* Allows to determine object's table status ('temp' - temp table, '' - live table)
*
* @var string
* @access public
*/
var $mode='';
function kDBBase()
{
parent::kBase();
$this->Conn =& $this->Application->GetADODBConnection();
}
/**
* Set current item' database table name
*
* @access public
* @param string $table_name
* @return void
*/
function setTableName($table_name)
{
$this->TableName = $table_name;
}
/**
* Set object' TableName to Live table from config
*
* @access public
*/
function SwitchToLive()
{
$this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
$this->mode = '';
}
/**
* Set object' TableName to Temp table from config
*
* @access public
*/
function SwitchToTemp()
{
$this->TableName = $this->Application->getUnitOption($this->Prefix, 'TableName');
$this->SetTableName( $this->Application->GetTempName($this->TableName, 'prefix:'.$this->Prefix) );
$this->mode = 't';
}
/**
* Checks if object uses temp table
*
* @return bool
*/
function IsTempTable()
{
return $this->Application->IsTempTable($this->TableName);
}
/**
* Sets SELECT part of list' query
*
* @access public
* @param string $sql SELECT and FROM [JOIN] part of the query up to WHERE
* @return void
*/
function SetSelectSQL($sql)
{
$this->SelectClause = $sql;
}
function GetSelectSQL($base_query = null)
{
if (!isset($base_query)) {
$base_query = $this->SelectClause;
}
$query = str_replace( Array('%1$s','%s'), $this->TableName, $base_query);
$query = $this->replaceModePrefix($query);
return $query;
}
/**
* Returns required mixing of aggregated & non-aggregated calculated fields
*
* @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only
* @return Array
*/
function getCalculatedFields($aggregated = 0)
{
switch ($aggregated) {
case 0:
$fields = array_merge($this->CalculatedFields, $this->AggregatedCalculatedFields);
break;
case 1:
$fields = $this->CalculatedFields;
break;
case 2:
$fields = $this->AggregatedCalculatedFields;
break;
default:
$fields = Array();
break;
}
return $fields;
}
/**
* Insert calculated fields sql into query in place of %2$s,
* return processed query.
*
* @param string $query
* @param int $aggregated 0 - having + aggregated, 1 - having only, 2 - aggregated only
* @return string
*/
function addCalculatedFields($query, $aggregated = 1)
{
$fields = $this->getCalculatedFields($aggregated);
if ($fields) {
$sql = Array();
foreach ($fields as $field_name => $field_expression) {
$sql[] = '('.$field_expression.') AS `'.$field_name.'`';
}
$sql = implode(',',$sql);
return $this->Application->ReplaceLanguageTags( str_replace('%2$s', ','.$sql, $query) );
}
else {
return str_replace('%2$s', '', $query);
}
}
/**
* Allows substables to be in same mode as main item (e.g. LEFT JOINED ones)
*
* @param string $query
* @return string
*/
function replaceModePrefix($query)
{
$live_table = substr($this->Application->GetLiveName($this->TableName), strlen(TABLE_PREFIX));
preg_match('/'.preg_quote(TABLE_PREFIX, '/').'(.*)'.preg_quote($live_table, '/').'/', $this->TableName, $rets);
return str_replace('%3$s', $rets[1], $query);
}
/**
* Adds calculated field declaration to object.
*
* @param string $name
* @param string $sql_clause
*/
function addCalculatedField($name, $sql_clause)
{
$this->CalculatedFields[$name] = $sql_clause;
}
/**
* Sets ID Field name used as primary key for loading items
*
* @access public
* @param string $field_name
* @return void
* @see kDBBase::IDField
*/
function setIDField($field_name)
{
$this->IDField = $field_name;
}
/**
* Performs initial object configuration
*
* @param bool $populate_ml_fields create all ml fields from db in config or not
*/
function Configure($populate_ml_fields = false)
{
$this->setTableName( $this->Application->getUnitOption($this->Prefix, 'TableName') );
$this->setIDField( $this->Application->getUnitOption($this->Prefix, 'IDField') );
$this->defineFields();
$this->ApplyFieldModifiers(); // should be called only after all fields definitions been set
$this->prepareConfigOptions(); // this should go last, but before setDefaultValues, order is significant!
$this->SetDefaultValues($populate_ml_fields);
}
/**
* Add field definitions from all possible sources (DB Fields, Virtual Fields, Calcualted Fields, e.t.c.)
*
*/
function defineFields()
{
$this->setConfigFields( $this->Application->getUnitOption($this->Prefix, 'Fields') );
$this->setCustomFields( $this->Application->getUnitOption($this->Prefix, 'CustomFields', Array()) );
$this->setVirtualFields( $this->Application->getUnitOption($this->Prefix, 'VirtualFields') );
$this->setCalculatedFields( $this->Application->getUnitOption($this->Prefix, 'CalculatedFields', Array()) );
$this->setAggragatedCalculatedFields( $this->Application->getUnitOption($this->Prefix, 'AggregatedCalculatedFields', Array()) );
}
function setCalculatedFields($fields)
{
$this->CalculatedFields = isset($fields[$this->Special]) ? $fields[$this->Special] : (isset($fields['']) ? $fields[''] : Array());
}
function setAggragatedCalculatedFields($fields)
{
$this->AggregatedCalculatedFields = isset($fields[$this->Special]) ? $fields[$this->Special] : (isset($fields['']) ? $fields[''] : Array());
}
/**
* Set's field names from table
* from config
*
* @param Array $fields
* @access public
*/
function setCustomFields($fields)
{
$this->customFields = $fields;
}
/**
* Set's field names from table
* from config
*
* @param Array $fields
* @access public
*/
function setConfigFields($fields)
{
$this->Fields = $fields;
}
/**
* Override field options with ones defined in submit via "field_modfiers" array (common for all prefixes)
*
* @access private
* @author Alex
*/
function ApplyFieldModifiers($field_modifiers = null)
{
$allowed_modifiers = Array('required');
if (!isset($field_modifiers)) {
$field_modifiers = $this->Application->GetVar('field_modifiers');
if (!$field_modifiers) {
// no field modifiers
return false;
}
$field_modifiers = getArrayValue($field_modifiers, $this->getPrefixSpecial());
}
if (!$field_modifiers) {
// no field modifiers for current prefix_special
return false;
}
foreach ($field_modifiers as $field => $field_options)
{
foreach ($field_options as $option_name => $option_value)
{
if ( !in_array(strtolower($option_name), $allowed_modifiers) ) continue;
$this->Fields[$field][$option_name] = $option_value;
}
}
}
/**
* Set fields (+options) for fields that physically doesn't exist in database
*
* @param Array $fields
* @access public
*/
function setVirtualFields($fields)
{
if($fields)
{
$this->VirtualFields = $fields;
$this->Fields = array_merge($this->VirtualFields, $this->Fields);
// $this->Fields = array_merge_recursive2($this->VirtualFields, $this->Fields);
}
}
function SetDefaultValues($populate_ml_fields = false)
{
foreach($this->Fields as $field => $options)
{
if( isset($options['default']) && $options['default'] === '#NOW#')
{
$this->Fields[$field]['default'] = adodb_mktime();
}
}
}
function SetFieldOptions($field, $options)
{
$this->Fields[$field] = $options;
}
function GetFieldOptions($field)
{
if (isset($this->Fields[$field])) {
$this->PrepareFieldOptions($field);
return $this->Fields[$field];
}
else {
return Array();
}
}
/**
* Returns formatted field value
*
* @param string $field
* @return string
* @access public
*/
function GetField($name, $format=null)
{
$options = $this->GetFieldOptions($name);
$val = $this->GetDBField($name);
$res = $val;
if (isset($options['formatter'])) {
$formatter =& $this->Application->recallObject($options['formatter']);
$res = $formatter->Format($val, $name, $this, $format );
}
return $res;
}
function HasField($name)
{
}
function GetFieldValues()
{
}
function UpdateFormattersSubFields($fields=null)
{
if (!is_array($fields)) {
$fields = array_keys($this->Fields);
}
foreach ($fields as $field) {
if ( isset($this->Fields[$field]['formatter']) ) {
$formatter =& $this->Application->recallObject($this->Fields[$field]['formatter']);
$formatter->UpdateSubFields($field, $this->GetDBField($field), $this->Fields[$field], $this);
}
}
}
function prepareConfigOptions()
{
foreach (array_keys($this->Fields) as $field_name)
{
// $this->PrepareFieldOptions($field_name);
$this->PrepareOptions($field_name);
}
}
+ /**
+ * Escapes fields only, not expressions
+ *
+ * @param string $field_expr
+ * @return string
+ */
+ function escapeField($field_expr)
+ {
+ return preg_match('/[.(]/', $field_expr) ? $field_expr : '`'.$field_expr.'`';
+ }
+
function PrepareFieldOptions($field_name)
{
$field_options =& $this->Fields[$field_name];
- if( isset($field_options['options_sql']) )
- {
+ if (array_key_exists('options_sql', $field_options) ) {
// replace with query result
$language_id = $this->Application->GetVar('m_lang');
- $select_clause = '`'.$field_options['option_title_field'].'`,`'.$field_options['option_key_field'].'`';
+
+ $select_clause = $this->escapeField($field_options['option_title_field']) . ',' . $this->escapeField($field_options['option_key_field']);
+
$sql = sprintf($field_options['options_sql'], $select_clause, $language_id);
$sql = str_replace('%2$s', $language_id, $sql); // replace langauge in field names
$options_hash = getArrayValue($field_options,'options');
if($options_hash === false) $options_hash = Array();
$dynamic_options = $this->Conn->GetCol($sql, $field_options['option_key_field']);
$field_options['options'] = array_merge_recursive2($options_hash, $dynamic_options);
unset($field_options['options_sql']);
}
}
function PrepareOptions($field_name)
{
if ( isset($this->Fields[$field_name]['formatter']) )
{
$formatter =& $this->Application->recallObject( $this->Fields[$field_name]['formatter'] );
$formatter->PrepareOptions($field_name, $this->Fields[$field_name], $this);
}
}
/**
* Returns unformatted field value
*
* @param string $field
* @return string
* @access public
*/
function GetDBField($field)
{
}
/**
* Returns ID of currently processed record
*
* @return int
* @access public
*/
function GetID()
{
return $this->GetDBField($this->IDField);
}
/**
* Allows kDBTagProcessor.SectionTitle to detect if it's editing or new item creation
*
* @return bool
*/
function IsNewItem()
{
return $this->GetID() ? false : true;
}
/**
* Returns parent table information
*
* @param bool $from_temp load parent item from temp table
* @param string $special special of main item
* @param bool $guess_special if object retrieved with specified special is not loaded, then try not to use special
* @return Array
*/
function getLinkedInfo($special = '', $guess_special = false)
{
$parent_prefix = $this->Application->getUnitOption($this->Prefix, 'ParentPrefix');
if($parent_prefix)
{
// if this is linked table, then set id from main table
$table_info = Array(
'TableName' => $this->Application->getUnitOption($this->Prefix,'TableName'),
'IdField' => $this->Application->getUnitOption($this->Prefix,'IDField'),
'ForeignKey' => $this->Application->getUnitOption($this->Prefix,'ForeignKey'),
'ParentTableKey' => $this->Application->getUnitOption($this->Prefix,'ParentTableKey'),
'ParentPrefix' => $parent_prefix
);
if (is_array($table_info['ForeignKey'])) {
$table_info['ForeignKey'] = getArrayValue($table_info, 'ForeignKey', $parent_prefix);
}
if (is_array($table_info['ParentTableKey'])) {
$table_info['ParentTableKey'] = getArrayValue($table_info, 'ParentTableKey', $parent_prefix);
}
$main_object =& $this->Application->recallObject($parent_prefix.'.'.$special, null, Array ('raise_warnings' => 0));
/* @var $main_object kDBItem */
if (!$main_object->isLoaded() && $guess_special) {
$main_object =& $this->Application->recallObject($parent_prefix);
}
return array_merge($table_info, Array('ParentId'=> $main_object->GetDBField( $table_info['ParentTableKey'] ) ) );
}
return false;
}
/**
* Returns true if item was queried/loaded
*
* @return bool
*/
function isLoaded()
{
return false;
}
/**
* Returns specified field value from all selected rows.
* Don't affect current record index
*
* @param string $field
* @return Array
*/
function GetCol($field)
{
return Array ();
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/kernel/kbase.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.32.2.2
\ No newline at end of property
+1.32.2.3
\ No newline at end of property
Index: branches/RC/core/units/users/users_event_handler.php
===================================================================
--- branches/RC/core/units/users/users_event_handler.php (revision 10293)
+++ branches/RC/core/units/users/users_event_handler.php (revision 10294)
@@ -1,1608 +1,1613 @@
<?php
class UsersEventHandler extends kDBEventHandler
{
/**
* Allows to override standart permission mapping
*
*/
function mapPermissions()
{
parent::mapPermissions();
$permissions = Array (
// admin
'OnSetPersistantVariable' => Array('self' => 'view'), // because setting to logged in user only
'OnUpdateRootPassword' => Array('self' => true),
'OnUpdatePassword' => Array('self' => true),
// front
'OnRefreshForm' => Array('self' => true),
'OnForgotPassword' => Array('self' => true),
'OnResetPassword' => Array('self' => true),
'OnResetPasswordConfirmed' => Array('self' => true),
'OnSubscribeQuery' => Array('self' => true),
'OnSubscribeUser' => Array('self' => true),
'OnRecommend' => Array('self' => true),
'OnItemBuild' => Array('self' => true),
'OnMassResetSettings' => Array('self' => 'edit'),
'OnMassCloneUsers' => Array('self' => 'add'),
);
$this->permMapping = array_merge($this->permMapping, $permissions);
}
/**
* Shows only admins when required
*
* @param kEvent $event
*/
function SetCustomQuery(&$event)
{
$object =& $event->getObject();
/* @var $object kDBList */
if ($event->Special == 'admins') {
$object->addFilter('primary_filter', 'ug.GroupId = 11');
}
if ($event->Special == 'regular') {
$object->addFilter('primary_filter', 'ug.GroupId <> 11');
}
if (!$this->Application->IsAdmin()) {
$object->addFilter('status_filter', '%1$s.Status = '.STATUS_ACTIVE);
}
if ($event->Special == 'group') {
$group_id = $this->Application->GetVar('g_id');
if ($group_id !== false) {
// show only users, that user doesn't belong to current group
$table_name = $this->Application->GetTempName(TABLE_PREFIX.'UserGroup', 'prefix:g');
$sql = 'SELECT PortalUserId
FROM '.$table_name.'
WHERE GroupId = '.$group_id;
$user_ids = $this->Conn->GetCol($sql);
array_push($user_ids); // Guest & Everyone groups are set dynamically
if ($user_ids) {
$object->addFilter('already_member_filter', '%1$s.PortalUserId NOT IN ('.implode(',', $user_ids).')');
}
}
}
}
/**
* Checks permissions of user
*
* @param kEvent $event
*/
function CheckPermission(&$event)
{
if ($event->Name == 'OnLogin' || $event->Name == 'OnLogout') {
// permission is checked in OnLogin event directly
return true;
}
if (!$this->Application->IsAdmin()) {
$user_id = $this->Application->RecallVar('user_id');
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($event->Name == 'OnCreate' && $user_id == -2) {
// "Guest" can create new users
return true;
}
if ($event->Name == 'OnUpdate' && $user_id > 0) {
$user_dummy =& $this->Application->recallObject($event->Prefix.'.-item', null, Array('skip_autoload' => true));
foreach ($items_info as $id => $field_values) {
if ($id != $user_id) {
// registered users can update their record only
return false;
}
$user_dummy->Load($id);
$status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField'));
if ($user_dummy->GetDBField($status_field) != STATUS_ACTIVE) {
// not active user is not allowed to update his record (he could not activate himself manually)
return false;
}
if (isset($field_values[$status_field]) && $user_dummy->GetDBField($status_field) != $field_values[$status_field]) {
// user can't change status by himself
return false;
}
}
return true;
}
if ($event->Name == 'OnUpdate' && $user_id <= 0) {
// guests are not allowed to update their record, because they don't have it :)
return false;
}
}
return parent::CheckPermission($event);
}
function OnSessionExpire()
{
$this->Application->resetCounters('UserSession');
if ($this->Application->IsAdmin()) {
$this->Application->Redirect('index', Array('expired' => 1), '', 'index.php');
}
if ($this->Application->GetVar('admin') == 1) {
$session_admin =& $this->Application->recallObject('Session.admin');
/* @var $session_admin Session */
if (!$session_admin->LoggedIn()) {
// front-end session created from admin session & both expired
$this->Application->DeleteVar('admin');
$this->Application->Redirect('index', Array('expired' => 1), '', 'admin/index.php');
}
}
$get = $this->Application->HttpQuery->getRedirectParams();
$t = $this->Application->GetVar('t');
$get['js_redirect'] = $this->Application->ConfigValue('UseJSRedirect');
$this->Application->Redirect($t ? $t : 'index', $get);
}
/**
* Checks user data and logs it in if allowed
*
* @param kEvent $event
*/
function OnLogin(&$event)
{
// persistent session data after login is not refreshed, because redirect will follow in any case
$prefix_special = $this->Application->IsAdmin() ? 'u.current' : 'u'; // "u" used on front not to change theme
$object =& $this->Application->recallObject($prefix_special, null, Array('skip_autoload' => true));
$password = $this->Application->GetVar('password');
$invalid_pseudo = $this->Application->IsAdmin() ? 'la_invalid_password' : 'lu_invalid_password';
if(!$password)
{
$object->SetError('ValidateLogin', 'invalid_password', $invalid_pseudo);
$event->status = erFAIL;
return false;
}
$email_as_login = $this->Application->ConfigValue('Email_As_Login');
list($login_field, $submit_field) = $email_as_login && !$this->Application->IsAdmin() ? Array('Email', 'email') : Array('Login', 'login');
$login_value = $this->Application->GetVar($submit_field);
// process "Save Username" checkbox
if ($this->Application->IsAdmin()) {
$save_username = $this->Application->GetVar('cb_save_username') ? $login_value : '';
$this->Application->Session->SetCookie('save_username', $save_username, adodb_mktime() + 31104000); // 1 year expiration
$this->Application->SetVar('save_username', $save_username); // cookie will be set on next refresh, but refresh won't occur if login error present, so duplicate cookie in HTTPQuery
}
$super_admin = ($login_value == 'super-root') && $this->verifySuperAdmin();
if ($this->Application->IsAdmin() && ($login_value == 'root') || ($super_admin && $login_value == 'super-root')) {
// logging in "root" (admin only)
$login_value = 'root';
$root_password = $this->Application->ConfigValue('RootPass');
$password_formatter =& $this->Application->recallObject('kPasswordFormatter');
$test = $password_formatter->EncryptPassword($password, 'b38');
if ($root_password != $test) {
$object->SetError('ValidateLogin', 'invalid_password', $invalid_pseudo);
$event->status = erFAIL;
return false;
}
elseif ($this->checkLoginPermission($login_value)) {
$user_id = -1;
$object->Load($user_id);
$object->SetDBField('Login', $login_value);
$session =& $this->Application->recallObject('Session');
$session->SetField('PortalUserId', $user_id);
// $session->SetField('GroupList', implode(',', $groups) );
$this->Application->SetVar('u.current_id', $user_id);
$this->Application->StoreVar('user_id', $user_id);
if ($super_admin) {
$this->Application->StoreVar('super_admin', 1);
}
+ $this->Application->HandleEvent($dummy, 'session-log:OnStartSession');
$this->processLoginRedirect($event, $password);
return true;
}
else {
$object->SetError('ValidateLogin', 'invalid_license', 'la_invalid_license');
$event->status = erFAIL;
return false;
}
}
/*$sql = 'SELECT PortalUserId FROM '.$object->TableName.' WHERE (%s = %s) AND (Password = MD5(%s))';
$user_id = $this->Conn->GetOne( sprintf($sql, $login_field, $this->Conn->qstr($login_value), $this->Conn->qstr($password) ) );*/
$sql = 'SELECT PortalUserId FROM '.$object->TableName.' WHERE (Email = %1$s OR Login = %1$s) AND (Password = MD5(%2$s))';
$user_id = $this->Conn->GetOne( sprintf($sql, $this->Conn->qstr($login_value), $this->Conn->qstr($password) ) );
if ($user_id) {
$object->Load($user_id);
if ($object->GetDBField('Status') == STATUS_ACTIVE) {
$groups = $object->getMembershipGroups(true);
if(!$groups) $groups = Array();
array_push($groups, $this->Application->ConfigValue('User_LoggedInGroup') );
$this->Application->StoreVar( 'UserGroups', implode(',', $groups) );
if ($this->checkLoginPermission($login_value)) {
$session =& $this->Application->recallObject('Session');
$session->SetField('PortalUserId', $user_id);
$session->SetField('GroupList', implode(',', $groups) );
$this->Application->SetVar('u.current_id', $user_id);
$this->Application->StoreVar('user_id', $user_id);
$this->Application->LoadPersistentVars();
$this_login = (int)$this->Application->RecallPersistentVar('ThisLogin');
$this->Application->StorePersistentVar('LastLogin', $this_login);
$this->Application->StorePersistentVar('ThisLogin', adodb_mktime());
+
+ $this->Application->HandleEvent($dummy, 'session-log:OnStartSession');
}
else {
$object->Load(-2);
$object->SetError('ValidateLogin', 'no_permission', 'lu_no_permissions');
$event->status = erFAIL;
}
$this->processLoginRedirect($event, $password);
}
else {
$event->redirect = $this->Application->GetVar('pending_disabled_template');
}
}
else
{
$object->SetID(-2);
$object->SetError('ValidateLogin', 'invalid_password', $invalid_pseudo);
$event->status = erFAIL;
}
$event->SetRedirectParam('pass', 'all');
// $event->SetRedirectParam('pass_category', 1); // to test
}
/**
* Checks that user is allowed to use super admin mode
*
* @return bool
*/
function verifySuperAdmin()
{
$sa_mode = ipMatch(defined('SA_IP') ? SA_IP : '');
return $sa_mode || $this->Application->isDebugMode();
}
/**
* Enter description here...
*
* @param string $user_name
* @return bool
*/
function checkLoginPermission($user_name)
{
$ret = true;
if ($this->Application->IsAdmin()) {
$modules_helper =& $this->Application->recallObject('ModulesHelper');
if ($user_name != 'root') {
// root is virtual user, so allow him to login to admin in any case
$ret = $this->Application->CheckPermission('ADMIN', 1);
}
$ret = $ret && $modules_helper->checkLogin();
}
else {
$ret = $this->Application->CheckPermission('LOGIN', 1);
}
return $ret;
}
/**
* Process all required data and redirect logged-in user
*
* @param kEvent $event
*/
function processLoginRedirect(&$event, $password)
{
$prefix_special = $this->Application->IsAdmin() ? 'u.current' : 'u'; // "u" used on front not to change theme
$object =& $this->Application->recallObject($prefix_special, null, Array('skip_autoload' => true));
$next_template = $this->Application->GetVar('next_template');
if ($next_template == '_ses_redirect') {
$location = $this->Application->BaseURL().$this->Application->RecallVar($next_template);
if( $this->Application->isDebugMode() && constOn('DBG_REDIRECT') )
{
$this->Application->Debugger->appendTrace();
echo "<b>Debug output above!!!</b> Proceed to redirect: <a href=\"$location\">$location</a><br>";
}
else {
header('Location: '.$location);
}
$session =& $this->Application->recallObject('Session');
$session->SaveData();
exit;
}
if ($next_template) {
$event->redirect = $next_template;
}
if ($this->Application->ConfigValue('UseJSRedirect')) {
$event->SetRedirectParam('js_redirect', 1);
}
$sync_manager =& $this->Application->recallObjectP('UsersSyncronizeManager', null, Array(), 'InPortalSyncronize');
$sync_manager->performAction('LoginUser', $object->GetDBField('Login'), $password);
$this->Application->resetCounters('UserSession');
}
/**
* Called when user logs in using old in-portal
*
* @param kEvent $event
*/
function OnInpLogin(&$event)
{
$sync_manager =& $this->Application->recallObjectP('UsersSyncronizeManager', null, Array(), 'InPortalSyncronize');
$sync_manager->performAction('LoginUser', $event->getEventParam('user'), $event->getEventParam('pass') );
if ($event->redirect && is_string($event->redirect)) {
// some real template specified instead of true
$this->Application->Redirect($event->redirect, $event->redirect_params);
}
}
/**
* Called when user logs in using old in-portal
*
* @param kEvent $event
*/
function OnInpLogout(&$event)
{
$sync_manager =& $this->Application->recallObjectP('UsersSyncronizeManager', null, Array(), 'InPortalSyncronize');
$sync_manager->performAction('LogoutUser');
}
function OnLogout(&$event)
{
$sync_manager =& $this->Application->recallObjectP('UsersSyncronizeManager', null, Array(), 'InPortalSyncronize');
$sync_manager->performAction('LogoutUser');
+ $this->Application->HandleEvent($dummy, 'session-log:OnEndSession');
+
$session =& $this->Application->recallObject('Session');
$session->SetField('PortalUserId', -2);
$this->Application->SetVar('u.current_id', -2);
$this->Application->StoreVar('user_id', -2);
$object =& $this->Application->recallObject('u.current', null, Array('skip_autoload' => true));
$object->Load(-2);
$this->Application->DestroySession();
$group_list = $this->Application->ConfigValue('User_GuestGroup').','.$this->Application->ConfigValue('User_LoggedInGroup');
$session->SetField('GroupList', $group_list);
$this->Application->StoreVar('UserGroups', $group_list);
if ($this->Application->ConfigValue('UseJSRedirect')) {
$event->SetRedirectParam('js_redirect', 1);
}
$this->Application->resetCounters('UserSession');
$event->SetRedirectParam('pass', 'all');
}
/**
* Prefill states dropdown with correct values
*
* @param kEvent $event
* @access public
*/
function OnPrepareStates(&$event)
{
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
$cs_helper->PopulateStates($event, 'State', 'Country');
$object =& $event->getObject();
if( $object->isRequired('Country') && $cs_helper->CountryHasStates( $object->GetDBField('Country') ) ) $object->setRequired('State', true);
$object->setLogin();
}
/**
* Redirects user after succesfull registration to confirmation template (on Front only)
*
* @param kEvent $event
*/
function OnAfterItemCreate(&$event)
{
$this->saveUserImages($event);
if ($this->Application->GetVar('skip_set_primary')) return;
$is_subscriber = $this->Application->GetVar('IsSubscriber');
if(!$is_subscriber)
{
$object =& $event->getObject();
$ug_table = TABLE_PREFIX.'UserGroup';
if ($object->mode == 't') {
$ug_table = $this->Application->GetTempName($ug_table, 'prefix:'.$event->Prefix);
}
$sql = 'UPDATE '.$ug_table.'
SET PrimaryGroup = 0
WHERE PortalUserId = '.$object->GetDBField('PortalUserId');
$this->Conn->Query($sql);
// set primary group to user
if ($this->Application->IsAdmin() && $this->Application->GetVar('user_group')) {
// while in admin you can set any group for new users
$group_id = $this->Application->GetVar('user_group');
}
else {
$group_id = $this->Application->ConfigValue('User_NewGroup');
}
$sql = 'REPLACE INTO '.$ug_table.'(PortalUserId,GroupId,PrimaryGroup) VALUES (%s,%s,1)';
$this->Conn->Query( sprintf($sql, $object->GetID(), $group_id) );
}
}
/**
* Login user if possible, if not then redirect to corresponding template
*
* @param kEvent $event
*/
function autoLoginUser(&$event)
{
$object =& $event->getObject();
$this->Application->SetVar('u.current_id', $object->GetID() );
if($object->GetDBField('Status') == STATUS_ACTIVE && !$this->Application->ConfigValue('User_Password_Auto'))
{
$email_as_login = $this->Application->ConfigValue('Email_As_Login');
list($login_field, $submit_field) = $email_as_login ? Array('Email', 'email') : Array('Login', 'login');
$this->Application->SetVar($submit_field, $object->GetDBField($login_field) );
$this->Application->SetVar('password', $object->GetDBField('Password_plain') );
$event->CallSubEvent('OnLogin');
}
}
/**
* When creating user & user with such email exists then force to use OnUpdate insted of ?
*
* @param kEvent $event
*/
function OnSubstituteSubscriber(&$event)
{
$ret = false;
$object =& $event->getObject( Array('skip_autoload' => true) );
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
list($id, $field_values) = each($items_info);
$user_email = isset($field_values['Email']) ? $field_values['Email'] : false;
if($user_email)
{
// check if is subscriber
$verify_user =& $this->Application->recallObject('u.verify', null, Array('skip_autoload' => true) );
$verify_user->Load($user_email, 'Email');
if( $verify_user->isLoaded() && $verify_user->isSubscriberOnly() )
{
$items_info = Array( $verify_user->GetDBField('PortalUserId') => $field_values );
$this->Application->SetVar($event->getPrefixSpecial(true), $items_info);
$ret = true;
}
}
}
if( isset($event->MasterEvent) )
{
$event->MasterEvent->setEventParam('is_subscriber_only', $ret);
}
else
{
$event->setEventParam('is_subscriber_only', $ret);
}
}
/**
* Enter description here...
*
* @param kEvent $event
* @return bool
*/
function isSubscriberOnly(&$event)
{
$event->CallSubEvent('OnSubstituteSubscriber');
$is_subscriber = false;
if( $event->getEventParam('is_subscriber_only') )
{
$is_subscriber = true;
$object =& $event->getObject( Array('skip_autoload' => true) );
$this->OnUpdate($event);
if($event->status == erSUCCESS)
{
$this->OnAfterItemCreate($event);
$object->SendEmailEvents();
if( !$this->Application->IsAdmin() && ($event->status == erSUCCESS) && $event->redirect) $this->autoLoginUser($event);
}
}
return $is_subscriber;
}
/**
* Creates new user
*
* @param kEvent $event
*/
function OnCreate(&$event)
{
if( !$this->Application->IsAdmin() ) $this->setUserStatus($event);
if( !$this->isSubscriberOnly($event) )
{
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
$cs_helper->CheckStateField($event, 'State', 'Country');
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object kDBItem */
if ($this->Application->ConfigValue('User_Password_Auto')) {
$pass = makepassword4(rand(5,8));
$object->SetField('Password', $pass);
$object->SetField('VerifyPassword', $pass);
$this->Application->SetVar('user_password',$pass);
}
parent::OnCreate($event);
$this->Application->SetVar('u.current_id', $object->getID() ); // for affil:OnRegisterAffiliate after hook
$this->setNextTemplate($event);
if( !$this->Application->IsAdmin() && ($event->status == erSUCCESS) && $event->redirect)
{
$object->SendEmailEvents();
$this->autoLoginUser($event);
}
}
}
/**
* Set's new user status based on config options
*
* @param kEvent $event
*/
function setUserStatus(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
$new_users_allowed = $this->Application->ConfigValue('User_Allow_New');
// 1 - Instant, 2 - Not Allowed, 3 - Pending
switch ($new_users_allowed)
{
case 1: // Instant
$object->SetDBField('Status', 1);
$next_template = $this->Application->GetVar('registration_confirm_template');
if($next_template) $event->redirect = $next_template;
break;
case 3: // Pending
$next_template = $this->Application->GetVar('registration_confirm_pending_template');
if($next_template) $event->redirect = $next_template;
$object->SetDBField('Status', 2);
break;
case 2: // Not Allowed
$object->SetDBField('Status', 0);
break;
}
/*if ($object->GetDBField('PaidMember') == 1) {
$this->Application->HandleEvent($add_to_cart, 'ord:OnAddToCart');
$event->redirect = 'in-commerce/checkout/shop_cart';
} */
}
/**
* Set's new unique resource id to user
*
* @param kEvent $event
*/
function OnBeforeItemCreate(&$event)
{
$email_as_login = $this->Application->ConfigValue('Email_As_Login');
$object =& $event->getObject();
if ($email_as_login) {
$object->Fields['Email']['error_msgs']['unique'] = $this->Application->Phrase('lu_user_and_email_already_exist');
}
}
/**
* Set's new unique resource id to user
*
* @param kEvent $event
*/
function OnAfterItemValidate(&$event)
{
$object =& $event->getObject();
$resource_id = $object->GetDBField('ResourceId');
if (!$resource_id)
{
$object->SetDBField('ResourceId', $this->Application->NextResourceId() );
}
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnRecommend(&$event)
{
$friend_email = $this->Application->GetVar('friend_email');
$friend_name = $this->Application->GetVar('friend_email');
// used for error reporting only -> rewrite code + theme (by Alex)
$object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too
/* @var $object UsersItem */
if (preg_match("/^[_a-zA-Z0-9-\.]+@[a-zA-Z0-9-\.]+\.[a-z]{2,4}$/", $friend_email))
{
$send_params = array();
$send_params['to_email']=$friend_email;
$send_params['to_name']=$friend_name;
$user_id = $this->Application->RecallVar('user_id');
$email_event =& $this->Application->EmailEventUser('SITE.SUGGEST', $user_id, $send_params);
if ($email_event->status == erSUCCESS){
$event->redirect_params = array('opener' => 's', 'pass' => 'all');
$event->redirect = $this->Application->GetVar('template_success');
}
else {
// $event->redirect_params = array('opener' => 's', 'pass' => 'all');
// $event->redirect = $this->Application->GetVar('template_fail');
$object->SetError('Email', 'send_error', 'lu_email_send_error');
$event->status = erFAIL;
}
}
else {
$object->SetError('Email', 'invalid_email', 'lu_InvalidEmail');
$event->status = erFAIL;
}
}
/**
* Saves address changes and mades no redirect
*
* @param kEvent $event
*/
function OnUpdateAddress(&$event)
{
$object =& $event->getObject( Array('skip_autoload' => true) );
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if($items_info)
{
list($id,$field_values) = each($items_info);
if($id > 0) $object->Load($id);
$object->SetFieldsFromHash($field_values);
$object->setID($id);
$object->Validate();
}
$event->redirect = false;
}
/**
* Validate subscriber's email & store it to session -> redirect to confirmation template
*
* @param kEvent $event
*/
function OnSubscribeQuery(&$event)
{
$user_email = $this->Application->GetVar('subscriber_email');
if (preg_match("/^[_a-zA-Z0-9-\.]+@[a-zA-Z0-9-\.]+\.[a-z]{2,4}$/", $user_email)) {
$object =& $this->Application->recallObject($this->Prefix.'.subscriber', null, Array('skip_autoload' => true));
/* @var $object UsersItem */
$this->Application->StoreVar('SubscriberEmail', $user_email);
$object->Load($user_email, 'Email');
if ($object->isLoaded()) {
$group_info = $this->GetGroupInfo($object->GetID());
$event->redirect = $this->Application->GetVar($group_info ? 'unsubscribe_template' : 'subscribe_template');
}
else {
$event->redirect = $this->Application->GetVar('subscribe_template');
$this->Application->StoreVar('SubscriberEmail', $user_email);
}
}
else {
// used for error reporting only -> rewrite code + theme (by Alex)
$object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too
/* @var $object UsersItem */
$object->SetError('SubscribeEmail', 'invalid_email', 'lu_InvalidEmail');
$event->status = erFAIL;
}
}
/**
* Subscribe/Unsubscribe user based on email stored in previous step
*
* @param kEvent $event
*/
function OnSubscribeUser(&$event)
{
$object = &$this->Application->recallObject($this->Prefix.'.subscriber', null, Array('skip_autoload' => true));
/* @var $object UsersItem */
$user_email = $this->Application->RecallVar('SubscriberEmail');
if (preg_match("/^[_a-zA-Z0-9-\.]+@[a-zA-Z0-9-\.]+\.[a-z]{2,4}$/", $user_email)) {
$this->RemoveRequiredFields($object);
$object->Load($user_email, 'Email');
if ($object->isLoaded()) {
$group_info = $this->GetGroupInfo($object->GetID());
if ($group_info){
if ($event->getEventParam('no_unsubscribe')) return;
if ($group_info['PrimaryGroup']){
// delete user
$object->Delete();
}
else {
$this->RemoveSubscriberGroup($object->GetID());
}
$event->redirect = $this->Application->GetVar('unsubscribe_ok_template');
}
else {
$this->AddSubscriberGroup($object->GetID(), 0);
$event->redirect = $this->Application->GetVar('subscribe_ok_template');
}
}
else {
$object->SetField('Email', $user_email);
$object->SetField('Login', $user_email);
$object->SetDBField('dob', 1);
$object->SetDBField('dob_date', 1);
$object->SetDBField('dob_time', 1);
$ip = getenv('HTTP_X_FORWARDED_FOR')?getenv('HTTP_X_FORWARDED_FOR'):getenv('REMOTE_ADDR');
$object->SetDBField('ip', $ip);
$this->Application->SetVar('IsSubscriber', 1);
if ($object->Create()) {
$this->AddSubscriberGroup($object->GetID(), 1);
$event->redirect = $this->Application->GetVar('subscribe_ok_template');
}
$this->Application->SetVar('IsSubscriber', 0);
}
}
}
function AddSubscriberGroup($user_id, $is_primary){
$group_id = $this->Application->ConfigValue('User_SubscriberGroup');
$sql = 'INSERT INTO '.TABLE_PREFIX.'UserGroup(PortalUserId,GroupId,PrimaryGroup) VALUES (%s,%s,'.$is_primary.')';
$this->Conn->Query( sprintf($sql, $user_id, $group_id) );
$this->Application->EmailEventAdmin('USER.SUBSCRIBE', $user_id);
$this->Application->EmailEventUser('USER.SUBSCRIBE', $user_id);
}
function RemoveSubscriberGroup($user_id){
$group_id = $this->Application->ConfigValue('User_SubscriberGroup');
$sql = 'DELETE FROM '.TABLE_PREFIX.'UserGroup WHERE PortalUserId='.$user_id.' AND GroupId='.$this->Application->ConfigValue('User_SubscriberGroup');
$this->Conn->Query($sql);
$this->Application->EmailEventAdmin('USER.UNSUBSCRIBE', $user_id);
$this->Application->EmailEventUser('USER.UNSUBSCRIBE', $user_id);
}
/**
* Allows to detect user subscription status (subscribed or not)
*
* @param int $user_id
* @return bool
*/
function GetGroupInfo($user_id)
{
$sql = 'SELECT *
FROM '.TABLE_PREFIX.'UserGroup
WHERE (PortalUserId = '.$user_id.') AND (GroupId = '.$this->Application->ConfigValue('User_SubscriberGroup').')';
return $this->Conn->GetRow($sql);
}
function OnForgotPassword(&$event)
{
$user_object =& $this->Application->recallObject('u.forgot', null, Array('skip_autoload' => true));
/* @var $user_object UsersItem */
// used for error reporting only -> rewrite code + theme (by Alex)
$user_current_object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true)); // TODO: change theme too
/* @var $user_current_object UsersItem */
$username = $this->Application->GetVar('username');
$email = $this->Application->GetVar('email');
$found = false;
$allow_reset = true;
if (strlen($username)) {
$user_object->Load($username, 'Login');
if ($user_object->isLoaded()) {
$found = ($user_object->GetDBField("Login")==$username && $user_object->GetDBField("Status")==1) && strlen($user_object->GetDBField("Password"));
}
}
else if(strlen($email)) {
$user_object->Load($email, 'Email');
if ($user_object->isLoaded()) {
$found = ($user_object->GetDBField("Email")==$email && $user_object->GetDBField("Status")==1) && strlen($user_object->GetDBField("Password"));
}
}
if ($user_object->isLoaded()) {
$PwResetConfirm = $user_object->GetDBField('PwResetConfirm');
$PwRequestTime = $user_object->GetDBField('PwRequestTime');
$PassResetTime = $user_object->GetDBField('PassResetTime');
//$MinPwResetDelay = $user_object->GetDBField('MinPwResetDelay');
$MinPwResetDelay = $this->Application->ConfigValue('Users_AllowReset');
$allow_reset = (strlen($PwResetConfirm) ?
adodb_mktime() > $PwRequestTime + $MinPwResetDelay :
adodb_mktime() > $PassResetTime + $MinPwResetDelay);
}
if ($found && $allow_reset) {
$this->Application->StoreVar('tmp_user_id', $user_object->GetDBField("PortalUserId"));
$this->Application->StoreVar('tmp_email', $user_object->GetDBField("Email"));
$confirm_template = $this->Application->GetVar('reset_confirm_template');
if (!$confirm_template) {
$this->Application->SetVar('reset_confirm_template', 'platform/login/forgotpass_reset');
}
$this->Application->EmailEventUser('USER.PSWDC', $user_object->GetDBField('PortalUserId'));
$event->redirect = $this->Application->GetVar('template_success');
}
else {
if (!strlen($username) && !strlen($email)) {
$user_current_object->SetError('Login', 'forgotpw_nodata', 'lu_ferror_forgotpw_nodata');
$user_current_object->SetError('Email', 'forgotpw_nodata', 'lu_ferror_forgotpw_nodata');
}
else {
if ($allow_reset) {
if (strlen($username)) {
$user_current_object->SetError('Login', 'unknown_username', 'lu_ferror_unknown_username');
}
if (strlen($email)) {
$user_current_object->SetError('Email', 'unknown_email', 'lu_ferror_unknown_email');
}
}
else {
if (strlen($username)) {
$user_current_object->SetError('Login', 'reset_denied', 'lu_ferror_reset_denied');
}
if (strlen($email)) {
$user_current_object->SetError('Email', 'reset_denied', 'lu_ferror_reset_denied');
}
}
}
if($user_current_object->FieldErrors){
$event->redirect = false;
}
}
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnResetPassword(&$event)
{
$user_object =& $this->Application->recallObject('u.forgot');
if($user_object->Load($this->Application->RecallVar('tmp_user_id'))){
$this->Application->EmailEventUser('USER.PSWDC', $user_object->GetDBField("PortalUserId"));
$event->redirect = $this->Application->GetVar('template_success');
$m_cat_id = $this->Application->findModule('Name', 'In-Commerce', 'RootCat');
$this->Application->SetVar('m_cat_id', $m_cat_id);
$event->SetRedirectParam('pass', 'm');
}
}
function OnResetPasswordConfirmed(&$event)
{
// used for error reporting only -> rewrite code + theme (by Alex)
$user_current_object =& $this->Application->recallObject('u', null, Array('skip_autoload' => true));// TODO: change theme too
/* @var $user_current_object UsersItem */
$passed_key = trim($this->Application->GetVar('user_key'));
if (!$passed_key) {
$event->redirect_params = Array('opener' => 's', 'pass' => 'all');
$event->redirect = false;
$user_current_object->SetError('PwResetConfirm', 'code_is_not_valid', 'lu_code_is_not_valid');
}
$user_object =& $this->Application->recallObject('u.forgot', null, Array('skip_autoload' => true));
/* @var $user_object UsersItem */
$user_object->Load($passed_key, 'PwResetConfirm');
if ($user_object->isLoaded()) {
$exp_time = $user_object->GetDBField('PwRequestTime') + 3600;
$user_object->SetDBField('PwResetConfirm', '');
$user_object->SetDBField('PwRequestTime', 0);
if ($exp_time > adodb_mktime()) {
$newpw = makepassword4();
$this->Application->StoreVar('password', $newpw);
$user_object->SetDBField('Password', $newpw);
$user_object->SetDBField('PassResetTime', adodb_mktime());
$user_object->SetDBField('PwResetConfirm', '');
$user_object->SetDBField('PwRequestTime', 0);
$user_object->Update();
$this->Application->SetVar('ForgottenPassword', $newpw);
$email_event_user =& $this->Application->EmailEventUser('USER.PSWD', $user_object->GetDBField('PortalUserId'));
$email_event_admin =& $this->Application->EmailEventAdmin('USER.PSWD');
$this->Application->DeleteVar('ForgottenPassword');
if ($email_event_user->status == erSUCCESS) {
$event->redirect_params = array('opener' => 's', 'pass' => 'all');
$event->redirect = $this->Application->GetVar('template_success');
}
$user_object->SetDBField('Password', md5($newpw));
$user_object->Update();
} else {
$user_current_object->SetError('PwResetConfirm', 'code_expired', 'lu_code_expired');
$event->redirect = false;
}
} else {
$user_current_object->SetError('PwResetConfirm', 'code_is_not_valid', 'lu_code_is_not_valid');
$event->redirect = false;
}
}
function OnUpdate(&$event)
{
$cs_helper =& $this->Application->recallObject('CountryStatesHelper');
$cs_helper->CheckStateField($event, 'State', 'Country');
parent::OnUpdate($event);
$this->setNextTemplate($event);
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function setNextTemplate(&$event)
{
if( !$this->Application->IsAdmin() )
{
$event->redirect_params['opener'] = 's';
$object =& $event->getObject();
if($object->GetDBField('Status') == STATUS_ACTIVE)
{
$next_template = $this->Application->GetVar('next_template');
if($next_template) $event->redirect = $next_template;
}
}
}
/**
* Delete users from groups if their membership is expired
*
* @param kEvent $event
*/
function OnCheckExpiredMembership(&$event)
{
// send pre-expiration reminders: begin
$pre_expiration = adodb_mktime() + $this->Application->ConfigValue('User_MembershipExpirationReminder') * 3600 * 24;
$sql = 'SELECT PortalUserId, GroupId
FROM '.TABLE_PREFIX.'UserGroup
WHERE (MembershipExpires IS NOT NULL) AND (ExpirationReminderSent = 0) AND (MembershipExpires < '.$pre_expiration.')';
$skip_clause = $event->getEventParam('skip_clause');
if ($skip_clause) {
$sql .= ' AND !('.implode(') AND !(', $skip_clause).')';
}
$records = $this->Conn->Query($sql);
if ($records) {
$conditions = Array();
foreach ($records as $record) {
$email_event_user =& $this->Application->EmailEventUser('USER.MEMBERSHIP.EXPIRATION.NOTICE', $record['PortalUserId']);
$email_event_admin =& $this->Application->EmailEventAdmin('USER.MEMBERSHIP.EXPIRATION.NOTICE');
$conditions[] = '(PortalUserId = '.$record['PortalUserId'].' AND GroupId = '.$record['GroupId'].')';
}
$sql = 'UPDATE '.TABLE_PREFIX.'UserGroup
SET ExpirationReminderSent = 1
WHERE '.implode(' OR ', $conditions);
$this->Conn->Query($sql);
}
// send pre-expiration reminders: end
// remove users from groups with expired membership: begin
$sql = 'SELECT PortalUserId
FROM '.TABLE_PREFIX.'UserGroup
WHERE (MembershipExpires IS NOT NULL) AND (MembershipExpires < '.adodb_mktime().')';
$user_ids = $this->Conn->GetCol($sql);
if ($user_ids) {
foreach ($user_ids as $id) {
$email_event_user =& $this->Application->EmailEventUser('USER.MEMBERSHIP.EXPIRED', $id);
$email_event_admin =& $this->Application->EmailEventAdmin('USER.MEMBERSHIP.EXPIRED');
}
}
$sql = 'DELETE FROM '.TABLE_PREFIX.'UserGroup
WHERE (MembershipExpires IS NOT NULL) AND (MembershipExpires < '.adodb_mktime().')';
$this->Conn->Query($sql);
// remove users from groups with expired membership: end
}
/**
* Enter description here...
*
* @param kEvent $event
*/
function OnRefreshForm(&$event)
{
$event->redirect = false;
$item_info = $this->Application->GetVar($event->Prefix_Special);
list($id, $fields) = each($item_info);
$object =& $event->getObject( Array('skip_autoload' => true) );
$object->setID($id);
$object->IgnoreValidation = true;
$object->SetFieldsFromHash($fields);
}
/**
* Sets persistant variable
*
* @param kEvent $event
*/
function OnSetPersistantVariable(&$event)
{
$field = $this->Application->GetVar('field');
$value = $this->Application->GetVar('value');
$this->Application->StorePersistentVar($field, $value);
$force_tab = $this->Application->GetVar('SetTab');
if ($force_tab) {
$this->Application->StoreVar('force_tab', $force_tab);
}
}
/**
* Overwritten to return user from order by special .ord
*
* @param kEvent $event
*/
function getPassedID(&$event)
{
switch ($event->Special) {
case 'ord':
$order =& $this->Application->recallObject('ord');
/* @var $order OrdersItem */
$id = $order->GetDBField('PortalUserId');
break;
case 'profile':
$id = $this->Application->GetVar('user_id');
if (!$id) {
// if none user_id given use current user id
$id = $this->Application->RecallVar('user_id');
}
break;
default:
$id = parent::getPassedID($event);
break;
}
return $id;
}
/**
* Allows to change root password
*
* @param kEvent $event
*/
function OnUpdateRootPassword(&$event)
{
return $this->OnUpdatePassword($event);
}
/**
* Allows to change root password
*
* @param kEvent $event
*/
function OnUpdatePassword(&$event)
{
$items_info = $this->Application->GetVar( $event->getPrefixSpecial(true) );
if (!$items_info) return ;
list ($id, $field_values) = each($items_info);
$user_id = $this->Application->RecallVar('user_id');
if ($id == $user_id && ($user_id > 0 || $user_id == -1)) {
$user_dummy =& $this->Application->recallObject($event->Prefix.'.-item', null, Array('skip_autoload' => true));
/* @var $user_dummy kDBItem */
$user_dummy->Load($id);
$status_field = array_shift($this->Application->getUnitOption($event->Prefix, 'StatusField'));
if ($user_dummy->GetDBField($status_field) != STATUS_ACTIVE) {
// not active user is not allowed to update his record (he could not activate himself manually)
return false;
}
}
if ($user_id == -1) {
$object =& $event->getObject( Array('skip_autoload' => true) );
/* @var $object UsersItem */
// put salt to user's config
$field_options = $object->GetFieldOptions('RootPassword');
$field_options['salt'] = 'b38';
$object->SetFieldOptions('RootPassword', $field_options);
$verify_options = $object->GetFieldOptions('VerifyRootPassword');
$verify_options['salt'] = 'b38';
$object->SetFieldOptions('VerifyRootPassword', $verify_options);
// this is internal hack to allow root/root passwords for dev
if ($this->Application->isDebugMode() && $field_values['RootPassword'] == 'root') {
$this->Application->ConfigHash['Min_Password'] = 4;
}
$this->RemoveRequiredFields($object);
$object->SetDBField('RootPassword', $this->Application->ConfigValue('RootPass'));
$object->SetFieldsFromHash($field_values);
$object->setID(-1);
$status = $object->Validate();
if ($status) {
// validation on, password match too
$fields_hash = Array (
'VariableValue' => $object->GetDBField('RootPassword')
);
$conf_table = $this->Application->getUnitOption('conf', 'TableName');
$this->Conn->doUpdate($fields_hash, $conf_table, 'VariableName = "RootPass"');
$event->SetRedirectParam('opener', 'u');
}
else {
$event->status = erFAIL;
$event->redirect = false;
return;
}
}
else {
$object =& $event->getObject();
$object->SetFieldsFromHash($field_values);
if (!$object->Update()) {
$event->status = erFAIL;
$event->redirect = false;
}
}
$event->SetRedirectParam('opener', 'u');
$event->redirect == true;
}
/**
* Apply some special processing to
* object beeing recalled before using
* it in other events that call prepareObject
*
* @param Object $object
* @param kEvent $event
* @access protected
*/
function prepareObject(&$object, &$event)
{
parent::prepareObject($object, $event);
if (!$this->Application->IsAdmin()) {
if ($this->Application->RecallVar('register_captcha_code')) return ;
$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
/* @var $captcha_helper kCaptchaHelper */
$this->Application->StoreVar('register_captcha_code', $captcha_helper->GenerateCaptchaCode());
}
}
/**
* Apply custom processing to item
*
* @param kEvent $event
*/
function customProcessing(&$event, $type)
{
if ($event->Name == 'OnCreate' && $type == 'before') {
$object =& $event->getObject();
/* @var $object kDBItem */
// if auto password has not been set already - store real one - to be used in email events
if (!$this->Application->GetVar('user_password')) {
$this->Application->SetVar('user_password', $object->GetDirtyField('Password'));
$object->SetDBField('Password_plain', $object->GetDirtyField('Password'));
}
// Validate captcha image if it's requried
if ($this->Application->ConfigValue('RegistrationCaptcha') && $object->GetDBField('Captcha') != $this->Application->RecallVar('register_captcha_code')) {
$object->SetError('Captcha', 'captcha_error', 'lu_captcha_error');
$captcha_helper =& $this->Application->recallObject('CaptchaHelper');
/* @var $captcha_helper kCaptchaHelper */
$this->Application->StoreVar('register_captcha_code', $captcha_helper->GenerateCaptchaCode());
}
}
}
function OnMassResetSettings(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$event->status=erSUCCESS;
$ids = $this->StoreSelectedIDs($event);
$default_user_id = $this->Application->ConfigValue('DefaultSettingsUserId');
if (in_array($default_user_id, $ids)) {
array_splice($ids, array_search($default_user_id, $ids), 1);
}
if ($ids) {
$q = 'DELETE FROM '.TABLE_PREFIX.'PersistantSessionData WHERE PortalUserId IN ('.join(',', $ids).') AND
(VariableName LIKE "%_columns_%"
OR
VariableName LIKE "%_filter%"
OR
VariableName LIKE "%_PerPage%")';
$this->Conn->Query($q);
}
$this->clearSelectedIDs($event);
}
/**
* Checks, that currently loaded item is allowed for viewing (non permission-based)
*
* @param kEvent $event
* @return bool
*/
function checkItemStatus(&$event)
{
$object =& $event->getObject();
if (!$object->isLoaded()) {
return true;
}
$virtual_users = Array (-1, -2); // root, Guest
return ($object->GetDBField('Status') == STATUS_ACTIVE) || in_array($object->GetID(), $virtual_users);
}
/**
* Sends approved/declined email event on user status change
*
* @param kEvent $event
*/
function OnAfterItemUpdate(&$event)
{
$this->saveUserImages($event);
$object =& $event->getObject();
/* @var $object UsersItem */
if (!$this->Application->IsAdmin() || $object->IsTempTable()) {
return ;
}
$this->sendStatusChangeEvent($object->GetID(), $object->GetOriginalField('Status'), $object->GetDBField('Status'));
}
/**
* Stores user's original Status before overwriting with data from temp table
*
* @param kEvent $event
*/
function OnBeforeDeleteFromLive(&$event)
{
$user_status = $this->Application->GetVar('user_status');
if (!$user_status) {
$user_status = Array ();
}
$user_id = $event->getEventParam('id');
if ($user_id > 0) {
$user_status[$user_id] = $this->getUserStatus($user_id);
$this->Application->SetVar('user_status', $user_status);
}
}
/**
* Sends approved/declined email event on user status change (in temp tables during editing)
*
* @param kEvent $event
*/
function OnAfterCopyToLive(&$event)
{
$temp_id = $event->getEventParam('temp_id');
if ($temp_id == 0) {
// this is new user create, don't send email events
return ;
}
$new_status = $this->getUserStatus($temp_id);
$user_status = $this->Application->GetVar('user_status');
$this->sendStatusChangeEvent($temp_id, $user_status[$temp_id], $new_status);
}
/**
* Returns user status (active, pending, disabled) based on ID and temp mode setting
*
* @param int $user_id
* @return int
*/
function getUserStatus($user_id)
{
$id_field = $this->Application->getUnitOption($this->Prefix, 'IDField');
$table_name = $this->Application->getUnitOption($this->Prefix, 'TableName');
$sql = 'SELECT Status
FROM '.$table_name.'
WHERE '.$id_field.' = '.$user_id;
return $this->Conn->GetOne($sql);
}
/**
* Sends approved/declined email event on user status change
*
* @param int $user_id
* @param int $prev_status
* @param int $new_status
*/
function sendStatusChangeEvent($user_id, $prev_status, $new_status)
{
$status_events = Array (
STATUS_ACTIVE => 'USER.APPROVE',
STATUS_DISABLED => 'USER.DENY',
);
$email_event = isset($status_events[$new_status]) ? $status_events[$new_status] : false;
if (($prev_status != $new_status) && $email_event) {
$this->Application->EmailEventUser($email_event, $user_id);
$this->Application->EmailEventAdmin($email_event);
}
}
/**
* OnAfterConfigRead for users
*
* @param kEvent $event
*/
function OnAfterConfigRead(&$event)
{
parent::OnAfterConfigRead($event);
$first_country = $this->Application->ConfigValue('User_Default_Registration_Country');
if ($first_country) {
// update user country dropdown sql
$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
$fields['Country']['options_sql'] = preg_replace('/ORDER BY (.*)/', 'ORDER BY IF (DestId = '.$first_country.', 1, 0) DESC, \\1', $fields['Country']['options_sql']);
$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
}
$file_helper =& $this->Application->recallObject('FileHelper');
/* @var $file_helper FileHelper */
$file_helper->createItemFiles($event->Prefix, true); // create image fields
}
/**
* OnMassCloneUsers
*
* @param kEvent $event
*/
function OnMassCloneUsers(&$event)
{
if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
return;
}
$event->status=erSUCCESS;
$ids = $this->StoreSelectedIDs($event);
$this->Application->SetVar('skip_set_primary', 1); // otherwise it will default primary group, search for skip_set_primary above
$temp_handler =& $this->Application->recallObject($event->Prefix.'_TempHandler', 'kTempTablesHandler');
/* @var $temp_handler kTempTablesHandler */
$cloned_users = $temp_handler->CloneItems($event->Prefix, '', $ids);
$this->clearSelectedIDs($event);
}
/**
* When cloning users, reset password (set random)
*
* @param kEvent $event
*/
function OnBeforeClone(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$object->setRequired('Password', 0);
$object->setRequired('VerifyPassword', 0);
$object->SetDBField('Password', rand(100000000, 999999999));
$object->SetDBField('CreatedOn', adodb_mktime());
$object->SetDBField('ResourceId', false); // this will reset it
// change email cause it should be unique
$object->NameCopy(array(), $object->GetID(), 'Email', 'copy%1$s.%2$s');
$object->UpdateFormattersSubFields();
}
/**
* Copy user groups after copying user
*
* @param kEvent $event
*/
function OnAfterClone(&$event)
{
$id = $event->getEventParam('id');
$original_id = $event->getEventParam('original_id');
$sql = 'INSERT '.TABLE_PREFIX."UserGroup SELECT $id, GroupId, MembershipExpires, PrimaryGroup, 0 FROM ".TABLE_PREFIX."UserGroup WHERE PortalUserId = $original_id";
$this->Conn->Query($sql);
}
/**
* Saves selected ids to session
*
* @param kEvent $event
*/
function OnSaveSelected(&$event)
{
$this->StoreSelectedIDs($event);
// remove current ID, otherwise group selector will use it in filters
$this->Application->DeleteVar($event->getPrefixSpecial(true).'_id');
}
/**
* Adds selected link to listing
*
* @param kEvent $event
*/
function OnProcessSelected(&$event)
{
$event->SetRedirectParam('opener', 'u');
$user_ids = $this->getSelectedIDs($event, true);
$this->clearSelectedIDs($event);
$dst_field = $this->Application->RecallVar('dst_field');
if ($dst_field != 'PrimaryGroupId') {
return ;
}
$group_ids = $this->Application->GetVar('g');
$primary_group_id = $group_ids ? array_shift( array_keys($group_ids) ) : false;
if (!$user_ids || !$primary_group_id) {
return ;
}
$table_name = $this->Application->getUnitOption('ug', 'TableName');
$sql = 'SELECT PortalUserId
FROM '.$table_name.'
WHERE (GroupId = '.$primary_group_id.') AND (PortalUserId IN ('.implode(',', $user_ids).'))';
$existing_members = $this->Conn->GetCol($sql);
// 1. reset primary group mark
$sql = 'UPDATE '.$table_name.'
SET PrimaryGroup = 0
WHERE PortalUserId IN ('.implode(',', $user_ids).')';
$this->Conn->Query($sql);
foreach ($user_ids as $user_id) {
if (in_array($user_id, $existing_members)) {
// 2. already member of that group -> just make primary
$sql = 'UPDATE '.$table_name.'
SET PrimaryGroup = 1
WHERE (PortalUserId = '.$user_id.') AND (GroupId = '.$primary_group_id.')';
$this->Conn->Query($sql);
}
else {
// 3. not member of that group -> make member & make primary
$fields_hash = Array (
'GroupId' => $primary_group_id,
'PortalUserId' => $user_id,
'PrimaryGroup' => 1,
);
$this->Conn->doInsert($fields_hash, $table_name);
}
}
}
/**
* Loads user images
*
* @param kEvent $event
*/
function OnAfterItemLoad(&$event)
{
parent::OnAfterItemLoad($event);
// linking existing images for item with virtual fields
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$object =& $event->getObject();
/* @var $object kDBItem */
$image_helper->LoadItemImages($object);
}
/**
* Save user images
*
* @param kEvent $event
*/
function saveUserImages(&$event)
{
if (!$this->Application->IsAdmin()) {
$image_helper =& $this->Application->recallObject('ImageHelper');
/* @var $image_helper ImageHelper */
$object =& $event->getObject();
/* @var $object kDBItem */
// process image upload in virtual fields
$image_helper->SaveItemImages($object);
}
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/users/users_event_handler.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.87.2.12
\ No newline at end of property
+1.87.2.13
\ No newline at end of property
Index: branches/RC/core/units/logs/session_logs/session_logs_config.php
===================================================================
--- branches/RC/core/units/logs/session_logs/session_logs_config.php (nonexistent)
+++ branches/RC/core/units/logs/session_logs/session_logs_config.php (revision 10294)
@@ -0,0 +1,133 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => 'session-log',
+ 'ItemClass' => Array ('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
+ 'ListClass' => Array ('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
+ 'EventHandlerClass' => Array ('class' => 'SessionLogEventHandler', 'file' => 'session_log_eh.php', 'build_event' => 'OnBuild'),
+ 'TagProcessorClass' => Array ('class' => 'kDBTagProcessor', 'file' => '', 'build_event' => 'OnBuild'),
+
+ 'AutoLoad' => true,
+
+ 'QueryString' => Array (
+ 1 => 'id',
+ 2 => 'Page',
+ 3 => 'event',
+ 4 => 'mode',
+ ),
+
+ 'IDField' => 'SessionLogId',
+ 'StatusField' => Array ('Status'),
+
+ 'TableName' => TABLE_PREFIX.'SessionLogs',
+
+ 'PermSection' => Array('main' => 'in-portal:session_logs'),
+
+ // don't forget to add corresponding permissions to install script
+ // INSERT INTO Permissions VALUES (0, 'in-portal:session_logs.view', 11, 1, 1, 0), (0, 'in-portal:session_logs.delete', 11, 1, 1, 0);
+ 'Sections' => Array (
+ 'in-portal:session_logs' => Array (
+ 'parent' => 'in-portal:reports',
+ 'icon' => 'conf_general',
+ 'label' => 'la_tab_SessionLogs',
+ 'url' => Array('t' => 'logs/session_logs/session_log_list', 'pass' => 'm'),
+ 'permissions' => Array('view', 'delete'),
+ 'priority' => 0.1,
+ 'show_mode' => smSUPER_ADMIN,
+ 'type' => stTREE,
+ ),
+ ),
+
+ 'TitleField' => 'SessionLogId',
+
+ 'ListSQLs' => Array (
+ '' => ' SELECT %1$s.* %2$s
+ FROM %1$s
+ LEFT JOIN '.TABLE_PREFIX.'PortalUser AS u ON u.PortalUserId = %1$s.PortalUserId',
+ ),
+
+ 'ListSortings' => Array (
+ '' => Array (
+ 'Sorting' => Array ('SessionLogId' => 'desc'),
+ )
+ ),
+
+ 'CalculatedFields' => Array(
+ '' => Array(
+ 'UserLogin' => 'IF(%1$s.PortalUserId=-1, \'root\', u.Login)',
+ 'UserFirstName' => 'u.FirstName',
+ 'UserLastName' => 'u.LastName',
+ 'UserEmail' => 'u.Email',
+ 'Duration' => 'IFNULL(SessionEnd, UNIX_TIMESTAMP())-SessionStart',
+ ),
+ ),
+
+ 'Fields' => Array (
+ 'SessionLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'PortalUserId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'SessionId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'Status' => Array (
+ 'type' => 'int', 'formatter' => 'kOptionsFormatter',
+ 'options'=> array(0=>'la_Active',1=>'la_LoggedOut',2=>'la_Expired'),
+ 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 1
+ ),
+ 'SessionStart' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'not_null' => 1, 'time_format' => 'H:i:s', 'default' => 0),
+ 'SessionEnd' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'time_format' => 'H:i:s', 'default' => NULL),
+ 'IP' => Array ('type' => 'string', 'max_len' => 15, 'not_null' => 1, 'default' => ''),
+ 'AffectedItems' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ ),
+
+ 'VirtualFields' => Array(
+ 'Duration' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'not_null' => 1, 'date_format' => '', 'time_format' => 'H:i:s', 'use_timezone' => false, 'default' => 0),
+ ),
+
+ 'Grids' => Array (
+ 'Default' => Array (
+ 'Fields' => Array (
+ 'SessionLogId' => Array ('title' => 'la_col_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter', ),
+ 'PortalUserId' => Array ('title' => 'la_col_PortalUserId', 'filter_block' => 'grid_like_filter',),
+ 'UserLogin' => Array ('title' => 'la_col_Username', 'filter_block' => 'grid_like_filter',),
+ 'UserFirstName' => Array ('title' => 'la_col_FirstName', 'filter_block' => 'grid_like_filter',),
+ 'UserLastName' => Array ('title' => 'la_col_LastName', 'filter_block' => 'grid_like_filter',),
+ 'SessionStart' => Array ('title' => 'la_col_SessionStart', 'filter_block' => 'grid_date_range_filter', ),
+ 'SessionEnd' => Array ('title' => 'la_col_SessionEnd', 'filter_block' => 'grid_date_range_filter', ),
+ 'Duration' => Array ('title' => 'la_col_Duration', 'filter_block' => 'grid_range_filter', ),
+ 'Status' => Array ('title' => 'la_col_Status', 'filter_block' => 'grid_options_filter', ),
+ 'IP' => Array ('title' => 'la_col_IP', 'filter_block' => 'grid_like_filter',),
+ 'AffectedItems' => Array ('title' => 'la_col_AffectedItems', 'data_block' => 'affected_td'),
+ ),
+ ),
+ ),
+
+ 'ConfigMapping' => Array(
+ 'PerPage' => 'Perpage_SessionLogs',
+ ),
+ );
+
+
+/* !!! Copy the rest of the file to appropriate files and templates
+ * !!! DON'T FORGET TO CREAT FIELDS AND GRIDS USING SYSTEM TOOLS SECTION !!!
+
+ /*
+
+Don't forget to:
+
+- Add table create statement to install_schema.sql
+ CREATE TABLE SessionLogs (
+ `SessionLogId` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
+ `Title` VARCHAR( 255 ) NOT NULL ,
+ `Description` TEXT NULL ,
+ `Email` VARCHAR( 255 ) NOT NULL ,
+ `Type` TINYINT NOT NULL ,
+ `Phone` VARCHAR( 50 ) NOT NULL ,
+ `Qty` DOUBLE NOT NULL ,
+ `Status` TINYINT NOT NULL ,
+ `CreatedOn` INT NOT NULL ,
+ `Good` TINYINT NOT NULL
+)
+
+- Add permissions for admin gorup to install script (see 'Sections' key above)
+
+
+*/
\ No newline at end of file
Property changes on: branches/RC/core/units/logs/session_logs/session_logs_config.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.2.1
\ No newline at end of property
Index: branches/RC/core/units/logs/session_logs/session_log_eh.php
===================================================================
--- branches/RC/core/units/logs/session_logs/session_log_eh.php (nonexistent)
+++ branches/RC/core/units/logs/session_logs/session_log_eh.php (revision 10294)
@@ -0,0 +1,58 @@
+<?php
+
+class SessionLogEventHandler extends kDBEventHandler {
+
+ /**
+ * Opens log for new session
+ *
+ * @param kEvent $event
+ */
+ function OnStartSession(&$event)
+ {
+ $object =& $this->Application->recallObject($event->Prefix, null, Array ('skip_autoload' => 1));
+ /* @var $object kDBItem */
+
+ $fields_hash = Array (
+ 'SessionStart' => adodb_mktime(),
+ 'IP' => $_SERVER['REMOTE_ADDR'],
+ 'PortalUserId' => $this->Application->RecallVar('user_id'),
+ 'SessionId' => $this->Application->GetSID(),
+ 'Status' => 0,
+ );
+
+ $object->SetDBFieldsFromHash($fields_hash);
+
+ $object->UpdateFormattersSubFields();
+
+ if ($object->Create()) {
+ $this->Application->StoreVar('_SessionLogId_', $object->GetID());
+ }
+ }
+
+ /**
+ * Closes log for current session
+ *
+ * @param kEvent $event
+ */
+ function OnEndSession(&$event)
+ {
+ $object =& $this->Application->recallObject($event->Prefix, null, Array ('skip_autoload' => 1));
+ /* @var $object kDBItem */
+
+ $object->Load($this->Application->RecallVar('_SessionLogId_'));
+ if (!$object->isLoaded()) {
+ return ;
+ }
+
+ $fields_hash = Array (
+ 'SessionEnd' => adodb_mktime(),
+ 'Status' => 1,
+ );
+
+ $object->SetDBFieldsFromHash($fields_hash);
+
+ $object->UpdateFormattersSubFields();
+ $object->Update();
+ }
+
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/logs/session_logs/session_log_eh.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.2.1
\ No newline at end of property
Index: branches/RC/core/units/logs/change_logs/changes_formatter.php
===================================================================
--- branches/RC/core/units/logs/change_logs/changes_formatter.php (nonexistent)
+++ branches/RC/core/units/logs/change_logs/changes_formatter.php (revision 10294)
@@ -0,0 +1,39 @@
+<?php
+
+class kChangesFormatter extends kFormatter {
+
+ function Format($value, $field_name, &$object, $format=null)
+ {
+ if ( is_null($value) ) {
+ return '';
+ }
+
+ $changes = unserialize($value);
+
+ $res = '';
+ if (!$changes) {
+ return ;
+ }
+
+ foreach ($changes as $field => $data) {
+ $fld_translation = $this->Application->Phrase('la_fld_'.$field);
+
+ // remove translation link (added in debug mode)
+ $fld_translation = preg_replace('/<a href="(.*?)">(.*?)<\/a>/', '\\2', $fld_translation);
+
+ if ($fld_translation == '!'.strtoupper('la_fld_'.$field).'!') {
+ // when phrase is not translated use field name as label
+ $fld_translation = $field;
+ }
+
+ if (is_array($data) && isset($data['old']) && isset($data['new'])) {
+ $res .= "$fld_translation: {$data['old']} => {$data['new']}<br/>\n";
+ }
+ else {
+ $res .= "$fld_translation: {$data['new']}<br/>\n";
+ }
+ }
+ return $res;
+ }
+
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/logs/change_logs/changes_formatter.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.2.1
\ No newline at end of property
Index: branches/RC/core/units/logs/change_logs/change_logs_config.php
===================================================================
--- branches/RC/core/units/logs/change_logs/change_logs_config.php (nonexistent)
+++ branches/RC/core/units/logs/change_logs/change_logs_config.php (revision 10294)
@@ -0,0 +1,158 @@
+<?php
+
+ $config = Array (
+ 'Prefix' => 'change-log',
+ 'ItemClass' => Array('class' => 'kDBItem', 'file' => '', 'build_event' => 'OnItemBuild'),
+ 'ListClass' => Array('class' => 'kDBList', 'file' => '', 'build_event' => 'OnListBuild'),
+ 'EventHandlerClass' => Array ('class' => 'kDBEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
+ 'TagProcessorClass' => Array ('class' => 'kDBTagProcessor', 'file' => '', 'build_event' => 'OnBuild'),
+
+ 'RegisterClasses' => Array (
+ Array ('pseudo' => 'kChangesFormatter', 'class' => 'kChangesFormatter', 'file' => 'changes_formatter.php', 'build_event' => '', 'require_classes' => 'kFormatter'),
+ ),
+
+ 'AutoLoad' => true,
+
+ 'QueryString' => Array (
+ 1 => 'id',
+ 2 => 'Page',
+ 3 => 'event',
+ 4 => 'mode',
+ ),
+
+ 'IDField' => 'ChangeLogId',
+ 'StatusField' => Array ('Status'),
+ 'TableName' => TABLE_PREFIX.'ChangeLogs',
+
+ 'TitlePresets' => Array (
+ 'default' => Array (
+ 'new_status_labels' => Array ('change-log' => '!la_title_AddingChangeLog!'),
+ 'edit_status_labels' => Array ('change-log' => '!la_title_EditingChangeLog!'),
+ ),
+
+ 'changelog_edit' => Array ('prefixes' => Array('change-log'), 'format' => '#change-log_status# #change-log_titlefield#',),
+ ),
+
+ 'PermSection' => Array ('main' => 'in-portal:change_logs'),
+
+ // don't forget to add corresponding permissions to install script
+ // INSERT INTO Permissions VALUES (0, 'in-portal:change_logs.view', 11, 1, 1, 0), (0, 'in-portal:change_logs.add', 11, 1, 1, 0), (0, 'in-portal:change_logs.edit', 11, 1, 1, 0), (0, 'in-portal:change_logs.delete', 11, 1, 1, 0);
+ 'Sections' => Array (
+ 'in-portal:change_logs' => Array (
+ 'parent' => 'in-portal:reports',
+ 'icon' => 'in-portal:change_logs',
+ 'label' => 'la_tab_ChangeLog',
+ 'url' => Array('t' => 'logs/change_logs/change_log_list', 'pass' => 'm'),
+ 'permissions' => Array('view', 'edit', 'delete'),
+ 'priority' => 0.2,
+ 'show_mode' => smSUPER_ADMIN,
+ 'type' => stTREE,
+ ),
+ ),
+
+ 'TitleField' => 'ChangeLogId',
+
+ 'ListSQLs' => Array (
+ '' => ' SELECT %1$s.* %2$s
+ FROM %1$s
+ LEFT JOIN '.TABLE_PREFIX.'PortalUser AS u ON u.PortalUserId = %1$s.PortalUserId',
+ ),
+
+ 'ListSortings' => Array (
+ '' => Array (
+ 'Sorting' => Array ('OccuredOn' => 'desc'),
+ )
+ ),
+
+ 'CalculatedFields' => Array (
+ '' => Array (
+ 'UserLogin' => 'IF(%1$s.PortalUserId = -1, \'root\', u.Login)',
+ 'UserFirstName' => 'u.FirstName',
+ 'UserLastName' => 'u.LastName',
+ 'UserEmail' => 'u.Email',
+ ),
+ ),
+
+ 'Fields' => Array (
+ 'ChangeLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'PortalUserId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'SessionLogId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'Action' => Array (
+ 'type' => 'int', 'formatter' => 'kOptionsFormatter',
+ 'options' => array (clCREATE => 'la_opt_ActionCreate', clUPDATE => 'la_opt_ActionUpdate', clDELETE => 'la_opt_ActionDelete'),
+ 'use_phrases' => 1,
+ 'not_null' => 1, 'default' => 0
+ ),
+ 'OccuredOn' => Array ('type' => 'int', 'formatter' => 'kDateFormatter', 'time_format' => 'H:i:s', 'not_null' => 1, 'default' => 0),
+ 'Prefix' => Array (
+ 'type' => 'string', 'formatter' => 'kOptionsFormatter',
+ 'options_sql' => 'SELECT DISTINCT %s FROM '.TABLE_PREFIX.'ChangeLogs ORDER BY Phrase',
+ 'option_key_field' => 'Prefix',
+ 'option_title_field' => 'CONCAT(\'la_prefix_\', Prefix) AS Phrase',
+ 'use_phrases' => 1,
+ 'max_len' => 255, 'not_null' => 1, 'default' => ''
+ ),
+ 'ItemId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ 'Changes' => Array ('type' => 'string', 'formatter' => 'kChangesFormatter', 'not_null' => 1, 'default' => ''),
+ 'MasterPrefix' => Array (
+ 'type' => 'string', 'formatter' => 'kOptionsFormatter',
+ 'options_sql' => 'SELECT DISTINCT %s FROM '.TABLE_PREFIX.'ChangeLogs ORDER BY Phrase',
+ 'option_key_field' => 'MasterPrefix',
+ 'option_title_field' => 'CONCAT(\'la_prefix_\',MasterPrefix) AS Phrase',
+ 'use_phrases' => 1,
+ 'max_len' => 255, 'not_null' => 1, 'default' => ''
+ ),
+ 'MasterId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
+ ),
+
+ 'Grids' => Array (
+ 'Default' => Array (
+ 'Fields' => Array (
+ 'ChangeLogId' => Array ('title' => 'la_col_Id', 'data_block' => 'grid_checkbox_td', 'filter_block' => 'grid_range_filter',),
+ 'PortalUserId' => Array ('title' => 'la_col_PortalUserId', 'filter_block' => 'grid_like_filter',),
+ 'UserLogin' => Array ('title' => 'la_col_Username', 'filter_block' => 'grid_like_filter',),
+ 'UserFirstName' => Array ('title' => 'la_col_FirstName', 'filter_block' => 'grid_like_filter',),
+ 'UserLastName' => Array ('title' => 'la_col_LastName', 'filter_block' => 'grid_like_filter',),
+ 'SessionLogId' => Array ('title' => 'la_col_SessionLogId', 'filter_block' => 'grid_like_filter',),
+ 'Action' => Array ('title' => 'la_col_Action', 'filter_block' => 'grid_options_filter', ),
+ 'OccuredOn' => Array ('title' => 'la_col_OccuredOn', 'filter_block' => 'grid_date_range_filter',),
+ 'MasterPrefix' => Array ('title' => 'la_col_MasterPrefix', 'filter_block' => 'grid_options_filter', ),
+ 'MasterId' => Array ('title' => 'la_col_MasterId', 'filter_block' => 'grid_range_filter',),
+ 'Prefix' => Array ('title' => 'la_col_ItemPrefix', 'filter_block' => 'grid_options_filter', ),
+ 'ItemId' => Array ('title' => 'la_col_ItemId', 'filter_block' => 'grid_range_filter',),
+ 'Changes' => Array ('title' => 'la_col_Changes', 'data_block' => 'grid_changes_td', 'filter_block' => 'grid_like_filter',),
+ ),
+ ),
+ ),
+
+ 'ConfigMapping' => Array(
+ 'PerPage' => 'Perpage_ChangeLog',
+ ),
+ );
+
+/* !!! Copy the rest of the file to appropriate files and templates
+ * !!! DON'T FORGET TO CREAT FIELDS AND GRIDS USING SYSTEM TOOLS SECTION !!!
+
+
+/*
+
+Don't forget to:
+
+- Add table create statement to install_schema.sql
+ CREATE TABLE ChangeLogs (
+ `ChangeLogId` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
+ `Title` VARCHAR( 255 ) NOT NULL ,
+ `Description` TEXT NULL ,
+ `Email` VARCHAR( 255 ) NOT NULL ,
+ `Type` TINYINT NOT NULL ,
+ `Phone` VARCHAR( 50 ) NOT NULL ,
+ `Qty` DOUBLE NOT NULL ,
+ `Status` TINYINT NOT NULL ,
+ `CreatedOn` INT NOT NULL ,
+ `Good` TINYINT NOT NULL
+)
+
+- Add permissions for admin gorup to install script (see 'Sections' key above)
+
+
+*/
\ No newline at end of file
Property changes on: branches/RC/core/units/logs/change_logs/change_logs_config.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.2.1
\ No newline at end of property
Index: branches/RC/core/units/configuration/configuration_config.php
===================================================================
--- branches/RC/core/units/configuration/configuration_config.php (revision 10293)
+++ branches/RC/core/units/configuration/configuration_config.php (revision 10294)
@@ -1,81 +1,82 @@
<?php
$config = Array(
'Prefix' => 'conf',
'ItemClass' => Array('class'=>'ConfigurationItem','file'=>'configuration.php','build_event'=>'OnItemBuild'),
'ListClass' => Array('class'=>'kDBList','file'=>'','build_event'=>'OnListBuild'),
'EventHandlerClass' => Array('class'=>'ConfigurationEventHandler','file'=>'configuration_event_handler.php','build_event'=>'OnBuild'),
'TagProcessorClass' => Array('class'=>'ConfigurationTagProcessor','file'=>'configuration_tag_processor.php','build_event'=>'OnBuild'),
'AutoLoad' => true,
'Hooks' => Array(),
'QueryString' => Array(
1 => 'id',
2 => 'page',
3 => 'event',
4 => 'mode',
),
'IDField' => 'VariableId',
+ 'TitleField' => 'VariableName',
'TitlePresets' => Array(
'default' => Array('tag_params' => Array('conf' => Array('per_page' => -1))),
'config_list_general' => Array('prefixes' => Array('conf_List'), 'format' => "!la_updating_config!"),
'config_list_output' => Array('prefixes' => Array('conf_List'), 'format' => "!la_updating_config!"),
'config_list_contacts' => Array('prefixes' => Array('conf_List'), 'format' => "!la_updating_config!"),
'config_list_categories' => Array('prefixes' => Array('conf_List'), 'format' => "!la_updating_config!"),
'config_list_users' => Array('prefixes' => Array('conf_List'), 'format' => "!la_updating_config!"),
),
'TableName' => TABLE_PREFIX.'ConfigurationValues',
'ListSQLs' => Array('' => ' SELECT %1$s.* %2$s
FROM '.TABLE_PREFIX.'ConfigurationAdmin ca
LEFT JOIN %1$s USING(VariableName)'),
'ItemSQLs' => Array('' => ' SELECT %1$s.* %2$s
FROM '.TABLE_PREFIX.'ConfigurationAdmin ca
LEFT JOIN %1$s USING(VariableName)'),
'ListSortings' => Array(
'' => Array(
'Sorting' => Array('DisplayOrder' => 'asc', 'GroupDisplayOrder' => 'asc'),
)
),
'CalculatedFields' => Array (
'' => Array (
'heading' => 'ca.heading',
'prompt' => 'ca.prompt',
'element_type' => 'ca.element_type',
'ValueList' => 'ca.ValueList',
'DisplayOrder' => 'ca.DisplayOrder',
'GroupDisplayOrder' => 'ca.GroupDisplayOrder',
'Install' => 'ca.Install',
),
),
'Fields' => Array(
'VariableId' => Array ('type' => 'int', 'not_null' => 1, 'default' => 0),
'VariableName' => Array('type' => 'string','not_null' => '1','default' => ''),
'VariableValue' => Array('type'=>'string', 'default' => null),
'ModuleOwner' => Array('type'=>'string', 'default'=>'In-Portal'),
'Section' => Array('type'=>'string','not_null' => '1','default'=>''),
),
'VirtualFields' => Array(
'heading' => Array('type' => 'string', 'default' => ''),
'prompt' => Array('type' => 'string', 'default' => ''),
'element_type' => Array('type' => 'string', 'not_null' => '1', 'default' => ''),
'ValueList' => Array('type' => 'string', 'default' => ''),
'DisplayOrder' => Array('type' => 'double', 'not_null' => '1', 'default' => 0),
'GroupDisplayOrder' => Array('type' => 'double', 'not_null' => '1', 'default' => 0),
'Install' => Array('type' => 'int', 'not_null' => '1', 'default' => 1),
'DirectOptions' => Array('type' => 'string', 'default' => ''),
),
'Grids' => Array(),
);
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/configuration/configuration_config.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.18
\ No newline at end of property
+1.18.2.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_image.php
===================================================================
--- branches/RC/core/units/pdf/pdf_image.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_image.php (revision 10294)
@@ -0,0 +1,48 @@
+<?php
+
+class kPDFImage extends kPDFElement {
+ public $ImageFile = null;
+ public $ImageInfo = null;
+
+ function Closed()
+ {
+ $src = $this->Node->Attributes['SRC'];
+ if ($tmp = preg_replace('/^'.preg_quote(PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').rtrim(BASE_PATH, '/'), '/').'/', FULL_PATH, $src)) {
+ $this->ImageFile = $tmp;
+ $this->ImageInfo = getimagesize($this->ImageFile);
+ $this->ImageInfo[0] *= 72 / 96;
+ $this->ImageInfo[1] *= 72 / 96;
+ }
+ else {
+
+ }
+ parent::Closed();
+ }
+
+ function CheckDimensions()
+ {
+ $elem = $this;
+ do {
+ $elem->SetCSSProperty('width', $elem->GetCSSProperty('width') + $this->ImageInfo[0]);
+ $elem->SetCSSProperty('height', $this->ImageInfo[1]);
+ $elem = $elem->Parent;
+ } while ($elem && $elem->GetDisplayLevel() == 'inline');
+ $this->GetLineBox()->CurX += $this->ImageInfo[0];
+ }
+
+ function CalcMinMaxContentWidth()
+ {
+ $this->MinContentWidth = $this->ImageInfo[0];
+ $this->MaxContentWidth = $this->ImageInfo[0];
+ parent::CalcMinMaxContentWidth();
+ }
+
+ function DrawAt($page, $x=0, $y=0, $spacer_w=0)
+ {
+ if ($this->ImageFile) {
+ if (defined('PDF_DEBUG_NO_TEXT')) return ;
+ $page->DrawImage($this->ImageFile, $x, $y, $this->GetCSSProperty('width'), $this->GetCSSProperty('height'));
+ }
+ }
+
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/pdf_image.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_styles.php
===================================================================
--- branches/RC/core/units/pdf/pdf_styles.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_styles.php (revision 10294)
@@ -0,0 +1,877 @@
+<?php
+
+require_once('css_defaults.php');
+
+class kPDFStylesheet {
+
+ protected $Selectors;
+ protected $Macros;
+
+ protected $Buffer = array();
+ protected $Openings = array();
+ protected $Level = 0;
+
+ public $Rules = array();
+ public $SelectorOrder = 0;
+ public $HTMLVisualPropsSelectorOrder = 0;
+
+ const STYLE_ORIGIN_AGENT_NORMAL = 0;
+ const STYLE_ORIGIN_USER_NORMAL = 1;
+ const STYLE_ORIGIN_AUTHOR_NORMAL = 2;
+ const STYLE_ORIGIN_AUTHOR_IMPORTANT = 3;
+ const STYLE_ORIGIN_USER_IMPORTANT = 4;
+
+ function __construct($nodefaults = false)
+ {
+ $this->Prepare();
+ if (!$nodefaults) {
+ $tokens = $this->GetTokens(kCSSDefaults::$DEFAULT_STYLE);
+ $this->ParseTokens($tokens, kPDFStylesheet::STYLE_ORIGIN_AGENT_NORMAL);
+ $this->HTMLVisualPropsSelectorOrder = $this->SelectorOrder;
+ $this->SelectorOrder += 1000;
+ }
+ }
+
+ public function ParseStyle($style)
+ {
+ $res = array();
+ $pairs = explode(';', $style);
+ foreach ($pairs as $property) {
+ $property = trim($property);
+ list($name, $value) = explode(':', $property);
+ $res[trim($name)] = trim($value);
+ }
+ }
+
+ /*
+ stylesheet : [ CDO | CDC | S | statement ]*;
+ statement : ruleset | at-rule;
+ at-rule : ATKEYWORD S* any* [ block | ';' S* ];
+ block : '{' S* [ any | block | ATKEYWORD S* | ';' S* ]* '}' S*;
+ ruleset : selector? '{' S* declaration? [ ';' S* declaration? ]* '}' S*;
+ selector : any+;
+ declaration : DELIM? property S* ':' S* value;
+ property : IDENT;
+ value : [ any | block | ATKEYWORD S* ]+;
+ any : [ IDENT | NUMBER | PERCENTAGE | DIMENSION | STRING
+ | DELIM | URI | HASH | UNICODE-RANGE | INCLUDES
+ | DASHMATCH | FUNCTION S* any* ')'
+ | '(' S* any* ')' | '[' S* any* ']' ] S*;
+ */
+
+ function ParseTokens($tokens, $origin=kPDFStylesheet::STYLE_ORIGIN_AUTHOR_NORMAL )
+ {
+ $this->Buffer[0] = Array();
+ foreach ($tokens as $token) {
+ if ($token['name'] == 'LBRACE') {
+ $this->Buffer[++$this->Level] = Array();
+ $this->Openings[$this->Level] = 'LBRACE';
+ }
+ elseif ($token['name'] == 'TEXT' && $token['data'] == '}') {
+ if ($this->Level == 1 && $this->Openings[$this->Level] == 'LBRACE') {
+ $this->AppendRule($this->Buffer[0], $this->Buffer[$this->Level], $origin);
+ $this->Buffer[0] = Array();
+ }
+ $this->Level--;
+ }
+ else {
+ $this->Buffer[$this->Level][] = $token;
+ }
+ }
+ }
+
+ protected function ConcatTokensData($tokens)
+ {
+ $res = '';
+ foreach ($tokens as $token) {$res .= $token['data'];}
+ return $res;
+ }
+
+ public function ParseDefinitionTokens($tokens)
+ {
+ $mode = 'property';
+ $properties = array();
+ $value = '';
+ foreach ($tokens as $token) {
+ if ($mode == 'property') {
+ if ($token['name'] == 'IDENT') {
+ $property = $token['data'];
+ $mode = 'colon';
+ }
+ }
+ elseif ($mode == 'colon') {
+ if ($token['name'] == 'TEXT' && $token['data'] == ':') {
+ $mode = 'value';
+ }
+ }
+ elseif ($mode == 'value') {
+ if ($token['name'] == 'TEXT' && $token['data'] == ';') {
+ $properties[strtoupper($property)] = trim($value);
+ $value = '';
+ $mode = 'property';
+ }
+ else {
+ $value .= $token['data'];
+ }
+ }
+ }
+ if ($mode == 'value') {
+ $properties[strtoupper($property)] = trim($value);
+ }
+ if ($mode == 'colon') {
+ trigger_error('Error parsing CSS definition, no colon and/or value after property '.$property, E_USER_WARNING);
+ }
+
+ $properties = $this->ProcessShortHands($properties);
+
+ return $properties;
+ }
+
+ public function ProcessShortHands($properties)
+ {
+ $res = array();
+ foreach ($properties as $property => $value)
+ {
+ switch ($property) {
+ case 'MARGIN':
+ if (preg_match('/^([.0-9]+(?:px|pt|em|ex|%)?|auto)$/i', $value, $regs)) {
+ $res['MARGIN-TOP'] = $regs[1];
+ $res['MARGIN-RIGHT'] = $regs[1];
+ $res['MARGIN-BOTTOM'] = $regs[1];
+ $res['MARGIN-LEFT'] = $regs[1];
+ }
+ if (preg_match('/^([.0-9]+(?:px|pt|em|ex|%)?|auto) ([.0-9]+(?:px|pt|em|ex|%)?|auto)$/i', $value, $regs)) {
+ $res['MARGIN-TOP'] = $regs[1];
+ $res['MARGIN-RIGHT'] = $regs[2];
+ $res['MARGIN-BOTTOM'] = $regs[1];
+ $res['MARGIN-LEFT'] = $regs[2];
+ }
+ if (preg_match('/^([.0-9]+(?:px|pt|em|ex|%)?|auto) ([.0-9]+(?:px|pt|em|ex|%)?|auto) ([.0-9]+(?:px|pt|em|ex|%)?|auto) ([.0-9]+(?:px|pt|em|ex|%)?|auto)$/i', $value, $regs)) {
+ $res['MARGIN-TOP'] = $regs[1];
+ $res['MARGIN-RIGHt'] = $regs[2];
+ $res['MARGIN-BOTTOM'] = $regs[3];
+ $res['MARGIN-LEFT'] = $regs[4];
+ }
+
+ break;
+ case 'BORDER-TOP':
+ case 'BORDER-RIGHT':
+ case 'BORDER-BOTTOM':
+ case 'BORDER-LEFT':
+ $parts = $this->ParseBorderShorthand($value);
+ if (isset($parts['style'])) {
+ $res[$property.'-STYLE'] = $parts['style'];
+ }
+ if (isset($parts['width'])) {
+ $res[$property.'-WIDTH'] = $parts['width'];
+ }
+ if (isset($parts['color'])) {
+ $res[$property.'-COLOR'] = $parts['color'];
+ }
+ break;
+ case 'BORDER':
+ $parts = $this->ParseBorderShorthand($value);
+ if (isset($parts['style'])) {
+ $res['BORDER-TOP-STYLE'] = $parts['style'];
+ $res['BORDER-RIGHT-STYLE'] = $parts['style'];
+ $res['BORDER-BOTTOM-STYLE'] = $parts['style'];
+ $res['BORDER-LEFT-STYLE'] = $parts['style'];
+ }
+ if (isset($parts['width'])) {
+ $res['BORDER-TOP-WIDTH'] = $parts['width'];
+ $res['BORDER-RIGHT-WIDTH'] = $parts['width'];
+ $res['BORDER-BOTTOM-WIDTH'] = $parts['width'];
+ $res['BORDER-LEFT-WIDTH'] = $parts['width'];
+ }
+ if (isset($parts['color'])) {
+ $res['BORDER-TOP-COLOR'] = $parts['color'];
+ $res['BORDER-RIGHT-COLOR'] = $parts['color'];
+ $res['BORDER-BOTTOM-COLOR'] = $parts['color'];
+ $res['BORDER-LEFT-COLOR'] = $parts['color'];
+ }
+ break;
+ case 'PADDING':
+ $parts = explode(' ', $value);
+ switch (count($parts)) {
+ case 1:
+ $res['PADDING-TOP'] = $parts[0];
+ $res['PADDING-RIGHT'] = $parts[0];
+ $res['PADDING-BOTTOM'] = $parts[0];
+ $res['PADDING-LEFT'] = $parts[0];
+ break;
+ case 2:
+ $res['PADDING-TOP'] = $parts[0];
+ $res['PADDING-RIGHT'] = $parts[1];
+ $res['PADDING-BOTTOM'] = $parts[0];
+ $res['PADDING-LEFT'] = $parts[1];
+ break;
+ case 3:
+ $res['PADDING-TOP'] = $parts[0];
+ $res['PADDING-RIGHT'] = $parts[1];
+ $res['PADDING-BOTTOM'] = $parts[2];
+ $res['PADDING-LEFT'] = $parts[1];
+ break;
+ case 4:
+ $res['PADDING-TOP'] = $parts[0];
+ $res['PADDING-RIGHT'] = $parts[1];
+ $res['PADDING-BOTTOM'] = $parts[2];
+ $res['PADDING-LEFT'] = $parts[3];
+ break;
+ }
+ break;
+ default:
+ $res[$property] = $value;
+ }
+ }
+ return $res;
+ }
+
+ public function ParseBorderShorthand($definition)
+ {
+ $res = array();
+ $parts = explode(' ', $definition);
+ foreach ($parts as $part) {
+ if (preg_match('/none|hidden|dotted|dashed|solid|double|groove|ridge|inset|outset/', $part)) { //style
+ $res['style'] = $part;
+ }
+ elseif (preg_match('/^(thin|medium|thick|[.0-9]+(?:px|pt|em|ex|%)?)/', $part)) { // width
+ $res['width'] = $part;
+ }
+ else { // color
+ $res['color'] = $part;
+ }
+ }
+ return $res;
+ }
+
+ public function ParseSelectorTokens($tokens, $origin)
+ {
+ $selectors = array();
+ $current = '';
+ foreach ($tokens as $token) {
+ if ($token['name'] == 'COMMA') {
+ $selectors[] = trim($current);
+ $current = '';
+ }
+ else {
+ $current .= $token['data'];
+ }
+ }
+ if (trim($current) != '') {
+ $selectors[] = trim($current);
+ }
+ return $this->IdentifySelectors($selectors, $origin);
+ }
+
+ /*
+
+ 'h' => '[0-9a-f]',
+ 'nonascii' => '[\\200-\\377]',
+ 'unicode' => '(\\{h}{1,6}(\r\n|[ \t\r\n\f])?)',
+ 'escape' => '(\\[^\r\n\f0-9a-f])',
+ 'nmstart' => '([_a-z]|{nonascii}|{escape})',
+ 'nmchar' => '([_a-z0-9-]|{nonascii}|{escape})',
+ 'string1' => '("([^\n\r\f"]|{nl}|{escape})*")',
+ 'string2' => '(\'([^\n\r\f\']|{nl}|{escape})*\')',
+ 'invalid1' => '("([^\n\r\f"]|{nl}|{escape})*?)',
+ 'invalid2' => '(\'([^\n\r\f\']|{nl}|{escape})*?)',
+
+ 'ident' => '-?{nmstart}{nmchar}*',
+ 'name' => '{nmchar}+',
+ 'num' => '([0-9]+|[0-9]*\.[0-9]+)',
+ 'string' => '({string1}|{string2})',
+ 'invalid' => '({invalid1}|{invalid2})',
+ 'url' => '([!#$%&*-~]|{nonascii}|{escape})*',
+ 's' => '[ \t\r\n\f]',
+ 'w' => '{s}*',
+ 'nl' => '(\n|\r\n|\r|\f)',
+
+ */
+
+ /*
+
+ A simple selector is either a type selector or universal selector followed immediately by zero or more attribute selectors, ID selectors,
+ or pseudo-classes, in any order. The simple selector matches if all of its components match.
+
+ A selector is a chain of one or more simple selectors separated by combinators. Combinators are: whitespace, ">", and "+".
+ Whitespace may appear between a combinator and the simple selectors around it.
+
+ A selector's specificity is calculated as follows:
+
+ * count 1 if the selector is a 'style' attribute rather than a selector, 0 otherwise (= a)
+ (In HTML, values of an element's "style" attribute are style sheet rules. These rules have no selectors, so a=1, b=0, c=0, and d=0.)
+ * count the number of ID attributes in the selector (= b)
+ * count the number of other attributes and pseudo-classes in the selector (= c)
+ * count the number of element names and pseudo-elements in the selector (= d)
+
+ The specificity is based only on the form of the selector.
+ In particular, a selector of the form "[id=p33]" is counted as an attribute selector (a=0, b=0, c=1, d=0),
+ even if the id attribute is defined as an "ID" in the source document's DTD.
+
+ Concatenating the four numbers a-b-c-d (in a number system with a large base) gives the specificity.
+
+ */
+
+ function IdentifySelectors($selectors, $origin)
+ {
+ $processed = array();
+ $ident = $this->Macros['ident'];
+
+ foreach ($selectors as $selector) {
+ $parts = preg_split('/[ ]*([ >+])[ ]*/', $selector, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $parsed_selector = array();
+ $a = 0;
+ $b = 0;
+ $c = 0;
+ $d = 0;
+ foreach ($parts as $simple_selector) {
+ $parsed_part = array();
+ if (preg_match('/^([ >+])$/', $simple_selector, $regs)) {
+ $parsed_part['combinator'] = $regs[1];
+ $parsed_selector[] = $parsed_part;
+ continue;
+ }
+ if (preg_match('/^(\*|'.$ident.')/i', $simple_selector, $regs)) {
+ $main = $regs[1];
+ if ($regs[1] != '*') {
+ $d++;
+ }
+ }
+ else {
+ $main = '*';
+ }
+ $parsed_part['main'] = strtoupper($main);
+ if (preg_match_all('/\.('.$ident.')/', $simple_selector, $regs)) {
+ $parsed_part['classes'] = $regs[1];
+ $c += count($regs[1]);
+ }
+ if (preg_match_all('/\[([^\]]+)\]/', $simple_selector, $regs)) {
+ $atts = $regs[1];
+ $c += count($regs[1]);
+ $parsed_atts = array();
+ foreach ($atts as $attribute) {
+ if (preg_match('/^[^=]+$/', $attribute)) {
+ $parsed_atts['set'][] = strtoupper($attribute);
+ }
+ elseif (preg_match('/(.*)\\|=(.*)/', $attribute, $att_regs)) {
+ $parsed_atts['hypen'][strtoupper($att_regs[1])] = $att_regs[2];
+ }
+ elseif (preg_match('/(.*)~=(.*)/', $attribute, $att_regs)) {
+ $parsed_atts['space'][strtoupper($att_regs[1])] = $att_regs[2];
+ }
+ elseif (preg_match('/(.*)=(.*)/', $attribute, $att_regs)) {
+ $parsed_atts['equals'][strtoupper($att_regs[1])] = $att_regs[2];
+ }
+ }
+ $parsed_part['atts'] = $parsed_atts;
+ }
+ if (preg_match_all('/#('.$ident.')/', $simple_selector, $regs)) {
+ $parsed_part['ids'] = $regs[1];
+ $b += count($regs[1]);
+ }
+ if (preg_match_all('/:('.$ident.')/', $simple_selector, $regs)) {
+ $pseudo_classes = array();
+ $pseudo_elements = array();
+ foreach ($regs[1] as $pseudo) {
+ if (preg_match('/^(first-line|first-letter|before|after)$/i', $pseudo)) {
+ $pseudo_elements[] = $pseudo;
+ }
+ else {
+ $pseudo_classes[] = $pseudo;
+ }
+ }
+ if ($pseudo_classes) {
+ $parsed_part['pseudo_classes'] = $pseudo_classes;
+ }
+ if ($pseudo_elements) {
+ $parsed_part['pseudo_elements'] = $pseudo_elements;
+ }
+ $c += count($pseudo_classes);
+ $d += count($pseudo_elements);
+ }
+ $parsed_selector[] = $parsed_part;
+ }
+ $parsed_selector = array_reverse($parsed_selector);
+
+ $main = array();
+ $cur =& $main;
+
+ foreach ($parsed_selector as $parts) {
+ if (isset($parts['combinator'])) {
+ switch ($parts['combinator']) {
+ case ' ':
+ $cur =& $cur['descendant_of'];
+ break;
+ case '>':
+ $cur =& $cur['child_of'];
+ break;
+ case '+':
+ $cur =& $cur['sibling_of'];
+ break;
+ }
+ continue;
+ }
+ $cur['main'] = $parts['main'];
+ if (isset($parts['classes'])) {
+ $cur['classes'] = $parts['classes'];
+ }
+ if (isset($parts['ids'])) {
+ $cur['ids'] = $parts['ids'];
+ }
+ if (isset($parts['pseudo_classes'])) {
+ $cur['pseudo_classes'] = $parts['pseudo_classes'];
+ }
+ if (isset($parts['pseudo_elements'])) {
+ $cur['pseudo_elements'] = $parts['pseudo_elements'];
+ }
+ if (isset($parts['atts'])) {
+ $cur['atts'] = $parts['atts'];
+ }
+ }
+ $main['specifity'] = intval(str_pad($a,2,0).str_pad($b,2,0).str_pad($c,2,0).str_pad($d,2,0));
+ $main['order'] = $this->SelectorOrder++;
+ $main['origin'] = $origin;
+ $processed[] = $main;
+ }
+ return $processed;
+ }
+
+ public function AppendRule($selector_tokens, $definition_tokens, $origin)
+ {
+ $selectors = $this->ParseSelectorTokens($selector_tokens, $origin);
+ $properties = $this->ParseDefinitionTokens($definition_tokens);
+ $definition = '';
+ foreach ($properties as $property => $value) {
+ $definition .= "<b>$property</b>: $value<br>";
+ }
+
+ foreach ($selectors as $selector) {
+ $this->Mapping[strtoupper($selector['main'])][] = array('selector' => $selector, 'properties' => $properties);
+ }
+
+ $this->Rules[] = array('selectors' => $selectors, 'properties' => $properties);
+// echo "appending rule:<br> selector: ".join(',', $selectors)."<br> definition:<br> $definition<br><br>";
+ }
+
+ public function GetTokens($css)
+ {
+ $patterns = array(
+ '{s}+' =>'S',
+
+ '<!--' =>'CDO',
+ '-->' =>'CDC',
+ '~=' =>'INCLUDES',
+ '\\|=' =>'DASHMATCH',
+
+ '{w}\\{' =>'LBRACE',
+ '{w}\\+' =>'PLUS',
+ '{w}\\>' =>'GREATER',
+ '{w},' =>'COMMA',
+
+ '{string}' =>'STRING',
+ '{invalid}' =>'INVALID', /* unclosed string */
+
+ '{ident}' =>'IDENT',
+
+ '#{name}' =>'HASH',
+
+ '@import' =>'IMPORT_SYM',
+ '@page' =>'PAGE_SYM',
+ '@media' =>'MEDIA_SYM',
+ '@charset' =>'CHARSET_SYM',
+
+ '!{w}important' =>'IMPORTANT_SYM',
+
+ /*'{num}{E}{M}' =>'EMS',
+ '{num}{E}{X}' =>'EXS',
+ '{num}{P}{X}' =>'LENGTH',
+ '{num}{C}{M}' =>'LENGTH',
+ '{num}{M}{M}' =>'LENGTH',
+ '{num}{I}{N}' =>'LENGTH',
+ '{num}{P}{T}' =>'LENGTH',
+ '{num}{P}{C}' =>'LENGTH',
+ '{num}{D}{E}{G}' =>'ANGLE',
+ '{num}{R}{A}{D}' =>'ANGLE',
+ '{num}{G}{R}{A}{D}' =>'ANGLE',
+ '{num}{M}{S}' =>'TIME',
+ '{num}{S}' =>'TIME',
+ '{num}{H}{Z}' =>'FREQ',
+ '{num}{K}{H}{Z}' =>'FREQ',
+ '{num}{ident}' =>'DIMENSION',*/
+
+ '{num}em' =>'EMS',
+ '{num}ex' =>'EXS',
+ '{num}px' =>'LENGTH',
+ '{num}cm' =>'LENGTH',
+ '{num}mm' =>'LENGTH',
+ '{num}in' =>'LENGTH',
+ '{num}pt' =>'LENGTH',
+ '{num}pc' =>'LENGTH',
+ '{num}deg' =>'ANGLE',
+ '{num}rad' =>'ANGLE',
+ '{num}grad' =>'ANGLE',
+ '{num}ms' =>'TIME',
+ '{num}s' =>'TIME',
+ '{num}hz' =>'FREQ',
+ '{num}khz' =>'FREQ',
+ '{num}{ident}' =>'DIMENSION',
+
+ '{num}%' =>'PERCENTAGE',
+ '{num}' =>'NUMBER',
+
+ 'url\({w}{string}{w}\)' =>'URI',
+ 'url\({w}{url}{w}\)' =>'URI',
+ '{ident}\(' =>'FUNCTION',
+
+ /*'.' =>'*yytext',*/
+ );
+
+ $final_patterns = array();
+ foreach ($patterns as $regexp => $token) {
+ foreach ($this->Macros as $macro => $replacement) {
+ $regexp = str_replace('{'.$macro.'}', $replacement, $regexp);
+ }
+ $final_patterns[$regexp] = $token;
+ }
+
+ $css = preg_replace('/\\/\\*[^*]*\\*+([^\\/*][^*]*\\*+)*\\//', '', $css);
+ $css = preg_replace('/[ \t\r\n\f]+\\/\\*[^*]*\\*+([^\\/*][^*]*\\*+)*\\//', ' ', $css);
+
+ $css = preg_replace('/[ \t\r\n\f]+/', ' ', $css); // remove repeated whitespace
+
+ $matches = array();
+ $token_indexes = array();
+ foreach ($final_patterns as $regexp => $token) {
+ if (preg_match_all('/'.$regexp.'/i', $css, $res, PREG_PATTERN_ORDER | PREG_OFFSET_CAPTURE)) {
+ $matches[$token] = $res[0];
+ $token_indexes[$token] = 0;
+ }
+ }
+
+ $tokens = array();
+ $last_token_pos = 0;
+ $i = 0;
+ do {
+ $has_more = false;
+ $max_len = 0;
+ $min_pos = false;
+ foreach ($matches as $token => $data)
+ {
+ $cur_index = $token_indexes[$token];
+ do {
+ $cur_match = isset($data[$cur_index]) ? $data[$cur_index++] : false;
+ } while ($cur_match && $cur_match[1] < $last_token_pos);
+ if ( !$cur_match ) continue;
+ $token_indexes[$token] = $cur_index-1;
+ if ( $min_pos === false ||
+ ($cur_match[1] < $min_pos
+ ||
+ ( $cur_match[1] == $min_pos && strlen( $cur_match[0] ) > $max_len )
+ )
+ ) {
+ $longest = $token;
+ $max_len = strlen( $cur_match[0] );
+ $min_pos = $cur_match[1];
+ }
+ $has_more = $has_more || isset($data[$token_indexes[$token]]);
+ }
+ if ($min_pos !== false) {
+ $token_data = $matches[$longest][$token_indexes[$longest]];
+ if ($token_data[1] > $last_token_pos) {
+ $text_data = substr($css, $last_token_pos, $token_data[1] - $last_token_pos);
+ $tokens[] = array('name' => 'TEXT', 'data' => $text_data);
+// echo "found token TEXT: [$text_data]<br>\n";
+ }
+ $tokens[] = array('name' => $longest, 'data' => $token_data[0]);
+// echo "found token $longest: {$token_data[0]} at {$token_data[1]}<br>\n";
+// flush();
+ $last_token_pos = $token_data[1] + strlen($token_data[0]);
+ $token_indexes[$longest]++;
+ }
+ } while ($has_more);
+ if ($last_token_pos <= strlen($css)) {
+ $text_data = substr($css, $last_token_pos);
+ $tokens[] = array('name' => 'TEXT', 'data' => $text_data);
+// echo "found token FINAL TEXT: [$text_data]<br>\n";
+ }
+
+ return $tokens;
+ }
+
+ public function Prepare()
+ {
+ /*$macros = array(
+ 'h' => '[0-9a-f]',
+ 'nonascii' => '[\200-\377]',
+ 'unicode' => '(\\{h}{1,6}(\r\n|[ \t\r\n\f])?)',
+ 'escape' => '({unicode}|\\[^\r\n\f0-9a-f])',
+ 'nmstart' => '([_a-z]|{nonascii}|{escape})',
+ 'nmchar' => '([_a-z0-9-]|{nonascii}|{escape})',
+ 'string1' => '("([^\n\r\f"]|{nl}|{escape})*")',
+ 'string2' => '(\'([^\n\r\f\']|{nl}|{escape})*\')',
+ 'invalid1' => '("([^\n\r\f"]|{nl}|{escape})*?)',
+ 'invalid2' => '(\'([^\n\r\f\']|{nl}|{escape})*?)',
+
+ 'ident' => '-?{nmstart}{nmchar}*',
+ 'name' => '{nmchar}+',
+ 'num' => '([0-9]+|[0-9]*\.[0-9]+)',
+ 'string' => '({string1}|{string2})',
+ 'invalid' => '({invalid1}|{invalid2})',
+ 'url' => '([!#$%&*-~]|{nonascii}|{escape})*',
+ 's' => '[ \t\r\n\f]',
+ 'w' => '{s}*',
+ 'nl' => '(\n|\r\n|\r|\f)',
+
+ 'A' => 'a|\\0{0,4}(41|61)(\r\n|[ \t\r\n\f])?',
+ 'C' => 'c|\\0{0,4}(43|63)(\r\n|[ \t\r\n\f])?',
+ 'D' => 'd|\\0{0,4}(44|64)(\r\n|[ \t\r\n\f])?',
+ 'E' => 'e|\\0{0,4}(45|65)(\r\n|[ \t\r\n\f])?',
+ 'G' => 'g|\\0{0,4}(47|67)(\r\n|[ \t\r\n\f])?|\\g',
+ 'H' => 'h|\\0{0,4}(48|68)(\r\n|[ \t\r\n\f])?|\\h',
+ 'I' => 'i|\\0{0,4}(49|69)(\r\n|[ \t\r\n\f])?|\\i',
+ 'K' => 'k|\\0{0,4}(4b|6b)(\r\n|[ \t\r\n\f])?|\\k',
+ 'M' => 'm|\\0{0,4}(4d|6d)(\r\n|[ \t\r\n\f])?|\\m',
+ 'N' => 'n|\\0{0,4}(4e|6e)(\r\n|[ \t\r\n\f])?|\\n',
+ 'P' => 'p|\\0{0,4}(50|70)(\r\n|[ \t\r\n\f])?|\\p',
+ 'R' => 'r|\\0{0,4}(52|72)(\r\n|[ \t\r\n\f])?|\\r',
+ 'S' => 's|\\0{0,4}(53|73)(\r\n|[ \t\r\n\f])?|\\s',
+ 'T' => 't|\\0{0,4}(54|74)(\r\n|[ \t\r\n\f])?|\\t',
+ 'X' => 'x|\\0{0,4}(58|78)(\r\n|[ \t\r\n\f])?|\\x',
+ 'Z' => 'z|\\0{0,4}(5a|7a)(\r\n|[ \t\r\n\f])?|\\z',
+ );*/
+
+ $simple = array(
+ 'h' => '[0-9a-f]',
+ 'nonascii' => '[\\200-\\377]',
+ 'unicode' => '(\\{h}{1,6}(\r\n|[ \t\r\n\f])?)',
+ 'escape' => '(\\[^\r\n\f0-9a-f])',
+ 'nmstart' => '([_a-z]|{nonascii}|{escape})',
+ 'nmchar' => '([_a-z0-9-]|{nonascii}|{escape})',
+ 'string1' => '("([^\n\r\f"]|{nl}|{escape})*")',
+ 'string2' => '(\'([^\n\r\f\']|{nl}|{escape})*\')',
+ 'invalid1' => '("([^\n\r\f"]|{nl}|{escape})*?)',
+ 'invalid2' => '(\'([^\n\r\f\']|{nl}|{escape})*?)',
+
+ 'ident' => '-?{nmstart}{nmchar}*',
+ 'name' => '{nmchar}+',
+ 'num' => '([0-9]+|[0-9]*\.[0-9]+)',
+ 'string' => '({string1}|{string2})',
+ 'invalid' => '({invalid1}|{invalid2})',
+ 'url' => '([!#$%&*-~]|{nonascii}|{escape})*',
+ 's' => '[ \t\r\n\f]',
+ 'w' => '{s}*',
+ 'nl' => '(\n|\r\n|\r|\f)',
+ );
+ $replaced_macros = array();
+ foreach ($simple as $key => $macro) {
+ $replaced = $macro;
+ foreach ($replaced_macros as $shorthand => $replacement) {
+ $replaced = str_replace('{'.$shorthand.'}', $replacement, $replaced);
+ }
+ $replaced_macros[$key] = $replaced;
+ }
+
+ $this->Macros = $replaced_macros;
+ }
+
+
+ public function GetHTMLVisualPropsSelector($node)
+ {
+ if (!$node->Attributes) return false;
+ $non_visal_props = array(
+ 'ABBR', 'ACCEPT-CHARSET', 'ACCEPT', 'ACCESSKEY', 'ACTION', 'ALT', 'ARCHIVE', 'AXIS', 'CHARSET', 'CHECKED', 'CITE', 'CLASS', 'CLASSID', 'CODE', 'CODEBASE',
+ 'CODETYPE', 'COLSPAN', 'COORDS', 'DATA', 'DATETIME', 'DECLARE', 'DEFER', 'DIR', 'DISABLED', 'ENCTYPE', 'FOR', 'HEADERS', 'HREF', 'HREFLANG', 'HTTP-EQUIV',
+ 'ID', 'ISMAP', 'LABEL', 'LANG', 'LANGUAGE', 'LONGDESC', 'MAXLENGTH', 'MEDIA', 'METHOD', 'MULTIPLE', 'NAME', 'NOHREF', 'OBJECT', 'ONBLUR', 'ONCHANGE',
+ 'ONCLICK', 'ONDBLCLICK', 'ONFOCUS', 'ONKEYDOWN', 'ONKEYPRESS', 'ONKEYUP', 'ONLOAD', 'ONLOAD', 'ONMOUSEDOWN', 'ONMOUSEMOVE', 'ONMOUSEOUT', 'ONMOUSEOVER',
+ 'ONMOUSEUP', 'ONRESET', 'ONSELECT', 'ONSUBMIT', 'ONUNLOAD', 'ONUNLOAD', 'PROFILE', 'PROMPT', 'READONLY', 'REL', 'REV', 'ROWSPAN', 'SCHEME', 'SCOPE',
+ 'SELECTED', 'SHAPE', 'SPAN', 'SRC', 'STANDBY', 'START', 'STYLE', 'SUMMARY', 'TITLE', 'USEMAP',
+ 'VALUE', 'VALUETYPE', 'VERSION',
+ );
+ if ($node->Name != 'LI' && $node->Name != 'OL' && $node->Name != 'UL') {
+ array_push($non_visal_props, 'TYPE');
+ }
+ $visual_attributes = array_diff_key($node->Attributes, array_combine($non_visal_props, array_fill(0, count($non_visal_props), '')));
+ if ($visual_attributes) {
+ $mapping = array(
+ 'ALIGN' => 'TEXT-ALIGN',
+ 'VALIGN' => 'VERTICAL-ALIGN',
+ 'CELLPADDING' => 'PADDING',
+ );
+ $mapped_attributes = array();
+ foreach ($visual_attributes as $key => $val) {
+ if ($key == 'CELLPADDING') {
+ $processed = $this->IdentifySelectors( array( $node->Name.'[cellpadding='.$val.'] TD' ), kPDFStylesheet::STYLE_ORIGIN_AUTHOR_NORMAL );
+ $processed[0]['order'] = $this->HTMLVisualPropsSelectorOrder++;
+ $processed[0]['specifity'] = 0;
+ $this->Mapping['TD'][] = array(
+ 'selector' => $processed[0],
+ 'properties' => $this->ProcessShortHands(array(
+ 'PADDING' => $val.'px',
+ )));
+ }
+ elseif (isset($mapping[$key])) {
+ $mapped_attributes[$mapping[$key]] = $val;
+ }
+ else {
+ $mapped_attributes[$key] = $val;
+ }
+ }
+
+ return array(
+ 'selector' => array('main' => $node->Name, 'specifity' => 0, 'order' => $this->HTMLVisualPropsSelectorOrder, 'origin' => kPDFStylesheet::STYLE_ORIGIN_AUTHOR_NORMAL ),
+ 'properties' => $mapped_attributes,
+ );
+ }
+ return false;
+ }
+
+ public function GetMatchingSelectors($node)
+ {
+ $map = isset($this->Mapping[$node->Name]) ? $this->Mapping[$node->Name] : array();
+ if (isset($this->Mapping['*'])) {
+ $map = array_merge($map, $this->Mapping['*']);
+ }
+
+ $matching = array();
+ $i = 0;
+ foreach ($map as $selector) {
+ $selector_data = $selector['selector'];
+ if ($this->SelectorMatches($selector['selector'], $node)) {
+ $matching[] = $selector;
+ }
+ }
+
+ $html_visual_selector = $this->GetHTMLVisualPropsSelector($node);
+ if ($html_visual_selector) {
+ $matching[] = $html_visual_selector;
+ }
+
+ usort($matching, array($this, 'CmpSelectors'));
+
+ if (isset($node->Attributes['STYLE'])) {
+ $style_selector = array(
+ 'selector' => array('main' => '_STYLE_'),
+ 'properties' => $this->ParseDefinitionTokens ( $this->GetTokens( $node->Attributes['STYLE'] ) ),
+ );
+ $matching[] = $style_selector;
+ }
+
+ return $matching;
+ }
+
+ public function CmpSelectors($a, $b)
+ {
+ if ($a['selector']['origin'] == $b['selector']['origin']) {
+ if ($a['selector']['specifity'] == $b['selector']['specifity']) {
+ return $a['selector']['order'] < $b['selector']['order'] ? -1 : 1;
+ }
+ return ($a['selector']['specifity'] < $b['selector']['specifity']) ? -1 : 1;
+ }
+ return $a['selector']['origin'] < $b['selector']['origin'] ? -1 : 1;
+ }
+
+ public function SelectorMatches($selector_data, $node)
+ {
+ if ($selector_data['main'] != '*' && $node->Name != $selector_data['main']) {
+ return false;
+ }
+
+ //check classes
+ if (isset($selector_data['classes'])) {
+ foreach ($selector_data['classes'] as $class) {
+ // (\A| )+foo( |\Z)+
+ if (!isset($node->Attributes['CLASS']) || !preg_match('/(\A| )+'.preg_quote($class).'( |\Z)+/i', $node->Attributes['CLASS'])) {
+ return false;
+ }
+ }
+ }
+
+ //check ids
+ if (isset($selector_data['ids'])) {
+ if (!isset($node->Attributes['ID']) || !in_array($node->Attributes['ID'], $selector_data['ids'])) {
+ return false;;
+ }
+ }
+
+ //check atts
+ if (isset($selector_data['atts'])) {
+ if (isset($selector_data['atts']['set'])) {
+ foreach ($selector_data['atts']['set'] as $att) {
+ if (!isset($node->Attributes[$att])) {
+ return false;;
+ }
+ }
+ }
+ if (isset($selector_data['atts']['equals'])) {
+ foreach ($selector_data['atts']['equals'] as $att => $value) {
+ if (!isset($node->Attributes[$att]) || strtoupper($node->Attributes[$att]) != strtoupper($value)) {
+ return false;;
+ }
+ }
+ }
+ if (isset($selector_data['atts']['space'])) {
+ foreach ($selector_data['atts']['space'] as $att => $value) {
+ if (!isset($node->Attributes[$att]) || !preg_match('/(\A| )+'.preg_quote($value).'( |\Z)+/i', $node->Attributes[$att])) {
+ return false;;
+ }
+ }
+ }
+ if (isset($selector_data['atts']['hypen'])) {
+ foreach ($selector_data['atts']['hypen'] as $att => $value) {
+ if (!isset($node->Attributes[$att]) || !preg_match('/^'.preg_quote($value).'(-|\Z)+/i', $node->Attributes[$att])) {
+ return false;;
+ }
+ }
+ }
+ }
+
+ //check pseudo
+ if (isset($selector_data['pseudo_elements'])) {
+ // we are not a browser - so don't know how to handle this....
+ return false;
+ }
+
+ if (isset($selector_data['pseudo_classes'])) {
+ // we are not a browser - so don't know how to handle this....
+ return false;
+ }
+
+ //check comibantors
+ if (isset($selector_data['child_of'])) {
+ if (!$this->SelectorMatches($selector_data['child_of'], $node->Parent)) {
+ return false;
+ }
+ }
+
+ if (isset($selector_data['sibling_of'])) {
+ if (!$this->SelectorMatches($selector_data['sibling_of'], $node->PrevSibling())) {
+ return false;
+ }
+ }
+
+ if (isset($selector_data['descendant_of'])) {
+ $ancestor = $node;
+ do {
+ $ancestor = $ancestor->Parent;
+ $matches = $this->SelectorMatches($selector_data['descendant_of'], $ancestor);
+ } while (!$matches && $ancestor->Parent);
+ if (!$matches) return false;
+ }
+
+ // if we came through here, the selector matches the node
+ return true;
+ }
+
+ public function GetAllProperties($node)
+ {
+ $selectors = $this->GetMatchingSelectors($node);
+ $properties = array();
+ foreach ($selectors as $the_selector) {
+ $properties = array_merge($properties, $the_selector['properties']);
+ /*foreach ($the_selector['properties'] as $property => $value) {
+ $properties[$property] = $value; //process !important here ?? !!!
+ }*/
+ }
+ return $properties;
+ }
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/pdf_styles.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_text.php
===================================================================
--- branches/RC/core/units/pdf/pdf_text.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_text.php (revision 10294)
@@ -0,0 +1,246 @@
+<?php
+
+class kPDFTextElement extends kPDFElement {
+ protected $Data;
+ public $Ascent;
+ public $Descent;
+ public $Gap;
+
+ public $ContentMinWidth;
+ public $ContentMaxWidht;
+
+ function __construct($data='', $node, $helper)
+ {
+ parent::__construct($node, $helper);
+ $this->SetData($data, 0);
+ }
+
+ function SetData($data)
+ {
+ $this->Data = $data;
+ }
+
+ function Init()
+ {
+ parent::Init();
+ $this->SetCSSProperty('display', 'inline');
+ }
+
+ function ComputeCSSProperties()
+ {
+ parent::ComputeCSSProperties();
+ // http://manual.prod.intechnic.lv/css21/text.html#q8
+
+ $whitespace = str_replace('-', '', $this->GetCSSProperty('white-space')); // remove "-" to avoid confusion
+ if ($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline') {
+ $this->Data = preg_replace('/[\n]{1}[\t\\r ]{1}|[\t\\r ]{1}[\n]{1}/', "\n", $this->Data);
+ }
+ if ($whitespace == 'pre' || $whitespace == 'prewrap') {
+ $this->Data = preg_replace('/ /', '&nbsp;', $this->Data);
+ }
+ if ($whitespace == 'normal' || $whitespace == 'nowrap') {
+ $this->Data = preg_replace('/[\r\n]/', ' ', $this->Data);
+ }
+ if ($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline') {
+ $this->Data = preg_replace('/\t/', ' ', $this->Data);
+ $this->Data = preg_replace('/ [ ]+/', ' ', $this->Data);
+ }
+
+ $transform = $this->GetCSSProperty('text-transform');
+ if ($transform == 'uppercase') {
+ $this->Data = strtoupper($this->Data);
+ }
+ if ($transform == 'lowercase') {
+ $this->Data = strtolower($this->Data);
+ }
+ if ($transform == 'capitalize') {
+ $this->Data = ucwords($this->Data);
+ }
+ }
+
+ function CheckDimensions()
+ {
+ $font_size = $this->GetCSSProperty('font-size');
+ $this->Helper->PDF->SetFont( $this->GetCSSProperty('font-family'), $font_size, $this->GetCSSProperty('font-weight'), $this->GetCSSProperty('font-style'), $this->GetCSSProperty('font-variant'));
+ $this->Ascent = $this->Helper->PDF->GetAscent();
+ $this->Descent = -$this->Helper->PDF->GetDescent(); // ((-$font->getDescent() / $units) * $size);
+ $this->Gap = $this->Helper->PDF->GetLineGap(); // (($font->getLineGap() / $units) * $size);
+
+ // proportionally fit ascent & descent into font-size. Wiered why they are greater...
+ if ($this->Ascent + $this->Descent > $font_size) {
+ $this->Ascent = $this->Ascent/($this->Ascent+$this->Descent)*$font_size;
+ $this->Descent = $this->Descent/($this->Ascent+$this->Descent)*$font_size;
+ }
+
+ if ($this->Helper->DimensionsMode == kPDFHelper::DM_SKIP) {
+ return ;
+ }
+
+ if ($this->Node->Name == 'BR') {
+ $this->ContentHeight = $this->Ascent + $this->Descent + $this->Gap;
+ $this->SetCSSProperty('height', $this->ContentHeight);
+ $this->NextLine('');
+ $this->GetLineBox()->Closed();
+ return ;
+ }
+
+ $whitespace = str_replace('-', '', $this->GetCSSProperty('white-space')); // remove "-" to avoid confusion
+
+ if (!$this->Data) {
+ parent::CheckDimensions();
+ return;
+ }
+
+ $this->Wrap2($whitespace);
+
+ $this->GetLineBox()->Closed();
+ parent::CheckDimensions();
+ }
+
+ function CalcMinMaxContentWidth()
+ {
+ $font_size = $this->GetCSSProperty('font-size');
+ $this->Helper->PDF->SetFont( $this->GetCSSProperty('font-family'), $font_size, $this->GetCSSProperty('font-weight'), $this->GetCSSProperty('font-style'), $this->GetCSSProperty('font-variant'));
+ $data = $this->Data;
+ $this->MaxContentWidth = ceil($this->Helper->PDF->GetStringWidth($data));
+ $words = preg_split('/([ \[\]\+\(\)]{1})/u', $data, null, PREG_SPLIT_NO_EMPTY);
+ $min_w = $this->MaxContentWidth;
+ foreach ($words as $word) {
+ $word_w = ceil($this->Helper->PDF->GetStringWidth($word));
+ if ($word_w < $min_w) {
+ $min_w = $word_w;
+ }
+ }
+ $this->MinContentWidth = $min_w;
+ parent::CalcMinMaxContentWidth();
+ }
+
+ function Wrap2($whitespace) {
+ $start = $this->GetLineBox()->CurX;
+
+ $data = $this->Data;
+
+ if ($this->Parent->FirstChild === $this && ($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline')) {
+ $data = ltrim($data);
+ }
+
+ $words = preg_split('/([ \[\]\+\(\)]{1})/u', $data, null, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+ $words_count = count($words);
+ $i = 0;
+ $elem_w = 0;
+ $max_width = $this->GetLineBox()->GetCSSProperty('width');
+ $line_break = false;
+ while ($i < $words_count) {
+ $word_w = $this->Helper->PDF->GetStringWidth($words[$i]);
+ if ( (floor($max_width - $start - $elem_w - $word_w) < 0) && ($i > 0 || $start > 0) ) {
+ $line_break = true;
+ break;
+ }
+ $elem_w += $word_w;
+ $i++;
+ }
+ // remove space at the end of line
+ // @todo Find a way to detect a space at the end of last line, which is NOT wrapped
+ // otherwise right-aligned blocks will have a space at the end of last line
+ if ( $words[$i-1] == ' ' && $line_break &&
+ ($whitespace == 'normal' || $whitespace == 'nowrap' || $whitespace == 'preline')
+ ) {
+ $i--;
+ $elem_w -= $this->Helper->PDF->GetStringWidth($words[$i]);
+ array_splice($words, $i, 1);
+ }
+ $this->Data = join( array_splice($words, 0, $i) ); //$i here is the number of last word (starting with 0) + 1, so it's fine for splice
+ if (!$this->Data) { // nothing fitted on current line
+ $this->Ascent = 0;
+ $this->Descent = 0;
+ $this->Gap = 0;
+ $this->NextLine(join( $words ));
+ }
+ else {
+ $h = $this->Ascent + $this->Descent + $this->Gap;
+ $elem = $this;
+ if (preg_match_all('/( )/', $this->Data, $regs, PREG_PATTERN_ORDER)) {
+ $spacers = count($regs[1]);
+ }
+ else {
+ $spacers = 0;
+ }
+ do {
+ $elem->SetCSSProperty('width', $elem->GetCSSProperty('width') + $elem_w);
+ $elem->Spacers = $elem->Spacers + $spacers;
+ $elem->ContentHeight = $h;
+ $elem->SetCSSProperty('height', $h);
+ $elem = $elem->Parent;
+ } while ($elem && $elem->GetDisplayLevel() == 'inline');
+ $elem->Spacers += $spacers;
+ $this->GetLineBox()->CurX = $start + $elem_w;
+
+ if ($i < $words_count) {
+ $this->NextLine(join( $words ));
+ }
+ }
+ }
+
+ function GetFollowingSiblings()
+ {
+ $cur_line = $this->GetLineBox();
+ $elem = $this;
+ $cur_pos = 0;
+ do {
+ $cur_pos = $elem->Position;
+ $elem = $elem->Parent;
+ } while ( $elem && !($elem instanceof kPDFLine) );
+ return $cur_line->RemoveChildren($cur_pos+1);
+ }
+
+ function CreateNextLine()
+ {
+ $cur_line = $this->GetLineBox();
+ $cur_line->Closed();
+ if ($this->Node->Name != 'BR') $cur_line->LastLine = false;
+ return $cur_line->Parent->AddChild( new kPDFLine($cur_line->Parent->Node, $this->Helper), true, $cur_line);
+ }
+
+ function NextLine($words)
+ {
+ $removed = $this->GetFollowingSiblings();
+ $next_line = $this->CreateNextLine();
+ if ($words) {
+ $new_elem = $next_line->AddChild( new kPDFTextElement( $words, $this->Node, $this->Helper ));
+ $new_elem->Closed();
+ }
+
+ foreach ($removed as $elem) {
+ $next_line->AddChild( $elem, false ); //don't init
+ }
+ }
+
+ function DrawAt($page, $x, $y, $spacer_w=0)
+ {
+ $page->SetLineWidth(0.1);
+
+ $y += $this->Ascent; //finding baseline
+ $this->Helper->PDF->SetFont( $this->GetCSSProperty('font-family'), $this->GetCSSProperty('font-size'), $this->GetCSSProperty('font-weight'), $this->GetCSSProperty('font-style'), $this->GetCSSProperty('font-variant'));
+ if ($color = $this->GetCSSProperty('color')) {
+ $page->SetFillColor($color);
+ }
+
+ if (defined('PDF_DEBUG_NO_TEXT')) return ;
+ if ($spacer_w == 0) {
+ $data = preg_replace('/\xA0/u', ' ', $this->Data);
+ $page->drawText($data, $x, $y);
+ }
+ else {
+ $spacer_w += $page->GetStringWidth(' ');
+ $words = explode(' ', $this->Data);
+ foreach ($words as $word) {
+ $word = preg_replace('/\xA0/u', ' ', $word);
+ $page->drawText($word, $x, $y);
+ $x += $page->GetStringWidth($word);
+ $x += $spacer_w;
+ }
+ }
+ $this->CurX = $x;
+ }
+
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/pdf_text.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_config.php
===================================================================
--- branches/RC/core/units/pdf/pdf_config.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_config.php (revision 10294)
@@ -0,0 +1,10 @@
+<?php
+
+ $config = Array(
+ 'Prefix' => 'pdf',
+ 'EventHandlerClass' => Array('class' => 'kEventHandler', 'file' => '', 'build_event' => 'OnBuild'),
+
+ 'RegisterClasses' => Array(
+ Array('pseudo'=>'PDFHelper','class'=>'kPDFHelper','file'=>'pdf_helper.php','build_event'=>'','require_classes'=>'kHelper'),
+ ),
+ );
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/pdf_config.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/css_defaults.php
===================================================================
--- branches/RC/core/units/pdf/css_defaults.php (nonexistent)
+++ branches/RC/core/units/pdf/css_defaults.php (revision 10294)
@@ -0,0 +1,652 @@
+<?php
+
+class kCSSDefaults {
+ public static $DEFAULT_STYLE =
+ 'html, address,
+ blockquote,
+ body, dd, div,
+ dl, dt, fieldset, form,
+ frame, frameset,
+ h1, h2, h3, h4,
+ h5, h6, noframes,
+ ol, p, ul, center,
+ dir, hr, menu, pre, footer { display: block }
+ li { display: list-item }
+ head { display: none }
+ table { display: table }
+ tr { display: table-row }
+ thead { display: table-header-group }
+ tbody { display: table-row-group }
+ tfoot { display: table-footer-group }
+ col { display: table-column }
+ colgroup { display: table-column-group }
+ td, th { display: table-cell }
+ caption { display: table-caption }
+ th { font-weight: bolder; text-align: center }
+ caption { text-align: center }
+ body { margin: 8px }
+
+ h1 { font-size: 2em; margin: .67em 0 }
+ h2 { font-size: 1.5em; margin: .75em 0 }
+ h3 { font-size: 1.17em; margin: .83em 0 }
+ h4, p,
+ blockquote, ul,
+ fieldset, form,
+ ol, dl, dir,
+ menu { margin: 1.12em 0 }
+ h5 { font-size: .83em; margin: 1.5em 0 }
+ h6 { font-size: .75em; margin: 1.67em 0 }
+ h1, h2, h3, h4,
+ h5, h6, b,
+ strong { font-weight: bolder }
+ blockquote { margin-left: 40px; margin-right: 40px }
+ i, cite, em,
+ var, address { font-style: italic }
+ pre, tt, code,
+ kbd, samp { font-family: monospace }
+ pre { white-space: pre }
+ button, textarea,
+ input, select { display: inline-block }
+ big { font-size: 1.17em }
+ small, sub, sup { font-size: .83em }
+ sub { vertical-align: sub }
+ sup { vertical-align: super }
+ table { border-spacing: 2px; }
+ thead, tbody,
+ tfoot { vertical-align: middle }
+ td, th { vertical-align: middle }
+ s, strike, del { text-decoration: line-through }
+ hr { border: 1px inset; }
+ ol, ul, dir,
+ menu, dd { margin-left: 40px }
+ ol { list-style-type: decimal }
+ ol ul, ul ol,
+ ul ul, ol ol { margin-top: 0; margin-bottom: 0 }
+ u, ins { text-decoration: underline }
+ br:before { content: "\A" }
+ :before, :after { white-space: pre-line }
+ center { text-align: center }
+ :link, :visited { text-decoration: underline }
+ :focus { outline: thin dotted invert }
+
+ /* Begin bidirectionality settings (do not change) */
+ BDO[DIR="ltr"] { direction: ltr; unicode-bidi: bidi-override }
+ BDO[DIR="rtl"] { direction: rtl; unicode-bidi: bidi-override }
+
+ *[DIR="ltr"] { direction: ltr; unicode-bidi: embed }
+ *[DIR="rtl"] { direction: rtl; unicode-bidi: embed }
+
+ /*@media print {
+ h1 { page-break-before: always }
+ h1, h2, h3,
+ h4, h5, h6 { page-break-after: avoid }
+ ul, ol, dl { page-break-before: avoid }
+ }*/';
+
+ public static $CSS_PROPERTIES = array(
+ 'BACKGROUND-ATTACHMENT' => array(
+ 'initial' =>'scroll',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BACKGROUND-COLOR' => array(
+ 'initial' =>'transparent',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BACKGROUND-IMAGE' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BACKGROUND-POSITION' => array(
+ 'initial' =>'0% 0%',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => 'refer to the size of the box itself'
+ ),
+ 'BACKGROUND-REPEAT' => array(
+ 'initial' =>'repeat',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BACKGROUND' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => 'allowed on background-position'
+ ),
+ 'BORDER-COLLAPSE' => array(
+ 'initial' =>'separate',
+ 'applies' => 'table and inline-table elements',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'BORDER-COLOR' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-SPACING' => array(
+ 'initial' =>'0',
+ 'applies' => 'table and inline-table elements�',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'BORDER-STYLE' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-TOP-COLOR' => array(
+ 'initial' =>'black',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-RIGHT-COLOR' => array(
+ 'initial' =>'black',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-BOTTOM-COLOR' => array(
+ 'initial' =>'black',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-LEFT-COLOR' => array(
+ 'initial' =>'black',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-TOP-STYLE' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-RIGHT-STYLE' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-BOTTOM-STYLE' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-LEFT-STYLE' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-TOP-WIDTH' => array(
+ 'initial' =>'medium',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-RIGHT-WIDTH' => array(
+ 'initial' =>'medium',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-BOTTOM-WIDTH' => array(
+ 'initial' =>'medium',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-LEFT-WIDTH' => array(
+ 'initial' =>'medium',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER-WIDTH' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BORDER' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'BOTTOM' => array(
+ 'initial' =>'auto',
+ 'applies' => 'positioned elements',
+ 'inherited' => false,
+ 'percentages' => 'refer to height of containing block'
+ ),
+ 'CAPTION-SIDE' => array(
+ 'initial' =>'top',
+ 'applies' => 'table-caption elements',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'CLEAR' => array(
+ 'initial' =>'none',
+ 'applies' => 'block-level elements',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'CLIP' => array(
+ 'initial' =>'auto',
+ 'applies' => 'absolutely positioned elements',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'COLOR' => array(
+ 'initial' =>'black',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'CONTENT' => array(
+ 'initial' =>'normal',
+ 'applies' => ':before and :after pseudo-elements',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'COUNTER-INCREMENT' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'COUNTER-RESET' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'CURSOR' => array(
+ 'initial' =>'auto',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'DIRECTION' => array(
+ 'initial' =>'ltr',
+ 'applies' => '"all elements, but see prose"',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'DISPLAY' => array(
+ 'initial' =>'inline',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'EMPTY-CELLS' => array(
+ 'initial' =>'show',
+ 'applies' => 'table-cell elements',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'FLOAT' => array(
+ 'initial' =>'none',
+ 'applies' => '"all, but see 9.7"',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'FONT-FAMILY' => array(
+ 'initial' =>'helvetica',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'FONT-SIZE' => array(
+ 'initial' => '10', //'medium',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => 'refer to parent element\'s font size'
+ ),
+ 'FONT-STYLE' => array(
+ 'initial' =>'normal',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'FONT-VARIANT' => array(
+ 'initial' =>'normal',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'FONT-WEIGHT' => array(
+ 'initial' =>'normal',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'FONT' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => 'see individual properties'
+ ),
+ 'HEIGHT' => array(
+ 'initial' =>'auto',
+ 'applies' => '"all elements but non-replaced inline elements, table columns, and column groups"',
+ 'inherited' => false,
+ 'percentages' => 'see prose'
+ ),
+ 'LEFT' => array(
+ 'initial' =>'auto',
+ 'applies' => 'positioned elements',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'LETTER-SPACING' => array(
+ 'initial' =>'normal',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'LINE-HEIGHT' => array(
+ 'initial' =>'normal',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => 'refer to the font size of the element itself'
+ ),
+ 'LIST-STYLE-IMAGE' => array(
+ 'initial' =>'none',
+ 'applies' => 'elements with display: list-item',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'LIST-STYLE-POSITION' => array(
+ 'initial' =>'outside',
+ 'applies' => 'elements with display: list-item',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'LIST-STYLE-TYPE' => array(
+ 'initial' =>'disc',
+ 'applies' => 'elements with display: list-item',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'LIST-STYLE' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => 'elements with display: list-item',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'MARGIN-RIGHT' => array(
+ 'initial' =>'0',
+ 'applies' => 'all elements except elements with table display types other than table and inline-table',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'MARGIN-LEFT' => array(
+ 'initial' =>'0',
+ 'applies' => 'all elements except elements with table display types other than table and inline-table',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'MARGIN-TOP' => array(
+ 'initial' =>'0',
+ 'applies' => 'all elements except elements with table display types other than table and inline-table',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'MARGIN-BOTTOM' => array(
+ 'initial' =>'0',
+ 'applies' => 'all elements except elements with table display types other than table and inline-table',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'MARGIN' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => 'all elements except elements with table display types other than table and inline-table',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'MAX-HEIGHT' => array(
+ 'initial' =>'none',
+ 'applies' => '"all elements but non-replaced inline elements, table columns, and column groups"',
+ 'inherited' => false,
+ 'percentages' => 'see prose'
+ ),
+ 'MAX-WIDTH' => array(
+ 'initial' =>'none',
+ 'applies' => '"all elements but non-replaced inline elements, table rows, and row groups"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'MIN-HEIGHT' => array(
+ 'initial' =>'0',
+ 'applies' => '"all elements but non-replaced inline elements, table columns, and column groups"',
+ 'inherited' => false,
+ 'percentages' => 'see prose'
+ ),
+ 'MIN-WIDTH' => array(
+ 'initial' =>'0',
+ 'applies' => '"all elements but non-replaced inline elements, table rows, and row groups"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'ORPHANS' => array(
+ 'initial' =>'2',
+ 'applies' => 'block-level elements',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'OUTLINE-COLOR' => array(
+ 'initial' =>'invert',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'OUTLINE-STYLE' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'OUTLINE-WIDTH' => array(
+ 'initial' =>'medium',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'OUTLINE' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'OVERFLOW' => array(
+ 'initial' =>'visible',
+ 'applies' => '"non-replaced block-level elements, table cells, and inline-block elements"',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'PADDING-TOP' => array(
+ 'initial' =>'0',
+ 'applies' => '"all elements except elements with table display types other than table, inline-table, and table-cell"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'PADDING-RIGHT' => array(
+ 'initial' =>'0',
+ 'applies' => '"all elements except elements with table display types other than table, inline-table, and table-cell"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'PADDING-BOTTOM' => array(
+ 'initial' =>'0',
+ 'applies' => '"all elements except elements with table display types other than table, inline-table, and table-cell"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'PADDING-LEFT' => array(
+ 'initial' =>'0',
+ 'applies' => '"all elements except elements with table display types other than table, inline-table, and table-cell"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'PADDING' => array(
+ 'initial' =>'see individual properties',
+ 'applies' => '"all elements except elements with table display types other than table, inline-table, and table-cell"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'PAGE-BREAK-AFTER' => array(
+ 'initial' =>'auto',
+ 'applies' => 'block-level elements',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'PAGE-BREAK-BEFORE' => array(
+ 'initial' =>'auto',
+ 'applies' => 'block-level elements',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'PAGE-BREAK-INSIDE' => array(
+ 'initial' =>'auto',
+ 'applies' => 'block-level elements',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'POSITION' => array(
+ 'initial' =>'static',
+ 'applies' => '',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'QUOTES' => array(
+ 'initial' =>'depends on user agent',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'RIGHT' => array(
+ 'initial' =>'auto',
+ 'applies' => 'positioned elements',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'TABLE-LAYOUT' => array(
+ 'initial' =>'auto',
+ 'applies' => 'table and inline-table elements',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'TEXT-ALIGN' => array(
+ 'initial' =>'left if direction is ltr; right if direction is rtl',
+ 'applies' => '"block-level elements, table cells and inline blocks"',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'TEXT-DECORATION' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => 'no (see prose)',
+ 'percentages' => ''
+ ),
+ 'TEXT-INDENT' => array(
+ 'initial' =>'0',
+ 'applies' => '"block-level elements, table cells and inline blocks"',
+ 'inherited' => true,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'TEXT-TRANSFORM' => array(
+ 'initial' =>'none',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'TOP' => array(
+ 'initial' =>'auto',
+ 'applies' => 'positioned elements',
+ 'inherited' => false,
+ 'percentages' => 'refer to height of containing block'
+ ),
+ 'UNICODE-BIDI' => array(
+ 'initial' =>'normal',
+ 'applies' => '"all elements, but see prose"',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ 'VERTICAL-ALIGN' => array(
+ 'initial' =>'baseline',
+ 'applies' => 'inline-level and table-cell elements',
+ 'inherited' => false,
+ 'percentages' => 'refer to the line-height of the element itself'
+ ),
+ 'VISIBILITY' => array(
+ 'initial' =>'visible',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'WHITE-SPACE' => array(
+ 'initial' =>'normal',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'WIDOWS' => array(
+ 'initial' =>'2',
+ 'applies' => 'block-level elements',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'WIDTH' => array(
+ 'initial' =>'auto',
+ 'applies' => '"all elements but non-replaced inline elements, table rows, and row groups"',
+ 'inherited' => false,
+ 'percentages' => 'refer to width of containing block'
+ ),
+ 'WORD-SPACING' => array(
+ 'initial' =>'normal',
+ 'applies' => '',
+ 'inherited' => true,
+ 'percentages' => ''
+ ),
+ 'Z-INDEX' => array(
+ 'initial' =>'auto',
+ 'applies' => 'positioned elements',
+ 'inherited' => false,
+ 'percentages' => ''
+ ),
+ );
+
+ static function IsInherited($property)
+ {
+ return kCSSDefaults::$CSS_PROPERTIES[$property]['inherited'];
+// return isset(kCSSDefaults::$CSS_PROPERTIES[$property]) ? : false;
+ }
+
+ static function IsValid($property)
+ {
+ return isset(kCSSDefaults::$CSS_PROPERTIES[$property]);
+ }
+
+ static function GetDefaultValue($property)
+ {
+ return kCSSDefaults::$CSS_PROPERTIES[$property]['initial'];
+// return isset(kCSSDefaults::$CSS_PROPERTIES[$property]) ? kCSSDefaults::$CSS_PROPERTIES[$property]['initial'] : false;
+ }
+
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/css_defaults.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_renderer.php
===================================================================
--- branches/RC/core/units/pdf/pdf_renderer.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_renderer.php (revision 10294)
@@ -0,0 +1,27 @@
+<?php
+
+class kPDFRenderer {
+ const SHAPE_DRAW_FILL = 1;
+ const SHAPE_DRAW_FILL_AND_STROKE = 2;
+ const SHAPE_DRAW_STROKE = 0 ;
+
+ function SetFont($font, $size) {}
+
+ function SetFillColor($color) {}
+
+ function SetLineColor($color) {}
+
+ function SetLineWith($width) {}
+
+ function DrawLine($x1, $y1, $x2, $y2) {}
+
+ function DrawRectangle($x1, $y1, $x2, $y2, $mode) {}
+
+ function DrawText($x, $y, $text) {}
+
+ function GetPDFString() {}
+
+ function GetAscent() {}
+
+ function GetDescent() {}
+}
Property changes on: branches/RC/core/units/pdf/pdf_renderer.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_renderer_tcpdf.php
===================================================================
--- branches/RC/core/units/pdf/pdf_renderer_tcpdf.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_renderer_tcpdf.php (revision 10294)
@@ -0,0 +1,258 @@
+<?php
+
+class kTCPDFRenderer extends kPDFRenderer {
+
+ /**
+ * Enter description here...
+ *
+ * @var TCPDF
+ */
+ public $PDF = null;
+
+ /**
+ * Enter description here...
+ *
+ * @var Zend_Pdf_Page
+ */
+ public $CurPage = null;
+
+ public $CurFont = null;
+ public $CurFontSize = null;
+
+ function __construct()
+ {
+ $this->IncludeTCPDF();
+
+ $this->PDF = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true);
+ $this->PDF->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
+ $this->PDF->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
+ $this->PDF->setPrintHeader(false);
+ $this->PDF->setPrintFooter(false);
+ $this->PDF->AddPage();
+
+// $this->PDF->SetX(50);
+// $this->PDF->SetY(200);
+// $this->PDF->wr
+ }
+
+ function IncludeTCPDF()
+ {
+ define('K_TCPDF_EXTERNAL_CONFIG', true);
+ define('K_PATH_MAIN', FULL_PATH.'/tcpdf/');
+ define('K_PATH_URL', PROTOCOL.SERVER_NAME.(defined('PORT')?':'.PORT : '').rtrim(BASE_PATH, '/').'/tcpdf/');
+ define ("K_PATH_FONTS", K_PATH_MAIN."fonts/");
+ define ("K_PATH_CACHE", K_PATH_MAIN."cache/");
+ define ("K_PATH_URL_CACHE", K_PATH_URL."cache/");
+ define ("K_PATH_IMAGES", K_PATH_MAIN."images/");
+ define ("K_BLANK_IMAGE", K_PATH_IMAGES."_blank.png");
+ define ("PDF_PAGE_FORMAT", "A4");
+ define ("PDF_PAGE_ORIENTATION", "P");
+ define ("PDF_CREATOR", "TCPDF");
+ define ("PDF_AUTHOR", "TCPDF");
+ define ("PDF_HEADER_TITLE", "0");
+ define ("PDF_HEADER_STRING", "0");
+ define ("PDF_HEADER_LOGO", "logo_example.png");
+ define ("PDF_HEADER_LOGO_WIDTH", 0);
+ define ("PDF_UNIT", "pt");
+ define ("PDF_MARGIN_HEADER", 0);
+ define ("PDF_MARGIN_FOOTER", 0);
+ define ("PDF_MARGIN_TOP", 0);
+ define ("PDF_MARGIN_BOTTOM", 0);
+ define ("PDF_MARGIN_LEFT", 0);
+ define ("PDF_MARGIN_RIGHT", 0);
+ define ("PDF_FONT_NAME_MAIN", "vera"); //vera
+ define ("PDF_FONT_SIZE_MAIN", 10);
+ define ("PDF_FONT_NAME_DATA", "vera"); //verase
+ define ("PDF_FONT_SIZE_DATA", 8);
+ define ("PDF_IMAGE_SCALE_RATIO", 4);
+ define("HEAD_MAGNIFICATION", 1.1);
+ define("K_CELL_HEIGHT_RATIO", 1.25);
+ define("K_TITLE_MAGNIFICATION", 1.3);
+ define("K_SMALL_RATIO", 2/3);
+ require_once(FULL_PATH.'/tcpdf/config/lang/eng.php');
+ require_once(FULL_PATH.'/tcpdf/tcpdf.php');
+ }
+
+ function NextPage()
+ {
+ $this->PDF->AddPage();
+ }
+
+ function GetWidth()
+ {
+ return $this->PDF->getPageWidth();
+ }
+
+ function GetHeight()
+ {
+ return $this->PDF->getPageHeight();
+ }
+
+ function SetFont($family, $size, $weight=400, $style='normal', $variant='normal')
+ {
+ $this->CurFontSize = $size;
+
+ $family = strtolower($family);
+ switch ($family) {
+ case 'serif':
+ $font = 'FreeSerif';
+ break;
+ case 'cursive':
+ $font = 'FreeSerif';
+ break;
+ case 'fantasy':
+ $font = 'FreeSans';
+ break;
+ case 'monospace':
+ $font = 'FreeMono';
+ break;
+ case 'sans-serif':
+ default:
+ $font = 'FreeSans';
+ break;
+ }
+
+ $bold = $weight >= 700 ? 'B' : '';
+ $italic = preg_match('/italic|oblique/i', $style) ? 'I' : '';
+
+ return $this->PDF->SetFont($font, $bold.$italic, $size);
+ }
+
+ function SetFontSize($size)
+ {
+ $this->CurFontSize = $size;
+ $this->PDF->SetFontSize($size);
+ }
+
+ function ProcessHTMLColor($color) {
+ $mapping = array(
+ 'maroon' => '#800000',
+ 'red' => '#ff0000',
+ 'orange' => '#ffA500',
+ 'yellow' => '#ffff00',
+ 'olive' => '#808000',
+ 'purple' => '#800080',
+ 'fuchsia' => '#ff00ff',
+ 'white' => '#ffffff',
+ 'lime' => '#00ff00',
+ 'green' => '#008000',
+ 'navy' => '#000080',
+ 'blue' => '#0000ff',
+ 'aqua' => '#00ffff',
+ 'teal' => '#008080',
+ 'black' => '#000000',
+ 'silver' => '#c0c0c0',
+ 'gray' => '#808080',
+ );
+ foreach ($mapping as $named_color => $value) {
+ $color = str_ireplace($named_color, $value, $color);
+ }
+ if ( preg_match('/^#([0-9a-f]{3})$/i', $color, $regs) ) {
+ $color = $color.$regs[1];
+ }
+ if ( preg_match('/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i', $color, $regs) )
+ {
+ return array(hexdec($regs[1]), hexdec($regs[2]), hexdec($regs[3]));
+ }
+ return array(255,255,0);
+
+ }
+
+ function SetFillColor($color)
+ {
+ list($r,$g,$b) = $this->ProcessHTMLColor($color);
+ $this->PDF->SetFillColor($r,$g,$b);
+ $this->PDF->SetTextColor($r,$g,$b);
+ }
+
+ function SetLineColor($color)
+ {
+ list($r,$g,$b) = $this->ProcessHTMLColor($color);
+ return $this->PDF->SetDrawColor($r,$g,$b);
+ }
+
+ function SetLineWidth($width)
+ {
+ return $this->PDF->setLineWidth($width);
+ }
+
+ function DrawLine($x1, $y1, $x2, $y2)
+ {
+ return $this->PDF->Line($x1, $y1, $x2, $y2);
+ }
+
+ function DrawRectangle($x1, $y1, $x2, $y2, $mode='D')
+ {
+ switch ($mode) {
+ case kPDFRenderer::SHAPE_DRAW_FILL:
+ $mode = 'F';
+ break;
+ case kPDFRenderer::SHAPE_DRAW_STROKE :
+ $mode = 'D';
+ break;
+ case kPDFRenderer::SHAPE_DRAW_FILL_AND_STROKE :
+ $mode = 'DF';
+ break;
+
+ }
+ $w = $x2-$x1;
+ $h = $y2-$y1;
+ return $this->PDF->Rect($x1, $y1, $w, $h, $mode);
+ }
+
+ function DrawText($text, $x, $y)
+ {
+ return $this->PDF->text($x, $y, $text);
+ }
+
+ function DrawImage($filepath, $x, $y, $w=0, $h=0)
+ {
+ $info = pathinfo($filepath);
+ if (preg_match('/jpg|jpeg|png/i', $info['extension'])) {
+ return $this->PDF->Image($filepath, $x, $y, $w, $h);
+ }
+ if (preg_match('/gif/i', $info['extension'])) {
+ $tmp_path = WRITEABLE.'/tmp';
+ if (!file_exists($tmp_path)) {
+ mkdir($tmp_path);
+ }
+ $converted_filepath = $tmp_path.'/'.$info['filename'].'.png';
+ if (!file_exists($converted_filepath) || filemtime($converted_filepath) < filemtime($filepath)) {
+ $im = @imagecreatefromgif ($filepath);
+ imagepng($im, $converted_filepath);
+ }
+
+ return $this->PDF->Image($converted_filepath, $x, $y, $w, $h);
+ }
+ }
+
+ function GetPDFString()
+ {
+ return $this->PDF->Output('', 'S');
+ }
+
+ function GetAscent()
+ {
+ //$this->CurrentFont['desc']
+ $font = $this->PDF->GetFont();
+ return ($font['desc']['Ascent'] / 1000) * $this->CurFontSize;
+ }
+
+ function GetDescent()
+ {
+ $font = $this->PDF->GetFont();
+ return ($font['desc']['Descent'] / 1000) * $this->CurFontSize;
+ }
+
+ function GetLineGap()
+ {
+ return 0;
+ $font = $this->PDF->GetFont();
+ return (($font['Ascent'] - $font['Descent'])*0 / 1000) * $this->CurFontSize;
+ }
+
+ function GetStringWidth($string)
+ {
+ return $this->PDF->GetStringWidth($string);
+ }
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/pdf_renderer_tcpdf.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_renderer_zend.php
===================================================================
--- branches/RC/core/units/pdf/pdf_renderer_zend.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_renderer_zend.php (revision 10294)
@@ -0,0 +1,117 @@
+<?php
+
+require_once 'Zend/Pdf.php';
+class kZendPDFRenderer extends kPDFRenderer {
+ public $PDF = null;
+
+ /**
+ * Enter description here...
+ *
+ * @var Zend_Pdf_Page
+ */
+ public $CurPage = null;
+
+ public $CurFont = null;
+ public $CurFontSize = null;
+
+ function __construct()
+ {
+ $this->PDF = new Zend_Pdf();
+ $this->PDF->pages[] = ($page1 = new Zend_Pdf_Page(Zend_Pdf_Page::SIZE_A4));
+ $this->CurPage = $page1;
+ }
+
+ function GetWidth()
+ {
+ return $this->CurPage->getWidth();
+ }
+
+ function GetHeight()
+ {
+ return $this->CurPage->getHeight();
+ }
+
+ function SetFont($font, $size)
+ {
+ $mapping = array(
+ 'helvetica' => Zend_Pdf_Font::FONT_HELVETICA,
+ );
+ $use_font = Zend_Pdf_Font::FONT_TIMES;
+ foreach ($mapping as $pattern => $zend_font) {
+ if (preg_match('/^'.$pattern.'$/i', $font)) {
+ $use_font = $zend_font;
+ break;
+ }
+ }
+ $this->CurFont = Zend_Pdf_Font::fontWithName($use_font);
+ $this->CurFontSize = $size;
+ return $this->CurPage->setFont($this->CurFont, $size);
+ }
+
+ function SetFontSize($size)
+ {
+ $this->SetFont($this->CurFont, $size);
+ }
+
+ function SetFillColor($color)
+ {
+ return $this->CurPage->setFillColor( new Zend_Pdf_Color_HTML($color) );
+ }
+
+ function SetLineColor($color)
+ {
+ return $this->CurPage->setLineColor( new Zend_Pdf_Color_HTML($color) );
+ }
+
+ function SetLineWidth($width)
+ {
+ return $this->CurPage->setLineWidth($width);
+ }
+
+ function DrawLine($x1, $y1, $x2, $y2)
+ {
+ return $this->CurPage->drawLine($x1, $y1, $x2, $y2);
+ }
+
+ function DrawRectangle($x1, $y1, $x2, $y2, $mode)
+ {
+ return $this->CurPage->drawRectangle($x1, $y1, $x2, $y2, $mode);
+ }
+
+ function DrawText($x, $y, $text)
+ {
+ return $this->CurPage->drawText($x, $y, $text);
+ }
+
+ function GetPDFString()
+ {
+ return $this->PDF->render();
+ }
+
+ function GetAscent()
+ {
+ return ($this->CurFont->getAscent() / $this->CurFont->getUnitsPerEm()) * $this->CurFontSize;
+ }
+
+ function GetDescent()
+ {
+ return ($this->CurFont->getDescent() / $this->CurFont->getUnitsPerEm()) * $this->CurFontSize;
+ }
+
+ function GetLineGap()
+ {
+ return ($this->CurFont->getLineGap() / $this->CurFont->getUnitsPerEm()) * $this->CurFontSize;
+ }
+
+ function GetStringWidth($string)
+ {
+ $drawingString = iconv('UTF-8', 'UTF-16BE//IGNORE', $string);
+ $characters = array();
+ for ($i = 0; $i < strlen($drawingString); $i++) {
+ $characters[] = (ord($drawingString[$i++]) << 8) | ord($drawingString[$i]);
+ }
+ $glyphs = $this->CurFont->cmap->glyphNumbersForCharacters($characters);
+ $widths = $this->CurFont->widthsForGlyphs($glyphs);
+ return (array_sum($widths) / $this->CurFont->getUnitsPerEm()) * $this->CurFontSize;
+ }
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/pdf_renderer_zend.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_table.php
===================================================================
--- branches/RC/core/units/pdf/pdf_table.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_table.php (revision 10294)
@@ -0,0 +1,335 @@
+<?php
+
+class kPDFTableRow extends kPDFElement {
+
+ function LayoutChildren()
+ {
+ parent::LayoutChildren();
+
+ // http://manual.prod.intechnic.lv/css21/tables.html#height-layout
+
+ // vertical-alignment
+ $row_height = $this->GetCSSProperty('height');
+ if ($row_height == 'auto') {
+ $row_height = 0;
+ }
+ $baseline = 0;
+ foreach ($this->Children as $elem) {
+ if ($elem->GetCSSProperty('vertical-align') == 'baseline') {
+// $ascent = $elem->FindChild('_LINE_')->Ascent;
+ $ascent = $elem->FirstChild->Ascent;
+ if ($ascent > $baseline) {
+ $baseline = $ascent;
+ }
+ }
+ $dim = $elem->GetBoxDimensions();
+ $elem_height = $dim[1];
+ if ($elem_height > $row_height) {
+ $row_height = $elem_height;
+ }
+ }
+
+ foreach ($this->Children as $elem) {
+ $vertical_align = $elem->GetCSSProperty('vertical-align');
+ $dim = $elem->GetBoxDimensions();
+ $elem_height = $dim[1];
+ $add_top = 0;
+ $add_bottom = 0;
+ if ($vertical_align == 'top') {
+ $add_bottom = $row_height - $elem_height;
+ }
+ elseif ($vertical_align == 'middle') {
+ $add_top = ($row_height - $elem_height)/2;
+ $add_bottom = $add_top;
+ }
+ elseif ($vertical_align == 'bottom') {
+ $add_top = $row_height - $elem_height;
+ }
+ else { // baseline and all other
+ if ($elem->Ascent < $baseline) {
+ $add_top = $baseline - $elem->Ascent;
+ }
+ $add_bottom = $row_height - $elem_height - $add_top;
+ }
+
+ $elem->SetCSSProperty('padding-top', $elem->GetCSSProperty('padding-top') + $add_top);
+ $elem->SetCSSProperty('padding-bottom', $elem->GetCSSProperty('padding-bottom') + $add_bottom);
+ }
+ }
+
+}
+
+class kPDFTable extends kPDFElement {
+ public $InitialMode = null;
+
+ public $Table = array();
+ public $TableBuild = false;
+ public $CurCol = 0;
+ public $CurRow = 0;
+
+ public $ColWidths = array();
+
+ function __construct($node, $helper)
+ {
+ parent::__construct($node, $helper);
+ }
+
+ function Init()
+ {
+ parent::Init();
+ $this->InitialMode = $this->Helper->DimensionsMode;
+ $this->Helper->DimensionsMode = kPDFHelper::DM_SKIP;
+ }
+
+ function Closed()
+ {
+ $this->BuildTable($this);
+ parent::Closed();
+ /*$this->Helper->DimensionsMode = kPDFHelper::DM_NORMAL ;
+// $this->LayoutChildren();
+ $this->Helper->DimensionsMode = $this->InitialMode;*/
+ }
+
+ function ComputeWidthAndMargins()
+ {
+ if (!$this->TableBuild || !$this->GetContainingBlock()->WidthComputed || $this->WidthComputed) return ;
+ $this->ComputeCSSProperty('WIDTH', $this->CSSSpecifiedProperties['WIDTH']);
+
+ if ($this->GetCSSProperty('table-layout') == 'fixed') {
+ $this->CalculateWidthsFixed();
+ }
+ if ($this->GetCSSProperty('table-layout') == 'auto') {
+ $this->CalculateWidthsAuto(); //CalculateWidthsAuto();
+ }
+ $this->WidthComputed = true;
+ }
+
+ function CalculateWidthsFixed()
+ {
+ if (count($this->Table) == 0) return ;
+
+ $specified_width = 0;
+ $specified_count = 0;
+ $i = 0;
+ foreach ($this->Table[1] as $cell) {
+ $i++;
+ $cur_w = $cell->GetCSSProperty('width');
+ $colspan = isset($cell->Node->Attributes['COLSPAN']) ? $cell->Node->Attributes['COLSPAN'] : 1;
+ if ($cur_w != 'auto') {
+ $specified_width += $cur_w;
+ $specified_count += $colspan;
+ $cur_w = $cur_w/$colspan;
+ }
+ for ($col=$i; $col < $i+$colspan; $col++) {
+ $this->ColWidths[$col] = $cur_w;
+ }
+ $i += $colspan-1;
+ }
+ $max_cols = $i;
+ $remaining_w = $this->GetCSSProperty('width') - $specified_width;
+ $auto_width = $remaining_w/($max_cols-$specified_count);
+ foreach ($this->ColWidths as $i => $width) {
+ if ($width == 'auto') {
+ $this->ColWidths[$i] = $auto_width;
+ }
+ }
+
+ $this->SetColWidths($max_cols);
+ }
+
+ function SetColWidths($max_cols)
+ {
+ foreach ($this->Table as $row) {
+ $i = 0;
+ foreach ($row as $cell) {
+ $i++;
+ if ($i > $max_cols) {
+ break;
+ }
+ $cell_extra_width =
+ $cell->GetCSSProperty('border-left-width') +
+ $cell->GetCSSProperty('padding-left') +
+ $cell->GetCSSProperty('padding-right') +
+ $cell->GetCSSProperty('border-right-width');
+ if (isset($cell->Node->Attributes['COLSPAN'])) {
+ $colspan = $cell->Node->Attributes['COLSPAN'];
+ $z = $i;
+ $width = 0;
+ do {
+ $width += $this->ColWidths[$z];
+ } while ($z++ < $i+$colspan-1);
+// $width = array_sum( array_slice($this->ColWidths, $i-1, $colspan) );
+ $i += $colspan-1;
+ }
+ else {
+ $width = $this->ColWidths[$i];
+ }
+ $cell->SetCSSProperty('width', $width - $cell_extra_width);
+ $cell->WidthComputed = true;
+ }
+ }
+ $this->SetCSSProperty('width', array_sum($this->ColWidths));
+ }
+
+ function BuildTable($node)
+ {
+ $this->ColWidths = array();
+ foreach ($node->Children as $child) {
+ if ($child->GetCSSProperty('display') == 'table-row') {
+ $this->CurRow++;
+ $this->CurCol = 0;
+ }
+ if ($child->GetCSSProperty('display') == 'table-cell') {
+ $this->CurCol++;
+ $this->Table[$this->CurRow][$this->CurCol] = $child;
+ if (isset($child->Node->Attributes['COLSPAN'])) {
+ $this->CurCol += $child->Node->Attributes['COLSPAN']-1;
+ }
+ }
+ else { // otherwise it will find all nested table cells
+ $this->BuildTable($child);
+ }
+ }
+ $this->TableBuild = true;
+ }
+
+ function CalculateWidthsAuto()
+ {
+ if (count($this->Table) == 0) return ;
+
+ $min_col_widths = array();
+ $max_col_widths = array();
+ $specified_widths = array();
+ $percent_widths = array();
+
+ $row = 0;
+ $max_cols = 0;
+ foreach ($this->Table as $row)
+ {
+ $row++;
+ $col = 0;
+ foreach ($row as $cell) {
+ $col++;
+ $cell_w = $cell->GetCSSProperty('width');
+ $percent_w = false;
+ if (preg_match('/([.0-9]+)%/', $cell_w, $regs)) {
+ $percent_w = $regs[1];
+ }
+ $min_cw = $cell_w == 'auto' && !$percent_w ? $cell->MinContentWidth : max($cell_w, $cell->MinContentWidth);
+ $max_cw = $cell->MaxContentWidth;
+
+ if ($cell_w != 'auto' && is_numeric($cell_w)) {
+ if ($cell_w < $min_cw) {
+ $cell_w = $min_cw;
+ }
+ if (!isset($specified_widths[$col]) || $cell_w > $specified_widths[$col]) {
+ $specified_widths[$col] = $cell_w;
+ }
+ }
+
+ $colspan = isset($cell->Node->Attributes['COLSPAN']) ? $cell->Node->Attributes['COLSPAN'] : 1;
+ if ($colspan == 1) {
+ if (!isset($min_col_widths[$col]) || $min_cw > $min_col_widths[$col]) {
+ $min_col_widths[$col] = $min_cw;
+ }
+ if (!isset($max_col_widths[$col]) || $max_cw > $max_col_widths[$col]) {
+ $max_col_widths[$col] = $max_cw;
+ }
+ if ($percent_w && (!isset($percent_widths[$col]) || $percent_w > $percent_widths[$col])) {
+ $percent_widths[$col] = $percent_w;
+ }
+ }
+ else {
+ $spans_min = array_slice($min_col_widths, $col-1, $colspan);
+ $spans_max = array_slice($max_col_widths, $col-1, $colspan);
+ $spans_percent = array_slice($percent_widths, $col-1, $colspan);
+
+ $min_diff = ($min_cw - array_sum($spans_min));
+ if ($min_diff > 0) {
+ for($i=$col; $i < $col+$colspan; $i++) {
+ $min_col_widths[$i] += $min_diff/$colspan;
+ }
+ }
+
+ $max_diff = ($max_cw - array_sum($spans_max));
+ if ($max_diff > 0) {
+ for($i=$col; $i < $col+$colspan; $i++) {
+ $max_col_widths[$i] += $max_diff/$colspan;
+ }
+ }
+
+ $percent_diff = ($percent_w - array_sum($spans_percent));
+ if ($percent_diff > 0) {
+ for($i=$col; $i < $col+$colspan; $i++) {
+ $percent_widths[$i] += $percent_diff/$colspan;
+ }
+ }
+
+ $col += $colspan-1;
+ }
+ }
+ if ($col > $max_cols) {
+ $max_cols = $col;
+ }
+ }
+ $table_min_width = array_sum($min_col_widths);
+ $table_max_width = array_sum($max_col_widths) - $this->GetCSSProperty('border-left-width') - $this->GetCSSProperty('border-right-width');
+ $table_specifid_width = array_sum($specified_widths);
+
+ $cb_width = $this->GetContainingBlock()->GetCSSProperty('width');
+ $computed_width = $this->ComputeCSSProperty('WIDTH', $this->GetCSSProperty('width'));
+ if ($computed_width == 'auto') {
+ $computed_width = $cb_width;
+ }
+ else {
+ $computed_width -= $this->GetCSSProperty('border-left-width') + $this->GetCSSProperty('border-right-width');
+ }
+ if ($this->CSSSpecifiedProperties['WIDTH'] == 'auto' && $table_max_width < $computed_width) {
+ $width = $table_max_width;
+ $this->ColWidths = $max_col_widths;
+ }
+ else {
+ $width = max($table_min_width, $computed_width);
+
+ // try to satisfy percent widths
+ $reset_to_min = false;
+ $percent_sum = 0;
+ for ($i=1; $i<=$max_cols; $i++) {
+ if (isset($percent_widths[$i])) {
+ $adjusted_percent = $reset_to_min ? 0 : min($percent_widths[$i], 100-$percent_sum);
+ $percent_sum += $adjusted_percent;
+ if ($adjusted_percent > 0) {
+ $min_col_widths[$i] = $width*$adjusted_percent/100;
+ }
+ }
+ if ($percent_sum >= 100) {
+ $reset_to_min = true;
+ }
+ }
+ $distribute = $width - array_sum($min_col_widths); // recalc min width here, because of % changes
+
+ $total_max = 0;
+ for ($i=1; $i<=$max_cols; $i++) {
+ if (isset($specified_widths[$i])) {
+ $this->ColWidths[$i] = $specified_widths[$i];
+// $distribute -= $specified_widths[$i];
+ continue;
+ }
+ else {
+ $total_max += $max_col_widths[$i];
+ }
+ }
+
+ for ($i=1; $i<=$max_cols; $i++) {
+ if (isset($this->ColWidths[$i])) {
+ continue;
+ }
+ $coeff = isset($percent_widths[$i]) ? $percent_widths[$i] / $percent_sum : $max_col_widths[$i]/$total_max;
+ $add = $coeff * $distribute;
+ $this->ColWidths[$i] = $min_col_widths[$i] + $add;
+ }
+ }
+
+ $this->SetColWidths($max_cols);
+ }
+}
\ No newline at end of file
Property changes on: branches/RC/core/units/pdf/pdf_table.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/pdf/pdf_helper.php
===================================================================
--- branches/RC/core/units/pdf/pdf_helper.php (nonexistent)
+++ branches/RC/core/units/pdf/pdf_helper.php (revision 10294)
@@ -0,0 +1,996 @@
+<?php
+
+//define('PDF_DEBUG_NO_TEXT', 1); // do not draw text
+//define('PDF_DEBUG_DUMP_ONLY', 1); // output elements dump and exit
+//define('PDF_DEBUG_DRAW_BOXES', 1); //
+//define('PDF_DEBUG_DRAW_BASELINE', 1); //
+//define('PDF_DEBUG_DRAW_BOX_INFO', '/.*/'); //
+//define('PDF_DEBUG_DRAW_BOX_INFO', '/(td|img)/i'); //
+//define('PDF_DEBUG_DRAW_MARGINS', 1); //
+//define('PDF_DEBUG_DRAW_ELEM_BORDERS', 1);
+//define('PDF_DEBUG_DRAW_LINE_BOXES', 1);
+//define('PDF_DRAW_CONTENT_AREA', 1);
+
+require_once FULL_PATH.'/core/units/pdf/pdf_styles.php';
+require_once FULL_PATH.'/core/units/pdf/pdf_text.php';
+require_once FULL_PATH.'/core/units/pdf/pdf_table.php';
+require_once FULL_PATH.'/core/units/pdf/pdf_image.php';
+require_once FULL_PATH.'/core/units/pdf/pdf_renderer.php';
+require_once FULL_PATH.'/core/units/pdf/pdf_renderer_tcpdf.php';
+
+class kPDFHelper extends kHelper {
+
+ /**
+ * Enter description here...
+ *
+ * @var kPDFRenderer
+ */
+ var $PDF;
+ var $CurPDFElem;
+
+ var $DimensionsMode = 1;
+
+ var $Stylesheet;
+
+ var $PtPerEm = 10;
+
+ public $Document = null;
+
+ const DM_NORMAL = 0;
+ const DM_SKIP = 1;
+
+ function BuildFromTemplate($template, $template_params = Array ())
+ {
+ $this->Application->InitParser();
+ $template_params['name'] = $template;
+ $xml = $this->Application->ParseBlock($template_params);
+ $xml_helper =& $this->Application->recallObject('kXMLHelper');
+ /* @var $xml_helper kXMLHelper */
+
+ $doc = $xml_helper->Parse($xml_helper->ConvertHTMLEntities($xml), XML_WITH_TEXT_NODES);
+ if ($doc->Name == 'ERROR') {
+ echo 'BAD TEMPLATE';
+ exit;
+ }
+
+// $this->Application->Debugger->profileStart('pdf_init', 'Initializing PDF');
+ $this->InitPDF($doc);
+// $this->Application->Debugger->profileFinish('pdf_init');
+// $this->Application->Debugger->profileStart('process_nodes', 'Processing nodes');
+ $this->ProcessNode($doc);
+// $this->Application->Debugger->profileFinish('process_nodes');
+
+ if (defined('PDF_DEBUG_DUMP_ONLY')) {
+ $this->DimensionsMode = kPDFHelper::DM_NORMAL ;
+ $this->Application->Debugger->profileStart('laying_out', 'Laying out nodes');
+// $this->CurPDFElem->LayoutChildren();
+ $this->Application->Debugger->profileFinish('laying_out');
+ $this->Application->Debugger->profileStart('rendering', 'rendering');
+// $this->Render();
+ $this->Application->Debugger->profileFinish('rendering');
+
+// echo $this->CurPDFElem->DumpStructure();
+ exit;
+ }
+
+ $this->Render();
+
+ return $this->PDF->GetPDFString();
+// exit;
+ }
+
+ function InitPDF($doc)
+ {
+ $this->PDF = new kTCPDFRenderer();
+
+ $this->Stylesheet = new kPDFStylesheet();
+
+ $this->CurPDFElem = kPDFElemFactory::CreateFromNode($doc, $this);
+ $this->Document = $this->CurPDFElem;
+// $this->CurPDFElem = new kPDFPage($page1, new kXMLNode('_NONE_', array('style' => 'display: block; width: '.$page1->getWidth().';')), $this);
+ $this->CurPDFElem->Init();
+ $this->CurPDFElem->SetCSSProperty('width', $this->PDF->getWidth());
+ $this->CurPDFElem->SetCSSProperty('height', $this->PDF->getHeight());
+ $this->PDF->SetFont('helvetica', $this->PtPerEm);
+ }
+
+ function Render()
+ {
+ $this->DimensionsMode = kPDFHelper::DM_NORMAL ;
+ $this->CurPDFElem->LayoutChildren();
+ $this->PageBottom = $this->PDF->getHeight() - $this->Document->GetCSSProperty('margin-bottom'); // margin
+ $this->CurPDFElem->DrawAt($this->PDF, 0, 0);
+ }
+
+ function ProcessHead($node)
+ {
+ if ($node->Name == 'STYLE') {
+ $css = $node->Data;
+ $tokens = $this->Stylesheet->GetTokens($node->Data);
+ $this->Stylesheet->ParseTokens($tokens);
+ }
+ foreach($node->Children as $child) {
+ $this->ProcessHead($child);
+ }
+ }
+
+ function ProcessNode($node)
+ {
+ $children = count($node->Children);
+ foreach($node->Children as $child) {
+ if ($child->Name == 'HEAD') {
+ $this->ProcessHead($child);
+ continue;
+ }
+
+ $elem = kPDFElemFactory::CreateFromNode($child, $this);
+ if (!$elem) continue;
+ $display = $elem->GetDisplayLevel();
+ if ($display == 'none') continue;
+
+ // http://manual.prod.intechnic.lv/css21/visuren.html#anonymous-block-level
+ if ($display == 'block' && $this->CurPDFElem->GetDisplayLevel() == 'inline') {
+ $this->CurPDFElem->Closed();
+ $this->CurPDFElem = $this->CurPDFElem->GetContainingBlock();
+ }
+
+ $current = $this->CurPDFElem;
+ $line = false;
+ if ($display == 'inline' && !($this->CurPDFElem instanceof kPDFLine) ) {
+ $this->CurPDFElem = $this->CurPDFElem->GetLineBox();
+ $line = $this->CurPDFElem;
+ }
+
+ $this->CurPDFElem = $this->CurPDFElem->AddChild( $elem );
+
+ $this->ProcessNode($child);
+ $this->CurPDFElem = $current;
+ }
+ $this->CurPDFElem->Closed();
+ }
+}
+
+class kPDFElemFactory {
+ static function CreateFromNode($node, $helper)
+ {
+ /* @todo Create elements, based on their display, rather than tag name - pure CSS rendering */
+
+ switch ($node->Name) {
+ case '_TEXT_':
+// $DOMNode = $node->Parent;
+ $elem = new kPDFTextElement($node->Data, $node, $helper);
+ if ($elem->CSSSpecifiedProperties['WHITE-SPACE'] == 'normal' && trim($node->Data) == '') {
+ return false;
+ }
+ return $elem;
+ break;
+ case 'TR':
+ return new kPDFTableRow($node, $helper);
+ case 'BR':
+ return new kPDFTextElement($node->Data, $node, $helper);
+ case 'TABLE':
+ return new kPDFTable($node, $helper);
+ case 'IMG':
+ return new kPDFImage($node, $helper);
+ default:
+ return new kPDFElement($node, $helper);
+ break;
+ }
+ }
+}
+
+class kPDFElement {
+ public $Parent;
+ protected $Font;
+ protected $FontSize;
+ public $Children = array();
+
+ public $Position = 0;
+
+ public $FirstChild;
+ public $LastChild;
+
+ public $ContentHeight = 0;
+
+ public $Style;
+
+ public $CurX = 0;
+ public $CurY = 0;
+
+ public $Baseline = 0;
+ public $Ascent;
+ public $Descent;
+ public $Gap;
+
+ public $Node;
+ public $Helper;
+
+ public $CSSSpecifiedProperties = array();
+ public $CSSComputedPoperties = array();
+ public $DirectStyle;
+
+ public $IsClosed = false;
+
+ public $LayedOut = false;
+
+ public $WidthComputed = false;
+
+ public $MinContentWidth = 0;
+ public $MaxContentWidth = 0;
+
+ public $CurLine_MinContentWidth = 0;
+ public $CurLine_MaxContentWidth = 0;
+
+ public $Spacers = 0;
+
+
+ function __construct($node, $helper)
+ {
+ $this->Node = $node;
+ $this->Helper = $helper;
+ $this->ProcessCSS();
+ }
+
+ function Init()
+ {
+ $this->ComputeCSSProperties();
+ }
+
+ function Reset()
+ {
+ $this->CurX = 0;
+ $this->CurY = 0;
+ }
+
+ function AddChild($child, $init=true, $after=null)
+ {
+ $node_count = count($this->Children);
+ if (isset($after)) {
+ $after_pos = $after->Position;
+ for($i=$after_pos+1; $i<$node_count; $i++) {
+ $this->Children[$i]->Position++;
+ }
+ array_splice($this->Children, $after_pos+1, 0, array($child));
+ $child->Position = $after_pos+1;
+ }
+ else {
+ $child->Position = $node_count;
+ $this->Children[] = $child;
+ }
+ if ($node_count == 0) {
+ $this->FirstChild = $child;
+ $this->LastChild = $child;
+ }
+ elseif ($child->Position == $node_count) {
+ $this->LastChild = $child;
+ }
+
+ $child->Parent = $this;
+ if ($init) $child->Init();
+ return $child;
+ }
+
+ public function Closed()
+ {
+ if ($this->LastChild && $this->LastChild instanceof kPDFLine && !$this->LastChild->IsClosed) {
+ $this->LastChild->Closed();
+ }
+ $this->ComputeWidthAndMargins();
+ $this->CalcMinMaxContentWidth();
+ $this->IsClosed = true;
+ return ;
+ }
+
+ function RemoveChildren($start, $count=null)
+ {
+ return array_splice($this->Children, $start);
+ }
+
+ function &FindChildByProperty($property, $value)
+ {
+ $property = strtoupper($property);
+ if (strtoupper($this->GetCSSProperty($property)) == strtoupper($value)) return $this;
+ foreach ($this->Children as $elem)
+ {
+ $child =& $elem->FindChildByProperty($property, $value);
+ if ($child !== false)
+ {
+ return $child;
+ }
+ }
+ $false = false;
+ return $false;
+ }
+
+ function LayoutChildren()
+ {
+ $this->ComputeWidthAndMargins();
+ $i = 0;
+ $this->Reset();
+ while (isset($this->Children[$i])) { // can't use foreach here, because LayoutChildren() may add new children to current elem (wrapping)
+ $child = $this->Children[$i];
+ $child->LayoutChildren();
+ $i++;
+ }
+ $this->CheckDimensions();
+ $this->ComputeHeight();
+// $this->ComputeBaseline();
+ }
+
+ public function ComputeHeight()
+ {
+ $display = $this->GetCSSProperty('display');
+ if ($display == 'inline') return ;
+
+ $height = 0; // $this->GetCSSProperty('height');
+ /* $extra_height =
+ $this->GetCSSProperty('margin-top') +
+ $this->GetCSSProperty('margin-bottom') +
+ $this->GetCSSProperty('padding-top') +
+ $this->GetCSSProperty('padding-bottom') +
+ $this->GetCSSProperty('border-top-width') +
+ $this->GetCSSProperty('border-bottom-width');*/
+
+ foreach ($this->Children as $elem) {
+ $dim = $elem->GetBoxDimensions();
+ $elem_height = $dim[1];
+ if ($elem->GetDisplayLevel() == 'block' && $elem->GetCSSProperty('display') != 'table-cell') {
+ $height += $elem_height;
+ }
+ else {
+ if ($elem_height > $height) {
+ $height = $elem_height;
+ }
+ }
+ }
+ $this->SetCSSProperty('height', $height);
+ }
+
+ function &FindChild($name)
+ {
+ $name = strtoupper($name);
+ if ($this->Node->Name == $name) return $this;
+ foreach ($this->Children as $elem)
+ {
+ $child =& $elem->FindChild($name);
+ if ($child !== false)
+ {
+ return $child;
+ }
+ }
+ $false = false;
+ return $false;
+ }
+
+ function DumpStructure($level=0)
+ {
+ $dump = '';
+ $tab = str_repeat('&nbsp;', $level*4);
+ $dump .= $tab . get_class($this) . ' Node: ' . $this->Node->Name . " child of ".$this->Node->Parent->Name."<br>\n";
+ if ($this instanceof kPDFTextElement) {
+ $dump .= $tab . 'Data: ' . $this->Data . "<br>\n";
+ }
+ $dump .= $tab . 'Width: ' . $this->GetCSSProperty('width') . ' Height: ' . $this->GetCSSProperty('height') . " Ascent: " . $this->Ascent . "<br>\n";
+ $dump .= $tab . 'MinCW: ' . $this->MinContentWidth . ' MaxCW: ' . $this->MaxContentWidth . "<br>\n";
+ $dump .= $tab . 'Children:' . "<br>\n";
+ $i = 0;
+ foreach ($this->Children as $elem)
+ {
+ $i++;
+ $dump .= $tab . $i . "<br>\n";
+ $level++;
+ $dump .= $elem->DumpStructure($level);
+ $level--;
+ }
+ return $dump;
+ }
+
+ function DrawAt($page, $x=0, $y=0, $spacer_w=0)
+ {
+ if ($this->Node->Name == 'FOOTER') {
+ $dim = $this->GetBoxDimensions();
+ $y = $this->Helper->PDF->GetHeight() - $dim[1];
+ }
+
+ if ($this->GetDisplayLevel() == 'block' ) {
+ $width = $this->GetCSSProperty('width');
+ $margin_left = $this->GetCSSProperty('margin-left');
+ $margin_right = $this->GetCSSProperty('margin-right');
+ $border_left = $this->GetCSSProperty('border-left-width');
+ $border_right = $this->GetCSSProperty('border-right-width');
+ $padding_left = $this->GetCSSProperty('padding-left');
+ $padding_right = $this->GetCSSProperty('padding-right');
+
+ $height = $this->GetCSSProperty('height');
+ $margin_top = $this->GetCSSProperty('margin-top');
+ $margin_bottom = $this->GetCSSProperty('margin-bottom');
+ $border_top = $this->GetCSSProperty('border-top-width');
+ $border_bottom = $this->GetCSSProperty('border-bottom-width');
+ $padding_top = $this->GetCSSProperty('padding-top');
+ $padding_bottom = $this->GetCSSProperty('padding-bottom');
+
+ $outer_width = $margin_left + $border_left + $padding_left + $width + $padding_right + $border_right + $margin_right;
+ $outer_height = $margin_top + $border_top + $padding_top + $height + $padding_bottom + $border_bottom + $margin_bottom;
+
+ if (defined('PDF_DEBUG_DRAW_BOXES')) {
+ $page->SetFillColor( '#eeeeee' );
+ if ($this instanceof kPDFLine) {
+ if (defined('PDF_DEBUG_DRAW_LINE_BOXES')) {
+ $page->SetLineWidth(0.5);
+ $page->SetLineColor( 'yellow' );
+ $page->SetFillColor( '#efefef' );
+ }
+ }
+ else {
+ $page->SetLineWidth(0.1);
+ $page->SetLineColor( '#0000ff' );
+ }
+// $page->DrawRectangle($x, $y, $x + $outer_width, $y - $outer_height, kPDFRenderer::SHAPE_DRAW_FILL_AND_STROKE);
+ $page->SetFillColor( '#000000' );
+ $page->setFont('helvetica', 6);
+ if (defined('PDF_DEBUG_DRAW_BOX_INFO') && preg_match(PDF_DEBUG_DRAW_BOX_INFO, $this->Node->Name)) {
+ $page->drawText($this->Node->Name . "{$outer_width}x{$outer_height} ".get_class($this), $x+2, $y+8);
+ }
+ }
+ }
+
+ if ($this->GetDisplayLevel() == 'block' && !($this instanceof kPDFLine)) {
+ // MARGINS
+ if (defined('PDF_DEBUG_DRAW_MARGINS')) {
+ $page->SetLineWidth(1);
+ $page->SetLineColor( 'green' );
+ $page->DrawLine($x, $y, $x + $margin_left, $y);
+ $page->DrawLine($x, $y, $x, $y + $margin_bottom);
+ $page->SetLineWidth(0.3);
+ $page->DrawLine($x + $margin_left, $y, $x + $margin_left, $y + 3);
+ $page->DrawLine($x, $y + $margin_top, $x + 3, $y + $margin_top);
+ }
+ $x += $margin_left;
+ $y += $margin_top;
+
+ // BACKGROUND
+ // http://manual.prod.intechnic.lv/css21/colors.html#q2
+ $body = false;
+ if ($this->Node->Name == 'HTML' && $this->GetCSSProperty('background-color') == 'transparent') {
+ // get BODY color
+ $body = $this->FindChild('BODY');
+ if ($body !== false) {
+ $background_color = $body->GetCSSProperty('background-color');
+ $body->SetCSSProperty('background-color', 'transparent');
+ }
+ }
+ else {
+ $background_color = $this->GetCSSProperty('background-color');
+ }
+ if ($background_color != 'transparent') {
+ $page->SetFillColor( $background_color );
+ $x1 = $x + $border_left +
+ $padding_left +
+ $width +
+ $padding_right +
+ $border_right;
+ $y1 = $y + ($border_top +
+ $padding_top +
+ $height +
+ $padding_bottom +
+ $border_bottom);
+ $page->DrawRectangle($x, $y, $x1, $y1, kPDFRenderer::SHAPE_DRAW_FILL);
+ }
+
+ // BORDERS
+ $x2 = $x + $border_left + $padding_left + $width + $padding_right + $border_right;
+ $y2 = $y + ($border_top + $padding_top + $height + $padding_bottom + $border_bottom);
+
+ if ($this->GetCSSProperty('border-top-style') != 'none' && $border_top > 0) {
+ $page->SetLineWidth($this->GetCSSProperty('border-top-width'));
+ $page->SetLineColor( $this->GetCSSProperty('border-top-color') );
+ $page->DrawLine($x+$border_left/2, $y+$border_top/2, $x2-$border_right/2, $y+$border_top/2);
+ }
+ if ($this->GetCSSProperty('border-right-style') != 'none' && $border_right > 0) {
+ $page->SetLineWidth($this->GetCSSProperty('border-right-width'));
+ $page->SetLineColor( $this->GetCSSProperty('border-right-color') );
+ $page->DrawLine($x2-$border_right/2, $y+$border_top/2, $x2-$border_right/2, $y2-$border_bottom/2);
+ }
+ if ($this->GetCSSProperty('border-bottom-style') != 'none' && $border_bottom > 0) {
+ $page->SetLineWidth($this->GetCSSProperty('border-bottom-width'));
+ $page->SetLineColor( $this->GetCSSProperty('border-bottom-color') );
+ $page->DrawLine($x+$border_left/2, $y2-$border_bottom/2, $x2-$border_right/2, $y2-$border_bottom/2);
+ }
+ if ($this->GetCSSProperty('border-left-style') != 'none' && $border_left > 0) {
+ $page->SetLineWidth($this->GetCSSProperty('border-left-width'));
+ $page->SetLineColor( $this->GetCSSProperty('border-left-color'));
+ $page->DrawLine($x+$border_left/2, $y+$border_top/2, $x+$border_left/2, $y2-$border_bottom/2);
+ }
+ $x += $border_left;
+ $y += $border_top;
+
+ // PADDING
+ $x += $this->GetCSSProperty('padding-left');
+ $y += $this->GetCSSProperty('padding-top');
+
+ if (defined('PDF_DRAW_CONTENT_AREA') && $this->Parent) {
+ $page->SetFillColor( 'pink' ) ;
+ $page->DrawRectangle($x, $y, $x + $width, $y + $height, kPDFRenderer::SHAPE_DRAW_FILL);
+ }
+
+ }
+
+ $this->CurX = $x;
+ $this->CurY = $y;
+// $max_width = $this->GetCSSProperty('max-width');
+ $this->TopLine = $y;
+ $page->SetLineWidth(0.1);
+
+ foreach ($this->Children as $elem)
+ {
+ $dim = $elem->GetBoxDimensions();
+ $align_offset_x = 0;
+ $align_offset_y = 0;
+ if ($elem->GetDisplayLevel() == 'inline') {
+ if ($this->GetCSSProperty('vertical-align') == 'baseline') {
+ $align_offset_y = $this->Ascent - $elem->Ascent;
+ }
+ }
+ if (defined('PDF_DEBUG_DRAW_BASELINE')) {
+ $page->SetLineWidth(0.5);
+ $page->SetLineColor( '#ff0000' );
+ $page->DrawLine($this->CurX, $this->CurY + $elem->Ascent, $this->CurX + $dim[0], $this->CurY + $elem->Ascent);
+ }
+ if ($elem instanceof kPDFLine ) {
+ $spacer_w = 0;
+ switch ($elem->GetCSSProperty('text-align')) {
+ case 'center':
+ $align_offset_x = ($dim[0] - $elem->CurX)/2;
+ break;
+ case 'right':
+ $align_offset_x = ($dim[0] - $elem->CurX);
+ break;
+ case 'justify':
+ $spacer_w = $elem->LastLine ? 0 : ($dim[0] - $elem->CurX)/$elem->Spacers;
+ }
+ }
+ if (defined('PDF_DEBUG_DRAW_ELEM_BORDERS')) {
+ $page->SetLineWidth(0.1);
+ $page->SetLineColor( '#bbbbbb' );
+ $page->SetFillColor( '#bbbbbb' );
+ $page->setFont('helvetica', 4);
+ $page->DrawRectangle($this->CurX, $this->CurY + $align_offset_y, $this->CurX + $dim[0], $this->CurY + $align_offset_y + $dim[1], kPDFRenderer::SHAPE_DRAW_STROKE);
+ if (defined('PDF_DEBUG_DRAW_BOX_INFO') && preg_match(PDF_DEBUG_DRAW_BOX_INFO, $this->Node->Name) && $elem->GetDisplayLevel() != 'block') {
+ $page->drawText("w:{$dim[0]}x{$dim[1]}", $this->CurX + 2, $this->CurY + $align_offset_y + 6);
+ }
+ }
+ $tmp_x = $this->CurX;
+ $this->CheckPageBreak($page, $elem, $dim);
+ $elem->DrawAt($page, $this->CurX + $align_offset_x, $this->CurY + $align_offset_y, $spacer_w);
+ if ($elem->GetDisplayLevel() == 'block' && $elem->GetCSSProperty('display') != 'table-cell') {
+ $this->CurY += $dim[1];
+ $this->CurX = $tmp_x;
+ }
+ else {
+ $this->CurX = $this->CurX + $dim[0] + ($elem->Spacers*$spacer_w);
+ }
+ }
+ if ($this->GetCSSProperty('PAGE-BREAK-AFTER') == 'always') {
+ $this->Helper->PDF->NextPage();
+ $this->Parent->CurY = $this->Helper->Document->GetCSSProperty('margin-top');
+ }
+ }
+
+ function CheckPageBreak($page, $elem, $dim)
+ {
+ if (($this->GetCSSProperty('DISPLAY') != 'block' && $this->GetCSSProperty('DISPLAY') != 'table') || $elem->Node->Name == 'BODY' || $elem->Node->Name == 'HTML') return;
+
+ if ($this->CurY + $dim[1] > $this->Helper->PageBottom) {
+ $this->Helper->PDF->NextPage();
+ $this->CurY = $this->Helper->Document->FindChild('BODY')->GetCSSProperty('margin-top');
+ }
+ }
+
+ function GetBoxDimensions()
+ {
+ return array(
+ $this->GetCSSProperty('margin-left') +
+ $this->GetCSSProperty('border-left-width') +
+ $this->GetCSSProperty('padding-left') +
+ $this->GetCSSProperty('width') +
+ $this->GetCSSProperty('padding-right') +
+ $this->GetCSSProperty('border-right-width') +
+ $this->GetCSSProperty('margin-right'),
+
+ $this->GetCSSProperty('margin-top') +
+ $this->GetCSSProperty('border-top-width') +
+ $this->GetCSSProperty('padding-top') +
+ $this->GetCSSProperty('height') +
+ $this->GetCSSProperty('padding-bottom') +
+ $this->GetCSSProperty('border-bottom-width') +
+ $this->GetCSSProperty('margin-bottom'),
+ );
+ }
+
+ function GetLineBox($first=false) {
+ if ($this instanceof kPDFLine ) {
+ if ($first) {
+ return $this->Parent->FirstChild;
+ }
+ else {
+ return $this;
+ }
+ }
+ if ($this->GetDisplayLevel() == 'block') {
+ if ($this->LastChild instanceof kPDFLine ) {
+ return $this->LastChild;
+ }
+ return $this->AddChild( new kPDFLine($this->Node, $this->Helper));
+ }
+
+ //in-line box
+ return $this->Parent->GetLineBox();
+ }
+
+ function GetTable() {
+ if ($this instanceof kPDFTable) {
+ return $this;
+ }
+ if ($this->Parent) {
+ return $this->Parent->GetTable();
+ }
+ return false;
+ }
+
+ function GetDisplayLevel()
+ {
+ // http://manual.prod.intechnic.lv/css21/visuren.html#q5
+ $display = $this->GetCSSProperty('display');
+ if (!$display) $display = $this->CSSSpecifiedProperties['DISPLAY'];
+ switch ($display) {
+ case 'block':
+ case 'list-item':
+ case 'table':
+ case 'table-cell':
+ case 'table-row':
+ case 'table':
+ return 'block';
+ case 'run-in':
+ // do special processing here: http://manual.prod.intechnic.lv/css21/visuren.html#run-in
+ return 'block';
+ case 'none':
+ return 'none';
+ }
+ return 'inline';
+ }
+
+ function ProcessCSS()
+ {
+ $supported_properties = array(
+ 'DISPLAY',
+ 'FONT-SIZE', // SHOULD BE FIRST, BECAUSE ALL EM UNITS RELY ON IT
+ 'WIDTH','MAX-WIDTH','MIN-WIDTH',
+ 'HEIGHT',
+ 'COLOR',
+ 'FONT-FAMILY', 'FONT-WEIGHT', 'FONT-STYLE', 'FONT-VARIANT',
+ 'WHITE-SPACE',
+ 'VERTICAL-ALIGN',
+ 'MARGIN-LEFT', 'MARGIN-RIGHT', 'MARGIN-TOP', 'MARGIN-BOTTOM',
+ 'BORDER-TOP-STYLE', 'BORDER-RIGHT-STYLE', 'BORDER-BOTTOM-STYLE', 'BORDER-LEFT-STYLE',
+ 'BORDER-TOP-WIDTH', 'BORDER-RIGHT-WIDTH', 'BORDER-BOTTOM-WIDTH', 'BORDER-LEFT-WIDTH',
+ 'BORDER-TOP-COLOR', 'BORDER-RIGHT-COLOR', 'BORDER-BOTTOM-COLOR', 'BORDER-LEFT-COLOR',
+ 'PADDING-TOP', 'PADDING-RIGHT', 'PADDING-BOTTOM', 'PADDING-LEFT',
+ 'BACKGROUND-COLOR',
+ 'TEXT-ALIGN', 'TEXT-TRANSFORM',
+ 'TABLE-LAYOUT',
+ 'PAGE-BREAK-AFTER'
+ );
+
+ $cascade = $this->Helper->Stylesheet->GetAllProperties($this->Node);
+
+ foreach ($supported_properties as $property) {
+ $value = false;
+ // !!! The following needs to be fixed somehow - thereis no major need in cascading properties for kPDFTextElement and kPDFLine also...
+ if (!($this instanceof kPDFTextElement) || ($this instanceof kPDFTextElement && $property != 'DISPLAY')) {
+ $value = isset($cascade[$property]) ? $cascade[$property] : false;
+ }
+ if (!$value && kCSSDefaults::IsInherited($property)) {
+ $value = $this->FindInheritedValue($property);
+ }
+ if (!$value) {
+ $value = kCSSDefaults::GetDefaultValue($property);
+ }
+ $this->CSSSpecifiedProperties[$property] = $value;
+ }
+ $this->Node->CssProperties = $this->CSSSpecifiedProperties;
+ }
+
+ function FindInheritedValue($property)
+ {
+ $node = $this->Node;
+ if (!$node->Parent) {
+ return false;
+ }
+ do {
+ $node = $node->Parent;
+ $value = isset($node->ComputedCSSProperties[$property]) ? $node->ComputedCSSProperties[$property] : false;
+ } while (!$value && $node->Parent);
+ return $value;
+ }
+
+ function ComputeCSSProperties()
+ {
+ foreach ($this->CSSSpecifiedProperties as $property => $value) {
+ $this->SetCSSProperty($property, $this->ComputeCSSProperty($property, $value));
+ }
+ $this->ComputeWidthAndMargins();
+ /*if ($this->GetDisplayLevel() == 'inline') {
+ $props = array(
+ 'margin-top' => 0,
+ 'margin-right' => 0,
+ 'margin-bottom' => 0,
+ 'margin-left' => 0,
+ 'width' => 0,
+ );
+ foreach ($props as $name => $value) {
+ $this->SetCSSProperty($name, $value);
+ }
+ }*/
+ $this->Node->ComputedCSSProperties = $this->CSSComputedPoperties;
+ }
+
+ function ComputeWidthAndMargins()
+ {
+ if ($this->WidthComputed) return ;
+
+ if ($this->GetDisplayLevel() == 'inline') {
+ return;
+ }
+
+ if (!$this->Parent) {
+ $this->WidthComputed = true;
+ return ;
+ }
+ $cb = $this->GetContainingBlock();
+ $cb_width = $cb->GetCSSProperty('width'); // containing block width
+ if (!$cb->WidthComputed) { // this means we are inside an element which width is not yet defined (nested TABLE for instance)
+ return ;
+ }
+ if ($this instanceof kPDFLine) { // otherwise margins will be applied from line containing block to the line
+ $this->SetCSSProperty('width', $cb_width);
+ return;
+ }
+
+ // 'margin-left' + 'border-left-width' + 'padding-left' + 'width' + 'padding-right' + 'border-right-width' + 'margin-right' = width of containing block
+ $width = $this->GetCSSProperty('width'); // may be auto
+ $margin_left = $this->GetCSSProperty('margin-left'); // may be auto
+ $margin_right = $this->GetCSSProperty('margin-right'); // may be auto
+ $border_left = $this->GetCSSProperty('border-left-width');
+ $border_right = $this->GetCSSProperty('border-right-width');
+ $padding_left = $this->GetCSSProperty('padding-left');
+ $padding_right = $this->GetCSSProperty('padding-right');
+
+ if ($width == 'auto' && $this->Parent) {
+ if ($margin_left == 'auto') {
+ $margin_left = 0;
+ }
+ if ($margin_right == 'auto') {
+ $margin_right = 0;
+ }
+ $width = $cb_width - $margin_left - $border_left - $padding_left - $padding_right - $border_right - $margin_right;
+ }
+ elseif ($margin_left != 'auto' && $margin_right != 'auto') { //over-constrained
+ $margin_right = $cb_width - $width - $margin_left - $border_left - $padding_left - $padding_right - $border_right;
+ }
+ elseif ($margin_left == 'auto' && $margin_right == 'auto') {
+ $margin_left = ($cb_width - $border_left - $padding_left - $width - $padding_right - $border_right)/2;
+ $margin_right = $margin_left;
+ }
+
+ $this->SetCSSProperty('width', $width);
+ $this->SetCSSProperty('margin-right', $margin_right);
+ $this->SetCSSProperty('margin-left', $margin_left);
+ $this->WidthComputed = true;
+ }
+
+ function ComputeCSSProperty($property, $value)
+ {
+ if ($property == 'FONT-WEIGHT') {
+ if ($value == 'normal') {
+ return 400;
+ }
+ if ($value == 'bold') {
+ return 700;
+ }
+ if ($value == 'bolder') {
+ if (!$this->Parent) {
+ return 700;
+ }
+ else {
+ return max($this->Parent->GetCSSProperty('font-weight') + 300, 900);
+ }
+ }
+ if ($value == 'lighter') {
+ if (!$this->Parent) {
+ return 400;
+ }
+ else {
+ return min($this->Parent->GetCSSProperty('font-weight') - 300, 100);
+ }
+ }
+ if (!is_integer($value)) {
+ return 400;
+ }
+ return $value;
+ }
+
+ if (preg_match('/([.0-9]+)em/i', $value, $regs)) {
+ $cb = $this->GetContainingBlock();
+ if ($property == 'FONT-SIZE') {
+ if (!$cb) {
+ $value = $regs[1] * $this->Helper->PtPerEm;
+ }
+ else {
+ $value = $cb->GetCSSProperty('font-size') * $regs[1];
+ }
+ }
+ else {
+ if ($cb) {
+ $value = $cb->GetCSSProperty('font-size') * $regs[1];
+ }
+ }
+ }
+ elseif (preg_match('/([.0-9]+)(px)/i', $value, $regs)) {
+ $value = $regs[1] * 72 / 96;
+ }
+ elseif (preg_match('/([.0-9]+)(pt)/i', $value, $regs)) {
+ $value = $regs[1];
+ }
+ elseif (preg_match('/([.0-9]+)%/i', $value, $regs)) {
+ $cb = $this->GetContainingBlock();
+ if ($cb && ($property != 'WIDTH' || ($property == 'WIDTH' && $cb->WidthComputed))) {
+ $value = $regs[1]/100 * $cb->GetCSSProperty($property);
+ }
+ }
+
+ if ($property == 'FONT-SIZE' && preg_match('/(xx-small|x-small|small|medium|large|x-large|xx-large)/i', $value)) {
+ switch (strtolower($value)) {
+ case 'xx-small':
+ return $this->Helper->PtPerEm * 0.5;
+ case 'x-small':
+ return $this->Helper->PtPerEm * 0.7;
+ case 'small':
+ return $this->Helper->PtPerEm * 0.8;
+ case 'medium':
+ return $this->Helper->PtPerEm;
+ case 'large':
+ return $this->Helper->PtPerEm * 1.2;
+ case 'x-large':
+ return $this->Helper->PtPerEm * 1.4;
+ case 'xx-large':
+ return $this->Helper->PtPerEm * 1.6;
+ }
+ }
+// elseif ($value == 'none') {
+// $value = 0;
+// }
+ return $value;
+ }
+
+ function GetContainingBlock()
+ {
+ if (!$this->Parent) return false;
+ $parent_display = $this->Parent->GetCSSProperty('display');
+ if (preg_match('/^(block|inline-block|table|table-cell|list-item)$/i', $parent_display)) {
+ return $this->Parent;
+ }
+ return $this->Parent->GetContainingBlock();
+ }
+
+ function GetCSSProperty($property)
+ {
+ $property = strtoupper($property);
+ return isset($this->CSSComputedPoperties[$property]) ? $this->CSSComputedPoperties[$property] : false;
+ }
+
+ function SetCSSProperty($name, $value)
+ {
+ $this->CSSComputedPoperties[strtoupper($name)] = $value;
+ }
+
+ function CheckDimensions()
+ {
+ $this->ComputeBaseline();
+ }
+
+ function ComputeBaseline()
+ {
+ if (!$this->Parent) return ;
+ $display = $this->GetCSSProperty('display');
+ /*$dim = $this->GetBoxDimensions();
+ $this->Ascent = $dim[1];*/
+ if ($display == 'inline' || $display == 'table-cell' || $this instanceof kPDFLine) {
+ if ($this->Parent->Ascent < $this->Ascent) {
+ $this->Parent->Ascent = $this->Ascent;
+ }
+ if ($this->Parent->Descent < $this->Descent) {
+ $this->Parent->Descent = $this->Descent;
+ }
+ if ($this->Parent->Gap < $this->Gap) {
+ $this->Parent->Gap = $this->Gap;
+ }
+ $this->Parent->ComputeBaseline();
+ }
+ }
+
+ function ContentWidthNewLine()
+ {
+ if ($this->CurLine_MinContentWidth > $this->MinContentWidth) {
+ $this->MinContentWidth = $this->CurLine_MinContentWidth;
+ }
+ if ($this->CurLine_MaxContentWidth > $this->MaxContentWidth) {
+ $this->MaxContentWidth = $this->CurLine_MaxContentWidth;
+ }
+ $this->CurLine_MinContentWidth = 0;
+ $this->CurLine_MaxContentWidth = 0;
+ }
+
+ function CalcMinMaxContentWidth() {
+ if (!$this->Parent) return ;
+ $this->ContentWidthNewLine();
+ $extra_width =
+ $this->GetCSSProperty('margin-left') +
+ $this->GetCSSProperty('margin-right') +
+ $this->GetCSSProperty('padding-left') +
+ $this->GetCSSProperty('padding-right') +
+ $this->GetCSSProperty('border-left-width') +
+ $this->GetCSSProperty('border-right-width');
+// $extra_width = 0;
+ $this->MinContentWidth += $extra_width;
+ $this->MaxContentWidth += $extra_width;
+ $display = $this->GetCSSProperty('display');
+
+ if (($display == 'inline' || $display == 'table-cell')) {
+ $this->Parent->CurLine_MinContentWidth += $this->MinContentWidth;
+ $this->Parent->CurLine_MaxContentWidth += $this->MaxContentWidth;
+ if ($this->Node->Name == 'BR') {
+ $this->Parent->ContentWidthNewLine();
+ }
+ }
+ else {
+ if ($this->MinContentWidth > $this->Parent->MinContentWidth) {
+ $this->Parent->MinContentWidth = $this->MinContentWidth;
+// $this->Parent->CalcMinMaxContentWidth();
+ }
+ if ($this->MaxContentWidth > $this->Parent->MaxContentWidth) {
+ $this->Parent->MaxContentWidth = $this->MaxContentWidth;
+// $this->Parent->CalcMinMaxContentWidth();
+ }
+ }
+// $this->ContentWidthNewLine();
+ }
+
+
+}
+
+class kPDFLine extends kPDFElement {
+ public $LastLine = true;
+
+ function __construct($node, $helper)
+ {
+ $line_node = new kXMLNode('_LINE_', array('STYLE' => 'display: block'));
+// $line_node->SetParent($node);
+ $node->AddChild($line_node);
+ parent::__construct($line_node, $helper);
+ }
+
+ function Init()
+ {
+ parent::Init();
+ $this->SetCSSProperty('display', 'block');
+ $this->SetCSSProperty('margin-left', '0');
+ $this->SetCSSProperty('margin-right', '0');
+ $this->SetCSSProperty('margin-top', '0');
+ $this->SetCSSProperty('margin-bottom', '0');
+ $this->SetCSSProperty('padding-left', '0');
+ $this->SetCSSProperty('padding-right', '0');
+ $this->SetCSSProperty('padding-top', '0');
+ $this->SetCSSProperty('padding-bottom', '0');
+ }
+
+}
Property changes on: branches/RC/core/units/pdf/pdf_helper.php
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.6.1
\ No newline at end of property
Index: branches/RC/core/units/general/helpers/controls/minput_helper.php
===================================================================
--- branches/RC/core/units/general/helpers/controls/minput_helper.php (revision 10293)
+++ branches/RC/core/units/general/helpers/controls/minput_helper.php (revision 10294)
@@ -1,124 +1,185 @@
<?php
class MInputHelper extends kHelper {
/**
* Returns user education table name
*
* @param kDBItem $object
* @return string
*/
function getTable($prefix, $temp=false)
{
$table_name = $this->Application->getUnitOption($prefix, 'TableName');
return $temp ? $this->Application->GetTempName($table_name, 'prefix:'.$prefix) : $table_name;
}
function prepareMInputXML($records, $use_fields)
{
$xml = '';
foreach ($records as $record) {
$xml .= '<record>';
foreach ($record as $field_name => $field_value) {
if (!in_array($field_name, $use_fields)) {
continue;
}
$xml .= '<field name="'.$field_name.'">'.$field_value.'</field>';
}
$xml .= '</record>';
}
return $xml ? '<records>'.$xml.'</records>' : '';
}
function prepareErrorsXML(&$object, $fields_hash)
{
$xml = '';
foreach ($fields_hash as $field_name => $field_value) {
$object->SetField($field_name, $field_value);
if (!$object->ValidateField($field_name)) {
$xml .= '<field name="'.$field_name.'">'.$object->GetErrorMsg($field_name, false).'</field>';
}
}
return '<errors>'.$xml.'</errors>';
}
/**
* Validates MInput control fields
*
* @param kEvent $event
*/
function OnValidateMInputFields(&$event)
{
$object =& $event->getObject();
/* @var $object kDBItem */
$items_info = $this->Application->GetVar($event->getPrefixSpecial(true));
if ($items_info) {
list ($id, $field_values) = each($items_info);
echo $this->prepareErrorsXML($object, $field_values);
}
$event->status = erSTOP;
}
function parseMInputXML($xml)
{
$xml_helper =& $this->Application->recallObject('kXMLHelper');
/* @var $xml_helper kXMLHelper */
$root_node =& $xml_helper->Parse($xml);
$root_node =& $root_node->FindChild('records');
if (!$root_node || !$root_node->firstChild) {
return false;
}
$records = Array ();
$current_node = $root_node->firstChild;
/* @var $current_node kXMLNode */
do {
$record = Array();
$sub_node =& $current_node->firstChild;
/* @var $current_node kXMLNode */
do {
$record[$sub_node->Attributes['NAME']] = $sub_node->Data;
}while ( ($sub_node =& $sub_node->NextSibling()) );
$records[] = $record;
} while (($current_node =& $current_node->NextSibling()));
return $records;
}
/**
* Loads selected values from sub_prefix to main item virtual field.
* Called from OnAfterItemLoad of main prefix.
*
* @param kEvent $event
* @param string $store_field main item's field name, to store values into
* @param string $sub_prefix prefix used to store info about selected items
* @param Array $use_fields fields, used in value string building
*/
function LoadValues(&$event, $store_field, $sub_prefix, $use_fields)
{
$object =& $event->getObject();
/* @var $object kDBItem */
+
+ $sub_item =& $this->Application->recallObject($sub_prefix, null, Array('skip_autoload' => true));
+ /* @var $sub_item kDBItem */
$foreign_key = $this->Application->getUnitOption($sub_prefix, 'ForeignKey');
$sql = 'SELECT *
FROM '.$this->getTable($sub_prefix, $object->IsTempTable()).'
WHERE '.$foreign_key.' = '.$object->GetID();
+
$selected_items = $this->Conn->Query($sql);
+
+ $field_names = array_keys( $sub_item->GetFieldValues() );
+
+ foreach ($selected_items as $key => $fields_hash) {
+ $sub_item->Clear();
+ $sub_item->SetDBFieldsFromHash($fields_hash);
+
+ // to fill *_date and *_time fields from main date fields
+ $sub_item->UpdateFormattersSubFields();
+
+ foreach ($field_names as $field) {
+ $field_options = $sub_item->GetFieldOptions($field);
+ $formatter = array_key_exists('formatter', $field_options) ? $field_options['formatter'] : false;
+
+ if ($formatter == 'kDateFormatter') {
+ $selected_items[$key][$field] = $sub_item->GetField($field);
+ }
+ else {
+ $selected_items[$key][$field] = $sub_item->GetDBField($field);
+ }
+ }
+ }
$object->SetDBField($store_field, $this->prepareMInputXML($selected_items, $use_fields));
}
+
+ /**
+ * Saves data from minput control to subitem table (used from subitem hook)
+ *
+ * @param kEvent $sub_event
+ * @param string $store_field
+ */
+ function SaveValues(&$sub_event, $store_field)
+ {
+ $main_object =& $sub_event->MasterEvent->getObject();
+ $affected_field = $main_object->GetDBField($store_field);
+
+ $object =& $this->Application->recallObject($sub_event->getPrefixSpecial(), null, Array('skip_autoload' => true));
+ /*@var $object kDBItem*/
+
+ $sub_table = $object->TableName;
+ $foreign_key = $this->Application->getUnitOption($sub_event->Prefix, 'ForeignKey');
+
+ $sql = 'DELETE FROM '.$sub_table.'
+ WHERE '.$foreign_key.' = '.$main_object->GetID();
+
+ $this->Conn->Query($sql);
+
+ if ($affected_field) {
+ $records = $this->parseMInputXML($affected_field);
+ $main_id = $main_object->GetID();
+
+ foreach ($records as $fields_hash) {
+ $object->Clear();
+ $fields_hash[$foreign_key] = $main_id;
+ $object->SetDBFieldsFromHash($fields_hash);
+ $object->Create();
+ }
+ }
+ }
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/general/helpers/controls/minput_helper.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.1.8.1
\ No newline at end of property
+1.1.8.2
\ No newline at end of property
Index: branches/RC/core/units/general/xml_helper.php
===================================================================
--- branches/RC/core/units/general/xml_helper.php (revision 10293)
+++ branches/RC/core/units/general/xml_helper.php (revision 10294)
@@ -1,236 +1,298 @@
<?php
class kXMLHelper extends kHelper {
var $RootElement = null;
/**
* Enter description here...
*
* @var kXMLNode
*/
var $CurrentElement = null;
+
+ var $Mode;
/**
* Parses XML data specified and returns root node
*
* @param string $xml
* @return kXMLNode
*/
- function &Parse($xml = null)
+ function &Parse($xml = null, $mode=XML_NO_TEXT_NODES)
{
+ $this->Mode = $mode;
$this->Clear(); // in case if Parse method is called more then one time
$xml_parser = xml_parser_create();
xml_set_element_handler( $xml_parser, Array(&$this, 'startElement'), Array(&$this, 'endElement') );
xml_set_character_data_handler( $xml_parser, Array(&$this, 'characterData') );
if (!xml_parse($xml_parser, $xml, 1)) {
$this->RootElement = new kXMLNode('ERROR', array('code'=>xml_get_error_code($xml_parser),'message'=>xml_error_string(xml_get_error_code($xml_parser))));
trigger_error(sprintf('XML error: %s at line %d',
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_current_line_number($xml_parser)), E_USER_WARNING);
}
xml_parser_free($xml_parser);
$root_copy = $this->RootElement;
return $root_copy;
}
-
+
+ function ConvertHTMLEntities($s){
+ //build first an assoc. array with the entities we want to match
+ $table1 = get_html_translation_table(HTML_ENTITIES, ENT_QUOTES);
+
+ $patterns = array();
+ $replacements = array();
+ //now build another assoc. array with the entities we want to replace (numeric entities)
+ foreach ($table1 as $k=>$v){
+ $patterns[] = "/$v/";
+ // $c = htmlentities($k,ENT_QUOTES,"UTF-8");
+ $replacements[] = "&#".ord($k).";";
+ }
+
+ //now perform a replacement using preg_replace
+ //each matched value in array 1 will be replaced with the corresponding value in array 2
+ $s = preg_replace($patterns,$replacements,$s);
+ return $s;
+ }
+
function startElement(&$Parser, &$Elem, $Attrs)
{
$parent =& $this->CurrentElement; // 1. $parent is now reference to $this->CurrentElement
$this->CurrentElement =& new kXMLNode($Elem, $Attrs); // 2. =& ensures, that new object won't be assigned to $parent as well (don't remove)
if (!isset($this->RootElement) || is_null($this->RootElement)) {
$this->RootElement =& $this->CurrentElement;
}
if (!is_null($parent)) {
$parent->AddChild($this->CurrentElement);
}
}
function characterData($Parser, $Line)
{
+ if ($this->Mode == XML_WITH_TEXT_NODES) {
+ $text_node = new kXMLNode('_TEXT_');
+ $text_node->AppendData($Line);
+ $this->CurrentElement->AddChild( $text_node );
+ }
$this->CurrentElement->AppendData($Line);
}
function endElement($Parser, $Elem)
{
+ if ($this->Mode == XML_WITH_TEXT_NODES) {
+ /*if (count($this->CurrentElement->Children) == 1 && $this->CurrentElement->firstChild->Name == '_TEXT_') {
+ $this->CurrentElement->Children = array();
+ }*/
+ }
if ($this->CurrentElement->Parent != null) {
$this->CurrentElement =& $this->CurrentElement->Parent;
}
}
function Clear()
{
unset($this->RootElement);
unset($this->CurrentElement);
}
}
class kXMLNode {
var $Name = null;
var $Attributes = array();
var $Children = array();
var $Data = null;
var $firstChild = null;
var $lastChild = null;
/**
* Parent node
*
* @var kXMLNode
*/
var $Parent = null;
/**
* Node position relative to other nodes of it's parent
*
* @var int
*/
var $Position = 0;
+
+ var $CRC = null;
function kXMLNode($name, $attrs = array())
{
- $this->Name = $name;
- $this->Attributes = $attrs;
+ $this->Name = strtoupper($name);
+ foreach ($attrs as $attr => $value) {
+ $this->Attributes[strtoupper($attr)] = $value;
+ }
+ $this->CRC = crc32($this->Name.join(array_keys($this->Attributes)).join(array_values($this->Attributes)));
}
function SetParent(&$elem)
{
$this->Parent =& $elem;
}
/**
* Adds new child to current node
*
* @param kXMLNode $a_child
*/
function AddChild(&$a_child)
{
$node_count = count($this->Children);
$a_child->Position = $node_count;
if ($node_count == 0) {
$this->firstChild =& $a_child;
$this->lastChild =& $a_child;
}
else {
$this->lastChild =& $a_child;
}
$this->Children[] =& $a_child;
$a_child->SetParent($this);
}
function AppendData($data)
{
$this->Data .= $data;
}
function &GetChild($path)
{
$entries = explode('/', strtoupper($path));
$cur = array_shift($entries);
if ($cur == $this->Name) $cur = array_shift($entries);
if (!$cur) return $this;
if (!isset($this->Children[$cur])) return false;
$left = implode('/', $entries);
if (!$left) return $this->Children[$cur];
return $this->Children[$cur]->GetChild($left);
}
function GetChildValue($path)
{
$child =& $this->GetChild($path);
if ($child !== false) {
return $child->Data;
}
}
function &GetChildByPosition($position)
{
if ($position < count($this->Children) ) {
return $this->Children[$position];
}
else {
$false = false;
return $false;
}
}
function &FindChild($name)
{
$name = strtoupper($name);
if ($this->Name == $name) return $this;
// if (isset($this->Children[$name])) return $this->Children[$name];
// $children = array_keys($this->Children);
foreach ($this->Children as $elem)
{
$child =& $elem->FindChild($name);
if ($child !== false)
{
return $child;
}
}
$false = false;
return $false;
}
function FindChildValue($name, $attr=null)
{
$child =& $this->FindChild($name);
if ($child !== false) {
if (isset($attr)) {
return $child->Attributes[strtoupper($attr)];
}
return $child->Data;
}
}
+
+ /**
+ * Returns next node to this, false in case of end list
+ *
+ * @return kXMLNode
+ */
+ function &PrevSibling()
+ {
+ if (!is_null($this->Parent) && $this->Position > 0) {
+ $pos = $this->Position - 1;
+ do {
+ $ret =& $this->Parent->GetChildByPosition($pos--);
+ } while ($ret->Name == '_TEXT_' && $pos >= 0);
+ if ($ret->Name == '_TEXT_') $ret = false;
+ return $ret;
+ }
+ else {
+ $false = false;
+ return $false;
+ }
+ }
/**
* Returns next node to this, false in case of end list
*
* @return kXMLNode
*/
function &NextSibling()
{
if (!is_null($this->Parent)) {
- $ret =& $this->Parent->GetChildByPosition($this->Position + 1);
+ $pos = $this->Position + 1;
+ do {
+ $ret =& $this->Parent->GetChildByPosition($pos++);
+ } while ($ret->Name == '_TEXT_' && $pos < count($this->Parent->Children));
+ if ($ret->Name == '_TEXT_') $ret = false;
return $ret;
}
else {
$false = false;
return $false;
}
}
/**
* Reconstructs XML of the node and subnodes
*
* $param bool $content_only
*/
function GetXML($content_only = false)
{
$xml = '';
if (!$content_only) {
$xml = '<'.$this->Name;
if (count($this->Attributes)) {
$xml .= ' ';
$att_contents = array();
foreach ($this->Attributes as $name => $value) {
$att_contents[] = $name.'="'.$value.'"';
}
$xml .= implode(' ', $att_contents);
}
$xml .= '>';
}
$xml .= $this->Data;
foreach ($this->Children as $node) {
$xml .= $node->GetXML();
}
if (!$content_only) {
$xml .= '</'.$this->Name.'>';
}
return $xml;
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/general/xml_helper.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.8.2.6
\ No newline at end of property
+1.8.2.7
\ No newline at end of property
Index: branches/RC/core/units/general/inp_ses_storage.php
===================================================================
--- branches/RC/core/units/general/inp_ses_storage.php (revision 10293)
+++ branches/RC/core/units/general/inp_ses_storage.php (revision 10294)
@@ -1,134 +1,134 @@
<?php
class InpSession extends Session
{
function Init($prefix,$special)
{
$this->SessionTimeout = $this->Application->ConfigValue('SessionTimeout');
$path = (BASE_PATH == '') ? '/' : BASE_PATH;
// if ( $this->Application->IsAdmin() ) $path = rtrim($path, '/').'/admin';
$this->SetCookiePath($path);
$cookie_name = $this->Application->ConfigValue('SessionCookieName');
if (!$cookie_name) $cookie_name = 'sid';
if (($this->Application->IsAdmin() && $special !== 'front') || $special == 'admin' ) { // || $this->Application->GetVar('admin') == 1
$cookie_name = 'adm_'.$cookie_name;
}
$this->SetCookieName($cookie_name);
$this->SetCookieDomain(SERVER_NAME);
if( $this->Application->IsAdmin()) { // && $this->Application->GetVar('admin') != 1
$mode = smAUTO;
}
elseif (constOn('IS_INSTALL')) {
$mode = smCOOKIES_ONLY;
}
else {
$ses_mode = $this->Application->ConfigValue('CookieSessions');
if ($ses_mode == 2) $mode = smAUTO;
if ($ses_mode == 1) $mode = smCOOKIES_ONLY;
if ($ses_mode == 0) $mode = smGET_ONLY;
}
$this->SetMode($mode);
parent::Init($prefix,$special);
if( !$this->Application->IsAdmin() && $this->GetField('PortalUserId') <= 0 )
{
$group_list = $this->Application->ConfigValue('User_GuestGroup').','.$this->Application->ConfigValue('User_LoggedInGroup');
$this->SetField('GroupId', $this->Application->ConfigValue('User_GuestGroup'));
$this->SetField('GroupList', $group_list);
}
}
function Destroy()
{
$this->Storage->DeleteSession($this);
$this->Storage->DeleteEditTables();
$this->Data =& new Params();
$this->SID = '';
if ($this->CookiesEnabled) $this->SetSessionCookie(); //will remove the cookie due to value (sid) is empty
$this->SetSession(); //will create a new session
}
}
class InpSessionStorage extends SessionStorage {
function Init($prefix,$special)
{
parent::Init($prefix,$special);
$this->setTableName(TABLE_PREFIX.'UserSession');
$this->SessionDataTable = TABLE_PREFIX.'SessionData';
$this->setIDField('SessionKey');
$this->TimestampField = 'LastAccessed';
$this->DataValueField = 'VariableValue';
$this->DataVarField = 'VariableName';
}
function LocateSession($sid)
{
$res = parent::LocateSession($sid);
if ($res) {
$this->Expiration += $this->SessionTimeout;
}
return $res;
}
function UpdateSession(&$session)
{
$time = adodb_mktime();
// Update LastAccessed only if it's newer than 1/10 of session timeout - perfomance optimization to eliminate needless updates on every click
- if ($time - $this->DirectVars['LastAccessed'] > $this->SessionTimeout/10) {
- $this->SetField($session, $this->TimestampField, $time);
- }
+// if ($time - $this->DirectVars['LastAccessed'] > $this->SessionTimeout/10) {
+ $this->SetField($session, $this->TimestampField, $time + $this->SessionTimeout);
+// }
}
function StoreSession(&$session, $additional_fields = Array())
{
$fields_hash = Array( 'PortalUserId' => $this->Application->IsAdmin() ? 0 : -2, // Guest
'Language' => $this->Application->GetDefaultLanguageId(),
'Theme' => $this->Application->GetDefaultThemeId(),
'IpAddress' => $_SERVER['REMOTE_ADDR'],
'GroupId' => $this->Application->ConfigValue('User_GuestGroup'),
'GroupList' => $this->Application->ConfigValue('User_GuestGroup'),
'CurrentTempKey'=> $session->SID,
);
parent::StoreSession($session, $fields_hash);
}
function GetExpiredSIDs()
{
- $query = ' SELECT '.$this->IDField.' FROM '.$this->TableName.' WHERE '.$this->TimestampField.' < '.(adodb_mktime()-$this->SessionTimeout);
+ $query = ' SELECT '.$this->IDField.' FROM '.$this->TableName.' WHERE '.$this->TimestampField.' < '.(adodb_mktime());
$ret = $this->Conn->GetCol($query);
if($ret) {
$this->DeleteEditTables();
}
return $ret;
}
function DeleteEditTables()
{
$tables = $this->Conn->GetCol('SHOW TABLES');
$mask_edit_table = '/'.TABLE_PREFIX.'ses_(.*)_edit_(.*)/';
$mask_search_table = '/'.TABLE_PREFIX.'ses_(.*?)_(.*)/';
$sql='SELECT COUNT(*) FROM '.$this->TableName.' WHERE '.$this->IDField.' = \'%s\'';
foreach($tables as $table)
{
if( preg_match($mask_edit_table,$table,$rets) || preg_match($mask_search_table,$table,$rets) )
{
$sid = preg_replace('/(.*)_(.*)/', '\\1', $rets[1]); // remove popup's wid from sid
$is_alive = $this->Conn->GetOne( sprintf($sql,$sid) );
if(!$is_alive) $this->Conn->Query('DROP TABLE IF EXISTS '.$table);
}
}
}
}
?>
\ No newline at end of file
Property changes on: branches/RC/core/units/general/inp_ses_storage.php
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.23.2.1
\ No newline at end of property
+1.23.2.2
\ No newline at end of property
Index: branches/RC/core/admin_templates/logs/session_logs/session_log_list.tpl
===================================================================
--- branches/RC/core/admin_templates/logs/session_logs/session_log_list.tpl (nonexistent)
+++ branches/RC/core/admin_templates/logs/session_logs/session_log_list.tpl (revision 10294)
@@ -0,0 +1,74 @@
+<inp2:m_include t="incs/header" />
+
+<inp2:m_RenderElement name="combined_header" section="in-portal:session_logs" prefix="session-log" title_preset="" pagination="1"/>
+
+<!-- ToolBar --->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+<tbody>
+ <tr>
+ <td>
+ <table width="100%" cellpadding="0" cellspacing="0">
+ <tr>
+ <td >
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+
+ function edit()
+ {
+
+ }
+
+ a_toolbar.AddButton( new ToolBarButton('view', '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>', function(id) {
+ show_viewmenu(a_toolbar,'view');
+ }
+ ) );
+
+ a_toolbar.Render();
+ </script>
+ </td>
+
+ <inp2:m_RenderElement name="search_main_toolbar" prefix="session-log" grid="Default"/>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</tbody>
+</table>
+
+<style type="text/css">
+ tr.row-active td {
+ background-color: #EAFFDC;
+ }
+ tr.row-expired td {
+ color: #555;
+ }
+</style>
+
+<inp2:m_DefineElement name="row_class">
+ <inp2:m_if check="FieldEquals" field="Status" value="0">
+ row-active
+ <inp2:m_else/>
+ <inp2:m_if check="FieldEquals" field="Status" value="2">
+ row-expired
+ </inp2:m_if>
+ </inp2:m_if>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="affected_td">
+ <inp2:m_if check="m_ModuleEnabled" module="Proj-Base">
+ <inp2:Field name="SessionLogId" result_to_var="sessionlog_id"/>
+ <a href="<inp2:m_t t="logs/change_logs/change_log_list" pass="m,change-log" grid_name="Default" custom_filters[change-log][Default][SessionLogId][like]="$sessionlog_id" change-log_event="OnSearch"/>"><inp2:Field name="AffectedItems"/></a>
+ <inp2:_else/>
+ <td valign="top" class="text" style="<inp2:m_param name="td_style"/>">
+ <inp2:Field name="SessionLogId" result_to_var="sessionlog_id"/>
+ <a href="<inp2:m_t t="logs/change_logs/change_log_list" pass="m,change-log" grid_name="Default" custom_filters[change-log][Default][SessionLogId][like]="$sessionlog_id" change-log_event="OnSearch"/>"><inp2:Field name="AffectedItems"/></a>
+ </td>
+ </inp2:m_if>
+</inp2:m_DefineElement>
+
+<inp2:m_ParseBlock name="grid" PrefixSpecial="session-log" IdField="SessionLogId" grid="Default" grid_filters="1" limited_heights="1" row_class_render_as="row_class"/>
+<script type="text/javascript">
+ Grids['session-log'].SetDependantToolbarButtons( new Array() );
+</script>
+
+<inp2:m_include t="incs/footer"/>
\ No newline at end of file
Property changes on: branches/RC/core/admin_templates/logs/session_logs/session_log_list.tpl
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.2.1
\ No newline at end of property
Index: branches/RC/core/admin_templates/logs/change_logs/change_log_list.tpl
===================================================================
--- branches/RC/core/admin_templates/logs/change_logs/change_log_list.tpl (nonexistent)
+++ branches/RC/core/admin_templates/logs/change_logs/change_log_list.tpl (revision 10294)
@@ -0,0 +1,86 @@
+<inp2:m_include t="incs/header" />
+
+<inp2:m_RenderElement name="combined_header" section="in-portal:change_logs" prefix="change-log" title_preset="" pagination="1"/>
+
+<!-- ToolBar --->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+<tbody>
+ <tr>
+ <td>
+ <table width="100%" cellpadding="0" cellspacing="0">
+ <tr>
+ <td >
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+
+
+ function edit()
+ {
+ std_edit_item('change-log', 'logs/change_logs/change_log_edit');
+ }
+
+ a_toolbar.AddButton( new ToolBarButton('view_item', '<inp2:m_phrase label="la_ToolTip_ViewItem" escape="1"/>::<inp2:m_phrase label="la_ShortToolTip_View" escape="1"/>', edit) );
+
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+
+ a_toolbar.AddButton( new ToolBarButton('view', '<inp2:m_phrase label="la_ToolTip_View" escape="1"/>', function(id) {
+ show_viewmenu(a_toolbar,'view');
+ }
+ ) );
+
+ a_toolbar.Render();
+ </script>
+ </td>
+
+ <inp2:m_RenderElement name="search_main_toolbar" prefix="change-log" grid="Default"/>
+ </tr>
+ </table>
+ </td>
+ </tr>
+</tbody>
+</table>
+
+<style type="text/css">
+ tr.row-create td {
+ background-color: #F0FFE6;
+ }
+
+ tr.row-update td {
+ background-color: #FFFFE6;
+ }
+
+ tr.row-delete td {
+ background-color: #FFE6E6;
+ }
+</style>
+
+<inp2:m_DefineElement name="row_class">
+ <inp2:m_if check="FieldEquals" field="Action" value="1">
+ row-create
+ <inp2:m_else/>
+ <inp2:m_if check="FieldEquals" field="Action" value="2">
+ row-update
+ <inp2:m_else/>
+ row-delete
+ </inp2:m_if>
+ </inp2:m_if>
+</inp2:m_DefineElement>
+
+<inp2:m_DefineElement name="grid_changes_td" format="" no_special="" nl2br="" first_chars="" td_style="">
+ <inp2:m_if check="m_ModuleEnabled" module="Proj-Base">
+ <inp2:Field field="$field" first_chars="$first_chars" nl2br="$nl2br" grid="$grid" no_special="1" format="$format"/>
+ <inp2:_else/>
+ <td valign="top" class="text" style="<inp2:m_param name="td_style"/>">
+ <inp2:Field field="$field" first_chars="$first_chars" nl2br="$nl2br" grid="$grid" no_special="1" format="$format"/>
+ </td>
+ </inp2:m_if>
+</inp2:m_DefineElement>
+
+<inp2:m_ParseBlock name="grid" PrefixSpecial="change-log" IdField="ChangeLogId" grid="Default" grid_filters="1" limited_heights="1" row_class_render_as="row_class"/>
+<script type="text/javascript">
+ Grids['change-log'].SetDependantToolbarButtons( new Array('edit', 'delete') );
+</script>
+
+<inp2:m_include t="incs/footer"/>
Property changes on: branches/RC/core/admin_templates/logs/change_logs/change_log_list.tpl
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.2.1
\ No newline at end of property
Index: branches/RC/core/admin_templates/logs/change_logs/change_log_edit.tpl
===================================================================
--- branches/RC/core/admin_templates/logs/change_logs/change_log_edit.tpl (nonexistent)
+++ branches/RC/core/admin_templates/logs/change_logs/change_log_edit.tpl (revision 10294)
@@ -0,0 +1,88 @@
+<inp2:adm_SetPopupSize width="750" height="570"/>
+<inp2:m_include t="incs/header" body_properties="" />
+
+<inp2:m_RenderElement name="combined_header" section="in-portal:change_logs" prefix="change-log" title_preset="changelog_edit" pagination="0"/>
+
+<!-- ToolBar --->
+<table class="toolbar" height="30" cellspacing="0" cellpadding="0" width="100%" border="0">
+<tbody>
+ <tr>
+ <td>
+ <script type="text/javascript">
+ a_toolbar = new ToolBar();
+ a_toolbar.AddButton( new ToolBarButton('select', '<inp2:m_phrase label="la_ToolTip_Save" escape="1"/>', function() {
+ submit_event('change-log','<inp2:change-log_SaveEvent/>');
+ }
+ ));
+ a_toolbar.AddButton( new ToolBarButton('cancel', '<inp2:m_phrase label="la_ToolTip_Cancel" escape="1"/>', function() {
+ cancel_edit('change-log','OnCancelEdit','<inp2:change-log_SaveEvent/>','<inp2:m_Phrase label="la_FormCancelConfirmation" escape="1"/>');
+ }
+ ));
+
+ a_toolbar.AddButton( new ToolBarButton('reset_edit', '<inp2:m_phrase label="la_ToolTip_Reset" escape="1"/>', function() {
+ reset_form('change-log', 'OnReset', '<inp2:m_Phrase label="la_FormResetConfirmation" escape="1"/>');
+ }
+ ));
+
+ a_toolbar.AddButton( new ToolBarSeparator('sep1') );
+
+ a_toolbar.AddButton( new ToolBarButton('prev', '<inp2:m_phrase label="la_ToolTip_Prev" escape="1"/>', function() {
+ go_to_id('change-log', '<inp2:change-log_PrevId/>');
+ }
+ ));
+ a_toolbar.AddButton( new ToolBarButton('next', '<inp2:m_phrase label="la_ToolTip_Next" escape="1"/>', function() {
+ go_to_id('change-log', '<inp2:change-log_NextId/>');
+ }
+ ));
+
+ a_toolbar.Render();
+
+ <inp2:m_if check="change-log_IsSingle">
+ a_toolbar.HideButton('prev');
+ a_toolbar.HideButton('next');
+ a_toolbar.HideButton('sep1');
+ <inp2:m_else/>
+ <inp2:m_if check="change-log_IsLast">
+ a_toolbar.DisableButton('next');
+ </inp2:m_if>
+ <inp2:m_if check="change-log_IsFirst">
+ a_toolbar.DisableButton('prev');
+ </inp2:m_if>
+ </inp2:m_if>
+ </script>
+
+
+ <script src="js/swfobject.js" type="text/javascript"></script>
+ <script type="text/javascript" src="js/uploader.js"></script>
+ </td>
+
+ </tr>
+</tbody>
+</table>
+
+<inp2:change-log_SaveWarning name="grid_save_warning"/>
+<inp2:change-log_ErrorWarning name="form_error_warning"/>
+<div id="scroll_container">
+<table class="edit-form">
+ <inp2:m_ParseBlock name="subsection" title="!la_section_Page!"/>
+
+ <inp2:m_ParseBlock name="inp_id_label" prefix="change-log" field="ChangeLogId" title="!la_fld_Id!"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="UserLogin" title="!la_fld_Login!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="UserFirstName" title="!la_fld_FirstName!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="UserLastName" title="!la_fld_LastName!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="SessionLogId" title="!la_fld_SessionLogId!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="Action" title="!la_fld_Action!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="OccuredOn" title="!la_fld_OccuredOn!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="MasterPrefix" title="!la_fld_MasterPrefix!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="MasterId" title="!la_fld_MasterId!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="Prefix" title="!la_fld_Prefix!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="ItemId" title="!la_fld_ItemId!" style="width: 100px"/>
+ <inp2:m_ParseBlock name="inp_label" prefix="change-log" field="Changes" no_special="1" title="!la_fld_Changes!" style="width: 100px"/>
+
+ <inp2:m_RenderElement name="inp_edit_filler"/>
+
+</table>
+</div>
+
+<inp2:m_include t="incs/footer"/>
+
Property changes on: branches/RC/core/admin_templates/logs/change_logs/change_log_edit.tpl
___________________________________________________________________
Added: cvs2svn:cvs-rev
## -0,0 +1 ##
+1.1.2.1
\ No newline at end of property
Index: branches/RC/core/admin_templates/incs/form_blocks.tpl
===================================================================
--- branches/RC/core/admin_templates/incs/form_blocks.tpl (revision 10293)
+++ branches/RC/core/admin_templates/incs/form_blocks.tpl (revision 10294)
@@ -1,715 +1,718 @@
<inp2:m_DefineElement name="combined_header" permission_type="view" tab_preset="" module="" icon="">
<inp2:adm_SectionInfo section="$section" info="perm_section" result_to_var="perm_section"/>
<inp2:m_RequireLogin permissions="{$perm_section}.{$permission_type}" system="1"/>
<inp2:m_if check="m_Param" name="prefix" inverse="1"><inp2:adm_SectionInfo section="$section" info="SectionPrefix" result_to_var="prefix"/></inp2:m_if>
<inp2:m_if check="m_get" var="m_wid" inverse="1">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr style="background: url(<inp2:adm_SectionInfo section="$section" info="module_path" module="$module"/>img/logo_bg.gif) no-repeat top right; height: 55px;">
<td valign="top" class="admintitle" align="left" style="padding-top: 10px; padding-bottom: 10px;">
<img width="46" height="46" src="<inp2:adm_SectionInfo section="$section" info="module_path" module="$module"/>img/icons/icon46_<inp2:adm_SectionInfo section="$section" info="icon"/>.gif" align="absmiddle" title="<inp2:adm_SectionInfo section="$section" info="label"/>">&nbsp;<inp2:adm_SectionInfo section="$section" info="label"/>
</td>
</tr>
</table>
</inp2:m_if>
<inp2:m_if check="m_Param" name="tabs">
<inp2:m_include t="$tabs"/>
</inp2:m_if>
<inp2:m_if check="m_Param" name="tab_preset">
<inp2:m_RenderElement name="edit_tabs" prefix="$prefix" preset_name="$tab_preset"/>
</inp2:m_if>
<table cellpadding="0" cellspacing="0" width="100%">
<tr>
<td class="tablenav">
<table border="0" cellpadding="2" cellspacing="0" class="bordered-no-bottom" width="100%" height="30">
<tr>
<td class="header_left_bg" nowrap valign="middle">
<inp2:adm_SectionInfo section="$section" info="label" result_to_var="default_title"/>
<span class="tablenav_link" id="blue_bar"><inp2:{$prefix}_SectionTitle title_preset="$title_preset" title="$default_title" cut_first="100" pass_params="true"/></span>
</td>
<td align="right" valign="middle">
<script type="text/javascript">
set_window_title( RemoveTranslationLink(document.getElementById('blue_bar').innerHTML, false).replace(/(<[^<]+>)/g, '') + ' - <inp2:m_Phrase label="la_AdministrativeConsole"/>');
</script>
<inp2:m_if check="m_ModuleEnabled" module="In-Portal">
<script>
var $help_url='<inp2:m_t t="help" h_prefix="$prefix" h_icon="$icon" h_module="$module" h_title_preset="$title_preset" pass="all,m,h" m_opener="p" escape="escape"/>';
$help_url = $help_url.replace(/#/g, '%23');
</script>
<a href="javascript: OpenHelp($help_url);">
<img src="img/blue_bar_help.gif" border="0">
</a>
</inp2:m_if>
<inp2:m_if check="m_Param" name="pagination">
<inp2:m_RenderElement name="grid_pagination_elem" PrefixSpecial="$prefix" pass_params="1"/>
</inp2:m_if>
</td>
</tr>
</table>
</td>
</tr>
</table>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="section_header">
<inp2:m_if check="m_ParamEquals" name="prefix" value="" inverse="inverse">
<inp2:m_RenderElement name="section_header_new" pass_params="true"/>
<inp2:m_else />
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr class="section_header_bg">
<td valign="top" class="admintitle" align="left" style="padding-top: 2px; padding-bottom: 2px;">
<img width="46" height="46" src="img/icons/<inp2:adm_GetSectionIcon icon="$icon"/>.gif" align="absmiddle" title="<inp2:adm_GetSectionTitle phrase="$title"/>">&nbsp;<inp2:adm_GetSectionTitle phrase="$title"/>
</td>
</tr>
</table>
</inp2:m_if>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="section_header_new" module="#session#">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr style="background: url(<inp2:ModulePath module="$module"/>img/logo_bg.gif) no-repeat top right; height: 55px;">
<td valign="top" class="admintitle" align="left" style="padding-top: 10px; padding-bottom: 10px;">
<img width="46" height="46" src="<inp2:ModulePath module="$module"/>img/icons/<inp2:adm_GetSectionIcon icon="$icon"/>.gif" align="absmiddle" title="<inp2:adm_GetSectionTitle phrase="$title"/>">&nbsp;<inp2:adm_GetSectionTitle phrase="$title"/>
</td>
</tr>
</table>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="blue_bar" module="" icon="" pagination="0">
<table border="0" cellpadding="2" cellspacing="0" class="bordered-no-bottom" width="100%" height="30">
<tr>
<td class="header_left_bg" nowrap width="80%" valign="middle">
<span class="tablenav_link" id="blue_bar"><inp2:{$prefix}_SectionTitle title_preset="$title_preset" title="Invalid OR Missing title preset [#preset_name#]" cut_first="100" pass_params="true"/></span>
</td>
<td align="right" class="tablenav" width="20%" valign="middle">
<inp2:m_if check="m_ModuleEnabled" module="In-Portal">
<script>
var $help_url='<inp2:m_t t="help" h_prefix="$prefix" h_icon="$icon" h_module="$module" h_title_preset="$title_preset" pass="all,m,h" m_opener="p" escape="escape"/>';
$help_url = $help_url.replace(/#/g, '%23');
set_window_title( RemoveTranslationLink(document.getElementById('blue_bar').innerHTML, false).replace(/(<[^<]+>)/g, '') );
</script>
<a href="javascript: OpenHelp($help_url);">
<img src="img/blue_bar_help.gif" border="0">
</a>
</inp2:m_if>
<inp2:m_if check="m_Param" name="pagination">
<inp2:m_RenderElement name="grid_pagination_elem" grid="st" PrefixSpecial="$prefix" pass_params="1"/>
</inp2:m_if>
</td>
</tr>
</table>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_original_label">
<td><inp2:$prefix.original_Field field="$field" nl2br="1"/></td>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="subsection" prefix="">
<tr class="subsectiontitle">
<td colspan="3"><inp2:m_phrase label="$title"/></td>
<inp2:m_if check="m_ParamEquals" name="prefix" value="" inverse="inverse">
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<td><inp2:m_phrase name="$original_title"/></td>
</inp2:m_if>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_field_caption" title="" subfield="" NamePrefix="">
<inp2:m_inc param="tab_index" by="1"/>
<td class="text">
<inp2:m_if check="m_Param" name="title">
<label for="<inp2:m_param name="NamePrefix"/><inp2:InputName field="$field" subfield="$subfield"/>">
<span class="<inp2:m_if check="HasError" field="$field" >error</inp2:m_if>">
<inp2:m_phrase label="$title"/></span><inp2:m_if check="{$prefix}_IsRequired" field="$field" ><span class="error">&nbsp;*</span></inp2:m_if>:
</label>
<inp2:m_else/>
&nbsp;
</inp2:m_if>
</td>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_label" is_last="" as_label="" currency="" is_last="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td valign="top" class="text">
<inp2:{$prefix}_Field field="$field" as_label="$as_label" currency="$currency"/>
<inp2:m_if check="{$prefix}_HasParam" name="hint_label"><span class="small"><inp2:m_phrase label="$hint_label"/></span></inp2:m_if>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_id_label" db="">
<inp2:m_if check="{$prefix}_FieldEquals" field="$field" value="" inverse="inverse">
<inp2:m_RenderElement name="inp_label" pass_params="true"/>
</inp2:m_if>
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="$db"/>">
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_box" subfield="" class="" is_last="" maxlength="" onblur="" size="" onkeyup="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" subfield="$subfield" title="$title" is_last="$is_last"/>
<td>
<input type="text" name="<inp2:{$prefix}_InputName field="$field" subfield="$subfield"/>" id="<inp2:{$prefix}_InputName field="$field" subfield="$subfield"/>" value="<inp2:{$prefix}_Field field="$field" subfield="$subfield"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" maxlength="<inp2:m_param name="maxlength"/>" class="<inp2:m_param name="class"/>" onblur="<inp2:m_Param name="onblur"/>" onkeyup="<inp2:m_Param name="onkeyup"/>">
<inp2:m_if check="{$prefix}_HasParam" name="hint_label"><span class="small"><inp2:m_phrase label="$hint_label"/></span></inp2:m_if>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_password" class="" size="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title"/>
<td>
<input type="password" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" value="" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" class="<inp2:m_param name="class"/>" />
<inp2:m_if check="{$prefix}_HasParam" name="hint_label"><span class="small"><inp2:m_phrase label="$hint_label"/></span></inp2:m_if>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_upload" class="" size="" thumbnail="" is_last="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<inp2:m_if check="m_Param" name="thumbnail">
<inp2:m_if check="{$prefix}_FieldEquals" name="$field" value="" inverse="inverse">
<img src="<inp2:{$prefix}_Field field="$field" format="resize:{$thumbnail}"/>" alt=""/><br />
<table cellpadding="0" cellspacing="0">
<tr>
<td>
<input type="hidden" id="<inp2:{$prefix}_InputName field="Delete{$field}"/>" name="<inp2:{$prefix}_InputName field="Delete{$field}"/>" value="0" />
<input type="checkbox" id="_cb_<inp2:{$prefix}_InputName field="Delete{$field}"/>" onchange="update_checkbox(this, document.getElementById('<inp2:{$prefix}_InputName field="Delete{$field}"/>'));">
</td>
<td>
<label for="_cb_<inp2:{$prefix}_InputName field="Delete{$field}"/>"><inp2:m_phrase name="la_btn_DeleteImage"/></label>
</td>
</tr>
</table>
</inp2:m_if>
<input type="file" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" class="<inp2:m_param name="class"/>">
<inp2:m_else/>
<input type="file" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" class="<inp2:m_param name="class"/>">
<inp2:m_if check="{$prefix}_FieldEquals" name="$field" value="" inverse="inverse">
(<inp2:{$prefix}_Field field="$field"/>)
</inp2:m_if>
</inp2:m_if>
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>[upload]" id="<inp2:{$prefix}_InputName field="$field"/>[upload]" value="<inp2:{$prefix}_Field field="$field"/>">
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_swf_upload" class="" is_last="" style="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td class="uploader-text">
<div class="uploader-main" id="<inp2:{$prefix}_InputName field="$field"/>_progress">
<div class="uploader-percent" id="<inp2:{$prefix}_InputName field="$field"/>_percent">0%</div>
<div class="uploader-left">
<div class="uploader-done" id="<inp2:{$prefix}_InputName field="$field"/>_done"></div>
</div>
<table style="border-collapse: collapse; width: 100%;">
<tr>
<td style="width: 120px">Uploading:</td><td id="<inp2:{$prefix}_InputName field="$field"/>_progress_filename"></td>
</tr>
<tr>
<td>Progress:</td><td id="<inp2:{$prefix}_InputName field="$field"/>_progress_progress"></td>
</tr>
<tr>
<td>Time elapsed:</td><td id="<inp2:{$prefix}_InputName field="$field"/>_progress_elapsed"></td>
</tr>
<tr>
<td>Time remaining:</td><td id="<inp2:{$prefix}_InputName field="$field"/>_progress_remaining"></td>
</tr>
<tr>
<td colspan="2" style="text-align: center"><a href="javascript:UploadsManager.CancelUpload('<inp2:{$prefix}_InputName field="$field"/>')">Cancel</a></td>
</tr>
</table>
</div>
<div>
<input class="button" type="button" onclick="UploadsManager.Browse('<inp2:{$prefix}_InputName field="$field"/>')" value="Browse"/>
<input class="button" type="button" onclick="UploadsManager.StartUpload('<inp2:{$prefix}_InputName field="$field"/>')" value="Upload"/>
</div>
<div id="<inp2:{$prefix}_InputName field="$field"/>_queueinfo"></div>
<div id="<inp2:{$prefix}_InputName field="$field"/>_holder"></div>
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>[upload]" id="<inp2:{$prefix}_InputName field="$field"/>[upload]" value="<inp2:{$prefix}_Field field="$field"/>"><br/>
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>[tmp_ids]" id="<inp2:{$prefix}_InputName field="$field"/>[tmp_ids]" value="">
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>[tmp_names]" id="<inp2:{$prefix}_InputName field="$field"/>[tmp_names]" value="">
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>[tmp_deleted]" id="<inp2:{$prefix}_InputName field="$field"/>[tmp_deleted]" value="">
<script type="text/javascript">
UploadsManager.AddUploader('<inp2:{$prefix}_InputName field="$field"/>',
{
allowedFiletypesDescription : '<inp2:{$prefix}_FieldOption field="$field" option="files_description" js_escape="1"/>',
allowedFiletypes : '<inp2:{$prefix}_FieldOption field="$field" option="file_types"/>',
allowedFilesize : '<inp2:{$prefix}_FieldOption field="$field" option="max_size"/>',
multiple : '<inp2:{$prefix}_FieldOption field="$field" option="multiple"/>',
prefix : '<inp2:m_Param name="prefix"/>',
field : '<inp2:m_Param name="field"/>',
urls : '<inp2:{$prefix}_Field field="$field" format="file_urls" js_escape="1"/>',
names : '<inp2:{$prefix}_Field field="$field" format="file_names" js_escape="1"/>',
sizes : '<inp2:{$prefix}_Field field="$field" format="file_sizes" js_escape="1"/>',
flashsid : '<inp2:m_SID/>',
uploadURL : '<inp2:m_t pass="m,$prefix" {$prefix}_event="OnUploadFile" field="#FIELD#" id="#ID#" flashsid="#SID#" js_escape="1" no_amp="1" />',
deleteURL : '<inp2:m_t pass="m,$prefix" {$prefix}_event="OnDeleteFile" field="#FIELD#" file="#FILE#" js_escape="1" no_amp="1"/>',
tmp_url : '<inp2:m_t pass="m,$prefix" {$prefix}_event="OnViewFile" tmp="1" field="#FIELD#" file="#FILE#" id="#ID#" js_escape="1" no_amp="1" />',
IconPath: '../../admin/editor/cmseditor/editor/images'
}
)
UploadsManager.formContainerId = 'scroll_container';
</script>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_box_ml" class="" size="" onblur="" maxlength="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<td class="text" valign="top">
<span class="<inp2:m_if check="{$prefix}_HasError" field="$field" >error</inp2:m_if>">
<inp2:m_phrase label="$title"/><inp2:m_if check="{$prefix}_IsRequired" field="$field" ><span class="error"> *</span></inp2:m_if>:</span><br>
<a href="javascript:PreSaveAndOpenTranslator('<inp2:m_param name="prefix"/>', '<inp2:m_param name="field"/>', 'popups/translator');" title="<inp2:m_Phrase label="la_Translate"/>"><img src="img/icons/icon24_translate.gif" style="cursor:hand" border="0"></a>
</td>
<td>
<input type="text" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" format="no_default"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" maxlength="<inp2:m_param name="maxlength"/>" class="<inp2:m_param name="class"/>" onblur="<inp2:m_Param name="onblur"/>">
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_hidden" db="">
<input type="hidden" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="$db"/>">
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_date" class="" is_last="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_date"/>" id="<inp2:{$prefix}_InputName field="{$field}_date"/>" value="<inp2:{$prefix}_Field field="{$field}_date" format="_regional_InputDateFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_date" input_format="1" edit_size="edit_size"/>" class="<inp2:m_param name="class"/>" datepickerIcon="<inp2:m_ProjectBase/>core/admin_templates/img/calendar_icon.gif">&nbsp;<span class="small">(<inp2:{$prefix}_Format field="{$field}_date" input_format="1" human="true"/>)</span>
<script type="text/javascript">
initCalendar("<inp2:{$prefix}_InputName field="{$field}_date"/>", "<inp2:{$prefix}_Format field="{$field}_date" input_format="1"/>");
</script>
<input type="hidden" name="<inp2:{$prefix}_InputName field="{$field}_time"/>" id="<inp2:{$prefix}_InputName field="{$field}_time" input_format="1"/>" value="">
</td>
<td class="error"><inp2:{$prefix}_Error field="{$field}_date"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_time" class="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td class="control-cell">
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_time"/>" id="<inp2:{$prefix}_InputName field="{$field}_time"/>" value="<inp2:{$prefix}_Field field="{$field}_time" format="_regional_InputTimeFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_time" input_format="1" edit_size="edit_size"/>" class="<inp2:m_param name="class"/>">&nbsp;
<span class="small">(<inp2:{$prefix}_Format field="{$field}_time" input_format="1" human="true"/>)</span>
<input type="hidden" name="<inp2:{$prefix}_InputName field="{$field}_date"/>" id="<inp2:{$prefix}_InputName field="{$field}_date" input_format="1"/>" value="">
</td>
<td class="error"><inp2:{$prefix}_Error field="{$field}_time"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_date_time" class="" is_last="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<!-- <input type="hidden" id="<inp2:{$prefix}_InputName field="$field"/>" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="db"/>"> -->
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_date"/>" id="<inp2:{$prefix}_InputName field="{$field}_date"/>" value="<inp2:{$prefix}_Field field="{$field}_date" format="_regional_InputDateFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_date" input_format="1" edit_size="edit_size"/>" class="<inp2:m_param name="class"/>" datepickerIcon="<inp2:m_ProjectBase/>core/admin_templates/img/calendar_icon.gif">
<span class="small">(<inp2:{$prefix}_Format field="{$field}_date" input_format="1" human="true"/>)</span>
<script type="text/javascript">
initCalendar("<inp2:{$prefix}_InputName field="{$field}_date"/>", "<inp2:{$prefix}_Format field="{$field}_date" input_format="1"/>");
</script>
&nbsp;<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_time"/>" id="<inp2:{$prefix}_InputName field="{$field}_time"/>" value="<inp2:{$prefix}_Field field="{$field}_time" format="_regional_InputTimeFormat"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:{$prefix}_Format field="{$field}_time" input_format="1" edit_size="edit_size"/>" class="<inp2:m_param name="class"/>"><span class="small"> (<inp2:{$prefix}_Format field="{$field}_time" input_format="1" human="true"/>)</span>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_textarea" class="" allow_html="allow_html">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<td class="text" valign="top">
<span class="<inp2:m_if check="{$prefix}_HasError" field="$field" >error</inp2:m_if>">
<inp2:m_phrase label="$title"/><inp2:m_if check="{$prefix}_IsRequired" field="$field" ><span class="error"> *</span></inp2:m_if>:</span><br>
<inp2:m_if check="m_ParamEquals" name="allow_html" value="allow_html">
<a href="javascript:OpenEditor('&section=in-link:editlink_general','kernel_form','<inp2:{$prefix}_InputName field="$field"/>');"><img src="img/icons/icon24_link_editor.gif" style="cursor:hand" border="0"></a>
</inp2:m_if>
</td>
<td>
<textarea tabindex="<inp2:m_get param="tab_index"/>" id="<inp2:{$prefix}_InputName field="$field"/>" name="<inp2:{$prefix}_InputName field="$field"/>" cols="<inp2:m_param name="cols"/>" rows="<inp2:m_param name="rows"/>" class="<inp2:m_param name="class"/>"><inp2:{$prefix}_Field field="$field"/></textarea>
<inp2:m_if check="{$prefix}_HasParam" name="hint_label">
<br /><span class="small"><inp2:m_phrase label="$hint_label"/></span>
</inp2:m_if>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_textarea_ml" class="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<td class="text" valign="top">
<span class="<inp2:m_if check="{$prefix}_HasError" field="$field" >error</inp2:m_if>">
<inp2:m_phrase label="$title"/><inp2:m_if check="{$prefix}_IsRequired" field="$field" ><span class="error"> *</span></inp2:m_if>:</span><br>
<a href="javascript:OpenEditor('&section=in-link:editlink_general','kernel_form','<inp2:{$prefix}_InputName field="$field"/>');"><img src="img/icons/icon24_link_editor.gif" style="cursor:hand" border="0"></a>
<a href="javascript:PreSaveAndOpenTranslator('<inp2:m_param name="prefix"/>', '<inp2:m_param name="field"/>', 'popups/translator', 1);" title="<inp2:m_Phrase label="la_Translate"/>"><img src="img/icons/icon24_translate.gif" style="cursor:hand" border="0"></a>
</td>
<td>
<textarea tabindex="<inp2:m_get param="tab_index"/>" id="<inp2:{$prefix}_InputName field="$field"/>" name="<inp2:{$prefix}_InputName field="$field"/>" cols="<inp2:m_param name="cols"/>" rows="<inp2:m_param name="rows"/>" class="<inp2:m_param name="class"/>"><inp2:{$prefix}_Field field="$field"/></textarea>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_user" class="" size="" is_last="" old_style="0" onkeyup="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<input type="text" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" class="<inp2:m_param name="class"/>" onkeyup="<inp2:m_Param name="onkeyup"/>">
<inp2:m_if check="m_ParamEquals" name="old_style" value="1">
<a href="#" onclick="return OpenUserSelector('','kernel_form','<inp2:{$prefix}_InputName field="$field"/>');">
<inp2:m_else/>
<a href="javascript:openSelector('<inp2:m_param name="prefix"/>', '<inp2:m_t t="user_selector" pass="all,$prefix" escape="1"/>', '<inp2:m_param name="field"/>');">
</inp2:m_if>
<img src="img/icons/icon24_link_user.gif" style="cursor:hand;" border="0">
</a>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_category" class="" size="" is_last="" old_style="0" onkeyup="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<table cellpadding="0" cellspacing="0">
<tr>
<td id="<inp2:{$prefix}_InputName field="$field"/>_path">
<inp2:m_DefineElement name="category_caption">
<inp2:m_if check="m_ParamEquals" name="cat_id" value="0" inverse="inverse">
<inp2:m_param name="separator"/>
</inp2:m_if>
<inp2:m_param name="cat_name"/>
</inp2:m_DefineElement>
<inp2:$prefix_FieldCategoryPath field="$field" separator=" &gt; " render_as="category_caption"/>
<inp2:m_RenderElement name="inp_edit_hidden" pass_params="1"/>
</td>
<td valign="middle">
<img src="img/spacer.gif" width="3" height="1" alt=""/>
<a href="javascript:openSelector('<inp2:m_param name="prefix"/>', '<inp2:adm_SelectorLink prefix="$prefix" selection_mode="single" tab_prefixes="none"/>', '<inp2:m_param name="field"/>');">
<img src="img/icons/icon24_cat.gif" border="0"/>
</a>
<a href="#" onclick="disable_category('<inp2:m_Param name="field"/>'); return false;"><inp2:m_Phrase name="la_Text_Disable"/></a>
<script type="text/javascript">
function disable_category($field) {
var $field = '<inp2:{$prefix}_InputName field="#FIELD_NAME#"/>'.replace('#FIELD_NAME#', $field);
set_hidden_field($field, '');
document.getElementById($field + '_path').style.display = 'none';
}
</script>
</td>
</tr>
</table>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_option_item">
<option value="<inp2:m_param name="key"/>"<inp2:m_param name="selected"/>><inp2:m_param name="option"/></option>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_option_phrase">
<option value="<inp2:m_param name="key"/>"<inp2:m_param name="selected"/>><inp2:m_phrase label="$option"/></option>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_options" is_last="" has_empty="0" empty_value="" onchange="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<select tabindex="<inp2:m_get param="tab_index"/>" name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>" onchange="<inp2:m_Param name="onchange"/>">
<inp2:m_if check="{$prefix}_FieldOption" field="$field" option="use_phrases">
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_option_phrase" selected="selected" has_empty="$has_empty" empty_value="$empty_value"/>
<inp2:m_else/>
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_option_item" selected="selected" has_empty="$has_empty" empty_value="$empty_value"/>
</inp2:m_if>
</select>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_multioptions" is_last="" has_empty="0" empty_value="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<select multiple tabindex="<inp2:m_get param="tab_index"/>" id="<inp2:{$prefix}_InputName field="$field"/>_select" onchange="update_multiple_options('<inp2:{$prefix}_InputName field="$field"/>');">
<inp2:m_if check="{$prefix}_FieldOption" field="$field" option="use_phrases">
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_option_phrase" selected="selected" has_empty="$has_empty" empty_value="$empty_value"/>
<inp2:m_else/>
<inp2:{$prefix}_PredefinedOptions field="$field" block="inp_option_item" selected="selected" has_empty="$has_empty" empty_value="$empty_value"/>
</inp2:m_if>
</select>
<input type="hidden" id="<inp2:{$prefix}_InputName field="$field"/>" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="db"/>"/>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_radio_item" onclick="" onchange="">
<input type="radio" <inp2:m_param name="checked"/> name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>" onclick="<inp2:m_param name="onclick"/>" onchange="<inp2:m_param name="onchange"/>"><label for="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>"><inp2:m_param name="option"/></label>&nbsp;
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_radio_phrase" onclick="" onchange="">
<input type="radio" <inp2:m_param name="checked"/> name="<inp2:{$prefix}_InputName field="$field"/>" id="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>" onclick="<inp2:m_param name="onclick"/>" onchange="<inp2:m_param name="onchange"/>"><label for="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>"><inp2:m_phrase label="$option"/></label>&nbsp;
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_radio" is_last="" pass_tabindex="" onclick="" onchange="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<inp2:m_if check="{$prefix}_FieldOption" field="$field" option="use_phrases">
<inp2:{$prefix}_PredefinedOptions field="$field" tabindex="$pass_tabindex" block="inp_radio_phrase" selected="checked" onclick="$onclick" onchange="$onchange" />
<inp2:m_else />
<inp2:{$prefix}_PredefinedOptions field="$field" tabindex="$pass_tabindex" block="inp_radio_item" selected="checked" onclick="$onclick" onchange="$onchange" />
</inp2:m_if>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_checkbox" is_last="" field_class="" onchange="" onclick="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last" NamePrefix="_cb_"/>
<td>
<input type="hidden" id="<inp2:{$prefix}_InputName field="$field"/>" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="db"/>">
<!--<input tabindex="<inp2:m_get param="tab_index"/>" type="checkbox" id="_cb_<inp2:{$prefix}_InputName field="$field"/>" name="_cb_<inp2:{$prefix}_InputName field="$field"/>" <inp2:{$prefix}_Field field="$field" checked="checked" db="db"/> class="<inp2:m_param name="field_class"/>" onclick="update_checkbox(this, document.getElementById('<inp2:{$prefix}_InputName field="$field"/>'));" onchange="<inp2:m_param name="onchange"/>">-->
<input tabindex="<inp2:m_get param="tab_index"/>" type="checkbox" id="_cb_<inp2:{$prefix}_InputName field="$field"/>" name="_cb_<inp2:{$prefix}_InputName field="$field"/>" <inp2:{$prefix}_Field field="$field" checked="checked" db="db"/> class="<inp2:m_param name="field_class"/>" onchange="update_checkbox(this, document.getElementById('<inp2:{$prefix}_InputName field="$field"/>'));<inp2:m_param name="onchange"/>" onclick="<inp2:m_param name="onclick"/>">
<inp2:m_if check="{$prefix}_HasParam" name="hint_label"><inp2:m_phrase label="$hint_label"/></inp2:m_if>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_checkbox_item">
<input type="checkbox" <inp2:m_param name="checked"/> id="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>" onclick="update_checkbox_options(/^<inp2:{$prefix}_InputName field="$field" as_preg="1"/>_([0-9A-Za-z-]+)/, '<inp2:{$prefix}_InputName field="$field"/>');"><label for="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>"><inp2:m_param name="option"/></label>&nbsp;
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_checkbox_phrase">
<input type="checkbox" <inp2:m_param name="checked"/> id="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>" value="<inp2:m_param name="key"/>" onclick="update_checkbox_options(/^<inp2:{$prefix}_InputName field="$field" as_preg="1"/>_([0-9A-Za-z-]+)/, '<inp2:{$prefix}_InputName field="$field"/>');"><label for="<inp2:{$prefix}_InputName field="$field"/>_<inp2:m_param name="key"/>"><inp2:m_phrase label="$option"/></label>&nbsp;
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_checkboxes" no_empty="" is_last="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" title="$title" is_last="$is_last"/>
<td>
<inp2:m_if check="{$prefix}_FieldOption" field="$field" option="use_phrases">
<inp2:{$prefix}_PredefinedOptions field="$field" no_empty="$no_empty" tabindex="$pass_tabindex" block="inp_checkbox_phrase" selected="checked"/>
<inp2:m_else/>
<inp2:{$prefix}_PredefinedOptions field="$field" no_empty="$no_empty" tabindex="$pass_tabindex" block="inp_checkbox_item" selected="checked"/>
</inp2:m_if>
<inp2:m_RenderElement prefix="$prefix" name="inp_edit_hidden" field="$field" db="db"/>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_checkbox_allow_html">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<td colspan="2">
<label for="_cb_<inp2:m_param name="field"/>"><inp2:m_phrase label="la_enable_html"/></label>
<input type="hidden" id="<inp2:{$prefix}_InputName field="$field"/>" name="<inp2:{$prefix}_InputName field="$field"/>" value="<inp2:{$prefix}_Field field="$field" db="db"/>">
<input tabindex="<inp2:m_get param="tab_index"/>" type="checkbox" id="_cb_<inp2:m_param name="field"/>" name="_cb_<inp2:m_param name="field"/>" <inp2:{$prefix}_Field field="$field" checked="checked"/> class="<inp2:m_param name="field_class"/>" onclick="update_checkbox(this, document.getElementById('<inp2:{$prefix}_InputName field="$field"/>'))">
<br>
<span class="hint"><img src="img/smicon7.gif" width="14" height="14" align="absmiddle"><inp2:m_phrase label="la_Warning_Enable_HTML"/></span>
</td>
<td>&nbsp;</td>
</tr>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="inp_edit_weight" subfield="" class="" is_last="" maxlength="">
<tr class="<inp2:m_odd_even odd="table-color1" even="table-color2"/>">
<inp2:m_RenderElement name="inp_edit_field_caption" prefix="$prefix" field="$field" subfield="$subfield" title="$title" is_last="$is_last"/>
<td>
<inp2:m_if check="lang.current_FieldEquals" field="UnitSystem" value="1">
<input type="text" name="<inp2:{$prefix}_InputName field="$field" subfield="$subfield"/>" id="<inp2:{$prefix}_InputName field="$field" subfield="$subfield"/>" value="<inp2:{$prefix}_Field field="$field" subfield="$subfield"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" maxlength="<inp2:m_param name="maxlength"/>" class="<inp2:m_param name="class"/>" onblur="<inp2:m_Param name="onblur"/>">
<inp2:m_phrase label="la_kg" />
</inp2:m_if>
<inp2:m_if check="lang.current_FieldEquals" field="UnitSystem" value="2">
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_a" subfield="$subfield"/>" id="<inp2:{$prefix}_InputName field="{$field}_a" subfield="$subfield"/>" value="<inp2:{$prefix}_Field field="{$field}_a" subfield="$subfield"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" maxlength="<inp2:m_param name="maxlength"/>" class="<inp2:m_param name="class"/>" onblur="<inp2:m_Param name="onblur"/>">
<inp2:m_phrase label="la_lbs" />
<input type="text" name="<inp2:{$prefix}_InputName field="{$field}_b" subfield="$subfield"/>" id="<inp2:{$prefix}_InputName field="{$field}_b" subfield="$subfield"/>" value="<inp2:{$prefix}_Field field="{$field}_b" subfield="$subfield"/>" tabindex="<inp2:m_get param="tab_index"/>" size="<inp2:m_param name="size"/>" maxlength="<inp2:m_param name="maxlength"/>" class="<inp2:m_param name="class"/>" onblur="<inp2:m_Param name="onblur"/>">
<inp2:m_phrase label="la_oz" />
</inp2:m_if>
</td>
<td class="error"><inp2:{$prefix}_Error field="$field"/>&nbsp;</td>
<inp2:m_if check="{$prefix}_DisplayOriginal" pass_params="1">
<inp2:m_RenderElement prefix="$prefix" field="$field" name="inp_original_label"/>
</inp2:m_if>
</tr>
</inp2:m_DefineElement>
+<inp2:m_DefineElement name="inp_edit_filler" control_options="false">
+
+</inp2:m_DefineElement>
<inp2:m_DefineElement name="ajax_progress_bar">
<table width="100%" border="0" cellspacing="0" cellpadding="4" class="bordered">
<tr class="table-color1">
<td colspan="2">
<img src="img/spacer.gif" height="10" width="1" alt="" /><br />
<!-- progress bar paddings: begin -->
<table width="90%" cellpadding="2" cellspacing="0" border="0" align="center">
<tr>
<td class="progress-text">0%</td>
<td width="100%">
<!-- progress bar: begin -->
<table cellspacing="0" cellpadding="0" width="100%" border="0" align="center" style="background-color: #FFFFFF; border: 1px solid #E6E6E6;">
<tr>
<td colspan="3"><img src="img/spacer.gif" height="2" width="1" alt="" /></td>
</tr>
<tr>
<td width="2"><img src="img/spacer.gif" height="13" width="3" alt="" /></td>
<td align="center" width="100%">
<table cellspacing="0" cellpadding="0" width="100%" border="0" style="background: url(img/progress_left.gif) repeat-x;">
<tr>
<td id="progress_bar[done]" style="background: url(img/progress_done.gif);" align="left"></td>
<td id="progress_bar[left]" align="right"><img src="img/spacer.gif" height="9" width="1" alt="" /></td>
</tr>
</table>
</td>
<td width="1"><img src="img/spacer.gif" height="13" width="3" alt="" /></td>
</tr>
<tr>
<td colspan="3"><img src="img/spacer.gif" height="2" width="1" alt="" /></td>
</tr>
</table>
<!-- progress bar: end -->
</td>
<td class="progress-text">100%</td>
</tr>
</table>
<!-- progress bar paddings: end -->
<img src="img/spacer.gif" height="10" width="1" alt="" /><br />
</td>
</tr>
<tr class="table-color2">
<td width="50%" align="right"><inp2:m_phrase name="la_fld_PercentsCompleted"/>:</td>
<td id="progress_display[percents_completed]">0%</td>
</tr>
<tr class="table-color1">
<td align="right"><inp2:m_phrase name="la_fld_ElapsedTime"/>:</td>
<td id="progress_display[elapsed_time]">00:00</td>
</tr>
<tr class="table-color2">
<td align="right"><inp2:m_phrase name="la_fld_EstimatedTime"/>:</td>
<td id="progress_display[Estimated_time]">00:00</td>
</tr>
<tr class="table-color1">
<td align="center" colspan="2">
<input type="button" class="button" onclick="<inp2:m_param name="cancel_action"/>" value="<inp2:m_phrase name="la_Cancel"/>" />
</td>
</tr>
</table>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="edit_navigation" toolbar="a_toolbar">
<inp2:m_if check="{$prefix}_IsTopmostPrefix">
<inp2:m_if check="{$prefix}_IsSingle">
<inp2:m_param name="toolbar"/>.HideButton('prev');
<inp2:m_param name="toolbar"/>.HideButton('next');
<inp2:m_else/>
<inp2:m_if check="{$prefix}_IsLast">
<inp2:m_param name="toolbar"/>.DisableButton('next');
</inp2:m_if>
<inp2:m_if check="{$prefix}_IsFirst">
<inp2:m_param name="toolbar"/>.DisableButton('prev');
</inp2:m_if>
</inp2:m_if>
</inp2:m_if>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="edit_tabs" preset_name="Default">
<inp2:m_if check="{$prefix}_HasEditTabs" preset_name="$preset_name">
<table cellpadding="0" cellspacing="0" border="0" width="100%">
<tr>
<td align="right" width="100%">
<table cellpadding="0" cellspacing="0" border="0" height="23">
<tr>
<inp2:m_DefineElement name="edit_tab">
<inp2:m_RenderElement name="tab" title="$title" t="$template" main_prefix="$PrefixSpecial"/>
</inp2:m_DefineElement>
<inp2:{$prefix}_PrintEditTabs render_as="edit_tab" preset_name="$preset_name"/>
</tr>
</table>
</td>
</tr>
</table>
</inp2:m_if>
</inp2:m_DefineElement>
<inp2:m_DefineElement name="ml_selector" prefix="">
</inp2:m_DefineElement>
Property changes on: branches/RC/core/admin_templates/incs/form_blocks.tpl
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.20.2.13
\ No newline at end of property
+1.20.2.14
\ No newline at end of property
Index: branches/RC/core/install/install_schema.sql
===================================================================
--- branches/RC/core/install/install_schema.sql (revision 10293)
+++ branches/RC/core/install/install_schema.sql (revision 10294)
@@ -1,462 +1,496 @@
CREATE TABLE PermissionConfig (
PermissionConfigId int(11) NOT NULL auto_increment,
PermissionName varchar(30) NOT NULL default '',
Description varchar(255) NOT NULL default '',
ErrorMessage varchar(255) NOT NULL default '',
ModuleId varchar(20) NOT NULL default '0',
PRIMARY KEY (PermissionConfigId),
KEY PermissionName (PermissionName)
);
CREATE TABLE Permissions (
PermissionId int(11) NOT NULL auto_increment,
Permission varchar(255) NOT NULL default '',
GroupId int(11) default '0',
PermissionValue int(11) NOT NULL default '0',
`Type` tinyint(4) NOT NULL default '0',
CatId int(11) NOT NULL default '0',
PRIMARY KEY (PermissionId),
UNIQUE KEY PermIndex (Permission,GroupId,CatId,`Type`)
);
CREATE TABLE CustomField (
CustomFieldId int(11) NOT NULL auto_increment,
Type int(11) NOT NULL default '0',
FieldName varchar(255) NOT NULL default '',
FieldLabel varchar(40) default NULL,
MultiLingual TINYINT UNSIGNED NOT NULL DEFAULT '1',
Heading varchar(60) default NULL,
Prompt varchar(60) default NULL,
ElementType varchar(50) NOT NULL default '',
ValueList varchar(255) default NULL,
DisplayOrder int(11) NOT NULL default '0',
OnGeneralTab tinyint(4) NOT NULL default '0',
IsSystem tinyint(3) unsigned NOT NULL default '0',
PRIMARY KEY (CustomFieldId),
KEY Type (Type)
);
CREATE TABLE ConfigurationAdmin (
VariableName varchar(80) NOT NULL default '',
heading varchar(255) default NULL,
prompt varchar(255) default NULL,
element_type varchar(20) NOT NULL default '',
validation varchar(255) default NULL,
ValueList text,
DisplayOrder double NOT NULL default '0',
GroupDisplayOrder double NOT NULL default '0',
Install int(11) NOT NULL default '1',
PRIMARY KEY (VariableName)
);
CREATE TABLE ConfigurationValues (
VariableId int(11) NOT NULL auto_increment,
VariableName varchar(255) NOT NULL default '',
VariableValue text,
ModuleOwner varchar(20) default 'In-Portal',
Section varchar(255) NOT NULL default '',
PRIMARY KEY (VariableId),
UNIQUE KEY VariableName (VariableName)
);
CREATE TABLE EmailMessage (
EmailMessageId int(10) NOT NULL auto_increment,
Template longtext,
MessageType enum('html','text') NOT NULL default 'text',
LanguageId int(11) NOT NULL default '0',
EventId int(11) NOT NULL default '0',
`Subject` text,
PRIMARY KEY (EmailMessageId)
);
CREATE TABLE EmailQueue (
EmailQueueId int(10) unsigned NOT NULL auto_increment,
ToEmail varchar(255) NOT NULL default '',
`Subject` varchar(255) NOT NULL default '',
MessageHeaders text,
MessageBody longtext,
Queued int(10) unsigned NOT NULL default '0',
SendRetries int(10) unsigned NOT NULL default '0',
LastSendRetry int(10) unsigned NOT NULL default '0',
PRIMARY KEY (EmailQueueId),
KEY LastSendRetry (LastSendRetry),
KEY SendRetries (SendRetries)
);
CREATE TABLE EmailSubscribers (
EmailMessageId int(11) NOT NULL default '0',
PortalUserId int(11) NOT NULL default '0'
);
CREATE TABLE Events (
EventId int(11) NOT NULL auto_increment,
Event varchar(40) NOT NULL default '',
ReplacementTags text,
Enabled int(11) NOT NULL default '1',
FromUserId int(11) NOT NULL default '-1',
Module varchar(40) NOT NULL default '',
Description varchar(255) NOT NULL default '',
Type int(11) NOT NULL default '0',
PRIMARY KEY (EventId)
);
CREATE TABLE IdGenerator (
lastid int(11) default NULL
);
CREATE TABLE Language (
LanguageId int(11) NOT NULL auto_increment,
PackName varchar(40) NOT NULL default '',
LocalName varchar(40) NOT NULL default '',
Enabled int(11) NOT NULL default '1',
PrimaryLang int(11) NOT NULL default '0',
AdminInterfaceLang tinyint(3) unsigned NOT NULL default '0',
Priority int(11) NOT NULL default '0',
IconURL varchar(255) default NULL,
DateFormat varchar(50) NOT NULL default '',
TimeFormat varchar(50) NOT NULL default '',
InputDateFormat varchar(50) NOT NULL default 'm/d/Y',
InputTimeFormat varchar(50) NOT NULL default 'g:i:s A',
DecimalPoint VARCHAR(10) NOT NULL DEFAULT '',
ThousandSep VARCHAR(10) NOT NULL DEFAULT '',
`Charset` varchar(20) NOT NULL default '',
UnitSystem tinyint(4) NOT NULL default '1',
PRIMARY KEY (LanguageId)
);
CREATE TABLE Modules (
`Name` varchar(255) NOT NULL default '',
Path varchar(255) NOT NULL default '',
`Var` VARCHAR(100) NOT NULL DEFAULT '',
Version varchar(10) NOT NULL default '0.0.0',
Loaded tinyint(4) NOT NULL default '1',
LoadOrder tinyint(4) NOT NULL default '0',
TemplatePath varchar(255) NOT NULL default '',
RootCat int(11) NOT NULL default '0',
BuildDate int(10) unsigned default NULL,
PRIMARY KEY (`Name`)
);
CREATE TABLE PersistantSessionData (
VariableId bigint(20) NOT NULL auto_increment,
PortalUserId int(11) NOT NULL default '0',
VariableName varchar(255) NOT NULL default '',
VariableValue text NOT NULL,
PRIMARY KEY (VariableId),
KEY UserId (PortalUserId),
KEY VariableName (VariableName)
);
CREATE TABLE Phrase (
Phrase varchar(255) NOT NULL default '',
Translation text NOT NULL,
PhraseType int(11) NOT NULL default '0',
PhraseId int(11) NOT NULL auto_increment,
LanguageId int(11) NOT NULL default '0',
LastChanged int(10) unsigned NOT NULL default '0',
LastChangeIP varchar(15) NOT NULL default '',
Module VARCHAR(30) NOT NULL DEFAULT 'In-Portal',
PRIMARY KEY (PhraseId),
KEY LanguageId (LanguageId),
INDEX Phrase_Index (Phrase)
);
CREATE TABLE PhraseCache (
Template varchar(40) NOT NULL default '',
PhraseList text NOT NULL,
CacheDate int(11) NOT NULL default '0',
ThemeId int(11) NOT NULL default '0',
StylesheetId int(10) unsigned NOT NULL default '0',
ConfigVariables text,
PRIMARY KEY (Template)
);
CREATE TABLE PortalGroup (
GroupId int(11) NOT NULL auto_increment,
Name varchar(255) NOT NULL default '',
Description varchar(255) default NULL,
CreatedOn INT UNSIGNED NULL DEFAULT NULL,
System tinyint(4) NOT NULL default '0',
Personal tinyint(4) NOT NULL default '0',
Enabled tinyint(4) NOT NULL default '1',
ResourceId int(11) NOT NULL default '0',
PRIMARY KEY (GroupId),
UNIQUE KEY Name (Name),
UNIQUE KEY ResourceId (ResourceId),
KEY Personal (Personal),
KEY Enabled (Enabled)
);
CREATE TABLE PortalUser (
PortalUserId int(11) NOT NULL auto_increment,
Login varchar(255) default NULL,
`Password` VARCHAR(255) NULL DEFAULT 'd41d8cd98f00b204e9800998ecf8427e',
FirstName VARCHAR(255) NOT NULL DEFAULT '',
LastName VARCHAR(255) NOT NULL DEFAULT '',
Company varchar(255) NOT NULL default '',
Email varchar(255) NOT NULL default '',
CreatedOn INT DEFAULT NULL,
Phone varchar(20) default NULL,
Fax varchar(255) NOT NULL default '',
Street varchar(255) default NULL,
Street2 varchar(255) NOT NULL default '',
City varchar(20) default NULL,
State varchar(20) NOT NULL default '',
Zip varchar(20) default NULL,
Country varchar(20) NOT NULL default '',
ResourceId int(11) NOT NULL default '0',
`Status` tinyint(4) NOT NULL default '2',
Modified int(11) NOT NULL default '0',
dob INT(11) NULL DEFAULT NULL,
tz int(11) default NULL,
ip varchar(20) default NULL,
IsBanned tinyint(1) NOT NULL default '0',
PassResetTime INT(11) UNSIGNED NULL DEFAULT NULL,
PwResetConfirm varchar(255) default NULL,
PwRequestTime INT(11) UNSIGNED NULL DEFAULT NULL,
MinPwResetDelay int(11) NOT NULL default '1800',
PRIMARY KEY (PortalUserId),
UNIQUE KEY ResourceId (ResourceId),
UNIQUE KEY Login (Login),
KEY CreatedOn (CreatedOn)
);
CREATE TABLE PortalUserCustomData (
CustomDataId int(11) NOT NULL auto_increment,
ResourceId int(10) unsigned NOT NULL default '0',
KEY ResourceId (ResourceId),
PRIMARY KEY (CustomDataId)
);
CREATE TABLE SessionData (
SessionKey varchar(50) NOT NULL default '',
VariableName varchar(255) NOT NULL default '',
VariableValue longtext NOT NULL,
PRIMARY KEY (SessionKey,VariableName),
KEY SessionKey (SessionKey),
KEY VariableName (VariableName)
);
CREATE TABLE Theme (
ThemeId int(11) NOT NULL auto_increment,
Name varchar(40) NOT NULL default '',
Enabled int(11) NOT NULL default '1',
Description varchar(255) default NULL,
PrimaryTheme int(11) NOT NULL default '0',
CacheTimeout int(11) NOT NULL default '0',
StylesheetId int(10) unsigned NOT NULL default '0',
PRIMARY KEY (ThemeId)
);
CREATE TABLE ThemeFiles (
FileId int(11) NOT NULL auto_increment,
ThemeId int(11) NOT NULL default '0',
FileName varchar(255) NOT NULL default '',
FilePath varchar(255) NOT NULL default '',
Description varchar(255) default NULL,
FileType int(11) NOT NULL default '0',
FileFound tinyint(3) unsigned NOT NULL default '0',
PRIMARY KEY (FileId),
KEY theme (ThemeId),
KEY FileName (FileName),
KEY FilePath (FilePath),
KEY FileFound (FileFound)
);
CREATE TABLE UserGroup (
PortalUserId int(11) NOT NULL default '0',
GroupId int(11) NOT NULL default '0',
MembershipExpires int(10) unsigned default NULL,
PrimaryGroup tinyint(4) NOT NULL default '1',
ExpirationReminderSent tinyint(4) NOT NULL default '0',
PRIMARY KEY (PortalUserId,GroupId),
KEY GroupId (GroupId),
KEY PrimaryGroup (PrimaryGroup)
);
CREATE TABLE UserSession (
SessionKey int(10) unsigned NOT NULL default '0',
CurrentTempKey int(10) unsigned default NULL,
PrevTempKey int(10) unsigned default NULL,
LastAccessed int(10) unsigned NOT NULL default '0',
PortalUserId int(11) NOT NULL default '-2',
`Language` int(11) NOT NULL default '1',
Theme int(11) NOT NULL default '1',
GroupId int(11) NOT NULL default '0',
IpAddress varchar(20) NOT NULL default '0.0.0.0',
`Status` int(11) NOT NULL default '1',
GroupList varchar(255) default NULL,
tz int(11) default NULL,
PRIMARY KEY (SessionKey),
KEY UserId (PortalUserId),
KEY LastAccessed (LastAccessed)
);
CREATE TABLE EmailLog (
EmailLogId int(11) NOT NULL auto_increment,
fromuser varchar(200) default NULL,
addressto varchar(255) default NULL,
`subject` varchar(255) default NULL,
`timestamp` bigint(20) default '0',
event varchar(100) default NULL,
EventParams text NOT NULL,
PRIMARY KEY (EmailLogId)
);
CREATE TABLE Cache (
VarName varchar(255) NOT NULL default '',
Data longtext,
Cached int(11) default NULL,
LifeTime int(11) NOT NULL default '-1',
PRIMARY KEY (VarName),
KEY Cached (Cached)
);
CREATE TABLE StdDestinations (
DestId int(11) NOT NULL auto_increment,
DestType int(11) NOT NULL default '0',
DestParentId int(11) default NULL,
DestName varchar(255) NOT NULL default '',
DestAbbr char(3) NOT NULL default '',
DestAbbr2 char(2) default NULL,
PRIMARY KEY (DestId)
);
CREATE TABLE Category (
CategoryId int(11) NOT NULL auto_increment,
`Type` int(11) NOT NULL default '0',
SymLinkCategoryId int(10) unsigned default NULL,
ParentId int(11) NOT NULL default '0',
Name varchar(255) NOT NULL default '',
l1_Name varchar(255) NOT NULL default '',
l2_Name varchar(255) NOT NULL default '',
l3_Name varchar(255) NOT NULL default '',
l4_Name varchar(255) NOT NULL default '',
l5_Name varchar(255) NOT NULL default '',
Filename varchar(255) NOT NULL default '',
AutomaticFilename tinyint(3) unsigned NOT NULL default '1',
Description text,
l1_Description text,
l2_Description text,
l3_Description text,
l4_Description text,
l5_Description text,
CreatedOn int(11) NOT NULL default '0',
EditorsPick tinyint(4) NOT NULL default '0',
`Status` tinyint(4) NOT NULL default '0',
Priority int(11) NOT NULL default '0',
MetaKeywords varchar(255) default NULL,
CachedDescendantCatsQty int(11) default NULL,
CachedNavbar text,
l1_CachedNavbar text,
l2_CachedNavbar text,
l3_CachedNavbar text,
l4_CachedNavbar text,
l5_CachedNavbar text,
CreatedById int(11) NOT NULL default '0',
ResourceId int(11) default NULL,
ParentPath TEXT NULL DEFAULT NULL,
TreeLeft bigint(20) NOT NULL default '0',
TreeRight bigint(20) NOT NULL default '0',
NamedParentPath TEXT NULL DEFAULT NULL,
MetaDescription varchar(255) default NULL,
HotItem int(11) NOT NULL default '2',
NewItem int(11) NOT NULL default '2',
PopItem int(11) NOT NULL default '2',
Modified int(11) NOT NULL default '0',
ModifiedById int(11) NOT NULL default '0',
CategoryTemplate varchar(255) NOT NULL default '',
CachedCategoryTemplate varchar(255) NOT NULL default '',
PRIMARY KEY (CategoryId),
UNIQUE KEY ResourceId (ResourceId),
KEY ParentId (ParentId),
KEY Modified (Modified),
KEY Priority (Priority),
KEY sorting (Name,Priority),
KEY Filename (Filename(5)),
KEY l1_Name (l1_Name(5)),
KEY l2_Name (l2_Name(5)),
KEY l3_Name (l3_Name(5)),
KEY l4_Name (l4_Name(5)),
KEY l5_Name (l5_Name(5)),
KEY l1_Description (l1_Description(5)),
KEY l2_Description (l2_Description(5)),
KEY l3_Description (l3_Description(5)),
KEY l4_Description (l4_Description(5)),
KEY l5_Description (l5_Description(5)),
KEY TreeLeft (TreeLeft),
KEY TreeRight (TreeRight),
KEY SymLinkCategoryId (SymLinkCategoryId)
);
CREATE TABLE CategoryCustomData (
CustomDataId int(11) NOT NULL auto_increment,
ResourceId int(10) unsigned NOT NULL default '0',
KEY ResourceId (ResourceId),
PRIMARY KEY (CustomDataId)
);
CREATE TABLE CategoryItems (
`CategoryId` int(11) NOT NULL default '0',
`ItemResourceId` int(11) NOT NULL default '0',
`PrimaryCat` tinyint(4) NOT NULL default '0',
`ItemPrefix` varchar(50) NOT NULL default '',
`Filename` varchar(255) NOT NULL default '',
UNIQUE KEY `CategoryId` (`CategoryId`,`ItemResourceId`),
KEY `PrimaryCat` (`PrimaryCat`),
KEY `ItemPrefix` (`ItemPrefix`),
KEY `Filename` (`Filename`(4))
);
CREATE TABLE PermCache (
PermCacheId int(11) NOT NULL auto_increment,
CategoryId int(11) NOT NULL default '0',
PermId int(11) NOT NULL default '0',
ACL varchar(255) NOT NULL default '',
PRIMARY KEY (PermCacheId),
KEY CategoryId (CategoryId),
KEY PermId (PermId)
);
CREATE TABLE Stylesheets (
StylesheetId int(11) NOT NULL auto_increment,
Name varchar(255) NOT NULL default '',
Description varchar(255) NOT NULL default '',
AdvancedCSS text NOT NULL,
LastCompiled int(10) unsigned NOT NULL default '0',
Enabled int(11) NOT NULL default '0',
PRIMARY KEY (StylesheetId)
);
CREATE TABLE PopupSizes (
PopupId int(10) unsigned NOT NULL auto_increment,
TemplateName varchar(255) NOT NULL default '',
PopupWidth int(11) NOT NULL default '0',
PopupHeight int(11) NOT NULL default '0',
PRIMARY KEY (PopupId),
KEY TemplateName (TemplateName)
);
CREATE TABLE Counters (
CounterId int(10) unsigned NOT NULL auto_increment,
Name varchar(100) NOT NULL default '',
CountQuery text,
CountValue text,
LastCounted int(10) unsigned default NULL,
LifeTime int(10) unsigned NOT NULL default '3600',
IsClone tinyint(3) unsigned NOT NULL default '0',
TablesAffected text,
PRIMARY KEY (CounterId),
UNIQUE KEY Name (Name)
);
CREATE TABLE Skins (
`SkinId` int(11) NOT NULL auto_increment,
`Name` varchar(255) default NULL,
`CSS` text,
`Logo` varchar(255) default NULL,
`Options` text,
`LastCompiled` int(11) NOT NULL default '0',
`IsPrimary` int(1) NOT NULL default '0',
PRIMARY KEY (`SkinId`)
);
+
+CREATE TABLE ChangeLogs (
+ ChangeLogId bigint(20) NOT NULL auto_increment,
+ PortalUserId int(11) NOT NULL default '0',
+ SessionLogId int(11) NOT NULL default '0',
+ `Action` tinyint(4) NOT NULL default '0',
+ OccuredOn int(11) NOT NULL default '0',
+ Prefix varchar(255) NOT NULL default '',
+ ItemId bigint(20) NOT NULL default '0',
+ Changes text NOT NULL,
+ MasterPrefix varchar(255) NOT NULL default '',
+ MasterId bigint(20) NOT NULL default '0',
+ PRIMARY KEY (ChangeLogId),
+ KEY PortalUserId (PortalUserId),
+ KEY SessionLogId (SessionLogId),
+ KEY `Action` (`Action`),
+ KEY OccuredOn (OccuredOn),
+ KEY Prefix (Prefix),
+ KEY MasterPrefix (MasterPrefix)
+);
+
+CREATE TABLE SessionLogs (
+ SessionLogId bigint(20) NOT NULL auto_increment,
+ PortalUserId int(11) NOT NULL default '0',
+ SessionId int(10) NOT NULL default '0',
+ `Status` tinyint(4) NOT NULL default '1',
+ SessionStart int(11) NOT NULL default '0',
+ SessionEnd int(11) default NULL,
+ IP varchar(15) NOT NULL default '',
+ AffectedItems int(11) NOT NULL default '0',
+ PRIMARY KEY (SessionLogId),
+ KEY SessionId (SessionId),
+ KEY `Status` (`Status`)
+);
Property changes on: branches/RC/core/install/install_schema.sql
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.14.2.6
\ No newline at end of property
+1.14.2.7
\ No newline at end of property
Index: branches/RC/core/install/upgrades.sql
===================================================================
--- branches/RC/core/install/upgrades.sql (revision 10293)
+++ branches/RC/core/install/upgrades.sql (revision 10294)
@@ -1,183 +1,218 @@
# ===== v 4.0.1 =====
ALTER TABLE EmailLog ADD EventParams TEXT NOT NULL;
INSERT INTO ConfigurationAdmin VALUES ('MailFunctionHeaderSeparator', 'la_Text_smtp_server', 'la_config_MailFunctionHeaderSeparator', 'radio', NULL, '1=la_Linux,2=la_Windows', 30.08, 0, 0);
INSERT INTO ConfigurationValues VALUES (0, 'MailFunctionHeaderSeparator', 1, 'In-Portal', 'in-portal:configure_general');
ALTER TABLE PersistantSessionData DROP PRIMARY KEY ;
ALTER TABLE PersistantSessionData ADD INDEX ( `PortalUserId` ) ;
# ===== v 4.1.0 =====
ALTER TABLE EmailMessage ADD ReplacementTags TEXT AFTER Template;
ALTER TABLE Phrase
CHANGE Translation Translation TEXT NOT NULL,
CHANGE Module Module VARCHAR(30) NOT NULL DEFAULT 'In-Portal';
ALTER TABLE Category
CHANGE Description Description TEXT,
CHANGE l1_Description l1_Description TEXT,
CHANGE l2_Description l2_Description TEXT,
CHANGE l3_Description l3_Description TEXT,
CHANGE l4_Description l4_Description TEXT,
CHANGE l5_Description l5_Description TEXT,
CHANGE CachedNavbar CachedNavbar text,
CHANGE l1_CachedNavbar l1_CachedNavbar text,
CHANGE l2_CachedNavbar l2_CachedNavbar text,
CHANGE l3_CachedNavbar l3_CachedNavbar text,
CHANGE l4_CachedNavbar l4_CachedNavbar text,
CHANGE l5_CachedNavbar l5_CachedNavbar text,
CHANGE ParentPath ParentPath TEXT NULL DEFAULT NULL,
CHANGE NamedParentPath NamedParentPath TEXT NULL DEFAULT NULL;
ALTER TABLE ConfigurationAdmin CHANGE ValueList ValueList TEXT;
ALTER TABLE EmailQueue
CHANGE `Subject` `Subject` TEXT,
CHANGE toaddr toaddr TEXT,
CHANGE fromaddr fromaddr TEXT;
ALTER TABLE Category DROP Pop;
ALTER TABLE PortalUser
CHANGE CreatedOn CreatedOn INT DEFAULT NULL,
CHANGE dob dob INT(11) NULL DEFAULT NULL,
CHANGE PassResetTime PassResetTime INT(11) UNSIGNED NULL DEFAULT NULL,
CHANGE PwRequestTime PwRequestTime INT(11) UNSIGNED NULL DEFAULT NULL,
CHANGE `Password` `Password` VARCHAR(255) NULL DEFAULT 'd41d8cd98f00b204e9800998ecf8427e';
ALTER TABLE Modules
CHANGE BuildDate BuildDate INT UNSIGNED NULL DEFAULT NULL,
CHANGE Version Version VARCHAR(10) NOT NULL DEFAULT '0.0.0',
CHANGE `Var` `Var` VARCHAR(100) NOT NULL DEFAULT '';
ALTER TABLE Language
CHANGE Enabled Enabled INT(11) NOT NULL DEFAULT '1',
CHANGE InputDateFormat InputDateFormat VARCHAR(50) NOT NULL DEFAULT 'm/d/Y',
CHANGE InputTimeFormat InputTimeFormat VARCHAR(50) NOT NULL DEFAULT 'g:i:s A',
CHANGE DecimalPoint DecimalPoint VARCHAR(10) NOT NULL DEFAULT '',
CHANGE ThousandSep ThousandSep VARCHAR(10) NOT NULL DEFAULT '';
ALTER TABLE Events CHANGE FromUserId FromUserId INT(11) NOT NULL DEFAULT '-1';
ALTER TABLE StdDestinations CHANGE DestAbbr2 DestAbbr2 CHAR(2) NULL DEFAULT NULL;
ALTER TABLE PermCache DROP DACL;
ALTER TABLE PortalGroup CHANGE CreatedOn CreatedOn INT UNSIGNED NULL DEFAULT NULL;
ALTER TABLE UserSession
CHANGE SessionKey SessionKey INT UNSIGNED NULL DEFAULT NULL ,
CHANGE CurrentTempKey CurrentTempKey INT UNSIGNED NULL DEFAULT NULL ,
CHANGE PrevTempKey PrevTempKey INT UNSIGNED NULL DEFAULT NULL ,
CHANGE LastAccessed LastAccessed INT UNSIGNED NOT NULL DEFAULT '0',
CHANGE PortalUserId PortalUserId INT(11) NOT NULL DEFAULT '-2',
CHANGE Language Language INT(11) NOT NULL DEFAULT '1',
CHANGE Theme Theme INT(11) NOT NULL DEFAULT '1';
CREATE TABLE Counters (
CounterId int(10) unsigned NOT NULL auto_increment,
Name varchar(100) NOT NULL default '',
CountQuery text,
CountValue text,
LastCounted int(10) unsigned default NULL,
LifeTime int(10) unsigned NOT NULL default '3600',
IsClone tinyint(3) unsigned NOT NULL default '0',
TablesAffected text,
PRIMARY KEY (CounterId),
UNIQUE KEY Name (Name)
);
CREATE TABLE Skins (
`SkinId` int(11) NOT NULL auto_increment,
`Name` varchar(255) default NULL,
`CSS` text,
`Logo` varchar(255) default NULL,
`Options` text,
`LastCompiled` int(11) NOT NULL default '0',
`IsPrimary` int(1) NOT NULL default '0',
PRIMARY KEY (`SkinId`)
);
INSERT INTO Skins VALUES (DEFAULT, 'Default', '/* General elements */\r\n\r\nhtml {\r\n height: 100%;\r\n}\r\n\r\nbody {\r\n font-family: verdana,arial,helvetica,sans-serif;\r\n font-size: 9pt;\r\n color: #000000;\r\n overflow-x: auto; overflow-y: auto;\r\n margin: 0px 0px 0px 0px;\r\n text-decoration: none;\r\n}\r\n\r\na {\r\n color: #006699;\r\n text-decoration: none;\r\n}\r\n\r\na:hover {\r\n color: #009ff0;\r\n text-decoration: none;\r\n}\r\n\r\nform {\r\n display: inline;\r\n}\r\n\r\nimg { border: 0px; }\r\n\r\nbody.height-100 {\r\n height: 100%;\r\n}\r\n\r\nbody.regular-body {\r\n margin: 0px 10px 5px 10px;\r\n color: #000000;\r\n background-color: @@SectionBgColor@@;\r\n}\r\n\r\nbody.edit-popup {\r\n margin: 0px 0px 0px 0px;\r\n}\r\n\r\ntable.collapsed {\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered, table.bordered, .bordered-no-bottom {\r\n border: 1px solid #000000;\r\n border-collapse: collapse;\r\n}\r\n\r\n.bordered-no-bottom {\r\n border-bottom: none;\r\n}\r\n\r\n.login-table td {\r\n padding: 1px;\r\n}\r\n\r\n.disabled {\r\n background-color: #ebebeb;\r\n}\r\n\r\n/* Head frame */\r\n.head-table tr td {\r\n background-color: @@HeadBgColor@@;\r\n color: @@HeadColor@@\r\n}\r\n\r\ntd.kx-block-header, .head-table tr td.kx-block-header{\r\n color: @@HeadBarColor@@;\r\n background-color: @@HeadBarBgColor@@;\r\n padding-left: 7px;\r\n padding-right: 7px;\r\n}\r\n\r\na.kx-header-link {\r\n text-decoration: underline;\r\n color: #FFFFFF;\r\n}\r\n\r\na.kx-header-link:hover {\r\n color: #FFCB05;\r\n text-decoration: none;\r\n}\r\n\r\n.kx-secondary-foreground {\r\n color: @@HeadBarColor@@;\r\n background-color: @@HeadBarBgColor@@;\r\n}\r\n\r\n.kx-login-button {\r\n background-color: #2D79D6;\r\n color: #FFFFFF;\r\n}\r\n\r\n/* General form button (yellow) */\r\n.button {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #000000;\r\n background: url(@@base_url@@/proj-base/admin_templates/img/button_back.gif) #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Disabled (grayed-out) form button */\r\n.button-disabled {\r\n font-size: 12px;\r\n font-weight: normal;\r\n color: #676767;\r\n background: url(@@base_url@@/proj-base/admin_templates/img/button_back_disabled.gif) #f9eeae repeat-x;\r\n text-decoration: none;\r\n}\r\n\r\n/* Tabs bar */\r\n\r\n.tab, .tab-active {\r\n background-color: #F0F1EB;\r\n padding: 3px 7px 2px 7px;\r\n border-top: 1px solid black;\r\n border-left: 1px solid black;\r\n border-right: 1px solid black;\r\n}\r\n\r\n.tab-active {\r\n background-color: #2D79D6;\r\n border-bottom: 1px solid #2D79D6;\r\n}\r\n\r\n.tab a {\r\n color: #00659C;\r\n font-weight: bold;\r\n}\r\n\r\n.tab-active a {\r\n color: #fff;\r\n font-weight: bold;\r\n}\r\n\r\n\r\n/* Toolbar */\r\n\r\n.toolbar {\r\n font-size: 8pt;\r\n border: 1px solid #000000;\r\n border-width: 0px 1px 1px 1px;\r\n background-color: @@ToolbarBgColor@@;\r\n border-collapse: collapse;\r\n}\r\n\r\n.toolbar td {\r\n height: 100%;\r\n}\r\n\r\n.toolbar-button, .toolbar-button-disabled, .toolbar-button-over {\r\n float: left;\r\n text-align: center;\r\n font-size: 8pt;\r\n padding: 5px 5px 5px 5px;\r\n vertical-align: middle;\r\n color: #006F99;\r\n}\r\n\r\n.toolbar-button-over {\r\n color: #000;\r\n}\r\n\r\n.toolbar-button-disabled {\r\n color: #444;\r\n}\r\n\r\n/* Scrollable Grids */\r\n\r\n\r\n/* Main Grid class */\r\n.grid-scrollable {\r\n padding: 0px;\r\n border: 1px solid black !important;\r\n border-top: none !important;\r\n}\r\n\r\n/* Div generated by js, which contains all the scrollable grid elements, affects the style of scrollable area without data (if there are too few rows) */\r\n.grid-container {\r\n background-color: #fff;\r\n}\r\n\r\n.grid-container table {\r\n border-collapse: collapse;\r\n}\r\n\r\n/* Inner div generated in each data-cell */\r\n.grid-cell-div {\r\n overflow: hidden;\r\n height: auto;\r\n}\r\n\r\n/* Main row definition */\r\n.grid-data-row td, .grid-data-row-selected td, .grid-data-row-even-selected td, .grid-data-row-mouseover td, .table-color1, .table-color2 {\r\n font-weight: normal;\r\n color: @@OddColor@@;\r\n background-color: @@OddBgColor@@;\r\n padding: 3px 5px 3px 5px;\r\n height: 30px;\r\n overflow: hidden;\r\n /* border-right: 1px solid black; */\r\n}\r\n.grid-data-row-even td, .table-color2 {\r\n background-color: @@EvenBgColor@@;\r\n color: @@EvenColor@@;\r\n}\r\n.grid-data-row td a, .grid-data-row-selected td a, .grid-data-row-mouseover td a {\r\n text-decoration: underline;\r\n}\r\n\r\n/* mouse-over rows */\r\n.grid-data-row-mouseover td {\r\n background: #FFFDF4;\r\n}\r\n\r\n/* Selected row, applies to both checkbox and data areas */\r\n.grid-data-row-selected td {\r\n background: #FEF2D6;\r\n}\r\n\r\n.grid-data-row-even-selected td {\r\n background: #FFF7E0;\r\n}\r\n\r\n/* General header cell definition */\r\n.grid-header-row td {\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n text-decoration: none;\r\n padding: 3px 5px 3px 5px;\r\n color: @@ColumnTitlesColor@@;\r\n border-right: none;\r\n text-align: left;\r\n vertical-align: middle !important;\r\n white-space: nowrap;\r\n /* border-right: 1px solid black; */\r\n}\r\n\r\n/* Filters row */\r\ntr.grid-header-row-0 td {\r\n background-color: @@FiltersBgColor@@;\r\n border-bottom: 1px solid black;\r\n}\r\n\r\n/* Grid Filters */\r\ntable.range-filter {\r\n width: 100%;\r\n}\r\n\r\n.range-filter td {\r\n padding: 0px 0px 2px 2px !important;\r\n border: none !important;\r\n font-size: 8pt !important;\r\n font-weight: normal !important;\r\n text-align: left;\r\n color: #000000 !important;\r\n}\r\n\r\ninput.filter, select.filter {\r\n margin-bottom: 0px;\r\n width: 85%;\r\n}\r\n\r\ninput.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\nselect.filter-active {\r\n background-color: #FFFF00;\r\n}\r\n\r\n/* Column titles row */\r\ntr.grid-header-row-1 td {\r\n height: 25px;\r\n font-weight: bold;\r\n background-color: @@ColumnTitlesBgColor@@;\r\n color: @@ColumnTitlesColor@@;\r\n}\r\n\r\ntr.grid-header-row-1 td a {\r\n color: @@ColumnTitlesColor@@;\r\n}\r\n\r\ntr.grid-header-row-1 td a:hover {\r\n color: #FFCC00;\r\n}\r\n\r\n\r\n.grid-footer-row td {\r\n background-color: #D7D7D7;\r\n font-weight: bold;\r\n border-right: none;\r\n padding: 3px 5px 3px 5px;\r\n}\r\n\r\ntd.grid-header-last-cell, td.grid-data-last-cell, td.grid-footer-last-cell {\r\n border-right: none !important;\r\n}\r\n\r\ntd.grid-data-col-0, td.grid-data-col-0 div {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-0 td.grid-header-col-0 {\r\n text-align: center;\r\n vertical-align: middle !important;\r\n}\r\n\r\ntr.grid-header-row-0 td.grid-header-col-0 div {\r\n display: table-cell;\r\n vertical-align: middle;\r\n}\r\n\r\n.grid-status-bar {\r\n border: 1px solid black;\r\n border-top: none;\r\n padding: 0px;\r\n width: 100%;\r\n border-collapse: collapse;\r\n height: 30px;\r\n}\r\n\r\n.grid-status-bar td {\r\n background-color: @@TitleBarBgColor@@;\r\n color: @@TitleBarColor@@;\r\n font-size: 11pt;\r\n font-weight: normal;\r\n padding: 2px 8px 2px 8px;\r\n}\r\n\r\n/* /Scrollable Grids */\r\n\r\n\r\n/* Forms */\r\ntable.edit-form {\r\n border: none;\r\n border-top-width: 0px;\r\n border-collapse: collapse;\r\n width: 100%;\r\n}\r\n\r\n.edit-form-odd, .edit-form-even {\r\n padding: 0px;\r\n}\r\n\r\n.subsectiontitle {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #4A92CE;\r\n color: #fff;\r\n height: 25px;\r\n border-top: 1px solid black;\r\n}\r\n\r\n.label-cell {\r\n background: #DEE7F6 url(@@base_url@@/proj-base/admin_templates/img/bgr_input_name_line.gif) no-repeat right bottom;\r\n font: 12px arial, sans-serif;\r\n padding: 4px 20px;\r\n width: 150px;\r\n}\r\n\r\n.control-mid {\r\n width: 13px;\r\n border-left: 1px solid #7A95C2;\r\n background: #fff url(@@base_url@@/proj-base/admin_templates/img/bgr_mid.gif) repeat-x left bottom;\r\n}\r\n\r\n.control-cell {\r\n font: 11px arial, sans-serif;\r\n padding: 4px 10px 5px 5px;\r\n background: #fff url(@@base_url@@/proj-base/admin_templates/img/bgr_input_line.gif) no-repeat left bottom;\r\n width: auto;\r\n vertical-align: middle;\r\n}\r\n\r\n.label-cell-filler {\r\n background: #DEE7F6 none;\r\n}\r\n.control-mid-filler {\r\n background: #fff none;\r\n border-left: 1px solid #7A95C2;\r\n}\r\n.control-cell-filler {\r\n background: #fff none;\r\n}\r\n\r\n\r\n.error-cell {\r\n background-color: #fff;\r\n color: red;\r\n}\r\n\r\n.form-warning {\r\n color: red;\r\n}\r\n\r\n.req-note {\r\n font-style: italic;\r\n color: #333;\r\n}\r\n\r\n#scroll_container table.tableborder {\r\n border-collapse: separate\r\n}\r\n\r\n\r\n/* Uploader */\r\n\r\n.uploader-main {\r\n position: absolute;\r\n display: none;\r\n z-index: 10;\r\n border: 1px solid #777;\r\n padding: 10px;\r\n width: 350px;\r\n height: 120px;\r\n overflow: hidden;\r\n background-color: #fff;\r\n}\r\n\r\n.uploader-percent {\r\n width: 100%;\r\n padding-top: 3px;\r\n text-align: center;\r\n position: relative;\r\n z-index: 20;\r\n float: left;\r\n font-weight: bold;\r\n}\r\n\r\n.uploader-left {\r\n width: 100%;\r\n border: 1px solid black;\r\n height: 20px;\r\n background: #fff url(@@base_url@@/core/admin_templates/img/progress_left.gif);\r\n}\r\n\r\n.uploader-done {\r\n width: 0%;\r\n background-color: green;\r\n height: 20px;\r\n background: #4A92CE url(@@base_url@@/core/admin_templates/img/progress_done.gif);\r\n}\r\n\r\n\r\n/* To be sorted */\r\n\r\n\r\n/* Section title, right to the big icon */\r\n.admintitle {\r\n font-size: 16pt;\r\n font-weight: bold;\r\n color: @@SectionColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Left sid of bluebar */\r\n.header_left_bg {\r\n background-color: @@TitleBarBgColor@@;\r\n background-image: none;\r\n padding-left: 5px;\r\n}\r\n\r\n/* Right side of bluebar */\r\n.tablenav, tablenav a {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n\r\n text-decoration: none;\r\n background-color: @@TitleBarBgColor@@;\r\n background-image: none;\r\n}\r\n\r\n/* Section title in the bluebar * -- why ''link''? :S */\r\n.tablenav_link {\r\n font-size: 11pt;\r\n font-weight: bold;\r\n color: @@TitleBarColor@@;\r\n text-decoration: none;\r\n}\r\n\r\n/* Active page in top and bottom bluebars pagination */\r\n.current_page {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n background-color: #fff;\r\n color: #2D79D6;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Other pages and arrows in pagination on blue */\r\n.nav_url {\r\n font-size: 10pt;\r\n font-weight: bold;\r\n color: #fff;\r\n padding: 3px 2px 3px 3px;\r\n}\r\n\r\n/* Tree */\r\n.tree-body {\r\n background-color: @@TreeBgColor@@;\r\n height: 100%\r\n}\r\n\r\n.tree_head.td, .tree_head, .tree_head:hover {\r\n font-weight: bold;\r\n font-size: 10px;\r\n color: #FFFFFF;\r\n font-family: Verdana, Arial;\r\n text-decoration: none;\r\n}\r\n\r\n.tree {\r\n padding: 0px;\r\n border: none;\r\n border-collapse: collapse;\r\n}\r\n\r\n.tree tr td {\r\n padding: 0px;\r\n margin: 0px;\r\n font-family: helvetica, arial, verdana,;\r\n font-size: 11px;\r\n white-space: nowrap;\r\n}\r\n\r\n.tree tr td a {\r\n font-size: 11px;\r\n color: @@TreeColor@@;\r\n font-family: Helvetica, Arial, Verdana;\r\n text-decoration: none;\r\n padding: 2px 0px 2px 2px;\r\n}\r\n\r\n.tree tr.highlighted td a {\r\n background-color: @@TreeHighBgColor@@;\r\n color: @@TreeHighColor@@;\r\n}\r\n\r\n.tree tr.highlighted td a:hover {\r\n color: #fff;\r\n}\r\n\r\n.tree tr td a:hover {\r\n color: #000000;\r\n}', 'just_logo.gif', 'a:20:{s:11:"HeadBgColor";a:2:{s:11:"Description";s:27:"Head frame background color";s:5:"Value";s:7:"#1961B8";}s:9:"HeadColor";a:2:{s:11:"Description";s:21:"Head frame text color";s:5:"Value";s:7:"#CCFF00";}s:14:"SectionBgColor";a:2:{s:11:"Description";s:28:"Section bar background color";s:5:"Value";s:7:"#FFFFFF";}s:12:"SectionColor";a:2:{s:11:"Description";s:22:"Section bar text color";s:5:"Value";s:7:"#2D79D6";}s:12:"HeadBarColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:14:"HeadBarBgColor";a:1:{s:5:"Value";s:7:"#1961B8";}s:13:"TitleBarColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TitleBarBgColor";a:1:{s:5:"Value";s:7:"#2D79D6";}s:14:"ToolbarBgColor";a:1:{s:5:"Value";s:7:"#F0F1EB";}s:14:"FiltersBgColor";a:1:{s:5:"Value";s:7:"#D7D7D7";}s:17:"ColumnTitlesColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:19:"ColumnTitlesBgColor";a:1:{s:5:"Value";s:7:"#999999";}s:8:"OddColor";a:1:{s:5:"Value";s:7:"#000000";}s:10:"OddBgColor";a:1:{s:5:"Value";s:7:"#F6F6F6";}s:9:"EvenColor";a:1:{s:5:"Value";s:7:"#000000";}s:11:"EvenBgColor";a:1:{s:5:"Value";s:7:"#EBEBEB";}s:9:"TreeColor";a:1:{s:5:"Value";s:7:"#006F99";}s:11:"TreeBgColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:13:"TreeHighColor";a:1:{s:5:"Value";s:7:"#FFFFFF";}s:15:"TreeHighBgColor";a:1:{s:5:"Value";s:7:"#4A92CE";}}', 1178706881, 1);
INSERT INTO Permissions VALUES (0, 'in-portal:skins.view', 11, 1, 1, 0), (0, 'in-portal:skins.add', 11, 1, 1, 0), (0, 'in-portal:skins.edit', 11, 1, 1, 0), (0, 'in-portal:skins.delete', 11, 1, 1, 0);
# ===== v 4.1.1 =====
DROP TABLE EmailQueue;
CREATE TABLE EmailQueue (
EmailQueueId int(10) unsigned NOT NULL auto_increment,
ToEmail varchar(255) NOT NULL default '',
`Subject` varchar(255) NOT NULL default '',
MessageHeaders text,
MessageBody longtext,
Queued int(10) unsigned NOT NULL default '0',
SendRetries int(10) unsigned NOT NULL default '0',
LastSendRetry int(10) unsigned NOT NULL default '0',
PRIMARY KEY (EmailQueueId),
KEY LastSendRetry (LastSendRetry),
KEY SendRetries (SendRetries)
);
ALTER TABLE Events ADD ReplacementTags TEXT AFTER Event;
# ===== v 4.2.0 =====
ALTER TABLE CustomField ADD MultiLingual TINYINT UNSIGNED NOT NULL DEFAULT '1' AFTER FieldLabel;
ALTER TABLE Category
ADD TreeLeft BIGINT NOT NULL AFTER ParentPath,
ADD TreeRight BIGINT NOT NULL AFTER TreeLeft;
ALTER TABLE Category ADD INDEX (TreeLeft);
ALTER TABLE Category ADD INDEX (TreeRight);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'CategoriesRebuildSerial', '0', 'In-Portal', '');
UPDATE ConfigurationAdmin SET `element_type` = 'textarea' WHERE `VariableName` IN ('Category_MetaKey', 'Category_MetaDesc');
ALTER TABLE PortalUser
CHANGE FirstName FirstName VARCHAR(255) NOT NULL DEFAULT '',
CHANGE LastName LastName VARCHAR(255) NOT NULL DEFAULT '';
# ===== v 4.2.1 =====
INSERT INTO ConfigurationAdmin VALUES ('UseSmallHeader', 'la_Text_Website', 'la_config_UseSmallHeader', 'checkbox', '', '', 10.21, 0, 0);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseSmallHeader', '0', 'In-Portal', 'in-portal:configure_general');
INSERT INTO ConfigurationAdmin VALUES ('User_Default_Registration_Country', 'la_Text_General', 'la_config_DefaultRegistrationCountry', 'select', NULL , '=+,<SQL>SELECT DestName AS OptionName, DestId AS OptionValue FROM <PREFIX>StdDestinations WHERE DestParentId IS NULL Order BY OptionName</SQL>', 10.111, 0, 0);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'User_Default_Registration_Country', '', 'In-Portal:Users', 'in-portal:configure_users');
ALTER TABLE Category ADD SymLinkCategoryId INT UNSIGNED NULL DEFAULT NULL AFTER `Type`, ADD INDEX (SymLinkCategoryId);
ALTER TABLE ConfigurationValues CHANGE VariableValue VariableValue TEXT NULL DEFAULT NULL;
ALTER TABLE Language
ADD AdminInterfaceLang TINYINT UNSIGNED NOT NULL AFTER PrimaryLang,
ADD Priority INT NOT NULL AFTER AdminInterfaceLang;
UPDATE Language SET AdminInterfaceLang = 1 WHERE PrimaryLang = 1;
DELETE FROM PersistantSessionData WHERE VariableName = 'lang_columns_.';
ALTER TABLE SessionData CHANGE VariableValue VariableValue longtext NOT NULL;
REPLACE INTO ConfigurationAdmin VALUES ('CSVExportDelimiter', 'la_Text_CSV_Export', 'la_config_CSVExportDelimiter', 'select', NULL, '0=la_Tab,1=la_Comma,2=la_Semicolon,3=la_Space,4=la_Colon', 40.1, 0, 1);
REPLACE INTO ConfigurationAdmin VALUES ('CSVExportEnclosure', 'la_Text_CSV_Export', 'la_config_CSVExportEnclosure', 'radio', NULL, '0=la_Doublequotes,1=la_Quotes', 40.2, 0, 1);
REPLACE INTO ConfigurationAdmin VALUES ('CSVExportSeparator', 'la_Text_CSV_Export', 'la_config_CSVExportSeparator', 'radio', NULL, '0=la_Linux,1=la_Windows', 40.3, 0, 1);
REPLACE INTO ConfigurationAdmin VALUES ('CSVExportEncoding', 'la_Text_CSV_Export', 'la_config_CSVExportEncoding', 'radio', NULL, '0=la_Unicode,1=la_Regular', 40.4, 0, 1);
REPLACE INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportDelimiter', '0', 'In-Portal', 'in-portal:configure_general');
REPLACE INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportEnclosure', '0', 'In-Portal', 'in-portal:configure_general');
REPLACE INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportSeparator', '0', 'In-Portal', 'in-portal:configure_general');
REPLACE INTO ConfigurationValues VALUES (DEFAULT, 'CSVExportEncoding', '0', 'In-Portal', 'in-portal:configure_general');
# ===== v 4.2.2 =====
INSERT INTO ConfigurationAdmin VALUES ('UseColumnFreezer', 'la_Text_Website', 'la_config_UseColumnFreezer', 'checkbox', '', '', 10.22, 0, 0);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'UseColumnFreezer', '0', 'In-Portal', 'in-portal:configure_general');
INSERT INTO ConfigurationAdmin VALUES ('TrimRequiredFields', 'la_Text_Website', 'la_config_TrimRequiredFields', 'checkbox', '', '', 10.23, 0, 0);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'TrimRequiredFields', '0', 'In-Portal', 'in-portal:configure_general');
INSERT INTO ConfigurationAdmin VALUES ('MenuFrameWidth', 'la_title_General', 'la_prompt_MenuFrameWidth', 'text', NULL, NULL, '11', '0', '0');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'MenuFrameWidth', 200, 'Proj-Base', 'in-portal:configure_general');
INSERT INTO ConfigurationAdmin VALUES ('DefaultSettingsUserId', 'la_title_General', 'la_prompt_DefaultUserId', 'text', NULL, NULL, '12', '0', '0');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'DefaultSettingsUserId', -1, 'Proj-Base', 'in-portal:configure_general');
INSERT INTO ConfigurationAdmin VALUES ('KeepSessionOnBrowserClose', 'la_title_General', 'la_prompt_KeepSessionOnBrowserClose', 'checkbox', NULL, NULL, '13', '0', '0');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'KeepSessionOnBrowserClose', 0, 'Proj-Base', 'in-portal:configure_general');
ALTER TABLE PersistantSessionData ADD VariableId BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST;
# ===== v 4.2.3 =====
INSERT INTO ConfigurationAdmin VALUES ('u_MaxImageCount', 'la_section_ImageSettings', 'la_config_MaxImageCount', 'text', '', '', 30.01, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_ThumbnailImageWidth', 'la_section_ImageSettings', 'la_config_ThumbnailImageWidth', 'text', '', '', 30.02, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_ThumbnailImageHeight', 'la_section_ImageSettings', 'la_config_ThumbnailImageHeight', 'text', '', '', 30.03, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_FullImageWidth', 'la_section_ImageSettings', 'la_config_FullImageWidth', 'text', '', '', 30.04, 0, 0);
INSERT INTO ConfigurationAdmin VALUES ('u_FullImageHeight', 'la_section_ImageSettings', 'la_config_FullImageHeight', 'text', '', '', 30.05, 0, 0);
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_MaxImageCount', 5, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_ThumbnailImageWidth', 120, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_ThumbnailImageHeight', 120, 'In-Portal:Users', 'in-portal:configure_users');
INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_FullImageWidth', 450, 'In-Portal:Users', 'in-portal:configure_users');
-INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_FullImageHeight', 450, 'In-Portal:Users', 'in-portal:configure_users');
\ No newline at end of file
+INSERT INTO ConfigurationValues VALUES (DEFAULT, 'u_FullImageHeight', 450, 'In-Portal:Users', 'in-portal:configure_users');
+
+# ===== v 4.3.0 =====
+CREATE TABLE ChangeLogs (
+ ChangeLogId bigint(20) NOT NULL auto_increment,
+ PortalUserId int(11) NOT NULL default '0',
+ SessionLogId int(11) NOT NULL default '0',
+ `Action` tinyint(4) NOT NULL default '0',
+ OccuredOn int(11) NOT NULL default '0',
+ Prefix varchar(255) NOT NULL default '',
+ ItemId bigint(20) NOT NULL default '0',
+ Changes text NOT NULL,
+ MasterPrefix varchar(255) NOT NULL default '',
+ MasterId bigint(20) NOT NULL default '0',
+ PRIMARY KEY (ChangeLogId),
+ KEY PortalUserId (PortalUserId),
+ KEY SessionLogId (SessionLogId),
+ KEY `Action` (`Action`),
+ KEY OccuredOn (OccuredOn),
+ KEY Prefix (Prefix),
+ KEY MasterPrefix (MasterPrefix)
+);
+
+CREATE TABLE SessionLogs (
+ SessionLogId bigint(20) NOT NULL auto_increment,
+ PortalUserId int(11) NOT NULL default '0',
+ SessionId int(10) NOT NULL default '0',
+ `Status` tinyint(4) NOT NULL default '1',
+ SessionStart int(11) NOT NULL default '0',
+ SessionEnd int(11) default NULL,
+ IP varchar(15) NOT NULL default '',
+ AffectedItems int(11) NOT NULL default '0',
+ PRIMARY KEY (SessionLogId),
+ KEY SessionId (SessionId),
+ KEY `Status` (`Status`)
+);
\ No newline at end of file
Property changes on: branches/RC/core/install/upgrades.sql
___________________________________________________________________
Modified: cvs2svn:cvs-rev
## -1 +1 ##
-1.19.2.20
\ No newline at end of property
+1.19.2.21
\ No newline at end of property

Event Timeline