From f4bfb0e367a8a8ff28523ec7540954d7f36298d9 Mon Sep 17 00:00:00 2001 From: Manuel Cillero Date: Fri, 10 Apr 2020 12:48:19 +0200 Subject: [PATCH] Initial commit --- Dam/Application.pm | 357 +++ Dam/Components/Actions/Download.pm | 124 + Dam/Components/Actions/Print.pm | 107 + Dam/Components/Actions/Run.pm | 122 + Dam/Components/Actions/Sort.pm | 216 ++ Dam/Components/Controls/Check.pm | 127 + Dam/Components/Controls/Date.pm | 158 + Dam/Components/Controls/DateRange.pm | 221 ++ Dam/Components/Controls/Input.pm | 153 + Dam/Components/Controls/Month.pm | 177 ++ Dam/Components/Controls/MultiCheck.pm | 161 + Dam/Components/Controls/Option.pm | 138 + Dam/Components/Controls/Upload.pm | 184 ++ Dam/Components/Controls/Year.pm | 160 + Dam/Components/Templates/About.tmpl.html | 46 + Dam/Components/Templates/Debug.tmpl.html | 14 + Dam/Components/Templates/Error403.tmpl.html | 5 + Dam/Components/Templates/Error500.tmpl.html | 5 + Dam/Components/Templates/Filter.tmpl.html | 72 + Dam/Components/Templates/Footer.tmpl.html | 39 + Dam/Components/Templates/Header.tmpl.html | 34 + Dam/Components/Templates/Login.tmpl.html | 26 + Dam/Components/Templates/Menu.tmpl.html | 23 + Dam/Components/Translations/ES_es.pm | 152 + Dam/DamLogic.pm | 1107 +++++++ Dam/Database.pm | 652 ++++ Dam/Debug.pm | 189 ++ Dam/LICENSE | 21 + Dam/Util.pm | 728 +++++ Dam/Var.pm | 299 ++ www/dam/css/bootstrap-datepicker3.min.css | 9 + www/dam/css/bootstrap-select.min.css | 6 + www/dam/css/bootstrap.min.css | 6 + www/dam/css/html5shiv.min.js | 4 + www/dam/css/ie8.css | 0 www/dam/css/jquery.smartmenus.bootstrap.css | 122 + www/dam/css/outdatedbrowser.min.css | 8 + www/dam/css/reports.css | 162 + www/dam/css/respond.min.js | 5 + www/dam/css/stylesheet.css | 382 +++ www/dam/fonts/codabar.eot | Bin 0 -> 4342 bytes www/dam/fonts/codabar.ttf | Bin 0 -> 4156 bytes www/dam/fonts/codabar.woff | Bin 0 -> 1604 bytes www/dam/fonts/codabar.woff2 | Bin 0 -> 876 bytes .../fonts/glyphicons-halflings-regular.eot | Bin 0 -> 20127 bytes .../fonts/glyphicons-halflings-regular.svg | 288 ++ .../fonts/glyphicons-halflings-regular.ttf | Bin 0 -> 45404 bytes .../fonts/glyphicons-halflings-regular.woff | Bin 0 -> 23424 bytes .../fonts/glyphicons-halflings-regular.woff2 | Bin 0 -> 18028 bytes www/dam/fonts/sirinstencil-regular.eot | Bin 0 -> 69520 bytes www/dam/fonts/sirinstencil-regular.svg | 851 ++++++ www/dam/fonts/sirinstencil-regular.ttf | Bin 0 -> 69332 bytes www/dam/fonts/sirinstencil-regular.woff | Bin 0 -> 35296 bytes www/dam/fonts/sirinstencil-regular.woff2 | Bin 0 -> 31304 bytes www/dam/img/icon2top.png | Bin 0 -> 3263 bytes www/dam/js/bootstrap-datepicker.es.min.js | 1 + www/dam/js/bootstrap-datepicker.min.js | 9 + www/dam/js/bootstrap-select.es.min.js | 7 + www/dam/js/bootstrap-select.min.js | 9 + www/dam/js/bootstrap.min.js | 7 + www/dam/js/chart.bundle.min.js | 10 + www/dam/js/handlebars.js | 2610 +++++++++++++++++ www/dam/js/javascript.js | 50 + www/dam/js/jquery.min.js | 5 + www/dam/js/jquery.smartmenus.bootstrap.min.js | 3 + www/dam/js/jquery.smartmenus.min.js | 3 + www/dam/js/jquery.validate.es.min.js | 4 + www/dam/js/jquery.validate.min.js | 4 + www/dam/js/outdatedbrowser.min.js | 8 + www/dam/js/spin.min.js | 2 + www/dam/js/typeahead.jquery.min.js | 7 + 71 files changed, 10399 insertions(+) create mode 100644 Dam/Application.pm create mode 100644 Dam/Components/Actions/Download.pm create mode 100644 Dam/Components/Actions/Print.pm create mode 100644 Dam/Components/Actions/Run.pm create mode 100644 Dam/Components/Actions/Sort.pm create mode 100644 Dam/Components/Controls/Check.pm create mode 100644 Dam/Components/Controls/Date.pm create mode 100644 Dam/Components/Controls/DateRange.pm create mode 100644 Dam/Components/Controls/Input.pm create mode 100644 Dam/Components/Controls/Month.pm create mode 100644 Dam/Components/Controls/MultiCheck.pm create mode 100644 Dam/Components/Controls/Option.pm create mode 100644 Dam/Components/Controls/Upload.pm create mode 100644 Dam/Components/Controls/Year.pm create mode 100644 Dam/Components/Templates/About.tmpl.html create mode 100644 Dam/Components/Templates/Debug.tmpl.html create mode 100644 Dam/Components/Templates/Error403.tmpl.html create mode 100644 Dam/Components/Templates/Error500.tmpl.html create mode 100644 Dam/Components/Templates/Filter.tmpl.html create mode 100644 Dam/Components/Templates/Footer.tmpl.html create mode 100644 Dam/Components/Templates/Header.tmpl.html create mode 100644 Dam/Components/Templates/Login.tmpl.html create mode 100644 Dam/Components/Templates/Menu.tmpl.html create mode 100644 Dam/Components/Translations/ES_es.pm create mode 100644 Dam/DamLogic.pm create mode 100644 Dam/Database.pm create mode 100644 Dam/Debug.pm create mode 100644 Dam/LICENSE create mode 100644 Dam/Util.pm create mode 100644 Dam/Var.pm create mode 100644 www/dam/css/bootstrap-datepicker3.min.css create mode 100644 www/dam/css/bootstrap-select.min.css create mode 100644 www/dam/css/bootstrap.min.css create mode 100644 www/dam/css/html5shiv.min.js create mode 100644 www/dam/css/ie8.css create mode 100644 www/dam/css/jquery.smartmenus.bootstrap.css create mode 100644 www/dam/css/outdatedbrowser.min.css create mode 100644 www/dam/css/reports.css create mode 100644 www/dam/css/respond.min.js create mode 100644 www/dam/css/stylesheet.css create mode 100644 www/dam/fonts/codabar.eot create mode 100644 www/dam/fonts/codabar.ttf create mode 100644 www/dam/fonts/codabar.woff create mode 100644 www/dam/fonts/codabar.woff2 create mode 100644 www/dam/fonts/glyphicons-halflings-regular.eot create mode 100644 www/dam/fonts/glyphicons-halflings-regular.svg create mode 100644 www/dam/fonts/glyphicons-halflings-regular.ttf create mode 100644 www/dam/fonts/glyphicons-halflings-regular.woff create mode 100644 www/dam/fonts/glyphicons-halflings-regular.woff2 create mode 100644 www/dam/fonts/sirinstencil-regular.eot create mode 100644 www/dam/fonts/sirinstencil-regular.svg create mode 100644 www/dam/fonts/sirinstencil-regular.ttf create mode 100644 www/dam/fonts/sirinstencil-regular.woff create mode 100644 www/dam/fonts/sirinstencil-regular.woff2 create mode 100644 www/dam/img/icon2top.png create mode 100644 www/dam/js/bootstrap-datepicker.es.min.js create mode 100644 www/dam/js/bootstrap-datepicker.min.js create mode 100644 www/dam/js/bootstrap-select.es.min.js create mode 100644 www/dam/js/bootstrap-select.min.js create mode 100644 www/dam/js/bootstrap.min.js create mode 100644 www/dam/js/chart.bundle.min.js create mode 100644 www/dam/js/handlebars.js create mode 100644 www/dam/js/javascript.js create mode 100644 www/dam/js/jquery.min.js create mode 100644 www/dam/js/jquery.smartmenus.bootstrap.min.js create mode 100644 www/dam/js/jquery.smartmenus.min.js create mode 100644 www/dam/js/jquery.validate.es.min.js create mode 100644 www/dam/js/jquery.validate.min.js create mode 100644 www/dam/js/outdatedbrowser.min.js create mode 100644 www/dam/js/spin.min.js create mode 100644 www/dam/js/typeahead.jquery.min.js diff --git a/Dam/Application.pm b/Dam/Application.pm new file mode 100644 index 0000000..77896b8 --- /dev/null +++ b/Dam/Application.pm @@ -0,0 +1,357 @@ +=head1 NAME + +Dam::Application + +=head1 DECRIPTION + +Initialization of the default global variables and definition of the entry point +for the predefined and customized run modes created using the Dam framework. + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Application; + +use base 'CGI::Application'; + +use CGI qw(-utf8); +use Authen::Simple::ActiveDirectory; +use Crypt::Tea_JS; +use String::Random qw(random_string); +use Date::Calc qw(Today_and_Now); + +use Dam::Util; +use Dam::Debug; +use Dam::Database; +use Dam::DamLogic qw( + is_report is_download Show__error_403 Show__about Show + Session__new Session__flush Session__close + User__is_logged_in User__access + cgiapp_param cgiapp_cookie cgiapp_header_add cgiapp_header_props + _t package_config tmpl_core +); +use Dam::Var; + +my %CURRENT_PACKAGE = (); + + + +sub pre__session_user_params { + my ($CGIAPP, $uid) = @_; + return (); +} + + + +sub pre__load_stylesheets { +} + + + +sub pre__load_javascripts { +} + + + +sub setup { + my $CGIAPP = shift; + + RESERVED(CGIAPP => $CGIAPP); + + # Connect to database: + RESERVED(DBH => database_connect( + DB_DSN => CONFIG('DB_DSN'), + DB_USER => CONFIG('DB_USER'), + DB_PASSWORD => CONFIG('DB_PASSWORD') + )); + + my @run_modes = ( + 'APP_login', + 'APP_confirm', + 'RUN_home', + 'RUN_report', + 'RUN_error403', + 'RUN_close' + ); + + if (User__is_logged_in()) { + my %ROUTES = %{CONFIG('REF_ROUTES')}; + my @user_access = User__access(); + foreach my $menu (sort keys(%ROUTES)) { + __setup_run_modes(\@run_modes, \%{$ROUTES{$menu}{OPTIONS}}, \@user_access); + } + } + $CGIAPP->run_modes(\@run_modes); + $CGIAPP->start_mode('RUN_home'); + + # The template directory is initialized: + $CGIAPP->tmpl_path(CONFIG('DIR_TEMPLATES')); + + # Enable file uploads: + $CGIAPP::DISABLE_UPLOADS = 0; + $CGIAPP::POST_SIZE = CONFIG('UPLOAD_MAX_FILESIZE'); +} + + + +sub teardown { + # Discconnect from database: + database_disconnect(); +} + + + +sub cgiapp_prerun { + my ($CGIAPP, $run_mode) = @_; + + my $binmode = 1; + cgiapp_header_props( + -charset => 'UTF-8' + ); + if (!is_eq(substr($run_mode, 0, 4), 'APP_')) { + if (User__is_logged_in()) { + if (!is_eq(substr($run_mode, 0, 4), 'RUN_')) { + # 1. Get the user access permissions: + my @user_access = User__access(); + + # 2. Debugging mode is disabled if user is not a developer: + CONFIG('DEBUG_MODE' => 0) if !in_array(0, \@user_access); + + # 3. Load report: + info($run_mode); + my %ROUTES = %{CONFIG('REF_ROUTES')}; + foreach my $menu (sort (%ROUTES)) { + %CURRENT_PACKAGE = __search_run_mode($run_mode, \%{$ROUTES{$menu}{OPTIONS}}); + if (%CURRENT_PACKAGE) { + $CURRENT_PACKAGE{ID} = $ROUTES{$menu}{ID}; + RESERVED('REF_CURRENT_PACKAGE' => \%CURRENT_PACKAGE); + last; + } + } + + # 4. Check if user has access permission to the current report: + if (!defined($CURRENT_PACKAGE{ACCESS}) || match_arrays(\@user_access, $CURRENT_PACKAGE{ACCESS})) { + # 5. Check if it's a download: + if (is_download()) { + my ($download_mode, $filename_extension) = split(',', cgiapp_param('dm')); + my $package = $run_mode; + my @packages = split('::', $run_mode); + if (scalar(@packages) > 1) { + $package = pop(@packages); + $package = pop(@packages) if is_eq($package, $CURRENT_PACKAGE{RUN}); + } + my $filename = strval($package, '_', $download_mode, '-', sprintf("%04d%02d%02d_%02d%02d%02d", Today_and_Now()), '.', $filename_extension); + cgiapp_header_props( + -type => 'application/x-download', + -Content_Disposition => strval('attachment; filename="', $filename, '"') + ); + $binmode = 0; + } + elsif (!is_report()) { + $CGIAPP->prerun_mode('RUN_report'); + } + } + else { + $CGIAPP->prerun_mode('RUN_error403'); + } + } + } + else { + $CGIAPP->prerun_mode('APP_login'); + } + } + binmode STDOUT, ":utf8" if $binmode; +} + + + +sub cgiapp_postrun { + DROP_TEMP_TABLES(); # Drop temporal database tables + Session__flush(); # Synchronize the session with the database +} + + + +sub APP_login { + return __login(); +} + + + +sub APP_confirm { + my $user = lc cgiapp_param('user'); + my $pass = decrypt(cgiapp_param('pass'), cgiapp_param('key')); + + # Check if the user exists (according to input parameters): + my $user_db = QUERY(SELECT( + FIELDS => 'user_uid, user_password, user_firstname, user_name, user_access, user_active', + FROM => 'users', + WHERE => COMPARE_STR('BINARY user_login', '=', $user) + )); + + # User not registered. Request the login again: + return __login($user, 1) if $user_db->rows == 0; + + my @user_data = $user_db->fetchrow_array(); + + # Non-active user. Show warning message: + return __login($user, 2, _t('User not active!'), _t('Consult with your systems manager to activate your user')) if $user_data[5] eq 0; + + # Check if user is in the Active Directory: + my $ad = Authen::Simple::ActiveDirectory->new(host => CONFIG('LDAP_DOMAIN'), principal => CONFIG('LDAP_DOMAIN'), timeout => 20); + if (!$ad->authenticate($user, $pass)) { + # Unidentified user. Or is it a local user: + my $passcrypt = __crypt_password($pass); + # Unidentified user. Request the login again: + return __login($user, 3) if !defined($user_data[1]) || $user_data[1] ne $passcrypt; + } + + # Validated user. Login with user settings: + Session__new($user_data[0], $user_data[2], $user_data[3], $user_data[4], RESERVED('CGIAPP')->pre__session_user_params($user_data[0])); + + # Show home page: + return RUN_home(); +} + + + +sub RUN_home { + return Show__about(); +} + + + +sub RUN_report { + return Show(); +} + + + +sub RUN_error403 { + return Show__error_403(); +} + + + +sub RUN_close { + Session__close(); # Delete the user session + return __login(); # Return to the login form +} + + +# PRIVATE FUNCTIONS: + + +sub __setup_run_modes { + my ($run_modes_ref, $options_ref, $user_access_ref) = @_; + + my $superuser = in_array(0, $user_access_ref); + foreach my $option (sort keys(%$options_ref)) { + next if !is_eq(ref($$options_ref{$option}), 'HASH') && is_eq($$options_ref{$option}, _DIVIDER_); + if (defined($$options_ref{$option}{OPTIONS})) { + __setup_run_modes($run_modes_ref, \%{$$options_ref{$option}{OPTIONS}}, $user_access_ref); + } + else { + next if is_empty($$options_ref{$option}{PACKAGE}) && is_empty($$options_ref{$option}{RUN}); + next if defined($$options_ref{$option}{ENABLED}) && $$options_ref{$option}{ENABLED} == 0; + next unless $superuser || (defined($$options_ref{$option}{ACCESS}) && match_arrays($user_access_ref, $$options_ref{$option}{ACCESS})); + + my $run_mode = strval_trio($$options_ref{$option}{PACKAGE}, '::', defined($$options_ref{$option}{RUN}) ? $$options_ref{$option}{RUN} : 'Run'); + fatal('Duplicated "', $run_mode, '" run mode.') if in_array($run_mode, $run_modes_ref); + push(@$run_modes_ref, $run_mode); + } + } +} + + + +sub __search_run_mode { + my ($run_mode, $options_ref) = @_; + + foreach my $option (sort keys(%$options_ref)) { + next if !is_eq(ref($$options_ref{$option}), 'HASH') && is_eq($$options_ref{$option}, _DIVIDER_); + if (defined($$options_ref{$option}{OPTIONS})) { + my %search_option = __search_run_mode($run_mode, \%{$$options_ref{$option}{OPTIONS}}); + return %search_option if %search_option; + } + else { + next if is_empty($$options_ref{$option}{PACKAGE}) && is_empty($$options_ref{$option}{RUN}); + next if !is_eq($run_mode, strval_trio($$options_ref{$option}{PACKAGE}, '::', defined($$options_ref{$option}{RUN}) ? $$options_ref{$option}{RUN} : 'Run')); + return package_config(\%{$$options_ref{$option}}); + } + } + return (); +} + + + +sub __login { + my ($login, $error, $error_title, $error_message) = @_; + + cgiapp_header_add(-cookie => cgiapp_cookie(CGISESSID => '')); + + my $tmpl_login = tmpl_core('Login', + APP_NAME => CONFIG('APP_NAME'), + KEY => random_string('ssssssssssssssssssssssssssssss'), + LOGIN => $login, + CRYPT_TEA => tea_in_javascript(), + + T_USERNAME => _t('Username'), + T_PASSWORD => _t('Password'), + T_LOGIN => _t('Login') + ); + + if (defined($error)) { + $tmpl_login->param( + ERROR => $error, + ERROR_TITLE => defined($error_title) ? $error_title : _t('Access error!'), + ERROR_MESSAGE => defined($error_message) ? $error_message : _t('Verify username and retype password') + ); + } + + return Show(DISPLAY => 'PAGE', TITLE => 'Login', TEMPLATE => $tmpl_login); +} + + + +sub __crypt_password { + my $password = shift; + return length($password) ? crypt($password, substr(crypt($password, 'CRTSGR'), -2, 2)) : ''; +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Actions/Download.pm b/Dam/Components/Actions/Download.pm new file mode 100644 index 0000000..78031eb --- /dev/null +++ b/Dam/Components/Actions/Download.pm @@ -0,0 +1,124 @@ +=head1 NAME + +Dam::Components::Actions::Download + +=head1 SYNOPSIS + +my $download_mode = Component__Get(ACTION_DOWNLOAD, ['csv']); + +=head1 DESCRIPTION + +Action to execute a download. + +=head1 ARGUMENTS + +( + TYPE => 'Download', + ID => 'csv' (default), + LABEL => 'CSV' (default), + TOOLTIP => 'Download the current report in CSV format' (default), + ICON => 'download-alt' (default), + MODE_EXT => 'CSV' (default), + FILE_EXT => 'csv' (default) +) + +=cut + +package Dam::Components::Actions::Download; + +use Exporter qw(import); +our @EXPORT = qw( + Action__html Action__js +); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'csv'; + + + +sub __arguments { + my $arg_ref = shift; + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + LABEL => [ ARG_DEFAULT, 'CSV' ], + TOOLTIP => [ ARG_DEFAULT, _t('Download current report in CSV format') ], + ICON => [ ARG_DEFAULT, 'download-alt' ], + MODE_EXT => [ ARG_DEFAULT, 'CSV' ], + FILE_EXT => [ ARG_DEFAULT, 'csv' ] + ); +} + + + +sub Action__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + return is_report() ? strval(' + + ') : ''; +} + + + +sub Action__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + return is_report() ? strval(' + $("#', $$arg_ref{ID}, '").click(function(){ + $("#xt").val(3); + $("#dm").val("', $$arg_ref{MODE_EXT}, ',', $$arg_ref{FILE_EXT}, '"); + $("#submit").click(); + }); + ') : ''; +} + + + +sub Get { + my ($download_mode, $filename_extension) = split(',', cgiapp_param('dm')); + return is_download() ? $download_mode : ''; +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Actions/Print.pm b/Dam/Components/Actions/Print.pm new file mode 100644 index 0000000..9ad8028 --- /dev/null +++ b/Dam/Components/Actions/Print.pm @@ -0,0 +1,107 @@ +=head1 NAME + +App::api::actions::Action_Print + +=head1 DESCRIPTION + +Action to print. + +=head1 ARGUMENTS + +( + TYPE => 'Print', + ID => 'print' (default), + LABEL => 'Print' (default) +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Actions::Print; + +use Exporter qw(import); +our @EXPORT = qw( + Action__html Action__js +); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'print'; + + + +sub __arguments { + my $arg_ref = shift; + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + LABEL => [ ARG_DEFAULT, _t('Print') ] + ); +} + + + +sub Action__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + return is_report() ? strval(' + + ') : ''; +} + + + +sub Action__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + return is_report() ? strval(' + $("#', $$arg_ref{ID},'").click(function(){ + window.print(); + }); + ') : ''; +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Actions/Run.pm b/Dam/Components/Actions/Run.pm new file mode 100644 index 0000000..069e1f7 --- /dev/null +++ b/Dam/Components/Actions/Run.pm @@ -0,0 +1,122 @@ +=head1 NAME + +Dam::Components::Actions::Run + +=head1 DESCRIPTION + +Action to run a report. + +=head1 ARGUMENTS + +( + TYPE => 'Run', + ID => 'submit' (default), + LABEL => 'Run' (default) +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Actions::Run; + +use Exporter qw(import); +our @EXPORT = qw( + Action__html Action__js +); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'submit'; + + + +sub __arguments { + my $arg_ref = shift; + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + LABEL => [ ARG_DEFAULT, _t('Run') ] + ); +} + + + +sub Action__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + return strval(' + + '); +} + + + +sub Action__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + # Required javascripts: + Component__Header(ADD => 'JS', RESOURCE => '/dam/js/spin.min.js', VERSION => '2.3.2' ); + + return strval(' + $(function(){ + var middle = Math.floor($(window).height() / 2) + "px"; + var spin = { lines: 10, length: 28, width: 25, radius: 40, scale: 0.5, corners: 1, color: "#000", opacity: 0.3, rotate: 0, direction: 1, speed: 1, trail: 60, fps: 20, zIndex: 2e9, className: "spinner", top: middle, left: "50%", shadow: false, hwaccel: false, position: "absolute" } + $("#filter").on("submit", function(e) { + if ($("#nv").val() != 1 && $("#filter").valid()) { + if ($("#xt").val() == 2) $("#xt").val(1); + if ($("#xt").val() == 3) $("#xt").val(2); + if ($("#xt").val() < 2) { + var spinner = new Spinner(spin).spin(document.getElementById("loading")); + $("#loading").show(); + } + } + $("#nv").val(0); + }); + }); + '); +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Actions/Sort.pm b/Dam/Components/Actions/Sort.pm new file mode 100644 index 0000000..ba500e0 --- /dev/null +++ b/Dam/Components/Actions/Sort.pm @@ -0,0 +1,216 @@ +=head1 NAME + +Dam::Components::Actions::Sort + +=head1 SYNOPSIS + +my $orderby = Component__Get(ACTION_SORT); + +=head1 DESCRIPTION + +Action to order a list by columns. + +=head1 ARGUMENTS + +( + TYPE => 'Sort', + COLUMNS => { 'col1' => 'Column 1', 'col2' => 'Column 2' } (default), + DEFAULT => 'col1' (default valus is undef) +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Actions::Sort; + +use Exporter qw(import); +our @EXPORT = qw( + Action__html Action__js +); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'sort'; + + + +sub __arguments { + my $arg_ref = shift; + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + COLUMNS => [ ARG_DEFAULT, { 'col1' => 'Column 1', 'col2' => 'Column 2' } ], + DEFAULT => [ ARG_OPTIONAL ] + ); +} + + + +sub Action__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + my $default = undef; + my %list_columns = %{$$arg_ref{COLUMNS}}; + if (!is_empty($$arg_ref{DEFAULT})) { + my @default = split(' ', $$arg_ref{DEFAULT}); + if (defined($list_columns{$default[0]}) && !defined($default[2])) { + my $dir = in_array(uc($default[1]), 'ASC', 'DESC') ? uc($default[1]) : 'ASC'; + $default = strval($default[0], ' ', $dir); + } + } + + # Order value: + my $orderby_value = cgiapp_param('orderby'); + $orderby_value = $default if is_empty($orderby_value) && defined($default); + + if (defined($orderby_value)) { + my @orderby = split(' ', $orderby_value); + if (defined($orderby[0]) && defined($list_columns{$orderby[0]})) { + my $orderby = $list_columns{$orderby[0]}; + if (defined($orderby[1])) { + $orderby = strval($orderby, is_eq($orderby[1], 'ASC') ? strval(' (', _t('ascendant'), ')') : is_eq($orderby[1], 'DESC') ? strval(' (', _t('descendent'), ')') : ''); + } + push(@{$info_ref}, { DATA => _t('Order by'), VALUE => $orderby }); + } + else { + $orderby_value = ''; + } + } + else { + $orderby_value = ''; + } + + return strval(' + + '); +} + + + +sub Action__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + my $default = undef; + my %list_columns = %{$$arg_ref{COLUMNS}}; + if (!is_empty($$arg_ref{DEFAULT})) { + my @default = split(' ', $$arg_ref{DEFAULT}); + if (defined($list_columns{$default[0]}) && !defined($default[2])) { + my $dir = in_array(uc($default[1]), 'ASC', 'DESC') ? uc($default[1]) : 'ASC'; + $default = strval($default[0], ' ', $dir); + } + } + + my $columns_id = ''; + my $columns_name = ''; + foreach my $column (keys(%list_columns)) { + $columns_id .= strval('#', $column, ','); + $columns_name .= strval($list_columns{$column}, ','); + } + chop($columns_id); + chop($columns_name); + + return strval(' + $(function(){ + var current_orderby = $("#orderby").val().split(" "); + var columns_id = ["', strval_join('","', split(',', $columns_id)), '"]; + var columns_name = ["', strval_join('","', split(',', $columns_name)), '"]; + columns_id.forEach(function(value,index,array){ + var glypho = "sort"; + if (current_orderby[0] == value.substring(1)) { + if (current_orderby[1] == "ASC") { + glypho = "triangle-bottom"; + } + else if (current_orderby[1] == "DESC") { + glypho = "triangle-top"; + } + } + $(value).css("white-space","nowrap"); + $(value).prepend(""); + $(value).hover(function(){ + $(this).css("cursor","pointer"); + }); + $(value).click(function(){ + var current_column = $(this).attr("id"); + if (current_column == current_orderby[0]) { + if (current_orderby[1] == "ASC") { + current_column += " DESC"; + } + else if (current_orderby[1] != "DESC") { + current_column += " ASC"; + } + else { + current_column = "', $default, '"; + } + } + else { + current_column += " ASC"; + } + $("#orderby").val(current_column); + $("#submit").click(); + }); + }); + $(".minitip").tooltip(); + }); + '); +} + + + +sub Get { + my $orderby_value = cgiapp_param('orderby'); + return undef if is_empty($orderby_value); + return $orderby_value; +} + + + +sub Set { + my ($self, $value, $id) = @_; + + cgiapp_param('orderby', $value); +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Controls/Check.pm b/Dam/Components/Controls/Check.pm new file mode 100644 index 0000000..10eca53 --- /dev/null +++ b/Dam/Components/Controls/Check.pm @@ -0,0 +1,127 @@ +=head1 NAME + +App::api::controls::Control_Check + +=head1 SYNOPSIS + +my $check = Component__Get(CONTROL_CHECK, ['check']); + +=head1 DESCRIPTION + +Control para marcar/desmarcar una opción. + +=head1 ARGUMENTS + +( + TYPE => 'Check', + ID => 'check' (default), + INFO => 1 (show info in header; default) or 0 (don't show), + LABEL => 'Check' (default), + LABEL_INFO => Same as LABEL (default), + DEFAULT => 0 (unchecked; default) or 1 (checked) +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Controls::Check; + +use Exporter qw(import); +our @EXPORT = qw( + Control__html Control__js Get +); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'check'; + + + +sub __arguments { + my $arg_ref = shift; + + $$arg_ref{LABEL} = 'Check' if is_empty($$arg_ref{LABEL}); + $$arg_ref{LABEL_INFO} = $$arg_ref{LABEL} if is_empty($$arg_ref{LABEL_INFO}); + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + INFO => [ ARG_DEFAULT, 1, 0 ], + LABEL => [ ARG_REQUIRED ], + LABEL_INFO => [ ARG_REQUIRED ], + DEFAULT => [ ARG_DEFAULT, 0, 1 ] + ); +} + + + +sub Control__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + my $check_value = !is_report() ? $$arg_ref{DEFAULT} : is_empty(cgiapp_param($$arg_ref{ID})) ? 0 : 1; + + push(@{$info_ref}, { DATA => _t('Option'), VALUE => $$arg_ref{LABEL_INFO} }) if $$arg_ref{INFO} && $check_value; + + return strval(' +
+ +
+ '); +} + + + +sub Control__js { +} + + + +sub Get { + my ($self, $id) = @_; + + $id = $ID_DEFAULT if is_empty($id); + + return is_empty(cgiapp_param($id)) ? 0 : 1; +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Controls/Date.pm b/Dam/Components/Controls/Date.pm new file mode 100644 index 0000000..66ee69d --- /dev/null +++ b/Dam/Components/Controls/Date.pm @@ -0,0 +1,158 @@ +=head1 NAME + +Dam::Components::Controls::Date + +=head1 SYNOPSIS + +my $date = Component__Get(CONTROL_DATE, ['date']); + +=head1 DESCRIPTION + +Control para seleccionar una fecha. + +=head1 ARGUMENTS + +( + TYPE => 'Date', + ID => 'date' (default), + INFO => 1 (show info in header; default) or 0 (don't show), + LABEL => 'Date' (default), + LABEL_INFO => Same as LABEL (default), + REQUIRED => 1 (control required; default) or 0 (not required) +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Controls::Date; + +use Exporter qw(import); +our @EXPORT = qw( + Control__html Control__js Get +); + +use Date::Calc qw(Today Add_Delta_Days); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'date'; + + + +sub __arguments { + my $arg_ref = shift; + + $$arg_ref{LABEL} = _t('Date') if is_empty($$arg_ref{LABEL}); + $$arg_ref{LABEL_INFO} = $$arg_ref{LABEL} if is_empty($$arg_ref{LABEL_INFO}); + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + INFO => [ ARG_DEFAULT, 1, 0 ], + LABEL => [ ARG_REQUIRED ], + LABEL_INFO => [ ARG_REQUIRED ], + REQUIRED => [ ARG_DEFAULT, 1, 0 ] + ); +} + + + +sub Control__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + my $date_value = cgiapp_param($$arg_ref{ID}); + + if (!is_report()) { + my @previous = Add_Delta_Days(Today(), -1); + $date_value = strval(sprintf("%02d", $previous[2]), '/', sprintf("%02d", $previous[1]), '/', $previous[0]); + } + push(@{$info_ref}, { DATA => $$arg_ref{LABEL_INFO}, VALUE => $date_value }) if $$arg_ref{INFO}; + + # Required stylesheets: + Component__Header(ADD => 'CSS', RESOURCE => PACK_DATEPICKER); + + return strval(' +
+ + +
+ '); +} + + + +sub Control__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + # Required javascripts: + Component__Header(ADD => 'JS', RESOURCE => PACK_DATEPICKER); + + return strval(' + $(function(){ + $("#', $$arg_ref{ID}, '").datepicker({ + language: "', _t('LANGUAGE_CODE'), '", + autoclose: true, + todayHighlight: true, + disableTouchKeyboard: true, + endDate: "0d" + }); + }); + '); +} + + + +sub Get { + my ($self, $id) = @_; + + $id = $ID_DEFAULT if is_empty($id); + + my @date_value = split('/', cgiapp_param($id)); + my $date_value = "$date_value[2]-$date_value[1]-$date_value[0]"; + + return $date_value; +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Controls/DateRange.pm b/Dam/Components/Controls/DateRange.pm new file mode 100644 index 0000000..7220dad --- /dev/null +++ b/Dam/Components/Controls/DateRange.pm @@ -0,0 +1,221 @@ +=head1 NAME + +Dam::Components::Controls::DateRange + +=head1 SYNOPSIS + +my ($ini, $end) = Component__Get(CONTROL_DATERANGE, ['range']); + +=head1 DESCRIPTION + +Control para obtener un rango de fechas. + +=head1 ARGUMENTS + +( + TYPE => 'DateRange', + ID => 'range' (default), + INFO => 1 (show info in header; default) or 0 (don't show), + LABEL => 'Date range' (default), + LABEL_INFO => Same as LABEL (default), + REQUIRED => 1 (control required; default) or 0 (not required) + MAXDAYS => 1095 (default) or maximum number of days for range +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Controls::DateRange; + +use Exporter qw(import); +our @EXPORT = qw( + Control__html Control__js Get +); + +use Date::Calc qw(Today Add_Delta_YM Days_in_Month); + +use Dam::Util; +use Dam::DamLogic; +use Dam::Var; + + + +my $ID_DEFAULT = 'range'; + + + +sub __arguments { + my $arg_ref = shift; + + $$arg_ref{LABEL} = _t('Date range') if is_empty($$arg_ref{LABEL}); + $$arg_ref{LABEL_INFO} = $$arg_ref{LABEL} if is_empty($$arg_ref{LABEL_INFO}); + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + INFO => [ ARG_DEFAULT, 1, 0 ], + LABEL => [ ARG_REQUIRED ], + LABEL_INFO => [ ARG_REQUIRED ], + REQUIRED => [ ARG_DEFAULT, 1, 0 ], + MAXDAYS => [ ARG_DEFAULT, 1095 ] + ); +} + + + +sub Control__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + my $ini_value = cgiapp_param($$arg_ref{ID}); + my $end_value = cgiapp_param(strval($$arg_ref{ID}, '_end')); + + if (!is_report()) { + my @previous = Add_Delta_YM(Today(), 0, -1); + $ini_value = strval('01/', sprintf("%02d", $previous[1]), '/', $previous[0]); + $end_value = strval(Days_in_Month($previous[0], $previous[1]), '/', sprintf("%02d", $previous[1]), '/', $previous[0]); + } + my @ini = split(/\//, $ini_value); + my @end = split(/\//, $end_value); + my $range = strval($ini_value, ' al ', $end_value); + if (($ini[0] == 1) && ($ini[2] == $end[2])) { + if (($end[0] == Days_in_Month($ini[2],$ini[1])) && ($ini[1] == $end[1])) { + $range = strval($range, ' (', uc(_t('MONTHS', $ini[1])), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 1) && ($end[0] == 31) && ($end[1] == 12)) { + $range = strval($range, ' (', _t('YEAR'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 1) && ($end[0] == 30) && ($end[1] == 6)) { + $range = strval($range, ' (', _t('FIRST SEMESTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 7) && ($end[0] == 31) && ($end[1] == 12)) { + $range = strval($range, ' (', _t('SECOND SEMESTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 1) && ($end[0] == 30) && ($end[1] == 4)) { + $range = strval($range, ' (', _t('FIRST QUARTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 5) && ($end[0] == 31) && ($end[1] == 8)) { + $range = strval($range, ' (', _t('SECOND QUARTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 9) && ($end[0] == 31) && ($end[1] == 12)) { + $range = strval($range, ' (', _t('THIRD QUARTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 1) && ($end[0] == 31) && ($end[1] == 3)) { + $range = strval($range, ' (', _t('FIRST TRIMESTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 4) && ($end[0] == 30) && ($end[1] == 6)) { + $range = strval($range, ' (', _t('SECOND TRIMESTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 7) && ($end[0] == 30) && ($end[1] == 9)) { + $range = strval($range, ' (', _t('THIRD TRIMESTER'), ' ', $ini[2], ')'); + } + elsif (($ini[1] == 10) && ($end[0] == 31) && ($end[1] == 12)) { + $range = strval($range, ' (', _t('FOURTH TRIMESTER'), ' ', $ini[2], ')'); + } + } + push(@{$info_ref}, { DATA => $$arg_ref{LABEL_INFO}, VALUE => $range }) if $$arg_ref{INFO}; + + # Required stylesheets: + Component__Header(ADD => 'CSS', RESOURCE => PACK_DATEPICKER); + + return strval(' +
+ +
+ + al + +
+
+ '); +} + + + +sub Control__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + # Required javascripts: + Component__Header(ADD => 'JS', RESOURCE => PACK_DATEPICKER); + + return strval(' + $(function(){ + $(".input-group.input-daterange").datepicker({ + language: "', _t('LANGUAGE_CODE'), '", + autoclose: true, + todayHighlight: true, + disableTouchKeyboard: true, + // endDate: "0d", + startDate: "01/01/1900" // https://github.com/uxsolutions/bootstrap-datepicker/issues/721#issuecomment-86275874 (workaround) + }); + $("#filter").on("submit", function(e) { + if ($("#filter").valid()) { + var range = ', $$arg_ref{MAXDAYS}, '; + if (Math.round(($("#', $$arg_ref{ID}, '_end").datepicker("getDate") - $("#', $$arg_ref{ID}, '").datepicker("getDate")) / (1000 * 60 * 60 * 24)) > range) { + $("#nv").val(1); + $("#filter-message").text("', _t('Date ranges greater than <--max--> are not allowed.', max => $$arg_ref{MAXDAYS} % 365 ? strval($$arg_ref{MAXDAYS}, ' ', _t('day(s)')) : strval($$arg_ref{MAXDAYS} / 365, ' ', _t('year(s)'))), '"); + $("#filter-error").modal(); + e.preventDefault(); + return false; + } + } + }); + }); + '); +} + + + +sub Get { + my ($self, $id) = @_; + + $id = $ID_DEFAULT if is_empty($id); + + my @ini_value = split('/', cgiapp_param($id)); + my $ini_value = "$ini_value[2]-$ini_value[1]-$ini_value[0]"; + + my @end_value = split('/', cgiapp_param(strval($id, '_end'))); + my $end_value = "$end_value[2]-$end_value[1]-$end_value[0]"; + + return ($ini_value, $end_value); +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Controls/Input.pm b/Dam/Components/Controls/Input.pm new file mode 100644 index 0000000..429cc6d --- /dev/null +++ b/Dam/Components/Controls/Input.pm @@ -0,0 +1,153 @@ +=head1 NAME + +Dam::Components::Controls::Input + +=head1 SYNOPSIS + +my $input = Component__Get(CONTROL_INPUT, ['input']); + +=head1 DESCRIPTION + +Control para introducir un texto. + +=head1 ARGUMENTS + +( + TYPE => 'Input', + ID => 'input' (default), + INFO => 1 (show info in header; default) or 0 (don't show), + LABEL => 'Enter text' (default), + LABEL_INFO => 'Input text' (default), + REQUIRED => 1 (control required; default) or 0 (not required) + ONLY => 'All' (allows any alphanumeric character; default) ó 'Digits' + (allow only numbers) +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Controls::Input; + +use Exporter qw(import); +our @EXPORT = qw( + Control__html Control__js Get +); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'input'; + + + +sub __arguments { + my $arg_ref = shift; + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + INFO => [ ARG_DEFAULT, 1, 0 ], + LABEL => [ ARG_DEFAULT, _t('Enter text') ], + LABEL_INFO => [ ARG_DEFAULT, _t('Input text') ], + REQUIRED => [ ARG_DEFAULT, 1, 0 ], + ONLY => [ ARG_DEFAULT, 'All', 'Digits' ] + ); +} + + + +sub Control__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + my $input_value = cgiapp_param($$arg_ref{ID}); + + push(@{$info_ref}, { DATA => $$arg_ref{LABEL_INFO}, VALUE => $input_value }) if !is_empty($input_value); + + return strval(' +
+ +
+ +
+
+ '); +} + + + +sub Control__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + return is_eq($$arg_ref{ONLY}, 'Digits') ? strval(' + $(function(){ + $.fn.inputFilter = function(inputFilter) { + return this.on("input keydown keyup mousedown mouseup select contextmenu drop", function() { + if (inputFilter(this.value)) { + this.oldValue = this.value; + this.oldSelectionStart = this.selectionStart; + this.oldSelectionEnd = this.selectionEnd; + } else if (this.hasOwnProperty("oldValue")) { + this.value = this.oldValue; + this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd); + } + }); + }; + $("#', $$arg_ref{ID}, '").inputFilter(function(value) { + return /^\d*$/.test(value); + }); + }); + ') : ''; +} + + + +sub Get { + my ($self, $id) = @_; + + $id = $ID_DEFAULT if is_empty($id); + + return cgiapp_param($id); +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Controls/Month.pm b/Dam/Components/Controls/Month.pm new file mode 100644 index 0000000..dec015b --- /dev/null +++ b/Dam/Components/Controls/Month.pm @@ -0,0 +1,177 @@ +=head1 NAME + +Dam::Components::Controls::Month + +=head1 SYNOPSIS + +my ($year, $month) = Component__Get(CONTROL_MONTH, ['month']); + +=head1 DESCRIPTION + +Control para seleccionar un mes del año. + +=head1 ARGUMENTS + +( + TYPE => 'Month', + ID => 'month' (default), + INFO => 1 (show info in header; default) or 0 (don't show), + LABEL => 'Month' (default), + LABEL_INFO => Same as LABEL (default), + REQUIRED => 1 (control required; default) or 0 (not required) +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Controls::Month; + +use Exporter qw(import); +our @EXPORT = qw( + Control__html Control__js Get +); + +use Date::Calc qw(Today); + +use Dam::Util; +use Dam::DamLogic; +use Dam::Var; + + + +my $ID_DEFAULT = 'month'; + + + +sub __arguments { + my $arg_ref = shift; + + $$arg_ref{LABEL} = _t('Month') if is_empty($$arg_ref{LABEL}); + $$arg_ref{LABEL_INFO} = $$arg_ref{LABEL} if is_empty($$arg_ref{LABEL_INFO}); + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + INFO => [ ARG_DEFAULT, 1, 0 ], + LABEL => [ ARG_REQUIRED ], + LABEL_INFO => [ ARG_REQUIRED ], + REQUIRED => [ ARG_DEFAULT, 1, 0 ] + ); +} + + + +sub Control__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + my $value = cgiapp_param($$arg_ref{ID}); + + my @today = Today(); + my ($month_name, $month_value, $year_value) = ('', $today[1], $today[0]); + + if (!is_report() || is_empty($value)) { + if ($month_value == 1) { + $month_value = 12; + $year_value--; + } + else { + $month_value--; + } + $month_name = _t('MONTHS', $month_value); + } + else { + ($month_name, $year_value) = split(/ /, $value); + $month_value = _t('MONTHS', $month_name); + } + push(@{$info_ref}, { DATA => $$arg_ref{LABEL_INFO}, VALUE => "$month_name $year_value" }) if $$arg_ref{INFO}; + + # Required stylesheets: + Component__Header(ADD => 'CSS', RESOURCE => PACK_DATEPICKER); + + return strval(' +
+ + +
+ '); +} + + + +sub Control__js { + my ($self, $arg_ref) = @_; + + __arguments($arg_ref); + + my @today = Today(); + + # Required javascripts: + Component__Header(ADD => 'JS', RESOURCE => PACK_DATEPICKER); + + return strval(' + $(function(){ + $("#', $$arg_ref{ID}, '").datepicker({ + language: "', _t('LANGUAGE_CODE'), '", + autoclose: true, + todayHighlight: true, + disableTouchKeyboard: true, + minViewMode: "months", + format: "MM yyyy", + endDate: "', $today[1] - 1, '-', $today[0], '" + }); + }); + '); +} + + + +sub Get { + my ($self, $id) = @_; + + $id = $ID_DEFAULT if is_empty($id); + + my $value = cgiapp_param($id); + return (undef, undef) if is_empty($value); + my ($month_name, $year_value) = split(/ /, $value); + my $month_value = _t('MONTHS', $month_name); + return ($year_value, $month_value); +} + + + +1; + +=head1 AUTHOR + +Manuel Cillero C<< >> + +=head1 COPYRIGHT + +The MIT License (MIT) + +Copyright (c) 2004-2020 Manuel Cillero. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +=cut diff --git a/Dam/Components/Controls/MultiCheck.pm b/Dam/Components/Controls/MultiCheck.pm new file mode 100644 index 0000000..cb64911 --- /dev/null +++ b/Dam/Components/Controls/MultiCheck.pm @@ -0,0 +1,161 @@ +=head1 NAME + +Dam::Components::Controls::MultiCheck + +=head1 SYNOPSIS + +my ($check_1, $check_2, ...) = Component__Get(CONTROL_MULTICHECK, ['multicheck']); + +=head1 DESCRIPTION + +Control para seleccionar una o más opciones de una lista. + +=head1 ARGUMENTS + +( + TYPE => 'MultiCheck', + ID => 'multicheck' (default), + INFO => 1 (show info in header; default) or 0 (don't show), + LABEL => 'MultiCheck' (default), + LABEL_INFO => Same as LABEL (default), + REQUIRED => 1 (control required; default) or 0 (not required) + MULTIPLE => 1 (allows to select any number of options; default) or 0 (allows + to select only one option), + OPTIONS => { 'op1' => 'Option 1', 'op2' => 'Option 2' } (default); you can + use { ..., 'opN' => _DIVIDER_, ... } to include separators + between the options according to order, + DEFAULT => Default option(s), e.g. "'op1'" or "'op1','op3'" +) + +=cut + +use strict; +use warnings; +use utf8; + +package Dam::Components::Controls::MultiCheck; + +use Exporter qw(import); +our @EXPORT = qw( + Control__html Control__js Get +); + +use Dam::Util; +use Dam::DamLogic; + + + +my $ID_DEFAULT = 'multicheck'; + + + +sub __arguments { + my $arg_ref = shift; + + $$arg_ref{LABEL} = 'MultiCheck' if is_empty($$arg_ref{LABEL}); + $$arg_ref{LABEL_INFO} = $$arg_ref{LABEL} if is_empty($$arg_ref{LABEL_INFO}); + + check_arguments($arg_ref, + TYPE => [ ARG_REQUIRED ], + ID => [ ARG_DEFAULT, $ID_DEFAULT ], + INFO => [ ARG_DEFAULT, 1, 0 ], + LABEL => [ ARG_REQUIRED ], + LABEL_INFO => [ ARG_REQUIRED ], + REQUIRED => [ ARG_DEFAULT, 1, 0 ], + MULTIPLE => [ ARG_DEFAULT, 1, 0 ], + OPTIONS => [ ARG_DEFAULT, { 'op1' => strval(_t('Option'), ' 1'), 'op2' => strval(_t('Option'), ' 2') } ], + DEFAULT => [ ARG_OPTIONAL ] + ); +} + + + +sub Control__html { + my ($self, $arg_ref, $info_ref) = @_; + + __arguments($arg_ref); + + my $multicheck_value = !is_report() && !is_empty($$arg_ref{DEFAULT}) ? $$arg_ref{DEFAULT} : strval_join(',', cgiapp_param($$arg_ref{ID})); + + my $form_group = 'form-group'; + + my $list_opts = ''; + my $info_opts = ''; + my $count_opts = 0; + for my $key (sort keys(%{$$arg_ref{OPTIONS}})) { + if (is_eq(${$$arg_ref{OPTIONS}}{$key}, _DIVIDER_)) { + $list_opts .= ''; + } + else { + my $checked = defined($multicheck_value) && index($multicheck_value, $key) >= 0; + my $selected = $checked ? '" selected="selected">' : '">'; + $list_opts .= strval('