From 8210c3fdc7460eb60892d8b2324b4ec05f661767 Mon Sep 17 00:00:00 2001 From: Paolo Date: Wed, 25 Sep 2019 17:15:46 +0200 Subject: [PATCH] Derived TableWidget from FilterWidget, added: - libraries/TableWidgetLib - widgets/TableWidget - controllers/widgets/Tables - public/js/TableWidget.js --- application/controllers/widgets/Tables.php | 105 ++++ application/libraries/TableWidgetLib.php | 204 +++++++ application/views/templates/FHC-Header.php | 7 + application/widgets/TableWidget.php | 414 +++++++++++++++ public/js/TableWidget.js | 587 +++++++++++++++++++++ 5 files changed, 1317 insertions(+) create mode 100644 application/controllers/widgets/Tables.php create mode 100644 application/libraries/TableWidgetLib.php create mode 100644 application/widgets/TableWidget.php create mode 100644 public/js/TableWidget.js diff --git a/application/controllers/widgets/Tables.php b/application/controllers/widgets/Tables.php new file mode 100644 index 000000000..21161ff9f --- /dev/null +++ b/application/controllers/widgets/Tables.php @@ -0,0 +1,105 @@ +load->library('AuthLib'); + + // Loads the tablewidgetlib with HTTP GET/POST parameters + $this->_loadTableWidgetLib(); + + // Checks if the caller is allow to read this data + $this->_isAllowed(); + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Retrieves data about the current filter from the session and will be written on the output in JSON format + */ + public function getTable() + { + $this->outputJsonSuccess($this->tablewidgetlib->getSession()); + } + + /** + * Retrieves the number of records present in the current dataset and will be written on the output in JSON format + */ + public function rowNumber() + { + $rowNumber = 0; + $dataset = $this->tablewidgetlib->getSessionElement(TableWidgetLib::SESSION_DATASET); + + if (isset($dataset) && is_array($dataset)) + { + $rowNumber = count($dataset); + } + + $this->outputJsonSuccess($rowNumber); + } + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Checks if the user is allowed to use this filter + */ + private function _isAllowed() + { + if (!$this->tablewidgetlib->isAllowed()) + { + $this->terminateWithJsonError('You are not allowed to access to this content'); + } + } + + /** + * Loads the tablewidgetlib with the TABLE_UNIQUE_ID parameter + * If the parameter TABLE_UNIQUE_ID is not given then the execution of the controller is terminated and + * an error message is printed + */ + private function _loadTableWidgetLib() + { + // If the parameter TABLE_UNIQUE_ID is present in the HTTP GET or POST + if (isset($_GET[self::TABLE_UNIQUE_ID]) || isset($_POST[self::TABLE_UNIQUE_ID])) + { + // If it is present in the HTTP GET + if (isset($_GET[self::TABLE_UNIQUE_ID])) + { + $tableUniqueId = $this->input->get(self::TABLE_UNIQUE_ID); // is retrieved from the HTTP GET + } + elseif (isset($_POST[self::TABLE_UNIQUE_ID])) // Else if it is present in the HTTP POST + { + $tableUniqueId = $this->input->post(self::TABLE_UNIQUE_ID); // is retrieved from the HTTP POST + } + + // Loads the tablewidgetlib that contains all the used logic + $this->load->library('TableWidgetLib'); + + $this->tablewidgetlib->setTableUniqueId($tableUniqueId); + } + else // Otherwise an error will be written in the output + { + $this->terminateWithJsonError('Parameter "'.self::TABLE_UNIQUE_ID.'" not provided!'); + } + } +} diff --git a/application/libraries/TableWidgetLib.php b/application/libraries/TableWidgetLib.php new file mode 100644 index 000000000..e97e0d754 --- /dev/null +++ b/application/libraries/TableWidgetLib.php @@ -0,0 +1,204 @@ +_ci =& get_instance(); // get code igniter instance + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Checks if at least one of the permissions given as parameter (requiredPermissions) belongs + * to the authenticated user, if confirmed then is allowed to use this FilterWidget. + * If the parameter requiredPermissions is NOT given or is not present in the session, + * then NO one is allow to use this FilterWidget + * Wrapper method to permissionlib->hasAtLeastOne + */ + public function isAllowed($requiredPermissions = null) + { + $this->_ci->load->library('PermissionLib'); // Load permission library + + // Gets the required permissions from the session if they are not provided as parameter + $rq = $requiredPermissions; + if ($rq == null) $rq = $this->getSessionElement(self::REQUIRED_PERMISSIONS_PARAMETER); + + return $this->_ci->permissionlib->hasAtLeastOne($rq, self::PERMISSION_TABLE_METHOD, self::PERMISSION_TYPE); + } + + /** + * Wrapper method to the session helper funtions to retrieve the whole session for this filter + */ + public function getSession() + { + return getSessionElement(self::SESSION_NAME, $this->_tableUniqueId); + } + + /** + * Wrapper method to the session helper funtions to retrieve one element from the session of this filter + */ + public function getSessionElement($name) + { + $session = getSessionElement(self::SESSION_NAME, $this->_tableUniqueId); + + if (isset($session[$name])) + { + return $session[$name]; + } + + return null; + } + + /** + * Wrapper method to the session helper funtions to set the whole session for this filter + */ + public function setSession($data) + { + $data[TableWidgetLib::TABLE_UNIQUE_ID] = $this->_tableUniqueId; // the unique id of this table widget + + setSessionElement(self::SESSION_NAME, $this->_tableUniqueId, $data); + } + + /** + * Wrapper method to the session helper funtions to set one element in the session for this filter + */ + public function setSessionElement($name, $value) + { + $session = getSessionElement(self::SESSION_NAME, $this->_tableUniqueId); + + $session[$name] = $value; + + setSessionElement(self::SESSION_NAME, $this->_tableUniqueId, $session); // stores the single value + } + + /** + * Generate the query to retrieve the dataset for a filter + */ + public function generateDatasetQuery($query) + { + return 'SELECT * FROM ('.$query.') '.self::DATASET_TABLE_ALIAS; + } + + /** + * Retrieves the dataset from the DB + */ + public function getDataset($datasetQuery) + { + $dataset = null; + + if ($datasetQuery != null) + { + $this->_ci->load->model('system/Filters_model', 'FiltersModel'); + + // Execute the given SQL statement suppressing error messages + $dataset = @$this->_ci->FiltersModel->execReadOnlyQuery($datasetQuery); + } + + return $dataset; + } + + /** + * Retrieves metadata from the last executed query + */ + public function getExecutedQueryMetaData() + { + return $this->_ci->FiltersModel->getExecutedQueryMetaData(); + } + + /** + * Retrieves the list of fields from the last executed query + */ + public function getExecutedQueryListFields() + { + return $this->_ci->FiltersModel->getExecutedQueryListFields(); + } + + /** + * Return an unique string that identify this filter widget + * NOTE: The default value is the URI where the FilterWidget is called + * If the fhc_controller_id is present then is also used + */ + public function setTableUniqueIdByParams($params) + { + if ($params != null + && is_array($params) + && isset($params[self::TABLE_UNIQUE_ID]) + && !isEmptyString($params[self::TABLE_UNIQUE_ID])) + { + $this->setTableUniqueId($params[self::TABLE_UNIQUE_ID]); + } + } + + /** + * Set the _tableUniqueId property + */ + public function setTableUniqueId($filterUniqueId) + { + $this->_tableUniqueId = $filterUniqueId; + } +} diff --git a/application/views/templates/FHC-Header.php b/application/views/templates/FHC-Header.php index ec04ffa53..1058fa32c 100644 --- a/application/views/templates/FHC-Header.php +++ b/application/views/templates/FHC-Header.php @@ -30,6 +30,7 @@ $pivotui = isset($pivotui) ? $pivotui : false; $sbadmintemplate = isset($sbadmintemplate) ? $sbadmintemplate : false; $tablesorter = isset($tablesorter) ? $tablesorter : false; + $tablewidget = isset($tablewidget) ? $tablewidget : false; $tabulator = isset($tabulator) ? $tabulator : false; $tinymce = isset($tinymce) ? $tinymce : false; ?> @@ -103,6 +104,9 @@ // NavigationWidget CSS if ($navigationwidget === true) generateCSSsInclude('public/css/NavigationWidget.css'); + // TableWidget CSS + if ($tablewidget === true) generateCSSsInclude('public/css/TableWidget.css'); + // Eventually required CSS generateCSSsInclude($customCSSs); // Eventually required CSS @@ -203,6 +207,9 @@ // PhrasesLib JS if ($phrases != null) generateJSsInclude('public/js/PhrasesLib.js'); + // TableWidget JS + if ($tablewidget === true) generateJSsInclude('public/js/TableWidget.js'); + // Load addon hooks JS // NOTE: keep it as the latest but one if ($addons === true) generateAddonsJSsInclude($calledPath.'/'.$calledMethod); diff --git a/application/widgets/TableWidget.php b/application/widgets/TableWidget.php new file mode 100644 index 000000000..396ca3bb3 --- /dev/null +++ b/application/widgets/TableWidget.php @@ -0,0 +1,414 @@ +load->library('TableWidgetLib'); // Loads the TableWidgetLib that contains all the used logic + + $this->_initTableWidget($args); // checks parameters and initialize properties + + $this->tablewidgetlib->setTableUniqueIdByParams($args); + + // Let's start if it's allowed + // NOTE: If it is NOT allowed then no data are loaded + if ($this->tablewidgetlib->isAllowed($this->_requiredPermissions)) + { + $this->_startTableWidget(); + } + } + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * Called when echoing the table widget call + */ + public function display($widgetData) + { + $this->view(self::WIDGET_URL_TABLE, array( + 'tableUniqueId' => $widgetData[TableWidgetLib::TABLE_UNIQUE_ID] + )); // GUI starts here + } + + //------------------------------------------------------------------------------------------------------------------ + // Public static methods used to load views and to access statically to some properies of the TableWidget + + /** + * Loads the view related to the dataset, here is decided how to represent the dataset (ex: tablesorter, pivotUI, ...) + */ + public static function loadViewDataset() + { + if (self::$_TableWidgetInstance->_datasetRepresentation == TableWidgetLib::DATASET_REP_TABLESORTER) + { + self::_loadView(self::WIDGET_URL_DATASET_TABLESORTER); + } + + if (self::$_TableWidgetInstance->_datasetRepresentation == TableWidgetLib::DATASET_REP_PIVOTUI) + { + self::_loadView(self::WIDGET_URL_DATASET_PIVOTUI); + } + + if (self::$_TableWidgetInstance->_datasetRepresentation == TableWidgetLib::DATASET_REP_TABULATOR) + { + self::_loadView(self::WIDGET_URL_DATASET_TABULATOR); + } + } + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Checks parameters and initialize all the properties of this TableWidget + */ + private function _initTableWidget($args) + { + $this->_checkParameters($args); + + // If here then everything is ok + + // Initialize class properties + $this->_requiredPermissions = null; + $this->_reloadDataset = null; + $this->_query = null; + $this->_additionalColumns = null; + $this->_columnsAliases = null; + $this->_formatRow = null; + $this->_markRow = null; + $this->_checkboxes = null; + $this->_datasetRepresentation = null; + $this->_datasetRepresentationOptions = null; + $this->_datasetRepFieldsDefs = null; + + // Retrieved the required permissions parameter if present + if (isset($args[TableWidgetLib::REQUIRED_PERMISSIONS_PARAMETER])) + { + $this->_requiredPermissions = $args[TableWidgetLib::REQUIRED_PERMISSIONS_PARAMETER]; + } + + // How to retrieve data for the table: SQL statement or a result from DB + if (isset($args[TableWidgetLib::QUERY_PARAMETER])) + { + $this->_query = $args[TableWidgetLib::QUERY_PARAMETER]; + } + + if (isset($args[TableWidgetLib::DATASET_RELOAD_PARAMETER])) + { + $this->_reloadDataset = $args[TableWidgetLib::DATASET_RELOAD_PARAMETER]; + } + + // Parameter is used to add extra columns to the dataset + if (isset($args[TableWidgetLib::ADDITIONAL_COLUMNS]) + && is_array($args[TableWidgetLib::ADDITIONAL_COLUMNS]) + && count($args[TableWidgetLib::ADDITIONAL_COLUMNS]) > 0) + { + $this->_additionalColumns = $args[TableWidgetLib::ADDITIONAL_COLUMNS]; + } + + // Parameter is used to add use aliases for the columns fo the dataset + if (isset($args[TableWidgetLib::COLUMNS_ALIASES]) + && is_array($args[TableWidgetLib::COLUMNS_ALIASES]) + && count($args[TableWidgetLib::COLUMNS_ALIASES]) > 0) + { + $this->_columnsAliases = $args[TableWidgetLib::COLUMNS_ALIASES]; + } + + // Parameter that contains a function to format the rows of the dataset + if (isset($args[TableWidgetLib::FORMAT_ROW]) && is_callable($args[TableWidgetLib::FORMAT_ROW])) + { + $this->_formatRow = $args[TableWidgetLib::FORMAT_ROW]; + } + + // Parameter that contains a function to mark in the GUI the rows of the dataset + if (isset($args[TableWidgetLib::MARK_ROW]) && is_callable($args[TableWidgetLib::MARK_ROW])) + { + $this->_markRow = $args[TableWidgetLib::MARK_ROW]; + } + + // Parameter used to specify the column of the dataset that will be used + // as id of the checkboxes column in the GUI + if (isset($args[TableWidgetLib::CHECKBOXES])) + { + $this->_checkboxes = $args[TableWidgetLib::CHECKBOXES]; + } + + // To specify how to represent the dataset (ex: tablesorter, pivotUI, ...) + if (isset($args[TableWidgetLib::DATASET_REPRESENTATION]) + && ($args[TableWidgetLib::DATASET_REPRESENTATION] == TableWidgetLib::DATASET_REP_TABLESORTER + || $args[TableWidgetLib::DATASET_REPRESENTATION] == TableWidgetLib::DATASET_REP_PIVOTUI + || $args[TableWidgetLib::DATASET_REPRESENTATION] == TableWidgetLib::DATASET_REP_TABULATOR)) + { + $this->_datasetRepresentation = $args[TableWidgetLib::DATASET_REPRESENTATION]; + } + + // To specify options for the dataset representation (ex: tablesorter, pivotUI, ...) + if (isset($args[TableWidgetLib::DATASET_REP_OPTIONS]) && !isEmptyString($args[TableWidgetLib::DATASET_REP_OPTIONS])) + { + $this->_datasetRepresentationOptions = $args[TableWidgetLib::DATASET_REP_OPTIONS]; + } + + // To specify how to represent each record field + if (isset($args[TableWidgetLib::DATASET_REP_FIELDS_DEFS]) && !isEmptyString($args[TableWidgetLib::DATASET_REP_FIELDS_DEFS])) + { + $this->_datasetRepFieldsDefs = $args[TableWidgetLib::DATASET_REP_FIELDS_DEFS]; + } + } + + /** + * Checks the required parameters used to call this TableWidget + */ + private function _checkParameters($args) + { + if (!is_array($args) || (is_array($args) && count($args) == 0)) + { + show_error('Second parameter of the widget call must be a NOT empty associative array'); + } + else + { + if (!isset($args[TableWidgetLib::TABLE_UNIQUE_ID])) + { + show_error('The parameter "'.TableWidgetLib::TABLE_UNIQUE_ID.'" must be specified'); + } + + if (!isset($args[TableWidgetLib::QUERY_PARAMETER])) + { + show_error('The parameters "'.TableWidgetLib::QUERY_PARAMETER.'" must be specified'); + } + + if (!isset($args[TableWidgetLib::DATASET_REPRESENTATION])) + { + show_error('The parameter "'.TableWidgetLib::DATASET_REPRESENTATION.'" must be specified'); + } + + if (isset($args[TableWidgetLib::DATASET_REPRESENTATION]) + && $args[TableWidgetLib::DATASET_REPRESENTATION] != TableWidgetLib::DATASET_REP_TABLESORTER + && $args[TableWidgetLib::DATASET_REPRESENTATION] != TableWidgetLib::DATASET_REP_PIVOTUI + && $args[TableWidgetLib::DATASET_REPRESENTATION] != TableWidgetLib::DATASET_REP_TABULATOR) + { + show_error( + 'The parameter "'.TableWidgetLib::DATASET_REPRESENTATION. + '" must be IN ("' + .TableWidgetLib::DATASET_REP_TABLESORTER.'", "' + .TableWidgetLib::DATASET_REP_PIVOTUI.'", "' + .TableWidgetLib::DATASET_REP_TABULATOR.'")' + ); + } + } + } + + /** + * Contains all the logic used to load all the data needed to the TableWidget + */ + private function _startTableWidget() + { + // Read the all session for this table widget + $session = $this->tablewidgetlib->getSession(); + + // If session is NOT empty -> a table was already loaded + if ($session != null) + { + // Get SESSION_RELOAD_DATASET from the session + $sessionReloadDataset = $this->tablewidgetlib->getSessionElement(TableWidgetLib::SESSION_RELOAD_DATASET); + + // if Filter changed or reload is forced by parameter then reload the Dataset + if ($this->_reloadDataset === true || $sessionReloadDataset === true) + { + // Set as false to stop changing the dataset + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_RELOAD_DATASET, false); + + // Generate dataset query using tables from the session + $datasetQuery = $this->tablewidgetlib->generateDatasetQuery($this->_query); + + // Then retrieve dataset from DB + $dataset = $this->tablewidgetlib->getDataset($datasetQuery); + + // Save changes into session if data are valid + if (!isError($dataset)) + { + $this->_formatDataset($dataset); // marks rows using markRow and format rowns using formatRow + + // Set the new dataset and its attributes in the session + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_METADATA, $this->tablewidgetlib->getExecutedQueryMetaData()); + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_ROW_NUMBER, count($dataset->retval)); + $this->tablewidgetlib->setSessionElement(TableWidgetLib::SESSION_DATASET, $dataset->retval); + } + } + } + + // If the session is empty -> first time that this table is loaded + if ($session == null) + { + // Generate dataset query + $datasetQuery = $this->tablewidgetlib->generateDatasetQuery($this->_query); + + // Then retrieve dataset from DB + $dataset = $this->tablewidgetlib->getDataset($datasetQuery); + + // Save changes into session if data are valid + if (!isError($dataset)) + { + $this->_formatDataset($dataset); // marks rows using markRow and format rowns using formatRow + + // Stores an array that contains all the data useful for + $this->tablewidgetlib->setSession( + array( + TableWidgetLib::SESSION_FIELDS => $this->tablewidgetlib->getExecutedQueryListFields(), // all the fields of the dataset + TableWidgetLib::SESSION_COLUMNS_ALIASES => $this->_columnsAliases, // all the fields aliases + TableWidgetLib::SESSION_ADDITIONAL_COLUMNS => $this->_additionalColumns, // additional columns + TableWidgetLib::SESSION_CHECKBOXES => $this->_checkboxes, // the name of the field used to build the checkboxes column + TableWidgetLib::SESSION_METADATA => $this->tablewidgetlib->getExecutedQueryMetaData(), // the metadata of the dataset + TableWidgetLib::SESSION_ROW_NUMBER => count($dataset->retval), // the number of loaded rows by this table + TableWidgetLib::SESSION_DATASET => $dataset->retval, // the entire dataset + TableWidgetLib::SESSION_RELOAD_DATASET => false, // if the dataset must be reloaded, not needed the first time + TableWidgetLib::SESSION_DATASET_REPRESENTATION => $this->_datasetRepresentation, // the choosen dataset representation + TableWidgetLib::SESSION_DATASET_REP_OPTIONS => $this->_datasetRepresentationOptions, // the choosen dataset representation options + TableWidgetLib::SESSION_DATASET_REP_FIELDS_DEFS => $this->_datasetRepFieldsDefs // the choosen dataset representation record fields definition + ) + ); + } + } + + // To be always stored in the session, otherwise is not possible to load data from Filters controller + // NOTE: must the latest operation to be performed in the session to be shure that is always present + $this->tablewidgetlib->setSessionElement(TableWidgetLib::REQUIRED_PERMISSIONS_PARAMETER, $this->_requiredPermissions); + } + + /** + * Calls the method _markRow and _formatRow to marks rows using markRow and format rowns using formatRow + * NOTE: this method operates directly on the retrieved dataset: parameter passed by reference + */ + private function _formatDataset(&$rawDataset) + { + if (hasData($rawDataset) && is_array($rawDataset->retval)) + { + // For each row of the data set + for ($rowCounter = 0; $rowCounter < count($rawDataset->retval); $rowCounter++) + { + // Calls the methods to mark and to format a row + // NOTE: keep this order! the markRow function given as parameter is supposing to work + // on a raw dataset, NOT on a formatted one + $rawDataset->retval[$rowCounter]->MARK_ROW_CLASS = $this->_markRow($rawDataset->retval[$rowCounter]); + $this->_formatRow($rawDataset->retval[$rowCounter]); + } + } + } + + /** + * Formats the columns of all the rows of the entire dataset + * - converts booleans into strings "true" and "false" + * - format dates using the format string defined in DEFAULT_DATE_FORMAT + * Calls the parameter formatRow if it was given and if it is a valid funtion + * NOTE: this method operates directly on the retrieved dataset: parameter passed by reference + */ + private function _formatRow(&$rawDatasetRow) + { + // For each column of the row + foreach ($rawDatasetRow as $columnName => $columnValue) + { + // Basic conversions + if (is_bool($columnValue)) + { + $rawDatasetRow->{$columnName} = ($columnValue === true ? 'true' : 'false'); + } + elseif (DateTime::createFromFormat('Y-m-d H:i:s', $columnValue) !== false) + { + $rawDatasetRow->{$columnName} = date(self::DEFAULT_DATE_FORMAT, strtotime($columnValue)); + } + } + + // If a valid function call the given formatRow + if ($this->_formatRow != null && is_callable($this->_formatRow)) + { + $formatRowFunction = $this->_formatRow; + $rawDatasetRow = $formatRowFunction($rawDatasetRow); + } + } + + /** + * Returns a string that contains a class name used to mark rows in the dataset table + * Calls the parameter markRow if it was given and if it is a valid funtion + */ + private function _markRow($rawDatasetRow) + { + // If a valid function call the given markRow + if ($this->_markRow != null && is_callable($this->_markRow)) + { + $markRowFunction = $this->_markRow; + $class = $markRowFunction($rawDatasetRow); + } + + return !isset($class) ? '' : $class; + } + + /** + * Utility method that retrieves the name of the columns present in a table JSON definition + */ + private function _getColumnsNames($columns) + { + $columnsNames = array(); + + foreach ($columns as $key => $obj) + { + if (isset($obj->name)) + { + $columnsNames[] = $obj->name; + } + } + + return $columnsNames; + } + + /** + * Loads a view using the given viewName and eventually other parameters + */ + private static function _loadView($viewName, $parameters = null) + { + $ci =& get_instance(); + $ci->load->view($viewName, $parameters); + } +} diff --git a/public/js/TableWidget.js b/public/js/TableWidget.js new file mode 100644 index 000000000..44e66cabd --- /dev/null +++ b/public/js/TableWidget.js @@ -0,0 +1,587 @@ +/** + * TableWidget JS magic + */ + +//-------------------------------------------------------------------------------------------------------------------- +// Constants + +// +const DATASET_REP_TABLESORTER = "tablesorter"; +const DATASET_REP_PIVOTUI = "pivotUI"; +const DATASET_REP_TABULATOR = "tabulator"; + +/** + * FHC_TableWidget this object is used to render the GUI of a table widget and to operate with it + */ +var FHC_TableWidget = { + + //------------------------------------------------------------------------------------------------------------------ + // Properties + + _datasetRepresentation: null, // contains the current data representation + + //------------------------------------------------------------------------------------------------------------------ + // Public methods + + /** + * To display the TableWidget using the loaded data prenset in the session + */ + display: function() { + + FHC_TableWidget._getTables(FHC_TableWidget._renderTableWidget); + }, + + /** + * Alias call to method display only to inprove the readability of the code + */ + refresh: function() { + + FHC_TableWidget.display(); + }, + + //------------------------------------------------------------------------------------------------------------------ + // Private methods + + /** + * Utility method that checks if data contains an error and print that to the console + * otherwise the TableWidget GUI is refreshed + */ + _failOrRefresh: function(data, textStatus, jqXHR) { + + if (FHC_AjaxClient.isError(data)) + { + console.log(FHC_AjaxClient.getError(data)); + } + else + { + FHC_TableWidget.refresh(); + } + }, + + /** + * Utility method that checks if data contains an error and print that to the console + * otherwise the page is reloaded + */ + _failOrReload: function(data, textStatus, jqXHR) { + + if (FHC_AjaxClient.isError(data)) + { + console.log(FHC_AjaxClient.getError(data)); + } + else + { + location.reload(); + } + }, + + /** + * To reset the Table Widget GUI + */ + _resetGUI: function(tableWidgetDiv) { + + // If the choosen dataset representation is tablesorter + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").html(""); + tableWidgetDiv.find("#tableWidgetTableDataset > tbody").html(""); + } + + // If the choosen dataset representation is pivotUI + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_PIVOTUI) + { + tableWidgetDiv.find("#tableWidgetPivotUI").html(""); + } + + // If the choosen dataset representation is tabulator + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABULATOR) + { + tableWidgetDiv.find("#tableWidgetTabulator").html(""); + } + }, + + /** + * To get via Ajax all the data related to the TableWidget present in the given page + * If the parameter renderFunction is a valid function, is called on success + */ + _getTables: function(renderFunction) { + + var tableWidgetUniqueIdArray = FHC_TableWidget._getTableWidgetUniqueIdArray(); + + for (var tableWidgetsCounter = 0; tableWidgetsCounter < tableWidgetUniqueIdArray.length; tableWidgetsCounter++) + { + + FHC_AjaxClient.ajaxCallGet( + "widgets/Tables/getTable", + { + tableUniqueId: tableWidgetUniqueIdArray[tableWidgetsCounter] + }, + { + successCallback: function(data, textStatus, jqXHR) { + + if (FHC_AjaxClient.hasData(data)) + { + if (typeof renderFunction == "function") + { + renderFunction(FHC_AjaxClient.getData(data)); + } + } + else + { + console.log(FHC_AjaxClient.getError(data)); + } + } + } + ); + } + }, + + /** + * This method calls all the other methods needed to rendere the GUI for a TableWidget + * The parameter data contains all the data about the TableWidget and it is given as parameter + * to all the methods that here are called + * NOTE: think very carefully before changing the order of the calls + */ + _renderTableWidget: function(data) { + + FHC_TableWidget._setDatasetRepresentation(data); // set what type of dataset representation was choosen + + var tableWidgetDiv = $('div[tableUniqueId="' + data.tableUniqueId + '"]'); + + FHC_TableWidget._turnOffEvents(tableWidgetDiv); // turns all the events off + + FHC_TableWidget._resetGUI(tableWidgetDiv); // Reset the entire GUI + + FHC_TableWidget._renderDataset(tableWidgetDiv, data); + + FHC_TableWidget._turnOnEvents(tableWidgetDiv); // turns all the events off + }, + + /** + * Turns all the events off + * NOTE: must be aligned to _turnOnEvents + */ + _turnOffEvents: function(tableWidgetDiv) { + + // If the choosen dataset representation is tablesorter + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + FHC_TableWidget._disableTablesorter(tableWidgetDiv); // disable the tablesorter + } + }, + + /** + * Turns all the events on + * NOTE: must be aligned to _turnOffEvents + */ + _turnOnEvents: function(tableWidgetDiv) { + + // If the choosen dataset representation is tablesorter + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + FHC_TableWidget._enableTableSorter(tableWidgetDiv); // enable the tablesorter + } + }, + + _renderDataset: function(tableWidgetDiv, data) { + + // If the choosen dataset representation is tablesorter then... + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABLESORTER) + { + FHC_TableWidget._renderDatasetTablesorter(tableWidgetDiv, data); // ...render the tablesorter GUI + } + + // If the choosen dataset representation is pivotUI then... + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_PIVOTUI) + { + FHC_TableWidget._renderDatasetPivotUI(tableWidgetDiv, data); // ...render the pivotUI GUI + } + + // If the choosen dataset representation is tabulator then... + if (FHC_TableWidget._datasetRepresentation == DATASET_REP_TABULATOR) + { + FHC_TableWidget._renderDatasetTabulator(tableWidgetDiv, data); // ...render the tabulator GUI + } + }, + + /** + * Renders the tablesorter for the TableWidget + * The data to be displayed are retrived from the parameter data + */ + _renderDatasetTablesorter: function(tableWidgetDiv, data) { + + if (data.hasOwnProperty("checkboxes") && data.checkboxes != null && data.checkboxes.trim() != "") + { + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").append("Select"); + } + + var arrayFieldsToDisplay = FHC_TableWidget._getFieldsToDisplay(data); + + for (var i = 0; i < arrayFieldsToDisplay.length; i++) + { + var columnName = arrayFieldsToDisplay[i]; + + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").append("" + columnName + ""); + } + + if (data.hasOwnProperty("additionalColumns") && $.isArray(data.additionalColumns)) + { + for (var i = 0; i < data.additionalColumns.length; i++) + { + var columnName = data.additionalColumns[i]; + + tableWidgetDiv.find("#tableWidgetTableDataset > thead > tr").append("" + columnName + ""); + } + } + + if (arrayFieldsToDisplay.length > 0) + { + if (data.hasOwnProperty("dataset") && $.isArray(data.dataset)) + { + if (data.checkboxes != null && data.checkboxes != "") + { + // select checkbox range with shift key + if (typeof tableWidgetDiv.find("#tableWidgetTableDataset").checkboxes === 'function') + tableWidgetDiv.find("#tableWidgetTableDataset").checkboxes("range", true); + } + + for (var i = 0; i < data.dataset.length; i++) + { + var record = data.dataset[i]; + + if ($.isEmptyObject(record)) + { + continue; + } + + var strHtml = ""; + + if (data.checkboxes != null && data.checkboxes != "") + { + strHtml += ""; + strHtml += ""; + strHtml += ""; + } + + $.each(arrayFieldsToDisplay, function(i, fieldToDisplay) { + + if (record.hasOwnProperty(data.fields[i])) + { + strHtml += "" + record[data.fields[i]] + ""; + } + }); + + if (data.additionalColumns != null && $.isArray(data.additionalColumns)) + { + $.each(data.additionalColumns, function(i, additionalColumn) { + + if (record.hasOwnProperty(additionalColumn)) + { + strHtml += "" + record[additionalColumn] + ""; + } + }); + } + + strHtml += ""; + + tableWidgetDiv.find("#tableWidgetTableDataset > tbody").append(strHtml); + } + } + } + }, + + /** + * Enable the tablesorter libs to render the dataset table with sorting features + */ + _enableTableSorter: function(tableWidgetDiv) { + + var tableWidgetTablesorter = tableWidgetDiv.find("#tableWidgetTableDataset"); + + // Checks if the table contains data (rows) + if (tableWidgetTablesorter.find("tbody:empty").length == 0 + && tableWidgetTablesorter.find("tr:empty").length == 0 + && tableWidgetTablesorter.hasClass("table-condensed")) + { + tableWidgetTablesorter.tablesorter({ + dateFormat: "ddmmyyyy", + widgets: ["zebra", "filter"], + widgetOptions: { + filter_saveFilters : true + } + }); + + $.tablesorter.updateAll(tableWidgetTablesorter[0].config, true, null); + } + }, + + /** + * Disable the tablesorter + */ + _disableTablesorter: function(tableWidgetDiv) { + + tableWidgetDiv.find("#tableWidgetTableDataset").trigger("disable"); + }, + + /** + * Renders the pivotUI for the TableWidget + * The data to be displayed are retrived from the parameter data + */ + _renderDatasetPivotUI: function(tableWidgetDiv, data) { + + // Checks if options were given and returns them + var options = FHC_TableWidget._getRepresentationOptions(data); + + // Manipulation for the representation! + var arrayFieldsToDisplay = FHC_TableWidget._getFieldsToDisplay(data); + + // If there are fields to be displayed... + if (arrayFieldsToDisplay.length > 0) + { + // ...if there are data to be displayed... + if (data.hasOwnProperty("dataset") && $.isArray(data.dataset)) + { + // Build the array of objects used by pivotUI and store it in pivotUIData + var pivotUIData = []; + + // Loops through data + for (var i = 0; i < data.dataset.length; i++) + { + var record = data.dataset[i]; // Single record + var tmpObj = {}; // New object that represents a record + + // Loops through columns of a record + $.each(arrayFieldsToDisplay, function(i, fieldToDisplay) { + + if (record.hasOwnProperty(data.fields[i])) + { + tmpObj[fieldToDisplay] = record[data.fields[i]]; // Add data with the column alias + } + }); + + // If additional columns are present... + if (data.additionalColumns != null && $.isArray(data.additionalColumns)) + { + // ...loops through them + $.each(data.additionalColumns, function(i, additionalColumn) { + + if (record.hasOwnProperty(additionalColumn)) + { + tmpObj[additionalColumn] = record[additionalColumn]; // Add the additional column + } + }); + } + + pivotUIData.push(tmpObj); // Add tmpObj to pivotUIData + } + + // Renders the pivotUI + tableWidgetDiv.find("#tableWidgetPivotUI").pivotUI( + pivotUIData, + options + ); + } + } + }, + + /** + * Retrives the fields to be displayed from the data parameter, if aliases are present then they are used + */ + _getFieldsToDisplay: function(data) { + + var arrayFieldsToDisplay = []; + + if (data.hasOwnProperty("fields") && $.isArray(data.fields)) + { + if (data.hasOwnProperty("columnsAliases") && $.isArray(data.columnsAliases)) + { + for (var sfc = 0; sfc < data.fields.length; sfc++) + { + for (var fc = 0; fc < data.fields.length; fc++) + { + if (data.fields[sfc] == data.fields[fc]) + { + arrayFieldsToDisplay[sfc] = data.columnsAliases[fc]; + } + } + } + } + else + { + arrayFieldsToDisplay = data.fields; + } + } + + return arrayFieldsToDisplay; + }, + + /** + * Renders the tabulator for the TableWidget + * The data to be displayed are retrived from the parameter data + */ + _renderDatasetTabulator: function(tableWidgetDiv, data) { + + // Checks if options were given and returns them + var options = FHC_TableWidget._getRepresentationOptions(data); + // Checks if record fields definitions were given and returns them + var recordFieldsDefinitions = FHC_TableWidget._getRepresentationFieldsDefinitions(data); + + // Manipulation for the representation! + var arrayTabulatorColumns = FHC_TableWidget._getTabulatorColumns(data, recordFieldsDefinitions); + + if (arrayTabulatorColumns.length > 0) + { + // ...if there are data to be displayed... + if (data.hasOwnProperty("dataset") && $.isArray(data.dataset)) + { + if (options == null) options = {}; + + options.columns = arrayTabulatorColumns; + options.data = data.dataset; + + // Renders the tabulator + tableWidgetDiv.find("#tableWidgetTabulator").tabulator(options); + } + } + }, + + /** + * Retrives the fields to be displayed from the data parameter, if aliases are present then they are used + */ + _getTabulatorColumns: function(data, recordFieldsDefinitions) { + + var fieldsToDisplayTabulator = []; + + if (data.hasOwnProperty("fields") && $.isArray(data.fields)) + { + for (var sfc = 0; sfc < data.fields.length; sfc++) + { + for (var fc = 0; fc < data.fields.length; fc++) + { + if (data.fields[sfc] == data.fields[fc]) + { + // Build the array of objects (columns) used by tabulator and store it in tabulatorColumns + var tmpColumnObj = {}; // New object that represents a column + + // If was given a definition for this field then use it! + if (recordFieldsDefinitions != null && recordFieldsDefinitions.hasOwnProperty(data.fields[sfc])) + { + tmpColumnObj = recordFieldsDefinitions[data.fields[sfc]]; + } + + tmpColumnObj.field = data.fields[sfc]; // Field name to be linked with dataset field name + + // If there is an alias for this field use it to give a title to this field (header) + if (data.hasOwnProperty("columnsAliases") && $.isArray(data.columnsAliases)) + { + tmpColumnObj.title = data.columnsAliases[fc]; + } + else // otherwise use the field name itself + { + tmpColumnObj.title = data.fields[sfc]; + } + + fieldsToDisplayTabulator.push(tmpColumnObj); // Add tmpColumnObj to tabulatorColumns + } + } + } + } + + // If additional columns are present... + if (data.hasOwnProperty("additionalColumns") && data.additionalColumns != null && $.isArray(data.additionalColumns)) + { + // ...loops through them + $.each(data.additionalColumns, function(i, additionalColumn) { + + var tmpColumnObj = {}; // New object that represents a column + + // If was given a definition for this field then use it! + if (recordFieldsDefinitions != null && recordFieldsDefinitions.hasOwnProperty(additionalColumn)) + { + tmpColumnObj = recordFieldsDefinitions[additionalColumn]; + } + + tmpColumnObj.title = additionalColumn; // Give a title to this field (header) + tmpColumnObj.field = additionalColumn; // Field name to be linked with dataset field name + + fieldsToDisplayTabulator.push(tmpColumnObj); // Add tmpColumnObj to tabulatorColumns + }); + } + + return fieldsToDisplayTabulator; + }, + + /** + * Gets options for the representation + */ + _getRepresentationOptions: function(data) { + + var options = {}; // eventually contains options fot the representation + + // Checks if options were given + if (data.hasOwnProperty("datasetRepresentationOptions") && data.datasetRepresentationOptions != "") + { + var tmpOptions = eval("(" + data.datasetRepresentationOptions + ")"); // and converts them from string to javascript code + + // If it is an object then can be used + if (typeof tmpOptions == "object") + { + options = tmpOptions; + } + } + + return options; + }, + + /** + * Gets record fields definitions to represent the dataset + */ + _getRepresentationFieldsDefinitions: function(data) { + + var fieldsDefinitions = {}; // eventually contains record fields definitions + + // Checks if record fields definitions was given as parameter + if (data.hasOwnProperty("datasetRepresentationFieldsDefinitions") && data.datasetRepresentationFieldsDefinitions != "") + { + var tmpFDefs = eval("(" + data.datasetRepresentationFieldsDefinitions + ")"); // and converts them from string to javascript code + + // If it is an object then can be used + if (typeof tmpFDefs == "object") + { + fieldsDefinitions = tmpFDefs; + } + } + + return fieldsDefinitions; + }, + + /** + * Set what type of dataset representation was choosen + */ + _setDatasetRepresentation: function(data) { + + if (data.hasOwnProperty("datasetRepresentation")) + { + FHC_TableWidget._datasetRepresentation = data.datasetRepresentation; + } + }, + + _getTableWidgetUniqueIdArray: function() { + + var tableWidgetUniqueIdArray = []; + + $("div[id*='divTableWidgetDataset']").each(function(i, e) { + + tableWidgetUniqueIdArray.push(e.attributes["tableUniqueId"].nodeValue); + }); + + return tableWidgetUniqueIdArray; + } +}; + +/** + * When JQuery is up + */ +$(document).ready(function() { + + FHC_TableWidget.display(); + +});