diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..edcdc72315a8d2b3bddf830cccdb3cc8866ce8a8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,36 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..105ce2da2d6447d11dfe32bfb846c3d5b199fc99 --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000000000000000000000000000000000000..060d2c5e8c365bdf4dafbb4e5ef23b4ac65aafd6 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000000000000000000000000000000000000..2047c36d5e0ed19df0d176d7e1c3545b30811f21 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/php.iml b/.idea/php.iml new file mode 100644 index 0000000000000000000000000000000000000000..cd9192b660f70181d92134dc83d8e93d44ec5558 --- /dev/null +++ b/.idea/php.iml @@ -0,0 +1,15 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000000000000000000000000000000000000..35eb1ddfbbc029bcab630581847471d7f238ec53 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000000000000000000000000000000000000..76a45f595edd66505b9875bc1046350336fc7d8b --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + 1718754548763 + + + + \ No newline at end of file diff --git a/php/.gitattributes b/php/.gitattributes new file mode 100644 index 0000000000000000000000000000000000000000..a6344aac8c09253b3b630fb776ae94478aa0275b --- /dev/null +++ b/php/.gitattributes @@ -0,0 +1,35 @@ +*.7z filter=lfs diff=lfs merge=lfs -text +*.arrow filter=lfs diff=lfs merge=lfs -text +*.bin filter=lfs diff=lfs merge=lfs -text +*.bz2 filter=lfs diff=lfs merge=lfs -text +*.ckpt filter=lfs diff=lfs merge=lfs -text +*.ftz filter=lfs diff=lfs merge=lfs -text +*.gz filter=lfs diff=lfs merge=lfs -text +*.h5 filter=lfs diff=lfs merge=lfs -text +*.joblib filter=lfs diff=lfs merge=lfs -text +*.lfs.* filter=lfs diff=lfs merge=lfs -text +*.mlmodel filter=lfs diff=lfs merge=lfs -text +*.model filter=lfs diff=lfs merge=lfs -text +*.msgpack filter=lfs diff=lfs merge=lfs -text +*.npy filter=lfs diff=lfs merge=lfs -text +*.npz filter=lfs diff=lfs merge=lfs -text +*.onnx filter=lfs diff=lfs merge=lfs -text +*.ot filter=lfs diff=lfs merge=lfs -text +*.parquet filter=lfs diff=lfs merge=lfs -text +*.pb filter=lfs diff=lfs merge=lfs -text +*.pickle filter=lfs diff=lfs merge=lfs -text +*.pkl filter=lfs diff=lfs merge=lfs -text +*.pt filter=lfs diff=lfs merge=lfs -text +*.pth filter=lfs diff=lfs merge=lfs -text +*.rar filter=lfs diff=lfs merge=lfs -text +*.safetensors filter=lfs diff=lfs merge=lfs -text +saved_model/**/* filter=lfs diff=lfs merge=lfs -text +*.tar.* filter=lfs diff=lfs merge=lfs -text +*.tar filter=lfs diff=lfs merge=lfs -text +*.tflite filter=lfs diff=lfs merge=lfs -text +*.tgz filter=lfs diff=lfs merge=lfs -text +*.wasm filter=lfs diff=lfs merge=lfs -text +*.xz filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.zst filter=lfs diff=lfs merge=lfs -text +*tfevents* filter=lfs diff=lfs merge=lfs -text diff --git a/php/ConnectionManager.php b/php/ConnectionManager.php new file mode 100644 index 0000000000000000000000000000000000000000..33aef4faee8ba9dc377161f0894277a352c8f6a7 --- /dev/null +++ b/php/ConnectionManager.php @@ -0,0 +1,206 @@ +_connectionsData[ $connId ]; + switch( $data["connStringType"] ) + { + case "mysql": + if( useMySQLiLib() ) + { + include_once getabspath("connections/MySQLiConnection.php"); + return new MySQLiConnection( $data ); + } + + include_once getabspath("connections/MySQLConnection.php"); + return new MySQLConnection( $data ); + + case "mssql": + case "compact": + if( useMSSQLWinConnect() ) + { + include_once getabspath("connections/MSSQLWinConnection.php"); + return new MSSQLWinConnection( $data ); + } + if( isSqlsrvExtLoaded() ) + { + include_once getabspath("connections/MSSQLSrvConnection.php"); + return new MSSQLSrvConnection( $data ); + } + + if( function_exists("mssql_connect") ) { + include_once getabspath("connections/MSSQLUnixConnection.php"); + return new MSSQLUnixConnection( $data ); + } + + if( class_exists("PDO") ) { + include_once getabspath("connections/PDOConnection.php"); + $drivers = pdo_drivers(); + if( in_array( "sqlsrv", $drivers) ) + { + $data["PDOString"] = "sqlsrv:Server=" . $data["connInfo"][0] . ";Database=" . $data["connInfo"][3]; + $data["PDOUser"] = $data["connInfo"][1]; + $data["PDOPass"] = $data["connInfo"][2]; + return new PDOConnection( $data ); + } + if( in_array( "dblib", $drivers) ) + { + $data["PDOString"] = "dblib:host=" . $data["connInfo"][0] . ";dbname=" . $data["connInfo"][3]; + $data["PDOUser"] = $data["connInfo"][1]; + $data["PDOPass"] = $data["connInfo"][2]; + return new PDOConnection( $data ); + } + } + echo "No SQL Server driver found in your PHP settings."; + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + echo "
To enable SQL Server support add the following line to php.ini file:"; + echo "
extension=php_com_dotnet.dll"; + } + exit(); + + case "msaccess": + case "odbc": + case "odbcdsn": + case "custom": + case "file": + if( stripos($data["ODBCString"], 'Provider=') !== false ) + { + include_once getabspath("connections/ADOConnection.php"); + return new ADOConnection( $data ); + } + + include_once getabspath("connections/ODBCConnection.php"); + return new ODBCConnection( $data ); + + case "oracle": + include_once getabspath("connections/OracleConnection.php"); + return new OracleConnection( $data ); + + case "postgre": + include_once getabspath("connections/PostgreConnection.php"); + return new PostgreConnection( $data ); + + case "db2": + include_once getabspath("connections/DB2Connection.php"); + return new DB2Connection( $data ); + + case "informix": + include_once getabspath("connections/InformixConnection.php"); + return new InformixConnection( $data ); + + case "sqlite": + include_once getabspath("connections/SQLite3Connection.php"); + return new SQLite3Connection( $data ); + case "pdo": + include_once getabspath("connections/PDOConnection.php"); + return new PDOConnection( $data ); + } + } + + /** + * Set the data representing the project's + * db connection properties + */ + protected function _setConnectionsData() + { + // content of this function can be modified on demo account + // variable names $data and $connectionsData are important + + $connectionsData = array(); + + $data = array(); + $data["dbType"] = 4; + $data["connId"] = "KnowledgeBase2_at_localhost"; + $data["connName"] = "KnowledgeBase2 at localhost"; + $data["connStringType"] = "postgre"; + $postgre_url = getenv("postgre_url"); + $data["connectionString"] = $postgre_url; //currently unused + + $this->_connectionsIdByName["KnowledgeBase2 at localhost"] = "KnowledgeBase2_at_localhost"; + + $data["connInfo"] = array(); + $data["ODBCUID"] = ""; + $data["ODBCPWD"] = ""; + $data["leftWrap"] = "\""; + $data["rightWrap"] = "\""; + + $data["DBPath"] = "db"; //currently unused + $data["useServerMapPath"] = 1; //currently unused + +$host="ep-odd-mode-93794521.us-east-2.aws.neon.tech"; +$user="miyataken999"; +$password="yz1wPf4KrWTm"; +$options="options=endpoint=ep-odd-mode-93794521 port=5432"; +$dbname="neondb"; +$data["connInfo"][0] = $host; +$data["connInfo"][1] = $user; +$data["connInfo"][2] = $password; +$data["connInfo"][3] = $options; +$data["connInfo"][4] = $dbname; +; + // encription set + $data["EncryptInfo"] = array(); + $data["EncryptInfo"]["mode"] = 0; + $data["EncryptInfo"]["alg"] = 128; + $data["EncryptInfo"]["key"] = ""; + + $connectionsData["KnowledgeBase2_at_localhost"] = $data; + $data = array(); + $data["dbType"] = 4; + $data["connId"] = "neondbatuseast2awsneontech"; + $data["connName"] = "neondb at us-east-2.aws.neon.t"; + $data["connStringType"] = "postgre"; + $data["connectionString"] = $postgre_url; //currently unused + + $this->_connectionsIdByName["neondb at us-east-2.aws.neon.t"] = "neondbatuseast2awsneontech"; + + $data["connInfo"] = array(); + $data["ODBCUID"] = ""; + $data["ODBCPWD"] = ""; + $data["leftWrap"] = "\""; + $data["rightWrap"] = "\""; + + $data["DBPath"] = "db"; //currently unused + $data["useServerMapPath"] = 1; //currently unused + +$host="ep-odd-mode-93794521.us-east-2.aws.neon.tech"; +$user="miyataken999"; +$password="yz1wPf4KrWTm"; +$options="options=endpoint=ep-odd-mode-93794521 port=5432"; +$dbname="neondb"; +$data["connInfo"][0] = $host; +$data["connInfo"][1] = $user; +$data["connInfo"][2] = $password; +$data["connInfo"][3] = $options; +$data["connInfo"][4] = $dbname; +; + // encription set + $data["EncryptInfo"] = array(); + $data["EncryptInfo"]["mode"] = 0; + $data["EncryptInfo"]["alg"] = 256; + $data["EncryptInfo"]["key"] = ""; + + $connectionsData["neondbatuseast2awsneontech"] = $data; + $this->_connectionsData = &$connectionsData; + } + + /** + * Close db connections + * @destructor + */ + function __desctruct() + { + $this->CloseConnections(); + } +} +?> diff --git a/php/Dockerfile b/php/Dockerfile new file mode 100644 index 0000000000000000000000000000000000000000..4195c9f5db1ca6793a651d7fc0382e1509b77334 --- /dev/null +++ b/php/Dockerfile @@ -0,0 +1,17 @@ +# Use the official phpMyAdmin image +# Use the official phpMyAdmin image +FROM phpmyadmin/phpmyadmin:latest +RUN chmod -R 777 /var/ +RUN chmod -R 777 /etc/phpmyadmin/ +RUN chmod -R 777 /etc/apache2/ +# Set correct permissions for phpMyAdmin configuration file +RUN chmod 644 /etc/phpmyadmin/config.inc.php +COPY test.php /var/www/html/test.php +# Set environment variables +ENV PMA_HOST=mysql-7364790-localbugtv.l.aivencloud.com +ENV PMA_PORT=10490 +ENV MYSQL_ROOT_PASSWORD=root +ENV APACHE_PORT=7860 +# Add test.php to the phpMyAdmin root directory + + diff --git a/php/README.md b/php/README.md new file mode 100644 index 0000000000000000000000000000000000000000..1a2196b16ed5319227bb3c927e9da45f63162c18 --- /dev/null +++ b/php/README.md @@ -0,0 +1,10 @@ +--- +title: php +emoji: 🚀 +colorFrom: blue +colorTo: blue +sdk: docker +pinned: false +--- + +Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference diff --git a/php/admin_comments_edit.php b/php/admin_comments_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..9e90ddb64a6c46ca910a19184645f525e3c3a7a5 --- /dev/null +++ b/php/admin_comments_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_comments_list.php b/php/admin_comments_list.php new file mode 100644 index 0000000000000000000000000000000000000000..1ef2b35749801533b91f4d0103d2082e05e6c121 --- /dev/null +++ b/php/admin_comments_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/admin_comments_search.php b/php/admin_comments_search.php new file mode 100644 index 0000000000000000000000000000000000000000..64c05f34cc7750d192966e3ad0a2ae308fae6d61 --- /dev/null +++ b/php/admin_comments_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_members_list.php b/php/admin_members_list.php new file mode 100644 index 0000000000000000000000000000000000000000..bc5093df9433e736dac0282095f84363abeeafaa --- /dev/null +++ b/php/admin_members_list.php @@ -0,0 +1,56 @@ +saveMembers( $modifiedMembers ); + return; +} + + // add button events if exist + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); +?> \ No newline at end of file diff --git a/php/admin_members_search.php b/php/admin_members_search.php new file mode 100644 index 0000000000000000000000000000000000000000..bb76d95f47ce97d2befabebc6f0ece3c4e8d0e36 --- /dev/null +++ b/php/admin_members_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_rights_list.php b/php/admin_rights_list.php new file mode 100644 index 0000000000000000000000000000000000000000..15e34bb04342478661578bf67b444160cc31ac62 --- /dev/null +++ b/php/admin_rights_list.php @@ -0,0 +1,609 @@ +saveRights( $modifiedRights ); + return; +} + + +// add buttons if exist + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + + + +?> diff --git a/php/admin_rights_search.php b/php/admin_rights_search.php new file mode 100644 index 0000000000000000000000000000000000000000..b81d59610fe968502c3f674e5c351a963ab29064 --- /dev/null +++ b/php/admin_rights_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_users_add.php b/php/admin_users_add.php new file mode 100644 index 0000000000000000000000000000000000000000..8168dd81d68da87d2b428d673befe5026cdc2cb4 --- /dev/null +++ b/php/admin_users_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_users_edit.php b/php/admin_users_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..073e3e0a0258de6b360bb604d3333aa5237da0c7 --- /dev/null +++ b/php/admin_users_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_users_export.php b/php/admin_users_export.php new file mode 100644 index 0000000000000000000000000000000000000000..8e1d733705d95bde4cdb19c28a5a26247d61497f --- /dev/null +++ b/php/admin_users_export.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_users_import.php b/php/admin_users_import.php new file mode 100644 index 0000000000000000000000000000000000000000..168e6a45e487ef516296063a0df9e840c48c6115 --- /dev/null +++ b/php/admin_users_import.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/admin_users_list.php b/php/admin_users_list.php new file mode 100644 index 0000000000000000000000000000000000000000..00d6448093ae723a32fbff00bd2f59dc307e895f --- /dev/null +++ b/php/admin_users_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/admin_users_print.php b/php/admin_users_print.php new file mode 100644 index 0000000000000000000000000000000000000000..059b3e0313d2dd3af370ff959c93b718d54ec976 --- /dev/null +++ b/php/admin_users_print.php @@ -0,0 +1,46 @@ +init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_users_search.php b/php/admin_users_search.php new file mode 100644 index 0000000000000000000000000000000000000000..3f859304d6968cbdf1f4882f1dc7bd9cca3b3969 --- /dev/null +++ b/php/admin_users_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/admin_users_view.php b/php/admin_users_view.php new file mode 100644 index 0000000000000000000000000000000000000000..60b5840b004803dd04f74a5e35d7af1e73a33ae7 --- /dev/null +++ b/php/admin_users_view.php @@ -0,0 +1,67 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/api/api.php b/php/api/api.php new file mode 100644 index 0000000000000000000000000000000000000000..572bebb9d0c17a48454eb1c88d9bef2fd748a4d0 --- /dev/null +++ b/php/api/api.php @@ -0,0 +1,148 @@ + $text + ), $responseCode ); + } + + public static function sendResponse( $success, $data, $responseCode = 0 ) { + if( !$responseCode ) { + $responseCode = $success ? 200 : 500; + } + http_response_code( $responseCode ); + $data["success"] = $success; + echo my_json_encode( $data ); + exit(); + } + + // read one record from the result + public static function readRecord( $result, $pSet ) { + $data = $result->fetchAssoc(); + if( !$data ) { + return null; + } + foreach( array_keys( $data ) as $f ) { + if( IsBinaryType( $pSet->getFieldType( $f ) ) && GetGlobalData("restReturnEncodedBinary") ) { + $data[ $f ] = base64_encode( $data[ $f ] ); + } + } + return $data; + } + + // read result into array of records + public static function readResult( $result, $pSet, $recordLimit = 0 ) { + $ret = array(); + while( ( !$recordLimit || count( $ret ) < $recordLimit ) && ( $data = API::readRecord( $result, $pSet ) ) ) { + $ret[] = $data; + } + return $ret; + } + + public static function login() { + if( !Security::hasLogin() ) { + return true; + } + $authType = GetGlobalData("restAuth"); + if( $authType == REST_BASIC ) { + // Authorization: Basic + $username = ""; + $password = ""; + $username = $_SERVER["PHP_AUTH_USER"]; + $password = $_SERVER["PHP_AUTH_PW"]; + if( !$username ) { + $loginHeader = getHttpHeader('Authorization') . ""; + if( substr( $loginHeader, 0, 6 ) !== 'Basic ' ) { + header( 'WWW-Authenticate: Basic realm="REST API"'); + return false; + } + $token = base64_decode( substr( $loginHeader, 6) ); + $colonPos = strpos( $token, ':' ); + if( $colonPos === false ) { + return false; + } + $username = substr( $token, 0, $colonPos ); + $password = substr( $token, $colonPos + 1 ); + } + return Security::login( $username, $password, false, true ); + } + + if ( $authType == REST_APIKEY ) { + $APIkey = ""; + if( isset( $_SERVER["HTTP_X_AUTH_TOKEN"] ) ) + $APIkey = $_SERVER["HTTP_X_AUTH_TOKEN"]; + else + $APIkey = postvalue("apikey"); + + if( !strlen( $APIkey ) ) + return false; + + if( Security::hardcodedLogin() ) { + if( GetGlobalData("APIkey", "") == $APIkey ) { + Security::createHardcodedSession(); + return true; + } + return false; + } + + $dataSource = getLoginDataSource(); + + $dc = new DsCommand(); + $dc->filter = DataCondition::FieldEquals( GetGlobalData("APIkeyField"), $APIkey ); + $rs = $dataSource->getSingle( $dc ); + if( !$rs ) + return false; + + $loginSet = ProjectSettings::getForLogin(); + $cipherer = RunnerCipherer::getForLogin( $loginSet ); + $userData = $cipherer->DecryptFetchedArray( $rs->fetchAssoc() ); + + return Security::login( $userData[ Security::usernameField() ], $userData[ Security::passwordField() ], true, true ); + } + + return false; + } + + public static function keysFromRequest( $pSet ) { + $keys = array(); + foreach( $pSet->getTableKeys() as $i => $k ) { + $keys[ $k ] = postvalue( "editid" . ( $i + 1 ) ); + } + return $keys; + } + + public static function valuesFromRequest( $pSet ) { + $values = array(); + foreach( $pSet->getFieldsList() as $f ) { + if( postvalue( $f ) || GetUploadedFileName( $f ) ) { + $values[ $f ] = API::processRequestValue( $f, postvalue( $f ), $pSet ); + } + } + + return $values; + } + + protected static function processRequestValue( $fieldName, $value, $pSet ) { + if( IsBinaryType( $pSet->getFieldType( $fieldName ) ) ) { + if( $value && GetGlobalData("restAcceptEncodedBinary") ) { + $decodedValue = base64_decode_binary( $value ); + + // invalid base64 value passed + if( !$decodedValue ) { + API::sendError( "Unable to decode " . $fieldName . " value from base64" ); + } + + return $decodedValue; + } + + // data passed as file + if( GetUploadedFileName( $fieldName ) ) { + return GetUploadedFileContents( $fieldName ); + } + } + + return $value; + } +} +?> \ No newline at end of file diff --git a/php/api/v1.php b/php/api/v1.php new file mode 100644 index 0000000000000000000000000000000000000000..f814695941ee6456e19289777c39f91a5cc6f0ce --- /dev/null +++ b/php/api/v1.php @@ -0,0 +1,278 @@ +pageTypeAvailable("list") ) { + API::sendError( "operation not supported" ); + } + if( !Security::userCan( "S", $table ) ) { + API::sendError( "operation not allowed" ); + } + $dataSource = getDataSource( $table, $pSet ); + $srchObj = SearchClause::getSearchObject( $table ); + + $dc = new DsCommand(); + $dc->filter = DataCondition::_And( array( + Security::SelectCondition( "S", $pSet ), + $srchObj->getSearchDataCondition() + )); + + $order = postvalue("orderby"); + if( $order ) { + $orderFields = explode( ";", $order ); + $projectFields = $pSet->getFieldsList(); + $dc->order[] = array(); + + foreach( $orderFields as $f ) { + $dir = substr( $f, 0, 1 ) == "d" ? "desc": "asc"; + $field = trim( substr( $f, 1 ) ); + if( in_array( $field, $projectFields ) ) { + $dc->order[] = array("column" => $field, "dir" => $dir); + } + } + } + + if( postvalue( "skip" ) ) { + $dc->startRecord = (int)postvalue( "skip" ); + } + if( postvalue( "records" ) ) { + $dc->reccount = (int)postvalue( "records" ); + } else { + $dc->reccount = 200; + } + $rs = $dataSource->getList( $dc ); + if( !$rs ) { + API::sendError( $dataSource->lastError() ); + } + API::sendResponse( true, array("data" => API::readResult( $rs, $pSet, $dc->reccount ) ) ); +} + +if( $action === "view" ) { + if( !$pSet->pageTypeAvailable("view") ) { + API::sendError( "operation not supported" ); + } + if( !Security::userCan( "S", $table ) ) { + API::sendError( "operation not allowed" ); + } + $dataSource = getDataSource( $table, $pSet ); + $dc = new DsCommand(); + $dc->keys = API::keysFromRequest( $pSet ); + $dc->filter = Security::SelectCondition( "S", $pSet ); + $rs = $dataSource->getSingle( $dc ); + if( !$rs ) { + API::sendError( $dataSource->lastError() ); + } + API::sendResponse( true, array("data" => API::readRecord( $rs, $pSet ) ) ); +} + +if( $action === "update" ) { + if( !$pSet->pageTypeAvailable("edit") ) { + API::sendError( "operation not supported" ); + } + if( !Security::userCan( "E", $table ) ) { + API::sendError( "operation not allowed" ); + } + + $dataSource = getDataSource( $table, $pSet ); + + $oldKeys = API::keysFromRequest( $pSet ); + $newRecordData = API::valuesFromRequest( $pSet ); + + $oldRecordData = null; + if( $eventsObject->exists("BeforeEdit") || $eventsObject->exists("AfterEdit") ) { + $dc = new DsCommand(); + $dc->filter = Security::SelectCondition( "E", $pSet ); + $dc->keys = $oldKeys; + $fetchedArray = $dataSource->getSingle( $dc )->fetchAssoc(); + $oldRecordData = $cipherer->DecryptFetchedArray( $fetchedArray ); + } + + $sqlValues = array(); + if( $eventsObject->exists("BeforeEdit") ) { + $usermessage = ""; + $keyWhereClause = KeyWhere( $oldKeys, $table ); + $pageObj = null; + + $beforeEdit = $eventsObject->BeforeEdit( $newRecordData, + $sqlValues, + $keyWhereClause, + $oldRecordData, + $oldKeys, + $usermessage, + false, + $pageObj ); + + if( !$beforeEdit ) { + API::sendResponse( false, array( "success" => false, "error" => $usermessage ) ); + } + } + + $dc = new DsCommand(); + $dc->keys = $oldKeys; + $dc->filter = Security::SelectCondition( "E", $pSet ); + $dc->values = $newRecordData; + + $dc->advValues = array(); + foreach( $sqlValues as $field => $sqlValue ) { + $dc->advValues[ $field ] = new DsOperand( dsotSQL, $sqlValue ); + } + + $ret = $dataSource->updateSingle( $dc ); + + if( $ret && $eventsObject->exists("AfterEdit") ) { + $keys = $oldKeys; + foreach( $newRecordData as $f => $v ) { + if( isset( $keys[ $f ] ) ) { + $keys[ $f ] = $v; + } + } + + $keyWhereClause = KeyWhere( $keys, $table ); + $pageObj = null; + + $eventsObject->AfterEdit( $newRecordData, + $keyWhereClause, + $oldRecordData, + $keys, + false, + $pageObj ); + } + + if( $ret ) { + API::sendResponse( true, array( "success" => true ) ); + } else { + API::sendResponse( false, array( "success" => false, "error" => $dataSource->lastError() ) ); + } + API::sendResponse( $ret["success"], $ret ); +} + +if( $action === "insert" ) { + if( !$pSet->pageTypeAvailable("add") ) { + API::sendError( "operation not supported" ); + } + + if( !Security::userCan( "A", $table ) ) { + API::sendError( "operation not allowed" ); + } + + $newRecordData = API::valuesFromRequest( $pSet ); + + $sqlValues = array(); + if( $eventsObject->exists("BeforeAdd") ) { + $usermessage = ""; + $pageObj = null; + + if( !$eventsObject->BeforeAdd( $newRecordData, $sqlValues, $usermessage, false, $pageObj ) ) { + API::sendResponse( false, array( "success" => false, "error" => $usermessage ) ); + } + } + + $dataSource = getDataSource( $table, $pSet ); + $dc = new DsCommand(); + $dc->values = $newRecordData; + + $dc->advValues = array(); + foreach( $sqlValues as $field => $sqlValue ) { + $dc->advValues[ $field ] = new DsOperand( dsotSQL, $sqlValue ); + } + + $ret = $dataSource->insertSingle( $dc ); + + if( $ret && $eventsObject->exists("AfterAdd") ) { + $pageObj = null; + $newRecordData = $ret; + $keys = array(); + foreach( $pSet->getTableKeys() as $kf ) { + $keys[ $kf ] = $newRecordData[ $kf ]; + } + + $eventsObject->AfterAdd( $newRecordData, $keys, false, $pageObj ); + } + + if( $ret !== false ) { + API::sendResponse( true, array( "success" => true, "data" => $ret ) ); + } else { + API::sendResponse( false, array( "success" => false, "error" => $dataSource->lastError() ) ); + } +} + +if( $action === "delete" ) { + if( !$pSet->pageTypeAvailable("list") ) { + API::sendError( "operation not supported" ); + } + if( !Security::userCan( "D", $table ) ) { + API::sendError( "operation not allowed" ); + } + + $dataSource = getDataSource( $table, $pSet ); + $dc = new DsCommand(); + $dc->keys = API::keysFromRequest( $pSet ); + $dc->filter = Security::SelectCondition( "D", $pSet ); + + $whereClause = ""; + $deletedValues = array(); + if( $eventsObject->exists("BeforeDelete") || $eventsObject->exists("AfterDelete") ) { + $deletedResult = $dataSource->getSingle( $dc ); + if( $deletedResult ) + $deletedValues = $cipherer->DecryptFetchedArray( $deletedResult->fetchAssoc() ); + + $whereClause = KeyWhere( $dc->keys, $table ); + } + + if( $eventsObject->exists("BeforeDelete") ) { + $userMessage = ""; + $pageObj = null; + if( !$eventsObject->BeforeDelete( $whereClause, $deletedValues, $userMessage, $pageObj ) ) { + API::sendResponse( false, array( "success" => false, "error" => $userMessage ) ); + } + } + + $ret = $dataSource->deleteSingle( $dc ); + + if( $ret && $eventsObject->exists("AfterDelete") ) { + $userMessage = ""; + $pageObj = null; + $eventsObject->AfterDelete( $whereClause, $deletedValues, $userMessage, $pageObj ); + } + + if( $ret ) { + API::sendResponse( true, array( "success" => true ) ); + } else { + API::sendResponse( false, array( "success" => false, "error" => $dataSource->lastError() ) ); + } +} + +API::sendError( "unknown operation" ); + diff --git a/php/appointments_add.php b/php/appointments_add.php new file mode 100644 index 0000000000000000000000000000000000000000..68ef8ba412ff763ab7d2fd581f7c8e88659dfd40 --- /dev/null +++ b/php/appointments_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/appointments_edit.php b/php/appointments_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..39f80ae3e8437536f5734127dd159639a951f1d1 --- /dev/null +++ b/php/appointments_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/appointments_export.php b/php/appointments_export.php new file mode 100644 index 0000000000000000000000000000000000000000..7db0cf4faf0719aabe711d4a314f66b608d64edf --- /dev/null +++ b/php/appointments_export.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/appointments_import.php b/php/appointments_import.php new file mode 100644 index 0000000000000000000000000000000000000000..4a86b250b63905b6da3f98c9215fc229200b4fab --- /dev/null +++ b/php/appointments_import.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/appointments_list.php b/php/appointments_list.php new file mode 100644 index 0000000000000000000000000000000000000000..2f957203f1edfad83e428359dd1e60e80400d911 --- /dev/null +++ b/php/appointments_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/appointments_print.php b/php/appointments_print.php new file mode 100644 index 0000000000000000000000000000000000000000..2f8ba8e79b227d951d05628338e44b31977a560d --- /dev/null +++ b/php/appointments_print.php @@ -0,0 +1,46 @@ +init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/appointments_search.php b/php/appointments_search.php new file mode 100644 index 0000000000000000000000000000000000000000..dfe171692901901992cd205a78576cb4d0cb27c2 --- /dev/null +++ b/php/appointments_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/appointments_view.php b/php/appointments_view.php new file mode 100644 index 0000000000000000000000000000000000000000..a62a2ebeb8bd0e592449b830923dfaf92f5abe1d --- /dev/null +++ b/php/appointments_view.php @@ -0,0 +1,67 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/autocomplete.php b/php/autocomplete.php new file mode 100644 index 0000000000000000000000000000000000000000..2d3f8fb3f90c9b0f43cee2585fead2f5aa8ac3b4 --- /dev/null +++ b/php/autocomplete.php @@ -0,0 +1,60 @@ +getControl( $field ); + + +$contextParams = array(); +$contextParams["data"] = my_json_decode( postvalue('data') ); + +$masterTable = postvalue('masterTable'); +if ( $masterTable != "" && isset($_SESSION[ $masterTable . "_masterRecordData" ] ) || postvalue('masterData') ) +{ + $masterData = $_SESSION[ $masterTable . "_masterRecordData" ]; + if( !is_array($masterData) ) { + $masterData = array(); + } + $masterControlsData = my_json_decode( postvalue('masterData') ); + foreach( $masterControlsData as $mField => $mValue ) + { + $masterData[ $mField ] = $mValue; + } + + $contextParams["masterData"] = $masterData; +} + +RunnerContext::push( new RunnerContextItem( CONTEXT_ROW, $contextParams ) ); + + +$parentCtrlsData = my_json_decode( postvalue('parentCtrlsData') ); +$isExistParent = postvalue('isExistParent'); +$mode = intval( postvalue('mode') ); + +$respObj = array( 'success' => true, 'data' => $control->getLookupContentToReload( $isExistParent === '1', $mode, $parentCtrlsData ) ); +echo printJSON( $respObj ); + +RunnerContext::pop(); +exit(); +?> \ No newline at end of file diff --git a/php/autofillfields.php b/php/autofillfields.php new file mode 100644 index 0000000000000000000000000000000000000000..ee453624e2dbae18c5dc7b100543903f0c4095d8 --- /dev/null +++ b/php/autofillfields.php @@ -0,0 +1,42 @@ +getControl( $mainField ); + + +$contextParams = array(); +$contextParams["data"] = my_json_decode( postvalue('data') ); + +$masterTable = postvalue('masterTable'); +if ( $masterTable != "" && isset($_SESSION[ $masterTable . "_masterRecordData" ]) ) + $contextParams["masterData"] = $_SESSION[ $masterTable . "_masterRecordData" ]; + +RunnerContext::push( new RunnerContextItem( CONTEXT_ROW, $contextParams ) ); + +echo printJSON( array( 'success'=> true, 'data' => $control->getAutoFillData( $linkFieldVal ) ) ); + +RunnerContext::pop(); +exit(); +?> \ No newline at end of file diff --git a/php/buildpdf.php b/php/buildpdf.php new file mode 100644 index 0000000000000000000000000000000000000000..c1ba4e077e0d564ba539e49cde6d4aed76817c38 --- /dev/null +++ b/php/buildpdf.php @@ -0,0 +1,17 @@ + + + + +PDF Building + + +
+ + + + \ No newline at end of file diff --git a/php/buttonhandler.php b/php/buttonhandler.php new file mode 100644 index 0000000000000000000000000000000000000000..f8f5e073942ea3fd1f357b0779e34971d99b01aa --- /dev/null +++ b/php/buttonhandler.php @@ -0,0 +1,982 @@ +customButtons(); + if( array_search( $buttId , $pageButtons ) === false ) { + exit; + } +} + +$params["masterTable"] = postValue("masterTable");; +$params["masterKeys"] = array(); +// RunnerPage::readMasterKeysFromRequest +$i = 1; +while( isset( $_REQUEST["masterkey".$i] ) ) { + $params["masterKeys"][ $i ] = $_REQUEST["masterkey".$i]; + $i++; +} + + +if($buttId=='Add_Comment') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_Add_Comment($params); +} +if($buttId=='Create_chart') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_Create_chart($params); +} +if($buttId=='Send') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_Send($params); +} +if($buttId=='New_Button') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_New_Button($params); +} +if($buttId=='select_user_button') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_select_user_button($params); +} +if($buttId=='New_Button1') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_New_Button1($params); +} +if($buttId=='Audio') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_Audio($params); +} +if($buttId=='stopAudio') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_stopAudio($params); +} +if($buttId=='video_chat') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_video_chat($params); +} +if($buttId=='clip') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_clip($params); +} +if($buttId=='audiotest') +{ + // for login page users table can be turned off + if( $table != GLOBAL_PAGES ) + { + require_once("include/". GetTableURL( $table ) ."_variables.php"); + $cipherer = new RunnerCipherer( $table ); + } + buttonHandler_audiotest($params); +} + +if( $eventId == 'select_provider' && "chat_settings" == $table ) +{ + require_once("include/chat_settings_variables.php"); + $cipherer = new RunnerCipherer("chat_settings"); + fieldEventHandler_select_provider( $params ); +} +if( $eventId == 'check_video' && "chat_settings" == $table ) +{ + require_once("include/chat_settings_variables.php"); + $cipherer = new RunnerCipherer("chat_settings"); + fieldEventHandler_check_video( $params ); +} +if( $eventId == 'tmp_file_event' && "chat_history" == $table ) +{ + require_once("include/chat_history_variables.php"); + $cipherer = new RunnerCipherer("chat_history"); + fieldEventHandler_tmp_file_event( $params ); +} + + + + +// create table and non table handlers +function buttonHandler_Add_Comment($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + // Put your code here. +$result["txt"] = $params["txt"]." world!"; +; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_Create_chart($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + /*global $loginKeyFields; +$userdata = Security::currentUserData(); +$rs = DB::Query("select count(id) as cnt from chat_history where ownerid='".$userdata[$loginKeyFields[0]]."' and targetid='".$params["id"]."' and isread=0"); +$data = $rs->fetchAssoc(); +if($data["cnt"]==0){ + DB::Exec("insert into chat_history (messages, created, isread, targetid, ownerid) values ('','".date("Y-m-d- h:i:s")."',0,".$params["id"].",'".$userdata[$loginKeyFields[0]]."')"); +} +$result["id"] = $params["id"];*/; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_Send($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + /*include_once("chat_functions.php"); +global $loginKeyFields; +$mess = $params["msg"]; +if(strlen($mess)>4000) + $mess = substr($mess,0,4000); +$userdata = Security::currentUserData(); +$t = explode(" ",this_microtime()); +$sql = DB::PrepareSQL("insert into chat_history (messages, created, isread, targetid, ownerid, status) values (':1',':2','0','".$_SESSION["targetid"]."','".$userdata[$loginKeyFields[0]]."','')", $mess, date("Y-m-d H:i:s",$t[1]).substr((string)$t[0],1,4)); +//echo $sql; +DB::Exec($sql); +$_SESSION["message_id"] = DB::LastId(); + +**/; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_New_Button($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + ; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_select_user_button($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + ; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_New_Button1($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + // Put your code here. +$result["txt"] = $params["txt"]." world!"; +; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_Audio($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + // Put your code here. +$result["txt"] = $params["txt"]." world!"; +; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_stopAudio($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + // Put your code here. +$result["txt"] = $params["txt"]." world!"; +; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_video_chat($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + include_once("chat_functions.php"); +global $loginKeyFields, $cDisplayNameField, $cUserNameField; +$result["message"] = ""; +$rs = DB::Select("chat_history", array("isVideo"=>1,"ownerid"=>$userdata[$loginKeyFields[0]])); +if(!($data = $rs->fetchAssoc())){ + if(!$cDisplayNameField) + $cDisplayNameField = $cUserNameField; + $userdata = Security::currentUserData(); + $username = $userdata[$cDisplayNameField]; + if(!$username) + $username = $userdata[$cUserNameField]; + $t = explode(" ",this_microtime()); +//--- create meeting + $values["name"] = "Video chat"; + $values["schedule"] = date("Y-m-d H:i:s"); + $values["password"] = ""; + + /*$rs = DB::Select("chat_settings"); + $data = $rs->fetchAssoc(); + $rs2 = DB::Select("chat_timezone", array("id"=>$data["timezone"])); + $data2 = $rs2->fetchAssoc(); + $rctimezone = $data2["rc"]; + $zoomtimezone = $data2["zoom"];*/ + + $rs = DB::Select("chat_settings"); + $data = $rs->fetchAssoc(); + + $OAuoh = base64_encode($data["Z_APIKey"].":".$data["Z_APISecret"]); + $url = "https://zoom.us/oauth/token"; + $headers = array("Authorization"=>" Basic ".$OAuoh, "Host"=>"zoom.us","Content-Type"=>"application/x-www-form-urlencoded"); + $postFields = "grant_type=account_credentials&account_id=".$data["Z_Token"]."&redirect_uri=https://zoom.us"; + $response = runner_http_request( $url, $postFields, "POST", $headers, true ); + $arrresponse = my_json_decode($response["content"]); + if($arrresponse["message"]){ + $result["message"] = $arrresponse["message"]; + } + else{ + $token = $arrresponse["access_token"]; + + $createAMeetingArray['topic'] = $values["name"]; + $createAMeetingArray['agenda'] = ""; + $dt = ""; + if($values["schedule"]){ + $datetime = date("Y-m-d\TH:i:s", strtotime($values["schedule"])); + $createAMeetingArray['type'] = 2; + $createAMeetingArray['start_time'] = $datetime; + $dt = date("m/d/Y H:i:s", strtotime($values["schedule"])); + } + else + $createAMeetingArray['type'] = 1; + + //$createAMeetingArray['timezone'] = $zoomtimezone; + if($values["password"]) + $createAMeetingArray['password'] = $values["password"]; + else + $createAMeetingArray['password'] = ""; + $createAMeetingArray['duration'] = 60; + $createAMeetingArray['settings'] = array( + 'join_before_host' => false, + 'host_video' => true, + 'participant_video' => true, + 'mute_upon_entry' => false, + 'enforce_login' => false, + 'alternative_hosts' => "" + ); + if($data["saveInCloud"]) + $createAMeetingArray['settings']['auto_recording'] = true; + + $postFields = my_json_encode($createAMeetingArray); + $url = "https://api.zoom.us/v2/users/me/meetings"; + $headers = array("authorization"=>" Bearer ".$token, "content-type"=>"application/json"); + $response = runner_http_request( $url, $postFields, "POST", $headers, true ); + $arrresponse = my_json_decode($response["content"]); + $result["createlink"] = ""; + if($arrresponse["message"]){ + $result["message"] = $arrresponse["message"]; + } + else{ + $values["createlink"] = $arrresponse["start_url"]; + $values["joinlink"] = $arrresponse["join_url"]; + + + $result["createlink"] = $values["createlink"]; + DB::Insert("chat_history", array("messages"=>$values["joinlink"],"created"=>date("Y-m-d H:i:s",$t[1]).substr((string)$t[0],1,4),"isread"=>0,"targetid"=>$_SESSION["targetid"], "isVideo"=>1, "ownerid"=>$userdata[$loginKeyFields[0]])); + //DB::Insert("chat_history", array("messages"=>"".$username." create video chat","created"=>date("Y-m-d H:i:s",$t[1]).substr((string)$t[0],1,4),"isread"=>0,"targetid"=>$_SESSION["targetid"], "isVideo"=>0, "ownerid"=>$userdata[$loginKeyFields[0]])); + } + } +} + +; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_clip($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + ; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} +function buttonHandler_audiotest($params) +{ + global $strTableName; + $result = array(); + + // create new button object for get record data + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = postvalue('isManyKeys'); + $params["location"] = postvalue('location'); + + $button = new Button($params); + $ajax = $button; // for examle from HELP + $keys = $button->getKeys(); + + $masterData = false; + if ( isset($params['masterData']) && count($params['masterData']) > 0 ) + { + $masterData = $params['masterData']; + } + else if ( isset($params["masterTable"]) ) + { + $masterData = $button->getMasterData($params["masterTable"]); + } + + $contextParams = array(); + if ( $params["location"] == PAGE_VIEW ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == PAGE_EDIT ) + { + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else if ( $params["location"] == "grid" ) + { + $params["location"] = "list"; + $contextParams["data"] = $button->getRecordData(); + $contextParams["newData"] = $params['fieldsData']; + $contextParams["masterData"] = $masterData; + } + else + { + $contextParams["masterData"] = $masterData; + } + + RunnerContext::push( new RunnerContextItem( $params["location"], $contextParams)); + // Put your code here. +$result["txt"] = $params["txt"]." world!"; +; + RunnerContext::pop(); + echo my_json_encode($result); + $button->deleteTempFiles(); +} + + + +function fieldEventHandler_select_provider( $params ) +{ + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = false; + $params["location"] = postvalue('pageType'); + + $button = new Button($params); + $keys = $button->getKeys(); + $ajax = $button; // for examle from HELP + $result = array(); + + $pageType = postvalue("pageType"); + $fieldsData = my_json_decode( postvalue("fieldsData") ); + + $contextParams = array( + "data" => $fieldsData, + "masterData" => $_SESSION[ $masterTable . "_masterRecordData" ] + ); + + RunnerContext::push( new RunnerContextItem( CONTEXT_ROW, $contextParams ) ); + ; + RunnerContext::pop(); + + echo my_json_encode( $result ); + $button->deleteTempFiles(); +} +function fieldEventHandler_check_video( $params ) +{ + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = false; + $params["location"] = postvalue('pageType'); + + $button = new Button($params); + $keys = $button->getKeys(); + $ajax = $button; // for examle from HELP + $result = array(); + + $pageType = postvalue("pageType"); + $fieldsData = my_json_decode( postvalue("fieldsData") ); + + $contextParams = array( + "data" => $fieldsData, + "masterData" => $_SESSION[ $masterTable . "_masterRecordData" ] + ); + + RunnerContext::push( new RunnerContextItem( CONTEXT_ROW, $contextParams ) ); + +// Sample: +$result["upper"] = strtoupper( $params["value"] ); +; + RunnerContext::pop(); + + echo my_json_encode( $result ); + $button->deleteTempFiles(); +} +function fieldEventHandler_tmp_file_event( $params ) +{ + $params["keys"] = (array)my_json_decode(postvalue('keys')); + $params["isManyKeys"] = false; + $params["location"] = postvalue('pageType'); + + $button = new Button($params); + $keys = $button->getKeys(); + $ajax = $button; // for examle from HELP + $result = array(); + + $pageType = postvalue("pageType"); + $fieldsData = my_json_decode( postvalue("fieldsData") ); + + $contextParams = array( + "data" => $fieldsData, + "masterData" => $_SESSION[ $masterTable . "_masterRecordData" ] + ); + + RunnerContext::push( new RunnerContextItem( CONTEXT_ROW, $contextParams ) ); + +// Sample: +$result["upper"] = strtoupper( $params["value"] ); +; + RunnerContext::pop(); + + echo my_json_encode( $result ); + $button->deleteTempFiles(); +} +?> \ No newline at end of file diff --git a/php/callVideo.mp3 b/php/callVideo.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..c8b4ee041721820f805c4d9e6d2f888bb8d08d9f Binary files /dev/null and b/php/callVideo.mp3 differ diff --git a/php/chat_files1_add.php b/php/chat_files1_add.php new file mode 100644 index 0000000000000000000000000000000000000000..381f68edf6bc760c7b131aabf5b79e089d11e523 --- /dev/null +++ b/php/chat_files1_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_files1_edit.php b/php/chat_files1_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..4c3fd85006fc77f17d442d6cb791e4668526c945 --- /dev/null +++ b/php/chat_files1_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_files1_export.php b/php/chat_files1_export.php new file mode 100644 index 0000000000000000000000000000000000000000..d19fc97a8d84631e62c37e6af61f85379d9c329f --- /dev/null +++ b/php/chat_files1_export.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_files1_import.php b/php/chat_files1_import.php new file mode 100644 index 0000000000000000000000000000000000000000..c67124ac2f0ba637885cb17e95c4e87876bda7c8 --- /dev/null +++ b/php/chat_files1_import.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_files1_list.php b/php/chat_files1_list.php new file mode 100644 index 0000000000000000000000000000000000000000..f5308463484802f61e1cdc149bdce1705931aff0 --- /dev/null +++ b/php/chat_files1_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/chat_files1_print.php b/php/chat_files1_print.php new file mode 100644 index 0000000000000000000000000000000000000000..0127a9d3b36fbbdf9be2ce8ed25a7649be4ee400 --- /dev/null +++ b/php/chat_files1_print.php @@ -0,0 +1,46 @@ +init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_files1_search.php b/php/chat_files1_search.php new file mode 100644 index 0000000000000000000000000000000000000000..ab99944ab9db8d68606f7d6a0a5288305f7fb52a --- /dev/null +++ b/php/chat_files1_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_files1_view.php b/php/chat_files1_view.php new file mode 100644 index 0000000000000000000000000000000000000000..73639d30f40bf9b66f5845c380d8973105584a4b --- /dev/null +++ b/php/chat_files1_view.php @@ -0,0 +1,67 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_files_list.php b/php/chat_files_list.php new file mode 100644 index 0000000000000000000000000000000000000000..27f130da800e6cb5a177b07c3465bece2a0f5261 --- /dev/null +++ b/php/chat_files_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/chat_files_search.php b/php/chat_files_search.php new file mode 100644 index 0000000000000000000000000000000000000000..8286ed62cf00df8e049ba3feee3ddf401e1540ad --- /dev/null +++ b/php/chat_files_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_functions.php b/php/chat_functions.php new file mode 100644 index 0000000000000000000000000000000000000000..5b0d289c377d64cf8adf6a994e87864b9b9427d5 --- /dev/null +++ b/php/chat_functions.php @@ -0,0 +1,868 @@ +getFieldType( $loginKeyFields[0] ); + if(NeedQuotes($ftype)) + $out = "'".implode("','",$res)."'"; + else + $out = implode(",",$res);*/ + return $res; + } + else + return array($targetid); + +} + +function getGroupMenu(){ + global $loginKeyFields; + $userdata = Security::currentUserData(); + $countGroups = 0; + $groups = ""; + $rs = DB::Select("chat_groups",""); + while($data = $rs->fetchAssoc()){ + $targetArr = explode(",",$data["targetid"]); + if($data["ownerid"] == $userdata[$loginKeyFields[0]]){ + if($groups) + $groups.=","; + $groups.= $data["id"]; + } + if(in_array($userdata[$loginKeyFields[0]],$targetArr)){ + if($groups) + $groups.=","; + $groups.= $data["id"]; + } + + $countGroups++; + } + $_SESSION["countGroups"] = $countGroups; + + $menu = ""; + // create group menu + if($groups){ + $menu.= ""; + $rs = DB::Select("chat_groups",AddFieldWrappers("id")." in (".$groups.")"); + while($data = $rs->fetchAssoc()){ + $author = $data["groupname"]; + if(!$author) + $author = "Group chat"; + $isType = 0; + $cnt_messages = 0; + $sql = DB::PrepareSQL("select * from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("ownerid")."<>':1' and ".AddFieldWrappers("targetid")."=':2'",$userdata[$loginKeyFields[0]],"G".$data["id"]); + $rs2 = DB::Query($sql); + while($data2 = $rs2->fetchAssoc()){ + $arr = explode(",",$data2["isread"]); + if(!in_array($userdata[$loginKeyFields[0]],$arr)) + $cnt_messages++; + } + if($cnt_messages>0) + $cnt_messages = "
".$cnt_messages."
"; + else + $cnt_messages = ""; + $avatar = ""; + $display_author = $author; + if(strlen($display_author)>27) + $display_author = substr($display_author,0,24)."..."; + $s = ""; + if($_SESSION["targetid"] == "G".$data["id"]) + $s = " td_users_selected"; + $type_popup = "user"; + if($data["ownerid"] == $userdata[$loginKeyFields[0]]) + $type_popup = "admin"; + + $menu.= ""; + } + else{ + $menu.= " + + + "; + $menu.= " + + + "; + } + if(!$_SESSION["targetid"]) + $_SESSION["targetid"] = "G".$data["id"]; + } + $menu.= "
".$avatar."".$cnt_messages; + + + if($data["ownerid"] == $userdata[$loginKeyFields[0]]){ + $menu.= " + + "; + $menu.= " + + ".$typing."
".$typing."
"; + $menu = "
".$menu."
"; + } + + return $menu; +} + + +function getMenu(){ + global $loginKeyFields, $cLoginTable,$cDisplayNameField, $cUserpicField, $cUserNameField; + if(!$cDisplayNameField) + $cDisplayNameField = $cUserNameField; + $userdata = Security::currentUserData(); + $users = array(); + if(!isGroupTarget($_SESSION["targetid"]) && $_SESSION["targetid"]) + $users[] = $_SESSION["targetid"]; + $sql = DB::PrepareSQL("select ".AddFieldWrappers("ownerid")." from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("targetid")."=':1' group by ".AddFieldWrappers("ownerid"),$userdata[$loginKeyFields[0]]); + $rs = DB::Query($sql); + $countUsers = 0; + while($data = $rs->fetchAssoc()){ + if(!isGroupTarget($data["ownerid"])){ + $users[] = $data["ownerid"]; + $countUsers++; + } + } + $sql = DB::PrepareSQL("select ".AddFieldWrappers("targetid")." from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("ownerid")."=':1' group by ".AddFieldWrappers("targetid"),$userdata[$loginKeyFields[0]]); + $rs = DB::Query($sql); + while($data = $rs->fetchAssoc()){ + if(!isGroupTarget($data["targetid"])){ + $users[] = $data["targetid"]; + $countUsers++; + } + } + $_SESSION["countUsers"] = $countUsers; + $menu = ""; + + + $menu = "
"; + + // create menu + if(count($users)){ + $menu.= ""; + $dc = new DsCommand(); + $conditions = array(); + $conditions[] = DataCondition::FieldIs( $loginKeyFields[0], dsopIN, $users ); + $dc->filter = DataCondition::_And( $conditions ); + $datasource = getLoginDataSource(); + $rs = $datasource->getList( $dc ); + while($data = $rs->fetchAssoc()){ + $author = $data[$cDisplayNameField]; + if(!$author) + $author = $data[$cUserNameField]; + $rs2 = DB::Select("chat_users",array("userid"=>$data[$loginKeyFields[0]])); + $isType = 0; + if($data2 = $rs2->fetchAssoc()){ + if(strtotime(date("Y-m-d H:i:s")) - strtotime($data2["lastaccess"]) > $_SESSION["loginTime"]) + $cl = "offline"; + else + $cl = "online"; + $isType = $data2["isTyping"]; + } + else + $cl = "offline"; + $cnt_messages = ""; + $sql = DB::PrepareSQL("select count(".AddFieldWrappers("id").") as cnt from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("isread")."='0' and ".AddFieldWrappers("ownerid")."=':1' and ".AddFieldWrappers("targetid")."=':2'",$data[$loginKeyFields[0]],$userdata[$loginKeyFields[0]]); + $rs2 = DB::Query($sql); + $data2 = $rs2->fetchAssoc(); + if($data2["cnt"]>0) + $cnt_messages = "
".$data2["cnt"]."
"; + $onoffline = "
"; + $avatar = getAvatar($data,"",false).""; + $display_author = $author; + if(strlen($display_author)>27) + $display_author = substr($display_author,0,24)."..."; + $s = ""; + if($_SESSION["targetid"] == $data[$loginKeyFields[0]]) + $s = " td_users_selected"; + $menu.= ""; + if(!$_SESSION["targetid"]) + $_SESSION["targetid"] = $data[$loginKeyFields[0]]; + } + + $menu.= "
".$onoffline.$avatar."".$cnt_messages."".$typing."
"; + } + return $menu; +} + +function getAjaxMenu(){ + $userdata = Security::currentUserData(); + global $loginKeyFields, $cLoginTable,$cDisplayNameField, $cUserpicField, $cUserNameField; + if(!$cDisplayNameField) + $cDisplayNameField = $cUserNameField; + + $users = array(); + if(!isGroupTarget($_SESSION["targetid"]) && $_SESSION["targetid"]) + $users[] = $_SESSION["targetid"]; + $sql = DB::PrepareSQL("select ".AddFieldWrappers("ownerid")." from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("targetid")."=':1' group by ".AddFieldWrappers("ownerid"),$userdata[$loginKeyFields[0]]); + $rs = DB::Query($sql); + $countUsers = 0; + while($data = $rs->fetchAssoc()){ + if(!isGroupTarget($data["ownerid"])){ + $users[] = $data["ownerid"]; + $countUsers++; + } + } + $sql = DB::PrepareSQL("select ".AddFieldWrappers("targetid")." from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("ownerid")."=':1' group by ".AddFieldWrappers("targetid"),$userdata[$loginKeyFields[0]]); + $rs = DB::Query($sql); + while($data = $rs->fetchAssoc()){ + if(!isGroupTarget($data["targetid"])){ + $users[] = $data["targetid"]; + $countUsers++; + } + } + if($_SESSION["countUsers"] == $countUsers){ + $arrMenu = array(); + if(count($users)){ + $dc = new DsCommand(); + $conditions = array(); + $conditions[] = DataCondition::FieldIs( $loginKeyFields[0], dsopIN, $users ); + $dc->filter = DataCondition::_And( $conditions ); + $datasource = getLoginDataSource(); + $rs = $datasource->getList( $dc ); + while($data = $rs->fetchAssoc()){ + $elemMenu = array(); + $rs2 = DB::Select("chat_users", array("userid"=>$data[$loginKeyFields[0]])); + $isType = 0; + if($data2 = $rs2->fetchAssoc()){ + if(strtotime(date("Y-m-d H:i:s")) - strtotime($data2["lastaccess"]) > $_SESSION["loginTime"]) + $cl = "offline"; + else{ + $cl = "online"; + if(!isGroupTarget($data2["isTyping"])) + $isType = $data2["isTyping"]; + } + } + else + $cl = "offline"; + + //$isType = $data2["isTyping"]; + + + $cnt_messages = ""; + $sql = DB::PrepareSQL("select count(".AddFieldWrappers("id").") as cnt from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("isread")."='0' and ".AddFieldWrappers("ownerid")."=':1' and ".AddFieldWrappers("targetid")."=':2'",$data[$loginKeyFields[0]],$userdata[$loginKeyFields[0]]); + $rs2 = DB::Query($sql); + $data2 = $rs2->fetchAssoc(); + if($data2["cnt"]>0) + $cnt_messages = $data2["cnt"]; + $elemMenu["notify"] = $cnt_messages; + $elemMenu["status"] = $cl; + $elemMenu["typing"] = $isType; + $elemMenu["username"] = $data[$cUserNameField]; + $arrMenu[$data[$loginKeyFields[0]]] = $elemMenu; + + if(!$_SESSION["targetid"]) + $_SESSION["targetid"] = $data[$loginKeyFields[0]]; + + } + } + } + else{ + $arrMenu["menu"] = getMenu(); + $_SESSION["countUsers"] = $countUsers; + } + return $arrMenu; +} + +function getGroupAjaxMenu(){ + global $loginKeyFields; + $userdata = Security::currentUserData(); + $countGroups = 0; + $groups = ""; + $rs = DB::Select("chat_groups",""); + while($data = $rs->fetchAssoc()){ + if($data["ownerid"] == $userdata[$loginKeyFields[0]]){ + if($groups) + $groups.=","; + $groups.= $data["id"]; + $countGroups++; + } + $targetArr = explode(",",$data["targetid"]); + if(in_array($userdata[$loginKeyFields[0]],$targetArr) && $data["ownerid"] != $userdata[$loginKeyFields[0]]){ + if($groups) + $groups.=","; + $groups.= $data["id"]; + $countGroups++; + } + } + $arrMenu = array(); + //$arrMenu["tmp"] = $_SESSION["countGroups"]."---".$countGroups; + if($_SESSION["countGroups"] == $countGroups){ + // create group menu + if($groups){ + $countGroups = 0; + $rs = DB::Select("chat_groups",AddFieldWrappers("id")." in (".$groups.")"); + while($data = $rs->fetchAssoc()){ + $elemMenu = array(); + $isType = 0; + $rs2 = DB::Select("chat_users", array("isTyping"=>"G".$data["id"])); + $isType = 0; + if($data2 = $rs2->fetchAssoc()){ + if(isGroupTarget($data2["isTyping"]) && $data2["userid"]!=$userdata[$loginKeyFields[0]]) + $isType = $data2["isTyping"]; + } + $cnt_messages = 0; + $sql = DB::PrepareSQL("select * from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("ownerid")."<>':1' and ".AddFieldWrappers("targetid")."=':2'",$userdata[$loginKeyFields[0]],"G".$data["id"]); + $rs2 = DB::Query($sql); + while($data2 = $rs2->fetchAssoc()){ + $arr = explode(",",$data2["isread"]); + if(!in_array($userdata[$loginKeyFields[0]],$arr)) + $cnt_messages++; + } + $elemMenu["notify"] = $cnt_messages; + $elemMenu["typing"] = $isType; + $elemMenu["name"] = $data["groupname"]; + $arrMenu["G".$data["id"]] = $elemMenu; + $countGroups++; + } + if($_SESSION["countGroups"] != $countGroups){ + $arrMenu["menu"] = getGroupMenu(); + $_SESSION["countGroups"] = $countGroups; + } + } + } + else{ + $arrMenu["menu"] = getGroupMenu(); + $_SESSION["countGroups"] = $countGroups; + } + + return $arrMenu; +} + + +function getUserStatus($targetid){ + + $rs2 = DB::Select("chat_users", array("userid"=>$targetid)); + if($data2 = $rs2->fetchAssoc()){ + if(strtotime(date("Y-m-d H:i:s")) - strtotime($data2["lastaccess"]) > $_SESSION["loginTime"]){ + $cl = "offline_header"; + } + else{ + $cl = "online"; + } + } + else + $cl = "offline_header"; + return $cl; +} + +function getUserStatusHeader($targetid){ + $resArray = array(); + if(isGroupTarget($targetid)){ + $ids = getGroupIDs($targetid); + $usersArray = explode(",",$ids); + foreach($usersArray as $tid) + $resArray[] = getStatusUser($tid); + } + else{ + $resArray[] = getStatusUser($targetid); + } + return $resArray; +} + +function getStatusUser($targetid){ + $rs2 = DB::Select("chat_users", array("userid"=>$targetid)); + if($data2 = $rs2->fetchAssoc()){ + if(strtotime(date("Y-m-d H:i:s")) - strtotime($data2["lastaccess"]) > $_SESSION["loginTime"]){ + $resArray = array( $targetid => "offline_header"); + } + else{ + $resArray = array( $targetid => "online"); + } + } + else + $resArray = array( $targetid => "offline_header"); + return $resArray; +} + +function getHeader(){ + global $loginKeyFields, $cLoginTable,$cDisplayNameField,$cUserNameField; + if(!$cDisplayNameField) + $cDisplayNameField = $cUserNameField; + if(!$_SESSION["targetid"]) + $_SESSION["targetid"]=0; + $hiddenInput = ""; + $userdata = Security::currentUserData(); + if(isGroupTarget($_SESSION["targetid"])){ + $currentUserName.= "
"; + $rs = DB::Select("chat_groups", array("id" => getGroupID($_SESSION["targetid"]))); + $data = $rs->fetchAssoc(); + $currentUserName.= "
".$data["groupname"]."
"; + $type_popup = "user"; + if($data["ownerid"] == $userdata[$loginKeyFields[0]]) + $type_popup = "admin"; + $currentUserName.= "
+ + +
"; + $usersArray = explode(",",$data["targetid"]); + $usersArray[] = $data["ownerid"]; + sort($usersArray); + foreach($usersArray as $users){ + if($userdata[$loginKeyFields[0]] != $users){ + DB::SetConnection(DB::ConnectionByTable($cLoginTable)); + $rs2 = DB::Select( $cLoginTable, array( $loginKeyFields[0] => $users ) ); + DB::SetConnection(DB::DefaultConnection()); + if($data2 = $rs2->fetchAssoc()){ + $avatar = getAvatar($data2,"",true); + $cl = getUserStatus($data2[$loginKeyFields[0]]); + $onoffline = "
"; + $uname = $data2[$cDisplayNameField]; + if(!$uname) + $uname = $data2[$cUserNameField]; + $currentUserName.= "
".$onoffline.$avatar." ".$uname."
"; + } + } + } + $currentUserName.= "
"; + /*$userdata = Security::currentUserData(); + if($userdata[$loginKeyFields[0]] == $data["ownerid"]) + $currentUserName.= "
"; + else + $currentUserName.= "
".getCustomLabel("leave_chat")."
";*/ + } + else{ + $currentUserName = ""; + DB::SetConnection(DB::ConnectionByTable($cLoginTable)); + $rs = DB::Select( $cLoginTable, array( $loginKeyFields[0] => $_SESSION["targetid"] ) ); + DB::SetConnection(DB::DefaultConnection()); + if($data = $rs->fetchAssoc()){ + $avatar = getAvatar($data, "_message", false); + $cl = getUserStatus($data[$loginKeyFields[0]]); + $uname = $data[$cDisplayNameField]; + if(!$uname) + $uname = $data[$cUserNameField]; + $onoffline = "
"; + $currentUserName = $onoffline.$avatar." ".$uname.""; + } + } + return $currentUserName.$hiddenInput; +} + +function getMessageRecordSet(){ + $userdata = Security::currentUserData(); + global $loginKeyFields, $cLoginTable,$cDisplayNameField, $cUserpicField, $cUserNameField; + $dc = new DsCommand(); + $conditions1 = array(); + $conditions2 = array(); + if(!isGroupTarget($_SESSION["targetid"])){ + if(!$_SESSION["searchValue"]){ + //$sqlGlobal = "select * from chat_history where targetid='".$userdata[$loginKeyFields[0]]."' and ownerid='".$_SESSION["targetid"]."' or targetid='".$_SESSION["targetid"]."' and ownerid='".$userdata[$loginKeyFields[0]]."' order by id"; + $conditions1[] = DataCondition::FieldIs( "targetid", dsopEQUAL, $userdata[$loginKeyFields[0]] ); + $conditions1[] = DataCondition::FieldIs( "ownerid", dsopEQUAL, $_SESSION["targetid"] ); + $conditions2[] = DataCondition::FieldIs( "targetid", dsopEQUAL, $_SESSION["targetid"] ); + $conditions2[] = DataCondition::FieldIs( "ownerid", dsopEQUAL, $userdata[$loginKeyFields[0]] ); + $dc->filter = DataCondition::_Or( array( + DataCondition::_And( $conditions1 ), + DataCondition::_And( $conditions2 ), + )); + } + else{ + + //$sqlGlobal = "select * from chat_history where targetid='".$userdata[$loginKeyFields[0]]."'".$_SESSION["searchSQLValue"]." or ownerid='".$userdata[$loginKeyFields[0]]."'".$_SESSION["searchSQLValue"]." order by id"; + $conditions1[] = DataCondition::FieldIs( "targetid", dsopEQUAL, $userdata[$loginKeyFields[0]] ); + $conditions1[] = DataCondition::FieldIs( "messages", dsopCONTAIN, $_SESSION["searchValue"] ); + $conditions2[] = DataCondition::FieldIs( "ownerid", dsopEQUAL, $userdata[$loginKeyFields[0]] ); + $conditions2[] = DataCondition::FieldIs( "messages", dsopCONTAIN, $_SESSION["searchValue"] ); + $dc->filter = DataCondition::_Or( array( + DataCondition::_And( $conditions1 ), + DataCondition::_And( $conditions2 ), + )); + } + } + else{ + if(!$_SESSION["searchValue"]){ + //$sqlGlobal = "select * from chat_history where targetid='".$_SESSION["targetid"]."' and ownerid in (".getGroupIDsIn($_SESSION["targetid"]).") order by id"; + $conditions1[] = DataCondition::FieldIs( "targetid", dsopEQUAL, $_SESSION["targetid"] ); + $conditions1[] = DataCondition::FieldIs( "ownerid", dsopIN, getGroupIDsIn($_SESSION["targetid"]) ); + $dc->filter = DataCondition::_And( $conditions1 ); + } + else{ + //$sqlGlobal = "select * from chat_history where ownerid in (".getGroupIDsIn($_SESSION["targetid"]).")".$_SESSION["searchSQLValue"]." order by id"; + $conditions1[] = DataCondition::FieldIs( "messages", dsopCONTAIN, $_SESSION["searchValue"] ); + $conditions1[] = DataCondition::FieldIs( "ownerid", dsopIN, getGroupIDsIn($_SESSION["targetid"]) ); + $dc->filter = DataCondition::_And( $conditions1 ); + } + } + $dc->order = array(array( "column" => "id", "dir" => "ASC" )); + $datasource = getDataSource("chat_history"); + $rs = $datasource->getList( $dc ); + return $rs; +} + +function getMessage($isStart){ + $scrollStep = 14; + $userdata = Security::currentUserData(); + global $loginKeyFields, $cLoginTable,$cDisplayNameField, $cUserpicField, $cUserNameField; + if(!$cDisplayNameField) + $cDisplayNameField = $cUserNameField; + $period = DB::DBLookup("select ".addFieldWrappers("timeperiod")." from ".addTableWrappers("chat_settings")); + $res_msg = ""; + $rs = getMessageRecordSet(); + $totalMessages = 0; + while($data = $rs->fetchAssoc()){ + if(isAddMessage($data,$period,$isStart) && $data["status"]!="delete") + $totalMessages++; + } + $rs = getMessageRecordSet(); + $counter = 0; + $counterTrue = 0; + $res_msg = array(); + $firstID = ""; + while($data = $rs->fetchAssoc()){ + if(isAddMessage($data,$period,$isStart) && $data["status"]!="delete" && !$data["isVideo"]){ + if(isCounter($counter,$totalMessages,$scrollStep,$data)){ + DB::SetConnection(DB::ConnectionByTable($cLoginTable)); + $rs2 = DB::Select($cLoginTable, array($loginKeyFields[0]=>$data["ownerid"])); + DB::SetConnection(DB::DefaultConnection()); + $data2 = $rs2->fetchAssoc(); + $avatar = getAvatar($data2,"_message", false); + $author = $data2[$cDisplayNameField]; + if(!$author) + $author = $data2[$cUserNameField]; + $timeArray = array(); + $arrtmp = explode(" ",$data["created"]); + $arrtmp1 = explode("-",$arrtmp[0]); + $arrtmp2 = explode(":",$arrtmp[1]); + $timeArray[0] = $arrtmp1[0]; + $timeArray[1] = $arrtmp1[1]; + $timeArray[2] = $arrtmp1[2]; + $timeArray[3] = $arrtmp2[0]; + $timeArray[4] = $arrtmp2[1]; + $timeArray[5] = "00"; + $not_read = ""; + if(!$firstID) + $firstID = $data["id"]; + if($data["ownerid"]==$userdata[$loginKeyFields[0]]){ //// || isGroupTarget($_SESSION["targetid"]) + if(!$data["isread"] || $data["isread"] == $data["ownerid"]) + $not_read = ''; + else{ + if(!isGroupTarget($_SESSION["targetid"])) + $not_read = ''; else{ + $ids = getGroupIDs($_SESSION["targetid"]); + $arrayIDs = explode(",",$ids); + sort($arrayIDs); + $arrayRead = explode(",",$data["isread"]); + sort($arrayRead); + if($arrayIDs == $arrayRead) + $not_read = ''; + else + $not_read = ''; + } + } + } + if(date("Y-m-d",strtotime($data["created"])) == date("Y-m-d")) + $current_date = str_format_time($timeArray); + else + $current_date = str_format_datetime($timeArray); + $current_date = str_replace(":00 "," ",$current_date); + $message_block_search = ""; + if($_SESSION["searchValue"]) + $message_box_search = " message_block_search"; + $actpoint = ""; + if($data["ownerid"] == $userdata[$loginKeyFields[0]]) + $actpoint = " addpoint"; + $search_class=""; + if(postvalue("searchanchor") == $data["id"]) + $search_class=" select_search_result"; + + $res_msg[$data["id"]] = "
"; + if($_SESSION["searchValue"]){ + $targetid = $data["targetid"]; + if($targetid == $userdata[$loginKeyFields[0]]) + $targetid = $data["ownerid"]; + + if(!isGroupTarget($targetid)){ + DB::SetConnection(DB::ConnectionByTable($cLoginTable)); + $rslog = DB::Select($cLoginTable, array($loginKeyFields[0]=>$targetid)); + DB::SetConnection(DB::DefaultConnection()); + $datalog = $rslog->fetchAssoc(); + $channel = $datalog[$cDisplayNameField]; + if(!$channel) + $channel = $datalog[$cUserNameField]; + } + else{ + $id = getGroupID($targetid); + $rslog = DB::Select("chat_groups", array("id"=>$id)); + $datalog = $rslog->fetchAssoc(); + $channel = $datalog["groupname"]; + } + $res_msg[$data["id"]].=""; + } + $res_msg[$data["id"]].="
".$avatar."
"; + $res_msg[$data["id"]].="
"; + + $res_msg[$data["id"]].="
".$author." ".$current_date.$not_read."
"; + $text = str_replace("\n","
",$data["messages"]); + if($_SESSION["searchValue"]){ + $text = str_replace(postvalue("search"),"".runner_htmlspecialchars(postvalue("search"))."",$text); + } + if($data["soundRecord"]){ + $arr = my_json_decode($data["soundRecord"]); + foreach($arr as $src) + $text.= "
"; + } + $res_msg[$data["id"]].= "
".$text."
"; + $strfiles = getAttachment($data); + if($strfiles) + $res_msg[$data["id"]].= "
".$strfiles."
"; + $res_msg[$data["id"]].= "
"; + $res_msg[$data["id"]].= "
"; + $counterTrue++; + } + $counter++; + } + + } + if($firstID) + $_SESSION["firstMessID"] = $firstID; + if(postvalue("searchanchor")){ + $_SESSION["scroll_step"] = floor($counterTrue/$scrollStep); + } + if($counter == 0 && $isStart=="true") + $res_msg[0] = "".GetCustomLabel("nomessage_id").""; + + return $res_msg; +} +function getAttachment($data){ + global $loginKeyFields, $cLoginTable,$cDisplayNameField, $cUserpicField, $cUserNameField; + if(!$cDisplayNameField) + $cDisplayNameField = $cUserNameField; + $rs2 = DB::Select("chat_files", array("messageid"=>$data["id"])); + $strfiles = ""; + $data2 = $rs2->fetchAssoc(); + $filesArray = my_json_decode($data2["files"]); + foreach($filesArray as $ind=>$val){ + if($strfiles) + $strfiles.="   "; + $fileType = getContentTypeByExtension(substr($val["usrName"], strrpos($val["usrName"], '.'))); + $icon = ""; + $p = strrpos($val["usrName"],"."); + $ext = CheckImageExtension($val["usrName"]); + if( $ext ){ + $strfiles.= "
".$val["usrName"]."
"; + $file = file_get_contents(getabspath($val["name"])); + $src = "data:image/png;base64,".base64_encode($file); + $strfiles.= "
"; + } + else{ + $fsize = $val["size"]; + if($val["size"]<1000) + $fsize = $val["size"]." B"; + else + $fsize = round($val["size"]/1000)." kB"; + $fname = "
".$icon." ".$val["usrName"]."
".$fsize."
"; + $strfiles.= "
".$val["usrName"]."
"; + $strfiles.= "
"; + $strfiles.= "
".$fname."
"; + $strfiles.= "
"; + } + } + return $strfiles; +} + +function getAvatar($data, $cl = "", $needLetter = false){ + global $loginKeyFields, $cLoginTable,$cDisplayNameField, $cUserpicField, $cUserNameField; + if(!$cDisplayNameField) + $cDisplayNameField = $cUserNameField; + if($data[$cUserpicField]){ + DB::SetConnection(DB::ConnectionByTable($cLoginTable)); + $rs2 = DB::Select($cLoginTable, array($loginKeyFields[0]=>$data[$loginKeyFields[0]])); + DB::SetConnection(DB::DefaultConnection()); + $data2 = $rs2->fetchAssoc(); + $src = "data:image/png;base64,".base64_encode($data2[$cUserpicField]); + $avatar = ""; + } + else{ + $letter = ""; + if($needLetter){ + if($data[$cDisplayNameField]) + $letter = substr($data[$cDisplayNameField],0,1); + else + $letter = substr($data[$cUserNameField],0,1); + $letter = "".strtoupper($letter).""; + } + $avatar = "".$letter; + } + return $avatar; +} + +function isAddMessage($data,$period,$isStart){ + $t = explode(" ",this_microtime()); + $now = date("Y-m-d H:i:s",$t[1]).substr((string)$t[0],1,4)."000"; + if(strtotime($data["created"])>strtotime($now)-$period || $isStart=="true") + return true; + else + return false; + +} + +function isCounter($counter,$totalMessages,$scrollStep,$data){ + if(postvalue("searchanchor")){ + if($data["id"] >= postvalue("searchanchor")) + return true; + else + return false; + } + else{ + if($counter>=$totalMessages-$scrollStep-$_SESSION["scroll_step"]*$scrollStep) + return true; + else + return false; + } +} + +function getDeleteMessage(){ + $res = array(); + $period = DB::DBLookup("select ".AddFieldWrappers("timeperiod")." from ".AddTableWrappers("chat_settings")); + $rs = DB::Select("chat_history", array("status"=>"delete")); + while($data = $rs->fetchAssoc()){ + $res[] = $data["id"]; + if(strtotime(date("Y-m-d H:i:s")) - strtotime($data["status_created"])>=$period*2) + DB::Delete("chat_history", array("id"=>$data["id"])); + } + return $res; +} +function getEditMessage(){ + $res = array(); + $period = DB::DBLookup("select ".AddFieldWrappers("timeperiod")." from ".AddTableWrappers("chat_settings")); + $rs = DB::Select("chat_history", array("status"=>"edit")); + while($data = $rs->fetchAssoc()){ + $res[] = $data["id"]; + if(strtotime(date("Y-m-d H:i:s")) - strtotime($data["status_created"])>=$period*2) + DB::Delete("chat_history", array("id"=>$data["id"])); + } + return $res; +} +function updateIsRead(){ + global $loginKeyFields, $cLoginTable; + $userdata = Security::currentUserData(); + if($_SESSION["targetid"]){ + if(strpos(postvalue("url"),"chat_history_add")>0 || strpos(postvalue("url"),"chat_history/add")>0){ + if(!isGroupTarget($_SESSION["targetid"])){ + DB::Update("chat_history",array("isread"=>$userdata[$loginKeyFields[0]]),array("ownerid"=>$_SESSION["targetid"],"targetid"=>$userdata[$loginKeyFields[0]])); + } + else{ + $targetIDs = getGroupIDsIn($_SESSION["targetid"]); + /*$pSet = new ProjectSettings( $cLoginTable ); + $ftype = $pSet->getFieldType( $loginKeyFields[0] ); + $val = $userdata[$loginKeyFields[0]]; + if(NeedQuotes($ftype)) + $val = "'".$userdata[$loginKeyFields[0]]."'"; + $rs2 = DB::Query("select * from chat_history where status<>'delete' and targetid='".$_SESSION["targetid"]."' and ".$val." in (".$targetIDs.")");*/ + + $dc = new DsCommand(); + $conditions = array(); + $conditions[] = DataCondition::FieldIs( "targetid", dsopEQUAL, $_SESSION["targetid"] ); + //$conditions[] = DataCondition::FieldIs( $userdata[$loginKeyFields[0]], dsopIN, $targetIDs ); + $conditions[] = DataCondition::_Not( DataCondition::FieldIs( "status", dsopEQUAL, 'delete' ) ); + $dc->filter = DataCondition::_And( $conditions ); + $datasource = getDataSource("chat_history"); + $rs2 = $datasource->getList( $dc ); + + while($data2 = $rs2->fetchAssoc()){ + if(in_array($userdata[$loginKeyFields[0]],$targetIDs)){ + $arrayRead = array(); + $arrayRead = explode(",",$data2["isread"]); + $key = array_search(0, $arrayRead); + if (false !== $key && $arrayRead[0]=="0") + unset($arrayRead[$key]); + if(!in_array($userdata[$loginKeyFields[0]],$arrayRead)){ + $arrayRead[] = $userdata[$loginKeyFields[0]]; + $isRead = implode(",",$arrayRead); + DB::Update("chat_history",array("isread"=>$isRead),"id=".$data2["id"]); + } + } + } + } + } + } +} + +function getIsReadStatus(){ + global $loginKeyFields; + $userdata = Security::currentUserData(); + $isRead = array(); + $rs = DB::Select("chat_history",array("targetid"=>$_SESSION["targetid"],"ownerid"=>$userdata[$loginKeyFields[0]])); + while($data = $rs->fetchAssoc()){ + if($data["isread"] && $data["isread"] != $data["ownerid"] && $data["id"]>=$_SESSION["firstMessID"]){ + if(!isGroupTarget($_SESSION["targetid"])) + $isRead[$data["id"]] = 2; + else{ + $ids = getGroupIDs($_SESSION["targetid"]); + $arrayIDs = explode(",",$ids); + if(!in_array($userdata[$loginKeyFields[0]],$arrayIDs)) + $arrayIDs[] = $userdata[$loginKeyFields[0]]; + sort($arrayIDs); + $arrayRead = explode(",",$data["isread"]); + sort($arrayRead); + if($arrayIDs == $arrayRead) + $isRead[$data["id"]] = 3; + else + $isRead[$data["id"]] = 2; + } + } + } + return $isRead; +} + +function getVideoCallData(){ + global $loginKeyFields, $cLoginTable, $cUserpicField, $cUserNameField; + $userdata = Security::currentUserData(); + $userid = $userdata[$loginKeyFields[0]]; + $sql = DB::PrepareSQL("select * from ".AddTableWrappers("chat_history")." where ".AddFieldWrappers("targetid")."=:1 and ".AddFieldWrappers("isVideo").">0",$userid); + $rs = DB::Query($sql); + if($data = $rs->fetchAssoc()){ + $_SESSION["targetid"] = $data["ownerid"]; + DB::SetConnection(DB::ConnectionByTable($cLoginTable)); + $rs2 = DB::Select( $cLoginTable, array( $loginKeyFields[0] => $data["ownerid"]) ); + DB::SetConnection(DB::DefaultConnection()); + $data2 = $rs2->fetchAssoc(); + + DB::Delete("chat_history", array("targetid"=>$userid, "isVideo"=>1)); + + if($data2[$cUserpicField]) + $src = "data:image/png;base64,".base64_encode($data2[$cUserpicField]); + else + $src = "images/no_avatar.jpg"; + + return array("msg"=>$data["messages"],"avatar"=>$src, "name"=>$data2[$cUserNameField], "isVideo"=>$data["isVideo"]); + } + else + return array(); +} + +function this_microtime(){ + return microtime(); +} +?> \ No newline at end of file diff --git a/php/chat_groups1_add.php b/php/chat_groups1_add.php new file mode 100644 index 0000000000000000000000000000000000000000..573c6a66428fdc849bea25af05288edeb4c874b2 --- /dev/null +++ b/php/chat_groups1_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_groups1_edit.php b/php/chat_groups1_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..0896db91de73c8959393db839bf6ae4e95a0b0fb --- /dev/null +++ b/php/chat_groups1_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_groups1_export.php b/php/chat_groups1_export.php new file mode 100644 index 0000000000000000000000000000000000000000..c16b8705d3dab4a905d6a9c4f22b7a09190da747 --- /dev/null +++ b/php/chat_groups1_export.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_groups1_import.php b/php/chat_groups1_import.php new file mode 100644 index 0000000000000000000000000000000000000000..6ad27ebafcd74de8a604b1ad2ee99d607b5d8e21 --- /dev/null +++ b/php/chat_groups1_import.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_groups1_list.php b/php/chat_groups1_list.php new file mode 100644 index 0000000000000000000000000000000000000000..41c5e2a512224a72c1fa6656b8310559030ec18e --- /dev/null +++ b/php/chat_groups1_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/chat_groups1_print.php b/php/chat_groups1_print.php new file mode 100644 index 0000000000000000000000000000000000000000..ca616da685179e75c5e9a53306bf0ad3b4307c25 --- /dev/null +++ b/php/chat_groups1_print.php @@ -0,0 +1,46 @@ +init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_groups1_search.php b/php/chat_groups1_search.php new file mode 100644 index 0000000000000000000000000000000000000000..9e8b71b9fece09eab4c0a3c02317f00cac640ac7 --- /dev/null +++ b/php/chat_groups1_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_groups1_view.php b/php/chat_groups1_view.php new file mode 100644 index 0000000000000000000000000000000000000000..ace3ca56a83e5b2426a91231c395fb87c1a71087 --- /dev/null +++ b/php/chat_groups1_view.php @@ -0,0 +1,67 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_groups_add.php b/php/chat_groups_add.php new file mode 100644 index 0000000000000000000000000000000000000000..8433752751b0792bfaffc4aed426fcc27e407990 --- /dev/null +++ b/php/chat_groups_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_groups_edit.php b/php/chat_groups_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..10d1584ad16110873882de4428adaa0c2bca6357 --- /dev/null +++ b/php/chat_groups_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_groups_list.php b/php/chat_groups_list.php new file mode 100644 index 0000000000000000000000000000000000000000..e0df6874bab1aa763e783e3ced5d542c62e9e619 --- /dev/null +++ b/php/chat_groups_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/chat_groups_search.php b/php/chat_groups_search.php new file mode 100644 index 0000000000000000000000000000000000000000..ca8da558815f62b356219c54837b3d4d5956044c --- /dev/null +++ b/php/chat_groups_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_history1_add.php b/php/chat_history1_add.php new file mode 100644 index 0000000000000000000000000000000000000000..ae10eedfb0a52ea975bf2105719e11da2da1aeac --- /dev/null +++ b/php/chat_history1_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_history1_edit.php b/php/chat_history1_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..531e16a5d8d30c48d7f5f954e0457619686f0da9 --- /dev/null +++ b/php/chat_history1_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_history1_export.php b/php/chat_history1_export.php new file mode 100644 index 0000000000000000000000000000000000000000..8bbb6c38c39f2e8f95e892e8ecbb3b36bfc7c500 --- /dev/null +++ b/php/chat_history1_export.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_history1_import.php b/php/chat_history1_import.php new file mode 100644 index 0000000000000000000000000000000000000000..fcd3a37e012998498a023a0da4091a2f15638c21 --- /dev/null +++ b/php/chat_history1_import.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_history1_list.php b/php/chat_history1_list.php new file mode 100644 index 0000000000000000000000000000000000000000..97e5373834b54c445a46c31427e6c5b412861252 --- /dev/null +++ b/php/chat_history1_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/chat_history1_print.php b/php/chat_history1_print.php new file mode 100644 index 0000000000000000000000000000000000000000..a4d0712d8d872fd7c42f1944506c20848719445b --- /dev/null +++ b/php/chat_history1_print.php @@ -0,0 +1,46 @@ +init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_history1_search.php b/php/chat_history1_search.php new file mode 100644 index 0000000000000000000000000000000000000000..e60397500e4891c11b478707c012ece37334b817 --- /dev/null +++ b/php/chat_history1_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_history1_view.php b/php/chat_history1_view.php new file mode 100644 index 0000000000000000000000000000000000000000..4152b8cec63bd50c67c776006e602e978b70b0d8 --- /dev/null +++ b/php/chat_history1_view.php @@ -0,0 +1,67 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_history_add.php b/php/chat_history_add.php new file mode 100644 index 0000000000000000000000000000000000000000..e562bd5f225f2740c6ab813eb8081ae1377dfd35 --- /dev/null +++ b/php/chat_history_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_history_search.php b/php/chat_history_search.php new file mode 100644 index 0000000000000000000000000000000000000000..2f9d1ed895f77749d5aebfe8eba061ebf56dd866 --- /dev/null +++ b/php/chat_history_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_peopletype1_add.php b/php/chat_peopletype1_add.php new file mode 100644 index 0000000000000000000000000000000000000000..122fecc737e9d0ecdb48d3ef9981c264bcc69863 --- /dev/null +++ b/php/chat_peopletype1_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_peopletype1_edit.php b/php/chat_peopletype1_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..c1d70c3123bc876c23ad7db149bcb04721c10b41 --- /dev/null +++ b/php/chat_peopletype1_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_peopletype1_export.php b/php/chat_peopletype1_export.php new file mode 100644 index 0000000000000000000000000000000000000000..435dd2753140808e1fe4d19fab0030f4f643fdcd --- /dev/null +++ b/php/chat_peopletype1_export.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_peopletype1_import.php b/php/chat_peopletype1_import.php new file mode 100644 index 0000000000000000000000000000000000000000..869917492a13e525be9806270325f9848e26589b --- /dev/null +++ b/php/chat_peopletype1_import.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_peopletype1_list.php b/php/chat_peopletype1_list.php new file mode 100644 index 0000000000000000000000000000000000000000..cd7b9bd471803c5b31f0608e29246a734d30d636 --- /dev/null +++ b/php/chat_peopletype1_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/chat_peopletype1_print.php b/php/chat_peopletype1_print.php new file mode 100644 index 0000000000000000000000000000000000000000..b08d589f4c76e02add13650d1c1835f2b4bc24a3 --- /dev/null +++ b/php/chat_peopletype1_print.php @@ -0,0 +1,46 @@ +init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_peopletype1_search.php b/php/chat_peopletype1_search.php new file mode 100644 index 0000000000000000000000000000000000000000..43af3b52cca7caa99149026dcb3c577401f51a65 --- /dev/null +++ b/php/chat_peopletype1_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_peopletype1_view.php b/php/chat_peopletype1_view.php new file mode 100644 index 0000000000000000000000000000000000000000..4cc620925137ab2ce49eef29c82aeccb4189bb8f --- /dev/null +++ b/php/chat_peopletype1_view.php @@ -0,0 +1,67 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_peopletype_search.php b/php/chat_peopletype_search.php new file mode 100644 index 0000000000000000000000000000000000000000..742cad1f2048786b3971be766bfa79808ef3c1b9 --- /dev/null +++ b/php/chat_peopletype_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_settings1_add.php b/php/chat_settings1_add.php new file mode 100644 index 0000000000000000000000000000000000000000..191121752d503ffd7f202b1c98dc77d43dd06168 --- /dev/null +++ b/php/chat_settings1_add.php @@ -0,0 +1,108 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_settings1_edit.php b/php/chat_settings1_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..5db550dd2a48b84e1def5c1f34e477b33965b010 --- /dev/null +++ b/php/chat_settings1_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_settings1_export.php b/php/chat_settings1_export.php new file mode 100644 index 0000000000000000000000000000000000000000..0d777b6336496e46d2c6b4637da479c4c7ca754a --- /dev/null +++ b/php/chat_settings1_export.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_settings1_import.php b/php/chat_settings1_import.php new file mode 100644 index 0000000000000000000000000000000000000000..74f24fb7627db619f65682745dec36297f897434 --- /dev/null +++ b/php/chat_settings1_import.php @@ -0,0 +1,53 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_settings1_list.php b/php/chat_settings1_list.php new file mode 100644 index 0000000000000000000000000000000000000000..cb7c9871d57fe0d20301e1d8fa19e89da9902eb5 --- /dev/null +++ b/php/chat_settings1_list.php @@ -0,0 +1,163 @@ +processSaveSearch() ) + exit(); + +if( $pageObject->updateRowOrder() ) + exit(); + +if ( $pageObject->processFieldFilter() ) + exit(); + +if( $pageObject->processTotals() ) + exit(); + +if( $mode != LIST_DETAILS && $mode != MAP_DASHBOARD && $mode != LIST_DASHBOARD ) +{ + //maps +} + +unset($_SESSION["message_add"]); +unset($_SESSION["message_edit"]); + +// prepare code for build page +$pageObject->prepareForBuildPage(); + +// show page depends of mode +$pageObject->showPage(); + +?> \ No newline at end of file diff --git a/php/chat_settings1_print.php b/php/chat_settings1_print.php new file mode 100644 index 0000000000000000000000000000000000000000..95a5699cd6636f0074513ac161d726dfd517de1a --- /dev/null +++ b/php/chat_settings1_print.php @@ -0,0 +1,46 @@ +init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_settings1_search.php b/php/chat_settings1_search.php new file mode 100644 index 0000000000000000000000000000000000000000..7bde99e7e0ac56a52d6337370c8a97fc0747b242 --- /dev/null +++ b/php/chat_settings1_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_settings1_view.php b/php/chat_settings1_view.php new file mode 100644 index 0000000000000000000000000000000000000000..c6480cd8cba2068ff13d3428894ee41ec8d08e94 --- /dev/null +++ b/php/chat_settings1_view.php @@ -0,0 +1,67 @@ +init(); + +$pageObject->process(); + +?> \ No newline at end of file diff --git a/php/chat_settings_edit.php b/php/chat_settings_edit.php new file mode 100644 index 0000000000000000000000000000000000000000..377517e707444cdfefa1678ebec284cca64f7924 --- /dev/null +++ b/php/chat_settings_edit.php @@ -0,0 +1,107 @@ +isLockingRequest() ) +{ + $pageObject->doLockingAction(); + exit(); +} + +$pageObject->init(); + +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_settings_search.php b/php/chat_settings_search.php new file mode 100644 index 0000000000000000000000000000000000000000..b6232570e02819b841549cc97e0308884e2b215d --- /dev/null +++ b/php/chat_settings_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_timezone_search.php b/php/chat_timezone_search.php new file mode 100644 index 0000000000000000000000000000000000000000..09a9f78799c3d0d46fdcca149f3f19028410bb04 --- /dev/null +++ b/php/chat_timezone_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/chat_users_search.php b/php/chat_users_search.php new file mode 100644 index 0000000000000000000000000000000000000000..f500c3adb536d83d8cf22784978e7dde2a7e6ac5 --- /dev/null +++ b/php/chat_users_search.php @@ -0,0 +1,95 @@ +displaySearchControl(); + return; +} + +$pageObject->init(); +$pageObject->process(); +?> \ No newline at end of file diff --git a/php/checkduplicates.php b/php/checkduplicates.php new file mode 100644 index 0000000000000000000000000000000000000000..d20db9c81e37dc33de7db7bf2029da31aa4ab20c --- /dev/null +++ b/php/checkduplicates.php @@ -0,0 +1,80 @@ +allowDuplicateValues( $fieldName ); + +$regEmailMode = false; +$regUsernameMode = false; +$userNameField = Security::usernameField(); +if( Security::registerPage() && $table == Security::loginDataSource() ) { + $regEmailMode = $fieldName == Security::emailField(); + $regUsernameMode = $fieldName == $userNameField; + $denyChecking = $denyChecking && $fieldName != $userNameField && $fieldName != Security::emailField(); +} + +if( $denyChecking ) { + $returnJSON = array( "success" => false, "error" => "Duplicated values are allowed" ); + echo printJSON( $returnJSON) ; + return; +} + +// set db connection +$_connection = $cman->byTable( $table ); +$dataSource = getDataSource( $table, $pSet, $_connection ); +$dc = new DsCommand(); + +$dc->totals = array(); +$dc->totals[] = array( + "total" => "count", + "alias" => "count_".$fieldName, + "field" => $fieldName, +); + +$dc->filter = DataCondition::FieldEquals( $fieldName, $value, 0, dsCASE_DEFAULT ); + +// emails should always be compared case-insensitively +if( $regEmailMode ) { + $dc->filter = DataCondition::FieldEquals( $fieldName, $value, 0, dsCASE_INSENSITIVE ); +} +// username on register page +if( $regUsernameMode ) { + $where = $_connection->comparisonSQL( $fieldSQL, $value, Security::caseInsensitiveUsername() ); + $dc->filter = DataCondition::FieldEquals( $fieldName, $value, 0, + Security::caseInsensitiveUsername() ? dsCASE_INSENSITIVE : dsCASE_STRICT ); +} + +$qResult = $dataSource->getTotals( $dc ); +if( !$qResult ) { + $returnJSON = array( "success" => false, "error" => "Error: Wrong SQL query" ); + echo printJSON( $returnJSON ); + return; +} + +$hasDuplicates = false; +$data = $qResult->fetchAssoc(); +if( $data ) + $hasDuplicates = $data[ "count_".$fieldName ] ? true : false; + +$returnJSON = array( "success" => true, "hasDuplicates" => $hasDuplicates, "error" => "" ); +echo printJSON( $returnJSON ); +return; +?> \ No newline at end of file diff --git a/php/classes/addpage.php b/php/classes/addpage.php new file mode 100644 index 0000000000000000000000000000000000000000..fa69cf80c574b3c09b9fef5d5fc8387e36fdc2ed --- /dev/null +++ b/php/classes/addpage.php @@ -0,0 +1,1885 @@ +addFields = $this->getPageFields(); + $this->auditObj = GetAuditObject($this->tName); + + $this->headerForms = array( "top" ); + $this->footerForms = array( "below-grid" ); + + if ( $this->isMultistepped() ) + $this->bodyForms = array( "above-grid", "steps" ); + else + $this->bodyForms = array( "above-grid", "grid" ); + + $this->addPageSettings(); + } + + function setSessionVariables() { + parent::setSessionVariables(); + // don't use mastertable pre-stroed in session + if( !postvalue("mastertable")) { + $this->masterTable = ""; + } + } + + /** + * Add js page settings + */ + protected function addPageSettings() + { + if( $_SESSION[ $this->sessionPrefix . "_recordAdded" ] ) + { + $this->setProxyValue( $this->shortTableName."_recordAdded", true ); + unset( $_SESSION[ $this->sessionPrefix . "_recordAdded" ] ); + } + else + $this->setProxyValue( $this->shortTableName."_recordAdded", false ); + + if( $this->mode != ADD_SIMPLE && $this->mode != ADD_POPUP ) + return; + + $afterAddAction = $this->getAfterAddAction(); + $this->jsSettings["tableSettings"][ $this->tName ]["afterAddAction"] = $afterAddAction; + + if ( $afterAddAction == AA_TO_DETAIL_LIST || $afterAddAction == AA_TO_DETAIL_ADD ) + $this->jsSettings["tableSettings"][ $this->tName ]["afterAddActionDetTable"] = GetTableURL( $this->pSet->getAADetailTable() ); + + if( $this->listPage && $afterAddAction == AA_TO_LIST ) { + $this->pageData["listPage"] = $this->listPage; + } + } + + /** + * Get the correct after add action + * basing on the table settings + * @return Number + */ + protected function getAfterAddAction() + { + if( isset( $this->afterAddAction ) && !is_null( $this->afterAddAction ) ) + return $this->afterAddAction; + + $action = $this->pSet->getAfterAddAction(); + + if( $this->mode == ADD_POPUP && $this->pSet->checkClosePopupAfterAdd() + || $action == AA_TO_VIEW && !$this->viewAvailable() + || $action == AA_TO_EDIT && !$this->editAvailable() ) + { + $action = AA_TO_LIST; + } + + if( $action == AA_TO_DETAIL_LIST || $action == AA_TO_DETAIL_ADD ) + { + $dTName = $this->pSet->getAADetailTable(); + $dPset = new ProjectSettings( $dTName ); + $dPermissions = $this->getPermissions( $dTName ); + + $listPageAllowed = $dPset->hasListPage() && $dPermissions["search"]; + + if( !$dTName || $action == AA_TO_DETAIL_LIST && !$listPageAllowed + || $action == AA_TO_DETAIL_ADD && ( !$dPset->hasAddPage() || !$dPermissions["add"] && !$listPageAllowed ) ) + { + $action = AA_TO_LIST; + } + } + + $this->afterAddAction = $action; + return $this->afterAddAction; + } + + /** + * Assign session prefix + */ + protected function assignSessionPrefix() + { + if( $this->mode == ADD_DASHBOARD || $this->mode == ADD_MASTER_DASH + || ($this->mode == ADD_POPUP || $this->mode == ADD_INLINE || $this->fromDashboard != "" ) && $this->dashTName ) + { + $this->sessionPrefix = $this->dashTName."_".$this->tName; + return; + } + + parent::assignSessionPrefix(); + + if( $this->mode == ADD_ONTHEFLY ) + $this->sessionPrefix.= "_add"; + } + + /** + * Set template file + */ + public function setTemplateFile() + { + if( $this->mode == ADD_INLINE ) + $this->templatefile = GetTemplateName($this->shortTableName, "inline_add"); + + parent::setTemplateFile(); + } + + /** + * Get the page's fields list + * @return Array + */ + protected function getPageFields() + { + if( $this->mode == ADD_INLINE ) + { + if( $this->masterTable && !$this->inlineAddAvailable() && $this->masterPageType == PAGE_ADD ) // #12518 + { + return $this->pSet->getInlineAddFields(); + } + + return $this->pSet->getInlineAddFields(); + } + + return $this->pSet->getAddFields(); + } + + /** + * Process a broken request + */ + public static function handleBrokenRequest() + { + if( sizeof($_POST) != 0 || !postvalue('submit') ) + return; + + if( postvalue("inline") ) + { + $returnJSON = array(); + $returnJSON['success'] = false; + $returnJSON['message'] = "Error occurred"; + $returnJSON['fatalError'] = true; + echo printJSON($returnJSON); + exit(); + } + + if( postvalue("fly") ) + { + echo -1; + exit(); + } + + $_SESSION["message_add"] = "<< "."Error occurred"." >>"; + } + + /** + * Redirect after details saved + */ + public function redirectAfterAdd() + { + if( $_SESSION['after_add_data'] ) { + $aaData =& $_SESSION['after_add_data']; + } else { + $aaData = array(); + } + if( isset($aaData[ $this->afterAdd_id ]) && $aaData[ $this->afterAdd_id ] ) + { + $data = $aaData[ $this->afterAdd_id ]; + $this->keys = $data['keys']; + $this->newRecordData = $data['avalues']; + } + if( $this->eventsObject->exists("AfterAdd") && isset($aaData[ $this->afterAdd_id ]) && $aaData[ $this->afterAdd_id ] ) + { + $this->eventsObject->AfterAdd( $data['avalues'], $data['keys'], $data['inlineadd'], $this ); + + } + unset( $aaData[ $this->afterAdd_id ] ); + + foreach( $aaData as $k => $v) + { + if( !is_array($v) or !array_key_exists('time', $v) ) + { + unset( $aaData[ $k ] ); + continue; + } + + if( $v['time'] < time() - 3600 ) + unset($aaData[ $k ]); + } + $this->afterAddActionRedirect(); + } + + /** + * Process the page + */ + public function process() + { + if( strlen($this->afterAdd_id) ) + { + $this->redirectAfterAdd(); + return; + } + + // Before Process event + if( $this->eventsObject->exists("BeforeProcessAdd") ) + $this->eventsObject->BeforeProcessAdd( $this ); + + if( $this->action == "added" ) + { + // insert new record if we have to + $this->processDataInput(); + + $this->readAddValues = !$this->insertedSuccessfully; + + if( $this->mode != ADD_SIMPLE && $this->mode != ADD_DASHBOARD && $this->mode != ADD_MASTER_DASH ) + { + $this->reportSaveStatus(); + return; + } + + if( $this->insertedSuccessfully ) + { + // VBScript fix! don't &&-join these two conditions + if( $this->afterAddActionRedirect() ) + return; + } + } + + if( $this->captchaExists() ) + $this->displayCaptcha(); + + $this->prgReadMessage(); + + $this->prepareDefvalues(); + + if( $this->eventsObject->exists("ProcessValuesAdd") ) + $this->eventsObject->ProcessValuesAdd( $this->defvalues, $this ); + + $this->prepareReadonlyFields(); + $this->prepareEditControls(); + + $this->prepareButtons(); + $this->prepareSteps(); + $this->prepareDetailsTables(); + + // add button events if exist + if( $this->mode == ADD_SIMPLE || $this->mode == ADD_ONTHEFLY ) + $this->addButtonHandlers(); + + $this->addCommonJs(); + + $this->doCommonAssignments(); + $this->prepareBreadcrumbs(); + $this->prepareCollapseButton(); + + $this->displayAddPage(); + } + + /** + * Insert a new record to db + */ + protected function processDataInput() + { + if( $this->action != "added" ) + return; + + // CSRF protection + if( !isPostRequest() ) + return; + + $this->buildNewRecordData(); + + if( !$this->checkCaptcha() ) + return; + + if( !$this->recheckUserPermissions() ) + return; + + if( !$this->callBeforeAddEvent() ) + return; + + //add or set updated lat-lng values for all map fileds with 'UpdateLatLng' ticked + $this->setUpdatedLatLng( $this->newRecordData ); + + if( !$this->checkDeniedDuplicatedValues() ) + return; + + if( $this->callCustomAddEvent() ) + { + $insertResult = $this->dataSource->insertSingle( $this->getInsertDataCommand() ); + $this->insertedSuccessfully = $insertResult !== false; + + if( !$this->insertedSuccessfully ) + $this->setDatabaseError( $this->dataSource->lastError() ); + else + { + $this->newRecordData = $insertResult; + // set up keys + foreach( $this->pSet->getTableKeys() as $kf ) { + if( isset( $this->newRecordData[ $kf ] ) ) + $this->keys[ $kf ] = $this->newRecordData[ $kf ]; + } + + if ( count( $this->pSet->getTableKeys() ) != count( $this->keys ) ) + $this->keys = array(); + } + } + + if( !$this->insertedSuccessfully ) + return; + + if( $this->getAfterAddAction() == AA_TO_ADD ) + $_SESSION[ $this->sessionPrefix . "_recordAdded" ] = true; + + $this->ProcessFiles(); + + if( $this->auditObj ) + $this->auditObj->LogAdd( $this->tName, $this->newRecordData, $this->keys ); + + $this->callAfterSuccessfulSave(); + $this->callAfterAddEvent(); + + $this->messageType = MESSAGE_INFO; + $this->setSuccessfulUpdateMessage(); + } + + /** + * Fill newRecordData properties + */ + protected function buildNewRecordData() + { + $avalues = array(); + $blobfields = array(); + $afilename_values = array(); + + foreach($this->addFields as $f) + { + $control = $this->getControl( $f, $this->id ); + $control->readWebValue($avalues, $blobfields, NULL, NULL, $afilename_values); + } + + if( Security::advancedSecurityAvailable() ) { + $securityType = $this->pSet->getAdvancedSecurityType(); + if( !$this->isAdminTable() && ($securityType == ADVSECURITY_EDIT_OWN || $securityType == ADVSECURITY_VIEW_OWN) ) + { + $tableOwnerIdField = $this->pSet->getTableOwnerIdField(); + // insert owner id value if it exists an It hasn't already set by user + if( $this->checkIfToAddOwnerIdValue( $tableOwnerIdField, $avalues[ $tableOwnerIdField ] ) ) + $avalues[ $tableOwnerIdField ] = prepare_for_db( $tableOwnerIdField, $_SESSION["_".$this->tName."_OwnerID"] ); + } + } + $masterTables = $this->pSet->getMasterTablesArr( ); + // insert master key value if exists and if not specified + foreach( $masterTables as $mTableData ) + { + if( $this->masterTable == $mTableData["mDataSourceTable"] ) + { + foreach( $mTableData["detailKeys"] as $idx => $dk ) + { + $masterkeyIdx = "masterkey".($idx + 1); + if( strlen( postvalue($masterkeyIdx) ) ) + $_SESSION[ $this->sessionPrefix."_".$masterkeyIdx ] = postvalue($masterkeyIdx); + + if( !isset( $avalues[ $dk ] ) || $avalues[ $dk ] == "" ) + $avalues[ $dk ] = prepare_for_db( $dk, $_SESSION[ $this->sessionPrefix."_".$masterkeyIdx ] ); + } + } + } + + $this->addLookupFilterFieldValue( $avalues, $avalues ); + + foreach($afilename_values as $fileFName => $value) + { + $avalues[ $fileFName ] = $value; + } + + // calculate order for the reorderRows feature + $listPSet = $this->getListPSet(); + if( $listPSet->reorderRows() ) { + $order = postvalue("order"); + if( $order ) { + $order = $this->getUniqueOrder( $listPSet, $order ); + } else { + $order = $this->getMaxOrderValue( $listPSet ) + 1; + } + $avalues[ $listPSet->reorderRowsField() ] = $order; + } + + $this->newRecordData = $avalues; + } + + /** + * Add to the values array the data about lookup filter field + * if it hasn't been set yet + * @param Array recordData + * @param &Array values + */ + protected function addLookupFilterFieldValue( $recordData, &$values ) + { + $lookupPSet = getLookupMainTableSettings($this->tName, $this->lookupTable, $this->lookupField); + if( !$lookupPSet ) + return; + + if( $lookupPSet->useCategory( $this->lookupField ) ) + { + foreach( $lookupPSet->getParentFieldsData( $this->lookupField ) as $cData ) + { + if( isset( $this->parentCtrlsData[ $cData['main'] ]) && !isset( $recordData[ $cData['lookup'] ] ) ) + $values[ $cData['lookup'] ]= $this->parentCtrlsData[ $cData['main'] ]; + } + } + } + + /** + * Check is captcha exists on current page + * + * @intellisense + */ + function captchaExists() + { + if ( $this->mode == ADD_ONTHEFLY || $this->mode == ADD_INLINE ) + { + return false; + } + + return $this->pSet->hasCaptcha(); + } + + /** + * Get captcha field name + * + * @intellisense + */ + function getCaptchaFieldName() + { + return $this->captchaName; + } + + /** + * @return Boolean + */ + protected function recheckUserPermissions() + { + if( CheckTablePermissions($this->tName, "A") ) + return true; + + return parent::recheckUserPermissions(); + } + + /** + * Execute before Add event + * @return Boolean + */ + protected function callBeforeAddEvent() + { + if( !$this->eventsObject->exists("BeforeAdd") ) + return true; + + $this->sqlValues = array(); + $usermessage = ""; + $ret = $this->eventsObject->BeforeAdd( $this->newRecordData, $this->sqlValues, $usermessage, $this->mode == ADD_INLINE, $this ); + if( $usermessage != "" ) + $this->setMessage( $usermessage ); + + return $ret; + } + + /** + * Check if some values are duplicated for the fields not allowing duplicates + * @return Boolean + */ + public function checkDeniedDuplicatedValues() + { + $usermessage = ""; + $ret = $this->hasDeniedDuplicateValues( $this->newRecordData, $usermessage ); + if( $ret ) + $this->setMessage( $usermessage ); + + return !$ret; + } + + /** + * #7374 + * @return Boolean + */ + protected function callCustomAddEvent() + { + if( !$this->eventsObject->exists("CustomAdd") ) + return true; + + $keys = array(); + $customAddError = ""; + $ret = $this->eventsObject->CustomAdd( $this->newRecordData, $keys, $customAddError, $this->mode == ADD_INLINE, $this ); + + if( strlen( $customAddError ) > 0 ) + { + $this->insertedSuccessfully = false; + $this->setMessage( $customAddError ); + $this->keys = array(); + return false; + } + + // do standard Add processing + if( $ret ) + return true; + + $this->insertedSuccessfully = true; + + // update keys and inserted data + $keyFields = $this->pSet->getTableKeys(); + + if( !is_array( $keys ) && count( $keyFields ) == 1 ) + $keys = array( $keyFields[0] => $keys ); + + foreach( $keyFields as $kf ) { + if( strlen( $keys[ $kf ] ) ) + $this->keys[ $kf ] = $kf; + else if( array_key_exists( $kf, $this->newRecordData ) ) + $this->keys[ $kf ] = $this->newRecordData[ $kf ]; + else + $this->keys[ $kf ] = $this->dataSource->lastAutoincValue( $kf ); + + $this->newRecordData[ $kf ] = $this->keys[ $kf ]; + } + + return false; + } + + /** + * Give possibility to all edit controls to clean their data + */ + protected function callAfterSuccessfulSave() + { + foreach($this->addFields as $f) + { + $this->getControl( $f, $this->id )->afterSuccessfulSave(); + } + } + + /** + * Execute After Add event or prepare all necessary data for its execution after redirect + */ + protected function callAfterAddEvent() + { + if( !$this->eventsObject->exists("AfterAdd") ) + return; + + if( $this->mode != ADD_MASTER ) + { + $this->eventsObject->AfterAdd( $this->newRecordData, $this->keys, $this->mode == ADD_INLINE, $this ); + return; + } + + $this->afterAdd_id = generatePassword(20); + + if( !$_SESSION['after_add_data'] ) { + $_SESSION['after_add_data'] = array(); + } + $_SESSION['after_add_data'][ $this->afterAdd_id ] = array( + 'avalues' => $this->newRecordData, + 'keys'=> $this->keys, + 'inlineadd' => $this->mode == ADD_INLINE, + 'time' => time() + ); + } + + /** + * Set a successful update message. + * Add the corresponding edit/view links to the info message + */ + protected function setSuccessfulUpdateMessage() + { + if( $this->isMessageSet() ) + return; + + if( $this->mode == ADD_INLINE ) + $infoMessage = ""."Record was added".""; + else + $infoMessage = "<<< "."Record was added"." >>>"; + + if( $this->mode != ADD_SIMPLE && $this->mode != ADD_MASTER || !$this->keys ) + { + $this->setMessage( $infoMessage ); + return; + } + + $k = 0; + $keyParams = array(); + $keysArray = array(); + foreach( $this->keys as $idx => $val ) + { + $keyParams[] = "editid".( ++$k )."=".runner_htmlspecialchars(rawurlencode(@$val)); + $keysArray[] = $val; + } + $keylink = implode("&", $keyParams); + + if ( count($keysArray) > 0 && $this->mode == ADD_SIMPLE ) + { + $_SESSION["successKeys"] = $keysArray; + } + else + { + $infoMessage.= "
"; + + if( $this->editAvailable() ) + $infoMessage.= " "."Edit"." "; + + if( $this->viewAvailable() ) + $infoMessage.= " "."View"." "; + } + + $this->setMessage( $infoMessage ); + } + + /** + * Print JSON containing a saved record data on ajax-like request + */ + protected function reportSaveStatus() + { + echo printJSON( $this->getSaveStatusJSON() ); + exit(); + } + + /** + * Get an array containing the record save status + * @return Array + */ + protected function getSaveStatusJSON() + { + global $globalEvents; + $returnJSON = array(); + + if( $this->action != "added" || $this->mode == ADD_SIMPLE ) + return $returnJSON; + + $returnJSON['success'] = $this->insertedSuccessfully; + $returnJSON['message'] = $this->message; + + if( !$this->isCaptchaOk ) + { + $returnJSON['wrongCaptchaFieldName'] = $this->getCaptchaFieldName(); + } + elseif( $this->mode == ADD_POPUP || $this->mode == ADD_MASTER || $this->mode == ADD_MASTER_POPUP || $this->mode == ADD_MASTER_DASH ) + { + $sessPrefix = $this->tName . "_" . $this->pageType; + if( isset($_SESSION["count_passes_captcha"]) || $_SESSION["count_passes_captcha"] > 0 || $_SESSION["count_passes_captcha"] < 5 ) + $returnJSON['hideCaptcha'] = true; + } + + + if( !$this->insertedSuccessfully ) + return $returnJSON; + + $jsKeys = array(); + $keyFields = $this->pSet->getTableKeys(); + if ( $this->keys ) { + foreach( $keyFields as $idx => $f) { + $jsKeys[ $idx ] = $this->keys[ $f ]; + } + } + + if( $this->mode == ADD_ONTHEFLY ) + { + $lokupData = $this->getLookupData(); + $returnJSON['linkValue'] = $lokupData['linkValue']; + $returnJSON['displayValue'] = $lokupData['displayValue']; + $returnJSON['vals'] = $lokupData['vals']; + + $returnJSON['keys'] = $jsKeys; + $returnJSON['keyFields'] = $keyFields; + + return $returnJSON; + } + + // get current values and show edit controls + $data = array(); + $haveData = true; + + if( $this->keys ) + $data = $this->getRecordData( $this->keys ); + + if( !$data ) + { + $data = $this->newRecordData; + $haveData = false; + } + + $keyParams = array(); + foreach( $this->pSet->getTableKeys() as $i => $kf ) { + $keyParams[] = "key".($i + 1). "=". runner_htmlspecialchars( rawurlencode( @$data[ $kf ] )); + } + $keylink = "&" . implode("&", $keyParams); + + $showValues = array(); + $showFields = array(); + $showRawValues = array(); + + $listPSet = $this->getListPSet(); + + $listViewControls = new ViewControlsContainer( + $listPSet, + $this->pageType, + $this + ); + + foreach( $this->pSet->getFieldsList() as $f ) + { + $control = $listViewControls->getControl( $f ); + $showValues[ $f ] = $control->showDBValue( $data, $keylink, true ); + $showFields[] = $f; + + if( IsBinaryType( $this->pSet->getFieldType( $f ) ) ) + $showRawValues[ $f ] = ""; + else + $showRawValues[ $f ] = runner_substr($data[ $f ], 0, 100); + } + + // reorderRows stuff + if( $listPSet->reorderRows() ) { + $returnJSON['order'] = $data[ $listPSet->reorderRowsField() ]; + } + + $returnJSON['keys'] = $jsKeys; + $returnJSON['vals'] = $showValues; + $returnJSON['fields'] = $showFields; + + $returnJSON['detKeys'] = $this->getShowDetailKeys( $data ); + + $dmapIconsData = $this->getDashMapsIconsData( $data ); + if( !!$dmapIconsData ) + $returnJSON['mapIconsData'] = $dmapIconsData; + + $fieldsIconsData = $this->getFieldMapIconsData( $data ); + if( !!$fieldsIconsData ) + $returnJSON['fieldsMapIconsData'] = $fieldsIconsData; + + //$isEditable = Security::userCan('E', $this->tName) || Security::userCan('D', $this->tName); + $isEditable = true; + if( $globalEvents->exists("IsRecordEditable", $this->tName) ) { + $isEditable = $globalEvents->IsRecordEditable( $data, $isEditable, $this->tName ); + } + + if( $this->forSpreadsheetGrid ) { + if( $haveData && $isEditable ) { + // new added grid row id + $newRowId = $this->newRowId ? $this->newRowId : $this->id; + $editPage = $this->getRelatedInlineEditPage( $this->hostPageName, $this->keys, $newRowId ); + + $returnJSON["editFields"] = $listPSet->getInlineEditFields(); + + // use "htmlControls" key no to interfire with dash html data + $returnJSON["htmlControls"] = array(); + foreach( $listPSet->getInlineEditFields() as $fName ) { + $controls = $editPage->getContolMapData( $fName, $newRowId, $data, $editPage->editFields ); + // set edit page controlsMap + $editPage->fillControlsMap( $controls ); + + if( $editPage->getEditFormat( $fName ) == EDIT_FORMAT_READONLY ) + $editPage->readOnlyFields[ $fName ] = $this->showDBValue( $fName, $data ); + + $returnJSON["htmlControls"][ $fName ] = $editPage->getSpreadsheetControlMarkup( $fName, $newRowId, $data ); + } + + $returnJSON["pageId"] = $newRowId; + + $editPage->fillSetCntrlMaps(); + // contols map for spreadsheet inline edit controls + $returnJSON["spreadControlsMap"] = $editPage->controlsHTMLMap; + } else { + $returnJSON['nonEditable'] = true; + } + } + + + if( $this->mode == ADD_INLINE || $this->mode == ADD_POPUP || $this->mode == ADD_DASHBOARD ) { + $returnJSON['noKeys'] = !$haveData; + $returnJSON['keyFields'] = $keyFields; + $returnJSON['rawVals'] = $showRawValues; + $returnJSON['hrefs'] = $this->buildDetailGridLinks( $returnJSON['detKeys'] ); + // add link and display value if list page is lookup with search + if( $this->forListPageLookup ) + { + $linkAndDispVals = $this->getLookupData(); + $returnJSON['linkValue'] = $linkAndDispVals['linkValue']; + $returnJSON['displayValue'] = $linkAndDispVals['displayValue']; + } + if( $globalEvents->exists("IsRecordEditable", $this->tName) ) { + if( !$isEditable ) + $returnJSON['nonEditable'] = true; + } + + return $returnJSON; + } + + if( $this->mode == ADD_MASTER || $this->mode == ADD_MASTER_POPUP || $this->mode == ADD_MASTER_DASH ) + { + $_SESSION["message_add"] = $this->message ? $this->message : ""; + $returnJSON['afterAddId'] = $this->afterAdd_id; + $tData = array(); + $returnJSON['mKeys'] = $this->getDetailTablesMasterKeys( $tData ); + + if( $this->mode == ADD_MASTER_POPUP || $this->mode == ADD_MASTER_DASH ) + { + $returnJSON['noKeys'] = !$haveData; + $returnJSON['keyFields'] = $keyFields; + $returnJSON['rawVals'] = $showRawValues; + $returnJSON['hrefs'] = $this->buildDetailGridLinks( $returnJSON['detKeys'] ); + + if( $globalEvents->exists("IsRecordEditable", $this->tName) ) { + if( !$isEditable ) + $returnJSON['nonEditable'] = true; + } + } + + return $returnJSON; + } + } + + /** + * @param &Array data + * @return Array + */ + protected function getShowDetailKeys( &$data ) + { + $showDetailKeys = array(); + foreach( $this->pSet->getDetailTablesArr() as $dt ) + { + foreach( $dt["masterKeys"] as $idx => $dk) + { + $showDetailKeys[ $dt['dDataSourceTable'] ][ "masterkey".($idx + 1) ] = $data[ $dk ]; + } + } + + if( $this->getAfterAddAction() == AA_TO_DETAIL_ADD ) + { + $AAdTName = $this->pSet->getAADetailTable(); + $dTUrl = GetTableUrl( $AAdTName ); + + if( !isset( $showDetailKeys[ $dTUrl ] ) ) + $showDetailKeys[ $dTUrl ] = $showDetailKeys[ $AAdTName ]; + } + + return $showDetailKeys; + } + + /** + * @return Array + */ + protected function getDetailTablesMasterKeys( $data ) + { + if( !$this->isShowDetailTables || $this->mobileTemplateMode() ) + return array(); + + $data = $this->newRecordData; + if( $this->keys ) + $data = $this->getRecordData( $this->keys ) ; + + $dpParams = $this->getDetailsParams( $this->id ); + $mKeysData = array(); + for( $i = 0; $i < count( $dpParams['ids'] ); $i++ ) { + $mKeysData[ $dpParams['strTableNames'][$i] ] = $this->getMasterKeysData( $dpParams['strTableNames'][$i], $data); + } + + return $mKeysData; + } + + /** + * @param String dTableName + * @param &Array data + */ + protected function getMasterKeysData( $dTableName, &$data ) + { + $mKeyId = 1; + $mKeysData = array(); + + $mKeys = $this->pSet->getMasterKeysByDetailTable( $dTableName ); + foreach($mKeys as $mk) + { + if( strlen( $data[ $mk ] ) ) + $mKeysData[ 'masterkey'.$mKeyId++ ] = $data[ $mk ]; + else + $mKeysData[ 'masterkey'.$mKeyId++ ] = ''; + } + + return $mKeysData; + } + + /** + * It redirects to a new page + * according to the add page settings + * @return Boolean + */ + protected function afterAddActionRedirect() + { + if( $this->mode != ADD_SIMPLE ) + return false; + + switch( $this->getAfterAddAction() ) + { + case AA_TO_ADD: + if ( $this->insertedSuccessfully ) + return $this->prgRedirect(); + + $getParams = array(); + if( $this->pageName ) + $getParams[] = "page=".$this->pageName; + $getParams[] = $this->getStateUrlParams(); + HeaderRedirect($this->shortTableName, PAGE_ADD, implode( '&', $getParams )); + return true; + + case AA_TO_LIST: + if( $this->pSet->hasListPage() ) { + HeaderRedirect( $this->shortTableName, PAGE_LIST, "a=return&" + .( $this->listPage ? "page=".$this->listPage."&" : "" ).$this->getStateUrlParams() ); + } else { + HeaderRedirect("menu"); + } + return true; + + case AA_TO_VIEW: + HeaderRedirect( $this->shortTableName, PAGE_VIEW, implode( '&', array( $this->getKeyParams(), $this->getStateUrlParams() ) ) ); + return true; + + case AA_TO_EDIT: + HeaderRedirect( $this->shortTableName, PAGE_EDIT, implode( '&', array( $this->getKeyParams(), $this->getStateUrlParams() ) ) ); + return true; + + case AA_TO_DETAIL_LIST: + $dTName = $this->pSet->getAADetailTable(); + HeaderRedirect( GetTableURL( $dTName ), PAGE_LIST, implode("&", $this->getNewRecordMasterKeys( $dTName ) ). "&mastertable=" .$this->tName ); + return true; + + case AA_TO_DETAIL_ADD: + $_SESSION["message_add"] = $this->message ? $this->message : ""; + + $dTName = $this->pSet->getAADetailTable(); + HeaderRedirect( GetTableURL( $dTName ), PAGE_ADD, implode("&", $this->getNewRecordMasterKeys( $dTName ) ). "&mastertable=" .$this->tName ); + return true; + + default: + return false; + } + } + + function getNewRecordMasterKeys( $dTName ) + { + $data = $this->getNewRecordData(); + + $mKeys = array(); + foreach($this->pSet->getMasterKeysByDetailTable( $dTName ) as $i => $mk) + { + $mKeys[] = "masterkey". ($i + 1) . "=" .$data[ $mk ]; + } + return $mKeys; + } + + + /** + * POST-REDIRECT-GET + * Redirect after saving the data to avoid saving again on refresh. + */ + protected function prgRedirect() + { + if( $this->stopPRG ) + return false; + if( !$this->insertedSuccessfully || $this->mode != ADD_SIMPLE || !no_output_done() ) + return false; + // saving message + $_SESSION["message_add"] = $this->message ? $this->message : ""; + $_SESSION["message_add_type"] = $this->messageType; + // redirect + + + $getParams = array(); + if( $this->pageName ) + $getParams[] = "page=".$this->pageName; + + $getParams[] = $this->getStateUrlParams(); + + HeaderRedirect( $this->pSet->getShortTableName(), $this->pageType, implode( '&', $getParams ) ); + // turned on output buffering, so we need to stop script + return true; + } + + /** + * POST-REDIRECT-GET + * Read the saved message on the GET step. + */ + protected function prgReadMessage() + { + // for PRG rule, to avoid POSTDATA resend. Saving mess in session + if( $this->mode == ADD_SIMPLE && isset( $_SESSION["message_add"] ) ) + { + $this->message = $_SESSION["message_add"]; + $this->messageType = $_SESSION["message_add_type"]; + unset( $_SESSION["message_add"] ); + } + } + + /** + * @return Array + */ + public function getCurrentRecord() + { + $data = array(); + if ( $this->masterTable && !!$this->masterKeysReq ) + { + foreach ($this->detailKeysByM as $key => $detKey ) + { + $data[$detKey] = $this->masterKeysReq[$key+1]; + } + } + + return $data; + } + + protected function replaceFileFieldsValuesWithCopies( &$defvalues ) { + foreach( $this->addFields as $f ) { + if( $this->pSet->getEditFormat( $f ) == EDIT_FORMAT_FILE ) //#10023 + $defvalues[ $f ] = $this->getControl( $f, $this->id )->getFieldValueCopy( $defvalues[ $f ] ); + } + } + + protected function getCopyKeys() { + $copyKeys = array(); + + if( !array_key_exists( "copyid1", $_REQUEST ) && !array_key_exists( "editid1", $_REQUEST ) ) + return $copyKeys; + + $prefix = array_key_exists( "copyid1", $_REQUEST ) ? "copyid" : "editid"; + foreach( $this->pSet->getTableKeys() as $idx => $k ) { + $copyKeys[ $k ] = postvalue( $prefix . ($idx + 1) ); + } + + return $copyKeys; + } + + /** + * Set the defvalues property + */ + protected function prepareDefvalues() + { + $copyKeys = $this->getCopyKeys(); + + if( $copyKeys && $this->mode != ADD_DASHBOARD ) + { + // copy record + $dc = $this->getDsCommand( $copyKeys ); + $prep = $this->dataSource->prepareSQL( $dc ); + $keyWhere = $prep["where"]; + + $fetchedArray = $this->dataSource->getSingle( $dc )->fetchAssoc(); + $this->defvalues = $this->cipherer->DecryptFetchedArray( $fetchedArray ); + + $this->replaceFileFieldsValuesWithCopies( $this->defvalues ); + + if( $this->eventsObject->exists("CopyOnLoad") ) { + // call CopyOnLoad event + $this->eventsObject->CopyOnLoad( $this->defvalues, $keyWhere, $this ); + + if( $keyWhere != $prep["where"] ) { + $this->dataSource->overrideWhere( $dc, $keyWhere ); + $fetchedArray = $this->dataSource->getSingle( $dc )->fetchAssoc(); + $this->defvalues = $this->cipherer->DecryptFetchedArray( $fetchedArray ); + + $this->replaceFileFieldsValuesWithCopies( $this->defvalues ); + } + } + } + else + { + foreach( $this->addFields as $f ) + { + $defaultValue = GetDefaultValue($f, PAGE_ADD, $this->tName ); + if( strlen($defaultValue) ) + $this->defvalues[ $f ] = $defaultValue; + } + } + + if( Security::advancedSecurityAvailable() ) { + $securityType = $this->pSet->getAdvancedSecurityType(); + if( !$this->isAdminTable() && ($securityType == ADVSECURITY_EDIT_OWN || $securityType == ADVSECURITY_VIEW_OWN) ) + { + $tableOwnerIdField = $this->pSet->getTableOwnerIdField(); + // insert default owner id value if exists + if( $this->checkIfToAddOwnerIdValue( $tableOwnerIdField, '' ) ) + $this->defvalues[ $tableOwnerIdField ] = prepare_for_db( $tableOwnerIdField, $_SESSION["_".$this->tName."_OwnerID"] ); + } + } + + $masterTables = $this->pSet->getMasterTablesArr(); + // set default values for the foreign keys + foreach( $masterTables as $mTableData ) + { + if( $this->masterTable == $mTableData["mDataSourceTable"] ) + { + foreach( $mTableData["detailKeys"] as $idx => $dk ) + { + $masterkeyIdx = "masterkey".($idx + 1); + if( strlen( postvalue($masterkeyIdx) ) ) + $_SESSION[ $this->sessionPrefix."_".$masterkeyIdx ] = postvalue($masterkeyIdx); + + if( $this->masterPageType != PAGE_ADD ) + $this->defvalues[ $dk ] = @$_SESSION[ $this->sessionPrefix."_".$masterkeyIdx ]; + } + } + } + + $this->addLookupFilterFieldValue( $this->newRecordData, $this->defvalues ); + + if( $this->readAddValues ) + { + foreach( $this->addFields as $fName ) + { + $editFormat = $this->pSet->getEditFormat($fName); + if( $editFormat != EDIT_FORMAT_DATABASE_FILE && $editFormat != EDIT_FORMAT_DATABASE_IMAGE && $editFormat != EDIT_FORMAT_FILE ) + $this->defvalues[ $fName ] = @$this->newRecordData[ $fName ]; + } + } + } + + /** + * Set read-only fields + */ + protected function prepareReadonlyFields() + { + foreach( $this->addFields as $f ) + { + if( $this->pSet->getEditFormat( $f ) == EDIT_FORMAT_READONLY ) + $this->readOnlyFields[ $f ] = $this->showDBValue($f, $this->defvalues); + } + } + + /** + * Assign buttons xt variables + */ + protected function prepareButtons() + { + if( $this->mode == ADD_INLINE ) + return; + + $this->xt->assign("save_button", true); + + $addStyle = ""; + if ( $this->isMultistepped() ) + { + $addStyle = " style=\"display: none;\""; + } + + // legacy assignment used in the Invoice template + $this->xt->assign("savebutton_attrs", "id=\"saveButton".$this->id."\"" . $addStyle ); + + if( $this->mode == ADD_DASHBOARD ) + { + $this->xt->assign("reset_button", true); + return; + } + + if( $this->mode != ADD_ONTHEFLY + && $this->mode != ADD_POPUP + && $this->mode != ADD_MASTER_DASH ) + { + // add was successful + if( isset( $_SESSION["successKeys"] ) ) + $this->xt->assign("message_back_button", true); + if( $this->pSet->hasListPage() ) + $this->xt->assign("back_button", true); + else if( $this->isShowMenu() ) + $this->xt->assign("backToMenu_button", true); + } + else + $this->xt->assign("cancel_button", true); + + if( $this->mode == ADD_SIMPLE ) + { + // back to list/menu buttons + if( $this->pSet->hasListPage() ) + { + $this->xt->assign("backbutton_attrs", "id=\"backButton".$this->id."\""); + } + else if( $this->isShowMenu() ) + { + $this->xt->assign("backbutton_attrs", "id=\"backToMenuButton".$this->id."\""); + } + } + + if ( isset($_SESSION["successKeys"]) ) + { + $keysArray = $_SESSION["successKeys"]; + $dataKeysAttr = 'data-keys="'.runner_htmlspecialchars( my_json_encode($keysArray) ).'"'; + unset($_SESSION["successKeys"]); + + if( $this->viewAvailable() && $keysArray ) + { + $this->xt->assign("view_page_button", true); + $this->xt->assign("view_page_button_attrs", 'id="viewPageButton'.$this->id.'" '.$dataKeysAttr); + } + + if( $this->editAvailable() && $keysArray ) + { + $this->xt->assign("edit_page_button", true); + $this->xt->assign("edit_page_button_attrs", 'id="editPageButton'.$this->id.'" '.$dataKeysAttr); + } + } + } + + /** + * Prepare edit controls + */ + protected function prepareEditControls() + { + $controlFields = $this->addFields; + + if( $this->mode == ADD_INLINE ) { //#9069 + $controlFields = $this->removeHiddenColumnsFromInlineFields( + $controlFields, + $this->screenWidth, + $this->screenHeight, + $this->orientation + ); + } + + foreach( $controlFields as $fName ) { + $isDetKeyField = in_array( $fName, $this->detailKeysByM ); + if( $isDetKeyField ) { + // to the ReadOnly control show the detail key control's value + $this->readOnlyFields[ $fName ] = $this->showDBValue( $fName, $this->defvalues ); + } + + $firstElementId = $this->getControl( $fName, $this->id )->getFirstElementId(); + if( $firstElementId ) + $this->xt->assign( "labelfor_" . GoodFieldName( $fName ), $firstElementId ); + + $parameters = $this->getEditContolParams( $fName, $this->id, $this->defvalues ); + $this->xt->assign_function( GoodFieldName( $fName )."_editcontrol", "xt_buildeditcontrol", $parameters ); + + $controls = $this->getContolMapData( $fName, $this->id, $this->defvalues, $controlFields ); + if ( in_array( $fName, $this->errorFields ) ) + $controls["controls"]["isInvalid"] = true; + + $this->fillControlsMap( $controls ); + $this->fillControlFlags( $fName ); + + // fill special settings for a time picker + if( $this->pSet->getEditFormat($fName) == "Time" ) + $this->fillTimePickSettings( $fName, @$this->defvalues[ $fName ] ); + } + } + + public function getContolMapData( $fName, $recId, &$data, $pageFields ) { + $controls = array(); + $controls["controls"] = array(); + $controls["controls"]["id"] = $recId; + $controls["controls"]["ctrlInd"] = 0; + $controls["controls"]["fieldName"] = $fName; + + //if richEditor for field + if( $this->pSet->isUseRTE( $fName ) ) + $controls["controls"]["mode"] = "add"; + else + $controls["controls"]["mode"] = $this->mode == ADD_INLINE ? "inline_add" : "add"; + + $isDetKeyField = in_array( $fName, $this->detailKeysByM ); + if( $isDetKeyField ) + $controls["controls"]["value"] = $data[ $fName ]; + + $preload = $this->fillPreload( $fName, $pageFields, $data ); + if( $preload !== false ) { + $controls["controls"]["preloadData"] = $preload; + if( !$data[ $fName ] && $preload["vals"] ) + $data[ $fName ] = $preload["vals"][0]; + } + + return $controls; + } + + /** + * + */ + public function getEditContolParams( $fName, $recId, &$data ) { + $parameters = array(); + $parameters["id"] = $recId; + $parameters["ptype"] = PAGE_ADD; + $parameters["field"] = $fName; + $parameters["value"] = $data[ $fName ]; + $parameters["pageObj"] = $this; + + if( $this->getEditFormat( $fName ) !== EDIT_FORMAT_READONLY ) { + $parameters["validate"] = $this->pSet->getValidation( $fName ); + + if( $this->pSet->isUseRTE($fName) ) + $_SESSION[ $this->sessionPrefix."_".$fName."_rte" ] = $data[ $fName ]; + } + + //if richEditor for field + if( $this->pSet->isUseRTE( $fName ) ) + $parameters["mode"] = "add"; + else + $parameters["mode"] = $this->mode == ADD_INLINE ? "inline_add" : "add"; + + return $parameters; + } + + public function getEditFormat( $field, $pSet = null ) { + $isDetKeyField = in_array( $field, $this->detailKeysByM ); + if( $isDetKeyField ) { + return EDIT_FORMAT_READONLY; + } + return parent::getEditFormat( $field, $pSet ); + } + + + /** + * Set details preview on the add master page + */ + protected function prepareDetailsTables() + { + if( !$this->isShowDetailTables + || $this->mode != ADD_SIMPLE && $this->mode != ADD_POPUP && $this->mode != ADD_DASHBOARD && $this->mode != ADD_MASTER_DASH + || $this->mobileTemplateMode() ) + { + return; + } + + $dpParams = $this->getDetailsParams( $this->id ); + + $this->jsSettings['tableSettings'][ $this->tName ]['isShowDetails'] = !!$dpParams; + $this->jsSettings['tableSettings'][ $this->tName ]['dpParams'] = array('tableNames' => $dpParams['strTableNames'], 'ids' => $dpParams['ids']); + + if( !$dpParams['ids'] ) + return; + + $this->xt->assign("detail_tables", true); + + for($d = 0; $d < count($dpParams['ids']); $d++) + { + $this->setDetailPreview( "list", $dpParams['strTableNames'][ $d ], $dpParams['ids'][ $d ], $this->defvalues ); + $this->displayDetailsButtons( $dpParams['type'][ $d ], $dpParams['strTableNames'][ $d ], $dpParams['ids'][ $d ] ); + } + } + + /** + * + */ + protected function displayDetailsButtons( $dpType, $dpTableName, $dpId ) + { + if ( !CheckTablePermissions($dpTableName, "S") ) + return; + + $listPageObject = $this->getDetailsPageObject( $dpTableName, $dpId ); + $listPageObject->assignButtonsOnMasterEdit( $this->xt ); + } + + /** + * Assign basic page's xt variables + */ + protected function doCommonAssignments() + { + if ( $this->mode === ADD_SIMPLE ) + { + $this->headerCommonAssign(); + } + else + { + $this->xt->assign("menu_chiddenattr", "data-hidden" ); + } + + $this->setLangParams(); + + $this->xt->assign("message_block", true); + + if( $this->isMessageSet() ) + { + $this->xt->assign("message", $this->message ); + $this->xt->assign("message_class", $this->messageType == MESSAGE_ERROR ? "alert alert-danger" : "alert alert-success" ); + } + else + { + $this->hideElement("message"); + } + + if( $this->mode != ADD_INLINE ) + $this->assignAddFieldsBlocksAndLabels(); + + if( $this->mode == ADD_SIMPLE ) + { + $this->assignBody(); + $this->xt->assign("flybody", true); + } + + if( $this->mode == ADD_ONTHEFLY + /*|| $this->mode == ADD_MASTER*/ + || $this->mode == ADD_POPUP + || $this->mode == ADD_DASHBOARD + || $this->mode == ADD_MASTER_DASH ) + { + $this->xt->assign("body", true); + $this->xt->assign("footer", false); + $this->xt->assign("header", false); + $this->xt->assign("flybody", $this->body); + } + } + + /** + * Assign add fields' blocks and labels variables + */ + public function assignAddFieldsBlocksAndLabels() + { + foreach($this->addFields as $fName) + { + $gfName = GoodFieldName($fName); + + $this->xt->assign($gfName."_fieldblock", true); + $this->xt->assign($gfName."_tabfieldblock", true); + } + } + + /** + * Display the add page basing on its mode + */ + protected function displayAddPage() + { + $templatefile = $this->templatefile; + + if( $this->eventsObject->exists("BeforeShowAdd") ) + $this->eventsObject->BeforeShowAdd($this->xt, $templatefile, $this); + + if( $this->mode != ADD_INLINE && $this->mode != ADD_ONTHEFLY ) + $this->displayMasterTableInfo(); + // invoked after displayMasterTableInfo to add master viewcontrols maps + $this->fillSetCntrlMaps(); + + if( $this->mode == ADD_SIMPLE /*|| $this->mode ==ADD_MASTER */) + { + $this->display( $templatefile ); + return; + } + + if( $this->mode == ADD_ONTHEFLY || $this->mode == ADD_POPUP || $this->mode == ADD_DASHBOARD || $this->mode == ADD_MASTER_DASH ) + { + $this->displayAJAX( $templatefile, $this->flyId + 1 ); + exit(); + } + + if( $this->mode == ADD_INLINE ) + { + $returnJSON = array(); + + $this->xt->load_template( $templatefile ); + + $returnJSON["htmlControls"] = array(); + foreach( $this->addFields as $fName ) { + $returnJSON["htmlControls"][ $fName ] = $this->xt->fetchVar( GoodFieldName($fName)."_editcontrol" ); + } + + $listPSet = $this->getListPSet(); + if( $listPSet->reorderRows() ) { + // provisional order value, to be adjusted at the time of saving + $returnJSON['order'] = $this->getMaxOrderValue( $listPSet ) + 1; + } + + + global $pagesData; + $returnJSON["pagesData"] = $pagesData; + + $returnJSON['settings'] = $this->jsSettings; + $returnJSON['controlsMap'] = $this->controlsHTMLMap; + $returnJSON['viewControlsMap'] = $this->viewControlsHTMLMap; + + $returnJSON["additionalJS"] = $this->grabAllJsFiles(); + $returnJSON["additionalCSS"] = $this->grabAllCSSFiles(); + + echo printJSON($returnJSON); + exit(); + } + } + + /** + * Get extra JSON params to display the page on AJAX-like request + * @return Array + */ + protected function getExtraAjaxPageParams() + { + return $this->getSaveStatusJSON(); + } + + /** + * Return link and display field values after Add on the fly + * @return array or false + * "link" => + * "display" => + */ + protected function getNewLookupValues( $lookupPSet ) + { + $linkFieldName = $lookupPSet->getLinkField( $this->lookupField ); + $dispFieldName = $lookupPSet->getDisplayField( $this->lookupField ); + if( $this->keys ) { + $dc = new DsCommand(); + $dc->keys = $this->keys; + + if( $lookupPSet->getCustomDisplay( $this->lookupField ) ) { + $customField = new DsFieldData( $dispFieldName, generateAlias(), "" ); + $dispFieldName = $customField->alias; + $dc->extraColumns[] = $customField; + } + $data = $this->cipherer->DecryptFetchedArray( $this->dataSource->getSingle( $dc )->fetchAssoc() ); + } + if( !$data ) { + $data = $this->newRecordData; + } + return array( + "link" => $data[ $linkFieldName ], + "display" => $data[ $dispFieldName ] + ); + } + + /** + * Get lookup data from a record added + * in 'add value On the Fly' mode + * or in Inline Add mode on List page with search. + * @return Array + */ + public function getLookupData() { + // get Project Settings object for $this->lookupTable + $lookupPSet = getLookupMainTableSettings( $this->tName, $this->lookupTable, $this->lookupField, $this->lookupPageType ); + if( !$lookupPSet ) + return array(); + + $lvals = $this->getNewLookupValues( $lookupPSet ); + if( !$lvals ) + return array(); + + $linkField = $lookupPSet->getLinkField( $this->lookupField ); + $dispfield = $lookupPSet->getDisplayField( $this->lookupField ); + + $respData = array( + $linkField => $lvals["link"], + $dispfield => $lvals["display"] + ); + + // format DATE or TIME value + if( in_array( $lookupPSet->getViewFormat( $this->lookupField ), array(FORMAT_DATE_SHORT, FORMAT_DATE_LONG, FORMAT_DATE_TIME) ) ) { + $viewContainer = new ViewControlsContainer( $lookupPSet, PAGE_LIST, null ); + + $ctrlData = array(); + $ctrlData[ $this->lookupField ] = $respData[ $linkField ]; + + $respData[ $dispfield ] = $viewContainer->getControl( $this->lookupField )->getTextValue( $ctrlData ); + } + + return array( + 'linkValue' => $respData[ $linkField ], + 'displayValue' => $respData[ $dispfield ], + 'vals' => $respData + ); + } + + /** + * Check if to add session owner id value + * @param String ownerField + * @param String currentValue + * @return Boolean + */ + public function checkIfToAddOwnerIdValue( $ownerField, $currentValue ) + { + return originalTableField( $ownerField, $this->pSet ) // legacy + && !$this->isAutoincPrimaryKey( $ownerField ) + && ( !CheckTablePermissions($this->tName, 'M') || !strlen($currentValue) ); + } + + /** + * Check if field is auto-incremented primary key + * @param String field + * @return Boolean + */ + protected function isAutoincPrimaryKey( $field ) + { + $keyFields = $this->pSet->getTableKeys(); + return count($keyFields) == 1 && in_array($field, $keyFields) && $this->pSet->isAutoincField( $field ); + } + + /** + * Check if the page's message is set + * @return Boolean + */ + protected function isMessageSet() + { + return strlen( $this->message ) > 0; + } + + /** + * Set a database error message + * @param String message + */ + public function setDatabaseError( $message ) + { + if( $this->mode != ADD_INLINE ) + { + $this->message = "<<< "."Record was NOT added"." >>>

".$message; + } + else + { + $this->message = "Record was NOT added".". ".$message; + } + + $this->messageType = MESSAGE_ERROR; + } + + /** + * @return Array + */ + public function getNewRecordData() + { + return $this->newRecordData; + } + + + /** + * @param String fName + * @return Boolean + */ + protected function checkFieldOnPage( $fName ) + { + if( $this->mode == ADD_INLINE ) + return $this->pSet->appearOnInlineAdd( $fName ); + + return $this->pSet->appearOnAddPage( $fName ); + } + + /** + * @param String table + */ + public static function processAddPageSecurity( $table ) + { + // user has necessary permissions + if( Security::checkPagePermissions( $table, "A" ) ) + return true; + + // display entered data. Give the user chance to relogin. Do nothing for now. + if( postvalue("a") == "added" ) + return true; + + // page can not be displayed. Redirect or return error + + // return error if the page is requested by AJAX + $pageMode = AddPage::readAddModeFromRequest(); + if( $pageMode != ADD_SIMPLE ) + { + Security::sendPermissionError(); + return false; + } + + // The user is logged in but lacks necessary permissions + // redirect to List page or Menu. + if( isLogged() && !Security::isGuest() ) + { + Security::redirectToList( $table ); + return false; + } + + redirectToLogin(); + return false; + } + + public static function readAddModeFromRequest() + { + $editType = postvalue("editType"); + + if( $editType == "inline" ) + return ADD_INLINE; + elseif( $editType == ADD_POPUP ) + return ADD_POPUP; + elseif( $editType == ADD_MASTER ) + return ADD_MASTER; + elseif( $editType == ADD_MASTER_POPUP ) + return ADD_MASTER_POPUP; + elseif( $editType == ADD_MASTER_DASH ) + return ADD_MASTER_DASH; + elseif( $editType == ADD_ONTHEFLY ) + return ADD_ONTHEFLY; + elseif( postvalue("mode") == "dashrecord" ) + return ADD_DASHBOARD; + else + return ADD_SIMPLE; + } + + function editAvailable() { + return !$this->dashElementData && parent::editAvailable(); + } + + function viewAvailable() { + return !$this->dashElementData && parent::viewAvailable(); + } + + /** + * API + */ + public function setMessageType( $type ) + { + $this->messageType = $type; + } + + function element2Item( $name ) { + if( $name == "message" ) { + return array( "add_message" ); + } + return parent::element2Item( $name ); + } + + protected function checkShowBreadcrumbs() + { + return $this->mode == ADD_SIMPLE; + } + + function createProjectSettings() { + $this->pSet = new ProjectSettings($this->tName, $this->pageType, $this->pageName, $this->pageTable ); + + if( $this->mode != ADD_INLINE && $this->pSet->getPageType() !== PAGE_ADD ) + { + $this->pSet = new ProjectSettings($this->tName, $this->pageType, null, $this->pageTable ); + } + + if( $this->mode == ADD_POPUP && $this->action == "added" ) { + $this->pSet->setPageType( "list" ); + } + } + + + public function getInsertDataCommand() { + $dc = new DsCommand(); + $dc->values = &$this->newRecordData; + + $dc->advValues = array(); + foreach( $this->sqlValues as $field => $sqlValue ) { + $dc->advValues[ $field ] = new DsOperand( dsotSQL, $sqlValue ); + } + return $dc; + } + + public function getSecurityCondition() { + return Security::SelectCondition( "S", $this->pSet ); + } + + protected function getRecordData( $keys ) { + $dc = $this->getDsCommand( $keys ); + + $fetchedArray = $this->dataSource->getSingle( $dc )->fetchAssoc(); + return $this->cipherer->DecryptFetchedArray( $fetchedArray ); + } + + protected function getDsCommand( $keys ) { + $dc = new DsCommand(); + $dc->keys = $keys; + $dc->filter = $this->getSecurityCondition(); + + return $dc; + } + + protected function getListPSet() { + if( !$this->listPagePSet ) { + $this->listPagePSet = new ProjectSettings( $this->tName, PAGE_LIST, $this->hostPageName, $this->pageTable ); + } + return $this->listPagePSet; + } +} +?> \ No newline at end of file diff --git a/php/classes/advancedsearchcontrol.php b/php/classes/advancedsearchcontrol.php new file mode 100644 index 0000000000000000000000000000000000000000..8a55d2f1794509ff34ad2b7eceb9afea1d95fb6b --- /dev/null +++ b/php/classes/advancedsearchcontrol.php @@ -0,0 +1,29 @@ +getSrchPanelAttrs['ctrlTypeComboStatus'] = true; + } + + function getCtrlSearchTypeOptions($fName, $selOpt, $not, $flexible = false, $both = false) + { + if( $this->pageObj->isBootstrap() ) + { + if( !$flexible && ($selOpt == EMPTY_SEARCH || $selOpt == NOT_EMPTY) ) + return $this->getControl($fName)->buildSearchOptions(array(EMPTY_SEARCH, NOT_EMPTY), $selOpt, $not, true); + + return $this->getControl($fName)->getSearchOptions($selOpt, $not, true); + } + + $withNot = $both ? $not : false; + return parent::getCtrlSearchTypeOptions($fName, $selOpt, $withNot, false, $both); + } +} +?> \ No newline at end of file diff --git a/php/classes/base32.php b/php/classes/base32.php new file mode 100644 index 0000000000000000000000000000000000000000..0ace316097e41a168c7ec6d6517771c4952e3031 --- /dev/null +++ b/php/classes/base32.php @@ -0,0 +1,98 @@ +> ( $bitOffset - 3 ); + $str[ $charIdx ] = chr( $byte ); + + // if lowest ( $bitOffset - 3 ) bits are not 0, write them to the next byte + $mask = (1 << ( $bitOffset - 3 )) - 1; + $nextByte = ( $fiveBits & $mask ) << ( 8 - ( $bitOffset - 3 ) ); + if( $nextByte !== 0 ) { + if( $charIdx + 1 >= strlen( $str ) ) { + $str .= chr( $nextByte ); + } + } + } + + return true; + } + + /** + * read and encode n-th 5-bit block from the string + */ + protected static function encodeChunk( &$str, $n ) { + $charIdx = (int)floor( $n * 5 / 8 ); + $bitOffset = ($n * 5) % 8; + if( $charIdx >= strlen( $str ) ) { + return ""; + } + $byte = ord( $str[ $charIdx ] ); + if( $bitOffset <= 3 ) { + // read highest ($bitOffset + 5) bits and puth them into $fiveBits + $fiveBits = ( $byte >> ( 3 - $bitOffset ) ) & 31; + } else { + // read 8 - $bitoffset bits from the first byte + $mask = ( 1 << ( 8 - $bitOffset ) ) - 1; + $fiveBits = ( $byte & $mask ) << ( $bitOffset - 3 ); + if( $charIdx < strlen( $str ) - 1 ) { + // read next ($bitOffset - 3) bits and put them in the lowest bits of $fiveBits + $nextByte = ord( $str[ $charIdx + 1 ] ); + $fiveBits += $nextByte >> ( 8 - ($bitOffset - 3) ); + } + } + $ret = self::$table[ $fiveBits ]; + return $ret; + } + protected static $table = array( + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', '2', '3', '4', '5', '6', '7', + '=' + ); +} +?> diff --git a/php/classes/button.php b/php/classes/button.php new file mode 100644 index 0000000000000000000000000000000000000000..4b925958dc51b9bc08665b1be31eba5b70a65a46 --- /dev/null +++ b/php/classes/button.php @@ -0,0 +1,208 @@ +nextInd = 0; + $this->modifyKeys(); + $this->separateKeys(); + } + /** + * Separate modified post keys to current and selected + */ + function separateKeys() + { + if($this->location == 'grid') + { + if($this->isManyKeys) + { + $this->currentKeys = $this->keys[0]; + for($i=1; $ikeys); $i++) + $this->selectedKeys[$i-1] = $this->keys[$i]; + } + else + $this->currentKeys = $this->keys; + } + if($this->location == PAGE_LIST) { + $this->selectedKeys = $this->keys; + $this->currentKeys = $this->keys; + } + + if($this->location == PAGE_EDIT || $this->location == PAGE_VIEW) + $this->currentKeys = $this->keys; + } + /** + * Modify post keys array to associative + */ + function modifyKeys() + { + $pSet = new ProjectSettings( $this->table, "", $this->page ); + + $keys = array(); + + // if array of keys exists + if( $this->keys ) + { + $tKeysNamesArr = $pSet->getTableKeys(); + if($this->isManyKeys) + { + foreach ($this->keys as $ind => $value) + { + $keys[$ind] = array(); + $recKeyArr = explode('&', $value); + for($j=0;$jkeys[ $kf ] ) ) { + $keysReady = false; + break; + } + } + + if( $keysReady ) + return; + + for($j=0;$jkeys[$j]); + } + } + } + $this->keys = $keys; + } + /** + * Get keys + * @return {array} + */ + function getKeys() { + return $this->keys; + } + + /** + * Get current record data + * @return {mixed} array of next record data or false + */ + function getCurrentRecord() { + return $this->getRecordData(); + } + + /** + * Get next selected record + * @return {mixed} array of next record data or false + */ + function getNextSelectedRecord() { + if( $this->nextInd < count( $this->selectedKeys ) ) { + $data = $this->getRecordData( $this->selectedKeys[ $this->nextInd ] ); + $this->nextInd += 1; + return $data; + } + + return false; + } + + /** + * Read values from the database by keys + * @return {mixed} array of current record data or false + */ + public function getRecordData( $keys = null ) { + global $cipherer; + + if( !$keys ) + $keys = $this->currentKeys; + + $pSet = new ProjectSettings( $this->table, "", $this->page ); + + $dc = new DsCommand(); + $dc->filter = Security::SelectCondition( "S", $pSet ); + $dc->keys = $keys; + + $dataSource = getDataSource( $this->table, $pSet ); + $fetchedArray = $dataSource->getSingle( $dc )->fetchAssoc(); + $data = $cipherer->DecryptFetchedArray( $fetchedArray ); + + return $data; + } + + + function getMasterData( $masterTable ) + { + if ( isset($_SESSION[ $masterTable . "_masterRecordData" ]) ) + { + return $_SESSION[ $masterTable . "_masterRecordData" ]; + } + + return false; + } + + function saveTempFile( $contents ) { + $filename = tempnam("", ""); + runner_save_file($filename, $contents); + $this->tempFileNames[] = $filename; + return $filename; + } + + function deleteTempFiles() { + foreach( $this->tempFileNames as $f ) { + @unlink( $f ); + } + } + + public function getMasterRecord() { + if( !$this->masterTable ) + return null; + + $pSet = new ProjectSettings( $this->table, "", $this->page ); + $mpSet = new ProjectSettings( $this->masterTable, PAGE_LIST ); + $masterDs = getDataSource( $this->masterTable, $mpSet ); + + $filters = array(); + foreach( $pSet->getMasterTablesArr() as $i => $masterTableInfo ) { + if( $this->masterTable != $masterTableInfo['mDataSourceTable'] ) + continue; + + foreach( $masterTableInfo['masterKeys'] as $j => $mKeyField ) { + $filters[] = DataCondition::FieldEquals( $mKeyField, $this->masterKeys[ $j + 1 ] ); + } + } + $filters[] = Security::SelectCondition( "S", $mpSet ); + + $dc = new DsCommand; + $dc->filter = DataCondition::_And( $filters ); + $dc->reccount = 1; + + return $masterDs->getList( $dc )->fetchAssoc(); + } +} +?> \ No newline at end of file diff --git a/php/classes/chartpage.php b/php/classes/chartpage.php new file mode 100644 index 0000000000000000000000000000000000000000..5e07539e6364d5e4a4594e3affbe988cb7d46795 --- /dev/null +++ b/php/classes/chartpage.php @@ -0,0 +1,374 @@ +bodyForms = array( "grid" ); + + $this->jsSettings['tableSettings'][ $this->tName ]['simpleSearchActive'] = $this->searchClauseObj->simpleSearchActive; + + if( $this->mode == CHART_DASHBOARD ) { + $this->pageData['detailsMasterKeys'] = $this->getStartMasterKeys(); + } + $this->pageData['singleChartPage'] = $this->pSet->getChartCount() == 1; + } + + /** + * Set the page's session prefix + */ + protected function assignSessionPrefix() + { + if( $this->mode == CHART_DASHBOARD ) + $this->sessionPrefix = $this->dashTName."_".$this->tName; + else + $this->sessionPrefix = $this->tName; + } + + /** + * Process the page + */ + public function process() + { + if( $this->mode == CHART_DASHDETAILS + || $this->mode == CHART_DETAILS && ( $this->masterPageType == PAGE_LIST || $this->masterPageType == PAGE_REPORT )) + $this->updateDetailsTabTitles(); + + + // Before Process event + if( $this->eventsObject->exists("BeforeProcessChart") ) + $this->eventsObject->BeforeProcessChart( $this ); + + + // build tabs and set current + $this->processGridTabs(); + + $this->doCommonAssignments(); + $this->addButtonHandlers(); + $this->addCommonJs(); + $this->commonAssign(); + + if( $this->mode != CHART_DASHBOARD ) { + $this->buildSearchPanel(); + $this->assignSimpleSearch(); + } + + // to restore correctly within a chart class + $_SESSION[ $this->sessionPrefix.'_advsearch' ] = serialize( $this->searchClauseObj ); + + // display the 'Back to Master' link and master table info + $this->displayMasterTableInfo(); + + $this->showPage(); + } + + function callBeforeQueryEvent( $dc ) { + if( !$this->eventsObject->exists("BeforeQueryChart") ) { + return; + } + $prep = $this->dataSource->prepareSQL( $dc ); + $where = $prep["where"]; + $order = $prep["order"]; + $sql = $prep["sql"]; + $this->eventsObject->BeforeQueryChart($sql, $where, $order ); + + if( $sql != $prep["sql"] ) + $this->dataSource->overrideSQL( $dc, $sql ); + else { + if( $where != $prep["where"] ) + $this->dataSource->overrideWhere( $dc, $where ); + if( $order != $prep["order"] ) + $this->dataSource->overrideOrder( $dc, $order ); + } + } + + + + function getMasterCondition() { + if( $this->mode == CHART_DASHBOARD ) + return null; + + return parent::getMasterCondition(); + } + + /** + * Get started master keys + * @return Array + */ + public function getStartMasterKeys() + { + $detailTablesData = $this->pSet->getDetailTablesArr(); + if( !$detailTablesData ) { + return array(); + } + + $dc = $this->getSubsetDataCommand(); + $dc->reccount = 1; + + $rs = $this->dataSource->getList( $dc ); + if( !$rs ) { + showError( $this->dataSource->lastError() ); + } + + $data = $this->cipherer->DecryptFetchedArray( $rs->fetchAssoc() ); + + $masterKeysArr = array(); + foreach ( $detailTablesData as $detailId => $detail ) { + foreach( $detail['masterKeys'] as $idx => $mk ) { + $masterKeysArr[ $detail['dDataSourceTable'] ] = array( 'masterkey'.($idx + 1) => $data[$mk] ); + } + } + + return $masterKeysArr; + } + + /** + * + */ + public function doCommonAssignments() + { + + //set the Search panel + $this->xt->assign("searchPanel", true); + + if( $this->isShowMenu() ) + $this->xt->assign("menu_block", true); + + $this->setLangParams(); + + $this->xt->assign("chart_block", true); + $this->xt->assign("asearch_link", true); + $this->xt->assign("exportpdflink_attrs", "onclick='chart.saveAsPDF();'"); + $this->xt->assign("advsearchlink_attrs", "id=\"advButton".$this->id."\""); + + if( !GetChartXML( $this->shortTableName ) ) + $this->xt->assign("chart_block", false); + + $this->xt->assign("message_block", true); + + if( ($this->mode == CHART_SIMPLE || $this->mode == CHART_DASHBOARD) && $this->pSet->noRecordsOnFirstPage() && !$this->searchClauseObj->isSearchFunctionalityActivated() ) + { + $this->show_message_block = true; + $this->hideElement("chart"); + $this->xt->assign("chart_block", false); + + $this->xt->assign("message", $this->noRecordsMessage()); + $this->xt->assign( "message_class", "alert-warning"); + } + + if( !$this->show_message_block ) + $this->hideElement("message"); + + if( $this->mobileTemplateMode() ) + $this->xt->assign('tableinfomobile_block', true); + + + $this->assignChartElement(); + + $this->body['begin'].= GetBaseScriptsForPage( $this->isDisplayLoading ); + if( !$this->isDashboardElement() && !$this->mobileTemplateMode() ) + $this->body['begin'].= "
"; + + // assign body end + $this->body['end'] = XTempl::create_method_assignment( "assignBodyEnd", $this); + + $this->xt->assignbyref('body', $this->body); + } + + /** + * Set the chart xt variable + */ + public function assignChartElement() + { + } + + /** + * + */ + public function prepareDetailsForEditViewPage() + { + $this->addButtonHandlers(); + + $this->xt->assign("body", $this->body); + $this->xt->assign("chart_block", true); + $this->xt->assign("message_block", true); + } + + protected function getExtraAjaxPageParams() + { + $returnJSON = array(); + if( $this->mode == REPORT_DETAILS ) + { + $returnJSON['headerCont'] = $this->getProceedLink() . $returnJSON['headerCont']; + } + + return $returnJSON; + } + + public function beforeShowChart() + { + if( $this->eventsObject->exists("BeforeShowChart") ) + $this->eventsObject->BeforeShowChart($this->xt, $this->templatefile, $this); + } + + public function showPage() + { + $this->beforeShowChart(); + + if( $this->mode == CHART_DETAILS || $this->mode == CHART_DASHBOARD || $this->mode == CHART_DASHDETAILS ) + { + $this->addControlsJSAndCSS(); + $this->fillSetCntrlMaps(); + + $this->xt->assign("header", false); + $this->xt->assign("footer", false); + + $this->body["begin"] = ""; + $this->body["end"] = ""; + $this->xt->assign("body", $this->body); + + $this->displayAJAX($this->templatefile, $this->id + 1); + exit(); + } + + if( $this->mode == CHART_POPUPDETAILS ) //currently unused + { + $this->xt->assign("header", false); + $this->xt->assign("footer", false); + $this->body["begin"] = ''; + $this->body["end"] = ''; + + $this->xt->prepare_template($this->templatefile); + $respArr = array(); + $respArr['success'] = true; + $respArr['body'] = $this->xt->fetch_loaded("body"); + $respArr['counter'] = postvalue('counter'); + $this->xt->assign("container_master", false); + + echo printJSON($respArr); + exit(); + } + + $this->display( $this->templatefile ); + } + + /** + * + */ + function processGridTabs() + { + $ctChanged = parent::processGridTabs(); + $_SESSION[ $this->sessionPrefix . "_chartTabWhere" ] = $this->getCurrentTabWhere(); + + return $ctChanged; + } + + function gridTabsAvailable() { + return true; + } + + function displayTabsInPage() + { + return $this->simpleMode() + || ( $this->mode == CHART_DETAILS && ($this->masterPageType == PAGE_VIEW || $this->masterPageType == PAGE_EDIT)) + || $this->mode == CHART_DASHBOARD && $this->dashElementData["tabLocation"] == "body"; + } + + protected function getBodyMarkup( $templatefile ) + { + if( $this->mode == CHART_DASHBOARD && $this->dashElementData["tabLocation"] == "body" ) + return $this->fetchBlocksList( array( "above-grid_block", "grid_tabs", "grid_block" ) ); + + return parent::getBodyMarkup( $templatefile ); + } + + function element2Item( $name ) { + if( $name == "message" ) { + return array( "grid_message" ); + } + if( $name == "chart" ) { + return array( "chart" ); + } + return parent::element2Item( $name ); + } + + public function prepareDisplayDetails() + { + $resizeChart = true; + if( $this->mode == CHART_SIMPLE || + $this->mode == CHART_DASHBOARD || + $this->mode == CHART_DETAILS && ( $this->masterPageType == PAGE_VIEW || $this->masterPageType == PAGE_EDIT ) ) + $resizeChart = false; + + //set params for the 'xt_showchart' method showing the chart + $chartXtParams = array( + "id" => $this->id, + "table" => $this->tName, + "ctype" => $this->pSet->getChartType(), + "resize" => $resizeChart, + "chartName" => $this->shortTableName, + "chartPreview" => $this->mode !== CHART_SIMPLE && $this->mode != CHART_DASHBOARD + ); + + if( $this->mode == CHART_DASHBOARD || $this->mode == CHART_DASHDETAILS ) + { + $chartXtParams["refreshTime"] = $this->dashElementData["reload"]; + } + + $this->prepareCharts(); + $forms = array( "grid" ); + $bodyContents = $this->fetchForms($forms); + $this->renderedBody = '
'.$bodyContents.'
'; + return; + } + + public function showGridOnly() + { + echo $this->renderedBody; + } + + function prepareCharts() + { + $chartXtParams = array( + "id" => $this->id, + // it shows if chart show details + "chartPreview" => $this->mode !== CHART_SIMPLE && $this->mode != CHART_DASHBOARD, + "stateLink" => $this->getStateUrlParams() + ); + + if( $this->dashTName && $this->mode == CHART_DASHBOARD ) + { + $chartXtParams["dash"] = true; + $chartXtParams["dashTName"] = $this->dashTName; + $chartXtParams["dashElementName"] = $this->dashElementName; + $chartXtParams["dashPage"] = $this->dashPage; + } + + $this->xt->assign_function("chart", "xt_showpdchart", $chartXtParams); + } + + public static function readChartModeFromRequest() + { + $mode = postvalue("mode"); + if( $mode == "listdetails" ) + return CHART_DETAILS; + elseif( $mode == "listdetailspopup" ) + return CHART_POPUPDETAILS; + elseif( $mode == "dashchart" ) + return CHART_DASHBOARD; + elseif( $mode == "dashdetails" ) + return CHART_DASHDETAILS; + else + return CHART_SIMPLE; + } +} +?> \ No newline at end of file diff --git a/php/classes/chartpage_master.php b/php/classes/chartpage_master.php new file mode 100644 index 0000000000000000000000000000000000000000..a2c11a3f25b86bf546f3dfca8bd58db966aa7bb4 --- /dev/null +++ b/php/classes/chartpage_master.php @@ -0,0 +1,71 @@ +xt->assign( "masterlist_title", true ); + return $this->xt->fetch_loaded( "masterlist_title" ); + } + + public function preparePage() + { + if( !$this->masterRecordData || !$this->masterRecordData ) + return; + + $this->xt->assign("chart_block", true); + $this->assignChartElement(); + + $this->xt->assign("pagetitlelabel", $this->getPageTitle( $this->pageType, GoodFieldName($this->tName), $this->masterRecordData )); + + $tKeys = $this->pSet->getTableKeys(); + $keylink = ""; + + + for($i = 0; $i < count($tKeys); $i ++) { + $keylink.= "&key".($i + 1)."=".runner_htmlspecialchars(rawurlencode(@$this->masterRecordData[$tKeys[$i]])); + } + + $fields = $this->pSet->getMasterListFields(); + $fields = array_merge( $fields, $tKeys); + foreach( $fields as $f ) + { + $fieldClassStr = $this->fieldClass($f); + $this->xt->assign( GoodFieldName( $f ) . "_mastervalue", "".$this->showDBValue( $f, $this->masterRecordData, $keylink).""); + $this->xt->assign( GoodFieldName( $f ) . "_class", $fieldClassStr); // add class for field header as field value + } + + if( $this->pageLayout ) + $this->xt->assign("pageattrs", 'class="'.$this->pageLayout->style." page-".$this->pageLayout->name.'"'); + + if( $this->pageLayout ) + $this->xt->assign("pageattrs", 'class="'.$this->pageLayout->style." page-".$this->pageLayout->name.'"'); + } + + public function showMaster( $params ) + { + if( !$this->masterRecordData || !$this->masterRecordData ) + return; + + $this->xt->load_template( $this->templatefile ); + + $this->xt->assign( "masterlist_title", false ); + $this->xt->display_loaded(); + } +} + +?> diff --git a/php/classes/charts.php b/php/classes/charts.php new file mode 100644 index 0000000000000000000000000000000000000000..a896f8fe8548936ed4f91fa7139076525447efd5 --- /dev/null +++ b/php/classes/charts.php @@ -0,0 +1,2065 @@ +webchart = $param["webchart"]; + + if( $this->webchart ) + $this->chrt_array = Convert_Old_Chart($ch_array); + else + $this->chrt_array = $ch_array; + + $this->tName = $this->chrt_array['tables'][0]; + + // #10461, $this->setConnection(); needs to be called after value is assigned to $this->webchart + $this->setConnection(); + + $this->pSet = new ProjectSettings( $this->tName, PAGE_CHART ); + $this->showDetails = $param['showDetails']; + if( $this->showDetails ) + { + $this->detailTablesData = $this->pSet->getDetailTablesArr(); + for($i = 0; $i < count($this->detailTablesData); $i ++) + { + $strPerm = GetUserPermissions($this->detailTablesData[$i]['dDataSourceTable']); + if ( strpos($strPerm, "S") === false ) + unset($this->detailTablesData[$i]); + } + } + + $this->table_type = $this->chrt_array["table_type"]; + if( !$this->table_type ) + $this->table_type = "project"; + + if( $this->table_type == "project" ) { + // project table + $this->dataSource = getDataSource( $this->tName, $this->pSet, $this->connection ); + } else { + // db-table-based webchart + $this->dataSource = getWebDataSource( $this->chrt_array ); + } + + $this->pageId = $param["pageId"]; + $this->chrt_array["appearance"]["autoupdate"] = false; + + + $this->cname = $param["cname"]; + + $this->sessionPrefix = $this->chrt_array['tables'][0]; + + $this->masterTable = $param["masterTable"]; + $this->masterKeysReq = $param["masterKeysReq"]; + + // true if chart has master + $this->chartPreview = $param["chartPreview"]; + $this->dashChart = $param["dashChart"]; + + if( $this->dashChart ) + { + $this->dashTName = $param["dashTName"]; + $this->dashElementName = $param["dashElementName"]; + $this->sessionPrefix = $this->dashTName."_".$this->sessionPrefix; + } + + if( !$this->webchart && !$this->chartPreview && isset( $_SESSION[ $this->sessionPrefix.'_advsearch' ] ) ) + $this->searchClauseObj = SearchClause::UnserializeObject( $_SESSION[ $this->sessionPrefix.'_advsearch' ] ); + + if( $this->searchClauseObj ) + RunnerContext::pushSearchContext( $this->searchClauseObj ); + + if( $this->isProjectDB() ) { + $this->cipherer = new RunnerCipherer( $this->tName ); + } + + $this->setBasicChartProp(); + + if( tableEventExists("UpdateChartSettings", $strTableName) ) + { + $eventObj = getEventObject( $strTableName ); + $eventObj->UpdateChartSettings( $this ); + } + } + + /** + * @param Array params + */ + protected function setSpecParams( $params ) + { + if( $params['name'] == "" ) + return; + + if( $this->table_type != "db" ) + $this->arrDataSeries[] = $params['agr_func'] ? $params['label'] : $params['name']; + else { + $this->arrDataSeries[] = $params['table']."_".$params['name']; +// $this->arrDataSeries[] = $params['name']; + } + } + + /** + * @param Array params + * @param String gTableName + */ + protected function setDataLabels( $params, $gTableName ) + { + $chartType = $this->chrt_array["chart_type"]["type"]; + if( $this->table_type == "project" && !$this->webchart ) + { + if( $chartType != "candlestick" && $chartType != "ohlc" ) + $this->arrDataLabels[] = GetFieldLabel( $gTableName, GoodFieldName($params['name']) ); + else + $this->arrDataLabels[] = GetFieldLabel( $gTableName, GoodFieldName($params['ohlcOpen']) ) ; + } + else + { + if( !$params['label'] ) + { + if( $chartType != "candlestick" && $chartType != "ohlc" ) + $this->arrDataLabels[] = $params['name']; + else + $this->arrDataLabels[] = $params['ohlcOpen']; + } + else + $this->arrDataLabels[] = $params['label']; + } + } + + /** + * + */ + protected function setBasicChartProp() + { + $this->header = $this->chrt_array['appearance']['head']; + $this->header = $this->header ? $this->header : ''; + + $this->footer = $this->chrt_array['appearance']['foot']; + $this->footer = $this->footer ? $this->footer : ''; + + for ( $i = 0; $ichrt_array['parameters']) - 1; $i++) + { + $this->setSpecParams( $this->chrt_array['parameters'][$i] ); + $this->setDataLabels( $this->chrt_array['parameters'][$i], GoodFieldName( $this->chrt_array['tables'][0] ) ); + } + + if( $this->chrt_array["chart_type"]["type"] != "gauge" ) + { + $chartParams = $this->chrt_array['parameters']; + $params = $chartParams[ count($chartParams) - 1 ]; + + if( $this->table_type != "db" ) + $this->strLabel = $params['name']; + else { +// $this->strLabel = $params['name']; + $this->strLabel = $params['agr_func'] ? $params['agr_func']."_".$params['table']."_".$params['name']: $params['table']."_".$params['name']; + } + } + + if( count( $this->arrDataLabels ) == 1 ) + $this->y_axis_label = $this->arrDataLabels[0]; + else + $this->y_axis_label = $this->chrt_array['appearance']['y_axis_label']; + } + + + protected function getMasterCondition() { + if( $this->dashChart ) + return null; + + $detailKeysByM = $this->pSet->getDetailKeysByMasterTable( $this->masterTable ); + if( !$detailKeysByM ) + return null; + + $conditions = array(); + for( $i = 0; $i < count( $detailKeysByM ); ++$i ) { + $conditions[] = DataCondition::FieldEquals( $detailKeysByM[ $i ], $this->masterKeysReq[ $i + 1 ] ); + } + + return DataCondition::_And( $conditions ); + } + + /** + * Get datasource command + */ + public function getSubsetDataCommand( $ignoreFilterField = "" ) { + $dc = new DsCommand(); + + $dc->filter = DataCondition::_And( array( + Security::SelectCondition( "S", $this->pSet ), + $this->getMasterCondition() + )); + + if( !$this->chartPreview && $this->searchClauseObj ) { + $search = $this->searchClauseObj->getSearchDataCondition(); + $filter = $this->searchClauseObj->getFilterCondition( $this->pSet ); + + $dc->filter = DataCondition::_And( array( $dc->filter, $search, $filter ) ); + } + + // where tabs + if( $_SESSION[ $this->sessionPrefix . "_chartTabWhere" ] ) { + $dc->filter = DataCondition::_And( array( + $dc->filter, + DataCondition::SQLCondition( $_SESSION[ $this->sessionPrefix . "_chartTabWhere" ] ) + )); + } + + require_once( getabspath('classes/orderclause.php') ); + $orderObject = new OrderClause( $this->pSet, $this->cipherer, $this->sessionPrefix, $this->connection ); + $dc->order = $orderObject->getOrderFields(); + + if( $this->pSet->getRecordsLimit() ) + $dc->reccount = $this->pSet->getRecordsLimit(); + + if( $this->pSet->groupChart() ) + $dc->totals = $this->getGroupChartCommandTotals(); + + return $dc; + } + + /** + * Get ds command totals + * total fields appear in the same order + they do in an original orderby clause + * @return array + */ + protected function getGroupChartCommandTotals() { + $totals = array(); + // label field + $totals[] = array( + "alias" => $this->pSet->chartLabelField(), + "field" => $this->pSet->chartLabelField(), + "modifier" => $this->pSet->chartLabelInterval() + ); + + $series = $this->pSet->chartSeries(); + foreach( $series as $s ) { + $totals[] = array( + "alias" => $s["field"], + "field" => $s["field"], + "total" => strtolower( $s["total"] ) + ); + } + + $orderInfo = $this->pSet->getOrderIndexes(); + if( !$orderInfo ) + return $totals; + + $fields = array(); + foreach( $orderInfo as $o ) { + $fields[] = $this->pSet->GetFieldByIndex( $o[0] ); + } + + foreach( $totals as $idx => $t ) { + if( !in_array( $t["field"], $fields ) ) + $fields[] = $t["field"]; + + foreach( $orderInfo as $o ) { + $fieldIdx = $this->pSet->getFieldIndex( $t["field"] ); + if( $fieldIdx == $o[0] ) { + $totals[ $idx ]["direction"] = $o[1]; + break; + } + } + } + + $_totals = array(); + foreach( $fields as $field ) { + foreach( $totals as $t ) { + if( $t["field"] == $field ) { + $_totals[] = $t; + } + } + } + + return $_totals; + } + + /** + * Check for a web chart if it's based on the project table + * @return Boolean + */ + protected function isProjectDB() + { + if( !$this->webchart ) + return true; + + if("public.kbarticles" == $this->chrt_array['tables'][0]) + return true; + if("public.kbcategories" == $this->chrt_array['tables'][0]) + return true; + if("public.kbcomments" == $this->chrt_array['tables'][0]) + return true; + if("public.kbusers" == $this->chrt_array['tables'][0]) + return true; + if("public.kbarticles" == $this->chrt_array['tables'][0]) + return true; + if("public.faicons" == $this->chrt_array['tables'][0]) + return true; + if("public.kbcomments" == $this->chrt_array['tables'][0]) + return true; + if("public.fasis_chat_history" == $this->chrt_array['tables'][0]) + return true; + if("public.diamondprice" == $this->chrt_array['tables'][0]) + return true; + if("public.products" == $this->chrt_array['tables'][0]) + return true; + if("public.items" == $this->chrt_array['tables'][0]) + return true; + if("public.appointments" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_history" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_users" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_settings" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_files" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_groups" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_peopletype" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_timezone" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_files" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_groups" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_history" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_peopletype" == $this->chrt_array['tables'][0]) + return true; + if("public.chat_settings" == $this->chrt_array['tables'][0]) + return true; + if("public.identity" == $this->chrt_array['tables'][0]) + return true; + if("public.dataset_info" == $this->chrt_array['tables'][0]) + return true; + if("public.KnowledgeBase1ugrights" == $this->chrt_array['tables'][0]) + return true; + if("public.KnowledgeBase1ugmembers" == $this->chrt_array['tables'][0]) + return true; + if("public.kbusers" == $this->chrt_array['tables'][0]) + return true; + if("public.history" == $this->chrt_array['tables'][0]) + return true; + if("public.zendesk__dataszz" == $this->chrt_array['tables'][0]) + return true; + if("public.view_zendesk" == $this->chrt_array['tables'][0]) + return true; + if("public.prompts" == $this->chrt_array['tables'][0]) + return true; + if("public.view_faisis_chat_history" == $this->chrt_array['tables'][0]) + return true; + if("public.server_setting" == $this->chrt_array['tables'][0]) + return true; + return false; + } + + /** + * Set the 'connection' property #9875 + */ + protected function setConnection() + { + global $cman; + + if($this->isProjectDB()) + $this->connection = $cman->byTable( $this->tName ); + else + $this->connection = $cman->getDefault(); + } + + public function setFooter($name) + { + $this->footer = $name; + } + + public function getFooter() + { + return $this->footer; + } + + public function setHeader($name) + { + $this->header = $name; + } + + public function getHeader() + { + return $this->header; + } + + public function setLabelField($name) + { + $this->strLabel = $name; + } + + public function getLabelField() + { + return $this->strLabel; + } + + /** + * @return String + */ + protected function getDetailedTooltipMessage() + { + if( !$this->showDetails || !$this->detailTablesData ) + return ""; + + $showClickHere = true; + + if( $this->dashChart ) + { + $showClickHere = false; + + $pDSet = new ProjectSettings( $this->dashTName ); + $arrDElem = $pDSet->getDashboardElements(); + foreach($arrDElem as $elem) + { + if( $elem["table"] == $this->chrt_array['tables'][0] && !!$elem["details"] ) + $showClickHere = true; + } + } + + if( $showClickHere ) + { + $tableCaption = GetTableCaption( $this->detailTablesData[0]['dDataSourceTable'] ); + $tableCaption = $tableCaption ? $tableCaption : $this->detailTablesData[0]['dDataSourceTable']; + + return "\nClick here to see ".$tableCaption." details"; + } + + return ""; + } + + /** + * @return String + */ + protected function getNoDataMessage() + { + if( !$this->noRecordsFound ) + return ""; + + if( !$this->searchClauseObj ) + return "No data yet."; + + if( $this->searchClauseObj->isSearchFunctionalityActivated() ) + return "No results found."; + + return "No data yet."; + } + + /** + * + */ + public function write() + { + $data = array(); + $chart = array(); + + $this->setTypeSpecChartSettings( $chart ); + if ( @$this->chrt_array["appearance"]["color71"] != "" || @$this->chrt_array["appearance"]["color91"] != "" ) + $chart["background"] = array(); + if ( @$this->chrt_array["appearance"]["color71"] != "" ) + $chart["background"]["fill"] = "#".$this->chrt_array["appearance"]["color71"]; + + if ( @$this->chrt_array["appearance"]["color91"] != "" ) + $chart["background"]["stroke"] = "#".$this->chrt_array["appearance"]["color91"]; + + if( $this->noRecordsFound ) + { + $data["noDataMessage"] = $this->getNoDataMessage(); + echo my_json_encode( $data ); + return; + } + + // animation + if( $this->chrt_array["appearance"]["sanim"] == "true" && $this->chrt_array["appearance"]["autoupdate"] != "true" ) // update? + $chart["animation"] = array("enabled" => "true", "duration" => 1000); + + // legend + if( $this->chrt_array['appearance']['slegend'] == "true" && !$this->chartPreview ) + $chart["legend"] = array("enabled" => "true"); + else + $chart["legend"] = array("enabled" => false); + + $chart["credits"] = false; + // title/header + $chart["title"] = array("enabled" => "true", "text" => $this->header); + if ( @$this->chrt_array["appearance"]["color101"] != "" ) + $chart["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color101"]; + + // assign and display + $data["chart"] = $chart; + echo my_json_encode( $data ); + } + + /** + * A stub + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + } + + /** + * @return Array + */ + protected function getGrids() + { + $grids = array(); + + if($this->chrt_array["appearance"]["sgrid"] == "true") + { + $stroke = @$this->chrt_array["appearance"]["color121"] != "" ? "#" . $this->chrt_array["appearance"]["color121"] : "#ddd"; + + $grid0 = array( + "enabled" => true, + "drawLastLine" => false, + "stroke" => $stroke, + "scale" => 0, + "axis" => 0 + ); + + if ( @$this->chrt_array["appearance"]["color81"] != "" ) + { + $dataPlotBackgroundColor = "#" . $this->chrt_array["appearance"]["color81"]; + $grid0["oddFill"] = $dataPlotBackgroundColor; + $grid0["evenFill"] = $dataPlotBackgroundColor; + } + + $grids[] = $grid0; + + $grids[] = array( + "enabled" => true, + "drawLastLine" => false, + "stroke" => $stroke, + "axis" => 1 + ); + } + + return $grids; + } + + /** + * @param String fieldName + * @param Array data + * @return String + */ + protected function labelFormat($fieldName, $data, $truncated = true) + { + if( !$fieldName ) + return ""; + + if( $this->table_type == "db" && !!$this->chrt_array['customLabels'] ) + $fieldName = $this->chrt_array['customLabels'][ $fieldName ]; + + include_once getabspath('classes/controls/ViewControlsContainer.php'); + $viewControls = new ViewControlsContainer( $this->pSet, PAGE_CHART ); + if( $this->pSet->groupChart() ) { + $interval = $this->pSet->chartLabelInterval(); + if( $interval ) { + $fType = $this->pSet->getFieldType( $fieldName ); + return RunnerPage::formatGroupValueStatic( $fieldName, $interval, $data[ $fieldName ], $this->pSet, $viewControls, false ); + } + } + $value = $viewControls->showDBValue( $fieldName, $data, "", "", false ); + + if( $truncated && strlen($value) > 50 ) + $value = runner_substr($value, 0, 47)."..."; + + return $value; + } + + protected function beforeQueryEvent( &$dc ) { + $eventsObject = getEventObject( $this->pSet->getTableName() ); + + // ASP conversion requires these checks be separate + if( !$eventsObject ) + return; + if( !$eventsObject->exists("BeforeQueryChart") ) { + return; + } + + $prep = $this->dataSource->prepareSQL( $dc ); + $where = $prep["where"]; + $sql = $prep["sql"]; + $order = $prep["order"]; + + // call Before Query event + $eventsObject->BeforeQueryChart( $sql, $where, $order ); + + if( $sql != $prep["sql"] ) + $this->dataSource->overrideSQL( $dc, $sql ); + else { + if( $where != $prep["where"] ) + $this->dataSource->overrideWhere( $dc, $where ); + if( $order != $prep["order"] ) + $this->dataSource->overrideOrder( $dc, $order ); + } + } + + /** + * @return Array + */ + public function get_data() + { + $data = array(); + $clickdata = array(); + for ( $i = 0; $i < count($this->arrDataSeries); $i++ ) + { + $data[$i] = array(); + $clickdata[$i] = array(); + } + + $dc = $this->getSubsetDataCommand(); + $this->beforeQueryEvent( $dc ); + + if( $this->pSet->groupChart() ) { + $rs = $this->dataSource->getTotals( $dc ); + } else { + $rs = $this->dataSource->getList( $dc ); + } + if( !$rs ) { + showError( $this->dataSource->lastError() ); + } + + $row = $rs->fetchAssoc(); + if( $this->cipherer ) + $row = $this->cipherer->DecryptFetchedArray( $row ); + + if( !$row ) + $this->noRecordsFound = true; + + while ($row) + { + for ( $i = 0; $i < count($this->arrDataSeries); $i++ ) + { + $data[$i][] = $this->getPoint($i, $row); + + $strLabelFormat = $this->labelFormat( $this->strLabel, $row ); + $clickdata[$i][] = $this->getActions( $row , $this->arrDataSeries[$i], $strLabelFormat ); + } + + $row = $rs->fetchAssoc(); + if( $this->cipherer ) + $row = $this->cipherer->DecryptFetchedArray( $row ); + } + + $series = array(); + for ( $i = 0; $i < count($this->arrDataSeries); $i++ ) + { + $series[] = $this->getSeriesData( $this->arrDataLabels[$i], $data[$i], $clickdata[$i], $i, count($this->arrDataSeries) > 1 ); + } + + return $series; + } + + /** + * @param Number seriesNumber + * @param Array row + * @return Array + */ + protected function getPoint( $seriesNumber, $row ) { + $strLabelFormat = $this->labelFormat( $this->strLabel, $row ); + + include_once getabspath('classes/controls/ViewControlsContainer.php'); + $viewControls = new ViewControlsContainer( $this->pSet, PAGE_CHART ); + + if( $this->table_type != "db" || !$this->chrt_array['customLabels'] ) { + $strDataSeries = $row[ $this->arrDataSeries[ $seriesNumber ] ]; + $fieldName = $this->arrDataSeries[ $seriesNumber ]; + $formattedValue = $viewControls->showDBValue( $fieldName, $row, "", "", false ); + } else { + $strDataSeries = $row[ $this->chrt_array['customLabels'][ $this->arrDataSeries[ $seriesNumber ] ] ]; + $fieldName = $this->chrt_array['customLabels'][ $this->arrDataSeries[ $seriesNumber ] ]; + $formattedValue = $viewControls->showDBValue( $fieldName, $row, "", "", false ); + } + + return array( + "x" => $strLabelFormat, + "value" => (double)str_replace(",", ".", $strDataSeries), + "viewAsValue" => $formattedValue + ); + } + + /** + * @param String name + * @param Array pointsData + * @param Array clickData + * @param Number seriesNumber + * @param Boolean multiSeries (optional) + * @return Array + */ + protected function getSeriesData( $name, $pointsData, $clickData, $seriesNumber, $multiSeries = true ) + { + $data = array( + "name" => $name, + "data" => $pointsData, + "xScale" => "0", + "yScale" => "1", + "seriesType" => $this->getSeriesType($seriesNumber) + ); + + $data["labels"] = array( + "enabled" => $this->chrt_array["appearance"]["sval"] == "true", + "format" => "{%viewAsValue}" + ); + + if ( @$this->chrt_array["appearance"]["color61"] != "" ) + $data["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color61"]; + + if( $clickData && $this->detailTablesData ) + $data["clickData"] = $clickData; + + $data["tooltip"] = $this->getSeriesTooltip( $multiSeries ); + + return $data; + } + + /** + * @param Boolean $multiSeries + * @return Array + */ + protected function getSeriesTooltip( $multiSeries ) { + return array( + "enabled" => true, + "format" => "{%seriesName}: {%viewAsValue}". $this->getDetailedTooltipMessage(), + ); + } + + /** + * @return String + */ + protected function getSeriesType($seriesNumber) + { + return "column"; + } + + /** + * @deprecated + * @param String str + * @return String + */ + protected function chart_xmlencode($str) + { + return str_replace(array("&","<",">","\""),array("&","<",">","""),$str); + } + + /** + * Get a 'point click' action data + * @param Array data + * @param Number seriesId + * @param Number pointId + * @return Array + */ + protected function getActions( $data, $seriesId, $pointId ) + { + global $strTableName; + + if( !$this->detailTablesData ) + return null; + + if ( $this->dashChart ) + { + $masterKeysArr = array(); + foreach ( $this->detailTablesData as $detailId => $detail ) + { + foreach( $detail['masterKeys'] as $idx => $mk ) + { + $masterKeysArr[ $detail['dDataSourceTable'] ] = array( 'masterkey'.($idx + 1) => $data[ $mk ] ); + } + } + + if (!$this->dashChartFirstPointSelected) + { + $this->dashChartFirstPointSelected = true; + $this->detailMasterKeys = my_json_encode( $masterKeysArr ); + } + + return array( "masterKeys" => $masterKeysArr, "seriesId" => $seriesId, "pointId" => $pointId ); + } + + // The one detail table is allowed for a chart page only + $detailTableData = $this->detailTablesData[0]; + $masterquery = "mastertable=".rawurlencode( $strTableName ); + foreach( $detailTableData['masterKeys'] as $idx => $mk ) + { + $masterquery.= "&masterkey".($idx + 1)."=".rawurlencode( $data[ $mk ] ); + } + + return array( "url" => GetTableLink( $detailTableData['dShortTable'], $detailTableData['dType'], $masterquery ) ); + } + + protected function getLogarithm() + { + if( $this->chrt_array["appearance"]["slog"] == "true" ) + return true; + return false; + } +} + + +class Chart_Bar extends Chart +{ + protected $stacked; + protected $bar; + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->stacked = $param["stacked"]; + $this->_2d = $param["2d"]; + $this->bar = $param["bar"]; + } + + /** + * @return String + */ + protected function getSeriesType($seriesNumber) + { + if($this->bar) + return "bar"; + else + return "column"; + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $chart["series"] = $this->get_data(); + + $chart["scales"] = $this->getScales(); + $chart["logarithm"] = parent::getLogarithm(); + + if( $this->bar ) + $chart["type"] = "bar"; + else + $chart["type"] = "column"; + + if( !$this->_2d ) + $chart["type"] .= "-3d"; + + $chart["xScale"] = 0; + $chart["yScale"] = 1; + + // grid + $chart["grids"] = $this->getGrids(); + + + // Y-axis label + $chart["yAxes"] = array( + array( + "enabled" => "true", + "title" => $this->y_axis_label + )); + + // X-axis label + $chart["xAxes"] = array( + array( + "enabled" => "true", + "title" => array( 'text' => $this->footer ), + "labels" => array( "enabled" => $this->chrt_array["appearance"]["sname"] == "true" ) + )); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + $chart["xAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + + if ( @$this->chrt_array["appearance"]["color111"] != "" ) + $chart["xAxes"][0]["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color111"]; + + if ( @$this->chrt_array["appearance"]["color131"] != "" ) + $chart["xAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color131"]; + + if ( @$this->chrt_array["appearance"]["color141"] != "" ) + $chart["yAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color141"]; + } + + /** + * "scales" + * @return Array + */ + protected function getScales() + { + if($this->stacked || $this->chrt_array["appearance"]["slog"] == "true") + { + $arr = array(); + if( $this->stacked ) + $arr["stackMode"] = "value"; + + if( $this->chrt_array["appearance"]["slog"] == "true" ) + { + $arr["logBase"] = 10; + $arr["type"] = "log"; + }; + + return array( + array("names" => array()), + $arr + ); + } + + return array(); + } +} + +class Chart_Line extends Chart +{ + protected $type_line; + + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->type_line = $param["type_line"]; + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $chart["series"] = $this->get_data(); + $chart["type"] = "line"; + + $chart["xScale"] = 0; + $chart["yScale"] = 1; + $chart["grids"] = $this->getGrids(); + $chart["logarithm"] = parent::getLogarithm(); + $chart["tooltip"] = array("displayMode" => "single"); + + $chart["yAxes"] = array( + array( "enabled" => "true", "title" => $this->y_axis_label ) + ); + + $chart["xAxes"] = array( + array( + "enabled" => "true", + "title" => array( 'text' => $this->footer ), + "labels" => array( "enabled" => $this->chrt_array["appearance"]["sname"] == "true" ) + )); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + $chart["xAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + + if ( @$this->chrt_array["appearance"]["color111"] != "" ) + $chart["xAxes"][0]["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color111"]; + + if ( @$this->chrt_array["appearance"]["color131"] != "" ) + $chart["xAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color131"]; + + if ( @$this->chrt_array["appearance"]["color141"] != "" ) + $chart["yAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color141"]; + } + + /** + * @return String + */ + protected function getSeriesType($seriesNumber) + { + switch( $this->type_line ) + { + case "line": + return "line"; + case "spline": + return "spline"; + case "step_line": + return "stepLine"; + default: + return "line"; + } + } +} + +class Chart_Area extends Chart +{ + protected $stacked; + + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->stacked = $param["stacked"]; + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $chart["series"] = $this->get_data(); + + if( $this->stacked ) + $chart["scales"] = $this->getScales(); + $chart["type"] = "area"; + $chart["xScale"] = 0; + $chart["yScale"] = 1; + $chart["logarithm"] = parent::getLogarithm(); + $chart["grids"] = $this->getGrids(); + + $chart["tooltip"] = array("displayMode" => "single"); + + $chart["yAxes"] = array( + array( "enabled" => "true", "title" => $this->y_axis_label ) + ); + + $chart["xAxes"] = array( + array( + "enabled" => "true", + "title" => array( 'text' => $this->footer ), + "labels" => array( "enabled" => $this->chrt_array["appearance"]["sname"] == "true" ) + )); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + $chart["xAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + + if ( @$this->chrt_array["appearance"]["color111"] != "" ) + $chart["xAxes"][0]["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color111"]; + + if ( @$this->chrt_array["appearance"]["color131"] != "" ) + $chart["xAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color131"]; + + if ( @$this->chrt_array["appearance"]["color141"] != "" ) + $chart["yAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color141"]; + } + + /** + * @return String + */ + protected function getSeriesType($seriesNumber) + { + return "area"; + } + + /** + * "scales" + * @return Array + */ + protected function getScales() + { + if( $this->stacked ) + { + $arr = array(); + $arr["stackMode"] = "value"; + + if( $this->chrt_array["appearance"]["sstacked"] == "true" ) + { + $arr["stackMode"] = "percent"; + $arr["maximumGap"] = "10"; + $arr["maximum"] = "100"; + }; + + return array( + array( "names"=> array() ), + $arr + ); + } + + return array(); + } +} + +/** + * A single series chart + */ +class Chart_Pie extends Chart +{ + protected $pie; + + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->pie = $param["pie"]; + $this->_2d = $param["2d"]; + $this->singleSeries = true; + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $series = $this->get_data(); + + $chart["data"] = $series[0]["data"]; + $chart["clickData"] = $series[0]["clickData"]; + $chart["singleSeries"] = true; + $chart["tooltip"] = $series[0]["tooltip"]; + $chart["logarithm"] = false; + if( $this->_2d ) + $chart["type"] = "pie"; + else + $chart["type"] = "pie-3d"; + + if( !$this->pie ) + $chart["innerRadius"] = "30%"; + + if( $this->chrt_array['appearance']['slegend'] == "true" && !$this->chartPreview ) + { + $chart["legend"] = array("enabled" => "true"); + } + + $chart["labels"] = array( "enabled" => $this->chrt_array["appearance"]["sval"] == "true" || $this->chrt_array["appearance"]["sname"] == "true" ); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + { + if ( $this->chrt_array["appearance"]["sval"] ) + { + $chart["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color61"]; + } + else if ( $this->chrt_array["appearance"]["sname"] ) + { + $chart["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + } + } + + } +} + +class Chart_Combined extends Chart +{ + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $chart["series"] = $this->get_data(); + $chart["type"] = "column"; + $chart["logarithm"] = parent::getLogarithm(); + $chart["xScale"] = 0; + $chart["yScale"] = 1; + $chart["grids"] = $this->getGrids(); + $chart["yAxes"] = array( + array( "enabled" => "true", "title" => $this->y_axis_label ) + ); + + $chart["xAxes"] = array( + array( + "enabled" => "true", + "title" => array( 'text' => $this->footer ), + "labels" => array( "enabled" => $this->chrt_array["appearance"]["sname"] == "true" ) + )); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + $chart["xAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + + if ( @$this->chrt_array["appearance"]["color111"] != "" ) + $chart["xAxes"][0]["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color111"]; + + if ( @$this->chrt_array["appearance"]["color131"] != "" ) + $chart["xAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color131"]; + + if ( @$this->chrt_array["appearance"]["color141"] != "" ) + $chart["yAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color141"]; + } + + /** + * @return String + */ + protected function getSeriesType($seriesNumber) + { + switch ($seriesNumber) { + case 0: + return "spline"; + break; + case 1: + return "splineArea"; + break; + default: + return "column"; + } + } + protected function getLogarithm() + { + if( $this->chrt_array["appearance"]["slog"] == "true" ) + return true; + return false; + } +} + +/** + * A single series chart + */ +class Chart_Funnel extends Chart +{ + protected $inver; + + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->inver = $param["funnel_inv"]; + $this->singleSeries = true; + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $series = $this->get_data(); + $chart["type"] = "pyramid"; + + $chart["data"] = $series[0]["data"]; + $chart["clickData"] = $series[0]["clickData"]; + $chart["singleSeries"] = true; + $chart["tooltip"] = $series[0]["tooltip"]; + $chart["logarithm"] = false; + if( $this->inver ) + $chart["reversed"] = true; + + $chart["labels"] = array( "enabled" => $this->chrt_array["appearance"]["sname"] == "true" ); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + $chart["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + } +} + +class Chart_Bubble extends Chart +{ + protected $arrDataSize = array(); + + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->_2d = $param["2d"]; + } + + /** + * @param Array params + */ + protected function setSpecParams( $params ) + { + parent::setSpecParams( $params ); + + if( $params['name'] != "" ) + { + if( $this->table_type != "db" ) + $this->arrDataSize[] = $params['size']; + else + $this->arrDataSize[] = $params['table']."_".$params['size']; + } + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $chart["series"] = $this->get_data(); + $chart["type"] = "cartesian"; + $chart["grids"] = $this->getGrids(); + $chart["logarithm"] = parent::getLogarithm(); + $chart["yAxes"] = array( + array( + "enabled" => true, + "title" => $this->y_axis_label, + "labels" => array( "enabled" => $this->chrt_array["appearance"]["sval"] == "true" ) + )); + + if ( @$this->chrt_array["appearance"]["color61"] != "" ) + $chart["yAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color61"]; + + $chart["xAxes"] = array( + array( + "enabled" => "true", + "title" => array( 'text' => $this->footer ), + "labels" => array( "enabled" => $this->chrt_array["appearance"]["sname"] == "true" ) + )); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + $chart["xAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + + if ( @$this->chrt_array["appearance"]["color111"] != "" ) + $chart["xAxes"][0]["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color111"]; + + if ( @$this->chrt_array["appearance"]["color131"] != "" ) + $chart["xAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color131"]; + + if ( @$this->chrt_array["appearance"]["color141"] != "" ) + $chart["yAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color141"]; + } + + /** + * @return String + */ + protected function getSeriesType($seriesNumber) + { + return "bubble"; + } + + /** + * @param Number seriesNumber + * @param Array row + * @return Array + */ + protected function getPoint( $seriesNumber, $row ) + { + $pointData = parent::getPoint( $seriesNumber, $row ); + $pointData["size"] = (double)str_replace(",", ".", $row[ $this->arrDataSize[ $seriesNumber ] ]); + + return $pointData; + } +} + +class Chart_Gauge extends Chart +{ + protected $arrGaugeColor = array(); + protected $gaugeType = ""; + protected $layout = ""; + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->gaugeType = $param["gaugeType"]; + $this->layout = $param["layout"]; + } + + /** + * @param Array params + */ + protected function setSpecParams( $params ) + { + parent::setSpecParams( $params ); + + if ( $params['name'] != "" ) + { + for ($k = 0; is_array( $params["gaugeColorZone"] ) && $k < count( $params["gaugeColorZone"] ); $k++ ) + { + $beginColor = (float)@$params["gaugeColorZone"][ $k ]["gaugeBeginColor"]; + $endColor = (float)@$params["gaugeColorZone"][ $k ]["gaugeEndColor"]; + $gColor = "#".@$params["gaugeColorZone"][ $k ]["gaugeColor"]; + + $this->arrGaugeColor[ count($this->arrDataSeries) - 1 ][] = array($beginColor, $endColor, $gColor); + } + } + } + + /** + * + */ + public function write() + { + $data = array(); + + for($i = 0; $i < count($this->arrDataSeries); $i++) + { + $chart = array(); + + if( $this->chrt_array["appearance"]["sanim"] == "true" ) + $chart["animation"] = array("enabled" => "true", "duration" => 1000); + + $this->setGaugeSpecChartSettings( $chart, $i ); + + if ( @$this->chrt_array["appearance"]["color71"] != "" || @$this->chrt_array["appearance"]["color91"] != "" ) + $chart["background"] = array(); + if ( @$this->chrt_array["appearance"]["color71"] != "" ) + $chart["background"]["fill"] = "#".$this->chrt_array["appearance"]["color71"]; + + if ( @$this->chrt_array["appearance"]["color91"] != "" ) + $chart["background"]["stroke"] = "#".$this->chrt_array["appearance"]["color91"]; + + if( $this->noRecordsFound ) + { + $data["noDataMessage"] = $this->getNoDataMessage(); + echo my_json_encode( $data ); + return; + } + + $data[] = array( "gauge" => $chart ); + } + + echo my_json_encode( array( "gauge" => $data, "header" => $this->header, "footer" => $this->footer ) ); + } + + /** + * @param &Array chart + * @param Number seriesNumber + */ + protected function setGaugeSpecChartSettings( &$chart, $seriesNumber ) + { + $series = $this->get_data(); + $chart["data"] = $series[ $seriesNumber ]["data"]; + + $chart["type"] = $this->gaugeType; + $chart["layout"] = $this->layout; + $chart["axes"] = array( $this->getAxesSettings( $seriesNumber ) ); + $chart["credits"] = false; + $chart["chartLabels"] = $this->getCircularGaugeLabel( $seriesNumber, $chart["data"][0] ); + if( $this->gaugeType == "circular-gauge" ) + { + $chart["needles"] = array( array("enabled" => true) ); + $chart["ranges"] = $this->getColorRanges( $seriesNumber ); + } + else + { + $hasColorZones = count( $this->arrGaugeColor ) > 0 && array_key_exists($seriesNumber, $this->arrGaugeColor ); + + $chart["pointers"] = array( + array( + "enabled" => true, + "pointerType" => "marker", + "type" => $this->layout == "horizontal" ? "triangleUp" : "triangleLeft", + "name" => "", + "offset" => $hasColorZones ? "20%" : "10%", + "dataIndex" => 0, + ) + ); + + if( $hasColorZones ) + { + foreach( $this->arrGaugeColor[ $seriesNumber ] as $ind => $val ) + { + $chart["pointers"][] = array( + "enabled" => true, + "pointerType" => "rangeBar", + "name" => "", + "offset" => "10%", + "dataIndex" => $ind + 1, // 0 is an index of the db point then range bars coords go + "color" => $val[2] + ); + } + } + + $scalesData = $this->getGaugeScales( $seriesNumber ); + + $chart["scale"] = 0; + $chart["scales"] = array( + array( + "maximum" => $scalesData["max"], + "minimum" => $scalesData["min"], + "ticks" => array( "interval"=> $scalesData["interval"] ), + "minorTicks" => array( "interval"=> $scalesData["interval"] / 2 ) + ) + ); + } + } + + /** + * @param Number seriesNumber + * @param Array pointData + * @return Array + */ + protected function getCircularGaugeLabel( $seriesNumber, $pointData ) + { + $label = array( + "enabled" => true, + "vAlign" => "center", + "hAlign" => "center", + "text" => $this->getChartLabelText( $seriesNumber, $pointData["value"] ) + ); + + if( $this->gaugeType == "circular-gauge" ) + { + $label["offsetY"] = -150; //fix it + $label["anchor"] = "center"; + + $label["background"] = array( + "enabled" => true, + "fill" => "#fff", + "cornerType" => "round", + "corner" => 0 + ); + + $label["padding"] = array( + "top" => 15, + "right" => 20, + "bottom" => 15, + "left" => 20 + ); + } + + return array( $label ); + } + + /** + * @param Number seriesNumber + * @return Array + */ + protected function getColorRanges( $seriesNumber ) + { + $ranges = array(); + if( count( $this->arrGaugeColor ) > 0 && array_key_exists($seriesNumber, $this->arrGaugeColor ) ) + { + foreach( $this->arrGaugeColor[ $seriesNumber ] as $ind => $val ) + { + $ranges[] = array( + "radius" => 70, + "from" => $val[0], + "to" => $val[1], + "fill" => $val[2], + "endSize" => "10%", + "startSize" => "10%" + ); + } + } + + return $ranges; + } + + /** + * @param Number seriesNumber + * @return Array + */ + protected function getAxesSettings( $seriesNumber ) + { + $axes = array(); + + if( $this->gaugeType == "circular-gauge" ) + { + $axes["startAngle"] = -150; + $axes["sweepAngle"] = 300; + + $scalesData = $this->getGaugeScales( $seriesNumber ); + + $axes["scale"] = array( + "maximum" => $scalesData["max"], + "minimum" => $scalesData["min"], + "ticks" => array( "interval"=> $scalesData["interval"] ), + "minorTicks" => array( "interval" => $scalesData["interval"] / 2 ) + ); + + $axes["ticks"] = array( + "type" => "trapezoid", + "interval" => $scalesData["interval"] + ); + + $axes["minorTicks"] = array( + "enabled" => true, + "length" => 2 + ); + + if ( @$this->chrt_array["appearance"]["color131"] != "" ) + $axes["fill"] = "#".$this->chrt_array["appearance"]["color131"]; + } + + $axes["enabled"] = true; + $axes["labels"] = array( "enabled" => $this->chrt_array["appearance"]["sval"] == "true" ); + + if ( @$this->chrt_array["appearance"]["color61"] != "" ) + $axes["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color61"]; + + return $axes; + } + + /** + * @param Number seriesNumber + * @return Array + */ + protected function getGaugeScales( $seriesNumber ) + { + $min = $this->chrt_array["parameters"][ $seriesNumber ]["gaugeMinValue"]; + $max = $this->chrt_array["parameters"][ $seriesNumber ]["gaugeMaxValue"]; + + if( !is_numeric( $min ) ) + $min = 0; + + if( !is_numeric( $max ) ) + $max = 100; + + $diff = $max - $min; + $slog = floor( log10( $diff ) ); + $interval = pow(10, $slog - 2); + $muls = array(1,2,3,5,10); + + while(true) + { + foreach($muls as $m) + { + if( $diff / ($interval * $m) <= 10 ) + { + $interval*= $m; + break; + } + } + if( $diff / ($interval) <= 10 ) + break; + + $interval*= 10; + } + + return array( + "min" => $min, + "max" => $max, + "interval" => $interval + ); + } + + + public function getSubsetDataCommand( $ignoreFilterField = "" ) { + $dc = parent::getSubsetDataCommand(); + + if( $this->table_type == "project" ) { + require_once( getabspath('classes/orderclause.php') ); + + $orderObject = new OrderClause( $this->pSet, $this->cipherer, $this->sessionPrefix, $this->connection ); + $order = $orderObject->getOrderFields(); + $revertedOrder = array(); + + foreach( $order as $o ) { + $ro = $o; + $ro['dir'] = $ro['dir'] == "ASC" ? "DESC" : "ASC"; + + $revertedOrder[] = $ro; + } + + $dc->order = $revertedOrder; + } + + return $dc; + } + + /** + * + */ + public function get_data() + { + $data = array(); + + $dc = $this->getSubsetDataCommand(); + $this->beforeQueryEvent( $dc ); + + $rs = $this->dataSource->getList( $dc ); + if( !$rs ) { + showError( $this->dataSource->lastError() ); + } + + $row = $rs->fetchAssoc(); + if( $this->cipherer ) + $row = $this->cipherer->DecryptFetchedArray( $row ); + + if( !$row ) + $this->noRecordsFound = true; + + for($i = 0; $i < count($this->arrDataSeries); $i++) + { + if( $row ) + { + $data[$i] = array(); + $data[$i][] = $this->getPoint($i, $row); + } + } + + $series = array(); + for ( $i = 0; $i < count($this->arrDataSeries); $i++ ) + { + $series[] = $this->getSeriesData( $this->arrDataLabels[$i], $data[$i], $clickdata[$i], $i, count($this->arrDataSeries) > 1 ); + } + + return $series; + } + + /** + * @param String name + * @param Array pointsData + * @param Array clickData + * @param Number seriesNumber + * @param Boolean multiSeries (optional) + * @return Array + */ + protected function getSeriesData( $name, $pointsData, $clickData, $seriesNumber, $multiSeries = true ) + { + if( $this->gaugeType == "linearGauge" && count( $this->arrGaugeColor ) > 0 && array_key_exists( $seriesNumber, $this->arrGaugeColor ) ) + { + foreach( $this->arrGaugeColor[ $seriesNumber ] as $ind => $val ) + { + $pointsData[] = array( + "low" => $val[0], + "high" => $val[1] + ); + } + } + + return array( + "data" => $pointsData, + "labelText" => $this->getChartLabelText( $seriesNumber, $pointsData[0]["value"] ) + ); + } + + /** + * @param Number seriesNumber + * @param String value + * @return String + */ + protected function getChartLabelText( $seriesNumber, $value ) + { + if( $this->table_type == "project" && !$this->webchart ) + { + $fieldName = $this->arrDataSeries[ $seriesNumber ]; + + include_once getabspath('classes/controls/ViewControlsContainer.php'); + $viewControls = new ViewControlsContainer($this->pSet, PAGE_CHART); + + $data = array( $fieldName => $value ); + $viewValue = $viewControls->showDBValue( $fieldName, $data, "", "", false ); + + return $this->arrDataLabels[ $seriesNumber ].": ". $viewValue; + } + + return $this->arrDataLabels[ $seriesNumber ].": ". $value; + } +} + +class Chart_Ohlc extends Chart +{ + protected $ohcl_type; + + protected $arrOHLC_high = array(); + protected $arrOHLC_low = array(); + protected $arrOHLC_open = array(); + protected $arrOHLC_close = array(); + + function __construct( &$ch_array, $param ) + { + parent::__construct( $ch_array, $param ); + + $this->ohcl_type = $param["ohcl_type"]; + } + + /** + * @param Array params + */ + protected function setSpecParams( $params ) + { + if($this->table_type != "db") + { + $this->arrOHLC_open[] = $params['ohlcOpen']; + $this->arrOHLC_high[] = $params['ohlcHigh']; + $this->arrOHLC_low[] = $params['ohlcLow']; + $this->arrOHLC_close[] = $params['ohlcClose']; + return; + } + + if( $params['agr_func'] ) + { + $this->arrOHLC_open[] = $params['agr_func']."_".$params['table']."_".$params['ohlcOpen']; + $this->arrOHLC_high[] = $params['agr_func']."_".$params['table']."_".$params['ohlcHigh']; + $this->arrOHLC_low[] = $params['agr_func']."_".$params['table']."_".$params['ohlcLow']; + $this->arrOHLC_close[] = $params['agr_func']."_".$params['table']."_".$params['ohlcClose']; + } + else + { + $this->arrOHLC_open[] = $params['table']."_".$params['ohlcOpen']; + $this->arrOHLC_high[] = $params['table']."_".$params['ohlcHigh']; + $this->arrOHLC_low[] = $params['table']."_".$params['ohlcLow']; + $this->arrOHLC_close[] = $params['table']."_".$params['ohlcClose']; + } + } + + /** + * + */ + public function write() + { + $data = array(); + $chart = array(); + + $this->setTypeSpecChartSettings( $chart ); + if ( @$this->chrt_array["appearance"]["color71"] != "" || @$this->chrt_array["appearance"]["color91"] != "" ) + $chart["background"] = array(); + if ( @$this->chrt_array["appearance"]["color71"] != "" ) + $chart["background"]["fill"] = "#".$this->chrt_array["appearance"]["color71"]; + + if ( @$this->chrt_array["appearance"]["color91"] != "" ) + $chart["background"]["stroke"] = "#".$this->chrt_array["appearance"]["color91"]; + + $chart["credits"] = false; + $chart["title"] = array("enabled" => "true", "text" => $this->header); + if ( @$this->chrt_array["appearance"]["color101"] != "" ) + $chart["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color101"]; + + if( $this->chrt_array['appearance']['slegend'] == "true" && !$this->chartPreview ) + $chart["legend"] = array("enabled" => "true"); + + $data["chart"] = $chart; + echo my_json_encode( $data ); + } + + /** + * @param &Array chart + */ + protected function setTypeSpecChartSettings( &$chart ) + { + $chart["series"] = $this->get_data(); + foreach ($this->chrt_array["parameters"] as $seriesNum => $params) { + if ( @$params["ohlcColor"] != "" ) + { + $chart["series"][$seriesNum]["fallingStroke"] = "#".$params["ohlcColor"]; + $chart["series"][$seriesNum]["fallingFill"] = "#".$params["ohlcColor"]; + if ( $this->ohcl_type == "ohcl" ) + { + $chart["series"][$seriesNum]["risingStroke"] = "#".$params["ohlcColor"]; + $chart["series"][$seriesNum]["risingFill"] = "#".$params["ohlcColor"]; + } + } + if ( @$params["ohlcCandleColor"] != "" && $this->ohcl_type != "ohcl" ) + { + $chart["series"][$seriesNum]["risingStroke"] = "#".$params["ohlcCandleColor"]; + $chart["series"][$seriesNum]["risingFill"] = "#".$params["ohlcCandleColor"]; + } + } + + $chart["grids"] = $this->getGrids(); + $chart["logarithm"] = parent::getLogarithm(); + $chart["type"] = "financial"; + $chart["xScale"] = 0; + $chart["yScale"] = 1; + + $chart["yAxes"] = array( + array( + "enabled" => "true", + "title" => $this->y_axis_label, + "labels" => array("enabled" => $this->chrt_array["appearance"]["sval"] == "true") + )); + + if ( @$this->chrt_array["appearance"]["color61"] != "" ) + $chart["yAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color61"]; + + $chart["xAxes"] = array( + array( + "enabled" => "true", + "title" => array( 'text' => $this->footer ), + "labels" => array("enabled" => $this->chrt_array["appearance"]["sname"] == "true" ) + )); + + if ( @$this->chrt_array["appearance"]["color51"] != "" ) + $chart["xAxes"][0]["labels"]["fontColor"] = "#".$this->chrt_array["appearance"]["color51"]; + + if ( @$this->chrt_array["appearance"]["color111"] != "" ) + $chart["xAxes"][0]["title"]["fontColor"] = "#".$this->chrt_array["appearance"]["color111"]; + + if ( @$this->chrt_array["appearance"]["color131"] != "" ) + $chart["xAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color131"]; + + if ( @$this->chrt_array["appearance"]["color141"] != "" ) + $chart["yAxes"][0]["stroke"] = "#".$this->chrt_array["appearance"]["color141"]; + + if( $this->chrt_array["appearance"]["slog"] == "true" ) + { + $chart["scales"] = array( + array( "names" => array() ), + array( "logBase" => 10, "type" => "log" ) + ); + } + } + + /** + * @return Array + */ + public function get_data() + { + $data = array(); + $clickdata = array(); + + for ( $i = 0; $i < count( $this->arrOHLC_open ); $i++ ) + { + $data[$i] = array(); + $clickdata[$i] = array(); + } + + $dc = $this->getSubsetDataCommand(); + $this->beforeQueryEvent( $dc ); + + $rs = $this->dataSource->getList( $dc ); + if( !$rs ) { + showError( $this->dataSource->lastError() ); + } + + $row = $rs->fetchAssoc(); + if( $this->cipherer ) + $row = $this->cipherer->DecryptFetchedArray( $row ); + + if( !$row ) + $this->noRecordsFound = true; + + while( $row ) + { + for ( $i = 0; $i < count( $this->arrOHLC_open ); $i++ ) + { + $data[$i][] = $this->getPoint( $i, $row ); + + $strLabelFormat = $this->labelFormat( $this->strLabel, $row ); + $clickdata[$i][] = $this->getActions( $row , $this->arrDataSeries[$i], $strLabelFormat ); + } + + $row = $rs->fetchAssoc(); + if( $this->cipherer ) + $row = $this->cipherer->DecryptFetchedArray( $row ); + } + + $series = array(); + for ( $i = 0; $i < count( $this->arrOHLC_open ); $i++ ) + { + $series[] = $this->getSeriesData( $this->arrDataLabels[$i], $data[$i], $clickdata[$i], $i ); + } + + return $series; + } + + /** + * @return String + */ + protected function getSeriesType($seriesNumber) + { + if( $this->ohcl_type == "ohcl" ) + return "ohlc"; + + return "candlestick"; + } + + /** + * @param Boolean $multiSeries + * @return Array + */ + protected function getSeriesTooltip( $multiSeries ) { + $tooltipSettings = array( + "enabled" => true + ); + + return $tooltipSettings; + } + + /** + * @param Number seriesNumber + * @param Array row + * @return Array + */ + protected function getPoint( $seriesNumber, $row ) + { + if( $this->table_type!="db" || !$this->chrt_array['customLabels'] ) + { + $high = $row[ $this->arrOHLC_high[ $seriesNumber ] ]; + $low = $row[ $this->arrOHLC_low[ $seriesNumber ] ]; + $open = $row[ $this->arrOHLC_open[ $seriesNumber ] ]; + $close = $row[ $this->arrOHLC_close[ $seriesNumber ] ]; + } + else + { + $high = $row[ $this->chrt_array['customLabels'][ $this->arrOHLC_high[ $seriesNumber ] ] ]; + $low = $row[ $this->chrt_array['customLabels'][ $this->arrOHLC_low[ $seriesNumber ] ] ]; + $open = $row[ $this->chrt_array['customLabels'][ $this->arrOHLC_open[ $seriesNumber ] ] ]; + $close = $row[ $this->chrt_array['customLabels'][ $this->arrOHLC_close[ $seriesNumber ] ] ]; + } + + return array( + "x" => $this->labelFormat( $this->strLabel, $row ), + "open" => (double)$open, + "high" => (double)$high, + "low" => (double)$low, + "close" => (double)str_replace(",", ".", $close) + ); + } +} +?> \ No newline at end of file diff --git a/php/classes/cipherer.php b/php/classes/cipherer.php new file mode 100644 index 0000000000000000000000000000000000000000..d15013f33735d7053a7417011b94c53335781171 --- /dev/null +++ b/php/classes/cipherer.php @@ -0,0 +1,341 @@ +strTableName = $strTableName; + + $this->setConnection(); + + if( $this->connection->dbBased() ) { + $this->key = $this->connection->_encryptInfo["key"]; + $this->alg = $this->connection->_encryptInfo["alg"]; + $this->mode = $this->connection->_encryptInfo["mode"]; + } + + if($pSet != null) + $this->pSet = $pSet; + else + $this->pSet = new ProjectSettings($strTableName); + } + + /** + * Set the 'connection' property + */ + protected function setConnection() + { + global $cman; + + if( $this->strTableName != GLOBAL_PAGES ) + $this->connection = $cman->byTable( $this->strTableName ); + else + $this->connection = getDefaultConnection(); + + if ( $this->connection->dbType == nDATABASE_MSSQLServer && $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_AES && $this->connection->_encryptInfo["mode"] == ENCRYPTION_DB ) + { + $symmetricSql = mysprintf("OPEN SYMMETRIC KEY [%s] DECRYPTION BY CERTIFICATE [%s];", array($this->connection->_encryptInfo["slqserverkey"], $this->connection->_encryptInfo["slqservercert"])); + $this->connection->setInitializingSQL($symmetricSql); + } + } + + function isEncryptionByPHPEnabled() + { + return $this->connection->isEncryptionByPHPEnabled(); + } + + /** + * DecryptFetchedArray + * Fetching record from sql result, looking through array of fetched values and decrypted all encrypted fields + * @param {array} fetchedArray + * @return {array} decrypted array + */ + public function DecryptFetchedArray( $fetchedArray ) + { + $result = array(); + + if($fetchedArray) + { + if( !$this->pSet->hasEncryptedFields() || !$this->connection->isEncryptionByPHPEnabled() ) + return $fetchedArray; + + foreach ($fetchedArray as $fieldName => $fieldValue) + { + $result[ $fieldName ] = $this->DecryptField($fieldName, $fieldValue); + } + } + + return $result; + } + + /** + * @param String field + * @param String + */ + public function isFieldEncrypted($field) + { + $table = $this->strTableName; + + if( array_key_exists($table, $this->encryptedFields) && array_key_exists($field, $this->encryptedFields[ $table ]) ) + return $this->encryptedFields[ $table ][ $field ]; + + if( !array_key_exists($table, $this->encryptedFields) ) + $this->encryptedFields[ $table ] = array(); + + $this->encryptedFields[ $table ][ $field ] = $this->pSet->isFieldEncrypted($field); + return $this->encryptedFields[ $table ][ $field ]; + } + + /** + * @param String field + * @return Boolean + */ + public function isFieldPHPEncrypted($field) + { + return $this->connection->isEncryptionByPHPEnabled() && $this->isFieldEncrypted($field); + } + + /** + * @param String field + * @param Mixed value + * @param String controltype (optional) + * @param Boolean phpEncryptionOnly (optional) + */ + public function MakeDBValue($field, $value, $controltype = "", $phpEncryptionOnly = false) + { + $ret = prepare_for_db($field, $value, $controltype, "", $this->strTableName); + if( $ret === false ) + return $ret; + + $ret = add_db_quotes($field, $this->EncryptField($field, $ret), $this->strTableName ); + + if( $phpEncryptionOnly ) + return $ret; + + return $this->EncryptValueByDB($field, $ret); + } + + /** + * @param String field + * @param Mixed value + */ + public function AddDBQuotes($field, $value) + { + return $this->EncryptValueByDB( $field, add_db_quotes($field, $this->EncryptField($field, $value), $this->strTableName) ); + } + + + /** + * GetFieldName + * Add to field name decryption function if field is encrypted by database + * @param {string} field name + * @param {string} alias of field name + * @param {bool} shows if 'as' construction needed + * @return {string} + */ + public function GetFieldName($field, $alias = null, $addAs = false) + { + if($this->connection->isEncryptionByPHPEnabled() || !$this->isFieldEncrypted($alias != null ? $alias : $field)) + return $field; + + return $this->GetEncryptedFieldName($field, $alias, $addAs); + } + + /** + * Get an SQL expression retriving the encrypted field's value + * Please note, when changing this function you should make appropriate changes in wizard method (dynamic permissions --> add new user) #8923 + * @param {string} field + * @param {string} alias + * @param {string} addAs + * @return {string} + */ + public function GetEncryptedFieldName($field, $alias = null, $addAs = false) + { + $result = ""; + if ( $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_DES) + { + if( $this->connection->dbType == nDATABASE_Oracle ) + $result = "utl_raw.cast_to_varchar2(DBMS_CRYPTO.DECRYPT(utl_raw.cast_to_raw(%s), 4353, utl_raw.cast_to_raw('%s')))"; + elseif( $this->connection->dbType == nDATABASE_MSSQLServer ) + $result = "CAST(DecryptByPassPhrase(N'%s', %s) as nvarchar)"; + elseif( $this->connection->dbType == nDATABASE_MySQL ) + $result = "cast(DES_DECRYPT(unhex(%s), '%s') as char)"; + elseif( $this->connection->dbType == nDATABASE_PostgreSQL ) + $result = "pgp_sym_decrypt(CAST(%s as bytea), '%s')"; + } + else if ( $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_AES) + { + if( $this->connection->dbType == nDATABASE_Oracle ) + { + $result = "utl_raw.cast_to_varchar2(DBMS_CRYPTO.DECRYPT(utl_raw.cast_to_raw(%s), 4358, utl_raw.cast_to_raw('%s')))"; + $this->key = substr($this->key, 0, 16); + } + elseif( $this->connection->dbType == nDATABASE_MSSQLServer ) + { + $result = "CAST(DecryptByKey(%s) as nvarchar(4000))"; + $this->key = $field; // for use in first as parametr in mysprintf func + } + elseif( $this->connection->dbType == nDATABASE_MySQL ) + $result = "cast(AES_DECRYPT(unhex(%s), '%s') as char)"; + elseif( $this->connection->dbType == nDATABASE_PostgreSQL ) + $result = "pgp_sym_decrypt(CAST(%s as bytea), '%s', 'cipher-algo=aes128')"; + } + + if($result == "") + return $field; + + if( $this->connection->dbType == nDATABASE_MSSQLServer ) + $result = mysprintf($result, array($this->key, $field)); + else + $result = mysprintf($result, array($field, $this->key)); + + return $addAs ? $result." as ".$this->connection->addFieldWrappers($alias != null ? $alias : $field) : $result; + } + + /** + * EncryptValueByDB + * Add to field name encryption function if field is encrypted by database + * Please note, when changing this function you should make appropriate changes in wizard method (dynamic permissions --> add new user) #8923 + * @param {string} field name + * @param {mixed} value + * @return {string} + */ + public function EncryptValueByDB($field, $value) + { + if( !$this->isFieldEncrypted($field) || $this->connection->isEncryptionByPHPEnabled() ) + return $value; + + $result = ""; + + if ( $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_DES) + { + if( $this->connection->dbType == nDATABASE_Oracle ) + $result = "utl_raw.cast_to_varchar2(DBMS_CRYPTO.ENCRYPT(utl_raw.cast_to_raw(%s), 4353, utl_raw.cast_to_raw('%s')))"; + elseif( $this->connection->dbType == nDATABASE_MSSQLServer ) + $result = "EncryptByPassPhrase(N'%s', %s)"; + elseif( $this->connection->dbType == nDATABASE_MySQL ) + $result = "hex(DES_ENCRYPT(%s, '%s'))"; + elseif( $this->connection->dbType == nDATABASE_PostgreSQL ) + $result = "pgp_sym_encrypt(%s, '%s')"; + } + else if ( $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_AES) + { + if( $this->connection->dbType == nDATABASE_Oracle ) + { + $result = "utl_raw.cast_to_varchar2(DBMS_CRYPTO.ENCRYPT(utl_raw.cast_to_raw(%s), 4358, utl_raw.cast_to_raw('%s')))"; + $this->key = substr($this->key, 0, 16); + } + elseif( $this->connection->dbType == nDATABASE_MSSQLServer ) + { + $result = "EncryptByKey(Key_GUID('%s'), %s)"; + $this->key = $this->connection->_encryptInfo["slqserverkey"]; + } + elseif( $this->connection->dbType == nDATABASE_MySQL ) + $result = "hex(AES_ENCRYPT(%s, '%s'))"; + elseif( $this->connection->dbType == nDATABASE_PostgreSQL ) + $result = "pgp_sym_encrypt(%s, '%s', 'cipher-algo=aes128')"; + } + + if($result != "") + { + if( $this->connection->dbType == nDATABASE_MSSQLServer ) + $result = mysprintf($result, array($this->key, $value)); + else + $result = mysprintf($result, array($value, $this->key)); + } + else + $result = $value; + + return $result; + } + + /** + * EncryptField + * Determine if field need to be encrypted and encrypt value if it so + * @param {string} field name + * @param {string} value + * @return {string} encrypted or plain value + */ + public function EncryptField($field, $value) + { + if( $this->isFieldEncrypted($field) && $this->connection->isEncryptionByPHPEnabled() ) + { + if( is_null($this->ESFunctions) ) + $this->ESFunctions = $this->getESFunctions(); + + return $this->ESFunctions->Encrypt($value); + } + + return $value; + } + + /** + * DecryptField + * Determine if field encrypted and decrypt value if it so + * Please note, when changing this function you should make appropriate changes in wizard method (dynamic permissions --> add new user) #8923 + * @param {string} field name + * @param {string} value + * @return {string} decrypted or plain value + */ + public function DecryptField($field, $value) + { + if($this->isFieldEncrypted($field) && $this->connection->isEncryptionByPHPEnabled()) + { + if(is_null($this->ESFunctions)) + $this->ESFunctions = $this->getESFunctions(); + + return $this->ESFunctions->Decrypt($value); + } + return $value; + } + + function getESFunctions() + { + if ( $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_DES ) + return new RunnerCiphererDES($this->key); + if ( $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_AES ) + return new RunnerCiphererAES($this->key); + if ( $this->connection->_encryptInfo["alg"] == ENCRYPTION_ALG_AES_256 ) + return new RunnerCiphererAES($this->key, true); + } + + /** + * @param Mixed loginSet (optional) + * @return Mixed + */ + public static function getForLogin( $loginSet = null ) + { + if( !!Security::loginTable() ) { + return new RunnerCipherer( "public.kbusers", $loginSet); + } + return new RunnerCipherer( GLOBAL_PAGES, null); + } +} +?> \ No newline at end of file diff --git a/php/classes/context.php b/php/classes/context.php new file mode 100644 index 0000000000000000000000000000000000000000..7548e853d7846bf5b7703602c4ddf76c5a161a99 --- /dev/null +++ b/php/classes/context.php @@ -0,0 +1,623 @@ +type = $type; + } + + public function getType() + { + return $this->type; + } + + /** + * @return Array + */ + public function getValues() + { + if( $this->data ) + return $this->data; + + if( $this->dc ) { + return $this->dc->values; + } + + if( $this->pageObj ) + return $this->pageObj->getCurrentRecord(); + + return array(); + } + + /** + * @param String field + * @return Mixed + */ + public function getFieldValue( $field ) + { + $data = $this->getValues(); + return getArrayElementNC( $data, $field ); + } + + public function getSearchValue( $field ) { + return $this->searchClause->_getFieldValue( $field, null, false, true ); + } + + public function getAllSearchValue() { + return $this->searchClause->getAllFieldsSearchValue(); + } + + /** + * @return Array + */ + public function getOldValues() + { + if( $this->oldData ) + return $this->oldData; + + if( $this->pageObj ) + return $this->pageObj->getOldRecordData(); + + return array(); + } + + public function getKeyValue( $field ) { + if( $this->dc ) { + return $this->dc->keys[ $field ]; + } + return null; + } + + public function getOrderValue( $key ) { + if( !$this->dc ) { + return null; + } + $idx = 0; + if( substr( $key, 0, 5) == "field" ) { + $param = "field"; + $idx = (int)substr( $key, 5); + } else if( substr( $key, 0, 3 ) == "dir" ) { + $param = "dir"; + $idx = (int)substr( $key, 3); + } + if( !$idx || $idx < 1 ) { + return null; + } + if( count( $this->dc->order ) <= $idx ) { + return null; + } + $order = $this->dc->order[ $idx - 1 ]; + if( $param == "field") { + return $order["column"]; + } + if( $param == "dir") { + return $order["dir"]; + } + return null; + } + + + public function getFilterValue( $field ) { + if( $this->dc ) { + return $this->dc->findFieldFilterValue( $field ); + } + } + + public function getLimitValue( $key ) { + if( !$this->dc ) { + return ""; + } + if( $key == "record_from" ) { + return $this->dc->startRecord + 1; + } + if( $key == "record_to" ) { + return $this->dc->startRecord + $this->dc->reccount; + } + if( $key == "record_count" ) { + return $this->dc->reccount; + } + if( $key == "record_offset" ) { + return $this->dc->startRecord; + } + } + + + /** + * @param String field + * @return Mixed + */ + public function getOldFieldValue( $field ) + { + $oldData = $this->getOldValues(); + return getArrayElementNC( $oldData, $field ); + } + + /** + * @param String field + * @return Mixed + */ + public function getNewFieldValue( $field ) + { + if ( $this->newData ) + return getArrayElementNC( $this->newData, $field ); + if( $this->dc ) { + return getArrayElementNC( $this->dc->values, $field ); + } + + return $this->getFieldValue( $field ); + } + + + + /** + * @return Array + */ + public function getMasterValues() + { + if( $this->masterData ) + return $this->masterData; + + if( $this->pageObj ) + return $this->pageObj->getMasterRecord(); + + return array(); + } + + /** + * @param String field + * @return Mixed + */ + public function getMasterFieldValue( $field ) + { + $masterData = $this->getMasterValues(); + if( !$masterData ) { + return ""; + } + return getArrayElementNC( $masterData, $field ); + + } + + /** + * @param String key + * @return String + */ + public function getUserValue( $key ) + { + return getArrayElementNC( Security::currentUserData(), $key ); + } + + /** + * @param String key + * @return Mixed + */ + public function getSessionValue( $key ) + { + return getSessionElementNC( $key ); + } + + public function getDetailsKeyValue( $key ) { + return $this->detailsKeys[ $key ]; + } + + + /** + * Returns true if context must serve this scope, and search must stop here. + * For example, when page context is found, it must serve the 'master' and 'details' scopes even if no master-detail is in effect. + * @param String - scope like 'keys', 'master', 'details' + * @return Boolean + */ + public function hasScope( $scope ) { + if( $scope == "master" ) + return $this->masterData || $this->type == CONTEXT_PAGE; + + if( $scope == "session" ) + return true; + + if( $scope == "user" ) + return true; + + if( $scope == "old" ) + return $this->oldData || $this->type == CONTEXT_PAGE; + + if( $scope == "keys" ) + return $this->type == CONTEXT_COMMAND; + + if( $scope == "order" ) + return $this->type == CONTEXT_COMMAND; + + + if( $scope == "new" ) + return $this->newData || $this->type == CONTEXT_PAGE || $this->type == CONTEXT_COMMAND; + + if ( $scope == "global" ) + return true; + + if( $scope == "details" ) + return $this->type == CONTEXT_PAGE || $this->type == CONTEXT_MASTER; + + if ( $scope == "values" ) + return !!$this->data || $this->type == CONTEXT_PAGE || $this->type == CONTEXT_COMMAND; + + if( $scope == "search" ) + return $this->type == CONTEXT_SEARCH; + + if( $scope == "filter" ) + return $this->type == CONTEXT_COMMAND; + + if( $scope == "request" ) + return true; + + if( $scope == "limit" ) + return $this->type == CONTEXT_COMMAND; + + if( $scope == "all_field_search" ) + return $this->type == CONTEXT_SEARCH; + } + + /** + * @param String key + * @return Mixed + */ + public function getContextValue( $scope, $key ) + { + + if( $scope == "master" ) + return $this->getMasterFieldValue( $key ); + + if( $scope == "session" ) + return $this->getSessionValue( $key ); + + if( $scope == "user" ) + return $this->getUserValue( $key ); + + if( $scope == "old" ) + return $this->getOldFieldValue( $key ); + + if( $scope == "keys" ) + return $this->getKeyValue( $key ); + + if( $scope == "order" ) + return $this->getOrderValue( $key ); + + if( $scope == "new" ) + return $this->getNewFieldValue( $key ); + + if ( $scope == "global" && $key == "language" ) + return mlang_getcurrentlang(); + + if( $scope == "details" ) { + if( $this->type == CONTEXT_PAGE ) + return $this->pageObj->getDetailsKeyValue( $key ); + if( $this->type == CONTEXT_MASTER ) + return $this->getDetailsKeyValue( $key ); + } + + if( $scope == "values" ) + return $this->getFieldValue( $key ); + + if( $scope == "search" ) + return $this->getSearchValue( $key ); + + if( $scope == "filter" ) + return $this->getFilterValue( $key ); + + if( $scope == "request" ) + return postvalue( $key ); + + if( $scope == "limit" ) + return $this->getLimitValue( $key ); + + if( $scope == "all_field_search" ) + return $this->getAllSearchValue(); + + return false; + } +} + +/** + * Singletone. All public functions are static + */ +class RunnerContext +{ + protected $stack = array(); + + public function __construct( ) + { + $context = new RunnerContextItem( CONTEXT_GLOBAL, array() ); + $this->stack[ count($this->stack) ] = $context; + } + + public static function push( $context ) + { + global $contextStack; + $contextStack->stack[ count($contextStack->stack) ] = $context; + } + + public static function current( ) + { + global $contextStack; + return $contextStack->stack[ count($contextStack->stack) - 1 ]; + } + + public static function pop( ) + { + global $contextStack; + + // this sometimes happens during the error reporting + if( !$contextStack->stack ) + return null; + + $context = $contextStack->stack[ count($contextStack->stack) - 1 ]; + unset( $contextStack->stack[ count($contextStack->stack) - 1 ] ); + + return $context; + } + + // Utility functions + /** + * Shortcut for adding page-based context + */ + public static function pushPageContext( $pageObj ) { + RunnerContext::push( new RunnerContextItem( CONTEXT_PAGE, array( "pageObj" => $pageObj ) ) ); + } + /** + * Shortcut for adding record-based context + */ + public static function pushRecordContext( $record, $pageObj ) { + RunnerContext::push( new RunnerContextItem( CONTEXT_ROW, array( "pageObj" => $pageObj, "data" => $record ) ) ); //? + } + + public static function pushDataCommandContext( $dc ) { + RunnerContext::push( new RunnerContextItem( CONTEXT_COMMAND, array( "dc" => $dc ) ) ); + } + + public static function pushSearchContext( $searchClause ) { + RunnerContext::push( new RunnerContextItem( CONTEXT_SEARCH, array( "searchClause" => $searchClause ) ) ); + } + + public static function pushMasterContext( $detailsKeys ) { + RunnerContext::push( new RunnerContextItem( + CONTEXT_MASTER, + array( + "detailsKeys" => $detailsKeys, + ) ) ); + } + + + public static function getMasterValues() { + $ctx = RunnerContext::current(); + return $ctx->getMasterValues(); + } + + public static function getValues() { + $ctx = RunnerContext::current(); + return $ctx->getValues(); + } + + /** + * @return String + */ + public static function PrepareRest( $str, $urlenc = true ) { + $context = RunnerContext::current(); + $tokens = DB::scanTokenString($str); + + $replacements = array(); + // build array of replacements in this format: + // "offset" => position in the string where replacement should be done + // "len" => length of original substring to cut out + // "insert" => string to insert in place of cut out + + foreach ($tokens["matches"] as $i => $match) { + $offset = $tokens["offsets"][$i]; + $token = $tokens["tokens"][$i]; + + $repl = array( + "offset" => $offset, + "len" => strlen($match) + ); + $val = ""; + if (is_numeric($token) && count( $args ) > $token) { + $val = $args[(int)$token]; + } else { + $val = RunnerContext::getValue($token); + } + if( $urlenc ) + $val = rawurlencode($val); + $repl["insert"] = $val; + + $replacements[] = $repl; + } + // do replacements + return RunnerContext::doReplacements( $str, $replacements ); + } + + /** + * locate all snippets in a string + * @param String str + * @return Array of array( + * "offset" => integer - offset of the opening bracket in the original string + * "len" => integer - length includes opening and closing brackets: + * ) + */ + protected static function getOptionalBlocks( $str ) { + if( !is_string( $str ) ) + return array(); + + $snippetStack = array(); + $snippets = array(); + $pos = strpos( $str, ' before the next ', $endPos+1 ) ) !== false && count( $snippetStack ) ) { + $stackIdx = count( $snippetStack ) - 1; + $snippets[] = array( "offset" => $snippetStack[ $stackIdx ], "len" => $endPos + $pos + 2 - $snippetStack[ $stackIdx ] ); + $snippetStack = array_slice( $snippetStack, 0, $stackIdx ); + } + if( $newPos === false ) + break; + $pos = $newPos; + } + return $snippets; + } + + /** + * do actual replacements + * @param String $str - source string + * @param Array $replacements - Array of Array( + * "offset" => Integer, position in the source tring + * "len" => Integer, length of the source string portion to be replaced + * "insert" => String, value to insert instead of replaced + * ) + */ + public static function doReplacements( $str, $replacements ) { + if( !is_string( $str ) ) + return $str; + + $snippets = RunnerContext::getOptionalBlocks( $str ); + /* snippets with 0 non-empty requirements must be deleted from the string */ + /* mark empty snippets */ + for( $i=0; $i < count( $snippets ); ++$i ) { + $s = &$snippets[$i]; + $s["empty"] = true; + foreach ($replacements as $r) { + /* replacement inside snippet */ + if( $r["offset"] > $s["offset"] && $r["offset"] < $s["offset"] + $s["len"] ) { + if( $r["insert"] != "" ) { + $s["empty"] = false; + break; + } + } + } + } + + /* do replacements */ + $offsetShift = 0; + foreach ($replacements as $r) { + $str = substr_replace($str, $r["insert"], $r["offset"] + $offsetShift, $r["len"]); + $offsetDelta = strlen($r["insert"]) - $r["len"]; + // update all $snippets + RunnerContext::updateOptionalBlockOffset( $snippets, $r["offset"], $offsetDelta ); + $offsetShift += $offsetDelta; + } + + /* process optional blocks - delete or remove brackets */ + for( $i=0; $i < count( $snippets ); ++$i ) { + $s = &$snippets[$i]; + if( $s["empty"]) { + $str = substr_replace($str, "", $s["offset"], $s["len"] ); + $offsetDelta = -$s["len"]; + } else { + $str = substr_replace($str, + substr( $str, $s["offset"] + 2, $s["len"] - 4 ), + $s["offset"], + $s["len"] + ); + $offsetDelta = -4; + } + RunnerContext::updateOptionalBlockOffset( $snippets, $s["offset"], $offsetDelta ); + } + return $str; + } + + protected static function updateOptionalBlockOffset( &$snippets, $offset, $delta ) { + for( $i=0; $i < count( $snippets ); ++$i ) { + $s = &$snippets[$i]; + if( $s["offset"] > $offset ) { + $s["offset"] += $delta; + } else { + if( $s["offset"] + $s["len"] > $offset ) { + $s["len"] += $delta; + } + } + } + } + + + public static function getValue( $key ) { + $prefix = ""; + $dotPos = strpos( $key, "."); + if( $dotPos !== FALSE ) + { + $scope = strtolower( substr( $key, 0, $dotPos ) ); + $key = substr( $key, $dotPos + 1 ); + } else { + if( $key === "language" ) { + $scope = "global"; + } else if( $key == "all_field_search") { + $scope = $key; + } else { + $scope = "values"; + } + + } + return RunnerContext::_getValue( $scope, $key ); + } + + + /** + * Search got requested value in the stack of contexts + * @param String - scope like 'keys', 'master', 'details' + * @param String - key. 'details.teamId' is translated to context=details, key=teamId + * @return String or false if value is not found + */ + protected static function _getValue( $scope, $key ) + { + global $contextStack; + $idx = count( $contextStack->stack ); + while( $idx > 0 ) { + $ctx = $contextStack->stack[ --$idx ]; + if( $ctx->hasScope( $scope ) ) { + return $ctx->getContextValue( $scope, $key ); + } + } + return false; + } + +} + +/** + * Push context in constructor and pop in destructor + */ +class TempContext +{ + function __construct( $context ) { + RunnerContext::push( $context ); + } + + function __destruct() { + RunnerContext::pop(); + } +} + +?> \ No newline at end of file diff --git a/php/classes/controls/CheckboxField.php b/php/classes/controls/CheckboxField.php new file mode 100644 index 0000000000000000000000000000000000000000..15b2883c1def7e9571ec4b0c49fb1995a977bb11 --- /dev/null +++ b/php/classes/controls/CheckboxField.php @@ -0,0 +1,91 @@ +format = EDIT_FORMAT_CHECKBOX; + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + if($mode == MODE_ADD || $mode == MODE_INLINE_ADD || $mode == MODE_EDIT || $mode == MODE_INLINE_EDIT) + { + $checked = ""; + + if( $this->connection->dbType == nDATABASE_PostgreSQL + && ($value === "t" || $value != "f" && $value != "" && $value != 0 ) + || $this->connection->dbType != nDATABASE_PostgreSQL && ($value != "" && $value != 0 )) { + + $checked=" checked"; + } + + if ( $this->connection->dbType == nDATABASE_PostgreSQL ) { + $reservedBoolean = 'data-true="t" data-false="f"'; + } + + echo ''; + } + else + { + echo ''; + echo '"; + } + $this->buildControlEnd($validate, $mode); + } + + function getFirstElementId() + { + return $this->cfield; + } + + /** + * Get 'equal to on/off' condition + */ + public static function getFieldCondition( $field, $searchFor ) { + if( $searchFor == "none" || $searchFor != "on" && $searchFor != "off" ) + return null; + + $offCondition = DataCondition::_Or( array( + DataCondition::FieldIs( $field, dsopEQUAL, '0', false, 0, null, false ), + DataCondition::FieldIs( $field, dsopEMPTY, '', false, 0, null, false ) + )); + + if( $searchFor == "off" ) + return $offCondition; + + return DataCondition::_Not( $offCondition ); + } + + /** + * Returns basic condition + */ + public function getBasicFieldCondition( $searchFor, $strSearchOption, $searchFor2 = "", $etype = "" ) { + if( $strSearchOption != EQUALS ) + return null; + + return CheckboxField::getFieldCondition( $this->field, $searchFor ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/Control.php b/php/classes/controls/Control.php new file mode 100644 index 0000000000000000000000000000000000000000..b389bea80bef457b1d1fc02fcce4274a16b0ef78 --- /dev/null +++ b/php/classes/controls/Control.php @@ -0,0 +1,790 @@ +field = $field; + $this->goodFieldName = GoodFieldName($field); + $this->setID($id); + $this->connection = $connection; + + $this->pageObject = $pageObject; + + $this->is508 = isEnableSection508(); + + $this->strLabel = $pageObject->pSetEdit->label($field); + $this->type = $pageObject->pSetEdit->getFieldType($this->field); + + if( $this->connection->dbType == nDATABASE_Oracle ) + $this->isOracle = true; + + if( $this->connection->dbType == nDATABASE_MSSQLServer ) + $this->ismssql=true; + + if( $this->connection->dbType == nDATABASE_DB2 ) + $this->isdb2=true; + + if( $this->connection->dbType == nDATABASE_MySQL ) + $this->isMysql = true; + + if( $this->connection->dbType == nDATABASE_PostgreSQL ) + $this->like = "ilike"; + + $this->searchOptions[CONTAINS] = "Contains"; + $this->searchOptions[EQUALS] = "Equals"; + $this->searchOptions[STARTS_WITH] = "Starts with"; + $this->searchOptions[MORE_THAN] = "More than"; + $this->searchOptions[LESS_THAN] = "Less than"; + $this->searchOptions[BETWEEN] = "Between"; + $this->searchOptions[EMPTY_SEARCH] = "Empty"; + $this->searchOptions[NOT_CONTAINS] = "Doesn't contain"; + $this->searchOptions[NOT_EQUALS] = "Doesn't equal"; + $this->searchOptions[NOT_STARTS_WITH] = "Doesn't start with"; + $this->searchOptions[NOT_MORE_THAN] = "Is not more than"; + $this->searchOptions[NOT_LESS_THAN] = "Is not less than"; + $this->searchOptions[NOT_BETWEEN] = "Is not between"; + $this->searchOptions[NOT_EMPTY] = "Is not empty"; + + $this->init(); + } + + function setID($id) + { + $this->id = $id; + $this->cfieldname = $this->goodFieldName."_".$id; + $this->cfield = "value_".$this->goodFieldName."_".$id; + $this->ctype = "type_".$this->goodFieldName."_".$id; + } + + /** + * addJSFiles + * Add control JS files to page object + */ + function addJSFiles() + { + //example + // $this->pageObject->AddJSFile("include/mupload.js"); + } + + /** + * addCSSFiles + * Add control CSS files to page object + */ + function addCSSFiles() + { + //example + // $this->pageObject->AddCSSFile("include/mupload.css"); + } + + function getSetting($key) + { + return $this->pageObject->pSetEdit->getFieldData($this->field, $key); + } + + function addJSSetting($key, $value) + { + $this->pageObject->jsSettings['tableSettings'][ $this->pageObject->tName ]['fieldSettings'][ $this->field ][ $this->container->pageType ][ $key ] = $value; + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + $this->searchPanelControl = $this->isSearchPanelControl( $mode, $additionalCtrlParams ); + $this->inputStyle = $this->getInputStyle( $mode ); + + if($fieldNum) + { + $this->cfield="value".$fieldNum."_".$this->goodFieldName."_".$this->id; + $this->ctype="type".$fieldNum."_".$this->goodFieldName."_".$this->id; + } + + $this->iquery = "field=".rawurlencode($this->field); + + $arrKeys = $this->pageObject->pSetEdit->getTableKeys(); + for ($j = 0; $j < count($arrKeys); $j++) + { + $this->keylink .= "&key".($j+1)."=".rawurlencode( $data[ $arrKeys[$j] ] ); + } + $this->iquery .= $this->keylink; + + $isHidden = (isset($additionalCtrlParams['hidden']) && $additionalCtrlParams['hidden']); + + $additionalClass = ""; + if( $this->pageObject->isBootstrap() ) + { + if( $this->pageObject->isPD() ) { + $additionalClass.= "bs-ctrlspan "; + } else { + $additionalClass.= "bs-ctrlspan rnr-nowrap "; + } + if( $this->format == EDIT_FORMAT_READONLY ) + $additionalClass.= "form-control-static "; + + if( $validate['basicValidate'] && array_search('IsRequired', $validate['basicValidate']) !== false ) + $additionalClass.= "bs-inlinerequired"; + } + else + { + $additionalClass.= "rnr-nowrap "; + } + + echo ''; + else if( $validate['basicValidate'] && array_search('IsRequired', $validate['basicValidate'])!==false) + echo' *'; + else + echo ''; + } + + function getPostValueAndType() + { + $this->webValue = postvalue("value_".$this->goodFieldName."_".$this->id); + $this->webType = postvalue("type_".$this->goodFieldName."_".$this->id); + } + + function getWebValue() + { + return $this->webValue; + } + + function readWebValue(&$avalues, &$blobfields, $legacy1, $legacy2, &$filename_values) + { + $this->getPostValueAndType(); + + if (FieldSubmitted($this->goodFieldName."_".$this->id)) + $this->webValue = prepare_for_db($this->field, $this->webValue, $this->webType); + else + $this->webValue = false; + + if($this->pageObject->pageType == PAGE_EDIT && $this->pageObject->getEditFormat( $this->field) === EDIT_FORMAT_READONLY ) + { + // ?? + if( $this->pageObject->pSetEdit->getAutoUpdateValue($this->field) ) + $this->webValue = $this->pageObject->pSetEdit->getAutoUpdateValue($this->field); + else if( !originalTableField( $this->field, $this->pageObject->pSetEdit ) ){ + $this->webValue = false; + } + } + + if(!($this->webValue===false)) + { + if( $this->connection->dbType == nDATABASE_Informix ) + { + if(IsTextType($this->pageObject->pSetEdit->getFieldType($this->field))) + $blobfields[] = $this->field; + } + $avalues[ $this->field ] = $this->webValue; + } + } + + /** + * Get the substitute columns list for the SELECT Clause and the FORM clause part + * that will be joined to the basic page's FROM clause + * @param String searchFor + * @param String searchOpt + * @param Boolean isSuggest + * @return Array + */ + public function getSelectColumnsAndJoinFromPart($searchFor, $searchOpt, $isSuggest) + { + return array( + "selectColumns"=> $this->getFieldSQLDecrypt(), + "joinFromPart"=> "" + ); + } + + /** + * @param String strSearchOption + * @return Boolean + */ + public function checkIfDisplayFieldSearch( $strSearchOption ) + { + return false; + } + + /** + * Form the control's search options markup basing on user's search options settings + * @param Array optionsArray Control specified search options + * @param String selOpt The control selected search option + * @param Boolean not It indicates if the search option passed should be inverted ($selOpt should be considered as "NOT ".$selOpt) + * @param Boolean both It indicates if control needs both positive and negative("NOT ...") search options + * @return String + */ + function buildSearchOptions($optionsArray, $selOpt, $not, $both) + { + $userSearchOptions = $this->pageObject->pSetEdit->getSearchOptionsList( $this->field ); + + $currentOption = $not ? 'NOT '.$selOpt : $selOpt; + if( $userSearchOptions && isset( $this->searchOptions[ $currentOption ] ) ) + $userSearchOptions[] = $currentOption; + + if( !!$userSearchOptions ) + $optionsArray = array_intersect($optionsArray, $userSearchOptions); + + $defaultOption = $this->pageObject->pSetEdit->getDefaultSearchOption( $this->field ); + if( !$defaultOption ) + $defaultOption = $optionsArray[0]; + + $result = ''; + foreach($optionsArray as $option) + { + if( !isset( $this->searchOptions[ $option ] ) || !$both && substr($option, 0, 4) == 'NOT ' ) + continue; + + $selected = $currentOption == $option ? 'selected' : ''; + $dataAttr = $defaultOption == $option ? ' data-default-option="true"' : ''; + $result.= ''; + } + return $result; + } + + /** + * Form the control specified search options array and built the control's search options markup + * @param String selOpt The search option value + * @param Boolean not It indicates if the search option negation is set + * @param Boolean both It indicates if the control needs 'NOT'-options + * @return String A string containing options markup + */ + function getSearchOptions($selOpt, $not, $both) + { + return $this->buildSearchOptions(array(EQUALS, NOT_EQUALS), $selOpt, $not, $both); + } + + /** + * Fill the response array with the suggest values + * + * @param String value + * Note: value is preceeded with "_" + * @param String searchFor + * @param &Array response + * @param &Array row + */ + function suggestValue($value, $searchFor, &$response, &$row) + { + $suggestStringSize = GetGlobalData("suggestStringSize", 40); + + if( $suggestStringSize <= runner_strlen($searchFor) ) + { + $response[ "_".$searchFor ] = $searchFor; + return; + } + + $viewFormat = $this->pageObject->pSetEdit->getViewFormat($this->field); + if( $viewFormat == FORMAT_NUMBER ) + { + $dotPosition = strpos($value, '.'); + if($dotPosition !== FALSE) + { + for($i = strlen($value) - 1; $i > $dotPosition; $i--) + { + if(substr($value, $i, 1) != '0') + { + if($i < strlen($value) - 1) + $value = substr($value, 0, $i + 1); + break; + } + if($i == $dotPosition + 1 && $dotPosition > 0) + { + $value = substr($value, 0, $dotPosition); + break; + } + } + } + } + + $realValue = $value; + + if( $viewFormat == FORMAT_HTML ) + { + // declarate patterns for regex + $html_tags = '/<.*?>/i'.($useUTF8 ? 'u':''); + $get_text = '/(.*<.*>|^.*?)([.]*'.preg_quote($searchFor, "/").'.*?)(<.*>|$)/i'.($useUTF8 ? 'u':''); + + // decode html entity and delete all html tags from value + $value = preg_replace($html_tags, '', runner_html_entity_decode($value)); + + // if not searchFor in value return + if (stristr($value, $searchFor) === false) + return; + + // get realValue (string between html tags) + if (preg_match($get_text, $realValue, $match)) + $realValue = $match[2]; + else + $realValue = $value; + } + + // if large string cut value and add dots + if( $suggestStringSize < runner_strlen($value) ) + { + $startPos = 0; + $valueLength = 0; + $suggestValues = $this->cutSuggestString( $value, $searchFor ); + if( $suggestValues ) { + if( $viewFormat == FORMAT_HTML ) { + $suggestValues["search"] = $realValue; + } + $response[ $suggestValues["display"] ] = $suggestValues["search"]; + } + } else { + $response[ $value ] = $realValue; + } + } + + /** + * Reduce long field value to leave only the text relevant to search suggest + * ( "There was a time when Mary had a little lamb", "Mary" ) => "when Mary had" + * @return Array - array of ( + * "search" => "when Mary had" - value that will be used for searching + * "display" => "...when Mary had..." - value to show to the user in the suggest list + * ) + * Returns false if anything went wrong + */ + function cutSuggestString( $_value, $searchFor ) + { + $suggestStringSize = GetGlobalData("suggestStringSize", 40); + $caseIns = $this->pageObject->pSetEdit->getNCSearch(); + + // split to lines. Line breaks shouldn't appear in the suggested values + $lines = explode( "\n", $_value ); + $value = ""; + for( $lineIdx = 0; $lineIdx< count( $lines); ++$lineIdx ) { + $line = $lines[ $lineIdx ]; + if( $caseIns ) + { + // case-insensitive search + $startPos = stripos($line, $searchFor); + if( $startPos ) + $startPos = runner_strlen( substr($line, 0 , $startPos) ); //UTF-8 support + } + else + { + $startPos = runner_strpos($line, $searchFor); + } + if( $startPos !== false ) + { + $value = $line; + break; + } + } + if( $startPos === false ) { + return false; + } + + // cut a chunk of the $value around the $searchFor. + // Paddings are parts of the chunk before and after $searchFor + // There are two "gray zones" at the begining and end of the chunk. + // If there are stop symbols ( spaces, commas ) in the gray zone, cut it up to them + // "tion of the next occu" => "of the next" + + $grayZoneLength = 5; + + $leftPaddingLength = min( $suggestStringSize / 2, $startPos ); + $leftPadding = runner_substr( $value, $startPos - $leftPaddingLength, $leftPaddingLength ); + $leftGrayZoneLength = $leftPaddingLength < $suggestStringSize / 2 + ? 0 + : $grayZoneLength; + + $rightPaddingLength = min( $suggestStringSize - $leftPaddingLength, runner_strlen( $value ) - $startPos - runner_strlen( $searchFor ) ); + $rightPadding = runner_substr( $value, $startPos + runner_strlen( $searchFor ), $rightPaddingLength ); + $rightGrayZoneLength = $rightPaddingLength < $suggestStringSize / 2 + ? 0 + : $grayZoneLength; + + $leftGrayZone = runner_substr( $leftPadding, 0, $leftGrayZoneLength ); + $stopPos = $this->findFirstStop( $leftGrayZone, true ); + if( $stopPos !== false ) { + $leftPadding = runner_substr( $leftPadding, $stopPos ); + } + + $rightGrayZone = runner_substr( $rightPadding, $rightPaddingLength - $rightGrayZoneLength ); + $stopPos = $this->findFirstStop( $rightGrayZone ); + if( $stopPos !== false ) { + $rightPadding = runner_substr( $rightPadding, 0, runner_strlen( $rightPadding ) - $rightGrayZoneLength + $stopPos ); + } + + $leftEllipsis = $lineIdx > 0 || runner_strlen( $leftPadding ) < $startPos + ? "... " + : ""; + $rightEllipsis = $lineIdx < count( $lines) - 1 || runner_strlen( $rightPadding ) < runner_strlen( $value ) - $startPos - runner_strlen( $searchFor ) + ? " ..." + : ""; + + $searchValue = $leftPadding . runner_substr( $value, $startPos, runner_strlen( $searchFor )) . $rightPadding; + return array( + "search" => $searchValue, + "display" => $leftEllipsis . $searchValue . $rightEllipsis + ); + } + + function findFirstStop( $str, $reverse = false ) { + $stopSymbols = " .,;:\"'?!|\\/=(){}[]*-+\n\r"; + $length = runner_strlen( $str); + for( $i = 0; $i < $length; ++$i ) { + $idx = $reverse ? $length - $i - 1 : $i; + $c = runner_substr( $str, $idx, 1 ); + if( runner_strpos( $stopSymbols, $c ) !== false ) + return $idx; + } + return false; + } + + /** + * This function ivokes after successful saving of added/edited record + */ + function afterSuccessfulSave() + { + } + + /** + * Control settings filling + */ + function init() + { + } + + /** + * Is the search string valid for LIKE search + */ + function isStringValidForLike($str) + { + if(!IsCharType($this->type) && hasNonAsciiSymbols($str)) + return false; + + return true; + } + + /** + * Get the displayed control elemnt's style attribute string + * @return String + */ + function getInputStyle( $mode ) + { + return ""; + if( $this->pageObject->isBootstrap() + && ($this->pageObject->pageType != PAGE_ADD || $this->pageObject->mode != ADD_INLINE) + && ($this->pageObject->pageType != PAGE_EDIT || $this->pageObject->mode != EDIT_INLINE) ) + { + return ""; + } + + $width = $this->searchPanelControl ? 150 : $this->pageObject->pSetEdit->getControlWidth( $this->field ); + $style = $this->makeWidthStyle( $width ); + + return 'style="'.$style.'"'; + } + + /** + * Create a CSS rule specifying the control's width + * @param Number widthPx + */ + function makeWidthStyle( $widthPx ) + { + return ""; +/* + if( 0 == $widthPx ) + return ""; + + return "width: ".$widthPx."px;"; +*/ + } + + public function loadLookupContent( $parentValuesData, $childVal = "", $doCategoryFilter = true, $initialLoad = true ) + { + return ""; // .net compatibility + } + + public function getLookupContentToReload( $isExistParent, $mode, $parentCtrlsData ) + { + return ""; // .net compatibility + } + + /** + * A stub + */ + public function getFieldValueCopy( $value ) + { + return $value; + } + + public function getFieldSQLDecrypt() + { + return RunnerPage::_getFieldSQLDecrypt( $this->field, $this->connection, $this->pageObject->pSetEdit, $this->pageObject->cipherer ); + } + + /** + * @return String + */ + protected function getPlaceholderAttr() + { + if( !$this->searchPanelControl && $this->container->pageType != PAGE_SEARCH ) + return ' placeholder="'.runner_htmlspecialchars(GetFieldPlaceHolder( GoodFieldname( $this->pageObject->tName ), GoodFieldname( $this->field ) )).'"'; + + return ""; + } + + /** + * + */ + public function getConnection() + { + return $this->connection(); + } + + /** + * Returns basic condition, where first operand is field itself + */ + public function getBasicFieldCondition( $svalue, $strSearchOption, $svalue2 = "", $etype = "" ) { + $searchFor = $this->processControlValue( $svalue, $etype ); + $searchFor2 = $this->processControlValue( $svalue2, $etype ); + $caseInsensitive = $this->pageObject->pSetEdit->getNCSearch() ? dsCASE_INSENSITIVE : dsCASE_DEFAULT; + if( $strSearchOption == EQUALS ) { + return DataCondition::FieldEquals( $this->field, $searchFor, 0, $caseInsensitive ); + } else if( $strSearchOption == STARTS_WITH ) { + return DataCondition::FieldIs( $this->field, dsopSTART, $searchFor, $caseInsensitive ); + } else if( $strSearchOption == CONTAINS ) { + return DataCondition::FieldIs( $this->field, dsopCONTAIN, $searchFor, $caseInsensitive ); + } else if( $strSearchOption == MORE_THAN ) { + return DataCondition::FieldIs( $this->field, dsopMORE, $searchFor, $caseInsensitive ); + } else if( $strSearchOption == LESS_THAN ) { + return DataCondition::FieldIs( $this->field, dsopLESS, $searchFor, $caseInsensitive ); + } else if( $strSearchOption == BETWEEN && ( $searchFor != "" || $searchFor2 != "") ) { + if( $searchFor == "" ) { + return $this->getSearchCondition( $svalue2, NOT_MORE_THAN, "", $etype ); + } + if( $searchFor2 == "" ) { + return $this->getSearchCondition( $svalue, NOT_LESS_THAN, "", $etype ); + } + return DataCondition::FieldBetween( $this->field, $searchFor, $searchFor2, $caseInsensitive ); + } else if( $strSearchOption == EMPTY_SEARCH ) { + return DataCondition::FieldIs( $this->field, dsopEMPTY, $searchFor ); + } + return null; + } + + public function getSearchCondition( $searchFor, $strSearchOption, $searchFor2 = "", $not = false, $etype = "" ) + { + if( substr( $strSearchOption, 0, 4) == "NOT " ) { + $strSearchOption = substr( $strSearchOption, 4 ); + $not = true; + } + $cond = $this->getBasicFieldCondition( $searchFor, $strSearchOption, $searchFor2, $etype ); + + if( $not ) { + $cond = DataCondition::_Not( $cond ); + } + return $cond; + } + + /** + * Reduce value passed from web to standard format using controlType + * Currently is used for Date and Time controls only + */ + public function processControlValue( $value, $controlType ) { + + if(substr($controlType, 0, 4) == "date") + { + $dformat = substr($controlType, 4); + if($dformat == EDIT_DATE_SIMPLE || $dformat == EDIT_DATE_SIMPLE_INLINE || $dformat == EDIT_DATE_SIMPLE_DP) + { + $time = localdatetime2db($value); + if($time == "null") + return ""; + return $time; + } + else if($dformat == EDIT_DATE_DD || $dformat == EDIT_DATE_DD_INLINE || $dformat == EDIT_DATE_DD_DP) + { + $a = explode("-",$value); + if(count($a) < 3) + return ""; + else + { + $y = $a[0]; + $m = $a[1]; + $d = $a[2]; + } + if($y < 100) + { + if($y < 70) + $y += 2000; + else + $y += 1900; + } + return mysprintf("%04d-%02d-%02d",array($y,$m,$d)); + } + else + return ""; + } + else if($controlType == "time") + { + if(!strlen($value)) + return ""; + $ret = localtime2db($value); + if( IsDateFieldType( $this->type ) ) + $ret = "2000-01-01 ".$ret; + return $ret; + + } + + return $value; + } + + /** + * + * @returgn String + */ + public function getControlMarkup( &$params, $data ) { + $fieldNum = 0; + if( $params["fieldNum"] ) + $fieldNum = $params["fieldNum"]; + + $validate = array(); + if( $params["validate"] ) + $validate = $params["validate"]; + + $additionalCtrlParams = array(); + if( $params["additionalCtrlParams"] ) + $additionalCtrlParams = $params["additionalCtrlParams"]; + + ob_start(); + + $this->buildControl( $data[ $this->field ], $params["mode"], $fieldNum, $validate, $additionalCtrlParams, $data ); + $markup = ob_get_contents() ; + + ob_end_clean(); + return $markup; + } + + /** + * @return DsCommand - create data command for search suggest + */ + public function getSuggestCommand( $searchFor, $searchOpt, $numberOfSuggests ) + { + $dc = new DsCommand(); + $dc->filter = DataCondition::_And( array( + $this->getSearchCondition( $searchFor, $searchOpt ), + Security::SelectCondition( "S", $this->pageObject->pSetEdit ) + )); + $dc->totals[] = array( + "field" => $this->field, + "total" => "distinct" + ); + $dc->skipAggregated = true; + $dc->reccount = $numberOfSuggests; + return $dc; + } + + /** + * Get the field's content + * @param &Array data + * @param Array + * @return String + */ + public function getDisplayValue( &$data ) + { + $fName = $this->field; + $htmlType = $this->pageObject->pSetEdit->getHTML5InputType( $fName ); + $value = $data[ $fName ]; + if( $this->format !== EDIT_FORMAT_READONLY ) { + if( IsFloatType( $this->type ) && !is_null( $value ) ) { + if( $htmlType == "number" ) { + // no thousand delimiters, only dot as decimal delimiter + $value = formatNumberForHTML5( $value ); + } else { + $value = formatNumberForEdit( $value ); + } + } + } + return $value; + } + +} +?> \ No newline at end of file diff --git a/php/classes/controls/DatabaseFileField.php b/php/classes/controls/DatabaseFileField.php new file mode 100644 index 0000000000000000000000000000000000000000..4f9aec44ab8ab3383b1b54aa69ef1e359897042e --- /dev/null +++ b/php/classes/controls/DatabaseFileField.php @@ -0,0 +1,287 @@ +format = $pageObject->pSetEdit->getEditFormat($field); + } + + /** + * addJSFiles + * Add control JS files to page object + */ + function addJSFiles() + { + } + + /** + * addCSSFiles + * Add control CSS files to page object + */ + function addCSSFiles() + { + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + $disp = ""; + $strfilename = ""; + + if($mode == MODE_EDIT || $mode == MODE_INLINE_EDIT) + { + $value = $this->connection->stripSlashesBinary( $value ); + $itype = SupposeImageType($value); + + if($itype) + { + if( $this->format == EDIT_FORMAT_DATABASE_IMAGE && !$this->pageObject->pSetEdit->showThumbnail( $this->field ) ) + { + // show real db image instead of icon + $src = GetTableLink( "file", "", "filename=file.jpg&table=".rawurlencode( $this->container->tName ) + ."&field=".rawurlencode( $this->field ) + ."&nodisp=1" + .$this->keylink."&fileHash=".fileAttrHash( $this->keylink, strlen_bin( $value ) ) ); + + $imgWidth = $this->container->pSetEdit->getImageWidth( $this->field ); + $imgHeight = $this->container->pSetEdit->getImageHeight( $this->field ); + + $style = ''; + if( $imgWidth ) + $style.= 'max-width:'.$imgWidth.'px;'; + if( $imgHeight ) + $style.= 'max-height:'.$imgHeight.'px;'; + + $imageId = generatePassword( 10 ); + if( $style != "" ) { + // don't use id attribute since this it should be possible to override this size in other CSS + $style = ''; + } + + $disp = $style.'is508 ) + $disp.= ' alt="Image from DB"'; + $disp.= ' border=0 src="'.$src.'">'; + } + else if( $this->pageObject->pSetEdit->showThumbnail($this->field) ) + { + $disp = "iquery. + "&rndVal=".rand(0,32768))."\" >"; + $disp.= "field)."_".$this->id."\" name=\"".$this->cfield."\" border=0"; + if($this->is508) + $disp .= " alt=\"Image from DB\""; + + // show thumbnail or fullsize image + $displayField = $this->pageObject->pSetEdit->getStrThumbnail($this->field); + if( !strlen( $data[ $displayField ]) ) { + $displayField = $this->field; + } + + $disp .= " src=\"". + GetTableLink("imager", "", + "page=".$this->pageObject->pageName. + "&table=".GetTableURL($this->pageObject->tName). + "&field=".rawurlencode( $displayField ). + $this->keylink. + "&rndVal=".rand(0,32768))."\">"; + $disp.= ""; + } + else + { + $disp='is508) + $disp.= ' alt="Image from DB"'; + $disp.=' border=0 src="'. + GetTableLink("imager", "", + 'table='.GetTableURL($this->pageObject->tName). + "&page=".$this->pageObject->pageName. + '&'.$this->iquery."&src=1&rndVal=".rand(0,32768)).'">'; + } + } + else + { + if(strlen($value)) + { + $disp = 'is508) + $disp .= ' alt="file"'; + $disp .= ' src="'.GetRootPathForResources("images/file.gif").'">'; + } + } +// filename + if($this->format == EDIT_FORMAT_DATABASE_FILE && !$itype && strlen($value)) + { + if(!($filename = @$data[$this->pageObject->pSetEdit->getFilenameField($this->field)])) + $filename = "file.bin"; + + $disp = 'iquery).'".>'.$disp.''; + } +// filename edit + if($this->format == EDIT_FORMAT_DATABASE_FILE && $this->pageObject->pSetEdit->getFilenameField($this->field)) + { + if(!($filename = @$data[$this->pageObject->pSetEdit->getFilenameField($this->field)])) + $filename = ""; + if($mode == MODE_INLINE_EDIT) + { + $strfilename = '
  inputStyle.' id="filename_'.$this->cfieldname + .'" name="filename_'.$this->cfieldname.'" size="20" maxlength="50" value="'.runner_htmlspecialchars($filename).'">'; + } + else + { + $strfilename = '
  inputStyle.' id="filename_'.$this->cfieldname.'" name="filename_' + .$this->cfieldname.'" size="20" maxlength="50" value="'.runner_htmlspecialchars($filename).'">'; + } + } + if(strlen($value)) { + $strtype = '
'."Keep"; + + if(strlen($value) && !$this->pageObject->pSetEdit->isRequired($this->field)) + { + $strtype .= ''."Delete"; + } + $strtype .= ''."Update"; + } else { + $strtype = ''; + } + } + else + { +// if Add mode + $strtype = ''; + if($this->format == EDIT_FORMAT_DATABASE_FILE && $this->pageObject->pSetEdit->getFilenameField($this->field)) + { + $strfilename = '
  inputStyle.' id="filename_'.$this->cfieldname.'" name="filename_' + .$this->cfieldname.'" size="20" maxlength="50">'; + } + } + + if($mode == MODE_INLINE_EDIT && $this->format == EDIT_FORMAT_DATABASE_FILE) + $disp = ""; + echo $disp.$strtype; + if (($mode == MODE_EDIT || $mode==MODE_INLINE_EDIT) && (strlen($value))) + { + echo '
'; + } + echo 'inputStyle.' id="'.$this->cfield.'" ' + .'accept="'.$this->pageObject->pSetEdit->getAcceptFileTypesHtml($this->field).'" ' + .(($mode==MODE_INLINE_EDIT || $mode==MODE_INLINE_ADD) && $this->is508 ? 'alt="'.$this->strLabel.'" ' : '').' name="' + .$this->cfield.'" >'.$strfilename; + echo ''; + $this->buildControlEnd($validate, $mode); + } + + /** + * Create CSS code for specifying control's width + */ + function makeWidthStyle($widthPx) + { + if(0 == $widthPx) + return ""; + return "min-width: ".$widthPx."px"; + } + + function readWebValue(&$avalues, &$blobfields, $legacy1, $legacy2, &$filename_values) + { + $filename = ""; + $this->getPostValueAndType(); + if (FieldSubmitted($this->goodFieldName."_".$this->id)) + { + $fileNameForPrepareFunc = securityCheckFileName(postvalue("filename_".$this->goodFieldName."_".$this->id)); + if( $this->pageObject->pageType != PAGE_EDIT && $this->pageObject->pageType != PAGE_USERINFO ) + { + $prepearedFile = prepare_file($this->webValue, $this->field, "file2", $fileNameForPrepareFunc, $this->id); + if($prepearedFile !== false) + { + $this->webValue = $prepearedFile["value"]; + $filename = $prepearedFile["filename"]; + } + else + $this->webValue = false; + } + else + { + if(substr($this->webType, 0, 4) == "file") + { + $prepearedFile = prepare_file($this->webValue, $this->field, $this->webType, $fileNameForPrepareFunc, $this->id); + if($prepearedFile !== false) + { + $this->webValue = $prepearedFile["value"]; + $filename = $prepearedFile["filename"]; + } + else + $this->webValue = false; + } + else if(substr($this->webType, 0, 6) == "upload") + { + if($this->webType == "upload1") + { + // file deletion, read filename from the database + $oldValues = $this->pageObject->getOldRecordData(); + $fileNameForPrepareFunc = $oldValues[$this->field]; + } + $this->webValue = prepare_upload($this->field, $this->webType, $fileNameForPrepareFunc, $this->webValue, "", $this->id, $this->pageObject); + } + else + $this->webValue = false; + } + } + else + $this->webValue = false; + + if(!($this->webValue === false)) + { + if($this->webValue) + { + if($this->pageObject->pSetEdit->getCreateThumbnail($this->field)) + { + $ext = CheckImageExtension(GetUploadedFileName("value_".$this->goodFieldName."_".$this->id)); + if( $ext ) { + $thumb = CreateThumbnail($this->webValue, $this->pageObject->pSetEdit->getThumbnailSize($this->field), $ext); + $blobfields[] = $this->pageObject->pSetEdit->getStrThumbnail($this->field); + $avalues[$blobfields[count($blobfields) - 1]] = $thumb; + } + } + // resize on upload + $resizeImageSize = 0; + if( $this->pageObject->pSetEdit->getResizeOnUpload($this->field) ) { + $resizeImageSize = $this->pageObject->pSetEdit->getNewImageSize($this->field); + } else if( $this->fieldIsUserpic() ) { + $resizeImageSize = 400; + } + if( $resizeImageSize ) { + $ext = CheckImageExtension( GetUploadedFileName("value_".$this->goodFieldName."_".$this->id) ); + $this->webValue = CreateThumbnail($this->webValue, $resizeImageSize, $ext); + } + } + else if($this->pageObject->pageType == PAGE_EDIT && $this->pageObject->pSetEdit->getCreateThumbnail($this->field)) + { + $blobfields[] = $this->pageObject->pSetEdit->getStrThumbnail($this->field); + $avalues[$blobfields[count($blobfields) - 1]] = ""; + } + $blobfields[] = $this->field; + $avalues[$this->field] = $this->webValue; + } + if($filename && $this->pageObject->pSetEdit->getStrFilename($this->field)) + $filename_values[$this->pageObject->pSetEdit->getStrFilename($this->field)] = $filename; + } + + protected function fieldIsUserpic() { + return $this->field === Security::userpicField() + && $this->container->tName === Security::loginTable(); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/DateField.php b/php/classes/controls/DateField.php new file mode 100644 index 0000000000000000000000000000000000000000..f5b40af18215c1bfc200769f0b879026bc2eef64 --- /dev/null +++ b/php/classes/controls/DateField.php @@ -0,0 +1,293 @@ +format = EDIT_FORMAT_DATE; + } + + function addCSSFiles() { + $this->pageObject->AddCSSFile("include/bootstrap/css/bootstrap-datetimepicker.min.css"); + } + + function getProjectSettings() + { + if($this->pageObject->pageType == PAGE_LIST) + return new ProjectSettings($this->pageObject->tName, PAGE_SEARCH); + else + return $this->pageObject->pSetEdit; + } + + function getDateEditType( $pSet = null ) + { + if( !$pSet ) + $pSet = $this->getProjectSettings(); + + $dateEditType = $pSet->getDateEditType($this->field); + + // search panel control + if( !$this->forSpreadsheetGrid + && ( ( $this->pageObject->pageType == PAGE_LIST || $this->pageObject->pageType == PAGE_CHART || $this->pageObject->pageType == PAGE_REPORT) + || $this->pageObject->pageType == PAGE_SEARCH && $this->pageObject->mode == SEARCH_LOAD_CONTROL) ) + { + if( $dateEditType == EDIT_DATE_DD ) + return EDIT_DATE_SIMPLE; + if( $dateEditType == EDIT_DATE_DD_DP ) + return EDIT_DATE_SIMPLE_DP; + if( $dateEditType == EDIT_DATE_DD_INLINE ) + return EDIT_DATE_SIMPLE_INLINE; + } + + return $dateEditType; + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + global $locale_info; + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + if($fieldNum) + $this->cfield = "value".$fieldNum."_".GoodFieldName($this->field).'_'.$this->id; + + $pSet = $this->getProjectSettings(); + + $dateEditType = $this->getDateEditType( $pSet ); + + //if( $this->pageObject->pageType == PAGE_LIST ) // + echo ''; + + $tvalue = $value; + + $time = db2time($tvalue); + if( !$time ) + $time = array(0, 0, 0, 0, 0, 0); + + $classString = ' form-control'; + + $dp = 0; + $hasImgCal = true; + $showTime = $pSet->dateEditShowTime($this->field); + switch( $dateEditType ) + { + case EDIT_DATE_SIMPLE_INLINE: + $hasImgCal = false; + case EDIT_DATE_SIMPLE_DP: + $ovalue = $value; + + if($locale_info["LOCALE_IDATE"] == 1) + $fmt = "dd".$locale_info["LOCALE_SDATE"]."MM".$locale_info["LOCALE_SDATE"]."yyyy"; + else if($locale_info["LOCALE_IDATE"] == 0) + $fmt = "MM".$locale_info["LOCALE_SDATE"]."dd".$locale_info["LOCALE_SDATE"]."yyyy"; + else + $fmt = "yyyy".$locale_info["LOCALE_SDATE"]."MM".$locale_info["LOCALE_SDATE"]."dd"; + + if($showTime || $time[3] || $time[4] || $time[5]){ + $timeAttrs = $this->pageObject->pSetEdit->getFormatTimeAttrs($this->field); + $fmt.= " " . $locale_info["LOCALE_STIMEFORMAT"]; + } + + if($time[0]) + $ovalue = format_datetime_custom($time, $fmt); + + $ovalue1 = $time[2]."-".$time[1]."-".$time[0]; + if($showTime || $time[3] || $time[4] || $time[5]) + $ovalue1.= " ".$time[3].":".$time[4].":".$time[5]; + + $ret= 'getPlaceholderAttr().' id="'.$this->cfield.'" '.$this->inputStyle.' class="'.$classString.'" type="Text" name="'.$this->cfield.'" value="'.$ovalue.'">'; + $ret.= ''; + + $ret .= ''; + + if ( isRTL() ) + $ret .= ""; // for bootstrap calend icon anomaly + + $ret = '
' . $ret . '
'; + + echo $ret; + break; + + case EDIT_DATE_DD_INLINE: + case EDIT_DATE_DD_DP: + $dp=1; + case EDIT_DATE_DD: + $controlWidth = $pSet->getControlWidth($this->field); + if($controlWidth > 0) + { + $controlWidth -= 10; + $yearWidth = floor($controlWidth * 0.3); + $yearStyle = 'style="min-width: '.$yearWidth.'px;margin-right:5px;" '; + $dayWidth = floor($controlWidth * 0.2); + $dayStyle = 'style="min-width: '.$dayWidth.'px; margin-right:5px;" '; + $mothWidth = $controlWidth - $yearWidth - $dayWidth; + $monthStyle = 'style="min-width: '.$mothWidth.'px; margin-right:5px;" '; + } + else + { + $dayStyle = ''; + $monthStyle = ''; + $yearStyle = ''; + } + $alt = 'alt="'.$this->strLabel.'" '; + + // for init normal select width/ After load js, this options will clear + $initMonthOpt = ""; + if ( $time[1] ) + { + $months = getMountNames(); + $initMonthOpt = ""; + } + $initMonthOpt .= ""; + $initDayOpt = ""; + $initYearOpt = ""; + $retday=''; + $retmonth=''; + $retyear=''; + + $space = ($controlWidth > 0 ? '' : " "); + + if($locale_info["LOCALE_ILONGDATE"] == 1) + $ret = $retday.$space.$retmonth.$space.$retyear; + else if($locale_info["LOCALE_ILONGDATE"] == 0) + $ret = $retmonth.$space.$retday.$space.$retyear; + else + $ret = $retyear.$space.$retmonth.$space.$retday; + + $setHiddenElem = 'class="'. $classString.' hiddenPickerElement"'; + + if($time[0] && $time[1] && $time[2]) + $ret.="cfield."\" ".$setHiddenElem." name=\"".$this->cfield."\" value=\"".$time[0]."-".$time[1]."-".$time[2]."\">"; + else + $ret.="cfield."\" ".$setHiddenElem." name=\"".$this->cfield."\" value=\"\">"; + + // calendar handling for three DD + if( $dp ) { + $ret .= ''; + } + + $ret = '' . $ret . ''; + echo $ret; + break; + + default: // case EDIT_DATE_SIMPLE: + $ovalue = $value; + if($time[0]) + { + if($showTime || $time[3] || $time[4] || $time[5]) + $ovalue = str_format_datetime($time); + else + $ovalue = format_shortdate($time); + } + echo 'getPlaceholderAttr().' id="'.$this->cfield.'" type=text class="'.$classString.'" name="'.$this->cfield.'" '.$this->inputStyle.' value="'.runner_htmlspecialchars($ovalue).'">'; + } + $this->buildControlEnd($validate, $mode); + } + + function getFirstElementId() + { + global $locale_info; + $dateEditType = $this->getDateEditType(); + + if ( !$dateEditType ) + { + return $this->cfield; + } + + switch( $dateEditType ) + { + case EDIT_DATE_DD: + case EDIT_DATE_DD_INLINE: + case EDIT_DATE_DD_DP: + if($locale_info["LOCALE_ILONGDATE"] == 1) + return "day".$this->cfield; + else if($locale_info["LOCALE_ILONGDATE"] == 0) + return "month".$this->cfield; + else + return "year".$this->cfield; + break; + + default: + return $this->cfield; + break; + } + } + + function maxLengthMonth() + { + $maxLengthMonth = ""; + $mounts = getMountNames(); + $maxLenght = 0; + for ( $i =0; $i < count($mounts); $i++ ) + { + $curMontn = $mounts[$i]; + $curMonthLen = runner_strlen($curMontn); + if ( $maxLenght < $curMonthLen ) + { + $maxLenght = $curMonthLen; + $maxLengthMonth = $curMontn; + } + } + + return $maxLengthMonth; + } + + /** + * Returns basic condition + */ + public function getBasicFieldCondition( $svalue, $strSearchOption, $svalue2 = "", $etype = "" ) { + $searchFor = $this->processControlValue( $svalue, $etype ); + $searchFor2 = $this->processControlValue( $svalue2, $etype ); + $etype = ""; + $pSet = $this->getProjectSettings(); + if( !$pSet->dateEditShowTime($this->field) && IsDateTimeFieldType( $pSet->getFieldType($this->field) ) ) { + // search for date only in a datetime field + + if( $strSearchOption == EQUALS ) { + // ( NOT field < date ) AND field < ( date + 1 day ) + $tm = db2time( $searchFor ); + if( !$tm[0] ) { + return DataCondition::_False(); + } + $nextDay = adddays( $tm, 1 ); + return DataCondition::_And( array( + DataCondition::_Not( + DataCondition::FieldIs( $this->field, dsopLESS, date2db( $tm ) ) + ), + DataCondition::FieldIs( $this->field, dsopLESS, date2db( $nextDay ) ) + )); + } else if( $strSearchOption == MORE_THAN ) { + // NOT ( field < ( date + 1 day ) ) + $tm = db2time( $searchFor ); + if( !$tm[0] ) { + return DataCondition::_False(); + } + $nextDay = adddays( $tm, 1 ); + return DataCondition::_Not( + DataCondition::FieldIs( $this->field, dsopLESS, date2db( $nextDay ) ) + ); + + } else if( $strSearchOption == BETWEEN && $searchFor != "" && $searchFor2 != "" ) { + // true between only + // NOT ( field < date ) AND field < (date2+1) + $tm = db2time( $searchFor ); + $tm2 = db2time( $searchFor2 ); + if( !$tm[0] || !$tm2[0] ) { + return DataCondition::_False(); + } + $tm2 = adddays( $tm2, 1 ); + return DataCondition::_And( array( + DataCondition::_Not( + DataCondition::FieldIs( $this->field, dsopLESS, date2db( $tm ) ) + ), + DataCondition::FieldIs( $this->field, dsopLESS, date2db( $tm2 ) ) + )); + + } + + } + return parent::getBasicFieldCondition( $searchFor, $strSearchOption, $searchFor2, $etype ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/DateTimeControl.php b/php/classes/controls/DateTimeControl.php new file mode 100644 index 0000000000000000000000000000000000000000..f5a791d45ade44a7ec2cbf654f0d01beccc12dba --- /dev/null +++ b/php/classes/controls/DateTimeControl.php @@ -0,0 +1,25 @@ +buildSearchOptions($optionsArray, $selOpt, $not, $both); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/EditControlsContainer.php b/php/classes/controls/EditControlsContainer.php new file mode 100644 index 0000000000000000000000000000000000000000..d6c16b010ee1996bfc6e95082a8da1e4afc86fd5 --- /dev/null +++ b/php/classes/controls/EditControlsContainer.php @@ -0,0 +1,330 @@ +pageObject = $pageObject; + $this->tName = $pageObject->tName; + + $this->pageLikeInline = $pageObject->pageType == PAGE_ADD && $pageObject->mode == ADD_INLINE || + $pageObject->pageType == PAGE_EDIT && $pageObject->mode == EDIT_INLINE; + } + else + { + $this->tName = $pSetEdit->_table; + $this->cipherer = $cipherer; + } + + $this->fillControlClassNames(); + + $this->setEditControlsConnection(); + + $this->pSetEdit = $pSetEdit; + $this->pageType = $pageType; + $this->searchPanelActivated = true; + } + + /** + * Set the connection property + */ + protected function setEditControlsConnection() + { + global $cman; + + if( $this->pageObject != null ) + $this->connection = $this->pageObject->connection; + else + $this->connection = $cman->byTable( $this->tName ); + } + + /** + * @return Boolean + */ + public function isSearchPanelActivated() + { + if( $this->pageObject != null ) + return $this->pageObject->isSearchPanelActivated(); + + return $this->pageType == PAGE_SEARCH; + } + + function addControlsJSAndCSS() + { + $allowedPageTypes = array( PAGE_ADD, PAGE_EDIT, PAGE_VIEW, PAGE_LIST, + PAGE_SEARCH, PAGE_REGISTER, PAGE_LOGIN, PAGE_USERINFO ); + + // showing if there is Search panel on the page + $searchPanelActivated = $this->isSearchPanelActivated(); + + if( !in_array( $this->pageType, $allowedPageTypes ) && !$searchPanelActivated ) + return; + + switch( $this->pageType ) + { + case PAGE_ADD: + $pageTypeStr = "Add"; + break; + case PAGE_EDIT: + $pageTypeStr = "Edit"; + break; + case PAGE_VIEW: + case PAGE_LIST: + $pageTypeStr = "List"; + break; + default: + $pageTypeStr = ""; + } + + if( $pageTypeStr != "" ) + { + $getEditFieldsFunc = "get".($this->pageLikeInline ? "Inline" : "").$pageTypeStr."Fields"; + if( $this->pageLikeInline ) + $appearOnPageFunc = "appearOnInline".$pageTypeStr; + else + $appearOnPageFunc = "appearOn".$pageTypeStr."Page"; + } + + switch( $this->pageType ) + { + case PAGE_LOGIN: + case PAGE_REGISTER: + case PAGE_USERINFO: + $fields = $this->pSetEdit->getPageFields(); + break; + case PAGE_SEARCH: + $fields = $this->pSetEdit->getAdvSearchFields(); + break; + default: + $fields = array(); + if( $getEditFieldsFunc ) + $fields = $this->pSetEdit->$getEditFieldsFunc(); + } + + // Addign fields that aren't appear at list page, but appear on search panel + $searchFields = array(); + if( $searchPanelActivated ) + { + $searchFields = $this->pSetEdit->getPanelSearchFields(); + $searchFields = array_merge($searchFields, $this->pSetEdit->getAllSearchFields()); + $fields = array_merge($searchFields, $fields); + $fields = array_unique($fields); + } + + foreach( $fields as $i => $f ) + { + $appear = false; + + if( $this->pageType == PAGE_REGISTER || $this->pageType == PAGE_SEARCH + || $this->pageType == PAGE_LOGIN || $this->pageType == PAGE_USERINFO + || in_array($f, $searchFields) ) + { + $appear = true; + } + else if( $appearOnPageFunc ) + $appear = $this->pSetEdit->$appearOnPageFunc($f); + + if( $appear ) + { + $editControl = $this->getControl($f); + $editControl->addJSFiles(); + $editControl->addCSSFiles(); + } + } + } + + /** + * @param String field + * @param String id (optional) + * @param Array extraParmas (optional) + * @return Control + */ + function getControl($field, $id = "", $extraParmas = array()) + { +/* + if( count($extraParmas) && $extraParmas["makeReadonly"] ) { + include_once(getabspath("classes/controls/Control.php")); + $className = $this->classNamesForEdit[ EDIT_FORMAT_READONLY ]; + + $ctrl = createControlClass($className, $field, $this->pageObject != null ? $this->pageObject : $this, $id, $this->connection); + $ctrl->container = $this; + + return $ctrl; + } +*/ + + if( count($extraParmas) && $extraParmas["getConrirmFieldCtrl"] ) + { + include_once(getabspath("classes/controls/Control.php")); + $className = $this->classNamesForEdit[ EDIT_FORMAT_PASSWORD ]; + + $ctrl = createControlClass($className, $field, $this->pageObject != null ? $this->pageObject : $this, $id, $this->connection); + if($extraParmas['isConfirm']) + $ctrl->field = Security::passwordField(); + $ctrl->container = $this; + + return $ctrl; + } + + // if conrol does not created previously + if(!array_key_exists($field, $this->controls)) + { + include_once(getabspath("classes/controls/Control.php")); + + $userControl = false; + $editFormat = $this->getEditFormat($field); + + if( ($this->pageType == PAGE_SEARCH || $this->pageType == PAGE_LIST ) && !$extraParmas["spreadsheet"] ) + { + // Text field may be Lookup field on some page + $pageTypebyLookupFormat = $this->pSetEdit->getPageTypeByFieldEditFormat($field, EDIT_FORMAT_LOOKUP_WIZARD); + + if( $editFormat == EDIT_FORMAT_TEXT_FIELD && $pageTypebyLookupFormat != "" ) + { + $localPSet = new ProjectSettings($this->pSetEdit->_table, $pageTypebyLookupFormat); + + if( $localPSet->getLinkField($field) != $localPSet->getDisplayField($field) ) + $className = "LookupTextField"; + else + $className = $this->classNamesForSearch[ $editFormat ]; + } + else + $className = $this->classNamesForSearch[ $editFormat ]; + } + else + $className = $this->classNamesForEdit[ $editFormat ]; + + if( $className == $this->classNamesForEdit[ EDIT_FORMAT_FILE ] && $this->pSetEdit->isBasicUploadUsed($field) ) + $className = "FileFieldSingle"; + + if( !$className ) + { + if($editFormat != "") + { + $className = "Edit".$editFormat; + $userControl = true; + include_once(getabspath("classes/controls/UserControl.php")); + if( !is_null($this->pageObject) ) + $this->pageObject->AddJSFile("include/runnerJS/controls/".$className.".js", "include/runnerJS/editControls/Control.js"); + } + else + $className = $this->classNamesForEdit[ EDIT_FORMAT_TEXT_FIELD ]; + } + + $this->controls[ $field ] = createControlClass($className, $field, $this->pageObject != null ? $this->pageObject : $this, $id, $this->connection); + $this->controls[ $field ]->container = $this; + $this->controls[ $field ]->forSpreadsheetGrid = $extraParmas["spreadsheet"]; + + if($userControl) + { + $this->controls[ $field ]->format = $className; + $this->controls[ $field ]->initUserControl(); + } + } + + if( $id !== "" ) + $this->controls[ $field ]->setID($id); + + return $this->controls[ $field ]; + } + + /** + * @deprecated + */ + function isSystemControl($className) + { + include_once(getabspath("classes/controls/Control.php")); + if($this->pageType == PAGE_SEARCH || $this->pageType == PAGE_LIST) + return isset($this->classNamesForSearch[$className]); + else + return isset($this->classNamesForEdit[$className]); + } + + /** + * Check if the host page is table based + * @return Boolean + */ + function isPageTableBased() + { + if($this->pageType == PAGE_MENU || $this->pageType == PAGE_LOGIN || $this->pageType == PAGE_REMIND || $this->pageType == PAGE_CHANGEPASS) + { + return false; + } + return true; + } + + function mobileTemplateMode() + { + return false; + } + + protected function fillControlClassNames() + { + $this->classNamesForEdit[EDIT_FORMAT_TEXT_FIELD] = "TextField"; + $this->classNamesForEdit[EDIT_FORMAT_TIME] = "TimeField"; + $this->classNamesForEdit[EDIT_FORMAT_TEXT_AREA] = "TextAreaField"; + $this->classNamesForEdit[EDIT_FORMAT_PASSWORD] = "PasswordField"; + $this->classNamesForEdit[EDIT_FORMAT_DATE] = "DateField"; + $this->classNamesForEdit[EDIT_FORMAT_CHECKBOX] = "CheckboxField"; + $this->classNamesForEdit[EDIT_FORMAT_DATABASE_IMAGE] = "DatabaseFileField"; + $this->classNamesForEdit[EDIT_FORMAT_DATABASE_FILE] = "DatabaseFileField"; + $this->classNamesForEdit[EDIT_FORMAT_HIDDEN] = "HiddenField"; + $this->classNamesForEdit[EDIT_FORMAT_READONLY] = "ReadOnlyField"; + $this->classNamesForEdit[EDIT_FORMAT_FILE] = "FileField"; + $this->classNamesForEdit[EDIT_FORMAT_LOOKUP_WIZARD] = "LookupField"; + + $this->classNamesForSearch[EDIT_FORMAT_TEXT_FIELD] = "TextField"; + $this->classNamesForSearch[EDIT_FORMAT_TIME] = "TimeField"; + $this->classNamesForSearch[EDIT_FORMAT_TEXT_AREA] = "TextField"; + $this->classNamesForSearch[EDIT_FORMAT_PASSWORD] = "TextField"; + $this->classNamesForSearch[EDIT_FORMAT_DATE] = "DateField"; + $this->classNamesForSearch[EDIT_FORMAT_CHECKBOX] = "CheckboxField"; + $this->classNamesForSearch[EDIT_FORMAT_DATABASE_IMAGE] = "TextField"; + $this->classNamesForSearch[EDIT_FORMAT_DATABASE_FILE] = "TextField"; + $this->classNamesForSearch[EDIT_FORMAT_HIDDEN] = "TextField"; + $this->classNamesForSearch[EDIT_FORMAT_READONLY] = "TextField"; + $this->classNamesForSearch[EDIT_FORMAT_FILE] = "FileField"; + $this->classNamesForSearch[EDIT_FORMAT_LOOKUP_WIZARD] = "LookupField"; + + } + + protected function getEditFormat( $field ) { + if( $this->pageObject ) { + return $this->pageObject->getEditFormat( $field ); + } + return $this->pSetEdit->getEditFormat( $field ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/FileField.php b/php/classes/controls/FileField.php new file mode 100644 index 0000000000000000000000000000000000000000..7d3188b8d53d7e739763cb5ae3bbbee7c083a6ac --- /dev/null +++ b/php/classes/controls/FileField.php @@ -0,0 +1,455 @@ +format = EDIT_FORMAT_FILE; + } + + function addJSFiles() { + if ( $this->format = EDIT_FORMAT_FILE ) { + $this->pageObject->AddJSFile("include/mupload.js"); + } + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + if( $mode == MODE_SEARCH ) { + $this->format = ""; + + $classString = ""; + if( $this->pageObject->isBootstrap() ) + $classString = " class=\"form-control\""; + + echo 'inputStyle.' type="text" ' + .('autocomplete="off" ') + .( $this->is508==true ? 'alt="'.$this->strLabel.'" ' : '') + .'name="'.$this->cfield.'" '.$this->pageObject->pSetEdit->getEditParams($this->field).' value="' + .runner_htmlspecialchars($value).'">'; + + $this->buildControlEnd($validate, $mode); + return; + } + + $this->formStamp = generatePassword(15); + + $filesArray = $this->getFileData( $value ); + + $keylink = ""; + if($this->pageObject->pageType == PAGE_EDIT) { + if( $this->pageObject->keys ) + { + $i = 1; + foreach($this->pageObject->keys as $keyName => $keyValue) + { + $keylink .= "&key".$i."=".rawurlencode( $keyValue ); + $i++; + } + } + } + $fh = new RunnerFileHandler( $this->field, $this->pageObject->pSet, $this->formStamp ); + $userFilesArray = $fh->loadFiles( $filesArray ); + + $jsonValue = my_json_encode($userFilesArray); + $multiple = ""; + if( $this->pageObject->pSetEdit->getMaxNumberOfFiles($this->field) != 1 ) + $multiple = "multiple "; + echo ' + +
+ + + + + + +
+
+ + + + ' + ."Add files" + .' + ' + .' + +
+ +
+ +
+
+
+ +
 
+
+
+ +
+ +
+
+ '; + if(!isset($this->container->globalVals["muploadTemplateIncluded"])) + { + echo ' +'; + $this->container->globalVals["muploadTemplateIncluded"] = true; + } + $this->buildControlEnd($validate, $mode); + } + + /** + * Create CSS code for specifying control's width + */ + function makeWidthStyle($widthPx) + { + if(0 == $widthPx) + return ""; + return "min-width: ".$widthPx."px"; + } + + public function readWebValue(&$avalues, &$blobfields, $legacy1, $legacy2, &$filename_values) + { + $this->getPostValueAndType(); + $this->formStamp = postvalue("formStamp_".$this->goodFieldName."_".$this->id); + if (FieldSubmitted($this->goodFieldName."_".$this->id) && $this->formStamp != "") + { + $filesArray = my_json_decode($this->webValue); + if(!is_array($filesArray) || count($filesArray) == 0) + $this->webValue = ""; + else + { + if(count($_SESSION["mupload_".$this->formStamp]) > 0) + { + foreach($_SESSION["mupload_".$this->formStamp] as $fileArray) + $fileArray["deleted"] = true; + } + $result = array(); + $uploadDir = $this->pageObject->pSetEdit->getLinkPrefix($this->field); + $searchStr = ""; + foreach ($filesArray as $file) + { + if(isset($_SESSION["mupload_".$this->formStamp][$file["name"]])) + { + $sessionFile = $_SESSION["mupload_".$this->formStamp][$file["name"]]["file"]; + $searchStr .= $file["name"].",!"; + $result[] = array("name" => $sessionFile["name"], + "usrName" => $file["name"], "size" => $sessionFile["size"], "type" => $sessionFile["type"] + ); + if($this->pageObject->pSetEdit->getCreateThumbnail($this->field) + && $sessionFile["thumbnail"] != "") + { + $lastIndex = count($result) - 1; + $result[$lastIndex]["thumbnail"] = $sessionFile["thumbnail"]; + $result[$lastIndex]["thumbnail_type"] = $sessionFile["thumbnail_type"]; + $result[$lastIndex]["thumbnail_size"] = $sessionFile["thumbnail_size"]; + } + $_SESSION["mupload_".$this->formStamp][$file["name"]]["deleted"] = false; + } + } + if(count($result) > 0) + { + $result[0]["searchStr"] = $searchStr.":sStrEnd"; + $this->webValue = my_json_encode_unescaped_unicode($result); + } + else + $this->webValue = ""; + } + } + else + $this->webValue = false; + + if(!($this->webValue===false)) + { + if( $this->connection->dbType == nDATABASE_Informix ) + { + if(IsTextType($this->pageObject->pSetEdit->getFieldType($this->field))) + $blobfields[] = $this->field; + } + $avalues[$this->field] = $this->webValue; + } + } + + /** + * Form the control specified search options array and built the control's search options markup + * @param String selOpt The search option value + * @param Boolean not It indicates if the search option negation is set + * @param Boolean both It indicates if the control needs 'NOT'-options + * @return String A string containing options markup + */ + public function getSearchOptions($selOpt, $not, $both) + { + $optionsArray = array(); + $isPHPEncripted = $this->pageObject->cipherer->isFieldPHPEncrypted($this->field); + if(!$isPHPEncripted){ + $optionsArray[] = CONTAINS; + $optionsArray[] = EQUALS; + } + $optionsArray[] = EMPTY_SEARCH; + if($both) + { + if(!$isPHPEncripted){ + $optionsArray[] = NOT_CONTAINS; + $optionsArray[] = NOT_EQUALS; + } + $optionsArray[] = NOT_EMPTY; + } + return $this->buildSearchOptions($optionsArray, $selOpt, $not, $both); + } + + /** + * Fill the response array with the suggest values + * + * @param String value + * Note: the real value is preceeded with "_" so It's necessary to remove + * the first character before json decoding . Also It's important to add "_" + * to the beggining of the response suggest value because Searchsuggest + * expects that it starts with this character. + * @param String searchFor + * @param &Array response + * @param &Array row + */ + public function suggestValue($value, $searchFor, &$response, &$row) + { + if(!$value) + return; + + //value is preceeded with "_" + $value = substr($value, 1); + + $filesArray = my_json_decode($value); + + if(!is_array($filesArray) || count($filesArray) == 0) + $response[ "_".$value ] = "_".$value; + else + { + for($i = 0; $i < count($filesArray) && count($response) < 10; $i++) + { + if($this->pageObject->pSetEdit->getNCSearch()) + $pos = stripos($filesArray[$i]["usrName"], $searchFor); + else + $pos = strpos($filesArray[$i]["usrName"], $searchFor); + + if($pos !== false) + $response[ "_".$filesArray[$i]["usrName"] ] = "_".$filesArray[$i]["usrName"]; + } + } + } + + public function afterSuccessfulSave() + { + if( !$_SESSION["mupload_".$this->formStamp] ) { + return; + } + $fs = getStorageProvider( $this->pageObject->pSet, $this->field ); + foreach( $_SESSION["mupload_".$this->formStamp] as $fileArray ) { + if( !$fileArray["deleted"] ) { + continue; + } + $fs->delete( $fileArray["file"]["name"] ); + if( $fileArray["file"]["thumbnail"] ) { + $fs->delete( $fileArray["file"]["thumbnail"] ); + } + } + unset($_SESSION["mupload_".$this->formStamp]); + } + + /** + * @param String fieldValue + * @return String + */ + public function getFieldValueCopy( $fieldValue ) + { + $fs = getStorageProvider( $this->pageObject->pSet, $this->field ); + if( !$fs->fast() ) { + return "[]"; + } + $uploadFolder = $this->pageObject->pSetEdit->getUploadFolder( $this->field ); + + $filesData = $this->getFileData( $fieldValue ); + foreach( array_keys( $filesData ) as $idx ) { + $file =& $filesData[ $idx ]; + $newName = $fs->copyFile( $file["name"], $file["usrName"] ); + if( !$newName ) { + continue; + } + $file["name"] = $newName; + + if( $this->pageObject->pSetEdit->getCreateThumbnail( $this->field ) && $file["thumbnail"] ) { + $thumbnailPrefix = $this->pageObject->pSetEdit->getStrThumbnail( $this->field ); + $newThumbnail = $fs->copyFile( $file["thumbnail"], $thumbnailPrefix.$file["usrName"] ); + if( $newThumbnail ) { + $file["thumbnail"] = $newThumbnail; + } else { + unset( $file["thumbnail"] ); + } + } + } + + return my_json_encode( $filesData ); + } + + /** + * Returns basic condition + */ + public function getBasicFieldCondition( $searchFor, $strSearchOption, $searchFor2 = "", $etype = "" ) { + if( $strSearchOption == EQUALS ) { + return $this->getFilenameCondition( dsopEQUAL, $searchFor ); + } else if( $strSearchOption == STARTS_WITH ) { + return $this->getFilenameCondition( dsopSTART, $searchFor ); + } else if( $strSearchOption == CONTAINS ) { + return $this->getFilenameCondition( dsopCONTAIN, $searchFor ); + } else if( $strSearchOption == EMPTY_SEARCH ) { + return DataCondition::FieldIs( $this->field, dsopEMPTY, $searchFor ); + } + return null; + } + + /** + * Get file field search condition + * @param operation dsopEQUAL | dsopSTART | dsopCONTAIN + * @param String searchFor + * @return DsCondition + */ + protected function getFilenameCondition( $operation, $searchFor ) { + $caseInsensitive = $this->pageObject->pSetEdit->getNCSearch() ? dsCASE_INSENSITIVE : dsCASE_DEFAULT; + + $startCondition = DataCondition::FieldIs( $this->field, dsopSTART, "[{", $caseInsensitive ); + + // To extend like condition pattern + $likeWrapper = null; + $before = 'searchStr":"'; + $after = ':sStrEnd"'; + + // set up suitable value and like wrapper parts + // to get proper like pattern for Condition with dsopCONTAIN op + // b $before, a $after, v $searchFor + if( $operation == dsopEQUAL ) { + // %bva% eg '%searchStr":"test.gif,!:sStrEnd"%' + // ',!' is added to the downloaded file name (ex. "test.gif,!") + $fileSearchFor = $before. $searchFor.',!' .$after; + } else if( $operation == dsopSTART ) { + // %bv%a% eg '%searchStr":"test.gif%:sStrEnd"%' + $fileSearchFor = $before.$searchFor; + $likeWrapper = array( 'after' => $after ); + } else /* dsopCONTAIN */ { + // %b%v%a% eg '%searchStr":"%test.gif%:sStrEnd"%' + $fileSearchFor = $searchFor; + $likeWrapper = array( 'before' => $before, 'after' => $after ); + } + + return new DsCondition( + array( + new DsOperand( dsotCONDITION, DataCondition::_And( array( + $startCondition, + DataCondition::FieldIs( $this->field, dsopCONTAIN, $fileSearchFor, $caseInsensitive, 0, $likeWrapper ) + ))), + new DsOperand( dsotCONDITION, DataCondition::_And( array( + DataCondition::_Not( $startCondition ), + DataCondition::FieldIs( $this->field, $operation, $searchFor, $caseInsensitive ) + ))) + ), + dsopOR, + $caseInsensitive + ); + } + /** + * return parsed file info in unified format + * @return Array of arrays [ + * "usrName" => user-provided filename + * "name" => file path if saved in filesystem + * "type" => (optional) file type in HTTP-ready format. + * "size" => (optional)size in bytes + * "thumbnail" => (optional)thumbnail file path + * "thumbnail_size" => (optional)thumbnail size + * "thumbnail_type" => (optional)thumbnail file type in HTTP-ready format + * ] + */ + protected function getFileData( $value ) { + return RunnerFileHandler::getFileArray( $value, $this->field, $this->pageObject->pSet ); + } + + + +} +?> \ No newline at end of file diff --git a/php/classes/controls/FileFieldSingle.php b/php/classes/controls/FileFieldSingle.php new file mode 100644 index 0000000000000000000000000000000000000000..c391cf2fb09704081bc30e2cb518af1569057900 --- /dev/null +++ b/php/classes/controls/FileFieldSingle.php @@ -0,0 +1,277 @@ +format = EDIT_FORMAT_FILE; + + } + + + /** + * addJSFiles + * Add control JS files to page object + */ + function addJSFiles() + { + } + + /** + * addCSSFiles + * Add control CSS files to page object + */ + function addCSSFiles() + { + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + if( $mode == MODE_SEARCH ) + { + $this->format = ""; + + $classString = ""; + if( $this->pageObject->isBootstrap() ) + $classString = " class=\"form-control\""; + + echo 'inputStyle.' type="text" ' + .('autocomplete="off" ') + .( $this->is508 == true ? 'alt="'.$this->strLabel.'" ' : '' ) + .'name="'.$this->cfield.'" '.$this->pageObject->pSetEdit->getEditParams($this->field).' value="' + .runner_htmlspecialchars($value).'">'; + + $this->buildControlEnd($validate, $mode); + return; + } + + $keyParams = array(); + foreach( $this->pageObject->pSetEdit->getTableKeys() as $i => $kf ) { + $keyParams[] = "key".($i + 1). "=".runner_htmlspecialchars(rawurlencode( @$data[ $kf ] )); + } + $keyLink = "&" . implode("&", $keyParams); + + + $disp = ""; + $strfilename = ""; + + $filename_size = $this->pageObject->pSetEdit->isUseTimestamp( $this->field ) + ? 50 + : 30; + + if( $mode == MODE_EDIT || $mode == MODE_INLINE_EDIT ) + { + // show current file + $filesArray = $this->getFileData( $value ); + $fileName = ""; + if( $filesArray ) { + $fileData = $filesArray[0]; + $fileName = $fileData["usrName"]; + + $viewFormat = $this->pageObject->pSetEdit->getViewFormat( $this->field ); + if( $viewFormat == FORMAT_FILE || $viewFormat == FORMAT_FILE_IMAGE ) + $disp = $this->getFileOrImageMarkup( $fileData, $keyLink ) . "
"; + } + + + // filename edit + $strfilename = '
' + ."Filename" + .'  '; + + $strtype = '
'."Keep"; + + if( (strlen($value) || $mode == MODE_INLINE_EDIT) && !$this->pageObject->pSetEdit->isRequired($this->field) ) + { + $strtype .= ''."Delete"; + } + $strtype .= ''."Update"; + } + else + { + // if Adding record + $strtype = ''; + + $strfilename = '
'."Filename" + .'  '; + } + + echo $disp.$strtype; + + if( $mode == MODE_EDIT || $mode == MODE_INLINE_EDIT ) + echo '
'; + + echo 'is508 == true ? 'alt="'.$this->strLabel.'" ' : '') + .' name="'.$this->cfield.'" >'.$strfilename; + + echo ''; + + $this->buildControlEnd($validate, $mode); + } + + /** + * Get the image or file link markup + * @param String value + * @param String fileName + * @param Boolean newUploaderWasUsed + * @param Array fileData + * @return String + */ + function getFileOrImageMarkup( $fileData, $keylink ) + { + $fileName = $fileData["usrName"]; + $urls = $this->getFileUrls( $fileData, $keylink ); + if( !$urls["url"] ) { + return ""; + } + + + if( !CheckImageExtension( $fileName ) ) + { + return "" + .runner_htmlspecialchars( $fileName ).""; + } + + if( !$urls["thumbnail"] ) { + $urls["thumbnail"] = $urls["url"]; + } + + $altAttr = " alt=\"".runner_htmlspecialchars( $fileName )."\"" ; + return "" + .""; + + } + + /** + * + */ + function readWebValue(&$avalues, &$blobfields, $legacy1, $legacy2, &$filename_values) + { + $this->getPostValueAndType(); + + if( FieldSubmitted( $this->goodFieldName."_".$this->id ) ) + { + $fileNameForPrepareFunc = securityCheckFileName( postvalue("filename_".$this->goodFieldName."_".$this->id) ); + if( $this->pageObject->pageType != PAGE_EDIT ) + { + $this->webValue = prepare_upload($this->field, "upload2", $fileNameForPrepareFunc, $fileNameForPrepareFunc, "" + , $this->id, $this->pageObject); + } + else + { + if(substr($this->webType, 0, 4) == "file") + { + $prepearedFile = prepare_file($this->webValue, $this->field, $this->webType, $fileNameForPrepareFunc, $this->id); + if($prepearedFile !== false) + { + $this->webValue = $prepearedFile["value"]; + $filename = $prepearedFile["filename"]; + } + else + $this->webValue = false; + } + else if(substr($this->webType, 0, 6) == "upload") + { + if($fileNameForPrepareFunc) + $this->webValue = $fileNameForPrepareFunc; + if($this->webType == "upload1") + { + // file deletion, read filename from the database + $oldValues = $this->pageObject->getOldRecordData(); + $fileNameForPrepareFunc = $oldValues[$this->field]; + } + $this->webValue = prepare_upload($this->field, $this->webType, $fileNameForPrepareFunc, $this->webValue, "", $this->id, $this->pageObject); + } + } + } + else + $this->webValue = false; + + if(!($this->webValue === false)) + { + if( $this->webValue && $this->pageObject->pSetEdit->getCreateThumbnail($this->field) ) + { + $contents = GetUploadedFileContents("value_".$this->goodFieldName."_".$this->id); + $ext = CheckImageExtension( GetUploadedFileName("value_".$this->goodFieldName."_".$this->id) ); + if( $ext ) { + $thumb = CreateThumbnail($contents, $this->pageObject->pSetEdit->getThumbnailSize($this->field), $ext); + $this->pageObject->filesToSave[] = new SaveFile($thumb, $this->pageObject->pSetEdit->GetStrThumbnail($this->field) + .$this->webValue, $this->pageObject->pSetEdit->getUploadFolder($this->field), $this->pageObject->pSetEdit->isAbsolute($this->field)); + } + } + + $avalues[ $this->field ] = $this->webValue; + } + } + + function makeWidthStyle($widthPx) + { + if(0 == $widthPx) + return ""; + return "min-width: ".$widthPx."px"; + } + + protected function getFileData( $value ) { + return RunnerFileHandler::getFileArray( $value, $this->field, $this->pageObject->pSet ); + } + + /** + * @return Array + * "url" => string + * "thumbnail" => string + * Each element can be empty if no corresponding file exists + * + */ + protected function getFileUrls( $fileData, $keylink ) { + $pSet = $this->pageObject->pSet; + $fs = getStorageProvider( $pSet, $this->field ); + $fsInfo = $fs->getFileInfo( $fileData["name"] ); + if( !$fsInfo ) { + return array(); + } + $lastModified = time(); + if( $fsInfo["lastModified"]) { + $lastModified = $fsInfo["lastModified"]; + } + + $params = array(); + $params["file"] = $fileData["usrName"]; + $params["table"] = $pSet->table(); + $params["field"] = $this->field; + $params["hash"] = fileAttrHash( $keylink, $file["size"], $lastModified ); + + foreach( $additionalParams as $k => $val ) { + $params[ $k ] = $val; + } + $ret = array(); + $ret["url"] = GetTableLink("file", "", prepareUrlQuery( $params ).$keylink ); + + + if( $fileData["thumbnail"] && $fs->getFileInfo( $fileData["thumbnail"] ) ) { + $params["thumbnail"] = 1; + $ret["thumbnail"] = GetTableLink("file", "", prepareUrlQuery( $params ).$keylink ); + } + + if( !$ret["thumbnail"] && $fsInfo["size"] > 512000 ) { + $ret["thumbnail"] = "images/icons/jpg.png"; + } + + + return $ret; + + + } + +} +?> \ No newline at end of file diff --git a/php/classes/controls/FilterBoolean.php b/php/classes/controls/FilterBoolean.php new file mode 100644 index 0000000000000000000000000000000000000000..5568ae88479fd6c84bcb96ebb973ce950e1cb4c3 --- /dev/null +++ b/php/classes/controls/FilterBoolean.php @@ -0,0 +1,137 @@ +separator = "~checked~"; + $this->filterFormat = FF_BOOLEAN; + + if( $this->totals == FT_NONE || $this->totals == FT_COUNT ) + $this->totalsfName = $this->fName; + } + + /** + * Get the view controls' value + * @param String value + * @return String + */ + protected function getValueToShow( $value ) { + return $this->getShownValue( $value == "on" ); + } + + /** + * Get the filter's label + * @param Boolean checked + * @return String + */ + protected function getShownValue( $checked ) { + $mData = $this->pSet->getBooleanFilterMessageData( $this->fName, $checked ); + return $this->getLabel( $mData["type"], $mData["text"] ); + } + + /** + * Form complex totals by aggregating SQL CASE statements, eg: + SELECT MAX( case when %field is on% then %total field% else null end ) AS `on_max`, + COUNT( case when %field is on% then 1 else null end ) AS `on_count`, + MAX( case when %field is off% then %total field% else null end ) AS `off_max`, + COUNT( case when %field is off% then 1 else null end ) AS `off_count` + FROM (...) + */ + protected function getDataCommand() { + $dc = new DsCommand; + $dc->filter = $this->pageObject->getDataSourceFilterCriteria( $this->fName ); + + $total = $this->dataTotalsName(); + if( !$total ) + $total = "count"; + + $values = array("on", "off"); + foreach( $values as $v ) { + if( $total == "count" ) { + $caseExpr = DataCondition::CaseConstOrNull( + FilterBoolean::getFilterCondition( $this->fName, $v, $this->pSet ), + 1 + ); + } else { + $caseExpr = DataCondition::CaseFieldOrNull( + FilterBoolean::getFilterCondition( $this->fName, $v, $this->pSet ), + $this->totalsfName + ); + } + $dc->totals[] = array( + "total" => $total, + "alias" => $v."_".$total, + "caseStatement" => $caseExpr +/* + "ifCondition" => FilterBoolean::getFilterCondition( $this->fName, $v, $this->pSet ), + "thenField" => $this->totalsfName, + "elseConst" => 'null' +*/ + ); + + if( $total != "count" ) { + $dc->totals[] = array( + "total" => "count", + "alias" => $v."_count", + "caseStatement" => DataCondition::CaseConstOrNull( + FilterBoolean::getFilterCondition( $this->fName, $v, $this->pSet ), + 1 + ) + ); + } + } + + return $dc; + } + + /** + * Add new filter blocks fetched from db + * @param &Array + */ + protected function addFilterBlocksFromDB( &$filterCtrlBlocks ) { + //$data = $this->connection->query( $this->strSQL )->fetchAssoc(); + + $qResult = $this->dataSource->getTotals( $this->getDataCommand() ); + $data = $qResult->fetchAssoc(); + + $this->decryptDataRow( $data ); + + if( $data["on_count"] == 0 && $data["off_count"] == 0 ) { + // no records found, hide filter + return; + } + + $values = array("on", "off"); + foreach( $values as $v ) { + $ctrlData = array( "value" => $v ); + if( $this->dataTotalsName() ) + $ctrlData["total"] = $data[ $v."_".$this->dataTotalsName() ]; + + $filterControl = $this->buildControl( $ctrlData ); + $filterCtrlBlocks[] = $this->getFilterBlockStructure( $filterControl ); + } + } + + /** + * Get a control's markup + * @params Array data + * @param Array parentFiltersData (optional) + * @return String + */ + protected function buildControl( $data, $parentFiltersData = array() ) { + $showValue = $this->getShownValue( $data["value"] == "on" ); + $totalValue = $this->getTotalValueToShow( $data["total"] ); + + return $this->getControlHTML( $data["value"], $showValue, $data["value"], $totalValue, $this->separator ); + } + + public static function getFilterCondition( $fName, $value, $pSet ) { + include_once getabspath("classes/controls/Control.php"); + include_once getabspath("classes/controls/CheckboxField.php"); + + return CheckboxField::getFieldCondition( $fName, $value ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/FilterControl.php b/php/classes/controls/FilterControl.php new file mode 100644 index 0000000000000000000000000000000000000000..f0e5c70533959fe200e3f6f53e70b33e43bed67b --- /dev/null +++ b/php/classes/controls/FilterControl.php @@ -0,0 +1,665 @@ +pageObject = $pageObj; + $this->id = $id; + $this->fName = $fName; + $this->gfName = GoodFieldName($this->fName); + $this->tName = $pageObj->tName; + $this->connection = $pageObj->connection; + $this->dataSource = $pageObj->getDataSource(); + + $this->pSet = $pageObj->pSet; + $this->cipherer = $pageObj->cipherer; + + $this->totals = $this->pSet->getFilterFieldTotal($fName); + $this->totalsfName = $this->pSet->getFilterTotalsField($fName); + if(!$this->totalsfName || $this->totals == FT_COUNT) + $this->totalsfName = $this->fName; + + $this->useTotals = $this->totals != FT_NONE; + + $this->multiSelect = $this->pSet->getFilterFiledMultiSelect($fName); + + + $this->filteredFields = $pageObj->searchClauseObj->getFilteredFields(); + $this->fieldType = $this->pSet->getFieldType($this->fName); + + if( !!$this->filteredFields[ $this->fName ] ) + $this->filtered = true; + + $this->assignViewControls($viewControls); + + $this->showCollapsed = $this->pSet->showCollapsed($this->fName); + } + + /** + * Get and assign view controls for the filter's and total fields + * @param object pageObj + */ + protected function assignViewControls($viewControls) + { + if( !$viewControls ) { + return; + } + $this->viewControl = $viewControls->getControl($this->fName); + //prevent filter's values from highlighting + $this->viewControl->searchHighlight = false; + //prevent filter's values from truncating + $this->viewControl->isUsedForFilter = true; + + if($this->totals == FT_MIN || $this->totals == FT_MAX) + { + $this->totalViewControl = $viewControls->getControl($this->totalsfName); + //prevent filter's values from highlighting + $this->totalViewControl->searchHighlight = false; + //prevent filter's values from truncating + $this->totalViewControl->isUsedForFilter = true; + } + } + + /** + * Add filter control's data to the ControlsMap + * @param Object pageObj + */ + public function addFilterControlToControlsMap($pageObj) + { + $ctrlsMap = $this->getBaseContolsMapParams(); + $pageObj->controlsMap["filters"]["controls"][] = $ctrlsMap; + } + + /** + * Get filter control's base ControlsMap array + * @return array + */ + protected function getBaseContolsMapParams() + { + $ctrlsMap = array(); + $ctrlsMap['fieldName'] = $this->fName; + $ctrlsMap['gfieldName'] = $this->gfName; + $ctrlsMap['filterFormat'] = $this->filterFormat; + $ctrlsMap['multiSelect'] = $this->multiSelect; + $ctrlsMap['filtered'] = $this->filtered; + $ctrlsMap['separator'] = $this->separator; + $ctrlsMap['collapsed'] = $this->showCollapsed; + + if( $this->filtered ) + { + $ctrlsMap['defaultValuesArray'] = $this->filteredFields[ $this->fName ]["values"]; + $ctrlsMap['defaultShowValues'] = array(); + foreach( $ctrlsMap['defaultValuesArray'] as $dv ) + { + $ctrlsMap['defaultShowValues'][] = $this->getValueToShow( $dv ); + } + } + + return $ctrlsMap; + } + + + /** + * The stub. It's overrided in the children classes + */ + protected function getValueToShow($value) + { + } + + /** + * Get the total field value + * @param String totalValue + * @return String + */ + protected function getTotalValueToShow($totalValue) + { + if($this->totals == FT_MIN || $this->totals == FT_MAX) + { + $totalData = array( $this->totalsfName => $totalValue ); + $totalValue = $this->totalViewControl->showDBValue($totalData, ""); + } + return $totalValue; + } + + /** + * Get the Filter's control block data. + * @param Object pageObj + * @param Array $dFilterBlocks (optional) + * @return Array + */ + public function buildFilterCtrlBlockArray( $pageObj, $dFilterBlocks = null ) + { + $this->addFilterControlToControlsMap($pageObj); + + $filterCtrlBlocks = array(); + + if($this->multiSelect != FM_ALWAYS && $this->filtered) + { + $filterCtrlBlocks = $this->getFilteredFilterBlocks(); + + if($this->multiSelect == FM_NONE) + return $filterCtrlBlocks; + } + + $this->addFilterBlocksFromDB($filterCtrlBlocks); + + if( $this->multiSelect != FM_NONE && $this->filtered ) + $this->addOutRangeValuesToFilter($filterCtrlBlocks); + + if( !$filterCtrlBlocks ) + $this->visible = false; + + $this->extraBlocksProcessing($filterCtrlBlocks); + + return $filterCtrlBlocks; + } + + /** + * Update filter blocks structures + * @param &Array + */ + protected function extraBlocksProcessing( &$filterCtrlBlocks ) + { + $this->sortFilterBlocks($filterCtrlBlocks); + } + + /** + * The stub. It could be overrided in the children classes + */ + protected function sortFilterBlocks( &$filterCtrlBlocks ) + { + } + + /** + * A stub + * @return Boolean + */ + protected function isTruncated() + { + return false; + } + + /** + * Usort callback function comparing filter blocks + * basing on db numeric values + */ + static function compareBlocksByNumericValues( $block1, $block2 ) + { + if( $block1["sortValue"] < $block2["sortValue"] ) + return -1; + + if( $block1["sortValue"] > $block2["sortValue"] ) + return 1; + + return 0; + } + + /** + * Usort callback function comparing filter blocks + * basing on db or formatted values + */ + static function compareBlocksByStringValues( $block1, $block2 ) + { + $sortValue1 = (string)$block1["sortValue"]; + $sortValue2 = (string)$block2["sortValue"]; + + $caseCompareResult = strcasecmp($sortValue1, $sortValue2); + if($caseCompareResult == 0) + return -strcmp($sortValue1, $sortValue2); + + return $caseCompareResult; + } + + /** + * Get the multiselect filters' filterblocks for values + * that are out of range. And add them to the existing filter blocks + * @param &Array filterCtrlBlocks + */ + protected function addOutRangeValuesToFilter(&$filterCtrlBlocks) + { + $visibilityClass = $this->multiSelect == FM_ON_DEMAND ? $this->onDemandHiddenItemClassName : ""; + + foreach( $this->filteredFields[ $this->fName ]["values"] as $value) + { + if(in_array($value, $this->valuesObtainedFromDB)) + continue; + + $filterControl = $this->buildControl( array($this->fName => $value) ); + $filterCtrlBlocks[] = $this->getFilterBlockStructure($filterControl, $visibilityClass, $value); + } + } + + /** + * Get the arrray with keys corresponding to filter blocks markup + * @param String filterControl + * @param String visibilityClass + * @param String value The raw Db field's value + * @param Array parentFiltersData (optional) + * @return Array + */ + protected function getFilterBlockStructure( $filterControl, $visibilityClass = "", $value = "", $parentFiltersData = array() ) + { + return array($this->gfName."_filter" => $filterControl, "visibilityClass_".$this->gfName => $visibilityClass); + } + + /** + * Get the filtered not multiselect filter's control block + * @return Array + */ + protected function getFilteredFilterBlocks() + { + $filterControl = array(); + foreach($this->filteredFields[ $this->fName ]["values"] as $value) + { + $showValue = $this->getControlCaption( $value ); + $delButtonHtml = $this->getDelButtonHtml($this->gfName, $this->id, $value); + $filterControl = ''.$delButtonHtml.$showValue.''; + $parentFiltersData = $this->getParentFiltersDataForFilteredBlock($value); + $classes = 'filter-ready-value'.( $this->multiSelect == FM_ON_DEMAND ? ' ondemand' : '' ); + $filterCtrlBlocks[] = $this->getFilterBlockStructure($filterControl, $classes, $value, $parentFiltersData); + } + + return $filterCtrlBlocks; + } + + protected function getControlCaption( $value ) + { + return $this->getValueToShow($value); + } + + /** + * A stab for not dependent filters + * @param String + * @return Array + */ + protected function getParentFiltersDataForFilteredBlock($value) + { + return array(); + } + + /** + * The stub. It's overrided in the children classes + */ + protected function addFilterBlocksFromDB(&$filterBlocks) + { + } + + /** + * Get the markup representing a control on the page + * @param String value + * @param String showValue + * @param String dataValue + * @param String totalValue + * @param String separator + * @param Array parentFiltersData + * @return String + */ + protected function getControlHTML($value, $showValue, $dataValue, $totalValue, $separator, $parentFiltersData = null) + { + $filterControl = ''; + $encodeDataValue = runner_htmlspecialchars($dataValue); + $dataValueAttr = 'data-filtervalue="'.$encodeDataValue.'"'; + + $extraDataAttrs = $this->getExtraDataAttrs($parentFiltersData); + + $pageType = 'list'; + if( isReport( $this->pSet->getEntityType() ) ) + $pageType = 'report'; + else if( isChart( $this->pSet->getEntityType() ) ) + $pageType = 'chart'; + + if($this->multiSelect != FM_NONE) + { + $style = $this->filtered || $this->multiSelect == FM_ALWAYS ? '' : 'style="display: none;"'; + $checkedAttr = $this->getCheckedAttr( $value, $parentFiltersData ); + + $checkBox = ''; + } + if($this->multiSelect != FM_ALWAYS) + { + $href = GetTableLink( GetTableURL($this->tName), $pageType, 'f=('.runner_htmlspecialchars( rawurlencode( $this->fName ) ). + $separator.$encodeDataValue.')' ); + $hrefAttr = 'href="'.$href.'"'; + $label = $checkBox . ' ' .$showValue; + } + else + { + $label = $checkBox . ' '.$showValue.''; + } + + if($this->useTotals && $totalValue != "") + $label .= ' ('.$totalValue.')'; + + $labelAttrs = implode( " ", array( $hrefAttr, $dataValueAttr, $extraDataAttrs ) ); + $label = '' . $label . ""; + + $filterControl.= $label; +// $filterControl.= ''.$label.''; + + return $filterControl; + } + + /** + * A stub for not dependat filters + * @param Array parentFiltersData + * @return String + */ + protected function getExtraDataAttrs( $parentFiltersData ) + { + return ''; + } + + /** + * Get the cheked attribute string for a multiselect filter control + * @return String + */ + protected function getCheckedAttr( $value, $parentFiltersData = null ) + { + if( $this->multiSelect == FM_NONE || $this->filtered && !in_array($value, $this->filteredFields[ $this->fName ]['values']) ) + return ''; + + return 'checked="checked"'; + } + + /** + * Get the filter's buttons parameters such as buttons' labels, + * class names and attributes + * @param Array dBtnParams (optional) + * @return Array + */ + public function getFilterButtonParams( $dBtnParams = null ) + { + return array( + 'attrs' => 'id="filter_'.$this->gfName.'_'.$this->id.'"', + 'hasMultiselectBtn' => $this->multiSelect == FM_ON_DEMAND, + 'hasApplyBtn' => $this->useApllyBtn + ); + } + + /** + * Get the filter's state array, + * @return Array + */ + public function getFilterState() + { + return array( + "visible" => $this->visible, + "filtered" => $this->filtered, + "collapsed" => $this->showCollapsed, + "truncated" => $this->isTruncated(), + "showMoreHidden" => $this->isShowMoreHidden() + ); + } + + /** + * Check if the "show more" button must be hidden by class attr + * @return Boolean + */ + protected function isShowMoreHidden() + { + return false; + } + + /** + * Get the filter's extra controlls parameters + * @param Array dBtnParams (dExtraCtrls) + * @return Array + */ + public function getFilterExtraControls( $dExtraCtrls = null ) + { + $selectAllAttrs = ""; + if( !$this->filtered && $this->multiSelect !== FM_NONE) + $selectAllAttrs = 'checked="checked"'; + + if( $this->multiSelect == FM_ON_DEMAND ) + $selectAllAttrs.= ' style="display: none;"'; + + return array( + "showValue" => $this->getShowValue(), + "filtered" => $this->filtered, + "selectAllAttrs" => $selectAllAttrs, + "numberOfExtraItemsToShow" => $this->getNumberOfExtraItemsToShow() + ); + } + + /** + * A stub + * @return Number + */ + protected function getNumberOfExtraItemsToShow() + { + return 0; + } + + /** + * Check if the control should be visible + * @return Boolean + */ + public function isVisible() + { + return $this->visible; + } + + /** + * Check if the control should be collapsed + * @return Boolean + */ + public function isCollapsed() + { + return $this->showCollapsed; + } + + /** + * Check if the control is filtered + * @return Boolean + */ + public function isFiltered() + { + return $this->filtered; + } + + /** + * Get the murkup of the control's delete button + * @param String gfName + * @param Number id + * @param String deleteValue + * @return String + */ + protected function getDelButtonHtml($gfName, $id, $deleteValue) + { + $deleteValue = runner_htmlspecialchars($deleteValue); + $html = ''; + return $html; + } + + /** + * Decrypt the database row data + * @param &Array data + */ + protected function decryptDataRow(&$data) + { + if( $this->cipherer->isFieldPHPEncrypted($this->fName) ) + $data[ $this->fName ] = $this->cipherer->DecryptField( $this->fName, $data[ $this->fName ] ); + } + + /** + * Get the lable basing on its type + * @param {String} type + * @param {String} message + * @return {String} + */ + public function getLabel($type, $message) + { + if( $type === "Text" ) + return $message; + + return GetCustomLabel($message); + } + + /** + * The static function creating the Filter control basing on the control's type + * @param String fName + * @param Object pageObj + * @param Number id + * @param Object viewControls + * @return Object + */ + static function getFilterControl($fName, $pageObj, $id, $viewControls = null ) + { + $filterFields = $pageObj->pSet->getFilterFields(); + if( array_search( $fName, $filterFields ) === false ) { + return null; + } + $contorlType = $pageObj->pSet->getFilterFieldFormat($fName); + switch($contorlType) + { + case FF_VALUE_LIST: + include_once getabspath("classes/controls/FilterValuesList.php"); + if( $pageObj->pSet->multiSelectLookupEdit($fName) ) { + include_once getabspath("classes/controls/FilterMultiselectLookup.php"); + return new FilterMultiselectLookup($fName, $pageObj, $id, $viewControls); + } + + return new FilterValuesList($fName, $pageObj, $id, $viewControls); + + case FF_BOOLEAN: + include_once getabspath("classes/controls/Control.php"); + include_once getabspath("classes/controls/CheckboxField.php"); + include_once getabspath("classes/controls/FilterBoolean.php"); + return new FilterBoolean($fName, $pageObj, $id, $viewControls); + + case FF_INTERVAL_LIST: + include_once getabspath("classes/controls/FilterIntervalList.php"); + return new FilterIntervalList($fName, $pageObj, $id, $viewControls); + + case FF_INTERVAL_SLIDER: + include_once getabspath("classes/controls/FilterIntervalSlider.php"); + $fieldType = $pageObj->pSet->getFieldType($fName); + + if( IsDateFieldType($fieldType) ) + { + include_once getabspath("classes/controls/FilterIntervalDateSlider.php"); + return new FilterIntervalDateSlider($fName, $pageObj, $id, $viewControls); + } + if( IsTimeType($fieldType) ) + { + include_once getabspath("classes/controls/FilterIntervalDateSlider.php"); + include_once getabspath("classes/controls/FilterIntervalTimeSlider.php"); + return new FilterIntervalTimeSlider($fName, $pageObj, $id, $viewControls); + } + return new FilterIntervalSlider($fName, $pageObj, $id, $viewControls); + + default: + include_once getabspath("classes/controls/FilterValuesList.php"); + return new FilterValuesList($fName, $pageObj, $id, $viewControls); + } + } + + public function hasDependentFilter() { + return false; + } + + protected function dataTotalsName() { + $totalOption = $this->pSet->getFilterFieldTotal( $this->fName ); + if( $totalOption == FT_COUNT ) { + return 'count'; + } else if( $totalOption == FT_MIN ) { + return 'min'; + } else if( $totalOption == FT_MAX ) { + return 'max'; + } + return ''; + } + + /** + * Returns string to be displayed in the horizontal control + */ + protected function getShowValue() { + if( !$this->filtered ) { + return ""; + } + $values =& $this->filteredFields[ $this->fName ]["values"]; + if( !$values ) { + return ""; + } + if( count( $values ) > 1 ) { + return "(" . count( $values ) . ")"; + } + return $this->getControlCaption( $values[0] ); + } +} + +?> \ No newline at end of file diff --git a/php/classes/controls/FilterIntervalDateSlider.php b/php/classes/controls/FilterIntervalDateSlider.php new file mode 100644 index 0000000000000000000000000000000000000000..e376bf5263f0cfa4b65edd83ab7af686edc746cc --- /dev/null +++ b/php/classes/controls/FilterIntervalDateSlider.php @@ -0,0 +1,773 @@ +stepType = $this->pSet->getFilterStepType($fName); + + if($this->stepType == FSST_MONTHS) + { + $this->months = array( + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December" ); + } + } + + /** + * Assign the control's knobs properties + */ + protected function assignKnobsValues() + { + $filterData = $this->filteredFields[ $this->fName ]; + + $filterValues = array(); + $filterValues[] = $filterData['values'][0]; + $filterValues[] = $filterData['sValues'][0]; + + $value1 = prepare_for_db( $this->fName, $filterValues[0], "" ); + + if( $this->knobsType == FS_MIN_ONLY ) { + $this->minKnobValue = $value1; + $this->minKnobFormatValue = $filterValues[0]; + return; + } + + if( $this->knobsType == FS_MAX_ONLY ) { + $this->maxKnobValue = $value1; + $this->maxKnobFormatValue = $filterValues[0]; + return; + } + + $this->minKnobValue = $value1; + $this->maxKnobValue = prepare_for_db( $this->fName, $filterValues[1], "" ); + + $this->minKnobFormatValue = $filterValues[0]; + $this->maxKnobFormatValue = $filterValues[1]; + } + + /** + * Get the array representation of the db-formatted date string: + * array(year, month, day, hour, minute, second) + * @param String value + * @return Array + */ + protected function getDateTimeArray($value, $forCaption = false) + { + return db2time($value); + } + + /** + * Get the html markup for the slider knobs' captions + * @return String + */ + protected function getCaptionSpansHTML() + { + $inlineStyelPrefix = $inlineStyelPostfix = ' style="display: none;"'; + $inlineStyelMin = $inlineStyelMax = ''; + + if( $this->stepType != FSST_YEARS || $this->stepType != FSST_DAYS ) + { + $minValueArr = $this->minDateArray; + if( $this->getValueInSeconds($this->minKnobValue) >= $this->getValueInSeconds($this->minValue) ) + $minValueArr = $this->getDateTimeArray($this->minKnobValue); + + $maxValueArr = $this->maxDateArray; + if($this->getValueInSeconds($this->maxKnobValue) <= $this->getValueInSeconds($this->maxValue)) + $maxValueArr = $this->getDateTimeArray($this->maxKnobValue); + + if( $this->stepType == FSST_MONTHS ) + { + $month = $minValueArr[1]; + if( !$this->filtered || $this->isMonthNumberToAdjust(true, $minValueArr[0], $minValueArr[1]) ) + $month = $this->getAdjustedMonthNumber($minValueArr[1], true); + + $prefix = $this->getMonthName($month); + + if( $minValueArr[0] == $maxValueArr[0] ) + { + $inlineStyelMin = ' style="display: none;"'; + $inlineStyelPrefix = ''; + } + } + else if( $this->stepType == FSST_HOURS || $this->stepType == FSST_MINUTES || $this->stepType == FSST_SECONDS ) + { + global $locale_info; + $timeFormatString = $locale_info["LOCALE_STIMEFORMAT"]; + if($this->stepType != FSST_SECONDS) + $timeFormatString = str_replace( $locale_info["LOCALE_STIME"]."ss", "", $timeFormatString ); + + $postfix = format_datetime_custom($maxValueArr, $timeFormatString); + if( $minValueArr[0] == $maxValueArr[0] && $minValueArr[1] == $maxValueArr[1] && $minValueArr[2] == $maxValueArr[2] ) + { + $inlineStyelMax = ' style="display: none;"'; + $inlineStyelPostfix = ''; + } + } + } + + $minSpan = ''.$this->getMinSpanValue().''; + $maxSpan = ''.$this->getMaxSpanValue().''; + $captionSpans = $minSpan." - ".$maxSpan; + + $prefixSpan = ''.$prefix.''; + $postfixSpan = ''.$postfix.''; + + $captionSpans = $prefixSpan . $captionSpans . $postfixSpan; + + return $captionSpans; + } + + /** + * Get the value converted into seconds + * @param String value + * @return Number + */ + protected function getValueInSeconds($value) + { + return strtotime($value); + } + + /** + * Get the caption fot the min slider's knob + * @return String + */ + protected function getMinSpanValue() + { + $minSpanValue = $this->minKnobValue; + //process the case when other where conditions make + //the real minKnobValue going out of the slider's bounds + if( $this->getValueInSeconds($minSpanValue) < $this->getValueInSeconds($this->minValue) ) + $minSpanValue = $this->minValue; + + $minSpanValue = $this->getRoundedDateCaption($minSpanValue, true); + + return $minSpanValue; + } + + /** + * Get the caption fot the max slider's knob + * @return String + */ + protected function getMaxSpanValue() + { + $maxSpanValue = $this->maxKnobValue; + //process the case when other where conditions make + //the real maxKnobValue going out of the slider's bounds + if($this->getValueInSeconds($maxSpanValue) > $this->getValueInSeconds($this->maxValue)) + $maxSpanValue = $this->maxValue; + + $maxSpanValue = $this->getRoundedDateCaption($maxSpanValue, false); + + return $maxSpanValue; + } + + /** + * Get the caption for the rounded date corresponding to + * the db-formatted date string passed + * @param String value + * @param Boolean isLower + * @return String + */ + protected function getRoundedDateCaption($value, $isLower = false) + { + //array(year,month,day,hour,minute,second) + $dateArray = $this->getDateTimeArray($value, true); + switch($this->stepType) + { + case FSST_SECONDS: + return $this->getSecondsCaption($dateArray); + case FSST_MINUTES: + return $this->getMinutesCaption($dateArray); + case FSST_HOURS: + return $this->getHoursCaption($dateArray, $isLower); + case FSST_DAYS: + return format_normalized_shortdate($dateArray); + case FSST_MONTHS: + return $this->getMonthCaption($dateArray, $isLower); + case FSST_YEARS: + return $dateArray[0]; + default: + return $value; + } + } + + /** + * Get the full caption value for the slider with the 'seconds' step type + * @param Array dateArray + * @return String + */ + protected function getSecondsCaption($dateArray) + { + return str_format_datetime($dateArray); + } + + /** + * Get the full caption value for the slider with the 'minutes' step type + * @param Array dateArray + * @return String + */ + protected function getMinutesCaption($dateArray) + { + global $locale_info; + $dateArray[5] = 0; + + $timeFormatString = str_replace( $locale_info["LOCALE_STIME"]."ss", "", $locale_info["LOCALE_STIMEFORMAT"]); + return format_datetime_custom($dateArray, normalized_date_format()." ".$timeFormatString); + } + + /** + * Get the full caption value for the slider with the 'hours' step type + * @param Array dateArray + * @param Boolean isLower + * @return String + */ + protected function getHoursCaption($dateArray, $isLower) + { + global $locale_info; + + $hours = $this->getAdjustedHoursValue($dateArray[3], $dateArray[4], $isLower); + $dateArray[3] = $dateArray[4] = $dateArray[5] = 0; + $dateArray = addHours($dateArray, $hours); + + $timeFormatString = str_replace( $locale_info["LOCALE_STIME"]."ss", "", $locale_info["LOCALE_STIMEFORMAT"]); + + return format_datetime_custom($dateArray, normalized_date_format()." ".$timeFormatString); + } + + /** + * Get the srep-rounded hours value + * @param Number hours + * @param Number minutes + * @param Boolean isLower + * @return Number + */ + protected function getAdjustedHoursValue($hours, $minutes, $isLower) + { + $step = $this->stepValue * 60; + $minutes = $hours * 60 + $minutes; + + if($isLower) + return floor( $minutes / $step ) * $this->stepValue; + + return ceil( $minutes / $step ) * $this->stepValue; + } + + /** + * Get the full caption value for the slider with the 'months' step type + * @param Array dateArray + * @param Boolean isLower + * @return String + */ + protected function getMonthCaption($dateArray, $isLower) + { + $year = $dateArray[0]; + $month = $dateArray[1]; + + if( !$this->filtered || $this->isMonthNumberToAdjust($isLower, $year, $month) ) + $month = $this->getAdjustedMonthNumber($month, $isLower); + + return $this->getMonthName($month)." ".$year; + } + + /** + * Check if it's necessary to adjust the month value + * It returns true for the limit knobs year, month values + * @param Boolean isLower + * @param Number year + * @param Number month + * @return Boolean + */ + protected function isMonthNumberToAdjust( $isLower, $year, $month ) + { + switch( $this->knobsType ) + { + case FS_MIN_ONLY: + return !$isLower; + + case FS_MAX_ONLY: + return $isLower; + + case FS_BOTH: + if( $isLower && $year == $this->minDateArray[0] && abs($month - $this->adjMinDateMonth) < $this->stepValue + || !$isLower && $year == $this->maxDateArray[0] && abs($month - $this->adjMaxDateMonth) < $this->stepValue ) + { + return true; + } + return false; + + default: + return false; + } + } + + /** + * Get the month's name by its number + * @param Number month + * @return String + */ + protected function getMonthName($month) + { + return $this->months[ $month - 1 ]; + } + + /** + * Get the srep-rounded month value + * @param Number month + * @param Boolean isLower + * @return Number + */ + protected function getAdjustedMonthNumber($month, $isLower) + { + $step = $this->stepValue; + if($step != 1) + { + if($isLower) + $month = floor( ( $month - 1 ) / $step ) * $step + 1; + else + $month = ceil( $month / $step ) * $step ; + } + return $month; + } + + /** + * Get date-time formatted string + * @param Array dateArray + * @return String + */ + protected function getDateTimeString($dateArray) + { + global $locale_info; + //to avoid locale-specific formatting + //$formatString = $locale_info["LOCALE_SSHORTDATE"]." HH:mm:ss"; + $formatString = "yyyy-MM-dd HH:mm:ss"; + return format_datetime_custom($dateArray, $formatString); + } + + /** + * Get the step-rounded date/date-time formatted string + * @param String value + * @param Boolean isLower + * @return String + */ + protected function getRoundedDate($value, $isLower, $isKnob = false) + { + //array(year,month,day,hour,minute,second) + $dateArray = $this->getDateTimeArray($value); + + switch($this->stepType) + { + case FSST_SECONDS: + if($isKnob) + return $this->getDateTimeString($dateArray); + + $prepDateArray = $this->minDateArray; + + $diffSec = $this->getDifferenceInSecWithMin($value, $isLower); + $prepDateArray = addSeconds($prepDateArray, $diffSec); + + return $this->getDateTimeString($prepDateArray); + + case FSST_MINUTES: + if($isKnob) + return $this->getDateTimeString($dateArray); + + $prepDateArray = $this->minDateArray; + + $diffSec = $this->getDifferenceInSecWithMin($value, $isLower); + $minutes = floor( $diffSec / 60); + $prepDateArray = addMinutes($prepDateArray, $minutes); + + return $this->getDateTimeString($prepDateArray); + + case FSST_HOURS: + $hours = $this->getAdjustedHoursValue( $dateArray[3], $dateArray[4], $isLower ); + $dateArray[3] = $dateArray[4] = $dateArray[5] = 0; + $dateArray = addHours($dateArray, $hours); + + return $this->getDateTimeString($dateArray); + + case FSST_DAYS: + return format_datetime_custom($dateArray, "yyyy-MM-dd"); + + case FSST_MONTHS: + if($isKnob) + return format_datetime_custom($dateArray, "yyyy-MM-dd"); + + $dateArray[1] = $this->getAdjustedMonthNumber( $dateArray[1], $isLower ); + $dateArray[2] = $isLower? 1 : getLastMonthDayNumber( $dateArray[0], $dateArray[1] ); + $dateArray[3] = $dateArray[4] = $dateArray[5] = 0; + + return format_datetime_custom($dateArray, "yyyy-MM-dd"); + + case FSST_YEARS: + $dateArray[3] = $dateArray[4] = $dateArray[5] = 0; + $dateArray[1] = $isLower ? 1 : 12; + $dateArray[2] = $isLower ? 1 : 31; + + return format_datetime_custom($dateArray, "yyyy-MM-dd"); + + default: + return $value; + } + } + + /** + * Get the seconds between the step-rounded value and the min slider's value + * @param String value Db time-formatted string + * @param Boolean isLower + * @return Number + */ + protected function getDifferenceInSecWithMin($value, $isLower) + { + $step = $this->getStepValue(); + $minSec = $this->getValueInSeconds($this->minValue); + $valueSec = $this->getValueInSeconds($value); + + $min = floor( $minSec / $step ) * $step; + if($isLower) + $rvalue = floor( $valueSec / $step) * $step; + else + $rvalue = ceil( $valueSec / $step ) * $step; + + return $rvalue - $min; + } + + /** + * Get the slider step value + * basing on the step type + * @return Number + */ + protected function getStepValue() + { + switch($this->stepType) + { + case FSST_MINUTES: + return 60 * $this->stepValue; + + case FSST_HOURS: + return 3600 * $this->stepValue; + + case FSST_DAYS: + return 86400 * $this->stepValue; + + default: + return $this->stepValue; + } + } + + /** + * Check if there are database values for the filter's field + * that are differs from each other for more than a step value + * @param Array data + * @return Boolean + */ + protected function fieldHasNoRange($data) + { + if (is_null( $data['sliderMin'] ) && is_null( $data['sliderMax'] ) || $data['sliderMax'] == $data['sliderMin']) + return true; + + $step = $this->getStepValue(); + if($this->stepType == FSST_MONTHS || $this->stepType == FSST_YEARS) + { + $dateArrayMin = db2time( $data['sliderMin'] ); + $dateArrayMax = db2time( $data['sliderMax'] ); + + if($this->stepType == FSST_MONTHS && $dateArrayMax[0] == $dateArrayMin[0] && ($dateArrayMax[1] - $dateArrayMin[1]) < $step ) + return true; + + if($this->stepType == FSST_YEARS && ($dateArrayMax[0] - $dateArrayMin[0]) < $step) + return true; + } + else + { + if( (strtotime( $data['sliderMax'] ) - strtotime( $data['sliderMin'] )) < $step ) + return true; + } + return false; + } + + /** + * Get the html markup representing the control on the page + * @param Array data + * @param Array parentFiltersData (optional) + * @return String + */ + protected function buildControl( $data, $parentFiltersData = array() ) + { + $this->minValue = $data['sliderMin']; + $this->maxValue = $data['sliderMax']; + + $timeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + + $this->minDateArray = $this->getDateTimeArray($this->minValue); + $this->maxDateArray = $this->getDateTimeArray($this->maxValue); + if($this->stepType == FSST_MINUTES) + $this->minDateArray = $this->getMinuteAdjustedMinValue(); + else if($this->stepType == FSST_SECONDS) + $this->minDateArray = $this->getSecAdjustedMinValue(); + + if($this->stepType == FSST_MONTHS) + { + $this->adjMinDateMonth = $this->getAdjustedMonthNumber($this->minDateArray[1], true); + $this->adjMaxDateMonth = $this->getAdjustedMonthNumber($this->maxDateArray[1], false); + } + + //assign the knobs values + if( !$this->filtered ) + { + $this->minKnobValue = $data['sliderMin']; + $this->maxKnobValue = $data['sliderMax']; + } + else + { + if($this->knobsType == FS_MAX_ONLY) + $this->minKnobValue = $data['sliderMin']; + + if($this->knobsType == FS_MIN_ONLY) + $this->maxKnobValue = $data['sliderMax']; + } + + date_default_timezone_set($timeZone); + return $this->getSliderHTML(); + } + + /** + * Get the step-rounded min slider value's array representation + * for the sliders with 'seconds' step type + * @return Array + */ + function getSecAdjustedMinValue() + { + $prepDateArray = $this->minDateArray; + $prepDateArray[5] = 0; + + $step = $this->getStepValue(); + $minRoundSec = floor( strtotime($this->minValue) / $step ) * $step ; + $minUpToSec = floor( strtotime($this->minValue) / 60 ) * 60; + $diffSec = $minRoundSec - $minUpToSec; + + $prepDateArray = addSeconds($prepDateArray, $diffSec); + return $prepDateArray; + } + + /** + * Get the step-rounded min slider value's array representation + * for the sliders with 'minutes' step type + * @return Array + */ + function getMinuteAdjustedMinValue() + { + $prepDateArray = $this->minDateArray; + $prepDateArray[4] = $prepDateArray[5] = 0; + + $step = $this->getStepValue(); + $minRoundSec = floor( strtotime($this->minValue) / $step ) * $step ; + $minUpToHour = floor( strtotime($this->minValue) / 3600 ) * 3600; + $diffSec = $minRoundSec - $minUpToHour; + + $minutes = floor( $diffSec / 60); + $prepDateArray = addMinutes($prepDateArray, $minutes); + + return $prepDateArray; + } + + /** + * Get the numeric equevalent for the date equivalent to the db date-formatted string + * @param String value Db date-formatted string + * @param Boolean isLower + * @return Number + */ + protected function round($value, $isLower, $isKnob = false) + { + switch($this->stepType) + { + case FSST_SECONDS: + case FSST_MINUTES: + case FSST_HOURS: + return $this->getDifferenceInSecWithMin($value, $isLower); + + case FSST_DAYS: + return strtotime($value) - strtotime($this->minValue); + + case FSST_MONTHS: + $dateArray = db2time($value); + $year = $dateArray[0]; + $month = $dateArray[1]; + if(!$isKnob || !$this->filtered) + $month = $this->getAdjustedMonthNumber($dateArray[1], $isLower); + + $minYear = $this->minDateArray[0]; + + $monthsNumber = ($year - $minYear) * 12 + $month - $this->adjMinDateMonth; + if(!$isLower) + $monthsNumber = $monthsNumber + 1; + + return $monthsNumber; + + case FSST_YEARS: + $step = $this->getStepValue(); + $dateArray = db2time($value); + $year = $dateArray[0]; + + $minYear = $this->minDateArray[0]; + + if($isLower) + return floor( ( $year - $minYear ) / $step ) * $step ; + + return ceil( ( $year - $minYear ) / $step ) * $step ; + + default: + return $value; + } + } + + /** + * Get the real slider's date value adjusted accordit to the step type + * @param String value + * @return String + */ + protected function getAdjustedRealDate($value) + { + $dateArray = $this->getDateTimeArray($value); + if($this->stepType == FSST_MINUTES) + $dateArray[5] = 0; + return $this->getDateTimeString($dateArray); + } + + /** + * Get date filter control's base ControlsMap array + * @return array + */ + protected function getBaseContolsMapParams() + { + $ctrlsMap = parent::getBaseContolsMapParams(); + $timeZone = date_default_timezone_get(); + date_default_timezone_set('UTC'); + + $ctrlsMap['stepType'] = $this->stepType; + + if( $this->stepType == FSST_SECONDS || $this->stepType == FSST_MINUTES ) { + $ctrlsMap['realMinValue'] = $this->getAdjustedRealDate( $this->minValue ); + $ctrlsMap['realMaxValue'] = $this->getAdjustedRealDate( $this->maxValue ); + } + + //the min, max formated dates + $ctrlsMap['minValue'] = $this->getRoundedDate( $this->minValue, true ); + $ctrlsMap['maxValue'] = $this->getRoundedDate( $this->maxValue, false ); + + //the min, max slider values (numbers) + $ctrlsMap['roundedMin'] = 0; + $ctrlsMap['roundedMax'] = $this->round( $this->maxValue, false ); + + $ctrlsMap['roundedMinKnobValue'] = $this->round( $this->minKnobValue, true, true ); + $ctrlsMap['roundedMaxKnobValue'] = $this->round( $this->maxKnobValue, false, true ); + + if( $this->filtered ) { + //$ctrlsMap['defaultValuesArray'] = array( $this->minKnobFormatValue, $this->maxKnobFormatValue ); + $ctrlsMap['minKnobValue'] = $ctrlsMap['minValue']; + $ctrlsMap['maxKnobValue'] = $ctrlsMap['maxValue']; + + if( $this->knobsType != FS_MAX_ONLY ) + $ctrlsMap['minKnobValue'] = $this->getRoundedDate( $this->minKnobFormatValue, true, true ); + + if( $this->knobsType != FS_MIN_ONLY ) + $ctrlsMap['maxKnobValue'] = $this->getRoundedDate( $this->maxKnobFormatValue, false, true ); + } + date_default_timezone_set( $timeZone ); + + if( $this->stepType == FSST_SECONDS ) + $ctrlsMap['showSeconds'] = true; + + if( $this->stepType == FSST_SECONDS || $this->stepType == FSST_MINUTES || $this->stepType == FSST_HOURS ) { + global $locale_info; + $ctrlsMap['showTime'] = true; + $ctrlsMap['timeDelimiter'] = $locale_info["LOCALE_STIME"]; + $ctrlsMap['timeFormat'] = $locale_info["LOCALE_STIMEFORMAT"]; + $ctrlsMap['is24hoursFormat'] = $locale_info["LOCALE_ITIME"] == "1"; + $ctrlsMap['leadingZero'] = $locale_info["LOCALE_ITLZERO"] == "1"; + + if( $locale_info["LOCALE_ITIME"] == "0" ) + $ctrlsMap['designators'] = array( "am" => $locale_info["LOCALE_S1159"], "pm" => $locale_info["LOCALE_S2359"] ); + } + + return $ctrlsMap; + } + + /** + * Add filter control's data to the ControlsMap + * @param Object pageObj + */ + public function addFilterControlToControlsMap($pageObj) + { + $ctrlsMap = $this->getBaseContolsMapParams(); + $ctrlsMap['isFieldDateType'] = true; + + $pageObj->controlsMap["filters"]["controls"][] = $ctrlsMap; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/FilterIntervalList.php b/php/classes/controls/FilterIntervalList.php new file mode 100644 index 0000000000000000000000000000000000000000..12ec94d5605f88406622fde9157222c0b795c981 --- /dev/null +++ b/php/classes/controls/FilterIntervalList.php @@ -0,0 +1,259 @@ +separator = "~interval~"; + $this->filterFormat = FF_INTERVAL_LIST; + + if( $this->totals == FT_NONE || $this->totals == FT_COUNT ) + $this->totalsfName = $this->fName; + + $this->useApllyBtn = $this->multiSelect == FM_ALWAYS; + } + + /** + * Form complex totals by aggregating SQL CASE statements, eg: + SELECT MIN( ( CASE WHEN %field is > 0% and %field is <= 10% ) THEN %total_field% ELSE NULL END ) ) AS %field%1_min, + COUNT( ( CASE WHEN %field is > 0% and %field is <= 10% THEN 1 ELSE NULL END ) ) AS %field%1_count, + MIN( ( CASE WHEN %field is > 10% and %field is <= 20% THEN %total_field% ELSE NULL END ) ) AS %field%2_min, + COUNT( ( CASE WHEN %field is > 10% and %field is <= 20% THEN 1 ELSE NULL END ) ) AS %field%2_count, + ... + FROM ( ... ) + */ + protected function getDataCommand() { + $dc = new DsCommand; + $dc->filter = $this->pageObject->getDataSourceFilterCriteria( $this->fName ); + + $intervalsRowData = $this->pSet->getFilterIntervals($this->fName); + foreach( $intervalsRowData as $intervalData ) { + $idx = $intervalData["index"]; + + $total = $this->dataTotalsName(); + if( !$total ) + $total = "count"; + + if( $total == "count" ) { + $caseExpr = DataCondition::CaseConstOrNull( + FilterIntervalList::getFilterCondition( $this->fName, $idx, $this->pSet ), + 1 + ); + } else { + $caseExpr = DataCondition::CaseFieldOrNull( + FilterIntervalList::getFilterCondition( $this->fName, $idx, $this->pSet ), + $this->totalsfName + ); + } + + $dc->totals[] = array( + "total" => $total, + "alias" => $this->fName.$idx."_".$total, + "caseStatement" => $caseExpr + ); + + if( $total != "count" ) { + $dc->totals[] = array( + "total" => "count", + "alias" => $this->fName.$idx."_count", + "caseStatement" => DataCondition::CaseConstOrNull( + FilterIntervalList::getFilterCondition( $this->fName, $idx, $this->pSet ), + 1 + ) + ); + } + } + + return $dc; + } + + + /** + * Get label + * @param String index + * @return String + */ + protected function getValueToShow( $value ) { + return $this->getIntervalLabel( $value ); + } + + protected function getIntervalLabel( $index ) { + $iData = $this->pSet->getFilterIntervalDatabyIndex( $this->fName, $index ); + return $this->getLabel( $iData["intervalLabelNameType"], $iData["intervalLabelText"] ); + } + + /** + * Get the filter blocks data using the database query + * and add it the the existing blocks + * @param &Array + */ + protected function addFilterBlocksFromDB( &$filterCtrlBlocks ) + { + $visibilityClass = $this->filtered && $this->multiSelect == FM_ON_DEMAND ? $this->onDemandHiddenItemClassName : ""; + + //query to database + $qResult = $this->dataSource->getTotals( $this->getDataCommand() ); + $data = $qResult->fetchAssoc(); + + $this->decryptDataRow( $data ); + + $intervalsRowData = $this->pSet->getFilterIntervals( $this->fName ); + foreach( $intervalsRowData as $iData ) { + if( !$this->pSet->showWithNoRecords( $this->fName ) && $data[ $this->fName.$iData["index"]."_count" ] == 0 ) + continue; + + $this->valuesObtainedFromDB[] = $iData["index"]; + + $ctrlData = array(); + $ctrlData["index"] = $iData["index"]; + + if( $this->dataTotalsName() ) + $ctrlData["total"] = $data[ $this->fName.$iData["index"]."_".$this->dataTotalsName() ]; + + $filterControl = $this->buildControl( $ctrlData ); + $filterCtrlBlocks[] = $this->getFilterBlockStructure( $filterControl, $visibilityClass, $iData["index"] ); + } + } + + /** + * Get the arrray with keys corresponding to filter blocks markup + * @param String filterControl + * @param String visibilityClass + * @param String value The Interval's index + * @param Array parentFiltersData (optional) + * @return Array + */ + protected function getFilterBlockStructure( $filterControl, $visibilityClass = "", $value = "", $parentFiltersData = array() ) + { + if( $this->multiSelect != FM_ALWAYS ) + $visibilityClass.= " filter-link"; + + return array( + $this->gfName."_filter" => $filterControl, + "visibilityClass_".$this->gfName => $visibilityClass, + "sortValue" => $value + ); + } + + /** + * Sort filter blocks depending on the field's type and format + * @param &Array filterCtrlBlocks + */ + protected function sortFilterBlocks( &$filterCtrlBlocks ) + { + usort( $filterCtrlBlocks, array("FilterControl", "compareBlocksByNumericValues") ); + } + + /** + * Get the multiselect filters' filterblocks for values + * that are out of range. And add them to the existing filter blocks + * @param &Array filterCtrlBlocks + */ + protected function addOutRangeValuesToFilter( &$filterCtrlBlocks ) + { + $visibilityClass = $this->multiSelect == FM_ON_DEMAND ? $this->onDemandHiddenItemClassName : ""; + + foreach( $this->filteredFields[ $this->fName ]["values"] as $index ) + { + if( in_array( $index, $this->valuesObtainedFromDB ) ) + continue; + + $filterControl = $this->buildControl( array( "index" => $index ) ); + $filterCtrlBlocks[] = $this->getFilterBlockStructure( $filterControl, $visibilityClass, $index ); + } + } + + /** + * Get the html markup representing the control on the page + * @params Array data + * @param Array parentFiltersData (optional) + * @return String + */ + protected function buildControl( $data, $parentFiltersData = array() ) + { + $showValue = $this->getIntervalLabel( $data["index"] ); + $totalValue = $this->getTotalValueToShow( $data["total"] ); + + return $this->getControlHTML( $data["index"], $showValue, $data["index"], $totalValue, $this->separator ); + } + + + public static function getOrdinaryIntervalCondition( $fName, $intervalData, $pSet ) { + $lowerCondition = null; + $caseInsensitive = $intervalData["caseSensitive"] ? dsCASE_DEFAULT : dsCASE_INSENSITIVE; + + $lowerLimit = $intervalData[ "lowerLimit" ]; + if( $intervalData[ "lowerUsesExpression" ] ) + $lowerLimit = getIntervalLimitsExpressions( $pSet->getTableName(), $fName, $intervalData["index"], true ); + + if( $intervalData["lowerLimitType"] == FIL_MORE_THAN ) { + $lowerCondition = DataCondition::FieldIs( $fName, dsopMORE, $lowerLimit, $caseInsensitive ); + } else if( $intervalData["lowerLimitType"] == FIL_MORE_THAN_OR_EQUAL ) { + $lowerCondition = DataCondition::_Not( + DataCondition::FieldIs( $fName, dsopLESS, $lowerLimit, $caseInsensitive ) + ); + } + + $upperCondition = null; + $upperLimit = $intervalData[ "upperLimit" ]; + if( $intervalData[ "upperUsesExpression" ] ) + $upperLimit = getIntervalLimitsExpressions( $pSet->getTableName(), $fName, $intervalData["index"], false ); + + if( $intervalData["upperLimitType"] == FIL_LESS_THAN ) { + $upperCondition = DataCondition::FieldIs( $fName, dsopLESS, $upperLimit, $caseInsensitive ); + } else if( $intervalData["upperLimitType"] == FIL_LESS_THAN_OR_EQUAL ) { + $upperCondition = DataCondition::_Not( + DataCondition::FieldIs( $fName, dsopMORE, $upperLimit, $caseInsensitive ) + ); + } + + if( $lowerCondition && $upperCondition ) { + return DataCondition::_And( array( $lowerCondition, $upperCondition ) ); + } + + if( $lowerCondition ) + return $lowerCondition; + + if( $upperCondition ) + return $upperCondition; + + return null; + } + + + public static function getFilterCondition( $fName, $index, $pSet ) { + + $intervalData = $pSet->getFilterIntervalDatabyIndex( $fName, $index ); + if( !$intervalData ) + return null; + + if( $intervalData["remainder"] ) { + $conditions = array(); + + foreach( $pSet->getFilterIntervals( $fName ) as $_intervalData ) { + if( $_intervalData["index"] == $index ) + continue; + + if( $_intervalData["noLimits"] ) + return DataCondition::_False(); + + $conditions[] = DataCondition::_Not( + FilterIntervalList::getOrdinaryIntervalCondition( $fName, $_intervalData, $pSet ) + ); + } + + return DataCondition::_And( $conditions ); + } + + if( $intervalData["noLimits"] ) { + return DataCondition::_Not( + DataCondition::FieldIs( $fName, dsopEMPTY, $index ) + ); + } + + return FilterIntervalList::getOrdinaryIntervalCondition( $fName, $intervalData, $pSet ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/FilterIntervalSlider.php b/php/classes/controls/FilterIntervalSlider.php new file mode 100644 index 0000000000000000000000000000000000000000..8858ae77e306ef03770aa86e50f5c2570b4c1457 --- /dev/null +++ b/php/classes/controls/FilterIntervalSlider.php @@ -0,0 +1,383 @@ +filterFormat = FF_INTERVAL_SLIDER; + + $this->useApllyBtn = $this->pSet->isFilterApplyBtnSet($fName); + $this->knobsType = $this->pSet->getFilterKnobsType($fName); + + $this->stepValue = $this->pSet->getFilterStepValue($fName); + + $this->addJS_CSSfiles($pageObject); + + if( $this->filtered ) + $this->assignKnobsValues(); + + $this->showCollapsed = $this->pSet->showCollapsed($fName); + + $this->separator = $this->getSeparator(); + } + + /** + * Assign the control's knobs properties + */ + protected function assignKnobsValues() + { + $filterData = $this->filteredFields[ $this->fName ]; + + $filterValues = array(); + $filterValues[] = $filterData['values'][0]; + $filterValues[] = $filterData['sValues'][0]; + + + if($this->knobsType == FS_MIN_ONLY) + { + $this->minKnobValue = $filterValues[0]; + return; + } + + if($this->knobsType == FS_MAX_ONLY) + { + $this->maxKnobValue = $filterValues[0]; + return; + } + + $this->minKnobValue = $filterValues[0]; + $this->maxKnobValue = $filterValues[1]; + } + + /** + * Get the separator value + * @return String + */ + protected function getSeparator() + { + if( $this->knobsType == FS_MIN_ONLY ) + return '~moreequal~'; + + if( $this->knobsType == FS_MAX_ONLY ) + return '~lessequal~'; + + return '~slider~'; + } + + /** + * Form totals of the following type: + SELECT MIN(field) AS sliderMin, MAX(field) AS sliderMax + FROM ( ... ) WHERE + */ + protected function getDataCommand() { + + $dc = new DsCommand; + $dc->filter = $this->pageObject->getDataSourceFilterCriteria( $this->fName ); + + $dc->totals[] = array( + "field" => $this->fName, + "alias" => "sliderMin", + "skipEmpty" => true, + "total" => "min" + ); + + $dc->totals[] = array( + "field" => $this->fName, + "alias" => "sliderMax", + "total" => "max" + ); + + return $dc; + } + + /** + * Get the filter blocks data using the database query + * and add it the the existing blocks + * @param &Array + */ + protected function addFilterBlocksFromDB( &$filterCtrlBlocks ) + { + //query to database + $qResult = $this->dataSource->getTotals( $this->getDataCommand() ); + $data = $qResult->fetchAssoc(); + + $this->decryptDataRow( $data ); + + if( $this->fieldHasNoRange( $data ) ) + return $filterCtrlBlocks; + + $filterControl = $this->buildControl( $data ); + $filterCtrlBlocks[] = $this->getFilterBlockStructure( $filterControl ); + } + + /** + * Check if there are database values for the filter's field + * that are differs from each other for more than a step value + * @param Array data + * @return Boolean + */ + protected function fieldHasNoRange($data) + { + if( is_null( $data['sliderMin'] ) && is_null( $data['sliderMax'] ) || $data['sliderMax'] == $data['sliderMin'] ) + return true; + + return false; + } + + /** + * Get the html markup representing the control on the page + * @param Array data + * @param Array parentFiltersData (optional) + * @return String + */ + protected function buildControl( $data, $parentFiltersData = array() ) + { + if( !$this->viewControl ) + return ""; + $this->minValue = $data['sliderMin']; + $this->maxValue = $data['sliderMax']; + + if( !$this->filtered ) + { + $this->minKnobValue = $data['sliderMin']; + $this->maxKnobValue = $data['sliderMax']; + } + else + { + if( $this->knobsType == FS_MAX_ONLY ) + $this->minKnobValue = $data['sliderMin']; + + if( $this->knobsType == FS_MIN_ONLY ) + $this->maxKnobValue = $data['sliderMax']; + } + + return $this->getSliderHTML(); + } + + /** + * Get the html markup for the slider knobs' captions + * @return String + */ + protected function getCaptionSpansHTML() + { + $minSpan = ''.$this->getMinSpanValue().''; + $maxSpan = ''.$this->getMaxSpanValue().''; + $captionSpans = $minSpan." - ".$maxSpan; + + $prefixSpan = ''; + $postfixSpan = ''; + + $captionSpans = $prefixSpan . $captionSpans . $postfixSpan; + + return $captionSpans; + } + + /** + * Get the html markup for the slider's control + * @return String + */ + protected function getSliderHTML() + { + $captionSpans = $this->getCaptionSpansHTML(); + + $filterControl = '
'.$captionSpans.'
'; + $filterControl.= '
'; + return $filterControl; + } + + /** + * Get the caption fot the min slider's knob + * @return String + */ + protected function getMinSpanValue() + { + $minSpanValue = $this->minKnobValue; + if( $minSpanValue < $this->minValue ) + $minSpanValue = $this->minValue; + + $viewFormat = $this->viewControl->viewFormat; + if( $viewFormat == FORMAT_CURRENCY || $viewFormat == FORMAT_NUMBER ) + { + $data = array($this->fName => $minSpanValue); + $minSpanValue = $this->viewControl->showDBValue($data, ""); + } + return $minSpanValue; + } + + /** + * Get the caption fot the max slider's knob + * @return String + */ + protected function getMaxSpanValue() + { + $maxSpanValue = $this->maxKnobValue; + if( $maxSpanValue > $this->maxValue ) + $maxSpanValue = $this->maxValue; + + $viewFormat = $this->viewControl->viewFormat; + if( $viewFormat == FORMAT_CURRENCY || $viewFormat == FORMAT_NUMBER ) + { + $data = array($this->fName => $maxSpanValue); + $maxSpanValue = $this->viewControl->showDBValue($data, ""); + } + return $maxSpanValue; + } + + /** + * Add filter control's data to the ControlsMap + * @param Object pageObj + */ + public function addFilterControlToControlsMap($pageObj) + { + if( !$this->viewControl ) + return; + + $ctrlsMap = $this->getBaseContolsMapParams(); + + $ctrlsMap['minValue'] = $this->minValue; + $ctrlsMap['maxValue'] = $this->maxValue; + $ctrlsMap['roundedMin'] = $this->round( $this->minValue, true); + $ctrlsMap['roundedMax'] = $this->round( $this->maxValue, false ); + + $ctrlsMap['roundedMinKnobValue'] = $this->round( $this->minKnobValue, true ); + $ctrlsMap['roundedMaxKnobValue'] = $this->round( $this->maxKnobValue, false ); + + if( $this->filtered ) { + $ctrlsMap['minKnobValue'] = $this->minKnobValue; + $ctrlsMap['maxKnobValue'] = $this->maxKnobValue; + } + + $viewFomat = $this->viewControl->viewFormat; + $ctrlsMap['viewAsNumber'] = $viewFomat == FORMAT_NUMBER; + $ctrlsMap['viewAsCurrency'] = $viewFomat == FORMAT_CURRENCY; + $ctrlsMap['formatSettings'] = getFormatSettings( $viewFomat, $this->pSet, $this->fName ); + + $pageObj->controlsMap["filters"]["controls"][] = $ctrlsMap; + } + + /** + * Get filter control's base ControlsMap array + * @return array + */ + protected function getBaseContolsMapParams() + { + $ctrlsMap = array(); + $ctrlsMap['fieldName'] = $this->fName; + $ctrlsMap['gfieldName'] = $this->gfName; + $ctrlsMap['filterFormat'] = $this->filterFormat; + $ctrlsMap['filtered'] = $this->filtered; + $ctrlsMap['separator'] = $this->separator; + $ctrlsMap['knobsType'] = $this->knobsType; + $ctrlsMap['useApllyBtn'] = $this->useApllyBtn; + $ctrlsMap['step'] = $this->getStepValue(); + $ctrlsMap['collapsed'] = $this->showCollapsed; + + return $ctrlsMap; + } + + /** + * Get the slider's step value + * @return number + */ + protected function getStepValue() + { + return $this->stepValue; + } + + /** + * Get the rounded to the upper or lower limit value + * basing on the step value + * @param number value + * @return number + */ + protected function round( $value, $min ) + { + $step = $this->stepValue; + + if( $min ) + return floor( $value / $step ) * $step; + + return ceil( $value / $step ) * $step; + } + + /** + * Add extra js and css files + * @param object pageObject + */ + protected function addJS_CSSfiles($pageObject) + { + } + + /** + * Get the Filter's control block data. + * @param Object pageObj + * @param Array $dFilterBlocks (optional) + * @return Array + */ + public function buildFilterCtrlBlockArray( $pageObj, $dFilterBlocks = null ) + { + $filterCtrlBlocks = array(); + $this->addFilterBlocksFromDB( $filterCtrlBlocks ); + + if( !$filterCtrlBlocks ) + $this->visible = false; + + if( $this->visible ) + $this->addFilterControlToControlsMap( $pageObj ); + + return $filterCtrlBlocks; + } + + /** + * secondValue is set up for knobsType FS_BOTH only + */ + public static function getFilterCondition( $fName, $value, $pSet, $secondValue ) { + + $knobsType = $pSet->getFilterKnobsType( $fName ); + + if( $knobsType == FS_MAX_ONLY ) { + return DataCondition::_Not( + DataCondition::FieldIs( $fName, dsopMORE, $value ) + ); + } + + $conditionMore = DataCondition::_Not( + DataCondition::FieldIs( $fName, dsopLESS, $value ) + ); + + if( $knobsType == FS_MIN_ONLY ) + return $conditionMore; + + if( $pSet->getFilterStepType( $fName ) >= 3 && IsDateFieldType( $pSet->getFieldType( $fName ) ) ) { + // interval "up to 2010-10-10" should translate into "x < 2010-10-11" and not in "x <= 2010-10-10" + $tm = db2time( $secondValue ); + if( !$tm[0] ) { + $conditionLess = null; + } else { + $conditionLess = DataCondition::FieldIs( $fName, dsopLESS, date2db( adddays( $tm, 1 ) ) ); + } + } else { + $conditionLess = DataCondition::_Not( + DataCondition::FieldIs( $fName, dsopMORE, $secondValue ) + ); + } + + return DataCondition::_And( array( + $conditionLess, + $conditionMore + )); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/FilterIntervalTimeSlider.php b/php/classes/controls/FilterIntervalTimeSlider.php new file mode 100644 index 0000000000000000000000000000000000000000..db286c10169283669e7c4722864af27357a1b260 --- /dev/null +++ b/php/classes/controls/FilterIntervalTimeSlider.php @@ -0,0 +1,133 @@ +baseDateArray = array(1970, 1, 1, 0, 0, 0); + } + + /** + * Get the date-time array representation + * @param String value + * @param Boolean forCaption + * @return Array + */ + protected function getDateTimeArray($value, $forCaption = false) + { + if($forCaption) + { + $timeArray = parsenumbers($value); + return array(0, 0, 0, $timeArray[0], $timeArray[1] ,$timeArray[2]); + } + $timeInSeonds = $this->getValueInSeconds($value); + $baseDateArray = $this->baseDateArray; + return addSeconds($baseDateArray, $timeInSeonds); + } + + /** + * Get the value converted into seconds + * @param String value + * @return Number + */ + protected function getValueInSeconds($value) + { + $timeArray = parsenumbers($value); + return $timeArray[2] + $timeArray[1] * 60 + $timeArray[0] * 3600; + } + + /** + * Get the full caption value for the slider with the 'seconds' step type + * @param Array dateArray + * @return String + */ + protected function getSecondsCaption($dateArray) + { + return str_format_time($dateArray); + } + + /** + * Get the full caption value for the slider with the 'minutes' step type + * @param Array dateArray + * @return String + */ + protected function getMinutesCaption($dateArray) + { + global $locale_info; + $dateArray[5] = 0; + + $timeFormatString = str_replace( $locale_info["LOCALE_STIME"]."ss", "", $locale_info["LOCALE_STIMEFORMAT"]); + return format_datetime_custom($dateArray, $timeFormatString); + } + + /** + * Get the full caption value for the slider with the 'hours' step type + * @param Array dateArray + * @param Boolean isLower + * @return String + */ + protected function getHoursCaption($dateArray, $isLower) + { + global $locale_info; + + $hours = $this->getAdjustedHoursValue($dateArray[3], $dateArray[4], $isLower); + $dateArray[3] = $dateArray[4] = $dateArray[5] = 0; + $dateArray = addHours($dateArray, $hours); + + $timeFormatString = str_replace( $locale_info["LOCALE_STIME"]."ss", "", $locale_info["LOCALE_STIMEFORMAT"]); + return format_datetime_custom($dateArray, $timeFormatString); + } + + /** + * Check if there are database values for the filter's field + * that are differs from each other for more than a step value + * @param Array data + * @return Boolean + */ + protected function fieldHasNoRange($data) + { + if (is_null( $data['sliderMin'] ) && is_null( $data['sliderMax'] ) || $data['sliderMax'] == $data['sliderMin']) + return true; + + $step = $this->getStepValue(); + $minSec = $this->getValueInSeconds( $data['sliderMin'] ); + $maxSec = $this->getValueInSeconds( $data['sliderMax'] ); + + if( ($maxSec - $minSec) < $step ) + return true; + + return false; + } + + /** + * Get the html markup for the slider knobs' captions + * @return String + */ + protected function getCaptionSpansHTML() + { + $minSpan = ''.$this->getMinSpanValue().''; + $maxSpan = ''.$this->getMaxSpanValue().''; + $captionSpans = $minSpan." - ".$maxSpan; + + return $captionSpans; + } + + /** + * Add filter control's data to the ControlsMap + * @param Object pageObj + */ + public function addFilterControlToControlsMap($pageObj) + { + $ctrlsMap = $this->getBaseContolsMapParams(); + $ctrlsMap['isFieldTimeType'] = true; + + $pageObj->controlsMap["filters"]["controls"][] = $ctrlsMap; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/FilterMultiselectLookup.php b/php/classes/controls/FilterMultiselectLookup.php new file mode 100644 index 0000000000000000000000000000000000000000..b959d318b3d83ca7a2a2b761fb4562e352e63728 --- /dev/null +++ b/php/classes/controls/FilterMultiselectLookup.php @@ -0,0 +1,87 @@ +aliases[ $this->fName ] = $this->fName; + } + + protected function getDataCommand() { + $dc = new DsCommand; + $dc->filter = $this->pageObject->getDataSourceFilterCriteria( $this->fName ); + + return $dc; + } + + + /** + * Get the filter blocks data using the database query + * and add it the the existing blocks + * @param &Array + */ + protected function addFilterBlocksFromDB( &$filterCtrlBlocks ) + { + $containsFilteredDependentOnDemandFilter = !$this->dependent && !$this->filtered + && $this->hasFilteredDependentOnDemandFilter(); + + $visibilityClass = $this->filtered && $this->multiSelect == FM_ON_DEMAND ? $this->onDemandHiddenItemClassName : ""; + $totalOption = $this->pSet->getFilterFieldTotal( $this->fName ); + + //query to database with current where settings + $qResult = $this->dataSource->getList( $this->getDataCommand() ); + + $metaData = array(); + while( $data = $qResult->fetchAssoc() ) { + $this->decryptDataRow( $data ); + + $parentFiltersData = array(); + $parentString = ""; + if( $this->dependent ) { + foreach( $this->parentFiltersNames as $pName ) { + $parentFiltersData[ $pName ] = $data[ $pName ]; + } + $parentString = my_json_encode( $parentFiltersData ); + } + + $values = splitLookupValues( $data[ $this->fName ] ); + foreach( $values as $value ) { + $hash = md5( $parentString.$value ); + if( !$metaData[ $hash ] ) { + $total = $data[ $this->totalsfName ]; + if( $totalOption == FT_COUNT ) + $total = 1; + + $metaData[ $hash ] = array( "rawValue" => $value, "total" => $total, "parent" => $parentFiltersData ); + } else { + if( $totalOption == FT_COUNT ) { + $metaData[ $hash ]["total"] = $metaData[ $hash ]["total"] + 1; + } else if( $totalOption == FT_MIN ) { + $metaData[ $hash ]["total"] = min( $data[ $this->totalsfName ], $metaData[ $hash ]["total"] ); + } else if( $totalOption == FT_MAX ) { + $metaData[ $hash ]["total"] = max( $data[ $this->totalsfName ], $metaData[ $hash ]["total"] ); + } + } + } + } + + foreach( $metaData as $meta ) { + $data = array(); + $data[ $this->fName ] = $meta["rawValue"]; + $data[ $this->fName."TOTAL" ] = $meta["total"]; + + $this->valuesObtainedFromDB[] = $meta["rawValue"]; + + $filterControl = $this->buildControl( $data, $meta["parent"] ); + if( $containsFilteredDependentOnDemandFilter ) + $filterControl = $this->getDelButtonHtml( $this->gfName, $this->id, $meta["rawValue"] ).$filterControl; + + $filterCtrlBlocks[] = $this->getFilterBlockStructure( $filterControl, $visibilityClass, $meta["rawValue"], $meta["parent"] ); + } + } + + public static function getFilterCondition( $fName, $value, $pSet ) { + return DataCondition::FieldHasList( $fName, dsopALL_IN_LIST, array( $value ) ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/FilterValuesList.php b/php/classes/controls/FilterValuesList.php new file mode 100644 index 0000000000000000000000000000000000000000..90825adc753ff6a5313384ccedc1d9dd94c9c404 --- /dev/null +++ b/php/classes/controls/FilterValuesList.php @@ -0,0 +1,723 @@ +filterFormat = FF_VALUE_LIST; + $this->separator = "~equals~"; + + $this->useApllyBtn = $this->multiSelect == FM_ALWAYS; + + $this->numberOfVisibleItems = $this->pSet->getNumberOfVisibleFilterItems($fName); + + $this->parentFilterName = $this->pSet->getParentFilterName($fName); + $this->dependent = !!$this->parentFilterName; + + $this->assignDependentFiltersData(); + $this->hasDependent = !!$this->dependentFilterName; + + + $this->assignParentFiltersData(); + + $this->setSortingParams(); + } + + /** + * Assign 'parentFiltersNames' properties to + * the corresponding data if the current filter is dependent + */ + protected function assignParentFiltersData() + { + if( !$this->dependent ) + return; + + $this->parentFiltersNames = FilterValuesList::getParentFilterFields( $this->fName, $this->pSet ); + + } + + public static function getParentFilterFields( $field, $pSet ) { + $parents = array(); + FilterValuesList::findParentFilters( $field, $parents, $pSet ); + return array_keys( $parents ); + } + + /** + * Assign the 'dependentFilterNames' property to + * the corresponding data if the current filter has any dependent filter + */ + protected function assignDependentFiltersData() + { + $dependents = array(); + $this->findDependentFilters( $this->fName, $this->pSet->getFilterFields(), $dependents ); + $this->dependentFilterNames = array_keys( $dependents ); + } + + public function hasDependentFilter() { + return !!$this->dependentFilterName; + } + + protected function findDependentFilters( $field, &$filterFields, &$dependents ) { + foreach( $filterFields as $f ) { + if( !isset( $dependents[$f] ) && $this->pSet->getParentFilterName( $f ) === $field ) { + $dependents[ $f ] = true; + if( $field == $this->fName ) + $this->dependentFilterName = $f; + FilterValuesList::findDependentFilters( $f, $filterFields, $dependents ); + break; + } + } + } + protected static function findParentFilters( $field, &$parents, $pSet ) { + $f = $pSet->getParentFilterName( $field ); + if( !$f ) + return; + if( !isset( $parents[$f] ) ) { + $parents[$f] = true; + FilterValuesList::findParentFilters( $f, $parents, $pSet ); + } + } + + protected function getDataCommand() + { + $dc = new DsCommand; + $dc->filter = $this->pageObject->getDataSourceFilterCriteria( $this->fName ); + + $alias = generateAlias(); + $this->aliases[ $this->fName ] = $alias; + $dc->totals[] = array( + "field" => $this->fName, + "alias" => $alias, + "modifier" => $this->pSet->getFilterByInterval($this->fName), + "skipEmpty" => true + ); + + $totalsType = $this->dataTotalsName(); + if( $totalsType ) { + $dc->totals[] = array( + "field" => $this->totalsfName, + "alias" => $this->fName."TOTAL", + "total" => $totalsType ); + } + + // calculate add master filter fields + if( $this->dependent ) + { + foreach( $this->parentFiltersNames as $p ) { + $pAlias = generateAlias(); + $this->aliases[ $p ] = $pAlias; + $dc->totals[] = array( + "field" => $p, + "alias" => $pAlias, + "modifier" => $this->pSet->getFilterByInterval( $p ), + "skipEmpty" => true + ); + } + } + + $sortingType = $this->pSet->getFilterSortValueType($this->fName); + + if( $sortingType != SORT_BY_DISP_VALUE ) + { + $direction = $this->pSet->isFilterSortOrderDescending($this->fName) + ? "DESC" + : "ASC"; + + if( $sortingType == SORT_BY_GR_VALUE && $totalsType ) { + $dc->totals[ 1 ][ "direction" ] = $direction; + } else { + $dc->totals[ 0 ][ "direction" ] = $direction; + } + } + return $dc; + } + + /** + * @deprecated + */ + protected function getFilterSQLExpr( $expr ) { + return FilterValuesList::_getFilterSQLExpr( $this->fName, $expr, $this->pSet, $this->connection ); + } + + /** + * @deprecated + * @return String + */ + protected static function _getFilterSQLExpr( $fName, $expr, $pSet, $connection ) + { + $filterInterval = $pSet->getFilterByInterval($fName); + if( !$filterInterval ) + return $expr; + + $ftype = $pSet->getFieldType( $fName ); + + if( IsNumberType($ftype) ) + { + return $connection->intervalExpressionNumber( $expr, $filterInterval ); + } + + if( IsCharType( $ftype ) ) + { + return $connection->intervalExpressionString( $expr, $filterInterval ); + } + + if( IsDateFieldType( $ftype ) ) + { + return $connection->intervalExpressionDate( $expr, $filterInterval ); + } + + return $expr; + } + + /** + * Set the sorting params + */ + protected function setSortingParams() + { + $this->sortingType = $this->pSet->getFilterSortValueType($this->fName); + $this->isDescendingSortOrder = $this->pSet->isFilterSortOrderDescending($this->fName); + $this->useFormatedValueInSorting = $this->sortingType == SORT_BY_DISP_VALUE + || IsCharType($this->fieldType) || $this->pSet->getEditFormat($this->fName) == EDIT_FORMAT_LOOKUP_WIZARD; + } + + /** + * Get the view controls' value + * + * @param String values + * @return String + */ + protected function getValueToShow($value) + { + if( !$this->viewControl ) { + return ""; + } + $data = array($this->fName => $value); + $showValue = $this->viewControl->showDBValue($data, ""); + + return $showValue; + } + + + + /** + * Get the filter blocks data using the database query + * and add it the the existing blocks + * @param &Array + */ + protected function addFilterBlocksFromDB( &$filterCtrlBlocks ) + { + $containsFilteredDependentOnDemandFilter = !$this->dependent && !$this->filtered && $this->hasFilteredDependentOnDemandFilter(); + $visibilityClass = $this->filtered && $this->multiSelect == FM_ON_DEMAND ? $this->onDemandHiddenItemClassName : ""; + + //query to database with current where settings + $qResult = $this->dataSource->getTotals( $this->getDataCommand() ); + $alias = $this->aliases[ $this->fName ]; + while( $data = $qResult->fetchAssoc() ) + { + $this->decryptDataRow($data); + + $rawValue = $data[ $alias ]; + + $parentFiltersData = array(); + if( $this->dependent ) + { + foreach($this->parentFiltersNames as $pName) + { + $parentFiltersData[ $pName ] = $data[ $this->aliases[ $pName ] ]; + } + } + + $this->valuesObtainedFromDB[] = $rawValue; + + $filterControl = $this->buildControl( $data, $parentFiltersData ); + if( $containsFilteredDependentOnDemandFilter ) + $filterControl = $this->getDelButtonHtml( $this->gfName, $this->id, $rawValue ).$filterControl; + + $filterCtrlBlocks[] = $this->getFilterBlockStructure($filterControl, $visibilityClass, $rawValue, $parentFiltersData); + } + } + + /** + * Check if the current filter has any dependent filtered 'on demand' filter + * @return Boolean + */ + protected function hasFilteredDependentOnDemandFilter() + { + if( !$this->hasDependent ) + return false; + + foreach( $this->dependentFilterNames as $dName ) + { + if( !!$this->filteredFields[ $dName ] && $this->pSet->getFilterFiledMultiSelect($dName) == FM_ON_DEMAND ) + return true; + } + + return false; + } + + /** + * Get the parent filters data + * @param String value + * @return Array + */ + protected function getParentFiltersDataForFilteredBlock( $value ) + { + $parentFiltersData = array(); + + if( !$this->filtered || !$this->dependent ) + return $parentFiltersData; + + $parentValuesData = $this->filteredFields[ $this->fName ]["parentValues"]; + if( count($parentValuesData) <= 1 ) + { + foreach($this->parentFiltersNames as $pName) + { + //parent filter is single selected + $pValue = $this->filteredFields[ $pName ]["values"][0]; + //parent filter is not presented in filter params string + if( !isset($this->filteredFields[ $pName ]) && count( $parentValuesData[0] ) ) + $pValue = $parentValuesData[0][0]; + + $parentFiltersData[ $pName ] = $pValue; + } + return $parentFiltersData; + } + + if( !$this->filteredFieldParentFiltersKeysToIgnore ) + $this->filteredFieldParentFiltersKeysToIgnore = array(); + + foreach( $parentValuesData as $key => $parentValues ) + { + if( $value != $this->filteredFields[ $this->fName ]['values'][ $key ] || in_array($key, $this->filteredFieldParentFiltersKeysToIgnore) ) + continue; + + $this->filteredFieldParentFiltersKeysToIgnore[] = $key; + + foreach($this->parentFiltersNames as $pKey => $pName) + { + $pValue = $parentValues[$pKey]; + $parentFiltersData[ $pName ] = $pValue; + } + + return $parentFiltersData; + } + + return $parentFiltersData; + } + + /** + * Get the arrray with keys corresponding to filter blocks markup + * @param String filterControl + * @param String visibilityClass + * @param String value The raw Db field's value + * @param Array parentFiltersData (optional) + * @return Array + */ + protected function getFilterBlockStructure( $filterControl, $visibilityClass = "", $value = "", $parentFiltersData = array() ) + { + if( !$this->viewControl ) + return array(); + $sortValue = $value; + if( $this->useFormatedValueInSorting ) + { + $valueData = array($this->fName => $sortValue); + $sortValue = $this->viewControl->showDBValue($valueData, ""); + } + + if( $this->multiSelect != FM_ALWAYS ) + $visibilityClass.= " filter-link"; + + return array( + $this->gfName."_filter" => $filterControl, + "visibilityClass_".$this->gfName => $visibilityClass, + "sortValue" => $sortValue, + "dbValue" => $value, + "mainValues" => $parentFiltersData + ); + } + + /** + * Get the html markup representing the control on the page + * @param Array data + * @param Array parentFiltersData (optional) + * @return String + */ + protected function buildControl( $data, $parentFiltersData = array() ) + { + $filterInterval = $this->pSet->getFilterByInterval($this->fName); + $value = $data[ $this->aliases[ $this->fName ] ]; + + // pass to attributes + $dataValue = $value; + $showValue = $this->getControlCaption( $value ); + + $totalValue = $this->getTotalValueToShow( $data[ $this->fName."TOTAL" ] ); + + return $this->getControlHTML( $value, $showValue, $dataValue, $totalValue, $this->separator, $parentFiltersData ); + } + + /** + * @param Array data + * @return String + */ + protected function getControlCaption( $value ) + { + $intervalType = $this->pSet->getFilterByInterval($this->fName); + if( !$intervalType ) + return $this->getValueToShow( $value ); + + return $this->pageObject->formatGroupValue( $this->fName, $intervalType, $value ); + } + + /** + * Check if to show the 'Show N more' button + * for a not dependent filter + * @return Boolean + */ + protected function isTruncated() + { + return !$this->dependent && $this->truncated; + } + + /** + * Get the extra data attributes for the control's HTML elements + * @param Array parentFiltersData + * @return String + */ + protected function getExtraDataAttrs( $parentFiltersData ) + { + if( !$this->dependent || is_null($parentFiltersData) ) + return ''; + + return ' data-parent-filters-values="'.runner_htmlspecialchars( my_json_encode( $parentFiltersData ) ).'" '; + } + + /** + * Get the cheked attribute string for a multiselect filter control + * @param String value + * @param String parentFiltersData + * @return String + */ + protected function getCheckedAttr( $value, $parentFiltersData = null ) + { + $filteredValues = $this->filteredFields[ $this->fName ]['values']; + + if( $this->multiSelect == FM_NONE || $this->filtered && !in_array($value, $filteredValues) ) + return ''; + + if( $this->filtered && $this->dependent && $this->multiSelect == FM_ON_DEMAND && count($filteredValues) == 1 ) + return 'checked="checked"'; + + if( !$this->filtered || !$this->dependent || is_null($parentFiltersData) ) + return 'checked="checked"'; + + foreach( $this->filteredFields[ $this->fName ]["parentValues"] as $key => $parentValues ) + { + if( $value == $this->filteredFields[ $this->fName ]['values'][$key] && $this->isParentsValuesDataTheSame($parentFiltersData, $parentValues) ) + return 'checked="checked"'; + } + return ''; + } + + /** + * Check if two data structures passed are similar + * @param Array parentFiltersData + * @param Array parentValues + * @return Boolean + */ + protected function isParentsValuesDataTheSame($parentFiltersData, $parentValues) + { + foreach($this->parentFiltersNames as $pKey => $pName) + { + if( $parentFiltersData[$pName] != $parentValues[$pKey] ) + return false; + } + return true; + } + + /** + * Get filter control's base ControlsMap array + * @return array + */ + protected function getBaseContolsMapParams() + { + $ctrlsMap = parent::getBaseContolsMapParams(); + + if( $this->dependent ) + { + $ctrlsMap['dependent'] = true; + $ctrlsMap['parentFilterNames'] = $this->parentFiltersNames; + $ctrlsMap['goodParentName'] = GoodFieldName( $this->parentFilterName ); + $ctrlsMap['goodOutermostParentName'] = GoodFieldName( $this->parentFiltersNames[ count($this->parentFiltersNames) - 1 ] ); + } + + if( $this->hasDependent ) + { + $ctrlsMap['hasDependent'] = true; + $ctrlsMap['dependentFilterNames'] = $this->dependentFilterNames; + } + + return $ctrlsMap; + } + + /** + * Get the murkup of the control's delete button + * @param String gfName + * @param Number id + * @param String deleteValue + * @return String + */ + protected function getDelButtonHtml($gfName, $id, $deleteValue) + { + if( $this->multiSelect == FM_ALWAYS || $this->dependent ) + return ''; + + return parent::getDelButtonHtml($gfName, $id, $deleteValue); + } + + /** + * A stub + * @return Number + */ + protected function getNumberOfExtraItemsToShow() + { + return $this->numberOfExtraItemsToShow; + } + + /** + * Update filter blocks structures + * @param &Array + */ + protected function extraBlocksProcessing( &$filterCtrlBlocks ) + { + parent::extraBlocksProcessing($filterCtrlBlocks); + + if( !$this->numberOfVisibleItems || $this->dependent ) + return; + + $visbleItemsCounter = $hiddenItemsCounter = 0; + foreach($filterCtrlBlocks as $index => $block) + { + $visible = ( strpos( $block[ "visibilityClass_".$this->gfName ], $this->onDemandHiddenItemClassName ) === FALSE ); + if( $visible ) + $visbleItemsCounter = $visbleItemsCounter + 1; + else + $hiddenItemsCounter = $hiddenItemsCounter + 1; + + if( $visible && $visbleItemsCounter > $this->numberOfVisibleItems || !$visible && $hiddenItemsCounter > $this->numberOfVisibleItems ) + $filterCtrlBlocks[ $index ][ "visibilityClass_".$this->gfName ].= " ".$this->hiddenExtraItemClassName; + } + + if( $this->filtered && $this->multiSelect == FM_ON_DEMAND ) + { + if( count($this->filteredFields[ $this->fName ]["values"]) < $this->numberOfVisibleItems && $hiddenItemsCounter > $this->numberOfVisibleItems ) + { + $this->truncated = true; + $this->hideShowMore = true; + $this->numberOfExtraItemsToShow = $hiddenItemsCounter - $this->numberOfVisibleItems; + } + } + elseif( $visbleItemsCounter > $this->numberOfVisibleItems ) + { + $this->truncated = true; + $this->numberOfExtraItemsToShow = $visbleItemsCounter - $this->numberOfVisibleItems; + } + } + + /** + * Check if the "show more" button must be hidden by class attr + * @return Boolean + */ + protected function isShowMoreHidden() + { + return $this->hideShowMore; + } + + /** + * Sort filter blocks depending on the field's type and format + * @param &Array filterCtrlBlocks + */ + protected function sortFilterBlocks(&$filterCtrlBlocks) + { + if( $this->sortingType != SORT_BY_DISP_VALUE ) + return; + + // always sort as strings. Lookups must be sorted as strings no matter field type + $compareFunction = "compareBlocksByStringValues"; + + usort( $filterCtrlBlocks, array("FilterControl", $compareFunction) ); + + if( $this->isDescendingSortOrder ) + $filterCtrlBlocks = array_reverse( $filterCtrlBlocks ); + } + + /** + * Get the Filter's control block data. + * @param Object pageObj + * @param Array $dFilterBlocks (optional) + * @return Array + */ + public function buildFilterCtrlBlockArray( $pageObj, $dFilterBlocks = null ) + { + $filterBlocks = parent::buildFilterCtrlBlockArray( $pageObj ); + + if( !$this->hasDependent || is_null($dFilterBlocks) ) + return $filterBlocks; + + return $this->getCtrlBlocksMergeWithDependentFilterBlocks( $filterBlocks, $dFilterBlocks ); + } + + /** + * Get the main filter's and dependent blocks merged + * @param Array mFilterBlocks + * @param Array dFilterBlocks + * @return Array + */ + protected function getCtrlBlocksMergeWithDependentFilterBlocks( $mFilterBlocks, $dFilterBlocks ) + { + $dgName = GoodFieldName( $this->dependentFilterName ); + $dBlockName = "filterCtrlBlock_".$dgName; + $showMoreBlockName = "filter_button_showmore_".$dgName; + + //Get 'Show first ...' settings + $numberOfdItemsToShow = $this->pSet->getNumberOfVisibleFilterItems( $this->dependentFilterName ); + + foreach($mFilterBlocks as $key => $block) + { + $mMainValues = $block["mainValues"]; + $visibleItemsCounter = 0; + $invisibleItemsCounter = 0; + + foreach($dFilterBlocks as $dBlock) + { + $dMainValues = $dBlock["mainValues"]; + if( $dMainValues[ $this->fName ] != $block["dbValue"] ) + continue; + + $addDependentBlock = true; + + foreach($mMainValues as $fName=>$value) + { + if( $mMainValues[ $fName ] != $dMainValues[ $fName ] ) + { + $addDependentBlock = false; + break; + } + } + + if( $addDependentBlock ) + { + if( $numberOfdItemsToShow ) + { + $visible = $dBlock["visibilityClass_".$dgName] != $this->onDemandHiddenItemClassName; + if( $visible ) + $visibleItemsCounter = $visibleItemsCounter + 1; + else + $invisibleItemsCounter = $invisibleItemsCounter + 1; + + if( $visible && $visibleItemsCounter > $numberOfdItemsToShow || !$visible && $invisibleItemsCounter > $numberOfdItemsToShow ) + $dBlock["visibilityClass_".$dgName] = $this->hiddenExtraItemClassName; + } + + $mFilterBlocks[ $key ][ $dBlockName ]["data"][] = $dBlock; + } + + + $mFilterBlocks[ $key ]["show_n_more_".$dgName] = str_replace( "%n%", $visibleItemsCounter - $numberOfdItemsToShow, "Show %n% more" ); + $mFilterBlocks[ $key ][ $showMoreBlockName ] = $numberOfdItemsToShow && $numberOfdItemsToShow < $visibleItemsCounter; + } + } + + return $mFilterBlocks; + } + + /** + * Get the filter's buttons parameters such as buttons' labels, + * class names and attributes + * @param Array dBtnParams (optional) + * @return Array + */ + public function getFilterButtonParams( $dBtnParams = null ) + { + $mBtnParams = parent::getFilterButtonParams(); + + if( $this->hasDependent && !is_null($dBtnParams) ) + { + $mBtnParams['hasMultiselectBtn'] = $mBtnParams['hasMultiselectBtn'] || $dBtnParams['hasMultiselectBtn']; + $mBtnParams['hasApplyBtn'] = $mBtnParams['hasApplyBtn'] || $dBtnParams['hasApplyBtn']; + } + + return $mBtnParams; + } + + /** + * Get the filter's extra controlls parameters + * @param Array dBtnParams (dExtraCtrls) + * @return Array + */ + public function getFilterExtraControls( $dExtraCtrls = null ) + { + $mExtraCtrls = parent::getFilterExtraControls(); + + if( !$this->hasDependent || is_null($dExtraCtrls) ) + return $mExtraCtrls; + + if( !$mExtraCtrls['selectAllAttrs'] || $this->multiSelect == FM_ON_DEMAND && $dExtraCtrls['selectAllAttrs'] ) + $mExtraCtrls['selectAllAttrs'] = $dExtraCtrls['selectAllAttrs']; + + if( !$mExtraCtrls['filtered'] ) + $mExtraCtrls['filtered'] = $dExtraCtrls['filtered']; + + return $mExtraCtrls; + } + + public static function getFilterCondition( $fName, $value, $pSet ) { + if( $pSet->multiSelectLookupEdit( $fName ) ) { + include_once getabspath("classes/controls/FilterMultiselectLookup.php"); + return FilterMultiselectLookup::getFilterCondition( $fName, $value, $pSet ); + } + + return DataCondition::FieldEquals( $fName, $value, $pSet->getFilterByInterval($fName) ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/HiddenField.php b/php/classes/controls/HiddenField.php new file mode 100644 index 0000000000000000000000000000000000000000..8d3f5b2d59098413ee7f70bbb88c3dd510785cc9 --- /dev/null +++ b/php/classes/controls/HiddenField.php @@ -0,0 +1,18 @@ +format = EDIT_FORMAT_HIDDEN; + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + echo ''; + $this->buildControlEnd($validate, $mode); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/LookupField.php b/php/classes/controls/LookupField.php new file mode 100644 index 0000000000000000000000000000000000000000..23dd16671ae7fcd66ef8a1960fdef86ca47fe3ef --- /dev/null +++ b/php/classes/controls/LookupField.php @@ -0,0 +1,1643 @@ +tName = $this->pageObject->tName; + if($this->pageObject->tableBasedSearchPanelAdded) + $this->tName = $this->pageObject->searchTableName; + + $this->format = EDIT_FORMAT_TEXT_FIELD; + + if($pageObject->pageType == PAGE_LIST || !$pageObject->isPageTableBased()) + $this->lookupPageType = PAGE_SEARCH; + else + $this->lookupPageType = $pageObject->pageType; + + $this->lookupTable = $this->pageObject->pSetEdit->getLookupTable($this->field); + $this->lookupType = $this->pageObject->pSetEdit->getLookupType($this->field); + $this->lookupDataSource = getLookupDataSource( $this->field, $this->pageObject->pSetEdit ); + + if($this->lookupType == LT_QUERY) { + $this->lookupPSet = new ProjectSettings($this->lookupTable); + } + + $this->displayFieldName = $this->pageObject->pSetEdit->getDisplayField($this->field); + $this->linkFieldName = $this->pageObject->pSetEdit->getLinkField($this->field); + $this->linkAndDisplaySame = $this->displayFieldName == $this->linkFieldName; + + if($this->lookupType == LT_QUERY) + $this->ciphererLookup = new RunnerCipherer($this->lookupTable); + + $this->LCType = $this->pageObject->pSetEdit->lookupControlType($this->field); + + $this->multiselect = $this->pageObject->pSetEdit->multiSelect($this->field); + $this->customDisplay = $this->pageObject->pSetEdit->getCustomDisplay($this->field); + + + // The number of rows in a multiline lookup + $this->lookupSize = $this->pageObject->pSetEdit->selectSize($this->field); + $this->bUseCategory = $this->pageObject->pSetEdit->useCategory($this->field); + } + + + /** + * Create a CSS rule specifying the control's width + * @param Number widthPx + * @return String + */ + function makeWidthStyle($widthPx) + { + if( $this->LCType !== LCT_DROPDOWN ) + return parent::makeWidthStyle( $widthPx ); + + if( 0 == $widthPx ) + return ""; + + return "width: ".( $widthPx + 7 )."px"; + } + + /** + * Add control JS files to page object + */ + function addJSFiles() + { + if( $this->multiselect && ( $this->LCType == LCT_DROPDOWN && $this->lookupSize == 1 || $this->LCType == LCT_AJAX || $this->LCType == LCT_LIST ) ) + $this->pageObject->AddJSFile("include/chosen/chosen.jquery.js"); + } + + /** + * Add control CSS files to page object + */ + function addCSSFiles() + { + if( $this->multiselect && ( $this->LCType == LCT_DROPDOWN && $this->lookupSize == 1 || $this->LCType == LCT_AJAX || $this->LCType == LCT_LIST ) ) + { + $this->pageObject->AddCSSFile("include/chosen/bootstrap-chosen.css"); + } + } + + /** + * This function need to bypass buildControl function of this class. It calls from LookupTextField class only. + */ + function parentBuildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + } + + /** + * Get the control's settings and build its HTML markup + */ + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + + $this->alt = ($mode == MODE_INLINE_EDIT || $mode == MODE_INLINE_ADD) && $this->is508 ? ' alt="'.runner_htmlspecialchars($this->strLabel).'" ' : ""; + + $suffix = "_".GoodFieldName($this->field)."_".$this->id; + $this->clookupfield = "display_value".($fieldNum ? $fieldNum : '').$suffix; + + $this->cfield = "value".$suffix; + $this->ctype = "type".$suffix; + if($fieldNum) + { + $this->cfield = "value".$fieldNum.$suffix; + $this->ctype = "type".$fieldNum.$suffix; + } + + if( $this->ciphererLookup ) + $this->isLinkFieldEncrypted = $this->ciphererLookup->isFieldPHPEncrypted( $this->linkFieldName ); + + $this->horizontalLookup = $this->pageObject->pSetEdit->isHorizontalLookup($this->field); + + $this->addMainFieldsSettings(); + + // alter "add on the fly" settings + $this->addNewItem = $this->isAllowToAdd( $mode ); + + // prepare multi-select attributes + $this->multiple = $this->multiselect ? " multiple" : ""; + $this->postfix = $this->multiselect ? "[]" : ""; + if( $this->multiselect ) + $avalue = splitLookupValues($value); + else + $avalue = array((string)$value); + + $searchOption = $additionalCtrlParams["option"]; + + // build the control + if( $this->lookupType == LT_LISTOFVALUES ) + { + $this->buildListOfValues($avalue, $value, $mode, $searchOption); + } + else + { + if( !$this->lookupDataSource ) { + return; + } + // build a table-based lookup + if( $this->ciphererLookup ) + $this->isDisplayFieldEncrypted = $this->ciphererLookup->isFieldPHPEncrypted( $this->displayFieldName ); + + if( $this->LCType == LCT_AJAX || $this->LCType == LCT_LIST ) + { + $this->buildAJAXLookup($avalue, $value, $mode, $searchOption); + } + else + { + $this->buildClassicLookup($avalue, $value, $mode, $searchOption); + } + } + + $this->buildControlEnd($validate, $mode); + } + + /** + * // alter "add on the fly" settings + * @param String mode + * @return Boolean + */ + protected function isAllowToAdd( $mode ) + { + $addNewItem = false; + $strPerm = GetUserPermissions($this->lookupTable); + if( strpos($strPerm,"A") !== false && $this->LCType != LCT_LIST && $mode != MODE_SEARCH ) + { + $addNewItem = $this->pageObject->pSetEdit->isAllowToAdd($this->field); + $advancedadd = !$this->pageObject->pSetEdit->isSimpleAdd($this->field); + if(!$advancedadd || $this->pageObject->pageType == PAGE_REGISTER) + $addNewItem = false; + } + + return $addNewItem; + } + + /** + * + */ + protected function addMainFieldsSettings() + { + if( $this->pageObject->pSetEdit->isLookupWhereCode( $this->field ) ) + return; + + $mainMasterFields = array(); + $mainFields = array(); + + $where = $this->pageObject->pSetEdit->getLookupWhere( $this->field ); + foreach( DB::readSQLTokens( $where ) as $token ) + { + $prefix = ""; + $field = $token; + $dotPos = strpos( $token, "."); + + if( $dotPos !== FALSE ) + { + $prefix = strtolower( substr( $token, 0, $dotPos ) ); + $field = substr( $token, $dotPos + 1 ); + } + + if( $prefix == "master" ) + $mainMasterFields[] = $field; + else if( !$prefix ) + $mainFields[] = $field; + } + + $this->addJSSetting( "mainFields", $mainFields ); + $this->addJSSetting( "mainMasterFields", $mainMasterFields ); + } + + /** + * Get indexes of link and display fields + */ + /* + public function fillLookupFieldsIndexes() + { + $lookupIndexes = GetLookupFieldsIndexes($this->pageObject->pSetEdit, $this->field); + $this->linkFieldIndex = $lookupIndexes["linkFieldIndex"]; + $this->displayFieldIndex = $lookupIndexes["displayFieldIndex"]; + } + */ + + /** + * Build HTML markup fo the 'List of values' lookup field + */ + public function buildListOfValues($avalue, $value, $mode, $searchOption) + { + // read lookup values + $arr = $this->pageObject->pSetEdit->getLookupValues($this->field); + $display_values = $arr; + + if (in_array( $this->pageObject->pSetEdit->getViewFormat($this->field), array(FORMAT_DATE_SHORT, FORMAT_DATE_LONG, FORMAT_DATE_TIME))) + { + $container = new ViewControlsContainer($this->pageObject->pSetEdit, PAGE_LIST, null); + foreach ( $arr as $key => $opt ) + { + $data = array(); + $data[$this->field] = $opt; + $display_values[$key] = $container->getControl($this->field)->getTextValue($data); + } + } + + $dropDownHasSimpleBox = $this->LCType == LCT_DROPDOWN && !$this->multiselect && $mode == MODE_SEARCH; + $optionContains = $dropDownHasSimpleBox && $this->isSearchOpitonForSimpleBox( $searchOption ); + + // print Type control to allow selecting nothing + if( $this->multiselect ) + echo ''; + + switch($this->LCType) + { + case LCT_DROPDOWN: + $dataAttr = $selectClass = ''; + if( $dropDownHasSimpleBox ) + { + $dataAttr = ' data-usesuggests="true"'; + $selectClass = $optionContains ? ' class="rnr-hiddenControlSubelem" ' : ''; + $simpleBoxClass = $optionContains ? '' : ' class="rnr-hiddenControlSubelem" '; + $simpleBoxStyle = $this->getWidthStyleForAdditionalControl(); + echo ''; + } + + echo '"; + break; + + case LCT_CBLIST: + echo '
'; + $spacer = '
'; + if($this->horizontalLookup) + $spacer = '  '; + $i = 0; + foreach($arr as $key => $opt) + { + echo ''; + $i++; + } + echo '
'; + break; + + case LCT_RADIO: +// $spacer = $this->horizontalLookup ? "  " : "
"; + echo '
'; + echo ''; + $i = 0; + foreach($arr as $key => $opt) + { + $checked = ""; + if($opt == $value) + $checked = ' checked="checked" '; + echo ''; + $i++; + } + echo '
'; + break; + } + } + + /** + * Build the markup for the 'Edit box with AJAX popup' or 'List page with search' lookup field + * @param Array avalue An array of the control values + * @param String value A control's value string representation + * @param String mode The control's mode (MODE_INLINE_EDIT, MODE_INLINE_ADD) + * @param String searchOption The control's search option + */ + public function buildAJAXLookup($avalue, $value, $mode, $searchOption) + { + if( $this->multiselect ) + { + $this->buildMultiselectAJAXLookup($avalue, $value, $mode, $searchOption); + return; + } + + + $listSearchHasSimpleBox = $mode == MODE_SEARCH && $this->isAdditionalControlRequired(); + $optionContains = $this->isSearchOpitonForSimpleBox( $searchOption ); + $listOptionContains = $listSearchHasSimpleBox && $optionContains; + $dataAttr = ''; + + + if( $this->LCType == LCT_LIST ) + { + $dataAttr = $listSearchHasSimpleBox ? ' data-usesuggests="true"' : ''; + } + else if( $this->LCType == LCT_AJAX && $optionContains ) + { + $dataAttr = ' data-simple-search-mode="true" '; + } + + if($this->bUseCategory) + { + $valueAttr = ''; + if( $this->LCType == LCT_AJAX && $optionContains || $this->LCType == LCT_LIST && $listOptionContains ) + $valueAttr = ' value="'.runner_htmlspecialchars($value).'"'; + + // dependent ajax-lookup control + $inputParams = '" '.$this->getPlaceholderAttr().' autocomplete="off" id="'.$this->clookupfield.'" '.$valueAttr.' name="'.$this->clookupfield.'" '.$this->inputStyle; + $inputParams.= $this->LCType == LCT_LIST && !$listOptionContains ? 'readonly': ''; + echo ''; + + echo ''; + + echo $this->getLookupLinks( $listOptionContains ); + return; + } + + // get the initial value + $lookup_value = ""; + $lookupDc = $this->getLookupDataCommand( array(), $value, false, true ); + + $qResult = $this->lookupDataSource->getList( $lookupDc ); + if( !$qResult ) { + showError( $this->lookupDataSource->lastError() ); + } + + if( $data = $qResult->fetchAssoc() ) + { + if($this->isDisplayFieldEncrypted) + $lookup_value = $this->ciphererLookup->DecryptField( $this->displayFieldName , $data[ $this->displayFieldAlias ]); + else + $lookup_value = $data[ $this->displayFieldAlias ]; + } + elseif( $this->pageObject->pSetEdit->isLookupWhereSet( $this->field ) ) + { + // try w/o WHERE expression + $lookupDc = $this->getLookupDataCommand( array(), $value, false, true, false ); + $qResult = $this->lookupDataSource->getList( $lookupDc ); + if( !$qResult ) { + showError( $this->lookupDataSource->lastError() ); + } + if( $data = $qResult->fetchAssoc() ) + { + if($this->isDisplayFieldEncrypted) + $lookup_value = $this->ciphererLookup->DecryptField( $this->displayFieldName , $data[ $this->displayFieldAlias ]); + else + $lookup_value = $data[ $this->displayFieldAlias ]; + } + } + + // build the regular ajax-lookup control + if( $this->LCType == LCT_AJAX && !strlen($lookup_value) && ($this->pageObject->pSetEdit->isfreeInput($this->field) || $this->lookupPageType == PAGE_SEARCH) + || $this->LCType == LCT_LIST && $listOptionContains ) + { + $lookup_value = $value; + } + + if ( in_array( $this->pageObject->pSetEdit->getViewFormat($this->field), array(FORMAT_DATE_SHORT, FORMAT_DATE_LONG, FORMAT_DATE_TIME) ) ) + { + $container = new ViewControlsContainer($this->pageObject->pSetEdit, PAGE_LIST, null); + + $ctrlData = array(); + $ctrlData[ $this->field ] = $lookup_value; + $lookup_value = $container->getControl( $this->field )->getTextValue( $ctrlData ); + } + + $inputParams = 'autocomplete="off" '.$this->getPlaceholderAttr().' id="'.$this->clookupfield.'" name="'.$this->clookupfield.'" '.$this->inputStyle.$this->alt; + $inputParams.= ' value="'.runner_htmlspecialchars($lookup_value).'"';; + + if( $this->LCType == LCT_LIST && !$listOptionContains ) + $inputParams.= ' readonly '; + + if( $this->LCType == LCT_LIST && !$this->pageObject->pSetEdit->isRequired($this->field)) + $inputParams.= ' class="clearable" '; + + $inputTag = ''; + if ( $this->LCType == LCT_LIST ) + { + echo ''.$inputTag.''; + } + else + { + echo $inputTag; + } + + echo ''; + + echo $this->getLookupLinks( $listOptionContains ); + } + + /** + * Build a multiselect control html markup to apply JS 'chosen' plugin + * @param Array avalue An array of the control values + * @param String value A control's value string representation + * @param String mode The control's mode (MODE_INLINE_EDIT, MODE_INLINE_ADD) + * @param String searchOption The control's search option + */ + protected function buildMultiselectAJAXLookup($avalue, $value, $mode, $searchOption) + { + echo ''; + + echo $this->getLookupLinks(); + } + + /** + * Build the control's 'option' elements. If the link and displayed fields are not the same + * a db query is used to retrieve displayed values corresponding to the link values ($avalue) + * @param Array avalue An array of the control values + * @param String value A control's value string representation + * @param String mode The control's mode (MODE_INLINE_EDIT, MODE_INLINE_ADD) + * @param String searchOption The control's search option + */ + protected function buildMultiselectAJAXLookupRows($avalue, $value, $mode, $searchOption) + { + //$this->fillLookupFieldsIndexes(); + + if( $this->linkAndDisplaySame || $this->lookupPageType == PAGE_SEARCH ) + { + $this->displayFieldAlias = $this->displayFieldName; + foreach($avalue as $mKey => $mValue) + { + $data = array(); + $data[ $this->linkFieldName ] = $mValue; + $data[ $this->displayFieldAlias ] = $mValue; + + $this->buildLookupRow( $mode, $data, ' selected', $mKey ); + } + return; + } + + $lookupDc = $this->getLookupDataCommand( array(), $value, false, true ); + $qResult = $this->lookupDataSource->getList( $lookupDc ); + if( !$qResult ) { + showError( $this->lookupDataSource->lastError() ); + } + + $options = 0; + while( $data = $qResult->fetchAssoc() ) + { + $this->decryptDataRow( $data ); + if( array_search( $data[ $this->linkFieldName ], $avalue ) !== FALSE ) + { + $this->buildLookupRow( $mode, $data, ' selected', $options ); + $options++; + } + } + + // try the same query w/o WHERE clause if options were not found + if( $options == 0 && strlen($value) && $mode == MODE_EDIT && $this->pageObject->pSetEdit->isLookupWhereSet( $this->field ) ) + { + //one record mode true + $lookupDc = $this->getLookupDataCommand( array(), $value, false, true, false, true ); + $qResult = $this->lookupDataSource->getList( $lookupDc ); + + if( $data = $qResult->fetchAssoc() ) + { + $this->decryptDataRow( $data ); + $this->buildLookupRow( $mode, $data, ' selected', $options ); + } + } + } + + /** + * Build HTML markup for the 'dropdown box', 'checkbox list' or 'radio button' lookup field + * @param Array avalue + * @param String value + * @param String mode + * @param String searchOption + */ + public function buildClassicLookup($avalue, $value, $mode, $searchOption) + { + $dropDownHasSimpleBox = $this->LCType == LCT_DROPDOWN && $mode == MODE_SEARCH && $this->isAdditionalControlRequired(); + $optionContains = $dropDownHasSimpleBox && $this->isSearchOpitonForSimpleBox( $searchOption ); + + if( $this->multiselect ) // print Type control to allow selecting nothing + echo ''; + + if($this->bUseCategory) + { + // dependent classic lookup + switch ($this->LCType) + { + case LCT_CBLIST: + echo '
'; + echo ''; + echo '
'; + break; + + case LCT_RADIO: + echo ''; + echo '
'; + echo '
'; + break; + + case LCT_DROPDOWN: + $dataAttr = ''; + $selectClass = 'form-control'; + $simpleBoxClass = 'form-control'; + if( $dropDownHasSimpleBox ) + { + $dataAttr = ' data-usesuggests="true"'; + $selectClass .= $optionContains ? ' rnr-hiddenControlSubelem' : ''; + $simpleBoxClass .= $optionContains ? '' : ' rnr-hiddenControlSubelem'; + $simpleBoxStyle = ''; + echo ''; + } + + echo ''; + break; + } + + echo $this->getLookupLinks(); + return; + } + + $lookupDc = $this->getLookupDataCommand( array(), "", false ); + $qResult = $this->lookupDataSource->getList( $lookupDc ); + if( !$qResult ) { + showError( $this->lookupDataSource->lastError() ); + } + + // simple classic lookup + if($this->LCType == LCT_DROPDOWN) + { + $dataAttr = ''; + $selectClass = 'form-control'; + $simpleBoxClass = 'form-control'; + + if( $dropDownHasSimpleBox ) + { + $dataAttr = ' data-usesuggests="true"'; + $selectClass .= $optionContains ? ' rnr-hiddenControlSubelem' : ''; + $simpleBoxClass .= $optionContains ? '' : ' rnr-hiddenControlSubelem'; + $simpleBoxStyle = ''; + echo ''; + } + + echo ''; + + echo '
'; + } + + // print lookup data + $found = false; + $i = 0; + $isLookupUnique = $this->lookupType == LT_QUERY && $this->pageObject->pSetEdit->isLookupUnique($this->field); + $uniqueArray = array(); + while( $data = $qResult->fetchAssoc() ) + { + $this->decryptDataRow( $data ); + $linkValue = $data[ $this->linkFieldName ]; + if($isLookupUnique) + { + if( in_array( $linkValue, $uniqueArray) ) + continue; + $uniqueArray[] = $linkValue; + } + + $res = array_search( (string) $linkValue, $avalue ); + $checked = ""; + if( $res !== FALSE ) + { + $found = true; + $checked = $this->LCType == LCT_CBLIST || $this->LCType == LCT_RADIO ? ' checked="checked"' : ' selected'; + } + $this->buildLookupRow($mode, $data, $checked, $i); + $i++; + } + + // try the same query w/o WHERE clause if current value not found + if(!$found && strlen($value) && $mode == MODE_EDIT && $this->pageObject->pSetEdit->isLookupWhereSet( $this->field ) ) + { + $lookupDc = $this->getLookupDataCommand( array(), $value, false, true, false, true ); + $qResult = $this->lookupDataSource->getList( $lookupDc ); + if( !$qResult ) { + showError( $this->lookupDataSource->lastError() ); + } + if( $data = $qResult->fetchAssoc() ) + { + $this->decryptDataRow($data); + $checked = $this->LCType == LCT_CBLIST || $this->LCType == LCT_RADIO ? ' checked="checked"' : ' selected'; + $this->buildLookupRow($mode, $data, $checked, $i); + } + } + + // print footer + $footer = $this->LCType == LCT_DROPDOWN ? '' : '
'; + echo $footer; + + echo $this->getLookupLinks(); + } + + /** + * @param &Array data + */ + public function decryptDataRow(&$data) + { + if($this->isLinkFieldEncrypted) + $data[$this->linkFieldName] = $this->ciphererLookup->DecryptField( $this->linkFieldName, $data[$this->linkFieldName] ); + if($this->isDisplayFieldEncrypted) + $data[$this->displayFieldAlias] = $this->ciphererLookup->DecryptField( $this->displayFieldName, $data[$this->displayFieldAlias] ); + } + + /** + * Build HTML markup for a lookup item + * @param String mode + * @param Array data + * @param String checked + * @param Number i + * @return String + */ + public function buildLookupRow($mode, $data, $checked, $i) + { + $display_value = $data[ $this->displayFieldAlias ]; + $link_value = $data[ $this->linkFieldName ]; + + if( in_array( $this->pageObject->pSetEdit->getViewFormat($this->field), array(FORMAT_DATE_SHORT, FORMAT_DATE_LONG, FORMAT_DATE_TIME) ) ) + { + $container = new ViewControlsContainer($this->pageObject->pSetEdit, PAGE_LIST, null); + + $ctrlData = array(); + + $ctrlData[ $this->field ] = $link_value; + + $display_value = $container->getControl( $this->field )->getTextValue( $ctrlData ); + } + + $render_value = $this->getLookupTextValue( $display_value ); + + switch($this->LCType) + { + case LCT_DROPDOWN: + case LCT_LIST: + case LCT_AJAX: + echo ''; + break; + + case LCT_CBLIST: + echo ''; + break; + + case LCT_RADIO: + echo ''; + break; + } + } + + function getFirstElementId() + { + switch($this->LCType) + { + case LCT_AJAX: + return "display_value_" . $this->goodFieldName . "_" . $this->id; + break; + default: + return $this->cfield; + break; + } + } + + /** + * Check if a simple search box should be displayed + * for a particular search options + * @param String searchOption + * @return Boolean + */ + public function isSearchOpitonForSimpleBox( $searchOption ) + { + if( $searchOption == 'Contains' || $searchOption == 'Starts with' ) + return true; + + if( $searchOption != '' ) + return false; + + $userSearchOptions = $this->pageObject->pSetEdit->getSearchOptionsList( $this->field ); + return !($userSearchOptions) || in_array('Contains', $userSearchOptions) || in_array('Starts with', $userSearchOptions); + } + + /** + * Check if an additional simple search box control should be added to + * the ordinary control's markup + * @return Boolean + */ + protected function isAdditionalControlRequired() + { + if( $this->multiselect ) + return false; + + $hostPageType = $this->pageObject->pSetEdit->getTableType(); + if( $hostPageType == "report" || $hostPageType == "chart" ) + return false; + + $userSearchOptions = $this->pageObject->pSetEdit->getSearchOptionsList( $this->field ); + if( !!$userSearchOptions && !in_array('Contains', $userSearchOptions) && !in_array('Starts with', $userSearchOptions) ) + return false; + + if( $this->lookupType == LT_LISTOFVALUES || $this->linkAndDisplaySame ) + return true; + + // #9875 connection and lookupConnection props must be the same + if( $this->connection->connId != $this->lookupDataSource->getConnectionId() ) + return false; + + if( !$this->connection->checkIfJoinSubqueriesOptimized() && $this->LCType == LCT_LIST ) + return false; + + return $this->isLookupSQLquerySimple() && $this->isMainTableSQLquerySimple(); + } + + /** + * Get the additional control element's style attribute string + * @return String + */ + protected function getWidthStyleForAdditionalControl() + { + $width = $this->searchPanelControl ? 150 : $this->pageObject->pSetEdit->getControlWidth( $this->field ); + //$style = parent::makeWidthStyle( $width ); + + return 'style="'.$style.'"'; + } + + /** + * Check if the lookup table doesn't have encription and its SQL query doesn't have HAVING, + * ORDER BY clauses and FROM clause with subqueries. #8564 + * @return Boolean + */ + protected function isLookupSQLquerySimple() + { + $lookupConnection = $this->lookupDataSource->getConnection(); + if( $lookupConnection->dbType == nDATABASE_DB2 || $lookupConnection->dbType == nDATABASE_Informix || $lookupConnection->dbType == nDATABASE_SQLite3 ) + return false; + + if( $this->lookupType == LT_LOOKUPTABLE || $this->lookupType == LT_LISTOFVALUES ) + return true; + + // encription is turned on + if( $this->lookupPSet->hasEncryptedFields() ) + return false; + + $lookupSqlQuery = $this->lookupPSet->getSQLQuery(); + + if( !$lookupSqlQuery ) { + return false; + } + + if( $lookupSqlQuery->HasGroupBy() || $lookupSqlQuery->HavingToSql() != "" || $lookupSqlQuery->HasSubQueryInFromClause() ) + return false; + + if( $lookupConnection->dbType != nDATABASE_MySQL ) + { + $linkFieldType = $this->lookupPSet->getFieldType( $this->linkFieldName ); + if( !(IsNumberType($this->type) && IsNumberType($linkFieldType) || IsCharType($this->type) && IsCharType($linkFieldType) || IsDateFieldType($this->type) && IsDateFieldType($linkFieldType)) ) + return false; + } + return true; + } + + /** + * Check if the main table doesn't have encryption and its SQL query doesn't have HAVING, + * ORDER BY clauses and FROM clause with sub-queries. #8564 + * @return Boolean + */ + protected function isMainTableSQLquerySimple() + { + if( $this->connection->dbType != nDATABASE_MySQL + && $this->connection->dbType != nDATABASE_MSSQLServer + && $this->connection->dbType != nDATABASE_Oracle + && $this->connection->dbType != nDATABASE_PostgreSQL ) + return false; + + // encription is turned on + if( $this->pageObject->pSetEdit->hasEncryptedFields() ) + return false; + + $sqlQuery = $this->pageObject->pSetEdit->getSQLQueryByField( $this->field ); + + if( !$sqlQuery ) { + return false; + } + + if( $sqlQuery->HasGroupBy() || $sqlQuery->HavingToSql() != "" || $sqlQuery->HasSubQueryInFromClause() ) + return false; + + return true; + } + + /** + * Check if searching by displayed field is allowed + * @return Boolean + */ + protected function isSearchByDispalyedFieldAllowed() + { + if ( !is_null( $this->searchByDisplayedFieldIsAllowed ) ) + return $this->searchByDisplayedFieldIsAllowed; + + // #9875 connection and lookupConnection props must be the same + if( !$this->lookupDataSource ) { + $this->searchByDisplayedFieldIsAllowed = false; + return $this->searchByDisplayedFieldIsAllowed; + } + if( $this->connection->connId != $this->lookupDataSource->getConnectionId() ) + { + $this->searchByDisplayedFieldIsAllowed = false; + return $this->searchByDisplayedFieldIsAllowed; + } + + if( !$this->connection->checkIfJoinSubqueriesOptimized() && ( $this->LCType == LCT_LIST || $this->LCType == LCT_AJAX ) ) + { + $this->searchByDisplayedFieldIsAllowed = false; + return $this->searchByDisplayedFieldIsAllowed; + } + + $hostPageType = $this->pageObject->pSetEdit->getTableType(); + + $this->searchByDisplayedFieldIsAllowed = $hostPageType != "report" && $hostPageType != "chart" && !$this->linkAndDisplaySame + && !$this->multiselect && ( $this->LCType == LCT_LIST || $this->LCType == LCT_DROPDOWN || $this->LCType == LCT_AJAX ) + && $this->lookupType != LT_LISTOFVALUES && $this->isLookupSQLquerySimple() && $this->isMainTableSQLquerySimple(); + + return $this->searchByDisplayedFieldIsAllowed; + } + + + /** + * @param String strSearchOption + * @return Boolean + */ + public function checkIfDisplayFieldSearch( $strSearchOption ) + { + return $this->isSearchByDispalyedFieldAllowed() && ( $strSearchOption === "Starts with" || $strSearchOption === "Contains" ); + } + + /** + * Get the substitute columns list for the SELECT Clause and the FORM clause part + * that will be joined to the basic page's FROM clause + * @param String searchFor + * @param String searchOpt + * @param Boolean isSuggest + * @return Array + */ + public function getSelectColumnsAndJoinFromPart($searchFor, $searchOpt, $isSuggest) + { + if( !$isSuggest || !$this->isSearchByDispalyedFieldAllowed() ) + return parent::getSelectColumnsAndJoinFromPart($searchFor, $searchOpt, $isSuggest); + + $this->initializeLookupTableAliases(); + + return array( + "selectColumns"=> $this->getSelectColumns( $isSuggest ), + "joinFromPart"=> $this->getFromClauseJoinPart( $searchFor, $searchOpt, $isSuggest) + ); + } + + /** + * Form the control specified search options array and built the control's search options markup + * @param String selOpt The search option value + * @param Boolean not It indicates if the search option negation is set + * @param Boolean both It indicates if the control needs 'NOT'-options + * @return String A string containing options markup + */ + function getSearchOptions($selOpt, $not, $both) + { + $optionsArray = array(); + if ($this->multiselect) + $optionsArray[] = CONTAINS; + else + { + if($this->lookupType == LT_QUERY) + $this->ciphererLookup = new RunnerCipherer($this->lookupTable); + + if( $this->ciphererLookup ) + $this->isDisplayFieldEncrypted = $this->ciphererLookup->isFieldPHPEncrypted( $this->displayFieldName ); + + if($this->LCType == LCT_AJAX && !$this->isDisplayFieldEncrypted) + { + if( $this->isSearchByDispalyedFieldAllowed() || $this->linkAndDisplaySame ) + { + $optionsArray[] = CONTAINS; + $optionsArray[] = STARTS_WITH; + } + $optionsArray[] = MORE_THAN; + $optionsArray[] = LESS_THAN; + $optionsArray[] = BETWEEN; + } + + if( ($this->LCType == LCT_LIST || $this->LCType == LCT_DROPDOWN) && $this->isAdditionalControlRequired() ) + { + $optionsArray[] = CONTAINS; + $optionsArray[] = STARTS_WITH; + } + } + $optionsArray[] = EQUALS; + $optionsArray[] = EMPTY_SEARCH; + + if($both) + { + if ($this->multiselect) + $optionsArray[] = NOT_CONTAINS; + else + { + if($this->LCType == LCT_AJAX && !$this->isDisplayFieldEncrypted) + { + if( $this->isSearchByDispalyedFieldAllowed() || $this->linkAndDisplaySame ) + { + $optionsArray[] = NOT_CONTAINS; + $optionsArray[] = NOT_STARTS_WITH; + } + $optionsArray[] = NOT_MORE_THAN; + $optionsArray[] = NOT_LESS_THAN; + $optionsArray[] = NOT_BETWEEN; + } + if( ($this->LCType == LCT_LIST || $this->LCType == LCT_DROPDOWN) && $this->isAdditionalControlRequired() ) + { + $optionsArray[] = NOT_CONTAINS; + $optionsArray[] = NOT_STARTS_WITH; + } + } + + $optionsArray[] = NOT_EQUALS; + $optionsArray[] = NOT_EMPTY; + } + + return $this->buildSearchOptions($optionsArray, $selOpt, $not, $both); + } + + /** + * Fill the response array with the suggest values + * + * + * @param String value + * Note: value is preceeded with "_" + * @param String searchFor + * @param &Array response + * @param &Array row + */ + function suggestValue($value, $searchFor, &$response, &$row) + { + parent::suggestValue($value, $searchFor, $response, $row); + return; + + // ?????? + if( !GetGlobalData("handleSearchSuggestInLookup", true) || $this->lookupType == LT_LISTOFVALUES || $this->isSearchByDispalyedFieldAllowed() ) + { + parent::suggestValue($value, $searchFor, $response, $row); + return; + } + + $lookupDc = $this->getLookupDataCommand( array(), substr($value, 1), false, true, true, true ); + $qResult = $this->lookupDataSource->getList( $lookupDc ); + + if( $data = $qResult->fetchAssoc() ) + { + // "_" is added to convert number type to string + if( $this->isDisplayFieldEncrypted ) + { + $lookup_value = "_" . $this->ciphererLookup->DecryptField( $this->displayFieldName , $data[ $this->displayFieldAlias ] ); + } + else + $lookup_value = "_" . $data[ $this->displayFieldAlias ]; + + parent::suggestValue($lookup_value, $searchFor, $response, $row); + } + } + + /** + * @param Array parentValuesData + * @return Boolean + */ + protected function needCategoryFiltering( $parentValuesData ) + { + foreach( $this->pageObject->pSetEdit->getParentFieldsData( $this->field ) as $cData ) + { + $strCategoryControl = $cData['main']; + + if( !isset( $parentValuesData[ $cData['main'] ] ) ) + continue ; + + $parentValue = $parentValuesData[ $cData['main'] ]; + $parentVals = $this->pageObject->pSetEdit->multiSelect($strCategoryControl) ? splitLookupValues( $parentValue ) : array( $parentValue ); + + foreach( $parentVals as $parentVal ) + { + if( strlen( trim( $parentVal ) ) ) + return true; + } + } + + return false; + } + + /** + * Get for the dependent lookup an array containing the link field values with even indices + * and the corresponding displayed values with odd indices + * + * @intellisense + * @param Array parentValuesData + * @param String childVal + * @param Boolean doCategoryFilter + * @param Boolean initialLoad + * @return Array + */ + public function loadLookupContent( $parentValuesData, $childVal = "", $doCategoryFilter = true, $initialLoad = true ) + { + if( $this->bUseCategory && $doCategoryFilter ) + { + if( !$this->needCategoryFiltering( $parentValuesData ) ) + return array(); + } + + $lookupDc = $this->getLookupDataCommand( $parentValuesData, $childVal, $doCategoryFilter, $this->LCType == LCT_AJAX && $initialLoad ); + return $this->getLookupContentData( $lookupDc, $childVal != "" ); + } + + /** + * @param DsCommand lookupDc + * @param Boolean selectValue + * @return Array + */ + protected function getLookupContentData( $lookupDc, $selectValue ) + { + $response = array(); + $qResult = $this->lookupDataSource->getList( $lookupDc ); + if( !$qResult ) { + showError( $this->lookupDataSource->lastError() ); + } + + if( $this->LCType !== LCT_AJAX || $this->multiselect ) + { + $isUnique = $this->pageObject->pSetEdit->isLookupUnique( $this->field ); + $uniqueArray = array(); + while( $data = $qResult->fetchAssoc() ) + { + $dispValue = $data[ $this->displayFieldAlias ]; + if( $isUnique ) + { + if( in_array( $dispValue, $uniqueArray) ) + continue; + + $uniqueArray[] = $dispValue; + } + $response[] = $data[ $this->linkFieldName ]; + $response[] = $this->getLookupTextValue( $dispValue ); + } + } + else + { + $data = $qResult->fetchAssoc(); + // assign value if it is asked for, or if there is only oine record in recordset + + if( $data && ( $selectValue || !$qResult->fetchAssoc() ) ) + { + $response[] = $data[ $this->linkFieldName ]; + $response[] = $this->getLookupTextValue( $data[ $this->displayFieldAlias ] ); + } + } + + return $response; + } + + /** + * @param Boolean isExistParent + * @param Number mode + * @param Array parentCtrlsData + * @return Mixed + */ + public function getLookupContentToReload( $isExistParent, $mode, $parentCtrlsData ) + { + // there are parent lookups on the page + if( $isExistParent ) + { + $hasEmptyParent = false; + foreach($parentCtrlsData as $value) + { + if( $value === '' ) + { + $hasEmptyParent = true; + break; + } + } + + if( !$hasEmptyParent ) + { + // there are parent lookups on the page none of them is empty + return $this->loadLookupContent( $parentCtrlsData, '', true, false ); + } + + if( $mode == MODE_SEARCH || $mode == MODE_EDIT || $mode == MODE_INLINE_EDIT || $mode == MODE_INLINE_ADD || $mode == MODE_ADD ) + return ''; + + // which mode is this? + return $this->loadLookupContent( $parentCtrlsData, '', true, false ); + } + // there are not parent lookups on the page + else + { + if( $mode == MODE_SEARCH || $mode == MODE_INLINE_ADD || $mode == MODE_ADD || $mode == MODE_EDIT || $mode == MODE_INLINE_EDIT ) + return $this->loadLookupContent( array(), '', false, false ); + + return $this->loadLookupContent( array(), '', true, false ); + } + + return ''; + } + + /** + * @param String linkFieldVal + * @return Array + */ + public function getAutoFillData( $linkFieldVal ) + { + $data = array(); + + $lookupDc = $this->getLookupDataCommand( array(), $linkFieldVal, false, true, true ); + $rs = $this->lookupDataSource->getList( $lookupDc ); + if( !$rs ) { + showError( $this->lookupDataSource->lastError() ); + } + $row = $rs->fetchAssoc(); + + $autoCompleteFields = $this->pageObject->pSetEdit->getAutoCompleteFields( $this->field ); + if( $this->lookupType == LT_QUERY ) + { + $data = $this->ciphererLookup->DecryptFetchedArray( $row ); + } + else + { + foreach( $autoCompleteFields as $aData ) + { + $data[ $aData["lookupF"] ] = $row[ $aData["lookupF"] ]; + } + } + + $ret = array(); + $masterData = array(); + foreach( $autoCompleteFields as $aData ) { + $masterData[ $aData["masterF"] ] = $data[ $aData["lookupF"] ]; + + $fieldData = array(); + $val = $data[ $aData["lookupF"] ]; + $ctrl = $this->pageObject->getControl( $aData["masterF"] ); + $dispValue = $ctrl->getDisplayValue( $masterData ); + if( $ctrl->format == EDIT_FORMAT_READONLY ) { + $fieldData["value"] = $val; + $fieldData["dispValue"] = $dispValue; + } else { + $fieldData["value"] = $dispValue; + } + + $ret[ $aData["lookupF"] ] = $fieldData; + } + + if( !$ret ) + $ret[ $this->field ] = ''; + + return $ret; + } + + + function getInputStyle( $mode ) + { + return "class='form-control'"; + } + + /** + * Select & Add new links block + * @param Boolean hiddenSelect + * @return String + */ + protected function getLookupLinks( $hiddenSelect = false ) + { + $links = array(); + + if( $this->LCType == LCT_LIST ) + { + $visibility = $hiddenSelect ? ' style="visibility: hidden;"' : ''; + $openId = "open_lookup_".GoodFieldName( $this->field )."_".$this->id; + $links[] = ''."Select".''; + + if( $this->multiselect ) { + $clearId = "clearLookup_".GoodFieldName( $this->field )."_".$this->id; + $links[] = ''; + } + } + + if( $this->addNewItem ) + $links[] = ''."Add new".''; + + + if( !count($links) ) + return ""; + + return ''; + } + + public function getBasicFieldCondition( $searchFor, $strSearchOption, $searchFor2 = "", $etype = "" ) { + if( $strSearchOption == EMPTY_SEARCH ) { + return parent::getBasicFieldCondition( $searchFor, $strSearchOption, $searchFor2 ); + } + if( !$this->multiselect ) + return $this->singleValueCondition( $searchFor, $strSearchOption, $searchFor2 ); + else + return $this->multiValueCondition( $searchFor, $strSearchOption, $searchFor2 ); + + } + public function multiValueCondition( $searchFor, $strSearchOption, $searchFor2 = "" ) { + $values = splitLookupValues( $searchFor ); + // single-select on Add/Edit, butmuti on search + if( !$this->pageObject->pSetEdit->multiSelectLookupEdit( $this->field ) ) { + $conditions = array(); + foreach( $values as $v ) { + $conditions[] = $this->singleValueCondition( $v, $strSearchOption, $searchFor2 ); + } + return DataCondition::_Or( $conditions ); + } + // true muti-select control + // takes only Equals and Contains + if( $strSearchOption == EQUALS ) { + // all of searched values must be present in the field + return DataCondition::FieldHasList( $this->field, dsopALL_IN_LIST, $values ); + } + if( $strSearchOption == CONTAINS ) { + // at least one of searched values must be present in the field + return DataCondition::FieldHasList( $this->field, dsopSOME_IN_LIST, $values ); + } + return null; + } + + + public function singleValueCondition( $searchFor, $strSearchOption, $searchFor2 = "" ) { + $cond = parent::getBasicFieldCondition( $searchFor, $strSearchOption, $searchFor2 ); + + if( $this->displayFieldSearch( $strSearchOption ) ) { + $cond->operands[0]->joinData = $this->createJoinData(); + } + return $cond; + } + + /** + * Returns true when searching by display field makes sense. + * It only takes in account field Edit settings. + * Database and other limitations are handled by the datasource + * @return Boolean + */ + protected function displayFieldSearch( $searchOption ) + { + if( $searchOption !== CONTAINS && $searchOption !== STARTS_WITH ) { + // basic search, no display field substitution + return false; + } + if( $this->linkAndDisplaySame || $this->lookupType == LT_LISTOFVALUES ) { + // no lookup display field + return false; + } + + if( $this->multiselect && $this->pageObject->pSetEdit->multiSelectLookupEdit( $this->field )) { + // multiselect everywhere + return false; + } + return true; + + } + + /** + * @return DsJoinData + */ + protected function createJoinData() { + $jd = new DsJoinData; + $jd->dataSource = $this->lookupDataSource; + $jd->linkField = $this->linkFieldName; + if( $this->customDisplay ) + $jd->displayExpression = $this->displayFieldName; + else + $jd->displayField = $this->displayFieldName; + + // we assume here that 'AJAX' and 'List page' lookups are choosen when the lookup table is rather long + $jd->longList = ( $this->LCType == LCT_AJAX || $this->LCType == LCT_LIST ); + $jd->displayAlias = generateAlias(); + return $jd; + } + + /** + * Returns command for the list of lookup values + * @param Array parentValuesData + * @param String value - field value. + * @param Boolean doCategoryFilter - dependent dropdowns + * @param Boolean doValueFilter - select only one value + * @param Boolean doWhereFilter - add custom WHERE filter + * @param Boolean oneRecordMode + * + * @return DsCommand + */ + + protected function getLookupDataCommand( + $parentValuesData, + $value = "", + $doCategoryFilter = true, + $doValueFilter = false, + $doWhereFilter = true, + $oneRecordMode = false ) + { + $pSet = $this->pageObject->pSetEdit; + + $ret = LookupField::makeLookupDataCommand( + $this->field, + $pSet, + $parentValuesData, + $value, + $doCategoryFilter, + $doValueFilter, + $doWhereFilter, + $oneRecordMode + ); + $this->displayFieldAlias = $ret["displayField"]; + return $ret["dc"]; + + + } + + /** + * @param String field name + * @param ProjectSettings + * @param Array parentValuesData + * @param String value - field value. + * @param Boolean doCategoryFilter - dependent dropdowns + * @param Boolean doValueFilter - select only one value + * @param Boolean doWhereFilter - add custom WHERE filter + * @param Boolean oneRecordMode + * @return array + * "ds" => DsCommand + * "displayField" => display field alias in the command result + */ + public static function makeLookupDataCommand( $field, $pSet, $parentValuesData, $value, $doCategoryFilter, $doValueFilter, $doWhereFilter, $oneRecordMode ) + { + + $dc = new DsCommand(); + + // order + $orderField = $pSet->getLookupOrderBy( $field ); + if( $orderField ) { + $dir = $pSet->isLookupDesc( $field ) ? 'DESC' : 'ASC'; + $dc->order[] = array( "column" => $orderField, "dir" => $dir ); + } else { + $lookupType = $pSet->getLookupType( $field ); + if( $lookupType == LT_QUERY ) { + require_once( getabspath('classes/orderclause.php') ); + $lookupTable = $pSet->getLookupTable( $field ); + $dc->order = OrderClause::originalOrderFields( new ProjectSettings( $lookupTable ) ); + } + } + + // custom display field + $displayField = $pSet->getDisplayField( $field ); + if( $pSet->getCustomDisplay( $field ) ) { + $displayFieldAlias = generateAlias(); + $dc->extraColumns[] = new DsFieldData( $displayField, $displayFieldAlias, "" ); + } else { + $displayFieldAlias = $displayField; + } + + // filters + $filters = array(); + + // select only current value + if( $doValueFilter ) { + if( $value === "" || $value === null ) { + // add/search page or empty value + $filters[] = DataCondition::_False(); + } else { + $linkField = $pSet->getLinkField( $field ); + $multiselect = $pSet->multiSelect( $field ); + if( !$multiselect ) { + $filters[] = DataCondition::FieldEquals( $linkField , $value ); + } else { + $values = splitLookupValues( $value ); + $valueConditions = array(); + foreach( $values as $v ) { + $valueConditions[] = DataCondition::FieldEquals( $linkField , $v ); + } + $filters[] = DataCondition::_Or( $valueConditions ); + } + } + } + + // user-provided WHERE expression + if( $doWhereFilter ) + { + $filters[] = DataCondition::SQLCondition( prepareLookupWhere( $field, $pSet ) ); + } + + // security filter + // only check row-level permissions + if( $pSet->getLookupType( $field ) == LT_QUERY ) { + $filters[] = Security::SelectCondition( "S", new ProjectSettings( $pSet->getLookupTable($field) ), true ); + } + + // category filter + $parents = $pSet->getParentFieldsData( $field ); + if( $doCategoryFilter && $parentValuesData && $parents ) + { + $parentFilters = array(); + foreach( $parents as $cdata ) { + $mainControlName = $cdata['main']; + $filterFieldName = $cdata['lookup']; + $mainControlVal = $parentValuesData[ $mainControlName ]; + + if( $pSet->multiSelect( $mainControlName ) || strlen( $mainControlVal ) ) + $filters[] = LookupField::categoryCondition( $pSet, $mainControlName, $filterFieldName, $mainControlVal ); + } + } + + if( $pSet->isLookupUnique($field) ) { + $dc->totals[] = array( "field" => $pSet->getLinkField($field), "total" => "distinct" ); + $dc->totals[] = array( "field" => $displayFieldAlias, "total" => "distinct" ); + } + + $dc->filter = DataCondition::_And( $filters ); + + if( $oneRecordMode ) + $dc->reccount = 1; + return array( + "dc" => $dc, + "displayField" => $displayFieldAlias + ); + } + + + /** + * + */ + public static function categoryCondition( $pSet, $parentControlName, $filterFieldName, $parentControlValue ) { + // single-select + if( !$pSet->multiSelect( $parentControlName ) ) { + return DataCondition::FieldEquals( $filterFieldName, $parentControlValue ); + } + + // multiselect parent + $values = splitLookupValues( $parentControlValue ); + + $conditions = array(); + foreach( $values as $value ) + { + $conditions[] = DataCondition::FieldEquals( $filterFieldName, $value ); + } + + return DataCondition::_Or( $conditions ); + } + + public function getSuggestCommand( $searchFor, $searchOpt, $numberOfSuggests ) + { + $dc = parent::getSuggestCommand( $searchFor, $searchOpt, $numberOfSuggests ); + + // add extra field and replace totals + if( $this->displayFieldSearch( $searchOpt ) ) { + + $displayAlias = generateAlias(); + $dc->extraColumns[] = new DsFieldData( "", $displayAlias, $this->field, 0, $this->createJoinData() ); + + $dc->totals = array( + array( + "field" => $displayAlias, + "total" => "distinct" + ) + ); + } + + return $dc; + } + + protected function getLookupTextValue( $displayValue ) { + if( $this->pageObject->pSetEdit->getViewFormat( $this->field ) == FORMAT_HTML ) { + if ( $this->LCType == LCT_CBLIST || $this->LCType == LCT_RADIO ) { + return $displayValue; + } + } + + return runner_htmlspecialchars( $displayValue ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/LookupTextField.php b/php/classes/controls/LookupTextField.php new file mode 100644 index 0000000000000000000000000000000000000000..eda42340528dcefecb9be3b5fd07644c30d420fe --- /dev/null +++ b/php/classes/controls/LookupTextField.php @@ -0,0 +1,96 @@ +format = EDIT_FORMAT_LOOKUP_WIZARD; + + $this->lookupPageType = $this->pageObject->pSetEdit->getPageTypeByFieldEditFormat($this->field, EDIT_FORMAT_LOOKUP_WIZARD); + + $this->localPSet = new ProjectSettings($this->pageObject->tName, $this->lookupPageType); + + $this->lookupDataSource = getLookupDataSource( $this->field, $this->localPSet ); + + + $this->lookupTable = $this->localPSet->getLookupTable($this->field); + $this->lookupType = $this->localPSet->getLookupType($this->field); + if($this->lookupType == LT_QUERY) + $this->lookupPSet = new ProjectSettings($this->lookupTable); + $this->displayFieldName = $this->localPSet->getDisplayField($this->field); + $this->linkFieldName = $this->localPSet->getLinkField($this->field); + $this->linkAndDisplaySame = $this->displayFieldName == $this->linkFieldName; + + $this->ciphererLink = new RunnerCipherer($this->pageObject->tName); + if($this->lookupType == LT_QUERY) + $this->ciphererDisplay = new RunnerCipherer($this->lookupTable); + else + $this->ciphererDisplay = $this->ciphererLink; + + $this->LCType = $this->localPSet->lookupControlType($this->field); + if( $this->pageObject->mobileTemplateMode() && $this->LCType == LCT_AJAX ) + $this->LCType = LCT_DROPDOWN; + + $this->multiselect = $this->localPSet->multiSelect($this->field); + $this->lwLinkField = $connection->addFieldWrappers($this->localPSet->getLinkField($this->field)); + $this->lwDisplayFieldWrapped = RunnerPage::sqlFormattedDisplayField($this->field, $connection, $this->localPSet); + $this->customDisplay = $this->localPSet->getCustomDisplay($this->field); + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::parentBuildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + echo 'inputStyle.' type="text" ' + .($mode == MODE_SEARCH ? 'autocomplete="off" ' : '') + .(($mode==MODE_INLINE_EDIT || $mode==MODE_INLINE_ADD) && $this->is508==true ? 'alt="'.$this->strLabel.'" ' : '') + .'name="'.$this->cfield.'" '.$this->pageObject->pSetEdit->getEditParams($this->field).' value="' + .runner_htmlspecialchars($value).'">'; + $this->buildControlEnd($validate, $mode); + } + + + /** + * Form the control specified search options array and built the control's search options markup + * @param String selOpt The search option value + * @param Boolean not It indicates if the search option negation is set + * @param Boolean both It indicates if the control needs 'NOT'-options + * @return String A string containing options markup + */ + function getSearchOptions($selOpt, $not, $both) + { + $optionsArray = array(); + $isPHPEncripted = $this->pageObject->cipherer->isFieldPHPEncrypted($this->field); + if(!$isPHPEncripted){ + $optionsArray[] = CONTAINS; + } + $optionsArray[] = EQUALS; + if(!$isPHPEncripted){ + $optionsArray[] = STARTS_WITH; + $optionsArray[] = MORE_THAN; + $optionsArray[] = LESS_THAN; + $optionsArray[] = BETWEEN; + } + $optionsArray[] = EMPTY_SEARCH; + if($both) + { + if(!$isPHPEncripted){ + $optionsArray[] = NOT_CONTAINS; + } + $optionsArray[] = NOT_EQUALS; + if(!$isPHPEncripted){ + $optionsArray[] = NOT_STARTS_WITH; + $optionsArray[] = NOT_MORE_THAN; + $optionsArray[] = NOT_LESS_THAN; + $optionsArray[] = NOT_BETWEEN; + } + $optionsArray[] = NOT_EMPTY; + } + return $this->buildSearchOptions($optionsArray, $selOpt, $not, $both); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/PasswordField.php b/php/classes/controls/PasswordField.php new file mode 100644 index 0000000000000000000000000000000000000000..5af51331319c1af76a0dc9259dacddfa7eb44fca --- /dev/null +++ b/php/classes/controls/PasswordField.php @@ -0,0 +1,32 @@ +format = EDIT_FORMAT_PASSWORD; + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + $classString = " class=\"form-control\""; + + $autocompleteAttr = $this->container->pageType == 'register' + ? 'autocomplete="new-password"' + : ''; + echo 'inputStyle.' '.$autocompleteAttr.' '.$this->getPlaceholderAttr().' id="'.$this->cfield.'" '.$classString.' type="Password" ' + .(($mode==MODE_INLINE_EDIT || $mode==MODE_INLINE_ADD) && $this->is508==true ? 'alt="'.$this->strLabel.'" ' : '').'name="' + .$this->cfield.'" '.$this->pageObject->pSetEdit->getEditParams($this->field).' value="'.runner_htmlspecialchars($value).'">'; + + $this->buildControlEnd($validate, $mode); + } + + function getFirstElementId() + { + return $this->cfield; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/ReadOnlyField.php b/php/classes/controls/ReadOnlyField.php new file mode 100644 index 0000000000000000000000000000000000000000..0e540890a556d359fc3d4f930fbeeb6f7283151d --- /dev/null +++ b/php/classes/controls/ReadOnlyField.php @@ -0,0 +1,47 @@ +format = EDIT_FORMAT_READONLY; + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + if( $mode == MODE_EDIT || $mode == MODE_ADD || $mode == MODE_INLINE_EDIT || $mode == MODE_INLINE_ADD ) { + echo 'inputStyle.'>' + .$this->pageObject->readOnlyFields[ $this->field ].''; + } + + $attr = ""; + if( $this->pageObject->pSetEdit->getViewFormat( $this->field ) == FORMAT_CHECKBOX ) { + $attr = "data-control-type='checkbox'"; + if ( $this->connection->dbType == nDATABASE_PostgreSQL ) { + $attr.=' data-true="t" data-false="f"'; + } + } + + echo ''; + $this->buildControlEnd( $validate, $mode ); + } + + /** + * Get the field's content + * @param &Array data + * @return String + */ + public function getDisplayValue( &$data ) + { + // $this->pageObject is not always a RunnerPage object, sometimes it is EditControlsContainer + $container = new ViewControlsContainer( $this->container->pSetEdit, $this->pageObject->pageType, null ); + $control = $container->getControl( $this->field ); + + return $control->showDbValue( $data, "", false ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/TextAreaField.php b/php/classes/controls/TextAreaField.php new file mode 100644 index 0000000000000000000000000000000000000000..4b42bef5a08714d63735f7fced8f998b7661861f --- /dev/null +++ b/php/classes/controls/TextAreaField.php @@ -0,0 +1,120 @@ +format = EDIT_FORMAT_TEXT_AREA; + } + + function buildControl( $value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data ) { + parent::buildControl( $value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data ); + + if( $this->pageObject->pSetEdit->isUseRTE( $this->field ) ) { + $value = $this->RTESafe( $value ); + + switch( $this->pageObject->pSetEdit->getRTEType( $this->field ) ) { + case "RTE": + $this->buildTinyMCE( $value ); + break; + case "RTECK_NEW": + case "RTECK": + $this->CreateCKeditor( $value ); + break; + case "RTEINNOVA": + $this->buildInnova( $value ); + break; + } + } else { + $nHeight = $this->pageObject->pSetEdit->getNRows( $this->field ); + $attrs = $this->getPlaceholderAttr(); + echo ''; + } + + $this->buildControlEnd($validate, $mode); + } + + function getFirstElementId() + { + return $this->cfield; + } + + /** + * returns safe code for preloading in the RTE + * @intellisense + * @param String text + * @return String + */ + protected function RTESafe($text) + { + $tmpString = trim($text); + if(!$tmpString) + return ""; + + // convert all types of single quotes + $tmpString = str_replace("'", "'", $tmpString); + + // replace carriage returns & line feeds + $tmpString = str_replace( chr(10), " ", $tmpString ); + $tmpString = str_replace( chr(13), " ", $tmpString ); + + return $tmpString; + } + + /** + * @intellisense + */ + protected function CreateCKeditor($value) + { + echo '
' + .'' + .'
'; + } + + /** + * addJSFiles + * Add control JS files to page object + */ + function addJSFiles() { + if ( $this->pageObject->pSetEdit->getRTEType( $this->field ) == "RTE" ) { + $this->pageObject->AddJSFile("plugins/tinymce/tinymce.min.js"); + } + } + + /** + * Build a stub markup for Innova editor + * @param String value + */ + protected function buildInnova( $value ) { + $nHeight = $this->pageObject->pSetEdit->getNRows( $this->field ); + if( $nHeight< 300 ) + $nHeight = 300; + + $assetManagerUrl = projectURL() .'plugins/innovaeditor/assetmanager/'. GetTableLink("assetmanager"); + + echo '
' + .'' + .'
' + .'
' + .'
'; + } + + protected function buildTinyMCE( $value ) { + $nHeight = $this->pageObject->pSetEdit->getNRows( $this->field ) + 100; + + echo '
' + .'' + .'
'; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/TextControl.php b/php/classes/controls/TextControl.php new file mode 100644 index 0000000000000000000000000000000000000000..e5e17539b7298ff107358eb6aaa2617dfbc1b559 --- /dev/null +++ b/php/classes/controls/TextControl.php @@ -0,0 +1,43 @@ +pageObject->cipherer->isFieldPHPEncrypted($this->field); + if(!$isPHPEncripted){ + $optionsArray[] = CONTAINS; + } + $optionsArray[] = EQUALS; + if(!$isPHPEncripted){ + $optionsArray[] = STARTS_WITH; + $optionsArray[] = MORE_THAN; + $optionsArray[] = LESS_THAN; + $optionsArray[] = BETWEEN; + } + $optionsArray[] = EMPTY_SEARCH; + if($both) + { + if(!$isPHPEncripted){ + $optionsArray[] = NOT_CONTAINS; + } + $optionsArray[] = NOT_EQUALS; + if(!$isPHPEncripted){ + $optionsArray[] = NOT_STARTS_WITH; + $optionsArray[] = NOT_MORE_THAN; + $optionsArray[] = NOT_LESS_THAN; + $optionsArray[] = NOT_BETWEEN; + } + $optionsArray[] = NOT_EMPTY; + } + return $this->buildSearchOptions($optionsArray, $selOpt, $not, $both); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/TextField.php b/php/classes/controls/TextField.php new file mode 100644 index 0000000000000000000000000000000000000000..8f5390b8796975141de8437c6446866e33f3399c --- /dev/null +++ b/php/classes/controls/TextField.php @@ -0,0 +1,47 @@ +format = EDIT_FORMAT_TEXT_FIELD; + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + $inputType = $this->pageObject->pSetEdit->getHTML5InputType( $this->field ); + $altAttr = ( $mode == MODE_INLINE_EDIT || $mode == MODE_INLINE_ADD ) && $this->is508 == true ? ' alt="'.$this->strLabel.'" ' : ''; + + $classString = ""; + if( $this->pageObject->isBootstrap() ) + $classString = " class=\"form-control\""; + + $autocompleteAttr = ''; + if( $mode == MODE_SEARCH ) { + $autocompleteAttr = 'autocomplete="off"'; + } + + if( $this->pageObject->pageType == 'register' && $this->field == Security::usernameField() ) { + $autocompleteAttr = 'autocomplete="username"'; + } + + + echo 'inputStyle.' type="'.$inputType.'" ' + .$autocompleteAttr . ' ' + .$altAttr + .'name="'.$this->cfield.'" '.$this->pageObject->pSetEdit->getEditParams( $this->field ) + . $this->getPlaceholderAttr() + .' value="'.runner_htmlspecialchars($value).'">'; + + $this->buildControlEnd($validate, $mode); + } + + function getFirstElementId() + { + return $this->cfield; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/TimeField.php b/php/classes/controls/TimeField.php new file mode 100644 index 0000000000000000000000000000000000000000..ad8a49c35247eff97a59737c2aa472b88222e0e9 --- /dev/null +++ b/php/classes/controls/TimeField.php @@ -0,0 +1,96 @@ +format = EDIT_FORMAT_TIME; + $this->timeAttrs = $this->pageObject->pSetEdit->getFormatTimeAttrs( $this->field ); + } + + function buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + if( $this->container->pageType == PAGE_LIST ) + $value = prepare_for_db($this->field, $value, "time"); + + parent::buildControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + + echo 'inputStyle.' type="hidden" name="'.$this->ctype.'" value="time">'; + + + if( count( $this->timeAttrs ) ) + { + $type = $this->pageObject->mobileTemplateMode() ? "time" : "text"; + + $classString = 'class="form-control"'; + + $resultHtml = 'getPlaceholderAttr().' type="'.$type.'" '.$this->inputStyle.' name="'.$this->cfield.'" ' . $classString + .(($mode==MODE_INLINE_EDIT || $mode==MODE_INLINE_ADD) && $this->is508 == true ? 'alt="'.$this->strLabel.'" ' : '') + .'id="'.$this->cfield.'" '.$this->pageObject->pSetEdit->getEditParams($this->field); + + if( $this->timeAttrs["useTimePicker"] && !$this->pageObject->mobileTemplateMode() ) + { + $convention = $this->timeAttrs["hours"]; + $loc = getLacaleAmPmForTimePicker($convention, true); + $tpVal = getValForTimePicker($this->type, $value, $loc['locale']); + + $resultHtml .= ' value="'.runner_htmlspecialchars($tpVal['val']).'">'; + + $resultHtml .= ''; + } + else + $resultHtml .=' value="'.runner_htmlspecialchars( $this->getOutputValue( $value ) ).'">'; + + + if ( isRTL() ) + $resultHtml .= ""; // for bootstrap calend icon anomaly + + $resultHtml = '
inputStyle.' >' . $resultHtml . '
'; + echo $resultHtml; + } + + $this->buildControlEnd($validate, $mode); + } + + /** + * @param Mixed fieldValue + * @return String + */ + protected function getOutputValue( $fieldValue ) + { + if ( IsDateFieldType( $this->type ) ) + return str_format_time( db2time( $fieldValue ) ); + + $numbers = parsenumbers( $fieldValue ); + if( !$numbers ) + return ""; + + while( count( $numbers ) < 3 ) + { + $numbers[] = 0; + } + + if( count( $numbers ) == 6 ) + return str_format_time( array(0, 0, 0, $numbers[3], $numbers[4], $numbers[5]) ); + + if( !$this->pageObject->mobileTemplateMode() ) + return str_format_time( array(0, 0, 0, $numbers[0], $numbers[1], $numbers[2]) ); + + return format_datetime_custom( array(0, 0, 0, $numbers[0], $numbers[1], $numbers[2]), "HH:mm:ss" ); + } + + function getFirstElementId() + { + return $this->cfield; + } + + function addCSSFiles() { + $this->pageObject->AddCSSFile("include/bootstrap/css/bootstrap-datetimepicker.min.css"); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/UserControl.php b/php/classes/controls/UserControl.php new file mode 100644 index 0000000000000000000000000000000000000000..a8c7903f6b2612ff851a2502b35bef8a354b0f23 --- /dev/null +++ b/php/classes/controls/UserControl.php @@ -0,0 +1,40 @@ +buildUserControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data); + $this->buildControlEnd($validate, $mode); + } + + public function buildUserControl($value, $mode, $fieldNum, $validate, $additionalCtrlParams, $data) + { + } + + public function initUserControl() + { + } + + function getUserSearchOptions() + { + return array(); + } + + /** + * Form the control specified search options array and built the control's search options markup + * @param String selOpt The search option value + * @param Boolean not It indicates if the search option negation is set + * @param Boolean both It indicates if the control needs 'NOT'-options + * @return String A string containing options markup + */ + function getSearchOptions($selOpt, $not, $both) + { + return $this->buildSearchOptions($this->getUserSearchOptions(), $selOpt, $not, $both); + } + + function init() + { + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/ViewAudioFileField.php b/php/classes/controls/ViewAudioFileField.php new file mode 100644 index 0000000000000000000000000000000000000000..9246a8ffb96cc450fad1c67e37d0f51a757348ec --- /dev/null +++ b/php/classes/controls/ViewAudioFileField.php @@ -0,0 +1,92 @@ +container->pageType; + // print or export + if( !$html || $pageType == PAGE_EXPORT || $pageType == PAGE_PRINT || $this->container->forExport != '' ) { + $ret = $this->getTextValue( $data ); + return $html + ? runner_htmlspecialchars( $ret ) + : $ret; + } + + $fileUrls = $this->getFileURLs( $data, $keylink ); + + $controls = array(); + foreach( $fileUrls as $u ) { + $controls[] = ViewAudioFileField::makeAudioControl( $u ); + } + return implode( "", $controls ); + } + + /** + * @param Array urlData - element of array returned by getFileURLs + * @return String (HTML) + */ + public static function makeAudioControl( $urlData ) { + + $htmlTitle = runner_htmlspecialchars( $urlData["title"] ); + $htmlAltTitle = runner_htmlspecialchars( $urlData["altTitle"] ); + $htmlUrl = runner_htmlspecialchars( $urlData["url"] ); + + return '
' + .'
' . $htmlTitle . '
' + .'
'; + } + + + /** + * @return Array of array( + * "url" => link to the file + * "title" => audio label + * ) + */ + protected function getFileURLs( &$data, $keylink ) + { + $pSet = $this->pSettings(); + $fileData = $this->getFilesData( $data[ $this->field ] ); + $fieldIsUrl = $pSet->isVideoUrlField( $this->field ); + + $ret = array(); + foreach( $fileData as $file ) { + if( !$file["name"] ) { + continue; + } + if( !$fieldIsUrl ) { + if( !$this->fastFileExists( $file["name"] ) ) { + continue; + } + } + if( $fieldIsUrl ) { + $url = $file["name"]; + } else { + $url = projectURL() . $this->getFileUrl( $file, $keylink, false ); + } + $titleField = $pSet->getAudioTitleField( $this->field ); + if ( $titleField ) { + $title = $data[ $titleField ]; + $altTitle = $title; + } else { + $altTitle = $file["usrName"]; + $title = ""; + } + $ret[] = array( + "url" => $url, + "title" => $title, + "altTitle" => $altTitle + ); + } + return $ret; + } + + protected function isUrl() { + return $this->pSettings()->isVideoUrlField( $this->field ); + } + +} +?> \ No newline at end of file diff --git a/php/classes/controls/ViewCheckboxField.php b/php/classes/controls/ViewCheckboxField.php new file mode 100644 index 0000000000000000000000000000000000000000..b6a1965e6cb501628cbd51e5dd4cc79be593c63f --- /dev/null +++ b/php/classes/controls/ViewCheckboxField.php @@ -0,0 +1,55 @@ +getHostPageDbType() == nDATABASE_PostgreSQL ) + return $data[$this->field] === "t" || $data[$this->field] !== "f" && $data[$this->field] != 0 && $data[$this->field] != ""; + else + return $data[$this->field] != 0 && $data[$this->field] != ""; + } + + public function getPdfValue(&$data, $keylink = "") + { + $boolVal = $this->getTrueCondition($data) ? "true" : "false"; + return "{text: '', checkbox: " . $boolVal . "}"; + } + + public function showDBValue(&$data, $keylink, $html = true ) + { + $result = "getTrueCondition($data) ? "yes" : "no"; + + $result.= GetRootPathForResources($imgSrc.".gif")."\" border=0"; + if(isEnableSection508()) + $result .= " alt=\" \""; + $result .= ">"; + + return $result; + } + + /** + * Get the host page's db connection's type + * @return Number + */ + protected function getHostPageDbType() + { + global $cman; + return $cman->byTable( $this->container->tName )->dbType; + } + + /** + * Get the field's content that will be exported + * @prarm &Array data + * @prarm String keylink + * @return String + */ + public function getExportValue(&$data, $keylink = "", $html = false ) + { + return nl2br( $data[ $this->field ] ); + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/ViewControl.php b/php/classes/controls/ViewControl.php new file mode 100644 index 0000000000000000000000000000000000000000..9f13f40d36e7697961099e09b08e07245d43833c --- /dev/null +++ b/php/classes/controls/ViewControl.php @@ -0,0 +1,971 @@ +AddJSFile("include/mupload.js"); + } + + /** + * addCSSFiles + * Add control CSS files to page object + */ + public function addCSSFiles() + { + //example + // $this->AddCSSFile("include/mupload.css"); + } + + /** + * The container's AddCSSFile method wrapper + * @param {String} + */ + public function AddCSSFile($fileName) + { + $this->getContainer()->AddCSSFile($fileName); + } + + /** + * The container's AddJSFile method wrapper + * @param {String} + */ + public function AddJSFile($fileName, $req1="", $req2="", $req3="") + { + $this->getContainer()->AddJSFile($fileName, $req1, $req2, $req3); + } + + public function pSettings() { + return $this->getContainer()->pSet; + } + + public function getContainer() + { + if(!is_null($this->pageObject)) + return $this->pageObject; + else + return $this->container; + } + + public function __construct($field, $container, $pageObject = null) + { + $this->useUTF8 = "utf-8" == "utf-8"; + $this->field = $field; + $this->container = $container; + $this->pageObject = $pageObject; + $this->is508 = isEnableSection508(); + + $this->fieldType = $container->pSet->getFieldType($this->field); + $this->viewFormat = $container->pSet->getViewFormat($this->field); + $this->editFormat = $container->pSet->getEditFormat($this->field); + + if( $this->pageObject ) { + $this->searchClauseObj = $this->pageObject->searchClauseObj; + if ( $this->searchClauseObj ) + $this->searchHighlight = $container->searchHighlight && $this->searchClauseObj->searchStarted(); + } + } + + /** + * Get the field's content that will be exported + * @prarm &Array data + * @prarm String keylink + * @return String + */ + public function getExportValue(&$data, $keylink = "", $html = false ) + { + return $this->showDBValue($data, $keylink, $html ); + } + + + public function getPdfValue(&$data, $keylink = "") + { + return "'" . jsreplace( $this->showDBValue($data, $keylink, false) ) . "'"; + } + + /** + * Get the field's content + * @param &Array data + * @param String keylink + * @return String + */ + public function showDBValue(&$data, $keylink, $html = true ) + { + $value = $data[$this->field]; + + if(IsBinaryType($this->fieldType)) + { + $value = "LONG BINARY DATA - CANNOT BE DISPLAYED"; + $this->searchHighlight = false; + } + + if($value === false) + $value = ""; + + + if($this->editFormat == EDIT_FORMAT_CHECKBOX && $this->viewFormat == FORMAT_NONE) + { + if($value && $value!=0) + $value = "Yes"; + else + $value = "No"; + + $this->searchHighlight = false; + } + + if($this->container->forExport == "excel" || $this->container->forExport == "csv") + { + return $value; + } + + $processedText = $this->processText($value, $keylink, $html); + if( $html ) + return nl2br( $processedText ); + return $processedText; + } + + /** + * @param &Array data + * @return String + */ + public function getTextValue(&$data) + { + return $data[ $this->field ]; + } + + /** + * Format the text trunceting it or highlighting the search word within this text. + * @param String value The field's content + * @param String keylink + * @return String + */ + public function processText($value, $keylink, $html = true ) + { + $isMobileLookup = false; + $inlineOrFlyMode = false; + $pageType = $this->container->pageType; + if( !is_null($this->pageObject) ) + { + $mode = $this->pageObject->mode; + $isMobileLookup = ($mode == LIST_LOOKUP) && $this->pageObject->mobileTemplateMode(); + $inlineOrFlyMode = $pageType == PAGE_EDIT && ($mode == EDIT_INLINE || $mode == EDIT_POPUP) || $pageType == PAGE_ADD && ($mode == ADD_INLINE || $mode == ADD_POPUP); + } + $isDetailPreview = $this->container->isDetailsPreview; + + if( $pageType == PAGE_ADD || $pageType == PAGE_EDIT ) + $pageType = PAGE_VIEW; + + $isPagePrint = ($pageType == PAGE_RPRINT && $this->container->forExport) || $pageType == PAGE_PRINT || $pageType == PAGE_RPRINT; + + if( $this->editFormat == EDIT_FORMAT_LOOKUP_WIZARD ) + { + $this->isFieldLookup = true; + $this->needLookupValueProcessing = $this->checkIfLookupValueIsToProcess(); + $value = $this->processMultiselectLWValue($value); + } + + $cNumberOfChars = $this->container->pSet->getNumberOfChars($this->field); + $needShortening = $this->textNeedsTruncating($value, $cNumberOfChars); + + $isReportPage = $pageType == PAGE_REPORT || $pageType == PAGE_MASTER_INFO_REPORT; + $isListPage = $pageType == PAGE_LIST || $pageType == PAGE_MASTER_INFO_LIST; + + if( $html && $needShortening && ( $isListPage || $isReportPage || $inlineOrFlyMode ) && !$isMobileLookup && !$isDetailPreview && $keylink != "" ) + return $this->getShorteningTextAndMoreLink($value, $cNumberOfChars, $keylink, $mode); + + if( $needShortening && ($isPagePrint || $isMobileLookup || $isDetailPreview) ) + return $this->getShorteningText($value, $cNumberOfChars, $html); + + return $this->getText($value, $html ); + } + + + /** + * Check if the text needs truncating + * @param String value The field's content + * @param Number cNumberOfChars The number of chars from the 'value' string that will be visible after truncation + * @return Boolean + */ + protected function textNeedsTruncating($value, $cNumberOfChars) + { + return !$this->isUsedForFilter && !$this->container->fullText && $cNumberOfChars > 0 && runner_strlen($value) > $cNumberOfChars; + } + + /** + * The object's wrapper for GetShorteningForLargeText function + * @param String value The field's content + * @param Number cNumberOfChars The number of chars up to truncation + * @return String + */ + protected function getShorteningText($value, $cNumberOfChars, $html = true ) + { + $tail = "..."; + if( $html ) { + $tail = " ..."; + } + return GetShorteningForLargeText($value, $cNumberOfChars, $html ).$tail; + } + + /** + * Get the More link following the truncated and highlighted field's content + * @param String value The field's content + * @param Number cNumberOfChars The number of chars from the 'value' string that will be visible after truncation + * @param String keylink + * @param Boolean isLookup An indicator showing if this is a lookup list page control + * @return String + */ + protected function getShorteningTextAndMoreLink($value, $cNumberOfChars, $keylink, $mode) + { + $truncatedValue = GetShorteningForLargeText($value, $cNumberOfChars); + if( $this->searchHighlight ) + $truncatedValue = $this->highlightTruncatedBeforeMore($value, $truncatedValue, $cNumberOfChars, $cNumberOfChars); + + $tName = $this->getContainer()->tName; + $params = array(); + $params[] = 'pagetype='.$this->container->pSet->_viewPage; + $params[] = 'table='.GetTableURL($tName); + $params[] = 'field='.rawurlencode($this->field); + /* $keylink starts with & */ + $params[] = substr( $keylink, 1 ); + $params[] = 'page='.$this->container->pSet->pageName(); + + if ( $mode == LIST_DASHBOARD ) + $params[] = 'mode='.$mode; + + if ( $mode == LIST_LOOKUP ) + { + $params[] = 'maintable='.$this->pageObject->mainTable; + $params[] = 'mainfield='.$this->pageObject->mainField; + } + + $label = $this->container->pSet->label( $this->field ); + $dataField = 'data-fieldlabel="'.runner_htmlspecialchars( $label ).'"'; + + return $truncatedValue.' ' + ."More".' ...'; + } + + /** + * Get the encoded and highlighted text + * @param String value + * @return String + */ + protected function getText($value, $html = true ) + { + if( !$html ) { + return $value; + } + $value = runner_htmlspecialchars($value); + if( $this->searchHighlight ) + $value = $this->highlightSearchWord($value, true, ""); + + return $value; + } + + /** + * Check if the fiedl is the project or database table's + * multiselect lookup wizard with the same link and display field + */ + protected function checkIfLookupValueIsToProcess() + { + $pSet = $this->container->pSet; + + if( ($pSet->getLookupType($this->field) == LT_LOOKUPTABLE || $pSet->getLookupType($this->field) == LT_QUERY) && + $pSet->getLinkField($this->field) == $pSet->getDisplayField($this->field) && $pSet->multiSelect($this->field) ) + { + return true; + } + + return false; + } + + /** + * Remove excessive quotes for the multiselect lookup wizard field with + * the same display and link field + * @param string value + * @return string + */ + protected function processMultiselectLWValue($value) + { + if( !$this->needLookupValueProcessing ) + return $value; + + return implode(",", splitLookupValues($value)); + } + + /** + * Highlight the search word within the $value string + * @param String value The field's content + * @param Boolean encoded An indicator showing if the field's content is htmlspecialchars encoded + * @param String dbValue The database field's value + * @return string + */ + public function highlightSearchWord($value, $encoded, $dbValue = "") + { + if( $dbValue == "" ) + { + $dbValue = $value; + } + + $lookupParams = $this->getLookupParams(); + $highlightData = $this->searchClauseObj->getSearchHighlightingData($this->field, $dbValue, $encoded, $lookupParams); + if( !$highlightData ) + { + return $value; + } + return $this->getValueHighlighted($value, $highlightData); + } + + /** + * Highlight a search word for number-like fields + * @param String value + * @param Boolean encoded + * @param String dbValue + * @return string + */ + public function highlightSearchWordForNumber( $value, $encoded, $dbValue ) + { + $lookupParams = $this->getLookupParams(); + $highlightData = $this->searchClauseObj->getSearchHighlightingData( $this->field, $dbValue, $encoded, $lookupParams, true ); + if( $highlightData ) + return $this->getValueHighlighted( $value, $highlightData ); + + return $value; + } + + /** + * Form the the string with the search word highlighted + * @param String value The field's content + * @param Array highlightData + * @return string + */ + public function getValueHighlighted($value, $highlightData) + { + $searchOpt = $highlightData['searchOpt']; + $searchWordsPattern = $this->getSearchWordPattern($highlightData['searchWords'], false); + + switch($searchOpt) + { + case 'Equals': + return $this->addHighlightingSpan($value); + + case 'Starts with': + return preg_replace('/(^'.$searchWordsPattern.')/i', $this->addHighlightingSpan('$1'), $value); + + case 'Contains': + $pattern = '/('.$searchWordsPattern.')/i'; + + if( !$this->haveTheSameSpChReference($pattern, $value) ) + return preg_replace($pattern, $this->addHighlightingSpan('$1'), $value); + + return $this->highlightValueWithSpecialChars($value, $pattern); + + default: + return $value; + } + } + + /** + * search highliting for view as number, percent + * @param String value The field's content + * @param Array highlightData + * @return string + */ + public function getNumberValueHighlighted( $value, $highlightData ) { + $searchWordArr = array(); + $decimalPlaces = $this->container->pSet->isDecimalDigits( $this->field ); + $quantifier = $decimalPlaces <= 1 ? '?' : '{1,'.$decimalPlaces.'}'; + + foreach( $highlightData['searchWords'] as $searchWord ) { + $currSearchWord = $searchWord; + if( !preg_match( '/^[\d]+$/', $searchWord ) ) { + $currSearchWord = $this->formatSearchWord( $searchWord ); + $currSearchWord = preg_replace( '/0'.$quantifier.'$/', '', $currSearchWord ); + $currSearchWord = preg_replace( '/\.$/', '', $currSearchWord ); + } + + $searchWordArray = str_split( $currSearchWord ); + // chain of numbers an possible separators + $searchWordArr[] = implode('[^\d]?', $searchWordArray ); + } + + $searchWord = implode( '|', $searchWordArr ); + $searchOpt = $highlightData['searchOpt']; + + switch( $searchOpt ) { + case 'Equals': + return $this->addHighlightingSpan( $value ); + + case 'Starts with': + return preg_replace('/^('.$searchWord.')/', $this->addHighlightingSpan('$1'), $value); + + case 'Contains': + return preg_replace('/('.$searchWord.')/', $this->addHighlightingSpan('$1'), $value); + + default: + return $value; + } + } + + /** + * @param String searchWord + * return String + */ + protected function formatSearchWord( $searchWord ) { + return $searchWord; + } + + /** + * Check if the pattern string is contained in any special chars codes + * occuring in the value string. + * @param string pattern + * @param string value + * @return array + */ + protected function haveTheSameSpChReference($pattern, $value) + { + $scContainedPattern = $this->getSpecialCharsContainingPattern($pattern); + $scFromValue = $this->getSpecialCharsFromString($value); + foreach($scContainedPattern as $sc) + { + if( array_search($sc, $scFromValue) !== FALSE ) + return true; + } + return false; + } + + /** + * Get the array of special chars contained the pattern + * @param string pattern + * @return array + */ + protected function getSpecialCharsContainingPattern($pattern) + { + $chars = array('&', '"', '<', '>'); + $csArray = array(); + foreach($chars as $char) + { + if( preg_match($pattern, $char, $matches) ) + { + if( $matches[0] != $char ) + $csArray[] = $char; + } + } + return $csArray; + } + + /** + * Get the array of special chars extracted from the string passed + * @param string str + * @return array + */ + protected function getSpecialCharsFromString($str) + { + $chars = array('&', '"', '<', '>'); + $csArray = array(); + foreach($chars as $char) + { + if( strpos($str, $char) !== FALSE ) + $csArray[] = $char; + } + + return $csArray; + } + + /** + * Split the string into array that contains all the string's not overlaping + * fragments that are delimeter-substrings and all non-delimeter parts + * adjacent with delimiter-substrings. These fragments are indexed in the + * same order as they occur in the string. + * @param String pattern The regular expression setting delimeter strings + * @param String str The string that is split based on its delimiter-substrings occurrences + * @return Array + */ + protected function getSplitStringWithCapturedDelimiters($pattern, $str) + { + $resArray = array(); + + if( !strlen($str) ) + return $resArray ; + + if( !preg_match_all($pattern, $str, $matches) ) + { + $resArray[] = $str; + return $resArray; + } + + $delimiters = $matches[0]; + $strArray = preg_split($pattern, $str); + foreach($strArray as $key=>$item) + { + $resArray[] = $item; + if( isset( $delimiters[$key] ) ) + $resArray[] = $delimiters[$key]; + } + + return $resArray; + } + + /** + * Highlight the value escaping the special chars codes + * @param string pattern + * @param string value + * @return string + */ + protected function highlightValueWithSpecialChars($value, $pattern) + { + $chars = array('&', '"', '<', '>'); + foreach($chars as $char) + { + $valueArr = $this->getSplitStringWithCapturedDelimiters('/'.$char.'/', $value); + if( count($valueArr) == 1 || !preg_match($pattern, $char, $matches) ) + continue; + + $valueArr2 = array(); + + foreach($valueArr as $key=>$part) + { + if( $part != $char ) + $valueArr2[] = preg_replace($pattern, $this->addHighlightingSpan('$1'), $part); + else + $valueArr2[] = $char; + } + + $value = implode("",$valueArr2); + } + return $value; + } + + /** + * Check if the item string has HTML entities + * @param String item + * @return Boolean + */ + protected function hasHTMLEntities($item) + { + if( preg_match_all("/&[^&;]{3,7};/", $item, $matches) ) + { + foreach($matches[0] as $entity) + { + $data = getHTMLEntityData($entity); + if( $data['isHTMLEntity'] ) + return true; + } + } + return false; + } + + /** + * Highlight item string basing on the pattern value + * skipping the HTML entities + * @param String item + * @param String pattern + * @return String + */ + protected function highlightValueWithHTMLEntities($item, $pattern) + { + $valueArr = $this->getSplitStringWithCapturedDelimiters("/&[^&;]{3,7};/", $item); + $valueArr2 = array(); + foreach($valueArr as $subitem) + { + $data = getHTMLEntityData($subitem); + if( $data['isHTMLEntity'] ) + $valueArr2[] = $subitem; + else + $valueArr2[] = preg_replace($pattern, $this->addHighlightingSpan('$1'), $subitem); + } + return implode("",$valueArr2); + } + + /** + * Get the lookup params and settings to pass it + * to the searchClause object's getSearchHighlightingData method + * @return Array + */ + protected function getLookupParams() + { + $lookupParams = array(); + + if( $this->isFieldLookup ) + { + $pSet = $this->container->pSet; + $lookupParams["multiselect"] = $pSet->multiSelect($this->field); + $lookupParams["needLookupProcessing"] = $this->needLookupValueProcessing; + //linkFieldValue and originLinkValue params are set for looku fields with distinct Link and Displayed fields only + $lookupParams["linkFieldValue"] = $this->container->linkFieldValues[$this->field]; + //originLinkValue param is set for multiselet lookups only + $lookupParams["originLinkValue"] = $this->container->originlinkValues[$this->field]; + } + return $lookupParams; + } + + /** + * Get the first search word from the text truncating field's value + * @param Array searchWords + * @param String value The raw field's value + * @return String + */ + protected function getFirstSearchWordInLargeText($searchWords, $value) + { + $searchWordsPattern = $this->getSearchWordPattern($searchWords, false); + + if( preg_match('/'.$searchWordsPattern.'/i', $value, $matches) ) + return $matches[0]; + + return $searchWords[0]; + } + + /** + * Format the string before the "More ..." link and highlight a search word depending on the search option's value. + * @param String value The raw field's content + * @param String truncatedValue The truncated, htmlspecialchars encoded field's content + * @param Number cNumberOfChars + * @prarm Number contenLength The length of the truncated value + * @return string + */ + protected function highlightTruncatedBeforeMore($value, $truncatedValue, $cNumberOfChars, $contenLength) + { + $lookupParams = $this->getLookupParams(); + $highlightData = $this->searchClauseObj->getSearchHighlightingData($this->field, $value, false, $lookupParams); + if(!$highlightData) + { + return $truncatedValue; + } + + $searchWord = $this->getFirstSearchWordInLargeText($highlightData['searchWords'], $value); + $searchWordEncoded = runner_htmlspecialchars($searchWord); + $highlighting = $this->addHighlightingSpan($searchWordEncoded); + $searchOpt = $highlightData['searchOpt']; + + switch ($searchOpt) + { + case 'Equals': + return $this->addHighlightingSpan($truncatedValue); + + case 'Starts with': + if( strlen($searchWordEncoded) > strlen($truncatedValue) ) + return $this->addHighlightingSpan($truncatedValue); + + return preg_replace('/^'.preg_quote($searchWordEncoded,"/").'/i', $highlighting, $truncatedValue); + + case 'Contains': + $regExpModifier = $this->useUTF8 ? 'u' : ''; + + $firstPos = $this->getFistOccurencePosition($value, $searchWord, $searchWordEncoded); + $lastPos = $this->getLastOccurencePosition($value, $searchWord, $searchWordEncoded); + $searchWordEncodedLen = runner_strlen($searchWordEncoded); + $truncLen = runner_strlen($truncatedValue); + + $pattern = '/('.$this->getSearchWordPattern($highlightData['searchWords'], true).')/i'; + + if( $lastPos + $searchWordEncodedLen <= $truncLen || $firstPos + $searchWordEncodedLen <= $truncLen ) + { + if( !$this->haveTheSameSpChReference($pattern, $truncatedValue) ) + return preg_replace($pattern.$regExpModifier, $this->addHighlightingSpan('$1'), $truncatedValue); + + return $this->highlightValueWithSpecialChars($truncatedValue, $pattern.$regExpModifier); + } + + if( $firstPos > $truncLen ) + { + $newNumberOfChars = ceil($cNumberOfChars / 2); + $qNumberOfChars = ceil($cNumberOfChars / 4); + $firstPosDecoded = runner_strpos($value, $searchWord); + + $truncSubsr = runner_substr($value, 0, $cNumberOfChars); + $valueSubstr = runner_substr($value, $firstPosDecoded - $qNumberOfChars, $qNumberOfChars + runner_strlen($searchWord)); + $truncSubsr = runner_substr($truncSubsr, 0, $newNumberOfChars); + $valueSubstr = runner_htmlspecialchars($valueSubstr); + + $pattern = '/('.preg_quote($searchWordEncoded,"/").')/i'; + + if( !$this->haveTheSameSpChReference($pattern, $valueSubstr) ) + $valueSubstr = preg_replace($pattern.$regExpModifier, $highlighting, $valueSubstr); + else + $valueSubstr = $this->highlightValueWithSpecialChars($valueSubstr, $pattern.$regExpModifier); + + return runner_htmlspecialchars($truncSubsr)." <...> ".$valueSubstr;; + } + + return runner_substr($truncatedValue, 0, $firstPos).$highlighting; + + default: + return $truncatedValue; + } + } + + /** + * Get the first searchWord occurence in the encoded value string + * @param String value + * @param String searchWord + * @param String searchWordEncoded + * @return Number + */ + protected function getFistOccurencePosition($value, $searchWord, $searchWordEncoded) + { + $planeFirstPos = strpos($value, $searchWord); + $planeSubstr = substr($value, 0, $planeFirstPos); + $encodedPlaneSubstr = runner_htmlspecialchars($planeSubstr); + + return runner_strpos( runner_htmlspecialchars($value), $searchWordEncoded, runner_strlen($encodedPlaneSubstr) ); + } + + /** + * Get the last searchWord occurence in the encoded value string + * @param String value + * @param String searchWord + * @param String searchWordEncoded + * @return Number + */ + protected function getLastOccurencePosition($value, $searchWord, $searchWordEncoded) + { + $planeLastPos = strrpos($value, $searchWord); + $planeSubstr = substr($value, 0, $planeLastPos); + $encodedPlaneSubstr = runner_htmlspecialchars($planeSubstr); + + return runner_strrpos(runner_htmlspecialchars($value), $searchWordEncoded, runner_strlen($encodedPlaneSubstr)); + } + + /** + * Get common search words pattern + * @param Array searchWords + * @param Boolean encoded + * @return String + */ + protected function getSearchWordPattern($searchWords, $encoded = false) + { + $searchWordsPatterns = array(); + foreach($searchWords as $searchWord) + { + $wordPattern = preg_quote($searchWord, "/"); + if( $encoded ) + $wordPattern = runner_htmlspecialchars($wordPattern); + + $searchWordsPatterns[] = $wordPattern; + } + return implode('|', $searchWordsPatterns); + } + + /** + * Wrap the string value with a span element + * @param String str + * @return String + */ + public function addHighlightingSpan($str) + { + return ''.$str.''; + } + + public function & getJSControl() + { + if(!isset($this->getContainer()->viewControlsMap["controls"])) + $this->getContainer()->viewControlsMap["controls"] = array(); + + for($i = 0; $i < count($this->getContainer()->viewControlsMap["controls"]); $i++) + { + if($this->getContainer()->viewControlsMap["controls"][$i]["fieldName"] == $this->field) + return $this->getContainer()->viewControlsMap["controls"][$i]; + } + + $controlData = array("fieldName" => $this->field, "viewFormat" => $this->viewFormat); + $this->getContainer()->viewControlsMap["controls"][] = $controlData ; + return $controlData; + } + + /** + * addJSControlSetting + * Add setting for JS control to controls map + * @param {string} setting name + * @param {object} setting value + */ + public function addJSControlSetting($name, $value) + { + $JScontrol =& $this->getJSControl(); + $JScontrol[$name] = $value; + } + + /** + * Check for need to load the javascript files + * @return boolean + */ + public function neededLoadJSFiles() + { + switch ($this->getContainer()->pageType) + { + case PAGE_PRINT: + return false; + default: + return true; + } + } + + /** + * Returns true if it is user control + * @return boolean + */ + public function isUserControl() + { + return $this->userControl && $this->userControl === true; + } + + /** + * Returns css code for thumbnail size optionally wrapped into style="" attribute + */ + protected function getThumbnailSizeStyle($returnStyleAttr = true) + { + $width = $this->container->pSet->getThumbnailSize($this->field); + if(!$width) + return ""; + $style = 'max-width:'.$width.'px; max-height:'.$width.'px;'; + if( $returnStyleAttr ) + return ' style="'.$style.'"'; + return $style; + } + + /** + * Returns css code for image size optionally wrapped into style="" attribute + */ + protected function getImageSizeStyle($returnStyleAttr = true) + { + $imgWidth = $this->container->pSet->getImageWidth($this->field); + $imgHeight = $this->container->pSet->getImageHeight($this->field); + if(!$imgWidth && !$imgHeight) + return ""; + $style = ''; + if( $imgWidth ) + $style .= 'max-width:'.$imgWidth.'px;'; + if( $imgHeight ) + $style .= 'max-height:'.$imgHeight.'px;'; + if( $returnStyleAttr ) + return ' style="'.$style.'"'; + return $style; + } + + /** + * User API function + * @param Array data + * @param String field + * @param String table The datasource table name + */ + public static function Format($data, $field, $table ) + { + global $strTableName; + if(!$table) + $table = $strTableName; + $pSet = new ProjectSettings( $table ); + + include_once getabspath("classes/controls/ViewControlsContainer.php"); + $viewControls = new ViewControlsContainer( $pSet, PAGE_VIEW ); + + return $viewControls->getControl( $field )->getTextValue( $data ); + } +} + +class ViewControlTypes +{ + public $viewTypes = array(); + + function __construct() + { + $this->viewTypes[FORMAT_NONE] = ""; + $this->viewTypes[FORMAT_DATE_SHORT] = "ViewShortDateField"; + $this->viewTypes[FORMAT_DATE_LONG] = "ViewLongDateField"; + $this->viewTypes[FORMAT_DATE_TIME] = "ViewDatetimeField"; + $this->viewTypes[FORMAT_TIME] = "ViewTimeField"; + $this->viewTypes[FORMAT_CURRENCY] = "ViewCurrencyField"; + $this->viewTypes[FORMAT_PERCENT] = "ViewPercentField"; + $this->viewTypes[FORMAT_HYPERLINK] = "ViewHyperlinkField"; + $this->viewTypes[FORMAT_EMAILHYPERLINK] = "ViewEmailHyperlinkField"; + $this->viewTypes[FORMAT_DATABASE_IMAGE] = "ViewDatabaseImageField"; + $this->viewTypes[FORMAT_DATABASE_FILE] = "ViewDatabaseFileField"; + $this->viewTypes[FORMAT_FILE] = "ViewFileDownloadField"; + $this->viewTypes[FORMAT_FILE_IMAGE] = "ViewImageDownloadField"; + $this->viewTypes[FORMAT_PHONE_NUMBER] = "ViewPhoneNumberField"; + $this->viewTypes[FORMAT_NUMBER] = "ViewNumberField"; + $this->viewTypes[FORMAT_CHECKBOX] = "ViewCheckboxField"; + $this->viewTypes[FORMAT_MAP] = "ViewMapField"; + $this->viewTypes[FORMAT_AUDIO] = "ViewAudioFileField"; + $this->viewTypes[FORMAT_DATABASE_AUDIO] = "ViewDatabaseAudioField"; + $this->viewTypes[FORMAT_VIDEO] = "ViewVideoFileField"; + $this->viewTypes[FORMAT_DATABASE_VIDEO] = "ViewDatabaseVideoField"; + $this->viewTypes[FORMAT_CUSTOM] = "ViewCustomField"; + $this->viewTypes[FORMAT_LOOKUP_WIZARD] = "ViewLookupWizardField"; + $this->viewTypes[FORMAT_HTML] = "ViewHTMLField"; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/ViewControlsContainer.php b/php/classes/controls/ViewControlsContainer.php new file mode 100644 index 0000000000000000000000000000000000000000..b78090ba4b317c13036c0d7a66a39b25b0602c83 --- /dev/null +++ b/php/classes/controls/ViewControlsContainer.php @@ -0,0 +1,232 @@ +pSet = $pSet; + $this->pageType = $pageType; + $this->pageObject = $pageObject; + $this->tName = $pSet->getTableName(); + if($pageObject) + $this->pSet->setPageMode($pageObject->mode); + + $this->searchHighlight= $this->highlightSearchResults(); + } + + /** + * Check if search results need to be highlighted through the page's view controls + * @return Boolean + */ + protected function highlightSearchResults() + { + $curPageObject = $this->pageObject; + + if( is_null($curPageObject) || !$this->pSet->highlightSearchResults() || $this->pageType != PAGE_LIST) + return false; + + if( $curPageObject->mode != LIST_SIMPLE && $curPageObject->mode != LIST_AJAX && $curPageObject->mode != LIST_LOOKUP && $curPageObject->mode != LIST_DASHBOARD) + return false; + + return true; + } + + function setForExportVar($forExport) + { + $this->forExport = $forExport; + } + + /** + * Add js files for page + */ + function AddJSFile($file,$req1="",$req2="",$req3="") + { + $rootPath = GetRootPathForResources($file); + $this->includes_js[] = $rootPath; + if($req1!="") + { + $this->includes_jsreq[$rootPath] = array(GetRootPathForResources($req1)); + } + if($req2!="") + { + $this->includes_jsreq[$rootPath][] = GetRootPathForResources($req2); + } + if($req3!="") + { + $this->includes_jsreq[$rootPath][] = GetRootPathForResources($req3); + } + } + + /** + * Add css files for page + */ + function AddCSSFile($file) + { + $this->includes_css[] = $file; + } + + function addControlsJSAndCSS() + { + $fields = $this->pSet->getPageFields(); + for($i = 0; $i < count($fields); $i++) + { + $control = $this->getControl($fields[$i]); + + // admin pages + if( !$control ) { + continue; + } + + if ($control->neededLoadJSFiles()) + $control->addJSFiles(); + + $control->addCSSFiles(); + } + } + + /** + * Create new control (if needed) for view field, and return it + * @param {string} field name + * @param {string} predefined view format + */ + public function getControl($field, $format = null) + { + // if conrol does not created previously + if(!array_key_exists($field, $this->viewControls)) + { + include_once(getabspath("classes/controls/ViewControl.php")); + $vcTypes = new ViewControlTypes(); + $editFormat = $this->pSet->getEditFormat($field); + if(is_null($format)){ + $localPSet = $this->pSet; + $lookupPageType = ""; + if(!$this->isLocal) + { + $lookupPageType = $this->pSet->getPageTypeByFieldEditFormat($field, EDIT_FORMAT_LOOKUP_WIZARD); + if($lookupPageType != "") + $localPSet = new ProjectSettings($this->pSet->_table, $lookupPageType); + } + if(!$this->isLocal + && ($editFormat == EDIT_FORMAT_LOOKUP_WIZARD || $lookupPageType != "") + && ($localPSet->getLookupType($field) == LT_LOOKUPTABLE || $localPSet->getLookupType($field) == LT_QUERY) + && $localPSet->getLinkField($field) != $localPSet->getDisplayField($field)) + { + $viewFormat = FORMAT_LOOKUP_WIZARD; + }else + $viewFormat = $this->pSet->getViewFormat($field); + }else + $viewFormat = $format; + + $className = $vcTypes->viewTypes[$viewFormat]; + if($className == "" && $viewFormat != "") + { + $className = "View".$viewFormat; + $userControl = true; + include_once(getabspath("classes/controls/ViewUserControl.php")); + } + + if($className != "") + { + $this->viewControls[$field] = createViewControlClass($className, $field, $this, $this->pageObject); + } + else + $this->viewControls[$field] = new ViewControl($field, $this, $this->pageObject); + + if($userControl) + { + $this->viewControls[$field]->viewFormat = $className; + $this->viewControls[$field]->init(); + $this->viewControls[$field]->initUserControl(); + } + } + return $this->viewControls[$field]; + } + + /** + * showDBValue + * Wrapper for ViewControl creation and showDBValue call on it + * @param {string} field name + * @param {array} associative array with record data + * @param {string} string with record keys and values + */ + function showDBValue($field, &$data, $keylink = "", $value = "", $html = true) + { + $control = $this->getControl($field); + if($value != ""){ + $control->displayField = $value; + } + + return $control->showDBValue( $data, $keylink, $html ); + } + + /** + * Check availability user control in ViewControlsContaier + * @return boolean + */ + public function hasUserControls() + { + $arFields = $this->pSet->getPrinterFields(); + foreach ($arFields as $arField) + { + if ($this->getControl($arField)->isUserControl()) + return true; + } + return false; + } + function mobileTemplateMode() + { + return false; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/ViewCurrencyField.php b/php/classes/controls/ViewCurrencyField.php new file mode 100644 index 0000000000000000000000000000000000000000..ea89612dd018fcba8548d16fa7475a94d05ac73d --- /dev/null +++ b/php/classes/controls/ViewCurrencyField.php @@ -0,0 +1,70 @@ +field ] ); + + if( !$this->container->forExport || $this->container->forExport != "excel" && $this->container->forExport != "csv" ) + $result = runner_htmlspecialchars( $result ); + + if( $this->searchHighlight ) + $result = $this->highlightSearchWord( $result, false, $data[ $this->field ] ); + + return $result; + } + + /** + * Highlight the search word within the $value string + * @param String value The field's content + * @param Boolean encoded An indicator showing if the field's content is htmlspecialchars encoded + * @param String dbValue The database field's value + * @return string + */ + public function highlightSearchWord($value, $encoded, $dbValue = "") + { + return $this->highlightSearchWordForNumber( $value, $encoded, $dbValue ); + } + + /** + * @param &Array data + * @return String + */ + public function getTextValue(&$data) + { + return str_format_currency( $data[ $this->field ] ); + } + + public function getValueHighlighted($value, $highlightData) + { + $searchWordArr = array(); + foreach($highlightData['searchWords'] as $searchWord) + { + $word = preg_replace('/[\.,]/', '' , $searchWord); + $wordArr = str_split($word); + $word = implode("[^\d]{0,2}", $wordArr); //add thousands and decimals separators to the pattern + $word = runner_htmlspecialchars($word); + if($searchOpt == 'Starts with') + $word = "^".$word; + $searchWordArr[] = $word; + } + $pattern = '/('.implode('|', $searchWordArr).')/'; + $searchOpt = $highlightData['searchOpt']; + + switch($searchOpt) + { + case 'Equals': + return $this->addHighlightingSpan($value); + + case 'Starts with': + return preg_replace($pattern, $this->addHighlightingSpan('$1'), $value); + + case 'Contains': + return preg_replace($pattern, $this->addHighlightingSpan('$1'), $value); + + default: + return $value; + } + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/ViewCustomField.php b/php/classes/controls/ViewCustomField.php new file mode 100644 index 0000000000000000000000000000000000000000..c0a3cc408c1b717977e1d8095675a2334401ef90 --- /dev/null +++ b/php/classes/controls/ViewCustomField.php @@ -0,0 +1,112 @@ +field ]; + if( !is_null( $this->displayField ) ) + { + $fieldData = $this->displayField; + } + + $pageType = $this->container->pSet->getViewPageType(); + /* + if( $this->pageObject ) + { + if( $this->pageObject->mode == EDIT_INLINE && $this->pageObject->pageType != PAGE_VIEW ) + { + $pageType = PAGE_LIST; + } + } + */ + + $result = CustomExpression( $fieldData, $data, $this->field, $pageType, $this->container->tName ); + + if( $this->searchHighlight ) + { + $result = $this->highlightSearchWord( $result, false, "" ); + } + + return $result; + } + + public function getPdfValue(&$data, $keylink = "") + { + return my_json_encode( array( + "text" => $this->showDBValue($data, $keylink), + "isHtml" => true + ) ); + } + + public function getValueHighlighted($value, $highlightData) + { + $searchOpt = $highlightData['searchOpt']; + if($searchOpt == 'Equals') + return $this->addHighlightingSpan($value); + + $flags = $this->useUTF8 ? "iu" : "i"; + $prefix = ($searchOpt == 'Starts with') ? "^" : ""; + //ungreedy tag pattern + $tagPattern = "/(<[^=>]+\s*(?:(?:[^=>]+=\s*'[^']+'\s*)|".'(?:[^=>]+=\s*"[^"]+"\s*)'.")*>)/iU"; + + foreach($highlightData['searchWords'] as $searchWord) + { + $searchWordParts = preg_split($tagPattern, $searchWord); + + if(count($searchWordParts) == 1) + { + $res = ""; + $replaced = false; + //remove tag fragments + $newSearchWord = preg_replace("/^.*>|<.*$/U", '', $searchWord); + $pattern = '/'.$prefix.'('.preg_quote($newSearchWord,"/").')/'.$flags; + + //the search word doesn't contain any tags + $valueArr = $this->getSplitStringWithCapturedDelimiters($tagPattern, $value); + foreach($valueArr as $item) + { + if( !strlen($item) ) + continue; + //the tag inside a tag's attribute was matched + if( $item[0] == "<" || $item[ strlen($item) - 1 ] == ">" || $replaced ) + { + $res.= $item; + continue; + } + + if( !$this->hasHTMLEntities($item) ) + $replacedItem = preg_replace($pattern, $this->addHighlightingSpan('$1'), $item); + else + $replacedItem = $this->highlightValueWithHTMLEntities($item, $pattern); + + if( $searchOpt == 'Starts with' && $item != $replacedItem ) + $replaced = true; + + $res.= $replacedItem; + } + $value = $res; + continue; + } + + //the search word contains tags + foreach($searchWordParts as $item) + { + if( trim($item) ) + { + if($item[0] != '<' && $item[ strlen($item) - 1 ] != '>' ) + { + //remove tag fragments + $newItem = preg_replace("/^.*>|<.*$/", '', $item); + $itemPattern = preg_quote($newItem, "/"); + $pattern = '/(>[^>]*)('.$itemPattern.')([^<]*<)|^([^<>]*)('.$itemPattern.')(<)|(>)('.$itemPattern.')([^<>]*$)/U'; + //$patterns = array('/(>[^>]*)('.$itemPattern.')([^<]*<)/U' , '/^([^<>]*)('.$itemPattern.')(<)/', '/(>)('.$itemPattern.')([^<>]*$)/'); + $value = preg_replace($pattern, "$1".$this->addHighlightingSpan("$2")."$3", $value); + } + } + } + } + + return $value; + } +} +?> \ No newline at end of file diff --git a/php/classes/controls/ViewDatabaseAudioField.php b/php/classes/controls/ViewDatabaseAudioField.php new file mode 100644 index 0000000000000000000000000000000000000000..742d412322049ac3a23fc77d7f815eaa2b66a4e8 --- /dev/null +++ b/php/classes/controls/ViewDatabaseAudioField.php @@ -0,0 +1,67 @@ +field ] ) ) + return ""; + + $titleField = $this->container->pSet->getAudioTitleField( $this->field ); + if( $titleField && $data[ $titleField ] ) + return $data[ $titleField ]; + + return "<