Subversion Repositories masonsql

Compare Revisions

No changes between revisions

Ignore whitespace Rev 797 → Rev 806

/tags/2.0/htdocs/data/public/anagrafiche.mql
0,0 → 1,172
<%doc>
</%doc>
 
<%method FROM>anagrafiche</%method>
 
<%method FUNZIONE>Anagrafiche</%method>
 
<%method DESCRIPTION>Anagrafiche Utenti</%method>
 
<%method CHILDREN>anagrafiche_gruppi</%method>
<%method CHILDREN_FIELDS>id</%method>
 
<%method FIELDS>nome, cognome, codice_fiscale, descrizione, indirizzo, provincia, citta, tel1, tel2, cell_sms,
email, login, password, no_psw_expiration, no_change_password, concurrent_sessions</%method>
 
<%method FIELDS_NOT_NULL>nome, cognome</%method>
 
%# invio il campo 'password' vuoto e non modificabile
<%method SELECT_FIELDS>nome, cognome, codice_fiscale, descrizione, indirizzo, provincia, citta, tel1, tel2, cell_sms,
email, login, '' as password, no_psw_expiration, no_change_password, concurrent_sessions</%method>
 
<%method FIELDS_DESCR>Nome\, Cognome, Codice Fiscale, Descrizione, Indirizzo, Provincia\, Città, Telefono\, 2° Telefono, Cell. SMS,
E-mail, Login, Password\, Blocco scadenza psw\, Blocco cambio psw\, sessioni simultanee</%method>
 
<%method FIELDS_NEW>,,,,,,,,,,,,,,</%method>
 
<%method FIND_FIELDS>login, nome, cognome, descrizione, codice_fiscale</%method>
 
<%method DELETE>\
<%args>$KEY</%args>
delete from anagrafiche_gruppi where id_anagrafiche = <%$KEY%>;
delete from <&SELF:FROM&> where <&SELF:KEY&> = <%$KEY%>;
</%method>
 
<%method FIELDS_RO>\
% if(!$Session{Group_Admins}){
*\
% }
</%method>
 
<%method FIELDS_NO_WRITE>\
</%method>
 
<%method WHERE></%method>
 
<%method ORDER>order by upper(cognome), upper(nome), upper(login)</%method>
 
<%method password_FIELD>
<& /input/string.comp, %ARGS, length => 18 &>
</%method>
 
<%method codice_fiscale_FIELD><& /input/codfisc_pi.comp, %ARGS &></%method>
 
<%method PARAMETERS_SELECT_FIELDS>cognome, nome</%method>
 
<%method login_CHECK>
<%args>
$KEY => undef
$VALUE
</%args>
<%perl>
length($VALUE) || return;
# verifico che la login indicata non sia già presente
my $sth = $KEY ?
ExecQuery('Check unique login', undef, qq{
select id from public.anagrafiche where login = ? and id != ?
}, $VALUE, $KEY) :
ExecQuery('Check unique login', undef, qq{
select id from public.anagrafiche where login = ?
}, $VALUE);
$Session{Dbh}->commit;
if($sth->rows){
</%perl>
La login (<% $VALUE %>) è già utilizzata.
% }
<%perl>
# verifico che la login indicata non sia tra quelle proibite
$sth = ExecQuery('Check reserved login', undef, qq{
select id from public.reserved_login where login = ?
}, $VALUE);
if($sth->rows){
</%perl>
La login (<% $VALUE %>) è riservata.
% }
</%method>
 
<%method PRE_UPDATE>
<%args>
$FIELDS_UPDATE
$PARAMS
</%args>
<%perl>
$m->comp('SELF:PRE_INSERT', FIELDS_INSERT => $FIELDS_UPDATE, PARAMS => $PARAMS);
</%perl>
</%method>
 
<%method POST_UPDATE>
<%args>
$KEY
$PARAMS
</%args>
<& SELF:ChangePassword, KEY => $KEY, PARAMS => $PARAMS &>
</%method>
 
<%method PRE_INSERT>
<%args>
$FIELDS_INSERT
$PARAMS
</%args>
<%perl>
if(defined $FIELDS_INSERT->{password}){
$PARAMS->{password} = $FIELDS_INSERT->{password};
delete $FIELDS_INSERT->{password};
}
</%perl>
</%method>
 
<%method POST_NO_INSERT>
<%args>
$KEY
$PARAMS
</%args>
<& SELF:ChangePassword, KEY => $KEY, PARAMS => $PARAMS &>
</%method>
 
<%method POST_NO_UPDATE>
<%args>
$KEY
$PARAMS
</%args>
<& SELF:ChangePassword, KEY => $KEY, PARAMS => $PARAMS &>
</%method>
 
<%method POST_INSERT>
<%args>
$KEY
$PARAMS
</%args>
<& SELF:ChangePassword, KEY => $KEY, PARAMS => $PARAMS &>
</%method>
 
<%method ChangePassword>
<%args>
$KEY
$PARAMS
</%args>
<%perl>
if(defined $PARAMS->{password}){
$Session{Dbh}->commit;
# recupero la login utente
my $sth = ExecQuery('User login', undef, q{
select id, login, password from public.anagrafiche where id = ?
}, $KEY);
my($id, $login, $password) = $sth->rows ? @{$sth->fetchrow_arrayref} : undef;
if($login){
# cambiamento password e forzo richiesta cambio password all'utente
my $err_message = $r->auth_type->update_password($r, $login, $PARAMS->{password}, 1);
if($err_message){
BrowserAlert('Password non '.($password ? 'sostituita' : 'inserita')."\n\n" . $err_message);
}else{
$password && BrowserAlert('Password sostituita');
}
}else{
if($id){
BrowserAlert('Non è codificata la login dell\'utente');
}else{
BrowserAlert('Errore inaspettato nel cambio password: '.$sth->errstr);
}
}
}
</%perl>
</%method>
/tags/2.0/htdocs/data/public/anagrafiche_gruppi.mql
0,0 → 1,78
<%doc>
Tabella "public.anagrafiche_gruppi"
Colonna | Tipo | Modificatori
----------------+---------+----------------------------------------------------------
id | integer | not null default nextval('anagrafiche_gruppi_seq'::text)
id_anagrafiche | integer | not null
id_gruppi | integer | not null
Indici:
"anagrafiche_gruppi_pkey" chiave primaria, btree (id)
"fki_anagrafiche_gruppi_id_anagrafiche" btree (id_anagrafiche)
"fki_anagrafiche_gruppi_id_gruppi" btree (id_gruppi)
Vincoli di integrità referenziale
"anagrafiche_gruppi_id_gruppi" FOREIGN KEY (id_gruppi) REFERENCES gruppi(id) ON UPDATE RESTRICT ON DELETE RESTRICT
"anagrafiche_gruppi_id_anagrafiche" FOREIGN KEY (id_anagrafiche) REFERENCES anagrafiche(id) ON UPDATE RESTRICT ON DELETE RESTRICT
</%doc>
<%method FUNZIONE>Anagrafiche</%method>
<%method DESCRIPTION>Gruppi a cui appartiene l'utente</%method>
 
<%method FIELDS>id_gruppi</%method>
 
<%method FIELDS_NOT_NULL>id_gruppi</%method>
 
<%method FIELDS_DESCR>Gruppi</%method>
 
%# formato: idref:table:key
%# idref = chiave_locale key = tabella padre
<%method FATHER>id_anagrafiche:anagrafiche</%method>
 
<%method PRE_UPDATE>
<%args>
$KEY
$FIELDS_UPDATE
</%args>
<%perl>
$m->comp('SELF:PRE_INSERT', FIELDS_INSERT => $FIELDS_UPDATE);
</%perl>
</%method>
 
<%method PRE_INSERT>
<%args>
$FIELDS_INSERT
</%args>
<%perl>
# chiamata anche per l'inserimento di un nuovo record
if(!$Session{Group_Admins}){ # se Admins non occorre alcun controllo
my $id_gruppi = $FIELDS_INSERT->{'id_gruppi'};
# verifico che l'utente corrente abbia diritto di assegnare il gruppo indicato
# Nota: l'interfaccia grafica propone gia la lista corretta. Il controllo viene fatto
# per motivi di sicurezza
my $query = <<__SQL__;
select distinct
gruppi.id
from
gruppi_modifica left join gruppi on gruppi.id = gruppi_modifica.id_gruppo_modifica
where
gruppi.id = ? and
gruppi_modifica.id_gruppo in (
select distinct
gruppi.id
from gruppi
left join anagrafiche_gruppi on anagrafiche_gruppi.id_gruppi = gruppi.id
left join anagrafiche on anagrafiche.id = anagrafiche_gruppi.id_anagrafiche
where
anagrafiche.login = ?
)
__SQL__
my $sth = $Session{Dbh}->prepare($query);
$sth->execute($id_gruppi, $Session{Login});
if($sth->rows != 1){
# annullo l'inserimento o modifica annullando il campo
delete $FIELDS_INSERT->{'id_gruppi'};
die "Richiesta di assegnazione del gruppo (id=$id_gruppi) non autorizzata!\n";
}
}
</%perl>
</%method>
 
 
/tags/2.0/htdocs/data/public/funzioni.mql
0,0 → 1,132
 
<%method FROM>funzioni</%method>
 
<%method FUNZIONE>Funzioni</%method>
 
<%method DESCRIPTION>Funzioni applicative</%method>
 
<%method CHILDREN>funzioni_permessi, funzioni_help</%method>
<%method CHILDREN_FIELDS>id, id</%method>
 
<%method FIELDS>nome, descrizione, commento, menu_ord, menu_contents, menu_father_id, menu_status, menu_cmdtype, menu_icon, menu_style, menu_command</%method>
 
<%method FIELDS_NOT_NULL>nome</%method>
 
<%method FIELDS_DESCR>Nome, Descrizione, Commento, Ord\, Menu\, Menu padre, Menu avviso, Tipo comando\, Icona, Menu style, Comando Menu</%method>
 
<%method FIELDS_NO_WRITE>permissions</%method>
 
<%method FIELDS_NEW>,,,,,,,,,,,</%method>
 
<%method FIND_FIELDS>\
nome, descrizione, menu_contents, menu_father_id
</%method>
 
<%method ORDER>order by menu_ord, nome, id</%method>
 
<%method menu_ord_FIELD><& /input/number.comp, ValMin => 0, ValMax => 9999, length => 4, NumDec => 0, NumCifre => 4, %ARGS &></%method>
 
<%method commento_FIELD>\
<& /input/string.comp, %ARGS, rows=>2, cols=>80 &>
</%method>
 
<%method menu_cmdtype_FIELD>\
<& /input/select.comp, %ARGS, list => [
'' => 'nessun comando',
'u' => 'Link WEB',
'U' => 'Link WEB - applicando eval Perl',
'j' => 'Client Javascript',
'J' => 'Client Javascript - applicando eval Perl',
]&>
</%method>
 
<%method menu_style_FIELD>\
<& /input/string.comp, %ARGS, width => '500' &>
</%method>
<%method menu_command_FIELD>\
<& /input/string.comp, %ARGS, rows=>4, cols=>80 &>
</%method>
 
<%method menu_father_id_FIELD>\
<& SELF:GenericSelect_FIELD, from => 'sel_funzioni', %ARGS, widget => 'htmlselect', width => 120 &>
<%attr>
find_select_list => ['=' => '=']
select_from => 'sel_funzioni'
</%attr>
</%method>
 
<%method DELETE>\
<%args>$KEY</%args>
delete from gruppi_funzioni where id_funzioni = <%$KEY%>;\
delete from <&SELF:FROM&> where <&SELF:KEY&> = <%$KEY%>;
</%method>
 
<%doc>
########################## Selettore delle Icone #######################
 
ATTENZIONE: quando sarà disponibile il widget select con il componente di dojo
si potrà eliminare questa 'pezza'
 
Estraggo l'elenco dei nomi delle classi delle icone disponibili
dal file /css/icons_controls.css che contiene delle righe del tipo:
.masonSqlIcons.cancel { background-position: 0px 0px; }
.masonSqlIcons.change { background-position: -22px 0px; }
</%doc>
<%method menu_icon_FIELD>
<%args>
$id # identificatore del componente nel documento HTML
</%args>
<%perl>
my $css = $m->scomp('/css/icons_controls.css');
my @list;
$css =~ s/^\s*\.masonSqlIcons\.(\w+)\s*\{/push(@list,$1)/meg;
</%perl>
<script>
require(["dojo/parser", "dijit/form/Select"]);
</script>
<span id="<% $id %>">
<div id="<% $id %>_dojo" data-dojo-type="dijit/form/Select" style="width:140px; height:28px;" maxHeight="-1">
<span value="">...</span>
% foreach my $value (@list){
<span value="<% $value %>"><span class="dijitInline masonSqlIcons <% $value %>"></span> <% $value %></span>
% }
</div>
</span>
<script>
require(["dojo/dom", "dijit/registry", "dojo/dom-class"], function (dom, registry, domClass){
masonSql.once('ready', function(data){
var Obj = Input_Init('<% $id %>', 'Icona del menu');
Obj.dojo_widget = registry.byId('<% $id %>_dojo');
Obj.get_value = function(){
return this.dojo_widget.get('value');
};
Obj.set_value = function(value){
return this.dojo_widget.set('value', value);
};
Obj.Readonly = function(read){
if(read == null){
return this.dojo_widget.get('readOnly');
}else{
this.dojo_widget.set('readOnly', read);
this.set_status();
return read;
}
};
Obj.Readonly(true);
Obj.set_status = function(status){
var classList = this.eval_status(status);
if(this.prev_classList != classList){
this.prev_classList && domClass.remove(this.dojo_widget.domNode, this.prev_classList);
console.debug('set_status obj <% $id %> status:' + status + ' classList:' + classList + ' className:' + this.className);
domClass.add(this.dojo_widget.domNode, classList);
this.prev_classList = classList;
}
};
window.Id_<% $id %> = Obj;
});
});
</script>
</%method>
 
 
/tags/2.0/htdocs/data/public/gruppi_anagrafiche.mql
0,0 → 1,22
<%doc>
</%doc>
<%method FUNZIONE>Gruppi</%method>
<%method DESCRIPTION>Utenti del gruppo</%method>
 
<%method FROM>anagrafiche_gruppi</%method>
 
<%method FIELDS>id_anagrafiche</%method>
 
<%method FIELDS_NOT_NULL>id_anagrafiche</%method>
 
<%method FIELDS_DESCR>Utenti</%method>
 
%# formato: idref:table:key
%# idref = chiave_locale key = tabella padre
<%method FATHER>id_gruppi:gruppi</%method>
 
<%method FIELDS_RO>\
% if(!$Session{Group_Admins}){
*\
% }
</%method>
/tags/2.0/htdocs/data/public/gruppi_modifica.mql
0,0 → 1,38
<%doc>
Tabella "public.gruppi_modifica"
Colonna | Tipo | Modificatori
--------------------+---------+-------------------------------------------------------
id | integer | not null default nextval('gruppi_modifica_seq'::text)
id_gruppo | integer | not null
id_gruppo_modifica | integer | not null
Indici:
"gruppi_modifica_pkey" chiave primaria, btree (id)
"fki_gruppi_modifica_id_gruppo" btree (id_gruppo)
"fki_gruppi_modifica_id_gruppo_modifica" btree (id_gruppo_modifica)
Vincoli di integrità referenziale
"gruppi_modifica_id_gruppo" FOREIGN KEY (id_gruppo) REFERENCES gruppi(id) ON UPDATE RESTRICT ON DELETE RESTRICT
"gruppi_modifica_id_gruppo_modifica" FOREIGN KEY (id_gruppo_modifica) REFERENCES gruppi(id) ON UPDATE RESTRICT ON DELETE RESTRICT
</%doc>
<%method FUNZIONE>Gruppi</%method>
<%method DESCRIPTION>Gruppi modificabili</%method>
 
<%method FROM>gruppi_modifica</%method>
 
<%method FIELDS>id_gruppo_modifica</%method>
 
<%method FIELDS_NOT_NULL>id_gruppo_modifica</%method>
 
<%method FIELDS_DESCR>Gruppi</%method>
 
<%method id_gruppo_modifica_ALIAS>id_gruppi</%method>
 
%# formato: idref:table:key
%# idref = chiave_locale key = tabella padre
<%method FATHER>id_gruppo:gruppi</%method>
 
<%method FIELDS_RO>\
% if(!$Session{Group_Admins}){
*\
% }
</%method>
 
/tags/2.0/htdocs/data/public/logs.mql
0,0 → 1,174
<%doc>
</%doc>
 
<%flags>
inherit => 'logs.common.mql'
</%flags>
 
<%method TABLE_ROWS><% $ARGS{'rows'} ? $ARGS{'rows'} : '20' %></%method>
 
<%method AUTHORIZED_KEYWORDS>AND, IN</%method>
 
<%method IS_WHERE2>
<%perl>
my $where = $Session{ARGS}->{where2};
if($where && !$where =~ m/^table_name = '\w+\.\w+' AND id_record IN \([\d,]+\)$/){
die "SQL injection detection width [$where]. Execution aborted!";
}
return $where;
</%perl>
</%method>
 
<%method FIELDS_HIDDEN>\
% if($m->comp('SELF:IS_WHERE2')){
table_name
% }
</%method>
 
<%method DESCRIPTION>Log modifiche al database da parte degli utenti</%method>
 
<%method FIELDS>timestamp, id_anagrafiche, table_name, id_record, field, old_value, new_value</%method>
 
<%method FIELDS_DESCR>Data e ora, Utente, <% $Session{Group_Admins} ? 'Scheda (tabella)' : 'Scheda' %>, Id, Campo, Valore precedente, Nuovo valore</%method>
 
<%method FIND_FIELDS>
% if(!$m->comp('SELF:IS_WHERE2')){
timestamp, timestamp, id_anagrafiche, table_name, field, old_value, new_value, id_record, id_record
% }
</%method>
 
<%method FIELDS_RO>*</%method>
 
<%method FIELDS_NO_WRITE>*</%method>
 
<%method ORDER>order by timestamp desc, id desc</%method>
 
<%method timestamp_FIELD><& /input/span.comp, width => 120, %ARGS &></%method>
 
<%method timestamp_FIND_FIELD>
<& /input/timestamp.comp, %ARGS &>
<%attr>
find_select_list => ['<=' => '<=', '>=' => '>=']
</%attr>
</%method>
 
<%method field_OUT_FILTER>\
<%args>
$Value
$Key
$names
$fetch_row
</%args>
<%perl>
if(length $Value){
my $field = $fetch_row->{field};
if($Value eq 'ARC.'){
$Value = 'Arc. file'.($Session{Group_Admins} ? " ($field)" : '');
}else{
my $table_name = $fetch_row->{table_name};
$table_name =~ s/\./\//;
my $base_comp = $Session{"Logs_report_COMP_$table_name"};
# cerco del campo $field l'attributo 'select_from'
if($base_comp){
# valuto la descrizione del campo corrispondente all'oggetto .mql
my $descr = $base_comp->scall_method('INFO', NAME => $field, WHAT => 'DESCR');
$Value = $descr ? $descr.($Session{Group_Admins} ? " ($field)" : '') : $field ;
$Value =~ s/[\\\/]//sg;
}else{
$Value = $field;
}
$Value =~ s/\<br\>/ /ig;
}
}
</%perl>
$_ = '<%$Value |js%>';
</%method>
<%method field_FIELD>
<& /input/string.comp, %ARGS, size => $Session{Group_Admins} ? 18 : 12 &>
</%method>
 
<%method new_value_OUT_FILTER>\
<%args>
$Value
$Key
$names
$fetch_row
</%args>
<%perl>
my $param;
if(length $Value){
my $table_name = $fetch_row->{table_name};
$table_name =~ s/\./\//;
my $field = $fetch_row->{field};
my $base_comp = $Session{"Logs_report_COMP_$table_name"};
# cerco del campo $field l'attributo 'select_from'
# valuto gli attributi del widget corrispondente all'oggetto .mql, quando esiste
$param = $base_comp ? FieldFilter_from($base_comp, $field, $Key, $Value, $names, $fetch_row) : '';
}
</%perl>
$param = '<% $param |js%>';
$_ = '<%$Value |js%>';
</%method>
 
<%method old_value_OUT_FILTER><& SELF:new_value_OUT_FILTER, %ARGS&></%method>
 
<%method old_value_FIELD>
<& /input/span.comp, %ARGS, width => 160, disp_template => q{P.join('; ')}.($Session{Group_Admins} ? q{+' ('+P[-1]+')'} : '') &>
</%method>
 
<%method new_value_FIELD>
<& /input/span.comp, %ARGS, width => 160, disp_template => q{P.join('; ')}.($Session{Group_Admins} ? q{+' ('+P[-1]+')'} : '') &>
</%method>
 
<%method old_value_FIND_FIELD>
<& /input/string.comp, %ARGS &>
</%method>
 
<%method new_value_FIND_FIELD>
<& /input/string.comp, %ARGS &>
</%method>
 
<%method FORM_INCLUDE_POST>
<%args>
$Display
$Recordset
</%args>
<script>
// chiamata da id_record_FIELD per visualizzare il form corrispondente al campo variato
<% $Display %>.view_form = function (widget){
// verifico che il widget non sia disabilitato
if(widget.Readonly()){
return false;
}
var table_name = <%$Display%>.getField('table_name', widget.dbRow).get_value();
// costruisco un oggetto 'display' minimale con i soli elementi necessari a lanciare il form
var display_log = {
prefix: 'Log_detail',
dataBinding: new DataBinding('Log_detail_db', 'log', 'Log ' + table_name),
gotoRecords: function (mode, key, recordset){
return this.dataBinding.gotoRecords(mode, key, recordset);
},
openFormDetailByKey: DisplayBinding_openFormDetailByKey
};
var d = new Date();
display_log.openFormDetailByKey('rewind', null, table_name, 1000, 600, 'Log ' + table_name, {
U: d.getTime() + '' + Math.floor(1000 * Math.random()),
rows: null,
disp_update: '',
pk: widget.get_value()
});
}
 
<%$Display%>.onchange = function(){
%# // disabilito i pulsanti che puntano a record cancellati
var Col = this.dataBinding.pos_name['id_record'];
for(var Row=0; Row<this.fields.length; Row++){
var Button = this.fields[Row][Col];
if(Button.get_param() == 'D'){
Button.Readonly(true);
}
}
};
</script>
</%method>
/tags/2.0/htdocs/data/public/messages.mql
0,0 → 1,194
<%doc>
Gestione messaggi
</%doc>
 
<%method FUNZIONE>Messages</%method>
 
<%method DESCRIPTION>Messaggi inviati agli utenti</%method>
 
<%method FIELDS>
owner, modification_time,
<% $r->dir_config('MailSmtpServer') ? 'email,' : '' %>
transmission_time,
<% $r->dir_config('SMSPlatform') ? 'sms,' : '' %>
subject,
<% $r->dir_config('SMSPlatform') ? 'short_message,' : '' %>
message
</%method>
 
<%method FIELDS_NEW>,,<% $r->dir_config('MailSmtpServer') ? ',' : '' %>,<% $r->dir_config('SMSPlatform') ? ',' : '' %>,<% $r->dir_config('SMSPlatform') ? '' : '' %>,</%method>
 
<%method FIELDS_NOT_NULL>message</%method>
 
<%method FIELDS_DESCR>
Proprietario, Data ultima modifica\
<% $r->dir_config('MailSmtpServer') ? '\,E-Mail' : '' %>,
Data di trasmissione\
<% $r->dir_config('SMSPlatform') ? '\,S.M.S.' : '' %>,
Oggetto\
<% $r->dir_config('SMSPlatform') ? ',Messaggio breve' : '' %>,
Messaggio
</%method>
 
<%method FIELDS_RO>owner, modification_time, transmission_time</%method>
 
<%method FIND_FIELDS>owner, transmission_time, transmission_time, subject<% $r->dir_config('SMSPlatform') ? ', short_message' : '' %>, message</%method>
 
<%method PERMISSION><%perl>
my $permission = $m->scomp('SELF:PERMISSION_BY_PROFILE');
my $Record0 = $Session{ARGS}->{Record0};
# disabilito cancellazione e modifica se record trasmesso
if($Record0->{'modification_time'} && $Record0->{'transmission_time'}){
$permission =~ s/DELETE//;
$permission =~ s/UPDATE//;
}
$m->out($permission);
</%perl></%method>
 
<%method ORDER>order by modification_time desc, id desc</%method>
 
<%method CHILDREN>messages_users</%method>
<%method CHILDREN_FIELDS>id</%method>
 
<%method message_FIELD><& /input/string.comp, %ARGS, rows => 5, cols => 80 &></%method>
 
<%method message_FIND_FIELD>
<& /input/string.comp, %ARGS &>
<%attr>
find_select_list => ['~*' => '~*', 'ilike' => 'ilike']
</%attr>
</%method>
 
<%method short_message_FIELD><& /input/string.comp, %ARGS, rows => 2, cols => 80 &></%method>
 
<%method short_message_FIND_FIELD>
<& /input/string.comp, %ARGS &>
<%attr>
find_select_list => ['~*' => '~*', 'ilike' => 'ilike']
</%attr>
</%method>
 
<%method owner_FIELD>\
<& SELF:id_anagrafiche_FIELD, %ARGS, empty_descr => 'Gestore sistema' &>
<%attr>
find_select_list => ['=' => '=']
select_from => 'anagrafiche'
</%attr>
</%method>
 
<%method PRE_UPDATE>
<%args>
$KEY
$FIELDS_UPDATE
</%args>
<%perl>
$m->comp('SELF:PRE_INSERT', FIELDS_INSERT => $FIELDS_UPDATE);
</%perl>
</%method>
<%method PRE_INSERT>
<%args>
$FIELDS_INSERT
</%args>
<%perl>
$FIELDS_INSERT->{'owner'} = $Session{User_id};
my($sec, $min, $hour, $mday, $mon, $year) = localtime time;
$FIELDS_INSERT->{'modification_time'} = sprintf '%04i-%02i-%02i %02i:%02i:%02i', 1900+$year, $mon+1, $mday, $hour, $min, $sec;
</%perl>
</%method>
 
<%method FIELDS_INCLUDE_POST>
<%args>
$Display
</%args>
<br>
&nbsp;&nbsp;&nbsp;<& /input/button.comp, caption => 'Conferma invio messaggio', style => 'display:none;',
id => $Display.'_send_button', onclick => "$Display.invio_messaggio();" &>
<br>&nbsp;
<script>
<%$Display%>.send_button = document.getElementById('<%$Display%>_send_button');
<%$Display%>.invio_messaggio = function(){
// valuto se ci sono registrazioni della tabella
var mess = 'Siete certi di voler inviare il messaggio ';
mess += this.dataBinding.children[0].max_rows ? 'agli utenti selezionati?' : 'a tutti gli utenti?';
if(confirm(mess)){
this.callRemote('send', {id:this.dataBinding.keys[0]});
}
}
</script>
</%method>
 
<%method FORM_INCLUDE_POST>
<%args>
$Display
</%args>
<script>
<%$Display%>.onreadonly = function (set){
var id = this.dataBinding.keys[0];
var transmission_time = this.getField('transmission_time').get_value();
// bottone attivo e visibile se record in lettura nonché non vuoto e non trasmesso
this.send_button.set_value(set ? id && !transmission_time : '');
this.send_button.style.display = set && id && !transmission_time ? '' : 'none';
}
<%$Display%>.onchange = function (set){
var id = this.dataBinding.keys[0];
var transmission_time = this.getField('transmission_time').get_value();
// bottone attivo e visibile se record in lettura nonché non vuoto e non trasmesso
this.send_button.set_value(this.readOnly() ? id && !transmission_time : '');
this.send_button.style.display = this.readOnly() && id && !transmission_time ? '' : 'none';
}
</script>
</%method>
 
<%method CALL_REMOTE_send>
<%args>
$id
$dbms_params
</%args>
<%perl>
# verifico se devo inviare a tutti gli utenti o solo ad un elenco ristretto
my $sth = ExecQuery('Test list users', undef, q{
select count(*) from public.messages_users
where id_messages = ?
}, $id);
if($sth->fetchrow_arrayref->[0] >= 1){
# esplodo la lista degli utenti se ci sono indicati dei gruppi e modifico lo stato del messaggio
my $sth = ExecQuery('Explode message\'s list users', undef, q{
insert into public.messages_users (id_messages, id_anagrafiche)
select * from (
select distinct
?::integer as id_messages,
anagrafiche_gruppi.id_anagrafiche as id_anagrafiche
from public.messages_users
left join public.anagrafiche_gruppi on anagrafiche_gruppi.id_gruppi = - messages_users.id_anagrafiche
left join public.anagrafiche on anagrafiche.id = anagrafiche_gruppi.id_anagrafiche and anagrafiche.login is not null
where messages_users.id_messages = ?::integer and messages_users.id_anagrafiche < 0 and anagrafiche_gruppi.id_anagrafiche is not null
) as lista
where id_anagrafiche not in ( -- escludo dall'inserimento le anagrafiche che sono già nella lista
select
messages_users.id_anagrafiche
from public.messages_users
where messages_users.id_messages = ?::integer and id_anagrafiche > 0
);
delete from public.messages_users
where messages_users.id_messages = ?::integer and id_anagrafiche < 0;
update public.messages set transmission_time = now() where id = ?::integer;
}, $id, $id, $id, $id, $id);
}else{
# inserisco nella lista tutti gli utenti e modifico lo stato del messaggio
my $sth = ExecQuery('Insert all users in list', undef, q{
insert into public.messages_users (id_messages, id_anagrafiche)
select
?::integer as id_messages,
gruppi_and_anagrafiche.id as id_anagrafiche
from public.gruppi_and_anagrafiche
where gruppi_and_anagrafiche.id > 0;
update public.messages set transmission_time = now() where id = ?::integer;
}, $id, $id);
}
$Session{Dbh}->commit;
</%perl>
// aggiorna il record corrente
<%$dbms_params->{'name'}%>.children[0].loadRecords('reload');
</%method>
/tags/2.0/htdocs/data/public/odt_portion_queries.mql
0,0 → 1,17
<%method FUNZIONE>OdtReports</%method>
<%method FROM>odt_report_portions</%method>
<%method DESCRIPTION>Portion Queries</%method>
 
<%method FIELDS>name, query</%method>
<%method FIELDS_DESCR>Portion Name, Query</%method>
<%method FIND_FIELDS>name</%method>
 
<%method FATHER>id_odt_reports:odt_reports</%method>
 
<%method ORDER>order by ord, id</%method>
<%method CHILD_TEMPLATE>FORM</%method>
 
<%method name_FIELD><& /input/string.comp, %ARGS, size => 30 &></%method>
<%method query_FIELD><& /input/string.comp, %ARGS, rows => 35, cols => 100 &></%method>
 
/tags/2.0/htdocs/data/public/odt_report_fields.mql
0,0 → 1,15
<%method FUNZIONE>OdtReports</%method>
 
<%method DESCRIPTION>Report Fields</%method>
 
<%method TABLE_ROWS>14</%method>
 
<%method FATHER>id_odt_reports:odt_reports</%method>
 
<%method FIELDS>key, function, format</%method>
<%method FIELDS_DESCR>Name, Value, Formatting</%method>
<%method ORDER>order by key, id</%method>
<%method key_FIELD><& /input/string.comp, %ARGS, width => 100 &></%method>
<%method function_FIELD><& /input/string.comp, %ARGS, width => 500 &></%method>
<%method format_FIELD><& /input/string.comp, %ARGS, width => 200 &></%method>
/tags/2.0/htdocs/data/public/odt_report_portions.mql
0,0 → 1,49
 
<%method FROM>odt_report_portions</%method>
 
<%method FUNZIONE>OdtReports</%method>
 
<%method DESCRIPTION>Report Portions</%method>
 
<%method DETAIL_FROM>public/odt_portion_queries</%method>
 
<%method TABLE_ROWS>14</%method>
 
<%method FIELDS>ord, name, type, id_father, file_name, obj_ref</%method>
 
<%method FIELDS_NOT_NULL>ord</%method>
 
<%method FIELDS_DESCR>Order, Portion Name, Portion Type, Father Portion, Filename, Obj. Reference</%method>
 
<%method ORDER>order by ord, id</%method>
 
<%method FATHER>id_odt_reports:odt_reports</%method>
 
<%method name_FIELD><& /input/string.comp, %ARGS, width => 70 &></%method>
 
<%method ord_FIELD><& /input/number.comp, %ARGS, length => 3 &></%method>
 
<%method file_name_FIELD><& /input/string.comp, %ARGS, width => 200 &></%method>
 
<%method obj_ref_FIELD><& /input/string.comp, %ARGS, width => 200 &></%method>
 
<%method type_FIELD>
<& /input/select.comp, %ARGS, list => [
'' => '',
'base_report' => 'ODT base template',
'odt_section' => 'ODT section',
'odt_table' => 'ODT table',
'odt_file' => 'ODT file',
'pdf_file' => 'PDF file (attach to PDF)',
'pdf_report' => 'ODT report (attach to PDF)',
]&>\
</%method>
 
<%method id_father_FIELD>
<& SELF:GenericSelect_FIELD, buffer => 'father', from => 'sel_odt_report_portions', widget => 'htmlselect', width => '80px', %ARGS &>
<%attr>
find_select_list => ['=' => '=']
select_from => 'sel_odt_report_portions'
</%attr>
</%method>
 
/tags/2.0/htdocs/data/public/sel_funzioni.mql
0,0 → 1,13
<%flags>
inherit => 'funzioni.mql'
</%flags>
 
<%method FIELDS>nome</%method>
 
<%method SELECT_FIELDS>nome</%method>
 
<%method FIELDS_DESCR>Nome funzione</%method>
 
<%method ORDER>nome, id</%method>
 
<%method WHERE>id != <% $Session{ARGS}{child_id} || -1 %></%method>
/tags/2.0/htdocs/data/public/sel_gruppi_and_anagrafiche.mql
0,0 → 1,17
<%doc>
Elenco dei gruppi e degli utenti
</%doc>
 
<%method FROM>gruppi_and_anagrafiche</%method>
 
<%method FUNZIONE>Anagrafiche</%method>
 
<%method DESCRIPTION>Gruppi e Utenti</%method>
 
<%method FIELDS_DESCR>Gruppo o utente</%method>
 
<%method FIELDS>descrizione</%method>
 
<%method SELECT_FIELDS>CASE WHEN id < 0 THEN 'GRUPPO - ' || descrizione || ' -' ELSE descrizione END</%method>
 
<%method ORDER>id > 0, descrizione, id</%method>
/tags/2.0/htdocs/data/public/session.mql
0,0 → 1,26
<%method FUNZIONE>Session</%method>
 
<%method FROM>session</%method>
 
<%method DESCRIPTION>Sessioni utenti</%method>
 
<%method FIELDS>id_anagrafiche, user_ip, session, session_time, session_inactive_time, user_agent</%method>
 
<%method FIELDS_DESCR>Utente, Indirizzo IP, Sessione, Ultima login, Inattivo, Browser</%method>
 
<%method FIND_FIELDS>id_anagrafiche, user_ip, session, session_time</%method>
 
<%method FORM_TYPE>TABLE</%method>
<%method TABLE_ROWS>20</%method>
<%method ORDER>session_time DESC, id DESC</%method>
 
<%method session_inactive_time_OUT_FILTER>
my $m = int(time/60) - $_;
my $h = int($m/60);
$m -= $h*60;
$_ = $h || $m ? sprintf('%02i:%02i', $h, $m) : '';
</%method>
 
<%method user_ip_FIELD><& /input/string.comp, width => '100px', %ARGS &></%method>
<%method session_inactive_time_FIELD><& /input/span.comp, width => '48px', %ARGS &></%method>
<%method user_agent_FIELD><& /input/span.comp, width => '180px', %ARGS &></%method>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/data/public/user_messages.mql
0,0 → 1,75
 
<%method FROM>messages</%method>
 
<%method FUNZIONE>User_messages</%method>
 
<%method FORM_TYPE>TABLE</%method>
<%method TABLE_ROWS>10</%method>
 
<%method CHILDREN>user_messages_body</%method>
<%method CHILDREN_FIELDS>messages.id</%method>
 
<%method DESCRIPTION>Messaggi inviati all'utente <%$Session{Nominativo}%></%method>
 
<%method FIELDS>owner, transmission_time, notification_time, subject</%method>
 
<%method FIELDS_DESCR>Mittente\, Data di trasmissione, Data di notifica, Oggetto</%method>
 
<%method WHERE>transmission_time is not null</%method>
 
<%method ORDER>notification_time desc, transmission_time desc, id desc</%method>
 
<%method ATTRS>
notification_time => {
TYPE => 'timestamp'
}
</%method>
 
<%method JOIN_TABLES>
public.messages
inner join public.messages_users on messages_users.id_messages = messages.id
and messages_users.id_anagrafiche = <%$Session{User_id}%>
</%method>
 
<%method FIELDS_RO>*</%method>
 
<%method FIND_FIELDS>owner, subject, transmission_time, transmission_time, notification_time, notification_time</%method>
 
<%method subject_FIELD>
<& /input/string.comp, %ARGS, width => '400' &>
</%method>
 
<%method subject_FIND_FIELD>
<& /input/string.comp, %ARGS &>
<%attr>
find_select_list => ['~*' => '~*', 'ilike' => 'ilike']
</%attr>
</%method>
 
<%method owner_FIELD>\
<& SELF:id_anagrafiche_FIELD, %ARGS, empty_descr => 'Gestore sistema' &>
<%attr>
find_select_list => ['=' => '=']
select_from => 'anagrafiche'
</%attr>
</%method>
 
<%method FORM_INCLUDE_POST>
<%args>
$Display
$Recordset
</%args>
<script>
<%$Display%>.onchange = function (){
require(["dojo/dom-class"], function(domClass){
for(var row = 0; row < <%$Recordset%>.keys.length; row++){
if(<%$Recordset%>.keys[row] && !<%$Recordset%>.get_value('notification_time', row)){
domClass.replace(<%$Display%>.getField('subject', row), 'MessagesNewMessage', 'widgetRo');
}else{
domClass.replace(<%$Display%>.getField('subject', row), 'widgetRo', 'MessagesNewMessage');
}
}
});
}
</script>
</%method>
/tags/2.0/htdocs/data/public/autohandler
0,0 → 1,35
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2018 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
<%method id_anagrafiche_FIELD>\
<& SELF:GenericSelect_FIELD, from => 'public/sel_anagrafiche', widget => 'divselect', width => '200',
cols => $Session{Group_Admins} ? [100, 100, 100] : [100, 100],
disp_template => q{P[0] + ' ' + P[1]}.($Session{Group_Admins} ? q{ + (P[2] ? ' (' + P[2] + ')' : '')} : ''),
%ARGS
&>
<%attr>
find_select_list => ['=' => '=']
select_from => 'public/sel_anagrafiche'
</%attr>
</%method>
 
<%method id_gruppi_FIELD>\
<& SELF:GenericSelect_FIELD, width => 220, from => 'public/sel_gruppi', %ARGS &>
<%attr>
find_select_list => ['=' => '=']
select_from => 'public/sel_gruppi'
</%attr>
</%method>
 
<%method commento_FIELD>\
<& /input/string.comp, %ARGS, rows=>6, cols=>60 &>
</%method>
 
/tags/2.0/htdocs/data/public/autorizzazioni.mql
0,0 → 1,22
<%doc>
</%doc>
 
<%method FROM>autorizzazioni</%method>
 
<%method FUNZIONE>ListAuth</%method>
 
<%method DESCRIPTION>Autorizzazioni</%method>
 
<%method FIELDS>nome, descrizione, commento</%method>
 
<%method FIELDS_NOT_NULL>nome, descrizione</%method>
 
<%method FIELDS_DESCR>Nome autorizzazione, Descrizione, Commento</%method>
 
<%method FIELDS_NEW>,,</%method>
 
<%method FIND_FIELDS>nome, descrizione</%method>
 
<%method ORDER>order by nome</%method>
 
 
/tags/2.0/htdocs/data/public/funzioni.common.mql
0,0 → 1,18
<%method FUNZIONE>Funzioni</%method>
 
<%method FROM>funzioni</%method>
 
<%method CHILD_TEMPLATE>FORM</%method>
 
<%method PERL_EVAL_PRE>
$ARGS{'disp_navbar'} = 0; # non visualizza il form padre con i pulsanti << < > >> Goto[ ] di navigazione
$ARGS{'disp_insert'} = 0; # ... pulsante inserimento
$ARGS{'disp_delete'} = 0; # ... pulsante cancella
$ARGS{'disp_print'} = 0; # ... pulsante stampa
$ARGS{'disp_xls'} = 0; # ... pulsante espostazione XLS
$ARGS{'disp_log'} = 0; # ... pulsante visualizzazione Log
</%method>
<%method FATHER>id:funzioni</%method>
<%method KEY>id</%method>
/tags/2.0/htdocs/data/public/funzioni_help.mql
0,0 → 1,15
<%flags>
inherit => 'funzioni.common.mql'
</%flags>
<%method DESCRIPTION>Help</%method>
 
<%method FIELDS>help</%method>
 
<%method FIELDS_DESCR>Help</%method>
 
<%method help_FIELD>
<& /input/FCKeditor.comp, %ARGS, width => '800px', height => '400px',
editWidth => '800px', editHeight => '400px' &>
</%method>
/tags/2.0/htdocs/data/public/funzioni_permessi.mql
0,0 → 1,87
<%flags>
inherit => 'funzioni.common.mql'
</%flags>
<%method DESCRIPTION>Permessi</%method>
 
<%method FIELDS>permissions</%method>
 
<%method SELECT_FIELDS>'' as permissions</%method>
 
<%method FIELDS_DESCR>Permessi</%method>
 
<%method FIELDS_NO_WRITE>permissions</%method>
 
<%method FIELDS_NEW>perm:</%method>
 
<%method permissions_FIELD>
<& /input/Permission.comp, %ARGS &>
</%method>
 
<%method UpdatePermissions>\
<%args>
$KEY
$PERM
</%args>
<%perl>
my @permissions = split /\n/, $PERM;
# DEBUG $PLogger->debug(sub{ '?' x 20, "$KEY => permission: [$PERM]"; });
if(shift(@permissions) eq 'perm:'){
# cancello i permessi presenti
my $sth = $Session{Dbh}->prepare(q|
delete from gruppi_funzioni where id_funzioni = ?;
|);
$sth->execute($KEY);
# nuovi permessi ...
$sth = $Session{Dbh}->prepare(q|insert into gruppi_funzioni (id_funzioni, id_gruppi, id_autorizzazioni) values (?, ?, ?)|);
foreach my $row (@permissions){
my($group, $perm) = split /\s+/, $row, 2;
$group =~ s/^g//;
$perm =~ s/^p//;
$PLogger->debug(sub{ "NEW QUERY-permissions_IN_FILTER=[insert into gruppi_funzioni (id_funzioni, id_gruppi, id_autorizzazioni) values ($KEY, $group, $perm)]"; });
$sth->execute($KEY, $group, $perm);
}
}
</%perl>
</%method>
 
<%method POST_INSERT>\
<%args>
$KEY
$ROW
</%args>
<%perl>
# 10== posizione del campo permissions in <%method FIELDS>
$m->scomp('SELF:UpdatePermissions', KEY => $KEY, PERM => $ROW->[10]);
</%perl>
</%method>
 
<%method permissions_IN_FILTER>\
<%args>
$Key
$Value
</%args>
<%perl>
# solo se c'è la chiave del record effettuo l'aggiornamento
if($Key){
$m->scomp('SELF:UpdatePermissions', KEY => $Key, PERM => $Value);
}
</%perl>\
</%method>
 
<%method permissions_OUT_FILTER>\
<%args>
$Key
</%args>
<%perl>
my $permissions = "perm:\n";
# devo estrarre i permessi associati ai gruppi per la funzione di id = $Key
my $sth = $Session{Dbh}->prepare(q|select id_gruppi, id_autorizzazioni from gruppi_funzioni where id_funzioni = ?|);
$sth->execute($Key);
while(my $auth = $sth->fetchrow_arrayref){
$permissions .= "g$auth->[0] p$auth->[1]\n";
}
</%perl>
$_ = q|<%$permissions%>|;
</%method>
 
/tags/2.0/htdocs/data/public/gruppi.mql
0,0 → 1,31
<%doc>
Tabella "public.gruppi"
Colonna | Tipo | Modificatori
-------------+------------------------+----------------------------------------------
id | integer | not null default nextval('gruppi_seq'::text)
nome | character varying(16) |
descrizione | character varying(60) |
commento | character varying(240) |
Indici:
"gruppi_pkey" chiave primaria, btree (id)
"idx_nome" unica, btree (nome)
</%doc>
 
<%method FROM>gruppi</%method>
 
<%method FUNZIONE>Gruppi</%method>
 
<%method DESCRIPTION>Gruppi</%method>
 
<%method FIELDS>nome, descrizione, commento</%method>
 
<%method FIELDS_NOT_NULL>nome, descrizione</%method>
 
<%method FIELDS_DESCR>Nome, Descrizione, Commento</%method>
 
<%method FIND_FIELDS>nome, descrizione</%method>
 
<%method ORDER>order by nome</%method>
 
<%method CHILDREN>gruppi_anagrafiche, gruppi_modifica</%method>
<%method CHILDREN_FIELDS>id, id</%method>
/tags/2.0/htdocs/data/public/gruppi_funzioni.mql
0,0 → 1,28
<%doc>
</%doc>
<%method FUNZIONE>Gruppi</%method>
<%method DESCRIPTION>Autorizzazioni</%method>
 
<%method FIELDS>id_gruppi, id_autorizzazioni</%method>
 
<%method FIELDS_NOT_NULL>id_gruppi, id_autorizzazioni</%method>
 
<%method FIELDS_DESCR>Gruppo, Autorizzazione</%method>
 
<%method FIND_FIELDS>\
id_gruppi
</%method>
 
<%method ORDER>order by id_gruppi, id_autorizzazioni</%method>
 
<%method id_autorizzazioni_FIELD>\
<& SELF:GenericSelect_FIELD, from => 'sel_autorizzazioni', %ARGS &>
<%attr>
find_select_list => ['=' => '=']
select_from => 'sel_autorizzazioni'
</%attr>
</%method>
 
%# formato: idref:table:key
%# idref = chiave_locale key = tabella padre
<%method FATHER>id_funzioni:funzioni</%method>
/tags/2.0/htdocs/data/public/logs.common.mql
0,0 → 1,125
<%doc>
Used by logs.mql and logs_report.mql
</%doc>
 
<%method FUNZIONE>Logs</%method>
 
<%method FATHER_TEMPLATE>TABLE</%method>
 
<%method OUT_FILTER>\
<%args>
$row
</%args>
<%perl>
my $table_name = $row->{table_name};
$table_name =~ s/\./\//;
my $cache_table = "Logs_report_COMP_$table_name";
if(!$Session{$cache_table}){
my $DataBaseUrl = $r->dir_config('DataBaseUrl');
my $table = "$DataBaseUrl/$table_name.mql";
my $base_comp = $m->fetch_comp($table);
my $sth;
if($base_comp){
my $KEY = $base_comp->scall_method('KEY');
my $schema = $base_comp->scall_method('SCHEMA');
my $query = $base_comp->scall_method('NUMREC', WHERE => qq{where $KEY = ?});
$sth = $Session{Dbh}->prepare("SET search_path TO $schema, public;\n$query");
}
# Save base component used when call next <field>_OUT_FILTER filters
$Session{$cache_table} = $base_comp;
$Session{'STH_'.$cache_table} = $sth;
}
my $base_comp = $Session{$cache_table};
my $permission;
if($base_comp){
if($Session{Group_Admins}){
# Force LOG permission to Admins
$permission = 'LOG';
}else{
# Autorizzazione in base alla configurazione della tabella
my $method = $base_comp->method_exists('PERMISSION') ? 'PERMISSION' : 'PERMISSION_BY_PROFILE';
$permission = $base_comp->scall_method($method);
}
}else{
# Autorizzo solo se utente amministratore
$permission = $Session{Group_Admins} ? 'LOG' : undef;
}
if(" $permission " !~ m/ LOG /i){
my $na = 'N.A.';
return {
id => $row->{id},
timestamp => undef,
id_anagrafiche => undef,
table_name => undef,
id_record => undef,
field => $na,
old_value => $na,
new_value => $na
}
}
return $row;
</%perl>
</%method>
 
<%method table_name_OUT_FILTER>\
<%args>
$Value
$Key
$names
$fetch_row
</%args>
<%perl>
my $param;
if(length $Value){
$Value =~ s/\./\//;
my $base_comp = $Session{"Logs_report_COMP_$Value"};
# cerco del campo $field l'attributo 'select_from'
$param = $base_comp ? $base_comp->scall_method('DESCRIPTION').($Session{Group_Admins} ? " ($Value)" : '') : "$Value (FORM Cancellato!)";
# elimino i tag <*> e </*>
$param =~ s/<[^>]*>//sg;
$param =~ s/<\/[^>]*>//sg;
}
</%perl>
$param = '<% $param |js%>';
$_ = '<%$Value |js%>';
</%method>
 
<%method table_name_FIND_FIELD><& /input/string.comp, %ARGS &></%method>
 
<%method table_name_FIELD>
<& /input/span.comp, %ARGS, width => $Session{Group_Admins} ? 160 : 130 &>
</%method>
 
<%method id_record_OUT_FILTER>\
<%args>
$Value
$Key
$names
$fetch_row
</%args>
<%perl>
my $Param = 'D';
if(length $Value){
my $table_name = $fetch_row->{table_name};
$table_name =~ s/\./\//;
my $sth = $Session{"STH_Logs_report_COMP_$table_name"};
if($sth){
$sth->execute($Value);
$Param = $sth->fetchrow_arrayref->[0] ? '' : 'D';
}else{
$Value = '';
}
}
</%perl>
$param = '<% $Param |js%>';
$_ = '<%$Value |js%>';
</%method>
<%method id_record_FIND_FIELD><& /input/number.comp, %ARGS &></%method>
 
<%method id_record_FIELD>
<& /input/button.comp, %ARGS, width => 60, caption_value => 1,
onclick => "this.displayBinding.view_form(this);"
&>
</%method>
 
/tags/2.0/htdocs/data/public/logs_report.mql
0,0 → 1,425
<%doc>
Used to create variation logs on archives (widget input/Files.mql)
Creation sql commands in file utility/sql/create_logs_report.mql
</%doc>
 
<%flags>
inherit => 'logs.common.mql'
</%flags>
 
<%once>
use String::Diff qw(diff_merge);
sub diff_report($$$$$$$$){
my($KEY, $fields, $fields_descr, $comp, $old_record, $new_record, $report_inserito, $report_cancellato) = @_;
# elaboro il report delle variazioni accumulate prima del LOG corrente
my @report;
if($report_inserito){
push @report, '(RECORD INSERITO)';
}
foreach my $key (keys %$new_record){
# salto se il campo è la chiave primaria
$key eq $KEY && next;
if($old_record->{$key} ne $new_record->{$key}){
# campo variato
my($old_val, $old_param) = Call_OutFieldFilter($key, $old_record->{$KEY}, $old_record->{$key}, $fields, $old_record, $comp);
my $old = $old_param ? $old_param : $old_val;
my($new_val, $new_param) = Call_OutFieldFilter($key, $new_record->{$KEY}, $new_record->{$key}, $fields, $new_record, $comp);
my $new = $new_param ? $new_param : $new_val;
my $diff_merge = diff_merge( $old, $new,
remove_open => '[',
remove_close => ']',
append_open => '{',
append_close => '}',
);
push @report, (exists $fields_descr->{$key} ? $fields_descr->{$key} : "Field $key").': '.$diff_merge;
}
}
if($report_cancellato){
push @report, '(RECORD CANCELLATO)';
}
return join "\n", @report;
}
# separa il nome del file indicato nei log nelle sue componenti dir, file e versione
sub split_archive_log_file($){
$_[0] || return undef;
my($file, $version) = split /:/, $_[0], 2;
if($file !~ m|^/|){
$file = '/'.$file;
}
my $is_dir;
if($file =~ m|(.*)/$|){
$is_dir = 1;
$file = $1;
}
my $dir = $file;
$dir =~ s|/[^/]*$||;
if(!$dir){
$dir = '/';
}
my $name = $file;
$name =~ s|^.*/||;
return ($is_dir, $dir, $name, $version);
}
</%once>
 
<%method TABLE_ROWS><% $ARGS{'rows'} ? $ARGS{'rows'} : '10' %></%method>
 
<%method FIELDS_HIDDEN>
<%perl>
my $where = $Session{ARGS}{'where2'};
if($where &&
$where !~ m/ and id_record\s*=\s*'{0,1}\d+'{0,1}/ &&
$where !~ m/table_name\s*=\s*'\w+\.\w+'/
){
die "SQL injection detection width [$where]. Execution aborted!";
}
</%perl>
% if($where =~ m/table_name\s*=/){
table_name,
% }
% if($where =~ m/ and id_record\s*=/){
id_record
% }
</%method>
 
<%method DESCRIPTION>Report delle modifiche \
<% $Session{ARGS}{'where2'} =~ m/table_name\s*=\s*'(.*)'/ ? "alla tabella $1 " : ''%> \
da parte degli utenti</%method>
 
<%method FIELDS>timestamp, id_anagrafiche, table_name, id_record, report</%method>
 
<%method FIELDS_DESCR>Data e ora, Utente, <% $Session{Group_Admins} ? 'Scheda (tabella)' : 'Scheda' %>, Id, Report variazioni</%method>
 
<%method FIND_FIELDS>timestamp, timestamp, id_anagrafiche, id_record, report</%method>
 
<%method FIELDS_RO>*</%method>
 
<%method FIELDS_NO_WRITE>*</%method>
 
<%method ORDER>order by timestamp desc, id</%method>
 
<%method timestamp_FIELD><& /input/span.comp, width => 120, %ARGS &></%method>
 
<%method timestamp_FIND_FIELD>
<& /input/timestamp.comp, %ARGS &>
<%attr>
find_select_list => ['=' => '=', '<=' => '<=', '>=' => '>=']
</%attr>
</%method>
 
<%method report_FIELD>
<& /input/span.comp, %ARGS, width => 600, style => 'font-size: 8pt; white-space: normal; text-wrap: normal;', disp_template => q{P.join('; ')}.($Session{Group_Admins} ? q{+' ('+P[-1]+')'} : '') &>
</%method>
 
<%method FORM_INCLUDE_POST>
<%args>
$Display
$Recordset
</%args>
<script>
// chiamata da id_record_FIELD per visualizzare il form corrispondente al campo variato
<% $Display %>.view_form = function (widget){
// verifico che il widget non sia disabilitato
if(widget.Readonly()){
return false;
}
var table_name = <%$Display%>.getField('table_name', widget.dbRow).get_value();
var table = table_name.replace(/.*\//, '');
// costruisco un oggetto 'display' minimale con i soli elementi necessari a lanciare il form
var display_log = {
prefix: 'Log_detail',
dataBinding: new DataBinding('Log_detail_db', 'log', 'Log ' + table),
gotoRecords: function (mode, key, recordset){
return this.dataBinding.gotoRecords(mode, key, recordset);
},
openFormDetailByKey: DisplayBinding_openFormDetailByKey
};
var d = new Date();
display_log.openFormDetailByKey('rewind', null, table, 1000, 600, 'Log ' + table_name, {
U: d.getTime() + '' + Math.floor(1000 * Math.random()),
rows: null,
disp_update: '',
pk: widget.get_value()
});
}
</script>
</%method>
 
<%method REPORT_UPGRADE>
<%args>
$TABLE_NAME
$ID_RECORD
</%args>
<%perl>
# verifica se ci sono da aggiornare i report del record selezionato
# lettura dei due logs_report più recenti
my $sth_logs_report = ExecQuery('check update logs_report', undef, q{
select *, to_char(timestamp, 'YYYYMMDD') as day
from public.logs_report
where table_name = ?
and id_record = ?
order by timestamp desc, id
limit 2;
}, $TABLE_NAME, $ID_RECORD);
my $logs_report = $sth_logs_report->rows >=1 ? $sth_logs_report->fetchrow_hashref : { id_anagrafiche => undef, timestamp => '1970-01-01T00:00:00+00' };
 
# verifico se il primo log della lista è dello stesso utente e nello stesso giorno dell'ultimo report presente.
# Se è il caso provvedo a cancellare l'ultimo report così da aggiornarlo
my $sth_check_logs = ExecQuery('check first logs', undef, q{
select id_anagrafiche, to_char(timestamp, 'YYYYMMDD') as day
from public.logs
where table_name = ?
and id_record = ?
and timestamp > ?
order by timestamp, id
limit 1;
}, $TABLE_NAME, $ID_RECORD, $logs_report->{'timestamp'});
if($sth_check_logs->rows == 1){
# c'è almeno un nuovo log da elaborare
my $DataBaseUrl = $r->dir_config('DataBaseUrl');
my $table = $TABLE_NAME;
$table =~ s/\./\//; # il nome della tabella con schema --> in formato schema/tabella
my $KEY = $m->scomp("$DataBaseUrl/$table.mql:KEY_NAME");
my $check_logs = $sth_check_logs->fetchrow_hashref;
if($check_logs->{'id_anagrafiche'} eq $logs_report->{'id_anagrafiche'} && $check_logs->{'day'} eq $logs_report->{'day'}){
# c'è almeno un ulteriore log da includere nell'ultimo report presente
# quindi lo scarto per ricrearlo aggiornato
ExecQuery('delete logs_report', undef, q{delete from public.logs_report where id = ?;}, $logs_report->{$KEY});
# il penultimo report, diventato ora l'ultimo
$logs_report = $sth_logs_report->rows == 2 ? $sth_logs_report->fetchrow_hashref : { id_anagrafiche => undef, timestamp => '1970-01-01T00:00:00+00' };
}
# elenco dei logs successivi a partire dal più recente
my $sth_logs = ExecQuery('check logs_report', undef, q{
select *, to_char(timestamp, 'YYYYMMDD') as day
from public.logs
where table_name = ?
and id_record = ?
and timestamp > ?
order by timestamp desc, id desc;
}, $TABLE_NAME, $ID_RECORD, $logs_report->{'timestamp'});
# leggo i dati attuali del record
my $sth_record = ExecQuery("read $TABLE_NAME:$ID_RECORD", undef, qq{
select *
from $TABLE_NAME
where $KEY=?
}, $ID_RECORD);
my $old_record = $sth_record->rows == 1 ? $sth_record->fetchrow_hashref : { id => $ID_RECORD };
my %new_record = %{$old_record};
my $log = $sth_logs->fetchrow_hashref;
my $max_curr_timestamp = $log->{'timestamp'};
my $curr_id_anagrafiche = $log->{'id_anagrafiche'};
my $curr_day = $log->{'day'};
 
# descrizioni dei campi per il report
# nella stessa sessione il metodo REPORT_UPGRADE viene richiamato più volte, quindi metto in cache la hash con le descrizioni dei campi
if(!$Session{"Logs_report_fields_descr_$TABLE_NAME"}){
my %fields_descr;
my $comp = $m->fetch_comp("$DataBaseUrl/$table.mql");
my @fields = &Method2Array("$DataBaseUrl/$table.mql:FIELDS");
my @fields_descr = &Method2Array("$DataBaseUrl/$table.mql:FIELDS_DESCR");
for(my $I=0; $I<@fields; $I++){
my $field = $fields[$I];
$field =~ s/^\w+\.//; # tolgo il nome della tabella
my $descr = $fields_descr[$I];
$descr =~ s/[\\\/]$//;
$fields_descr{$field} = $descr;
}
$Session{"Logs_report_$TABLE_NAME"} = [$comp, \@fields, \%fields_descr ];
}
my($comp, $fields, $fields_descr) = @{$Session{"Logs_report_$TABLE_NAME"}};
my $report_inserito;
my $report_cancellato;
my $old_report_cancellato;
my %ghost_old_record;
my %ghost_new_record;
my @log_archive;
my $sql_insert_report = q{
insert into public.logs_report (timestamp, id_anagrafiche, table_name, id_record, report) values (?, ?, ?, ?, ?)
};
while(1){
if($log->{'id_anagrafiche'} ne $curr_id_anagrafiche || $log->{'day'} ne $curr_day){
# se vi sono state variazioni fantasma (LOG assenti) le registro
if(!$report_cancellato && %ghost_new_record){
# aggiungo le chiavi primarie
$ghost_new_record{$KEY} = $new_record{$KEY};
$ghost_old_record{$KEY} = $old_record->{$KEY};
# genero il report delle differenze
my $report = diff_report($KEY, $fields, $fields_descr, $comp, \%ghost_old_record, \%ghost_new_record, undef, undef);
if(length($report)){
# salvo il report
ExecQuery('new ghost logs_report', undef, $sql_insert_report, $max_curr_timestamp, undef, $TABLE_NAME, $ID_RECORD, $report);
}
%ghost_new_record = undef;
%ghost_old_record = undef;
}
# genero il report delle differenze
my $report = diff_report($KEY, $fields, $fields_descr, $comp, $old_record, \%new_record, $report_inserito, $report_cancellato);
if(@log_archive){
$report .= "\nArchivio: ".join("; ", @log_archive).'.';
@log_archive = ();
}
$report_inserito = undef;
if($report_cancellato){
$old_report_cancellato = 1;
}
$report_cancellato = undef;
# salvo il report
ExecQuery('new logs_report', undef, $sql_insert_report, $max_curr_timestamp, $curr_id_anagrafiche, $TABLE_NAME, $ID_RECORD, $report);
# prossimo report ...
%new_record = %{$old_record};
$max_curr_timestamp = $log->{'timestamp'};
$curr_id_anagrafiche = $log->{'id_anagrafiche'};
$curr_day = $log->{'day'};
}
# ho terminato la lettura del log?
$log->{$KEY} || last;
# accumulo i cambiamenti effettuati dallo stesso utente nello stesso giorno
my $field = $log->{'field'};
if(defined $field){
if($field eq 'ARC.'){
# modifiche all'archivio associato
my($old_is_dir, $old_dir, $old_name, $old_ver) = split_archive_log_file($log->{'old_value'});
my($new_is_dir, $new_dir, $new_name, $new_ver) = split_archive_log_file($log->{'new_value'});
if(!$old_name){
# caricamento
if($new_is_dir){
unshift @log_archive, "new dir $new_name in $new_dir";
}else{
unshift @log_archive, "load file $new_name in $new_dir".($new_ver ? " ver.$new_ver" : '');
}
}elsif(!$new_name){
# cancellazione
unshift @log_archive, ($old_is_dir ? 'del dir' : 'del file')." $old_name in $old_dir";
}else{
if($old_name ne $new_name && $old_dir eq $new_dir){
# modificato il nome
unshift @log_archive, 'mod. '.($old_is_dir ? ' dir ' : ' file ').
"$old_name a $new_name in $old_dir";
}elsif($old_name eq $new_name && $old_dir ne $new_dir && $old_ver == $new_ver){
# spostamento del file
unshift @log_archive, 'spost.'.($old_is_dir ? ' dir ' : ' file ').
"$old_name da $old_dir a $new_dir";
}else{
unshift @log_archive, 'spost.'.($old_is_dir ? ' dir ' : ' file ').
"da $old_dir/$old_name a $new_dir/$new_name";
}
}
}else{
# modifica di un campo
if($old_report_cancellato && !exists $old_record->{$field}){
# mancando l'informazione del record finale (in quanto cancellato) se il campo non è
# stato registrato nel LOG (letto a ritroso nel tempo) devo considerare il dato corrente del LOG veritiero
$new_record{$field} = $log->{'new_value'};
$old_record->{$field} = $log->{'old_value'};
}elsif($log->{'new_value'} eq $old_record->{$field}){
$old_record->{$field} = $log->{'old_value'};
}else{
# c'è stata una variazione del campo intermedia nel log che non è registrata
$ghost_old_record{$field} = $log->{'new_value'};
$ghost_new_record{$field} = $old_record->{$field};
$new_record{$field} = $log->{'new_value'};
$old_record->{$field} = $log->{'old_value'};
}
}
}elsif($ID_RECORD eq $log->{'new_value'}){
# inserimento del record
$old_record->{$KEY} = undef;
$report_inserito = 1;
}elsif($ID_RECORD eq $log->{'old_value'}){
# cancellazione del record
$old_record->{$KEY} = $ID_RECORD;
$report_cancellato = 1;
}else{
die 'Dati inaspettati',$log, Dumper($log);
}
# riga di log precedente del giorno
$log = $sth_logs->fetchrow_hashref;
} # while(1)
$Session{Dbh}->commit;
return 1;
}
</%perl>
</%method>
 
<%method PRE_SELECT>
<%args>
$PARAMS
</%args>
<%perl>
# DEBUG $PARAMS->{'where2'} = q{table_name = 'impianti.apparecchiature' and id_record = '31173'};
my $where = $PARAMS->{'where2'};
if($where && $where =~ m/table_name\s*=\s*'(\w+\.\w+)'\s*and\s*id_record\s*=\s*'{0,1}(\d+)'{0,1}/){
my $table_name = $1;
my $id_record = $2;
if($m->comp('SELF:REPORT_UPGRADE', TABLE_NAME => $table_name, ID_RECORD => $id_record)){
$PARAMS->{'RecordsetCache'}= undef;
}
}elsif($where && $where =~ m/table_name\s*=\s*'(\w+\.\w+)'/){
# devo provvedere all'aggiornamento dei dati di tutti i record della tabella
my $table_name = $1;
my $id_list = ExecQuery('logs_report table id list', undef, q{
select id_record from (
select max(logs.timestamp) as t_log, max(logs_report.timestamp) as t_rep, logs.id_record
from logs
left join logs_report on logs_report.table_name = logs.table_name and logs_report.id_record = logs.id_record
where logs.table_name = ?
group by logs.id_record
) as logs
where t_rep is null or t_log > t_rep;
}, $table_name);
#my $C=10;
while(my $rec = $id_list->fetchrow_arrayref){
if($m->comp('SELF:REPORT_UPGRADE', TABLE_NAME => $table_name, ID_RECORD => $rec->[0])){
$PARAMS->{'RecordsetCache'}= undef;
}
#$C--;
#$C || last;
}
}else{
die "Errore inaspettato; il form logs_report deve essere richiamato con limitazione WHERE(table_name = '<nome tabella>)'";
}
</%perl>
</%method>
 
<%method FIELDS_INCLUDE_POST>
<%args>
$Display
</%args>
<script>
dojo.addOnLoad(function(){
%# // la stampa comprende tutto il recordset
var print_btn = dojo.byId('<%$Display%>_Ctrl_print');
print_btn.value = 'Stampa';
print_btn.onclick = function(){
<%$Display%>.printSelected('recordset');
};
});
 
<%$Display%>.onchange = function(){
%# // disabilito i pulsanti che puntano a record cancellati
var Col = this.dataBinding.pos_name['id_record'];
for(var Row=0; Row<this.fields.length; Row++){
var Button = this.fields[Row][Col];
if(Button.get_param() == 'D'){
Button.Readonly(true);
}
}
};
</script>
</%method>
 
<%method PERMISSION>SELECT PRINT PRINTSEL</%method>
<%method FIND_MENU_POST>
<p><br><br><br>
Per filtrare i cancellati<br>
inserire la frase<br>
&nbsp;&nbsp;&nbsp;<B>RECORD CANCELLATO</B><br>
in 'Report variazioni'.
</p>
</%method>
/tags/2.0/htdocs/data/public/messages_users.mql
0,0 → 1,68
<%doc>
Utenti destinatari dei messaggi
</%doc>
<%method FUNZIONE>Messages</%method>
 
<%method DESCRIPTION>Utenti destinatari dei messaggi</%method>
 
<%method FIELDS_COMMON>
notification_time
<% $r->dir_config('MailSmtpServer') ? ', email_result' : '' %>
<% $r->dir_config('SMSPlatform') ? ', sms_result' : '' %>
</%method>
 
<%method FIELDS>id_anagrafiche, <& SELF:FIELDS_COMMON &></%method>
 
<%method FIELDS_NOT_NULL></%method>
 
<%method FIELDS_DESCR>Destinatari, Notifica Web\
<% $r->dir_config('MailSmtpServer') ? ', E-mail' : '' %>\
<% $r->dir_config('SMSPlatform') ? ', S.M.S.' : '' %>
</%method>
 
<%method FIELDS_RO><& SELF:FIELDS_COMMON &></%method>
 
<%method FIND_AREA>left</%method>
 
<%method FIND_FIELDS>id_anagrafiche, notification_time, notification_time</%method>
 
<%method FATHER>id_messages:messages</%method>
 
<%method DETAIL_FROM>messages_users_detail</%method>
 
<%method TABLE_ROWS>15</%method>
 
<%method PERMISSION><%perl>
my $permission = $m->scomp('SELF:PERMISSION_BY_PROFILE');
# verifico lo stato del padre
my $sth = ExecQuery('Check message status', undef, q{
select transmission_time from public.messages where id = ?;
}, $Session{ARGS}->{'father_id'});
if($sth->rows){
my $transmission_time = $sth->fetchrow_arrayref->[0];
# disabilito cancellazione e modifica se record trasmesso
if($transmission_time){
$permission =~ s/DELETE//;
$permission =~ s/INSERT//;
$permission =~ s/UPDATE//;
}
}
$m->out($permission);
</%perl></%method>
 
<%method id_anagrafiche_FIELD>
<& SELF:GenericSelect_FIELD,from => 'sel_gruppi_and_anagrafiche', widget => 'divselect', width => '260',
cols => [250],
disp_template => q{P[0]},
%ARGS
&>
<%attr>
find_select_list => ['=' => '=']
select_from => 'sel_gruppi_and_anagrafiche'
</%attr>
</%method>
 
<%method email_result_FIELD><& /input/span.comp, %ARGS, width => 300 &></%method>
 
<%method sms_result_FIELD><& /input/span.comp, %ARGS, width => 300 &></%method>
 
/tags/2.0/htdocs/data/public/messages_users_detail.mql
0,0 → 1,58
<%doc>
Dettaglio utente destinatario dei messaggi
</%doc>
<%method FROM>messages_users</%method>
 
<%method FUNZIONE>Messages</%method>
 
<%method DESCRIPTION>Utente destinatario del messaggo</%method>
 
<%method FIELDS>
id_anagrafiche, notification_time,
<% $r->dir_config('MailSmtpServer') ? 'email_result,' : '' %>
<% $r->dir_config('SMSPlatform') ? 'sms_result, user_short_message,' : '' %>
user_message
</%method>
 
<%method SELECT_FIELDS>
id_anagrafiche, notification_time,
<% $r->dir_config('MailSmtpServer') ? 'email_result,' : '' %>
<% $r->dir_config('SMSPlatform') ? q{sms_result, coalesce(user_short_message, messages.short_message) as user_short_message,} : '' %>
coalesce(user_message, messages.message) as user_message
</%method>
 
 
<%method FIELDS_NOT_NULL></%method>
 
<%method FIELDS_DESCR>
Destinatari, Notifica Web,
<% $r->dir_config('MailSmtpServer') ? 'E-mail,' : '' %>
<% $r->dir_config('SMSPlatform') ? 'S.M.S., Messaggio breve,' : '' %>
Messaggio
</%method>
 
<%method FIELDS_RO>*</%method>
 
<%method JOIN_TABLES>
public.messages_users
inner join public.messages on messages.id = messages_users.id_messages
</%method>
 
<%method id_anagrafiche_FIELD>
<& SELF:GenericSelect_FIELD, from => 'sel_gruppi_and_anagrafiche', %ARGS &>
<%attr>
find_select_list => ['=' => '=']
select_from => 'sel_gruppi_and_anagrafiche'
</%attr>
</%method>
<%method email_result_FIELD><& /input/span.comp, %ARGS, width => 500 &></%method>
<%method sms_result_FIELD><& /input/span.comp, %ARGS, width => 500 &></%method>
<%method user_message_FIELD><& /input/string.comp, %ARGS, rows => 18, cols => 86, style => 'font-family: monospace;' &></%method>
 
<%method user_short_message_FIELD><& /input/string.comp, %ARGS, rows => 3, cols => 86, style => 'font-family: monospace;' &></%method>
/tags/2.0/htdocs/data/public/odt_reports.mql
0,0 → 1,63
<%method FUNZIONE>OdtReports</%method>
<%method DESCRIPTION>ODT Reports</%method>
 
<%method CHILDREN>odt_report_portions, odt_report_fields</%method>
<%method CHILDREN_FIELDS>id, id</%method>
 
<%method FIELDS>name, description, comment, cmd_parameters, global_parameters, id</%method>
<%method FIELDS_NOT_NULL>name</%method>
<%method FIELDS_DESCR>Report Name, Description, Comment, Test parameters, Global parameters, Template Files</%method>
<%method FIND_FIELDS>name, description, comment</%method>
 
<%method name_FIELD><& /input/string.comp, %ARGS, size => 60 &></%method>
<%method description_FIELD><& /input/string.comp, %ARGS, size => 60 &></%method>
<%method comment_FIELD><& /input/string.comp, %ARGS, rows => 4, cols => 80 &></%method>
<%method comment_FIND_FIELD><& /input/string.comp, %ARGS, rows => 1 &></%method>
 
<%method FORM_HEIGHT>300</%method>
 
<%method id_FIELD>
<& /input/Files.comp, %ARGS,
from => 'public/odt_reports',
width => 400,
height => 300,
readonly => 0,
&>\
</%method>
 
<%method PRE_INSERT>
<%args>
$FIELDS_INSERT
$PARAMS
</%args>
% delete $FIELDS_INSERT->{'id'};
% delete $PARAMS->{'id'};
</%method>
 
<%method PRINT_FORM>, <%$ARGS{'cmd_parameters'}%></%method>
 
<%method cmd_parameters_FIELD>
<%args>
$Display
</%args>
<& /input/string.comp, %ARGS, rows => 2, cols => 64 &>
<button dojoType="dijit.form.Button" style="vertical-align:top;" type="submit" onClick="GenerateOdtReport();">Test<br>ODT</button>
<button dojoType="dijit.form.Button" style="vertical-align:top;" type="submit" onClick="GeneratePdfReport();">Test<br>PDF</button>
<script>
function GenerateOdtReport(){
var report_name = <%$Display%>.getField('name').get_value();
var cmd_parameters = <%$Display%>.getField('cmd_parameters').get_value();
<%$Display%>.printSelected('odt_rpt', report_name+'.odt', cmd_parameters);
}
function GeneratePdfReport(){
var report_name = <%$Display%>.getField('name').get_value();
var cmd_parameters = <%$Display%>.getField('cmd_parameters').get_value();
<%$Display%>.printSelected('pdf_rpt', report_name+'.pdf', cmd_parameters);
}
</script>
</%method>
 
<%method global_parameters_FIELD>
<& /input/string.comp, %ARGS, rows => 1, size => 64 &>
</%method>
 
/tags/2.0/htdocs/data/public/sel_anagrafiche.mql
0,0 → 1,9
<%flags>
inherit => 'anagrafiche.mql'
</%flags>
 
<%method FIELDS>nome, cognome<% $Session{Group_Admins} ? ', login' : ''%></%method>
 
<%method SELECT_FIELDS><& SELF:FIELDS &></%method>
 
<%method FIELDS_DESCR>Nome, Cognome<% $Session{Group_Admins} ? ', Login' : ''%></%method>
/tags/2.0/htdocs/data/public/sel_autorizzazioni.mql
0,0 → 1,10
<%flags>
inherit => 'autorizzazioni.mql'
</%flags>
 
<%method FIELDS>nome</%method>
 
<%method SELECT_FIELDS>nome</%method>
 
<%method FIELDS_DESCR>Nome</%method>
 
/tags/2.0/htdocs/data/public/sel_gruppi.mql
0,0 → 1,50
<%flags>
inherit => 'gruppi.mql'
</%flags>
 
<%method FIELDS_DESCR>Gruppo</%method>
 
<%method FIELDS>gruppo</%method>
 
<%method SELECT_FIELDS>(coalesce(gruppi.nome , '') || ' - ' || coalesce(gruppi.descrizione, '')) as gruppo</%method>
 
<%method ORDER>gruppo</%method>
 
<%method SELECT>\
<%args>
$ID => undef
$WHERE => ''
</%args>
% if(defined $ID){
select <& SELF:KEY &>, <& SELF:SELECT_FIELDS &> from <& SELF:JOIN_TABLES &> where <& SELF:KEY &> = '<%$ID%>';\
% }else{
% if($Session{Group_Admins}){ # amministratore; lista completa
select distinct
<& SELF:KEY &>, <& SELF:SELECT_FIELDS &>
from gruppi
<% $WHERE %>
<& SELF:ORDER_BY &>;\
% }else{
% # elenco solo i gruppi che l'utente è autorizzato ad assegnare
% if($WHERE){
% $WHERE =~ s/\s*where\s*/and /i;
% }
select distinct
<& SELF:KEY &>, <& SELF:SELECT_FIELDS &>
from
gruppi_modifica left join gruppi on gruppi.id = gruppi_modifica.id_gruppo_modifica
where
gruppi_modifica.id_gruppo in (
select distinct
gruppi.id
from gruppi
left join anagrafiche_gruppi on anagrafiche_gruppi.id_gruppi = gruppi.id
left join anagrafiche on anagrafiche.id = anagrafiche_gruppi.id_anagrafiche
where
anagrafiche.id = '<%$Session{User_id}%>'
)
<%$WHERE%>
<& SELF:ORDER_BY &>;\
% }
% }
</%method>
/tags/2.0/htdocs/data/public/sel_odt_report_portions.mql
0,0 → 1,14
<%flags>
inherit => 'odt_report_portions.mql'
</%flags>
 
<%method FIELDS>name</%method>
 
<%method FIELDS_DESCR>Porzione</%method>
 
<%method SELECT_FIELDS>coalesce (name, '')</%method>
 
<%method WHERE>
id_odt_reports = <% $Session{ARGS}{father_id} %> AND
id != <% $Session{ARGS}{child_id} || -1 %>
</%method>
/tags/2.0/htdocs/data/public/user_messages_body.mql
0,0 → 1,84
 
<%method FROM>messages_users</%method>
 
<%method FUNZIONE>User_messages</%method>
 
<%method FORM_TYPE>FORM</%method>
<%method TABLE_ROWS>1</%method>
 
<%method FATHER>id_messages:user_messages</%method>
 
<%method DESCRIPTION>Messaggio</%method>
 
<%method FIELDS>message</%method>
 
<%method SELECT_FIELDS>
CASE
WHEN messages_users.user_message is not null THEN messages_users.user_message
WHEN messages_users.user_short_message is not null THEN messages_users.user_short_message
WHEN messages.message is not null THEN messages.message
ELSE messages.short_message
END as message
</%method>
 
<%method JOIN_TABLES>
public.messages_users
inner join public.messages on messages_users.id_messages = messages.id
and messages_users.id_anagrafiche = <%$Session{User_id}%>
</%method>
 
<%method FIELDS_DESCR>Messaggio</%method>
 
<%method FIELDS_RO>message</%method>
 
<%method message_FIELD>
<& /input/string.comp, %ARGS, rows => 26, cols => 140, style => 'font-family: monospace;' &>
</%method>
 
<%method FORM_INCLUDE_POST>
<%args>
$Display
$Recordset
</%args>
<script>
<%$Display%>.onload = function (){
this.getField('message').TooltipShowDelay = 9999999999;
this.getField('message').TooltipObj.showDelay = 9999999999;
}
 
<%$Display%>.onchange = function (){
// metto in evidenza il nuovo messaggio
var new_mess = <%$Recordset%>.keys[0] && !<%$Recordset%>.father.get_value('notification_time', <%$Recordset%>.father.rowFather);
require(["dojo/dom-class"], function(domClass){
if(new_mess){
domClass.replace(<%$Display%>.getField('message'), 'MessagesNewMessage', 'widgetRo');
}else{
domClass.replace(<%$Display%>.getField('message'), 'widgetRo', 'MessagesNewMessage');
}
});
// notifico al server che l'utente ha visionato il record caricato nel form
if(new_mess){
// Messaggio visionato per la prima volta
<%$Display%>.callRemote('viewed', {id:<%$Recordset%>.keys[0]});
}
}
</script>
</%method>
 
<%method CALL_REMOTE_viewed>
<%args>
$id
$dbms_params
</%args>
<%perl>
# l'utente ha visionato il messaggio che posso quindi aggiornare
my $sth = ExecQuery('Displayed message', undef, q{
UPDATE public.messages_users
SET notification_time = now()
WHERE id_anagrafiche = ?
AND notification_time IS NULL
AND id = ?;
}, $Session{User_id}, $id);
$Session{Dbh}->commit;
</%perl>
</%method>
/tags/2.0/htdocs/data/public/user_session.mql
0,0 → 1,27
<%flags>
inherit => 'session.mql'
</%flags>
 
<%method FUNZIONE>UserSession</%method>
 
<%method DESCRIPTION>Sessioni dell'utente</%method>
 
<%method FIELDS>user_ip, session_time, session_inactive_time, user_agent</%method>
 
<%method FIELDS_DESCR>Indirizzo IP, Ultima login, Inattivo, Browser</%method>
 
<%method FIND_FIELDS></%method>
 
<%method WHERE>id_anagrafiche = <% $Session{User_id} %></%method>
 
<%method session_inactive_time_OUT_FILTER>
my $m = int(time/60) - $_;
my $h = int($m/60);
$m -= $h*60;
$_ = $h || $m ? sprintf('%02i:%02i', $h, $m) : '';
</%method>
 
<%method user_ip_FIELD><& /input/span.comp, width => '100px', %ARGS &></%method>
<%method session_inactive_time_FIELD><& /input/span.comp, width => '48px', %ARGS &></%method>
<%method user_agent_FIELD><& /input/span.comp, width => '280px', %ARGS &></%method>
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/data/public/anagrafiche.kylix.rep
0,0 → 1,769
object TRpReport
PageOrientation = rpOrientationPortrait
Pagesize = rpPageSizeCustom
PageHeight = 8120
PageWidth = 5742
PageBackColor = 2147483647
LeftMargin = 454
TopMargin = 454
RightMargin = 454
BottomMargin = 454
SubReports = <
item
SubReport = TRpSubReport0
end
item
SubReport = TRpSubReport1
end
item
SubReport = TRpSubReport2
end>
DataInfo = <
item
Alias = 'ANAGRAFICHE'
DatabaseAlias = 'MASONSQL'
SQL =
#13#10'select '#13#10' anagrafiche.*'#13#10'from '#13#10' report_id, anagrafiche'#13 +
#10'where '#13#10' report_id.group_id = :GROUP_ID'#13#10' and anagrafiche.i' +
'd=key'#13#10'order by id;'#13#10
end
item
Alias = 'DATI'
DatabaseAlias = 'MASONSQL'
SQL =
'select nome from gruppi, anagrafiche_gruppi ag'#13#10'where ag.id_anag' +
'rafiche = :ID'#13#10'and ag.id_gruppi = gruppi.id'#13#10' '
DataSource = 'ANAGRAFICHE'
end>
DatabaseInfo = <
item
Alias = 'MASONSQL'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdatazeos
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString = ''
end>
Params = <
item
Name = 'GROUP_ID'
Value = -1
ParamType = rpParamInteger
Datasets.Strings = (
'ANAGRAFICHE')
Description = 'Identificatore report_id per stampa multipla'
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
TwoPass = True
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection2
end
item
Section = TRpSection0
end
item
Section = TRpSection3
end
item
Section = TRpSection4
end>
Alias = 'ANAGRAFICHE'
PrintOnlyIfDataAvailable = False
end
object TRpSection0: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSubReport1: TRpSubReport
Sections = <
item
Section = TRpSection10
end>
ParentSubReport = TRpSubReport0
ParentSection = TRpSection0
end
object TRpSection10: TRpSection
Width = 10605
Height = 2430
SubReport = TRpSubReport1
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression0
end
item
Component = TRpExpression2
end
item
Component = TRpExpression4
end
item
Component = TRpLabel3
end
item
Component = TRpLabel5
end
item
Component = TRpExpression8
end
item
Component = TRpExpression10
end
item
Component = TRpLabel7
end
item
Component = TRpLabel9
end
item
Component = TRpLabel10
end
item
Component = TRpLabel15
end
item
Component = TRpShape2
end
item
Component = TRpShape5
end
item
Component = TRpExpression11
end
item
Component = TRpExpression3
end
item
Component = TRpLabel1
end
item
Component = TRpExpression6
end
item
Component = TRpShape0
end>
AutoExpand = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSubReport2: TRpSubReport
Sections = <
item
Section = TRpSection1
end>
Alias = 'DATI'
ParentSubReport = TRpSubReport0
ParentSection = TRpSection3
end
object TRpSection1: TRpSection
Width = 1425
Height = 225
SubReport = TRpSubReport2
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression1
end>
HorzDesp = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection3: TRpSection
Width = 10772
Height = 30
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression1: TRpExpression
Width = 915
Height = 225
PosX = 465
PosY = 0
Type1Font = poHelvetica
FontSize = 8
VAlignment = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DATI.nome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression0: TRpExpression
Width = 2295
Height = 225
PosX = 6675
PosY = 810
Type1Font = poHelvetica
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.descrizione'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression2: TRpExpression
Width = 2295
Height = 225
PosX = 6675
PosY = 1050
Type1Font = poHelvetica
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.indirizzo'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression4: TRpExpression
Width = 2415
Height = 225
PosX = 6675
PosY = 1275
Type1Font = poHelvetica
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.tel1'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel3: TRpLabel
Width = 570
Height = 225
PosX = 6090
PosY = 1050
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Via: '
end
object TRpLabel5: TRpLabel
Width = 690
Height = 225
PosX = 5985
PosY = 1725
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'C.F.: '
end
object TRpExpression8: TRpExpression
Width = 1140
Height = 225
PosX = 6675
PosY = 1725
Type1Font = poHelvetica
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.codice_fiscale'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression10: TRpExpression
Width = 2640
Height = 225
PosX = 6675
PosY = 1500
Type1Font = poHelvetica
FontSize = 8
WordWrap = True
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.tel2'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel7: TRpLabel
Width = 1260
Height = 225
PosX = 5400
PosY = 810
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Descrizione: '
end
object TRpLabel9: TRpLabel
Width = 570
Height = 225
PosX = 6090
PosY = 1275
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Tel1: '
end
object TRpLabel10: TRpLabel
Width = 570
Height = 225
PosX = 6090
PosY = 1500
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Tel2: '
end
object TRpSection2: TRpSection
Width = 10772
Height = 1230
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpheader
Components = <
item
Component = TRpLabel11
end
item
Component = TRpLabel12
end
item
Component = TRpExpression12
end
item
Component = TRpLabel14
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel11: TRpLabel
Width = 2070
Height = 345
PosX = 8745
PosY = 0
Type1Font = poHelvetica
FontSize = 13
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'MasonSQL'
end
object TRpLabel12: TRpLabel
Width = 465
Height = 225
PosX = 8400
PosY = 915
Type1Font = poHelvetica
FontSize = 8
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'helvetica'
WideText = 'Data:'
end
object TRpExpression12: TRpExpression
Width = 1155
Height = 225
PosX = 8850
PosY = 915
Type1Font = poHelvetica
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'FormatStr('#39'dd/mm/yyyy'#39', today)'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel14: TRpLabel
Width = 2995
Height = 691
PosX = 225
PosY = 0
Type1Font = poHelvetica
FontSize = 28
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Anagrafiche'
end
object TRpLabel15: TRpLabel
Width = 3210
Height = 225
PosX = 465
PosY = 2190
Type1Font = poHelvetica
FontSize = 7
Alignment = 1
VAlignment = 16
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Gruppi di appartenenza dell'#39'utente:'
end
object TRpShape2: TRpShape
Width = 10470
Height = 240
PosX = 0
PosY = 345
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpShape5: TRpShape
Width = 5055
Height = 1380
PosX = 120
PosY = 690
BrushColor = 15724527
PenColor = 16777215
Shape = rpsRoundRect
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpExpression11: TRpExpression
Width = 4485
Height = 345
PosX = 570
PosY = 810
Type1Font = poHelvetica
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.nome + '#39' '#39' + ANAGRAFICHE.cognome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression3: TRpExpression
Width = 2880
Height = 345
PosX = 1260
PosY = 1265
Type1Font = poHelvetica
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.login'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel1: TRpLabel
Width = 585
Height = 345
PosX = 570
PosY = 1260
Type1Font = poHelvetica
Alignment = 1
VAlignment = 16
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'login: '
end
object TRpExpression6: TRpExpression
Width = 3210
Height = 345
PosX = 570
PosY = 1730
Type1Font = poHelvetica
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.email'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpShape0: TRpShape
Width = 10350
Height = 75
PosX = 120
PosY = 2070
Shape = rpsHorzLine
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpSection4: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpShape3
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpShape3: TRpShape
Width = 10350
Height = 120
PosX = 110
PosY = 0
Shape = rpsHorzLine
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
end
/tags/2.0/htdocs/data/public/anagrafiche.wine.rep
0,0 → 1,796
object TRpReport
PageOrientation = rpOrientationPortrait
Pagesize = rpPageSizeCustom
PageHeight = 8120
PageWidth = 5742
PageBackColor = 2147483647
LeftMargin = 454
TopMargin = 454
RightMargin = 454
BottomMargin = 454
SubReports = <
item
SubReport = TRpSubReport0
end
item
SubReport = TRpSubReport1
end
item
SubReport = TRpSubReport2
end>
DataInfo = <
item
Alias = 'ANAGRAFICHE'
DatabaseAlias = 'MASONSQL'
SQL =
'select '#13#10' anagrafiche.*'#13#10'from '#13#10' report_id, anagrafiche'#13#10'w' +
'here '#13#10' :GROUP_ID > 0 and'#13#10' report_id.group_id = :GROUP_ID'#13#10' ' +
'and anagrafiche.id=key'#13#10#13#10'UNION'#13#10#13#10'select '#13#10' anagrafiche.*'#13#10'f' +
'rom '#13#10' anagrafiche'#13#10'where '#13#10' :GROUP_ID < 0 and'#13#10' anagrafich' +
'e.id = - :GROUP_ID'#13#10#13#10'order by id;'#13#10#13#10
end
item
Alias = 'DATI'
DatabaseAlias = 'MASONSQL'
SQL =
'select nome from gruppi, anagrafiche_gruppi ag'#13#10'where ag.id_anag' +
'rafiche = :id'#13#10'and ag.id_gruppi = gruppi.id'#13#10' '
DataSource = 'ANAGRAFICHE'
end>
DatabaseInfo = <
item
Alias = 'MASONSQL'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdataado
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString =
'Provider=MSDASQL.1;Persist Security Info=False;Mode=Read;Extende' +
'd Properties="DRIVER={PostgreSQL Unicode};DATABASE=masonsql;SERV' +
'ER=127.0.0.1;USER=report;PASSWORD=<password>;PORT=5432;UID=repor' +
't;SSLmode=allow;ReadOnly=1;Protocol=7.4-1;FakeOidIndex=0;ShowOid' +
'Column=0;RowVersioning=0;ShowSystemTables=0;ConnSettings=;Fetch=' +
'100;Socket=4096;UnknownSizes=0;MaxVarcharSize=254;MaxLongVarchar' +
'Size=8190;Debug=0;CommLog=0;Optimizer=1;Ksqo=1;UseDeclareFetch=0' +
';TextAsLongVarchar=1;UnknownsAsLongVarchar=0;BoolsAsChar=1;Parse' +
'=1;CancelAsFreeStmt=0;ExtraSysTablePrefixes=dd_;;LFConversion=1;' +
'UpdatableCursors=1;DisallowPremature=0;TrueIsMinus1=0;BI=0;Bytea' +
'AsLongVarBinary=0;UseServerSidePrepare=0;LowerCaseIdentifier=0;X' +
'aOpt=1"'
end>
Params = <
item
Name = 'GROUP_ID'
Value = -1
ParamType = rpParamInteger
Datasets.Strings = (
'ANAGRAFICHE')
Description = 'Identificatore report_id per stampa multipla'
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end
item
Name = 'ID'
AllowNulls = False
Value = 0
ParamType = rpParamInteger
Datasets.Strings = (
'DATI')
Description = ''
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
TwoPass = True
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection2
end
item
Section = TRpSection0
end
item
Section = TRpSection3
end
item
Section = TRpSection4
end>
Alias = 'ANAGRAFICHE'
PrintOnlyIfDataAvailable = False
end
object TRpSection0: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSubReport1: TRpSubReport
Sections = <
item
Section = TRpSection10
end>
ParentSubReport = TRpSubReport0
ParentSection = TRpSection0
end
object TRpSection10: TRpSection
Width = 10605
Height = 2430
SubReport = TRpSubReport1
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression0
end
item
Component = TRpExpression2
end
item
Component = TRpExpression4
end
item
Component = TRpLabel3
end
item
Component = TRpLabel5
end
item
Component = TRpExpression8
end
item
Component = TRpExpression10
end
item
Component = TRpLabel7
end
item
Component = TRpLabel9
end
item
Component = TRpLabel10
end
item
Component = TRpLabel15
end
item
Component = TRpShape2
end
item
Component = TRpShape5
end
item
Component = TRpExpression11
end
item
Component = TRpExpression3
end
item
Component = TRpLabel1
end
item
Component = TRpExpression6
end
item
Component = TRpShape0
end>
AutoExpand = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSubReport2: TRpSubReport
Sections = <
item
Section = TRpSection1
end>
Alias = 'DATI'
ParentSubReport = TRpSubReport0
ParentSection = TRpSection3
end
object TRpSection1: TRpSection
Width = 1425
Height = 225
SubReport = TRpSubReport2
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression1
end>
HorzDesp = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection3: TRpSection
Width = 10772
Height = 30
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression1: TRpExpression
Width = 915
Height = 225
PosX = 465
PosY = 0
Type1Font = poLinked
FontSize = 8
VAlignment = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'DATI.nome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression0: TRpExpression
Width = 2295
Height = 225
PosX = 6675
PosY = 810
Type1Font = poLinked
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.descrizione'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression2: TRpExpression
Width = 2295
Height = 225
PosX = 6675
PosY = 1050
Type1Font = poLinked
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.indirizzo'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression4: TRpExpression
Width = 2415
Height = 225
PosX = 6675
PosY = 1275
Type1Font = poLinked
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.tel1'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel3: TRpLabel
Width = 570
Height = 225
PosX = 6090
PosY = 1050
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Via: '
end
object TRpLabel5: TRpLabel
Width = 690
Height = 225
PosX = 5985
PosY = 1725
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'C.F.: '
end
object TRpExpression8: TRpExpression
Width = 1140
Height = 225
PosX = 6675
PosY = 1725
Type1Font = poLinked
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.codice_fiscale'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression10: TRpExpression
Width = 2640
Height = 225
PosX = 6675
PosY = 1500
Type1Font = poLinked
FontSize = 8
WordWrap = True
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.tel2'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel7: TRpLabel
Width = 1260
Height = 225
PosX = 5400
PosY = 810
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Descrizione: '
end
object TRpLabel9: TRpLabel
Width = 570
Height = 225
PosX = 6090
PosY = 1275
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Tel1: '
end
object TRpLabel10: TRpLabel
Width = 570
Height = 225
PosX = 6090
PosY = 1500
Type1Font = poHelvetica
FontSize = 8
Alignment = 2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Tel2: '
end
object TRpSection2: TRpSection
Width = 10772
Height = 1230
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpheader
Components = <
item
Component = TRpLabel11
end
item
Component = TRpLabel12
end
item
Component = TRpExpression12
end
item
Component = TRpLabel14
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel11: TRpLabel
Width = 2070
Height = 345
PosX = 8745
PosY = 0
Type1Font = poLinked
FontSize = 13
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'MasonSQL'
end
object TRpLabel12: TRpLabel
Width = 465
Height = 225
PosX = 8400
PosY = 915
Type1Font = poLinked
FontSize = 8
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'helvetica'
WideText = 'Data:'
end
object TRpExpression12: TRpExpression
Width = 1155
Height = 225
PosX = 8850
PosY = 915
Type1Font = poLinked
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'FormatStr('#39'dd/mm/yyyy'#39', today)'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel14: TRpLabel
Width = 2995
Height = 691
PosX = 225
PosY = 0
Type1Font = poLinked
FontSize = 28
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Anagrafiche'
end
object TRpLabel15: TRpLabel
Width = 3210
Height = 225
PosX = 465
PosY = 2190
Type1Font = poHelvetica
FontSize = 7
Alignment = 1
VAlignment = 16
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Gruppi di appartenenza dell'#39'utente:'
end
object TRpShape2: TRpShape
Width = 10470
Height = 240
PosX = 0
PosY = 345
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpShape5: TRpShape
Width = 5055
Height = 1380
PosX = 120
PosY = 690
BrushColor = 15724527
PenColor = 16777215
Shape = rpsRoundRect
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpExpression11: TRpExpression
Width = 4485
Height = 345
PosX = 570
PosY = 810
Type1Font = poLinked
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.nome + '#39' '#39' + ANAGRAFICHE.cognome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression3: TRpExpression
Width = 2880
Height = 345
PosX = 1260
PosY = 1265
Type1Font = poLinked
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.login'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel1: TRpLabel
Width = 585
Height = 345
PosX = 570
PosY = 1260
Type1Font = poHelvetica
Alignment = 1
VAlignment = 16
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'login: '
end
object TRpExpression6: TRpExpression
Width = 3210
Height = 345
PosX = 570
PosY = 1730
Type1Font = poLinked
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.email'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpShape0: TRpShape
Width = 10350
Height = 75
PosX = 120
PosY = 2070
Shape = rpsHorzLine
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpSection4: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpShape3
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpShape3: TRpShape
Width = 10350
Height = 120
PosX = 110
PosY = 0
Shape = rpsHorzLine
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
end
/tags/2.0/htdocs/data/public/gruppi.kylix.rep
0,0 → 1,1076
object TRpReport
PageOrientation = rpOrientationPortrait
Pagesize = rpPageSizeCustom
PageHeight = 8120
PageWidth = 5742
PageBackColor = 2147483647
LeftMargin = 454
TopMargin = 454
RightMargin = 454
BottomMargin = 454
SubReports = <
item
SubReport = TRpSubReport0
end
item
SubReport = TRpSubReport2
end
item
SubReport = TRpSubReport1
end
item
SubReport = TRpSubReport3
end>
DataInfo = <
item
Alias = 'ANAGRAFICHE'
DatabaseAlias = 'MASONSQL'
SQL =
'select '#13#10' anagrafiche.*'#13#10'from '#13#10' anagrafiche, anagrafiche_' +
'gruppi ag'#13#10'where ag.id_gruppi = :ID_GRUPPO'#13#10'and ag.id_anagrafich' +
'e = anagrafiche.id'#13#10'order by id;'
DataSource = 'GRUPPI'
end
item
Alias = 'AUTORIZZAZIONI'
DatabaseAlias = 'MASONSQL'
SQL =
'select distinct funzioni.nome , '#13#10' (select distinct id_autoriz' +
'zazioni'#13#10' from gruppi_funzioni gf'#13#10' where gf.id_funzion' +
'i = gg.id_funzioni and'#13#10' gf.id_autorizzazioni = 1) as ' +
'm_menu,'#13#10' (select distinct id_autorizzazioni'#13#10' from grupp' +
'i_funzioni gf'#13#10' where gf.id_funzioni = gg.id_funzioni and'#13#10' ' +
' gf.id_autorizzazioni = 2) as m_select,'#13#10' (select dis' +
'tinct id_autorizzazioni'#13#10' from gruppi_funzioni gf'#13#10' wher' +
'e gf.id_funzioni = gg.id_funzioni and'#13#10' gf.id_autoriz' +
'zazioni = 3) as m_update,'#13#10' (select distinct id_autorizzazioni' +
#13#10' from gruppi_funzioni gf'#13#10' where gf.id_funzioni = gg.' +
'id_funzioni and'#13#10' gf.id_autorizzazioni = 4) as m_delet' +
'e,'#13#10' (select distinct id_autorizzazioni'#13#10' from gruppi_fun' +
'zioni gf'#13#10' where gf.id_funzioni = gg.id_funzioni and'#13#10' ' +
' gf.id_autorizzazioni = 5) as m_print,'#13#10' (select distinct ' +
'id_autorizzazioni'#13#10' from gruppi_funzioni gf'#13#10' where gf.' +
'id_funzioni = gg.id_funzioni and'#13#10' gf.id_autorizzazion' +
'i = 6) as m_printsel,'#13#10' (select distinct id_autorizzazioni'#13#10' ' +
' from gruppi_funzioni gf'#13#10' where gf.id_funzioni = gg.id_f' +
'unzioni and'#13#10' gf.id_autorizzazioni = 7) as m_insert'#13#10'f' +
'rom funzioni'#13#10'inner join gruppi_funzioni gg on gg.id_funzioni = ' +
'funzioni.id'#13#10'inner join autorizzazioni on gg.id_autorizzazioni =' +
' autorizzazioni.id'#13#10'where gg.id_gruppi= :ID_GRUPPO'
DataSource = 'GRUPPI'
end
item
Alias = 'GRUPPI'
DatabaseAlias = 'MASONSQL'
SQL =
'select *, gruppi.id as ID_GRUPPO from report_id, gruppi '#13#10'where ' +
'report_id.group_id = :GROUP_ID'#13#10' and gruppi.id=key;'#13#10
end>
DatabaseInfo = <
item
Alias = 'MASONSQL'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdatazeos
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString = ''
end>
Params = <
item
Name = 'GROUP_ID'
Value = -1
ParamType = rpParamInteger
Datasets.Strings = (
'GRUPPI')
Description = 'Identificatore report_id per stampa multipla'
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
TwoPass = True
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection2
end
item
Section = TRpSection0
end
item
Section = TRpSection3
end
item
Section = TRpSection4
end
item
Section = TRpSection6
end>
Alias = 'GRUPPI'
PrintOnlyIfDataAvailable = False
end
object TRpSection0: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSubReport1: TRpSubReport
Sections = <
item
Section = TRpSection10
end>
ParentSubReport = TRpSubReport0
ParentSection = TRpSection0
end
object TRpSection10: TRpSection
Width = 11355
Height = 1455
SubReport = TRpSubReport1
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpShape2
end
item
Component = TRpExpression16
end
item
Component = TRpExpression17
end
item
Component = TRpExpression18
end
item
Component = TRpLabel0
end
item
Component = TRpLabel1
end
item
Component = TRpLabel2
end
item
Component = TRpLabel3
end
item
Component = TRpLabel4
end
item
Component = TRpLabel5
end
item
Component = TRpLabel6
end
item
Component = TRpLabel7
end
item
Component = TRpShape0
end
item
Component = TRpLabel9
end
item
Component = TRpShape3
end>
AutoExpand = True
HorzDesp = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection3: TRpSection
Width = 10772
Height = 30
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport3
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection2: TRpSection
Width = 10772
Height = 1230
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpheader
Components = <
item
Component = TRpLabel11
end
item
Component = TRpLabel12
end
item
Component = TRpExpression12
end
item
Component = TRpLabel14
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel11: TRpLabel
Width = 2070
Height = 345
PosX = 8745
PosY = 0
Type1Font = poHelvetica
FontSize = 13
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'MasonSQL'
end
object TRpLabel12: TRpLabel
Width = 465
Height = 225
PosX = 8400
PosY = 915
Type1Font = poHelvetica
FontSize = 8
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'helvetica'
WideText = 'Data:'
end
object TRpExpression12: TRpExpression
Width = 1155
Height = 225
PosX = 8850
PosY = 915
Type1Font = poHelvetica
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'FormatStr('#39'dd/mm/yyyy'#39', today)'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel14: TRpLabel
Width = 4380
Height = 690
PosX = 225
PosY = 0
Type1Font = poHelvetica
FontSize = 28
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Distinta GRUPPI'
end
object TRpSubReport3: TRpSubReport
Sections = <
item
Section = TRpSection5
end>
Alias = 'AUTORIZZAZIONI'
ParentSubReport = TRpSubReport0
ParentSection = TRpSection3
end
object TRpSection5: TRpSection
Width = 11130
Height = 225
SubReport = TRpSubReport3
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression13
end
item
Component = TRpExpression14
end
item
Component = TRpExpression15
end
item
Component = TRpExpression20
end
item
Component = TRpExpression21
end
item
Component = TRpExpression22
end
item
Component = TRpExpression23
end
item
Component = TRpExpression24
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection6: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression13: TRpExpression
Width = 1380
Height = 225
PosX = 120
PosY = 0
Type1Font = poHelvetica
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'AUTORIZZAZIONI.nome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression14: TRpExpression
Width = 1275
Height = 225
PosX = 3330
PosY = 0
Type1Font = poHelvetica
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_menu == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression15: TRpExpression
Width = 1155
Height = 225
PosX = 4605
PosY = 0
Type1Font = poHelvetica
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_select == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression16: TRpExpression
Width = 1725
Height = 360
PosX = 1260
PosY = 570
Type1Font = poHelvetica
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'GRUPPI.nome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression17: TRpExpression
Width = 1485
Height = 240
PosX = 2985
PosY = 690
Type1Font = poHelvetica
FontSize = 8
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'GRUPPI.descrizione'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression18: TRpExpression
Width = 1380
Height = 240
PosX = 4605
PosY = 690
Type1Font = poHelvetica
FontSize = 8
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'GRUPPI.commento'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression20: TRpExpression
Width = 810
Height = 225
PosX = 5640
PosY = 0
Type1Font = poHelvetica
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_update == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression21: TRpExpression
Width = 930
Height = 225
PosX = 6780
PosY = 0
Type1Font = poHelvetica
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_delete == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression22: TRpExpression
Width = 945
Height = 225
PosX = 10125
PosY = 0
Type1Font = poHelvetica
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_print == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression23: TRpExpression
Width = 1050
Height = 225
PosX = 8970
PosY = 0
Type1Font = poHelvetica
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_printsel == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression24: TRpExpression
Width = 990
Height = 225
PosX = 7815
PosY = 0
Type1Font = poHelvetica
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_insert == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel0: TRpLabel
Width = 915
Height = 240
PosX = 8625
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'stampa sel.'
end
object TRpLabel1: TRpLabel
Width = 915
Height = 240
PosX = 9885
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'stampa'
end
object TRpLabel2: TRpLabel
Width = 915
Height = 240
PosX = 6435
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'cancella'
end
object TRpLabel3: TRpLabel
Width = 915
Height = 240
PosX = 5280
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'aggiorna'
end
object TRpLabel4: TRpLabel
Width = 915
Height = 240
PosX = 4140
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'selezione'
end
object TRpLabel5: TRpLabel
Width = 915
Height = 240
PosX = 3105
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'menu'
end
object TRpLabel6: TRpLabel
Width = 915
Height = 240
PosX = 120
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Nome'
end
object TRpLabel7: TRpLabel
Width = 915
Height = 240
PosX = 7365
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'inserimento'
end
object TRpSubReport2: TRpSubReport
Sections = <
item
Section = TRpSection1
end>
Alias = 'ANAGRAFICHE'
ParentSubReport = TRpSubReport0
ParentSection = TRpSection6
end
object TRpSection1: TRpSection
Width = 11730
Height = 135
SubReport = TRpSubReport2
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression0
end
item
Component = TRpExpression2
end
item
Component = TRpExpression3
end>
HorzDesp = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression0: TRpExpression
Width = 1605
Height = 225
PosX = 120
PosY = 0
Type1Font = poHelvetica
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.nome + '#39' '#39' + ANAGRAFICHE.cognome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression2: TRpExpression
Width = 1380
Height = 225
PosX = 2295
PosY = 0
Type1Font = poHelvetica
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.login'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression3: TRpExpression
Width = 2760
Height = 195
PosX = 4140
PosY = 0
Type1Font = poHelvetica
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.email'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpShape2: TRpShape
Width = 10815
Height = 225
PosX = 0
PosY = 345
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpSection4: TRpSection
Width = 10772
Height = 630
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpShape1
end
item
Component = TRpLabel8
end
item
Component = TRpLabel10
end
item
Component = TRpLabel15
end
item
Component = TRpShape4
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpShape1: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 120
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpLabel9: TRpLabel
Width = 1035
Height = 225
PosX = 120
PosY = 690
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'GRUPPO: '
end
object TRpShape3: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 1380
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpLabel8: TRpLabel
Width = 1605
Height = 225
PosX = 120
PosY = 225
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'ELENCO UTENTI'
end
object TRpLabel10: TRpLabel
Width = 1605
Height = 225
PosX = 2295
PosY = 240
Type1Font = poHelvetica
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'login'
end
object TRpLabel15: TRpLabel
Width = 1605
Height = 225
PosX = 4140
PosY = 240
Type1Font = poHelvetica
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'e-mail'
end
object TRpShape0: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 1035
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpShape4: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 465
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
end
/tags/2.0/htdocs/data/public/gruppi.wine.rep
0,0 → 1,1105
object TRpReport
PageOrientation = rpOrientationPortrait
Pagesize = rpPageSizeCustom
PageHeight = 8120
PageWidth = 5742
PageBackColor = 2147483647
LeftMargin = 454
TopMargin = 454
RightMargin = 454
BottomMargin = 454
SubReports = <
item
SubReport = TRpSubReport0
end
item
SubReport = TRpSubReport2
end
item
SubReport = TRpSubReport1
end
item
SubReport = TRpSubReport3
end>
DataInfo = <
item
Alias = 'ANAGRAFICHE'
DatabaseAlias = 'MASONSQL'
SQL =
'select '#13#10' anagrafiche.*'#13#10'from '#13#10' anagrafiche, anagrafiche_' +
'gruppi ag'#13#10'where ag.id_gruppi = :ID_GRUPPO'#13#10'and ag.id_anagrafich' +
'e = anagrafiche.id'#13#10'order by id;'
DataSource = 'GRUPPI'
end
item
Alias = 'AUTORIZZAZIONI'
DatabaseAlias = 'MASONSQL'
SQL =
'select distinct funzioni.nome , '#13#10' (select distinct id_autoriz' +
'zazioni'#13#10' from gruppi_funzioni gf'#13#10' where gf.id_funzion' +
'i = gg.id_funzioni and'#13#10' gf.id_autorizzazioni = 1) as ' +
'm_menu,'#13#10' (select distinct id_autorizzazioni'#13#10' from grupp' +
'i_funzioni gf'#13#10' where gf.id_funzioni = gg.id_funzioni and'#13#10' ' +
' gf.id_autorizzazioni = 2) as m_select,'#13#10' (select dis' +
'tinct id_autorizzazioni'#13#10' from gruppi_funzioni gf'#13#10' wher' +
'e gf.id_funzioni = gg.id_funzioni and'#13#10' gf.id_autoriz' +
'zazioni = 3) as m_update,'#13#10' (select distinct id_autorizzazioni' +
#13#10' from gruppi_funzioni gf'#13#10' where gf.id_funzioni = gg.' +
'id_funzioni and'#13#10' gf.id_autorizzazioni = 4) as m_delet' +
'e,'#13#10' (select distinct id_autorizzazioni'#13#10' from gruppi_fun' +
'zioni gf'#13#10' where gf.id_funzioni = gg.id_funzioni and'#13#10' ' +
' gf.id_autorizzazioni = 5) as m_print,'#13#10' (select distinct ' +
'id_autorizzazioni'#13#10' from gruppi_funzioni gf'#13#10' where gf.' +
'id_funzioni = gg.id_funzioni and'#13#10' gf.id_autorizzazion' +
'i = 6) as m_printsel,'#13#10' (select distinct id_autorizzazioni'#13#10' ' +
' from gruppi_funzioni gf'#13#10' where gf.id_funzioni = gg.id_f' +
'unzioni and'#13#10' gf.id_autorizzazioni = 7) as m_insert'#13#10'f' +
'rom funzioni'#13#10'inner join gruppi_funzioni gg on gg.id_funzioni = ' +
'funzioni.id'#13#10'inner join autorizzazioni on gg.id_autorizzazioni =' +
' autorizzazioni.id'#13#10'where gg.id_gruppi= :ID_GRUPPO'
DataSource = 'GRUPPI'
end
item
Alias = 'GRUPPI'
DatabaseAlias = 'MASONSQL'
SQL =
'select '#13#10' gruppi.id as ID_GRUPPO, '#13#10' gruppi.* '#13#10'from gruppi, r' +
'eport_id'#13#10'where :GROUP_ID > 0 and gruppi.id=report_id.key and ' +
'report_id.group_id = :GROUP_ID'#13#10#13#10'UNION'#13#10#13#10'select '#13#10' gruppi.id ' +
'as ID_GRUPPO, '#13#10' gruppi.* '#13#10'from gruppi'#13#10'where :GROUP_ID < 0 a' +
'nd gruppi.id = - :GROUP_ID'#13#10#13#10
end>
DatabaseInfo = <
item
Alias = 'MASONSQL'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdataado
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString =
'Provider=MSDASQL.1;Persist Security Info=False;Mode=Read;Extende' +
'd Properties="DRIVER={PostgreSQL Unicode};DATABASE=masonsql;SERV' +
'ER=127.0.0.1;USER=report;PASSWORD=<password>;PORT=5432;UID=repor' +
't;SSLmode=allow;ReadOnly=1;Protocol=7.4-1;FakeOidIndex=0;ShowOid' +
'Column=0;RowVersioning=0;ShowSystemTables=0;ConnSettings=;Fetch=' +
'100;Socket=4096;UnknownSizes=0;MaxVarcharSize=254;MaxLongVarchar' +
'Size=8190;Debug=0;CommLog=0;Optimizer=1;Ksqo=1;UseDeclareFetch=0' +
';TextAsLongVarchar=1;UnknownsAsLongVarchar=0;BoolsAsChar=1;Parse' +
'=1;CancelAsFreeStmt=0;ExtraSysTablePrefixes=dd_;;LFConversion=1;' +
'UpdatableCursors=1;DisallowPremature=0;TrueIsMinus1=0;BI=0;Bytea' +
'AsLongVarBinary=0;UseServerSidePrepare=0;LowerCaseIdentifier=0;X' +
'aOpt=1"'
end>
Params = <
item
Name = 'GROUP_ID'
Value = -1
ParamType = rpParamInteger
Datasets.Strings = (
'GRUPPI')
Description = 'Identificatore report_id per stampa multipla'
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end
item
Name = 'ID_GRUPPO'
AllowNulls = False
Value = 0
ParamType = rpParamInteger
Datasets.Strings = (
'ANAGRAFICHE'
'AUTORIZZAZIONI')
Description = ''
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
TwoPass = True
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection2
end
item
Section = TRpSection0
end
item
Section = TRpSection3
end
item
Section = TRpSection4
end
item
Section = TRpSection6
end>
Alias = 'GRUPPI'
PrintOnlyIfDataAvailable = False
end
object TRpSection0: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSubReport1: TRpSubReport
Sections = <
item
Section = TRpSection10
end>
ParentSubReport = TRpSubReport0
ParentSection = TRpSection0
end
object TRpSection10: TRpSection
Width = 11355
Height = 1455
SubReport = TRpSubReport1
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpShape2
end
item
Component = TRpExpression16
end
item
Component = TRpExpression17
end
item
Component = TRpExpression18
end
item
Component = TRpLabel0
end
item
Component = TRpLabel1
end
item
Component = TRpLabel2
end
item
Component = TRpLabel3
end
item
Component = TRpLabel4
end
item
Component = TRpLabel5
end
item
Component = TRpLabel6
end
item
Component = TRpLabel7
end
item
Component = TRpShape0
end
item
Component = TRpLabel9
end
item
Component = TRpShape3
end>
AutoExpand = True
HorzDesp = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection3: TRpSection
Width = 10772
Height = 30
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport3
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection2: TRpSection
Width = 10772
Height = 1230
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpheader
Components = <
item
Component = TRpLabel11
end
item
Component = TRpLabel12
end
item
Component = TRpExpression12
end
item
Component = TRpLabel14
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel11: TRpLabel
Width = 2070
Height = 345
PosX = 8745
PosY = 0
Type1Font = poLinked
FontSize = 13
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'MasonSQL'
end
object TRpLabel12: TRpLabel
Width = 465
Height = 225
PosX = 8400
PosY = 915
Type1Font = poLinked
FontSize = 8
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'helvetica'
WideText = 'Data:'
end
object TRpExpression12: TRpExpression
Width = 1155
Height = 225
PosX = 8850
PosY = 915
Type1Font = poLinked
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'FormatStr('#39'dd/mm/yyyy'#39', today)'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel14: TRpLabel
Width = 4380
Height = 690
PosX = 225
PosY = 0
Type1Font = poLinked
FontSize = 28
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Distinta GRUPPI'
end
object TRpSubReport3: TRpSubReport
Sections = <
item
Section = TRpSection5
end>
Alias = 'AUTORIZZAZIONI'
ParentSubReport = TRpSubReport0
ParentSection = TRpSection3
end
object TRpSection5: TRpSection
Width = 11130
Height = 225
SubReport = TRpSubReport3
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression13
end
item
Component = TRpExpression14
end
item
Component = TRpExpression15
end
item
Component = TRpExpression20
end
item
Component = TRpExpression21
end
item
Component = TRpExpression22
end
item
Component = TRpExpression23
end
item
Component = TRpExpression24
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection6: TRpSection
Width = 10772
Height = 0
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
ChildSubReport = TRpSubReport2
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression13: TRpExpression
Width = 1380
Height = 225
PosX = 120
PosY = 0
Type1Font = poLinked
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'AUTORIZZAZIONI.nome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression14: TRpExpression
Width = 1275
Height = 225
PosX = 3330
PosY = 0
Type1Font = poLinked
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_menu == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression15: TRpExpression
Width = 1155
Height = 225
PosX = 4605
PosY = 0
Type1Font = poLinked
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_select == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression16: TRpExpression
Width = 1725
Height = 360
PosX = 1260
PosY = 570
Type1Font = poLinked
FontSize = 12
FontStyle = 1
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'GRUPPI.nome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression17: TRpExpression
Width = 1485
Height = 240
PosX = 2985
PosY = 690
Type1Font = poLinked
FontSize = 8
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'GRUPPI.descrizione'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression18: TRpExpression
Width = 1380
Height = 240
PosX = 4605
PosY = 690
Type1Font = poLinked
FontSize = 8
VAlignment = 16
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'GRUPPI.commento'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression20: TRpExpression
Width = 810
Height = 225
PosX = 5640
PosY = 0
Type1Font = poLinked
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_update == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression21: TRpExpression
Width = 930
Height = 225
PosX = 6780
PosY = 0
Type1Font = poLinked
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_delete == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression22: TRpExpression
Width = 945
Height = 225
PosX = 10125
PosY = 0
Type1Font = poLinked
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_print == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression23: TRpExpression
Width = 1050
Height = 225
PosX = 8970
PosY = 0
Type1Font = poLinked
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_printsel == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression24: TRpExpression
Width = 990
Height = 225
PosX = 7815
PosY = 0
Type1Font = poLinked
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'IIF(AUTORIZZAZIONI.m_insert == NULL , '#39' '#39', '#39'x'#39')'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel0: TRpLabel
Width = 915
Height = 240
PosX = 8625
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'stampa sel.'
end
object TRpLabel1: TRpLabel
Width = 915
Height = 240
PosX = 9885
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'stampa'
end
object TRpLabel2: TRpLabel
Width = 915
Height = 240
PosX = 6435
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'cancella'
end
object TRpLabel3: TRpLabel
Width = 915
Height = 240
PosX = 5280
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'aggiorna'
end
object TRpLabel4: TRpLabel
Width = 915
Height = 240
PosX = 4140
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'selezione'
end
object TRpLabel5: TRpLabel
Width = 915
Height = 240
PosX = 3105
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'menu'
end
object TRpLabel6: TRpLabel
Width = 915
Height = 240
PosX = 120
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Nome'
end
object TRpLabel7: TRpLabel
Width = 915
Height = 240
PosX = 7365
PosY = 1155
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'inserimento'
end
object TRpSubReport2: TRpSubReport
Sections = <
item
Section = TRpSection1
end>
Alias = 'ANAGRAFICHE'
ParentSubReport = TRpSubReport0
ParentSection = TRpSection6
end
object TRpSection1: TRpSection
Width = 11730
Height = 135
SubReport = TRpSubReport2
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression0
end
item
Component = TRpExpression2
end
item
Component = TRpExpression3
end>
HorzDesp = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression0: TRpExpression
Width = 1605
Height = 225
PosX = 120
PosY = 0
Type1Font = poLinked
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.nome + '#39' '#39' + ANAGRAFICHE.cognome'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression2: TRpExpression
Width = 1380
Height = 225
PosX = 2295
PosY = 0
Type1Font = poLinked
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.login'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression3: TRpExpression
Width = 2760
Height = 195
PosX = 4140
PosY = 0
Type1Font = poLinked
FontSize = 6
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'ANAGRAFICHE.email'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpShape2: TRpShape
Width = 10815
Height = 225
PosX = 0
PosY = 345
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpSection4: TRpSection
Width = 10772
Height = 630
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpShape1
end
item
Component = TRpLabel8
end
item
Component = TRpLabel10
end
item
Component = TRpLabel15
end
item
Component = TRpShape4
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpShape1: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 120
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpLabel9: TRpLabel
Width = 1035
Height = 225
PosX = 120
PosY = 690
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'GRUPPO: '
end
object TRpShape3: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 1380
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpLabel8: TRpLabel
Width = 1605
Height = 225
PosX = 120
PosY = 225
Type1Font = poHelvetica
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'ELENCO UTENTI'
end
object TRpLabel10: TRpLabel
Width = 1605
Height = 225
PosX = 2295
PosY = 240
Type1Font = poHelvetica
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'login'
end
object TRpLabel15: TRpLabel
Width = 1605
Height = 225
PosX = 4140
PosY = 240
Type1Font = poHelvetica
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'e-mail'
end
object TRpShape0: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 1035
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpShape4: TRpShape
Width = 10815
Height = 75
PosX = 0
PosY = 465
BrushColor = 14540253
PenColor = 16777215
PenWidth = 0
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
end
/tags/2.0/htdocs/data/public/logs_report.kylix.rep
0,0 → 1,503
object TRpReport
PageOrientation = rpOrientationPortrait
Pagesize = rpPageSizeCustom
PageHeight = 8120
PageWidth = 5742
PageBackColor = 2147483647
LeftMargin = 454
TopMargin = 454
RightMargin = 454
BottomMargin = 454
SubReports = <
item
SubReport = TRpSubReport0
end>
DataInfo = <
item
Alias = 'LOGS_REPORT'
DatabaseAlias = 'MASONSQL'
SQL =
'select '#10' logs_report.table_name,'#10' logs_report.id_record,'#10' to' +
'_char(logs_report.timestamp, '#39'DD/MM/YYYY HH24:MM'#39') as timestamp,' +
#10' logs_report.report,'#10' coalesce(anagrafiche.nome || '#39' '#39', '#39#39') |' +
'| coalesce(anagrafiche.cognome) as nominativo'#10'from '#10' public.rep' +
'ort_id, public.logs_report, public.anagrafiche'#10'where '#10' ( :GROUP' +
'_ID = 0 or report_id.group_id = :GROUP_ID'#10' ) and logs_report.id' +
'=report_id.key and anagrafiche.id = logs_report.id_anagrafiche'#10'o' +
'rder by logs_report.timestamp desc;'#10#10
end>
DatabaseInfo = <
item
Alias = 'MASONSQL'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdatazeos
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString = ''
end>
Params = <
item
Name = 'GROUP_ID'
AllowNulls = False
Value = 0
ParamType = rpParamInteger
Datasets.Strings = (
'LOGS_REPORT')
Description = 'Identificatore report_id per stampa multipla'
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
TwoPass = True
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection2
end
item
Section = TRpSection0
end
item
Section = TRpSection1
end>
Alias = 'LOGS_REPORT'
PrintOnlyIfDataAvailable = False
end
object TRpSection0: TRpSection
Width = 10772
Height = 911
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression0
end
item
Component = TRpExpression2
end
item
Component = TRpExpression3
end
item
Component = TRpShape1
end>
AutoExpand = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection2: TRpSection
Width = 10772
Height = 1007
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpheader
Components = <
item
Component = TRpLabel12
end
item
Component = TRpExpression12
end
item
Component = TRpExpression1
end
item
Component = TRpLabel0
end
item
Component = TRpLabel1
end
item
Component = TRpLabel2
end
item
Component = TRpLabel3
end
item
Component = TRpLabel4
end
item
Component = TRpExpression6
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel12: TRpLabel
Width = 465
Height = 225
PosX = 8983
PosY = 118
Type1Font = poHelvetica
FontSize = 8
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'helvetica'
WideText = 'Data:'
end
object TRpExpression12: TRpExpression
Width = 1155
Height = 225
PosX = 9433
PosY = 118
Type1Font = poHelvetica
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'FormatStr('#39'dd/mm/yyyy'#39', today)'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression0: TRpExpression
Width = 8229
Height = 696
PosX = 2527
PosY = 118
Type1Font = poHelvetica
FontSize = 8
WordWrap = True
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.report'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression2: TRpExpression
Width = 2420
Height = 460
PosX = 0
PosY = 343
Type1Font = poHelvetica
FontSize = 9
WordWrap = True
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.nominativo'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression3: TRpExpression
Width = 2420
Height = 225
PosX = 0
PosY = 118
Type1Font = poHelvetica
FontSize = 9
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.timestamp'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel0: TRpLabel
Width = 3100
Height = 294
PosX = 3791
PosY = 0
Type1Font = poHelvetica
FontSize = 12
FontStyle = 1
Alignment = 4
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Variazioni dei dati'
end
object TRpSection1: TRpSection
Width = 10767
Height = 349
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpfooter
Components = <
item
Component = TRpExpression4
end
item
Component = TRpShape0
end
item
Component = TRpExpression5
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
FooterAtReportEnd = True
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression4: TRpExpression
Width = 2762
Height = 231
PosX = 7703
PosY = 114
Type1Font = poHelvetica
FontSize = 9
Alignment = 2
VAlignment = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = #39'Pag. '#39'+Str(NUMPAGINA)+'#39' di '#39
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel2: TRpLabel
Width = 2880
Height = 235
PosX = 6787
PosY = 463
Type1Font = poHelvetica
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = '[xxxx] - dato cancellato'
end
object TRpLabel3: TRpLabel
Width = 2880
Height = 235
PosX = 6787
PosY = 691
Type1Font = poHelvetica
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = '{xxxx} - dato inserito'
end
object TRpShape0: TRpShape
Width = 10810
Height = 115
PosX = 0
PosY = 114
Shape = rpsHorzLine
PenWidth = 17
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpShape1: TRpShape
Width = 10810
Height = 115
PosX = 0
PosY = 50
PenColor = 5855577
Shape = rpsHorzLine
PenWidth = 17
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpLabel1: TRpLabel
Width = 911
Height = 353
PosX = 0
PosY = 578
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Tabella: '
end
object TRpExpression1: TRpExpression
Width = 4144
Height = 353
PosX = 921
PosY = 578
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.table_name'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel4: TRpLabel
Width = 338
Height = 338
PosX = 0
PosY = 235
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'ID: '
end
object TRpExpression6: TRpExpression
Width = 1734
Height = 338
PosX = 338
PosY = 235
Type1Font = poHelvetica
FontSize = 11
FontStyle = 1
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.id_record'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression5: TRpExpression
Width = 298
Height = 231
PosX = 10466
PosY = 114
Type1Font = poHelvetica
FontSize = 9
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'PAGECOUNT'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
end
/tags/2.0/htdocs/data/public/logs_report.wine.rep
0,0 → 1,515
object TRpReport
PageOrientation = rpOrientationPortrait
Pagesize = rpPageSizeCustom
PageHeight = 8120
PageWidth = 5742
PageBackColor = 2147483647
LeftMargin = 454
TopMargin = 454
RightMargin = 454
BottomMargin = 454
SubReports = <
item
SubReport = TRpSubReport0
end>
DataInfo = <
item
Alias = 'LOGS_REPORT'
DatabaseAlias = 'MASONSQL'
SQL =
'select '#13#10' logs_report.table_name,'#13#10' logs_report.id_record,'#13#10' ' +
' to_char(logs_report.timestamp, '#39'DD/MM/YYYY HH24:MM'#39') as timesta' +
'mp,'#13#10' logs_report.report,'#13#10' coalesce(anagrafiche.nome || '#39' '#39', ' +
#39#39') || coalesce(anagrafiche.cognome) as nominativo'#13#10'from '#13#10' pub' +
'lic.report_id, public.logs_report, public.anagrafiche'#13#10'where '#13#10' ' +
'( :GROUP_ID = 0 or report_id.group_id = :GROUP_ID'#13#10' ) and logs' +
'_report.id=report_id.key and anagrafiche.id = logs_report.id_ana' +
'grafiche'#13#10'order by logs_report.timestamp desc;'#13#10#13#10
end>
DatabaseInfo = <
item
Alias = 'MASONSQL'
LoadParams = True
LoadDriverParams = True
LoginPrompt = False
Driver = rpdataado
ReportTable = 'REPMAN_REPORTS'
ReportSearchField = 'REPORT_NAME'
ReportField = 'REPORT'
ReportGroupsTable = 'REPMAN_GROUPS'
ADOConnectionString =
'Provider=MSDASQL.1;Persist Security Info=False;Mode=Read;Extende' +
'd Properties="DRIVER={PostgreSQL Unicode};DATABASE=masonsql;SERV' +
'ER=127.0.0.1;USER=report;PASSWORD=<password>;PORT=5432;UID=repor' +
't;SSLmode=allow;ReadOnly=1;Protocol=7.4-1;FakeOidIndex=0;ShowOid' +
'Column=0;RowVersioning=0;ShowSystemTables=0;ConnSettings=;Fetch=' +
'100;Socket=4096;UnknownSizes=0;MaxVarcharSize=254;MaxLongVarchar' +
'Size=8190;Debug=0;CommLog=0;Optimizer=1;Ksqo=1;UseDeclareFetch=0' +
';TextAsLongVarchar=1;UnknownsAsLongVarchar=0;BoolsAsChar=1;Parse' +
'=1;CancelAsFreeStmt=0;ExtraSysTablePrefixes=dd_;;LFConversion=1;' +
'UpdatableCursors=1;DisallowPremature=0;TrueIsMinus1=0;BI=0;Bytea' +
'AsLongVarBinary=0;UseServerSidePrepare=0;LowerCaseIdentifier=0;X' +
'aOpt=1"'
end>
Params = <
item
Name = 'GROUP_ID'
AllowNulls = False
Value = -1
ParamType = rpParamInteger
Datasets.Strings = (
'LOGS_REPORT')
Description = 'Identificatore report_id per stampa multipla'
Hint = ''
Search = ''
ErrorMessage = ''
Validation = ''
end>
TwoPass = True
StreamFormat = rpStreamText
ReportAction = []
Type1Font = poHelvetica
WFontName = 'Arial'
LFontName = 'Helvetica'
object TRpSubReport0: TRpSubReport
Sections = <
item
Section = TRpSection2
end
item
Section = TRpSection0
end
item
Section = TRpSection1
end>
Alias = 'LOGS_REPORT'
PrintOnlyIfDataAvailable = False
end
object TRpSection0: TRpSection
Width = 10772
Height = 911
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecdetail
Components = <
item
Component = TRpExpression0
end
item
Component = TRpExpression2
end
item
Component = TRpExpression3
end
item
Component = TRpShape1
end>
AutoExpand = True
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpSection2: TRpSection
Width = 10772
Height = 1007
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpheader
Components = <
item
Component = TRpLabel12
end
item
Component = TRpExpression12
end
item
Component = TRpExpression1
end
item
Component = TRpLabel0
end
item
Component = TRpLabel1
end
item
Component = TRpLabel2
end
item
Component = TRpLabel3
end
item
Component = TRpLabel4
end
item
Component = TRpExpression6
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpLabel12: TRpLabel
Width = 465
Height = 225
PosX = 8983
PosY = 118
Type1Font = poLinked
FontSize = 8
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'helvetica'
WideText = 'Data:'
end
object TRpExpression12: TRpExpression
Width = 1155
Height = 225
PosX = 9433
PosY = 118
Type1Font = poLinked
FontSize = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'FormatStr('#39'dd/mm/yyyy'#39', today)'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression0: TRpExpression
Width = 8229
Height = 696
PosX = 2535
PosY = 120
Type1Font = poLinked
FontSize = 8
WordWrap = True
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.report'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression2: TRpExpression
Width = 2420
Height = 460
PosX = 8
PosY = 345
Type1Font = poLinked
FontSize = 9
WordWrap = True
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.nominativo'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression3: TRpExpression
Width = 2420
Height = 225
PosX = 8
PosY = 120
Type1Font = poLinked
FontSize = 9
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.timestamp'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel0: TRpLabel
Width = 3100
Height = 294
PosX = 3791
PosY = 0
Type1Font = poLinked
FontSize = 12
FontStyle = 1
Alignment = 4
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Variazioni dei dati'
end
object TRpSection1: TRpSection
Width = 10767
Height = 349
SubReport = TRpSubReport0
ChangeBool = False
PageRepeat = False
SkipPage = False
AlignBottom = False
SectionType = rpsecpfooter
Components = <
item
Component = TRpExpression4
end
item
Component = TRpShape0
end
item
Component = TRpExpression5
end>
ExternalTable = 'REPMAN_REPORTS'
ExternalField = 'REPORT'
ExternalSearchField = 'REPORT_NAME'
StreamFormat = rpStreamText
FooterAtReportEnd = True
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
ChangeExpression = ''
BeginPageExpression = ''
ChangeExpression = ''
SkipExpreV = ''
SkipExpreH = ''
SkipToPageExpre = ''
BackExpression = ''
Stream = {0000000000000000}
end
object TRpExpression4: TRpExpression
Width = 2762
Height = 231
PosX = 7703
PosY = 114
Type1Font = poHelvetica
FontSize = 9
Alignment = 2
VAlignment = 8
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = #39'Pag. '#39'+Str(NUMPAGINA)+'#39' di '#39
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel2: TRpLabel
Width = 2880
Height = 235
PosX = 6787
PosY = 463
Type1Font = poLinked
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = '[xxxx] - dato cancellato'
end
object TRpLabel3: TRpLabel
Width = 2880
Height = 235
PosX = 6787
PosY = 691
Type1Font = poLinked
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = '{xxxx} - dato inserito'
end
object TRpShape0: TRpShape
Width = 10810
Height = 115
PosX = 0
PosY = 114
Shape = rpsHorzLine
PenWidth = 17
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpShape1: TRpShape
Width = 10810
Height = 115
PosX = 8
PosY = 52
PenColor = 5855577
Shape = rpsHorzLine
PenWidth = 17
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
end
object TRpLabel1: TRpLabel
Width = 911
Height = 353
PosX = 0
PosY = 578
Type1Font = poLinked
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'Tabella: '
end
object TRpExpression1: TRpExpression
Width = 4144
Height = 353
PosX = 921
PosY = 578
Type1Font = poLinked
FontSize = 11
FontStyle = 1
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.table_name'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpLabel4: TRpLabel
Width = 338
Height = 338
PosX = 0
PosY = 235
Type1Font = poLinked
FontSize = 11
FontStyle = 1
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
WideText = 'ID: '
end
object TRpExpression6: TRpExpression
Width = 1734
Height = 338
PosX = 338
PosY = 235
Type1Font = poLinked
FontSize = 11
FontStyle = 1
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'LOGS_REPORT.id_record'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
object TRpExpression5: TRpExpression
Width = 298
Height = 231
PosX = 10466
PosY = 114
Type1Font = poHelvetica
FontSize = 9
AutoExpand = False
AutoContract = False
ExportPosition = 0
ExportSize = 1
ExportDoNewLine = False
PrintCondition = ''
DoBeforePrint = ''
DoAfterPrint = ''
WFontName = 'Arial'
LFontName = 'Helvetica'
Expression = 'PAGECOUNT'
DisplayFormat = ''
ExportDisplayFormat = ''
AgIniValue = '0'
ExportExpression = ''
end
end
/tags/2.0/htdocs/data/dhandler
0,0 → 1,10
<%doc>
Metodo di 'default'; non fa nulla in quanto i metodi di default sono
implementati in autohandler.
 
Questo permette di definire oggetti di accesso al database il cui <nome>.mql
corrispondono al nome della tabella.
 
NON CANCELLARE QUESTO FILE!!!
 
</%doc>
/tags/2.0/htdocs/data/global_autohandler
0,0 → 1,179
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2018 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%once>
use JSON;
my $DataBaseUrl = $r->dir_config('DataBaseUrl');
my $BaseUrl = $r->dir_config('BaseUrl');
</%once>
<%flags>
inherit => '/lib/dbms_library.comp' # # NON CANCELLARE !!!
</%flags>
%#-----------------------------------------------------------------------
%# overload metodi di uso generale nell'applicazione specifica
%#-----------------------------------------------------------------------
 
%# per definire un campo è possibile definire un metodo di nome <nome_campo>_FIELD
 
<%method GenericSelect_FIELD>\
<%args>
$from
$remote => undef
$buffer => $from
$readonly => 1
$widget => 'htmlselect' # oppure 'select' o 'divselect'
</%args>
<%perl>
$buffer =~ s/[\/\\\.]/_/g; # caratteri che non si possono utilizzare come nome buffer
$ARGS{'buffer'} = $buffer;
$ARGS{'remote'} = $remote;
if(!exists $ARGS{empty}){
$ARGS{empty} = '';
}
if(!exists $ARGS{empty_descr}){
$ARGS{empty_descr} = '';
}
if(!exists $ARGS{empty_button} && $widget eq 'divselect'){
# il pulsante di nessuna selezione nel widget divselect è incomprensibile se non contiene una descrizione;
$ARGS{empty_button} = 'Nessuna descrizione';
}
delete $ARGS{'length'};
delete $ARGS{'size'};
$widget = "/input/$widget.comp";
</%perl>
<& $widget, %ARGS &>\
</%method>
 
<%method JSON_SELECT_FIELDS>
<%args>
$JSON_FIELD => 'fields'
</%args>
<%perl>
my $attrs = $m->comp('SELF:INFO', OBJ => 1);
my @list;
my @names = &Method2Array('FIELDS');
my %standards = map { $_ => 1 } &Method2Array('STANDARD_FIELDS');
foreach my $name (@names){
if(exists $ARGS{$name}){
push @list, $ARGS{$name};
}elsif($standards{$name}){
push @list, $name;
}else{
# Nota: se il campo contiene altri oggetti JSON annidati viene restituita una stringa JSON
my $json_key = exists $attrs->{$name}{JSON} ? $attrs->{$name}{JSON} : $name;
push @list, "$JSON_FIELD->>'$json_key' as $name";
}
}
$m->out(join ', ', @list);
</%perl>
</%method>
 
<%method JSON_INSERT>
<%args>
$JSON_FIELD => 'fields'
$FIELDS_INSERT
</%args>
<%perl>
my $attrs = $m->comp('SELF:INFO', OBJ => 1);
my @standards = &Method2Array('STANDARD_FIELDS');
my %standards;
foreach my $name (@standards){
$standards{$name} = 1;
}
my %FIELDS;
# empty fields are replaced with undef value
foreach my $key (keys %$FIELDS_INSERT){
if(!$standards{$key}){
my $value = delete $FIELDS_INSERT->{$key};
if(defined $value && $value ne ''){
if($value =~ m/^\{.*\}$/ or $value =~ m/^\[.*\]$/){
# se il campo contiene una stringa in formato JSON senza errori ...
my $json = eval { from_json $value };
if(!$@){
$value = $json;
}
}
my $json_key = exists $attrs->{$key}{JSON} ? $attrs->{$key}{JSON} : $key;
$FIELDS{$json_key} = $value;
}
}
}
# fields are returned with values in the JSON hash
$FIELDS_INSERT->{$JSON_FIELD} = to_json(\%FIELDS);
</%perl>
</%method>
 
<%method JSON_UPDATE>
<%args>
$JSON_FIELD => 'fields'
$FIELDS_UPDATE
</%args>
<%perl>
my $attrs = $m->comp('SELF:INFO', OBJ => 1);
my @standards = &Method2Array('STANDARD_FIELDS');
my %standards;
foreach my $name (@standards){
$standards{$name} = 1;
}
my %FIELDS;
foreach my $key (keys %$FIELDS_UPDATE){
if(!$standards{$key}){
my $value = delete $FIELDS_UPDATE->{$key};
if($value eq ''){
# empty fields are replaced with undef value
$value = undef;
}elsif($value =~ m/^\{.*\}$/ or $value =~ m/^\[.*\]$/){
# se il campo contiene una stringa in formato JSON senza errori ...
my $json = eval { from_json $value };
if(!$@){
$value = $json;
}
}
my $json_key = exists $attrs->{$key}{JSON} ? $attrs->{$key}{JSON} : $key;
$FIELDS{$json_key} = $value;
}
}
# using array ref it is possible to change assignment (default equal to '?' as value of the field)
# fields are replaced with new values in the JSON hash
$FIELDS_UPDATE->{$JSON_FIELD} = [qq[coalesce($JSON_FIELD, '{}'::jsonb) || ?::jsonb], to_json(\%FIELDS)];
</%perl>
</%method>
 
%# chiamata per valutare la query fornita dal browser
<%method JSON_WHERE>\
<%args>
$JSON_FIELD => 'fields'
$arr_where
$no_check => undef
</%args>
<%perl>
my $attrs = $m->comp('SELF:INFO', OBJ => 1);
# rielaboro la query per adattarla ai reali campi presenti nel database di tipo JSON
my %standards = map { $_ => 1 } &Method2Array('STANDARD_FIELDS');
foreach my $par (@$arr_where){
my $key = $par->[0];
if($key !~ m/^--/){ # no special key
if(!exists $standards{$key}){
my $json_key = exists $attrs->{$key}{JSON} ? $attrs->{$key}{JSON} : $key;
if(defined $par->[2]){
$par->[4] = "$JSON_FIELD->>'$json_key'";
}else{
$par->[4] = "coalesce($JSON_FIELD->>'$json_key', '')";
$par->[3] = undef;
$par->[2] = '';
}
}
}elsif(!$no_check && $key =~ '^--where'){
# verifica la sub-query alla ricerca di codice SQL non autorizzato (sql injection)
&check_where_clause(shift @$par);
}
}
return $arr_where;
</%perl></%method>
/tags/2.0/htdocs/data/autohandler
0,0 → 1,16
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%once>
my $DataBaseUrl = $r->dir_config('DataBaseUrl');
my $BaseUrl = $r->dir_config('BaseUrl');
</%once>
<%flags>
inherit => '/data/global_autohandler' # # NON CANCELLARE !!!
</%flags>
/tags/2.0/htdocs/lib/displaybinding.js
0,0 → 1,2001
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2003 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
 
---+ libreria DisplayBinding
 
Provvede ad effettuare l'aggiornamento dei dati gestiti dalla classe dataBinding
L'oggetto mette a disposizione una serie di metodi richiamati direttamente
da recordset a risposta degli eventi che aggiornano i dati.
 
Per accedere ai campi nel form la libreria utilizza una matrice di riferimenti agli oggetti
<this.fields[row,col]> che deve viene predisposta dopo la creazione dell'oggetto "DisplayBinding"
utilizzando il metodo ... .
 
Per la selezione di righe da cancellare va predisposto un vettore <checks[row]> contenetene
i riferimenti agli oggetti "checkbox".
 
Al caricamento del primo blocco di dati la libreria inizializza anche il seguente vettore:
* vettore <labels[col]> con la etichetta dei campi da visualizzare nel form.
 
---++ Form associati ai dataBinding con numero di record variabili, visualizzati dinamicamente
 
Oltre alla gestione del recordset con form dal rumero di righe fisse (per visualizzare e modificare un corrispondente
numero di record), la libreria permette anche la rappresentazione di form con numero di righe visualizzate pari al numero di
record o meno del recordset.
 
Lo scopo di questa modalità di funzionamento è quello di permettere il caricamento dinamico di template differenti per ogni
riga associati a differenti contenuti del record relativo e/o rappresentare l'intero recordset (poche righe comunque) abilitando
le funzioni di inserimento, modifica e cancellazione di record e gestire la corrispondente visualizzazione dinamica nel form che
cambierà di lunghezza e contenuto grafico.
 
La modalità è disponibile solo per i form DIVS (non per TABLE) in quanto gestiscono meglio le funzionalià di inserimento e
cancellazione di blocchi HTML, collocati in tag "<div/>"
Per il caricamento dinamico delle righe viene utilizzato il metodo ROWS_DIVS che restituisce tutte le righe che rappresentano
i singoli form di un record (una righa).
Per ottenere un form differente in funzione del contenuto del record si passa al metodo il parametro "type" che determina il
tipo di form; è responsabilità dell'applicazione definire il metodo .type_div che restituisce il tipo di form; se il metodo
non è definito, al parametro "type" verrà passato il valore "undef".
 
DEPRECATED: Per il caricamento dinamico delle righe viene utilizzato il metodo ROW_DIVS che rappresenta il singolo form di un rec
Per ottenere un form differente in funzione del contenuto del record si passa al metodo il parametro "type" che determina il
tipo di form; è responsabilità dell'applicazione definire il metodo .type_div che restituisce il tipo di form; se il metodo
non è definito, al parametro "type" verrà passato il valore "undef".
</%doc>
 
// variabile globale con i riferimenti nome --> oggetto DisplayBinding
DisplayBinding_ContextPool = [];
 
// Oggetto DisplayBinding per la navigazione di dati SQL nel browser
//
// constructor for DisplayBinding object
// Parametri:
// dataBinding oggetto dataBinding
//
function DisplayBinding(prefix, db){
// oggetto DataBinding
this.dataBinding = db;
this.prefix = prefix;
this.id = prefix;
// l'oggetto DisplayBinding (usato dagli Handler degli eventi lanciati dall'oggetto DataBinding
db.displayBinding = this;
// aggancio le funzioni agli eventi generati da DataBinding
db.onload = DisplayBinding_onloadHandler;
db.onloadrecord = DisplayBinding_onloadrecordHandler;
db.ondeleterecords = DisplayBinding_ondeleterecordsHandler;
db.onrequest = DisplayBinding_onrequestHandler;
db.onprechange = DisplayBinding_onprechangeHandler;
db.onchange = DisplayBinding_onchangeHandler;
db.onerror = DisplayBinding_onerrorHandler;
db.onreadonly = DisplayBinding_onreadonlyHandler;
// Oggetto grafico contenitore del widget interessato dal binding dei dati
// (utilizzato per bloccare o nascondere l'area interessata)
this.widgetsContainer = null;
// matrice dei widget
this.fields = [];
// vettore di input di tipo check utilizzati per selezionare i record visualizzati
// per operazioni di insieme (stampa, cancellazione)
this.checks = null;
// vettore delle etichette nel form (usate per visualizzare la chiave del record)
this.labels = [];
// vettore delle intestazioni nel form
this.headers = [];
// vettore di template; usato con il componente di tipo DIVS
this.divs = [];
// dup è un oggetto utilizzato per copiare la riga record nel display da duplicare
this.dup = null;
// cp_record is a copy of record to be duplicated in the pasted lines with Copy-Paste method
this.cp_record = null;
//this.cp = null;
// indicates row number of copied record
this.cp_row = null;
// contains cp_fields which are selected
this.cp_modes = [];
// contains row number of previously checked row
this.cp_previous = null;
// indicates whether there is any selectable row
this.cp_enabled = false;
// oggetto contenente i vari controlli di navigazione
this.navigationBar = {};
// abilita/disabilita i pulsanti di navigazione
this.navigationBar.setButtons = NavigationBar_setButtons;
 
// campi del filtro di ricerca
// widget contenuto del campo filtro
this.finds = null;
// contiene i nomi dei campi di ricerca nell'ordine in cui vengono forniti nel vettore .finds
this.find_fields = null;
// contiene gli operatori di filtro
this.ftypes = null;
// contiene le posizioni dei campi di ricerca, individuati dal loro nome (è l'inverso di .find_fields)
this.find_fields_pos = [];
// oggetto del documento (SPAN, DIV, ecc.) per la visualizzazione della posizione nel recordset
this.info = null;
// condizione where imposta al display
this.where = '';
// abilita il movimento tra i campi con Enter(Invio) e con i tasti freccia
this.formKeysMovement = '';
// record padre in evidenza
this.rowFather = null;
// methods
 
// chiamato da /frame.comp dopo la creazione del form
this.post_init = DisplayBinding_post_init;
// valuta l'elenco delle chiavi dei record selezionati
this.selectedKeys = DisplayBinding_selectedKeys;
// stampa il recordset in funzione del tipo di stampa
this.printSelected = DisplayBinding_printSelected;
// visualizza il Log delle modifiche apportate
this.displayLog = DisplayBinding_displayLog;
// modifica lo stato lettura/scrittura dei widget e relativo recordset
this.readOnly = DisplayBinding_readOnly;
// modifica lo ststo dei bottoni di navigazione
this.setButtons = DisplayBinding_setButtons;
// Abilita/disabilita il bottone (se nascosto lo attiva)
this.disableButton = DisplayBinding_disableButton;
// utilizzata per aggiornare lo stato di una riga quando si utilizzano i DIVS
this.Divs_onChange = DisplayBinding_Divs_onChange;
// sostituisce nell'oggetto HTML "div_container" la riga template identificata da "id"
// sostituendo nel template l'identificativo di riga "id_row"
this.updateTemplateRow = DisplayBinding_updateTemplateRow;
//
this.load_Row = DisplayBinding_load_Row;
// Inizializza gli array .checks, .labels e la matrice .fields con i riferimenti
// dei widget che compongono il form
this.bindEditComponents = DisplayBinding_bindEditComponents;
// Inizializza gli array .checks, .labels e la matrice .fields con i riferimenti
// dei widget che compongono la singola riga del form
this.bindEditComponentsRow = DisplayBinding_bindEditComponentsRow;
// ritorna l'identificatore del widget del campo/etichetta, campi di ricerca o intestazione
this.getField = DisplayBinding_getField;
// nasconde/mostra la colonna del campo nel form
this.hiddenColumn = DisplayBinding_hiddenColumn;
// ritorna l'identificatore del widget di una particolare chiave record
this.getFieldByKey = DisplayBinding_getFieldByKey;
// metodo che ritorna una clausola "where" in formato JSON da inviare al server
// il package mette a disposizione la funzione DisplayBinding_jsonWhere
// utilizzata, ad esempio, da method FIND e method FIND_MENU (vedi dbms_library.comp)
this.jsonWhere = DisplayBinding_jsonWhere;
// metodo che ritorna una clausola di ordinamento dei campi da inviare al server
this.sqlOrderBy = null;
// attiva/disattiva l'area dei widget dallo stato di attesa
this.waitingStatus = DisplayBinding_waitingStatus;
// calcella i record selezionati
this.deleteSelected = DisplayBinding_deleteSelected;
// recupera i dati dal server applicando il filtro corrente
this.loadRecords = DisplayBinding_loadRecords;
// lancia un metodo remoto sul server definito come CALL_REMOTE_<function> aggiornando le condizioni di filtro ed ordinamento
this.callRemote = DisplayBinding_callRemote;
// spostamenti nel recordset
this.gotoRecords = DisplayBinding_gotoRecords;
// Annulla le modifiche in corso
this.cancelUpdate = DisplayBinding_cancelUpdate;
// Apre un form con maggiore dettaglio del record indicato (parametro: riga del record)
this.openFormDetail = DisplayBinding_openFormDetail;
// Apre un form con maggiore dettaglio del record indicato per chiave
this.openFormDetailByKey = DisplayBinding_openFormDetailByKey;
// Seleziona la riga quale Padre corrente
this.selectRowFather = DisplayBinding_selectRowFather;
// Uncheck all rows and return list of rows that were checked
this.uncheckAll = DisplayBinding_uncheckAll;
 
// Functions used by both dup (Duplica button) and cp (Copy-Paste):
// Create a new record
this.newRecord = DisplayBinding_newRecord;
// Make a copy of the original field by taking into account cp_fields and dup_fields
this.duplicateField = DisplayBinding_duplicateField;
// Make a copy of the original record by taking into account cp_fields and dup_fields
this.duplicateRecord = DisplayBinding_duplicateRecord;
// Make a full copy of the content of the original record
this.copyRecord = DisplayBinding_copyRecord;
 
// Functions for Copy-Pasting in the displayed table:
// Undo changes of the record - only in the fields selected for copy-paste
this.cpUndoRecord = DisplayBinding_cpUndoRecord;
// Delete row to be copied
this.cpDeleteCopy = DisplayBinding_cpDeleteCopy;
// Set Copy-Paste class of the 'sel.' field in the table header
this.cpSetSelect = DisplayBinding_cpSetSelect;
// Invert Copy-Paste selection of the field in the table header
this.cpInvertHeader = DisplayBinding_cpInvertHeader;
// Set all Copy-Paste classes in the table header
this.cpSetHeaderClass = DisplayBinding_cpSetHeaderClass;
// Deselect selection in the table header
this.cpDeselectHeaders = DisplayBinding_cpDeselectHeaders;
// Invert Copy-Paste selection of entire table header
this.cpInvertAllHeaders = DisplayBinding_cpInvertAllHeaders;
// Set Copy-Paste properties and classes of the table row
this.cpSetRow = DisplayBinding_cpSetRow;
// Set Copy-Paste classes of the table row
this.cpSetRowClasses = DisplayBinding_cpSetRowClasses;
// Set Copy-Paste properties and classes of table rows checked with Shift key
this.cpSetMultipleRows = DisplayBinding_cpSetMultipleRows;
// Update row's Copy-Paste classes
this.cpRefreshRow = DisplayBinding_cpRefreshRow;
// Set Copy-Paste properties and classes of the table column
this.cpSetColumn = DisplayBinding_cpSetColumn;
// Set Copy-Paste classes of single table field
this.cpSetFieldClass = DisplayBinding_cpSetFieldClass;
// Uncheck all rows except of the copied row
this.cpUncheckPasted = DisplayBinding_cpUncheckPasted;
// Convert FIELDS_COPY_PASTE information to the cp.modes[] array
this.cpSetModes = DisplayBinding_cpSetModes;
// Update complete displayed table with Copy-Paste properties and classes
this.cpSetAll = DisplayBinding_cpSetAll;
// Forza il campo nel form e nel dataset (no aggiornamento nel server)
this.forceValueField = DisplayBinding_forceValueField;
// events
this.oninit = null; // chiamata dopo la inizializzazione del form
this.onload = null; // chiamata dopo la prima inizializzazione
this.onchange = null; // richiama la funzione indicata quando i dati sono stati aggiornati
this.onrequest = null; // richiama la funzione indicata quando inizia una richiesta di cambio del recordset
this.onloadrecord = null; // richiama la funzione indicata dopo che displaybinding ha preparato i dati nel databinding per l'invio
this.deleterecords = null; // richiama la funzione indicata quando arriva una richiesta di cancellazione di records
this.onreadonly = null; // richiama la funzione indicata dopo che displaybinding ha modificato lo stato lettura/scrittura del display
this.onclosedetail = null // richiama la funzione indicata alla chiusura del form di dettaglio
masonSql.disp[prefix] = this;
}
 
// valuta l'elenco delle chiavi dei record selezionati
function DisplayBinding_selectedKeys(){
var lista = [];
var db = this.dataBinding;
if(db.max_table_rows == 1){
// se ho un solo record non occorre testare i check dei record da cancellare
if(db.keys[0] != null){
lista.push(db.keys[0]);
}
}else if(this.checks){
for(var R=0; R < db.max_table_rows; R++){
var checksR = this.checks[R];
if(db.keys[R] && checksR && checksR.checked){
checksR.checked = false;
lista.push(db.keys[R]);
}
}
if(!lista.length && this.rowFather != null){
lista.push(db.keys[this.rowFather]);
}
}
return lista;
}
 
// stampa del recordset
// type: sel -> stampa della selezione corrente
// type: recordset -> stampa del recordset filtrato
function DisplayBinding_printSelected(type, report, cmdParams){
var db = this.dataBinding;
// aggiorno il filtro corrente
var json_where = this.jsonWhere();
if(!db.json_where != !json_where && !confirm('Hai cambiato la selezione senza aggiornare i dati visualizzati.\nConfermi la stampa dei dati con i filtri indicati?')){
return false;
}
db.json_where = json_where;
// aggiorno ordinamento corrente
db.orderby = (this.sqlOrderBy) ? this.sqlOrderBy() : '';
var url;
//DEBUG my_alert("DisplayBinding_printSelected "+type);
switch(type){
case 'odt_rpt':
case 'pdf_rpt':
case 'sel':
if(!db.canPrint && report == null){ // test solo sul report principale
my_alert('Non siete autorizzati a stampare','txt');
return;
}
// valutazione della lista delle chiavi da stampare
var keyList = this.selectedKeys();
if(!keyList.length){
my_alert('Nessun record selezionato per la stampa','txt');
return;
}
url = db.printUrl(type, keyList, report, cmdParams);
break;
case 'xls_sel':
if(!db.canXls){
my_alert('Non siete autorizzati a scaricare i dati in formato XLS','txt');
return;
}
// valutazione della lista delle chiavi da stampare
var keyList = this.selectedKeys();
// if keylist is empty the xls file include all records
url = db.printUrl(type, keyList);
window.open(url, '_blank');
return;
case 'recordset':
if(!db.canPrintsel){
my_alert('Non siete autorizzati a stampare','txt');
return;
}
url = db.printUrl(type, report);
break;
case 'create_recordset':
if(!db.canPrintsel){
my_alert('Non siete autorizzati a stampare','txt');
return;
}
url = db.printUrl(type);
break;
case 'xls_recordset':
if(!db.canXls){
my_alert('Non siete autorizzati a scaricare i dati in formato XLS','txt');
return;
}
url = db.printUrl(type);
window.open(url, '_blank');
return;
default:
my_alert("ERRORE: DisplayBinding_Print type="+type+" sconosciuto",'txt');
return;
}
//DEBUG my_alert(URL);
// apro una nuova finestra indipendente
var params = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable,alwaysRaised,dependent,titlebar=no';
var LANDSCAPE = false;
var re_landscape = /^LAND/i;
// db.print_form contiene <method PRINT_FORM> inizializzato da dbms_library.comp
// se il nome del form (che per default corrisponde a <method FROM%>.rep)
// inizia per "LAND" o "land" verrà scelta la visualizzazione landscape (orizzontale)
for(var I=1; I<db.print_form.length; I++){
if(re_landscape.test(db.print_form[I])){
LANDSCAPE = true;
break;
}
}
var w = LANDSCAPE ? 800 : 600;
var h = LANDSCAPE ? 600 : 800;
var left = (screen.width - w) / 2;
var top = (screen.height - h) / 3;
window.open(url, '_blank', 'width='+w+',height='+h+',top='+top+',left='+left+','+params);
}
 
// visualizza il Log delle modifiche apportate al recordset
function DisplayBinding_displayLog(){
var keys = this.selectedKeys();
var db = this.dataBinding;
if(keys.length == 0){
// se nessun record selezionato viene mostrato il log dei record visibili nel form
for(var R=0; R < db.max_table_rows; R++){
if(db.keys[R]){
keys.push(db.keys[R]);
}
}
}
if(keys.length == 0){
my_alert('Nessun record da mostrare', 'alert');
return
}
var list = keys.join(',');
// costruisco un oggetto 'display' minimale con i soli elementi necessari a lanciare il form
var display_log = {
prefix: 'Log_' + this.prefix,
dataBinding: new DataBinding('Log_' + db.prefix + '_db', 'log', 'Log ' + db.from),
gotoRecords: function (mode, key, recordset){
return this.dataBinding.gotoRecords(mode, key, recordset);
},
openFormDetailByKey: DisplayBinding_openFormDetailByKey
};
display_log.openFormDetailByKey('rewind', null, 'logs', 865, 590, 'Log ' + db.from, {
form: 'TABLE',
rows: null,
disp_find: 1,
disp_navbar: 1,
find_area: 'left',
where: "table_name = '" + db.from.replace(/\//, '.') + "' AND id_record IN (" + list + ")"
});
}
 
// metodo getField - ritorna l'identificatore del campo
// name = nome del campo
// row = riga del campo; se omessa verrà ritornata la prima riga (riga = 0)
function DisplayBinding_getField(name, row){
if(row == null){
row = this.rowFather == null ? 0 : this.rowFather;
}
if(row == 'find'){
return this.finds[this.find_fields_pos[name]];
}else if(row == 'type'){
return this.ftypes[this.find_fields_pos[name]];
}else if(row == 'header'){
return this.headers[this.dataBinding.pos_name[name]];
}else{
return this.fields[row][this.dataBinding.pos_name[name]];
}
}
 
// metodo hiddenColumn - nasconde la colonna del form
// name = nome del campo
// hidden = se true nasconde, altrimenti mostra
function DisplayBinding_hiddenColumn(name, hidden){
var display = hidden ? 'none' : '';
this.getField(name, 'header').style.display = display;
for(var Col=0; Col<this.fields.length; Col++){
this.getField(name, Col).dispSpan.style.display = display;
}
}
 
// metodo getFieldByKey - ritorna l'identificatore del campo di una particolare chiave record
// name = nome del campo
// key = chiave del record. Se la chiave non è presente nella tabella ritornerà null
function DisplayBinding_getFieldByKey(name, key){
if(key == null){
return null;
}
var row = this.dataBinding.pos_key[key];
if(row == null){
return null;
}else{
return this.fields[row][this.dataBinding.pos_name[name]];
}
}
 
// metodo readOnly
// chiama il metodo corrispondente in dataBinding che provvederà a sua volta a richiamare
// la funzione DisplayBinding_onreadonlyHandler se c'è variazione di stato
function DisplayBinding_readOnly(set, update){
return this.dataBinding.readOnly(set, update);
}
 
// richiamata da dataBinding se c'è variazione di stato lettura/scrittura
// modifica gli attributi di lettura/scrittura di tutti gli oggetti 'input' associati al recordset
// se al cambio del set c'è il record corrente in modifica provvede ad aggiornarlo
function DisplayBinding_onreadonlyHandler(set, update){
//DEBUG my_alert('DisplayBinding_readOnly '+this.prefix+'\n set='+set+' update='+update+'\nfields_ro:'+Array2String(this.fields_ro)+'\nfields_ro_update:'+Array2String(this.fields_ro_update));
var disp = this.displayBinding;
// sblocco/blocco i campi del filtro di selezione (se presente)
if(disp.finds){
var set_find = !set;
for(var I=0; I<disp.finds.length; I++){
disp.finds[I].Readonly(set_find);
disp.ftypes[I].Readonly(set_find);
}
}
// blocco/sblocco dei componenti
for(var I=0; I<disp.fields.length; I++){
var row = disp.fields[I];
//GDO my_alert("DataBinding_readOnly("+set+") this.keys="+this.keys[I]);
var ro = this.keys[I] == null ? this.fields_ro : this.fields_ro_update;
var set_row = set || (this.keys[I] == null && !this.canInsert) || (this.keys[I] != null && !this.canUpdate);
//GDO my_alert('DataBinding_readOnly set_row:'+set_row+' ro'+Array2String(ro));
for(var J=0; J<row.length; J++){
if(row[J]){
//GDO my_alert('DataBinding_readOnly I:'+I+'set:'+set+' this.keys='+this.keys[I]+'readonly:'+(set || ro[J] == true));
row[J].Readonly(set_row || ro[J] == true);
}
}
}
disp.cpDeselectHeaders(set);
disp.uncheckAll(this.max_table_rows);
disp.cpDeleteCopy(set);
disp.cpSetAll();
 
// se update è nullo o true e lo stato del recordset era in modifica
if((update == null || update) && set){
// provvedo ad aggiornare i dati nei widget in this.new_data in modo che
// le modifiche vengano inviate al server
Form2Array(disp.fields, this.new_data);
}
disp.setButtons();
// chiamo l'eventuale funzione in risposta all'evento onreadonly
if(disp.onreadonly){
disp.onreadonly(set, update);
}
}
 
// abilita/disabilita il pulsante (se inizialmente nascosto, anche lo visualizza/nasconde)
function DisplayBinding_disableButton(button, disable){
button.set('disabled', disable);
if(!disable && button.domNode.style.display == 'none'){
button.domNode.style.display = '';
button._hidden_when_disabled = true;
}
if(disable && button._hidden_when_disabled){
button.domNode.style.display = 'none';
}
}
 
// regola lo stato dei pulsanti di navigazione
function DisplayBinding_setButtons(){
var db = this.dataBinding;
// my_alert('DisplayBinding_setButtons '+this.prefix+' canUpdate:'+db.canUpdate);
var navBar = this.navigationBar;
var readonly = db.readonly;
// valuto se tutti i campi sono in sola lettura
var readOnlyAll = true;
if(this.fields && this.fields.length){
var row = this.fields[0]; // utilizzo la prima riga
for(var J=0; J<row.length; J++){
if(!db.fields_ro[J]){
readOnlyAll = false;
break;
}
if(!db.fields_ro_update[J]){
readOnlyAll = false;
break;
}
}
}
if(readOnlyAll){
this.disableButton(navBar.cancelButton, true);
this.disableButton(navBar.refreshButton, false);
this.disableButton(navBar.changeButton, true);
this.disableButton(navBar.saveButton, true);
}else{
this.disableButton(navBar.cancelButton, readonly);
this.disableButton(navBar.refreshButton, !readonly);
this.disableButton(navBar.changeButton, !readonly || !db.canUpdate);
this.disableButton(navBar.saveButton, readonly || !(db.canUpdate || db.canInsert));
}
this.disableButton(navBar.insertButton, !db.canInsert);
this.disableButton(navBar.deleteButton, !db.canDelete);
this.disableButton(navBar.printButton, !readonly || !db.canPrint);
this.disableButton(navBar.xlsButton, !readonly || !db.canXls);
this.disableButton(navBar.logButton, !db.keys[0] || !readonly || !db.canLog);
this.disableButton(navBar.dupButton, !db.canInsert);
// abilito il pulsante di salto se il numero di record disponibili e maggiore dei record visualizzati in ciascuna pagina
var goto_disabled = (db.max_rows == null || db.max_rows <= db.rows);
navBar._record.disabled = goto_disabled;
this.disableButton(navBar.gotoButton, goto_disabled);
if(navBar.filterButton){
// non sempre il form di filtro viene utilizzato
this.disableButton(navBar.filterButton, !readonly);
if(navBar.printselButton){
this.disableButton(navBar.printselButton, !(readonly && db.canPrintsel));
}
if(navBar.xlsselButton){
this.disableButton(navBar.xlsselButton, !(readonly && db.canXls));
}
}
var dis = db.max_rows == null || db.start >= (db.max_rows - db.max_table_rows);
this.disableButton(navBar.forwardButton, dis);
this.disableButton(navBar.upButton, dis);
dis = db.max_rows == null || db.start < 1;
this.disableButton(navBar.rewindButton, dis);
this.disableButton(navBar.downButton, dis);
var disp = this;
require(["dijit/registry", "dojo/dom-style"], function(registry, domStyle){
// valuto se visualizzare o meno i pulsanti specifici di ciascun record visualizzato
for(var R=0; R<disp.fields.length; R++){
var button = registry.byId(disp.prefix + '_d_' + R);
if(button){
domStyle.set(button.domNode, 'display', db.keys[R] ? 'inline' : 'none');
}
}
// valuto se visualizzare il pulsante per la duplicazione dei record (solo se è visibile anche il pulsante di inserimento)
domStyle.set(navBar.dupButton.domNode, 'display', db.canDup && db.dup_fields.length && db.canInsert ? '' : 'none');
});
}
 
// utilizzata per aggiornare lo stato di una riga quando si utilizzano i DIVS
// div_id ID dell'oggetto DIV da cambiare
// row riga del recordset da sostituire
// changed_col colonna del campo che ha determinato il cambiamento
//
function DisplayBinding_Divs_onChange(div_id, row, changed_col){
var db = this.dataBinding;
var old = db.new_data[row][changed_col];
Form2Row(row, this.fields, db.new_data);
this.updateTemplateRow(document.getElementById(div_id), row);
db.new_data[row][changed_col] = old;
}
 
// sostituisce nell'oggetto HTML "div_container" la riga template identificata da "id"
// sostituendo nel template l'identificativo di riga "id_row"
//
function DisplayBinding_updateTemplateRow(Div, id_row){
var db = this.dataBinding;
//my_alert("DisplayBinding_updateTemplateRow("+id_row+") Div.id="+Div.id_row+' Div.type_row='+Div.type_row+'.');
if(!Div.type_row){
Div.type_row = '';
}
if(!db.type_div){
my_alert('ERROR DisplayBinding_updateTemplateRow: ['+this.prefix+'] non ha inizializzato il metodo .type_div\n'+
', id_row='+id_row,'txt');
return null;
}
// il tipo dipende dal valore nel db
var type = db.type_div(id_row);
if(Div.type_row != type){
//my_alert("UPDATE DisplayBinding_updateTemplateRow("+id_row+") "+Div.type_row+'<>'+type);
Div.type_row = type;
this.load_Row(Div, id_row, type);
}
Row2Form(id_row, db.data, db.params, this.fields, db.keys, this.labels);
}
 
// sostituisco il codice del template di tipo type con l'identificativo id_row e lo inserisco nel contenitore div_container
// ed aggiorno lo stato read/write del record
function DisplayBinding_load_Row(div_container, id_row, type){
var db = this.dataBinding;
if(!type){
type = '';
}
// verifico se il template c'è nel buffer
var template = this.divs[type];
if(template == null){
my_alert('ERROR DisplayBinding_load_Row: ['+this.prefix+'] non ha precaricato il template di riga "'+type+'"','txt');
return null;
}
// sostituisco il codice di riga nel template
template = template.replace(/@@@/g, id_row);
//DEBUG my_alert('DisplayBinding_Load_Row id_row='+id_row+', str='+template, 'txt');
// carico nel form
hReqMason_innerHTML(div_container, template);
div_container.type_row = type;
// aggiorno lo stato readOnly
// blocco/sblocco flag cancellazione
// db.checks[id_row].disabled = db.readonly;
// blocco/sblocco dei componenti
var row = this.fields[id_row];
var ro = db.keys[id_row] == null ? db.fields_ro : db.fields_ro_update;
for(var J=0; J<row.length; J++){
if(row[J]){
row[J].Readonly(db.readonly || ro[J] == true);
}
}
}
 
// Inizializza gli array .checks, .labels e la matrice .fields con i riferimenti
// dei widget che compongono la singola riga del form
function DisplayBinding_bindEditComponentsRow(pos, cols, suff_check, suff_label, suff_field1, suff_field2){
var db = this.dataBinding;
// caso in cui al posto del numero di riga si mette il codice '@@@' da sostituire successivamente
var check = document.getElementById(this.prefix+suff_check+pos);
if(check){
if(!this.checks){
this.checks = [];
}
this.checks[pos] = document.getElementById(this.prefix+suff_check+pos);
}
this.labels[pos] = document.getElementById(this.prefix+suff_label+pos);
var row = this.fields[pos] = [];
for(var col=0; col<cols; col++){
var obj = document.getElementById(this.prefix+suff_field1+pos+suff_field2+col);
row[col] = obj;
// indico al componente a quale DisplayBinding appartiene
obj.displayBinding = this;
obj.dbCol = col;
obj.dbRow = pos;
// riferimento al tag <span> che racchiude il widget con la sua descrizione del campo
var id = this.prefix+suff_field1+pos+suff_field2+col;
obj.dispSpan = document.getElementById('Span_'+id);
// riferimento al tag <span> che racchiude la descrizione
obj.descrSpan = document.getElementById('Descr_'+id);
obj.getField = function (nome){
this.displayBinding.getField(nome, this.dbRow);
}
}
}
 
// Inizializza gli array .checks, .labels e la matrice .fields con i riferimenti
// dei widget che compongono il form
// I campi "ID" dei widget vengono formati utilizzando nomi composti con le seguenti regole
// check '<prefix><suff_check>[0..row-1]'
// label '<prefix><suff_label>[0..row-1]'
// field '<prefix><suff_field1>[0..row-1]<suff_field2>[0..col-1]'
//
function DisplayBinding_bindEditComponents(rows, cols, suff_check, suff_label, suff_field1, suff_field2){
// header
this.headers_select = document.getElementById(this.prefix+'_h_sel');
for(var col=0; col<cols; col++){
this.headers[col] = document.getElementById(this.prefix+'_h_'+col);
}
if(rows == '@@@'){
this.bindEditComponentsRow('@@@', cols, suff_check, suff_label, suff_field1, suff_field2);
}else{
for(var j=0;j<rows; j++){
this.bindEditComponentsRow(j, cols, suff_check, suff_label, suff_field1, suff_field2);
}
}
}
 
// gestione cursore e dati del recordset durante il caricamento
function DisplayBinding_waitingStatus(wait){
var db = this.dataBinding;
if(wait){
this.widgetsContainer.style.cursor='wait';
if(this.info){
this.info.innerHTML='Caricamento ...';
}
}else{
if(this.info){
// aggiorno il range di visualizzazione
if(db.max_table_rows == 1){
this.info.innerHTML='Rec. '+(db.start+1)+' / '+db.max_rows
}else{
this.info.innerHTML='Rec. '+(db.start+1)+'-'+(db.start+db.rows)+' / '+db.max_rows
}
}
this.widgetsContainer.style.cursor='auto';
}
}
 
// costruisce un oggetto JSON con i parametri di filtro
// campi = array dei nomi dei campi della selezione
// values = array agli oggetti nel form che contengono i campi selezionati
//
function DisplayBinding_jsonWhere(disp){
// l'oggetto displayBinding è fornito come parametro
// oppure utilizzo this (suppongo che la funzione sia usata come metodo)
if(disp == null){
disp = this;
}
var test = false;
var arr_where = [];
if(disp.finds && disp.finds.length && disp.find_fields){
for(var I=0; I<disp.find_fields.length; I++){
var Op = disp.ftypes[I].get_value().toUpperCase();
if(Op != ''){
var widget = disp.finds[I];
var Type = widget.getAttribute('value-type');
// default hour non attribuita se campo di tipo timestamp
var Val = Type == 'timestamp' ? widget.get_value('') : widget.get_value();
Val = Val == null ? '' : Val.toString();
Val = Val.replace(/\s+$/, '');
Val = Val.replace(/^\s+/, '');
if(Op == '~*' && !Val.length){
my_alert('Con l\'operatore ~* si deve inserire un valore di ricerca non vuoto; ignoro il filtro per ' + disp.find_fields[I],'txt', 400,200);
}else{
if(widget.className.replace(/.*_FIND$/,'') == ''){
Val = Val.replace(/:.*$/,'');
}
if(Val == ''){ Val = null; }
arr_where.push([disp.find_fields[I], Op, Val, Type]);
test = true;
}
}
}
}
if(disp.where){
arr_where.push(['--where-disp', disp.where])
test = true;
}
return test ? JSON.stringify(arr_where) : '';
}
 
// cambio lo stato di visibilità dell'oggetto
function setDisplay(Obj, visible){
var status = visible ? '' : 'none';
// evito di assegnare lo stato se uguale, altrimenti in Mozilla si ha l'effetto indesiderato di refresh del form
if(Obj.style.display != status){
Obj.style.display = status
}
}
 
// richiamata da /frame.comp dopo la creazione degli oggetti nel form
function DisplayBinding_post_init(){
// forzo l'azzeramento dei widget del filtro, altrimenti se si ricarica il form dal browser
// rimangono visibili dei valori dal form precedente che non corrispondono al reale contenuto
if(this.finds){
for(var C=0; C<this.finds.length; C++){
var w = this.finds[C]; w.set_value(w.init_find_value);
w = this.ftypes[C]; w.set_value(w.init_find_sel);
}
}
// chiamo il metodo anche nelle tabelle figlie
var children = this.dataBinding.children;
for(var I = 0; I < children.length; I++){
children[I].displayBinding.post_init();
}
if(this.oninit){
return this.oninit();
}
return true;
}
 
// richiamata da dataBinding quando sono disponibili i dati riguardanti i campi del dataset
// chiamata la prima volta che l'oggetto viene utilizzato
function DisplayBinding_onloadHandler(mode){
//my_alert('DisplayBinding_onloadHandler mode='+mode);
var disp = this.displayBinding;
// init array posizione campi di filtro
if(disp.find_fields){
disp.find_fields_pos = [];
for(var col=0; col<disp.find_fields.length; col++){
disp.find_fields_pos[disp.find_fields[col]] = col;
}
}
// cambio il nome dei widget con il nome dei campi nel recordset
for(var R=0; R<disp.fields.length; R++){
var row = disp.fields[R];
for(var C=0; C<row.length; C++){
if(row[C]){
row[C].name = this.names[C];
}
}
}
// cambio il nome dei widget di ricerca con il nome dei campi nel recordset e pongo il filtro vuoto
if(disp.finds){
for(var C=0; C<disp.finds.length; C++){
var wfind = disp.finds[C];
var wtype = disp.ftypes[C];
wtype.displayBinding = disp;
wtype.ftypePos = C;
wtype.name = disp.find_fields[C];
wfind.displayBinding = disp;
wfind.findPos = C;
wfind.name = disp.find_fields[C];
if(!wfind.setFocus && (wfind.type == 'text' || wfind.type == 'textarea')){
// attribuisco il metodo se si tratta di un cambo input di tipo testo
wfind.setFocus = Input_setFocus;
}
}
}
// metto in evidenza il primo recordset
this.children.length && disp.selectRowFather(null, true);
// se il primo caricamento riguarda una operazione di inserimento ...
if(mode == 'insert'){
disp.readOnly(false);
}
// evento primo caricamento
if(disp.onload){
disp.onload(mode);
}
disp.cpSetAll();
}
 
// richiamata da dataBinding quando arriva una richiesta di cambio del recordset
function DisplayBinding_onloadrecordHandler(pos, key, recordset){
var disp = this.displayBinding;
if(!this.readonly){
// provvedo ad aggiornare i dati nei widget in .new_data in modo che
// le modifiche vengano inviate al server
Form2Array(disp.fields, this.new_data);
}
// .onloadrecord dell'applicazione viene chiamata prima
if(disp.onloadrecord){
if(!disp.onloadrecord(pos, key, recordset)){
return false;
}
}
if(!this.readonly){
// anticipo il calcolo delle differenze, che verranno utilizzate da DisplayBinding_CheckForm
this._difference = ArrayDiffKeys(this.keys, this.data, this.new_data, true);
//DEBUG my_alert('DisplayBinding_onloadrecordHandler diff '+Array2String(this._difference, 'null'));
// il form è in modalità di modifica; verifico se i campi del form sono tutti validi
if(!DisplayBinding_CheckForm(disp, pos, key, recordset)){
// altrimenti annullo la richiesta di aggiornamento
// Attenzione: se ci sono campi che richiedono un test asincrono (es. chiamata al server)
// la funzione ritorna false provvisoriamente, ma si occupa di monitorare
// le risposte dal server, che se positive, rilanceranno la richiesta con i
// parametri passati 'pos' e 'key'
// annullo la matrice differenze, che andrà ricalcolata
this._difference = null;
return false;
}
}
return true;
}
 
function DisplayBinding_ondeleterecordsHandler(keyList){
// chiamo la funzione utente, se definita prima di elaborare la richiesta
var disp = this.displayBinding;
if(disp.ondeleterecords){
return disp.ondeleterecords(keyList);
}
return true;
}
 
// richiamata da dataBinding quando ha inizio una richiesta di dati al server
function DisplayBinding_onrequestHandler(){
// my_alert('DisplayBinding_onrequestHandler');
var disp = this.displayBinding;
// anticipo la scomparsa del form se figlio di un padre con un nuovo record
disp.widgetsContainer.style.display != 'none' && setDisplay(disp.widgetsContainer, this.father_id != -1);
// form in stato di attesa
disp.waitingStatus(true);
this.storeRowToCopy();
// se ho un solo record non occorre azzerare i check di cancellazione
if(this.max_table_rows > 1 && disp.checks){
disp.uncheckAll(this.max_table_rows);
disp.cpSetAll();
}
// anticipo la messa in attesa delle tabelle figlie
for(var I = 0; I < this.children.length; I++){
var disp_child = this.children[I].displayBinding;
disp_child && disp_child.waitingStatus(true);
}
}
 
function DisplayBinding_onprechangeHandler(){
var disp = this.displayBinding;
// comparsa del form se figlio di un padre con record (.onrequest anticipa la scomparsa se record padre nuovo)
setDisplay(disp.widgetsContainer, this.father_id != -1);
}
 
// richiamata da dataBinding quando è completata una richiesta di dati al server
function DisplayBinding_onchangeHandler(){
var disp = this.displayBinding;
// my_alert('DisplayBinding_onchangeHandler prefix='+this.prefix+'readonly='+this.readonly+' start=' + this.start + ' rows=' + this.rows + ' max_rows=' + this.max_rows);
 
// aggiorno il range del campo di immissione del recordset
var record = disp.navigationBar._record;
if(record){
record.ValMax = this.max_rows;
record.maxLength = this.max_rows ? this.max_rows.toString().length : 0;
}
// aggiorno lo stato dei pulsanti di navigazione e di editing
disp.setButtons();
// aggiorno lo stato dei widget se obbligatori
for(var R=0; R<this.data.length; R++){
var row = disp.fields[R];
for(var C=0; C<row.length; C++){
var input = row[C];
input.set_status(this.required_fields[C] == true ? 'Required' : '');
}
}
// solo se è stato definito il metodo "type_div" attivo lo scambio dinamico delle righe
if(this.type_div){
// <div/> che contiene tutte le righe del recordset
var DIVS = document.getElementById(disp.prefix+'_DIVS');
var elenco = DIVS.getElementsByTagName('div');
// percorro le righe del recordset e modifico il form
// in modo da adattarlo
//DEBUG my_alert(this.data.length+' '+this.fields.length+' ');
for(var R=0; R<this.data.length; R++){
// verifico che la riga corrente sia conforme al template
disp.updateTemplateRow(this, elenco[R], R);
}
}else{
// altrimenti aggiorno i dati nel documento
Array2Form(this.data, this.params, disp.fields, this.keys, disp.labels);
}
disp.waitingStatus(false);
// compilo i campi dell'eventuale record da duplicare
if(disp.dup){
// cerco la prima riga vuota da usare per la copia dei dati
var R;
for(R=0; R < this.max_table_rows; R++){
if(!this.keys[R]){
break;
}
}
if(R >= this.max_table_rows){
my_alert('ERRORE: non c\'è neanche una riga disponibile per duplicare i dati','txt');
}else{
disp.duplicateRecord(disp.dup, R, this.dup_fields);
// Salvo i riferimenti dei record duplicati
this.dup_keys[R] = disp.dup.key;
}
}
// aggiorno l'evidenza del record padre
this.children.length && disp.selectRowFather(null, true);
// chiamo l'eventuale funzione in risposta all'evento onchange
if(disp.onchange){
disp.onchange();
}
disp.dup = null;
this.retrieveRowToCopy();
}
 
function DisplayBinding_duplicateRecord(Original, R, Mode){
// riga da modificare
var copy = this.fields[R];
for(var C = 0; C < copy.length; C++){
this.duplicateField(Original, copy, C, Mode[C]);
}
}
 
function DisplayBinding_duplicateField(Original, Copy, C, Mode){
if(!Original){
return;
}
if(Copy[C] != null){
// valuto cosa copiare
var value = Original.value[C] == null ? '' : Original.value[C].toString();
if(Mode == 'D' || (Mode == 'd' && value.length > 0) ||
Mode == 'C' || (Mode == 'c' && value.length > 0)){
Copy[C].set_value(value, Original.param[C]);
// duplico anche le condizioni di errore e di stato del widget
Copy[C].widgetStatus = Original.widgetStatus[C];
Copy[C].widgetError = Original.widgetError[C];
Copy[C].set_status();
}
}
return;
}
 
// richiamata da dataBinding quando si presenta un errore
function DisplayBinding_onerrorHandler(err, str){
var disp = this.displayBinding;
disp.waitingStatus(false);
disp.setButtons();
if(err == 'TIMEOUT'){
my_alert('Timeout ricezione dati [' + this.prefix + ']\n il server potrebbe non essere raggiungibile.', 'txt');
}else{
my_alert(err + ': ' + str, 'txt', 400,200);
}
}
 
// cancella i record selezionati (se multiriga) o il record corrente (singolo record)
function DisplayBinding_deleteSelected(){
var db = this.dataBinding;
// valutazione della lista delle chiavi da stampare
var keyList = this.selectedKeys();
if(!keyList.length){
my_alert('Nessun record selezionato per la cancellazione','txt');
return;
}
if(!confirm(this.confirmDelMessage + ': ' + keyList.join(',') + '.')){
return;
}
if(!db.deleteRecords(keyList)){
my_alert('Errore inaspettato: cancellazione annullata!','txt');
}
}
 
// recupera i dati dal server applicando il filtro corrente
function DisplayBinding_loadRecords(mode, key){
// richiamo i dati dal server
var db = this.dataBinding;
%#//DEBUG my_alert('DisplayBinding_loadRecords '+mode+' key:'+key + ' start:'+db.start);
// aggiorno il filtro corrente
db.json_where = this.jsonWhere();
// aggiorno ordinamento corrente
db.orderby = (this.sqlOrderBy) ? this.sqlOrderBy() : '';
// dataBinding.max_rows è null al primo caricamento
if(db.start != null && this.onrequest){
// evento non lanciato al primo caricamento (db.start==null)
this.onrequest(mode, key);
}
return db.loadRecords(mode, key);
}
 
%#// lancia un metodo remoto sul server definito come CALL_REMOTE_<function> aggiornando le condizioni di filtro ed ordinamento
function DisplayBinding_callRemote(remote_func, params, mode, win_params){
var db = this.dataBinding;
// aggiorno il filtro corrente
var json_where = this.jsonWhere();
if(!db.json_where != !json_where && !confirm('Hai cambiato la selezione senza aggiornare i dati visualizzati.\nConfermi l\'elaborazione dei dati con i filtri modificati?')){
return false;
}
db.json_where = json_where;
// aggiorno ordinamento corrente
db.orderby = (this.sqlOrderBy) ? this.sqlOrderBy() : '';
return db.callRemote(remote_func, params, mode, win_params);
}
 
function DisplayBinding_newRecord(){
return {
key: null,
value: [],
param: [],
widgetStatus: [],
widgetError: []
};
}
 
function DisplayBinding_copyRecord(Original, R, Copy){
Form2Vect(Original, Copy.value, Copy.param);
for(var C = 0; C < Original.length; C++){
Copy.widgetStatus[C] = Original[C].widgetStatus;
Copy.widgetError[C] = Original[C].widgetError;
}
return;
}
 
// spostamenti nel recordset corrente
function DisplayBinding_gotoRecords(mode, key, recordset){
%#//DEBUG my_alert('DisplayBinding_gotoRecords "'+mode+'","'+key+'"');
if(mode.length == 0){
my_alert('Indicare la posizione del record nella selezione corrente a cui si vuole puntare','txt');
return;
}
var db = this.dataBinding;
if(mode == 'dup'){
this.dup = this.newRecord();
// copio i dati presenti della riga indicata nel display
if(db.max_table_rows == 1){
// se in numero delle righe è 1 devo salvare il record da copiare
// che potrò rimpiazzare solo dopo aver richiamato un record nuovo
// (salvando eventualmente quello corrente, se modificato)
this.dup.key = db.keys[0];
this.copyRecord(this.fields[0], 0, this.dup);
}else if(this.checks){
// lista delle righe selezionate
var lista = this.uncheckAll(db.max_table_rows);
this.cpDeleteCopy(true);
this.cpSetAll();
var riga_dup; // riga da duplicare
if(!lista.length){
// individuo il record non vuoto più in basso nella lista
var R;
var Data = [];
Form2Array(this.fields, Data);
RICERCA:for(R=Data.length-1; R>=0; R--){
var Row = Data[R];
var C;
for(C=0; C<Row.length; C++){
if(Row[C]){
riga_dup = R;
break RICERCA;
}
}
}
if(riga_dup == null){
my_alert('Nulla da duplicare; le righe sono tutte vuote','txt');
return false;
}
}else if(lista.length > 1){
my_alert('E\' possibile duplicare un solo record per volta','txt');
return false;
}else{
riga_dup = lista[0];
}
this.dup.key = db.keys[riga_dup];
this.copyRecord(this.fields[riga_dup], riga_dup, this.dup);
// se c'è nel form almeno una riga ancora non utilizzata
// posso duplicare il record senza chiamare il server
var unusedRow = DisplayBinding_unusedRow(this, db);
if(unusedRow.found){
// c'è una riga vuota che utilizzo per duplicare il record
this.duplicateRecord(this.dup, unusedRow.R, db.dup_fields);
db.dup_keys[unusedRow.R] = this.dup.key ? this.dup.key : db.dup_keys[riga_dup];
this.dup = null;
this.readOnly(false);
return true;
}
// duplico la riga dovo aver salvato le eventuali righe correnti modificate
}
mode = 'insert';
}else{
this.dup = null;
}
if(db.start != null && this.onrequest){
// evento non lanciato al primo caricamento (db.start==null)
this.onrequest(mode, key);
}
return db.gotoRecords(mode, key, recordset);
}
 
function DisplayBinding_unusedRow(Disp, Db){
var data = [];
Form2Array(Disp.fields, data);
var diff = ArrayDiffKeys(Db.keys, Db.data, data, true);
//DEBUG my_alert('length=' + diff.length+ '' +KeyArray2String(Db.keys, diff, 'null', true, true),'txt');
for(var R = 0; R < diff.length; R++){
if(Db.keys[R] == null){
var row = diff[R];
for(var C = 0; C < row.length; C++){
if(row[C]){
break;
}
}
if(C == row.length){
break;
}
}
}
var unusedRow = {
R: R,
found: (R < diff.length)
};
return unusedRow;
}
 
// Annulla le modifiche in corso
function DisplayBinding_cancelUpdate(key, pos){
this.dataBinding.cancelUpdate(key, pos);
}
 
// Dialog Edit
DisplayBinding_Edit = null;
 
// Apre un form con maggiore dettaglio del record indicato (row: riga del record)
function DisplayBinding_openFormDetailByKey(mode, find_key, from, dimX, dimY, title, form_params){
dimX = dimX || 800;
dimY = dimY || 600;
var display = this;
this.modeDetail = mode;
require(["dojo/io-query", "dojox/widget/DialogSimple", "dojo/dom-construct", "dojo/dom-style"],
function(ioQuery, DialogSimple, domConstruct, domStyle){
if(!DisplayBinding_Edit){
DisplayBinding_Edit = new DialogSimple({
title: title,
executeScripts: true,
renderStyles: true,
scriptHasHooks: true,
parseOnLoad: true,
cleanContent: true,
closable: false,
ioArgs: {
headers: {
'MasonSql-body': '1'
},
timeout: <% $r->dir_config('GetFormTimeout') %>
},
onLoad: function(){
domStyle.set(DisplayBinding_Edit.containerNode, 'height', (DisplayBinding_Edit.dimY - DisplayBinding_Edit.titleBar.offsetHeight - 6) + 'px');
}
});
DisplayBinding_Edit.editSingle_Handler = function(save){
if(save){
var display = masonSql.disp[this.disp_prefix]; // vedi definizione del nome in /frame.html
display.onchange = function () {
// aggiorno i record correnti e chiudo il popup
window.setTimeout("DisplayBinding_Edit.closeDetail(true);", 10);
};
display.gotoRecords('save');
}else{
DisplayBinding_Edit.closeDetail();
}
};
DisplayBinding_Edit.closeDetail = function(update){
var disp = this.displayBinding;
update && disp.gotoRecords('update', null, disp.modeDetail == 'insert');
this.hide();
if(disp.onclosedetail){
disp.onclosedetail(update);
}
disp = null;
};
DisplayBinding_Edit.containerNode.style.padding = '2px 2px';
domConstruct.place('<% q{
<span style="float:right;">
<button tabindex="-1" onclick="DisplayBinding_Edit.editSingle_Handler(true);">Salva e chiudi</button>
<button tabindex="-1" onclick="DisplayBinding_Edit.editSingle_Handler()">Annulla</button>
</span>
} |js%>', DisplayBinding_Edit.titleBar, 2 /* seconda posizione */);
}else{
DisplayBinding_Edit.set('content', '');
}
DisplayBinding_Edit.displayBinding = display;
DisplayBinding_Edit.dimY = dimY;
DisplayBinding_Edit.set('style', 'width:' + dimX + 'px; height:' + dimY + 'px;');
DisplayBinding_Edit.show();
var d = new Date();
// valori 'di default' da passare alla chiamata
var url_params = {
U: d.getTime() + '' + Math.floor(1000 * Math.random()),
prefix: 'Detail',
from: from,
rows: 1,
disp_navbar: '',
disp_insert: '',
disp_delete: '',
disp_xls: '',
disp_log: '',
disp_dup: '',
find_area: 'none',
disp_refresh: '',
disp_print: '',
mode: display.modeDetail, // forward/insert
find_key: find_key,
father_id: display.dataBinding.father_id,
father_id_update: display.dataBinding.father_id_update
};
// parametri aggiuntivi
for(var k in form_params){
url_params[k] = form_params[k];
}
DisplayBinding_Edit.disp_prefix = 'Disp_' + url_params.prefix + '_' + url_params.from.replace(/\//g, '_');
DisplayBinding_Edit.set('href', '/frame.html?' + ioQuery.objectToQuery(url_params)).then(
function(){
console.debug('downloaded href', DisplayBinding_Edit);
masonSql.ready();
},
function(err){
tab.set('errorMessage', "<span class='dijitContentPaneError'>"+
"<span class='dijitInline dijitIconError'></span>"+err+' id:'+DisplayBinding_Edit.id+' timeout:'+<% $r->dir_config('GetFormTimeout') %>+"</span>");
console.error('ERROR href',err , DisplayBinding_Edit);
}
);
});
}
 
// Apre un form con maggiore dettaglio del record indicato (row: riga del record)
function DisplayBinding_openFormDetail(mode, row, from, dimX, dimY, title, params){
return this.openFormDetailByKey(mode, this.dataBinding.keys[row], from, dimX, dimY, title, params);
}
 
// in risposta al click di una riga di TABLE o DIVS indica quale sia il padre corrente da mostrare nei recordset figli
function DisplayBinding_selectRowFather(row, no_update){
if(row == null){
row = this.rowFather == null ? 0 : this.rowFather;
}
var db = this.dataBinding;
var row_div = dojo.byId(this.id + '_div_' + row);
if(!row_div){
// row_div se non esiste, non gestisco il cambio dei figli (ad esempio il template 'FORM' non lo prevede)
return;
}
var old_rowFather = this.rowFather;
this.rowFather = null;
// tolgo evidenza dell'eventuale riga selezionata in precedenza
if(old_rowFather != null){
dojo.removeClass(dojo.byId(this.id + '_div_' + old_rowFather), 'selectRowFather');
}
// se il record padre non esiste oppure il recordset non ha figli non devo evidenziare la riga selezionata
if(db.children.length){
if(db.fathers_id && db.fathers_id[row]){
// evidenzio la riga selezionata
dojo.addClass(row_div, 'selectRowFather');
this.rowFather = row;
}
// aggiorno i figli se chiamata da onclick delle righe da parte dell'utente
if(!no_update && db.keys[row] && this.rowFather != old_rowFather){
db.updateChildren(row);
}else if(!db.keys[row] || (no_update && !db.fathers_id)){
db.rowFather = null;
// le tabelle figlie vanno nascoste
for(var I = 0; I < db.children.length; I++){
var disp_child = db.children[I].displayBinding;
if(disp_child){
disp_child.waitingStatus(false);
setDisplay(disp_child.widgetsContainer, false);
}
}
}
}
}
 
function DisplayBinding_cpDeleteCopy(ReadOnly){
if(ReadOnly){
this.dataBinding.cp_key = null;
this.cp_row = null;
this.cp_record = null;
}
return;
}
 
// Check multiple rows if the shift key has been pressed. Otherwise keep track
// of last checked row and proceed with normal updating of the
// checked/unchecked row.
function DisplayBinding_cpSetMultipleRows(Evt, R){
var db = this.dataBinding;
if(!this.checks || !this.checks[R]){
return;
}
var cp = !db.readonly && this.cp_enabled;
var checkedR = this.checks[R].checked;
var prev = this.cp_previous;
if(Evt.shiftKey && prev !== null && prev != R){
var from;
var to;
if(prev < R){
from = prev;
to = R;
}else{
from = R;
to = prev;
}
for(var row = from; row <= to; row++){
var checksRow = this.checks[row];
if(checksRow && (!checksRow.checked || row == R)){
checksRow.checked = true;
cp && this.cpSetRow(row, true);
}
}
}else{
if(checkedR){
this.cp_previous = R;
}else{
this.cp_previous = null;
}
cp && this.cpSetRow(R, checkedR);
}
cp && this.cpSetSelect(false);
return;
}
 
// Determine whether the row is unchecked, is to be copied or is to be pasted.
// Manage row to be copied and its content. Set row classes accordingly.
function DisplayBinding_cpSetRow(R, Checked){
var db = this.dataBinding;
if(db.readonly || !this.cp_enabled || !this.fields || !this.fields[R]){
return;
}
var row = this.fields[R];
if(Checked){
if(this.cp_row === null && db.cp_key === null){
this.cp_record = this.newRecord();
this.copyRecord(row, R, this.cp_record);
this.cp_row = R;
this.cpSetRowClasses(row, Checked, 'WidgetToCopy');
// cp_row must not be overwritten with Shift selection
}else if(this.cp_row != R){
this.duplicateRecord(this.cp_record, R, this.cp_modes);
this.cpSetRowClasses(row, Checked, 'WidgetPasted');
}else{
this.cpSetRowClasses(row, Checked, 'WidgetToCopy');
}
}else{
this.cpUndoRecord(db.data[R], row);
if(this.cp_row == R){
this.cpDeleteCopy(true);
this.cpSetSelect(false);
}
this.cpSetRowClasses(row, Checked, '');
}
return;
}
 
function DisplayBinding_cpSetRowClasses(Row, Checked, WidgetClass){
var h = this.headers;
if(h){
for(var C = 0; C < Row.length; C++){
var field = Row[C];
var header = h[C];
var isSelected = header.selectable && header.selected && Checked;
this.cpSetFieldClass(field, WidgetClass, isSelected);
}
}
return;
}
 
// Set Copy-Paste properties and classes, of the field specified with 'Pos'.
// If the field is not checked revert its value. Set the field class according
// to the determined status.
function DisplayBinding_cpSetColumn(Header, Pos){
var db = this.dataBinding;
if(db.readonly || !this.cp_enabled || !this.checks){
return;
}
for(var R = 0; R < db.max_table_rows; R++){
if(this.checks[R]){
var isSelected = Header.selectable && Header.selected && this.checks[R].checked;
var record = this.fields[R];
var field = record[Pos];
if(db.data[R]){
//console.log('undo from db.data[R][Pos]=', db.data[R][Pos]);
Scalar2Form(db.data[R][Pos], null, field);
}
if(this.cp_row === R){
this.cpSetFieldClass(field, 'WidgetToCopy', isSelected);
}else{
this.cpSetFieldClass(field, 'WidgetPasted', isSelected);
}
}
}
return;
}
 
// Field Copy-Paste classes:
// 'WidgetToCopy' indicates a row to be copied;
// 'WidgetPasted' indicates a row in which the copied row is pasted;
// '' absence of both classes indicates unchanged row.
function DisplayBinding_cpSetFieldClass(Field, WidgetClass, IsSelected){
require(["dojo/dom-class", "dojo/domReady!"], function(domClass){
if(IsSelected){
domClass.replace(Field.dispSpan, WidgetClass, 'WidgetToCopy WidgetPasted');
}else{
domClass.remove(Field.dispSpan, 'WidgetToCopy WidgetPasted');
}
});
return;
}
 
// Used for deactivating Copy-Paste properties and classes of the table headers
// during transition to read-only state.
function DisplayBinding_cpDeselectHeaders(ReadOnly){
if(ReadOnly){
var h = this.headers;
for(var C = 0; C < h.length; C++){
if(h && h[C]){
h[C].selectable = false;
h[C].selected = false;
this.cpSetHeaderClass(h[C], C, true);
}
}
this.cpSetSelect(true);
}
return;
}
 
function DisplayBinding_cpRefreshRow(Row){
if(this.checks[Row]){
this.checks[Row].checked = true;
this.cpSetRow(Row, true);
}
return;
}
 
// Called from onclick event on 'sel.' header.
// Invert 'selected' status of all columns that can be selected for Copy-Paste.
// Do not modify field classes of the displayed records except if the row is to be copied.
// Also update cp_modes, 'sel.' classes and the classes of the rest of the table headers
function DisplayBinding_cpInvertAllHeaders(){
var db = this.dataBinding;
if(db.readonly){
return;
}
var h = this.headers;
for(var C = 0; C < this.headers.length; C++){
h[C].selected = h[C].selected ? false : true;
}
this.cpSetModes(h, db.cp_fields);
this.cpUncheckPasted(db.max_table_rows);
this.cpRefreshRow(this.cp_row);
this.cpSetSelect(false);
for(var C = 0; C < this.headers.length; C++){
this.cpSetHeaderClass(h[C], C, false);
}
return;
}
 
// Called from onclick event on table header field.
// 1. Invert 'selected' status of the header field.
// 2. Uncheck all rows except the row to be copied.
// 3. Update classess of the row to be copied.
// 4. Update classes of the 'sel.' header and the rest of the table headers.
function DisplayBinding_cpInvertHeader(Pos){
var db = this.dataBinding;
if(db.readonly){
return;
}
var h = this.headers;
h[Pos].selected = h[Pos].selected ? false : true;
this.cpSetModes(h, db.cp_fields);
this.cpUncheckPasted(db.max_table_rows);
this.cpRefreshRow(this.cp_row);
this.cpSetSelect(false);
this.cpSetHeaderClass(h[Pos], Pos, false);
return;
}
 
// Header classes:
// 'ColSelected' set when column Copy-Paste is active;
// 'ColSelectable' set when its possible to select column for Copy-Paste operation;
// 'CopyPasteDisabled' set when at least one column is selectable;
// '' absence of all three classes indicates the column is in read-only state.
function DisplayBinding_cpSetHeaderClass(Header, Pos, ReadOnly){
var cp_fields = this.dataBinding.cp_fields;
require(["dojo/dom-class", "dojo/domReady!"], function(domClass){
if(Header){
if(Header.selectable){
if(Header.selected){
domClass.replace(Header, 'ColSelected', 'ColSelectable CopyPasteDisabled');
}else{
domClass.replace(Header, 'ColSelectable', 'ColSelected CopyPasteDisabled');
}
}else{
if(ReadOnly){
domClass.remove(Header, 'CopyPasteDisabled ColSelectable ColSelected');
}else if(cp_fields.length > 0){
domClass.replace(Header, 'CopyPasteDisabled', 'ColSelectable ColSelected');
}
}
}
});
return;
}
 
// 1. Search if any of the columns can be selected for Copy-Paste and if any of
// the columns is selected for copy paste by user. The column property
// 'selectable' is obtained during parsing of FIELDS_COPY_PASTE method. The
// column property 'selected' indicates whether the column is also selected for
// Copy-Paste.
// 2.a Use found information to determine whether Copy-Paste is active ('cp_enabled' property).
// 2.b When the Copy-Paste is (re)activated uncheck all rows and delete row to be copied.
// 3.a Set 'sel.' header class to 'CopyPasteResetInvert' only when at least one
// column can be selected and Copy-Paste is active and the row to be copied has been
// checked by user.
// 3.b Set 'sel.' header class to 'CopyPasteDisabled' if not in read-only mode and
// at least one column is selectable.
function DisplayBinding_cpSetSelect(ReadOnly){
var obj = this;
var h = this.headers;
var db = this.dataBinding;
var sel = this.headers_select;
var cp_fields = this.dataBinding.cp_fields;
if(!sel || !h){
return;
}
require(["dojo/dom-class", "dojo/_base/array", "dojo/domReady!"], function(domClass, array){
var existsSelectable = false;
var existsSelected = false;
array.forEach(h, function(header){
if(header.selectable){
existsSelectable = true;
if(header.selected){
existsSelected = true;
}
}
});
if(existsSelected){
if(!obj.cp_enabled){
obj.cp_enabled = true;
obj.uncheckAll(db.max_table_rows);
obj.cpDeleteCopy(true);
}
}else{
obj.cp_enabled = false;
}
//console.log('cp_enabled=', obj.cp_enabled);
if(existsSelectable && (obj.cp_row !== null || db.cp_key !== null) && obj.cp_enabled){
domClass.replace(sel, 'CopyPasteResetInvert', 'CopyPasteDisabled');
}else if(ReadOnly){
domClass.remove(sel, 'CopyPasteResetInvert CopyPasteDisabled');
}else if(cp_fields.length > 0){
domClass.replace(sel, 'CopyPasteDisabled', 'CopyPasteResetInvert');
}
});
return;
}
 
function DisplayBinding_cpUncheckPasted(MaxTableRows){
if(!this.checks){
return;
}
for(var R = 0; R < MaxTableRows; R++){
var checksR = this.checks[R];
if(this.cp_row != R && checksR && checksR.checked){
checksR.checked = false;
}
}
return;
}
 
function DisplayBinding_uncheckAll(MaxTableRows){
var lista = [];
if(!this.checks){
return lista;
}
for(var R = 0; R < MaxTableRows; R++){
var checksR = this.checks[R];
var row = this.fields[R];
if(checksR && checksR.checked){
checksR.checked = false;
this.cpSetRowClasses(row, false, '');
lista.push(R);
}
}
this.cp_previous = null;
return lista;
}
 
function DisplayBinding_cpSetModes(H, CpFields){
this.cp_modes = [];
for(var C = 0; C < H.length; C++){
var cpField = CpFields[C];
if(cpField && (cpField == 'C' || cpField == 'c')){
H[C].selectable = true;
if(H[C].selected){
this.cp_modes[C] = cpField;
}else{
this.cp_modes[C] = '';
}
}else if(H[C]){
H[C].selectable = false;
this.cp_modes[C] = '';
}
}
return;
}
 
function DisplayBinding_cpSetAll(){
var db = this.dataBinding;
if(db.readonly){
return;
}
var h = this.headers;
this.cpSetModes(h, db.cp_fields);
this.cpSetSelect(false);
for(var C = 0; C < h.length; C++){
var cpField = db.cp_fields[C];
this.cpSetHeaderClass(h[C], C, false);
if(h[C] && cpField && (cpField == 'C' || cpField == 'c')){
this.cpSetColumn(h[C], C);
}
}
return;
}
 
// abilita/disabilita i pulsanti di navigazione
function NavigationBar_setButtons(set, list){
var re_button = /Button$/;
if(list == null){
// disabilito tutti i pulsanti di controllo
for(name in this){
var elem = this[name];
if(elem != null && re_button.test(name)){
elem.disabled = !set;
}
}
}else{
// disabilito i pulsanti di controllo il cui nome è elencato nella lista
for(I in list){
var name = list[I];
if(!re.test(name)){
// se il nome non termina con 'Button' lo aggiungo
name += Button;
}
var elem = this[name];
if(elem != null){
elem.disabled = !set;
}
}
}
}
 
// copia una singola riga dell'Array nel form
function Row2Form(Row, Data, Params, formP, key, Lbl){
if(key && Lbl && Lbl[Row]){
var rec = key[Row];
Lbl[Row].innerHTML = key.length == 1 ? '(' + (key[Row] == null ? '...' : key[Row]) + ')' : key[Row];
}
Vect2Form(Data[Row], Params[Row], formP[Row]);
}
 
function DisplayBinding_cpUndoRecord(BackedUpVals, Form){
var h = this.headers;
if(BackedUpVals && h){
for(var C = 0; C < Form.length; C++){
var header = h[C];
if(header.selectable && header.selected){
Scalar2Form(BackedUpVals[C], null, Form[C]);
}
}
}
return;
}
 
function Scalar2Form(Value, Parameter, Field){
if(Field != null){
if(Value == null){
Field.set_value('', Parameter);
}else{
Field.set_value(Value, Parameter);
}
Field.widgetError = false;
Field.set_status();
}
return;
}
 
function Vect2Form(Vals, Params, Form){
for(var C = 0; C < Form.length; C++){
Scalar2Form(Vals[C], Params ? Params[C] : null, Form[C]);
}
}
 
function Array2Form(Data, Params, formP, key, Lbl){
// my_alert('Array2Form('+key+')\nformp='+Data);
// riempio i campi
for(var R=0; R<Data.length; R++){
Row2Form(R, Data, Params, formP, key, Lbl);
}
}
 
// riempio i campi della riga R dell'Array Data con i campi del form formP
function Form2Row(Row, formP, arrayVal){
if(!arrayVal[Row]){
arrayVal[Row] = [];
}
Form2Vect(formP[Row], arrayVal[Row]);
}
 
function Form2Vect(P, Val, Par){
for(var C=0; C<P.length; C++){
var input = P[C];
if(input != null){
Val[C] = input.get_value();
if(Par){
Par[C] = input.get_param();
}
//alert("value="+Val[C]+" "+input.id+":"+input.type+" check:"+input.checked+" cal="+input.value);
}
}
}
 
// riempio i campi dell'Array con i valori inseriti nel form
function Form2Array(formP, Data){
for(var R=0; R<formP.length; R++){
Form2Row(R, formP, Data);
}
}
 
// verifico se tutti i campi contengono valori validi
// Se ci sono campi che richiedono un test asincrono (es. chiamata al server)
// la funzione ritorna false provvisoriamente, ma si occupa di monitorare
// le risposte dal server, che se tutte positive, rilanceranno la richiesta con i
// parametri passati 'pos' e 'key'
function DisplayBinding_CheckForm(displayBinding, pos, key, recordset, loop){
var check = displayBinding.CheckForm_check;
if(check && check.widgets.length == 0){
// chiamata arrivata in quanto ho richiamato databinding dopo il test concluso positivo
displayBinding.CheckForm_check = null;
// segnalo OK
return true;
}
var formP = displayBinding.fields;
var db = displayBinding.dataBinding;
if(loop){
// verifico lo stato dei campi che hanno segnalato una verifica asincrona
// loop all'indietro in quanto tolgo dalla lista i widget che hanno terminato il test
for(var C=check.widgets.length-1; C>=0; C--){
var input = check.widgets[C];
// test effettuato senza che venga gestito dal singolo campo la visualizzazione del messaggio di errore
var str_err = input.remote_test();
if(typeof(str_err) == 'string'){
if(str_err){
var descRiga = formP.length == 1 ? '' : 'Riga:' + (input.dbRow + 1) + ' ';
check.errors += descRiga + input.Descr + ': ' + str_err + '\n';
}
// tolgo il widget dalla lista
check.widgets.splice(C, 1);
}
}
}else{
check = displayBinding.CheckForm_check = {
widgets: [],
errors: ''
};
// test validità dei campi locale e campo non nullo
for(var R=0; R<formP.length; R++){
var P = formP[R];
var row_difference = db._difference[R];
// valuto se la riga è stata modificata
var row_is_changed = false;
var descRiga = formP.length == 1 ? '' : 'Riga:' + (R+1) + ' ';
for(var C=0; C<P.length; C++){
if(row_difference[C] != null){
row_is_changed = true;
// la verifica la eseguo solo se il campo è stato variato dall'utente
var input = P[C];
// test validità locale
if(input && input.local_test){
var str_err = input.local_test();
if(str_err){
check.errors += descRiga + input.Descr + ': ' + str_err + '\n';
}
}
}
}
if(row_is_changed){
// test campi non nulli
if(db.keys[R] != null){
// record modificato: la verifica la eseguo solo se il campo è stato variato dall'utente
for(var C=0; C<P.length; C++){
if(db.required_fields[C] == true && row_difference[C] != null && row_difference[C].length == 0){
var input = P[C];
input.widgetError = 'Error';
input.set_status();
check.errors += descRiga + input.Descr + ': campo obbligatorio\n';
}
}
}else{
// nuovo record: la verifica la eseguo su tutti i campi
for(var C=0; C<P.length; C++){
var input = P[C];
if(db.required_fields[C] == true && input.get_value().length == 0){
input.widgetError = 'Error';
input.set_status();
check.errors += descRiga + input.Descr + ': campo obbligatorio\n';
}
}
}
}
}
if(check.errors){
// se ci sono errori nei campi a livello locale non effettuo il rest remoto
my_alert('Controllo locale dei campi negativo:\n' + check.errors, 'auto');
displayBinding.CheckForm_check = null;
return false;
}
// test validità dei campi remota: la verifica la eseguo solo se il campo è stato variato dall'utente
for(var R=0; R<formP.length; R++){
var row_difference = db._difference[R];
var P = formP[R];
var descRiga = formP.length == 1 ? '' : 'Riga:' + (R+1) + ' ';
for(var C=0; C<P.length; C++){
if(row_difference[C] != null){
var input = P[C];
if(input && input.remote_test){
var str_err = input.remote_test();
if(typeof(str_err) == 'boolean' && !str_err){
input.widgetError = 'Wait';
input.set_status();
// aggiungo il widget per il controllo successivo
check.widgets.push(input);
}else if(typeof(str_err) == 'string' && str_err){
input.widgetError = 'Error';
input.set_status();
check.errors += descRiga + input.Descr + ': ' + str_err + '\n';
}
}
}
}
}
}
if(check.widgets.length){
// c'è almeno un widget che sta effettuando un controllo remoto
window.setTimeout('DisplayBinding_CheckForm('+displayBinding.prefix+', "'+pos+'", '+
(key == null ? 'null' : key)+', '+(recordset == null ? 'null' : recordset)+',true);', 100);
return false;
}else if(check.errors){
my_alert('Controllo remoto dei campi negativo:\n' + check.errors, 'txt');
displayBinding.CheckForm_check = null;
return false;
}
if(loop){
// chiamate di controllo successive alla prima
if(pos){
// se tutti i widget sono OK lancio il comando che avevo sospeso
db.gotoRecords(pos, key, recordset);
}
}else{
displayBinding.CheckForm_check = null;
return true;
}
}
 
// ritorna il widget adiacente in funzione della direzione indicata
function DisplayBinding_getWidget(input, event){
if(input.dbRow != null){
// widget appartenente a un form di tipo DisplayBinding
var fields = input.displayBinding.fields;
var formKeysMovement = input.displayBinding.formKeysMovement;
// alert(input.id +': ' + event.keyCode + ' R:' + input.dbRow + ' C:' + input.dbCol);
if((event.keyCode == 9 && !event.shiftKey) || (event.keyCode == 39 && formKeysMovement.search('ARROWS') != -1)){ // TAB o Right arrow
return input.dbCol == fields[0].length - 1 ? (input.dbRow == fields.length - 1 ? fields[0][0] : fields[input.dbRow + 1][0]) : fields[input.dbRow][input.dbCol + 1];
}else if((event.keyCode == 9 && event.shiftKey) || (event.keyCode == 37 && formKeysMovement.search('ARROWS') != -1)){ // Shift-TAB o Left arrow
return input.dbCol == 0 ? (input.dbRow == 0 ? fields[fields.length - 1][fields[0].length -1] : fields[input.dbRow - 1][fields[0].length -1]) : fields[input.dbRow][input.dbCol - 1];
}else if(event.keyCode == 38 && formKeysMovement.search('ARROWS') != -1){ // Up arrow
return input.dbRow == 0 ? (input.dbCol == 0 ? fields[fields.length - 1][fields[0].length -1] : fields[fields.length - 1][input.dbCol - 1]) : fields[input.dbRow - 1][input.dbCol];
}else if((event.keyCode == 13 && !event.shiftKey && formKeysMovement.search('ENTER') != -1) || (event.keyCode == 40 && formKeysMovement.search('ARROWS') != -1)){ // CR o Down arrow
return input.dbRow == fields.length - 1 ? (input.dbCol == fields[0].length -1 ? fields[0][0] : fields[0][input.dbCol + 1]) : fields[input.dbRow + 1][input.dbCol];
}else{
return null;
}
}else if(input.findPos != null){
// widget appartenente ad un form di filtro finds
var fields = input.displayBinding.finds;
if(event.keyCode == 39 || (event.keyCode == 9 && !event.shiftKey)){ // Right arrow o TAB
return input.findPos == fields.length - 1 ? input.displayBinding.ftypes[0] : input.displayBinding.ftypes[input.findPos + 1];
}else if(event.keyCode == 37 || event.keyCode == 9 && event.shiftKey){ // Left arrow o Shift-TAB
return input.displayBinding.ftypes[input.findPos];
}else if((event.keyCode == 13 && !event.shiftKey) || event.keyCode == 40){ // CR o Down arrow
return input.findPos == fields.length - 1 ? input.displayBinding.ftypes[0] : fields[input.findPos + 1];
}else if(event.keyCode == 38){ // Up arrow
return input.findPos == 0 ? input.displayBinding.ftypes[fields.length - 1] : fields[input.findPos - 1];
}else{
return null;
}
}else if(input.ftypePos != null){
// widget appartenente ad un form di filtro ftypes
var fields = input.displayBinding.ftypes;
if(event.keyCode == 39 || (event.keyCode == 9 && !event.shiftKey)){ // Right arrow o TAB
return input.displayBinding.finds[input.ftypePos];
}else if(event.keyCode == 37 || event.keyCode == 9 && event.shiftKey){ // Left arrow o Shift-TAB
return input.ftypePos == 0 ? input.displayBinding.finds[fields.length - 1] : input.displayBinding.finds[input.ftypePos - 1];
}else if((event.keyCode == 13 && !event.shiftKey) || event.keyCode == 40){ // CR o Down arrow
return input.ftypePos == fields.length - 1 ? input.displayBinding.finds[0] : fields[input.ftypePos + 1];
}else if(event.keyCode == 38){ // Up arrow
return input.ftypePos == 0 ? input.displayBinding.finds[fields.length - 1] : fields[input.ftypePos - 1];
}else{
return null;
}
}else{
return null;
}
}
 
// Forza il campo nel form e nel dataset (no aggiornamento nel server)
function DisplayBinding_forceValueField(value, field_name, row){
if(arguments.length == 2){
row = 0
}
this.getField(field_name, row).set_value(value);
var db = this.dataBinding;
db.data[row][db.pos_name[field_name]] = value;
db.new_data[row][db.pos_name[field_name]] = value;
}
 
%# END displaybinding.js
 
/tags/2.0/htdocs/lib/dbms_library.comp
0,0 → 1,5731
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010-2016 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
 
in $method va indicato il formato dei dati restituiti
'select' codice javascript per popolare <select/>
'array' codice javascript di inizializzazione di array 2 dimensioni
'pdf' report di stampa in formato pdf (richiede che venga creato il report in formato .rep (http://reportman.sourceforge.net/)
'xml' documento xml
'txt' formato tabulare con \t come delimitatore di campo; nome dei campi sulla prima riga
'xls' formato Excel (XLS)
'html' tabella html (per debug)
'array' tabella in formato Array jscript
'field_check' richiesta di verifica validità di un widget
'call_remote' chiamata di funzione remota
. . . . .
</%doc>
<%args>
$method => $Session{ARGS}{method}
@P => ()
</%args>
%##################################################### html
<%method html>\
<% $r->dir_config('HtmlDocType') %>
<html>
<head>
<meta http-equiv="Content-Type" content="test/html; charset=utf-8">
<title><& SELF:DESCRIPTION &></title>
<link rel="stylesheet" href="/css/main.css" type="text/css">
<style type='text/css'>
body {
color:#000000; background:#FFFFFF;
margin:0px; padding:0px;
}
</style>
<meta name="AUTHOR" content="Brugnara ing. Guido - gdo@leader.it">
<meta name="COPYRIGHT" content="Leader.IT di Guido Brugnara; Strada della Pozzata, 41 - Villazzano; 38123 TRENTO (ITALY); info@leader.it">
</head>
<body><p align="center">
<H3><& SELF:DESCRIPTION &></H3>
<table border="1">
<%perl>
my $KEY = $m->scomp('SELF:KEY');
my $base_comp = $m->base_comp;
$sth = SqlSelect('SELECT', 'SELECT_FIELDS', \%ARGS);
# i nomi dei campi risultato della query
my $query_names = $sth->{NAME};
</%perl>
<hr>\
% foreach my $key ( @$query_names ){
<td><b><%$key%></b></td>\
% }
</hr>
<%perl>
while(my $row = $sth->fetchrow_hashref){
if($base_comp->method_exists('OUT_FILTER')){
$row = $base_comp->call_method('OUT_FILTER', row => $row);
}
if($row){
</%perl>
<tr>
<%perl>
my $id = $row->{$query_names->[0]};
for(my $i=0; $i<@$query_names; $i++){
my $key = $query_names->[$i];
my($val, undef) = Call_OutFieldFilter($key, $id, $row->{$key}, $query_names, $row, $base_comp, 1);
$val =~ s/\n/<br>/gm;
$val || ($val = '&nbsp;');
</%perl>
<td><%$val%></td>
% }
</tr>
% }
% }
</table></p></body></html>
</%method>
 
%##################################################### metodi utilizzati da /archive
%## Vedi widget /input/Files.comp
%##
<%method archive_check>\
<%args>
$Base
$rec_id
$permission
</%args>
<%perl>
my $perm = Permission($ARGS{PermissionGroup});
if(!$rec_id){
$m->out('{}');
$m->abort;
}
$rec_id =~ m/[^\w]/s && return {error => "Field rec_id malformed"};
# verifico esistenza del record
if($ARGS{RecordsetCache} && !RecordsetCache($ARGS{name}, 'check_key', $rec_id)){
# recordset non attivo oppure record assente nel recordset ...
$ARGS{json_where} = to_json [[$m->scomp('SELF:KEY'), '=', $rec_id]];
# chiamo SqlSelectWhere con father_id=-2 per disabilitare il controllo (tanto uso una query con la PK)
my $sth = ExecQuery('numrec', 'SELF:NUMREC', WHERE => SqlSelectWhere(\%ARGS, -2));
if(!$sth->fetchrow_arrayref->[0]){
return {error => "Not found or no $permission in archive of $Base record $rec_id"};
}
}
my $dir = $r->dir_config('InputFilesArchive')."/$Base/$rec_id";
if(! -d $dir){
make_path $dir || return {error => "create dir for $Base:$rec_id $!"};
}
return undef;
</%perl>
</%method>
 
<%method archive_get>\
<%args>
$Base
$name
$path
$rec_id
$mode_download
</%args>
<%perl>
$r->headers_out->{'Cache-Control'} = 'max-age=0';
# $r->content_type($mime);
#DEBUG print STDERR Dumper(\%ARGS);
if(my $err = $m->comp('SELF:archive_check', %ARGS, permission => 'Select')){
$Session{StatusCode} = 404;
die $err->{error}."\n";
}
my $base_dir = $r->dir_config('InputFilesArchive')."/$Base/$rec_id";
if($path =~ m/\.\./s){
$Session{StatusCode} = 404;
die "path malformed\n";
}
my $Files_Trash_dir = $r->dir_config('Files_Trash_dir');
if(!$Session{Group_Admins} && ($path eq '/.'.$Files_Trash_dir || $path =~ m|^/\.$Files_Trash_dir/|)){
die "cestino visibile solo agli amministratori\n";
}
my $files;
my $finds = File::Find::Rule->file;
if($path =~ /[\*\?]/){
# esistono wildcard nel percorso
($files,$path) = fileparse($path);
if($path eq './'){
$path = '';
}
$finds->name($files);
}
my $file = "$base_dir/$path";
$path = '/'.$path;
my $obj_name = $path;
$obj_name =~ s|^.*/||;
if(! -e $file){
$Session{StatusCode} = 404;
die "File $Base:$rec_id:$path not exists";
}
if($mode_download && $mode_download ne 'json' && $mode_download ne 'csv' ){
my $filetype;
my $filename = $file;
$filename =~ s/^.*\///;
$r->headers_out->{'Content-transfer-encodig'} = 'binary';
if($mode_download eq 'save'){
$filetype = 'application/octet-stream; charset=binary';
$r->headers_out->{'Content-disposition'} = qq{attachment; filename="$filename"};
}elsif($mode_download eq 'download'){
$r->headers_out->{'Content-disposition'} = qq{inline; filename="$filename"};
my $mime_file = $file;
if(-l $file){
run ['/bin/readlink', '-f', $file], '>', \$mime_file;
chomp $mime_file;
}
if(!run ['/usr/bin/file', '--mime', '--brief', $mime_file], '>', \$filetype){
$Session{StatusCode} = 500;
die "run: $!";
}
chomp $filetype;
}elsif($mode_download eq 'zipSave'){
$filetype = 'application/zip; charset=binary';
if(!$filename){
$filename = "$name.$rec_id";
}
$r->headers_out->{'Content-disposition'} = qq{attachment; filename="$filename.zip"};
# creazione dell'archivio coi i file presenti nella cartella $file
my $zip = Archive::Zip->new();
my($zip_fh, $zip_file) = tempfile(
DIR => $r->dir_config('TmpDir'),
SUFFIX => '.zip',
UNLINK => 0
);
$finds->start($file);
while(my $path_file = $finds->match){
my $rel_file = $path_file;
# tolgo la radice del percorso
$rel_file = substr($rel_file, length($file));
$rel_file =~ s/^\///;
if($rel_file && $rel_file !~ m/^\./ && $rel_file !~ m/\/\./ && -r $path_file){
# non allego i file/dir nascosti, la radice e i file non leggibili
Encode::_utf8_on($rel_file);
$zip->addFileOrDirectory($path_file, $rel_file) || die "Failed Zip to add $rel_file\n";
}
}
die "Copy files to zip error\n" unless $zip->writeToFileHandle($zip_fh) == 0;
close $zip_fh;
$file = $zip_file;
}elsif($mode_download eq 'tgzSave'){
$filetype = 'application/x-tar; charset=binary';
if(!$filename){
$filename = "$name.$rec_id";
}
$r->headers_out->{'Content-disposition'} = qq{attachment; filename="$filename.tgz"};
# creazione dell'archivio coi i file presenti nella cartella $file
my $tmp_dir = $r->dir_config('TmpDir');
my $tar = Archive::Tar::Wrapper->new( tmpdir => $tmp_dir );
my($tar_fh, $tar_file) = tempfile(
DIR => $tmp_dir,
SUFFIX => '.tgz',
UNLINK => 0
);
close $tar_fh;
my $count_file;
$finds->start($file);
while(my $path_file = $finds->match){
my $rel_file = $path_file;
# tolgo la radice del percorso
$rel_file = substr($rel_file, length($file));
$rel_file =~ s/^\///;
if($rel_file && $rel_file !~ m/^\./ && $rel_file !~ m/\/\./ && -r $path_file){
# non allego i file/dir nascosti, la radice e i file non leggibili
Encode::_utf8_on($rel_file);
$tar->add($rel_file, $path_file) || die "Failed Tar to add $rel_file: $!\n";
$count_file++;
}
}
if($count_file){
$tar->write($tar_file, 9) || die "Copy files to tar error: $!\n";
}
$file = $tar_file;
}elsif($mode_download eq 'tgzArc'){
$filetype = 'application/x-tar; charset=binary';
if(!$filename){
$filename = "$name.$rec_id";
}
if($m->APACHE2){
$r->headers_out->{'Content-disposition'} = qq{attachment; filename="$filename.tgz"};
}else{
$r->header_out('Content-disposition' => qq{attachment; filename="$filename.tgz"});
}
# creazione dell'archivio coi i file presenti nella cartella $file
my $tmp_dir = $r->dir_config('TmpDir');
my($tar_fh, $tar_file) = tempfile(
DIR => $tmp_dir,
SUFFIX => '.tgz',
UNLINK => 0
);
close $tar_fh;
chdir $file || die "Error to change dir $file: $!\n";
system '/bin/tar', 'czf', $tar_file, '-C', $file, './' || die "Error to create tar archive from $file: $!\n";
$file = $tar_file;
}
#DEBUG print STDERR "DOWNLOAD [$mode_download: $filetype] $Base:$rec_id $path\n";
$r->content_type($filetype);
sysopen FILE, $file, 'O_RDONLY' || die "sysopen $file: $!";
my $buffer;
# leggo il file generato a blocchi di 64Kbyte
while(my $numchar = sysread FILE, $buffer, 2^16){
if(undef $numchar){
$Session{StatusCode} = 500;
die "sysread $file: $!";
};
$m->clear_buffer;
$m->out($buffer);
$m->flush_buffer;
}
if($mode_download eq 'zipSave' || $mode_download eq 'zgzSave'){
unlink $file
}
return 200;
}else{
# oggetto per preparare la lista
my %list_obj;
if(-d $file){
#DEBUG print STDERR "RETURN DIR $Base:$rec_id $path\n";
my @children;
if($path eq '/.'.$Files_Trash_dir){
%list_obj = ('name' => $r->dir_config('Files_Trash_name'), 'id' => $path, type => 'trash');
}else{
%list_obj = ('name' => $obj_name || '...', 'id' => $path );
}
my $dir;
opendir($dir, $file) || die "can't opendir $Base:$rec_id $path: $!";
if($path eq '/'){
$path = '';
}
# usato per ritardare l'inserimento del cestino nella lista
my $trash_p_obj;
while(my $filename = readdir $dir){
utf8::is_utf8($filename) || utf8::decode($filename);
# salto se puntatori alla dir corrente, dir padre o dir/file nascosti
my %file_obj;
if($Session{Group_Admins} && "$path/$filename" eq '/.'.$Files_Trash_dir){
%file_obj = ( 'name' => $r->dir_config('Files_Trash_name'), 'id' => "$path/$filename", type => 'trash');
}else{
next if($filename =~ m/^\./);
%file_obj = ( 'name' => $filename, 'id' => "$path/$filename");
}
if(-d "$file/$filename"){
# verifico se la cartella contiene dei file
my $empty = 1;
my $dir;
opendir($dir, "$file/$filename") || die "can't opendir $Base:$rec_id $file/$filename: $!";
while(my $filename = readdir $dir){
next if($filename =~ m/^\./);
$empty = 0;
closedir $dir;
last;
}
$file_obj{children} = $empty ? [] : 1;
}
if($file_obj{type} eq 'trash'){
# ritardo l'inserimento del cestino nella lista
$trash_p_obj = \%file_obj;
}else{
push @children, \%file_obj;
}
}
closedir $dir;
# ordinamento con le cartelle in testa
my @sorted = sort { $b->{'children'} cmp $a->{'children'} || uc $a->{'name'} cmp uc $b->{'name'} } @children;
# piazzo il cestino in fondo alla lista
$trash_p_obj && push @sorted, $trash_p_obj;
$list_obj{children} = \@sorted;
#DEBUG print STDERR Dumper(\%list_obj), objToJson(\%list_obj);
}else{
#DEBUG print STDERR "RETURN FILE $Base:$rec_id $path\n";
%list_obj = ( 'name' => $obj_name, 'id' => $path );
}
if($mode_download eq 'csv'){
# lista file/cartelle nel formato svs (separatore \t)
$r->content_type('text/plain; charset=utf-8');
$m->print("id\ttype\tname\n");
my $type = $list_obj{type} || $list_obj{children} ? 'dir' : 'file';
$m->print("$list_obj{id}\t$type\t$list_obj{name}\n");
if(defined $list_obj{children}){
foreach my $child (@{$list_obj{children}}){
my $type = $child->{type} || $child->{children} ? 'dir' : 'file';
$m->print("$child->{id}\t$type\t$child->{name}\n");
}
}
}else{
$r->content_type('application/json; charset=utf-8');
$m->print(objToJson(\%list_obj));
}
}
</%perl>
</%method>
 
<%perl>
 
sub move_file_archive($$$$){
my($Base, $rec_id, $file_old, $file_new) = @_;
my $base_dir = $r->dir_config('InputFilesArchive')."/$Base/$rec_id";
# verifico che non venga usato '/..' nel percorso dei file
$file_old =~ m|\/\.\.| && return {error => "file_old malformed"};
$file_new =~ m|\/\.\.| && return {error => "file_new malformed"};
$base_dir =~ s|/$||;
$file_old =~ s|^/||;
$file_new =~ s|^/||;
# verifico che il nome non contenga caratteri proibiti, altrimenti li converto in '_'
$file_new =~ s/[\*<>#\?\\'"]/_/g;
-e "$base_dir/$file_old" || return {name => $file_old, error => "file/dir non esistente"};
my $Files_Trash_dir = $r->dir_config('Files_Trash_dir');
$file_new eq $Files_Trash_dir && return {name => $file_new, error => "nome riservato al cestino"};
if($file_new =~ m/^\.$Files_Trash_dir\//){
if(-e "$base_dir/$file_new"){
# aggiungo un suffisso per non sovrascrivere il file/dir presente nel cestino
my $suff = 1;
while(-e "$base_dir/$file_new.$suff"){
$suff++;
}
$file_new .= ".$suff";
}
}else{
-d "$base_dir/$file_new" && return {name => $file_new, error => "esiste già una cartella con quel nome"};
}
-e "$base_dir/$file_new" && return {name => $file_new, error => "esiste già un file/link con quel nome"};
# separo il nome dal percorso della cartella (es '/my/dir/file' => '/my/dir/' 'file' -- 'file' => '' 'file')
my $name_old = $file_old; $name_old =~ s|^.*/||;
my $dir_old = $file_old; $dir_old =~ s|[^/]*$||;
my $name_new = $file_new; $name_new =~ s|^.*/||;
my $dir_new = $file_new; $dir_new =~ s|[^/]*$||;
if($dir_new =~ m/\.$Files_Trash_dir\// && !-d "$base_dir/$dir_new"){
make_path "$base_dir/$dir_new" || return {name => $file_new, error => "creando cartella $dir_new"};
}
-d "$base_dir/$dir_new" || return {name => $dir_new, error => "la cartella non esiste"};
-e "$base_dir/$dir_new.$name_new" && return {name => $file_new, error => "sono presenti delle versioni del file"};
my $op = $dir_old eq $dir_new ? "rinominando $name_old in $name_new" : "spostando $file_old in $file_new";
if(-l "$base_dir/$file_old"){
# sposto/rinomino la cartella associata al file
-d "$base_dir/$dir_old.$name_old" || return {name => $file_old, error => "manca la cartella delle versioni"};
# recupero il numero della versione
my $version_name = readlink("$base_dir/$file_old") || return {name => $file_old, error => "lettura del link: $!"};
$version_name =~ s|.*/||;
my(undef, $version, undef, undef) = split /\./, $version_name, 4;
move("$base_dir/$dir_old.$name_old", "$base_dir/$dir_new.$name_new") || return {error => "$op: $!"};
if($name_old eq $name_new){
# sposto il link
move("$base_dir/$file_old", "$base_dir/$file_new") || return {error => "$op: $!"};
}else{
# ricreo il link
if(!symlink ".$name_new/$version_name", "$base_dir/$file_new"){
# rimetto history al posto di prima
my $err = "nel creare il link al file $file_new della versione $version: $!";
move("$base_dir/$dir_new.$name_new", "$base_dir/$dir_old.$name_old")
|| return {name => $file_old, error => "$err e ripristinando la cartella delle versioni: $!"};
return {error => $err};
}
if(!unlink("$base_dir/$file_old")){
DB_log('update', $rec_id, { 'ARC.' => "$file_new:$version" }, { 'ARC.' => "$file_old:$version" });
return {name => $file_old, info => "nel cancellare il link alla versione: $!"};
}
}
DB_log('update', $rec_id, { 'ARC.' => "$file_new:$version"}, { 'ARC.' => "$file_old:$version"});
}else{
if(-d "$base_dir/$file_old"){
$file_old .= '/';
$file_new .= '/';
}
# sposto il file/dir
move("$base_dir/$file_old", "$base_dir/$file_new") || return {error => "$op: $!"};
# se ho spostato/cambiato nome a una cartella nel Log si comprende che era una cartella se i nomi terminano con '/'
DB_log('update', $rec_id, { 'ARC.' => $file_new}, { 'ARC.' => $file_old});
}
return undef;
}
</%perl>
 
<%method archive_put>\
<%args>
$Base
$path
$rec_id
$obj_id
$obj_new_id
$obj_name
$obj_new_name
</%args>
<%perl>
#DEBUG print STDERR Dumper(\%ARGS);
# modifica del nome o creazione di una cartella?
my $mess = $m->comp('SELF:archive_check', %ARGS, permission => 'Update');
if(!$mess){
my $base_dir = $r->dir_config('InputFilesArchive')."/$Base/$rec_id";
my $test = '/'.$path;
$test =~ m|\/\.\.| && return {error => "path malformed"};
$test = '/'.$obj_name;
$test =~ m|\/\.\.| && return {error => "obj_id malformed"};
$test = '/'.$obj_new_name;
$test =~ m|\/\.\.| && return {error => "obj_new_name malformed"};
$obj_id =~ m|\/\.\.| && return {error => "obj_id malformed"};
$obj_new_id =~ m|\/\.\.| && return {error => "obj_new_id malformed"};
my $file = "$base_dir/$path";
my $filename = $obj_id;
$filename =~ s|^.*/||;
if($obj_new_name){
### CREATE DIR
# 'obj_new_name' => 'NUOVA',
# 'table' => 'apparecchiature',
# 'schema' => 'impianti',
# 'rec_id' => '31173',
# 'obj_new_id' => undef,
# 'obj_id' => '/test/NUOVA',
# 'path' => 'test/NUOVA',
# 'obj_name' => undef,
if("$path" eq '.'.$r->dir_config('Files_Trash_dir')){
$mess = { name => $obj_new_id, error => "Nome riservato al cestino"};
}elsif(-d "$base_dir/$path"){
$mess = { name => $path, error => "Esiste già una cartella con quel nome"};
}elsif(-e $base_dir.'/'.$path){
$mess = { name => $path, error => "Esiste già un file/link con quel nome"};
}elsif(!make_path $base_dir.'/'.$path){
$mess = { name => $path, error => "Errore nella creazione della cartella: $!"};
}
$path .= '/';
DB_log('update', $rec_id, { 'ARC.' => $path }, { 'ARC.' => undef });
}else{
if($obj_new_id){
### MOVE
# 'obj_new_name' => undef,
# 'table' => 'apparecchiature',
# 'schema' => 'impianti',
# 'rec_id' => '31173',
# 'obj_new_id' => '/test/readme.html',
# 'obj_id' => '/readme.html',
# 'path' => 'readme.html',
# 'obj_name' => 'readme.html',
# muovi
if($path eq '.'.$r->dir_config('Files_Trash_dir')){
$mess = { name => $path, error => "Il cestino non si può spostare"};
}else{
$mess = move_file_archive $Base, $rec_id, $obj_id, $obj_new_id;
}
}else{
# RENAME
#'rec_id' => '31173',
#'obj_new_id' => undef,
#'obj_id' => '/oldname',
#'path' => 'oldname',
#'obj_name' => 'NEWNAME',
#'table' => 'apparecchiature',
#'schema' => 'impianti',
#'obj_new_name' => undef,
if($path eq '.'.$r->dir_config('Files_Trash_dir')){
$mess = { name => $path, error => "Il cestino non si può rinominare"};
}else{
# rinomino il file e il relativo archivio storico
my $obj_new_id = $obj_id;
$obj_new_id =~ s|[^/]*$||;
$obj_new_id .= $obj_name;
$mess = move_file_archive $Base, $rec_id, $obj_id, $obj_new_id;
}
}
}
}
$m->out($mess ? JSON::objToJson($mess) : '{}');
$Session{Dbh}->commit;
</%perl>
</%method>
 
<%method archive_delete>\
<%args>
$Base
$rec_id
$path
</%args>
<%perl>
#DEBUG print STDERR Dumper(\%ARGS);
my $mess = $m->comp('SELF:archive_check', %ARGS, permission => 'Delete');
if(!$mess){
my $test = '/'.$path;
my $base_dir = $r->dir_config('InputFilesArchive')."/$Base/$rec_id";
my $file = "$base_dir/$path";
my $Files_Trash_dir = $r->dir_config('Files_Trash_dir');
if($test =~ m|\/\.\.|){
$mess = {error => "path malformed"}
}elsif(! -e $file){
$mess = { name => $path, info => "file o cartella inesistente"};
}elsif(-d $file){
if($file !~ m/\/$/){
$file .= '/';
}
if($path =~ m/^\.$Files_Trash_dir/){
# svuoto il cestino
if(remove_tree $file){
$path .= '/';
DB_log 'update', $rec_id, { 'ARC.' => undef }, { 'ARC.' => $path };
}else{
$mess = { name => $path, error => "cancellazione cartella: $!"};
}
}else{
$mess = move_file_archive $Base, $rec_id, $path, ".$Files_Trash_dir/$path";
}
}else{
if($path =~ m/^\.$Files_Trash_dir/){
# svuoto il cestino
if(unlink $file){
DB_log 'update', $rec_id, { 'ARC.' => undef }, { 'ARC.' => $path };
# cancello anche la cartella delle versioni (se presente)
my $name = $file; $name =~ s|^.*/||;
my $subdir = $file; $subdir =~ s|[^/]*$||;
if(-d "$subdir/.$name"){
if(!remove_tree "$subdir/.$name"){
$mess = { name => $path, error => "cancellazione della cartella delle versioni: $!"};
}
}
}else{
$mess = { name => $path, error => "cancellazione file: $!"};
}
}else{
$mess = move_file_archive $Base, $rec_id, $path, ".$Files_Trash_dir/$path";
}
}
}
#DEBUG print STDERR "DELETED $Base:$rec_id $path\n";
$m->out($mess ? JSON::objToJson($mess) : '{}');
$Session{Dbh}->commit;
</%perl>
</%method>
 
<%method archive_history>
<%args>
$Base
$rec_id
$obj_id
$new_ver => undef
$edit => undef
</%args>
<%perl>
$Session{StatusCode} = 200;
if(my $err = $m->comp('SELF:archive_check', %ARGS, permission => $edit ? 'Update' : 'Select')){
die $err->{error}."\n";
}
$obj_id =~ m|\/\.\.|s && die "obj_id malformed\n";
$new_ver =~ m/^\d*$/ || die "new_ver malformed\n";
my $base_dir = $r->dir_config('InputFilesArchive')."/$Base/$rec_id";
my $file = "$base_dir$obj_id";
-e $file || die "File/dir $obj_id inesistente\n";
if(-l $file){
my $name = $obj_id; $name =~ s|^.*/||;
my $dir = $obj_id; $dir =~ s|[^/]*$||;
my $v_dir = "$base_dir$dir/.$name";
if(!-d $v_dir){
die "Cartella delle versioni non presente\n";
}
# versione corrente
my $v_name_curr = readlink $file;
$v_name_curr =~ s/.*\///;
my(undef, $ver_curr, undef, undef) = split /\./, $v_name_curr, 4;
opendir (DIR, $v_dir) || die "opendir: $!";
$m->out('<table class="Files_table_history"><tr><th>Ver.</th><th>Data</th><th>Utente</th></tr>');
my %entries;
my %users;
while(my $v_name = readdir(DIR)){
next if($v_name =~ /^\./);
my($date, $ver, $userid, $hash) = split /\./, $v_name, 4;
if($new_ver && $ver eq $new_ver){
# cambio la versione corrente
unlink $file || die "unlink: $!";
symlink ".$name/$v_name", $file || die "link ver. $new_ver: $!";
$ver_curr = $new_ver;
}
$entries{$ver} = $v_name;
if($userid){
$users{$userid} = "id: $userid";
}
}
# recupero i dati anagrafici degli utenti
my $elenco_id = join(',', keys(%users));
if($elenco_id){
my $sth_users = ExecQuery("Get users", undef, qq{
select id, coalesce(nome || ' ', '') || coalesce(cognome, '') as nominativo
from public.anagrafiche
where id in ($elenco_id);
});
while(my $user = $sth_users->fetchrow_hashref){
$users{$user->{id}} = $user->{nominativo};
}
}
# tabella versioni da postare all'utente
for my $version (sort {$b <=> $a} keys %entries){
my($date, $ver, $userid, $hash) = split /\./, $entries{$version}, 4;
$date =~ s/_/ /;
my $curr = ($new_ver || $ver_curr ) eq $ver;
my $curr_class = $curr ? ' class="Files_current"' : '';
my $button = !$edit || $curr ? '' : qq{<button class="Files_button" onClick="Input_Files_TreeNodeObj.set_new_version('$ver');">Set</button>};
$m->out("<tr".($curr_class)."><td>$ver $button</td><td>$date</td> <td>$users{$userid}</td></tr>");
}
closedir(DIR);
if($new_ver && $ver_curr ne $new_ver){
$m->out(qq{<tr><td colspan="3" class="Files_alert">ATTENZIONE:<br> Versione richiesta ($new_ver) inesistente</td></tr>});
}
$m->out("</table>");
}elsif(-f $file){
$m->out("<pre>Non è presente l'archivio delle versioni</pre>");
}elsif(-d $file){
###DIR
}else{
die "unexpected typeof $obj_id\n";
}
</%perl>
</%method>
 
<%method archive_post>
% $Session{StatusCode} = 500;
% die "POST is not provided";
</%method>
 
%##################################################### metodi utilizzati da /dbms
 
%# genera il tag che contiene il tracciato XML
<%method XML_PATH>\
<%args>
$close => 0
$start => undef
$rows => undef
$max_rows => undef
</%args>
% if($close){
</<%$Session{ARGS}{xml_path}%>>\
% }else{
% my $sth = $Session{Dbh}->prepare('select now();');
% $sth->execute;
% my $timestamp = $sth->fetchrow_arrayref->[0];
<<%$Session{ARGS}{xml_path}%> method="<%$Session{ARGS}{method}%>" user="<%$Session{Login}%>" timestamp="<%$timestamp%>"\
% if(defined $start){
start="<%$start%>" rows="<%$rows%>" max_rows="<%$max_rows%>"\
% }
>\
% }
</%method>
 
%##################################################### keyname
<%method keyname>\
<?xml version="1.0" encoding="utf-8"?>
<& SELF:XML_PATH &>
<%perl>
# se abilitato ...
my $permission = Permission($ARGS{PermissionGroup});
my $keyname = $m->scomp('SELF:KEY');
if($keyname =~ m/\.(.*)$/){
$keyname = $1;
}
</%perl>
<<%$ARGS{name}%> keyname="<%$keyname|xml%>" />
<& SELF:XML_PATH, close => 1 &>
</%method>
 
%##################################################### info
<%method info>\
<?xml version="1.0" encoding="utf-8"?>
<& SELF:XML_PATH &>
<%perl>
# se abilitato ...
my $permission = Permission($ARGS{PermissionGroup});
my $keyname = $m->scomp('SELF:KEY');
if($keyname =~ m/\.(.*)$/){
$keyname = $1;
}
</%perl>
<<%$ARGS{name}%> keyname="<%$keyname|xml%>"\
% # elenco dei permessi
% foreach my $perm (keys %{$permission}){
<%lc $perm%>="<%$permission->{$perm}%>"\
% }
% # tabella padre
father_name="<& SELF:FATHER_NAME &>"\
% # campo che collega la tabella padre
father_id_name="<& SELF:FATHER_ID_NAME &>"\
% # nome del campo chiave del padre
father_key_name="<& SELF:FATHER_KEY_NAME &>"\
>
<%perl>
my @names = &Method2Array('FIELDS');
unshift @names, $keyname;
foreach my $name (@names){
$name =~ s/^.*\.//;
my $info = $m->comp('SELF:INFO', NAME => $name);
delete $info->{FIND_DESCR};
delete $info->{PRIMARY_KEY} if(!$info->{PRIMARY_KEY});
delete $info->{HIDDEN};
delete $info->{FIND};
delete $info->{NOTNULL} if(!$info->{NOTNULL});
delete $info->{DECIMAL} if(!$info->{DECIMAL});
$info->{DESCR} =~ s|[\\/]$||;
$info->{TYPE} =~ s| varying||;
</%perl>
<field\
% foreach my $key (keys %{$info}){
<%lc $key%>="<%$info->{$key}|xml%>"\
% }
/>
% }
<%perl>
my %entity_children = method2hash('ENTITY_CHILDREN');
foreach my $key (keys %entity_children){
my($table, $keyname) = split /\s*\:\s*/, $entity_children{$key}, 2;
</%perl>
<child field="<%$key|xml%>" table="<%$table|xml%>" key="<%$keyname|xml%>" />
<%perl>
}
my %entity_relations = method2hash('ENTITY_RELATIONS');
foreach my $key (keys %entity_relations){
my($table, $keyname) = split /\s*\:\s*/, $entity_relations{$key}, 2;
</%perl>
<relation field="<%$key|xml%>" table="<%$table|xml%>"<%$keyname ? ' key="'.$keyname.'"' : ''%> />
% }
</<%$ARGS{name}%>>
<& SELF:XML_PATH, close => 1 &>
</%method>
 
%##################################################### newkey
<%method newkey>\
<%perl>
my $rest = $ARGS{envelope_response} eq 'rest';
if($rest){
# The status code used in case of error
$Session{StatusCode} = 400;
}
if(!$rest && !$ARGS{no_xml_header}){
</%perl>
<?xml version="1.0" encoding="utf-8"?>
<& SELF:XML_PATH &>
<%perl>
}
# se abilitato all'inserimento
my $permission = Permission($ARGS{PermissionGroup});
if(!$permission->{Insert}){
die "No insert permission\n";
}
my $keyname = $m->scomp('SELF:KEY');
if($keyname =~ m/\.(.*)$/){
$keyname = $1;
}
# ritorna una nuova chiave utilizzabile per l'inserimento
my $serial_seq = $m->scomp('SELF:SERIAL_SEQ');
my $sth = $Session{Dbh}->prepare('select nextval(?);');
$sth->execute($serial_seq);
my $new_key = $sth->fetchrow_arrayref->[0];
$Session{Dbh}->commit;
if($rest){
$m->out(to_json({ key => $new_key, keyname => $keyname }));
}else{
</%perl>
<<%$ARGS{name}%> key="<%$new_key|xml%>" keyname="<%$keyname|xml%>" />
<& SELF:XML_PATH, close => 1 &>
% }
</%method>
 
%##################################################### delete
<%method delete>\
<%perl>
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
my $rest = $ARGS{envelope_response} eq 'rest';
if($rest){
# The status code used in case of error
$Session{StatusCode} = 400;
}else{
</%perl>
<?xml version="1.0" encoding="utf-8"?>
<& SELF:XML_PATH &>
<%perl>
}
# se abilitato alla cancellazione
my $permission = Permission($ARGS{PermissionGroup});
if(!$permission->{Delete}){
die "No delete permission\n";
}
if(!length $ARGS{key_list}){
die "No key param\n";
}
if($ARGS{key_list} =~ m/,/){
die "No multiple key in param key\n";
}
$sth = ExecQuery('records t delete', 'SELF:RECORDS', WHERE => SqlSelectWhere(\%ARGS));
my $rec = $sth->fetchrow_arrayref;
my $record_id = $rec ? $rec->[0] : undef;
if(!defined $record_id){
die "No record retrieve or record not exists\n";
}
# verifico se il record può essere letto (altrimenti non è concesso di poterlo cancellare)
# N.B. SqlSelectWhere controlla anche i diritti di accesso al padre, se definito
my %params; # per il passaggio di parametri tra PRE_DELETE DELETE POST_DELETE e POST_NO_DELETE
# eseguo il metodo di pre delete se dichiarato nel metodo ___.mql
if($m->base_comp->method_exists('PRE_DELETE')){
$m->scomp('SELF:PRE_DELETE', KEY => $record_id, PARAMS => \%params);
}
my $sth = ExecQuery('delete', 'SELF:DELETE', KEY => $record_id, PARAMS => \%params);
if($sth){
if($sth->rows != 1){
die 'Delete record return '.$sth->rows." rows\n";
}
# log cancellazione record
DB_log('delete', $record_id, undef);
# eseguo il metodo di post delete se dichiarato nel metodo ___.mql
if($m->base_comp->method_exists('POST_DELETE')){
$m->scomp("SELF:POST_DELETE", KEY => $record_id, PARAMS => \%params);
}
}elsif($m->base_comp->method_exists('POST_NO_DELETE')){
$m->scomp("SELF:POST_NO_DELETE", KEY => $record_id, PARAMS => \%params);
}
if($Session{Dbh}->commit){
# notifico la cancellazione dei record
</%perl>
<<%$ARGS{name}%> key="<%$record_id|xml%>" />
% }else{
% die 'SQL error: '.DBI::errstr;
% }
% if(!$rest){
<& SELF:XML_PATH, close => 1 &>
% }else{
% # The status code used in case of normal exit
% $Session{StatusCode} = 204;
% $r->status(204);
% }
</%method>
 
%##################################################### numrec
<%method numrec>\
<?xml version="1.0" encoding="utf-8"?>
<& SELF:XML_PATH &>
<%perl>
# se abilitato ...
my $permission = Permission($ARGS{PermissionGroup});
if(!$permission->{Select}){
die "No retrieve permission\n";
}
my $sth = ExecQuery('numrec', 'SELF:NUMREC', WHERE => SqlSelectWhere(\%ARGS));
my $numrec=$sth->fetchrow_arrayref->[0];
</%perl>
<<%$ARGS{name}%> numrec="<%$numrec%>" />
<& SELF:XML_PATH, close => 1 &>
</%method>
 
%##################################################### retrieve
<%method retrieve>\
<%perl>
my $rest = $ARGS{envelope_response} eq 'rest';
if($rest){
# The status code used in case of error
$Session{StatusCode} = 400;
}
if(!$rest && !$ARGS{no_xml_header}){
$m->out(qq{<?xml version="1.0" encoding="utf-8"?>\n});
}
# se abilitato alla lettura
my $permission = Permission($ARGS{PermissionGroup});
#DEBUG print STDERR "permission ".Dumper($permission);
if(!$permission->{Select}){
die "No retrieve permission\n";
}
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
# $Params{orderby}='id';
$sth = SqlSelect('SELECT', 'ENTITY_FIELDS', \%ARGS);
my $KEY = $m->scomp('SELF:KEY');
# i nomi dei campi risultato della query
my $query_names = $sth->{NAME};
my $base_comp = $m->base_comp;
if($rest){ # rispondo in formato JSON
$r->headers_out->{'Content-Range'} = 'items '.$SQL{START}.'-'.($SQL{START}+$SQL{ROWS}-1).'/'.$SQL{MAX_ROWS};
$m->out('[');
my $rec_sep="\n";
while(my $row = $sth->fetchrow_hashref){
if($base_comp->method_exists('OUT_FILTER')){
$row = $base_comp->call_method('OUT_FILTER', row => $row);
}
if($row){
my %out_row;
my $id = $row->{$query_names->[0]};
for(my $i=0; $i<@$query_names; $i++){
my $key = $query_names->[$i];
my($val, undef) = Call_OutFieldFilter($key, $id, $row->{$key}, $query_names, $row, $base_comp, 1);
if(defined $val){
$out_row{$key} = $val;
}
}
$m->out($rec_sep.to_json(\%out_row));
$rec_sep = ",\n";
}
}
$m->out("\n]");
}else{ # rispondo in formato XML
if(!$ARGS{no_xml_header}){
$m->comp('SELF:XML_PATH', start => $SQL{START}, rows => $SQL{ROWS}, max_rows => $SQL{MAX_ROWS});
}
while (my $row=$sth->fetchrow_hashref){
if($base_comp->method_exists('OUT_FILTER')){
$row = $base_comp->call_method('OUT_FILTER', row => $row);
}
my %children;
if($row){
$m->out("<$ARGS{name} ");
my $id = $row->{$query_names->[0]};
for(my $i=0; $i<@$query_names; $i++){
my $key = $query_names->[$i];
my($val, undef) = Call_OutFieldFilter($key, $id, $row->{$key}, $query_names, $row, $base_comp, 1);
if(ref $val eq 'ARRAY'){
# presumo ci sia un array di hash o di scalari
$children{$key} = $val;
}elsif(defined $val){
$m->out(qq{$key="}.$m->interp->apply_escapes($val, 'xml').qq{" });
}
}
if(%children){
$m->out(">\n");
foreach my $key (keys %children){
foreach my $subrec (@{$children{$key}}){
$m->out("<$key ");
if(ref $subrec eq 'HASH'){
foreach my $subkey (keys %{$subrec}){
$m->out(qq{$subkey="}.$m->interp->apply_escapes($subrec->{$subkey}, 'xml').qq{" });
}
$m->out('/>');
}else{
$m->out(">$subrec</$key>");
}
}
}
$m->out("</$ARGS{name}>");
}else{
$m->out("/>\n");
}
}
}
if(!$ARGS{no_xml_header}){
$m->comp('SELF:XML_PATH', close => 1);
}
}
if($rest){
# The status code used in case of normal exit
$Session{StatusCode} = undef;
}
</%perl>
</%method>
 
%##################################################### update
<%method update>\
% my $rest = $ARGS{envelope_response} eq 'rest';
% if(!$rest){
<?xml version="1.0" encoding="utf-8"?>
<& SELF:XML_PATH &>
% }
<%perl>
if($rest){
# The status code used in case of error
$Session{StatusCode} = 400;
}
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
# se abilitato ...
my $permission = Permission($ARGS{PermissionGroup});
if(!$permission->{Update}){
die "No update permission\n";
}
if(!length $ARGS{key_list}){
die "No key param\n";
}
if($ARGS{key_list} =~ m/,/){
die "No multiple key in param key\n";
}
my @keynames;
my $keyname = $m->scomp('SELF:KEY');
$keyname =~ s/^\s+\|\s+$//;
push @keynames, $keyname;
if($keyname =~ m/\.(.*)$/){
unshift @keynames, $1;
}
my $fields;
if($rest){
# parsing JSON
my $rows = from_json($ARGS{content});
# $fields = $rows->{params};
$fields = $rows;
# die "NOT IMPLEMENTED";
}else{
my $xml_simple = new XML::Simple(
keyattr => \@keynames,
RootName => $ARGS{xml_path},
xmldecl => '<?xml version="1.0" encoding="utf-8"?>',
);
if($ARGS{content} !~ m|<dbms>.*</dbms>\s*$|is){
die "Malformed xml content: no <dbms> tag\n";
}
my $data = $xml_simple->XMLin($ARGS{content});
$fields = $data->{$ARGS{name}};
$ARGS{father_id_update} = $ARGS{father_id};
}
# trasformo la hash in un array
my @update;
# chiave del record
push @update, $ARGS{key_list};
# elenco dei nomi dei campi
my @names = &Method2Array('FIELDS');
for(my $I=0; $I<@names; $I++){
my $name = $names[$I];
my $val = $fields->{$name};
push @update, defined $val ? $val : undef;
}
my @update_list = (\@update);
my $id_list = Array2UpdateSql(\@update_list, \%ARGS);
if(@{$id_list}){
$m->comp('SELF:retrieve', %ARGS, key_list => $id_list->[0], no_xml_header => 1);
}
if($rest){
# The status code used in case of normal exit
$Session{StatusCode} = undef;
}else{
</%perl>
<& SELF:XML_PATH, close => 1 &>
% }
</%method>
 
%##################################################### create
<%method create>\
<%perl>
my $rest = $ARGS{envelope_response} eq 'rest';
if($rest){
# The status code used in case of error
$Session{StatusCode} = 400;
}else{
</%perl>
<?xml version="1.0" encoding="utf-8"?>
<& SELF:XML_PATH &>
<%perl>
}
# se abilitato ...
my $permission = Permission($ARGS{PermissionGroup});
if(!$permission->{Insert}){
die "No insert permission\n";
}
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
my @keynames;
my $keyname = $m->scomp('SELF:KEY');
$keyname =~ s/^\s+\|\s+$//;
push @keynames, $keyname;
if($keyname =~ m/\.(.*)$/){
unshift @keynames, $1;
}
my $fields;
if($rest){
# parsing JSON
my $rows = from_json($ARGS{content});
$fields = $rows->{params};
}else{
my $xml_simple = new XML::Simple(
keyattr => \@keynames,
RootName => $ARGS{xml_path},
xmldecl => '<?xml version="1.0" encoding="utf-8"?>',
);
if($ARGS{content} !~ m|<dbms>.*</dbms>\s*$|is){
#DEBUG $PLogger->debug(sub{ "ARGS=$ARGS{content}"});
die "Malformed xml content: no <dbms> tag\n";
}
my $data = $xml_simple->XMLin($ARGS{content});
$fields = $data->{$ARGS{name}};
}
# trasformo la hash in un array
my @insert;
# chiave del record (array) per l'inserimento con chiave fornita
push @insert, $ARGS{key_list} ? [$ARGS{key_list}] : undef;
# elenco dei nomi dei campi
my @names = &Method2Array('FIELDS');
for(my $I=0; $I<@names; $I++){
my $name = $names[$I];
if($name =~ m/\.(\w+)$/){
# campo definito completo di nome della tabella
my $name_field = $1;
# se non esiste il campo con nome completo di tabella ma è definito senza, utilizzo quest'ultimo
if(!exists $fields->{$name} && exists $fields->{$name_field}){
$fields->{$name} = $fields->{$name_field};
}
}
my $val = $fields->{$name};
if($name eq $keyname && length $ARGS{key_list}){
# inserisco la chiave dichiarata nella URL
push @insert, $ARGS{key_list};
}else{
push @insert, defined $val ? $val : undef;
}
}
my @insert_list = (\@insert);
my $id_list = Array2UpdateSql(\@insert_list, \%ARGS);
if(@{$id_list}){
$m->comp('SELF:retrieve', %ARGS, key_list => $id_list->[0], no_xml_header => 1);
}
if($rest){
# The status code used in case of normal exit
$Session{StatusCode} = undef;
}else{
</%perl>
<& SELF:XML_PATH, close => 1 &>
% }
</%method>
%##################################################### metodi utilizzati da /dbms - END
 
%##################################################### xml
<%method xml>\
<& SELF:XML_PATH &>
<%perl>
# se abilitato alla cancellazione
my $permission = Permission();
if($permission->{Select}){
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
$sth = SqlSelect('SELECT', 'ENTITY_FIELDS', \%ARGS);
my $KEY = $m->scomp('SELF:KEY');
# i nomi dei campi risultato della query
my $query_names = $sth->{NAME};
my $base_comp = $m->base_comp;
while (my $row = $sth->fetchrow_hashref){
if($base_comp->method_exists('OUT_FILTER')){
$row = $base_comp->call_method('OUT_FILTER', row => $row);
}
if($row){
</%perl>
<<%$ARGS{name}%> \
<%perl>
my $id = $row->{$query_names->[0]};
for(my $i=1; $i<@$query_names; $i++){
my $key = $query_names->[$i];
my($val, undef) = Call_OutFieldFilter($key, $id, $row->{$key}, $query_names, $row, $base_comp, 1);
</%perl>
<%$key%>="<%$val|xml%>" \
% }
/>
% }
% }
% }
<& SELF:XML_PATH, close => 1 &>
</%method>
 
 
%##################################################### xml_tree
 
<%method ENTITY_RELATIONS></%method>
 
<%method ENTITY_CHILDREN></%method>
 
<%method ENTITY_FIELDS><& SELF:SELECT_FIELDS &></%method>
 
<%method xml_tree>\
<%args>
$myxml => undef
$header => 1
$name
</%args>
<%perl>
use XML::Simple;
my $name_xml = $name;
$name_xml =~ s/\//\./gs;
if($name_xml !~ m/\./){
my $schema = $m->scomp('SELF:SCHEMA');
$name_xml = "$schema.$name_xml";
}
my $xml_op = new XML::Simple(keyattr => ['id'],
RootName => $ARGS{xml_path},
xmldecl => '<?xml version="1.0" encoding="utf-8"?>' );
my %relations;
#DEBUG $PLogger->debug(sub{ 'XML_TREE_'x10, Dumper(\%ARGS), 'xml_tree_'x10; });
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
my $sth = SqlSelect('SELECT', 'ENTITY_FIELDS', \%ARGS);
#DEBUG $PLogger->debug(sub{ 'XML_TREE NUMERO RIGHE DA PROCESSARE:',$sth->rows; });
if($header){
$m->clear_buffer;
}
my %entity_relations = method2hash('ENTITY_RELATIONS');
my %entity_children = method2hash('ENTITY_CHILDREN');
#DEBUG $PLogger->debug(sub{ "NAME:$name \nRELATIONS:".Dumper(\%entity_relations).'CHILDREN:'.Dumper(\%entity_children) });
my $DataBaseUrl = $r->dir_config('DataBaseUrl');
while (my $row = $sth->fetchrow_hashref){
foreach my $key (keys %entity_relations){
if(length($row->{$key})){
$relations{$entity_relations{$key}.'|'.$row->{$key}}=1;
}
}
foreach my $key ( keys %$row ){
$_ = $row->{$key};
s/^\s+//;
s/\s+$//;
s/\\/\\\\/g;
s/\t/\\t/g;
s/\n/\\n/g;
if (length($_)) {
$myxml->{$name_xml}->{$row->{"id"}}->{$key} = $_;
}
}
foreach my $key (keys %entity_children){
#DEBUG $PLogger->debug(sub{ "##### entity_child '$key' '$entity_children{$key}'"; });
if(length($row->{$key})){
my($table, $keyname) = split /\s*\:\s*/, $entity_children{$key}, 2;
if(!$keyname){
$keyname = $m->scomp('SELF:KEY_NAME');
}
my $KEY = $row->{$key};
#DEBUG $PLogger->debug(sub{"key:$KEY table:$table keyname:$keyname"; });
#DEBUG $PLogger->debug(sub{ "###################################### $table.mql:CHILDREN"; });
my $child = $m->fetch_comp("$DataBaseUrl/$table.mql") || die("No table $table.mql\n");
# fornisco il parametro father_id solo se la tabella figlia ha come padre l'oggetto corrente
my $father_name = $child->scall_method('FATHER_NAME');
my $father_id_name = $child->scall_method('FATHER_ID_NAME');
my $father_id;
if($father_name && ($father_name eq $name_xml) && $father_id_name eq $keyname){
$father_id = $KEY;
}
#DEBUG $PLogger->debug(sub{ "name:$name_xml child:$table key:$KEY keyname:$keyname father_id:$father_id, father_name:$father_name father_id_name:$father_id_name\n" });
$m->comp("$DataBaseUrl/$table.mql:xml_tree",
%ARGS,
start => undef,
rows => undef, # tutti i record
key_list => undef,
father_id => $father_id,
name => $table,
json_where => to_json({ $keyname => ['=', $KEY] }),
header => undef,
myxml => $myxml
);
}
}
}
#### Inserisco dati ENTITY_RELATIONS
foreach my $key (sort keys %relations){
#DEBUG $PLogger->debug(sub{ 'RELATIONS_'x6, Dumper(\%relations), 'relations_'x6; });
my($table_keyname, $KEY) = split /\|/, $key, 2;
my($table, $keyname) = split /\s*\:\s*/, $table_keyname, 2;
if(!$keyname){
$keyname = 'id';
}
#DEBUG print STDERR "name:$name_xml child:$table key:$KEY keyname:$keyname\n";
$m->comp("$DataBaseUrl/$table.mql:xml_tree",
%ARGS,
name => $table,
json_where => to_json({ $keyname => ['=', $KEY] }),
rows => '1', # un solo record
start => undef,
father_id => undef,
key_list => undef,
header => undef,
myxml => $myxml
);
}
if($header){
$m->clear_buffer;
$m->out($xml_op->XMLout($myxml));
}
</%perl>
</%method>
 
%##################################################### txt
<%method txt>\
<%perl>
my $sth = SqlSelect('SELECT', 'SELECT_FIELDS', \%ARGS);
$m->out(join("\t", @{$sth->{NAME}}), "\n");
while(my $row = $sth->fetchrow_arrayref){
map {
s/\t/\\t/sg;
s/\n/\\n/sg;
s/\r/\\r/sg;
} @{$row};
$m->out(join("\t", @{$row}), "\n");
}
</%perl>
</%method>
 
%##################################################### xls
<%method xls>\
<%perl>
my $permission = Permission('Xls');
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
 
use Spreadsheet::WriteExcel;
# mi assicuro che non venga utilizzata la cache per le query
$ARGS{RecordsetCache} = undef;
my $sth = SqlSelect('SELECT_XLS', 'SELECT_XLS_FIELDS', \%ARGS);
 
# creazione nuovo spreadsheet
my $file_xls = $r->dir_config('TmpDir')."/file_excel.$$.xls";
my $workbook = Spreadsheet::WriteExcel->new($file_xls);
my $worksheet = $workbook->add_worksheet();
# individuo i tipi delle colonne
my @types;
if($m->base_comp->method_exists('TYPE_FIELDS_XLS')){
# elenco tipi definito
@types = &Method2Array('TYPE_FIELDS_XLS');
}else{
# ricavo l'elenco dai tipi campo del database
foreach my $name (@{$sth->{NAME}}){
my $type = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'TYPE');
if($type =~ m/int/i || $type =~ m/real/i || $type =~ m/bool/i || $type =~ m/num/i || $type =~ m/numeric/i){
push @types, 'number';
}elsif($type =~ m/dat/i || $type =~ m/time/i){
push @types, 'date';
}else{
push @types, 'string';
}
}
}
for(my $col=0; $col<@{$sth->{NAME}}; $col++){
my $type = $types[$col];
if($type eq 'number'){
$worksheet->set_column($col, $col, 8);
}elsif($type eq 'date'){
$worksheet->set_column($col, $col, 11);
}elsif($type eq 'string'){
$worksheet->set_column($col, $col, 20);
}else{ # auto
$worksheet->set_column($col, $col, 10);
}
}
# intestazioni
# formato di stampa dell'intestazione dei campi
my $format_int = $workbook->add_format();
#$format_int->set_text_wrap();
$format_int->set_bold();
$format_int->set_align('center');
$format_int->set_align('vcenter');
$worksheet->write_row(0, 0, $sth->{NAME}, $format_int);
# formato di stampa delle righe dei dati
$worksheet->keep_leading_zeros();
my $string_format = $workbook->add_format();
$string_format->set_text_wrap();
 
# formato di stampa delle date
my $date_format = $workbook->add_format(num_format => 'dd/mm/yyyy');
my $date_time_format = $workbook->add_format(num_format => 'dd/mm/yyyy hh:mm:ss');
my $timestamp_format = $workbook->add_format(num_format => 'dd/mm/yyyy hh:mm:ss.sss');
 
# appendo tutte le righe del dataset
# righe del foglio elettronico
my $row=1;
while(my $columns = $sth->fetchrow_arrayref){
my $col = 0;
foreach my $column (@{$columns}){
if(defined $column){
my $type = $types[$col];
if(!defined $type || $type eq 'auto'){
if($column =~ m/^\s*\d+[.,]*\d*$/){
$worksheet->write_number($row, $col, $column);
}else{
# verifico se si tratta di una data
my($date, $dformat) = dateXls($column);
if(defined $dformat){
$worksheet->write_date_time($row, $col, $date, ($date_format, $date_time_format, $timestamp_format)[$dformat]);
}else{
$worksheet->write_string($row, $col, $column, $string_format);
}
}
}elsif($type eq 'number'){
$worksheet->write_number($row, $col, $column);
}elsif($type eq 'date'){
my($date, $dformat) = dateXls($column);
$worksheet->write_date_time($row, $col, $date, ($date_format, $date_time_format, $timestamp_format)[$dformat]);
}else{
$worksheet->write_string($row, $col, $column, $string_format);
}
}
$col++;
}
$row++;
}
 
$workbook->close();
if(-f $file_xls){
sysopen XLS, $file_xls, 'O_RDONLY' || die "sysopen $file_xls: $!";
my $buffer;
# leggo il file generato a blocchi di 64Kbyte
while(my $numchar = sysread XLS, $buffer, 2^16){
if(undef $numchar){
die "sysread $file_xls: $!";
};
$m->out($buffer);
}
close XLS;
}else{
$r->content_type('application/html');
$m->out("ERRORE: il report non ha generato il file XLS")
}
unlink $file_xls || $PLogger->warn("unlink $file_xls: $!");
</%perl>
</%method>
 
%##################################################### pdf
<%method pdf>\
<%perl>
# identifico gli ID in base alle condizioni WHERE indicate
my($GROUP_ID, $report_ids) = SqlSelect2report_id(\%ARGS);
$m->clear_buffer;
if($GROUP_ID){
if(@$report_ids){
# inizializzo la tabella report_id
$m->comp('SELF:PDF', GROUP_ID => $GROUP_ID, report_ids => $report_ids, %ARGS);
}else{
# elenco vuoto
$r->content_type('text/html; charset=utf-8');
$m->out('<br><br><br><p align="center">Elenco vuoto</p>');
}
# cancello l'elenco ...
ExecQuery('delete print group', undef, "delete from public.report_id where group_id = ?", $GROUP_ID);
}else{
$m->comp('SELF:PDF', %ARGS);
}
</%perl>
</%method>
%##################################################### field_check
<%doc>
Metodo chiamato per la verifica del campo
Parametri passati in %ARGS:
$COL colonna nel form
$ROW riga nel form
$KEY chiave del record in modifica (se inserimento sarà uguale a undef)
$VALUE valore del campo da verificare
$PARAM parametri del campo da verificare
$ID_FIELD identificatore del widget nel browser
$FIELD nome del campo (se definito, completo del nome della tabella)
$FATHER_ID chiave del record padre
@VALUES array dei valori nello stesso record del campo da verificare
 
Al metodo specifico <nome_campo>_CHECK vengono passati anche i parametri:
@NAMES array con i nomi dei campi
%VALUES hash con i valori dei campi
</%doc>
<%method field_check>\
<%args>
$FIELD
$ID_FIELD
@VALUES
</%args>\
<%perl>
my $field = $FIELD;
$field =~ s/^\w\.//;
my $comp = Exist_Check($FIELD);
my @names = &Method2Array('FIELDS');
my %values;
for(my $I=0; $I<@names; $I++){
$values{$names[$I]} = $VALUES[$I];
}
$m->clear_buffer;
if($comp){
$m->comp($comp, %ARGS, NAMES => \@names, VALUES => \%values);
}else{
$m->out("Non esiste sul server un metodo per verificare il campo $FIELD di id:$ID_FIELD");
}
</%perl>\
</%method>
%##################################################### table
<%method table>\
% $m->comp('SELF:TABLE', 'rows' => $ARGS{rows});
</%method>
%##################################################### array
<%method array>\
<%perl>
$SQL{DIFF_RECORDS}=0;
if(!$ARGS{recordset}){
$ARGS{recordset} = 'new';
}
# valuto la clausola Where
$ARGS{SelectWhere} = SqlSelectWhere(\%ARGS);
# Predispongo la cache per il recordset
$ARGS{RecordsetCache} = RecordsetCache($ARGS{name}, $ARGS{recordset},
'SELF:NUMREC',
'SELF:RECORDS',
'SELF:FIND_RECORDS',
$ARGS{SelectWhere}); # 'new' oppure 'cache'
if($ARGS{start} < 0){
# devo calcolare la posizione di start in fondo al recordset
$ARGS{start} += $ARGS{RecordsetCache}{Size};
}
if(defined $ARGS{update}){
my $arr = $ARGS{update};
my $data = my_eval($arr);
if($SQL{UPDATE_LIST} = Array2UpdateSql($data, \%ARGS)){
$ARGS{recordsetChanged} = 1;
}
}
#DEBUG $PLogger->debug(sub{ if($SQL{UPDATE_LIST}){ "UPDATE_LIST UPDATE_LIST UPDATE_LIST ", join ',', @{$SQL{UPDATE_LIST}};}; });
if(defined $ARGS{delete}){
if(Array2DeleteSql(\%ARGS)){
$ARGS{recordsetChanged} = 1;
}
}
my $sth = SqlSelect('SELECT', 'SELECT_FIELDS', \%ARGS);
# preparo il codice javascript ...
$m->out("window.db = $ARGS{name};\n");
# i nomi dei campi risultato della query
my $query_names = $sth->{NAME};
# messaggio da visualizzare all'utente
if($ARGS{BrowserAlert}){
</%perl>\
my_alert('<%$ARGS{BrowserAlert}|js%>', 'alert');
 
% }elsif($Session{ARGS}->{BrowserAlert}){
my_alert('<%$Session{ARGS}->{BrowserAlert}|js%>', 'alert');
<%perl>
}
my @names = &Method2Array('FIELDS');
# solo alla prima richiesta invio i parametri di inizializzazione
if($ARGS{initRecordset}){
&Fields_JList('db', \@names, 'FIELDS_NOT_NULL', 'required_fields');
</%perl>\
db.names = [<%ListJscript(\@names, '', 'array2list') %>];
db.descriptions = [<%ListJscript('FIELDS_DESCR', '', 'list') %>];
db.cols = <%$sth->{NUM_OF_FIELDS}-1%>;
% my $print_form = ListJscript('PRINT_FORM', '', 'list');
% # non invio al client l'eventuale password di protezione del report
% $print_form =~ s/,'PROTECT=.*'//;
db.print_form = [<% $print_form %>];
% } #initRecordset
% if($ARGS{initRecordset} or $ARGS{type} eq 'reload'){
db.new_fields = [<%ListJscript('FIELDS_NEW', '', 'list') %>];
db.dup_fields = [<%ListJscript('FIELDS_DUP', '', 'list') %>];
db.cp_fields = [<%ListJscript('FIELDS_COPY_PASTE', '', 'list') %>];
% }
db.father_id_update = db.father_id = <% encodeJs($ARGS{father_id}) %>;
db.start = <%$SQL{START}%>;
db.rows = <%$SQL{ROWS}%>;
db.max_rows = <%$SQL{MAX_ROWS}%>;
db.recordset_changed = <% $ARGS{recordsetChanged} ? 'true' : 'false' %>;
% # nome del campo chiave primaria
% my $KEY = $m->scomp('SELF:KEY');
% # vettore delle chiavi primarie
% my $keys = [];
<%perl>
# matrice dei dati
my @data = ();
# matrice dei parametri
my @params = ();
# reference record - solo se il recordset ha una sola riga
# usato per cambiare dinamicamente l'elenco dei campi in FIELDS_RO, FIELDS_RO_UPDATE, PERMISSION ecc.
$Session{ARGS}->{Record0} = undef;
if($ARGS{RecordsetCache}){
#DEBUG $PLogger->debug(sub{ "Leggo tutto l'elenco per poter stampare le righe nell'ordine desiderato" });
# se le chiavi dei record sono rese persistenti, l'ordinamento dei record
# deve tenere conto di quell'ordine anziché l'ordine della query di dettaglio in $sth
# devo quindi leggere tutto il recordset per poi stampare le righe nell'ordine desiderato
my %data;
my %params;
my $base_comp = $m->base_comp;
while (my $row = $sth->fetchrow_hashref){
if($base_comp->method_exists('OUT_FILTER')){
$row = $base_comp->call_method('OUT_FILTER', row => $row);
}
if($row){
my @params_row = ();
my @row = ();
my $str;
my $id = $row->{$query_names->[0]};
#DEBUG $PLogger->debug(sub{'row->'.Dumper($row)});
if($SQL{ROWS} == 1){
$Session{ARGS}->{Record0}{$KEY} = $id;
}
for(my $i=1; $i<@$query_names; $i++){
my $key = $query_names->[$i];
my($val, $param) = Call_OutFieldFilter($key, $id, $row->{$key}, $query_names, $row, $base_comp, 0);
if($SQL{ROWS} == 1){
$Session{ARGS}->{Record0}{$key} = $val;
}
push @params_row, escape_value($param);
push @row, escape_value($val);
}
$data{$id} = \@row;
$params{$id} = \@params_row;
}
}
$keys = $ARGS{recordset_list};
for(my $R=0; $R<@$keys; $R++){
my $key = $keys->[$R];
if(exists $data{$key}){
push @data, $data{$key};
push @params, $params{$key};
}else{
# manca il record indicato in cache. Si tratta di un record cancellato
#DEBUG $PLogger->debug(sub{"manca il record id:$key indicato in cache. Si tratta di un record cancellato"});
# genero una riga vuota
push @data, [];
push @params, [];
}
}
#DEBUG $PLogger->debug(sub{ 'recordset_list ' . Dumper($ARGS{recordset_list}); });
}else{
#DEBUG PLogger->debug('Genero l\'array direttamente dal recordset di dettaglio');
# genero l'array direttamente dal recordset di dettaglio in $sth
my $num_rows = $SQL{ROWS}-1;
my $base_comp = $m->base_comp;
while (my $row = $sth->fetchrow_hashref){
if($base_comp->method_exists('OUT_FILTER')){
$row = $base_comp->call_method('OUT_FILTER', row => $row);
}
if($row){
my $id = $row->{$query_names->[0]};
push @$keys, $id;
my @params_row = ();
if($SQL{ROWS} == 1){
$Session{ARGS}->{Record0}{$KEY} = $id;
}
my @row;
for(my $i=1; $i<@$query_names; $i++){
my $key = $query_names->[$i];
my($val, $param) = Call_OutFieldFilter($key, $id, $row->{$key}, $query_names, $row, $base_comp, 0);
if($SQL{ROWS} == 1){
$Session{ARGS}->{Record0}{$key} = $val;
}
push @params_row, escape_value($param);
push @row, escape_value($val);
}
push @data, \@row;
push @params, \@params_row;
}
}
}
</%perl>
db.data = <% to_json(\@data) %>;
%#DEBUG % $PLogger->debug(sub{Dumper(\@params)});
db.params = <% to_json(\@params) %>;
db.keys = <% to_json(\@$keys) %>;
%# aggiungo la matrice con i valori delle chiavi delle tabelle figlie
<%perl>
if($ARGS{rows} >= 1){
my @fathers_id = ();
my $FIELDS = $m->scomp('SELF:CHILDREN_FIELDS');
if($FIELDS){
# abbiamo dei recordset figli
# elenco chiavi dei recordset figli
my $sth = ExecQuery('list children keys', 'SELF:SELECT_CHILDREN_ID', FIELDS => "$KEY, $FIELDS", WHERE => $SQL{LAST_WHERE}, ORDER => $SQL{LAST_ORDER});
# devo ordinare le chiavi come in (db.keys)
my %children_keys;
while(my @row = $sth->fetchrow_array){
# nella prima colonna ho la chiave primaria
my $pk = shift @row;
$children_keys{$pk} = \@row;
}
foreach my $pk (@$keys){
my $row = $children_keys{$pk};
my @cols;
for(my $i=0; $i<@{$row}; $i++){
push @cols, $row->[$i];
}
push @fathers_id, \@cols;
}
}
$m->out('db.fathers_id = '.to_json(\@fathers_id).';');
}
 
# campi FIELDS_RO & FIELDS_RO_UPDATE
&Fields_RO('db', \@names);
# permessi ...
my $permission = Permission();
foreach my $perm (keys %{$permission}){
$m->out("db.can$perm = ".($permission->{$perm} ? 'true' : 'false').";\n");
#DEBUG $PLogger->debug(sub{ "db.can$perm = ".($permission->{$perm} ? 'true' : 'false'); });
}
</%perl>
% if($m->base_comp->method_exists('POST_array')){
%#// begin POST_array
% $m->comp('SELF:POST_array', KEYS => $keys, Params => \%ARGS, SQL => \%SQL);
%#// end POST_array
% }
%#// end array.
</%method>
%##################################################### select - elenco options in formato jscript (senza buffer)
<%method select>\
% my $sth = ExecQuery('jscript select', 'SELF:SELECT', WHERE => EvalSqlWhere(undef, \%ARGS), %ARGS);
% # Sel viene definito prima della chiamata
function _Add(id, value, parameters){
var O=document.createElement("OPTION"); O.innerHTML=value; O.value=id; Sel.appendChild(O); Sel.Cache_parameters[id] = parameters;
}
% while (my @row = $sth->fetchrow_array){
% my $id = shift @row;
_Add('<%$id |js%>','<%$row[0] |js%>', '<%join '|', @row |js%>');
% }
</%method>
%##################################################### bufferselect - elenco options in formato jscript per costituire un buffer
<%method bufferselect>\
<%args>
$C
</%args>
% my $sth = ExecQuery('bufferselect', 'SELF:SELECT', WHERE => EvalSqlWhere(undef, \%ARGS), %ARGS);
function _Add_<%$C%>(S, id, value, param){
var O=document.createElement("OPTION"); O.innerHTML=value; O.value=id; S.appendChild(O);
S.params[id]=param;
}
function _PopulateSelect_<%$C%>(S){
S.params = [];
% while (my $row=$sth->fetchrow_arrayref){
_Add_<%$C%>(S,'<%($row->[0])|js%>','<%($row->[1])|js%>'<% defined $row->[2] ? (', \''.$m->interp->apply_escapes($row->[2], 'js').'\'') : ''%>);
% }
}
</%method>
%##################################################### parameters_select - restituisce la descrizione corrispondente ad un identificatore
<%method parameters_select>\
<%args>
$key
</%args>
% my $sth = ExecQuery('parameters_select', 'SELF:SELECT', ID => $key, WHERE => undef);
% # formato p1|p2|p3|...
% if($sth->rows){
% my @fields = $sth->fetchrow_array;
% shift @fields;
<% join('|', @fields) %>\
% }
</%method>
%##################################################### selectoptions - elenco opzioni in formato HTML
<%method selectoptions>\
% my $sth = ExecQuery('selectoptions', 'SELF:SELECT', WHERE => EvalSqlWhere(undef, \%ARGS), %ARGS);
% while (my $row=$sth->fetchrow_arrayref){
<option value="<%($row->[0])|h%>"><%($row->[1])|h%></option>
% }
</%method>
%##################################################### htmlselectpopup - elenco opzioni in formato HTML da visualizzare in una finestra Popup
<%method htmlselectpopup>\
<%args>
$V => undef
$max_width
$max_height
$empty => undef
$empty_descr => ''
</%args>
% my $pari;
<div class="htmlselect_Body" style="<% $max_width ? "max-width:$max_width;" : '' %><% $max_height ? "max-height:$max_height;" : '' %>">
% if(defined $empty){
<div class="htmlselect_<% ($pari = !$pari) ? 'P' : 'D'%>" id="htmlselect_Id<%$empty|h%>" onmouseover="htmlselect_PD(this, true)" onmouseout="htmlselect_PD(this)"\
onClick="Input_HtmlSelect_PopupHandler(this)" mql-id="<%$empty|h%>" mql-parameters=""><%$empty_descr|h%>&nbsp;</div>
% }
% my $sth = ExecQuery('htmlselectpopup', 'SELF:SELECT', WHERE => EvalSqlWhere(undef, \%ARGS), %ARGS);
% my @Script_buffer;
% while (my @row = $sth->fetchrow_array){
% my $id = shift @row;
% my $descr = shift @row;
<div class="htmlselect_<% ($pari = !$pari) ? 'P' : 'D'%>" id="htmlselect_Id<% $id |h%>" onmouseover="htmlselect_PD(this, true)" onmouseout="htmlselect_PD(this)"\
onClick="Input_HtmlSelect_PopupHandler(this)" mql-id="<% $id |h%>" mql-parameters="<% $m->interp->apply_escapes(join('|', @row)) |h%>"><% $descr |h%></div>
% }
</div>
</%method>
 
%##################################################### input_file_uload - per upload file dal widget input/file.comp
<%method input_file_uload>\
<%args>
$field
$value
$key
</%args>
<%perl>
my $sth = ExecQuery('input_file_uload', 'SELF:SELECT', ID => $key, FIELDS => $field);
my $file = from_json $sth->fetchrow_arrayref->[1];
my $check = from_json $value;
if($file->{filename} eq $check->{filename} &&
$file->{'content-type'} eq $check->{'content-type'} &&
(!exists $file->{digest_md5} || $file->{digest_md5} eq $check->{digest_md5})
){
$m->clear_buffer;
$r->content_type($file->{'content-type'});
$r->headers_out->{'Content-disposition'} = qq{inline; filename="$check->{filename}"};
$m->out(decode_base64($file->{base64}));
$m->abort;
}else{
die "Data file mismatch\n";
}
</%perl>
</%method>
 
%##################################################### call_remote
<%method call_remote>\
%#//GDO my_alert('<% $m->interp->apply_escapes(Dumper(\%ARGS), 'js') %>');
<%perl>
# ricerco il metodo
my $remote_func = 'CALL_REMOTE_'.$ARGS{remote_func_name};
if($m->base_comp->method_exists($remote_func)){
# valuto la clausola Where
$ARGS{SelectWhere} = SqlSelectWhere(\%ARGS);
#DEBUG $PLogger->debug('remote_func_params:'.Dumper(\%{$ARGS{remote_func_params}}));
#DEBUG $PLogger->debug('dbms_params:'.Dumper(\%ARGS));
$m->comp("SELF:$remote_func", %{$ARGS{remote_func_params}}, dbms_params => \%ARGS);
}else{
die("Il metodo remoto $remote_func non definito\n");
}
</%perl>
</%method>
 
%################################################################################# END METHODS
<%flags>
inherit => '/init.comp'
</%flags>
<%shared>
my %Params;
%SQL = ();
my $sth;
BrowserAlert();
</%shared>
<%once>
use IPC::Run qw(run);
use IPC::Run::SafeHandles;
use File::Path qw(make_path remove_tree);
use File::Temp qw/ tempfile /;
use File::Find::Rule;
use File::Copy qw/move/;
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
use Archive::Tar::Wrapper;
use Text::Balanced;
use JSON;
use MIME::Base64;
my %envelope_type = (
xml => 'text/xml; charset=utf-8',
json => 'application/json; charset=utf-8',
rest => 'application/json; charset=utf-8'
);
my %mimelist = (
htmlselectpopup => 'text/html; charset=utf-8',
divselectpopup => 'text/html; charset=utf-8',
select => 'text/plain; charset=utf-8',
bufferselect => 'text/plain; charset=utf-8',
numrec => 'text/xml; charset=utf-8',
xml => 'text/xml; charset=utf-8',
xml_tree => 'text/xml; charset=utf-8',
newkey => 'text/xml; charset=utf-8',
info => 'text/xml; charset=utf-8',
keyname => 'text/xml; charset=utf-8',
html => 'text/html; charset=utf-8',
table => 'text/plain; charset=utf-8',
array => 'text/plain; charset=utf-8',
field_check => 'text/plain; charset=utf-8',
parameters_selecT => 'text/plain; charset=utf-8',
pdf => 'application/pdf',
txt => 'text/plain; charset=utf-8',
xls => 'application/vnd.ms-excel',
call_remote => 'text/plain; charset=utf-8',
);
 
# Appende un messaggio che verra' visualizzato sul browser
sub BrowserAlert(@) {
if(@_){
#DEBUG print STDERR 'BrowserAlert '.Dumper(\@_);
$PLogger->debug(sub{ 'BrowserAlert '.Dumper(\@_);});
$Session{ARGS}->{BrowserAlert} .= join("\n", @_) . "\n";
}else{
$PLogger->debug('Reset BrowserAlert');
$Session{ARGS}->{BrowserAlert} = '';
}
}
 
sub escape_value($){
$_ = shift;
s/\r//gs;
# \x{2028} & \x{2029} count as line endings in Javascript ECMAScript standard (3rd edition section 7.3)
s/\x{2028}/\n/gs;
s/\x{2029}/\n/gs;
return $_;
}
 
# tratta il parametro verificando il tipo
# se numerico non viene posto tra ''
# se undef ritorna null
sub encodeJs($){
local $_ = $_[0];
if(!defined){
return 'null';
}elsif(m/^[+-]{0,1}0\d+\.*\d*$/){
s/'/\\'/;
s/\n/\\n/;
return '\''.$_.'\'';
}elsif(m/^[+-]{0,1}\d+\.*\d*$/){
return $_;
}else{
s/'/\\'/;
s/\n/\\n/;
return '\''.$_.'\'';
}
}
 
# tratta il parametro verificando il tipo
# se numerico non viene posto tra ''
# se stringa vuota ritorna null
sub encodeSql($){
local $_ = $_[0];
if(length == 0){
return 'null';
}elsif(m/^[+-]{0,1}0\d+\.*\d*$/){
$_ = $Session{Dbh}->quote($_);
s/\n/\\n/;
return $_;
}elsif(m/^[+-]{0,1}\d+\.*\d*$/){
return $_;
}else{
$_ = $Session{Dbh}->quote($_);
s/\n/\\n/;
return $_;
}
}
 
# elabora l'out di un stringa contenente una lista, realizzando un array degli elementi
# $sep è espressione regolare per la separazione degli elementi nella lista; se non dichiarato utilizza /\s*,\s*/
sub List2Array{
my $list = shift;
my $sep = shift;
if(!defined $sep){
$sep = '\s*,\s*';
}
$list =~ s/^\s+|\s+$//g; # spazi davanti e dietro
#DEBUG $PLogger->debug(sub{ my @arr = split /$sep/, $list; "List2Array '$list' with '$sep' -->", Dumper(\@arr); });
return split /$sep/, $list;
}
 
sub List2Params{
my $list = shift;
my $sep = shift;
if(!defined $sep){
$sep = '\s*,*\s*';
}
my %params = ();
if($list){
$list =~ s/\\//g;
}else{
return \%params;
}
my $options = $list;
my @name = Text::Balanced::extract_multiple($options, [
qr/$sep([\w-]+)\s*=\s*/,
qr/^\s*([\w-]+)\s*=\s*/,
], undef, 1);
$options = $list;
my @value = Text::Balanced::extract_multiple($options, [
sub { Text::Balanced::extract_quotelike($_[0]) },
qr/\s*=\s*([\w-]+)/,
], undef, 1);
if($#name != $#value){
die "Non valido formato di parametri di comando: $list\nUso [ param1=100 ][ MyPAR='my string data' ].\n";
}
for (my $I = 0; $I<@value; $I++){
$value[$I] =~ s/^("|'|`|\s)+//;
$value[$I] =~ s/("|'|`|\s)+$//;
$value[$I] =~ s/$sep$//;
$params{uc $name[$I]} = $value[$I];
$PLogger->debug(sub{ "List2Params param($name[$I])=$value[$I]"; });
}
return \%params;
}
 
# elabora un array generando una lista separata da ', '
sub Array2List {
#DEBUG $PLogger->debug('Array2List '.Dumper(\@_));
my @arr;
foreach my $elem (@_){
push @arr, encodeSql($elem);
}
return join ', ', @arr;
}
 
# elabora l'out di un metodo realizzando un array degli elementi
# $sep è espressione regolare per la separazione degli elementi nel metodo; se non dichiarato utilizza /\s*,\s*/
sub Method2Array{
my $comp = shift;
my $sep = shift;
if($comp !~ m/:/){
# se manca la definizione di oggetto:metodo considero si tratti di metodo dell'oggetto corrente
$comp = "SELF:$comp";
#DEBUG $PLogger->debug("comp=$comp");
}
return List2Array $m->scomp($comp, @_), $sep ;
}
 
# valuta un campo proveniente dal client
# ritorna una stringa adatta ad essere inserita in una query SQL
# o per essere inserita nel codice Javascipt
sub str2sql_js_delimited($;$){
my($val, $null)=@_;
if($null && length($val)==0){
return $null;
}elsif(!defined $val){
return 'null';
}else{
return "'$val'";
}
}
 
# valuta il codice in modo protetto
sub my_eval($){
use Safe;
my $lim_eval = new Safe;
$lim_eval->permit_only(qw(:default));
$lim_eval->share('%SQL');
#DEBUG $PLogger->debug(sub{ "MY_EVAL=($_[0])"; });
my $ris = $lim_eval->reval($_[0]);
if(!$ris){
die "Errore nella valutazione di ".$_[0]."\n";
}
# $PLogger->debug(sub{ "MY_EVAL=",Dumper($ris); });
return $ris;
}
 
# costruisce un Hash con il testo ritornato dal metodo Mason di nome $comp
sub method2hash($){
my $comp = shift;
if($comp !~ m/:/){
$comp = "SELF:$comp";
}
my $str = $m->scomp($comp);
#DEBUG $PLogger->debug("method2hash($str)");
$str =~ s/'{0,1}([\w\.\/:]+)'{0,1}/'$1'/g;
#DEBUG $PLogger->debug("method2hash => '$str'");
#DEBUG $PLogger->debug(Dumper(eval "(${str})") );
return eval "(${str})";
}
 
sub PrepareQuery(@){
my $descr = shift;
my $cmd = shift;
my $query = $cmd ? $m->scomp($cmd, @_) : shift;
if($query){
my $schema = $m->scomp('SELF:SCHEMA');
if($schema ne 'public' && $query !~ m/SET\s+search_path\s+TO\s+/is){
$query = "SET search_path TO $schema, public;\n$query";
}
my $sth = $Session{Dbh}->prepare($query);
if($PLogger->is_debug){
if($query =~ m/\n/s){
# predispondo la query multiriga con '|' iniziale per migliorare la lettura nel file di log
$query =~ s/\n/\n \| /sg;
$PLogger->debug("PrepareQuery $descr $cmd query:{\n | $query\n |}.");
}else{
$PLogger->debug("PrepareQuery $descr $cmd query:[$query]");
}
# }else{
# $PLogger->info(sub{ "PrepareQuery $descr $cmd." });
}
return $sth;
}else{
$PLogger->debug(sub{ "PrepareQuery $descr $cmd ( no query )"; });
return undef;
}
}
 
sub ExecQuery(@){
my $sth;
if(defined $_[1]){
if($sth = PrepareQuery(@_)){
$sth->execute();
}
}else{ # se $_[1] è undef allora $_[2] è la query ed i campi successivi sono i parametri
my $descr = shift;
shift;
my $query = shift;
my $schema = $m->scomp('SELF:SCHEMA');
if($schema ne 'public' && $query !~ m/SET\s+search_path\s+TO\s+/is){
$query = "SET search_path TO $schema, public;\n$query";
}
$sth = $Session{Dbh}->prepare($query);
my $rows = $sth->execute(@_);
if($PLogger->is_debug){
if($query =~ m/\n/s){
$query =~ s/\n/\n \| /sg;
$PLogger->debug("ExecQuery $descr with [".Array2List(@_)."] query:{\n | $query\n |}.");
}else{
$PLogger->debug("ExecQuery $descr with [".Array2List(@_)."] query:[$query]");
}
# }else{
# $PLogger->info(sub{ "ExecQuery $descr result rows:$rows." });
}
}
return $sth;
}
 
# check sintassi clausola where fornita dal client
#
# Utilizzo le keyword dichiarate nel parser SQL::Parser
use SQL::Dialects::ANSI;
my $check_where_clause_dialect = SQL::Dialects::ANSI->get_config_as_hash;
# parser
use HOP::Lexer 'string_lexer';
 
sub check_where_clause($){
my $sql = shift;
#DEBUG $PLogger->debug("check_where_clause($sql)");
# List authorized keyword
my %authorized_keywords = map { uc $_, 1 } Method2Array 'AUTHORIZED_KEYWORDS';
# List keywords
# $check_where_clause_dialect->{reserved_words} & $check_where_clause_dialect->{valid_commands}
 
# Authorized operators
my %authorized_operators = map { uc $_, 1 } Method2Array 'AUTHORIZED_OPERATORS';
# List Operators
my %forbidden_operators = %{$check_where_clause_dialect->{valid_comparison_operators}};
$forbidden_operators{'~*'} = 1;
$forbidden_operators{ILIKE} = 1;
$forbidden_operators{NOT} = 1;
# List authorized field
my %authorized_fields = map { $_, 1 } Method2Array 'AUTHORIZED_FIELDS';
# ai campi senza indicazione della tabella vanno aggiunti i campi completi di nome della tabella
my $table = $m->scomp('SELF:FROM');
foreach my $field (keys %authorized_fields){
if($field !~ m/\./){
my $new_field = $table.'.'.$field;
if(!exists $authorized_fields{$new_field}){
$authorized_fields{$new_field} = 1;
}
}
}
# List authorized function
my %authorized_functions = map { uc $_, 1 } Method2Array 'AUTHORIZED_FUNCTIONS';
 
my @tokens = (
[ 'COMMENT', qr/--/ ],
[ 'CR', qr/\n/ ],
[ 'STR_DELIM', qr/'/ ],
[ 'CAST', qr/\:\:\w+/ , sub {[]} ],
[ 'FIELD_DELIM', qr/"[a-zA-Z][\w\.]*"/, sub {
my($label, $value) = @_;
$value =~ s/^"|"$//g;
[ $label, $value ]
}],
[ 'FUNCTION', qr/[a-zA-Z][\w\.]*\s*\(/ ],
[ 'FIELD', qr/[a-zA-Z][\w\.]*/ ],
[ 'COMMAS', qr/[,;]/ ],
[ 'P_UP', qr/\(/ ],
[ 'P_DOWN', qr/\)/ ],
[ 'NUMBER', qr/[\-\d\.]+/ ],
[ 'RETURN', qr/\n/ ],
[ 'SPACE', qr/\s+/ ],
[ 'OTHER', qr/.*/ ]
);
 
#DEBUG $PLogger->debug(sub{ "LEXING [$sql]" });
 
my $lexer = string_lexer($sql, @tokens);
# ad ogni chiamata $lexer ritorna il token successivo
my $level = 0; # livello delle parantesi
my $in_comment = 0; # ==1 quando il parser attraversa un commento (che inizia con -- fino a fine riga)
my $in_string = 0; # ==1 quando il parser attraversa una stringa delimitata da "'"
my $curr_string; # contiene il valore della stringa corrente
while ( my $token = $lexer->() ) {
my($name, $value) = @{$token};
#DEBUG $PLogger->debug(sub{ "\tLEXER $name: [$value]\n" });
if($in_comment){
if($name eq 'CR'){
$in_comment = 0;
}
}else{
if($in_string){
if($name eq 'STR_DELIM'){
$in_string = 0;
}
}else{
if($name eq 'COMMENT'){
$in_comment = 1;
}elsif($name eq 'STR_DELIM'){
$in_string = 1;
}
}#in_string
}#in_comment
next if($in_string or $in_comment);
my $uc_value = uc $value;
#DEBUG $PLogger->debug(sub{ "\t\tEXAMINE $name: [$value]\n" });
if($name eq 'FUNCTION'){
$value =~ s/\s*\($//;
my $uc_value = uc $value;
next if($authorized_functions{$uc_value});
next if($authorized_keywords{$uc_value});
if($check_where_clause_dialect->{reserved_words}{$uc_value}){
die "Utilizzo della parola riservata '$value' non autorizzato\n";
}
if($check_where_clause_dialect->{valid_commands}{$uc_value}){
die "Utilizzo della parola riservata '$value' non autorizzato\n";
}
next if($authorized_operators{$uc_value});
if($forbidden_operators{$uc_value}){
die "Utilizzo dell'operatore '$value' non autorizzato\n";
}
die "Utilizzo della funzione '$value' non autorizzato\n";
}elsif($name eq 'OTHER'){
next if($authorized_operators{$uc_value});
die "Utilizzo della parola sconosciuta '$value' non autorizzato\n";
}elsif($name eq 'FIELD_DELIM'){
next if($authorized_fields{$value});
die "Utilizzo del campo '\"$value\"' non autorizzato\n";
}elsif($name eq 'FIELD'){
next if($authorized_fields{$value});
next if($authorized_keywords{$uc_value});
if($check_where_clause_dialect->{reserved_words}{$uc_value}){
die "Utilizzo della parola riservata '$value' non autorizzato\n";
}
if($check_where_clause_dialect->{valid_commands}{$uc_value}){
die "Utilizzo del comando '$value' non autorizzato\n";
}
next if($authorized_operators{$uc_value});
if($forbidden_operators{$uc_value}){
die "Utilizzo dell'operatore '$value' non autorizzato\n";
}
die "Utilizzo del campo '$value' non autorizzato\n";
}
}#while lexer
}
 
# genera una clausola where dalla struttura array inviata dal client
# arr_where = array query
# check == true viene fatto il check nelle porzioni SQL (--were....)
sub Json2SqlWhere {
my($arr_where, $check) = @_;
my @and_clauses;
foreach my $par (@$arr_where){
my $key = $par->[0];
if($key =~ m/^--where/i){
my $query = $par->[1];
$query =~ s/^\s*where\s*//i;
if(length $query){
if($check){
&check_where_clause($query);
}
push @and_clauses, $query;
}
}elsif($key =~ m/^--or/i){
push @and_clauses, '('.&Json2SqlWhere($par->[1]).' OR '.&Json2SqlWhere($par->[2]).')';
}else{
my(undef, $op, $value, $type, $elem) = @$par;
if(!defined $elem){
$elem = $key;
}
if($elem !~ m/^[\w_]+$/){
# complex field (eg. field->>'subfield')
$elem = "($elem)";
}
if(defined $type && !$type =~ m/^[\w ]+$/){
die "Type '$type' in Json2SqlWhere function not authorized!\n";
}
if(defined $value){
$value =~ s/'/''/gs;
if($type eq 'timestamp' && $value !~ m/\s\d\d:\d\d$/){
# timestamp senza orario
if($op eq '='){
push @and_clauses, "(${elem}::timestamp >= '$value 00:00:00'::timestamp AND $elem <= '$value 23:59:59.9999999'::timestamp)";
}elsif($op eq '>' || $op eq '<='){
push @and_clauses, "${elem}::timestamp $op '$value 23:59:59.9999999'::timestamp";
}elsif($op eq '<' || $op eq '>='){
push @and_clauses, "${elem}::timestamp $op '$value 00:00:00'::timestamp";
}else{
push @and_clauses, "${elem}::timestamp $op '$value'::timestamp";
}
}else{
if($op eq '~*' || $op eq 'LIKE' || $op eq 'ILIKE'){
push @and_clauses, "${elem}::text $op '$value'::text";
}else{
if(defined $type){
# force field cast
push @and_clauses, "${elem}::$type $op '$value'::$type"
}else{
push @and_clauses, "$elem $op '$value'"
}
}
}
}else{
# valore non definito
if($op eq '='){
push @and_clauses, "$elem IS NULL";
}elsif($op eq '!=' || $op eq '<>'){
push @and_clauses, "$elem IS NOT NULL";
}
}
}
}
return join(' AND ', @and_clauses);
}
 
# query di selezione
sub SqlWhere($){
my $Params = shift;
my $arr_where = [];
if($Params->{json_where}){
$arr_where = from_json($Params->{json_where});
}else{
# costruzione della condizione where ricercando tra i parametri
# i campi corrispondenti "FIND_<nome_campo>"
my @names = &Method2Array('FIELDS');
my @where;
for(my $C=0; $C<@names; $C++){
my $name = $names[$C];
if(defined $Params->{'FIND_'.$name}){
my $value = $Params->{'FIND_'.$name};
$value =~ s/\s+$//;
$value =~ s/^\s+//;
if($value ne ''){
push @where, "$name $value";
}
}
}
if(@where){
push @$arr_where, [ '--where', join(' and ', @where) ];
}
}
return $m->scomp('SELF:EVAL_WHERE', arr_where => $arr_where);
}
 
# combina più condizioni where in una unica condizione "where ........ and ......... and .........."
sub Combine_WhereClauses(@){
my $WHERE = '';
# tolgo un livello di parentesi
while(@_){
my $where = shift;
# tolgo spazi all'inizio ed alla fine
$where =~ s/^\s+//;
$where =~ s/\s+$//;
$where =~ s/^where\s+//i;
# tolgo un livello di parentesi
$where =~ s/^\s*\(\s*(.*)\s*\)\s*$/$1/;
$where =~ s/where\s+$//i;
if($where){
$WHERE .= $WHERE ? " and ( $where )" : "( $where )";
}
#DEBUG $PLogger->debug(sub{ "WHERE [$where][$WHERE]"; });
}
return $WHERE ? 'where '.$WHERE : '';
}
 
# Inizializza la tabella report_id con gli identificativi dei record da stampare
# ritorna group_id da passare come parametro al report di stampa
#
# Initializes the report_id table with the IDs of the records to be printed.
# Returns group_id and report_ids to be passed as parameters to the print report.
# The returned parameter group_id contains a GROUP_ID value.
# The returned parameter report_ids contains a reference to an array of REPORT_ID values.
sub SqlSelect2report_id($){
my $Params = shift;
my $group_id = NewGroupId();
if(defined $Params->{reportlist}){
return Array2report_idSql($group_id, $Params->{reportlist});
}
# produco l'elenco dei record da stampare con la query del recordset corrente
$Params->{type} = 'records';
# elenco degli ID da inserire
# valutazione clausola where
my $WHERE = EvalSqlWhere(undef, $Params);
my $sth = ExecQuery('SqlSelect2report_id select', 'SELF:SELECT_REPORTS', WHERE => $WHERE);
my $reports = $sth->fetchall_arrayref;
$SQL{MAX_ROWS} = @{$reports};
#DEBUG $PLogger->debug(sub{ "SQL{MAX_ROWS}=".$SQL{MAX_ROWS}; });
#DEBUG $PLogger->debug(sub{ "reports=".Dumper($reports); });
my @report_ids = ();
foreach my $report (@{$reports}){
ExecQuery('SqlSelect2report_id insert', 'SELF:INSERT_REPORTS', REPORT_ID => $report->[0], GROUP_ID => $group_id);
push(@report_ids, $report->[0]);
}
if($Session{Dbh}->commit){
return ($group_id, \@report_ids);
}
return (undef, undef);
}
 
# valutazione della clausola Where da usare nella select dei record
# con verifica dei permessi di accesso al padre, se dichiarato
sub SqlSelectWhere {
my($Params, $father_id) = @_;
# father_id = -1 è usato nell'inserimento per individuare un insieme vuoto
# -2 è usato in frame.html per il parametro 'pk'
my @queries;
# valuto se la tabella ha un padre
my $father_name = $m->scomp('SELF:FATHER_NAME');
# valuto se ho il campo chiave della tabella padre
$father_id = defined $father_id ? $father_id : $Params->{father_id};
if(length $father_name && !length $father_id){
die "No father_id param with father $father_name from ".$m->scomp('SELF:FROM')."\n";
}elsif(length $father_name && length($father_id) && $father_id >0 ){
# Se il record padre non è presente nella cache
if(!RecordsetCache($father_name, 'check_key', $father_id)){
# verifico che il padre sia leggibile (altrimenti non autorizzo modifiche e cancellazioni dei figli)
my $father_path = $father_name;
$father_path =~ s|\.|/|;
$father_path = $r->dir_config('DataBaseUrl').'/'.$father_path.'.mql';
# verifico i diritti di accesso all'oggetto padre
my $father_permission = Permission(undef, $father_path);
if(!$father_permission->{Select}){
die "No father retrieve permission from ".$m->scomp('SELF:FROM')."\n";
}
my @father_queries;
push @father_queries, $m->scomp($father_path.':WHERE');
my $father_key_name = $m->scomp('SELF:FATHER_TABLE_KEY_NAME');
push @father_queries, $father_key_name.' = '.encodeSql($father_id);
my $sth = ExecQuery('check father retrieve record ', $father_path.':NUMREC', WHERE => Combine_WhereClauses(@father_queries));
if(!$sth->fetchrow_arrayref->[0]){
die "No father record retrieve id:$father_id from ".$m->scomp('SELF:FROM')."\n";
}
}
# aggiungo la condizione per selezionare solo i record figli
#DEBUG $PLogger->debug(sub{ 'Record padre ',$father_name,'(',$m->scomp('SELF:FATHER_WHERE', FATHER_ID => $father_id),')'; });
push @queries, $m->scomp('SELF:FATHER_WHERE', FATHER_ID => $father_id);
}
if($father_id == -2){
# -2 è usato in frame.html per il parametro 'pk'
$father_id = undef;
}
# aggiungo la condizione per selezionare solo i record con le "primary key" elencate
my $key_list = $Params->{key_list};
if(length $key_list){
# lista di chiavi
my $KEY = $m->scomp('SELF:KEY');
my @keys = split ',', $key_list;
push @queries, $KEY.'='.join(' or '.$KEY.'=', map(encodeSql($_), @keys));
}
# valutazione clausola where
return EvalSqlWhere(\@queries, $Params);
}
 
# esegue la query selezionando il range indicato
sub SqlSelect($$$){
my($select, $select_fields_method, $Params) = @_;
my $select_fields = $m->scomp('SELF:'.$select_fields_method);
my $start = $Params->{start};
my $rows = $Params->{rows};
my $KEY = $m->scomp('SELF:KEY');
# elenco delle chiavi dei record da inserire nel recordset
my @RecordList = ();
$Params->{recordset_list} = \@RecordList;
if($Params->{father_id} == -1){
# ritorno un elenco vuoto
$SQL{START}=0;
$SQL{ROWS}=0;
$SQL{MAX_ROWS}=0;
$SQL{LAST_WHERE}='';
return ExecQuery('father_id is not defined', 'SELF:'.$select, FIELDS => $select_fields, WHERE => 'where false');
}
if($Params->{type} eq 'update' && $SQL{UPDATE_LIST}){
# Imposto il recordset con i campi oggetto di modifica ed inserimento.
# Come start metto la stessa posizione
my $update_list = $SQL{UPDATE_LIST};
$SQL{ROWS} = @$update_list;
$SQL{MAX_ROWS} = $Params->{max_rows} + $SQL{DIFF_RECORDS};
$SQL{START} = $Params->{start};
my $last;
my $QUERY;
my $query = "SELECT $KEY, $select_fields".
' FROM '.$m->scomp('SELF:SCHEMA_FROM')." WHERE $KEY = ";
foreach my $key (@$update_list){
$QUERY .= $query.encodeSql($key).' UNION ALL ';
}
$QUERY =~ s/ UNION ALL $//;
if($SQL{ROWS} == 1){
$SQL{LAST_WHERE} = "WHERE $KEY = " . encodeSql($update_list->[0]);
}
# se è richiesto un update ma con la restituzione di un record con chiave diversa non devo ritornare
# lo stesso record aggiornato
my $find_key = $Params->{find_key};
if(!$find_key || $find_key eq $KEY){
$Params->{recordset_list} = $update_list;
my $sth = ExecQuery('select with updated records', undef, $QUERY);
$SQL{ROWS} = $sth->rows;
return $sth;
}
}
if($m->base_comp->method_exists('PRE_SELECT')){
$m->scomp('SELF:PRE_SELECT', PARAMS => $Params);
}
# elaborazione del recordset normale ...
my $WHERE = $Params->{SelectWhere} ? $Params->{SelectWhere} : $Params->{SelectWhere} = SqlSelectWhere($Params);
# espressione SQL (id = key1 or id = key2 ...)
my $RecordList;
my $ORDER;
# quanti record sono presenti?
my $numrec;
my $sth;
if($Params->{RecordsetCache}){
# utilizzo il numero dichiarato nella cache
$numrec = RecordsetCache($Params->{name}, 'numrec');
}else{
# ricavo il numero dei record del recordset
my $sth = ExecQuery('numrec', 'SELF:NUMREC', WHERE => $WHERE);
$numrec = $sth->fetchrow_arrayref->[0];
}
# aggiusto il record di inizio nel caso sia passata dal client una etichetta
# di posizione, anzichè la posizione numerica
if($start eq 'forward'){
# in fondo
$start = $numrec-$SQL{MAX_ROWS};
}elsif($start eq 'insert'){
# oltre il fondo
$start = $numrec+1-int($SQL{MAX_ROWS}/2);
}elsif(!defined $start){
$start = 0;
}
$SQL{MAX_ROWS} = $numrec;
# aggiusto i range minimi e massimi all'interno del range reale del recordset
if($start < 0){
$start = 0;
}
if($rows =~ m/^\d+$/){
# se il numero di righe è un dato fornito procedo con l'individuazione
# dell'elenco
# find_key se presente, definisce un particolare id record che va ricercato
# nel recordset indicato in modo che venga ritornato un range di record che
# lo contenga in posizione centrale
my $find_key = $Params->{find_key};
if(!defined $find_key){
$find_key = undef;
}
if(!$find_key){ # utilizzo LIMIT e OFFSET nella query
# verifico i limiti per $rows all'interno del range di record
# realmente presenti nel recordset
if($start > $numrec){
$start = $numrec;
$rows = 0;
}
if($rows > $numrec-$start){
$rows = $numrec-$start;
}
if($rows < 0){
$rows = 0;
}
# con find_key non definito posso recuperare i dati utilizzando i costrutti del linguaggio SQL LIMIT e OFFSET
$SQL{START} = $start;
$SQL{ROWS} = $rows;
if($rows>0){
if($Params->{RecordsetCache}){
# è attiva la gestione dei recordset persistenti sul server
# quindi verifico se il range di righe richieste è già presente nella cache
if(!RecordsetCache($Params->{name}, 'list', \@RecordList, $Params->{rows}, $rows, $start)){
# è stato annullato il recordset persistente e a causa di un record recuperato ma già presente in cache e pertanto è necessario riformulare la query
if($Params->{recordset} ne 'new'){
# invio un messaggio di allerta all'utente
RecordsetCache($Params->{name}, 'alert');
}
return &SqlSelect('SELECT', 'SELECT_FIELDS', $Params);
}
$ORDER = '';
}else{
$sth = ExecQuery('records', 'SELF:RECORDS', WHERE => $WHERE, LIMIT => "limit $rows", OFFSET => "offset $start");
while(my $row = $sth->fetchrow_arrayref){
push @RecordList, $row->[0];
}
$ORDER = $m->scomp('SELF:ORDER_BY');
}
}
}else{
# find key
# nel caso della ricerca si ignora il parametro 'start'.
#Nel caso il record non venisse individuato, viene ritornato il recordset in fondo
if($rows <= 0){
$SQL{START} = 0;
$SQL{ROWS} = @RecordList = ();
}else{
if($Params->{RecordsetCache}){
# individuo la posizione del record indicato nel recordset
my $pos_key = RecordsetCache($Params->{name}, 'find_key', $find_key);
if(defined $pos_key){
# chiave presente; mi posiziono a 1/2
$start = $pos_key - int($rows/2);
#DEBUG print STDERR "chiave presente; mi posiziono a 1/2 - pos_key:$pos_key rows:$rows start:$start\n";
}else{
# chiave non presente; mi posiziono in fondo al recordset
$start = $numrec - $rows;
}
if($start < 0){
$start = 0;
}
if($start + $rows > $numrec){
$start = $numrec - $rows;
if($start < 0){
$start = 0;
$rows = $numrec;
}
}
if(!RecordsetCache($Params->{name}, 'list', \@RecordList, $Params->{rows}, $rows, $start)){
# è stato annullato il recordset persistente e a causa di un record recuperato ma già presente in cache e pertanto è necessario riformulare la query
if($Params->{recordset} ne 'new'){
# invio un messaggio di allerta all'utente
RecordsetCache($Params->{name}, 'alert');
}
return &SqlSelect('SELECT', 'SELECT_FIELDS', $Params);
}
$SQL{START} = $start;
$SQL{ROWS} = @RecordList
}else{
$SQL{ROWS} = $rows;
my $exist = 0;
$sth = ExecQuery('records', 'SELF:RECORDS', WHERE => $WHERE);
$ORDER = $m->scomp('SELF:ORDER_BY');
# cerco la posizione della chiave indicata
my $count = 0;
# scarto i record fino a trovare il record con chiave $find_key
# mantenendo i precedenti $rows/2 o più record se in fondo al recordset
while(my $row = $sth->fetchrow_arrayref){
$count++;
# inserisco nello stack il nuovo record
push @RecordList, $row->[0];
# svuoto lo stack se troppo pieno
@RecordList > $rows && shift @RecordList;
if($row->[0] eq $find_key){
$exist = $count;
last;
}
}
# se ho trovato un record con la chiave, allora potrebbero esserci
# altri record da caricare, altrimenti ho esaurito l'elenco
if($exist){
while(my $row = $sth->fetchrow_arrayref){
$count++;
last if($count-$exist >= int($rows/2) && @RecordList >= $rows);
push @RecordList, $row->[0];
@RecordList > $rows && shift @RecordList;
}
}
# il record di partenza è la posizione della chiave trovata
# altrimenti è in fondo al recordset (elenco vuoto)
$SQL{START} = $exist ? $exist-1 : $numrec-@RecordList;
$SQL{ROWS} = @RecordList;
}
}
}
# costruisco la clausola where di selezione dell'elenco
if(@RecordList == 0){
# elenco vuoto
$RecordList = 'false';
}elsif(@RecordList == 1){
# un solo record
$RecordList = $KEY.'='.encodeSql($RecordList[0]);
}elsif($r->dir_config('SqlWhereKeyListOr')){
# lista or
$RecordList = "$KEY=".join(" or $KEY = ", map {encodeSql($_)} @RecordList);
}else{
# lista in un insieme
$RecordList = $KEY.' in ('.join(',', map(encodeSql($_), @RecordList)).')';
}
# estraggo solo i record della lista
$WHERE = "where ($RecordList)";
}else{
#DEBUG $PLogger->debug(sub{ "Non è stato fornito il numero di righe e quindi si ritorna l'intero recordset"; });
# se non viene fornito il numero di righe desiderato si ritorna
# l'intero range di record presente in archivio
$Params->{RecordsetCache} = undef;
$SQL{START} = 0;
$SQL{ROWS} = $numrec;
$ORDER = $m->scomp('SELF:ORDER_BY');
}
$SQL{LAST_WHERE} = $WHERE;
$SQL{LAST_ORDER} = $ORDER;
$sth = ExecQuery('select list', 'SELF:'.$select, FIELDS => $select_fields, WHERE => $WHERE, ORDER => $ORDER );
$SQL{ROWS} = $sth->rows;
return $sth;
}
 
# recupera la lista delle chiavi dei record dalla cache del recordset, se presenti
# altrimenti provvede a recuperare le righe mancanti
# $recordset_id id del record persistente
# $list array con l'elenco completo delle chiavi nel range richiesto
# $records_query query SQL da utilizzare per recuperare le chiavi del recordset
# $where clausola 'where' da usare assieme a $records_query
# $limit_max numero di righe del blocco normalmente recuperato
# $limit numero di righe da recuperare. <=$limit_max, limitato se $offset è in prossimità di $max
# (è responsabilità del chiamante fornire un valore compatibile)
# $offset posizione nel recordset (0==prima riga)
# $max numero massimo di righe nel recordset
# $dim_block dimensione del blocco di record da recuperare e salvare in cache
sub getPersistentRecords {
my($recordset_id, $list, $records_query, $where, $limit_max, $limit, $offset, $max, $dim_block) = @_;
#DEBUG
$PLogger->debug(sub{ "getPersistentRecords(recordset_id:$recordset_id limit:$limit offset:$offset limit_max:$limit_max max:$max query:'$records_query' where:'$where')"; });
# il numero di record da recuperare in una query sarà almeno di $dim_block record, oppure di 3 volte
# il numero di record richiesto
my $query_limit = $limit < $dim_block ? $dim_block : $limit * 3;
#DEBUG $PLogger->debug(sub{ "\tquery_limit:$query_limit"; });
# prelevo dalla cache i record nel range specificato
my $cache_sth = ExecQuery("Get records from cache id:$recordset_id", undef, q{
select num_row, id_record
from public.recordset_rows
where id_recordset = ? and num_row >= ? and num_row < ?
order by num_row
}, $recordset_id, $offset, $offset + $limit
);
my $num_rows = $cache_sth->rows;
#DEBUG $PLogger->debug(sub{ "\tTrovati in cache $num_rows records"; });
# l'elenco potrebbe essere completo, incompleto o del tutto vuoto dato che in cache abbiamo
# almeno il doppio dei record richiesti. Per questo motivo non avremo mai il caso di mancanza
# di codici in mezzo ad un range di dati presenti in cache
# controllo se il primo record corrisponde
if($num_rows < $limit){
#DEBUG $PLogger->debug(sub{ "\talmeno un record è assente nella cache $num_rows < $limit"; });
# almeno un record è assente nella cache
# verifico se manca all'inizio o alla fine del range ricercato
my($num_row, $id_record) = $cache_sth->fetchrow_array;
my $start = ( $num_row != $offset ? int($offset/$query_limit) : int(($offset+$limit-1)/$query_limit) ) * $query_limit;
#DEBUG $PLogger->debug(sub{ "\tcalcolo start:$start = ($num_row != $offset ? int($offset/$query_limit) : int(($offset+$limit-1)/$query_limit) ) * $query_limit"; });
if(($start + $query_limit) > $max){
#DEBUG $PLogger->debug(sub{ "\tvero ($start + $query_limit) > $max"; });
# mi trovo nell'ultimo blocco della cache di dimensioni inferiori al blocco $query_limit
if($query_limit < $max){
#DEBUG $PLogger->debug(sub{ "\tse c'è almeno un blocco di record di dimensione $query_limit < $max"; });
# se c'è almeno un blocco di record di dimensione $query_limit
# verifico se ci sono record nel blocco precedente
my $prev_sth = ExecQuery('Check previus range of records from cache', undef, q{
select id from public.recordset_rows
where id_recordset = ? and num_row = ?
}, $recordset_id, $start-1
);
if($prev_sth->rows == 1){
# se sono già presenti recupero solo il blocco parziale
$query_limit = $max - $start;
#DEBUG $PLogger->debug(sub{ "\tgià presenti recupero solo il blocco parziale di $query_limit record da $start"; });
}else{
# altrimenti allargo il range aggiungendo al blocco parziale un ulteriore blocco intero
$start -= $query_limit;
$query_limit += $max - $start;
#DEBUG $PLogger->debug(sub{ "\tassenti; allargo il range start:$start query_limit:$query_limit"; });
}
}else{
#DEBUG $PLogger->debug(sub{ "\tnumero record ridotto; recupero solo il blocco parziale di $query_limit record da $start"; });
# numero record ridotto; recupero solo il blocco parziale
$query_limit = $max - $start;
}
}
# eseguo la query
my $sth = ExecQuery('records', $records_query, WHERE => $where, LIMIT => "limit $query_limit", OFFSET => "offset $start");
if($sth->rows >= 1){
# preparo la query di inserimento
my $insert_sth = $Session{Dbh}->prepare("insert into public.recordset_rows (id_recordset, num_row, id_record) values (?, ?, ?)");
while(my($id) = $sth->fetchrow_array){
#DEBUG $PLogger->debug(sub{ "\tinsert in cache rec:$id recordset:$recordset_id, start:$start"; });
# se il record fosse già presente devo provvedere ad svuotare la cache ed a ricalcolare il numero di record disponibili
eval { $insert_sth->execute($recordset_id, $start, $id) };
if($@){
# controllo che l'errore non sia recorsivo
if($Session{ARGS}->{conflict_on_load_records}){
$PLogger->warn("Recursive conflict on load records to cache id:$recordset_id");
die "Recursive conflict on load records to cache id:$recordset_id [[$@]]\n";
}
$Session{ARGS}->{conflict_on_load_records} = 1;
$PLogger->warn("Conflict on load records to cache id:$recordset_id [[$@]]");
# in caso di errore svuoto la cache
$Session{Dbh}->commit;
$sth = ExecQuery('Empty persistent recordset', undef,
q{
delete from public.recordset_rows
where id_recordset = ?
},
$recordset_id
);
$Session{Dbh}->commit;
return 0;
}
$start++;
}
$Session{Dbh}->commit;
return getPersistentRecords($recordset_id, $list, $records_query, $where, $limit_max, $limit, $offset, $max, $dim_block);
}
}
if($num_rows){
#DEBUG $PLogger->debug('\tinserisco i record nell\'elenco');
while(my($num_row, $id_record) = $cache_sth->fetchrow_array){
#DEBUG $PLogger->debug(sub{ "\tlist record $num_row: $id_record"; });
push @{$list}, $id_record;
}
}
return 1;
}
 
# prepara la lista dei campi e la lista dei valori da utilizzare in una query
# di inserimento o di aggiornamento
sub fields_values($$){
my($type, $hash_fields) = @_;
my @list = keys %$hash_fields; # array nomi dei campi della tabella
if(!@list){
return undef;
}
if($type eq 'insert'){
my @values;
my @sql_params;
foreach my $key (@list){
# permit in PRE_INSERT method to redefine the assigment as a function, like 'insert ... (field) VALUES ((select x from y where id = ?))
my $val = $hash_fields->{$key};
if(ref $val eq 'ARRAY'){
push @sql_params, $val->[0];
for(my $C=1; $C<@$val; $C++){
my $value = $val->[$C];
# if the value is defined
push @values, $value eq '' ? undef : $value;
}
}else{
push @sql_params, '?';
push @values, $val eq '' ? undef : $val;
}
}
# restituisco la lista dei nomi, dei ?,... e la lista dei nuovi valori
return join(',', @list), join(',', @sql_params), \@values;
}elsif($type eq 'update'){
my @values;
my @sql_params;
foreach my $key (@list){
my $val = $hash_fields->{$key};
if(ref $val eq 'ARRAY'){
# permit in PRE_UPDATE method to redefine the assigment as a function, like 'field=field || ?::json'
push @sql_params, $key.'='.$val->[0];
for(my $C=1; $C<@$val; $C++){
my $value = $val->[$C];
push @values, $value eq '' ? undef : $value;
}
}else{
push @sql_params, $key.'=?';
push @values, $val eq '' ? undef : $val;
}
}
# restituisco la lista "field1=?, field2=?, ..." e la lista dei nuovi valori
return join(',', @sql_params), \@values;
}else{
return undef;
}
}
 
# verifica la relazione esterna (vedi ENTITY_RELATIONS)
sub check_related_table($$$){
my($relation, $key, $field) = @_;
my($tablename, $keyname) = split /\s*\:\s*/, $relation, 2;
if($tablename != /\./){
# se lo schema non è dichiarato uso lo schema del padre
$tablename = $m->scomp('SELF:SCHEMA').'.'.$tablename;
}
# verifico i permessi della tabella collegata
my $table_path = $tablename;
$table_path =~ s|\.|/|;
$table_path = $r->dir_config('DataBaseUrl').'/'.$table_path.'.mql';
my $table_permission = Permission(undef, $table_path);
if(!$table_permission->{Select}){
die "No related '$tablename' retrieve permission\n";
}
if(!defined $keyname){
# se la chiave non è dichiarata utilizzo la chiave primaria della tabella
$keyname = $m->scomp($table_path.':KEY');
}
# verifico se il record nella tabella collegata è leggibile
my @table_queries;
push @table_queries, $m->scomp($table_path.':WHERE');
 
push @table_queries, $keyname.' = '.encodeSql($key);
my $sth = ExecQuery("check related '$tablename' retrieve record ", $table_path.':NUMREC', WHERE => Combine_WhereClauses(@table_queries));
if(!$sth->fetchrow_arrayref->[0]){
die "No related '$tablename' record retrieve $field:$key relation:$relation\n";
}
}
 
# aggiorna i dati passati in $array
sub Array2UpdateSql($$){
my($data, $Params)=@_;
my $father_id_update = $Params->{father_id_update};
my $father_id_name = $m->scomp('SELF:FATHER_ID_NAME');
my $father_id = $Params->{father_id};
my $schema_from = $m->scomp('SELF:SCHEMA_FROM');
# se dichiarato il padre deve essere dichiarato anche l'identificatore del padre
if(!length $father_id_update && length $father_id_name){
die("No father_id param with father $father_id_name from $schema_from\n");
}
if(length $father_id_name && $father_id_update == -1){
die "No father_id == -1\n";
}
my $KEY = $m->scomp('SELF:KEY');
my $key_name = $m->scomp('SELF:KEY_NAME');
my @names = &Method2Array('FIELDS');
my @nw = &Method2Array('FIELDS_NO_WRITE');
# verifica dei diritti di accesso al padre
# query di verifica dei diritti di accesso (anche del padre in quanto SqlSelectWhere effettua la verifica se è dichiarato il padre)
my $where = SqlSelectWhere($Params, $father_id_update);
if($nw[0] eq '*'){
@nw = @names;
}
# array contenente le key(id) dei record modificati ed inseriti
my @id;
# se abilitato ...
my $permission = Permission();
# relazioni da verificare: i campi in relazione con altre tabelle devono contenere chiavi di oggetti accessibili all'utente
my %entity_relations = method2hash('ENTITY_RELATIONS');
# usata per passare a POST_UPDATES i parametri eventualmente definiti
# nelle varie chiamate a PRE/POST_INSERT/UPDATE
my %PARAMS;
# in $data abbiamo la matrice dei dati da aggiornare; costruisco la query di aggiornamento
for(my $pos=0; $pos<@$data; $pos++){
my %params; # per passare parametri tra i metodi PRE/POST_INSERT/UPDATE, ..., POST_UPDATES
my $row = $data->[$pos];
my $insert_with_key;
# se hash viene fornita la chiave per l'inserimento (rif. method retrieve)
if(ref($row->[0]) eq 'ARRAY'){
# tolgo l'array
$row->[0] = $row->[0]->[0];
$insert_with_key = 1;
}
my $id = $row->[0];
if($insert_with_key){
my $key = $row->[0];
if($key == -1){
die "No key == -1\n";
}
# verifico che la chiave non sia già presente
my $sth = ExecQuery('check exists for insert', undef, q{
select count(*) from }.$schema_from.qq{ where $KEY = ?
}, $key);
if($sth->fetchrow_arrayref->[0] > 0){
die "Key already used\n";
}
# verifico che la chiave non sia maggiore della sequenza
my $serial_seq = $m->scomp('SELF:SERIAL_SEQ');
$sth = ExecQuery('check sequence for insert', undef, qq{
select last_value from $serial_seq;
});
my $last_value = $sth->fetchrow_arrayref->[0];
if($key > $last_value){
die "Key greater last key\n";
}
}elsif(length $id){
if($id == -1){
die "No key == -1\n";
}
# verifico se i record possono essere letti (altrimenti non è certamente concesso di poterli anche modificare)
# se è presente in cache non serve verificare ulteriormente
if(!$Params->{RecordsetCache} || !RecordsetCache($Params->{name}, 'check_key', $id)){
my @queries;
push @queries, $where;
push @queries, $KEY.' = '.encodeSql($id);
my $sth = ExecQuery('check record for update', 'SELF:NUMREC', WHERE => Combine_WhereClauses(@queries));
if(!$sth->fetchrow_arrayref->[0]){
$Session{StatusCode} = 404;
die "No record permission or record not exists\n";
}
}
}
if(!defined $id || $id eq '' || $insert_with_key){
if(!$permission->{Insert}){
die "No insert permission\n";
}
if($father_id_update && !$father_id_name){
die("No FATHER_ID_NAME in this table\n");
}
# la funzione KeyArray2String aggiunge in fondo all'elenco dei valori la chiave del record da cui la riga è stata duplicata
my $dup_key = $row->[@$row-1];
# hash contenente i nuovi valori da inserire
my %fields_insert;
if($insert_with_key){
# se la chiave viene fornita provvedo a inserirla nella query di inserimento
$fields_insert{$key_name} = $id;
}
# inserimento; manca l'identificatore del record
for(my $i=0; $i<@names; $i++){
my $name = $names[$i];
# verifico se il campo è da escludere (FIELDS_NO_WRITE)
my $rw=1;
foreach my $val (@nw){
if($name eq $val){
$rw=0;
last;
}
}
# applico il filtro sullo specifico campo se definito
# Attenzione a lasciare $_ !!!
$_ = Call_InFieldFilter($name, $row->[0], $row->[$i+1]);
if($rw){
# tolgo dal nome l'eventuale nome tabella "tabella.campo"
$name =~ s/^\w+\.//;
if(length){
# se si tratta di un campo in relazione con una tabella esterna
my $relation = $entity_relations{$name};
if(defined $relation){
check_related_table($relation, $_, $name);
}
}
$fields_insert{$name} = $_;
}
}
# valuto se la tabella è di tipo "DETAIL"
if($father_id_name && length($father_id_update)){
# aggiungo anche il valore del campo 'father_id_update' se presente
# eliminando dal nome del campo la tabella, ma solo se corrisponde al nome della tabella nella quale si effettua l'inserimento
my $from = $schema_from;
$from =~ s/^.*\.//;
if($father_id_name =~ m/^$from\.(.*)$/){
$father_id_name = $1;
}
$fields_insert{$father_id_name} = $father_id_update;
}
if(keys %fields_insert){
# eseguo il metodo di pre insert se dichiarato nel metodo ___.mql
if($m->base_comp->method_exists('PRE_INSERT')){
$m->scomp('SELF:PRE_INSERT', FIELDS_INSERT => \%fields_insert, DUP_KEY => $dup_key, PARAMS => \%params);
}
# PRE_INSERT può aver cambiato %fields_insert
my($fields, $values, $list_values) = fields_values('insert', \%fields_insert);
if($fields){
my $sth = PrepareQuery('insert', 'SELF:INSERT',
FIELDS =>$fields,
NEW_KEY => $id,
FIELDS_INSERT => \%fields_insert,
VALUES => $values,
LIST_VALUES => $list_values,
PARAMS => \%params
);
if($sth){
#DEBUG $PLogger->debug(sub{ 'execute(', ListJscript($list_values, 'null', 'array2list'),')' });
$sth->execute(@{$list_values});
if(!defined $id || $id eq ''){
# recupero l'id del nuovo record inserito
$id = $sth->fetchrow_arrayref->[0];
push @id, $id;
}
# log inserimento nuovo record
DB_log('insert', $id, \%fields_insert);
# incremento il contatore dei record nuovi e cancellati
$SQL{DIFF_RECORDS}++;
push @id, $id;
# eseguo il metodo di post insert se dichiarato nel metodo ___.mql
if($m->base_comp->method_exists('POST_INSERT')){
$m->scomp("SELF:POST_INSERT", KEY => $id, DUP_KEY => $dup_key, ROW => $row, FIELDS_INSERT => \%fields_insert, PARAMS => \%params);
}
}
}elsif($m->base_comp->method_exists('POST_NO_INSERT')){
$m->scomp("SELF:POST_NO_INSERT", KEY => $id, DUP_KEY => $dup_key, ROW => $row, PARAMS => \%params);
}
}
if($Params->{RecordsetCache} && $id){
# se ho i riferimenti al record padre attivi ma non coincidenti non devo
# aggiungere al recordset permanente il nuovo record in quanto il record
# inserito appartiene al recordset figlio precedente (caso spostamento
# nel recordset padre con recordset figlio in modifica)
if(!$father_id_update || !$father_id ||
( $father_id_update && $father_id && $father_id_update eq $father_id)
){
# aggiungo in coda alla cache il nuovo record
RecordsetCache($Params->{name}, 'append', $id);
}
}
}else{
if(!$permission->{Update}){
die "No update permission\n";
}
# modifica ...
push @id, $id;
# aggiornamento
my %fields_update;
for(my $C=0; $C<@names; $C++){
my $name = $names[$C];
# verifico se il campo è da escludere (FIELDS_NO_WRITE)
my $rw=1;
foreach my $val (@nw){
if($name eq $val){
$rw=0;
last;
}
}
# applico il filtro sullo specifico campo se definito
# Attenzione a lasciare $_ !!!
$_ = Call_InFieldFilter($name, $row->[0], $row->[$C+1]);
if($rw){
if(defined){
# tolgo dal nome l'eventuale nome tabella "tabella.campo"
$name =~ s/^\w+\.//;
if(length){
# se si tratta di un campo in relazione con una tabella esterna
my $relation = $entity_relations{$name};
if(defined $relation){
check_related_table($relation, $_, $name);
}
}
$fields_update{$name} = $_;
}
}
}
if(keys %fields_update){
# eseguo il metodo di pre update se dichiarato nel metodo ___.mql
if($m->base_comp->method_exists('PRE_UPDATE')){
$m->scomp("SELF:PRE_UPDATE", KEY => $id, FIELDS_UPDATE => \%fields_update, PARAMS => \%params);
}
# PRE_UPDATE può aver cambiato %fields_update
my($fields_values, $list_values) = fields_values('update', \%fields_update);
if($fields_values){
if($m->base_comp->method_exists('DELETE_IF_FIELD_EMPTY')){
my $field = $m->scomp('SELF:DELETE_IF_FIELD_EMPTY');
if(exists $fields_update{$field} && (!defined $fields_update{$field} || $fields_update{$field} eq 'null')){
if($m->base_comp->method_exists('PRE_DELETE')){
$m->scomp('SELF:PRE_DELETE', KEY => $id, PARAMS => \%params);
}
ExecQuery('delete because join-field is empy', 'SELF:DELETE', KEY => $id, PARAMS => \%params);
# log cancellazione record
DB_log('delete', $id, undef);
$fields_values = undef;
}
}
}
if($fields_values){
my $sth = PrepareQuery('update', 'SELF:UPDATE', KEY => $id,
UPDATES => $fields_values,
LIST_VALUES => $list_values,
FIELDS_UPDATE => \%fields_update,
PARAMS => \%params
);
if($sth){
DB_log('update', $id, \%fields_update);
#DEBUG $PLogger->debug(sub{ 'execute(', ListJscript($list_values, 'null', 'array2list'),")"; });
$sth->execute(@{$list_values});
# eseguo il metodo di post update se dichiarato nel metodo ___.mql
if($m->base_comp->method_exists('POST_UPDATE')){
$m->scomp("SELF:POST_UPDATE", KEY => $id, ROW => $row, FIELDS_UPDATE => \%fields_update, PARAMS => \%params);
}
}
}else{
# eseguo il metodo di post no update
if($m->base_comp->method_exists('POST_NO_UPDATE')){
$m->scomp("SELF:POST_NO_UPDATE", KEY => $id, ROW => $row, PARAMS => \%params);
}
}
}
}
# hash dei parametri
$PARAMS{$id} = \%params;
}
#DEBUG print STDERR "TEST BrowserAlert".$Session{ARGS}->{BrowserAlert};
if($m->base_comp->method_exists('POST_UPDATES')){
$m->scomp("SELF:POST_UPDATES", KEYS => \@id, PARAMS => \%PARAMS);
}
# POST_UPDATES potrebbe aver annullato la transazione ponendo @id = undef o array vuoto
if(@id && $Session{Dbh}->commit){
# se la transazione di modifica/inserimento è andata a buon fine fornisco l'elenco dei record modificati/inseriti
return \@id;
}
return undef;
}
 
# determino un nuovo group_id da utilizzare
sub NewGroupId(){
my $query = $r->dir_config('PrintNextValQuery') || "select nextval('public.report_id_id_seq')";
my $sth = ExecQuery('NewGroupId', undef, $query);
return $sth->fetchrow_arrayref->[0];
}
 
# Inserisce in report_id i record i cui identificatori (id) sono passati in $array
# ritorna group_id
#
# Inserts an array of REPORT_ID values from the input into the publi.report_id table.
# The inserted values are indentified by common group_id.
#
# Returns group_id and report_ids to be passed as parameters to the print report.
# The returned parameter group_id contains a GROUP_ID value.
# The returned parameter report_ids contains a reference to an array of REPORT_ID values.
sub Array2report_idSql($$){
my($group_id, $arr)=@_;
my $report_ids=my_eval($arr);
# in $report_ids abbiamo il vettore degli ID da inserire
# determino un nuovo group_id da utilizzare
$PLogger->debug(sub{ "Array2report_idSql group_id = $group_id list = $arr"; });
$SQL{DIFF_RECORDS}-=@$report_ids;
my $sth = PrepareQuery('insert Array2report_idSql', undef, "insert into public.report_id (group_id, key) values (?, ?)");
foreach my $id (@$report_ids){
$sth->execute($group_id, $id);
}
if($Session{Dbh}->commit){
return ($group_id, $report_ids);
}
return (undef, undef);
}
 
# cancella i record i cui identificatori (id) sono passati in $array
sub Array2DeleteSql($){
my($Params)=@_;
my $num_rec_deleted = 0;
# se abilitato alla cancellazione
my $permission = Permission();
if($permission->{Delete}){
my $data = my_eval($Params->{delete});
# in $data abbiamo il vettore dei dati da cancellare
$SQL{DIFF_RECORDS}-=@$data;
foreach my $id (@$data){
my %params; # per il passaggio di parametri tra DELETE e POST_NO_DELETE
if($m->base_comp->method_exists('PRE_DELETE')){
$m->scomp('SELF:PRE_DELETE', KEY => $id, PARAMS => \%params);
}
my $sth = ExecQuery('delete', 'SELF:DELETE', KEY => $id, PARAMS => \%params);
if($sth){
$num_rec_deleted++;
# log cancellazione record
DB_log('delete', $id, undef);
# eseguo il metodo di post delete se dichiarato nel metodo ___.mql
if($m->base_comp->method_exists('POST_DELETE')){
$m->scomp("SELF:POST_DELETE", KEY => $id, PARAMS => \%params);
}
if($Params->{RecordsetCache}){
# elimino dalla cache il record cancellato
RecordsetCache($Params->{name}, 'delete', $id);
}
}elsif($m->base_comp->method_exists('POST_NO_DELETE')){
$m->scomp("SELF:POST_NO_DELETE", KEY => $id, PARAMS => \%params);
}
}
if($Session{Dbh}->commit){
return $num_rec_deleted;
}
}
return undef;
}
 
# elabora l'out di un componente realizzando una lista degli elementi separati da ',' aggiungendo gli apici ai campi testo
sub ListJscript($$$){
my($comp, $null, $type)=@_;
my $out ='';
if($type =~ m/list/){
# l'alternativa è il caso array2list
my @names = $type eq 'list' || $type eq 'method2list' ? &Method2Array($comp) : @{$comp};
#DEBUG $PLogger->debug(sub{ "ListJscript [".$m->scomp($comp)."]'$comp''$null''$type' ====", Dumper(\@names); });
for(my $col=0; $col<@names; $col++){
my $val = $names[$col];
$val =~ s/^\s+//;
$val =~ s/\s+$//;
$val =~ s/\\$//;
$val =~ s/'/\\'/;
$val =~ s/\n/\\n/;
$out .= str2sql_js_delimited($val, $null).',';
}
$out =~ s/,$//;
}elsif($type eq 'scalar'){
$out = $m->scomp($comp);
$out =~ s/'/\\'/;
$out =~ s/\n/\\n/;
$out = str2sql_js_delimited($out, $null).',';
}
return $out
}
 
# valuta l'espressione sql Where sia dal metodo $where_method che dall'eventuale parametro where passato
sub EvalSqlWhere($$){
my($queries, $Params) = @_;
if(!defined $queries){
$queries = [];
}
# valuto la condizione where impostata nell'oggetto
push @$queries, $m->scomp('SELF:WHERE');
# valuto la condizione where che proviene dal client (parametro 'json_where')
push @$queries, SqlWhere($Params);
# valuto la condizione WHERE finale
my $WHERE = Combine_WhereClauses(@$queries);
# completo la condizione con la clausola 'where' solo se ci sono presenti delle condizioni
if($WHERE =~ m/^\s*where\s*$/i){
$WHERE = '';
}
return $WHERE;
}
 
# genera codice Jscript per inizializzare l'elenco di campi
sub Fields_JList($$$$){
my($Recordset, $names, $list, $array) = @_;
my @lst = &Method2Array($list);
my $cols = @{$names};
if($lst[0] eq '*'){
$m->out(qq|for(var J=0; J<$cols; J++){$Recordset.$array\[J] = true;}\n|);
}else{
# creo la hash dei campi indicati nella lista
my %ro;
for(my $col=0; $col<@lst; $col++){
$ro{$lst[$col]} = 1;
}
my $str = "$Recordset.$array = [";
for(my $J=0; $J<$cols; $J++){
$str .= $ro{$names->[$J]} ? 'true,' : 'false,';
}
$str =~ s/,$//;
$m->out($str."];\n");
}
}
 
# genera codice Jscript per inizializzare l'elenco dei campi
# - in sola lettura
# - in sola lettura in aggiornamento (tipico dei campi chiave)
sub Fields_RO($$){
my($Recordset, $names)=@_;
&Fields_JList($Recordset, $names, 'FIELDS_RO', 'fields_ro');
&Fields_JList($Recordset, $names, 'FIELDS_RO_UPDATE', 'fields_ro_update');
}
 
sub FieldFilter_from($$$$$$){
my($base_comp, $field, $key, $value, $names, $fetch_row) = @_;
# verifico se il dato è presente in cache parametri
my $cache = $Session{Fields_params};
my $key_cache = $base_comp->path."|$field|$value";
if(exists $cache->{$key_cache}){
return $cache->{$key_cache};
}
my $widget = $m->fetch_comp(Field_Component($field, $base_comp, $base_comp->path));
my $param;
my $tablename = $widget->attr_if_exists('select_from');
if($tablename eq '?'){
if($base_comp->method_exists("${field}_FROM")){
$tablename = $m->scomp("SELF:${field}_FROM", field => $field, key => $key, value => $value, names => $names, fetch_row => $fetch_row);
#DEBUG $PLogger->debug(sub{ "FieldFilter_from with tablename:? and ${field}_FROM:$tablename"; });
}else{
die "Il metodo SELF:${field}_FROM non è definito\n";
}
}
if($tablename){
if($tablename !~ m|/|){
# tabella nello stesso schema del padre
$tablename = $m->scomp('SELF:SCHEMA').'/'.$tablename;
}
# devo attivare il filtro specifico per il componente che prevede l'invio
# di parametri aggiuntivi separati dal carattere speciale '|'
my $table_comp = $m->fetch_comp($r->dir_config('DataBaseUrl').'/'.$tablename.'.mql');
if(!$table_comp){
die "Rif. (select_from => '$tablename') non esistente nel componente ".$base_comp->path."\n";
}
my $sql = $table_comp->scall_method('SELECT', ID => $value);
#DEBUG $PLogger->debug(sub{ "FieldFilter_from id:$value SELECT sql='$sql'".Dumper($Session{ARGS}); });
if($sql =~ m/^\s*$/s){
die "ERROR select_from from:$Session{ARGS}->{name} field:$field key:$key value:$value\n\tLa query è nulla\n";
}
my $sth = ExecQuery("select_from from:$Session{ARGS}->{name} field:$field key:$key value:$value SELECT", undef, $sql);
if($sth->rows > 0){
# formato p1|p2|p3|...
my @fields = $sth->fetchrow_array;
shift @fields;
$param = join('|', @fields);
# salvo in cache il parametro, dovesse essere richiesto nella stessa sessione
$cache->{$key_cache} = $param;
}else{
$cache->{$key_cache} = undef;
}
}
#DEBUG $PLogger->debug(sub{ "FieldFilter_from select_from '$value'"; });
return $param
}
 
# applica il filtro del campo in uscita, se definito
# ritorna una array con due campi (valore, parametro)
# $field nome del campo
# $key valore della chiave primaria del record
# $value valore del campo
# $names array dei nomi dei campi del record
# $fetch_row hash dei valori dei campi del record
# $comp componente (.mql) se non definito si utilizza il componente di base
# $noparam se 1 non recupera i parametri (usato per ottimizzare nei casi in cui non sono utilizzati)
sub Call_OutFieldFilter {
my($field, $key, $value, $names, $fetch_row, $comp, $noparam) = @_;
#DEBUG $PLogger->debug(sub{"Call_OutFieldFilter(field:$field, key:$key, value:$value"});
if(!$comp){
$comp = $m->base_comp;
}
my $param;
if(!$noparam && length $value){
# valuto gli attributi del widget utilizzato
$param = FieldFilter_from($comp, $field, $key, $value, $names, $fetch_row);
}
my $filter = $field.'_OUT_FILTER';
if($comp->method_exists($filter)){
#DEBUG $PLogger->debug(sub{ "Call_OutFieldFilter('$filter', '$key', '$value')"; });
my $func = $comp->scall_method($filter, Key => $key, Value => $value, names => $names, fetch_row => $fetch_row, noparam => $noparam);
#DEBUG $PLogger->debug(sub{ "[$func]"; });
$_ = $value;
# Nel codice del filtro la variabile $param potrebbe essere modificata !!!
eval $func;
$value = $_;
#DEBUG $PLogger->debug(" to [$_]");
if($@) {
die "ERROR: Call_OutFieldFilter('$filter', '$key', '$value'): $@\n";
}
}
#DEBUG $PLogger->debug(sub{ "Call_OutFieldFilter value:$value, param:$param" });
return ($value, $param);
}
 
# applica il filtro del campo, se definito
sub Call_InFieldFilter($$$){
my($field, $key, $value) = @_;
my $filter = $field.'_IN_FILTER';
if($m->base_comp->method_exists($filter)){
###DEBUG $PLogger->debug(sub{ "Call_InFieldFilter('$filter', '$key', '$value')"; });
my $func = $m->base_comp->scall_method($filter, Key => $key, Value => $value);
###DEBUG $PLogger->debug(sub{ "[$func]"; });
$_ = $value;
eval $func;
$value = $_;
###DEBUG $PLogger->debug(sub{ " to [$_]"; });
if($@) {
die "ERROR: Call_InFieldFilter('$filter', '$key', '$value'): $@\n";
}
}
return $value;
}
 
# verifica se è definito il metodo <nome>_CHECK
# e restituisce il nome del componente da utilizzare per il check
sub Exist_Check($){
my $name = shift;
# tolgo dal nome l'eventuale prefisso del nome della tabella
$name =~ s/.+\.//;
my $new_name;
# verifico se esiste un campo alias il quale punti ad un componente esistente
if($m->base_comp->method_exists($name.'_ALIAS')){
my $alias = $m->scomp('SELF:'.$name.'_ALIAS');
if($m->base_comp->method_exists($alias.'_CHECK')){
$new_name = 'SELF:'.$alias.'_CHECK';
}
}elsif($m->base_comp->method_exists($name.'_CHECK')){
$new_name = 'SELF:'.$name.'_CHECK';
}
#DEBUG $PLogger->debug(sub{ "Exist_Check '$name' -> '$new_name'"; });
return $new_name;
}
 
# restituisce il nome del componente da utilizzare per il campo
sub Field_Component {
my($name, $base_comp, $base_name) = @_;
if(!$base_comp){
$base_comp = $m->base_comp;
}
if(!$base_name){
$base_name = 'SELF';
}
# tolgo dal nome l'eventuale prefisso del nome della tabella
$name =~ s/.+\.//;
my $new_name;
# verifico se esiste un campo alias il quale punti ad un componente esistente
if($base_comp->method_exists($name.'_ALIAS')){
my $alias = $m->scomp($base_name.':'.$name.'_ALIAS');
if($base_comp->method_exists($alias.'_FIELD')){
$new_name = $base_name.':'.$alias.'_FIELD';
}else{
# altrimenti utilizzo il componente generico
$new_name = $base_name.':STANDARD_FIELD';
}
# verifico se esiste il componente <campo>_FIELD specifico
}elsif($base_comp->method_exists($name.'_FIELD')){
$new_name = $base_name.':'.$name.'_FIELD';
}else{
# altrimenti utilizzo il componente generico
$new_name = $base_name.':STANDARD_FIELD';
}
#DEBUG $PLogger->debug(sub{ "Field_Component '$name' -> '$new_name'"; });
return $new_name;
}
 
# restituisce il nome del componente da utilizzare per il campo di ricerca
sub Find_Component {
my($name, $type) = @_;
my $component;
# tolgo dal nome l'eventuale prefisso del nome della tabella
$name =~ s/.+\.//;
# se esiste un componente specifico
if($m->base_comp->method_exists($name.'_FIND_FIELD')){
return 'SELF:'.$name.'_FIND_FIELD';
}
# componente generico
my $standard_field = $type =~ m/^bool/i ? 'SELF:BOOL_FIND_FIELD' : 'SELF:STANDARD_FIELD';
#
# verifico se esiste un campo alias che fornisce il nome di un componente esistente
if($m->base_comp->method_exists($name.'_FIND_ALIAS')){
my $alias = $m->scomp('SELF:'.$name.'_FIND_ALIAS');
if($m->base_comp->method_exists($alias.'_FIELD')){
return 'SELF:'.$alias.'_FIELD';
}else{
$PLogger->warn(sub{ "WARNING: Il campo alias '${alias}_FIELD' dichiarato in ${name}_FIND_ALIAS' non è definito!"; });
return $standard_field;
}
# verifico se esiste un alias del campo
}elsif($m->base_comp->method_exists($name.'_ALIAS')){
my $alias = $m->scomp('SELF:'.$name.'_ALIAS');
return Find_Component($alias, $type);
# verifico se esiste il componente <campo>_FIELD specifico
}elsif($m->base_comp->method_exists($name.'_FIELD')){
return 'SELF:'.$name.'_FIELD';
}else{
# altrimenti utilizzo il componente generico
return $standard_field;
}
}
 
# individua un array di selettori per le ricerche
sub findSelectList($$){
my($comp, $type) = @_;
if($comp->attr_exists('find_select_list')){
return $comp->attr('find_select_list');
}else{
if($type =~ m/int|numeric|real|double|decimal|serial/i){
return [ '=' => '=', '<' => '<', '<=' => '<=', '>' => '>', '>=' => '>=','!=' => '!='];
}elsif($type =~ m/date|timestamp|time/i){
return ['=' => '=', '<' => '<', '<=' => '<=', '>' => '>', '>=' => '>=','!=' => '!='];
}elsif($type =~ m/bool/i){
return [ '!=' => 'si', '=' => 'no'];
}else{
return ['~*' => '~*', '=' => '=', '!=' => '!=', 'ilike' => 'ilike'];
}
}
}
 
# funzioni per la gestione del recordset permanente
# alla chiamata provvede a creare il recordset per l'utente corrente
sub RecordsetCache {
my $Name = shift;
my $Method = shift;
#DEBUG print STDERR "RecordsetCache $Name method $Method params:[", join(',', @_),"]\n";
$PLogger->debug(sub{ "RecordsetCache $Name method $Method params:[", join(',', @_),"]"; });
# recupero i riferimenti del recordset
my $Recordset = $Session{ARGS}->{RecordsetCache}->{$Name};
if(!$Recordset){
$Recordset = $Session{ARGS}->{RecordsetCache}->{$Name} = { Name => $Name };
}
if($Recordset->{Disabled}){
return undef;
}
if(!defined $Session{Session_id}){
die "Session ID not defined\n";
}
#DEBUG $PLogger->debug(sub{ "\t", Dumper($Recordset); });
if(!$Recordset->{Id}){
my $sth = ExecQuery("Select persistent recordset '$Name'", undef,q{
select id, size, block, query_numrec, query_records, query_find_records, query_where
from public.recordset where name = ? and id_session = ?
},$Name,
$Session{Session_id}
);
my $row = $sth->fetchrow_arrayref;
$Recordset->{Id} = $row ? $row->[0] : undef;
if($Recordset->{Id}){
$Recordset->{Size} = $row ? $row->[1] : undef;
$Recordset->{Block} = $row ? $row->[2] : undef;
$Recordset->{Numrec} = $row ? $row->[3] : undef;
$Recordset->{Records} = $row ? $row->[4] : undef;
$Recordset->{Find_records} = $row ? $row->[5] : undef;
$Recordset->{Where} = $row ? $row->[6] : undef;
}else{
# dimensione del blocco di chiavi da copiare nella cache
$Recordset->{Block} = 0 + $m->scomp('SELF:DIM_BLOCK_CACHE');
if($Recordset->{Block} > 0){
# solo se la dimensione del blocco della cache è maggiore di zero, abilito la gestione del recordset persistente
# creo quindi un recordset persistente vuoto
$sth = ExecQuery("Create persistent recordset '$Name'", undef,
q{
insert into public.recordset (name, id_session, size, block) values (?, ?, null, ?);
select currval('public.recordset_id_seq');
}, $Name, $Session{Session_id}, $Recordset->{Block});
$Session{Dbh}->commit;
$Recordset->{Id} = $sth->fetchrow_arrayref->[0];
$Recordset->{Size} = undef;
}else{
# gestione recordset disabilitata
$Recordset->{Disabled} = 1;
return undef;
}
}
}
if($Method eq 'new'){
$Recordset->{Numrec} = shift;
$Recordset->{Records} = shift;
$Recordset->{Find_records} = shift;
$Recordset->{Where} = shift;
# calcolo il numero dei record del recordset
my $sth = ExecQuery("numrec '$Name'", $Recordset->{Numrec}, WHERE => $Recordset->{Where});
my $numrec = $sth->fetchrow_arrayref->[0];
# aggiorno nella cache i nuovi dati
# e svuoto il recordset
ExecQuery("Set new recordset '$Name'", undef, q{
update recordset
set size = ?, query_numrec = ?, query_records = ?, query_find_records = ?, query_where = ?
where id = ?;
delete from public.recordset_rows
where id_recordset = ?;
}, $numrec,
$Recordset->{Numrec},
$Recordset->{Records},
$Recordset->{Find_records},
$Recordset->{Where},
$Recordset->{Id},
$Recordset->{Id});
$Session{Dbh}->commit;
$Recordset->{Size} = $numrec;
}elsif($Method eq 'cache'){
# verifico che il recordset sia effettivamente in cache
if(!exists $Recordset->{Size}){
$PLogger->warn(sub{ "RecordsetCache '$Name' not in cache"; });
# richiamo il metodo 'new'
return RecordsetCache($Name, $Method, 'new', @_);
}
}elsif($Method eq 'numrec'){
#DEBUG// $PLogger->debug(sub{ "Return Size:$Recordset->{Size}"; });
return $Recordset->{Size};
}elsif($Method eq 'list'){
my($list, $limit_max, $limit, $offset) = @_;
return getPersistentRecords($Recordset->{Id}, $list, $Recordset->{Records},
$Recordset->{Where}, $limit_max, $limit, $offset,
$Recordset->{Size}, $Recordset->{Block});
}elsif($Method eq 'alert'){
BrowserAlert("E\' stato necessario ricalcolare la selezione dei record di ${Name}!\n".
"Pertanto l'ordine potrebbe non essere identico a quello della selezione\n".
"precedente, in quanto essa dipende dai record modificati nel fattempo.");
}elsif($Method eq 'append'){
# verifico che il record non sia già presente nella cache
my $sth = ExecQuery("Check key in recordset '$Name'", undef, q{
select num_row from public.recordset_rows
where id_recordset = ? and id_record = ?
}, $Recordset->{Id}, $_[0]
);
if($sth->rows){
#record presente; ritorno la posizione [1..N]
return 1 + $sth->fetchrow_arrayref->[0];
}else{
# aggiungo in coda alla cache il nuovo record
# e aggiorno il numero dei record
ExecQuery("Append key to recordset '$Name'", undef, q{
insert into public.recordset_rows
(id_recordset, num_row, id_record) values (?, ?, ?);
update recordset set size = size+1 where id = ?
}, $Recordset->{Id}, $Recordset->{Size}, $_[0],
$Recordset->{Id}
);
$Recordset->{Size}++;
$Session{Dbh}->commit;
return $Recordset->{Size};
}
}elsif($Method eq 'replace'){
my $delete;
# sostituisco una chiave con un'altra
# se la chiave da sostituire è già presente cancello la chiave in più
my $sth= ExecQuery("Find records from recordset '$Name'", undef, q{
select id from public.recordset_rows
where id_recordset = ? and id_record = ?;
}, $Recordset->{Id}, $_[1]
);
if($sth->rows){
# c'è un record da cancellare
RecordsetCache($Name, 'delete', $_[1]);
$delete=1;
}
ExecQuery("Replace record in recordset '$Name'", undef, q{
update public.recordset_rows
set id_record = ? where id_recordset = ? and id_record = ?
}, $_[1], $Recordset->{Id}, $_[0]
);
$Session{Dbh}->commit;
return $delete;
}elsif($Method eq 'delete'){
# elimino dalla cache il record indicato
# e aggiorno il numero dei record
my $sth_c = ExecQuery("Delete records from recordset '$Name'", undef, q{
update public.recordset_rows
set num_row = num_row-1
where id_recordset = ? and num_row > (
select num_row from public.recordset_rows
where id_recordset = ? and id_record = ?
);
delete from public.recordset_rows
where id_recordset = ? and id_record = ?;
update recordset set size = size-1 where id = ?;
select size from recordset where id = ?;
}, $Recordset->{Id}, $Recordset->{Id}, $_[0],
$Recordset->{Id}, $_[0],
$Recordset->{Id},
$Recordset->{Id}
);
$Session{Dbh}->commit;
$Recordset->{Size} = $sth_c->fetchrow_arrayref->[0];
}elsif($Method eq 'reset'){
# svuoto la cache
ExecQuery("Delete all records from recordset_rows '$Name'", undef, q{
delete from public.recordset_rows
where id_recordset = ?;
}, $Recordset->{Id}
);
$Session{Dbh}->commit;
}elsif($Method eq 'check_key'){
# cerco nel recordset la posizione del record con key == $_[0]
#DEBUG $PLogger->debug(sub{ "RecordsetCache ".Dumper($Recordset); });
if(!$_[0]){
die "ERRORE: chiamata RecordsetCache($Recordset->{Find_records}, 'check_key' con parametro key nullo";
}
# verifico se la chiave e' presente nella cache
my $sth_check_cache = ExecQuery("Check record from cache '$Name'", undef, q{
select num_row from public.recordset_rows
where id_record = ?
and id_recordset = ?;
}, $_[0], $Recordset->{Id});
my($row) = $sth_check_cache->fetchrow_array;
return defined $row;
}elsif($Method eq 'find_key'){
# cerco nel recordset la posizione del record con key == $_[0]
#DEBUG $PLogger->debug(sub{ "RecordsetCache ".Dumper($Recordset); });
if(!$_[0]){
die "ERRORE: chiamata RecordsetCache($Recordset->{Find_records}, 'find_key' con parametro key nullo";
}
# verifico se la chiave e' presente nella cache
my $sth_find_cache = ExecQuery("Find record from cache '$Name'", undef, q{
select num_row from public.recordset_rows
where id_record = ?
and id_recordset = ?;
}, $_[0], $Recordset->{Id});
my($row) = $sth_find_cache->fetchrow_array;
if(!defined $row){
# se non e' presente nella cache cerco la chiave nell'intero recordset
my $sth_find = ExecQuery("Find record from recordset '$Name'", $Recordset->{Find_records},
KEY => $_[0], WHERE => $Recordset->{Where}, RECORDS => $Recordset->{Records});
($row) = $sth_find->fetchrow_array;
}
return $row;
}else{
die "recordset persistente: parametro recordset '$Method' sconosciuto\n";
}
return $Recordset;
}
 
sub str2nbsp($){
$_ = shift;
$_ = $_ ? $m->interp->apply_escapes($_, 'h') : '&nbsp;';
s/\s/\&nbsp;/gs;
return $_;
}
 
# log modifiche al database
# $type - tipo dell'aggiornamento
# $id - identificativo del record
# %{$fields} - hash dati modificati, inseriti o cancellati
# %{$old_fields} - hash dati prima della modifica (opzionale)
# $table_name - nome tabella (opzionale)
sub DB_log {
my($type, $id, $fields, $old_fields, $table_name) = @_;
# nome dell'oggetto/tabella per i log
if(!$table_name){
$table_name = $m->scomp('SELF:LOG_TABLE_NAME');
}
$table_name =~ s/^\s+|\s+$//g;
# se non definito un nome il log è disabilitato
if(!$table_name){
return;
}
if($type eq 'delete'){
$Session{Logs}->execute($Session{User_id}, $table_name, $id, undef, $id, undef);
}elsif($type eq 'insert'){
$Session{Logs}->execute($Session{User_id}, $table_name, $id, undef, undef, $id);
foreach my $field (keys %{$fields}){
if(length($fields->{$field}) > 0){
$Session{Logs}->execute($Session{User_id}, $table_name, $id, $field, undef, $fields->{$field});
}
}
}elsif($type eq 'update'){
if(!defined $old_fields){
# devo recuperare i valori attuali da inserire in %{$old_fields}
# i nomi dei campi nella hash %$fields sono privi del riferimento alla
# tabella che invece è eventualmente presente nel metodo SELF:FIELD
my $table_comp = $table_name;
$table_comp =~ s/\./\//;
my @names = &Method2Array($r->dir_config('DataBaseUrl')."/$table_comp.mql:FIELDS");
foreach my $field (@names){
if($field =~ m/^(\w+)\.(\w+)$/ && exists $fields->{$2}){
# sostituisco il nome del campo con il nome completo di
# riferimento della tabella
$fields->{$field} = $fields->{$2};
delete $fields->{$2};
}
}
my $FIELDS = join ', ', keys(%{$fields});
my $sth = ExecQuery('DB_log:old value', 'SELF:SELECT', ID => $id, FIELDS => $FIELDS);
$old_fields = $sth->fetchrow_hashref;
}
foreach my $field (keys %{$fields}){
if($old_fields->{$field} ne $fields->{$field}){
$Session{Logs}->execute($Session{User_id}, $table_name, $id, $field, $old_fields->{$field}, $fields->{$field});
}
}
}else{
die "Error: DB_log. type '$type' mismatch\n";
}
}
 
sub ReportMethod($){
my $report = shift;
my $method = '';
if($report && $report =~ /\.(\w+)$/){
my $suffix = $1;
if($suffix =~ /(odt|pdf|rep)/i){
$method = lc $suffix;
}else{
die "Unknown report suffix '.$suffix'";
}
}elsif($r->dir_config('DefaultReportEngine')){
my $engine = $r->dir_config('DefaultReportEngine');
if($engine =~ /^(odt|pdf|rep)$/i){
$method = lc $1;
}else{
die "Unknown DefaultReportEngine '$engine'";
}
}else{
die "DefaultReportEngine is not defined";
}
$PLogger->debug(sub{ "ReportMethod method='$method'"; });
return $method;
}
 
sub FindReportmanFile($){
my $report = shift;
$PLogger->debug(sub{ "FindReportmanFile report=$report"; });
my $base = $r->dir_config('DataBaseUrl');
my $report_file = '';
unless($r->dir_config('ReportmanADOserver')){
# utilizzo la versione Kylix di Reportman che utilizza i driver con i dati di connessione al database nei file di configurazione
$report_file = request_to_comp_path("$base/$report.rep");
# verifico che il file sia presente o se ha percorso nel framework
unless(-e $report_file){
$report_file = request_to_comp_path("$base/$report.kylix.rep");
unless(-e $report_file){
return ('', "ERRORE: il report '$report' non esiste [$base/$report.rep oppure $base/$report.kylix.rep]");
}
}
}else{
# utilizzo la versione Windows di Reportman con il driver ADO che incorpora la stringa di connessione
my $report_in = request_to_comp_path("$base/$report.rep");
if(-e $report_in){
$report_file = $report;
$report_file =~ s|/|_|g;
$report_file = $r->dir_config('TmpDir').'/'.$report_file.'.rep';
# verifico che il file sia presente
}else{
$report_file = request_to_comp_path("$base/$report.wine.rep");
unless(-e $report_file){
return ('', "ERRORE: il report '$report' non esiste [$base/$report.rep oppure $base/$report.wine.rep]");
}
}
}
$PLogger->debug(sub{ "FindReportmanFile report_file=$report_file"; });
return ($report_file, '');
}
 
sub CheckIfReportExists($){
my $table = shift;
my @print_form = &Method2Array($table.':PRINT_FORM');
#DEBUG $PLogger->debug(sub{ "CheckIfReportExists table=$table"; });
#DEBUG $PLogger->debug(sub{ "CheckIfReportExists print_form: ".Dumper(\@print_form); });
my $report = shift @print_form;
$PLogger->debug(sub{ "CheckIfReportExists report=$report"; });
my $report_method = ReportMethod($report);
my $report_exists = 0;
if($report_method eq 'odt' || $report_method eq 'pdf'){
my $odtrpt_name = $report =~ s/\//\./r;
#DEBUG $PLogger->debug(sub{ "CheckIfReportExists odt_rpt_name=$odtrpt_name"; });
my $sth = ExecQuery('', undef, "select name from public.odt_reports where odt_reports.name = '$odtrpt_name';");
if($sth->fetchrow_hashref){
$report_exists = 1;
}
}elsif($report_method eq 'rep'){
my ($report_file, $die_msg) = FindReportmanFile($report);
$PLogger->debug(sub{ "CheckIfReportExists report_file=$report_file, die_msg=$die_msg"; });
if($report_file && -e $report_file){
$report_exists = 1;
}
}
$PLogger->debug(sub{ "CheckIfReportExists report_exists=$report_exists"; });
return $report_exists;
}
 
# valutazione dei permessi
# Parametri:
# permission_group: gruppo/gruppi a cui si deve essere autorizzati (scalare o array ref)
# table: tabella per la quale si determinano i permessi
sub Permission {
my $permission_group = shift;
my $table = @_ ? shift : 'SELF';
my $permission;
my $base_comp = $table eq 'SELF' ? $m->base_comp : $m->fetch_comp($table);
$base_comp || die "Object $table not existent\n";
my $hash_perm = 'PermHash_'.$base_comp->path;
if(exists $Session{$hash_perm}){
$permission = $Session{$hash_perm};
}else{
my %permission = ( Archive => 0, Dbms => 0, Insert => 0, Update => 0, Select => 0, Delete => 0, Print => 0, Printsel => 0, Xls => 0, Log => 0);
my $method = $base_comp->method_exists('PERMISSION') ? 'PERMISSION' : 'PERMISSION_BY_PROFILE';
my @permission = &Method2Array("$table:$method", '\s*[\s,]\s*');
@permission || die "Method $method return empy permission list\n";
if($permission[0] eq '*'){
# Attivo tutti i permessi
@permission = keys %permission;
}
my $report_exists = CheckIfReportExists($table);
foreach my $perm (@permission){
$perm = ucfirst lc $perm;
if(($perm ne 'Print' && $perm ne 'Printsel') || $report_exists){
$permission{$perm} = 1;
#DEBUG $PLogger->debug(sub{ "permission($perm)=1"; });
}
}
$permission = \%permission;
if($method ne 'PERMISSION'){
# abilito la cache solo se NON è definito il metodo PERMISSION
# (usato nell'applicazione per alterare i permessi)
$Session{$hash_perm} = $permission;
}
}
if($permission_group){
if(!ref($permission_group)){
$permission_group = [ $permission_group ];
}
foreach my $group (@$permission_group){
if(!$permission->{$group}){
$Session{StatusCode} = 403;
die "No $group permission\n";
}
}
}
return $permission;
}
 
# conversione campo data nel formato adatto per l'esportazione in formato Excel
sub dateXls($){
$_ = shift;
# gg/mm/yyyy
if(m|^(\d\d)/(\d\d)/(\d\d\d\d)$|){
#DEBUG die "gg/mm/yyyy $_ to $1|$2|$3|$4|$5|$6|$7";
return ("$3-$2-$1T", 0);
}elsif(m|^(\d\d)/(\d\d)/(\d\d\d\d)[\sT](\d\d):(\d\d):(\d\d)$|){
#DEBUG die "gg/mm/yyyy hh:mm:ss $_ to $1|$2|$3|$4|$5|$6|$7";
return ("$3-$2-$1T$4:$5:$6.000", 1);
}elsif(m|^(\d\d)/(\d\d)/(\d\d\d\d)[\sT](\d\d):(\d\d):(\d\d)\.(\d+)$|){
#DEBUG die "gg/mm/yyyy hh:mm:ss.sss $_ to $1|$2|$3|$4|$5|$6|$7";
return ("$3-$2-$1T$4:$5:$6.$7", 2);
}elsif(m|^(\d\d\d\d)-(\d\d)-(\d\d)$|){
#DEBUG die "yyyy-mm-dd $_ to $1|$2|$3|$4|$5|$6|$7";
return ("$1-$2-$3T", 0);
}elsif(m|^(\d\d\d\d)-(\d\d)-(\d\d)[\sT](\d\d):(\d\d):(\d\d)$|){
#DEBUG die "yyyy-mm-dd hh:mm:ss $_ to $1|$2|$3|$4|$5|$6|$7";
return ("$1-$2-$3T$4:$5:$6.000", 1);
}elsif(m|^(\d\d\d\d)-(\d\d)-(\d\d)[\sT](\d\d):(\d\d):(\d\d)\.(\d+)$|){
#DEBUG die "yyyy-mm-dd hh:mm:ss.sss $_ to $1|$2|$3|$4|$5|$6|$7";
return ("$1-$2-$3T$4:$5:$6.$7", 2);
}else{
#DEBUG die "$_ to undef";
return (undef, undef);
}
}
</%once>
 
<%method DATA_URI><%perl>
# URI del file <DataBaseUrl>/<schema</<table>.mql
my $name = $m->base_comp->path;
$name =~ s/\.mql$//;
$name = substr $name, 1 + length $r->dir_config('DataBaseUrl');
$name =~ s/\./_/gs;
$name =~ s/\//\./gs;
$m->out($name);
</%perl></%method>
 
%# metodi di default per i componenti /data
%#
%# informazione sulla tabella
<%method INFO>\
<%args>
$DATA_URI => $m->scomp('SELF:DATA_URI')
$KEY => undef
$WHAT => ''
$SEP => ','
$NAME => undef
$OBJ => undef
</%args>
<%perl>
#DEBUG $PLogger->debug(sub{ "SCHEMA_FROM='$SCHEMA_FROM' NAME='$NAME' KEY='$KEY' WHAT='$WHAT' SEP='$SEP'"; });
my $SCHEMA_FROM = $m->scomp('SELF:SCHEMA_FROM');
 
if(!defined($Global{"ATTRS_${DATA_URI}"})){
# separo lo schema dal nome della tabella
my($schema, $from) = split /\./, $SCHEMA_FROM, 2;
# Get the primary key
my $pri_key;
if(my $sth = $Session{Dbh}->primary_key_info(undef, $schema, $from)){
my $data = $sth->fetchrow_hashref;
$pri_key = $data->{COLUMN_NAME};
}
## || die "DBH Error primary_key_info (schema=$schema from=$from):".DBI::errstr;
## my $data = $sth->fetchrow_hashref;
## my $pri_key = $data->{COLUMN_NAME};
 
# Get list of fields
$sth = $Session{Dbh}->column_info(undef, $schema, $from, '%');
my $ATTRS = [];
$Global{"ATTRS_${DATA_URI}"} = $ATTRS;
while(my $field = $sth->fetchrow_hashref){
#DEBUG print STDERR Dumper($field);
# caso tipo 'numeric' in PostgreSQL
if($field->{TYPE_NAME} eq 'numeric'){
($field->{DECIMAL_DIGITS}, $field->{COLUMN_SIZE}) = split /,/, $field->{COLUMN_SIZE};
}
push @$ATTRS, { NAME => $field->{COLUMN_NAME},
TYPE => $field->{TYPE_NAME},
SIZE => $field->{COLUMN_SIZE},
DECIMAL => $field->{DECIMAL_DIGITS},
NOTNULL => !$field->{NULLABLE},
PRIMARY_KEY => ($field->{COLUMN_NAME} eq $pri_key),
};
}
# GDO Ho dovuto inserire il commit dopo l'aggiornamento a SuSE8.2 e Postgres 7.3
$Session{Dbh}->commit;
# costruisco una HASH di ricerca con chiave nome del campo
my $FIELDS = {};
$Global{"FIELDS_${DATA_URI}"} = $FIELDS;
foreach my $key (@{$ATTRS}){
my $name = $key->{NAME};
$FIELDS->{$name} = $key;
}
# recupero le descrizioni di ogni campo previsto
# se FIELDS utilizza <%method INFO> i dati necessari sono stati creati
# nelle righe precedenti del codice
my @names = &Method2Array('FIELDS');
# tolgo dai nomi l'eventuale prefisso della tabella
foreach(@names){
s/.*\.//;
}
my @fields_descr = &Method2Array('FIELDS_DESCR');
my %description;
for(my $P=0; $P <@names; $P++){
$description{$names[$P]}=$fields_descr[$P];
}
my @find_names = &Method2Array('FIND_FIELDS');
my @find_fields_descr = &Method2Array('FIND_FIELDS_DESCR');
my %find_description;
for(my $P=0; $P <@find_names; $P++){
# tolgo dal nome il prefisso
$find_names[$P] =~ s/.*\.//;
$find_description{$find_names[$P]} = (defined $find_fields_descr[$P]) ?
$find_fields_descr[$P] : $description{$find_names[$P]};
}
 
my @hidden_names = &Method2Array('FIELDS_HIDDEN');
my %hidden_names;
for(my $P=0; $P <@hidden_names; $P++){
# tolgo dal nome il prefisso
$hidden_names[$P] =~ s/.*\.//;
$hidden_names{$hidden_names[$P]} = 1;
}
 
foreach my $key (@{$ATTRS}){
my $name = $key->{NAME};
# aggiungo all'hash anche la descrizione del campo recuperata da SELF:FIELDS_DESCR
$key->{DESCR} = delete $description{$name};
$key->{FIND_DESCR} = delete $find_description{$name};
$key->{HIDDEN} = delete $hidden_names{$name};
}
# completo con i nomi non presenti nella tabella
foreach my $name (keys %description){
my $key = $FIELDS->{$name} = { NAME => $name };
push @{$ATTRS}, $key;
# aggiungo all'hash anche la descrizione del campo recuperata da SELF:FIELDS_DESCR e SELF:FIND_FIELDS_DESCR
$key->{DESCR} = $description{$name};
$key->{FIND_DESCR} = delete $find_description{$name};
$key->{HIDDEN} = delete $hidden_names{$name};
}
# completo con i nomi non presenti nella tabella
foreach my $name (keys %find_description){
my $key = $FIELDS->{$name} = { NAME => $name };
push @{$ATTRS}, $key;
# aggiungo all'hash anche la descrizione del campo recuperata da SELF:FIND_FIELDS_DESCR
$key->{FIND_DESCR} = delete $find_description{$name};
$key->{HIDDEN} = delete $hidden_names{$name};
}
#DEBUG $PLogger->debug(sub{ '°'x60,"\nFIELDS_${DATA_URI} = ",Dumper($Global{"FIELDS_${DATA_URI}"}); });
}
# recupero i parametri dei campi del recordset inseriti manualmente
my $params = {};
if($m->base_comp->method_exists('ATTRS')){
$params = eval('{'.$m->scomp('SELF:ATTRS').'}');
# aggiungo i parametri alla struttura dei parametri recuperata da 'table_attributes'
my $FIELDS = $Global{"FIELDS_${DATA_URI}"};
foreach my $name (keys %{$params}){
my $keys = $params->{$name};
foreach my $k (keys %{$keys}){
$FIELDS->{$name}{$k} = $keys->{$k};
}
}
#DEBUG $PLogger->debug(sub{ "dopo aggiunta FIELDS_${DATA_URI} = ", Dumper($Global{"FIELDS_${DATA_URI}"}); });
}
if($NAME){
# il nome potrebbe essere nella forma "tabella.nome"
if($NAME =~ m/(.+)\.(.+)/){
$NAME = $2;
}
if($WHAT){
my $val = $Global{"FIELDS_${DATA_URI}"}->{$NAME}->{$WHAT};
#DEBUG $PLogger->debug(sub{ "INFO NAME:$NAME VAL:$val DATA_URI:$DATA_URI KEY:$KEY WHAT:$WHAT SEP:$SEP"; });
$m->out($val);
return;
}else{
return $Global{"FIELDS_${DATA_URI}"}->{$NAME};
}
}
if($OBJ){
return $Global{"FIELDS_${DATA_URI}"}
}
my $nokey;
if($WHAT eq 'NAME_NOPK'){
$WHAT = 'NAME';
$nokey = 1;
}
# compongo la lista mettendo i campi PRIMARY_KEY all'inizio
my $list='';
my $pklist='';
foreach my $key (@{$Global{"ATTRS_${DATA_URI}"}}){
if( ! $KEY || $key->{$KEY} ){
if($key->{PRIMARY_KEY}){
if(!$nokey){
$pklist.=$key->{$WHAT}.$SEP;
}
}else{
$list.=$key->{$WHAT}.$SEP;
}
}
}
local $/ = $SEP;
chomp $pklist;
if($pklist){
$pklist.=$SEP.$list;
}else{
$pklist=$list;
}
chomp $pklist;
#DEBUG $PLogger->debug(sub{ "INFO VAL:$pklist DATA_URI:$DATA_URI KEY:$KEY WHAT:$WHAT SEP:$SEP"; });
$m->out($pklist);
</%perl>
</%method>
 
%# individua lo schema del database
<%method SCHEMA>\
<%perl>
# ricavo il nome dello schema dal nome della cartella in cui è salvato il componente
my $path = $m->base_comp->path;
my $base = $r->dir_config('DataBaseUrl');
if($path =~ m/^$base\/{0,1}(.*)$/){
my $name = $1;
if($name eq 'dhandler'){
$name = $Session{ARGS}{name};
die "Unexpected path $path\n";
}
if($name =~ m|^(\w+)/|){
$m->out($1);
}else{
die "Unhautorized name ($name)\n;";
}
}else{
die "Unhautorized path ($path)\n;";
}
</%perl>\
</%method>
 
<%method FROM_OBJ>\
<%perl>
# ricavo il nome della tabella dal nome del componente richiamato
my $from = $m->base_comp->name;
if($from eq $m->dhandler_name){
$from = $m->dhandler_arg;
}
# tolgo il suffisso (.mql, .xsl, .txt, ecc.)
$from =~ s/\.[^.]+//;
# tolgo la classe, se presente
$from =~ s|^.*/||;
$m->out($from);
</%perl>\
</%method>
 
<%method DESCRIPTION>\
Tabella <& SELF:FROM &> (<& SELF:SCHEMA &>)\
</%method>
 
<%method FROM><& SELF:FROM_OBJ &></%method>
 
<%method SCHEMA_FROM><& SELF:SCHEMA &>.<& SELF:FROM &></%method>
 
<%method LOG_TABLE_NAME><& SELF:SCHEMA &>.<& SELF:FROM_OBJ &></%method>
 
<%method JOIN_TABLES><& SELF:SCHEMA_FROM &></%method>
 
<%method KEY><& SELF:FROM &>.<& SELF:KEY_NAME &></%method>
 
<%method KEY_NAME>\
<%perl># individua la colonna PRIMARY KEY
if(my $key = $m->scomp('SELF:INFO', KEY => 'PRIMARY_KEY', WHAT => 'NAME') ){
$m->out($key);
return;
}
my @names = &Method2Array('INFO', undef, WHAT => 'NAME');
foreach $_ (@names){
if(m/^pkey/i){
$m->out($_);
return;
}
if(m/pkey$/i){
$m->out($_);
return;
}
}
foreach $_ (@names){
if(m/^id/i){
$m->out($_);
return;
}
if(m/id$/i){
$m->out($_);
return;
}
}
# se non c'è una chiave primaria e nemmeno un campo di nome
# pkey* *pkey id* *id ritorna il primo campo della lista
$m->out($names[0]);
</%perl></%method>
 
<%method FIELDS><& SELF:INFO, WHAT => 'NAME_NOPK' &></%method>
 
<%method SELECT_FIELDS><& SELF:FIELDS, %ARGS &></%method>
 
<%method SELECT_XLS_FIELDS><& SELF:SELECT_FIELDS &></%method>
 
<%method FIELDS_RO></%method>
 
<%method FIELDS_HIDDEN></%method>
 
<%method FIELDS_RO_UPDATE>\
<& SELF:FIELDS_RO &>\
</%method>
 
<%method FIELDS_NO_WRITE>\
<& SELF:FIELDS_RO &>\
</%method>
 
<%method FIELDS_NEW></%method>
 
<%method FIELDS_DUP></%method>
 
<%method FIELDS_COPY_PASTE></%method>
 
<%method FIELDS_NOT_NULL></%method>
 
<%method FIELDS_DESCR><& SELF:FIELDS &></%method>
 
<%method FIND_FIELDS_DESCR></%method>
 
%# metodi utilizzati in &check_where_clause per la verifica della clausola json_where elaborata dal client
 
<%method AUTHORIZED_FIELDS><& SELF:KEY &>, <& SELF:FIELDS &>, <& SELF:FIND_FIELDS &></%method>
 
<%method AUTHORIZED_KEYWORDS>AND, OR, NOT, IS, NULL</%method>
 
<%method AUTHORIZED_FUNCTIONS></%method>
 
<%method AUTHORIZED_OPERATORS><=, >=, !=, <, >, =, ~*, LIKE, ILIKE</%method>
 
%# chiamata per valutare la query fornita dal browser
<%method EVAL_WHERE>\
<%args>
$arr_where
</%args>
<%perl>
# genera la where e verifica nella query JSON le porzioni di codice SQL non autorizzato (sql injection)
my $where = Json2SqlWhere($arr_where, 1);
# riverifica l'intera query alla ricerca di codice SQL non autorizzato (sql injection)
&check_where_clause($where);
$m->out($where);
</%perl></%method>
 
<%method ORDER>order by <& SELF:KEY &></%method>
 
<%method ORDER_BY>
<%perl>
my $orderby = $Params{orderby};
if(!length($orderby) || $orderby eq 'null'){
$orderby = $m->scomp('SELF:ORDER');
}
if(length($orderby) && $orderby !~ m/^\s*order\s+by\s+/i){
$orderby = 'order by '.$orderby;
}
$m->out($orderby);
</%perl>
</%method>
<%method DISTINCT></%method>
 
<%method NUMREC>\
<%args>
$WHERE => ''
</%args>
% my $schema_from = $m->scomp('SELF:JOIN_TABLES', WHERE =>$WHERE);
% my $distinct = $m->scomp('SELF:DISTINCT');
% if($distinct){
% # se c'è la direttiva 'distinct' devo contare i record dopo averli raggruppati
select count(*) from (
select <% $distinct %> <& SELF:KEY &> from <%$schema_from%> <% $WHERE %>
) as count_table;\
% }else{
% if(!$r->dir_config('USEpgstattuple') || $WHERE && $schema_from !~ m/,/){
select count(*) from <%$schema_from%> <% $WHERE %>;\
% }else{
% # ottimizzazione; l'uso di pgstattuple('xx') è più veloce di count(*), soprattutto se ci sono molti record nella tabella
% # installare il package postgresql_contrib ed eseguire il codice sql per creare la funzione e la struttura dati associata
% # trucco per trovare i file interessati: 'find / -name "pgstattuple*" '
select tuple_count FROM pgstattuple('<%$schema_from%>');\
% }
% }
</%method>
 
<%method NUM_RECORDS>\
<%perl>
my $sth = ExecQuery('numrec', 'SELF:NUMREC', WHERE => EvalSqlWhere(undef, \%Params) );
my $numrec=$sth->fetchrow_arrayref->[0];
$m->out($numrec);
</%perl>
</%method>
 
%# numero di record che vengono copiati nella cache (vedi tabelle public.recordset e public.recordset_rows)
%# un numero pari a 0 disabilita la cache
<%method DIM_BLOCK_CACHE>100</%method>
 
<%method RECORDS>\
%# il metodo è utilizzato per ricavare le chiavi primarie di una select, per poi richiedere la select completa fornendo
%# la clausola WHERE del tipo (where id=x or id=y or id=.....)
<%args>
$WHERE => ''
$LIMIT => ''
$OFFSET => ''
</%args>
<%perl>
# se è applicato DISTINCT è necessario che nell'elenco dei campi vengano aggiunti anche i campi di ordinamento
my $distinct = $m->scomp('SELF:DISTINCT');
my $order_by = $m->scomp('SELF:ORDER_BY');
my $key = $m->scomp('SELF:KEY');
my $list_sorted_field = '';
if($distinct && $order_by){
$list_sorted_field = $order_by;
$list_sorted_field =~ s/\s+ASC\s*$|\s*DESC\s*$//i;
$list_sorted_field =~ s/\s*ORDER BY\s+//i;
$list_sorted_field =~ s/\s+USING.*//i;
$list_sorted_field = ', '.$list_sorted_field.' ';
# elimino dalla lista la KEY,se presente
$list_sorted_field =~ s/,\s*$key([ ,])/$1/;
}
</%perl>
select <%$distinct%> <%$key%><%$list_sorted_field%> from <& SELF:JOIN_TABLES, %ARGS &> <% $WHERE %> <%$order_by%> <%$OFFSET%> <%$LIMIT%>;\
</%method>
 
<%method FIND_RECORDS>\
<%args>
$WHERE => ''
$RECORDS
$KEY
</%args>
% my $sql = $m->scomp($RECORDS, WHERE => $WHERE);
% my $key_name = $m->scomp('SELF:KEY_NAME');
% $sql =~ s/;\s*$//s;
SELECT pos_<%$key_name%> FROM ( select ROW_NUMBER() OVER () AS pos_<%$key_name%>, <%$key_name%> FROM (
<% $sql %>
) "TABLE1") "TABLE2" WHERE <%$key_name%> = <% $KEY %>;
</%method>
 
<%method SELECT_REPORTS>\
%# The method selects a recordset that will be used for printing a report.
<%args>
$WHERE => ''
</%args>
select <& SELF:KEY &> as key from <& SELF:JOIN_TABLES, %ARGS &> <% $WHERE %> <&SELF:ORDER_BY&>\
</%method>
 
<%method INSERT_REPORTS>\
%# The method inserts one primary key from the selected recordset into the report_id table.
<%args>
$REPORT_ID
$GROUP_ID
</%args>
insert into public.report_id (key, group_id) values (<%$REPORT_ID%>, <%$GROUP_ID%>)
</%method>
 
<%method SELECT_XLS><& SELF:SELECT, %ARGS &></%method>
 
<%method SELECT>\
<%args>
$WHERE => ''
$ORDER => $m->scomp('SELF:ORDER_BY')
$FIELDS => $m->scomp('SELF:SELECT_FIELDS')
$ID => undef
</%args>
% if(defined $ID){
select <& SELF:KEY &>, <% $FIELDS %>
from <& SELF:JOIN_TABLES, %ARGS &> where <& SELF:KEY &> = <% encodeSql($ID) %>
% }else{
select <& SELF:DISTINCT &> <& SELF:KEY &>, <% $FIELDS %>
from <& SELF:JOIN_TABLES, %ARGS &> <% $WHERE %> <% $ORDER %>
% }
</%method>
 
<%method SERIAL_SEQ><& SELF:SCHEMA_FROM &>_<& SELF:KEY_NAME &>_seq</%method>
 
<%method INSERT>\
<%args>
$NEW_KEY # chiave primaria, se fornita
$FIELDS # elenco campi "campo1,campo2,..."
$FIELDS_INSERT # hash dei campi e rispettivi valori
$VALUES # elenco "?,?,..."
$LIST_VALUES # $LIST_VALUES->[n] lista valori usata in $sth->execute(); può essere modificata
</%args>
insert into <& SELF:SCHEMA_FROM &> (<% $FIELDS %>) values (<%$VALUES%>);
% if(!defined $NEW_KEY){
% # se la chiave non è fornita, si deve recuperarla dalla sequenza
select currval('<&SELF:SERIAL_SEQ&>');
% }
</%method>
 
<%method UPDATE>\
<%args>
$UPDATES # elenco campi "campo1=?, campo2=?, ..."
$FIELDS_UPDATE # hash dei campi e rispettivi valori
$LIST_VALUES # $LIST_VALUES->[n] lista valori usata in $sth->execute(); può essere modificata
$KEY # PK del record
</%args>
update <& SELF:SCHEMA_FROM &> set <%$UPDATES%> where <& SELF:KEY &> = <% encodeSql($KEY) %>;\
</%method>
 
<%method DELETE>\
<%args>$KEY</%args>
delete from <& SELF:SCHEMA_FROM &> where <& SELF:KEY &> = <% encodeSql($KEY) %>;\
</%method>
 
<%method VARCHAR_DEFAULT_LENGTH>80</%method>
 
<%method STANDARD_FIELD>\
<%args>
$name
$type
$id
$description
$length => 12
$size => undef
$length_in_descr => 1
</%args>
<%perl>
$ARGS{length} = $length;
my $component;
#DEBUG $PLogger->debug(sub{ "STANDARD_FIELD $name, $type, $id, $description, $length"; });
if($type =~ m/int/i){
$component = '/input/number.comp';
}elsif($type =~ m/date/i){
$component = '/input/date.comp';
}elsif($type =~ m/timestamp/i){
$component = '/input/timestamp.comp';
}elsif($type =~ m/time/i){
$component = '/input/time.comp';
}elsif($type =~ m/bool/i){
$component = '/input/checkbox.comp';
}elsif($type =~ m/float/i || $type =~ m/double precision/i || $type =~ m/real/i){
$component = '/input/number.comp';
}elsif($type =~ m/numeric/i){
$component = '/input/number.comp';
if($ARGS{NumDec}){
$ARGS{NumDec} = 2;
}
}else{
$component = '/input/string.comp';
if(!defined $length){
$ARGS{length} = $m->scomp('SELF:VARCHAR_DEFAULT_LENGTH');
}
if($length_in_descr && defined $length){
$ARGS{description}.=" ($length)";
}
}
</%perl>
%# $PLogger->debug(sub{ "COMPONENTE $component con parametri ", Dumper(\%ARGS); });
<& $component, %ARGS &>\
</%method>
 
<%method GENERIC_D_FIELD>\
<%args>
$id
$name
$description => $m->scomp('SELF:INFO', NAME => $name, WHAT => 'DESCR')
$hidden => $m->scomp('SELF:INFO', NAME => $name, WHAT => 'HIDDEN')
$break => undef
$nobreak => undef
$descr_sep_nobreak => undef
$descr_sep_break => undef
$descr_sep => undef
</%args>
<%perl>
#DEBUG
my $br = (($description =~ s/\/$//) && $break); # abbiamo / alla fine della descrizione
my $nobr = (($description =~ s/\\$//) && $nobreak); # abbiamo \ alla fine della descrizione
if(!$descr_sep){
if($br){
$descr_sep = $descr_sep_break;
}elsif($nobr){
$descr_sep = $descr_sep_nobreak;
}
}
#DEBUG $PLogger->debug(sub{ Dumper(\%ARGS), "br='$br' nobr='$nobr' descr_sep='$descr_sep'"; });
$ARGS{description} = $description; # applico modifica anche al parametro nella lista degli argomenti
# annullo i campi che non devono propagarsi ai componenti richiamati
delete $ARGS{break};
delete $ARGS{nobreak};
delete $ARGS{descr_sep_nobreak};
delete $ARGS{descr_sep_break};
delete $ARGS{descr_sep};
</%perl>
<span class="widget_span" id="Span_<%$id%>" <% $hidden ? 'style="display:none;"' : '' %>>\
% if($descr_sep && $description){
<b id="DescrField_<%$id%>"><%$description%></b><%$descr_sep%>\
% }
<& SELF:GENERIC_FIELD, %ARGS &></span>
% if($br){
<%$break%>
% }elsif($nobr){
<%$nobreak%>
% }
</%method>
 
<%method GENERIC_FIELD>
<%args>
$id
$name
$type => $m->scomp('SELF:INFO', NAME => $name, WHAT => 'TYPE')
$description => $m->scomp('SELF:INFO', NAME => $name, WHAT => 'DESCR')
$length => undef
$NumDec => undef
$readonly => 1
</%args>
<%perl>
$ARGS{type} = $type;
$description =~ s/\/$|\\$//;
$ARGS{description} = $description;
$ARGS{readonly} = $readonly;
if(!$length){
$length = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'SIZE');
if($type =~ m/int/i){
$length = 8;
}elsif($type =~ m/date/i || $type =~ m/timestamp/i){
}elsif($type =~ m/bool/i){
}elsif($type =~ m/float/i || $type =~ m/double precision/i || $type =~ m/real/i){
$length = 12;
$ARGS{NumDec} = 4;
$ARGS{NumCifre} = 16;
}
}
if($type =~ m/numeric/i && !defined $NumDec){
$ARGS{NumDec} = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'DECIMAL');
}
$ARGS{length} = $length;
if(Exist_Check($name)){
# è definito il metodo per il test lato server del widget
$ARGS{remote_check} = 1;
}
$m->comp(Field_Component($name), %ARGS);
</%perl>
</%method>
 
<%method BOOL_FIND_FIELD>\
<%args>
$id
</%args>
<& /input/span.comp, id => $id, style => 'display:none;', value => '', %ARGS, 'value-type' => 'boolean' &>\
</%method>
 
%# larghezza dei campi di ricerca
<%method FIND_FIELD_WIDTH>120</%method>
 
%# generico componente per le ricerche
<%method GENERIC_FIND>\
<%args>
$name
$id
$length => $m->scomp('SELF:INFO', NAME => $name, WHAT => 'SIZE')
$type => $m->scomp('SELF:INFO', NAME => $name, WHAT => 'TYPE')
$description => $m->scomp('SELF:INFO', NAME => $name, WHAT => 'FIND_DESCR')
$find_size => undef
$find_width => undef
$size => undef
$width => undef
</%args>
<%perl>
#DEBUG $PLogger->debug(sub{ "GENERIC_FIND name:$name id:$id type:$type, destination:$description length:$length, find_size:$find_size find_width:$find_width size:$size width:$width"; });
my $id_sel=$id.'_ftype';
$ARGS{id_sel} = $id_sel;
$id.='_find';
$ARGS{id} = $id;
# verifico se è definito un widget di ricerca
if($m->base_comp->method_exists($name.'_FIND_WIDGET')){
$m->comp('SELF:'.$name.'_FIND_WIDGET', %ARGS);
}else{
my $component = &Find_Component($name, $type);
my $comp = $m->fetch_comp($component);
# visualizzo un selettore per la scelta del tipo di confronto nella query
# verifico se il componente definisce la lista degli operatori di confronto da utilizzare
my $list_sel = findSelectList($comp, $type);
$m->comp('/input/select.comp', id =>$id_sel,
description => 'Selezione tipo di confronto',
list => $list_sel,
empty => '');
# sistemo alcuni parametri
$ARGS{type} = $type;
$ARGS{description} = $description;
$ARGS{size} = $find_size ? $find_size : ($length<10 ? $length : 10);
$ARGS{length} = 128;
my $find_field_width = $m->scomp('SELF:FIND_FIELD_WIDTH');
$ARGS{width} = $find_width ? $find_width : (!defined $width || $find_field_width < $width ? $find_field_width : $width);
# suffisso per la classe che identifica un campo di filtro
#DEBUG $PLogger->debug(sub{ "GENERIC_FIND $component:$type ARGS:", Dumper(\%ARGS); });
$m->comp($comp, length_in_descr => 0, %ARGS, onchange => qq|Set_first_if_not_selected(this, '$id_sel', '$list_sel->[0]');|);
}
</%perl>
</%method>
 
%# restituisce i campi HTML per la navigazione del recordset
<%method CONTROLS>\
<%args>
$Recordset
$Display
$rows
$disp_navbar => 1
$disp_cancel => undef
$disp_refresh => 1
$disp_change => undef
$disp_insert => undef
$disp_dup => 0
$disp_save => undef
$disp_delete => undef
$disp_print => undef
$disp_xls => undef
$disp_log => undef
</%args>
<%perl>
my $permission = Permission();
$disp_navbar = $disp_navbar ? '' : 'style="display: none;"';
$disp_cancel = $disp_cancel == 1 || ($disp_cancel eq '' && ($permission->{Insert} || $permission->{Update})) ? '' : 'style="display: none;"';
$disp_refresh = $disp_refresh ? '' : 'style="display: none;"';
$disp_change = $disp_change == 1 || ($disp_change eq '' && $permission->{Update}) ? '' : 'style="display: none;"';
$disp_insert = $disp_insert == 1 || ($disp_insert eq '' && $permission->{Insert}) ? '' : 'style="display: none;"';
$disp_dup = $disp_dup ? '' : 'style="display: none;"';
$disp_save = $disp_save == 1 || ($disp_save eq '' && ($permission->{Insert} || $permission->{Update})) ? '' : 'style="display: none;"';
$disp_delete = $disp_delete == 1 || ($disp_delete eq '' && $permission->{Delete}) ? '' : 'style="display: none;"';
$disp_print = $disp_print == 1 || ($disp_print eq '' && $permission->{Print}) ? '' : 'style="display: none;"';
$disp_xls = $disp_xls == 1 || ($disp_xls eq '' && $permission->{Xls}) ? '' : 'style="display: none;"';
my $table_name = $m->scomp('SELF:LOG_TABLE_NAME');
$table_name =~ s/^\s+|\s+$//g;
# mostro il pulsante [Log] solo se la tabella non è figlia
my $father = $m->scomp('SELF:FATHER');
$father =~ s/^\s+|\s+$//g;
$disp_log = ($disp_log == 1 || ($disp_log eq '' && $permission->{Log})) && $table_name && !$father ? '' : 'style="display: none;"';
</%perl>
<span style="white-space:nowrap;" id="<%$Display%>_Controls">
% if($m->base_comp->method_exists('CONTROLS_INCLUDE_PRE')){
<& SELF:CONTROLS_INCLUDE_PRE, %ARGS &>
% }
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_cancel %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons cancel', showLabel:true, title:'Annulla le modifiche'"
id="<%$Display%>_Ctrl_cancel" onclick="<%$Display%>.cancelUpdate()" type="button">Annulla</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_refresh %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons refresh', showLabel:true, title:'Ricarica i dati dal server'"
id="<%$Display%>_Ctrl_refresh" onclick="<%$Display%>.cancelUpdate();<%$Display%>.gotoRecords('update');" type="button">Aggiorna</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_navbar %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons rewind', showLabel:false, title:'Salta all\'inizio della selezione dei record'"
id="<%$Display%>_Ctrl_rewind" onclick="<%$Display%>.gotoRecords('rewind')" type="button">Primo</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_navbar %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons down', showLabel:false, title:'Salta al record precedente'"
id="<%$Display%>_Ctrl_down" onclick="<%$Display%>.gotoRecords('down')" type="button">Precedente</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_navbar %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons up', showLabel:false, title:'Salta al record successivo'"
id="<%$Display%>_Ctrl_up" onclick="<%$Display%>.gotoRecords('up')" type="button">Successivo</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_navbar %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons forward', showLabel:false, title:'Salta alla fine della selezione dei record'"
id="<%$Display%>_Ctrl_forward" onclick="<%$Display%>.gotoRecords('forward')" type="button">Ultimo</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_change %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons change', showLabel:true, title:'Modifica <% $rows==1 ? 'il' : 'i' %> record'"
id="<%$Display%>_Ctrl_change" onclick="<%$Display%>.readOnly(false);<%$Display%>.cpSetAll();" type="button">Modifica</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_insert %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons insert', showLabel:true, title:'Aggiunge <% $rows==1 ? 'un nuovo record' : 'nuovi record' %>'"
id="<%$Display%>_Ctrl_insert" onclick="<%$Display%>.gotoRecords('insert')" type="button">Nuov<% $rows==1 ? 'o' : 'i' %></button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_dup %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons dup', showLabel:true, title:'Duplica <% $rows==1 ? 'il record' : 'i record selezionati' %>'"
id="<%$Display%>_Ctrl_dup" onclick="<%$Display%>.gotoRecords('dup')" type="button">Duplica<% $rows==1 ? '' : ' sel.' %></button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_save %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons save', showLabel:true, title:'Salva le modifiche effettuate'"
id="<%$Display%>_Ctrl_save" onclick="<%$Display%>.gotoRecords('save')" type="button">Salva</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_delete %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons delete', showLabel:true, title:'Cancella <% $rows==1 ? 'il record' : 'i record selezionati' %>'"
id="<%$Display%>_Ctrl_delete" onclick="<%$Display%>.deleteSelected()" type="button"><%$rows==1?'Cancella':'Canc.sel.'%></button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_print %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons print', showLabel:true, title:'Stampa <% $rows==1 ? 'il record' : 'i record selezionati' %>'"
id="<%$Display%>_Ctrl_print" onclick="<%$Display%>.printSelected('sel');" type="button"><%$rows==1?'Stampa':'St.sel.'%></button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_xls %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons xls', showLabel:true, title:'Esporta nel formato XLS'"
id="<%$Display%>_Ctrl_xls" onclick="<%$Display%>.printSelected('xls_sel')" type="button">XLS</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_navbar %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons goto', showLabel:true, title:'Salta alla posizione indicata a fianco'"
id="<%$Display%>_Ctrl_goto" onclick="<%$Display%>.gotoRecords(document.getElementById('<%$Display%>_record').value)"
type="button"><% $rows==1 ? 'R' : 'Da r' %>ec.
<& /input/number.comp, tabindex => -1, style => $disp_navbar ? 'display: none;' : '', id => $Display.'_record', value=>1,
NumDec=>0, ValMin=>1, ValMax=>1, size=>6, description=>'Posizione del record a cui saltare' &>
</button>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" <% $disp_log %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons log', showLabel:true, title:'Visualizza l\'attività <%$rows==1 ? 'del record' : 'dei record selezionati' %>'"
id="<%$Display%>_Ctrl_log" onclick="<%$Display%>.displayLog()" type="button">LOG</button>
% if($m->base_comp->method_exists('CONTROLS_INCLUDE_POST')){
<& SELF:CONTROLS_INCLUDE_POST, %ARGS &>
% }
</span>
<script>
require(["dijit/form/Button", "dijit/form/ValidationTextBox"]);
% # inizializzo i puntatori agli oggetti per la "navigazione" del recordset
require(["dojo/dom", "dijit/registry", "dojo/_base/array", "dojo/on", "dojo/_base/event"], function (dom, registry, array, on, event){
masonSql.once('ready', function(data){
array.forEach(['cancel', 'refresh', 'rewind', 'down', 'up', 'forward', 'change', 'insert', 'dup', 'save', 'delete', 'print', 'xls', 'goto', 'log'], function(prefix){
<%$Display%>.navigationBar[prefix + 'Button'] = registry.byId('<%$Display%>_Ctrl_'+prefix);
});
<%$Display%>.navigationBar._record = window.Id_<% $Display %>_record;
on(window.Id_<% $Display %>_record, 'click', function(evt){
event.stop(evt);
this.setFocus(evt);
});
});
});
</script>
</%method>
 
%# generica riga per il browsing della tabella
<%method ROW_TABLE>
<%args>
$row
$Recordset
$Display
$Class
$delay_script => undef # ritarda l'esecuzione degli script associati ai componenti
$Detail_from => undef
</%args>
<tr id="<%$Display%>_div_<%$row%>" class="ROW_TABLE_<%$Class%>" onclick="<%$Display%>.selectRowFather(<%$row%>);">
% if($row =~ m/^\d+$/ || $row eq '{{ row }}'){
<td class="ROW_TABLE_Sel" ><span id="<%$Display%>_l_<%$row%>">-</span></td>
<td><input type="checkbox" class="checkbox" id="<%$Display%>_s_<%$row%>" onclick="<%$Display%>.cpSetMultipleRows(event, <%$row%>)"></td>
% if($Detail_from){
% my $table_comp = $m->fetch_comp($r->dir_config('DataBaseUrl').'/'.$Detail_from.'.mql');
% my($width, $height, $properties);
% if($table_comp->method_exists('DETAIL_WINDOW')){
% ($width, $height) = split /\s+/, $table_comp->scall_method('DETAIL_WINDOW'), 2;
% }
% my $title = $table_comp->scall_method('DESCRIPTION');
<td><button data-dojo-type="dijit/form/Button" class="controlBtn recordDetailBtn" data-dojo-props="tabIndex:-1, showLabel:true, title:'Apre form di dettaglio'"
onclick="<%$Display%>.openFormDetail('forward', <%$row%>, '<%$Detail_from%>', <% $width || 'null' %>, <% $height || 'null' %>, '<% $title |js%>', {});"
style="display:none;" id="<%$Display%>_d_<%$row%>">DET</button>
</td>
% }
% }else{
<td colspan="<% $Detail_from ? 3 : 2 %>"></td>
% }
% my @fields = &Method2Array('FIELDS');
% for(my $col=0; $col<@fields; $col++){
% my $name = $fields[$col];
% $name =~ s/\s//g;
<td class="nowrap">
% my $hidden = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'HIDDEN');
<span class="widget_span" id="Span_<%"${Display}_c_${row}_$col"%>" <% $hidden ? 'style="display:none;"' : '' %>>
<& SELF:GENERIC_FIELD, name => $name, id =>"${Display}_c_${row}_$col", Display => $Display, row => $row, col => $col &>
</span></td>
% }
<td width="10"></td>
</tr>
% if(!$delay_script && @Script_buffer){
<script>
% $m->out(@Script_buffer);
% @Script_buffer=();
</script>
% }
</%method>
 
<%method TABLE_HEADER>
<%args>
@FIELDS
$Display
$Detail_from => undef
</%args>
<th colspan="<% $Detail_from ? 3 : 2 %>" width="<% $Detail_from ? 80 : 50 %>">
<p id="<%"${Display}_h_sel"%>" onclick="<%$Display%>.cpInvertAllHeaders();">sel.</p></th>
%# descrizione campi
% for(my $col=0; $col<@FIELDS; $col++){
% my $name = $FIELDS[$col];
% my $hidden = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'HIDDEN');
% my $descr = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'DESCR');
% $descr =~ s/\\$//;
% $descr =~ s/\/$//;
<th><p id="<%"${Display}_h_$col"%>" <% $hidden ? 'style="display:none;"' : '' %>
onclick="<%$Display%>.cpInvertHeader(<%$col%>);"><%$descr%></p></th>
% }
</%method>
 
%# generica tabella per il browsing della tabella del database
<%method TABLE>
<%args>
$rows
$group_cols => 1 # numero di gruppi con cui suddividere la tabella, da affiancare orizzontalmente
$Recordset => 'TABLE'
$Display => 'DISP_'.$Recordset
$Header => 1
$Controls => 1
$Detail_from => undef # se definita viene inserito per ciascun record un bottone per richiamare un form separato per modificare/inserire il record
</%args>
<%perl>
if($rows % $group_cols){ die "Il numero di righe (rows=$rows) non è multiplo del numero di gruppi (group_cols=$group_cols)\n" }
my $rcol = $rows/$group_cols;
if($Header){
$m->comp('SELF:FORM_HEADER', %ARGS);
}
if($Controls){
$m->comp('SELF:CONTROLS', %ARGS);
}
my @names = &Method2Array('FIELDS');
my $Row_buffer;
my $Script_buffer;
{ local @Script_buffer;
$Row_buffer = $m->scomp('SELF:ROW_TABLE', row=>'{{ row }}', Class => '{{ class }}', Recordset => $Recordset, Display => $Display, delay_script => 1, Detail_from => $Detail_from);
$Script_buffer = join('', @Script_buffer);
}
my $Header_buffer = $m->scomp('SELF:TABLE_HEADER', FIELDS => \@names , Display => $Display, Detail_from => $Detail_from, %ARGS);
if($group_cols > 1){
</%perl>
<table class="TABLE_group" id="<%$Display%>_table_list"><table>
<script>
require(['dojox/dtl/Context']);
var buf = ['<tr>'];
var jbuf = [];
var row_template = new dojox.dtl.Template('<% $Row_buffer |js%>');
%#// On MS Edge with empty string the method .Template return wrong text
var script_template = new dojox.dtl.Template('// Script_buffer\n<% $Script_buffer |js%>');
for(var C=0; C<<%$group_cols%>; C++){
buf.push('<td><table class="TABLE_form"><tr><% $Header_buffer |js%></tr>');
for(var R=0; R<<% $rcol %>; R++){
var row = C * <% $rcol %> + R;
var context = new dojox.dtl.Context({
row: row,
"class": row % 2 ? 'D' : 'P'
});
buf.push(row_template.render(context));
jbuf.push(script_template.render(context));
}// for R
buf.push('</table></td>');
} // for C
buf.push('</tr>');
% }else{ # tabella di una sola colonna
<table class="TABLE_form" id="<%$Display%>_table_list"></table>
<script>
require(['dojox/dtl/Context']);
var buf = ['<tr><% $Header_buffer |js%></tr>'];
var jbuf = [];
var row_template = new dojox.dtl.Template('<% $Row_buffer |js%>');
var script_template = new dojox.dtl.Template('// Script_buffer\n<% $Script_buffer |js%>');
for(var R=0; R<<%$rows%>; R++){
var context = new dojox.dtl.Context({
row: R,
"class": R % 2 ? 'D' : 'P'
});
buf.push(row_template.render(context));
jbuf.push(script_template.render(context));
}
% } # if $group_cols > 1
var html_table = buf.join('\n') + '<script>' + '<% join("\n", @Script_buffer) |js%>\n' + jbuf.join('\n') + '</' + 'script>';
hReqMason_innerHTML(document.getElementById('<%$Display%>_table_list'), html_table);
% @Script_buffer = ();
% my $cols = @names;
<%$Display%>.bindEditComponents(<%$rows%>, <%$cols%>, '_s_', '_l_', '_c_', '_');
<%$Display%>.info = document.getElementById('<%$Display%>_info');
<%$Display%>.info.innerHTML = '? - ? ( ? )';
</script>
</%method>
 
<%method HEADER_INCLUDE></%method>
 
<%method FORM_HEADER>\
<%args>
$rows => 0
$Controls => 0
$Recordset => 'FORM'
$Display => 'DISP_'.$Recordset
$info => "${Display}_info" # identificatore <span/> per le informazioni del recordset
$rec => ($rows==1 ? "${Display}_l_0" : "${Display}_rec") # se c'è un solo record l'identificatore corrisponde a DisplayBinding.label[0]
</%args>
<table class="FormHeader">
<tr style="width:100%;">
% if($Controls){
<td class="nowrap record_info" >
<span id="<%$info%>"></span> <span id="<%$rec%>"></span>
</td>
<td align="left" style="width:150px;">
<& SELF:CONTROLS, %ARGS &>
</td>
<td align="left"><& SELF:HEADER_INCLUDE, %ARGS &></td>
<td>
<div class="FormHeaderDescription">
<& SELF:DESCRIPTION &>
</div>
</td>
% }else{
<td class="nowrap record_info">
<span id="<%$info%>"></span> <span id="<%$rec%>"></span>
</td>
<td style="align:left;"><& SELF:HEADER_INCLUDE, %ARGS &></td>
<td>
<div class="FormHeaderDescription">
<& SELF:DESCRIPTION &>
</div>
</td>
% }
</tr>
</table>
</%method>
 
%# generica riga <ROW_DIVS> per il browsing della tabella
<%method ROW_DIVS>\
<%args>
$row # riga nel form; nel caricamento dinamico potrebbe essere anche un TAG da usare poi per la sostituzione
$Recordset # nome dell'oggetto Recordset di riferimento
$Display # nome dell'oggetto DisplayBinding
$delay_script => undef # ritarda l'esecuzione degli script associati ai componenti
$Detail_from => undef
</%args>
% if($row =~ m/^\d+$/ || $row eq '@@@'){
<span class="ROW_DIVS_Sel" id="<%$Display%>_l_<%$row%>">-</span>
<input type="checkbox" class="checkbox" id="<%$Display%>_s_<%$row%>">
% if($Detail_from){
% my $table_comp = $m->fetch_comp($r->dir_config('DataBaseUrl').'/'.$Detail_from.'.mql');
% my($width, $height, $properties);
% if($table_comp->method_exists('DETAIL_WINDOW')){
% ($width, $height) = split /\s+/, $table_comp->scall_method('DETAIL_WINDOW'), 2;
% }
% my $title = $table_comp->scall_method('DESCRIPTION');
<button data-dojo-type="dijit/form/Button" class="controlBtn recordDetailBtn" data-dojo-props="tabIndex:-1, showLabel:true, title:'Apre form di dettaglio'"
onclick="<%$Display%>.openFormDetail('forward', <%$row%>, '<%$Detail_from%>', <% $width || 'null' %>, <% $height || 'null' %>, '<% $title |js%>', {});"
style="display:none;" id="<%$Display%>_d_<%$row%>">DET</button>
% }
% }
% my @fields = &Method2Array('FIELDS');
% my $cols = @fields;
% for(my $col=0; $col<$cols; $col++){
% my $name = $fields[$col];
% $name =~ s/\s//g;
<& SELF:GENERIC_D_FIELD, descr_sep => ':', name => $name, id =>"${Display}_c_${row}_$col", Display => $Display, row => $row, col => $col, break => '<br>' &>\
% }
% if($row =~ m/^\d+$/ || $row eq '@@@'){
% push @Script_buffer, qq| ${Display}.bindEditComponentsRow($row, $cols, '_s_', '_l_', '_c_', '_');\n|;
% }
% if(!$delay_script && @Script_buffer){
<script>
% $m->out(@Script_buffer);
% @Script_buffer=();
</script>
% }
</%method>
 
%# riga <ROW_DIVS> per il browsing della tabella usando DIVS_TEMPLATE
<%method ROW_DIVS_TEMPLATE>\
<%args>
$row # riga nel form; nel caricamento dinamico potrebbe essere anche un TAG da usare poi per la sostituzione
$Recordset # nome dell'oggetto Recordset di riferimento
$Display # nome dell'oggetto DisplayBinding
$delay_script => undef # ritarda l'esecuzione degli script associati ai componenti
$Detail_from => undef
</%args>
<& SELF:TEMPLATE, Template => 'DIVS_TEMPLATE', Row => $row, Recordset => $Recordset, Display => $Display, Header => 0,
Controls => 0, Class => 'ROW_DIVS' , Detail_from => $Detail_from &>
% my @fields = &Method2Array('FIELDS');
% my $cols = @fields;
% push @Script_buffer, qq| ${Display}.bindEditComponentsRow($row, $cols, '_s_', '_l_', '_c_', '_');\n|;
% if(!$delay_script && @Script_buffer){
<script>
% $m->out(@Script_buffer);
% @Script_buffer=();
</script>
% }
</%method>
 
%# indicazione del campo nel recordset che determina il tipo di riga nel caso di template di tipo DIVS variabili
<%method FIELD_ROW_DIVS></%method>
 
%# tutte le righe <ROW_DIVS> per il browsing della tabella che hanno template differenti
%# restituisce del codice jscript che inizializza nell'oggetto DataBinding un array con i template
%# per i vari tipi riga da utilizzare dal client
<%method ALL_ROW_DIVS>\
<%args>
$row # riga nel form; nel caricamento dinamico potrebbe essere anche un TAG da usare poi per la sostituzione
$Recordset # nome dell'oggetto Recordset di riferimento
$Display
$delay_script => undef # ritarda l'esecuzione degli script associati ai componenti
</%args>
% foreach my $key ( undef ){ # elenco dei tipi; di default solo undef
<%$Display%>.divs['<%$key%>'] = "\
<%$m->scomp('SELF:ROW_DIVS', row => $row, form_type => $key, Recordset => $Recordset, Display => $Display, delay_script => 0) |js %>\
";
% }
% if(!$delay_script && @Script_buffer){
% $m->out(@Script_buffer);
% @Script_buffer=();
% }
</%method>
 
%# separatore tra le righe
<%method SEP_DIV><hr></%method>
 
%# generico elenco di record racchiuso in elementi <DIV>
%# tabella per il browsing della tabella del database
<%method DIVS>\
<%args>
$start => 0
$rows => 0
$where => undef
$max_rows => $rows
$Recordset => 'DIVS'
$Display => 'DISP_'.$Recordset
$inner => undef # se definito non viene generato il tag <DIV> che contiene le righe; usato dal Client per aggiornare le righe
$Header => 1
$Controls => 1
$Detail_from => undef # se definita viene inserito per ciascun record un bottone per richiamare un form separato per modificare/inserire il record
</%args>
% my @names = &Method2Array('FIELDS');
% if(!$inner){
% if($Header){
<& SELF:FORM_HEADER, %ARGS &>
% }
% if($Controls){
<& SELF:CONTROLS, %ARGS &>
% }
<div id="<%$Display%>_DIVS">
% }
% my $row_form = $m->base_comp->method_exists('DIVS_TEMPLATE') ? 'ROW_DIVS_TEMPLATE' : 'ROW_DIVS';
% for(my $j=0;$j<$rows; $j++){
%# un elemento <div/> per ogni record
% if($j){
<& SELF:SEP_DIV &>
% }
<div id="<%$Display%>_div_<%$j%>" class="DIVS_<% $j % 2 ? 'P' : 'D' %>" style="align:block;" onclick="<%$Display%>.selectRowFather(<%$j%>);">
<& "SELF:$row_form", row => $j, Recordset => $Recordset, Display => $Display, form_type => undef, delay_script => 1, Detail_from => $Detail_from &>
</div>
% # identificatore del tipo di template corrente
% }
% if(!$inner){
</div>
% }
<script>
% my $cols = @names;
%# Script_buffer BEGIN
% $m->out(@Script_buffer);
%# Script_buffer END
% @Script_buffer = ();
% my $field_row_divs = $m->scomp('SELF:FIELD_ROW_DIVS');
% if($field_row_divs =~ m/\w/){
%# includo nell'oggetto DataBinding i template
<& SELF:ALL_ROW_DIVS, row => '@@@', Recordset => $Recordset, Display => $Display, delay_script => 0 &>
%# metodo per individuare il tipo di riga
%# .type_div restituisce il tipo di form del record di posizione nel recordset "record"
<%$Display%>.type_div = function(id_row){
%# posizione del campo indicato in %method FIELD_ROW_DIVS>
% my $name = $m->scomp('SELF:FIELD_ROW_DIVS');
% $name =~ s/^\s*//;
% $name =~ s/\s*$//;
% if($name){
% my $pos=0;
% for(my $i=0; $i<@names; $i++){
% if($names[$i] eq $name){
% $pos=$i;
% last;
% }
% }
% # alla funzione/metodo indicata viene passato il parametro "id_row", posizione nel buffer;
% # deve restituire il tipo di riga da caricare
% # posizione in colonna nel recordset (vedi posizione dei campi)
return this.data[id_row][<%$pos%>];
% }else{
return null;
% }
};
% }
<%$Display%>.info = document.getElementById('<%$Display%>_info');
<%$Display%>.info.innerHTML = '? - ? ( ? )';
% if(@Script_buffer){
// Script_buffer BEGIN
% $m->out(@Script_buffer);
// Script_buffer END
% @Script_buffer = ();
% }
</script>
</%method>
 
%# generico form per il browsing della tabella del database
<%method FORM>\
<%args>
$Recordset => 'FORM'
$Display => 'DISP_'.$Recordset
$Header => 1
$Controls => 1
</%args>
% if($Header){
<& SELF:FORM_HEADER, %ARGS &>
% }
% if($Controls){
<& SELF:CONTROLS, %ARGS &>
% }
% my @names = &Method2Array('FIELDS');
<table class="FORM_form">
% my $rcol=0;
% for(my $col=0; $col<@names; $col++){
% if(!$rcol){
<tr>
<td align="right">\
% }
% $rcol++;
% my $n = $names[$col];
% $n =~ s/\s//g;
% my $description = $m->scomp('SELF:INFO', NAME => $n, WHAT => 'DESCR');
% my $hidden = $m->scomp('SELF:INFO', NAME => $n, WHAT => 'HIDDEN');
% $description =~ s/\/$//;
% my $nobr = ($description =~ s/\\$//); # abbiamo \ alla fine della descrizione
<span id="Descr_<%"${Display}_c_0_$col"%>" <% $hidden ? 'style="display:none;"' : '' %>><%$description%>:<span> \
% # se $nobr non devo iniziare una nuova riga, ma devo allineare il successivo campo nella stessa riga
% if($rcol == 1){ # prima colonna: attivo seconda colonna
</td>
<td class="nowrap">
% }
<span class="widget_span" id="Span_<%"${Display}_c_0_$col"%>" <% $hidden ? 'style="display:none;"' : '' %>>
<& SELF:GENERIC_FIELD, id => "${Display}_c_0_$col", Display => $Display, row => 0, col => $col, name => $n &>\
</span>
% if(!$nobr){
% $rcol=0;
</td>
</tr>
% }
% }
</table>
<script>
% my $cols = @names;
<%$Display%>.bindEditComponents(1, <%$cols%>, '_s_', '_l_', '_c_', '_');
<%$Display%>.info = document.getElementById('<%$Display%>_info');
<%$Display%>.info.innerHTML = '? ( ? )';
</script>
</%method>
 
%# generico form con formattazione lineare per il browsing della tabella del database
%# i campi vengono allineati nell'ordine in cui sono stati elencati
%# per interrompre una riga inserire il carattere "/" in fondo alla descrizione del campo
<%method LINEAR>\
<%args>
$Recordset => 'LINEAR'
$Display => 'DISP_'.$Recordset
$Header => 1
$Controls => 1
</%args>
% if($Header){
<& SELF:FORM_HEADER, %ARGS &>
% }
% if($Controls){
<& SELF:CONTROLS, %ARGS &>
% }
% my @names = &Method2Array('FIELDS');
<table class="LINEAR_form">
<tr><td class="nowrap">
% for(my $col=0; $col<@names; $col++){
% my $n = $names[$col];
% $n =~ s/\s//g;
<& SELF:GENERIC_D_FIELD, break => '</td></tr><tr><td class="nowrap">', descr_sep => ':',
name => $n, id =>"${Display}_c_0_$col", Display => $Display, row => 0, col => $col &>
% }
</td></tr>
</table>
<script>
% my $cols = @names;
<%$Display%>.bindEditComponents(1, <%$cols%>, '_s_', '_l_', '_c_', '_');
<%$Display%>.info = document.getElementById('<%$Display%>_info');
<%$Display%>.info.innerHTML = '? ( ? )';
</script>
</%method>
 
%# generico form con formattazione lineare per il browsing della tabella del database
%# i campi vengono inseriti nel template fornito <%method FORM_TEMPLATE> (o $Template, ad esempio DIVS_TEMPLATE)</%method>
%# ad esempio:
%# <%method FORM_TEMPLATE><p><DESCR:description>: <FIELD:description></p></%method>
%#
<%method TEMPLATE>\
<%args>
$Recordset => 'FORM'
$Display => 'DISP_'.$Recordset
$Header => 1
$Controls => 1
$Row => undef # if not defined will create a form with 1 row
$Template => 'FORM_TEMPLATE'
$Class => 'TEMPLATE'
</%args>
% if($Header){
<& SELF:FORM_HEADER, %ARGS &>
% }
% if($Controls){
<& SELF:CONTROLS, %ARGS &>
% }
<%perl>
my $row = $Row ? $Row : 0;
my $TEMPLATE = $m->scomp("SELF:$Template", %ARGS);
$TEMPLATE =~ s/\<INFO\>/<span id="${Display}_info"><\/span>/i;
$TEMPLATE =~ s/\<RECORD\>/<span class="${Class}_Sel" id="${Display}_l_$row"><\/span>/i;
$TEMPLATE =~ s/\<CHECKBOX\>/<input type="checkbox" class="checkbox" id="${Display}_s_$row">/i;
# sostituisco i campi nel template
$TEMPLATE =~ s/<DISPLAY>/${Display}/sg;
$TEMPLATE =~ s/<RECORDSET>/${Recordset}/sg;
my @names = &Method2Array('FIELDS');
for(my $col=0; $col<@names; $col++){
my $n = $names[$col];
$n =~ s/\s//g;
my $descr = $m->scomp('SELF:INFO', NAME => $n, WHAT => 'DESCR');
$descr =~ s/\\$//;
$descr =~ s/\/$//;
my $field = $m->scomp('SELF:GENERIC_FIELD', name => $n, id =>"${Display}_c_${row}_$col",
Display => $Display, , row => $row, col => $col, description => $descr);
$TEMPLATE =~ s/<DESCR:$n>/$descr/s;
if($TEMPLATE =~ m/<FIELD:$n>/s){
$TEMPLATE =~ s/<FIELD:$n>/$field/s;
}else{
die "Elemento mancante <FIELD:$n> nel template del recordset $Recordset\n";
}
}
</%perl>
<%$TEMPLATE%>
<script>
% my $cols = @names;
% if(!defined $Row){
<%$Display%>.bindEditComponents(1, <%$cols%>, '_s_', '_l_', '_c_', '_');
<%$Display%>.info = document.getElementById('<%$Display%>_info');
<%$Display%>.info.innerHTML = '? ( ? )';
% }
</script>
</%method>
 
<%method BUTTON_Ctrl_filter>
<%args>
$Display
</%args>
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" id="<%$Display%>_Ctrl_filter" type="button"
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons refresh', showLabel:true, title:'Applica il filtro di selezione ai dati'"
onclick="<%$Display%>.loadRecords('rewind')">Filtra</button>
</%method>
 
<%method BUTTON_Ctrl_printsel>
<%args>
$Display
$disp_print => undef
</%args>
% my $permission = Permission();
% $disp_print = $disp_print == 1 || ($disp_print eq '' && $permission->{Print}) ? '' : 'style="display: none;"';
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" id="<%$Display%>_Ctrl_printsel" type="button" <% $disp_print %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons print', showLabel:true, title:'Stampa la selezione filtrata'"
onclick="<%$Display%>.printSelected('recordset');">St.sel.</button>
</%method>
 
<%method BUTTON_Ctrl_xlssel>
<%args>
$Display
$disp_xls => undef
</%args>
% my $permission = Permission();
% $disp_xls = $disp_xls == 1 || ($disp_xls eq '' && $permission->{Xls}) ? '' : 'style="display: none;"';
<button disabled data-dojo-type="dijit/form/Button" class="controlBtn" id="<%$Display%>_Ctrl_xlssel" type="button" <% $disp_xls %>
data-dojo-props="tabIndex:-1, iconClass:'masonSqlIcons xls', showLabel:true, title:'Download selezione filtrata in formato XLS'"
onclick="<%$Display%>.printSelected('xls_recordset');">XLS</button>
</%method>
 
<%method INIT_FIND_FIELDS>
<%args>
$Display
$names
</%args>
<script>
% my $cols = @{$names};
masonSql.once('ready', function(data){
require(["dijit/registry"], function(registry){
var disp = <%$Display%>;
disp.navigationBar.filterButton = registry.byId('<%$Display%>_Ctrl_filter');
disp.navigationBar.printselButton = registry.byId('<%$Display%>_Ctrl_printsel');
disp.navigationBar.xlsselButton = registry.byId('<%$Display%>_Ctrl_xlssel');
disp.find_fields = [<%ListJscript('FIND_FIELDS', '', 'list') %>];
var finds = disp.finds = [];
var ftypes = disp.ftypes = [];
for(var col=0; col<<% $cols %>; col++){
finds[col] = document.getElementById('<%$Display%>_'+col+'_find');
ftypes[col] = document.getElementById('<%$Display%>_'+col+'_ftype');
}
% for(my $col=0; $col<$cols; $col++){
% my $name = $names->[$col];
% if(exists $ARGS{"find_value_$name"}){
var w = finds[<%$col%>];
w.init_find_value = '<%$ARGS{"find_value_$name"}|js%>';
w.set_value(w.init_find_value);
% }
% if(exists $ARGS{"find_sel_$name"}){
var w = ftypes[<%$col%>];
w.init_find_sel = '<%$ARGS{"find_sel_$name"}|js%>';
w.set_value(w.init_find_sel);
% }
% }
});
});
</script>
</%method>
 
<%method FIND>\
<%doc>
FIND: metodo per costruire un form per il filtraggio dei record ...
Al metodo FIND vengono passati tutti i parametri passati al form di inizializzazione
è possibile definire dei valori iniziali da inserire nei campi del form di filtro
aggiungendo dei parametri nel seguente modo: &find_value_<nome_campo>=VALORE&....
</%doc>
<%args>
$find_fields => $m->scomp('SELF:FIND_FIELDS') # elenco (nome1, nome2, nome3, ecc.) di campi da visualizzare per la ricerca
$Recordset
$Display
$disp_find_print => undef # ... pulsante stampa nella sezione di ricerca
$disp_find_xls => undef # ... pulsante espostazione XLS nella sezione di ricerca
</%args>
% my @names = &List2Array($find_fields);
% my $cols = @names;
%# $PLogger->debug(sub{ "NAMES= ", Dumper(\@names); });
<table class="FIND_form">
<tr><td class="nowrap">
% if($cols){
% for(my $col=0; $col<$cols; $col++){
% my $name=$names[$col];
% my $break=($name =~ s/\\$//);
% my $descr = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'FIND_DESCR');
% $descr =~ s/\\$//;
% $descr =~ s/\/$//;
<span class="widget_span" id="Span_find_<%$Display.'_'.$col%>">
<%$descr%>:<& SELF:GENERIC_FIND, readonly => 0, name => $name, id =>$Display.'_'.$col, description => $descr, Display => $Display, col => $col, class=>'|_FIND' &>
</span>
% if($break){
</td><td class="nowrap">
% }
% }
<& SELF:BUTTON_Ctrl_filter, Display => $Display &>
<& SELF:BUTTON_Ctrl_printsel, Display => $Display, disp_print => $disp_find_print &>
<& SELF:BUTTON_Ctrl_xlssel, Display => $Display, disp_xls => $disp_find_xls &>
% }
</td></tr>
</table>
<& SELF:INIT_FIND_FIELDS, %ARGS, names => \@names &>
</%method>
 
<%method FIND_MENU>\
<%doc>
FIND_MENU: metodo per costruire un form per il filtraggio dei record ...
</%doc>
<%args>
$find_fields => $m->scomp('SELF:FIND_FIELDS') # elenco (nome1, nome2, nome3, ecc.) di campi da visualizzare per la ricerca
$Recordset
$Display
$DescrOnRight => undef
$disp_find_print => undef # ... pulsante stampa nella sezione di ricerca
$disp_find_xls => undef # ... pulsante espostazione XLS nella sezione di ricerca
</%args>
% my @names = &List2Array($find_fields);
% my $cols = @names;
%# $PLogger->debug(sub{ "FIND_MENU cols=$cols fields='$find_fields'..."; });
%# $PLogger->debug(sub{ "NAMES= ", Dumper(\@names); });
%# $PLogger->debug(sub{ '#################################################', Dumper(\%ARGS); });
% if($m->base_comp->method_exists('FIND_MENU_PRE')){
<& SELF:FIND_MENU_PRE, find_fields => $find_fields, Recordset => $Recordset, Display => $Display &>
% }
<table class="FIND_MENU_form" id="<%$Display%>_elencoFiltriRestrizione">
% if($cols){
% for(my $col=0; $col<$cols; $col++){
<tr class="widget_span" id="Span_find_<%$Display.'_'.$col%>">
% my $name=$names[$col];
% my $break=($name =~ s/\\$//);
% my $descr = $m->scomp('SELF:INFO', NAME => $name, WHAT => 'FIND_DESCR');
% $descr =~ s/\\$//;
% $descr =~ s/\/$//;
% if($DescrOnRight){
<td class="nowrap" align="right"><%$descr%>: </td>
% }
<td class="nowrap"><p>
<%$DescrOnRight ? '' : $descr.':<br>'%>\
<& SELF:GENERIC_FIND, readonly => 0, name => $name, id =>$Display.'_'.$col,
Display => $Display, col => $col, description => $descr, class=>'|_FIND' &>
</p></td>
</tr>
% }
<tr><td class="nowrap" width="100%"<%$DescrOnRight ? ' colspan="2"' : ''%>><p align="center"><br>
<& SELF:BUTTON_Ctrl_filter, Display => $Display &>
<& SELF:BUTTON_Ctrl_printsel, Display => $Display, disp_print => $disp_find_print &>
<& SELF:BUTTON_Ctrl_xlssel, Display => $Display, disp_xls => $disp_find_xls &>
</p></td></tr>
% }
</table>
<& SELF:INIT_FIND_FIELDS, %ARGS, names => \@names &>
% if($m->base_comp->method_exists('FIND_MENU_POST')){
<& SELF:FIND_MENU_POST, find_fields => $find_fields, Recordset => $Recordset, Display => $Display &>
% }
</%method>
 
<%method WHERE></%method>
 
<%method FIND_FIELDS><& SELF:FIELDS &></%method>
 
<%method SORT_FIELDS><& SELF:FIND_FIELDS &></%method>
 
<%method CONFIRM_DEL_MESSAGE>Conferma cancellazione dei record selezionati</%method>
 
%# formato: id:table
%# id = chiave_locale key = tabella padre
<%method FATHER></%method>
 
%# metodo per ricavare il nome del campo da usare in insert e update
<%method FATHER_ID_NAME><%perl>
# identifico il nome del campo
# il campo è nel formato [tabella_join.]field:tabella_father[:id]
if(my $father = $m->scomp('SELF:FATHER')){
$father =~ s/\s//gs;
my($field, $father_name, $father_id) = split /\s*:\s*/, $father;
$m->out($field);
}
</%perl></%method>
 
%# metodo per ricavare la tabella padre
<%method FATHER_NAME><%perl>
# identifico il nome del campo
# il campo è nel formato [tabella_join].field:tabella_father[:id]
if(my $father = $m->scomp('SELF:FATHER')){
$father =~ s/\s//gs;
my($field, $father_name, $father_id) = split /\s*:\s*/, $father;
if($father_name !~ m/\./){
# aggiungo lo schema della tabella figlia
my $schema = $m->scomp('SELF:SCHEMA');
$father_name = "$schema.$father_name";
}
$m->out($father_name);
}
</%perl></%method>
 
%# metodo per ricavare il nome del campo della tabella padre
<%method FATHER_KEY_NAME>\
<%perl>
# identifico il nome del campo
# il campo è nel formato [tabella_join].field:tabella_father[:id]
if(my $father = $m->scomp('SELF:FATHER')){
$father =~ s/\s//gs;
my($field, $father_name, $father_id) = split /\s*:\s*/, $father;
if(!$father_id){
if($father_name !~ m/\./){
# aggiungo lo schema della tabella figlia
my $schema = $m->scomp('SELF:SCHEMA');
$father_name = "$schema.$father_name";
}
$father_name =~ s/\./\//;
my $father_table = $r->dir_config('DataBaseUrl').'/'.$father_name.'.mql';
if(!$m->comp_exists($father_table)){
die "Father $father_name not exists in FATHER method [$father]\n";
}
$father_id = $m->scomp("$father_table:KEY_NAME");
}
$m->out($father_id);
}
</%perl></%method>
 
%# metodo per ricavare il nome della tabella e del campo di join della tabella padre
<%method FATHER_TABLE_KEY_NAME>\
<%perl>
# identifico il nome del campo
# il campo è nel formato [tabella_join].field:tabella_father[:id]
if(my $father = $m->scomp('SELF:FATHER')){
$father =~ s/\s//gs;
my($field, $father_name, $father_id) = split /\s*:\s*/, $father;
if($father_name !~ m/\./){
# aggiungo lo schema della tabella figlia
my $schema = $m->scomp('SELF:SCHEMA');
$father_name = "$schema.$father_name";
}
$father_name =~ s/\./\//;
my $father_table = $r->dir_config('DataBaseUrl').'/'.$father_name.'.mql';
if(!$m->comp_exists($father_table)){
die "Father $father_name not exists in FATHER method [$father]\n";
}
if($father_id){
$father_id = $m->scomp("$father_table:FROM").'.'.$father_id
}else{
$father_id = $m->scomp("$father_table:KEY");
}
$m->out($father_id);
}
</%perl></%method>
 
<%method FATHER_WHERE>\
<%args>
$FATHER_ID
</%args>\
% my $field = $m->scomp('SELF:FATHER');
% # il campo è nel formato [tabella_join].field:tabella_father
% $field =~ s/\:.*//;
% $field =~ s/^\s+//;
% my $father_id = str2sql_js_delimited($FATHER_ID);
<% $field %> = <%$father_id%>\
</%method>
 
%# elenco separato da , di tabelle figlie
<%method CHILDREN></%method>
 
%# elabora elenco aggiungendo lo schema del padre, se non specificato
<%method SCHEMA_CHILDREN>\
<%perl>
my $children = $m->scomp('SELF:CHILDREN');
my $schema = $m->scomp('SELF:SCHEMA');
$children =~ s/\s+//g;
my @children = split /,/, $children;
for(my $C=0; $C<@children; $C++){
if($children[$C] !~ m|/|){
$children[$C] = $schema.'/'.$children[$C];
}
}
$m->out(join(',', @children));
</%perl>\
</%method>
 
%# tabella figlia selezionata (con container di tipo Tab o Accordion)
<%method CHILD_SELECTED></%method>
<%method SCHEMA_CHILD_SELECTED>\
<%perl>
my $child_selected = $m->scomp('SELF:CHILD_SELECTED');
my $schema = $m->scomp('SELF:SCHEMA');
$child_selected =~ s/\s+//g;
if($child_selected !~ m|/|){
$child_selected = $schema.'/'.$child_selected;
}
$m->out($child_selected);
</%perl>\
</%method>
 
%# elenco di nomi campo di "join" con le tabelle figlie (separato da ,)
<%method CHILDREN_FIELDS></%method>
<%method SELECT_CHILDREN_ID>\
<%args>
$FIELDS
$WHERE
$ORDER => $m->scomp('SELF:ORDER_BY')
</%args>\
select <% $FIELDS %> from <& SELF:JOIN_TABLES, %ARGS &> <% $WHERE %> <% $ORDER %>;\
</%method>
 
%# nome della funzione associata al comando; se non indicata corrisponde al nome della tabella
<%method FUNZIONE><& SELF:SCHEMA_FROM &></%method>
 
%# genera i permessi in base al profilo dei permessi dell'utente
<%method PERMISSION_BY_PROFILE>\
<%perl>
my $funzione = $m->scomp('SELF:FUNZIONE');
$funzione =~ s/^\s+|\s+$//;
my $Auth = $Session{Auth}{$funzione};
if(!defined $Auth){
die "Function $funzione is not defined in object ".$m->base_comp->path."\n";
}
my @permission;
for my $auth (keys %{$Auth}){
if($Auth->{$auth}){
push @permission, uc $auth;
}
}
#DEBUG $PLogger->debug(sub{ "PERMISSION_BY_PROFILE for ".$m->scomp('SELF:SCHEMA_FROM')." from $funzione: ".join(' ', @permission); });
$m->out(join(' ', @permission));
</%perl>\
</%method>
 
%# nome del file report da utilizzare
%# orientamento e nessun parametro aggiuntivo
<%method PRINT_FORM>\
% my $schema = $m->scomp('SELF:SCHEMA');
<& SELF:SCHEMA &>/<& SELF:FROM &>, PORTRAIT, \
</%method>
 
<%method DB_LOG>
<%args>
$type # tipo dell'aggiornamento (insert,update,delete))
$id # identificativo del record
$fields # hash dati modificati, inseriti o cancellati
$old_fields => undef # hash dati prima della modifica (opzionale)
$table_name => undef # nome tabella (opzionale)
</%args>
<%perl>
DB_log($type, $id, $fields, $old_fields, $table_name);
</%perl>
</%method>
 
%# Metodo per definire la stampa in formato PDF
%# Method that prints PDF and ODT reports.
<%method PDF>\
<%args>
$GROUP_ID => undef # Identification of the group of records that will be printed with Report Manager (see "record_id" table)
$report_ids => undef # The group of records that will be printed with ODT Reportman
$LANDSCAPE => undef
$report => undef
</%args>
<%perl>
# Process parameters ...
# PRINT_FORM which contains part of the report name, PORTRAIT/LANDSCAPE, REPORT_ID, various other parameters (for example KEY=100, Descr='Example report', K=5)
my @params = &List2Array($m->scomp('SELF:PRINT_FORM', %ARGS));
my $form_report = shift @params;
if($report){
$form_report .= $report;
}
# portrait or landscape
if($params[0] =~ m/portrait|landscape/i){
# The parameter is discarded because it is only used by the client to open the preview window
shift @params;
}
my $params = List2Params(join(', ', @params));
my $report_method = ReportMethod($form_report);
$form_report =~ s/\.(odt|pdf|rep)$//;
my $report_file = undef;
my $die_msg = '';
if($report_method eq 'rep'){
($report_file, $die_msg) = FindReportmanFile($form_report);
unless($report_file){
die $die_msg;
}
$m->comp('/lib/report.pdf',
base => $r->dir_config('DataBaseUrl'),
report => $form_report,
report_method => $report_method,
report_file => $report_file,
GROUP_ID => $GROUP_ID,
%{$params}
);
}else{
# When the REPORT_ID is passed as a cmd_parameter from ODT Reportman form, it overrides the values from the report_ids (see ODT Reportman documentation),
if(defined $params->{REPORT_ID}){
my @array = ($params->{REPORT_ID});
$report_ids = \@array;
delete $params->{REPORT_ID};
}
$m->comp('/lib/report.pdf',
report => $form_report,
report_method => $report_method,
report_ids => $report_ids,
%{$params}
);
}
</%perl>
</%method>
 
<%doc>
Il metodo FORM_KEYS_MOVEMENT definisce quali tasti attivare nella navigazione tra i campi del form:
ENTER - il tasto Invio(Enter) sposta il corsore nel campo sottostante
ARROWS - viene attivata la navigazione nelle quattro direzioni con i tasti freccia (arrow)
Esempio: <%method FORM_KEYS_MOVEMENT>ARROWS ENTER</%method>
</%doc>
<%method FORM_KEYS_MOVEMENT></%method>
 
<%perl>
############################################################################################# MAIN
### $PLogger->debug(sub{ 'PARAMETRI ARGS=', Dumper(\%ARGS); });
### ATTENZIONE: La normalizzazione delle veriabili viene fatta in init.comp
### e resa disponibile in %{$Session{ARGS}}
 
#DEBUG $PLogger->debug(sub{ "PARAMETRI ARGS=", Dumper($Session{ARGS}); });
$m->clear_buffer;
my $mime = $envelope_type{$ARGS{envelope_response}} || $mimelist{$method} || 'text/plain; charset=utf-8';
$r->content_type($mime);
# preload permissions and check minimal Read permission
Permission('Select');
#DEBUG $PLogger->debug(sub{ "method=$method\n".Dumper($Session{ARGS}); });
$m->base_comp->call_method($method, %{$Session{ARGS}});
</%perl>\
%# ATTENZIONE; è importante che questa riga termini senza <CR> finale
/tags/2.0/htdocs/lib/error.comp
0,0 → 1,102
<%perl>
$m->clear_buffer;
my $timestamp;
if($Session{Dbh}){
$Session{Dbh}->rollback;
my $sth = $Session{Dbh}->prepare('select now();');
$sth->execute;
$timestamp = $sth->fetchrow_arrayref->[0];
}else{
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
$timestamp = sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec;
}
my $status_code = $Session{StatusCode} || $r->status(400);
$r->status($status_code);
my @error = split /\t/, $error->as_line();
if($Session{'envelope_response'} eq 'json' || $Session{'envelope_response'} eq 'rest'){
$r->content_type('application/json; charset=utf-8');
if($Session{'envelope_response'} eq 'json'){
$r->headers_out->{'X-JSON-RPC'} = 'JSONError';
}
if($PLogger->level eq $DEBUG){
$m->out(MasonSQL::JSONRPCUtils::json_rpc_error_response($analyzed_error, $message, $status_code, $timestamp));
}else{
$m->out(MasonSQL::JSONRPCUtils::json_rpc_error_response('-', shift(@error), $status_code, $timestamp));
}
}elsif($Session{'envelope_response'} eq 'xml'){
$r->content_type('text/xml; charset=utf-8');
</%perl>
<?xml version="1.0" encoding="utf-8"?>
<error user="<%$Session{Login}%>" timestamp="<%$timestamp%>" code="<%$status_code%>">
<message><% shift @error |xml%></message>
% if($PLogger->level eq $DEBUG){
% for(my$L=1; $L<@error; $L++){
<debug row="<%$L%>"><%$error[$L]|xml%></debug>
% }
% }
</error>
<%perl>
}elsif($Session{'envelope_response'} eq 'none' || !defined($Session{'envelope_response'}) || $Session{'envelope_response'} eq '' ){
$r->content_type('text/html; charset=utf-8');
if($PLogger->level eq $DEBUG){
$m->out($error->as_html());
}else{
$m->out('<h3>', $error->as_brief(), '</h3>');
}
}else{
$r->content_type('text/html; charset=utf-8');
</%perl>
<html>
<head>
<title>Envelope error!</title>
</head>
<body>
<% "Envelope type \"$Session{'envelope_response'}\" is not valid!" %>
<% $error->as_html() %>
</body>
</html>
% }
<%once>
use Data::Dumper;
</%once>
<%init>
use Log::Log4perl;
my $error = $r->pnotes('error');
my $analyzed_error = $error->analyze_error();
my $message = "Operazione annullata!\n";
#DEBUG print STDERR Dumper({ANALIZED_ERROR => $analyzed_error, ERROR => $error->full_message(), DUMP_ERROR => Dumper($error)});
 
# Verifico se si tratta di un errore di integrità referenziale di PostgreSQL - ESEMPIO:
# 'DBD::Pg::st execute failed: ERROR: update or delete on table "soggetti" violates
# foreign key constraint "id_soggetto" on table "siti"
# DETAIL: Key (id)=(3763) is still referenced from table "siti"
 
if($error =~ m/^DBD::Pg::st execute failed: ERROR:\s*(.*)DETAIL:(.*)\.\s*\[for Statement/si){
my $sql_err = $1;
my $sql_err_detail = $2;
if($sql_err =~ m/duplicate key value violates unique constraint "(.*)"/si){
my $index = $1;
$message .= "Il valore immesso è già presente nell'archivio";
}elsif($sql_err =~ m/constraint "([^"]*)" on table "([^"]*)"/si){
my $constraint = $1;
my $table = $2;
$message .= "L'oggetto in $table non può essere cancellato/alterato in quanto\nci sono altri oggetti che vi fanno riferimento ($constraint).";
}else{
$message .= "Database error!";
}
if($PLogger->level eq $DEBUG){
$message .= "\n\n[".$error->full_message."]";
}
}else{
$message = $error->full_message();
}
if($PLogger){
$PLogger->error(sub{"envelope_response:$Session{envelope_response} - ".$error->as_string()});
}else{
print STDERR "envelope_response:$Session{envelope_response} - ".$error->as_string()
}
</%init>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/lib/httpRequestMason.js
0,0 → 1,550
<%doc>
Authors:
BA Brent Ashley <hReqMason_@megahuge.com> codice originario di partenza
GDO Guido brugnara <gdo@leader.it> tutte le modifiche successive
TRC Tarcisio Fedrizzi <tarch@leader.it>
 
24/02/2018 GDO
Limita l'esecuzione di "XMLHttpRequest" per evitare un Bug di Firefox che con più
di 6 chiamate pone in attesa le chiamate in più ma poi le riattiva solo dopo 15
secondi.
 
07/06/2006 TRC
Creata una funzione che gestisce in maniera ibrida GET e POST decidendo a seconda del
tipo dei dati passati se stringa array o null usa il metodo vecchio GET + oggetto in
get, se viene invece passato un oggetto utilizza il POST. Modificata anche la gestione
dell'oggetto XMLHttpRequest che per mozilla viene creato solo una volta all'inizio.
Corretto anche un errore che dipendeva dal fatto che i parametri per una callback
venivano attaccati all'oggetto ContextObj dopo la chiamata del timeout. Ora puo'
essere passato un oggetto come parametro al metodo hReqMason_ExecuteTimeout in maniera
che questo venga appiccicato all'oggetto contextObj selezionato dal pool nel campo
obj_parms.
07/05/2006 GDO
Eliminato dal codice l'utilizzo di container DIV/SPAN in quanto si utilizza unicamente XMLHttpRequest quale metodo per il download
 
30/04/2006 GDO
Riscrittura del codice con integrazione in Mason anche per differenziare il codice
tra IE e Moz.
12/04/2004 GDO
Libreria intermedia che utilizza le classi "XMLHttpRequest" per Mozilla e "Microsoft.XMLHTTP" per IE
che permettono un maggior controllo sugli errori durante il caricamento, compresi i casi
di mancata connessione per non risoluzione del DNS o errori dello stack TCP .... riscontrati
nel caso di reti congestionate (con il risultato non desiderato di errori di Timeout)
 
07/04/2004 GDO
Parameter format compatible with Mason
 
26/07/2001 BA Rel 2.0 (release utilizzata in partenza)
Il codice è derivato dal lavoro di Brent Ashley [hReqMason_@megahuge.com http://www.ashleyit.com/rs/]
la cui licenza Open Source è la seguente:
License:
 
You can use this however you like. I make no guarantees whatsoever that it
will suit your purpose. You take full responsibility for getting it working
properly and for any implications of its failure or inability to satisfy your
every need.
 
 
Possibili migliorie:
1) unica istanza oggetto XMLHttpRequest per ciascun "context"
2) gestione chiamate POST
 
</%doc>
 
dojo.require("dojo.json");
dojo.require("dojox.encoding.digests._base");
dojo.require("dojox.encoding.digests.MD5");
// callback pool needs global scope
var hReqMason_ContextPoolSize = 0;
var hReqMason_ContextMaxPool = 32;
var hReqMason_ContextPool = {};
var hReqMason_Interval = 200; // intervallo di verifica dello stato del caricamento
%#// numero massimo di chiamate XMLHttpRequest in esecuzione contemporaneamente
%#// In firefox 52 e 59 Quantum se >3 ogni tanto una chiamata non viene inviata
%#// anche se presente nel debug network, poi va in timeout.
var hReqMason_MaxConcurrent = <% $Session{Browser}->firefox ? 3 : 'hReqMason_ContextMaxPool' %>;
// constructor for context object
function hReqMason_ContextObj( contextID, tag ){
// properties
this.id = contextID;
this.tag = tag;
this.URL = null;
this.busy = false;
this.callStack = new Array();
// methods
this.POST = hReqMason_contextPOST;
var req = new XMLHttpRequest();
req.onload = httpRequest_handler;
req.onerror = httpRequest_handler;
req.hReqMason_obj = this;
this.httpRequest = req;
// annulla la chiamata
this.abort = hReqMason_abort;
}
 
// chiamata a conclusione del caricamento remoto
function httpRequest_handler(){
var httpRequest = this;
var contextObj = this.hReqMason_obj;
var contextID = contextObj.id;
var ERROR = 'ERROR';
var ERR = null;
switch(httpRequest.readyState) {
case 1,2,3:
ERR = 'Errore dal browser: '+httpRequest.status+' stato: '+httpRequest.readyState;
break;
case 4:
if(httpRequest.status == 200){
var headers = httpRequest.getAllResponseHeaders();
// get context object and invoke callback
var JSONResponse;
if(!(/X-JSON-RPC/i.test(headers))){
JSONResponse = {version:1.1, result:httpRequest.responseText};
}else{
JSONResponse = dojo.json.parse(httpRequest.responseText);
}
if(JSONResponse){
if(JSONResponse.error){
ERR = JSONResponse.error.message;
ERROR = 'SERVER';
window.status = 'Errore JSON ricevuto dal server';
}else{
window.status = 'Completato caricamento';
hReqMason_callbackStack(JSONResponse.result, contextID);
}
}else{
if(httpRequest.responseText.length == 0){
window.status = ERR = 'ERRORE: ricevuto inaspettatamente un messaggio vuoto';
}else{
window.status = ERR = 'ERRORE JSON: dati non validi ricevuti dal server';
ERR += '\n' +"[" + httpRequest.responseText + "]";
}
ERROR = 'SERVER';
}
}else if(httpRequest.status == 403){
ERR = 'Accesso negato; la sessione è probabilmente scaduta';
ERROR = 'AUTHFAILED';
window.status = 'Accesso negato';
}else{
if(httpRequest.status == 0 && httpRequest.responseText == ''){
ERROR = 'SERVER';
ERR = 'Il server non risponde';
}else{
var error = dojo.json.parse(httpRequest.responseText);
if(error){
ERROR = 'SERVER';
ERR = error.message;
}else{
ERR = httpRequest.status + ' ('+httpRequest.statusText + ')';
}
}
}
break;
}
if(ERR != null){
// verifico se l'oggetto esiste ancora, altrimenti tralascio l'errore, dato che l'oggetto è stato distrutto
if(contextObj){
hReqMason_Error(contextObj.id, ERR, 'Errore durante il caricamento dati ', ERROR)
}else{
concole.error('httpRequest_handler', httpRequest, ERR);
}
}
contextObj && contextObj.rspage != null && contextObj.abort();
return false;
}
 
 
//Sistemare content-type
function hReqMason_getURL(contextObj, URL, parm, doPost){
%#DEBUG// console.debug('hReqMason_getURL id:'+contextObj.id + ' ' + URL);
// make the call
contextObj.busy = true;
var req = contextObj.httpRequest;
%#DEBUG <% $JSLogger->debug(q|'hReqMason_getURL id:'+contextObj.id+' Post:' + doPost + ' URL:' + URL + ' PARM:'+parm|) %>\
req.open(doPost ? "POST" : "GET", URL, true);
req.setRequestHeader('Content-Type', 'multipart/form-data; charset=utf-8');
req.send(parm);
}
 
// Genera un id unico per le chiamate in "vecchio stile" =)
function getUnique(){
return ((new Date()).getTime() + '' + Math.floor(1000 * Math.random()));
}
 
// Nuova funzione che utilizza POST + JSON
// resa ora compatibile con la vecchia per
// gestire anche i casi gestiti in precedenza
// cosi' da poter fare il porting con calma
function hReqMason_contextPOST(){
var URL = this.rspage;
var parms = this.parms;
var strParms;
var post = null;
var doPost = false;
if (URL == null || URL == ''){
hReqMason_getURL(this, '/blank.html', null);
return;
}
URL += "?C=" + this.id;
URL += "&U=" + getUnique();
URL += "&envelope_response=json";
if (this.func != null){
URL += "&method=" + hReqMason_Escape(this.func);
if (parms != null){
if (parms.constructor == String){
// single parameter
URL += "&P=" + hReqMason_Escape('' + parms);
}else if (parms.constructor == Array){
for( var i=0; i < parms.length; i++ ){
URL += "&P=" + hReqMason_Escape('' + parms[i]);
}
}else if (typeof(parms) == "object"){ // parm type
URL = this.rspage;
URL += "?U=" + getUnique() + "&envelope_request=json";
var toSend = {version:"1.1", method:hReqMason_Escape(this.func), params:parms, envelope_response:"json"};
doPost = true;
post = dojo.json.stringify(toSend);
}else{
my_alert('Unhandled type ' + parms + ' !', 'txt');
return;
}
}
}
hReqMason_getURL(this, URL, post, doPost);
}
 
// end of context constructor
 
function hReqMason_GetContextID(tag){
var contextObj;
// riutilizza un contenitore libero
for (contextID in hReqMason_ContextPool){
var contextObj = hReqMason_ContextPool[contextID];
if(!contextObj.init && !contextObj.busy && contextObj.tag == tag){
contextObj.URL = null;
%#DEBUG// console.debug('hReqMason_GetContextID '+ contextObj.id + ' ' + tag);
return contextObj.id;
}
}
 
// if we got here, there are no existing free contexts
if ( hReqMason_ContextPoolSize <= hReqMason_ContextMaxPool ){
// create new context
var contextID = "hReqMason_" + (hReqMason_ContextPoolSize + 1);
hReqMason_ContextPool[ contextID ] = new hReqMason_ContextObj( contextID, tag );
hReqMason_ContextPoolSize++;
%#DEBUG// console.debug('hReqMason_GetContextID new ' + contextID + ' ' + tag);
return contextID;
} else {
my_alert( "hReqMason_ Error: context pool full", 'txt');
return null;
}
}
 
// verifico se c'è attiva una chiamata con la stessa URL (rspage)
function hReqMason_ContextFindURL(URL, tag){
var contextObj;
for (var contextID in hReqMason_ContextPool){
var contextObj = hReqMason_ContextPool[contextID];
if(contextObj.busy && contextObj.URL == URL && contextObj.tag == tag){
%#DEBUG// console.debug('hReqMason_ContextFindURL FINDED', URL, tag, contextObj);
return contextObj.id;
}
}
// var id = hReqMason_GetContextID(tag);
// contextObj = hReqMason_ContextPool[id];
%#DEBUG// console.debug('hReqMason_ContextFindURL NEW', URL, tag, contextObj);
// return id;
return hReqMason_GetContextID(tag);
}
 
// call a server routine from client code
function hReqMason_Execute( rspage, callback, func, parms){
return hReqMason_ExecuteTimeout(rspage, 30000, DefaultTimeout, callback, func, parms, null, null, null);
}
 
// abort the request
function hReqMason_abort(){
this.callStack = new Array();
// annullo timer timeout
window.clearTimeout(this.EtTimeout);
this.EtTimeout=null;
// annullo callback
this.EtCallback=null;
this.busy = false;
this.init = false;
this.rspage = null;
this.parms = null;
this.func = null;
this.URL = null;
// annullo chiamata
this.httpRequest.abort();
hReqMason_CheckPool();
}
 
// abort all the request
// richiamata dall'evento window close (window.onclose) per evitare che vi siano chiamate pendenti
// che arrivano dopo che la finestra è stata chiusa
function hReqMason_abort_all(){
for (var contextID in hReqMason_ContextPool){
hReqMason_ContextPool[contextID].abort();
}
}
 
// chiamata in caso di errore
//
function hReqMason_Error( contextID, str, str2, typeError ){
var contextObj = hReqMason_ContextPool[contextID];
if(str2 == null)
str2 = 'ERROR from server for ';
if(contextObj){
var callStack = contextObj.callStack;
contextObj.abort();
if (typeError == 'AUTHFAILED'){
var w = 540;
var h = 620;
var left = (screen.width - w) / 2;
var top = (screen.height - h) / 3;
window.open('/welcome.html?U='+getUnique(), 'masonSqlLogon', 'width='+w+',height='+h+',top='+top+',left='+left+',directories=no,location=no,menubar=no,status=no,toolbar=no');
}
// clean up and return context to pool
var contextCall;
while(contextCall = callStack.shift()){ //intentional assignment
if(contextCall.timeout_callback){
try{
contextCall.timeout_callback(contextID, typeError, str, contextCall.callback_obj);
}catch(err){
console.error('ERROR to execute timeout_callback:', err, str);
my_alert_error('ERROR to execute timeout_callback: '+err.message + '\n' +contextCall.timeout_callback.toString()+
'\n---------------------------\ntypeError:'+typeError+' str:'+str);
}
}else{
my_alert(str2+contextObj.URL+':\n['+unescape(str)+']', 'pre');
}
}
contextObj.abort();
}else{
my_alert('ERROR (no contextObj):\n['+unescape(str)+']', 'pre');
}
}
 
function hReqMason_Escape( thing ){
var R = escape(thing);
// Sostituzione per la corretta gestione del carattere euro
R = R.replace(/%u20AC/g, '%A4');
// sostituisco simbolo '+' per evitare che venga sostituito da ' ' sul server (MASON ???)
return R.replace(/\+/g, '%2B');
}
 
function hReqMason_Load_Callback(str, contextID) {
var contextObj = hReqMason_ContextPool[contextID];
var Dest = contextObj.obj_params.Loadobj;
//GDO my_alert("hReqMason_Load_Callback "+contextID+' URL='+contextObj.URL+'\n'+str, 'txt');
hReqMason_innerHTML(Dest, str);
var contextObj = hReqMason_ContextPool[contextID];
if(contextObj.obj_params.Loadcallback != null){
contextObj.obj_params.Loadcallback(contextObj.obj_params.Loadobj, contextID);
contextObj.obj_params.Loadcallback = null;
}
}
 
// recupera documento remoto e lo sostituisce nell'oggetto locale "obj" (SPAN, BODY, ecc.)
function hReqMason_Load(obj, callback, url, params){
return hReqMason_LoadTimeout(obj, 30000, DefaultTimeout, callback, url, params);
}
 
// recupera documento remoto e lo sostituisce nell'oggetto locale "obj" (SPAN, BODY, ecc.)
// supporta funzioni di callback su timeout della ricezione
function hReqMason_LoadTimeout(obj, timeout, timeout_callback, callback, url, params){
// obj.innerHTML='<p style="height: 100%"></p>';
if(url){
return hReqMason_ExecuteTimeout('/lib/getDocument.mason', timeout, timeout_callback, hReqMason_Load_Callback, url, params, null, { Loadobj: obj, Loadcallback:callback});
}
return null;
}
 
// funzione callback di hReqMason_ExecuteTimeout
function hReqMason_callbackStack(str, contextID) {
var contextObj = hReqMason_ContextPool[contextID];
//GDO my_alert("hReqMason_callbackStack("+contextID+","+str+")", 'txt');
window.clearTimeout(contextObj.EtTimeout);
contextObj.URL = null;
var contextCall;
// richiamo le callback presenti nello stack
while(contextCall = contextObj.callStack.shift()){ // intentional assignment
%#DEBUG// console.debug('contextCall callback', contextCall);
try{
contextCall.callback(str, contextID, contextCall.callback_obj);
}catch(err){
console.error('ERROR to execute callback:', err, contextCall.callback, contextID, contextCall.callback_obj, str);
my_alert_error('ERROR to execute callback: '+err.message+'\n----------\nstack:'+err.stack+'\n----------\ncallback:'+contextCall.callback.toString()+
'\n----------\ncontextID:'+contextID+' str:'+str);
}
}
}
 
// funzione di controllo dello stato di tutte le chiamate; provvede a lanciare le chiamate
// quando le chiamate parallele sono inferiori al limite prefissato
function hReqMason_CheckPool(){
// conto le chiamate attive e mi annoto la prima chiamata da attivare
var count = 0;
for (var contextID in hReqMason_ContextPool){
var contextObj = hReqMason_ContextPool[contextID];
if(contextObj.busy){
count++;
}
}
for (var contextID in hReqMason_ContextPool){
var contextObj = hReqMason_ContextPool[contextID];
if(count >= hReqMason_MaxConcurrent){
return;
}
if(contextObj.init){
count++;
contextObj.init = false;
contextObj.POST();
}
}
}
 
// funzione callback di hReqMason_ExecuteTimeout in caso di timeout ricezione
function hReqMason_EtTimeout(contextID) {
var contextObj = hReqMason_ContextPool[contextID];
if(contextObj){
// verifico se il conteggio degli intervalli è finito
contextObj.EtTimeoutCounter -= 1;
if(contextObj.EtTimeoutCounter>0){
if(!contextObj.init){
// chiamata in corso
var httpRequest = contextObj.httpRequest;
// verifico lo stato del caricamento del documento
if(httpRequest && httpRequest.readyState == 4 && httpRequest.status != 200){
hReqMason_Error(contextID, 'Errore durante il caricamento della pagina code:'+httpRequest.status + '\n\n' + httpRequest.responseText, 'Error from browser ', 'ERROR');
return;
}
}
// DEBUG// GDO window.status = 'caricamento '+contextObj.id+' '+contextObj.EtTimeoutCounter+' '+contextObj.URL;
// ritardo un'altro intervallo
contextObj.EtTimeout=window.setTimeout("hReqMason_EtTimeout('"+contextObj.id+"')", hReqMason_Interval);
}else{
contextObj.EtTimeout = null;
window.status = 'timeout '+contextObj.id+' '+contextObj.URL;
hReqMason_Error(contextID, 'Errore TIMEOUT durante il caricamento', 'Errore TIMEOUT', 'TIMEOUT');
}
}
}
 
// esegue il comando remoto con un timeout sulla ricezione
// rspage - href to asp file
// timeout - timeout for receive data
// timeout_callback - function to call on timeout
// callback - function to call on return
// or null if no return needed
// (passes returned string to callback)
// func - sub or function name to call
// parms - string parameter to function
// or array of string parameters if more than one
// tag - oggetto o tag o etichetta di riferimento per il riuso dei container nella stessa finestra
// (usato quando si hanno più finestre IFRAME)
// obj_params - oggetto che viene appiccicato al contextObj selezionato dalla ricerca nel pool
// callback_obj - oggetto passato alla chiamata della callback (se ci sono delle chiamate contemporanee ogni chiamata ha il suo oggetto)
// Restituisce l'oggetto della chiamata
function hReqMason_ExecuteTimeout(rspage, timeout, timeout_callback, callback, func, parms, tag, obj_params, callback_obj){
%#DEBUG// <% $JSLogger->debug(q|'hReqMason_ExecuteTimeout rspage:'+rspage+' timeout:'+timeout+' func:'+func+' parms:'+dojo.json.stringify(parms)+' tag:'+tag|) %>\
var NEW_URL=rspage+'->'+func;
if (!parms || parms.constructor == String || parms.constructor == Array){
NEW_URL += '(' + parms + ')';
}else{
NEW_URL += '#' + dojox.encoding.digests.MD5(dojo.json.stringify(parms), dojox.encoding.digests._base.outputTypes.Hex);
}
var contextID = hReqMason_ContextFindURL(NEW_URL, tag);
var contextObj = hReqMason_ContextPool[contextID];
contextObj.obj_params = obj_params;
//GDO my_alert("URL="+contextObj.URL+" NEW="+NEW_URL+" ID="+contextObj.id);
var contextCall = {
'contextObj': contextObj,
'callback': callback,
'callback_obj': callback_obj,
'timeout_callback': timeout_callback
};
// aggiungo nello stack la nuova richiesta
contextObj.callStack.push(contextCall);
if(contextObj.URL != NEW_URL){
// si tratta della prima chiamata
contextObj.rspage = rspage;
contextObj.func = func;
contextObj.parms = parms;
contextObj.URL = NEW_URL;
contextObj.init = true;
if(timeout != null && timeout){
contextObj.EtTimeoutCounter = (timeout/hReqMason_Interval)+1;
contextObj.EtTimeout = window.setTimeout("hReqMason_EtTimeout('"+contextObj.id+"')", hReqMason_Interval);
}else{
contextObj.EtTimeout = null;
}
hReqMason_CheckPool();
}
return contextObj.id;
}
 
function DefaultTimeout(contextID, err, str){
var contextObj = hReqMaso
n_ContextPool[contextID];
if(err == 'TIMEOUT'){
my_alert('Timeout ricezione dati URL ' + contextObj.URL + ' ID=' + contextID, 'txt');
}else{
my_alert('Errore ricezione dati URL ' + contextObj.URL + ' ID=' + contextIDerr+':\n'+str, 'txt');
}
}
 
// carica il codice HTML in "str" nell'oggetto DOM "Dest" preoccupandosi di eseguire il codice <sc*ipt>
function hReqMason_innerHTML(destination, str){
destination.disabled = false;
// distruggo eventuali widget presenti nel contenitore
dojo.forEach(dijit.findWidgets(destination), function(widget) {
widget.destroyRecursive(false);
});
// svuoto il contenitore
dojo.empty(destination);
// my_alert(str,'txt');
// my_alert("hReqMason_innerHTML MOZ\n"+str, 'txt');
try{
destination.innerHTML=str;
}catch(err){
console.error('hReqMason_innerHTML HTML', err, str);
my_alert_error('hReqMason_innerHTML HTML', err, str);
return;
}
var codelist = destination.getElementsByTagName('script');
// Nota: non usare direttamente codelist.length in quanto il numero di script cresce dinamicamente durante l'esecuzione
// se ci sono errori ...
var maxI = codelist.length;
for(var I=0; I<maxI; I++){
var code = codelist[I].text
try{
window.eval(code);
}catch(err){
console.log('hReqMason_innerHTML CODE('+I+')', err, code);
my_alert_error('hReqMason_innerHTML CODE('+I+')', err, code);
return;
}
}
//I=I-1; my_alert("LAST EVAL "+I+":\n"+codelist[I].text, 'pre');
%#DOJO dojo.addOnLoad(function(destination){
%#DOJO if(destination){
%#DOJO // parsing di eventuali widget Dojo
%#DOJO try{
%#DOJO dojo.parser.parse(destination);
%#DOJO }catch(err){
%#DOJO console.error('dojo.parser.parse', err, destination);
%#DOJO my_alert_error('dojo.parser.parse', err);
%#DOJO }
%#DOJO }
%#DOJO });
}
/tags/2.0/htdocs/lib/databinding.js
0,0 → 1,941
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2003 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
 
---+ libreria DataBinding
 
La libreria implementa un modello client-server per la gestione remota.
I dati in transito si limitano a <max_form_rows> righe che vengono visualizzate nel form.
 
I dati vengono collocati nella matrice <data[row,col]>, mentre le chiavi univoche nel
database vengono collocate nel vettore <keys[row]>.
 
Al caricamento del primo blocco di dati la libreria inizializza anche il seguente vettore:
* Vettore <names[col]> con i nomi dei campi nel database
 
Al caricamento dei blocchi dati vengono caricate le seguenti matrici, vettori:
* Matrice <data[row,col]> con i dati del recordset richiesto, un record per ogni riga
con i valori dei singoli campi disposti nella riga.
* Vettore <keys[row]> con le chiavi univoche dei record del recordset
 
Tutte le operazioni si modifica, inserimento e cancellazione tengono sincronizzati i dati tra
il database remoto ed i dati contenuti nell'oggetto.
 
 
---++ DataBinding Master -> Detail
 
E` implementato il meccanismo che permette la sinconizzazione dei dati di una tabella padre "master" con i
dati visualizzati di una o più tabelle figlie "detail".
 
La tabella padre viene rappresentata un record alla volta (form di tipo FORM, LINEAR o TEMPLATE),
mentre le tabelle figlie vengono rappresentate da form di tipo TABLE o DIVS ma anche FORM o LINEAR.
 
Per definire le relazioni tra le tabelle vanno definite nei file di definizione dei recordset (data/<recordset>.mql)
del padre i metodi CHILDREN e CHILDREN_FIELDS rispettivamente con l'elenco delle tabelle figlie ed elenco dei campi chiavi.
 
Per ciacuna delle tabelle figlie va invece definito il metodo FATHER con il valore <idref>:<table>:<key>, dove <idref>
è la chiave locale, <table> è il nome della tabella padre e <key> è il campo chiave della tabella padre corrispondente
a <key>; se omesso si fa riferimento alla chiave indicata nella tabella padre
Per attivare il meccanismo di sincronizzazione è necessario creare innanzitutto un DataBinding per ciascuna delle
tabelle interessate per poi completare nel DataBinding figlio l'attributo .father con il riferimento al DataBinding
del padre e nel padre l'attributo array .children[] con i riferimenti ai recordset figli.
 
A seguito della configurazione iniziale, ad ogni variazione del record visualizzato nel form padre si ha conseguentemente la
sincronizzazione delle tabelle figlie.
</%doc>
<%once>
my $DataBaseUrl = $r->dir_config('DataBaseUrl');
my $GetRecordTimeout = $r->dir_config('GetRecordTimeout');
</%once>
// variabile globale con i riferimenti nome --> oggetto DataBinding
DataBinding_ContextPool = {};
 
// Oggetto DataBinding per la navigazione di dati SQL nel browser
//
// constructor for DataBinding object
// Parametri:
// prefix - prefisso da utilizzare per i nomi dei campi nell'oggetto
// from - nome (senza .mql) della tabella
// max_table_rows - numero di righe a disposizione nella matrice
//
function DataBinding(prefix, from, max_table_rows){
// properties
this.max_table_rows = max_table_rows;
this.max_rows = null;
%#DEBUG//my_alert("DataBinding("+prefix+", "+from+", "+max_table_rows+")");
this.prefix = prefix;
this.from = from;
this.hReqMason_ID = null;
// timeout di attesa della risposta
this.timeout = <%$GetRecordTimeout%>;
// vettore delle chiavi (PK) del recordset
this.keys = [];
// posizione nell'array della riga di una determinata chiave record
this.pos_key = [];
// matrice dei dati non modificati
this.data = [];
// matrice dei parametri aggiuntivi associati ai dati (usato per i widget htmlselect divselect ecc.)
this.params = [];
// matrice dei dati da modificare sul server
this.new_data = [];
// vettore contenente i valori di default da attribuire ai campi
// indicati in <method FIELDS_NEW>
this.new_fields = [];
// vettore contenente le modalità con cui ciascun campo deve essere copiato da una duplicazione
// 'D' --> da copiare, 'd' --> copiare solo se != ''
// indicati in <method FIELDS_DUP>
this.dup_fields = [];
// determined with <method FIELDS_COPY_PASTE>
this.cp_fields = [];
// key of the copied row to be pasted with copy-paste method
this.cp_key = null;
// chiavi dei record duplicati (vedi displaybinding.js:DisplayBinding_onchangeHandler)
this.dup_keys = [];
// contiene i nomi dei campi nell'ordine in cui vengono forniti nella matrice (colonne)
this.names = [];
// vettore true/false dei campi che al salvataggio non devono essere vuoti
this.required_fields = [];
// contiene le descrizioni dei campi
this.descriptions = [];
// contiene le posizioni dei campi, individuati dal loro nome (è l'inverso di .names)
this.pos_name = {};
// componente select
this.select = '';
// clausola where nel formato json [ 'field', 'cond', value], ['--where', 'sql where'], ... ]
this.json_where = '';
// parametri supplementali da inviare al server
this.query_param = null;
// clausola "order by xxx"
this.orderby = '';
// posizione di inizio del recordset corrente
// inizializzato a null; dopo la prima connessione conterrà un intero da 0 a n-1 max_records
this.start = null;
// oggetto DataBinding padre (per la sincronizzazione di tabelle MASTER-->DETAIL)
this.father = null;
// array di oggetti DataBinding figli (per la sincronizzazione di tabelle MASTER-->DETAIL)
this.children = [];
// matrice di chiavi per selezionare i record figli;
// vedi <method SELECT_CHILDREN_ID> e <method CHILDREN_FIELDS>
this.fathers_id = [];
// riga del recordset da utilizzare quale padre delle tabelle figlie
this.rowFather = null;
// chiave per selezionare i record in base al codice della tabella MASTER
// == null o '' recordset di tipo master
// == -1 il padre non è definito (attenzione: lato server verrà restituito un figlio con elenco vuoto)
this.father_id = null;
// chiave per modificare i record in base al codice della tabella MASTER
this.father_id_update = null;
// utilizzato per anticipare la valutazione delle differenze
this._difference = null;
// select attivato
this.canSelect = false; // non è implementato questo controllo !!!!
// insert attivato
this.canInsert = false;
// delete attivato
this.canDelete = false;
// update attivato;
this.canUpdate = false;
// print attivato
this.canPrint = false;
// print all recordset attivato
this.canPrintsel = false;
// recordset in sola lettura
this.readonly = true;
// condizione di cambio stato solo lettura/scrittura
this.changed_readonly = false;
// matrice dei campi in sola lettura
this.fields_ro = [];
// vettore campi in sola lettura ma considerati in aggiornamento (tipico dei campi chiave)
this.fields_ro_update = [];
// definisco il comportamento quando ci sono due richieste di aggiornamento del recordset
this.delete_previus_req = false; // se true viene annullata la richiesta in corso ed inoltrata la nuova
// tipo di chiamata (top, up, down, inser, update, ecc.) in corso
this.call_mode = null;
// methods
// Save and restore row to be copied (used by Copy-Paste) during onrequest and onchange events
this.storeRowToCopy = DataBinding_storeRowToCopy;
this.retrieveRowToCopy = DataBinding_retrieveRowToCopy;
// restituisce la URL da inviare al server per ottenere la stampa in formato PDF
this.printUrl = DataBinding_printUrl;
// recupera i dati dal server (con inizializzazione del recordset)
this.loadRecords = DataBinding_loadRecords;
// lancia un metodo remoto sul server definito come CALL_REMOTE_<function>
this.callRemote = DataBinding_callRemote;
// posizionamento nel recordset corrente (recordset persistente nel server)
this.gotoRecords = DataBinding_gotoRecords;
// inizializzazione del recordset
this.initRecordset = DataBinding_initRecordset;
// Annulla le modifiche in corso
this.cancelUpdate = DataBinding_cancelUpdate;
// .type_div restituisce il tipo di form del record di posizione nel recordset "num_record"
// alla inizializzazione è null (funzionalità disabilitata)
this.type_div = null;
// modifica lo stato lettura/scrittura del recordset
this.readOnly = DataBinding_readOnly;
// cancella i record elencati in keyList
this.deleteRecords = DataBinding_deleteRecords;
// stato del download in corso. Accetta un parametro, se true l'eventuale download in corso viene abortito
this.statusDownload = DataBinding_statusDownload;
// restituisce il valore del campo (parametri nome campo e opzionale riga)
this.get_value = DataBinding_get_value;
// modifica il valore del campo (parametri nome campo e opzionale riga)
this.set_value = DataBinding_set_value;
// Aggiorna i recordset figli
this.updateChildren = DataBinding_updateChildren;
// dopo un aggiornamento indica se ci sono state variazioni nel recordset sul server
this.recordset_changed = null;
// eventi gestiti dall'oggetto recordset
this.onloadrecord = null; // richiama la funzione indicata quando arriva una richiesta di cambiamento del recordset
this.ondeleterecords = null; // richiama la funzione indicata quando arriva una richiesta di cancellazione di records
this.onrequest = null; // richiama la funzione indicata quando è iniziata una richiesta al server di cambio del recordset
this.onprechange = null; // richiama la funzione indicata al cambio del recordset, prima che i dati siano disponibili
this.onchange = null; // richiama la funzione indicata al cambio del recordset, quando i dati sono disponibili
this.onchange_children = null; // richiama la funzione indicata quando tutti i recordset (padre e figli) sono stati aggiornati
this.onpreload = null; // chiamata prima della prima inizializzazione
this.onload = null; // chiamata dopo la prima inizializzazione
this.onerror = null; // chiamata in caso di errore
this.onreadonly = null; // chiamata quando cambia lo stato lettura/scrittura
this.ondiff_recordset = null; // chiamata quando c'è una differenza nel recordset prima della trasmissione al server
}
 
// metodo readOnly
// modifica lo stato lettura/scrittura del recordset
// blocca ogni tentativo di inviare al server modifiche
// se al cambio del set c'è il record corrente modificato ... provvede prima ad aggiornarlo
// set == true/false stato readonly
// update == null|true provvede ad aggiornare il recordset prima di cambiare lo stato, se necessario
function DataBinding_readOnly(set, update){
if(set == null){
return this.readonly;
}
if(this.readonly == set){
this.changed_readonly = false;
return set;
}
this.readonly = set;
// funzione chiamata quando cambia lo stato lettura/scrittura
if(this.onreadonly){
this.changed_readonly = true;
this.onreadonly(set, update);
}
// se il recordset corrente è stato modificato prima di renderlo readonly ... provvedo ad aggiornare il record
if((update == null || update) && set){
// valuto se la differenza è stata gia calcolata (prima di azzerare i campi del form durante la trasmissione)
if(!this._difference){
this._difference = ArrayDiffKeys(this.keys, this.data, this.new_data, true);
//DEBUG my_alert('DataBinding_readOnly diff '+Array2String(this._difference, 'null'));
}
if(!this._difference.allNull()){
//DEBUG my_alert('DataBinding_readOnly('+set+','+update+') father='+this.father_id+' father_id_update='+this.father_id_update+' update '+Array2String(this._difference));
this.gotoRecords('update');
}
}
//DEBUG my_alert('DataBinding_readOnly('+set+','+update+') father='+this.father_id+' father_id_update='+this.father_id_update);
return set;
}
 
// funzione richiamata al termine del download
function DataBinding_Load_Callback(str, contextID){
// recupera l'oggetto associato al download
var db = DataBinding_ContextPool[contextID];
// se max_row è nullo questa è la prima volta che l'oggetto riceve risposte dal server
var first_time = (db.max_rows == null);
%#DEBUG//my_alert("Load_Callback prefix="+db.prefix+' from='+db.from+' max_table_rows='+db.max_table_rows+' str=\n\n'+str+'\n________');
db.hReqMason_ID = null;
// elimino il riferimento all'eventuale record duplicato in precedenza
db.dup_keys = [];
// evento primo caricamento
if(first_time && db.onpreload){
db.onpreload(db.call_mode, str);
}
// evento cambiamento dati disponibili
if(db.onprechange){
db.onprechange();
}
try{
// valuto i dati trasmessi dal server
window.eval(str);
}catch(err){
// potrebbe trattarsi di codice HTML inviato dal server (ad esempio codice di errore Mason)
var re_htmlCode = RegExp('<html>','i');
if(re_htmlCode.test(str)){
my_alert(str, 'html');
}else{
my_alert_error("DataBinding_Load_Callback", err, str);
}
}
if(first_time){
db.pos_name = {};
for(var col=0; col<db.names.length; col++){
db.pos_name[db.names[col]] = col;
}
}
// preparo il vettore inverso delle chiavi key --> row
for(var col=0; col<db.keys.length; col++){
db.pos_key[db.keys[col]] = col;
}
%#//DEBUG my_alert('db.data:'+Array2String(db.data,'NUL')+' db.data.length:'+db.data.length);
if(db.data.length == 0){
db.data[0] = new Array(db.cols);
db.params[0] = new Array(db.cols);
db.keys[0] = null;
db.fathers_id = [];
}
%#//DEBUG my_alert('db.data:'+Array2String(db.data,'NUL')+' db.cols:'+db.cols+' db.data.length:'+db.data.length);
if(db.rows < db.max_table_rows){
// completiamo le matrici con righe nulle
for(I=db.rows; I<db.max_table_rows; I++){
db.keys[I] = null;
db.data[I] = new Array(db.cols);
// copio i valori di default se presenti ...
var len = db.new_fields.length;
if(len > db.cols){
len = db.cols;
}
for(var J=0; J<len; J++){
db.data[I][J] = db.new_fields[J];
}
}
///my_alert(KeyArray2String(db.keys, db.data, 'null', true, 'false', db.dup_keys));
}
%#//DEBUG my_alert('db.data:'+Array2String(db.data,'NUL')+' db.cols:'+db.cols+' db.data.length:'+db.data.length);
// preparo la copia modificabile
db.new_data = DuplicaArray(db.data);
// forzo aggiornamento dello stato readonly corrente
// in quanto può dipendere dallo stato dei campi correnti
if(!db.readonly){
db.readonly = true;
db.readOnly(false);
}
// evento primo caricamento
if(first_time && db.onload){
db.onload(db.call_mode);
}
%#//DEBUG my_alert('db.data:'+Array2String(db.data,'NUL')+' db.cols:'+db.cols+' db.data.length:'+db.data.length);
// evento cambiamento dati disponibili
if(db.onchange){
db.onchange();
}
%#//DEBUG my_alert('db.data:'+Array2String(db.data,'NUL')+' db.cols:'+db.cols+' db.data.length:'+db.data.length);
db.updateChildren();
db.deferred_onload && db.deferred_onload.resolve();
}
 
// aggiornamento delle tabelle figlie
function DataBinding_updateChildren(row){
if(row == null){
row = this.rowFather == null ? 0 : this.rowFather;
}
if(this.children.length && this.fathers_id){
var children_id = this.fathers_id[row];
this.rowFather = row
var father = this;
require(['dojo/promise/all', 'dojo/Deferred'], function(all, Deferred){
// aggiorno i dati delle tabelle figlie collegate
var list_promises = [];
for(var I = 0; I < father.children.length; I++){
var child = father.children[I];
// aggiorno la chiave del record MASTER
// nel caso di record nuovo il valore della chiave è null, quindi restituisco -1
var father_id = children_id && children_id[I];
child.father_id = father_id == null ? -1 : father_id;
child.deferred_onload = new Deferred();
list_promises.push(child.deferred_onload.promise);
// lancio la richiesta
child.loadRecords('rewind');
}
all(list_promises).then(function(){
// terminato il caricamento dei nuovi recordset nei figli
father.onchange_children && father.onchange_children();
}, function(error){
father.onchange_children && father.onchange_children(error);
});
});
}
}
 
// preparo una stringa con la lista dei campi in keyList in formato ['v','v',...]
function DataBinding_paramList(keyList){
// preparo la stringa con la lista dei parametri in formato ['v','v',...]
for(var I=0; I<keyList.length; I++){
keyList[I] = "'" + keyList[I] + "'";
}
return '[' + keyList.join(',') + ']';
}
 
// stampa del recordset
// type: sel -> stampa della selezione corrente
// type: recordset -> stampa del recordset filtrato
// template: se definito identifica il report da utilizzare nella stampa
function DataBinding_printUrl(type, keyList, report, cmdParams){
//DEBUG: console.log('printUrl, type='+type+', report='+report+', cmdParams='+cmdParams);
var params = [];
//DEBUG my_alert("DataBinding_Print "+type+' keyList='+keyLis.join(','));
var F='.mql?method=pdf';
switch(type){
case 'sel':
if(report == null && !this.canPrint){ // test solo con il report standard
return null;
}
if(!keyList && !keyList.length){
return null;
}
var reportList = DataBinding_paramList(keyList);
// parametri da passare al server
params = ['reportlist', reportList, 'name', this.prefix, 'start',
this.start, 'rows', this.max_table_rows,
'orderby', this.orderby, 'json_where', this.json_where,
'father_id',this.father_id, 'father_id_update',this.father_id_update,
'query_param',this.query_param, 'report', report];
break;
case 'odt_rpt':
if(report == null && !this.canPrint){
return null;
}
if(!keyList && !keyList.length){
return null;
}
var reportList = DataBinding_paramList(keyList);
params = ['reportlist', reportList, 'report', report,
'cmd_parameters', cmdParams];
break;
case 'pdf_rpt':
if(report == null && !this.canPrint){
return null;
}
if(!keyList && !keyList.length){
return null;
}
var reportList = DataBinding_paramList(keyList);
params = ['reportlist', reportList, 'report', report,
'cmd_parameters', cmdParams];
break;
case 'xls_sel':
if(!this.canXls){
return null;
}
if(!keyList && !keyList.length){
return null;
}
var key_list = keyList.join(',');
// parametri da passare al server
params = ['name', this.prefix, 'key_list', key_list, 'orderby', this.orderby, 'rows', '',
'father_id',this.father_id ];
F='.xls?method=xls';
break;
case 'recordset':
if(!this.canPrintsel){
return null;
}
// parametri da passare al server
params = ['name', this.prefix, 'start', this.start,
'orderby', this.orderby, 'json_where', this.json_where,
'father_id', this.father_id, 'father_id_update',this.father_id_update,
'query_param',this.query_param, 'report', report];
break;
case 'create_recordset':
if(!this.canPrintsel){
return null;
}
// parametri da passare al server
params = ['create', 'auto', 'name', this.prefix, 'start', this.start,
'orderby', this.orderby, 'json_where', this.json_where,
'father_id', this.father_id, 'father_id_update',this.father_id_update,
'query_param',this.query_param];
break;
case 'xls_recordset':
if(!this.canXls){
return null;
}
// parametri da passare al server
params = ['name', this.prefix, 'start', this.start,
'orderby', this.orderby, 'json_where', this.json_where, 'rows', '',
'father_id', this.father_id, 'father_id_update',this.father_id_update,
'query_param',this.query_param];
F='.xls?method=xls';
break;
default:
return null;
}
var url = '<%$DataBaseUrl%>/'+this.from+F;
for( var i=0; i < params.length; i++ ){
url += "&P" + "=" + escape(''+params[i]);
}
//DEBUG my_alert(url);
return url;
}
 
function DataBinding_storeRowToCopy(){
disp = this.displayBinding;
if(disp.cp_row !== null){
this.cp_key = this.keys[disp.cp_row];
}
//console.log('storeRowToCopy cp_row='+disp.cp_row+', cp_key='+this.cp_key);
return;
}
 
function DataBinding_retrieveRowToCopy(){
disp = this.displayBinding;
disp.cp_row = null;
if(this.cp_key !== null){
for(var R=0; R < this.max_table_rows; R++){
if(this.cp_key == this.keys[R]){
disp.cp_row = R;
disp.cpRefreshRow(R);
break;
}
}
}
//console.log('retrieveRowToCopy cp_row='+disp.cp_row+', cp_key='+this.cp_key);
return;
}
 
// test stato del download in corso;
// return false se libero
// true se in corso
// null se non inizializzato
// se abort == true, viene abortito il download eventualmente in corso
function DataBinding_statusDownload(abort){
if(this.hReqMason_ID){
var contextObj = hReqMason_ContextPool[this.hReqMason_ID];
if(contextObj && contextObj.busy){
if(abort){
// annullo la chiamata in corso
contextObj.abort();
// e le chiamate in corso dei figli
for(var I = 0; I < this.children.length; I++){
this.children[I].statusDownload(true);
}
}
return true;
}else{
return false;
}
}else{
return null;
}
}
 
// elaborazione della query di selezione nel recordset
function DataBinding_loadRecords(mode, key){
%#//DEBUG my_alert('DataBinding_loadRecords mode='+mode+' key='+key);
// verifico se è stato caricato un primo recordset
if(this.start == null){
return this.initRecordset(mode, key);
}
// forzo il ricaricamento del recordset con il terzo parametro a true
return this.gotoRecords(mode, key, true);
}
 
// handler errore timeout su chiamata di .callRemote
function DataBinding_Timeout_callRemote(contextID, err, str){
var db = DataBinding_ContextPool[contextID];
if(db.onerror){
db.onerror(err, str);
}
db.deferred_onload && db.deferred_onload.reject(str);
}
 
// funzione richiamata al termine della chiamata a .callRemote
function DataBinding_callRemote_Callback(str, contextID){
// recupera l'oggetto associato al download da mettere a disposizione dello script inviato dal server
window.db_context = DataBinding_ContextPool[contextID];
%#DEBUG// my_alert("callRemote_Callback prefix="+db.prefix+' from='+db.from+' str=\n\n'+str+'\n____');
if(window.db_context){
window.db_context.hReqMason_ID = null;
}
if(str){
try{
// valuto i dati trasmessi dal server
window.eval('var db = window.db_context;\n' + str);
}catch(err){
// potrebbe trattarsi di codice HTML inviato dal server (ad esempio codice di errore Mason)
var re_htmlCode = RegExp('<html>','i');
if(re_htmlCode.test(str)){
my_alert(str, 'html');
}else{
my_alert_error("DataBinding_callRemote_Callback", err, str);
}
}
}
}
 
// lancia un metodo remoto sul server definito come CALL_REMOTE_<function>
function DataBinding_callRemote(remote_func, params, mode, win_params){
var call_params = {'caller':'.callRemote',
'name':this.prefix, 'orderby': this.orderby, 'json_where': this.json_where, remote_func_params:params,
'father_id': this.father_id, 'father_id_update':this.father_id_update,
remote_func_name: remote_func
};
if(mode == 'html'){
var db = this;
require(["dojo/json"], function(json){
var d = new Date();
var url_params = {
F: 'call_remote',
json_params: json.stringify(call_params),
Ver: '<%$Ver%>',
U: d.getTime() + '' + Math.floor(1000 * Math.random())
};
var X = win_params ? win_params.X : null;
var Y = win_params ? win_params.Y : null;
var title = win_params ? win_params.title : null;
masonSql_Dialog.openUrl('<%$DataBaseUrl%>/'+db.from+'.mql', url_params, X, Y, title);
});
}else{
this.hReqMason_ID = hReqMason_ExecuteTimeout('<%$DataBaseUrl%>/'+this.from+'.mql', this.timeout,
DataBinding_Timeout_callRemote, DataBinding_callRemote_Callback, 'call_remote', call_params);
DataBinding_ContextPool[this.hReqMason_ID] = this;
return this.hReqMason_ID;
}
}
 
// posizionamento in finestra del DataBinding
// mode:
// up su di una finestra
// down giù di una finestra
// top o forward dall'ultimo record
// bottom o rewind primo record
// changed salva i dati solo se risultano modificati nel form
// save salva le modifiche/inserimenti
// reload ricarica i dati
// insert si posiziona con almeno una riga vuota
// <numero> salta alla posizione nel recordset indicata
// update salva le modifiche/inserimenti e mantiene i dati visualizzati in modifica
// nota: il recordset restituito dal server contiene solo i dati modificati/inseriti
// key: chiave del record da ricercare nel recordset quale posizione da ritornare
// recordset: se true forza sul server il ricaricamento del recordset permanente
//
function DataBinding_gotoRecords(mode, key, recordset){
%#//DEBUG my_alert('DataBinding_gotoRecords mode='+mode+' key='+key+' recordset='+recordset);
// verifico se è in corso un download
if(this.statusDownload(this.delete_previus_req) && !this.delete_previus_req){
//annullo se c'è in corso un download e non ho abortito il precedente download
return false;
}
// chiamo la funzione utente, se definita prima di elaborare la richiesta
if(this.onloadrecord){
if(!this.onloadrecord(mode, key, recordset)){
// interrompo la chiamata se la funzione utente ritorna 'false'
return false;
}
}
%#//DEBUG my_alert('DataBinding_gotoRecords next .onloadrecord mode='+mode+' key='+key);
this.call_mode = mode;
// my_alert('DataBinding_loadRecords ' + this.prefix + ' mode=' + mode + ' key=' + key);
// tipo di caricamento finale del recordset:
// reload = select con i record nella posizione di partenza aggiornati in base all'ordinamento dei record corrente
// update = select mantenendo i record visualizzati
// save = esegue un salvataggio dei record modificati
var new_start;
var type;
switch(mode){
case 'reload':
new_start=this.start;
type='reload';
break;
case 'update':
new_start=this.start;
type='update';
break;
case 'changed':
// verifico se ci sono record modificati
if(!this._difference){
this._difference = ArrayDiffKeys(this.keys, this.data, this.new_data, true);
}
if(this._difference.allNull()){
this._difference = null;
return false;
}
new_start=this.start;
type='reload';
break;
case 'save':
// il metodo readOnly provvede anche all'aggiornamento del record corrente se risulta modificato
// metto il secondo parametro per disabilitare il test
this.readOnly(true, false);
new_start=this.start;
type='reload';
break;
case 'bottom':
case 'rewind':
new_start=0;
type='reload';
break;
case 'insert':
// campi di input in scrittura
this.readOnly(false);
new_start=this.max_rows-Math.floor(this.max_table_rows/4);
type='reload';
// new_start=this.max_rows-this.max_table_rows+1; // lascia vuota una sola riga
break;
case 'top':
case 'forward':
//this.max_rows-this.max_table_rows;
new_start = this.max_rows-this.max_table_rows;
type='reload';
break;
case 'up':
new_start=this.start+this.max_table_rows;
% if($r->dir_config('LastUpAsForward')){
if(new_start>=(this.max_rows-this.max_table_rows)){
new_start=this.max_rows-this.max_table_rows;
}
% }
type='reload';
break;
case 'down':
new_start=this.start-this.max_table_rows;
type='reload';
break;
default:
// verifico se numero
if(/\d+/.test(mode)){
new_start = mode > this.max_rows+1 ? this.max_rows : mode-1;
}else{
my_alert('ERROR DataBinding_loadRecords: Valore ('+mode+') per il posizionamento del record '+this.prefix+' non numerico', 'txt', 400,100);
return false;
}
type='reload';
// end case
}
if(new_start<0){
new_start=0;
}
if(new_start>this.max_rows){
new_start=this.max_rows;
}
// valuto se la differenza è stata gia calcolata (prima di azzerare i campi del form durante la trasmissione)
if(!this._difference){
this._difference = ArrayDiffKeys(this.keys, this.data, this.new_data, true);
}
var diff = KeyArray2String(this.keys, this._difference, 'undef', false, true, this.dup_keys);
if(diff != '[]' && this.ondiff_recordset){
this.ondiff_recordset(diff, mode, key, recordset);
}
// valore da attribuire al parametro che sul server determinerà il ricaricamento del recordset persistente
// 'new' il recordset viene rigenerato
// 'cache' viene usato il recordset corrente
// non definito: non viene utilizzato il recordset permanente sul server
recordset = recordset ? 'new' : 'cache';
%#//DEBUG my_alert('mode:'+mode+' diff:' + diff + "\n---------data----------\n" + KeyArray2String(this.keys, this.data, 'undef', false, true, this.dup_keys) + "\n---------new----------\n" + KeyArray2String(this.keys, this.new_data, 'undef', false, true, this.dup_keys) );
if(diff == '[]' || mode == 'reload'){
if(recordset && (mode == 'forward' || mode == 'top')){
// con un valore negativo il server lo interpreterà come valore di start riferito alla posizione in fondo al recordset
new_start = -this.max_table_rows;
}
this.hReqMason_ID=hReqMason_ExecuteTimeout('<%$DataBaseUrl%>/'+this.from+'.mql', this.timeout,
DataBinding_TimeoutData, DataBinding_Load_Callback, 'array',
{'caller':'gotoRecords', 'start':new_start,'type':type,'max_rows':this.max_rows,'rows': this.max_table_rows,'name':this.prefix,
'orderby': this.orderby, 'json_where': this.json_where, 'find_key': key, 'query_param':this.query_param,
'father_id': this.father_id, 'father_id_update':this.father_id_update,
'select': this.select, 'recordset': recordset});
}else{
if(mode == 'insert'){
// aggiungo la quantità di nuove righe da inserire
new_start += ArrayNewRowNum(this.keys, this._difference);
}
%#//DEBUG my_alert('call with mode='+mode+' new_start='+new_start+' type='+type+' diff=['+diff+']');
// invio la differenza
this.hReqMason_ID=hReqMason_ExecuteTimeout('<%$DataBaseUrl%>/'+this.from+'.mql', this.timeout,
DataBinding_TimeoutData, DataBinding_Load_Callback, 'array',
{'caller':'gotoRecords', 'update':diff,'type':type,'max_rows':this.max_rows, 'name':this.prefix, 'start':new_start,'rows': this.max_table_rows,
'orderby': this.orderby, 'json_where': this.json_where, 'find_key': key, 'query_param':this.query_param,
'father_id': this.father_id, 'father_id_update':this.father_id_update,
'select': this.select, 'recordset': recordset});
}
this._difference = null;
DataBinding_ContextPool[this.hReqMason_ID] = this;
// chiamo la funzione utente, se definita
if(this.onrequest){
this.onrequest();
}
return true;
}
 
// richiamata in caso di timeout o di errore
function DataBinding_TimeoutData(contextID, err, str){
var db = DataBinding_ContextPool[contextID];
// verifico se prima della richiesto lo stato del recordset era in modifica
if(db.changed_readonly && db.readonly){
// ricopio i dati originali da db.data in db.new_data
db.new_data = DuplicaArray(db.data);
// ripristino la condizione di modifica del recordset
db.readOnly(false);
}
if(db.onerror){
db.onerror(err, str);
}
// notifico nelle tabelle figlie
for(var I = 0; I < db.children.length; I++){
var child = db.children[I];
if(child.onchange){
child.onchange();
}
}
db.deferred_onload && db.deferred_onload.reject(str);
}
 
function DataBinding_initRecordset(mode, key){
// forzo la condizione di primo record caricato
this.max_rows = null;
// interrompo un eventuale download in corso
this.statusDownload(true);
var new_start;
switch(mode){
case 'reload':
case 'update':
case 'changed':
case 'save':
case 'down':
case 'up':
my_alert('ERROR DataBinding_initRecordset: Valore ('+mode+') per il posizionamento del record '+this.prefix+' non previsto');
return false;
break;
case 'bottom':
case 'rewind':
new_start=0;
break;
case 'top':
case 'forward':
new_start = 'forward';
break
case 'insert':
new_start = 'insert';
break;
default:
// verifico se numero
if(/\d+/.test(mode)){
new_start = mode>this.max_rows ? this.max_rows-1 : mode-1;
}else{
my_alert('ERROR DataBinding_initRecordset: Valore ('+mode+') per il posizionamento del record '+this.prefix+' non numerico', 'txt', 400,100);
return false;
}
}
//DEBUG my_alert('DataBinding_initRecordset('+mode+','+key+')');
//carico la tabella da visualizzare dall'inizio del recordset
this.hReqMason_ID=hReqMason_ExecuteTimeout('<%$DataBaseUrl%>/'+this.from+'.mql', this.timeout,
DataBinding_TimeoutData, DataBinding_Load_Callback,'array',
{'caller':'initRecordset', 'start':new_start, 'rows':this.max_table_rows, 'name':this.prefix,
'orderby':this.orderby, 'json_where':this.json_where, 'find_key': key, 'query_param':this.query_param,
'father_id':this.father_id, 'father_id_update':this.father_id_update,
'initRecordset':1, 'select': this.select, 'recordset': 'new'});
this.call_mode = mode;
DataBinding_ContextPool[this.hReqMason_ID] = this;
// download dati dal server in corso ...
if(this.onrequest){
this.onrequest();
}
return true;
}
 
// annulla le modifiche nel form
// key == chiave record da cercare
// pos == posizione nel recordset
// se viene indicato key o pos, oltre ad annullare il record lancia il caricamento
// del recordset puntando al record con key indicata
function DataBinding_cancelUpdate(key, pos){
if(!this.readOnly()){
// seleziono lo stato in sola lettura
this.readOnly(true, false);
// ripristino la copia originaria
this.new_data = DuplicaArray(this.data);
if(this.start < this.max_rows && !key && !pos){
// avviso nuovi dati disponibili
if(this.onchange){
this.onchange();
}
}else{
%#//DEBUG my_alert("---------data----------\n" + KeyArray2String(this.keys, this.data, 'undef', false, true, this.dup_keys) + "\n---------new----------\n" + KeyArray2String(this.keys, this.new_data, 'undef', false, true, this.dup_keys) );
// caso di annullamento da inserimento di un nuovo record
// mi posiziono in fondo al recordset
if(pos){
this.gotoRecords(pos);
}else{
this.gotoRecords('forward', key);
}
}
}
}
 
// cancella i record elencati in keyList
function DataBinding_deleteRecords(keyList){
//DEBUG my_alert('DataBinding_deleteRecords: ' + keyList.join(',') + '. max_table_rows='+this.max_table_rows+' start='+this.start+' max_rows='+this.max_rows);
if(!this.canDelete || !keyList || keyList.lenght ==0){
return false;
}
// verifico caso cancellazione record in fondo al recordset
if(this.max_table_rows == 1 && this.start >0 && this.start == (this.max_rows - 1) ){
this.start--;
}
// chiamo la funzione utente, se definita prima di elaborare la richiesta
if(this.ondeleterecords){
if(!this.ondeleterecords(keyList)){
// interrompo la chiamata se la funzione utente ritorna 'false'
return false;
}
}
this.hReqMason_ID = hReqMason_ExecuteTimeout('<%$DataBaseUrl%>/'+this.from+'.mql', this.timeout,
DataBinding_TimeoutData, DataBinding_Load_Callback, 'array',
{'caller':'deleteRecords', 'delete':DataBinding_paramList(keyList), 'name':this.prefix,
'start':this.start, 'rows': this.max_table_rows,
'orderby':this.orderby, 'json_where':this.json_where, 'query_param':this.query_param,
'father_id': this.father_id, 'father_id_update':this.father_id_update,
'select': this.select, 'recordset': 'cache'});
DataBinding_ContextPool[this.hReqMason_ID] = this;
// chiamo la funzione utente, se definita
if(this.onrequest){
this.onrequest();
}
return true;
}
 
// restituisce il valore del campo di nome 'name' e riga 'row'
// se 'name' o 'row' sono nulli restituisce rispettivamente la riga o la colonna del dataset
function DataBinding_get_value(name, row){
if(row == null){
var colums = [];
var pos = this.pos_name[name];
for(var R=0; R<this.data.length; R++){
colums[R] = this.data[R][pos];
}
return colums;
}else if(name == null){
return this.data[row];
}else{
return this.data[row][this.pos_name[name]];
}
}
 
// modifica il valore del campo di nome 'name' e riga 'row'
// se 'name' o 'row' sono nulli restituisce rispettivamente la riga o la colonna del dataset
function DataBinding_set_value(name, row, value){
if(row == null){
var pos = this.pos_name[name];
for(var R=0; R<this.data.length; R++){
this.data[R][pos] = value[R];
this.new_data[R][pos] = value[R];
}
}else if(name == null){
this.data[row] = value;
this.new_data[row] = value;
}else{
var pos = this.pos_name[name];
this.new_data[row][pos] = value;
this.data[row][pos] = value;
}
if(this._difference){
this._difference = null;
}
}
 
%# END databinding.js
/tags/2.0/htdocs/lib/getDocument.mason
0,0 → 1,60
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
 
in $method va indicato il nome del componente
in @P va indicato l'elenco dei parametri in numero pari con la convenzione di id1, value1, id2, value2, ecc.
</%doc>
<%attr>
Cache_MaxAge => 12*60*60
</%attr>
<%args>
$method
$C
@P => ()
</%args>
% $Global{'C'}=$C;
% $r->headers_out->{'Cache-Control'} = 'max-age='.$m->base_comp->attr('Cache_MaxAge');
<%perl>
$r->content_type('text/html');
# F=URL completa dei parametri
if($method !~ m|^/|){
# se il percorso è relativo (senza / iniziale) impongo il percorso del componente chiamante
$_ = $ENV{'HTTP_REFERER'};
s|.*//||;
s|^[^/]*/|/|;
s|/[^/]*$||;
$method = $_.'/'.$method;
}
my $query = $method;
$query =~ s/.*\?//;
$method =~ s/\?.*//;
$query = new CGI($query);
#DEBUG $PLogger->debug(sub{ "QUERYQUERYQUERY method='$method' ",Dumper($query); });
my $respond_mess = $m->scomp($method, $query->Vars);
#DEBUG $PLogger->debug(sub{ "RESPOND [$respond_mess]"; });
if(@Script_buffer){
$respond_mess .= "<!-- Script_buffer BEGIN -->\n<script>\n";
$respond_mess .= join('', @Script_buffer);
@Script_buffer = ();
$respond_mess .= "</script>\n<!-- Script_buffer END -->\n";
}
$m->out($respond_mess);
###$PLogger->debug(sub{ ('#' x 79)."\n".$respond_mess."\n".('#' x 79); });
</%perl>
<%flags>
inherit => '/init.comp'
</%flags>
<%shared>
</%shared>
<%once>
use Data::Dumper;
use URI::Escape;
</%once>
/tags/2.0/htdocs/lib/report.pdf
0,0 → 1,791
<%doc>
=head1 report.pdf
 
=head2 Revision
 
$Revision: $
 
=head2 Description
 
A component for generating MasonSQL reports in PDF or ODT format.
 
=head2 Arguments
 
B<Argument Name> | B<Default Value> | B<Description>
-------------------------------------------------------------------------------------------------
$base | $r->dir_config('DataBaseUrl') | The data directory.
$report | undef | The name of a new report file.
$report_method | undef | A report method (rep, pdf or odt).
$report_file | undef | A Reportman config filepath.
$GROUP_ID | undef | Identifier of a group of records to be printed
| | (see the report_id table).
$report_ids | undef | An array of records to be printed.
$landscape | undef | Deprecated.
$orientation | PORTRAIT | Deprecated.
$path_pdf | undef | If defined, determines ODT and PDF filepaths.
$send_pdf | 1 | The report is transmitted with the Mason request object.
$cups_printer | undef | If defined, instead of sending the file with $m->out(),
| | send the file to the indicated Cups printer.
 
=cut
</%doc>
<%init>
if(!$Session{Dbh_report}){
$Session{Dbh_report} = Auth_AC::AuthCookieHandler->connect($r, $r->dir_config('ReportDBIconnect'), 1);
}
</%init>
<%args>
$base => $r->dir_config('DataBaseUrl')
$report
$report_method => 'rep'
$report_file => undef
$GROUP_ID => undef
$report_ids => undef
$landscape => undef
$orientation => 'PORTRAIT'
$path_pdf => undef
$send_pdf => 1
$cups_printer => undef
</%args>
<%perl>
$Session{StatusCode} = 400;
=head2 Component Body
 
The component is called from the L<dbms_library.comp|https://www.leader.it/MasonSQL/DbmsLibraryComponent> from the L<PDF|https://www.leader.it/MasonSQL/DbmsLibraryReportMethods> method.
 
The procedure to print the report document:
 
=over 2
 
=item 1
 
If L<send_pdf|/Arguments> is set, clear the Mason request buffer and set C<content_type> to C<text/html>.
 
=item 2
 
Compose the L<temporary filepaths|/PrintPaths()> of the PDF and ODT report files.
 
=item 3
 
Create a new report file using the utility determined by the L<report_method|/Arguments>.
 
=over 2
 
=item a.
 
When the C<report_method> is C<rep>, print the complete B<.pdf> report with Report Manager using L<GROUP_ID|/Arguments>.
 
=item b.
 
When the C<report_method> is C<odt>, print single B<.odt> report with ODT Reportman.
 
=item c.
 
When the C<report_method> is C<pdf>, print the complete B<.pdf> report with ODT Reportman using L<group_ids|/Arguments>.
 
=back
 
=item 4
 
Process newly created report file.
 
=over 2
 
=item a.
 
If the PDF report file is present print it with L<PrintPdf()|PrintPdf()>.
 
=item b.
 
Otherwise if ODT report file is present print it with L<SendFile()|/SendFile()>.
 
=back
 
=back
 
=cut
if($send_pdf){
$m->clear_buffer;
$r->content_type('text/html');
}
$PLogger->debug(sub{ "report.pdf ARGS:".to_json(\%ARGS); });
my ($PDF, $ODT) = PrintPaths($report, $path_pdf);
if($report_method eq 'rep'){
my $exec = Reportman($base, $report, $report_file, $PDF, \%ARGS);
if(system @{$exec}){
my $exit_value = $? >> 8;
my $signal_num = $? & 127;
my $dumped_core = $? & 128;
$m->out("ERRORE: generazione report exit=[$exit_value] err=[$?]");
}
}elsif($report_method eq 'odt'){
OdtReport($report, $report_ids->[0], $ODT, \%ARGS);
}elsif($report_method eq 'pdf'){
my @pdf_reports = ();
my @odt_reports = ();
foreach my $REPORT_ID (@{$report_ids}){
PdfReport($report, $REPORT_ID, \@pdf_reports, \@odt_reports, \%ARGS);
}
CatPdfs(\@pdf_reports, $PDF);
UnlinkTmpReports(\@pdf_reports, \@odt_reports);
}
if(-f $PDF){
PrintPdf($report, $cups_printer, $send_pdf, $PDF, \%ARGS);
}elsif(-f $ODT){
if($send_pdf){
SendFile($report, $ODT, 'application/vnd.oasis.opendocument.text', 'odt');
}
}else{
die "ERRORE: il rapporto '$report' non ha generato alcun file PDF o ODT";
}
$Session{StatusCode} = 200;
</%perl>
<%shared>
</%shared>
<%once>
 
use MasonSQL::Report;
use MasonSQL::Report::OdtConv;
 
=head2 Once Block
 
=head3 SendFile()
 
Prints the new report file:
 
=over 2
 
=item 1
 
Opens the new report file for reading.
 
=item 2
 
Depending on the Apache version sets the C<Cache-Control>, C<Content-transfer-encodig> and the C<Content-disposition> L<Apache::Request|http://www.masonbook.com/book/chapter-7.mhtml> attributes.
 
=item 3
 
Outputs the content of the report file to the L<HTML::Mason::Request|http://www.masonbook.com/book/chapter-4.mhtml> buffer.
Raises an error in case any undefined character was detected.
 
=item 4
 
Then flushes the C<HTML::Mason::Request> buffer and deletes the report file after the file was read.
 
=back
 
=cut
sub SendFile($$$$){
my $report = shift;
my $file = shift;
my $content_type = shift;
my $extension = shift;
sysopen SENT_FILE, $file, 'O_RDONLY' || die "sysopen $file: $!";
$m->clear_buffer;
$r->content_type($content_type);
$r->headers_out->{'Cache-Control'} = 'max-age=0';
$r->headers_out->{'Content-transfer-encodig'} = 'binary';
$r->headers_out->{'Content-disposition'} = "inline; filename=$report.$extension";
my $start = time;
my $buffer;
# leggo il file generato a blocchi di 64Kbyte
while(my $numchar = sysread SENT_FILE, $buffer, 2^16){
if(undef $numchar){
die "sysread $file: $!";
};
$m->out($buffer);
$m->flush_buffer;
}
close SENT_FILE;
unlink $file;
### $m->print($_);
my $duration = time - $start;
$PLogger->debug(sub{ "duration=$duration" });
return;
}
 
=head3 PrintPdf()
 
Prints the created report file and handles a printing errors:
 
=over 2
 
=item *
 
If the C<PROTECT> argument is defined, encrypts the content of the report file using the C<qpdf> utility.
 
=item *
 
If the C<cups_printer> is defined, prints the report file using the C<lp> utility.
 
=item *
 
If the C<cups_printer> is not defined prints the report file with default subroutine L<SendFile|/SendFile()>.
 
=back
 
=cut
sub PrintPdf($$$$$){
my $report = shift;
my $cups_printer = shift;
my $send_pdf = shift;
my $PDF = shift;
my $args = shift;
if($args->{PROTECT}){
my $file_orig = $PDF.'_ORIG.pdf';
rename $PDF, $file_orig;
if(! -e '/usr/bin/qpdf'){
die "PrintPdf ERROR /usr/bin/qpdf not exists\n";
}
if(system '/usr/bin/qpdf', '--linearize', '--encrypt', '', $args->{PROTECT}, 40, '--modify=n', '--annotate=n', '--', $file_orig, $PDF){
my $exit_value = $? >> 8;
if($exit_value == 3){
# warning da trascurare
unlink $file_orig;
}else{
my $signal_num = $? & 127;
my $dumped_core = $? & 128;
my $err = $? == -1 ? $! : "err:$?";
die "ERRORE: qpdf - [$exit_value:$signal_num:$dumped_core] $err\n";
}
}else{
unlink $file_orig;
}
}
if($cups_printer){
if(! -e '/usr/bin/lp'){
die "PrintPdf ERROR /usr/bin/lp not exists\n";
}
if(!system '/usr/bin/lp', '-d', $cups_printer, $PDF){
$m->out("Stampa completata");
}else{
my $exit_value = $? >> 8;
my $signal_num = $? & 127;
my $dumped_core = $? & 128;
my $err = $? == -1 ? $! : "err:$?";
$m->out("ERRORE: errore di stampa - [$exit_value:$signal_num:$dumped_core] $err");
}
}elsif($send_pdf){
SendFile($report, $PDF, 'application/pdf', 'pdf');
}
return;
}
 
=head3 UpdateReportmanConfigFile()
 
The procedure to update Reportman's report configuration file:
 
=over 2
 
=item 1
 
If the report configuration file is older than the C<database_directory/report_name.rep> file it updates it with the content of the later file.
 
=item 2
 
During update it additionally updates the C<ADOConnectionString> with the current L<Apache config|https://www.leader.it/MasonSQL/DatabaseAccess#Apache> settings.
 
=item 3
 
At the end updates the L<report_file's|/Arguments> modification time.
 
=back
 
=cut
sub UpdateReportmanConfigFile($$$){
my $report = shift;
my $report_in = shift;
my $report_file = shift;
$PLogger->debug(sub{ "UpdateReportmanConfigFile report_in=$report_in"; });
my (undef, undef, undef, undef, undef, undef, undef, undef, $atime_report_in, $mtime_report_in) = stat($report_in);
if(-f $report_file){
# confronto le date dei due file
my (undef, undef, undef, undef, undef, undef, undef, undef, undef, $mtime_report_file) = stat($report_file);
if($mtime_report_in > $mtime_report_file){
# report esistente non aggiornato
unlink $report_file;
}
}
if(! -f $report_file){
open REP_IN, "<$report_in" or die "Can't open $report_in file for reading.";
open REP_OUT, ">$report_file" or die "Cant'open $report_file file for writing.";
my $ADO;
while(<REP_IN>){
if(m/^\s+ADOConnectionString\s+=\s*$/){
$ADO = 1;
last;
}
print REP_OUT $_;
}
if(!$ADO){
die "ERRORE: il report '$report' non contiene il parametro di connessione ADOConnectionString";
}
my $ADOConnectionString = '';
# leggo le righe del parametro ADOConnectionString
while(<REP_IN>){
if(m/^\s*'(.*)'\s*\+\s*$/){
$ADOConnectionString .= $1;
}elsif(m/^\s*'(.*)'\s*$/){
$ADOConnectionString .= $1;
last;
}else{
die "Error parsing .rep ADOConnectionString in file $report_in";
}
}
# sostituisco alcuni parametri
$_ = $r->dir_config('ReportmanADOserver');
$ADOConnectionString =~ s/;SERVER=[\w\d\.]+;/;SERVER=$_;/;
$_ = $r->dir_config('ReportmanADOdatabase');
$ADOConnectionString =~ s/;DATABASE=[\w_\-\.]+;/;DATABASE=$_;/;
$_ = $r->dir_config('ReportmanADOuser');
$ADOConnectionString =~ s/;USER=[\w_]+;/;USER=$_;/;
$_ = $r->dir_config('ReportmanADOpassword');
$ADOConnectionString =~ s/;PASSWORD=[^;]+;/;PASSWORD=$_;/;
print REP_OUT " ADOConnectionString = '$ADOConnectionString'\n";
# concludo la copia
while(<REP_IN>){
print REP_OUT $_;
}
close REP_OUT;
close REP_IN;
# set mtime del file report identico all'originale
utime $atime_report_in, $mtime_report_in, $report_file;
}
return;
}
 
=head3 Reportman()
 
Composes a command to be passed to the printreptopdf:
 
=over 2
 
=item 1
 
Verifies the L<base|/Arguments> directory.
 
=item 2
 
=over 2
 
=item *
 
If defined L<ReportmanADOserver|https://www.leader.it/MasonSQL/DatabaseAccess#Apache> variable, composes a Wine command.
 
=item *
 
If not defined L<ReportmanADOserver|https://www.leader.it/MasonSQL/DatabaseAccess#Apache> variable, composes a Kylix command.
 
=back
 
=item 3
 
As a commandline options, appends all argument C<name=value> pairs with an exception of the reserved arguments:
 
report,
base,
path_pdf,
send_pdf,
cups_printer,
PROTECT and
GROUP_ID
 
=back
 
Synopsis for printreptopdf:
 
printreptopdf 2.9a
Prints a report manager (.rep) file to a Adobe PDF file
Usage: printreptopdf [Options] -stdin|reportfilename [outputfilename]
-q Quiet mode, don't show progress
-from n Prints report from page pnum
-to n Prints report to page pnum
-copies n Prints pnum copies
-u Generate not compressed pdf
-m Generate Report Metafile Stream format
-collate Collate the copies
-csv Output to comma separated values
-svg Output to scalable vector graphics format
-ctxt Output to custom text
-csvseparator CSV output separator
-paramPARAMNAME=paramvalue Assign a value to a parameter
-stdin Read from standard input instead from a file
-text Generate text output with escape codes to print
-textdriver driver Use the text driver for text output
-oemconvert Force recode to oem for text output
-html Generate Html output
 
=cut
sub Reportman($$$$$){
my $base = shift;
my $report = shift;
my $report_file = shift;
my $PDF = shift;
my $args = shift;
my @EXEC = (); # comando e parametri di chiamata a Reportman
# test $base per sicurezza
$base = $base;
my $test = $r->dir_config('DataBaseUrl');
if($base != $r->dir_config('DataBaseUrl') && $base !~ m/^$test/){
die "Base report corrupted ($base).\n";
}
# nome report
if(!$r->dir_config('ReportmanADOserver')){
# script di esecuzione di Reportman
push @EXEC, $r->dir_config('ReportmanDir').'/printreptopdf.kylix';
}else{
# utilizzo la versione Windows di Reportman con il driver ADO che incorpora la stringa di connessione
my $report_in = request_to_comp_path("$base/$report.rep");
if(-s $report_in){
UpdateReportmanConfigFile($report, $report_in, $report_file);
}
# script di esecuzione di Reportman
push @EXEC, $r->dir_config('ReportmanDir').'/printreptopdf.wine';
}
# aggiungo i vari parametri
push @EXEC, '-q';
$PLogger->debug(sub{ Dumper($args); });
foreach my $key (keys %{$args}){
if($key !~ m/^report|base|path_pdf|send_pdf|cups_printer|PROTECT$/){
my $arg = $args->{$key};
if(defined $arg){
push @EXEC, "-param$key=$args->{$key}",
}
}
}
# aggiungo ai parametri il report
push @EXEC, $report_file;
# aggiungo ai parametri il file PDF
push @EXEC, $PDF;
$PLogger->debug(sub{ "report_params=",Dumper(\@EXEC); });
$PLogger->debug(sub{ Dumper(\%ENV); });
$PLogger->debug(sub{ "CALL ".' '.join(' ', @EXEC); });
return \@EXEC;
}
 
=head3 OdtReport()
 
Creates the ODT report.
 
Procedure to create ODT report:
 
=over 2
 
=item 1
 
The CLI options for creating the report are passed to the ODT Report's L<CLI parser|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#parse_cli()> as an array.
The required arguments are in the C<arg_name:arg_value> format.
The required arguments: C<config_path>, C<report_name> and C<odt_filepath>.
The rest of the arguments are L<added|/AddArgs()> to the array in the C<arg_name=arg_value> format.
 
=item 2
 
L<get_odt_report()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#get_odt_report()>
 
=item 3
 
L<get_odt_report_fields()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#get_odt_report_fields()>
 
=item 4
 
L<get_odt_report_portions()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#get_odt_report_portions()>
 
=item 5
 
L<make_report()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#make_report()>
 
=back
 
=cut
sub OdtReport($$$$){
my $report = shift;
my $REPORT_ID = shift;
my $odt = shift;
my $args = shift;
$report =~ s/\//\./;
$PLogger->debug(sub{ "OdtReport REPORT_ID=$REPORT_ID"; });
my @cli_options = (
'config_path:'.$r->dir_config('ConfigPath'),
'report_name:'.$report,
'odt_filepath:'.$odt
);
AddArgs(\@cli_options, $REPORT_ID, $args);
my $rpt = MasonSQL::Report->new(
OdtConvEngine => $r->dir_config('OdtConvEngine'),
Dbh => $Session{Dbh_report},
TmpDir => $r->dir_config('TmpDir'),
InputFilesArchive => $r->dir_config('InputFilesArchive'),
Cli_options => \@cli_options
);
unless($rpt->make_report){
die "Base filename must be specified when creating ODT report!";
}
if(my $out = $rpt->output){
$PLogger->debug(sub{ "OdtReport out=[\n$out\n]"; });
}
$rpt = undef;
return;
}
 
=head3 PdfReport()
 
Creates the PDF report.
 
Procedure to create PDF report:
 
=over 2
 
=item 1
 
The CLI options for creating the report are passed to the ODT Report's L<CLI parser|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#parse_cli()> as an array.
The required arguments are in the C<arg_name:arg_value> format.
The required arguments: C<config_path>, C<report_name>, C<odt_filepath> and C<pdf_filepath>.
The rest of the arguments are L<added|/AddArgs()> to the array in the C<arg_name=arg_value> format.
 
=item 2
 
L<get_odt_report()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#get_odt_report()>
 
=item 3
 
L<get_odt_report_fields()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#get_odt_report_fields()>
 
=item 4
 
L<get_odt_report_portions()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#get_odt_report_portions()>
 
=item 5
 
L<make_report()|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#make_report()>
If PDF filepath is created convert it to PDF format with Unoconv or Libreoffice.
If any attachments exist also L<append|https://www.leader.it/MasonSQL/SrcLibMasonSQLReportPm#add_attachments()> them to the converted PDF.
 
=item 6
 
Push the generated report to the list of reports which will be later concatenated into one PDF.
 
=back
 
=cut
sub PdfReport($$$$$){
my $report = shift;
my $REPORT_ID = shift;
my $pdf_reports = shift;
my $odt_reports = shift;
my $args = shift;
my $pdf = &TmpFile("pdf_report", '.pdf');
my $odt = &TmpFile("odt_report", '.odt');
$report =~ s/\//\./;
$PLogger->debug(sub{ "PdfReport REPORT_ID=$REPORT_ID odt=$odt pdf=$pdf report=$report" });
$report =~ s/\//\./;
my @cli_options = (
'config_path:'.$r->dir_config('ConfigPath'),
'report_name:'.$report,
'odt_filepath:'.$odt,
'pdf_filepath:'.$pdf
);
AddArgs(\@cli_options, $REPORT_ID, $args);
my $rpt = MasonSQL::Report->new(
OdtConvEngine => $r->dir_config('OdtConvEngine'),
Dbh => $Session{Dbh_report},
TmpDir => $r->dir_config('TmpDir'),
InputFilesArchive => $r->dir_config('InputFilesArchive'),
Cli_options => \@cli_options
);
my $pdf_filepath = $rpt->get_pdf_filepath;
if(my $odt_filepath = $rpt->make_report){
if(-z $odt_filepath){
die "PdfReport running make_report: $odt_filepath is empty\n";
}
my $main_report = $pdf_filepath.'_main.pdf';
my $converter = MasonSQL::Report::OdtConv->new(Engine => $r->dir_config('OdtConvEngine'));
$converter->convert_to_pdf($odt_filepath, $main_report);
unlink $odt_filepath;
$rpt->add_attachments($main_report, $pdf_filepath);
unlink $main_report;
}else{
$rpt->add_attachments('', $pdf_filepath);
}
if(my $out = $rpt->output){
$PLogger->debug(sub{ "OdtReport out=[\n$out\n]"; });
}
$rpt = undef;
push(@{$pdf_reports}, $pdf);
push(@{$odt_reports}, $odt);
return;
}
 
=head3 CatPdfs()
 
Concatenate multiple PDFs into one PDF.
The concatenation is made with C<pdftk> executable, with the command:
 
pdftk <filepath1> <filepath2> ... <filepathN> cat output <output_filepath>
 
=cut
sub CatPdfs($$){
my $pdf_reports = shift;
my $PDF = shift;
foreach my $file (@{$pdf_reports}){
if(! -e $file){
die "CatPdfs ERROR file '$file' in list not exists\n";
}
if(-z $file){
die "CatPdfs ERROR file '$file' in list is empty\n";
}
}
my $pdftk = '/usr/bin/pdftk';
if(! -e $pdftk){
die "CatPdfs ERROR $pdftk not exists\n";
}
my @cmd = ($pdftk);
push(@cmd, @{$pdf_reports});
push(@cmd, 'cat');
push(@cmd, 'output');
push(@cmd, $PDF);
RunCmd('CatPdfs', \@cmd);
return;
}
 
=head3 UnlinkTmpReports()
 
Unlink temporary B<.pdf> and B<.odt> files.
 
=cut
sub UnlinkTmpReports($$){
my $pdf_reports = shift;
my $odt_reports = shift;
foreach my $odt (@{$odt_reports}){
$PLogger->debug(sub{ "unlink $odt" });
unlink $odt;
}
foreach my $pdf (@{$pdf_reports}){
$PLogger->debug(sub{ "unlink $pdf" });
unlink $pdf;
}
return;
}
 
=head3 RunCmd()
 
L<Run|http://search.cpan.org/~toddr/IPC-Run-0.94/lib/IPC/Run.pm> command.
Print the command output to the debug log.
In case an error is detected, pass on the error message and die.
 
=cut
sub RunCmd($$){
my $name = shift;
my $cmd = shift;
my ($err, $out);
#DEBUG $PLogger->debug(sub{ "run: name:$name ".Dumper($cmd); });
if(run $cmd, \undef, \$out, \$err){
if($out){
$PLogger->debug(sub{ "$name out=[\n$out\n]"; });
}
if($err){
$PLogger->error(sub{ $err });
}
}else{
my $mess_run = "ERROR '$?' Run('".(join "', '", @$cmd)."')";
#DEBUG print STDERR "$mess_run\nSTDOUT:[$out]\nSTDERR:[$err]\n";
$out =~ s/\n/ - /sg;
$err =~ s/\n/ - /sg;
$PLogger->error("$mess_run - STDOUT:[$out] STDERR:[$err]\n");
if($PLogger->level eq $DEBUG){
die "$mess_run - STDOUT:[$out] STDERR:[$err]\n";
}else{
die "$mess_run - Details in logs!\n";
}
}
return;
}
 
=head3 AddArgs()
 
Appends all arguments (along with the REPORT_ID) to the command line with exception of the reserved arguments. The reserved arguments are:
 
report,
base,
path_pdf,
send_pdf,
cups_printer and
PROTECT
GROUP_ID
 
=cut
sub AddArgs($$$){
my $cmd = shift;
my $REPORT_ID = shift;
my $args = shift;
push (@{$cmd}, "REPORT_ID=$REPORT_ID");
foreach my $key (keys %{$args}){
if($key !~ m/^report|base|path_pdf|send_pdf|cups_printer|PROTECT|GROUP_ID$/){
my $arg = $args->{$key};
if(defined $arg){
push (@{$cmd}, "$key=$args->{$key}");
}
}
}
return;
}
 
=head3 PrintPaths()
 
Returns a newly created temporary ODT and PDF filepaths.
In case the L<path_pdf|/Arguments> is defined it uses it for filepath instead of composing it with L<TmpDir|https://www.leader.it/MasonSQL/DatabaseAccess#Apache> directory root path.
 
=cut
sub PrintPaths($$){
my $report = shift;
my $path_pdf = shift;
my $PDF = '';
my $ODT = '';
if($path_pdf){
$PDF = $path_pdf;
$ODT = $path_pdf;
$ODT =~ s/\.pdf$/\.odt/;
}else{
my $tmp_dir = $r->dir_config('TmpDir');
$PDF = "$tmp_dir/report.$$.pdf";
$ODT = "$tmp_dir/report.$$.odt";
}
#DEBUG $PLogger->debug(sub{ "ODT=$ODT"; });
#DEBUG $PLogger->debug(sub{ "PDF=$PDF"; });
return ($PDF, $ODT);
}
 
=head3 TmpFile()
 
Uses L<File::Temp::tempfile|http://search.cpan.org/~dagolden/File-Temp-0.2304/lib/File/Temp.pm> to create a new temporary file.
Closes the file, to make sure it is unlocked, then returns its filepath.
 
=cut
sub TmpFile($$){
my $prefix = shift;
my $suffix = shift;
my($fh, $filepath) = tempfile(
$prefix . '_XXXXX',
DIR => $r->dir_config('TmpDir'),
SUFFIX => $suffix,
UNLINK => 0
);
close $fh;
#DEBUG $PLogger->debug(sub{ "TmpFile=$filepath"; });
return $filepath;
}
 
=head2 Copyright
 
(C) 2003 Leader.IT di Guido Brugnara <http://www.leader.it>
Strada della Pozzata, 41 - Villazzano
38123 T R E N T O (ITALY)
 
=head2 Authors
 
Guido Brugnara <gdo@leader.it>
=cut
</%once>
<%flags>
inherit => '/init.comp'
</%flags>
/tags/2.0/htdocs/lib/head_style.comp
0,0 → 1,15
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2006 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
Componente utilizzato per dichiarare degli <STYLE/> tag che verranno interiti
nell'intestazione della pagina html.
</%doc>
<%perl>
push @{$Global{LoadHeader_Style}}, $m->content;
</%perl>
/tags/2.0/htdocs/lib/library.js
0,0 → 1,681
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2003 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%once>
my $GetRecordTimeout = $r->dir_config('GetRecordTimeout');
my $GetFormTimeout = $r->dir_config('GetFormTimeout');
</%once>
// libreria di funzioni generiche
require(["dijit/Dialog", "dijit/form/Button"]);
 
%#//DOJO1.8 dojo.require("dijit.Dialog");
%#//DOJO1.8 dojo.require("dijit.form.Button");
 
%#// VEDI http://dojotoolkit.org/reference-guide/1.8/dijit/focus.html
%#// BEGIN DEBUG
%#// require([ "dijit/focus" ], function(focusUtil){
%#// focusUtil.watch("activeStack", function(name, oldValue, newValue){
%#// console.debug("Focused widget + ancestors: ", newValue.join(", "));
%#// });
%#// focusUtil.on("widget-focus", function(widget){
%#// console.debug("Focused widget", widget);
%#// });
%#// focusUtil.on("widget-blur", function(widget){
%#// console.debug("Blurred widget", widget);
%#// });
%#// });
%#// END DEBUG
 
require(["dojo/_base/declare", "dojo/Evented", "dijit/registry", "dojo/_base/array", "dojo/_base/fx", "dojo/dom-construct", "dojo/dom"],
function(declare, Evented, registry, array, fx, domConstruct, dom){
// Nuova classe masonSql
var MasonSql = declare(Evented, {
version: '1.0',
disp: {},
createDisplay: function(name, from, rows){
if(this.disp[name]){
var mess = "Display 'name' già esistente";
my_alert(mess);
console.error(mess, this.displays[name]);
}
var recordset = new DataBinding(name, from, rows);
var display = new DisplayBinding(name, recordset);
this.disp[name] = display;
return display;
},
ready: function(obj){
this.emit("ready", obj);
},
once: function(evt, func){
var handler = this.on(evt, function(data){
func(data);
handler.remove();
});
},
%# // richiamata da /frame.html quando viene lanciato l'evento masonSql ready (al termine del caricamento e rendering dojo)
frameLoad_Handler: function(prefix, with_children, height){
%# // dimensione finestra principale (solo se vi sono finestre figlie)
var FatherMain = registry.byId('FatherMain_'+prefix);
if(with_children){
var FatherMainDom = FatherMain.get("containerNode");
if(!height){
height = 0;
var heigh_centr = 0;
array.forEach(FatherMain.getChildren(), function(child){
var region = child.get("region");
var container = child.get("containerNode")
if(region == 'top' || region == 'bottom'){
height += container.offsetHeight;
}else if(heigh_centr < container.scrollHeight){
heigh_centr = container.scrollHeight
}
});
height += heigh_centr;
}
console.debug('Resize form ' + FatherMainDom.id + ' to ' + height + 'px');
% # riscontrato in Chrome e Safari la necessità di ridimensionare due volte per evitare l'attivazione delle barre di scorrimento
% if($Session{Browser}->chrome || $Session{Browser}->webkit){
FatherMainDom.style.height = (height + 50).toString()+'px';
FatherMain.getParent().resize();
% }
FatherMainDom.style.height = (height + 4).toString()+'px';
}
FatherMain.getParent().resize();
fx.fadeOut({
node: dom.byId('loadingOverlay_' + prefix),
duration: 700,
onEnd: function(node){
domConstruct.destroy(node);
}
}).play();
}
});
window.masonSql = new MasonSql();
});
 
// oggetto dojox/widget/DialogSimple per gli avvisi
var masonSql_Dialog;
 
require(["dojo/ready", "dojo/io-query", "dojox/widget/DialogSimple"], function(ready, ioQuery, DialogSimple){
ready(function(){
masonSql_Dialog = new DialogSimple({
title: '',
executeScripts: true,
renderStyles: true,
scriptHasHooks: true,
parseOnLoad: true,
cleanContent: true,
closable: true,
ioArgs: {
headers: {
'MasonSql-body': '1'
},
timeout: <% $r->dir_config('GetFormTimeout') %>
}
});
masonSql_Dialog.openUrl = function (url, url_params, width, height, title){
if(width && height){
this.set('style', 'width:' + width + 'px; height:' + height + 'px;');
}
this.set('title', title);
this.show();
if(url_params){
url += '?' + ioQuery.objectToQuery(url_params);
}
this.set('href', url).then(
function(){
console.debug('downloaded', url, masonSql_Dialog);
masonSql.ready();
},
function(err){
tab.set('errorMessage', "<span class='dijitContentPaneError'>"+
"<span class='dijitInline dijitIconError'></span>"+err+' id:'+masonSql_Dialog.id+' timeout:'+<% $r->dir_config('GetFormTimeout') %>+"</span>");
console.error('ERROR href',err , masonSql_Dialog);
}
);
};
masonSql_Dialog.openHtml = function (html, width, height, title, timeout){
if(masonSql_Dialog.timer){
window.clearTimeout(masonSql_Dialog.timer);
masonSql_Dialog.timer = null;
}
if(width && height){
this.set('style', 'width:' + width + 'px; height:' + height + 'px;');
}
this.set('title', title);
this.set('content', html);
this.show();
if(timeout){
masonSql_Dialog.timer = setTimeout( function(){
masonSql_Dialog.hide();
}, timeout * 1000);
}
};
});
});
 
// finestra di avviso
// str messaggio da visualizzare
// type tipo di messaggio: html, txt, auto, alert o pre(default)
// X, Y: dimensioni della finestra (default 300x600
// timeout: secondi di attesa per la chiusura della finestra
function my_alert(str, type, X, Y, timeout){
if(type == 'auto'){
// cerco di determinare il formato di visualizzazione più adatto in base al contenuto
var re = /<html/i;
if(re.test(str)){
type = 'html';
}else{
type = 'txt';
}
}
if(type == 'alert'){
alert(str);
return;
}
switch(type){
case 'html':
break;
case 'txt':
str=str.replace(/</g,'&lt;');
str=str.replace(/>/g,'&gt;');
str=str.replace(/\n/g,'<br>\n');
break;
case 'pre':
default:
str = '<pre>'+str+'</pre>';
}
masonSql_Dialog.openHtml(str, X, Y, 'ALERT', timeout);
}
 
// numero la stringa
function enum_text(txt){
var linecodes = txt.split(/\n/);
for(var C=0; C<linecodes.length; C++){
linecodes[C] = '[' + C + '] ' + linecodes[C];
}
return linecodes.join('\n');
}
 
// visualizza una finestra di avviso con l'errore riscontrato
//
function my_alert_error(message, err, code){
if(err){
// numero il codice
code = enum_text(code);
var stack = err.stack;
stack = stack.replace(/\n/gm, '\n________________________________________ stack ________________________________________\n');
stack = stack.replace(/\\n/gm, '\n');
my_alert('Error: MOZ ' + message + ' line=' + err.lineNumber +
' message = [' + err.message + ']\n' +
'________________________________________ STACK ________________________________________\n' + stack + '\n' +
'________________________________________ CODE ________________________________________\n' + code, 'txt');
}else{
my_alert('Error: ' + message, 'txt');
}
}
 
function pageTimeoutLoad(contextID, type, str){
var contextObj = hReqMason_ContextPool[contextID];
contextObj.obj_params.Loadobj.innerHTML='';
if(type == 'TIMEOUT'){
my_alert('Timeout caricamento pagina ' + contextObj.URL);
}else{
my_alert('ERRORE '+type+' pagina '+contextObj.URL+': \n['+str+']');
}
}
 
// funzione callback; esegue il codice passato nella chiamata dopo il caricamento della pagina
// Loadobj è l'oggetto nel quale la pagina è stata caricata
function pageCallbackLoad(Loadobj, contextID){
if(Loadobj != null){
var callback_code = Loadobj.Callback_code;
var timeout = Loadobj.Callback_code_timeout;
if(callback_code != null && callback_code != ''){
// riferimento globale dell'oggetto, da potersi usare nel codice da eseguire
CurrentLoadobj = Loadobj;
if(timeout){
%#DEBUG
<% $JSLogger->debug(q|'pageCallbackLoad - setTimeout timeout:'+timeout+' code:'+callback_code|)%>
window.setTimeout(callback_code, timeout);
}else{
eval(callback_code);
}
}
}
}
 
 
function divReload(Elem){
if(Elem.URL != null){
divLoad(Elem, Elem.URL, Elem.Params, Elem.Callback_code, Elem.Callback_code_timeout);
}else{
my_alert("ERRORE: L'elemento '"+Elem.id+"' indicato non ha riferimenti alla URL da caricare", 'txt', 400, 100);
}
}
 
 
// caricamento dinamico della pagina remota "page" nell'elemento "Elem" con i parametri "params"
// e funzione di callback "callback"
function divLoad(Elem, page, params, callback_code, timeout){
if(Elem){
dojo.forEach(dijit.findWidgets(Elem), function(widget) {
widget.destroyRecursive(false);
});
dojo.empty(Elem);
if(page == ''){
//Elem.innerHTML='';
Elem.disabled = false;
Elem.Callback_code_timeout = timeout;
if(callback_code != null && callback_code != ''){
if(timeout){
%#DEBUG <% $JSLogger->debug(q|'divLoad page null - setTimeout timeout:'+timeout+' code:'+callback_code|)%>
window.setTimeout(callback_code, timeout);
}else{
eval(callback_code);
}
}
}else{
Elem.disabled = true;
Elem.Callback_code = callback_code;
Elem.Callback_code_timeout = timeout;
hReqMason_LoadTimeout(Elem, <%$GetFormTimeout%>, pageTimeoutLoad, pageCallbackLoad, page, params);
}
}else{
my_alert('ERRORE: divLoad(Elem, '+page+', '+params+') non utilizzabile in quanto non è definito l\'oggetto Elem di destinazione', 'txt', 400, 100);
}
}
 
// provvede a caricare un tag DIV differente per ogni differente "page" e lo inserisce in "Div"
//
function divLoadBuffered(Div, page, params, callback_code, reload, timeout){
// elenco elementi gia presenti
var elenco = Div.childNodes;
var current = null;
for(var i=0; i<elenco.length; i++){
var elem = elenco.item(i);
if(elem.URL != null){
// elaboro solo gli elementi che hanno definito l'attributo "URL"
if(elem.URL == page){
// trovato elemento
current = elem;
}else{
// disattivo elemento
elem.style.display = 'none';
}
}
}
var loaded;
if(current == null){
loaded = false;
current = document.createElement('div');
current.URL = page;
current.Params = params;
Div.appendChild(current);
divLoad(current, page, params, callback_code, timeout);
}else{
loaded = true;
if(reload){
divLoad(current, page, params, callback_code);
}else{
if(callback_code != null && callback_code != ''){
eval(callback_code);
}
}
}
// attivo l'elemento
current.style.display = 'inline';
return current;
}
 
 
// DEPRECATED !! -legacy framework < 2013
function pageLoad(page, menu, params, cb_code_page, cb_code_menu, reload, timeout_page, timeout_menu){
if(menu){
my_alert("ATTENZIONE: Non è più possibile chiamare pageLoad!");
}else{
bodyLoad(page, params, cb_code_page, reload, timeout_page);
}
}
 
// caricamento dinamico di pagina
// ad ogni tipo di pagina caricato dispone un differente TAG di tipo <DIV> che lo contiene
function bodyLoad(page, params, cb_code, reload, timeout){
cb_code = cb_code ? cb_code + ';' : '';
if(timeout == null){
timeout = 10;
}
if(page != null){
divLoad(CurrentBody, page, params, cb_code, reload, timeout);
if(CurrentBody != null && CurrentBody.onMenuSelect){
CurrentBody.onMenuSelect();
}
}
}
 
// manipolazione array
 
// estende i metodi della classe Array
 
// verifica se tutti gli elementi dell'array sono nulli
Array.prototype.allNull = function(){
for(var I=0; I<this.length; I++){
// verifico se l'elemento a sua volta è un Array
var elem = this[I];
if(Array.prototype.isPrototypeOf(elem)){
if(!elem.allNull()){
return false
}
}else{
if(elem != null){
return false;
}
}
}
return true;
}
 
function CreateEmptyArray(Row,Col){
var arr = new Array(Row);
for(var r=0; r<Row; r++){
arr[r] = new Array(Col);
}
return arr;
}
 
function DuplicaArray(arr){
var N = new Array(arr.length);
for(var R=0; R<arr.length; R++){
var V=arr[R];
N[R] = new Array(V.length);
var D=N[R];
for(var C=0; C<V.length; C++){
D[C]=V[C];
}
}
%#//my_alert('old='+arr.length+' new='+N.length+'\nold:'+Array2String(arr, 'null')+'\nnew:'+Array2String(N, 'null'));
return N;
}
 
// usata da ArrayDiffKeys e da ArrayDiff
// valuta New <=> Old se c'è differenza oppure Val <> ''
// New = nuovo dato
// Old = dato precedente
// Null = == true il campo con valore 'null' viene considerato uguali a ''
// Val <> '' ritorna sempre il valore nuovo
function Diff_values(New, Old, Null, Val){
// my_alert('null="'+Null+'"\nis_different='+(New != Old)+'\non TEST [[['+New+']]]\n[[['+Old+']]]');
var S = null;
if(!( Null &&
(New == '' || New == null) &&
(Old == '' || Old == null)
) ||
Val != ''
){
if(New == null){
S = '';
}else{
S = ''+New;
S = S.replace(/\r/g,'');
}
}
// my_alert('New:'+New+' old:'+Old+' Null:'+Null+' Val:'+Val+'\n Return:'+(Val != '' ? S : ( New != Old ? S : null )));
return Val != '' ? S : ( New != Old ? S : null );
}
 
// calcola una matrice di differenze;
// Key = vettore di chiavi relative all'array
// Old = matrice non modificata
// New = matrice modificata
// Null = == true i campi null vengono considerati uguali a ''
//
function ArrayDiffKeys(Key, Old, New, Null){
var Diff = CreateEmptyArray(Old.length, Old[0] && Old[0].length);
for(var R=0; R<Old.length; R++){
var New_row = New[R];
var Old_row = Old[R];
var Diff_row = Diff[R];
// valuto se la prima colonna è vuota
// se vuota si tratta di un nuovo campo (inserimento)
if(Key[R]){
for(var C=0; C<New_row.length; C++){
Diff_row[C] = Diff_values(New_row[C], Old_row[C], Null, '');
}
}else{
// valuto se c'è almeno un campo diverso; se sì: copio
// indistintamente tutti i campi
for(var L=0; L<New_row.length; L++){
var N = New_row[L];
N = (N == '' || N == null) ? '' : N;
var O = Old_row[L];
O = (O == '' || O == null) ? '' : O;
// se c'è almeno un campo diverso valuto tutta la riga
if(N != O){
for(var C=0; C<New_row.length; C++){
Diff_row[C] = Diff_values(New_row[C], Old_row[C], Null, New_row[C]);
}
break;
}
}
}
}
//DEBUG my_alert('ArrayDiffKeys\nKey:'+Vector2String(Key,'null')+'\nOld:'+Array2String(Old,'null')+'\nNew:'+Array2String(New,'null')+'\nDiff:'+Array2String(Diff,'null'));
return Diff;
}
 
// calcola una matrice di differenze;
// Old = matrice non modificata
// New = matrice modificata
// Null = == true i campi null vengono considerati uguali a ''
//
function ArrayDiff(Old, New, Null){
var D=CreateEmptyArray(Old.length, Old[0].length);
for(var R=0; R<Old.length; R++){
var New_row=New[R];
var Old_row=Old[R];
var Diff_row=D[R];
for(var C=0; C<New_row.length; C++){
Diff_row[C] = Diff_values(New_row[C], Old_row[C], Null, '');
}
}
return D;
}
 
// valuta il numero di righe con la prima colonna vuota (record nuovi)
function ArrayNewRowNum(Key, Data){
var num=0;
for(var R=0; R<Data.length; R++){
var P = Data[R];
if(P && Key[R] == null){
for(var C=0; C<P.length; C++){
if(P[C] !='' && P[C]!=null){
num++;
C=P.length;
}
}
}
}
return num;
}
 
// restituisce una stringa rappresentazione della matrice
// il campo non definito viene lasciato vuoto
// Key = vettore chiavi
// Data = matrice dei dati
// Null = stringa di rappresentazione campi nulli
// AllRows = ==true vengono generate anche le righe nulle
// OnlyKey per le righe nulle viene inserito una riga con il solo campo chiave
// DupKeys viene accodato il valore della riga corrispondente in fondo alla nuova riga restituita (usato in dbms_library.comp)
function KeyArray2String(Key, Data, Null, AllRows, OnlyKey, DupKeys){
var S='[';
var no0=false;
for(var R=0; R<Data.length; R++){
var Dif=Data[R];
var key=Key[R];
var differ=false
if(Dif){
var Sr;
if(key != null){
Sr='[\''+key+'\'';
}else{
Sr='['+Null;
}
for(var C=0; C<Dif.length; C++){
if(Dif[C] != null){
var V=new String(Dif[C]);
V=V.replace(/\\/g,'\\\\');
V=V.replace(/'/g,"\\'");//"
Sr+=',\''+V+'\'';
differ=true;
}else{
Sr+=','+Null;
}
}
if(key == null && DupKeys[R]){
Sr+=','+DupKeys[R];
}
if(AllRows){
if(OnlyKey){
if(differ){
no0 ? S+=',' : no0=true;
S+=Sr+']';
}else{
if(key != null){
no0 ? S+=',' : no0=true;
S+='[\''+key+'\']';
}
}
}else{
no0 ? S+=',' : no0=true;
S+=Sr+']';
}
}else{
if(differ){
no0 ? S+=',' : no0=true;
S+=Sr+']';
}
}
}
}
S+=']';
return S;
}
 
 
// restituisce una stringa rappresentazione della matrice
// Data = matrice dei dati
// Null = stringa di rappresentazione campi nulli, se omessa 'null'
//
function Array2String(Data, Null){
if(!Data){
return '[ Array data null ]';
}
var S = '[\n';
for(var R=0; R<Data.length; R++){
S += Vector2String(Data[R], Null) + '\n';
}
S += '];';
return S;
}
 
// restituisce una stringa rappresentazione del vettore
// Data = vettore dei dati
// Null = stringa di rappresentazione campi nulli, se omessa 'null'
//
function Vector2String(Data, Null){
if(!Data){
return '[ Vector data null ]';
}
var Sr = ' [';
for(var C=0; C<Data.length; C++){
if(Data[C] != null){
var V=new String(Data[C]);
V=V.replace(/\\/g,'\\\\');
V=V.replace(/'/g,"\\'");
Sr += C==0 ? '\''+V+'\'' : ',\''+V+'\''; //"
}else{
Sr += C==0 ? Null : ','+Null;
}
}
return Sr + ']';
}
 
// tabella entity HTML
var Entities = {
Aacute:0x00c1, aacute:0x00e1, Acirc:0x00c2, acirc:0x00e2, acute:0x00b4, AElig:0x00c6, aelig:0x00e6, Agrave:0x00c0,
agrave:0x00e0, alefsym:0x2135, Alpha:0x0391, alpha:0x03b1, amp:0x0026, and:0x2227, ang:0x2220, Aring:0x00c5,
aring:0x00e5, asymp:0x2248, Atilde:0x00c3, atilde:0x00e3, Auml:0x00c4, auml:0x00e4, bdquo:0x201e, Beta:0x0392,
beta:0x03b2, brvbar:0x00a6, bull:0x2022, cap:0x2229, Ccedil:0x00c7, ccedil:0x00e7, cedil:0x00b8, cent:0x00a2,
Chi:0x03a7, chi:0x03c7, circ:0x02c6, clubs:0x2663, cong:0x2245, copy:0x00a9, crarr:0x21b5, cup:0x222a, curren:0x00a4,
dagger:0x2020, Dagger:0x2021, darr:0x2193, dArr:0x21d3, deg:0x00b0, Delta:0x0394, delta:0x03b4, diams:0x2666,
divide:0x00f7, Eacute:0x00c9, eacute:0x00e9, Ecirc:0x00ca, ecirc:0x00ea, Egrave:0x00c8, egrave:0x00e8, empty:0x2205,
emsp:0x2003, ensp:0x2002, Epsilon:0x0395, epsilon:0x03b5, equiv:0x2261, Eta:0x0397, eta:0x03b7, ETH:0x00d0, eth:0x00f0,
Euml:0x00cb, euml:0x00eb, euro:0x20ac, exist:0x2203, fnof:0x0192, forall:0x2200, frac12:0x00bd, frac14:0x00bc,
frac34:0x00be, frasl:0x2044, Gamma:0x0393, gamma:0x03b3, ge:0x2265, gt:0x003e, harr:0x2194, hArr:0x21d4, hearts:0x2665,
hellip:0x2026, Iacute:0x00cd, iacute:0x00ed, Icirc:0x00ce, icirc:0x00ee, iexcl:0x00a1, Igrave:0x00cc, igrave:0x00ec,
image:0x2111, infin:0x221e, int:0x222b, Iota:0x0399, iota:0x03b9, iquest:0x00bf, isin:0x2208, Iuml:0x00cf, iuml:0x00ef,
Kappa:0x039a, kappa:0x03ba, Lambda:0x039b, lambda:0x03bb, lang:0x2329, laquo:0x00ab, larr:0x2190, lArr:0x21d0,
lceil:0x2308, ldquo:0x201c, le:0x2264, lfloor:0x230a, lowast:0x2217, loz:0x25ca, lrm:0x200e, lsaquo:0x2039,
lsquo:0x2018, lt:0x003c, macr:0x00af, mdash:0x2014, micro:0x00b5, middot:0x00b7, minus:0x2212, Mu:0x039c, mu:0x03bc,
nabla:0x2207, nbsp:0x00a0, ndash:0x2013, ne:0x2260, ni:0x220b, not:0x00ac, notin:0x2209, nsub:0x2284, Ntilde:0x00d1,
ntilde:0x00f1, Nu:0x039d, nu:0x03bd, Oacute:0x00d3, oacute:0x00f3, Ocirc:0x00d4, ocirc:0x00f4, OElig:0x0152,
oelig:0x0153, Ograve:0x00d2, ograve:0x00f2, oline:0x203e, Omega:0x03a9, omega:0x03c9, Omicron:0x039f, omicron:0x03bf,
oplus:0x2295, or:0x2228, ordf:0x00aa, ordm:0x00ba, Oslash:0x00d8, oslash:0x00f8, Otilde:0x00d5, otilde:0x00f5,
otimes:0x2297, Ouml:0x00d6, ouml:0x00f6, para:0x00b6, part:0x2202, permil:0x2030, perp:0x22a5, Phi:0x03a6, phi:0x03c6,
Pi:0x03a0, pi:0x03c0, piv:0x03d6, plusmn:0x00b1, pound:0x00a3, prime:0x2032, Prime:0x2033, prod:0x220f, prop:0x221d,
Psi:0x03a8, psi:0x03c8, quot:0x0022, radic:0x221a, rang:0x232a, raquo:0x00bb, rarr:0x2192, rArr:0x21d2, rceil:0x2309,
rdquo:0x201d, real:0x211c, reg:0x00ae, rfloor:0x230b, Rho:0x03a1, rho:0x03c1, rlm:0x200f, rsaquo:0x203a, rsquo:0x2019,
sbquo:0x201a, Scaron:0x0160, scaron:0x0161, sdot:0x22c5, sect:0x00a7, shy:0x00ad, Sigma:0x03a3, sigma:0x03c3,
sigmaf:0x03c2, sim:0x223c, spades:0x2660, sub:0x2282, sube:0x2286, sum:0x2211, sup1:0x00b9, sup2:0x00b2, sup3:0x00b3,
sup:0x2283, supe:0x2287, szlig:0x00df, Tau:0x03a4, tau:0x03c4, there4:0x2234, Theta:0x0398, theta:0x03b8, thetasym:0x03d1,
thinsp:0x2009, THORN:0x00de, thorn:0x00fe, tilde:0x02dc, times:0x00d7, trade:0x2122, Uacute:0x00da, uacute:0x00fa,
uarr:0x2191, uArr:0x21d1, Ucirc:0x00db, ucirc:0x00fb, Ugrave:0x00d9, ugrave:0x00f9, uml:0x00a8, upsih:0x03d2,
Upsilon:0x03a5, upsilon:0x03c5, Uuml:0x00dc, uuml:0x00fc, weierp:0x2118, Xi:0x039e, xi:0x03be, Yacute:0x00dd,
yacute:0x00fd, yen:0x00a5, yuml:0x00ff, Yuml:0x0178, Zeta:0x0396, zeta:0x03b6, zwj:0x200d, zwnj:0x200c
}
 
// conversione testo HTML a stringa
function Html2String(str){
var out = '';
if(str == null){
return;
}
var l = str.length;
for(var i=0; i<l; i++){
var ch = str.charAt(i);
if(ch == '&'){
var pos = str.indexOf(';', i+1);
if(pos > 0){
var entity = str.substring(i + 1, pos);
ch = (entity.length > 1 && entity.charAt(0) == '#') ?
((entity.charAt(1) == 'x' || entity.charAt(1) == 'X') ?
String.fromCharCode(eval('0'+entity.substring(1))) :
String.fromCharCode(eval(entity.substring(1)))) :
String.fromCharCode(Entities[entity]);
i = pos;
}
}
out += ch;
}
return out;
}
 
// Funzione utilizzata in dbms_library.comp method GENERIC_FIND
// Se il widget di id id_sel non è selezionato si provvede a selezionare val
function Set_first_if_not_selected(id, id_sel, val){
var sel = document.getElementById(id_sel);
if(id.get_value()){
if(!sel.get_value()){
sel.set_value(val);
}
}else{
sel.set_value('');
}
}
/tags/2.0/htdocs/lib/autohandler
0,0 → 1,42
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
// MasonSQL Copyright:2002-2010-2008 Leader.IT di Guido Brugnara http://www.leader.it
<%attr>
Cache_MaxAge => 12*60*60
</%attr>
<%perl>
$r->headers_out->{'Cache-Control'} = 'max-age='.$m->base_comp->attr('Cache_MaxAge');
</%perl>
% $m->call_next; # $m->comp($next);
<%flags>
inherit => '/init.comp'
</%flags>
<%shared>
initBrowserDetect();
# N.B. $Ver è una variabile globale; utilizzo l'ID session
$Ver = $Session{Session};
my $type = lc $m->fetch_next->name;
$type =~ s/.*\.//;
if($type eq 'js'){
$r->content_type('text/javascript');
}elsif($type eq 'css'){
$r->content_type('text/css');
}
</%shared>
<%init>
# return if $m->cache_self(expire_in => '300 sec'[, key => "lib_$type"]);
</%init>
<%filter>
# if($type eq 'js' && ! $JSLogger->level() eq $DEBUG){
# filtra tutti i commenti Jscript
s|^\s*//.*$||img;
# }
</%filter>
/tags/2.0/htdocs/lib/head_meta.comp
0,0 → 1,35
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2006 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
Componente utilizzato per dichiarare i <META> tag che verranno inseriti
nell'intestazione della pagina html.
</%doc>
<%args>
$http_equiv => undef
$name => undef
$content
</%args>
<%perl>
my $meta = '<meta';
if($name){
$meta .= ' name="'.$m->interp->apply_escapes($name, 'h').'"';
}
if($http_equiv){
$meta .= ' http-equiv="'.$m->interp->apply_escapes($http_equiv, 'h').'"';
}
$meta .= ' content="'.$m->interp->apply_escapes($content, 'h').'"/>';
my $old_meta = $Global{"Meta/${name}/${http_equiv}"};
if(defined $old_meta and $old_meta != $meta){
# se la definizione è ripetuta una seconda volta diversa
# dalla precedente, si tratta di un errore che interrompe l'esecuzione
die qq|ERROR: Meta $name [$old_meta] different to [$meta]"|;
}
$Global{"Meta/${name}/${http_equiv}"} = $meta;
push @{$Global{LoadHeader_Meta}}, $meta;
</%perl>
/tags/2.0/htdocs/lib/LEGGIMI
0,0 → 1,6
N.B.
Sostituire eventualmente nelle chiamata window.open(URL ..... "about:blank" con ''
per evitare la segnalazione di sicurezza in Netscape/Mozilla
 
 
 
/tags/2.0/htdocs/lib/FCKeditor_config.js
0,0 → 1,188
/*
* FCKeditor - The text editor for internet
* Copyright (C) 2003-2006 Frederico Caldeira Knabben
*
* Licensed under the terms of the GNU Lesser General Public License:
* http://www.opensource.org/licenses/lgpl-license.php
*
* For further information visit:
* http://www.fckeditor.net/
*
* "Support Open Source software. What about a donation today?"
*
* File Name: fckconfig.js
* Editor configuration settings.
* See the documentation for more info.
*
* File Authors:
* Frederico Caldeira Knabben (fredck@fckeditor.net)
*/
 
FCKConfig.CustomConfigurationsPath = '' ;
 
FCKConfig.EditorAreaCSS = FCKConfig.BasePath + 'css/fck_editorarea.css' ;
 
FCKConfig.DocType = '' ;
 
FCKConfig.BaseHref = '' ;
 
FCKConfig.FullPage = false ;
 
FCKConfig.Debug = false ;
FCKConfig.AllowQueryStringDebug = true ;
 
FCKConfig.SkinPath = FCKConfig.BasePath + 'skins/default/' ;
FCKConfig.PreloadImages = [ FCKConfig.SkinPath + 'images/toolbar.start.gif', FCKConfig.SkinPath + 'images/toolbar.buttonarrow.gif' ] ;
 
FCKConfig.PluginsPath = FCKConfig.BasePath + 'plugins/' ;
 
// FCKConfig.Plugins.Add( 'autogrow' ) ;
FCKConfig.AutoGrowMax = 400 ;
 
FCKConfig.ProtectedSource.Add( /<script[\s\S]*?\/script>/gi ) ; // <SCRIPT> tags.
//FCKConfig.ProtectedSource.Add( /<\%[\s\S]*?\%>/g ) ; // ASP style server side code <\%...\%>
//FCKConfig.ProtectedSource.Add( /<\?[\s\S]*?\?>/g ) ; // PHP style server side code
//FCKConfig.ProtectedSource.Add( /(<asp:[^\>]+>[\s|\S]*?<\/asp:[^\>]+>)|(<asp:[^\>]+\/>)/gi ) ; // ASP.Net style tags <asp:control>
 
FCKConfig.AutoDetectLanguage = true ;
FCKConfig.DefaultLanguage = 'it' ;
FCKConfig.ContentLangDirection = 'ltr' ;
 
FCKConfig.ProcessHTMLEntities = true ;
FCKConfig.IncludeLatinEntities = true ;
FCKConfig.IncludeGreekEntities = true ;
 
FCKConfig.FillEmptyBlocks = true ;
 
FCKConfig.FormatSource = true ;
FCKConfig.FormatOutput = true ;
FCKConfig.FormatIndentator = ' ' ;
 
FCKConfig.ForceStrongEm = true ;
FCKConfig.GeckoUseSPAN = false ;
FCKConfig.StartupFocus = false ;
FCKConfig.ForcePasteAsPlainText = false ;
FCKConfig.AutoDetectPasteFromWord = true ; // IE only.
FCKConfig.ForceSimpleAmpersand = false ;
FCKConfig.TabSpaces = 0 ;
FCKConfig.ShowBorders = true ;
FCKConfig.SourcePopup = false ;
FCKConfig.UseBROnCarriageReturn = false ; // IE only.
FCKConfig.ToolbarStartExpanded = true ;
FCKConfig.ToolbarCanCollapse = true ;
FCKConfig.IgnoreEmptyParagraphValue = true ;
FCKConfig.PreserveSessionOnFileBrowser = false ;
FCKConfig.FloatingPanelsZIndex = 10000 ;
 
FCKConfig.ToolbarLocation = 'In' ;
 
FCKConfig.ToolbarSets["Default"] = [
['Source','DocProps','-','Save','NewPage','Preview','-','Templates'],
['Cut','Copy','Paste','PasteText','PasteWord','-','Print','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
['Form','Checkbox','Radio','TextField','Textarea','Select','Button','ImageButton','HiddenField'],
'/',
['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak','UniversalKey'],
'/',
['Style','FontFormat','FontName','FontSize'],
['TextColor','BGColor'],
['FitWindow','-','About']
] ;
 
FCKConfig.ToolbarSets["Basic"] = [
['Bold','Italic','-','OrderedList','UnorderedList','-','Link','Unlink','-','About']
] ;
 
FCKConfig.ToolbarSets["MyToolbar"] = [
['Cut','Copy','Paste','PasteText','PasteWord','-','Print','SpellCheck'],
['Undo','Redo','-','Find','Replace','-','SelectAll','RemoveFormat'],
['TextColor','BGColor'],
['FitWindow','-','About'],
['Bold','Italic','Underline','StrikeThrough','-','Subscript','Superscript'],
['OrderedList','UnorderedList','-','Outdent','Indent'],
['JustifyLeft','JustifyCenter','JustifyRight','JustifyFull'],
['Link','Unlink','Anchor'],
['Image','Flash','Table','Rule','Smiley','SpecialChar','PageBreak','UniversalKey'],
['Style','FontFormat','FontName','FontSize']
] ;
 
FCKConfig.ContextMenu = ['Generic','Link','Anchor','Image','Flash','Select','Textarea','Checkbox','Radio','TextField','HiddenField','ImageButton','Button','BulletedList','NumberedList','Table','Form'] ;
 
FCKConfig.FontColors = '000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,808080,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF' ;
 
FCKConfig.FontNames = 'Arial;Comic Sans MS;Courier New;Tahoma;Times New Roman;Verdana' ;
FCKConfig.FontSizes = '1/xx-small;2/x-small;3/small;4/medium;5/large;6/x-large;7/xx-large' ;
FCKConfig.FontFormats = 'p;div;pre;address;h1;h2;h3;h4;h5;h6' ;
 
FCKConfig.StylesXmlPath = FCKConfig.EditorPath + 'fckstyles.xml' ;
FCKConfig.TemplatesXmlPath = FCKConfig.EditorPath + 'fcktemplates.xml' ;
 
FCKConfig.SpellChecker = 'ieSpell' ; // 'ieSpell' | 'SpellerPages'
FCKConfig.IeSpellDownloadUrl = 'http://iespell.huhbw.com/ieSpellSetup220647.exe' ;
 
FCKConfig.MaxUndoLevels = 15 ;
 
FCKConfig.DisableObjectResizing = false ;
FCKConfig.DisableFFTableHandles = true ;
 
FCKConfig.LinkDlgHideTarget = false ;
FCKConfig.LinkDlgHideAdvanced = false ;
 
FCKConfig.ImageDlgHideLink = false ;
FCKConfig.ImageDlgHideAdvanced = false ;
 
FCKConfig.FlashDlgHideAdvanced = false ;
 
// The following value defines which File Browser connector and Quick Upload
// "uploader" to use. It is valid for the default implementaion and it is here
// just to make this configuration file cleaner.
// It is not possible to change this value using an external file or even
// inline when creating the editor instance. In that cases you must set the
// values of LinkBrowserURL, ImageBrowserURL and so on.
// Custom implementations should just ignore it.
var _FileBrowserLanguage = '' ; // asp | aspx | cfm | lasso | perl | php | py
var _QuickUploadLanguage = '' ; // asp | aspx | cfm | lasso | php
 
// Don't care about the following line. It just calculates the correct connector
// extension to use for the default File Browser (Perl uses "cgi").
var _FileBrowserExtension = _FileBrowserLanguage == 'perl' ? 'cgi' : _FileBrowserLanguage ;
 
FCKConfig.LinkBrowser = false ;
FCKConfig.LinkBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Connector=connectors/' + _FileBrowserLanguage + '/connector.' + _FileBrowserExtension ;
FCKConfig.LinkBrowserWindowWidth = FCKConfig.ScreenWidth * 0.7 ; // 70%
FCKConfig.LinkBrowserWindowHeight = FCKConfig.ScreenHeight * 0.7 ; // 70%
 
FCKConfig.ImageBrowser = false ;
FCKConfig.ImageBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Type=Image&Connector=connectors/' + _FileBrowserLanguage + '/connector.' + _FileBrowserExtension ;
FCKConfig.ImageBrowserWindowWidth = FCKConfig.ScreenWidth * 0.7 ; // 70% ;
FCKConfig.ImageBrowserWindowHeight = FCKConfig.ScreenHeight * 0.7 ; // 70% ;
 
FCKConfig.FlashBrowser = false ;
FCKConfig.FlashBrowserURL = FCKConfig.BasePath + 'filemanager/browser/default/browser.html?Type=Flash&Connector=connectors/' + _FileBrowserLanguage + '/connector.' + _FileBrowserExtension ;
FCKConfig.FlashBrowserWindowWidth = FCKConfig.ScreenWidth * 0.7 ; //70% ;
FCKConfig.FlashBrowserWindowHeight = FCKConfig.ScreenHeight * 0.7 ; //70% ;
 
FCKConfig.LinkUpload = false ;
FCKConfig.LinkUploadURL = FCKConfig.BasePath + 'filemanager/upload/' + _QuickUploadLanguage + '/upload.' + _QuickUploadLanguage ;
FCKConfig.LinkUploadAllowedExtensions = "" ; // empty for all
FCKConfig.LinkUploadDeniedExtensions = ".(php|php3|php5|phtml|asp|aspx|ascx|jsp|cfm|cfc|pl|bat|exe|dll|reg|cgi)$" ; // empty for no one
 
FCKConfig.ImageUpload = false ;
FCKConfig.ImageUploadURL = FCKConfig.BasePath + 'filemanager/upload/' + _QuickUploadLanguage + '/upload.' + _QuickUploadLanguage + '?Type=Image' ;
FCKConfig.ImageUploadAllowedExtensions = ".(jpg|gif|jpeg|png)$" ; // empty for all
FCKConfig.ImageUploadDeniedExtensions = "" ; // empty for no one
 
FCKConfig.FlashUpload = false ;
FCKConfig.FlashUploadURL = FCKConfig.BasePath + 'filemanager/upload/' + _QuickUploadLanguage + '/upload.' + _QuickUploadLanguage + '?Type=Flash' ;
FCKConfig.FlashUploadAllowedExtensions = ".(swf|fla)$" ; // empty for all
FCKConfig.FlashUploadDeniedExtensions = "" ; // empty for no one
 
FCKConfig.SmileyPath = FCKConfig.BasePath + 'images/smiley/msn/' ;
FCKConfig.SmileyImages = ['regular_smile.gif','sad_smile.gif','wink_smile.gif','teeth_smile.gif','confused_smile.gif','tounge_smile.gif','embaressed_smile.gif','omg_smile.gif','whatchutalkingabout_smile.gif','angry_smile.gif','angel_smile.gif','shades_smile.gif','devil_smile.gif','cry_smile.gif','lightbulb.gif','thumbs_down.gif','thumbs_up.gif','heart.gif','broken_heart.gif','kiss.gif','envelope.gif'] ;
FCKConfig.SmileyColumns = 8 ;
FCKConfig.SmileyWindowWidth = 320 ;
FCKConfig.SmileyWindowHeight = 240 ;
/tags/2.0/htdocs/lib/date.js
0,0 → 1,293
// ===================================================================
/* Author: Matt Kruse <matt@mattkruse.com>
WWW: http://www.mattkruse.com/ */
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however it is
// appreciated by the author if at least my web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download.
// If you wish to share this code with others, please just point them
// to the URL instead.
// Please DO NOT link directly to my .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================
 
// ------------------------------------------------------------------
// These functions use the same 'format' strings as the
// java.text.SimpleDateFormat class, with minor exceptions.
// The format string consists of the following abbreviations:
//
// Field | Full Form | Short Form
// -------------+--------------------+-----------------------
// Year | yyyy (4 digits) | yy (2 digits), y (2 or 4 digits)
// Month | MMM (name or abbr.)| MM (2 digits), M (1 or 2 digits)
// Day of Month | dd (2 digits) | d (1 or 2 digits)
// Day of Week | EE (name) | E (abbr)
// Hour (1-12) | hh (2 digits) | h (1 or 2 digits)
// Hour (0-23) | HH (2 digits) | H (1 or 2 digits)
// Hour (0-11) | KK (2 digits) | K (1 or 2 digits)
// Hour (1-24) | kk (2 digits) | k (1 or 2 digits)
// Minute | mm (2 digits) | m (1 or 2 digits)
// Second | ss (2 digits) | s (1 or 2 digits)
// AM/PM | a |
//
// NOTE THE DIFFERENCE BETWEEN MM and mm! Month=MM, not mm!
// Examples:
// "MMM d, y" matches: January 01, 2000
// Dec 1, 1900
// Nov 20, 00
// "M/d/yy" matches: 01/20/00
// 9/2/00
// "MMM dd, yyyy hh:mm:ssa" matches: "January 01, 2000 12:30:45AM"
// ------------------------------------------------------------------
 
var MONTH_NAMES=new Array('January','February','March','April','May','June','July','August','September','October','November','December','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
var DAY_NAMES=new Array('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sun','Mon','Tue','Wed','Thu','Fri','Sat');
function LZ(x) {return(x<0||x>9?"":"0")+x}
 
// ------------------------------------------------------------------
// isDate ( date_string, format_string )
// Returns true if date string matches format of format string and
// is a valid date. Else returns false.
// It is recommended that you trim whitespace around the value before
// passing it to this function, as whitespace is NOT ignored!
// ------------------------------------------------------------------
function isDate(val,format) {
var date=getDateFromFormat(val,format);
if (date==0) { return false; }
return true;
}
 
// -------------------------------------------------------------------
// compareDates(date1,date1format,date2,date2format)
// Compare two date strings to see which is greater.
// Returns:
// 1 if date1 is greater than date2
// 0 if date2 is greater than date1 of if they are the same
// -1 if either of the dates is in an invalid format
// -------------------------------------------------------------------
function compareDates(date1,dateformat1,date2,dateformat2) {
var d1=getDateFromFormat(date1,dateformat1);
var d2=getDateFromFormat(date2,dateformat2);
if (d1==0 || d2==0) {
return -1;
}
else if (d1 > d2) {
return 1;
}
return 0;
}
 
// ------------------------------------------------------------------
// formatDate (date_object, format)
// Returns a date in the output format specified.
// The format string uses the same abbreviations as in getDateFromFormat()
// ------------------------------------------------------------------
function formatDate(date,format) {
format=format+"";
var result="";
var i_format=0;
var c="";
var token="";
var y=date.getYear()+"";
var M=date.getMonth()+1;
var d=date.getDate();
var E=date.getDay();
var H=date.getHours();
var m=date.getMinutes();
var s=date.getSeconds();
var yyyy,yy,MMM,MM,dd,hh,h,mm,ss,ampm,HH,H,KK,K,kk,k;
// Convert real date parts into formatted versions
var value=new Object();
if (y.length < 4) {y=""+(y-0+1900);}
value["y"]=""+y;
value["yyyy"]=y;
value["yy"]=y.substring(2,4);
value["M"]=M;
value["MM"]=LZ(M);
value["MMM"]=MONTH_NAMES[M-1];
value["d"]=d;
value["dd"]=LZ(d);
value["E"]=DAY_NAMES[E+7];
value["EE"]=DAY_NAMES[E];
value["H"]=H;
value["HH"]=LZ(H);
if (H==0){value["h"]=12;}
else if (H>12){value["h"]=H-12;}
else {value["h"]=H;}
value["hh"]=LZ(value["h"]);
if (H>11){value["K"]=H-12;} else {value["K"]=H;}
value["k"]=H+1;
value["KK"]=LZ(value["K"]);
value["kk"]=LZ(value["k"]);
if (H > 11) { value["a"]="PM"; }
else { value["a"]="AM"; }
value["m"]=m;
value["mm"]=LZ(m);
value["s"]=s;
value["ss"]=LZ(s);
while (i_format < format.length) {
c=format.charAt(i_format);
token="";
while ((format.charAt(i_format)==c) && (i_format < format.length)) {
token += format.charAt(i_format++);
}
if (value[token] != null) { result=result + value[token]; }
else { result=result + token; }
}
return result;
}
// ------------------------------------------------------------------
// Utility functions for parsing in getDateFromFormat()
// ------------------------------------------------------------------
function _isInteger(val) {
var digits="1234567890";
for (var i=0; i < val.length; i++) {
if (digits.indexOf(val.charAt(i))==-1) { return false; }
}
return true;
}
function _getInt(str,i,minlength,maxlength) {
for (var x=maxlength; x>=minlength; x--) {
var token=str.substring(i,i+x);
if (token.length < minlength) { return null; }
if (_isInteger(token)) { return token; }
}
return null;
}
// ------------------------------------------------------------------
// getDateFromFormat( date_string , format_string )
//
// This function takes a date string and a format string. It matches
// If the date string matches the format string, it returns the
// getTime() of the date. If it does not match, it returns 0.
// ------------------------------------------------------------------
function getDateFromFormat(val,format) {
val=val+"";
format=format+"";
var i_val=0;
var i_format=0;
var c="";
var token="";
var token2="";
var x,y;
var now=new Date();
var year=now.getYear();
var month=now.getMonth()+1;
var date=1;
var hh=now.getHours();
var mm=now.getMinutes();
var ss=now.getSeconds();
var ampm="";
while (i_format < format.length) {
// Get next token from format string
c=format.charAt(i_format);
token="";
while ((format.charAt(i_format)==c) && (i_format < format.length)) {
token += format.charAt(i_format++);
}
// Extract contents of value based on format token
if (token=="yyyy" || token=="yy" || token=="y") {
if (token=="yyyy") { x=4;y=4; }
if (token=="yy") { x=2;y=2; }
if (token=="y") { x=2;y=4; }
year=_getInt(val,i_val,x,y);
if (year==null) { return 0; }
i_val += year.length;
if (year.length==2) {
if (year > 70) { year=1900+(year-0); }
else { year=2000+(year-0); }
}
}
else if (token=="MMM"){
month=0;
for (var i=0; i<MONTH_NAMES.length; i++) {
var month_name=MONTH_NAMES[i];
if (val.substring(i_val,i_val+month_name.length).toLowerCase()==month_name.toLowerCase()) {
month=i+1;
if (month>12) { month -= 12; }
i_val += month_name.length;
break;
}
}
if ((month < 1)||(month>12)){return 0;}
}
else if (token=="EE"||token=="E"){
for (var i=0; i<DAY_NAMES.length; i++) {
var day_name=DAY_NAMES[i];
if (val.substring(i_val,i_val+day_name.length).toLowerCase()==day_name.toLowerCase()) {
i_val += day_name.length;
break;
}
}
}
else if (token=="MM"||token=="M") {
month=_getInt(val,i_val,token.length,2);
if(month==null||(month<1)||(month>12)){return 0;}
i_val+=month.length;}
else if (token=="dd"||token=="d") {
date=_getInt(val,i_val,token.length,2);
if(date==null||(date<1)||(date>31)){return 0;}
i_val+=date.length;}
else if (token=="hh"||token=="h") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<1)||(hh>12)){return 0;}
i_val+=hh.length;}
else if (token=="HH"||token=="H") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<0)||(hh>23)){return 0;}
i_val+=hh.length;}
else if (token=="KK"||token=="K") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<0)||(hh>11)){return 0;}
i_val+=hh.length;}
else if (token=="kk"||token=="k") {
hh=_getInt(val,i_val,token.length,2);
if(hh==null||(hh<1)||(hh>24)){return 0;}
i_val+=hh.length;hh--;}
else if (token=="mm"||token=="m") {
mm=_getInt(val,i_val,token.length,2);
if(mm==null||(mm<0)||(mm>59)){return 0;}
i_val+=mm.length;}
else if (token=="ss"||token=="s") {
ss=_getInt(val,i_val,token.length,2);
if(ss==null||(ss<0)||(ss>59)){return 0;}
i_val+=ss.length;}
else if (token=="a") {
if (val.substring(i_val,i_val+2).toLowerCase()=="am") {ampm="AM";}
else if (val.substring(i_val,i_val+2).toLowerCase()=="pm") {ampm="PM";}
else {return 0;}
i_val+=2;}
else {
if (val.substring(i_val,i_val+token.length)!=token) {return 0;}
else {i_val+=token.length;}
}
}
// If there are any trailing characters left in the value, it doesn't match
if (i_val != val.length) { return 0; }
// Is date valid for month?
if (month==2) {
// Check for leap year
if ( ( (year%4==0)&&(year%100 != 0) ) || (year%400==0) ) { // leap year
if (date > 29){ return false; }
}
else { if (date > 28) { return false; } }
}
if ((month==4)||(month==6)||(month==9)||(month==11)) {
if (date > 30) { return false; }
}
// Correct hours value
if (hh<12 && ampm=="PM") { hh=hh-0+12; }
else if (hh>11 && ampm=="AM") { hh-=12; }
var newdate=new Date(year,month-1,date,hh,mm,ss);
return newdate.getTime();
}
/tags/2.0/htdocs/lib/graypixel.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/logo.comp
0,0 → 1,21
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2002 Leader.IT S.r.l. <http://www.leader.it>
# Via Trener, 10
# 38100 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<table align="center">
<tr>
<td align="right">
<img src="/logo.svg" border="0" style="width:54px">
</td>
<td align="left">
<div style="font-size:12pt">MasonSQL</div>
<div style="font-size:10pt">Framework</div>
</td>
</tr>
</table>
/tags/2.0/htdocs/logo.svg
0,0 → 1,898
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
viewBox="0 0 6000 5000"
preserveAspectRatio="xMidYMid"
id="svg2"
inkscape:version="0.47 r22583"
width="100%"
height="100%"
sodipodi:docname="logo_leader_corto_2011.svg"
style="fill-rule:evenodd">
<metadata
id="metadata764">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs762">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 3000 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="6000 : 3000 : 1"
inkscape:persp3d-origin="3000 : 2000 : 1"
id="perspective766" />
</defs>
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1280"
inkscape:window-height="946"
id="namedview760"
showgrid="false"
inkscape:zoom="0.11125147"
inkscape:cx="3508.7467"
inkscape:cy="2824.0781"
inkscape:window-x="0"
inkscape:window-y="24"
inkscape:window-maximized="1"
inkscape:current-layer="g14" />
<g
visibility="visible"
id="Predefinito"
style="visibility:visible"
transform="translate(0,-1000)">
<desc
id="desc5">Master slide</desc>
<g
style="fill:none;stroke:none"
id="g7">
<rect
x="-14"
y="-14"
width="6030"
height="6030"
id="rect9" />
</g>
</g>
<g
style="visibility:visible"
id="g14"
transform="translate(0,-1000)">
<desc
id="desc16">Group</desc>
<g
id="g3945"
transform="translate(8.9886455,910.88726)">
<g
id="g18">
<desc
id="desc20">Drawing</desc>
<g
id="g22">
<g
style="fill:#ffc63d;stroke:none"
id="g24">
<path
d="m 4398,1623 0,-186 1069,0 0,372 -1069,0 0,-186 z"
id="path26" />
</g>
<g
style="fill:none;stroke:none"
id="g28">
<rect
x="4384"
y="1423"
width="1098"
height="401"
id="rect30" />
</g>
<g
id="g32" />
</g>
</g>
<g
id="g34">
<desc
id="desc36">Drawing</desc>
<g
id="g38">
<g
style="fill:#000000;stroke:none"
id="g40">
<path
d="m 3839,1808 -796,0 0,-372 1591,0 0,372 -795,0 z"
id="path42" />
</g>
<g
style="fill:none;stroke:#000000"
id="g44">
<path
style="fill:none"
d="m 3839,1808 -796,0 0,-372 1591,0 0,372 -795,0"
id="path46" />
</g>
<g
id="g48" />
</g>
</g>
<g
id="g50">
<desc
id="desc52">Drawing</desc>
<g
id="g54">
<g
style="fill:#ffc63d;stroke:none"
id="g56">
<path
d="m 2737,4527 -186,0 0,-1066 372,0 0,1066 -186,0 z"
id="path58" />
</g>
<g
style="fill:none;stroke:none"
id="g60">
<rect
x="2537"
y="3447"
width="401"
height="1095"
id="rect62" />
</g>
<g
id="g64" />
</g>
</g>
<g
id="g66">
<desc
id="desc68">Drawing</desc>
<g
id="g70">
<g
style="fill:#ffc63d;stroke:none"
id="g72">
<path
d="m 3849,4527 -186,0 0,-1066 372,0 0,1066 -186,0 z"
id="path74" />
</g>
<g
style="fill:none;stroke:none"
id="g76">
<rect
x="3649"
y="3447"
width="401"
height="1095"
id="rect78" />
</g>
<g
id="g80" />
</g>
</g>
<g
id="g82">
<desc
id="desc84">Drawing</desc>
<g
id="g86">
<g
style="fill:#ffc63d;stroke:none"
id="g88">
<path
d="m 2736,1546 -185,0 0,-1069 370,0 0,1069 -185,0 z"
id="path90" />
</g>
<g
style="fill:none;stroke:none"
id="g92">
<rect
x="2537"
y="463"
width="399"
height="1098"
id="rect94" />
</g>
<g
id="g96" />
</g>
</g>
<g
id="g98">
<desc
id="desc100">Group</desc>
<g
id="g102">
<desc
id="desc104">Drawing</desc>
<g
id="g106">
<g
style="fill:#000000;stroke:none"
id="g108">
<path
d="m 1739,3029 c -222,0 -402,-180 -402,-402 0,-222 180,-402 402,-402 222,0 402,180 402,402 0,222 -180,402 -402,402 z"
id="path110" />
<path
d="m 1739,3034 c -56,0 -110,-11 -158,-32 l 2,-5 1,-4 c 48,20 100,31 155,31 l 0,5 0,5 z"
id="path112" />
<path
d="m 1581,3002 c -49,-21 -93,-50 -130,-87 l 4,-4 3,-3 c 36,36 79,65 126,85 l -1,4 -2,5 z"
id="path114" />
<path
d="m 1451,2915 c -37,-37 -66,-81 -87,-130 l 5,-2 4,-1 c 20,47 49,90 85,126 l -3,3 -4,4 z"
id="path116" />
<path
d="m 1364,2785 c -21,-48 -32,-102 -32,-158 l 5,0 5,0 c 0,55 11,107 31,155 l -4,1 -5,2 z"
id="path118" />
<path
d="m 1332,2627 c 0,-56 11,-110 32,-158 l 5,2 4,1 c -20,48 -31,100 -31,155 l -5,0 -5,0 z"
id="path120" />
<path
d="m 1364,2469 c 21,-49 50,-93 87,-130 l 4,4 3,3 c -36,36 -65,79 -85,126 l -4,-1 -5,-2 z"
id="path122" />
<path
d="m 1451,2339 c 37,-37 81,-66 130,-87 l 2,5 1,4 c -47,20 -90,49 -126,85 l -3,-3 -4,-4 z"
id="path124" />
<path
d="m 1581,2252 c 48,-21 102,-32 158,-32 l 0,5 0,5 c -55,0 -107,11 -155,31 l -1,-4 -2,-5 z"
id="path126" />
<path
d="m 1739,2220 c 56,0 110,11 158,32 l -2,5 -1,4 c -48,-20 -100,-31 -155,-31 l 0,-5 0,-5 z"
id="path128" />
<path
d="m 1897,2252 c 49,21 93,50 130,87 l -4,4 -3,3 c -36,-36 -79,-65 -126,-85 l 1,-4 2,-5 z"
id="path130" />
<path
d="m 2027,2339 c 37,37 66,81 87,130 l -5,2 -4,1 c -20,-47 -49,-90 -85,-126 l 3,-3 4,-4 z"
id="path132" />
<path
d="m 2114,2469 c 21,48 32,102 32,158 l -5,0 -5,0 c 0,-55 -11,-107 -31,-155 l 4,-1 5,-2 z"
id="path134" />
<path
d="m 2146,2627 c 0,56 -11,110 -32,158 l -5,-2 -4,-1 c 20,-48 31,-100 31,-155 l 5,0 5,0 z"
id="path136" />
<path
d="m 2114,2785 c -21,49 -50,93 -87,130 l -4,-4 -3,-3 c 36,-36 65,-79 85,-126 l 4,1 5,2 z"
id="path138" />
<path
d="m 2027,2915 c -37,37 -81,66 -130,87 l -2,-5 -1,-4 c 47,-20 90,-49 126,-85 l 3,3 4,4 z"
id="path140" />
<path
d="m 1897,3002 c -48,21 -102,32 -158,32 l 0,-5 0,-5 c 55,0 107,-11 155,-31 l 1,4 2,5 z"
id="path142" />
</g>
<g
id="g144" />
</g>
</g>
<g
id="g146">
<desc
id="desc148">Drawing</desc>
<g
id="g150">
<g
style="fill:#ff0000;stroke:none"
id="g152">
<path
d="m 1741,2867 c -136,0 -246,-107 -246,-240 0,-133 110,-240 246,-240 135,0 245,107 245,240 0,133 -110,240 -245,240 z"
id="path154" />
</g>
<g
style="fill:#000000;stroke:none"
id="g156">
<path
d="m 1741,2872 c -35,0 -68,-7 -98,-19 l 2,-5 2,-4 c 29,11 60,18 94,18 l 0,5 0,5 z"
id="path158" />
<path
d="m 1643,2853 c -30,-13 -57,-31 -80,-53 l 4,-3 3,-4 c 22,21 48,39 77,51 l -2,4 -2,5 z"
id="path160" />
<path
d="m 1563,2800 c -22,-22 -41,-48 -53,-78 l 4,-2 5,-2 c 12,29 30,54 51,75 l -3,4 -4,3 z"
id="path162" />
<path
d="m 1510,2722 c -13,-29 -20,-61 -20,-95 l 5,0 5,0 c 0,32 7,63 19,91 l -5,2 -4,2 z"
id="path164" />
<path
d="m 1490,2627 c 0,-34 7,-66 20,-95 l 4,2 5,2 c -12,28 -19,59 -19,91 l -5,0 -5,0 z"
id="path166" />
<path
d="m 1510,2532 c 12,-30 31,-56 53,-78 l 4,3 3,4 c -21,21 -39,46 -51,75 l -5,-2 -4,-2 z"
id="path168" />
<path
d="m 1563,2454 c 23,-22 50,-40 80,-53 l 2,5 2,4 c -29,12 -55,30 -77,51 l -3,-4 -4,-3 z"
id="path170" />
<path
d="m 1643,2401 c 30,-12 63,-19 98,-19 l 0,5 0,5 c -34,0 -65,7 -94,18 l -2,-4 -2,-5 z"
id="path172" />
<path
d="m 1741,2382 c 34,0 67,7 97,19 l -2,5 -2,4 c -29,-11 -60,-18 -93,-18 l 0,-5 0,-5 z"
id="path174" />
<path
d="m 1838,2401 c 30,13 57,31 80,53 l -4,3 -3,4 c -22,-21 -48,-39 -77,-51 l 2,-4 2,-5 z"
id="path176" />
<path
d="m 1918,2454 c 22,22 41,48 53,78 l -4,2 -5,2 c -12,-29 -30,-54 -51,-75 l 3,-4 4,-3 z"
id="path178" />
<path
d="m 1971,2532 c 13,29 20,61 20,95 l -5,0 -5,0 c 0,-32 -7,-63 -19,-91 l 5,-2 4,-2 z"
id="path180" />
<path
d="m 1991,2627 c 0,34 -7,66 -20,95 l -4,-2 -5,-2 c 12,-28 19,-59 19,-91 l 5,0 5,0 z"
id="path182" />
<path
d="m 1971,2722 c -12,30 -31,56 -53,78 l -4,-3 -3,-4 c 21,-21 39,-46 51,-75 l 5,2 4,2 z"
id="path184" />
<path
d="m 1918,2800 c -23,22 -50,40 -80,53 l -2,-5 -2,-4 c 29,-12 55,-30 77,-51 l 3,4 4,3 z"
id="path186" />
<path
d="m 1838,2853 c -30,12 -63,19 -97,19 l 0,-5 0,-5 c 33,0 64,-7 93,-18 l 2,4 2,5 z"
id="path188" />
</g>
<g
id="g190" />
</g>
</g>
</g>
<g
id="g192">
<desc
id="desc194">Drawing</desc>
<g
id="g196">
<g
style="fill:#000000;stroke:none"
id="g198">
<path
d="m 549,1444 c 153,0 305,0 459,0 -80,194 -335,529 -335,1190 0,476 92,679 158,827 2341,0 -1260,0 1081,0 54,90 191,279 274,370 -2523,0 887,1 -1637,1 C 417,3568 250,3357 250,2634 250,1920 426,1700 549,1444 z"
id="path200" />
<path
d="m 526,1433 c 5,-8 13,-14 23,-14 l 0,25 -23,-11 z"
id="path202" />
<path
d="m 549,1419 459,0 0,25 0,25 -459,0 0,-25 0,-25 z"
id="path204" />
<path
d="m 1008,1419 c 14,0 25,11 25,25 0,3 -1,7 -2,10 l -23,-10 0,-25 z"
id="path206" />
<path
d="m 1031,1454 c -20,49 -51,106 -87,176 l -22,-11 -22,-12 c 34,-68 65,-125 85,-173 l 23,10 23,10 z"
id="path208" />
<path
d="m 944,1630 c -35,69 -74,148 -110,243 l -23,-9 -24,-9 c 37,-96 77,-178 113,-248 l 22,12 22,11 z"
id="path210" />
<path
d="m 834,1873 c -37,94 -71,203 -95,328 l -25,-5 -24,-4 c 25,-129 60,-241 97,-337 l 24,9 23,9 z"
id="path212" />
<path
d="m 739,2201 c -25,126 -41,270 -41,433 l -25,0 -25,0 c 0,-167 16,-314 42,-442 l 24,4 25,5 z"
id="path214" />
<path
d="m 698,2634 c 0,118 6,219 15,307 l -25,2 -24,3 c -10,-89 -16,-192 -16,-312 l 25,0 25,0 z"
id="path216" />
<path
d="m 713,2941 c 10,87 23,160 39,224 l -25,6 -24,5 c -16,-65 -30,-141 -39,-230 l 24,-3 25,-2 z"
id="path218" />
<path
d="m 752,3165 c 15,63 32,116 50,162 l -24,9 -23,9 c -18,-48 -36,-103 -52,-169 l 24,-5 25,-6 z"
id="path220" />
<path
d="m 802,3327 c 18,47 36,87 52,124 l -23,10 -23,10 c -17,-37 -35,-78 -53,-126 l 23,-9 24,-9 z"
id="path222" />
<path
d="m 831,3486 c -10,0 -19,-6 -23,-15 l 23,-10 0,25 z"
id="path224" />
<path
d="m 831,3436 831,0 0,25 0,25 -831,0 0,-25 0,-25 z"
id="path226" />
<path
d="m 1662,3436 c 13,0 25,11 25,25 0,14 -12,25 -25,25 l 0,-25 0,-25 z"
id="path228" />
<path
d="m 1662,3486 -581,0 0,-25 0,-25 581,0 0,25 0,25 z"
id="path230" />
<path
d="m 1081,3486 c -13,0 -25,-11 -25,-25 0,-14 12,-25 25,-25 l 0,25 0,25 z"
id="path232" />
<path
d="m 1081,3436 831,0 0,25 0,25 -831,0 0,-25 0,-25 z"
id="path234" />
<path
d="m 1912,3436 c 9,0 17,5 21,12 l -21,13 0,-25 z"
id="path236" />
<path
d="m 1933,3448 c 54,89 189,276 271,366 l -18,17 -18,17 c -84,-92 -223,-283 -277,-374 l 21,-13 21,-13 z"
id="path238" />
<path
d="m 2204,3814 c 5,5 7,11 7,17 0,14 -11,25 -25,25 l 0,-25 18,-17 z"
id="path240" />
<path
d="m 2186,3856 c -97,0 -185,0 -265,0 l 0,-25 0,-25 c 80,0 168,0 265,0 l 0,25 0,25 z"
id="path242" />
<path
d="m 1921,3856 c -80,0 -152,0 -216,0 l 0,-25 0,-25 c 64,0 136,0 216,0 l 0,25 0,25 z"
id="path244" />
<path
d="m 1705,3856 c -65,0 -122,0 -172,0 l 0,-25 0,-25 c 50,0 107,0 172,0 l 0,25 0,25 z"
id="path246" />
<path
d="m 1533,3856 c -51,0 -94,0 -132,0 l 0,-25 0,-25 c 38,0 81,0 132,0 l 0,25 0,25 z"
id="path248" />
<path
d="m 1401,3856 c -38,0 -69,0 -95,0 l 0,-25 0,-25 c 26,0 57,0 95,0 l 0,25 0,25 z"
id="path250" />
<path
d="m 1306,3856 c -14,0 -25,0 -36,0 l 0,-25 0,-25 c 11,0 22,0 36,0 l 0,25 0,25 z"
id="path252" />
<path
d="m 1270,3856 c -10,0 -20,0 -28,0 l 0,-25 0,-25 c 8,0 18,0 28,0 l 0,25 0,25 z"
id="path254" />
<path
d="m 1242,3856 c -8,0 -15,0 -20,0 l -1,-25 0,-25 c 6,0 13,0 21,0 l 0,25 0,25 z"
id="path256" />
<path
d="m 1222,3856 c -3,0 -6,0 -8,0 l 0,-25 0,-25 c 2,0 5,0 7,0 l 0,25 1,25 z"
id="path258" />
<path
d="m 1214,3856 c -3,0 -5,0 -7,0 l 0,-25 0,-25 c 2,0 4,0 7,0 l 0,25 0,25 z"
id="path260" />
<path
d="m 1207,3856 c -2,0 -3,0 -4,0 l -1,-25 0,-25 c 2,0 3,0 5,0 l 0,25 0,25 z"
id="path262" />
<path
d="m 1203,3856 c -1,0 -2,0 -2,0 l 0,-25 0,-25 c 0,0 1,0 1,0 l 0,25 1,25 z"
id="path264" />
<path
d="m 1201,3856 c -1,0 -1,0 -2,0 l 0,-25 0,-25 c 0,0 1,0 2,0 l 0,25 0,25 z"
id="path266" />
<path
d="m 1199,3856 c 0,0 -1,0 -1,0 l 0,-25 0,-25 c 0,0 1,0 1,0 l 0,25 0,25 z"
id="path268" />
<path
d="m 1198,3856 c 0,0 0,0 -1,0 l 0,-25 0,-25 c 0,0 0,0 1,0 l 0,25 0,25 z"
id="path270" />
<path
d="m 1197,3856 c 0,0 0,0 0,0 l 0,-25 -1,-25 c 0,0 1,0 1,0 l 0,25 0,25 z"
id="path272" />
<path
d="m 1197,3831 -1,0 -25,0 c 0,0 2,-24 25,-25 l 1,25 0,0 z"
id="path274" />
<path
d="m 1197,3831 0,0 -1,25 c -23,0 -25,-24 -25,-25 l 25,0 1,0 z"
id="path276" />
<path
d="m 1197,3806 c 0,0 0,0 1,0 l -1,25 0,25 c 0,0 0,0 -1,0 l 1,-25 0,-25 z"
id="path278" />
<path
d="m 1198,3806 c 0,0 0,0 1,0 l 0,25 0,25 c -1,0 -1,0 -2,0 l 0,-25 1,-25 z"
id="path280" />
<path
d="m 1199,3806 c 0,0 1,0 1,0 l 0,25 0,25 c 0,0 -1,0 -1,0 l 0,-25 0,-25 z"
id="path282" />
<path
d="m 1200,3806 c 2,0 3,0 5,0 l 0,25 0,25 c -2,0 -4,0 -5,0 l 0,-25 0,-25 z"
id="path284" />
<path
d="m 1205,3806 c 2,0 4,0 6,0 l 0,25 0,25 c -2,0 -4,0 -6,0 l 0,-25 0,-25 z"
id="path286" />
<path
d="m 1211,3806 c 5,0 11,0 17,0 l 0,25 0,25 c -6,0 -12,0 -17,0 l 0,-25 0,-25 z"
id="path288" />
<path
d="m 1228,3806 c 7,0 14,0 22,0 l 0,25 0,25 c -8,0 -15,0 -22,0 l 0,-25 0,-25 z"
id="path290" />
<path
d="m 1250,3806 c 32,0 75,0 118,0 l 0,25 0,25 c -43,0 -86,0 -118,0 l 0,-25 0,-25 z"
id="path292" />
<path
d="m 1368,3806 c 43,1 86,1 118,1 l 0,25 0,25 c -33,0 -75,0 -118,-1 l 0,-25 0,-25 z"
id="path294" />
<path
d="m 1486,3807 c 8,0 15,0 22,0 l 0,25 -1,25 c -6,0 -13,0 -21,0 l 0,-25 0,-25 z"
id="path296" />
<path
d="m 1508,3807 c 6,0 12,0 16,0 l 0,25 0,25 c -4,0 -10,0 -17,0 l 1,-25 0,-25 z"
id="path298" />
<path
d="m 1524,3807 c 3,0 5,0 7,0 l 0,25 0,25 c -2,0 -4,0 -7,0 l 0,-25 0,-25 z"
id="path300" />
<path
d="m 1531,3807 c 2,0 3,0 4,0 l 0,25 0,25 c -1,0 -3,0 -4,0 l 0,-25 0,-25 z"
id="path302" />
<path
d="m 1535,3807 c 1,0 2,0 2,0 l 0,25 0,25 c -1,0 -1,0 -2,0 l 0,-25 0,-25 z"
id="path304" />
<path
d="m 1537,3807 c 1,0 1,0 1,0 l 0,25 0,25 c 0,0 -1,0 -1,0 l 0,-25 0,-25 z"
id="path306" />
<path
d="m 1538,3807 c 1,0 1,0 1,0 l 0,25 0,25 c -1,0 -1,0 -1,0 l 0,-25 0,-25 z"
id="path308" />
<path
d="m 1539,3807 c 24,0 25,24 25,25 l -25,0 0,0 0,0 0,-25 z"
id="path310" />
<path
d="m 1564,3832 c 0,0 -1,24 -25,25 l 0,-25 0,0 0,0 25,0 z"
id="path312" />
<path
d="m 1539,3857 c 0,0 0,0 0,0 l 0,-25 -1,-25 c 0,0 0,0 1,0 l 0,25 0,25 z"
id="path314" />
<path
d="m 1539,3857 c 0,0 -1,0 -1,0 l 0,-25 0,-25 c 0,0 0,0 0,0 l 1,25 0,25 z"
id="path316" />
<path
d="m 1538,3857 c 0,0 -1,0 -1,0 l 0,-25 -1,-25 c 1,0 1,0 2,0 l 0,25 0,25 z"
id="path318" />
<path
d="m 1537,3857 c -1,0 -1,0 -2,0 l 0,-25 0,-25 c 0,0 1,0 1,0 l 1,25 0,25 z"
id="path320" />
<path
d="m 1535,3857 c 0,0 -1,0 -2,0 l 0,-25 0,-25 c 1,0 1,0 2,0 l 0,25 0,25 z"
id="path322" />
<path
d="m 1533,3857 c -1,0 -3,0 -5,0 l 0,-25 0,-25 c 2,0 4,0 5,0 l 0,25 0,25 z"
id="path324" />
<path
d="m 1528,3857 c -1,0 -4,0 -6,0 l 0,-25 0,-25 c 2,0 4,0 6,0 l 0,25 0,25 z"
id="path326" />
<path
d="m 1522,3857 c -2,0 -5,0 -8,0 l 0,-25 0,-25 c 3,0 6,0 8,0 l 0,25 0,25 z"
id="path328" />
<path
d="m 1514,3857 c -6,0 -13,0 -21,0 l 0,-25 0,-25 c 8,0 15,0 21,0 l 0,25 0,25 z"
id="path330" />
<path
d="m 1493,3857 c -8,0 -17,0 -28,0 l 0,-25 0,-25 c 11,0 20,0 28,0 l 0,25 0,25 z"
id="path332" />
<path
d="m 1465,3857 c -10,0 -22,0 -35,0 l 0,-25 0,-25 c 13,0 25,0 35,0 l 0,25 0,25 z"
id="path334" />
<path
d="m 1430,3857 c -26,0 -58,0 -96,0 l 0,-25 0,-25 c 38,0 70,0 96,0 l 0,25 0,25 z"
id="path336" />
<path
d="m 1334,3857 c -37,0 -81,0 -131,0 l 0,-25 0,-25 c 50,0 94,0 131,0 l 0,25 0,25 z"
id="path338" />
<path
d="m 1203,3857 c -51,0 -108,0 -173,0 l 0,-25 0,-25 c 65,0 122,0 173,0 l 0,25 0,25 z"
id="path340" />
<path
d="m 1030,3857 c -64,0 -136,0 -216,0 l 0,-25 0,-25 c 80,0 152,0 216,0 l 0,25 0,25 z"
id="path342" />
<path
d="m 814,3857 c -80,0 -168,0 -265,0 l 0,-25 0,-25 c 97,0 185,0 265,0 l 0,25 0,25 z"
id="path344" />
<path
d="m 549,3857 c -10,0 -18,-6 -22,-14 l 22,-11 0,25 z"
id="path346" />
<path
d="M 527,3843 C 460,3710 385,3590 326,3413 l 24,-8 24,-8 c 58,175 132,293 197,424 l -22,11 -22,11 z"
id="path348" />
<path
d="m 326,3413 c -29,-89 -55,-193 -73,-320 l 25,-4 25,-3 c 17,123 42,224 71,311 l -24,8 -24,8 z"
id="path350" />
<path
d="m 253,3093 c -17,-127 -28,-277 -28,-459 l 25,0 25,0 c 0,179 10,327 28,452 l -25,3 -25,4 z"
id="path352" />
<path
d="m 225,2634 c 0,-180 11,-329 30,-455 l 24,4 25,3 c -18,125 -29,271 -29,448 l -25,0 -25,0 z"
id="path354" />
<path
d="m 255,2179 c 18,-127 45,-230 75,-320 l 23,8 24,8 c -29,87 -55,188 -73,311 l -25,-3 -24,-4 z"
id="path356" />
<path
d="m 330,1859 c 59,-177 135,-297 196,-426 l 23,11 23,11 c -62,127 -136,245 -195,420 l -24,-8 -23,-8 z"
id="path358" />
</g>
<g
id="g360" />
</g>
</g>
<g
id="g362">
<desc
id="desc364">Drawing</desc>
<g
id="g366">
<g
style="fill:#666699;stroke:none"
id="g368">
<path
d="m 3432,192 c 1380,0 2421,1125 2421,2452 0,1488 -1275,2375 -2421,2375 -1036,0 -1852,-715 -2087,-1198 273,0 550,0 823,0 221,188 577,541 1264,541 804,0 1759,-615 1759,-1739 0,-856 -693,-1751 -1759,-1751 -596,0 -1108,303 -1457,806 -596,3 -328,0 -636,0 0,-20 -2,-237 0,-241 C 1536,979 2319,192 3432,192 z"
id="path370" />
</g>
<g
style="fill:#000000;stroke:none"
id="g372">
<path
d="m 3432,167 c 348,0 676,71 970,199 l -10,23 -10,22 C 4094,287 3773,217 3432,217 l 0,-25 0,-25 z"
id="path374" />
<path
d="m 4402,366 c 295,127 557,311 776,537 l -18,17 -18,18 C 4928,717 4671,536 4382,411 l 10,-22 10,-23 z"
id="path376" />
<path
d="m 5178,903 c 218,226 393,494 514,789 l -23,9 -23,9 C 5528,1421 5356,1159 5142,938 l 18,-18 18,-17 z"
id="path378" />
<path
d="m 5692,1692 c 120,295 186,617 186,952 l -25,0 -25,0 c 0,-328 -65,-644 -182,-934 l 23,-9 23,-9 z"
id="path380" />
<path
d="m 5878,2644 c 0,188 -20,366 -58,535 l -24,-6 -25,-5 c 37,-165 57,-340 57,-524 l 25,0 25,0 z"
id="path382" />
<path
d="m 5820,3179 c -37,168 -92,327 -162,474 l -22,-10 -23,-11 c 68,-144 122,-299 158,-464 l 25,5 24,6 z"
id="path384" />
<path
d="m 5658,3653 c -139,296 -336,549 -569,755 l -17,-18 -16,-19 c 228,-202 421,-450 557,-739 l 23,11 22,10 z"
id="path386" />
<path
d="m 5089,4408 c -234,206 -503,365 -786,473 l -9,-24 -9,-23 c 278,-106 542,-261 771,-463 l 16,19 17,18 z"
id="path388" />
<path
d="m 4303,4881 c -284,107 -582,163 -871,163 l 0,-25 0,-25 c 283,0 575,-55 853,-160 l 9,23 9,24 z"
id="path390" />
<path
d="m 3432,5044 c -262,0 -510,-45 -738,-121 l 8,-23 8,-24 c 223,74 466,118 722,118 l 0,25 0,25 z"
id="path392" />
<path
d="m 2694,4923 c -228,-75 -437,-180 -620,-301 l 14,-21 14,-21 c 179,119 384,222 608,296 l -8,24 -8,23 z"
id="path394" />
<path
d="m 2074,4622 c -183,-121 -341,-257 -468,-393 l 18,-17 19,-17 c 124,134 279,267 459,385 l -14,21 -14,21 z"
id="path396" />
<path
d="m 1606,4229 c -128,-137 -224,-274 -284,-397 l 23,-11 22,-11 c 58,119 152,252 276,385 l -19,17 -18,17 z"
id="path398" />
<path
d="m 1322,3832 c -1,-3 -2,-7 -2,-11 0,-14 11,-25 25,-25 l 0,25 -23,11 z"
id="path400" />
<path
d="m 1345,3796 823,0 0,25 0,25 -823,0 0,-25 0,-25 z"
id="path402" />
<path
d="m 2168,3796 c 6,0 12,2 16,6 l -16,19 0,-25 z"
id="path404" />
<path
d="m 2184,3802 c 55,47 119,104 194,163 l -16,20 -16,19 c -75,-59 -139,-117 -194,-164 l 16,-19 16,-19 z"
id="path406" />
<path
d="m 2378,3965 c 74,59 159,120 259,175 l -12,22 -12,22 c -103,-57 -190,-119 -267,-180 l 16,-19 16,-20 z"
id="path408" />
<path
d="m 2637,4140 c 100,55 214,104 345,140 l -6,24 -7,24 c -135,-37 -253,-87 -356,-144 l 12,-22 12,-22 z"
id="path410" />
<path
d="m 2982,4280 c 132,35 281,57 450,57 l 0,25 0,25 c -174,0 -328,-22 -463,-59 l 7,-24 6,-24 z"
id="path412" />
<path
d="m 3432,4337 c 198,0 405,-38 605,-112 l 9,23 9,24 c -206,76 -419,115 -623,115 l 0,-25 0,-25 z"
id="path414" />
<path
d="m 4037,4225 c 200,-74 392,-185 560,-330 l 16,19 16,19 c -172,149 -369,263 -574,339 l -9,-24 -9,-23 z"
id="path416" />
<path
d="m 4597,3895 c 167,-145 309,-324 410,-537 l 22,11 23,11 c -104,219 -251,404 -423,553 l -16,-19 -16,-19 z"
id="path418" />
<path
d="m 5007,3358 c 50,-106 90,-220 117,-343 l 24,5 25,6 c -28,126 -69,244 -121,354 l -23,-11 -22,-11 z"
id="path420" />
<path
d="m 5124,3015 c 27,-123 42,-253 42,-392 l 25,0 25,0 c 0,142 -15,277 -43,403 l -25,-6 -24,-5 z"
id="path422" />
<path
d="m 5166,2623 c 0,-211 -43,-424 -123,-625 l 23,-10 23,-9 c 83,207 127,427 127,644 l -25,0 -25,0 z"
id="path424" />
<path
d="m 5043,1998 c -81,-202 -199,-391 -350,-555 l 18,-16 18,-17 c 156,167 277,362 360,569 l -23,9 -23,10 z"
id="path426" />
<path
d="m 4693,1443 c -151,-162 -335,-299 -547,-395 l 10,-23 11,-23 c 218,99 407,240 562,408 l -18,17 -18,16 z"
id="path428" />
<path
d="M 4146,1048 C 3934,952 3695,897 3432,897 l 0,-25 0,-25 c 270,0 517,57 735,155 l -11,23 -10,23 z"
id="path430" />
<path
d="m 3432,897 c -147,0 -289,19 -424,54 l -6,-24 -7,-24 c 140,-37 286,-56 437,-56 l 0,25 0,25 z"
id="path432" />
<path
d="m 3008,951 c -135,36 -264,89 -385,157 l -12,-22 -13,-21 c 125,-71 258,-125 397,-162 l 7,24 6,24 z"
id="path434" />
<path
d="m 2623,1108 c -121,69 -235,152 -340,250 l -17,-18 -17,-18 c 108,-101 225,-187 349,-257 l 13,21 12,22 z"
id="path436" />
<path
d="m 2283,1358 c -105,98 -201,210 -288,334 l -20,-14 -21,-14 c 89,-128 187,-242 295,-342 l 17,18 17,18 z"
id="path438" />
<path
d="m 1995,1692 c -4,7 -12,11 -20,11 l 0,-25 20,14 z"
id="path440" />
<path
d="m 1975,1703 c -50,0 -93,0 -132,1 l 0,-25 0,-25 c 38,-1 82,-1 132,-1 l 0,25 0,25 z"
id="path442" />
<path
d="m 1843,1704 c -38,0 -72,0 -101,0 l 0,-25 0,-25 c 29,0 62,0 101,0 l 0,25 0,25 z"
id="path444" />
<path
d="m 1742,1704 c -29,0 -53,0 -75,0 l 0,-25 0,-25 c 21,0 46,0 75,0 l 0,25 0,25 z"
id="path446" />
<path
d="m 1667,1704 c -21,0 -38,0 -53,0 l 0,-25 0,-25 c 15,0 32,0 53,0 l 0,25 0,25 z"
id="path448" />
<path
d="m 1614,1704 c -15,0 -28,0 -38,0 l 0,-25 0,-25 c 10,0 23,0 38,0 l 0,25 0,25 z"
id="path450" />
<path
d="m 1576,1704 c -11,0 -20,0 -27,0 l 0,-25 0,-25 c 8,0 16,0 27,0 l 0,25 0,25 z"
id="path452" />
<path
d="m 1549,1704 c -16,0 -27,0 -41,0 l 0,-25 1,-25 c 13,0 25,0 40,0 l 0,25 0,25 z"
id="path454" />
<path
d="m 1508,1704 c -7,0 -15,-1 -24,-1 l 0,-25 1,-25 c 9,1 16,1 24,1 l -1,25 0,25 z"
id="path456" />
<path
d="m 1484,1703 c -9,0 -20,0 -33,0 l 1,-25 0,-25 c 13,0 23,0 33,0 l -1,25 0,25 z"
id="path458" />
<path
d="m 1451,1703 c -13,0 -28,0 -46,0 l 0,-25 0,-25 c 18,0 34,0 47,0 l 0,25 -1,25 z"
id="path460" />
<path
d="m 1405,1703 c -19,0 -40,0 -66,0 l 0,-25 0,-25 c 26,0 47,0 66,0 l 0,25 0,25 z"
id="path462" />
<path
d="m 1339,1703 c -14,0 -25,-11 -25,-25 l 25,0 0,25 z"
id="path464" />
<path
d="m 1314,1678 c 0,-13 -1,-114 -1,-181 l 25,0 25,0 c 0,67 1,168 1,181 l -25,0 -25,0 z"
id="path466" />
<path
d="m 1313,1497 c 0,-17 0,-32 0,-42 l 25,0 25,0 c 0,11 0,25 0,42 l -25,0 -25,0 z"
id="path468" />
<path
d="m 1313,1455 c 0,-3 0,-6 0,-8 l 25,1 25,0 c 0,2 0,5 0,7 l -25,0 -25,0 z"
id="path470" />
<path
d="m 1313,1447 c 0,-2 0,-4 0,-6 l 25,1 25,1 c 0,2 0,3 0,5 l -25,0 -25,-1 z"
id="path472" />
<path
d="m 1313,1441 c 1,-1 1,-1 1,-2 l 25,1 25,1 c -1,1 -1,2 -1,2 l -25,-1 -25,-1 z"
id="path474" />
<path
d="m 1314,1439 c 0,-1 0,-2 0,-2 l 25,2 25,2 c 0,0 0,0 0,0 l -25,-1 -25,-1 z"
id="path476" />
<path
d="m 1314,1437 c 0,-1 0,-1 0,-2 l 25,3 24,3 -24,-2 -25,-2 z"
id="path478" />
<path
d="m 1314,1435 c 0,0 0,-1 0,-1 l 25,4 11,1 -11,-1 -25,-3 z"
id="path480" />
<path
d="m 1314,1434 c 0,-1 0,-2 0,-2 l 25,5 4,1 -4,0 -25,-4 z"
id="path482" />
<path
d="m 1314,1432 c 1,-1 1,-2 1,-2 l 24,7 1,1 -1,-1 -25,-5 z"
id="path484" />
<path
d="m 1315,1430 c 0,-2 1,-3 2,-4 l 22,11 0,0 0,0 -24,-7 z"
id="path486" />
<path
d="m 1362,1447 c 0,0 -1,1 -1,1 l -22,-11 23,10 z"
id="path488" />
<path
d="m 1316,1427 c 50,-116 137,-254 258,-394 l 19,16 18,17 c -116,135 -201,268 -249,381 l -23,-10 -23,-10 z"
id="path490" />
<path
d="m 1574,1033 c 119,-140 272,-282 453,-411 l 15,21 14,20 c -178,126 -327,266 -445,403 l -18,-17 -19,-16 z"
id="path492" />
<path
d="m 2027,622 c 182,-128 392,-242 628,-323 l 8,23 8,24 c -230,80 -437,191 -615,317 l -14,-20 -15,-21 z"
id="path494" />
<path
d="m 2655,299 c 235,-82 496,-132 777,-132 l 0,25 0,25 c -275,0 -530,49 -761,129 l -8,-24 -8,-23 z"
id="path496" />
</g>
<g
id="g498" />
</g>
</g>
<g
id="g712">
<desc
id="desc714">Drawing</desc>
<g
id="g716">
<g
style="fill:#000000;stroke:none"
id="g718">
<path
d="m 4035,2800 0,1033 -372,0 0,-2066 372,0 0,1033 z"
id="path720" />
</g>
<g
style="fill:none;stroke:#000000"
id="g722">
<path
style="fill:none"
d="m 4035,2800 0,1033 -372,0 0,-2066 372,0 0,1033"
id="path724" />
</g>
<g
id="g726" />
</g>
</g>
<g
id="g728">
<desc
id="desc730">Drawing</desc>
<g
id="g732">
<g
style="fill:#000000;stroke:none"
id="g734">
<path
d="m 2921,1624 0,188 -372,0 0,-376 372,0 0,188 z"
id="path736" />
</g>
<g
style="fill:none;stroke:#000000"
id="g738">
<path
style="fill:none"
d="m 2921,1624 0,188 -372,0 0,-376 372,0 0,188"
id="path740" />
</g>
<g
id="g742" />
</g>
</g>
<g
id="g744">
<desc
id="desc746">Drawing</desc>
<g
id="g748">
<g
style="fill:#000000;stroke:none"
id="g750">
<path
d="m 2921,2881 0,952 -372,0 0,-1903 372,0 0,951 z"
id="path752" />
</g>
<g
style="fill:none;stroke:#000000"
id="g754">
<path
style="fill:none"
d="m 2921,2881 0,952 -372,0 0,-1903 372,0 0,951"
id="path756" />
</g>
<g
id="g758" />
</g>
</g>
</g>
</g>
</svg>
/tags/2.0/htdocs/init.comp
0,0 → 1,288
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%args>
@P => ()
$envelope_response => 'none'
$envelope_request => 'none'
$json_params => undef
</%args>
<%once>
use Digest::MD5 qw(md5_hex);
use URI;
use URI::QueryParam;
</%once>
<%perl>
binmode(STDERR, ":utf8");
my $http_method = $r->method();
#DEBUG $PLogger->debug(sub { ('#' x 30)." http_method.$http_method ARGS:".Dumper(\%ARGS)});
if($http_method =~ /GET/i){
#accodo a @_ i parametri di @P provenienti da chiamate remote (vedi lib/httpRequestMason.js)
for(my $I=0; $I<@P; $I+=2){
my $var = $P[$I+1];
# condizione di campo nullo
$ARGS{$P[$I]} = $var eq 'undefined' ? undef : $var;
}
delete $ARGS{P};
if($json_params){
my $params = jsonToObj($json_params);
foreach my $key (keys %{$params}){
$ARGS{$key} = $params->{$key}
}
}
delete $ARGS{json_params};
}elsif($http_method =~ /POST|PUT|DELETE/i){
my $content;
if(my $size = $r->headers_in->{'Content-length'}){
$r->read($content, $size);
}
# verifico che sia nel formato UTF-8
utf8::is_utf8($content) || utf8::decode($content);
if ($envelope_request eq 'json'){
$PLogger->debug(sub{ "CONTENT JSON OBJECT = [$content]" });
if(length($content) == 0){
my $err = "ERRORE: Il browser ha inviato una chiamata di tipo POST senza il content\n";
$PLogger->warn(sub{ $err });
$m->put($r->dir_config('HtmlDocType').qq|\n<html><body>$err</body></html>|);
return;
}
my $requestObject = jsonToObj($content);
#DEBUG $PLogger->debug(sub{ "##################### requestObject =", Dumper($requestObject); });
$ARGS{method} = $requestObject->{method};
#DEBUG $PLogger->debug(sub{ "method=" . $ARGS{method}; });
if (defined $requestObject->{params}){
for my $param (keys %{$requestObject->{params}}){
#DEBUG $PLogger->debug(sub{ Dumper($requestObject->{P}{$param}); });
$ARGS{$param} = $requestObject->{params}{$param};
}
}
$envelope_response = $requestObject->{envelope_response} if defined $requestObject->{envelope_response};
}elsif($envelope_request eq 'xml'){
$ARGS{content} = $content;
}elsif ($envelope_request eq 'none' || $envelope_request eq '' || !defined $envelope_request){
$Session{Content} = $content;
}
}
$Session{envelope_response} = $envelope_response;
 
#DEBUG $PLogger->info("\nURI=$ENV{REQUEST_URI}\nARGS=".Dumper(\%ARGS));
 
# numero di righe da ritornare dal recordset
if(!defined $ARGS{rows}){
$ARGS{rows} = 1;
}
# indico un limite ragionevole nel caso venga indicato rows=
# o superiore al limite
if(!$ARGS{rows} || $ARGS{rows} > $r->dir_config('MaxRetrieveRows')){
$ARGS{rows} = $r->dir_config('MaxRetrieveRows');
}
 
# se definito start='' pongo la partenza all'inizio
if(!$ARGS{start}){
$ARGS{start} = 0;
}
 
# Utilizzato per la generazione dei dati nel formato XML <$xml_path>...</$xml_path>
if(!$ARGS{xml_path}){
my $xml_path = $m->base_comp->dir_path;
$xml_path =~ s|^/||;
$xml_path =~ s|/.*||;
$ARGS{xml_path} = $xml_path;
}
 
# verifico il suffisso
my $arg;
if($m->base_comp->name eq $m->dhandler_name){
# chiamata da un dhandler
$arg = $m->dhandler_arg;
}else{
$arg = $m->base_comp->path;
# elimino dal percorso il primo livello
$arg =~ s|/\w+/||;
}
my $suff = $arg;
$suff =~ s/^.*\.//;
if(!$suff){
$suff = 'mql';
}
$ARGS{Suff} = $suff;
$arg =~ s/\..*$//;
$ARGS{Base} = $arg;
if($suff eq 'mql'){
$suff = 'html';
}
if(!$ARGS{method}){
$ARGS{method} = $suff;
}
if(!$ARGS{name}){
my $name = $arg;
$name =~ s|/|.|g;
$ARGS{name} = $name;
}
 
# utilizzato per verificare se c'è ripetuto conflitto nel caricamento dei record in cache
$ARGS{conflict_on_load_records} = 0;
 
# buffer dei recordset
$ARGS{RecordsetCache} = {};
 
# metto a disposizione gli argomenti a tutti
$Session{ARGS} = \%ARGS;
 
</%perl>
%# $PLogger->debug(sub{ '-'x40,'ARGS=',Dumper(\%ARGS), '-'x40; });
%# $PLogger->debug(sub{ '-'x40,'@_=',Dumper(\@_), '-'x40; });
%# $PLogger->debug(sub{ '#' x 70, Dumper(\%ENV), '#' x 70; });
%# componente di inizializzazione dell'applicazione specifica
%# componente da includere in fondo
<& /init.application.comp &>\
% # se il file richiamato è .xls, effettuo un redirect interno al file .mql corrispondente
% if($ARGS{Suff} eq 'xls'){
% $r->internal_redirect($r->dir_config('DataBaseUrl').'/'.$ARGS{Base}.'.mql?'.$ENV{QUERY_STRING});
% $m->clear_buffer;
% $m->abort;
%# my $req = $m->make_subrequest( comp => $r->dir_config('DataBaseUrl').'/'.$ARGS{Base}.'.mql', args => [ %ARGS ] );
%# $req->exec;
%# $m->subexec($r->dir_config('DataBaseUrl').'/'.$ARGS{Base}.'.mql');
% }else{
% $m->call_next;
% }
<%init>
# mi assicuro che venga utilizzata la locale 'C' per i numeri
use POSIX qw(locale_h);
setlocale(LC_NUMERIC, 'C');
# connessione al database
# N.B. Utilizzo Auth_AC::AuthCookieHandler anche per le connessioni con Auth_AC::AuthBasicHandler e anonime
my $dbh = $Session{Dbh} = Auth_AC::AuthCookieHandler->connect($r);
# Nel caso di autenticazione basic $Sess_id, $Hash saranno undef
my ($Login, $Sess_id, $Hash) = split /:/, $Session{Auth_cookie}, 3;
#DEBUG print STDERR "SESSION ($Login, $Sess_id, $Hash) '$ENV{HTTP_SESSION}' '$ENV{REMOTE_USER}' '".$r->user()."'\n";
# recupero i dati dell'Utente
my $sth;
my $row_user;
if($Sess_id){
$sth = $dbh->prepare(q{
SELECT
anagrafiche.id AS anagrafiche_id,
rtrim(anagrafiche.nome) || ' ' || rtrim(anagrafiche.cognome) as nominativo,
session.id AS session_id,
rtrim(nome) || ' ' || rtrim(cognome) as nominativo,
session.user_ip,
session.session,
session.session_time,
session.previus_session_time
FROM anagrafiche
INNER JOIN session ON session.id_anagrafiche = anagrafiche.id
WHERE anagrafiche.login = ?
AND session.session = ?;
});
$sth->execute($Login, $Sess_id);
$row_user = $sth->fetchrow_hashref;
$Session{IP} = $row_user->{user_ip};
}else{
# siamo senza la session (Auth Basic)
$sth = $dbh->prepare(q{
SELECT
id AS anagrafiche_id,
rtrim(nome) || ' ' || rtrim(cognome) as nominativo,
session,
session_time,
previus_session_time
FROM anagrafiche
WHERE anagrafiche.login = ?;
});
$sth->execute($Login);
$row_user = $sth->fetchrow_hashref;
$Session{IP} = $ENV{HTTP_X_FORWARDED_HOST} ? $ENV{HTTP_X_FORWARDED_FOR} : $ENV{REMOTE_ADDR};
}
$Session{Session_id} = $row_user->{session_id};
$Session{User_id} = $row_user->{anagrafiche_id};
$Session{SessionTime} = $row_user->{session_time};
$Session{PreviusSessionTime} = $row_user->{previus_session_time};
$Session{Nominativo} = $row_user->{nominativo};
 
# N.B. $Ver è una variabile globale; utilizzo l'ID session e l'indirizzo IP per definire la hash
$Ver = $Sess_id ? md5_hex($Sess_id.$Session{IP}) : undef;
$Session{Session} = $Sess_id;
$sth = $dbh->prepare(q{
select
gruppi.id,
gruppi.nome
from
gruppi,
anagrafiche_gruppi
where
gruppi.id = anagrafiche_gruppi.id_gruppi and
anagrafiche_gruppi.id_anagrafiche = ?;
});
$sth->execute($Session{User_id});
my @groups = ();
while(my $row_group = $sth->fetchrow_hashref){
$Session{"Group_$row_group->{nome}"} = 1;
push @groups, $row_group->{nome};
}
$Session{Groups} = \@groups;
 
# elaboro i permessi dell'utente
$sth = $dbh->prepare(q{
select distinct
funzioni.nome as funz,
autorizzazioni.nome as auth
from
funzioni,
gruppi,
anagrafiche_gruppi,
autorizzazioni,
gruppi_funzioni
where
gruppi.id = anagrafiche_gruppi.id_gruppi and
anagrafiche_gruppi.id_anagrafiche = ? and
gruppi_funzioni.id_autorizzazioni = autorizzazioni.id and
gruppi_funzioni.id_gruppi = gruppi.id and
gruppi_funzioni.id_funzioni = funzioni.id
order by funzioni.nome, autorizzazioni.nome;
});
$sth->execute($Session{User_id});
my $prev_funz;
while(my $row_auth = $sth->fetchrow_hashref){
# Albero dei permessi
$Session{Auth}{$row_auth->{funz}}{$row_auth->{auth}} = 1;
}
$Session{Input_Date}=0;
$Session{envelope_response} = $envelope_response;
 
# log modifiche al database
$Session{Logs} = $dbh->prepare(q|insert into public.logs (id_anagrafiche, table_name, id_record, field, old_value, new_value) values (?,?,?,?,?,?);|);
#DEBUG $PLogger->debug(sub{ 'SESSION', Dumper(\%Session); });
initBrowserDetect();
</%init>
<%filter>
if($_){
if ($Session{envelope_response} eq 'json'){
$r->headers_out->{'X-JSON-RPC'} = 'JSONResult';
$_ = MasonSQL::JSONRPCUtils::json_rpc_response($_);
}elsif($Session{envelope_response} eq 'xml'){
$r->headers_out->{'X-XML-RPC'} = 'XMLResult';
}elsif($Session{envelope_response} eq 'none' || $Session{envelope_response} eq '' || !defined($Session{envelope_response})){
# Non modifico nulla
}elsif($Session{envelope_response} eq 'rest'){
# Non modifico nulla
}else{
$_ = "<html><head><title>Envelope error!</title></head><body>Envelope type \"$Session{envelope_response}\" is not valid!</body></html>";
}
}else{
$_ = '';
}
</%filter>
<%flags>
inherit => '/library.comp'
</%flags>
%# Ultima riga senza <CR>
/tags/2.0/htdocs/library.comp
0,0 → 1,251
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2020 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%init>
# azzero le variabili globali
%Global=();
# usata dal componente /input/select.comp per la gestione dei buffer
$Global{SelectBufferFlag}=();
if($Session{Dbh}){
$Session{Dbh}->disconnect();
}
# inizializzo i valori di sessione
%Session=();
# cache per i parametri dei campi (vedi lib/dbms_library.comp - FieldFilter_from )
$Session{Fields_params} = {};
 
# individuazione dell'utente (autenticazioni basic, cookies, anonymous)
my $auth_cookie = $r->user;
my ($Login, $Sess_id, $Hash) = split /:/, $auth_cookie, 3;
if(!defined $Login){
# verifico se esiste il cookie di autenticazione con Auth_AC
if(my $cookie = Apache2::Cookie::Jar->new($r)->cookies('Auth_AC::AuthCookieHandler_Auth_AC_')){
$auth_cookie = Apache2::Cookie::Jar->new($r)->cookies('Auth_AC::AuthCookieHandler_Auth_AC_')->value;
if(defined $auth_cookie){
# Verifico la presenza del Cookie di sessione anonima e relativa sessione nel database
($Login, $Sess_id, $Hash) = split /:/, Auth_AC::AuthCookieHandler->authen_ses_key($r, $auth_cookie);
}
}
# Nel caso di assenza di autenticazione attivo la sessione con l'utente anonimo indicato nella configurazione
if(!defined $Login && defined $ENV{HTTP_SESSION}){
my $uri = URI->new( '?'.$ENV{HTTP_SESSION});
my $params = $uri->query_form_hash;
# Verifico la presenza del Cookie di sessione anonima e relativa sessione nel database
$auth_cookie = $params->{session_key};
if(defined $auth_cookie){
($Login, $Sess_id, $Hash) = split /:/, Auth_AC::AuthCookieHandler->authen_ses_key($r, $auth_cookie);
}
if(!$Login){
$Login = $r->dir_config('AnonymousGuestLogin');
# Creo una nuova sessione utente anonimo (anche nel caso che authen_ses_key abbia restituito undef
$auth_cookie = Auth_AC::AuthCookieHandler->authen_cred($r, $Login, undef, undef, undef);
$r->headers_out->{'X-Anonymous-Guest-Session'} = "session_key=$auth_cookie";
($Login, $Sess_id, $Hash) = split /:/, $auth_cookie;
}
}
}
$Session{Login} = $Login;
$Session{Auth_cookie} = $auth_cookie;
 
# Inizializzazione logger Log4perl
my $PLogFilename = $r->dir_config('LogBaseDir') . $r->dir_config('ApplicationName') . '/' . $Login . '.log';
my $PLogName = $r->dir_config('ApplicationName') . 'Appender' . $Login;
$Session{PLogCategory} = $r->dir_config('ApplicationName') . '::' . $Login;
$PLogger = Log::Log4perl::get_logger($Session{PLogCategory});
$PLogger->level(eval '$'.$r->dir_config('PLogLevel'));
unless (defined $Log::Log4perl::Logger::APPENDER_BY_NAME{$PLogName}){
$PLogger->additivity(0);
my $user_appender = Log::Log4perl::Appender->new(
"Log::Log4perl::Appender::File",
name => $PLogName,
filename => $PLogFilename
);
my $user_layout = Log::Log4perl::Layout::PatternLayout->new($r->dir_config('PLogPatternLayout'));
$user_appender->layout($user_layout);
$PLogger->add_appender($user_appender);
}
 
# Sezione JSLogger
unless (defined $JSLogger){
my $check_code = <<CODE;
if (!window.#NAME#){
#INIT#
}
CODE
my $init_code1 = '';
my $init_code2 = <<CODE;
window.#NAME# = console;
CODE
my $log_code = <<CODE;
window.#NAME#.#LEVEL#('MasonSQL', #MSG#);
CODE
$JSLogger = MasonSQL::JSLogger->new();
# $JSLogger->join_separator(' + ');
$JSLogger->set_code({ 'init' => $check_code, 'log' => $log_code});
$JSLogger->init_code(['init'], {init => $init_code2});
$JSLogger->init_code(['init', 'log'], {name => 'JSLogger', minlevel => 'DEBUG'});
}
# Livello di log JavaScript
$JSLogger->level(eval '$'.$r->dir_config('JSLogLevel'));
</%init>
<%perl>
$m->call_next;
</%perl>
<%once>
use Apache2::Cookie;
use Data::Dumper; # DEBUG
$Data::Dumper::Terse = 1;
my $log_dir = $r->dir_config('LogDir');
my $conf = q(
default_pattern = [%d] - %p - %F:%L %m%n
 
log4perl.rootLogger = DEBUG, rootLogfile
 
log4perl.appender.rootLogfile = Log::Log4perl::Appender::File
log4perl.appender.rootLogfile.filename = ).$log_dir.q(/root.log
log4perl.appender.rootLogfile.layout = Log::Log4perl::Layout::PatternLayout
log4perl.appender.rootLogfile.layout.ConversionPattern = ${default_pattern}
 
log4perl.category.masonsql = DEBUG, masonsqlLogfile
 
log4perl.additivity.masonsql = 0
log4perl.appender.masonsqlLogfile = Log::Log4perl::Appender::File
log4perl.appender.masonsqlLogfile.filename = ).$log_dir.q(/masonsql.log
log4perl.appender.masonsqlLogfile.layout = Log::Log4perl::Layout::PatternLayout
log4perl.appender.masonsqlLogfile.layout.ConversionPattern = ${default_pattern}
);
 
Log::Log4perl::init( \$conf );
use Log::Log4perl qw(:levels);
 
use Carp;
use Compress::Zlib;
use HTTP::BrowserDetect;
use DBI;
use JSON;
$JSON::UnMapping = 1;
use Encode 'from_to';
 
# pulisce nella stringa gli spazi iniziali finali ed intermedi se superiori ad uno
sub AllTrim($){
$_ = shift;
s/^\s+//;
s/\s+$//;
s/\s+/ /g;
return $_;
}
# applica alla URL la versione (per gestire la cache del browser)
sub URL {
my $url = shift;
# verifico se è già presente "?"
if($url =~ m/\?/){
$url .= '&'.shift;
}else{
$url .= '?'.shift
}
return $url;
}
 
# cerca nelle varie MasonCompRoot il file specificato, ritornando il persorso completo
sub request_to_comp_path($){
my($comp_name) = @_;
foreach my $root (@{$m->interp->comp_root}) {
my $file_name = ${$root}[1].$comp_name;
if( -e $file_name ) {
return $file_name;
}
}
return undef;
}
 
# set link configurazione accesso database (se si utilizza Reportman versione Kylix
if(my $BorlandConfig = $r->dir_config('BorlandConfig')){
my $ReportmanDir = $r->dir_config('ReportmanDir');
my $link = readlink $ReportmanDir.'/.borland';
if(! defined $link or $link ne $BorlandConfig){
unlink $ReportmanDir.'/.borland';
symlink $BorlandConfig, $ReportmanDir.'/.borland' or die "Errore nel creare il link $ReportmanDir/.borland --> $BorlandConfig\n";
}
}
# Usati per catalogare i componenti da inserire nell'intestazione della pagina <HEAD/>
# $Global{LoadHeader_Css} = {};
# $Global{LoadHeader_Js} = {};
# $Global{LoadHeader_Meta} = {};
# $Global{LoadHeader_Style} = {};
# $Global{LoadHeader_Head} = {};
# $Global{LoadHeader_Body} = {};
 
# componenti di uso generale ...
# Precarica dichiarazioni nella sezione <HEAD> del documento; utilizzata per i componenti della libreria di input
sub LoadHeader{
while(my $comp = shift){
if($comp eq 'SELF'){
$comp = $m->current_comp->name;
}
my $name = $comp;
my $URL = URL($comp, "Ver=$Ver");
# %Global è una variabile dichiarata globale; in /autohandler vengono richiamate
# ed allegate tutte le occorrenze dell'HASH all'interno della sezione <HEAD>
if($name =~ m/\.js$/i){
if(! defined $Global{'Input/'.$name}){
$Global{'Input/'.$name} = 1;
push @{$Global{LoadHeader_Js}}, $name;
}
}elsif($name =~ m/\.css$/i){
if(!defined $Global{'Input/'.$name}){
$Global{'Input/'.$name} = 1;
push @{$Global{LoadHeader_Css}}, qq|<link rel="stylesheet" href="$URL" type="text/css">|;
}
}elsif($name =~ m/\.comp$/i){
my $Comp = $m->fetch_comp($name);
if(!$Comp){
$PLogger->error("Il componente '$name' ha provocato un errore durante il tentativo di caricamento da parte della procedura LoadHeader");
}else{
if($Comp->method_exists('HTML_HEAD')){
if(!defined $Global{'Head/'.$name}){
$Global{'Head/'.$name} = 1;
push @{$Global{LoadHeader_Head}}, $Comp->scall_method('HTML_HEAD');
}
}
if($Comp->method_exists('HTML_BODY')){
if(!defined $Global{'Body/'.$name}){
$Global{'Body/'.$name} = 1;
push @{$Global{LoadHeader_Body}}, "<!-- [Body/$name] -->\n".$Comp->scall_method('HTML_BODY');
}
}
if($Comp->method_exists('LIBRARY')){
my $list = $Comp->scall_method('LIBRARY');
$list =~ s/^\s+|\s+$//g;
my @list = split /\s+/, $list;
&LoadHeader(@list);
}
}
}else{
if(! defined $Global{'Head/'.$name}){
$Global{'Head/'.$name} = 1;
push @{$Global{LoadHeader_Head}}, $m->scomp($comp);
}
}
}
}
 
use HTTP::BrowserDetect;
 
sub initBrowserDetect(){
# verifico se gia inizializzati alcuni attributi della sessione
if(!$Session{Browser}){
# individuo il tipo di browser...
$Session{Browser} = new HTTP::BrowserDetect($r->headers_in->{'User-Agent'});
}
}
</%once>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/frame.html
0,0 → 1,474
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2012 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%once>
my $DataBaseUrl = $r->dir_config('DataBaseUrl');
</%once>
<%init>
# cache
if(my $expiration_time = $r->dir_config('CacheFramesExpiration')){
my %cache_keys = %ARGS;
delete $cache_keys{Ver}; # la cache del server non deve essere influenzata dalla versione (usata per gestire la cache nel browser)
$cache_keys{Groups} = $Session{Groups}; # nella cache devo tener conto anche dei gruppi che potrebbero influenzarne il contenuto
return if $m->cache_self(expire_in => $expiration_time, key => $from.'-'.md5_hex(to_json(\%cache_keys)), busy_lock => '30 sec');
}
# caricamento nella sezione <HEAD/> delle librerie
&LoadHeader('/lib/httpRequestMason.js', '/lib/library.js', '/lib/databinding.js', '/lib/displaybinding.js');
</%init>
<%args>
$from
$form => undef
$children => undef # form da utilizzare per disegnare i figli
$children_container => 'Tab' #undef # contenitore per la visualizzazione dei figli ( undef, 'Tab' oppure 'Accordion' )
$rows => undef # se dichiarato indica il numero di righe da visualizzare nel form (se si tratta di TABLE o DIVS)
# il valore dichiarato nella tabella con <%method TABLE_ROWS> ha la precedenza
$group_cols => 1 # numero di gruppi con cui suddividere la tabella, da affiancare orizzontalmente
$rows_child => undef # se dichiarato indica il numero delle righe delle tabelle figlie
# il valore dichiarato nella tabella figlia con <%method TABLE_ROWS> ha la precedenza
$group_cols_child => 1 # numero di gruppi con cui suddividere le tabelle figlie, da affiancare orizzontalmente
$find_area => undef # posizione area menu; [top, bottom, left, right] - se 'none' non viene visualizzata, se undef viene usata la definizione presente nel file
$find_area_child => undef # posizione area menu dei figli [top] se undef non viene visualizzata - N.B. Da implementare le altre posizioni
$find_component => undef # nome del componente utilizzato per la funzione di filtro
# disp_* - visualizza pulsanti 1:sempre visibile, 0: mai visibile, ''|undef: dipende dai permessi attivati
$disp_navbar => 1 # visualizza il form padre con i pulsanti << < > >> Goto[ ] di navigazione
$disp_cancel => undef # ... pulsante annulla
$disp_refresh => 1 # ... pulsante aggiorna
$disp_change => undef # ... pulsante modifica
$disp_insert => undef # ... pulsante inserimento
$disp_dup => 1 # ... pulsante duplicazione
$disp_save => undef # ... pulsante salva
$disp_delete => undef # ... pulsante cancella
$disp_print => undef # ... pulsante stampa
$disp_xls => undef # ... pulsante espostazione XLS
$disp_log => undef # ... pulsante visualizzazione Log
$disp_find_print => undef # ... pulsante stampa nella sezione di ricerca
$disp_find_xls => undef # ... pulsante espostazione XLS nella sezione di ricerca
$find_key => undef # chiave da cercare al primo caricamento del recordset del padre
$father_id => '' # chiave per selezionare i record in base al codice della tabella MASTER
$father_id_update => '' # chiave per modificare i record in base al codice della tabella MASTER
$mode => 'rewind' # posiziona il record all'inizio
$form_include_pre => undef # nome del metodo aggiuntivo contenuto nel padre da allegate in testa al form
$form_include_post => undef # nome del metodo aggiuntivo contenuto nel padre da allegate in coda al form
$Detail_from => undef # visualizza nel form padre i pulsanti per aprire un form di inserimento/modifica più dettagliato
$childrenDetail_from => undef # visualizza nei form figli i pulsanti per aprire un form di inserimento/modifica più dettagliato
$where => undef # query di filtro da passare al recordset principale
$pk => undef # valore della Primary key da passare come filtro
$prefix => undef # prefisso da utilizzare nel definire i nomi dei form e dei recordset
$MenuDescrOnRight => undef # nel menù di ricerca (quando non è di tipo top/bottom, posiziona le descrizioni dei campi a destra
# del campo, anziché sopra (il metodo MENU_DESCR_ON_RIGHT ha la precedenza)
$min_height => '200px' # altezza minima del form
$height => undef
# se sono presenti dei campi $force_<NOME> vengono utilizzati per inizializzare i valori dei campi al caricamento del primo record
</%args>
<%perl>
if($from !~ m|/|){
# default schema
$ARGS{from} = $from = $r->dir_config('DefaultSchema').'/'.$from;
}
# schema
my($schema) = split(/\//, $from);
my $FATHER = $m->fetch_comp("$DataBaseUrl/$from.mql");
$FATHER || die("Oggetto non esistente '$DataBaseUrl/$from.mql'\n");
if($FATHER->method_exists('PERL_EVAL_PRE')){
eval $FATHER->scall_method('PERL_EVAL_PRE');
$@ && die "PERL_EVAL_PRE error on $from: $@\n";
}
if($FATHER->method_exists('MENU_DESCR_ON_RIGHT')){
$MenuDescrOnRight = $FATHER->scall_method('MENU_DESCR_ON_RIGHT');
}
if(!$find_area){
$find_area = $FATHER->method_exists('FIND_AREA') ? $FATHER->scall_method('FIND_AREA') : 'left';
$find_area =~ s/\s+//sg;
}
if($find_area && !$find_component){
$find_component = ($find_area eq 'top' || $find_area eq 'bottom') ? 'FIND' : 'FIND_MENU';
}
if(!$Detail_from && $FATHER->method_exists('DETAIL_FROM')){
$Detail_from = $FATHER->scall_method('DETAIL_FROM');
}
if($Detail_from && $Detail_from !~ m|/|){
$ARGS{Detail_from} = $Detail_from = $schema.'/'.$Detail_from;
}
if($childrenDetail_from && $childrenDetail_from !~ m|/|){
$ARGS{childrenDetail_from} = $childrenDetail_from = $schema.'/'.$childrenDetail_from;
}
if(!defined $form && $FATHER->method_exists('FATHER_TEMPLATE')){
$form = $FATHER->scall_method('FATHER_TEMPLATE');
}
if(!defined $form){
$form = 'FORM';
}
if($FATHER->method_exists('FORM_TYPE')){
$form = $FATHER->scall_method('FORM_TYPE');
$form =~ s/\s+//sg;
}
my $father_prefix = defined $prefix ? "${prefix}_${from}" : "${form}_${from}";
$father_prefix =~ s|/|_|g;
my $Recordset = $Session{Recordset} = "Rec_${father_prefix}";
my $Display = $Session{Display} = "Disp_${father_prefix}";
if(!defined $children && $FATHER->method_exists('CHILDREN_TEMPLATE')){
$children = $FATHER->scall_method('CHILDREN_TEMPLATE');
}
if(!$children){
$children = 'TABLE';
}
if($rows_child && ($children eq 'FORM' || $children =~ /^TEMPLATE/ || $children eq 'LINEAR')){
$rows_child = 1;
}
if(!defined $children && $FATHER->method_exists('CHILDREN_CONTAINER')){
$children_container = $FATHER->scall_method('CHILDREN_CONTAINER');
}
$children_container = ucfirst lc $children_container;
if($form eq 'FORM' || $form =~ /^TEMPLATE/ || $form eq 'LINEAR'){
$rows = 1;
}else{
if($FATHER->method_exists('TABLE_ROWS')){
$rows = $FATHER->scall_method('TABLE_ROWS', %ARGS);
}elsif(!$rows){
$rows = 10; # default value
}
if($FATHER->method_exists('TABLE_GROUP_COLS')){
# numero di gruppi con cui suddividere la tabella, da affiancare orizzontalmente
$group_cols = $FATHER->scall_method('TABLE_GROUP_COLS', %ARGS);
}
}
$ARGS{'rows'} = $rows;
if($pk){
my $PK = $FATHER->scall_method('KEY', %ARGS);
$where = "$PK = $pk";
if(!$father_id){
# in lib/dbms_library.comp verifico la condizione per evitare il test sul campo "father_id"
$father_id = -2;
}
}
my @child_names;
if($children){
# valuto se la tabella ha figli
$_ = $FATHER->scall_method('SCHEMA_CHILDREN');
@child_names = split /,/, $_;
}
</%perl>
%# In IE deve essere dichiarato name=''
<script>
require(["dojo/parser", "dijit/layout/BorderContainer","dijit/layout/ContentPane"]);
var <%$Recordset%> = new DataBinding('<%$Recordset%>', '<%$from%>', <%$rows%>);
<%$Recordset%>.father_id = '<% $father_id %>';
<%$Recordset%>.father_id_update = '<% $father_id_update %>';
var <%$Display%> = new DisplayBinding('<%$Display%>', <%$Recordset%>);
<%$Display%>.where = '<% $where |js%>';
<%$Display%>.confirmDelMessage = "<%$FATHER->call_method('CONFIRM_DEL_MESSAGE')|js%>";
<%$Display%>.formKeysMovement = '<% $FATHER->scall_method('FORM_KEYS_MOVEMENT') |js%>';
</script>
%# nasconde la pagina durande il rendering dei componenti Dojo
%# Vedi demo: https://dojotoolkit.org/documentation/tutorials/1.8/loading_overlay/
<div id="loadingOverlay_<%$father_prefix%>" class="loadingOverlay pageOverlay"></div>
% # contenitore di padre e figli
<div id="FatherContainer_<%$father_prefix%>" class="FatherContainer"
data-dojo-type="dijit/layout/BorderContainer" design="headline" gutters="false"
style="min-width:400px; min-height:<%$min_height%>; height:<% $height ? $height : '100%' %>; z-index:0; width:100%;">
% if($form_include_pre && $FATHER->method_exists($form_include_pre)){
<div id="FatherIncludePre_<%$father_prefix%>" class="FatherContent FatherIncludePre"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="top" splitter="false" >
% $FATHER->call_method($form_include_pre, Recordset => $Recordset, Display => $Display);
</div>
% }
<div id="FatherMain_<%$father_prefix%>" class="FatherMainContainer"
data-dojo-type="dijit/layout/BorderContainer" design="headline" gutters="false" doLayout="true"
% if(@child_names){
region="top" splitter="true"
style="min-width:100px; min-height:100px; z-index:0; width:100%; height:<% @child_names ? '100px' : '100%' %>;">
% }else{
region="center" splitter="false"
style="min-width:100px; min-height:100px; z-index:0; width:100%; height:100%;">
% }
<A disabled href="#" id="anchor_<%$Display%>"></A>
% if($FATHER->method_exists('FORM_INCLUDE_PRE')){
<div id="FatherFormIncludePre_<%$father_prefix%>" class="FatherContent FatherFormIncludePre"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="top" splitter="false" >
% $FATHER->call_method('FORM_INCLUDE_PRE', Recordset => $Recordset, Display => $Display,
% Recordset_father => undef, Display_father => undef);
</div>
% }
<div id="FatherFormHeader_<%$father_prefix%>" class="FatherContent FatherFormHeader"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="top" splitter="false" >
% $FATHER->call_method('FORM_HEADER', %ARGS, rows => $rows, Controls => 1, Recordset => $Recordset, Display => $Display);
</div>
<div id="FatherFindArea_<%$father_prefix%>" class="<%$find_component%> FatherContent FatherFindArea"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="<% $find_area %>"
splitter="<% $find_area eq 'top' || $find_area eq 'bottom' ? 'false' : 'true' %>" >
% $FATHER->call_method($find_component, %ARGS, Recordset => $Recordset, Display => $Display, DescrOnRight => $MenuDescrOnRight);
</div>
<div id="FatherForm_<%$father_prefix%>" class="FatherContent FatherForm"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="center" splitter="false" >
% if($FATHER->method_exists('FIELDS_INCLUDE_PRE')){
% $FATHER->call_method('FIELDS_INCLUDE_PRE', Recordset => $Recordset, Display => $Display,
% Recordset_father => undef, Display_father => undef);
% }
% $FATHER->call_method($form, %ARGS, rows => $rows, group_cols => $group_cols, Recordset => $Recordset,
% Display => $Display, Header => 0, Controls => 0, Detail_from => $Detail_from);
% if($FATHER->method_exists('FIELDS_INCLUDE_POST')){
% $FATHER->call_method('FIELDS_INCLUDE_POST', Recordset => $Recordset, Display => $Display,
% Recordset_father => undef, Display_father => undef);
% }
</div>
</div>
<script>
<%$Display%>.widgetsContainer = document.getElementById('FatherContainer_<%$father_prefix%>');
console.debug('frame.html FatherContainer_<%$father_prefix%>', <%$Display%>);
% $m->out(@Script_buffer);
% @Script_buffer=();
</script>
% if($children){
% if(@child_names){
<script>
<%perl>
if(@child_names == 1){
$children_container = 'Stack';
}
my %rows_child;
my %template_child;
for(my $col=0; $col<@child_names; $col++){
my $child = $child_names[$col];
# tabella figlia ...
my $child_prefix = defined $prefix ? $prefix.'_'.$child : $child;
$child_prefix =~ s|/|_|g;
my $Recordset_child = $Session{Recordset_child} = 'RecC_'.$child_prefix;
my $Display_child = $Session{Display_child} = 'DispC_'.$child_prefix;
# valuto il numero di righe della tabella figlia
my $CHILD = $m->fetch_comp("$DataBaseUrl/$child.mql");
$CHILD || die("Oggetto figlio di $from non esistente '$DataBaseUrl/$child.mql'\n");
my $rows;
if($CHILD->method_exists('TABLE_ROWS')){
$rows = $CHILD->scall_method('TABLE_ROWS', %ARGS);
}
if(!$rows){
if(!($rows = $rows_child)){
$rows = 10; # numero di righe se non diversamente dichiarato
}
}
my $child_template = $children;
if($CHILD->method_exists('CHILD_TEMPLATE')){
$child_template = $CHILD->scall_method('CHILD_TEMPLATE', from => $from);
}
$template_child{$child} = $child_template;
$rows_child{$child} = $child_template eq 'FORM' || $child_template =~ /^TEMPLATE/ || $child_template eq 'LINEAR' ? 1 : $rows;
</%perl>
var <%$Recordset_child%> = new DataBinding('<%$Recordset_child%>', '<%$child%>', <%$rows_child{$child}%>);
var <%$Display_child%> = new DisplayBinding('<%$Display_child%>', <%$Recordset_child%>);
<%$Recordset_child%>.father = <%$Recordset%>;
<%$Recordset%>.children[<%$col%>] = <%$Recordset_child%>;
<%$Display_child%>.confirmDelMessage = "<%$CHILD->call_method('CONFIRM_DEL_MESSAGE')|js%>";
<%$Display_child%>.formKeysMovement = '<% $CHILD->scall_method('FORM_KEYS_MOVEMENT') |js%>';
% } # loop @child_names
% if($children_container){
require(["dijit/layout/<%$children_container%>Container"]);
% }
</script>
<div id="ChildrenContainer_<%$father_prefix%>" class="ChildrenContainer"
% if($children_container){
data-dojo-type="dijit/layout/<%$children_container%>Container" style="width:100%; height:100%;"
doLayout="true" region="center" splitter="true" >
% }else{
% # tabelle figlie una sotto l'altra
data-dojo-type="dijit/layout/ContentPane" region="center" splitter="true" >
% }
<%perl>
my $child_selected = $FATHER->scall_method('SCHEMA_CHILD_SELECTED');
for(my $col=0; $col<@child_names; $col++){
my $child = $child_names[$col];
my $child_prefix = defined $prefix ? $prefix.'_'.$child : $child;
$child_prefix =~ s|/|_|g;
my $Recordset_child = $Session{Reordset_child} ='RecC_'.$child_prefix;
my $Display_child = $Session{Display_child} = 'DispC_'.$child_prefix;
my $CHILD = $m->fetch_comp("$DataBaseUrl/$child.mql");
my $Description = $CHILD->scall_method($CHILD->method_exists('TITLE') ? 'TITLE' : 'DESCRIPTION', %ARGS);
my $this_group_cols_child = $group_cols_child;
if($CHILD->method_exists('TABLE_GROUP_COLS')){
# numero di gruppi con cui suddividere la tabella figlia, da affiancare orizzontalmente
$this_group_cols_child = $CHILD->scall_method('TABLE_GROUP_COLS', %ARGS);
}
# inserisco nel documento la tabella figlia ...
</%perl>
<& .CHILD, schema => $schema, form => $template_child{$child}, rows => $rows_child{$child}, group_cols => $this_group_cols_child, from => $child,
prefix => $child_prefix, Detail_from => $childrenDetail_from, find_area => $find_area_child,
Recordset => $Recordset_child, Display => $Display_child, MenuDescrOnRight => $MenuDescrOnRight,
Description => $Description, Recordset_father => $Recordset, Display_father => $Display,
Selected => ($child eq $child_selected)
&>
% } # loop @child_names
% if($children_container){
</div>
% }
% } # if(@child_names){
% } # if($children)
% if($FATHER->method_exists('FORM_INCLUDE_POST')){
<div id="FatherFormIncludePost_<%$father_prefix%>" class="FatherContent FatherFormIncludePost"
data-dojo-type="dijit/layout/ContentPane" region="bottom" splitter="false" >
% $FATHER->call_method('FORM_INCLUDE_POST', Recordset => $Recordset, Display => $Display);
</div>
% }
% if($form_include_post && $FATHER->method_exists($form_include_post)){
<div id="FatherIncludePost_<%$father_prefix%>" class="FatherContent FatherIncludePost"
data-dojo-type="dijit/layout/ContentPane" region="bottom" splitter="false" >
% $FATHER->call_method($form_include_post, Recordset => $Recordset, Display => $Display);
</div>
% }
</div>
%#
%# form per la gestione di una tabella figlia
<%def .CHILD>
<%args>
$schema
$from
$form
$prefix
$Recordset
$Display
$Recordset_father
$Display_father
$rows
$group_cols
$find_area => undef
$Detail_from => undef
$Description
$MenuDescrOnRight => undef # nel menù di ricerca (quando non è di tipo top bottom, posiziona le descrizioni dei campi a destra del campo, anziché sopra
$Selected => undef
</%args>
<div id="ChildContainer_<%$prefix%>" class="ChildContainer"
style="display:none;" data-dojo-type="dijit/layout/BorderContainer" doLayout="true"
gutters="false" title="<% $Description |h%>"<% $Selected ? ' selected="true"' : ''%>>
<A disabled href="#" id="anchor_<%$Display%>"></A>
<%perl>
my $CHILD = $m->fetch_comp("$DataBaseUrl/$from.mql");
if($CHILD->method_exists('PERL_EVAL_PRE')){
eval $CHILD->scall_method('PERL_EVAL_PRE');
$@ && die "PERL_EVAL_PRE error on $from: $@\n";
}
if($CHILD->method_exists('MENU_DESCR_ON_RIGHT')){
$MenuDescrOnRight = $CHILD->scall_method('MENU_DESCR_ON_RIGHT');
}
if(!$Detail_from && $CHILD->method_exists('DETAIL_FROM')){
$Detail_from = $CHILD->scall_method('DETAIL_FROM');
}
if($Detail_from && $Detail_from !~ m|/|){
$ARGS{Detail_from} = $Detail_from = $schema.'/'.$Detail_from;
}
if($CHILD->method_exists('FORM_TYPE')){
$form = $CHILD->scall_method('FORM_TYPE');
$form =~ s/\s+//sg;
}
if(!$find_area && $CHILD->method_exists('FIND_AREA')){
$find_area = $CHILD->scall_method('FIND_AREA');
$find_area =~ s/\s+//sg;
}
my $find_component = ($find_area eq 'top' || $find_area eq 'bottom') ? 'FIND' : 'FIND_MENU';
</%perl>
% if($CHILD->method_exists('FORM_INCLUDE_PRE')){
<div id="ChildFormIncludePre_<%$prefix%>" class="ChildContent ChildFormIncludePre"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="top" splitter="false" >
% $CHILD->call_method('FORM_INCLUDE_PRE', Recordset => $Recordset, Display => $Display,
% Recordset_father => $Recordset_father, Display_father => $Display_father);
</div>
% }
% if($find_area){
<div id="ChildFindArea_<%$prefix%>" class="<%$find_component%> ChildContent ChildFindArea"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="<% $find_area %>"
splitter="<% $find_area eq 'top' || $find_area eq 'bottom' ? 'false' : 'true' %>" >
% $CHILD->call_method($find_component, %ARGS, Recordset => $Recordset, Display => $Display, DescrOnRight => $MenuDescrOnRight,
% Recordset_father => $Recordset_father, Display_father => $Display_father);
</div>
% }
<div id="ChildFormHeader_<%$prefix%>" class="ChildContent ChildFormHeader"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="top" splitter="false" >
% $CHILD->call_method('FORM_HEADER', %ARGS, Recordset => $Recordset, Display => $Display, rows => $rows,
% Recordset_father => $Recordset_father, Display_father => $Display_father, Controls => 1);
</div>
<div id="ChildForm_<%$prefix%>" class="ChildContent ChildForm"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="center" splitter="true" >
% if($CHILD->method_exists('FIELDS_INCLUDE_PRE')){
% $CHILD->call_method('FIELDS_INCLUDE_PRE', Recordset => $Recordset, Display => $Display,
% Recordset_father => $Recordset_father, Display_father => $Display_father);
% }
% $CHILD->call_method($form, %ARGS, rows => $rows, group_cols => $group_cols, Header => 0, Controls => 0,
% Recordset => $Recordset, Display => $Display, Detail_from => $Detail_from,
% Recordset_father => $Recordset_father, Display_father => $Display_father);
% if($CHILD->method_exists('FIELDS_INCLUDE_POST')){
% $CHILD->call_method('FIELDS_INCLUDE_POST', Recordset => $Recordset, Display => $Display,
% Recordset_father => $Recordset_father, Display_father => $Display_father);
% }
</div>
% if($CHILD->method_exists('FORM_INCLUDE_POST')){
<div id="ChildFormIncludePost_<%$prefix%>" class="ChildContent ChildFormIncludePost"
data-dojo-type="dijit/layout/ContentPane" doLayout="true" region="bottom" splitter="false" >
% $CHILD->call_method('FORM_INCLUDE_POST', Recordset => $Recordset, Display => $Display,
% Recordset_father => $Recordset_father, Display_father => $Display_father);
</div>
% }
</div>
<script>
<%$Display%>.widgetsContainer = document.getElementById('ChildContainer_<%$prefix%>');
% $m->out(@Script_buffer);
% @Script_buffer=();
</script>
</%def>
%#
<script>
<%perl>
# se inserimento e non è attiva la barra di navigazione limito il recordset
# ai record di id maggiore del valore presente in quel momento
my $key = $FATHER->scall_method('KEY');
if(!$disp_navbar && ($find_key || $mode eq 'insert')){
my $from = $FATHER->scall_method('SCHEMA_FROM');
my $sth = $Session{'Dbh'}->prepare("select max($key) from $from;");
$sth->execute;
my $max_id = $sth->fetchrow_arrayref->[0];
my $where;
if($find_key && $mode eq 'insert' && $max_id){
$where = qq|$key = $find_key or $key > $max_id|;
}elsif($find_key){
$where = qq|$key = $find_key|;
}elsif($mode eq 'insert' && $max_id){
$where = qq|$key > $max_id|;
}
</%perl>\
<%$Display%>.where = '<% $where |js%>';
% }
<%$Recordset%>.canDup = <% $disp_dup ? 'true' : 'false' %>;
%#// se definiti dei valori di default iniziali per il primo inserimento ...
% my %force;
% foreach my $par (keys %ARGS){
% if($par =~ m/force_(.*)/){
% $force{$1} = $ARGS{$par};
% }
% }
% if(keys %force){
<%$Display%>.onchange_frame_force = <%$Display%>.onchange;
<%$Display%>.onchange = function(set, update) {
% foreach my $par (keys %force){
this.getField(<% str2sql_js_delimited($par) %>).set_value(<% str2sql_js_delimited($force{$par})%>);
% }
if(this.onchange_frame_force){
this.onchange_frame_force(this.call_mode);
}
<%$Display%>.onchange = <%$Display%>.onchange_frame_force
}
% }
%#// completamento del rendering grafico ...
masonSql.once('ready', function(tab){
// tab è null se si chiama il frame direttamente dal browser
if(tab){
tab.displayBinding = <%$Display%>;
}
masonSql.frameLoad_Handler('<%$father_prefix%>', <%@child_names ? 'true' : 'false'%>, <%$FATHER->method_exists('FORM_HEIGHT') ? $FATHER->scall_method('FORM_HEIGHT') : 'null' %>);
if(<%$Display%>.post_init()){
<%$Display%>.loadRecords('<%$mode%>', '<%$find_key%>');
}
});
</script>
/tags/2.0/htdocs/css/base.css
0,0 → 1,356
html, body {
border: 0 none;
height: 100%;
padding: 0;
width: 100%;
}
#bodyMasonSql.claro {
font: 9pt Calibri,Arial,Helvetica,Verdana;
}
body {
color: #000090;
background-color: #FAFAFA;
}
p {
margin: 1px 1px 1px 2px;
}
 
%# Copy&Paste classes
p.ColSelectable {
background-color:#f1f1f1;
}
p.ColSelected {
background-color:#fccb9f;
font-style: italic;
}
p.CopyPasteResetInvert {
background-color:#fecccd;
}
p.CopyPasteDisabled {
color:#9d9b9b;
}
 
div.FIND_MENU {
background-color: #F5F5F5;
}
div.FIND {
background-color: #F5F5F5;
}
 
.claro .MessagesNewMessage {
background-color: #FEF7ED;
}
 
div.WinPopupDIV {
position:absolute;
visibility:hidden;
background-color:white;
}
 
div.BodyHelpContainer ul,
div.MenuHelpContainer ul {
margin: 4px 4px 14px -15px;
}
div.BodyHelpContainer li,
div.MenuHelpContainer li {
margin: 4px 8px 4px 10px;
}
 
#bodyMasonSql.claro div.BodyHelpContainer {
margin: 5px;
}
div.BodyHelpContainer p,h1,h2,h3,h4,h5,h6 {
margin-left: 4px;
padding-left: 4px;
}
 
div.MenuHelpContainer a:hover,
div.BodyHelpContainer a:hover {
background-color: #D5D0F0;
}
 
 
%# Riga selezionata quale padre delle tabelle figlie associate
.selectRowFather {
background-color: #6699CC;
}
%# Barra di intestazione di testata e dettaglio
table.FormHeader {
width:100%;
border: 0;
background-color:#E5E5E5;
margin:1;
padding:0;
}
.FormHeader td {
font-size: 0.9em;
}
.FormHeader .record_info {
width:150px;
}
 
%# DA VERIFICARE
%# #bodyMasonSql.claro .ChildFormHeader, #bodyMasonSql.claro .FatherFormHeader {
%# background-color: red;
%# }
 
div.FormHeaderDescription {
white-space: normal;
height: 22px;
line-height: 11px;
text-align: center;
font-size: 0.95em;
display: block;
overflow: hidden;
}
 
%# ----- Layout -----
 
#bodyMasonSql.claro .dijitContentPane {
padding: 0;
margin: 0;
background-color: #FAFAFA;
}
 
#bodyMasonSql.claro .dijitContentPane.FatherForm, #bodyMasonSql.claro .dijitContentPane.ChildForm {
padding: 4px;
}
 
#bodyMasonSql.claro .ChildrenContainer {
%# background-color: #F4F4F4;
}
 
%# in fondo alla finestra principale
%#bodyMasonSql.claro .dijitContentPane
 
#bodyMasonSql.claro #BottomContent {
background-color: #F0F0F0;
}
 
#bodyMasonSql.claro .dijitSplitterV {
background: none repeat scroll 0 0 #E5E5E5;
width: 3px;
}
#bodyMasonSql.claro .dijitSplitterH {
background: none repeat scroll 0 0 #E5E5E5;
height: 3px;
}
#bodyMasonSql.claro .dijitSplitterVHover, #bodyMasonSql.claro .dijitSplitterHHover {
background: none repeat scroll 0 0 #C9C9C9;
}
 
%# Bottoni di controllo (vedi dbms_library.comp:CONTROLS)
#bodyMasonSql.claro .controlBtn.dijitButton {
margin: 1px;
}
#bodyMasonSql.claro .controlBtn .dijitButtonNode {
padding: 1px;
margin:0;
}
#bodyMasonSql.claro .controlBtn .dijitButtonText {
padding: 0px 0px 0px 1px;
line-height: 9pt;
letter-spacing:-0.4pt;
}
#bodyMasonSql.claro .controlBtn .dijitButtonText input {
font-size: 0.9em;
}
 
%# Bug height in Firefox textarea
textarea {
overflow-x: hidden;
}
 
#bodyMasonSql.claro .recordDetailBtn {
font-size: 0.75em;
}
 
#bodyMasonSql.claro .dijitTooltipContainer {
padding: 1px;
}
 
#bodyMasonSql.claro .dijitCalendarEnabledDate {
font-weight: lighter;
}
#bodyMasonSql.claro .dijitCalendarDateLabel {
padding: 1px 4px 0 0;
}
 
#bodyMasonSql.claro .dijitTabChecked {
background-color: #6699cc;
}
 
#bodyMasonSql.claro .dijitDialog {
background-color: #ffffff;
resize: both;
overflow: auto;
}
 
table.FORM_form {
border-style: none;
margin: 0px;
}
table.FORM_form tr {
line-height: 16px;
}
table.FORM_form td {
padding: 0px;
spacing: 0px;
}
 
table.TABLE_group {
border-style: none;
margin: 0px;
}
table.TABLE_group tr {
}
table.TABLE_group td {
padding: 0px;
spacing: 0px;
}
 
table.TABLE_form {
border-style: none;
margin: 0px;
}
table.TABLE_form tr {
line-height: 16px;
}
table.TABLE_form td {
padding: 0px;
spacing: 0px;
text-align: center;
}
table.TABLE_form th {
text-align: center;
padding: 0px;
spacing: 0px;
}
 
tr.ROW_TABLE_D {
%# background-color: #f9f9f9;
}
tr.ROW_TABLE_P {
%# background-color: #eeeeee;
}
%# selezione del record
td.ROW_TABLE_Sel, span.ROW_DIVS_Sel {
width: 35px;
text-align: left;
font-size: 0.72em;
}
 
%# Copy&Paste classes
#bodyMasonSql.claro .WidgetToCopy {
border: 1px solid red;
}
#bodyMasonSql.claro .WidgetPasted {
border: 1px solid #316ac5;
}
 
table.LINEAR_form {
border-style: none;
margin: 0px;
}
table.LINEAR_form tr {
}
table.LINEAR_form td {
padding: 0px;
spacing: 0px;
}
 
table.FIND_form {
border-style: none;
margin: 0px;
width: 100%;
border: 0px;
}
table.FIND_form tr {
line-height: 16px;
}
table.FIND_form td {
padding: 0px;
spacing: 0px;
}
 
table.FIND_MENU_form {
border-style: none;
margin: 0px;
border: 0px;
}
table.FIND_MENU_form tr {
line-height: 16px;
}
table.FIND_MENU_form td {
padding: 0px;
spacing: 0px;
}
 
%##### pageOverlay (usato per nascondere il rendering delle pagine Dojo durante il caricamento)
.pageOverlay {
top: 0;
left: 0;
position: absolute;
height: 100%;
width: 100%;
z-index: 1001;
display: block;
}
 
.loadingOverlay {
background: #fff url('<% $Session{'Dojo_dir'} %>/dijit/themes/claro/images/loadingAnimation.gif') no-repeat 10px 23px;
}
 
.loadingMessage {
padding: 25px 40px;
color: #999;
}
 
 
%################################ CSS per manuale database
p.w3ref {
font-size: 0.8em;
font-style: italic;
text-align: right;
}
 
p.detail {
font-size: 0.9em;
}
 
.error {
color: #FFFFFF;
background-color: #FF0000;
}
 
ul.topic {
list-style-type: upper-alpha;
}
 
li.topic {
font-weight : bold;
}
 
tr.tr0 {
background-color: #F0F0F0;
}
 
tr.tr1 {
background-color: #D8D8D8;
}
 
td.col0 {
font-weight : bold;
width: 20%;
}
 
td.col1 {
font-style: italic;
width: 15%;
}
 
td.col2 {
font-size: 1em;
}
%#END.
/tags/2.0/htdocs/css/input.css
0,0 → 1,226
%# richiamata da /input/input.comp
 
.nowrap {
white-space: nowrap;
}
 
%# pulsanti barra in bottom.html
input.bottom {
font-size: 9pt;
}
 
button, input.button {
height: 15pt;
font-size: 9pt;
background-color: #BCD8F4;
background-image: linear-gradient(#FFFFFF 0px, rgba(255, 255, 255, 0) 3px, rgba(255, 255, 255, 0.75) 100%);
background-repeat: repeat-x;
border: 1px solid #759DC0;
border-radius: 4px 4px 4px 4px;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.15);
color: #000000;
}
button:disabled, input.button:disabled {
background-color: #D3D3D3;
}
button:hover:enabled, input.button:hover:enabled {
background-color: #86BDF2;
color: #000000;
transition-duration: 0.2s;
}
button:active:enabled, input.button:active:enabled {
background-color: #BCD8F4;
}
input.file {
border: 1px solid #BABABA;
height: 13pt;
background-color: #ffffff;
}
 
.UrlComp {
font-size: 0.86em;
}
 
input.radio {
}
 
select {
border: 1px solid #BABABA;
height: 13pt;
background-color: #ffffff;
}
 
span.checkbox {
border: 2px solid #BABABA;
border-right-width: 1px;
border-bottom-width: 1px;
padding-top: 3px;
padding-bottom: 0px;
}
 
input.time {
width: 35px;
text-align: center;
}
 
input.color {
width: 67px;
}
 
input.date {
width: 65px;
}
 
.masonSqlIcons.vAlign {
vertical-align: bottom;
}
 
input.string {
}
input.numberRo {
text-align: right;
}
 
textarea.text {
}
 
span.inputspan_c {
border: 1px solid #BABABA;
border-right-width: 1px;
border-bottom-width: 1px;
display: -moz-inline-box;
display: inline-block;
vertical-align: bottom;
white-space: nowrap;
overflow: hidden;
}
 
span.widget_span {
padding: 0;
margin: 0;
display: inline-block;
border: 1px solid transparent;
text-align:left;
}
 
span.inputspan {
border: 1px solid #BABABA;
border-right-width: 1px;
border-bottom-width: 1px;
display: -moz-inline-box;
display: inline-block;
vertical-align: bottom;
overflow: hidden;
white-space: nowrap;
}
 
span.Files {
border: 1px solid #BABABA;
border-right-width: 1px;
border-bottom-width: 1px;
display: -moz-inline-box;
display: inline-block;
overflow: hidden;
white-space: nowrap;
}
 
span.container {
display: inline-block;
vertical-align: bottom;
white-space: nowrap;
margin: 0px;
border: 0px;
background-color: transparent;
}
 
div.container {
margin: 0px;
border: 0px;
background-color: transparent;
}
 
div.inputdiv {
border: 1px solid #BABABA;
border-right-width: 1px;
border-bottom-width: 1px;
overflow: auto;
}
 
.claro .widget {
color: #000000;
border: 1px solid #BABABA;
font: 1em Calibri,Arial,Helvetica,Verdana;
}
.claro .widgetRo {
background-color: #FFFFFF;
}
.claro .widgetRw {
%# Giallo chiaro
background-color: #FAFADC;
}
.claro .widgetRw:focus, .claro .widgetRwFocus {
%# Giallo-verde chiaro
background-color: #F5FADC;
}
.claro .widgetRoError {
background-color: #FFF4F4;
}
.claro .widgetRwError {
background-color: #FFBFBA;
}
.claro .widgetRwError:focus, .claro .widgetRwErrorFocus {
background-color: #FFB4B4;
}
.claro .widgetRoRequired {
background-color: #FFFFFF;
}
.claro .widgetRwRequired {
%# Arancio chiaro
background-color: #FEF5EA;
}
.claro .widgetRwRequired:focus, .widgetRwRequiredFocus {
background-color: #F9F5EA;
}
.claro .widgetRoWait {
background-color: #F0F0F0;
}
.claro .widgetRwWait {
background-color: #D0D0D0;
}
 
%#Files.comp
#bodyMasonSql.claro .Files_tree .dijitTreeRowSelected.dijitTreeRowHover {
background-color: #cfe5fa;
background-image: url("images/standardGradient.png");
background-image: -moz-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);
background-image: -webkit-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);
background-image: -o-linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);
background-image: linear-gradient(rgba(255, 255, 255, 0.7) 0%, rgba(255, 255, 255, 0) 100%);
border-color: #759dc0;
}
#bodyMasonSql.claro .Files_tree .dijitTreeRowHover {
background-image: none;
background-color: rgba(171, 214, 255, 0);
}
table.Files_table_history {
border-collapse:collapse;
}
table.Files_table_history td {
border: 1px solid #a0a0a0;
}
table.Files_table_history th {
background-color: #e9e9e9;
}
tr.Files_current {
font-weight: bold;
}
td.Files_alert {
font-color: red;
font-weight: bold;
}
button.Files_button {
font-size:0.7em;
margin: 0;
padding: 0;
}
 
/tags/2.0/htdocs/css/divselectpopup.css
0,0 → 1,104
 
tr.DivSelect_Pari {
background-color: #ffffff;
}
tr.DivSelect_Dispari {
background-color: #f9f9f9;
}
tr.DivSelect {
}
tr.DivSelect_Pari_Hover, tr.DivSelect_Dispari_Hover {
background-color: #E4EEF3;
}
tr.DivSelect_Pari_Selected, tr.DivSelect_Dispari_Selected {
background-color: #BFD1DB;
}
tr.DivSelect_Pari_Selected_Hover, tr.DivSelect_Dispari_Selected_Hover {
background-color: #B1C2CB;
}
td.DivSelect_Head {
text-align: center;
font-size: 0.94em;
white-space: nowrap;
}
td.DivSelect_Column {
margin-left: 1;
margin-right: 1;
font-size: 0.94em;
white-space: nowrap;
overflow: hidden;
}
td.DivSelect_Detail {
background-color: #ececec;
padding: 0;
margin: 0;
width: 28px;
white-space: nowrap;
overflow: hidden;
}
button.DivSelect_Detail {
margin: 0;
padding: 0;
height: 13px;
font-size: 0.7em;
}
div.DivSelect_Container {
margin: 0px;
background-color: #ececec;
display: inline-block;
white-space: nowrap;
%# overflow-y: hidden;
%# overflow-x: hidden;
padding-right: 4px;
}
div.DivSelect_ButtonsContainer {
white-space: normal;
}
div.DivSelect_TableContainer {
padding-top: 3;
float: left;
height: 100;
margin: 0px;
border-style: none;
overflow: auto;
background-color: #ececec;
}
span.DivSelect_Info {
line-height: 26px;
}
table.DivSelect_Table {
table-layout:fixed;
width:0;
}
div.DivSelect_Cursor {
background-color: #ececec;
margin: 0px;
border-style: none;
overflow: auto;
width: 19px;
}
div.DivSelect_CursorContent {
margin: 0px;
border-style: none;
width: 1;
height: 1000px;
}
input.DivSelect_TextFilter {
background-color: #fafadc;
font-size: 0.96em;
width: 100%;
}
span.DivSelectButton {
border: 1px outset;
margin-left: 1px;
margin-right: 1px;
border-color: #dfcdcf;
background-color: #dfdddf;
padding-left: 2px;
padding-right: 2px;
cursor: pointer;
}
span.DivSelectButton:hover {
background-color: #dfddbf;
}
 
/tags/2.0/htdocs/css/htmlselectpopup.css
0,0 → 1,26
div.htmlselect_Body {
display: -moz-inline-box;
display: inline-block;
white-space: nowrap;
overflow-y: scroll;
overflow-x: hidden;
padding-right: 4px;
}
 
div.htmlselect_P, div.htmlselect_D {
cursor:pointer;
}
 
div.htmlselect_P {
background-color: #ffffff;
}
div.htmlselect_D {
background-color:#f9f9f9;
}
div.htmlselect_hover {
background-color:#E4EEF3;
}
div.htmlselect_selected {
background-color:#BFD1DB;
}
 
/tags/2.0/htdocs/css/autohandler
0,0 → 1,22
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%attr>
Cache_MaxAge => 12*60*60
</%attr>
<%perl>
$Session{'Dojo_dir'} = $JSLogger->level() eq $DEBUG ? $r->dir_config('DojoDirUrlDebug') : $r->dir_config('DojoDirUrl');
$r->headers_out->{'Cache-Control'} = 'max-age='.$m->base_comp->attr('Cache_MaxAge');
$r->content_type('text/css');
$m->call_next;
</%perl>
<%flags>
inherit => '/library.comp'
</%flags>
/tags/2.0/htdocs/css/icons_controls.css
0,0 → 1,44
%#// Source: http://art.gnome.org/download/themes/icon/1150/ICON-UnofficialTango.tar.bz2
%#// Copyright: CC BY-SA
%#// Author: "Jones Lee" <joneslee85@gmail.com>
%#//
%#// Generated with: http://www.instantsprite.com/ with params: Offset:0 Direction:horizontal FileType:png
%#//
%#// Usare con: <div class='sprite address-book-new'></div>
%#//
.masonSqlIcons { background: url('icons_controls.png') no-repeat top left; width: 16px; height: 16px;}
 
.dijitDisabled .masonSqlIcons { background: url('icons_controlsDisabled.png') no-repeat top left; width: 16px; height: 16px; }
.dijitDisabled.masonSqlIcons { background: url('icons_controlsDisabled.png') no-repeat top left; width: 16px; height: 16px; }
.masonSqlIcons :disabled { background: url('icons_controlsDisabled.png') no-repeat top left; width: 16px; height: 16px; }
 
%#// Position of single images
.masonSqlIcons.calendar { background-position: 0px 0px; }
.masonSqlIcons.cancel { background-position: -17px 0px; }
.masonSqlIcons.change { background-position: -34px 0px; }
.masonSqlIcons.delete { background-position: -51px 0px; }
.masonSqlIcons.down { background-position: -68px 0px; }
.masonSqlIcons.dup { background-position: -85px 0px; }
.masonSqlIcons.find { background-position: -102px 0px; }
.masonSqlIcons.forward { background-position: -119px 0px; }
.masonSqlIcons.goto { background-position: -136px 0px; }
.masonSqlIcons.groups { background-position: -153px 0px; }
.masonSqlIcons.help { background-position: -170px 0px; }
.masonSqlIcons.home { background-position: -187px 0px; }
.masonSqlIcons.insert { background-position: -204px 0px; }
.masonSqlIcons.labels { background-position: -221px 0px; }
.masonSqlIcons.log { background-position: -238px 0px; }
.masonSqlIcons.logout { background-position: -255px 0px; }
.masonSqlIcons.messages { background-position: -272px 0px; }
.masonSqlIcons.password { background-position: -289px 0px; }
.masonSqlIcons.preferences { background-position: -306px 0px; }
.masonSqlIcons.print { background-position: -323px 0px; }
.masonSqlIcons.refresh { background-position: -340px 0px; }
.masonSqlIcons.rewind { background-position: -357px 0px; }
.masonSqlIcons.run { background-position: -374px 0px; }
.masonSqlIcons.save { background-position: -391px 0px; }
.masonSqlIcons.up { background-position: -408px 0px; }
.masonSqlIcons.users { background-position: -425px 0px; }
.masonSqlIcons.xls { background-position: -442px 0px; }
.masonSqlIcons.zip { background-position: -459px 0px; }
 
/tags/2.0/htdocs/css/icons_controls/pallet_ro.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/pallet_rw.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/print.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/refresh.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/save.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/users.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/preferences.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/delete.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/zip.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/password.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/labels.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/insert.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/forward.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/run.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/xls.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/down.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/messages.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/goto.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/logout.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/calendar.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/groups.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/find.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/log.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/up.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/cancel.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/change.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/rewind.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/home.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/dup.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controls/help.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/ColorPicker.css
0,0 → 1,37
.tundra .dojoxColorPicker:hover {
background:#c8e4ff;
border:1px solid #ccc;
}
.tundra .dojoxColorPicker {
background:#e0ecfb;
border:1px solid #ccc;
}
.claro .dojoxColorPicker:hover {
background:#c8e4ff;
border:1px solid #cdcdcd;
}
.claro .dojoxColorPicker {
background:#e0ecfb;
border:1px solid #cdcdcd;
}
.masonSqlIcons.pallet { background-position: 0px 0px;
background-image: url('icons_controls/pallet_rw.png');
}
.dijitDisabled .masonSqlIcons.pallet {
background-image: url('icons_controls/pallet_ro.png');
no-repeat top left;
width: 16px;
height: 16px;
}
.dijitDisabled.masonSqlIcons.pallet {
background-image: url('icons_controls/pallet_ro.png');
no-repeat top left;
width: 16px;
height: 16px;
}
.masonSqlIcons.pallet :disabled {
background-image: url('icons_controls/pallet_ro.png');
no-repeat top left;
width: 16px;
height: 16px;
}
/tags/2.0/htdocs/css/main.css
0,0 → 1,8
<& /css/base.css &>
<& /css/base.application.css &>
<& /css/input.css &>
<& /css/input.application.css &>
<& /css/icons_controls.css &>
<& /css/htmlselectpopup.css &>
<& /css/divselectpopup.css &>
<& /css/ColorPicker.css &>
/tags/2.0/htdocs/css/icons_controls.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/menuarrow.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_actionsDisabled.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/icons_controlsDisabled.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/css/base.application.css
/tags/2.0/htdocs/css/menu.application.css
--- 2.0/htdocs/input/divselect.js (nonexistent)
+++ 2.0/htdocs/input/divselect.js (revision 806)
@@ -0,0 +1,795 @@
+<%doc>
+# ---------------------------------------------------------------------- #
+# Copyright:2002-2013 Leader.IT di Guido Brugnara <http://www.leader.it>
+# Strada della Pozzata, 41 - Villazzano
+# 38123 T R E N T O (ITALY)
+# Authors: Guido Brugnara <gdo@leader.it>
+#
+# $Revision: $ info@leader.it
+# ---------------------------------------------------------------------- #
+</%doc>
+function Input_DivSelect_set_value(value, param){
+ if(value == null){
+ value = this.Empty;
+ }
+ this.value = value;
+ // parametro dato nel formato "descrizione|parametri...\n.....\n...."
+ if(param != null){
+ this.set_param(param, null, value);
+ }else{
+ if(value != this.Empty && this.Source){
+ // verifico la presenza nella cache
+ var cache_param = this.Cache_parameters && this.Cache_parameters[value];
+ if(cache_param == null){
+ // richiedo il valore al server
+ // hReqMason_ExecuteTimeout(rspage, timeout, timeout_callback, callback, func, parms, tag, obj_params, callback_obj)
+ hReqMason_ExecuteTimeout(
+ this.Source,
+ <%$r->dir_config('GetRecordTimeout')%>,
+ Input_DivSelect_TimeoutData,
+ Input_DivSelect_Load_Callback,
+ 'parameters_select',
+ ['key', value],
+ null,
+ null,
+ this
+ );
+ this.set_param(null, null, value);
+ }else{
+ this.set_param(cache_param);
+ }
+ }else{
+ this.set_param(null);
+ }
+ }
+}
+
+// Handler risposta in caso di errore o timeout
+function Input_DivSelect_TimeoutData(contextID, type, str, Obj){
+ if(type == 'TIMEOUT'){
+ my_alert('Timeout caricamento parametri ' + Obj.id);
+ }else{
+ my_alert('ERRORE caricamento parametri ' + Obj.id + ' url=' +this.contextObj.URL+': \n['+str+']');
+ }
+}
+
+// Handler risposta caricamento dinamico dei parametri
+function Input_DivSelect_Load_Callback(str, contextID, Obj){
+ str = str.replace(/^\s+|\s+$/g, '');
+ Obj.set_param(str, null, Obj.get_value());
+ if(Obj.onloadremoteparam){
+ Obj.onloadremoteparam();
+ }
+}
+
+function Input_DivSelect_get_value(value){
+ return this.value;
+}
+
+function Input_DivSelect_Init(Objname, Id_Descr, from, Where, OrderBy, Insert_descr, Insert_parameters, Insert_copyfields, Empty, EmptyDescr, EmptyButton,
+ Descr, Read, Rows, Cols, Buttons, DispTemplate, Query_param, Cache_params, Detail_from, Detail_width, Detail_height, Detail_father, Class){
+ var Obj = Input_Init(Objname, Descr);
+ Obj.icon = document.getElementById('icon_' + Objname);
+ Obj.value = null;
+ Obj.from = from; //Nome del file da caricare (senza .mql)
+ Obj.Source = '<%$r->dir_config('DataBaseUrl')%>/'+Obj.from+'.mql';
+ Obj.DisplayDescr = Input_Init('display_'+Objname, Descr);
+ if(Id_Descr == '')Id_Descr = null;
+ Obj.Id_Descr = Id_Descr;
+ Obj.set_status = function(status){
+ var classList = this.eval_status(status);
+ // non applico la variazione della lista delle classi se non cambia
+ if(this.DisplayDescr.className != classList){
+ this.DisplayDescr.className = classList;
+ }
+ }
+ Obj.Readonly = function (set) {
+ if(set == null){
+ return this.readOnly;
+ }else{
+ this.style.cursor = set ? 'default' : 'pointer';
+ this.readOnly = set;
+ this.set_status();
+ var icon = this.icon;
+ require(["dojo/dom-class"], function(domClass){
+ if(icon){
+ domClass[set ? 'add' : 'remove'](icon, 'dijitDisabled');
+ }
+ });
+ return set;
+ }
+ }
+ Obj.Where = Where;
+ Obj.OrderBy = OrderBy;
+ Obj.Insert_descr = Insert_descr;
+ Obj.Insert_parameters = Insert_parameters;
+ Obj.Insert_copyfields = Insert_copyfields;
+ Obj.Empty = Empty;
+ Obj.EmptyDescr = EmptyDescr;
+ Obj.EmptyButton = EmptyButton;
+ Obj.Rows = Rows;
+ Obj.Cols = Cols;
+ Obj.Buttons = Buttons;
+ Obj.DispTemplate = DispTemplate;
+ Obj.Query_param = Query_param;
+ Obj.Editing = false;
+ Obj.get_value = Input_DivSelect_get_value;
+ Obj.set_value = Input_DivSelect_set_value;
+ Obj.ListEqualBuffer = null;
+ Obj.Previus = Obj.get_value();
+ Obj.Readonly(Read);
+ Obj.Parameters = null;
+ if(Cache_params){
+ Obj.Cache_parameters = {}; //cache dei parametri corrispondenti ai valori presenti nella lista
+ }
+ Obj.Detail_from = Detail_from;
+ Obj.Detail_width = Detail_width;
+ Obj.Detail_height = Detail_height;
+ Obj.Detail_father = Detail_father;
+ Obj.Class = Class;
+ Obj.setFocus = null;
+ // inizializzo dijit/TooltipDialog
+ Input_DivSelect_initPopup();
+ return Obj;
+}
+
+// Visualizza un form di dettaglio del record selezionato
+function Input_DivSelect_PopupDetail(mode, num_row, params){
+ // Obj è il widget
+ var Obj = Input_DivSelect_Popup.Input;
+ // apro una finestra con il dettaglio del record selezionato
+ // costruisco un oggetto 'display' minimale con i soli elementi necessari a lanciare il form (vedi file ../lib/displaybinding.js )
+ var display = {
+ prefix: Obj.id,
+ dataBinding: Input_DivSelect_Popup.dataBinding,
+ gotoRecords: function (mode, key, recordset){
+ return this.dataBinding.gotoRecords(mode, key, recordset);
+ },
+ openFormDetail: DisplayBinding_openFormDetail,
+ openFormDetailByKey: DisplayBinding_openFormDetailByKey,
+ onclosedetail: function(save){
+%# // riapro il popup quando si chiude il form di dettaglio
+ Input_DivSelect_open_list(this.prefix);
+ }
+ };
+ display.openFormDetail(mode, num_row, Obj.Detail_from || Obj.from, Obj.Detail_width, Obj.Detail_height, Obj.Descr, params);
+}
+
+// Richiamato al click di una riga dell'elenco
+function Input_DivSelect_PopupHandler(num_row){
+ var dataBinding = Input_DivSelect_Popup.dataBinding;
+ dataBinding.statusDownload(true); // interrompo l'eventuale recordset in arrivo
+ var value;
+ var param_list;
+ if(num_row == null){
+ value='';
+ }else{
+ if(dataBinding.keys[num_row] == null){
+ // la riga scelta non contiene dati del recordset: ignoro
+ return false;
+ }
+ param_list = dataBinding.data[num_row];
+ value = dataBinding.keys[num_row];
+%#//DEBUG alert('Selezionata riga '+num_row+'\ndi contenuto 1° colonna:' + value + ' param_list=' + param_list.join('|'));
+ // test validità della selezione
+ }
+ // Obj è il widget
+ var Obj = Input_DivSelect_Popup.Input;
+ if(Obj.get_value() != value){
+ // ho un effettivo cambio del valore del widget
+ Obj.set_value(value, param_list);
+ window.setTimeout("document.getElementById('"+Obj.id+"').test_value()",1);
+ Input_DivSelect_Popup.hidePopup();
+ if(Obj.onchange){
+ Obj.onchange();
+ }
+ }else{
+ Input_DivSelect_Popup.hidePopup();
+ }
+}
+
+function Input_DivSelect_emptyRecordset(wait){
+ // .isEmpty è usata per evitare continui aggiornamenti con i campi vuoti (lampeggio)
+ if(!this.isEmpty){
+ var rows = this.Table.tBodies[0].rows;
+ // tolgo la precedente impostazione
+ if(this.row_current != null){
+ rows[this.row_current].style.backgroundColor = ''; // tolgo il colore di sfondo
+ this.row_current = null;
+ }
+ this.DivContainer.style.cursor = wait ? 'wait' : 'default';
+ for(var row=0; row<rows.length; row++){
+ var Row = rows[row];
+ Row.cells[0].firstChild.style.display = 'none';
+ Row.onmouseover = Row.onmouseout = null;
+ var cols = Row.getElementsByTagName('td');
+ Row.style.cursor = wait ? 'wait' : 'default';
+ for(var col=1; col<cols.length; col++){
+ cols[col].innerHTML = '&nbsp;';
+ }
+ }
+ }
+ this.isEmpty = true;
+}
+
+// ridimensionamento del componente
+function Input_DivSelect_rescaleDisplay(){
+ var db = this.dataBinding;
+ // se il primo recordset è stato caricato
+ if(db.max_rows != null){
+ // dimensionamento del cursore proporzionale alle righe del recordset
+ this.DivCursorContent.style.height = Math.floor(db.max_rows / db.max_table_rows * this.DivCursor.offsetHeight).toString() + 'px';
+ }
+ // dimensiono l'altezza per contenere tutta la tabella
+ this.TableContainer.style.height = '1px'; // altrimenti in Moz./Firefox la finestra si allarga ad ogni click
+ var height_px = (this.TableContainer.scrollHeight).toString() + 'px';
+ this.TableContainer.style.height = height_px
+ this.DivCursor.style.height = height_px;
+ // set dimensions larger, so the browser can remove cursors and recalculate dimensions
+ this.DivContainer.style.height = (this.TableContainer.scrollHeight + 30).toString() + 'px';
+ this.TableContainer.style.width = (this.Table.scrollWidth + 10).toString() + 'px';;
+ // set dimensions near limits
+ this.DivContainer.style.height = (this.ButtonsContainer.scrollHeight + this.TableContainer.scrollHeight + 2).toString() + 'px';
+ // con 2 (anziché 15) è ok in Firefox
+ this.TableContainer.style.width = (this.Table.scrollWidth + 15).toString() + 'px';
+ // set larghezza del contenitore, che adatta perfettamente all'occupazione in larghezza dell'oggetto
+ // contenuto comprensiva dello spazio occupato dal cursore
+ this.DivContainer.style.width = (this.TableContainer.offsetWidth+this.DivCursor.offsetWidth).toString() + 'px';
+ // riposiziono il cursore
+ var new_scrollTop = Math.round(this.start * this.DivCursor.scrollHeight / this.dataBinding.max_rows);
+ // my_alert('start='+this.start+' scrollHeight='+this.DivCursor.scrollHeight+' max_rows='+this.dataBinding.max_rows+'\ncambio da '+this.DivCursor.scrollTop+' new_scrollTop='+new_scrollTop);
+ // stringo lo spazio che inizialmente ho dovuto mantenere più largo (15) perché con Chrome si deve tener contro dello scroll laterale che poi non è visibile
+ this.TableContainer.style.width = (this.Table.scrollWidth + 2).toString() + 'px';
+ this.DivContainer.style.width = (this.TableContainer.offsetWidth+this.DivCursor.offsetWidth).toString() + 'px';
+ if(new_scrollTop != this.DivCursor.scrollTop){
+ // ignoro l'evento provocato dall'aggiustamento
+ this.DivCursor.ignore_onscroll = true;
+ // cambio ...
+ this.DivCursor.scrollTop = new_scrollTop;
+ // tolgo il flag dopo un po' di tempo
+ window.setTimeout('Input_DivSelect_Popup.DivCursor.ignore_onscroll = false', 100);
+ }
+}
+
+// inizializzazione dei componenti grafici visualizzati nel popup
+function Input_DivSelect_initDisplay(Info, Table, Container, ButtonsContainer, TableContainer, Cursor, CursorContent){
+ // salvataggio dei vari oggetti grafici
+ // this è l'oggetto dove viene visualizzato il widget
+ this.Info = window.document.getElementById(Info);
+ this.Table = window.document.getElementById(Table);
+ this.DivContainer = window.document.getElementById(Container);
+ this.ButtonsContainer = window.document.getElementById(ButtonsContainer);
+ this.TableContainer = window.document.getElementById(TableContainer);
+ this.DivCursor = window.document.getElementById(Cursor);
+ this.DivCursor.old_scrollTop = this.DivCursor.scrollTop; // per calcolare le variazioni di posizione del cursore
+ this.DivCursor.Popup = this;
+ this.DivCursorContent = window.document.getElementById(CursorContent);
+
+ this.TextFilters = [];
+ // inizializzo i campi di input per la ricerca fulltext
+ var cols = this.Table.tHead.rows[1].cells;
+ for(var c=1; c<cols.length; c++){
+ // ricerco il primo elemento 'input' contenuto in <td/>
+ var input_elem = cols[c].getElementsByTagName('input')[0];
+ // ad ogni variazione chiamo con timeout
+ input_elem.onkeyup = function(){
+ Input_DivSelect_Popup.loadFilteredList(true);
+ }
+ // su cambiamento confermato (perdita di focus oppure con <CR>)
+ input_elem.onchange = function(){
+ Input_DivSelect_Popup.loadFilteredList(false);
+ }
+ this.TextFilters.push(input_elem);
+ }
+ // diattivo se necessario la colonna dei bottoni per attivare i dettagli
+ if(!this.Input.Detail_from){
+ var tHead = this.Table.tHead;
+ tHead.rows[0].cells[0].style.display = 'none';
+ tHead.rows[1].cells[0].style.display = 'none';
+ var rows = this.Table.tBodies[0].rows;
+ for(var row=0; row<rows.length; row++){
+ rows[row].cells[0].style.display = 'none';
+ }
+ }
+
+ // calcolo dimensioni documento cursore provvisoriamente a 10 volte il numero di righe visibili
+ this.DivCursorContent.style.height = (this.DivCursor.offsetHeight * 10).toString() + 'px';
+
+ // ritardo in msec con cui aggiornare il recordset se si muove il cursore
+ this.delayUpdate = 300;
+ this.delayFilter = 300;
+
+ // timer per gestire il ritardo con cui si aggiorna il recordset
+ this.delayUpdateTimer;
+
+ this.DivCursor.onclick = function(evt){
+ console.debug('DivCursor.onclick', evt, this);
+ }
+
+ // evento scroll del cursore
+ var debounce_timer;
+ this.DivCursor.onscroll = function(){
+ if(debounce_timer){
+ // annullo il precedente evento onscroll
+ clearTimeout(debounce_timer)
+ }
+ var DivCursor = this;
+ // attendo un po' prima di eseguire l'evento (debounce)
+ debounce_timer = setTimeout(function(){
+ DivCursor.debounce_timer = null;
+ if(DivCursor.ignore_onscroll){
+ DivCursor.ignore_onscroll = false;
+ return false;
+ }
+ var Popup = DivCursor.Popup;
+ var dataBinding = Popup.dataBinding;
+ // ignoro l'evento se non è stato caricato completamente il primo recordset
+ if(dataBinding.max_rows == null){
+ return false;
+ }
+ DivCursor.ignore_onscroll = true;
+ // calcolo la nuova posizione del recordset
+ var new_start = Math.round(DivCursor.scrollTop * dataBinding.max_rows / DivCursor.scrollHeight);
+ if(new_start == Popup.start){
+ // ignoro l'evento se non cambia la posizione del recordset
+ DivCursor.ignore_onscroll = false;
+ return false;
+ }
+ // cancello il timer legato alla digitazione di caratteri di ricerca
+ if(DivCursor.delayFilterTimer){
+ window.clearTimeout(DivCursor.delayFilterTimer);
+ }
+ // cancellando l'eventuale timer attivo
+ if(Popup.delayUpdateTimer){
+ window.clearTimeout(Popup.delayUpdateTimer);
+ Popup.delayUpdateTimer = null;
+ }
+ Popup.start = new_start;
+%#//DEBUG my_alert('ccc='+DivCursor.ccc+' new start='+Popup.start+' scrollTop='+DivCursor.scrollTop+' scrollHeight='+DivCursor.scrollHeight+' max_rows='+dataBinding.max_rows);
+ // ricalcolo la posizione esatta del cursore e lo riposiziono
+ var new_scrollTop = Math.round(Popup.start * DivCursor.scrollHeight / dataBinding.max_rows);
+ if(new_scrollTop != DivCursor.scrollTop){
+ DivCursor.scrollTop = new_scrollTop;
+ }
+%#//DEBUG my_alert('start='+Popup.start+' new scrollTop='+DivCursor.scrollTop+' scrollHeight='+DivCursor.scrollHeight+' max_rows='+dataBinding.max_rows);
+ // visualizzo il range di righe selezionato
+ Popup.updateInfo(Popup.start);
+ // aggiorna report delle dimensioni
+ var diff = Math.abs(DivCursor.old_scrollTop-DivCursor.scrollTop);
+ DivCursor.old_scrollTop = DivCursor.scrollTop;
+ // spostamento cursore: applico un ritardo
+ if(Popup.start != dataBinding.start){
+%#//DEBUG my_alert('Input_DivSelect_initDisplay ccc='+DivCursor.ccc+' timer '+Popup.delayUpdate+' start='+Popup.start+' previus='+dataBinding.start);
+ Popup.delayUpdateTimer = window.setTimeout("Input_DivSelect_Popup.dataBinding.gotoRecords(Input_DivSelect_Popup.start + 1);", Popup.delayUpdate);
+ }
+ DivCursor.ignore_onscroll = false;
+ }, 60); // debounce_timer
+ } //.onscroll
+
+ // dimensionamento dei componenti e del popup (viene comunque richiamato ad ogni cambiamento dei dati visualizzati)
+ this.rescaleDisplay();
+ // condizioni iniziali del recordset richiamato passando la chiave del record
+ this.dataBinding.initRecordset('rewind', this.Input.get_value());
+}
+
+// Template
+require(['dojox/dtl/filter/strings', 'dojox/dtl/Context']);
+%#DOJO1.8 dojo.require('dojox.dtl.filter.strings');
+%#DOJO1.8 dojo.require('dojox.dtl.Context');
+
+// filtro custom
+%#// esempio di filtro: http://code.google.com/p/dools/source/browse/trunk/dools/docs/widget/_util.js
+dojox.dtl.filter.strings.nbsp = function(value){
+ return value.replace(/\s/g, '&nbsp;');
+};
+dojox.dtl.register.filters("dojox.dtl.filter", {
+ "strings": ["nbsp"]
+});
+
+// inizializzazione del componente popup utilizzato da divselect.comp
+// viene anche inizializzato il dataBinding
+function Input_DivSelect_initPopup(){
+ require(["dojo/ready", "dijit/TooltipDialog", "dijit/popup", "dojo/dom", "dojo/on", "dojo/_base/event"], function(ready, TooltipDialog, popup, dom, on, event){
+ ready(function(){
+ // oggetto dijit/TooltipDialog condiviso tra più componenti
+ if(window.Input_DivSelect_Popup){
+ // da inizializzare una sola volta
+ return;
+ }
+ var Popup = new TooltipDialog({
+ id: 'Input_DivSelect_Popup',
+ onKeyUp: function(event){
+ if(event.keyCode == 27){
+ // chiudo se uso tasto <Esc>
+ this.hidePopup();
+ }
+ }
+ });
+ window.Input_DivSelect_Popup = Popup;
+ Popup.watch('focused', function(property_name, old_val, new_val){
+ if(!new_val){
+ // chiudo la lista se perdo il focus
+ this.hidePopup();
+ }
+ });
+ // inizializzazione recordset
+ Popup.dataBinding = new DataBinding('Input_DivSelect_Popup_db', null, null);
+ window.Input_DivSelect_Popup_db = Popup.dataBinding;
+ // l'arrivo di nuove richieste annullano le precedenti
+ Popup.dataBinding.delete_previus_req = true;
+
+ // collego tra di loro i due oggetti
+ Popup.dataBinding.Popup = Popup;
+
+ // template dell'oggetto per il rendering del codice HTML
+ Popup.templateObj = new dojox.dtl.Template('<% $m->scomp('.Input_DivSelect_template') |js%>');
+
+ // var usata per evitare continui aggiornamenti con i campi vuoti (lampeggio)
+ Popup.isEmpty = false;
+
+ // metodo per cancellare i dati contenuti nel popup
+ Popup.emptyRecordset = Input_DivSelect_emptyRecordset;
+
+ // metodo per inizializzare i componenti grafici nel popup
+ Popup.initDisplay = Input_DivSelect_initDisplay;
+
+ // metodo per ridisegnare i componenti grafici e popup
+ Popup.rescaleDisplay = Input_DivSelect_rescaleDisplay;
+
+ // chiamata quando inizia una richiesta di caricamento di un recordset
+ Popup.dataBinding.onrequest = function (){
+ this.Popup.emptyRecordset(true);
+ }
+
+ Popup.dataBinding.onprechange = function (){
+ // ridimensiono i componenti ed il popup
+ Input_DivSelect_Popup.rescaleDisplay();
+ };
+
+ // show Popup vicino al Widget (se null fa riferimento al Widget della chiamata corrente)
+ Popup.showPopup = function(Widget){
+ popup.open({
+ popup: this,
+ around: Widget,
+ maxHeight: 'Infinity'
+ });
+ // se cambia il widget di riferimento
+ if(Widget != this.Widget){
+ // inizializzo il popup passando i nomi degli oggetti grafici
+ this.Widget = Widget;
+ this.initDisplay('DivSelect_Info', 'DivSelect_Table', 'DivSelect_Container',
+ 'DivSelect_ButtonsContainer', 'DivSelect_TableContainer', 'DivSelect_Cursor', 'DivSelect_CursorContent');
+ // devo riaprire per ricalcolare la posizione del popup
+ popup.open({
+ popup: this,
+ around: Widget,
+ maxHeight: 'Infinity'
+ });
+ this.focus();
+ }else{
+ this.dataBinding.initRecordset('rewind', this.Input.get_value());
+ this.focus();
+ }
+ };
+
+ // nasconde il Popup
+ Popup.hidePopup = function(){
+ //interrompo eventuali download in corso
+ this.dataBinding.statusDownload(true);
+ popup.close(this);
+ };
+
+ // chiamata quando il recordset richiesto è disponibile
+ Popup.dataBinding.onchange = function (){
+ delayUpdateTimer = null;
+ var Popup = this.Popup;
+ // aggiorno lo stato
+ Popup.start = this.start;
+ Popup.updateInfo(this.start);
+ var Id = Popup.Input.get_value(); // ID corrente
+ // carico i dati in tabella
+ var rows = Popup.Table.tBodies[0].rows;
+ // tolgo la precedente impostazione
+ if(Popup.row_current != null){
+ rows[Popup.row_current].style.backgroundColor = ''; // tolgo il colore di sfondo
+ Popup.row_current = null;
+ }
+ Popup.DivContainer.style.cursor = 'default';
+ for(var row=0; row<this.rows; row++){
+ var Row = rows[row];
+ Row.style.cursor = 'default';
+ Row.onmouseover = function(){
+ this.className += '_Hover';
+ return true;
+ }
+ Row.onmouseout = function(){
+ this.className = this.className.replace(/_Hover$/, '');
+ return true;
+ }
+ // verifico se il record corrente corrisponde al campo corrente
+ if(this.keys[row] == Id){
+ Popup.row_current = row;
+ Row.isCurrent = true;
+ // rendo visibile il record corrente della select
+ if(Row.className.match(/_Selected/) == null){
+ Row.className += '_Selected';
+ }
+ }else{
+ Row.className = Row.className.replace(/_Selected/m, '');
+ Row.isCurrent = false;
+ }
+ Row.cells[0].firstChild.style.display = '';
+ var cols = Row.getElementsByTagName('td');
+ for(var col=1; col<cols.length; col++){
+ var value = Popup.dataBinding.data[row][col-1];
+ cols[col].innerHTML = (value == '' || value == null) ? '&nbsp;' : value;
+ }
+ }
+ // righe senza dati
+ for(var row=this.rows; row<rows.length; row++){
+ var Row = rows[row];
+ Row.style.cursor = 'default';
+ Row.onmouseover = Row.onmouseout = null;
+ Row.className = Row.className.replace(/_Selected/m, '');
+ Row.cells[0].firstChild.style.display = 'none';
+ var cols = Row.getElementsByTagName('td');
+ for(var col=1; col<cols.length; col++){
+ cols[col].innerHTML = '&nbsp;';
+ }
+ }
+ // ridimensiono i componenti ed il popup
+ window.setTimeout("window.setTimeout('Input_DivSelect_Popup.rescaleDisplay();', 50); Input_DivSelect_Popup.rescaleDisplay();", 20);
+ Popup.isEmpty = false;
+ }
+
+ // richiamata da dataBinding quando si presenta un errore
+ Popup.dataBinding.onerror = function (err, str){
+ this.Popup.emptyRecordset(false);
+ if(err == 'TIMEOUT'){
+ my_alert('Timeout ricezione dati [' + this.prefix + ']\n il server potrebbe non essere raggiungibile.', 'txt');
+ }else{
+ my_alert(err + ': ' + str, 'txt');
+ }
+ }
+
+ // chiamata dopo la prima inizializzazione del recordset
+ Popup.dataBinding.onload = function (){
+ // blocco la possibilità di modificare i dati
+ this.canUpdate = this.canDelete = this.canInsert = false;
+ // visualizzo le descrizioni dei campi
+ var cols = this.Popup.Table.tHead.rows[0].cells;
+ for(var c=1; c<cols.length; c++){
+ cols[c].innerHTML = '<b>' + this.descriptions[c-1] +'</b>';
+ }
+ }
+
+ // chiamata per aggiornare il filtro, in base al testo inserito
+ // check == true se devo lanciare il timer di attesa
+ Popup.loadFilteredList = function (check){
+%#//DEBUG my_alert('loadFilteredList ' + check);
+ var db = this.dataBinding;
+ // azzero eventuale timer attivo
+ if(this.delayFilterTimer){
+ window.clearTimeout(this.delayFilterTimer);
+ }
+ if(check){
+ // il testo sta cambiando; attendo un certo lasso di tempo prima di
+ // aggiornare il recordset in base ai nuovi parametri
+ if(this.delayUpdateTimer){
+ window.clearTimeout(this.delayUpdateTimer);
+ this.delayUpdateTimer = null;
+ }
+%#//DEBUG my_alert('loadFilteredList timer '+this.delayFilter);
+ this.delayFilterTimer = window.setTimeout("Input_DivSelect_Popup.loadFilteredList(false);", this.delayFilter);
+ return;
+ }
+
+ // provvedo ad inviare la richiesta di una nuova pagina
+ var arr_where = [];
+ var test;
+ for(var I=0; I<this.TextFilters.length; I++){
+ var val = this.TextFilters[I].value;
+ if(val.length > 0){
+ val = val.replace(/'/g, "\\'"); //"
+ arr_where.push([db.names[I], '~*', val, 'text']);
+ test = true;
+ }
+ }
+ if(this.Input.Where){
+ arr_where.push(['--where-input', this.Input.Where]);
+ test = true;
+ }
+ var json_where = test ? JSON.stringify(arr_where) : '';
+
+ // valuto se la condizione di ricerca è variata dalla precedente
+ if(json_where != db.json_where || this.Input.Query_param != db.query_param){
+ db.query_param = this.Input.Query_param;
+ db.json_where = json_where;
+ this.start = 0;
+ this.updateInfo(0);
+ db.loadRecords('bottom');
+ }
+ }
+
+ // aggiorno lo stato del recordset nel display
+ Popup.updateInfo = function (start){
+ var db = this.dataBinding;
+ var max = start + db.max_table_rows;
+ max = (max > db.max_rows) ? db.max_rows : max;
+ this.Info.innerHTML = (start + 1) + '-' + max + '(' + db.max_rows + ')';
+ }
+
+ // chiamata da editSingle_Handler se c'è un cambiamento
+ // è possibile ridefinire l'handler nel caso si voglia cambiare il comportamento del widget
+ Popup.onchangeSingle = function(key){
+ this.Input.set_value(key);
+ this.hidePopup();
+ }
+
+ // chiamata da lib/dbms_library.comp method:Input_DivSelect_Popup_EDIT_SINGLE
+ Popup.editSingle_Handler = function(func, key, Recordset, Display){
+ if(func == 'save'){
+ // verifico se ci sono pendenti modifiche nei record figli
+ if(Recordset.children){
+ for(var I = 0; I < Recordset.children.length; I++){
+ Recordset.children[I].readOnly(true, true);
+ }
+ }
+ if(key){
+ // devo cambiare il valore
+ // ATTENZIONE: codice ritardato, altrimenti XMLHttpRequest viene instanziato nella finestra che viene chiusa!
+ window.setTimeout('Input_DivSelect_Popup.onchangeSingle("'+key+'")', 1);
+ }else{
+ // si verifica quando è stato selezionato il pulsante con i dati non salvati e pertanto la chiave del record è nulla
+ // predispongo la risposta al cambiamento verificando se c'è un record selezionabile
+ Display.onchange = function () {
+ var key = this.dataBinding.keys[0];
+ if(key){
+ // se effettivamente ho un record salvato cambio il valore nel campo del widget
+ window.setTimeout('Input_DivSelect_Popup.onchangeSingle("'+key+'")', 1);
+ window.setTimeout(' Input_DivSelect_Popup.PopupInsert.hidePopup();', 1);
+ }else{
+ // chiudo il form e riapro il selettore
+ window.setTimeout('Input_DivSelect_Popup.PopupInsert.hidePopup();',10);
+ window.setTimeout('Input_DivSelect_Popup.popupWindow.focus();', 1);
+ }
+ }
+ Display.loadRecords('save');
+ return;
+ }
+ }else{
+ // riapro il selettore
+ window.setTimeout('Input_DivSelect_Popup.popupWindow.focus()', 1);
+ }
+ this.PopupInsert.hidePopup();
+ }
+
+ // utilizzata per aprire il form di inserimento di un nuovo record del divselect corrente
+ Popup.openInsert = function (){
+ // valori aggiuntivi da passare alla chiamata
+ var url_params = {};
+ // valori forniti dalla chiamata che sovrascrivono quelli 'di default'
+ var params = this.Input.Insert_parameters;
+ for(var I=0; I<params.length; I+=2){
+ url_params[params[I]] = params[I+1];
+ }
+ // copio dai campi filtro i campi compilati scelti e li passo al form di inserimento come valori iniziali
+ var cols = this.Table.tHead.rows[1].cells;
+ var copyfields = this.Input.Insert_copyfields;
+ for(var c=1; c<cols.length; c++){
+ if(copyfields[c-1]){
+ // ricerco il primo elemento 'input' contenuto in <td/>
+ var input_elem = cols[c].getElementsByTagName('input')[0];
+ if(input_elem.value != ''){
+ url_params['force_' + copyfields[c-1]] = input_elem.value;
+ }
+ }
+ }
+ Input_DivSelect_PopupDetail('insert', null, url_params);
+ }
+ });
+ });
+}
+
+// apre la finestra per selezionare la lista
+// richiamata dal widget quando viene selezionato dall'utente
+function Input_DivSelect_open_list(id){
+ var Obj = document.getElementById(id);
+ if(!Obj.Readonly()){
+ var Popup = Input_DivSelect_Popup;
+ if(Popup.Input != Obj){
+ Popup.isEmpty = false;
+ var dataBinding = Popup.dataBinding;
+ // aggiorno il riferimento al recordset e righe del componente corrente
+ dataBinding.from = Obj.from;
+ // righe visibili
+ dataBinding.max_table_rows = Obj.Rows;
+ // clausola where (all'inizio con il solo filtro definito dalla chiamata del componente)
+ dataBinding.json_where = JSON.stringify([['--where-input', Obj.Where]]);
+ dataBinding.orderby = Obj.OrderBy;
+
+ // parametri supplementali da inviare al server
+ dataBinding.query_param = Obj.Query_param;
+ Popup.Input = Obj;
+ // preparo i dati per il template
+ Obj._MODIFIERS = document._MODIFIERS; //eredito i modificatori per il parsing sull'oggetto Obj
+ // purtroppo il motore del template non permette il loop su un array con incremento 2
+ Obj.Buttons_descr = [];
+ Obj.Buttons_link = [];
+ for(var I=0; I<Obj.Buttons.length; I+=2){
+ var J = Math.ceil(I/2);
+ Obj.Buttons_descr[J] = Obj.Buttons[I];
+ Obj.Buttons_link[J] = Obj.Buttons[I+1];
+ }
+ // purtroppo il motore del template non permette loop sull'incremento di una variabile
+ Obj.Rows_array = new Array(Obj.Rows);
+ for(var I=0; I<Obj.Rows; I++){
+ Obj.Rows_array[I] = I;
+ }
+ // riempio il popup con il codice HTML del template
+ Popup.set('content', Popup.templateObj.render(new dojox.dtl.Context(Obj)));
+ }
+ if(Obj.Detail_father && Obj.displayBinding){
+ var db = Obj.displayBinding.dataBinding;
+ // passo al recordset di selezione l'indicazione dell'ID del padre
+ Popup.dataBinding.father_id = db.father_id;
+ // e del record corrente
+ Popup.dataBinding.child_id = db.keys[Obj.dbRow];
+ }
+ Popup.showPopup(Obj);
+ }
+ return false;
+}
+%# template da utilizzare nel Popup
+%# per la sintassi del template vedi https://docs.djangoproject.com/en/1.3/ref/templates/builtins/
+<%def .Input_DivSelect_template>
+<div id="DivSelect_Container" class="{{Class}} DivSelect_Container">
+ <div id="DivSelect_ButtonsContainer" class="{{Class}} DivSelect_ButtonsContainer">
+ <span id="DivSelect_Info" class="{{Class}} DivSelect_Info"></span>&nbsp;
+{% if EmptyButton.length > 0 %}
+ <span class="{{Class}} DivSelectButton" onclick="window.Input_DivSelect_PopupHandler()">{{EmptyButton|nbsp|safe}}</span>
+{% endif %}
+{% if Insert_descr != null %}
+ <span class="{{Class}} DivSelectButton" onclick="window.Input_DivSelect_Popup.openInsert()">{{Insert_descr|nbsp|safe}}</span>
+{% endif %}
+{% for button_link in Buttons_link %}
+ <span class="{{Class}} DivSelectButton" onclick="{{button_link}}">{{ Buttons_descr.shift()|nbsp|safe}}</span>
+{% endfor %}
+ <span class="{{Class}} DivSelectButton" onclick="Input_DivSelect_Popup.hidePopup();">Annulla</span>
+ </div>
+ <div id="DivSelect_TableContainer" class="{{Class}} DivSelect_TableContainer">
+ <table id="DivSelect_Table" class="{{Class}} DivSelect_Table">
+ <thead>
+ <tr class="{{Class}} DivSelect">
+ <td class="{{Class}} DivSelect_Detail"></td>
+{% for col in Cols %}
+ <td class="{{Class}} DivSelect_Head" style="width:{{col}}px;"><b></b></td>
+{% endfor %}
+ </tr>
+ <tr class="{{Class}} DivSelect">
+ <td class="{{Class}} DivSelect_Detail"></td>
+{% for col in Cols %}
+ <td class="{{Class}} DivSelect_Head" style="width:{{col}}px;">
+ <input class="{{Class}} DivSelect_TextFilter" type="text">
+ </td>
+{% endfor %}
+ </tr>
+ </thead>
+ <tbody>
+{% for datarow in Rows_array %}
+ <tr class="{{Class}} DivSelect_{% cycle Pari,Dispari %}">
+ <td class="{{Class}} DivSelect_Detail"><button class="{{Class}} DivSelect_Detail" onclick="window.Input_DivSelect_PopupDetail('forward', {{forloop.counter}}-1, {})">DET</button></td>
+ {% for datacol in Cols %}
+ <td class="{{Class}} DivSelect_Column" onclick="window.Input_DivSelect_PopupHandler({{forloop.parentloop.counter}}-1)">&nbsp;</td>
+ {% endfor %}
+ </tr>
+{% endfor %}
+ </tbody>
+ </table>
+ </div>
+ <div id="DivSelect_Cursor" class="{{Class}} DivSelect_Cursor">
+ <div id="DivSelect_CursorContent" class="{{Class}} DivSelect_CursorContent">
+ </div>
+ </div>
+</div>
+</%def>
/tags/2.0/htdocs/input/file.comp
0,0 → 1,71
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
# Tarcisio Fedrizzi <tarch@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
 
Optimization: on server use query to upload field without JSON 'base64' field!
eg. file .mql:
<%method FIELDS>file</%method>
<%method SELECT_FIELDS>file - 'base64' AS file</%method>
 
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/file.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$id
$value => undef
$description => ''
$prompt => 'No file selected'
$bgcolor => undef
$icon => 'find' # icona da utilizzare
$icon_del => 'delete' # icona per cancellare il file
$readonly => undef
$width => undef
$style => ''
</%args>
<span class="container" base_class="inputspan" id="<%$id%>" style='background-color: transparent;'
<%&ArgsOnly2HtmlTaglist(
onkeydown => 'return Input_keydown(event);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
ondblclick => "Input_File_Ondblclick('$id', event);"
)%>>
<input id="Upload_<%$id%>" type="file" style='display: none;'
<%&ArgsOnly2HtmlTaglist(
onchange => "Input_File_Onchange('$id', event);"
)%>>
<a id="Link_<%$id%>" style="display: none" href=""></a>
% $width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
<span base_class="inputspan" unselectable id="Display_<%$id%>"
style="<% (defined $width ? "width:$width;" : '').(defined $bgcolor ? "background-color:$bgcolor;" : '').$style %>"></span>
<span class="dijitInline dijitIcon masonSqlIcons <%$icon%> vAlign" id="Icon_<%$id%>"></span>
</span>
% $ARGS{'value'} = defined $value ? $value : '';
% push @Script_buffer, $m->scomp('.defer', %ARGS, icon => $icon, icon_del => $icon_del);
<%def .defer>
<%args>
$id
$value
$description
$icon
$icon_del
$prompt
$readonly
</%args>
% $readonly = $readonly ? 'true' : 'false';
var Id_<%$id%> = Input_File_Init('<%$id%>', '<%$description|js%>', '<%$prompt|js%>', <%$readonly%>, '<%$icon%>', '<%$icon_del%>');
% if(defined $value){
Id_<%$id%>.set_value('<%$value|js%>');
% }
</%def>
/tags/2.0/htdocs/input/file.js
0,0 → 1,237
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2016 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
require(["dijit/Tooltip"]);
 
function Input_File_Init(ObjName, Descr, Prompt, ReadOnly, Icon, Icon_del){
var Obj = Input_Init(ObjName, Descr);
Obj.DisplayDescr = Input_Init('Display_'+ObjName, Descr);
Obj.icon = document.getElementById('Icon_' + ObjName);
Obj.Icon = Icon;
if(Icon_del){
Obj.Icon_del = Icon_del;
require(['dojo/_base/connect', 'dojo/_base/event'], function(connect, event){
connect.connect(Obj.icon, 'onclick', function(evt){
if(!Obj.Readonly()){
Obj.set_value(null);
event.stop(evt);
}
});
});
}
Obj.upload = document.getElementById('Upload_'+ObjName);
Obj.link = document.getElementById('Link_'+ObjName);
Obj.objName = ObjName;
Obj.onclickHandle = null;
Obj.add_onclick = Input_File_add_onclick;
Obj.remove_onclick = Input_File_remove_onclick;
Obj.set_onclick = Input_File_set_onclick;
Obj.update_prompt = Input_File_update_prompt;
Obj.set_value = Input_File_set_value;
Obj.get_value = Input_File_get_value;
Obj.set_status = Input_File_set_status;
Obj.Readonly = Input_File_Readonly;
Obj.file_reader = Input_File_FileReader;
Obj.get_display = function(){
return Html2String(this.DisplayDescr.innerHTML);
}
Obj.DisplayDescr.get_display = function(){
return Html2String(this.innerHTML);
}
Obj.defaultPrompt = Prompt;
Obj.update_prompt(Prompt);
Obj.Tooltip_icon = new dijit.Tooltip({
connectId: [Obj.icon],
showDelay: this.TooltipShowDelay,
});
Obj.Readonly(ReadOnly);
Obj.Parameters = null;
Obj.setFocus = null;
return Obj;
}
 
function Input_File_FileReader(){
if(window.FileReader) {
var obj = this;
var reader = new FileReader();
reader.onload = function(){
obj.upload.dataURL = reader.result;
obj.set_value();
obj.widgetError = false;
obj.set_status();
};
require(["dojo/on"], function(on){
on(reader, "error", function(evt){
var err = evt.target.error;
my_alert(err.name+': '+err.message);
obj.widgetError = 'Error';
obj.set_status();
});
});
return reader;
}else{
Input_ErrorMessage(Event,
'The FileReader API is not fully supported in this browser.');
return null;
}
}
 
function Input_File_Ondblclick(ObjName, Event){
var obj = document.getElementById(ObjName);
if(obj.file && obj.file.hasOwnProperty('base64')){
obj.link.href = "data:application/octet-stream;base64,"+obj.file.base64;
obj.link.download = obj.file.filename;
obj.link.click();
}else{
var db = obj.displayBinding.dataBinding;
require(["dojo/io-query"], function(ioQuery){
var query = {
method: 'input_file_uload',
father_id: db.father_id,
field: obj.name,
value: obj.value,
key: db.keys[obj.dbRow]
}
var url = '<%$r->dir_config('DataBaseUrl')%>/' + db.from + '.mql?' + ioQuery.objectToQuery(query);
var w = 800;
var h = 1000;
var left = (screen.width - w) / 2;
var top = (screen.height - h) / 3;
window.open(url, '_blank', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,copyhistory=no,width='+w+',height='+h+',top='+top+',left='+left);
});
}
}
 
function Input_File_set_status(Status){
var classList = this.eval_status(Status);
// non applico la variazione della lista delle classi se non cambia
if(this.DisplayDescr.className != classList){
this.DisplayDescr.className = classList;
}
}
 
function Input_File_Readonly(Set){
if(Set == null){
return this.readOnly;
}else{
this.readOnly = Set;
this.set_onclick(Set);
this.disabled = Set;
this.style.cursor = Set ? 'default' : 'pointer';
this.set_status();
var widget = this;
require(["dojo/dom-class"], function(domClass){
domClass[Set ? 'add' : 'remove'](widget.icon, 'dijitDisabled');
if(widget.Icon_del){
domClass.replace(widget.icon, Set ? widget.Icon : widget.Icon_del, Set ? widget.Icon_del : widget.Icon);
widget.Tooltip_icon.label = Set ? null : 'Cancella il file';
}
});
return Set;
}
}
 
function Input_File_set_onclick(readonly){
if(readonly){
this.remove_onclick();
}else{
this.add_onclick();
}
return;
};
 
function Input_File_remove_onclick(){
var handle = this.onclickHandle;
if(handle && handle.hasOwnProperty('remove')){
handle.remove();
}
this.onclickHandle = null;
return;
}
 
function Input_File_add_onclick(){
var obj = this;
require(["dojo/on"], function(on){
if(!obj.onclickHandle){
obj.onclickHandle = on(obj, "click", function(){
obj.upload.click();
});
}
});
}
 
function Input_File_Onchange(ObjName, Event){
var input = Event.target;
var obj = document.getElementById(ObjName);
Input_DeleteDescription();
obj.isChanged = false;
if(!window.FileReader){
my_alert('The FileReader API is not fully supported in this browser.');
return Input_abortChange(obj, Event);
}
var inputFile = input.files[0];
var reader = obj.file_reader();
if(inputFile && reader){
reader.readAsDataURL(inputFile);
obj.upload.fileName = inputFile.name;
obj.update_prompt(inputFile.name);
return true;
}
return false;
};
 
function Input_File_update_prompt(Prompt){
var obj = this;
require(["dojo/dom"], function(aspect){
obj.DisplayDescr.innerHTML = '<p>'+Prompt+'</p';
});
return;
}
 
function Input_File_set_value(Value, param){
var upload = this.upload;
if(Value){
this.value = Value;
this.file = JSON.parse(Value);
this.update_prompt(this.file.filename);
upload.value = '';
delete upload.fileName;
delete upload.dataURL;
}else if(upload.hasOwnProperty('fileName') &&
upload.hasOwnProperty('dataURL')){
var arr = upload.dataURL.split(/(:|;|,)/);
dojo.require("dojox.encoding.digests.MD5");
this.file = {
filename: upload.fileName,
'content-type': arr[2],
base64: arr[6],
digest_md5: dojox.encoding.digests.MD5(arr[6])
};
this.value = JSON.stringify(this.file);
delete upload.fileName;
delete upload.dataURL;
}else{
this.value = null;
upload.value = '';
this.update_prompt(this.defaultPrompt);
}
if(param != null){
this.set_param(param);
}
};
 
function Input_File_get_value(){
if(this.value){
return this.value;
}else{
return null;
}
};
 
/tags/2.0/htdocs/input/Files.js
0,0 → 1,526
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2011 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
require(["dojo/store/JsonRest", "dojo/store/Observable", "dijit/Menu", "dijit/Tree", "dijit/TooltipDialog",
"dijit/tree/dndSource", "dojox/form/Uploader", "dojox/form/uploader/FileList", "dojo/io-query"]);
 
dojo.ready(function(){
%#// tooltip per mostare la storia dei file
window.Input_Files_history_dialog = new dijit.TooltipDialog({
id: 'Input_Files_history_dialog',
onLoad: function(){
var Id = this.tree.widget.get_value(); // ID corrente
%# // toglie barra scorrimento se non necessaria (vedi <div class="htmlselect_Body" ... )
this.focus();
},
onKeyUp: function(event){
if(event.keyCode == 27){
// chiudo la lista se uso tasto <Esc>
dijit.popup.close(this);
}
},
hidePopup: function(){
dijit.popup.close(this);
}
});
Input_Files_history_dialog.hidePopup = function(){
dijit.popup.close(this);
};
Input_Files_history_dialog.watch('focused', function(property_name, old_val, new_val){
if(!new_val){
Input_Files_history_dialog.hidePopup();
}
});
});
 
function Input_Files_Init(Objname, Descr, Readonly, From, Value, Delete_if_update){
var Obj = Input_Init(Objname, Descr);
Obj.From = From;
Obj.value = Value;
Obj.Delete_if_update = Delete_if_update;
 
Obj.get_value = function (){
return this.value;
};
 
Obj.set_value = function (value){
this.value = value;
var store = this.tree.model;
%# // svuoto la tree
store.setChange({id:'/', name:'...', children: []});
%# // cambio tree
store.target = "/archive/" + this.From + '/' + value;
if(value){
%# // richiedo la tree al server
store.get('/').then(function (dir){
store.setChange(dir)
});
}
};
// inizializzo i widget solo quando Dojo è pronto
dojo.ready(function(){
// creo lo store
var Store = dojo.store.JsonRest({
target: "/archive/" + From + '/' + Value,
root: '/',
mayHaveChildren: function(object){
return object.children != null;
},
getRoot: function(onItem, onError){
onItem({ id: '/', name:'...', children:1});
},
getChildren: function(object, onComplete, onError){
// retrieve the full copy of the object
var store = this;
this.get(object.id).then(
function(fullObject){
// copy to the original object so it has the children array as well.
object.children = fullObject.children;
// now that full object, we should have an array of children
onComplete(fullObject.children);
store.setChildrenEmpty(fullObject.children);
},
function(error){
my_alert('ERROR getChildren:' + error.message + '<br>' + error.responseText, 'html');
console.debug('Error on getChildren', error);
onError(error);
}
);
},
setChange: function(item){
this.onChange(item);
if(item.children){
this.onChildrenChange(item, item.children);
this.setChildrenEmpty(item.children);
}
},
setChildrenEmpty: function(children){
var store = this;
require(["dojo/_base/array"], function(array){
array.forEach(children, function(child, i){
%# // .children è nullo se non è cartella, 1: se ha figli e [] se è cartella vuota
if(child.children && child.children.length == 0){
%# // toglie [+] a sinistra della cartella
store.onChildrenChange({ id: child.id }, []);
}
});
});
},
getLabel: function(object){
// just get the name
return object.name;
},
pasteItem: function(child, oldParent, newParent, bCopy, insertIndex){
if(this.tree.widget.readOnly){
my_alert('Spostamento non autorizzato');
return false;
}
var dest_dir_id = this.mayHaveChildren(newParent) ? newParent.id : newParent.id.replace(/\/[^\/]*$/, '');
if(oldParent.id == dest_dir_id){
return false;
}
// comunico al server lo spostamento
child.new_id = dest_dir_id + '/' + child.id.replace(/^.*\//, '');
child.children = null;
var store = this;
store.put(child).then(function(){
// aggiorno la cartella nell'albero
store.get(dest_dir_id).then(function(dir){
store.setChange(dir)
});
store.get(oldParent.id).then(function(dir){
store.setChange(dir)
});
});
},
put: function(object, options){
// execute the default action
var item = this;
return dojo.store.JsonRest.prototype.put.apply(this, arguments).then(
function(response){
if(response.error){
console.error('put response', response);
my_alert((response.name ? 'File ' + response.name + ' - ' : '') + 'Errore: ' + response.error);
}else{
console.debug('put response', response);
// fire the onChildrenChange event
item.onChildrenChange(object, object.children);
item.setChildrenEmpty(object.children);
// fire the onChange event
item.onChange(object);
if(response.info){
my_alert((response.name ? 'File ' + response.name + ': ' : '') + response.info);
}
}
},
function(error){
my_alert('ERROR:' + error.message +'<br>'+ error.responseText, 'html');
console.debug('Error on put', error);
}
);
},
remove: function(id){
var store = this;
var id_dir = id.replace(/\/[^\/]*$/, '');
return dojo.store.JsonRest.prototype.remove.apply(this, arguments).then(
function(response){
response = dojo.json.parse(response);
if(response.error){
console.error('remove response', response);
my_alert((response.name ? 'File ' + response.name + ' - ' : '') + 'Errore: ' + response.error);
}else{
console.debug('remove response', response);
// aggiorno la directory che conteneva il file cancellato
store.get(id_dir).then(function(dir){
// notifico il cambiamento
store.setChange(dir)
});
if(response.info){
my_alert((response.name ? 'File ' + response.name + ': ' : '') + response.info);
}
}
},
function(error){
my_alert('ERROR:' + error.message + '<br>' + error.responseText, 'html');
console.debug('Error on delete', error);
}
);
}
%# // we can also put event stubs so these methods can be
%# // called before the listeners are applied
%# ,onChildrenChange: function(parent, children){
%# // fired when the set of children for an object change
%# console.debug('onChildrenChange', parent, children)
%# },
%# onChange: function(object){
%# // fired when the properties of an object change
%# console.debug('onChange', object);
%# }
});//Store
// creo la tree
var Obj_tree = new dijit.Tree({
model: Store,
'class': 'Files_tree',
autoExpand: false,
openOnClick: true,
persist: false, // disables use of cookies for state saving
showRoot: true, //false,
// define the drag-n-drop controller
dndController: dijit.tree.dndSource,
checkAcceptance: function(source, nodes){
%# console.debug('Files checkAcceptance', source, nodes);
this.nodes_to_move = nodes;
return nodes.length == 1;
},
checkItemAcceptance: function(source, nodes, position){
%# console.debug('Files checkItemAcceptance', position, source, nodes);
%# // verifico se la destinazione è compatibile
if(this != nodes || this.nodes_to_move.length > 1)return false;
var from = dijit.getEnclosingWidget(this.nodes_to_move[0]);
var to_dir = dijit.getEnclosingWidget(source);
if(!from || !to_dir)return false;
if(!to_dir.item.children){
to_dir = to_dir.getParent()
}
var from_dir = from.getParent();
return from_dir != to_dir;
}
}, Objname + '_tree'); // Il node del widget - esiste un elemento div esistente con quel nome definito includendo Files.comp
 
Store.tree = Obj_tree;
Obj.tree = Obj_tree;
Obj_tree.widget = Obj;
Obj_tree.getIconClass = function(item, opened){
return item.type == 'trash' ? 'masonSqlIcons delete' :
(this.model.mayHaveChildren(item) ? (opened ? 'dijitFolderOpened' : 'dijitFolderClosed') : 'dijitLeaf');
};
Obj_tree.close_popups = function(){
// chiudo e svuoto i pannelli aperti
dijit.popup.close(dijit.byId('Input_Files_tree_dialog'));
dijit.popup.close(dijit.byId('Input_Files_trash_dialog'));
% if($Session{Group_Admins}){
dijit.popup.close(dijit.byId('Input_Files_delete_dialog'));
% }
dijit.popup.close(dijit.byId('Input_Files_upload_dialog'));
Input_Files_history_dialog.hidePopup();
dijit.byId('Input_Files_files').reset();
%# console.debug('close_popups');
}
Obj_tree.onClick = function(){
this.close_popups();
%# console.debug('Click tree');
};
Obj_tree.onDblClick = function (item) {
this.close_popups();
if(!item.children){
this.download_item(item, 'download');
%# console.debug('download ...');
}
};
Obj_tree.onClose = Obj_tree.close_popups;
Obj_tree.onOpen = Obj_tree.close_popups;
%# // seleziona la riga della Tree in corrispondenza delle coordinate indicate
Obj_tree.selectedByCoord = function(coord, child){
var tree = this;
require(["dojo/_base/array", "dojo/dom-geometry"], function(array, domGeom){
array.forEach((child || tree).getChildren(), function(tree_node, i){
var pos = domGeom.position(tree_node.rowNode, true);
if(coord.x >= pos.x && coord.x <= pos.x + pos.w && coord.y >= pos.y && coord.y <= pos.y + pos.h){
tree.set('selectedItems', [tree_node.item]);
return;
}
if(tree_node.item.children){
%# // chiamo ricorsivamente la Tree
tree.selectedByCoord(coord, tree_node);
}
});
});
};
Obj_tree.open_history = function(new_ver){
var Obj = this.widget;
Input_Files_history_dialog.tree = this;
if(!new_ver){
%# // se è richiesto un cambio della versione corrente il popup è già aperto
dijit.popup.open({
popup: Input_Files_history_dialog,
around: this.selectedNode.contentNode
});
}
Input_Files_history_dialog.set('href','<% $r->dir_config('DataBaseUrl') %>/' + Obj.From + '.mql?' +
dojo.objectToQuery({
F: 'archive_history',
rec_id: Obj.value,
new_ver: new_ver,
obj_id: this.selectedNode.item.id,
edit: Obj.Readonly() ? '' : 1
})
);
},
Obj_tree.set_new_version = function(new_ver){
%# // cambia la versione corrente del file selezionato
this.open_history(new_ver);
},
Obj_tree.onClick = function(item, node, evt){
%# console.debug('Files onClick', item, node, evt);
},
Obj_tree.startup();
var menu = dijit.byId('Input_Files_tree_menu');
Obj_tree.menu = menu;
var menuChildren = menu.getChildren();
%# // riferimenti usati sotto (es. menu.Input_Files_rename )
menuChildren.forEach(function(child){
menu[child.id] = child;
});
// when we right-click anywhere on the tree, make sure we open the menu
menu.bindDomNode(Obj_tree.domNode);
dojo.connect(menu, '_openMyself', this, function(e) {
// get a hold of, and log out, the tree node that was the source of this open event
Input_Files_TreeNodeObj = dijit.getEnclosingWidget(e.target).tree;
Input_Files_TreeNodeObj.selectedByCoord(e.coords);
var selected = Input_Files_TreeNodeObj.selectedNode;
%# console.debug('Files_TreeNode menu', Input_Files_TreeNodeObj.selectedItem.id, selected);
var widget = Input_Files_TreeNodeObj.tree.widget;
if(!widget.get_value()){
dijit.popup.close(menu);
return false;
}
var isWr = !widget.readOnly;
var DEL;
if(widget.displayBinding){
var db = widget.displayBinding.dataBinding;
DEL = widget.Delete_if_update ? (db.canUpdate || db.canDelete) : db.canDelete;
}else{
DEL = true;
}
%# console.debug('dijit.getEnclosingWidget:', selected.item.id, Input_Files_TreeNodeObj);
menu.Input_Files_rename.set('style', {'display': (isWr && selected.indent > 0) ? '' : 'none'});
var isTrash = (0 == Input_Files_TreeNodeObj.selectedItem.id.search('/.<% $r->dir_config('Files_Trash_dir') %>'));
menu.Input_Files_trash.set('style', {'display': (!isTrash && isWr && DEL && selected.indent > 0) ? '' : 'none'});
% if($Session{Group_Admins}){
menu.Input_Files_delete.set('style', {'display': (isTrash && isWr && DEL && selected.indent > 0) ? '' : 'none'});
% }
menu.Input_Files_new_folder.set('style', {'display': (isWr && selected.item.children) ? '' : 'none'});
menu.Input_Files_download.set('style', {'display': selected.item.children ? 'none' : ''});
menu.Input_Files_zipDownload.set('style', {'display': selected.item.children ? '' : 'none'});
menu.Input_Files_tgzDownload.set('style', {'display': selected.item.children ? '' : 'none'});
menu.Input_Files_upload.set('style', {'display': isWr ? '' : 'none'});
menu.Input_Files_history.set('style', {'display': !selected.item.children ? '' : 'none'});
});
menu.open_dialog = function(){
var tree_dialog;
if(this.id == 'Input_Files_rename' || this.id == 'Input_Files_new_folder'){
tree_dialog = dijit.byId('Input_Files_tree_dialog');
// comando: rename / new_folder
tree_dialog.id_cmd = this.id;
// nome del file
dojo.byId('Input_Files_tree_dialog_name').value = this.id == 'Input_Files_rename' ? Input_Files_TreeNodeObj.selectedNode.item.name : '';
dojo.byId('Input_Files_tree_dialog_btn').innerHTML = this.id == 'Input_Files_rename' ? 'Rinomina' : 'Nuova cartella';
}else{
tree_dialog = dijit.byId(this.id + '_dialog');
}
dijit.popup.open({
popup: tree_dialog,
around: Input_Files_TreeNodeObj.selectedNode.contentNode
});
};
menu.close_tree_dialog = function(){
var tree_dialog = dijit.byId('Input_Files_tree_dialog');
var new_name = dojo.byId('Input_Files_tree_dialog_name').value
var item = Input_Files_TreeNodeObj.selectedNode.item;
// verifico che nel nome non ci siano alcuni caratteri speciali
var forbidden_chars = [];
['*', ':', '|', '<', '>', '?', '/', '\\', '"'].forEach(function (c){
if(new_name.indexOf(c) != -1){
forbidden_chars.push(c);
}
});
if(forbidden_chars.length){
if(forbidden_chars.length == 1){
alert('Il carattere (' + forbidden_chars[0] + ') non può essere utilizzato nel nome');
}else{
alert('I caratteri (' + forbidden_chars.join(', ') + ') non possono essere utilizzati nel nome');
}
return false;
}
if(tree_dialog.id_cmd == 'Input_Files_rename'){
%# console.debug('rename', Obj_tree.id, new_name, item);
item.name = new_name;
Input_Files_TreeNodeObj.tree.model.put(item).then(function(){
var id_dir = item.id.replace(/\/[^\/]*$/, '');
Input_Files_TreeNodeObj.tree.model.get(id_dir).then(function(dir){
// notifico il cambiamento
Input_Files_TreeNodeObj.tree.model.setChange(dir);
});
});
}else{
%# console.debug('new_folder', new_name, item);
var id_dir = Input_Files_TreeNodeObj.selectedNode.item.id;
Input_Files_TreeNodeObj.tree.model.add({ new_name:new_name, id:id_dir + '/' + new_name, children:1 }).then(function (){
// aggiorno la cartella nell'albero
Input_Files_TreeNodeObj.tree.model.get(id_dir).then(function(dir){
Input_Files_TreeNodeObj.tree.model.setChange(dir);
});
});
}
%#// console.debug('close_dialog', this);
dijit.popup.close(tree_dialog);
};
dojo.connect(dijit.byId('Input_Files_rename'), 'onClick', menu.open_dialog);
dojo.connect(dijit.byId('Input_Files_new_folder'), 'onClick', menu.open_dialog);
dojo.connect(dijit.byId('Input_Files_trash'), 'onClick', menu.open_dialog);
% if($Session{Group_Admins}){
dojo.connect(dijit.byId('Input_Files_delete'), 'onClick', menu.open_dialog);
% }
var upload_dialog = dijit.byId('Input_Files_upload_dialog');
dojo.connect(dojo.byId('Input_Files_upload'), 'onclick', function(){
var TreeObj = Input_Files_TreeNodeObj.tree;
var node = Input_Files_TreeNodeObj.selectedNode;
if(!node.item.children){
%# // è un file, seleziono la dir padre
node = node.getParent();
}
dojo.byId('Input_Files_upload_dir').value = TreeObj.widget.From + '/' + TreeObj.widget.value + node.item.id;
dijit.popup.open({
popup: upload_dialog,
around: Input_Files_TreeNodeObj.selectedNode.contentNode
});
});
dojo.connect(dijit.byId('Input_Files_history'), 'onClick', function(evt){
%#DEBUG// console.debug('Input_Files_history onclick', evt);
Input_Files_TreeNodeObj.open_history();
});
// eventi del caricamento dei file
var uploader = dijit.byId('Input_Files_uploader');
dojo.connect(uploader, 'onComplete', function(params){
%# console.debug('uploader onComplete', unescape(dojo.toJson(params)));
upload_dialog.domNode.style.cursor = 'default';
// valuto gli errori
require(["dojo/_base/array"], function(array){
var mess = '';
array.forEach(params, function(item, i){
if(item.error){
mess += (item.name ? 'File ' + item.name + ' - ' : '') + 'Errore: ' + item.error + '\n';
}else if(item.info){
mess += (item.name ? 'File ' + item.name + ': ' : '')+ item.info + '\n';
}
});
mess.length && my_alert(mess);
});
dijit.byId(Objname + '_tree').close_popups();
var node = Input_Files_TreeNodeObj.selectedNode;
if(!node.item.children){
%# // è un file, seleziono la dir padre
node = node.getParent();
}
Input_Files_TreeNodeObj.tree.model.get(node.item.id).then(function(dir){
Input_Files_TreeNodeObj.tree.model.setChange(dir);
});
});
dojo.connect(uploader, 'onError', function(mess, err){
upload_dialog.domNode.style.cursor = 'default';
console.debug('uploader onError', mess, err);
my_alert(mess + '\n' + err.message);
});
dojo.connect(uploader, 'onBegin', function(params){
// cursor durante il caricamento
upload_dialog.domNode.style.cursor = 'wait';
%# console.debug('uploader onBegin', unescape(dojo.toJson(params)));
});
// richiamato dalla combo e da dblclick della tree
Obj_tree.download_item = function (item, mode) {
var id_file = item ? item.id : Input_Files_TreeNodeObj.selectedNode.item.id;
var w = 800;
var h = 600;
var left = (screen.width - w) / 2;
var top = (screen.height - h) / 3;
var params = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable,alwaysRaised,dependent,titlebar=no,width='+w+',height='+h+',top='+top+',left='+left;
//var url = Input_Files_TreeNodeObj.tree.model.target + mode + '.' + escape(id_file);
var url = (item ? this.model.target : Input_Files_TreeNodeObj.tree.model.target) + id_file + '?' + mode;
%# console.debug('download item', id_file, url);
window.open(url, '_blank', params);
}
// richiamato alla conferma della cancellazione del file/dir
Obj_tree.delete_item = function (item) {
var id_file = item ? item.id : Input_Files_TreeNodeObj.selectedNode.item.id;
%# console.debug('delete item', id_file);
// cancello il file nello store remoto
var store = Input_Files_TreeNodeObj.tree.model;
store.remove(id_file).then(function(mess){
% if($Session{Group_Admins}){
// aggiorno il cestino
store.get('/.<% $r->dir_config('Files_Trash_dir') %>').then(function(dir){
store.setChange(dir)
});
% }
%# console.debug('file deleted', mess);
});
dijit.popup.close(dijit.byId('Input_Files_trash_dialog'));
% if($Session{Group_Admins}){
dijit.popup.close(dijit.byId('Input_Files_delete_dialog'));
% }
}
 
//modifico il metodo standard per provvedere alla chiusura nel menu quando cambia lo stato r/w del widget
Obj.InputReadonly = Input_Readonly;
Obj.Readonly = function (read){
read == null || this.tree.close_popups();
return this.InputReadonly(read);
};
Obj.readOnly = !Readonly; // costringo il componente a cambiare la configurazione
Obj.Readonly(Readonly);
Obj.setFocus = null;
});//dojo.ready
}//function Input_Files_Init
 
 
/tags/2.0/htdocs/input/url.js
0,0 → 1,76
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2009-2012 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
Input_Url_Display = null;
 
function Input_Url_displayURL(open_window){
if(this.popup && !open_window){
// mostra in una finestra separata la URL contenuta nel widget
var widget = this;
require(["dijit/Dialog"], function(Dialog){
if(!Input_Url_Display){
Input_Url_Display = new Dialog({
title: widget.Descr,
closable: true,
timeout: <% $r->dir_config('GetFormTimeout') %>,
content: ''
});
Input_Url_Display.containerNode.style.padding = '2px 2px';
}else{
Input_Url_Display.set('content', '');
}
var url = widget.base_url + widget.get_value();
if(!/^\w+:\/\//i.test(url)){
url = 'http://' + url.replace(/^\/+/, '');
}
Input_Url_Display.show();
Input_Url_Display.set('content', '<iframe src="' + url +
'" width="' + widget.window_width + '" height="' + widget.window_height +
'" seamless="seamless" frameborder="0" marginwidth="0" marginheight="0"></iframe>');
});
}else{
var url = this.base_url + this.get_value();
if(!/^\w+:\/\//i.test(url)){
url = 'http://' + url.replace(/^\/+/, '');
}
var w = this.window_width;
var h = this.window_height;
var left = (screen.width - w) / 2;
var top = (screen.height - h) / 3;
window.open(url, '_blank', 'width='+w+',height='+h+',top='+top+',left='+left+','+this.window_properties);
}
}
 
function Input_Url_Init(Objname, base_url, popup, window_width, window_height, window_properties){
var Obj = document.getElementById(Objname);
var button_url = document.getElementById(Objname + '_button_url');
button_url.widget = Obj;
Obj.button_url = button_url;
Obj.popup = popup;
Obj.displayURL = Input_Url_displayURL;
Obj.base_url = base_url;
Obj.window_width = window_width;
Obj.window_height = window_height;
Obj.window_properties = window_properties;
// controllo del campo al termine della modifica
Obj.local_test = function(){
this.button_url.style.display = this.value.length == 0 ? 'none' : '';
return '';
};
Obj.onkeypress = null;
Obj.set_value = function(value){
this.value = value;
this.button_url.style.display = this.value.length == 0 ? 'none' : '';
};
button_url.style.display = Obj.value.length == 0 ? 'none' : '';
return Obj;
}
 
/tags/2.0/htdocs/input/form.js
0,0 → 1,151
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
// Popup
var Input_Form_Popup;
 
function Input_Form_Init(Objname, Descr, Empty, EmptyDescr, from, Where, OrderBy, formParameters, ReadOnly, popupWidth, popupHeight, DispTemplate, Query_param){
var Obj = Input_Init(Objname, Descr);
Obj.icon = document.getElementById('icon_' + Objname);
Obj.Empty = Empty;
Obj.EmptyDescr = EmptyDescr;
Obj.from = from;
Obj.Source = '<%$r->dir_config('DataBaseUrl')%>/'+Obj.from+'.mql';
Obj.formParameters = formParameters;
Obj.Where = Where;
Obj.OrderBy = OrderBy;
Obj.popupWidth = popupWidth;
Obj.popupHeight = popupHeight;
Obj.DisplayDescr = document.getElementById('display_'+Objname);
Obj.DispTemplate = DispTemplate;
Obj.Query_param = Query_param;
Obj.setFocus = null;
 
Obj.onafterupdate = function(){
eval(this.onchange);
}
 
// metodo per la lettura del valore del componente
Obj.get_value = function () {
return this.value;
}
 
Obj.set_status = function(status){
var classList = this.eval_status(status);
// non applico la variazione della lista delle classi se non cambia
if(this.DisplayDescr.className != classList){
this.DisplayDescr.className = classList;
}
}
 
// metodo per il caricamento del valore del componente
Obj.set_value = function(value, param){
this.value = value;
// parametro dato nel formato "descrizione|parametri...\n.....\n...."
if(param != null){
this.set_param(param);
}else{
if(value != this.Empty){
// richiedo il valore al server
hReqMason_ExecuteTimeout(
this.Source,
<%$r->dir_config('GetRecordTimeout')%>,
Input_Form_TimeoutData,
Input_Form_Load_Callback,
'parameters_select',
['key', value],
null,
null,
this
);
}else{
this.set_param(null);
}
}
}
 
Obj.Readonly = function(set){
if(set == null){
return this.readOnly;
}else{
this.disabled = set;
this.style.cursor = set ? 'default' : 'pointer';
this.readOnly = set;
this.set_status();
var icon = this.icon;
require(["dojo/dom-class"], function(domClass){
if(icon){
domClass[set ? 'add' : 'remove'](icon, 'dijitDisabled');
}
});
return set;
}
};
 
Obj.Readonly(ReadOnly);
Obj.set_status('');
 
// apro una finestra con il form
// costruisco un oggetto 'display' minimale con i soli elementi necessari a lanciare il form (vedi file ../lib/displaybinding.js )
Obj.display = {
prefix: 'Input_Form_display',
Input: Obj,
dataBinding: new DataBinding('Input_Form_db', null, null),
gotoRecords: function(mode, key, recordset){
return this.dataBinding.gotoRecords(mode, key, recordset);
},
onclosedetail: function(update){
if(update){
// forzo l'aggiornamento del display nel widget (non passando i parametri essi vengono caricati dal server ...)
this.Input.set_value(this.Input.get_value(), null);
if(this.Input.onchange)this.Input.onchange();
}
},
openFormDetailByKey: DisplayBinding_openFormDetailByKey
};
 
Obj.formClick = function(){
if(this.Readonly()){
return false;
}
var value = this.get_value();
var default_params = {
father_id: value,
father_id_update: value,
grandfather_id: this.displayBinding ? this.displayBinding.dataBinding.father_id : '',
json_where: JSON.stringify([['--where-input', this.Where]])
};
// sovrascrivo con i valori forniti dalla chiamata
for(var name in this.formParameters){
default_params[name] = this.formParameters[name];
}
this.display.openFormDetailByKey('forward', value, this.from, this.popupWidth, this.popupHeight, Obj.Descr, default_params);
};
} // Input_Form_Init
 
// Handler risposta in caso di errore o timeout
function Input_Form_TimeoutData(contextID, type, str, Obj){
var contextObj = hReqMason_ContextPool[contextID];
if(type == 'TIMEOUT'){
my_alert('Timeout caricamento parametri ' + Obj.id);
}else{
my_alert('ERRORE caricamento parametri ' + Obj.id + ' url=' +contextObj.URL+': \n['+str+']');
}
}
 
// Handler risposta caricamento dinamico dei parametri
function Input_Form_Load_Callback(str, contextID, Obj){
str = str.replace(/^\s+|\s+$/g, '');
Obj.set_param(str);
if(Obj.onloadremoteparam){
Obj.onloadremoteparam();
}
}
/tags/2.0/htdocs/input/htmlselect.comp
0,0 → 1,101
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
Widget htmlselect
testo in sola lettura di descrizione e pulsante per richiamare la lista in finestra separata
</%doc>
<%args>
$id # identificatore del componente nel documento HTML
$description => '' # descrizione visualizzata nella barra
$value => undef # valore da attribuire <option selected> dopo il caricamento della lista (funziona solo se la lista è statica o caricata nel form)
$from # schema/nome documento ".mql" corrispondente ad una lista
$where => undef # clausola where da applicare
$empty => undef # lascia il primo campo della lista vuoto con "value" uguale al contenuto di $empty
$empty_descr => '' # descrizione da visualizzare per il campo 'empty'
$disp_template => undef # funzione eval per definire la descrizione (i parametri sono disponibili con P[n])
$edit => undef # link all'oggetto che permette la modifica della lista
$bgcolor => undef
$width => '80'
$length => 28 # numero di caratteri minimo da visualizzare
$icon => 'find' # icona da utilizzare
$cache_params => undef # se !undef attiva la cache sui parametri caricati
$popup_properties => undef
</%args>
% $width && ($width -= 19); # spazio del bottone
% $width < 0 && ($width = 0);
% $width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
<%method LIBRARY>\
/lib/httpRequestMason.js
/input/input.comp
/input/htmlselect.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
%# $PLogger->debug(sub{ "htmlselect.comp",Dumper(\%ARGS); });
<span class="container" base_class="inputspan" id="<%$id%>" <%&Args2HtmlTaglist(
style => 'background-color: transparent;',
onchange => undef,
onkeydown => 'return Input_keydown(event);',
onclick => "return Input_HtmlSelect_open_list('$id');",
type => undef,
widget => undef,
descr_sep => undef,
from => undef,
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);')%>>
<span id="display_<%$id%>" base_class="inputspan" unselectable <%&Args2HtmlTaglist(
onchange => undef,
onclick => undef,
type => undef,
widget => undef,
descr_sep => undef,
from => undef,
style => (defined $width ? "width:${width};" : '').(defined $bgcolor ? "background-color:$bgcolor;" : '')
)%>>&nbsp;</span>
% if($icon){
<span class="dijitInline dijitIcon masonSqlIcons <%$icon%> vAlign" id="icon_<%$id%>"></span>
% }
</span>
% push @Script_buffer, $m->scomp('.defer', %ARGS);
<%def .defer>
<%args>
$id
$value => undef
$description => ''
$from
$where => undef
$empty => undef
$empty_descr => ''
$disp_template => undef # funzione eval per definire la descrizione (i parametri sono disponibili con P[n])
$edit => undef
$id_descr => '' # identificatore campo descrizione associato del recordset da aggiornare
$readonly => undef
$cache_params => undef # se !undef attiva la cache sui parametri caricati
$popup_max_width => ''
$popup_max_height => '300px'
</%args>
<%perl>
if($from !~ m|/|){
my $pfrom = $Session{ARGS}{from};
if($pfrom){
$from = $pfrom =~ m|^(\w+)/| ? $1.'/'.$from : 'public/'.$from;
}
}
my $source = $r->dir_config('DataBaseUrl').'/'.$from.'.mql';
$empty = (defined $empty) ? "'$empty'" : 'null';
</%perl>
var Id_<%$id%>=Input_HtmlSelect_Init('<%$id%>', '<%$id_descr%>', '<%$source|js%>', '<%$where|js%>','<%$edit|js%>', <%$empty%>,
'<%$empty_descr|js%>', '<% $disp_template ? $disp_template : ''|js%>', '<%$description|js%>', <% $readonly ? 'true' : 'false'%>,
<%$cache_params ? 'true' : 'false'%>, '<%$popup_max_width|js%>', '<%$popup_max_height|js%>');
<% &ArgsOnly2JscriptTaglist("Id_$id", onchange => undef) %>
% if(defined $value){
Id_<%$id%>.set_value('<%$value|js%>');
% }
</%def>
/tags/2.0/htdocs/input/htmlselect.js
0,0 → 1,252
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
function Input_HtmlSelect_set_value(value, param){
if(value == null){
value = this.Empty;
}
this.value = value;
// parametro dato nel formato "descrizione|parametri...\n.....\n...."
if(param != null){
this.set_param(param, null, value);
}else{
if(value != this.Empty && this.Source){
// verifico la presenza nella cache
var cache_param = this.Cache_parameters && this.Cache_parameters[value];
if(cache_param == null){
// richiedo il valore al server
// hReqMason_ExecuteTimeout(rspage, timeout, timeout_callback, callback, func, parms, tag, obj_params, callback_obj)
hReqMason_ExecuteTimeout(
this.Source,
<%$r->dir_config('GetRecordTimeout')%>,
Input_HtmlSelect_TimeoutData,
Input_HtmlSelect_Load_Callback,
'parameters_select',
['key', value],
null,
null,
this
);
this.set_param(null, null, value);
}else{
this.set_param(cache_param);
}
}else{
this.set_param(null);
}
}
}
 
// Handler risposta in caso di errore o timeout
function Input_HtmlSelect_TimeoutData(contextID, type, str, Obj){
var contextObj = hReqMason_ContextPool[contextID];
if(type == 'TIMEOUT'){
Obj.set_value(Obj.value, '--- TIMEOUT rec('+Obj.value+') ---');
my_alert('Timeout caricamento parametri widget id:' + Obj.id);
}else{
Obj.set_value(Obj.value, '--- ERROR rec('+Obj.value+') ---');
my_alert('ERRORE caricamento parametri widget id:' + Obj.id + ' url=' + this.contextObj.URL+': \n['+str+']');
}
}
 
// Handler risposta caricamento dinamico dei parametri
function Input_HtmlSelect_Load_Callback(str, contextID, Obj){
var x = hReqMason_ContextPool[contextID];
//console.debug('Input_HtmlSelect_Load_Callback', Obj, str, contextID, x);
str = str.replace(/^\s+|\s+$/g, '');
if(str.length > 0){
Obj.set_value(Obj.value, str);
}
}
 
function Input_HtmlSelect_get_value(value){
return this.value;
}
 
 
function Input_HtmlSelect_Init(Objname, Id_Descr, Source, Where, Edit, Empty, EmptyDescr, DispTemplate, Descr, Read, Cache_param, Popup_max_width, Popup_max_height){
var Obj = Input_Init(Objname, Descr);
Obj.icon = document.getElementById('icon_' + Objname);
Obj.Source = Source; //Nome del file da caricare (senza .mql)
Obj.DisplayDescr = Input_Init('display_'+Objname, Descr);
if(Id_Descr == '')Id_Descr = null;
Obj.Id_Descr = Id_Descr;
Obj.set_status = function(status){
//console.log('set_status id:'+this.id+' status:'+status);
var classList = this.eval_status(status);
//console.log('set_status id:'+this.id+' classList:'+classList);
// non applico la variazione della lista delle classi se non cambia
if(this.DisplayDescr.className != classList){
//console.log('NEW id:'+this.id+' className:'+classList);
this.DisplayDescr.className = classList;
}
}
Obj.Readonly = function (set) {
if(set == null){
return this.readOnly;
}else{
this.disabled = set;
this.style.cursor = set ? 'default' : 'pointer';
this.readOnly = set;
this.set_status();
var icon = this.icon;
require(["dojo/dom-class"], function(domClass){
if(icon){
domClass[set ? 'add' : 'remove'](icon, 'dijitDisabled');
}
});
return set;
}
}
Obj.get_display = function(){
return Html2String(this.DisplayDescr.innerHTML);
}
Obj.DisplayDescr.get_display = function(){
return Html2String(this.innerHTML);
}
Obj.Where = Where;
Obj.Edit = Edit;
Obj.Empty = Empty;
Obj.EmptyDescr = EmptyDescr;
Obj.DispTemplate = DispTemplate;
Obj.Editing = false;
Obj.get_value = Input_HtmlSelect_get_value;
Obj.set_value = Input_HtmlSelect_set_value;
// Obj.EditingEnd = Input_HtmlSelect_EditingEnd;
Obj.ListEqualBuffer = null;
// Obj.LoadCallback = Input_HtmlSelect_LoadCallback;
// Obj.LoadRemote = Input_HtmlSelect_LoadRemote;
Obj.Previus = Obj.get_value();
Obj.Readonly(Read);
Obj.Parameters = null;
if(Obj.Cache_param){
Obj.Cache_parameters = {}; //cache dei parametri corrispondenti ai valori presenti nella lista
}
Obj.setFocus = null;
Obj.Popup_max_width = Popup_max_width;
Obj.Popup_max_height = Popup_max_height;
return Obj;
}
 
function Input_HtmlSelect_Timeout(contextID, err, str){
// var contextObj = hReqMason_ContextPool[contextID];
if(err == 'TIMEOUT'){
my_alert('Timeout ricezione dati ' + contextID, 'txt');
}else{
my_alert(err+': '+str, 'txt');
}
}
 
// utilizzata per salvare il riferimento alla finestra di selezione
// vedi: Input_HtmlSelect_open_list
var Input_HtmlSelect_Popup;
 
// Par è un array generato dal method dbms_library.comp?method=htmlselectpopup richiamato
// nella finestra Input_HtmlSelect_Popup e serve per salvare i parametri associati
// a ciascuna riga del componente
function Input_HtmlSelect_PopupHandler(div){
require(["dojo/dom-attr"], function(domAttr){
var Obj = Input_HtmlSelect_Popup.Input;
var id = domAttr.get(div, 'mql-id');
if(Obj.get_value() != id){
var str = div.innerHTML;
str = str.replace(/\&nbsp;/g, '');
Obj.set_value(id, str+'|'+domAttr.get(div, 'mql-parameters'));
Input_HtmlSelect_Popup.hidePopup();
window.setTimeout("document.getElementById('"+Obj.id+"').test_value()",1);
if(Obj.onchange){
Obj.onchange();
}
}else{
Input_HtmlSelect_Popup.hidePopup();
}
});
}
 
function htmlselect_PD(obj, color){
if(color){
obj.className += ' htmlselect_hover';
}else{
obj.className = obj.className.match(/^\w+/)[0];
}
return 1;
}
 
// apre la finestra per selezionare la lista
function Input_HtmlSelect_open_list(id){
require(["dojo/ready", "dijit/TooltipDialog", "dijit/popup", "dojo/dom"], function(ready, TooltipDialog, popup, dom){
ready(function(){
var Obj = document.getElementById(id);
if(!Obj.Readonly()){
if(!Input_HtmlSelect_Popup){
Input_HtmlSelect_Popup = new TooltipDialog({
id: 'Input_HtmlSelect_Popup',
onLoad: function(){
var Id = Input_HtmlSelect_Popup.Input.get_value(); // ID corrente
var Div = document.getElementById('htmlselect_Id' + Id);
if(Div){ // Se l'elemento è presente nella lista viene colorato diversamente
Div.className = 'htmlselect_selected';
Div.scrollIntoView(); // posiziono l'elemento visibile nella finestra
}
%# // toglie barra scorrimento se non necessaria (vedi <div class="htmlselect_Body" ... )
this.containerNode.firstChild.style.overflowY = 'auto';
// larghezza minima pari alla larghezza del widget
this.containerNode.firstChild.style.minWidth = Obj.DisplayDescr.scrollWidth + 'px';
this.focus();
},
onKeyUp: function(event){
if(event.keyCode == 27){
// chiudo la lista se uso tasto <Esc>
popup.close(this);
}
}
});
Input_HtmlSelect_Popup.hidePopup = function(){
popup.close(this);
};
Input_HtmlSelect_Popup.watch('focused', function(property_name, old_val, new_val){
if(!new_val){
Input_HtmlSelect_Popup.hidePopup();
}
});
}
var Popup = Input_HtmlSelect_Popup;
Popup.Input = Obj;
require(["dojo/io-query"], function(ioQuery){
var query = {
method: 'htmlselectpopup',
V: '<%$Ver%>',
max_width: Obj.Popup_max_width,
max_height: Obj.Popup_max_height,
select_key: Obj.value
};
if(Obj.Empty != null){
query.empty = Obj.Empty;
query.empty_descr = Obj.EmptyDescr;
}
if(Obj.Where){
query.json_where = JSON.stringify([['--where-input', Obj.Where]]);
}
if(Obj.displayBinding){
var db = Obj.displayBinding.dataBinding;
query.child_id = db.keys[Obj.dbRow];
query.father_id = db.father_id;
}
Popup.set('href', Obj.Source + '?' + ioQuery.objectToQuery(query));
popup.open({
popup: Popup,
around: dom.byId(id)
});
});
}
return false;
});
});
}
/tags/2.0/htdocs/input/input.js
0,0 → 1,581
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
require(["dijit/Tooltip"]);
%#DOJO1.8 dojo.require("dijit.Tooltip");
dijit.Tooltip.defaultPosition = ['above-centered', 'before-centered', 'after-centered', 'below-centered'];
function Input_EscapeHTML(str){
str = '' + str;
str = str.replace(/</g, '&lt;');
str = str.replace(/>/g, '&gt;');
str = str.replace(/\n/g, '<br>\n');
return str;
}
 
function Input_Init(Objname, Descr){
var Obj = document.getElementById(Objname);
%#// DOJO_1.8 BEGIN - per compatibilità con masonSql versioni ante 2013
window['Id_' + Objname] = Obj;
%#// DOJO_1.8 END
Obj.Descr = Descr;
Obj.TooltipShowDelay = <% $r->dir_config('TooltipDelay') %>;
Obj.setTooltip = function(Descr){
if(!this.TooltipObj){
this.TooltipObj = new dijit.Tooltip({
connectId: [this.id],
showDelay: this.TooltipShowDelay,
label: Descr
});
}else{
this.TooltipObj.label = Descr;
}
};
Obj.setTooltip(Descr);
if(Obj.readOnly || Obj.disabled){
Obj.style.cursor = 'default';
}
// ritorna il valore del widget
Obj.get_value = Input_get_value;
// ritorna il/i parametri del campo specificato
Obj.get_param = Input_get_param;
// funzione per definire il valore del widget
Obj.set_value = Input_set_value;
// funzione per definire il/i parametri
Obj.set_param = Input_set_param;
// valutazione stato del widget
Obj.eval_status = Input_eval_status;
// applico lo stile all'oggetto widget principale
Obj.widgetStatus = '';
// condizione del campo in stato di errore
Obj.widgetError = false;
// particolari widget possono sovrascrivere il metodo
Obj.set_status = function(status){
var classList = this.eval_status(status);
%#DEBUG <% $JSLogger->debug(q|'set_status obj '+Objname+' status:' + status + ' classList:' + classList + ' className:' + this.className|) %>
// non applico la variazione della lista delle classi se non cambia
if(this.className != classList){
this.className = classList;
}
}
Obj.set_display = function(){
// determina il valore da visualizzare del widget
if(this.DisplayDescr){
if(this.contextObj){
this.DisplayDescr.innerHTML = '...';
}else if(this.Parameters){
var P = this.Parameters;
P[-1] = this.get_value();
this.DisplayDescr.innerHTML = Input_EscapeHTML(((this.get_value() == this.Empty || this.Parameters.length == 0) ? this.EmptyDescr :
(this.DispTemplate != '' ? eval(this.DispTemplate) : (P[0] ? P[0] : '')).replace(/^ \| \$/,'')) + '&nbsp;');
}else if(this.get_value() == this.Empty){
this.DisplayDescr.innerHTML = Input_EscapeHTML(this.EmptyDescr + '&nbsp;');
}else{
this.DisplayDescr.innerHTML = Input_EscapeHTML(this.get_value() + '&nbsp;');
}
}
var tooltip_mess = (this.Descr != null ? this.Descr + ': ' : (this.name ? 'Campo ' + this.name +': ' : '')) + this.get_display();
if(this.DisplayDescr && this.DisplayDescr.setTooltip){
this.DisplayDescr.setTooltip(tooltip_mess);
}
this.setTooltip(tooltip_mess);
}
Obj.get_display = function(){
if(this.DisplayDescr){
return Html2String(this.DisplayDescr.innerHTML);
}else{
return this.get_value();
}
}
// metodi standard
Obj.Readonly = Input_Readonly;
Obj.test_value = Input_test_value;
if(Obj.getAttribute('remote_check')){
// definisco il metodo se lato server è definito il metodo di risposta
Obj.remote_test = Input_remote_test;
}
Obj.changeKeypress = Input_changeKeypress;
Obj.widgetKeydown = Input_widgetKeydown;
Obj.setFocus = Input_setFocus;
Obj.onfocus = function (){
%#// ritardo l'apertuta all'infinito (quasi)
if(this.TooltipObj){
this.TooltipObj.close();
this.TooltipObj.set('showDelay', 999999999);
}
if(this.Widget && this.Widget.TooltipObj){
this.Widget.TooltipObj.close();
this.Widget.TooltipObj.set('showDelay', 999999999);
}
this.Focus = true;
}
Obj.onblur = function (){
if(Obj.isChanged){
require(["dojo/on"], function(on){
on.emit(Obj, 'change', {
bubbles: true,
cancelable: true
});
});
}
this.Focus = null;
%#// ripristino il ritardo
if(this.TooltipObj){
this.TooltipObj.close();
this.TooltipObj.set('showDelay', this.TooltipShowDelay);
}
if(this.Widget && this.Widget.TooltipObj){
this.Widget.TooltipObj.close();
this.Widget.TooltipObj.set('showDelay', this.TooltipShowDelay);
}
}
return Obj;
}
 
function Input_changeKeypress(charcode){
// provvedo a cambiare il carattere digitato nell'ultimo evento keypress
// dall aversione 12 di FF in poi non funziona più
// Vedi:
// https://bugzilla.mozilla.org/show_bug.cgi?id=749185
// https://bugzilla.mozilla.org/show_bug.cgi?id=751801
// https://bugzilla.mozilla.org/show_bug.cgi?id=751810
var ev = this.currentEvent;
var target = ev.currentTarget;
if(target == this){
ev.stopPropagation();
ev.preventDefault();
var value = target.value;
var start = target.selectionStart;
var stop = target.selectionEnd;
target.value = value.substr(0, start) +
String.fromCharCode(charcode) +
value.substr(stop);
target.setSelectionRange(start+1, start+1);
target.isChanged = true;
}else{
my_alert(this.Descr+': chiamata di .changeKeypress senza un evento keypress pendente.', 'alert');
}
}
 
function Input_Readonly(read){
if(read == null){
return (this.Hidden || this.style.display == 'none' || (this.dispSpan && this.dispSpan.style.display == 'none') || this.readOnly);
}else{
this.readOnly = read;
if(this.type == 'text' || this.type == 'textarea'){
this.style.cursor = read ? 'default' : 'text';
}else{
this.style.cursor = read ? 'default' : 'pointer';
}
this.set_status && this.set_status();
return (this.Hidden || this.style.display == 'none' || read);
}
}
 
function Input_Event(ev){
if(ev == null){
console.error('Input_Event without event object');
my_alert('Input_Event without event object', 'alert');
}
ev.chCode = ev.charCode;
ev.currentTarget.currentEvent = ev;
ev.normalKey = !(ev.altKey || ev.ctrlKey || ev.metaKey);
return ev.currentTarget;
}
function Input_abortChange(input, e){
if(e){
e.stopPropagation();
e.preventDefault();
}
input.focus && input.focus();
input.select && input.select();
return false;
}
function Input_ErrorMessage(e, message){
var input = Input_Event(e);
my_alert(input.Descr+': '+message, 'alert');
return Input_abortChange(input, e);
}
 
function Input_ViewDescription(e){
}
 
function Input_DeleteDescription(){
}
 
// ritorna il valore del campo specificato
function Input_get_value(){
var value;
if(this.type == 'checkbox'){
value = this.checked ? 1 : '' ;
}else if(this.type == 'text' || this.type == 'textarea' ||
this.type == 'select' || this.type == 'select-multiple' ||
this.type == 'hidden'){
value = this.value;
}else{
value = this.innerHTML;
}
%#DEBUG my_alert('get_value id='+this.id+' type='+this.type+' value="'+value+'"');
return value;
}
// inizializza il valore del campo selezionato
function Input_set_value(value, param){
if(param != null){
this.set_param(param);
}
if(value == null){
value = '';
}
if(this.type=='checkbox'){
this.checked = (value != '' && value != '0')
}else if(this.type=='text' || this.type=='textarea' ||
this.type=='select' || this.type=='select-one' ||
this.type=='select-multiple' ||
this.type == 'hidden'){
this.value = value;
}else{
this.innerHTML = Input_EscapeHTML(value);
}
if(this.set_display){
this.set_display();
}
}
// ritorna il/i parametri del campo specificato
function Input_get_param(pos){
var param = this.Parameters;
%#DEBUG my_alert('get_param id='+this.id+' type='+this.type+' param="'+param+'"');
if(pos != null){
if(param){
return param[pos];
}else{
return null;
}
}else{
return param;
}
}
 
function Input_set_param(param, pos, key){
if(pos == null){
this.Parameters = typeof(param) == 'object' ? param : (param ? param.split('|') : null);
}else{
this.Parameters[pos] = param;
}
if(key && this.Cache_parameters){
this.Cache_parameters[key] = this.Parameters;
}
if(this.DisplayDescr){
this.set_display();
}
if(this.onloadparam){
this.onloadparam();
}
}
 
// verifica la validità del dato contenuto nel campo
// se async == false ( o null) provvede a visualizzare il messaggio
// di errore e quindi controllare il termine del controllo remoto
function Input_test_value(async){
// verifica test locale
var str_err = this.local_test == null ? '' : this.local_test();
if(str_err){
this.widgetError = 'Error';
this.set_status();
if(!async){
my_alert(this.Descr + ': ' + str_err + '\n', 'alert');
}
return str_err;
}
// verifica del test remoto
// il metodo .remote_test, se presente ritorna:
// false se il controllo sul campo è in esecuzione
// '' se il controllo è andato a buon fine
// 'messaggio di errore' se il controllo è negativo, con la stringa che descrive il problema riscontrato
//
var str_err = (this.remote_test == null) ? '' : this.remote_test();
if(!async){
if(typeof(str_err) == 'boolean' && !str_err){
this.widgetError = 'Wait';
this.set_status();
window.setTimeout("Input_test_value_Handler('" + this.id + "')", 100);
}else if (typeof(str_err) == 'string' && str_err){
this.widgetError = 'Error';
this.set_status();
my_alert(this.Descr + ': ' + str_err + '\n', 'auto');
return str_err;
}
}
if(!str_err){
this.widgetError = false;
}
this.set_status();
return str_err;
}
// chiamata periodicamente da Input_test_value() o da se stessa
// per verificare se un test remoto si è completato;
// provvede a visualizzare l'eventuale messaggio di errore
function Input_test_value_Handler(id){
var input = document.getElementById(id);
var str_err = input.remote_test();
if(str_err == null){
// da ignorare
return;
}
if(typeof(str_err) == 'boolean' && !str_err){
// test ancora in corso; ricontrollo tra un po' ...
window.setTimeout("Input_test_value_Handler('" + input.id + "')", 100);
}else{
if(str_err){
my_alert(input.Descr + ': ' + str_err + '\n', 'alert');
input.focus && input.focus();
input.select && input.select();
}
}
}
 
// controllo del campo al termine della modifica
// e: evento passato alla chiamata di onchange
// obj: oggetto widget (opzionale), usato se si chiama .onchange manualmente .onchange(null, this)
function Input_change(e, obj){
Input_DeleteDescription();
var input = obj ? obj : Input_Event(e);
input.isChanged = false;
if(input.test_value()){
return Input_abortChange(input, e);
}
input.set_display();
return true;
}
 
function Input_remote_test(abort){
if(abort){
this.remote_test_result = null;
// l'eventuale download in corso viene abortito
var contextObj = hReqMason_ContextPool[this.hReqMason_Check];
if(contextObj && contextObj.busy){
// annullo la chiamata in corso
contextObj.abort();
}
return null;
}
// verifico se c'è da ritornare il risultato di una precedente chiamata
// che ha iniziato il test
if(this.remote_test_result != null){
if(typeof(this.remote_test_result) != 'boolean'){
// test concluso; passo il risultato
var R = this.remote_test_result;
// e alla prossima richiesta verrà rifatto il test
this.remote_test_result = null;
return R;
}else{
// test ancora in esecuzione
return this.remote_test_result;
}
}
// lancio la verifica sul server
var disp = this.displayBinding;
var db = disp.dataBinding;
this.remote_test_result = false; // test in progress ...
var Values = [];
// valori attuali nel form da inviare al server per il check
Form2Vect(disp.fields[this.dbRow], Values);
var params = {
KEY: db.keys[this.dbRow],
ID_FIELD: this.id,
FIELD: db.names[this.dbCol],
COL: this.dbCol,
ROW: this.dbRow,
VALUE: this.get_value(),
PARAM: this.get_param(),
RECORDSET: db.prefix,
FATHER_ID: db.father_id,
VALUES: Values
};
this.hReqMason_Check = hReqMason_ExecuteTimeout(
'<%$r->dir_config('DataBaseUrl')%>/'+db.from+'.mql',
5000,
Input_check_errorHandler,
Input_check_Handler,
'field_check',
params,
null,
null,
this
);
// ... per avvisare che il test è in esecuzione
return this.remote_test_result;
}
// richiamata da hReqMason quando si presenta un errore
function Input_check_errorHandler(contextID, err, str, Obj){
Obj.remote_test_result = (err != 'TIMEOUT') ? err + ': ' + str :
'Timeout ricezione verifica del campo ' + Obj.Descr + '\n il server potrebbe non essere raggiungibile.';
}
 
function Input_check_Handler(str, contextID, Obj){
// sostituisco i \n in quanto l'espressione regolare per ricercare <scr*pt>...</scr*pt> non funziona se ci
// sono in mezzo dei \n
var str = str.replace(/\n/g, '&#13;');
// verifico se la stringa contiene una sezione di codice script
var re = /(.*)\s*<scri{1}pt>(.*)<\/scri{1}pt>\s*(.*)/i;
if(re.test(str)){
str = RegExp.$1 + (RegExp.$3 ? '&#13;' + RegExp.$3 : '');
var code = RegExp.$2;
code = code.replace(/&#13;/g, '\n');
try{
eval(code);
}catch(err){
my_alert_error('CHECK(' + Obj.name + ')', err, code);
}
}
// rimetto come prima i \n
var str = str.replace(/&#13;/g, '\n');
// tolgo spazi e \n all'inizio ed alla fine
str = str.replace(/^\s+|\s+$/, '');
Obj.remote_test_result = str;
}
 
// test implementazione metodo .status
function Input_eval_status(status, check_focus){
// se status è null mi limito ad aggiornare gli style
if(status != null){
this.widgetStatus = status;
}
var RoRw = this.Readonly() ? 'Ro' : 'Rw';
// classe differenziata per Focus
var classFocus = check_focus && this.Focus ? 'Focus' : '';
// suffisso che determina quale style utilizzare in base allo stato
var displayStatus = this.widgetError ? this.widgetError : this.widgetStatus;
// classe di base
var classes = ['widget'];
// classe differenziata di base per stato attivo
classes.push('widget' + RoRw + displayStatus + classFocus);
// classe differenziata per classe di widget o singolo widget
var base_class = this.getAttribute('base_class');
if(base_class){
classes.push(base_class);
classes.push(base_class + RoRw + displayStatus + classFocus);
var widget_class = this.getAttribute('widget_class');
if(widget_class){
classes.push(widget_class);
}
}
%#DEBUG <% $JSLogger->debug(q|'eval_status obj '+this.id+' status:' + status + ' check_focus:' + check_focus + ' classList:' + classList|) %>
return classes.join(' ');
}
 
// chiamata dall'evento keydown
// valutati i tasti di movimento del form per la navigazione
// il parametro widget viene passato alla chiamata quando viene reiterato l'evento su un widget in sola lettura o disabilitato (vedi avanti nella funzione stessa)
// se wdest è definito viene utilizzato come widget di destinazione
function Input_keydown(event){
var input = Input_Event(event);
// eventuale sotto-widget
var widget = input.Widget ? input.Widget : input;
if(widget.displayBinding){
// il widget appartiene ad un form gestito da displaybinding
if((widget.Readonly && widget.Readonly()) || (!widget.Readonly && (widget.disabled || widget.readOnly))){
// solo se il widget è in modifica gestisco i caratteri di navigazione
return false;
}
return widget.widgetKeydown(event, input);
}else{
return true;
}
}
 
// verifica nel caso di left/right arrow se sono all'inizio o alla fine del campo selezionato
// ritorna vero se posso fare il salto
function Input_checkCaretLimit(widget, event){
if(widget.type == 'text' || widget.type == 'textarea'){
if(event.keyCode == 37){ // Left arrow
// salto solo se sono con il caret all'inizio
return (widget.selectionStart == 0);
}else if(event.keyCode == 39){ // Right arrow
// salto solo se sono con il caret alla fine
return (widget.selectionStart == widget.value.length);
}
}
return true;
}
 
// event: evento che ha iniziato il processo di valutazione del widget di destinazione del focus
// this: widget corrente da abbandonare
// display: campo del widget da abbandonare sul quale operare le variazione dell'aspetto
// wdest: widget di destinazione
function Input_widgetKeydown(event, display, wdest){
var ro = (this.Readonly && this.Readonly()) || (!this.Readonly && (this.disabled || this.readOnly));
// individua il widget a cui assegnare il focus
if(!wdest){
wdest = DisplayBinding_getWidget(this, event);
if(!wdest){
return true;
}
}
if(!display){
display = this;
}
%#DEBUG <% $JSLogger->debug(q|'Input_widgetKeydown keyCode:' + event.keyCode + ' shiftKey:' + event.shiftKey + ' from id:' + display.id + ' eval to:' + wdest.id|) %>
if(!ro && !Input_checkCaretLimit(display, event)){
return true;
}
if(!ro){
if(display.type == 'text' || display.type == 'textarea'){
display.setSelectionRange(0, 0);
}
event.stopPropagation();
event.preventDefault();
display.blur();
}
this.Focus = null;
if(wdest.setFocus){
// se il metodo è definito posso selezionare il widget individuato
if(!wdest.setFocus(event)){
// se in focus del widget non è possibile, salto al widget successivo
wdest.widgetKeydown(event);
}
}else{
// salto il widget disabilitato o in sola lettura
wdest.widgetKeydown(event);
}
return false;
}
 
// focus sul widget e selezione del testo presente
function Input_setFocus(event){
%#DEBUG <% $JSLogger->debug(q|'Input_setFocus keyCode:' + event.keyCode + ' shiftKey:' + event.shiftKey|) %>
if( (this.Readonly && this.Readonly()) ||
( this.disabled || this.readOnly || this.getAttribute('tabindex') == -1 ||
this.style.display == 'none' || this.style.visibility == 'hidden' )
){
return null;
}
this.Focus = true;
if(this.DisplayDescr){
this.DisplayDescr.focus();
}else{
// chiamo l'evento blur e ritardo l'esecuzione per il BUG http://groups.google.com/group/mozilla.dev.tech.dom/browse_thread/thread/1d36842726345123
this.blur();
window.setTimeout(function(widget){
widget.focus();
if(widget.type == 'text' || widget.type == 'textarea'){
// selezione del contenuto
widget.setSelectionRange(0, widget.value.length);
}
}, 1, this);
return this;
}
}
/tags/2.0/htdocs/input/select.comp
0,0 → 1,177
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
Widget select
select standard HTML
</%doc>
<%once>
$Global{SelectBufferFlag}=();
</%once>
<%method LIBRARY>\
/lib/httpRequestMason.js
/input/input.comp
/input/select.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
%########################################################################### MAIN
%# $PLogger->debug(sub{ "select.comp", Dumper(\%ARGS); });
<%args>
$id # identificatore del componente nel documento HTML
$description => '' # descrizione visualizzata nella barra
$value => undef # valore da attribuire <option selected> dopo il caricamento della lista (funziona solo se la lista è statica o caricata nel form)
$from => undef # schema/nome documento ".mql" corrispondente ad una lista
$where => undef # clausola where da applicare
$empty => undef # lascia il primo campo della lista vuoto con "value" uguale al contenuto di $empty
$empty_descr => '' # descrizione da visualizzare per il campo 'empty'
$remote => undef # caricamento della lista differito; dal server al client
$buffer_elements => undef # se attivo viene mantenuta una cache dei dati provenienti dal server in base ai diversi valori di Where utilizzati
$clone => undef # identificatore di lista dalla quale copiare la lista
$buffer => undef # codice identificatore di un "buffer" in comune tra più "select.comp" di uguale lista (stesso $from)
# più oggetti select.comp che fanno riferimento allo stesso "buffer" avranno la lista in comune (risparmi di spazio e tempo di download)
$rows => 1 # mumero di righe nella select; se >1 viene attivata l'opzione MULTIPLE
$edit => undef # link all'oggetto che permette la modifica della lista
$editmessage => '***MODIFICA***' # messaggio che verrà visualizzato in fondo alla lista per richiamare con (click)
$editwindowparam => '' # parametri da passare alla chiamata window.open() nel browser
$sep => ';' # separatore di lista per le selezioni multiple
@list => () # lista degli elementi
$id_descr => '' # identificatore campo descrizione associato del recordset da aggiornare
$readonly => undef
$bgcolor => undef
$width => undef
</%args>
<%perl>
if($from && $from !~ m|/|){
my $pfrom = $Session{ARGS}{from};
if($pfrom){
$from = $pfrom =~ m|^(\w+)/| ? $1.'/'.$from : 'public/'.$from;
}
}
my $source = $from ? $r->dir_config('DataBaseUrl').'/'.$from.'.mql' : undef;
$width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
</%perl>
<select base_class="select" id="<%$id%>" SIZE=<% $rows>1 ? qq("$rows" MULTIPLE) : '"1"' %> <%&Args2HtmlTaglist(
onchange => 'if(this.readOnly){return this.set_curret_value()}; Input_Select_ChangeList(event);',
onkeydown => 'return Input_keydown(event);',
onclick => 'if(!Input_Select_onclick(event)){return false}',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
style => (defined $width ? "width:${width};" : '').(defined $bgcolor ? "background-color:$bgcolor;" : '')
)%>>
% if($edit && !$remote){
<option value="<%$editmessage%>"><%$editmessage%></option>
% }
% if(defined $empty && !$remote){
<option selected value="<%$empty%>" ><%$empty_descr%></option>
% }
% if($m->content){
<%$m->content%>
% }elsif(@list){
% for(my $r=0; $r<@list; $r=$r+2){
<option value="<%$list[$r]%>" ><%$list[$r+1]%></option>
% }
% }elsif($remote){
<option selected value="<%$empty%>" >*** In caricamento ***</option>
% }elsif(defined $source && !defined $buffer){
% # ricavo la lista direttamente dal server
% $m->comp($source.':selectoptions', json_where => to_json [['--where-input', $where]]);
% }
</select>
% push @Script_buffer, $m->scomp('.defer', @_, source => $source);
<%def .defer>
<%args>
$id # identificatore del componente nel documento HTML
$description => '' # descrizione visualizzata nella barra
$value => undef # valore da attribuire <option selected> dopo il caricamento della lista (funziona solo se la lista è statica o caricata nel form)
$source => undef # documento ".mql" corrispondente ad una lista
$where => undef # clausola where da applicare
$empty => undef # lascia il primo campo della lista vuoto con "value" uguale al contenuto di $empty
$empty_descr => '' # descrizione da visualizzare per il campo 'empty'
$remote => undef # caricamento della lista differito; dal server al client
$buffer_elements => undef # se attivo viene mantenuta una cache dei dati provenienti dal server in base ai diversi valori di Where utilizzati
$clone => undef # identificatore di lista dalla quale copiare la lista
$buffer => undef # codice identificatore di un "buffer" in comune tra più "select.comp" di uguale lista (stessa $source)
# più oggetti select.comp che fanno riferimento allo stesso "buffer" avranno la lista in comune (risparmi di spazio e tempo di download)
$rows => 1 # mumero di righe nella select; se >1 viene attivata l'opzione MULTIPLE
$edit => undef # link all'oggetto che permette la modifica della lista
$editmessage => '***MODIFICA***' # messaggio che verrà visualizzato in fondo alla lista per richiamare con (click)
$editwindowparam => '' # parametri da passare alla chiamata window.open() nel browser
$sep => ';' # separatore di lista per le selezioni multiple
@list => () # lista degli elementi
$id_descr => '' # identificatore campo descrizione associato del recordset da aggiornare
$readonly => undef
$bgcolor => undef
$width => '80'
</%args>
<%perl>
$width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
if(defined $buffer && defined $source && !$remote && ! defined $Global{SelectBufferFlag}->{$buffer}){
# in-line buffer; carico la lista direttamente nel codice
$m->comp($source.':bufferselect', C => $buffer, json_where => to_json [['--where-input', $where]]);
}
$empty = defined $empty ? "'$empty'" : 'null';
</%perl>
var Id_<%$id%>=Input_Select_Init('<%$id%>', '<%$id_descr%>','<%$source|js%>', <% $remote ? 'true' : 'false'%>, '<%$where|js%>','<%$edit|js%>', <%$empty%>, '<%$empty_descr|js%>',
'<%$editmessage|js%>', '<%$editwindowparam|js%>', '<%$sep|js%>', '<%$description|js%>', <% $readonly ? 'true' : 'false'%>, <%$buffer_elements ? 'true' : 'false'%>);
% if(defined $clone){
% #codice per copiare la lista da altra lista
var S = document.getElementById('<%$clone%>');
var D = document.getElementById('<%$id%>');
var I;
for(I=0; I<S.options.length; I++){
var SourceOption = S.options.item(I);
var Option = document.createElement("OPTION");
Option.innerHTML = SourceOption.text;
Option.value = SourceOption.value;
D.appendChild(Option);
}
% }elsif(defined $buffer && defined $source && !$remote){
% # inserisco il componente nella lista dei componenti di stesso buffer
% if(!defined $Global{SelectBufferFlag}->{$buffer}){
var SelectBuf_<%$buffer%> = new Array();
% $Global{SelectBufferFlag}->{$buffer}=1;
% }
Id_<%$id%>.ListEqualBuffer=SelectBuf_<%$buffer%>;
SelectBuf_<%$buffer%>.push(Id_<%$id%>);
Id_<%$id%>.LoadCallbackID = function (strlist){
%#// necessario in quanto la libreria "httpRequestMason" non chiama un metodo ma una funzione e quindi manca il riferimento all'oggetto :-(
document.getElementById('<%$id%>').LoadCallback(strlist);
}
% # carico la lista richiamando la funzione che popola la select (una funzione per tutte le select di uguale "buffer")
_PopulateSelect_<%$buffer%>(Id_<%$id%>);
% }elsif($source && $remote){
% if(! defined $buffer){
% $buffer='Buf_'.$id;
% }
% if(!defined $Global{SelectBufferFlag}->{$buffer}){
% # primo componente "select.comp"; dichiarato (fa da master agli altri)
% # predispongo la funzione che si occupa di caricare la lista dopo il caricamento dal server
var SelectBuf_<%$buffer%> = new Array();
% $Global{SelectBufferFlag}->{$buffer}=1;
Id_<%$id%>.ListEqualBuffer=SelectBuf_<%$buffer%>;
SelectBuf_<%$buffer%>.push(Id_<%$id%>);
Id_<%$id%>.LoadCallbackID = function (strlist){
%#// necessario in quanto la libreria "httpRequestMason" non chiama un metodo ma una funzione e quindi manca il riferimento all'oggetto :-(
document.getElementById('<%$id%>').LoadCallback(strlist);
}
% # chiamata al server remoto per il caricamento della lista
Id_<%$id%>.LoadRemote();
% }else{
% # componente "select.comp" successivo al primo; non carica la lista ma clona i dati dalla "select" master
SelectBuf_<%$buffer%>.push(Id_<%$id%>);
Id_<%$id%>.ListEqualBuffer=SelectBuf_<%$buffer%>;
% }
% }
% if(defined $value){
Id_<%$id%>.set_value('<%$value|js%>');
% }elsif($edit){
Id_<%$id%>.set_value('<%$editmessage|js%>');
% }
</%def>
/tags/2.0/htdocs/input/select.js
0,0 → 1,400
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
// estrae dalla select una lista degli elementi selezionati; utilizza il separatore this.Sel
function Input_Select_get_value(){
if(this.multiple){
var elenco = new Array();
// individuo l'elenco dei campi selezionati
for(var i=0; i<this.options.length; i++){
var elem=this.options[i];
var value= elem.getAttribute('value');
if(elem.selected && value != this.changeMess && elem.text != this.changeMess){
elenco.push(value);
}else{
this.Editing = false;
elem.selected = false;
}
}
this.valueSelect = elenco.join(this.Sep);
return this.valueSelect;
}else{
return this.valueSelect;
}
}
 
// usato per i riempire il tooltip del widget
// determina una descrizione del contenuto del widget
function Input_Select_get_display(){
if(this.multiple){
var elenco = new Array();
// individuo l'elenco dei campi selezionati
for(var i=0; i<this.options.length; i++){
var elem=this.options[i];
var value= elem.getAttribute('value');
if(elem.selected && value != this.changeMess && elem.text != this.changeMess){
elenco.push(elem.text);
}else{
this.Editing = false;
elem.selected = false;
}
}
return elenco.join(this.Sep);
}else{
if(this.selectedIndex == -1){
return this.EmptyDescr;
}else{
return this.options[this.selectedIndex].text;
}
}
}
 
// Handler risposta in caso di errore o timeout
function Input_Select_TimeoutData(contextID, type, str, Obj){
if(type == 'TIMEOUT'){
Obj.options[Obj.selectedIndex].innerHTML = '--- TIMEOUT rec('+Obj.value+') ---';
my_alert('Timeout caricamento parametri ' + Obj.id);
}else{
Obj.options[Obj.selectedIndex].innerHTML = '--- ERROR rec('+Obj.value+') ---';
my_alert('ERRORE caricamento parametri ' + Obj.id + ' url=' +this.contextObj.URL+': \n['+str+']');
}
}
 
// Handler risposta caricamento dinamico dei parametri
function Input_Select_Load_Callback(str, contextID, Obj){
str = str.replace(/^\s+|\s+$/g, '');
if(str.length > 0){
Obj.set_param(str, null, Obj.get_value());
// descrizione selezionata nel widget
Obj.options[Obj.selectedIndex].innerHTML = str;
}
}
 
// seleziona nella select gli elementi nella lista "value"; utilizza il separatore this.Sel
function Input_Select_set_value(value, param){
if(value == null){
value = this.Empty;
}
if(param != null){
this.set_param(param, null, value);
}else if(this.Remote && !this.multiple){
if(value == this.Empty){
this.set_param(null, null, value);
}else{
// verifico la presenza nella cache
var cache_param = this.Cache_parameters[value];
if(cache_param == null){
// richiedo il valore al server
// hReqMason_ExecuteTimeout(rspage, timeout, timeout_callback, callback, func, parms, tag, obj_params, callback_obj)
hReqMason_ExecuteTimeout(
this.Source,
<%$r->dir_config('GetRecordTimeout')%>,
Input_Select_TimeoutData,
Input_Select_Load_Callback,
'parameters_select',
['key', value],
null,
null,
this
);
this.set_param(null, null, value);
}else{
this.set_param(cache_param);
}
}
}
var Sep=this.Sep;
this.valueSelect=value;
if(this.multiple){
value = Sep+value+Sep;
// per attivare la lista ricerco nella stringa la chiave con il carattere o stringa di separazione ai lati
for(var i=0; i<this.options.length; i++){
var elem=this.options[i];
elem.selected=(value.indexOf(Sep+elem.value+Sep) >= 0);
}
}else{
this.value = value;
if(this.value != value){
// la selezione non era disponibile nel widget
// aggiungo nella lista l'elemento mancante con descrizione
// il primo parametro disponibile o con una scritta che riposta il codice
var descr = this.get_param(0);
if(!descr){
descr = this.contextObj ? '...' : 'Elemento mancante ' + value;
}
var O=document.createElement("OPTION");
O.innerHTML=descr;
O.value=value;
this.selected = true;
this.appendChild(O);
this.value = value;
}
}
if(this.set_display){
this.set_display();
}
}
 
function Input_Select_EditingEnd(){
if(this.Edit){
if(this.Editing){
this.Editing=false;
var elem = this.options[0];
if(elem.selected && elem.value == this.changeMess && elem.text == this.changeMess){
elem.selected=false;
}
return true;
}
return false;
}else{
return null;
}
}
 
function Input_Select_LoadCallback(strlist, noBuffer){
// salvo il valore attuale del componente
var OldVal = this.get_value();
while(this.childNodes.length){
this.removeChild(this.lastChild);
}
if(this.Edit){
var O=document.createElement("OPTION");
O.innerHTML=this.changeMess;
O.value=this.changeMess;
this.appendChild(O);
}
if(this.Empty != null){
var O=document.createElement("OPTION");
O.innerHTML=this.EmptyDescr;
O.value=this.Empty;
this.selected=true;
this.appendChild(O);
}
 
// non escludo in bufferin nella chiamata e se e' attivo il buffering dei dati provenienti dal server
if(!noBuffer && this.buffer_elements){
this.buffer_elements[this.Where] = strlist;
}
// Sel è la variabile utilizzata nella funzione passata dal server per puntare al componente select da inizializzare
var Sel = this;
try{
eval(strlist)
}catch(err){
my_alert("ERROR function Input_Select_"+this.id+"_LoadCallback ("+(err.number&0xFFFF)+':'+err.message+") source "+this.Source+" on exec code:\n"+strlist, 'txt');
}
this.style.cursor='auto';
// se il valore del componente è presente nelle nuove opzioni lo rispristino, altrimenti no
var Val = null;
for(C=this.childNodes.length-1; C>0; C--){
if(this.childNodes[C].value == OldVal){
Val = OldVal;
break;
}
}
// ripristino il valore dopo l'aggiornamento della lista
this.set_value(Val);
// clono le option in tutte le altre "select" con stesso buffer
for(var C=0; C<this.ListEqualBuffer.length; C++){
var Child = this.ListEqualBuffer[C];
if(Child == this){
// salto la select da clonare
continue;
}
// salvo il valore attuale del componente
OldVal = Child.get_value();
// cancello le option presenti
while(Child.childNodes.length){
Child.removeChild(Child.lastChild);
}
// ricopio le option dalla select master
for(I=0; I<this.options.length; I++){
var SourceOption = this.options.item(I);
var Option = document.createElement("OPTION");
Option.innerHTML=SourceOption.innerHTML;
Option.value=SourceOption.value;
Child.appendChild(Option);
}
// se il valore del componente è presente nelle nuove opzioni lo rispristino, altrimenti no
var Val = null;
for(C=Child.childNodes.length-1; C>0; C--){
if(Child.childNodes[C].value == OldVal){
Val = OldVal;
break;
}
}
// ripristino il valore dopo l'aggiornamento della lista
Child.set_value(Val);
Child.style.cursor='auto';
}
if(this.FuncCallback){
this.FuncCallback();
}
}
 
// chiama il server per scaricare la lista
// func_callback: funzione da richiamare dopo aver completato il caricamento
// where: filtro di selezione della lista
function Input_Select_LoadRemote(func_callback, where){
this.Remote = true;
if(where == null || where != this.Where){
if(where != null){
this.Where = where;
}
if(this.ListEqualBuffer){
for(var C=0; C<this.ListEqualBuffer.length; C++){
this.ListEqualBuffer[C].style.cursor='wait';
}
}else{
this.style.cursor='wait';
}
this.FuncCallback = func_callback;
if(this.buffer_elements && this.buffer_elements[this.Where] != null){
this.LoadCallback(this.buffer_elements[this.Where], true);
}else{
// hReqMason_ExecuteTimeout(rspage, timeout, timeout_callback, callback, func, parms, tag, obj_params, callback_obj)
hReqMason_ExecuteTimeout(
this.Source,
10000,
Input_Select_Timeout,
this.LoadCallbackID,
'select',
['json_where', JSON.stringify([['--where-input', this.Where]])],
document
);
}
}
}
 
function Input_Select_EmptyList(){
this.Where = '--\n';
this.set_value('');
this.LoadCallback('');
}
 
function Input_Select_Init(Objname, Id_Descr, Source, Remote, Where, Edit, Empty, EmptyDescr, changeMess, EditWindowParam, Sep, Descr, Read, Buffer_elements){
var Obj = Input_Init(Objname, Descr);
Obj.Source = Source; //Nome del file da caricare (senza .mql)
Obj.Remote = Remote;
Obj.Where = Where;
Obj.Edit = Edit;
Obj.Empty = Empty;
Obj.EmptyDescr = EmptyDescr;
if(Buffer_elements){
Obj.buffer_elements = {};
}
Obj.Editing = false;
Obj.EditWindowParam = EditWindowParam;
Obj.changeMess = changeMess;
Obj.Sep = Sep;
Obj.get_value = Input_Select_get_value;
Obj.set_value = Input_Select_set_value;
Obj.get_display = Input_Select_get_display;
Obj.EditingEnd = Input_Select_EditingEnd;
Obj.ListEqualBuffer = null;
Obj.Cache_parameters = {}; //cache dei parametri corrispondenti ai valori presenti nella lista
Obj.LoadCallback = Input_Select_LoadCallback;
Obj.LoadRemote = Input_Select_LoadRemote;
Obj.EmptyList = Input_Select_EmptyList;
Obj.Readonly = Input_Select_Readonly;
Obj.valueSelect = null;
Obj.Readonly(Read);
Obj.set_curret_value = function (){
this.set_value(this.valueSelect);
return false;
};
Obj.get_display_value = function (){
return (this.options[this.selectedIndex] || '').text;
};
return Obj;
}
 
// chiamata da onclick
function Input_Select_onclick(e){
var input = Input_Event(e);
if(input.readOnly){
return false;
}
}
 
function Input_Select_Readonly(read){
if(read == null){
return (this.Hidden || this.style.display == 'none' || (this.dispSpan && this.dispSpan.style.display == 'none') || this.readOnly);
}else{
this.readOnly = read;
this.disabled = read ? true : false;
this.style.cursor = read ? 'default' : 'pointer';
this.set_status && this.set_status();
return (this.Hidden || this.style.display == 'none' || read);
}
}
 
function Input_Select_Timeout(contextID, err, str){
// var contextObj = hReqMason_ContextPool[contextID];
if(err == 'TIMEOUT'){
my_alert('Timeout ricezione dati ' + contextID, 'txt');
}else{
my_alert(err+': '+str, 'txt');
}
}
 
// richiamata ad ogni variazione della lista
function Input_Select_ChangeList(e){
var input = Input_Event(e);
// alert('id="'+input.id+'" source="'+input.Source+'" edit="'+input.Edit+'" value="'+input.options[input.selectedIndex].value+'" text="'+input.options[input.selectedIndex].text+'" changeMess="'+input.changeMess+'"');
if(input.Edit && input.options[input.selectedIndex].value == input.changeMess
&& input.options[input.selectedIndex].text == input.changeMess){
if(input.ListEqualBuffer){
for(var C=0; C<input.ListEqualBuffer.length; C++){
input.ListEqualBuffer[C].style.cursor='wait';
}
}else{
this.style.cursor='wait';
}
input.Editing = true;
// selezionato il campo di modifica
// alert('EDIT id='+input.id+' source='+input.Source);
input.EditWindow = window.open(input.Edit, 'Input_Select_Window_'+input.id, input.EditWindowParam);
// blocco l'editing della select fino a che non chiudo la finestra di editing
input.disabled = true;
// metto in evidenza la finestra di editing
input.EditWindow.focus();
// verifico periodicamente che la finestra sia attiva e che abbia il focus
window.setTimeout('Input_Select_TestWindowsFocus("'+input.id+'")', 2000);
}else{
// aggiorno la selezione
input.valueSelect = input.multiple ? input.get_value() : input.value;
input.set_value(input.valueSelect);
if(input.test_value()){
return Input_abortChange(input, e);
}
return true;
}
}
 
// verifico periodicamente che la finestra sia attiva e che abbia il focus
function Input_Select_TestWindowsFocus(id){
var input = document.getElementById(id);
if(input.EditWindow.closed){
input.EditWindow=null;
input.style.cursor='auto';
input.set_value(input.valueSelect);
// componente master (primo componente con stesso buffer, corrisponde a se stesso se $buffer non è definito)
var Sel = input.ListEqualBuffer ? input.ListEqualBuffer[0] : input;
Sel.LoadRemote();
// riabilito la select
input.disabled = false;
input.EditingEnd();
window.focus();
}else{
window.setTimeout('Input_Select_TestWindowsFocus("'+input.id+'")', 200);
}
}
 
/tags/2.0/htdocs/input/divselect.comp
0,0 → 1,141
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2006 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
Widget divselect
testo in sola lettura di descrizione e pulsante per richiamare la lista in finestra (DIV)
separata con gestiore dei dati attraverso l'uso di databinding
</%doc>
<%args>
$id # identificatore del componente nel documento HTML
$description => '' # descrizione visualizzata nella barra
$value => undef # valore da attribuire <option selected> dopo il caricamento della lista (funziona solo se la lista è statica o caricata nel form)
$from # documento corrispondente ad una lista (solo il nome, senza estensione e percorso "..../data/"
$where => '' # clausola where da applicare
$orderby => '' # clausola 'order by' da applicare
$empty => undef # lascia il primo campo della lista vuoto con "value" uguale al contenuto di $empty
$empty_descr => '' # descrizione da visualizzare per il campo 'empty'
@buttons => () # pulsanti supplementari
$empty_button => undef # descrizione da visualizzare nel pulsante di selezione del campo vuoto
$insert_descr => undef # descrizione pulsante inserimento nuovo record (se undef il pulsante non viene visualizzato
@insert_parameters => () # per indicare i parametri da aggiungere nella chiamata al form di inserimento
@insert_copyfields => () # per indicare i campi che vanno copiati dal filtro
$bgcolor => undef
$width => 80
$length => 28 # numero di caratteri minimo da visualizzare
$rows => 20 #numero di righe da visualizzare nella selezione
@cols => (280) # array colonne rappresentante le larghezze di ciascuna colonna
$disp_template => undef # funzione eval per definire la descrizione (i parametri sono disponibili con P[n])
$query_param => '' # parametro opzionale da inviare al server ad ogni chiamata del recordset
@fetch_params => () # elenco campi da ritornare
$icon => 'find' # icona da utilizzare
$cache_params => undef # se !undef attiva la cache sui parametri caricati
$Detail_from => undef # se definita viene inserito per ciascun record un bottone per richiamare un form separato per visualizzare il record
$Detail_width => 800 # larghezza della finestra dettaglio
$Detail_height => 600 # altezza della finestra dettaglio
$Detail_father => 0 # se 1 al recordset della finesta di dettaglio verrà passato l'id del record da cui è stato aperta la select
</%args>
% $width && ($width -= 19); # spazio del bottone
% $width < 0 && ($width = 0);
% $width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
% $ARGS{'width'} = $width;
<%method LIBRARY>\
/lib/httpRequestMason.js
/input/input.comp
/input/divselect.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
%# $PLogger->debug(sub{ "divselect.comp",Dumper(\%ARGS); });
<span class="container" base_class="inputspan" id="<%$id%>" <%&Args2HtmlTaglist(
style => 'background-color: transparent;',
onchange => undef,
onclick => "return Input_DivSelect_open_list('$id');",
type => undef,
widget => undef,
descr_sep => undef,
from => undef,
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);') %>>
<span id="display_<%$id%>" base_class="inputspan" unselectable <%&Args2HtmlTaglist(
onchange => undef,
onclick => undef,
type => undef,
widget => undef,
descr_sep => undef,
from => undef,
style => (defined $width ? "width:${width};" : '').(defined $bgcolor ? "background-color:$bgcolor;" : '')
)%>>&nbsp;</span>
% if($icon){
<span class="dijitInline dijitIcon masonSqlIcons <%$icon%> vAlign" id="icon_<%$id%>"></span>
% }
</span>
% push @Script_buffer, $m->scomp('.defer', @_);
<%def .defer>
<%args>
$id
$value => undef
$description => ''
$from
$where => ''
$orderby => '' #clausola 'order by' da applicare
$empty => undef
$empty_descr => ''
@buttons => () # pulsanti supplementari
$empty_button => undef # descrizione da visualizzare nel pulsante di selezione del campo vuoto
$insert_descr => undef # descrizione pulsante inserimento nuovo record (se undef il pulsante non viene visualizzato
@insert_parameters => () # per indicare i parametri da aggiungere nella chiamata al form di inserimento
@insert_copyfields => () # per indicare i campi che vanno copiati dal filtro
$id_descr => '' # identificatore campo descrizione associato del recordset da aggiornare
$readonly => undef
$rows => 20 # numero di righe da visualizzare nella selezione
@cols => (280) # array colonne rappresentante le larghezze di ciascuna colonna
$disp_template => undef # funzione eval per definire la descrizione (i parametri sono disponibili con P[n])
$query_param => '' # parametro opzionale da inviare al server ad ogni chiamata del recordset
$cache_params => undef # se !undef attiva la cache sui parametri caricati
$Detail_from => undef # se definita viene inserito per ciascun record un bottone per richiamare un form separato per visualizzare il record
$Detail_width => 800 # larghezza della finestra dettaglio
$Detail_height => 600 # altezza della finestra dettaglio
$Detail_father => 0 # se 1 al recordest della finesta di dettaglio verrà passato l'id del record da cui è stato aperta la select
$Class => '' # se definita viene aggiunta la classe negli elementi del template
</%args>
<%perl>
$empty = (defined $empty) ? "'$empty'" : 'null';
if(!defined $empty_button){ $empty_button = $empty_descr }
$insert_descr = (defined $insert_descr) ? "'".$m->interp->apply_escapes($insert_descr, 'js')."'" : 'null';
for(my $c=0; $c<@buttons; $c++){
$buttons[$c] = "'".$m->interp->apply_escapes($buttons[$c], 'js')."'";
}
for(my $c=0; $c<@insert_parameters; $c++){
$insert_parameters[$c] = "'".$m->interp->apply_escapes($insert_parameters[$c], 'js')."'";
}
for(my $c=0; $c<@insert_copyfields; $c++){
$insert_copyfields[$c] = "'".$m->interp->apply_escapes($insert_copyfields[$c], 'js')."'";
}
if($from !~ m|/|){
my $pfrom = $Session{ARGS}{from};
if($pfrom){
$from = $pfrom =~ m|^(\w+)/| ? $1.'/'.$from : 'public/'.$from;
}
}
</%perl>
var Id_<%$id%> = Input_DivSelect_Init('<%$id%>', '<%$id_descr%>', '<%$from|js%>', '<%$where|js%>',
'<%$orderby|js%>', <%$insert_descr%>, [<%join ',', @insert_parameters%>],
[<%join ',', @insert_copyfields%>],
<%$empty%>, '<%$empty_descr|js%>', '<%$empty_button|js%>', '<%$description|js%>',
<% $readonly ? 'true' : 'false'%>, <% $rows %>, [<%join ',', @cols%>],
[<%join ',', @buttons%>], '<% $disp_template ? $disp_template : ''|js%>',
'<%$query_param|js%>', <%$cache_params ? 'true' : 'false'%>,
<%defined $Detail_from ? "'".$m->interp->apply_escapes($Detail_from, 'js')."'" : 'null'%>,
<%defined $Detail_width ? $Detail_width : 'null'%>,<%defined $Detail_height ? $Detail_height : 'null'%>, <%$Detail_father%>, '<% $Class %>');
<% &ArgsOnly2JscriptTaglist("Id_$id", onchange => undef) %>
% if(defined $value){
Id_<%$id%>.set_value('<%$value|js%>');
% }
</%def>
/tags/2.0/htdocs/input/form.comp
0,0 → 1,65
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/form.js
/lib/httpRequestMason.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$readonly => undef
$width => undef
$bgcolor => undef
$popupWidth => 800
$popupHeight => 600
$from # documento corrispondente ad una lista (solo il nome, senza estensione e percorso "..../data/"
$where => '' # clausola where da applicare
$orderby => '' # clausola 'order by' da applicare
$empty => undef # lascia il primo campo della lista vuoto con "value" uguale al contenuto di $empty
$empty_descr => '' # descrizione da visualizzare per il campo 'empty'
%formParameters => {}
$disp_template => undef # funzione eval per definire la descrizione (i parametri sono disponibili con P[n])
$query_param => '' # parametro opzionale da inviare al server ad ogni chiamata del recordset
$icon => 'find' # icona da utilizzare
</%args>
% $width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
<a base_class="inputspan" id="<%$id%>" <%&Args2HtmlTaglist(
onclick => "return this.formClick();",
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);')%>>
<span base_class="inputspan" id="display_<%$id%>" <%&Args2HtmlTaglist(
onclick => undef,
style => (defined($width) ? "width:$width;" : '').(defined($bgcolor) ? "background-color:$bgcolor;" : ''))
%>><%$value|h%>&nbsp;</span>
% if($icon){
<span class="dijitInline dijitIcon masonSqlIcons <%$icon%> vAlign" id="icon_<%$id%>"></span>
% }
</a>\
<%perl>
# ".jsonToObj(%formParameters)."
if($id){
$empty = (defined $empty) ? "'$empty'" : 'null';
push @Script_buffer, "var Id_$id = Input_Form_Init('$id', '".$m->interp->apply_escapes($description, 'js').
"', $empty, '".$m->interp->apply_escapes($empty_descr, 'js').
"', '".$m->interp->apply_escapes($from, 'js')."', '".$m->interp->apply_escapes($where, 'js').
"', '".$m->interp->apply_escapes($orderby, 'js')."', ".objToJson(\%formParameters).", ".($readonly ? 'true':'false').
", $popupWidth, $popupHeight, ".
"'".$m->interp->apply_escapes($disp_template, 'js').
"', '".$m->interp->apply_escapes($query_param, 'js').
"');\n";
}
</%perl>
 
/tags/2.0/htdocs/input/codfisc_pi.comp
0,0 → 1,42
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/codfisc_pi.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$size => 16
$trans => 'U' # U:upper - caratteri tutti maiuscoli; L: lower - caratteri tutti minuscoli
$description => ''
$readonly => undef
$width => undef
</%args>
<%perl>
if(!$width){
$width = int($size * ($trans eq 'U' ? 8.125 : 6.875));
}
$width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
</%perl>
<input <%$readonly ? 'readOnly':''%> type="text" base_class="string" id="<%$id%>" value="<%$value%>" size="<%$size%>" maxlength="<%$size%>" <%&Args2HtmlTaglist(
onkeypress => 'return Input_Codfisc_pi_keypress(event);',
onchange => 'Input_change(event);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
style => defined $width ? "width:${width};" : '')
%>>
% if($id){
% push @Script_buffer, "var Id_$id = Input_Codfisc_pi_Init('$id', '".$m->interp->apply_escapes($description, 'js')."','".$m->interp->apply_escapes($trans, 'js')."');\n";
% }
/tags/2.0/htdocs/input/input_group.js
0,0 → 1,239
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2017 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_group_Init(Objname, Descr, Format, Suffixes){
var Obj = Input_Init(Objname, Descr);
// Format of value (Json or list separated by Type char
if(Format.toLowerCase() == 'json'){
Obj.json = true;
}else{
Obj.sep = Format;
}
// array, list of widgets suffix
Obj.suffix = Suffixes.split(' ');
// is arrow management active?
Obj.active_arrows = Obj.displayBinding ? (Obj.displayBinding.formKeysMovement.search('ARROWS') != -1) : false;
// list of widgets
Obj.widgets = [];
for(var pos=0; pos<Obj.suffix.length; pos++){
var widget = document.getElementById(Objname + '_' + Obj.suffix[pos]);
Obj.widgets[pos] = widget;
widget.Widget = Obj;
widget.Widget_pos = pos;
widget.onkeydown = Input_group_onkeydown;
}
Obj.onafterupdate = function(){
eval(this.onchange);
}
Obj.Input_widgetKeydown = Input_widgetKeydown;
Obj.setFocus = Input_group_setFocus;
Obj.set_obj = Input_group_set_obj;
Obj.set_value = Input_group_set_value;
Obj.get_obj = Input_group_get_obj;
Obj.get_value = Input_group_get_value;
Obj.local_test = Input_group_local_test;
Obj.Readonly = Input_group_readonly;
Obj.set_status = Input_group_set_status;
Obj.set_display_children = Input_group_set_display_children;
Obj.set_display = Input_group_set_display;
Obj.set_status();
return Obj;
}
 
function Input_group_get_obj(){
var hash = {};
var no_empty;
for(var pos=0; pos<this.suffix.length; pos++){
var val = this.widgets[pos].get_value();
if(val != null && val != ''){
hash[this.suffix[pos]] = val;
no_empty = true;
}
}
return no_empty ? hash : null;
}
 
function Input_group_get_value(){
if(this.json){
var obj = this.get_obj();
var val = obj ? JSON.stringify(obj) : '';
// return original set value if widget values are not changed
return this.value_set == val ? this.value_orig : val;
}else{
var array = [];
var no_empty;
for(var pos=0; pos<this.suffix.length; pos++){
var val = this.widgets[pos].get_value();
if(val != null && val != ''){
no_empty = true;
}
array.push(val);
}
return no_empty ? array.join(this.sep) : '';
}
}
 
function Input_group_set_obj(hash){
if(hash == null || hash == ''){
for(var pos=0; pos<this.suffix.length; pos++){
this.widgets[pos].set_value(hash);
}
}else{
for(var pos=0; pos<this.suffix.length; pos++){
var value = hash[this.suffix[pos]];
this.widgets[pos].set_value(value == null ? '' : value);
}
}
this.set_display();
}
 
function Input_group_set_value(value, param){
if(param != null){
this.set_param(param);
}
if(value == null || value == ''){
this.set_obj(value);
}else{
if(this.json){
// save original set to return with .get_value if value are not changed
this.value_orig = value;
var hash = JSON.parse(value);
if(hash == null){
console.error('Parsing JSON error on field ' + this.id, value, this);
my_alert('Parsing JSON error on field ' + this.id + ' value ['+value+']');
this.set_obj(null);
}else{
this.set_obj(hash);
}
// save value as parsed by .get_value (used to compare in .get_value)
this.value_set = null;
this.value_set = this.get_value();
}else{
var array = value.split(sep, this.suffix.length);
for(var pos=0; pos<this.suffix.length; pos++){
this.widgets[pos].set_value(array[pos]);
}
}
this.set_display();
}
}
 
function Input_group_set_display_children(){
for(var pos=0; pos<this.suffix.length; pos++){
var widget = this.widgets[pos];
var tooltip_text = (widget.Descr ? widget.Descr : 'Campo ' + widget.name) + ': ' + widget.get_value();
widget.setTooltip(tooltip_text);
}
}
 
function Input_group_set_display(){
this.set_display_children();
}
 
function Input_group_set_status(status){
for(var pos=0; pos<this.suffix.length; pos++){
this.widgets[pos].set_status(status);
}
}
 
function Input_group_readonly(set){
if(set == null){
return this.readOnly;
}else{
this.readOnly = set;
for(var pos=0; pos<this.suffix.length; pos++){
this.widgets[pos].Readonly(set);
}
this.set_status();
return set;
}
}
 
function Input_group_local_test(){
var error = [];
for(var pos=0; pos<this.suffix.length; pos++){
var widget = this.widgets[pos];
if(widget.local_test != null){
var err = widget.local_test();
if(err){
error.push(err);
widget.eval_status('Error');
Input_abortChange(widget);
}else{
widget.eval_status('');
}
}
}
if(error.length){
var err = error.join('\n');
return err.replace(/^\s+|\s+$/, '');
}else{
return '';
}
}
 
function Input_group_onkeydown(ev){
if(!ev){
ev = window.event;
}
var input = Input_Event(ev);
var widget = input.Widget;
if(widget.Readonly()){
return false;
}
var wdest; //widget destination
if((ev.keyCode == 9 && !ev.shiftKey) || (ev.keyCode == 39 && widget.active_arrows) ){ // TAB o Right arrow
for(var pos = input.Widget_pos + 1; pos < widget.widgets.length; pos++){
var widget = widget.widgets[pos];
if(widget.getAttribute('tabindex') != -1){
wdest = widget;
break;
}
}
}else if((ev.keyCode == 9 && ev.shiftKey) || (ev.keyCode == 37 && widget.active_arrows) ){ // Shift-TAB o Left arrow
for(var pos = input.Widget_pos -1; pos >= 0; pos--){
var widget = widget.widgets[pos];
if(widget.getAttribute('tabindex') != -1){
wdest = widget;
break;
}
}
}
if(!wdest){
wdest = DisplayBinding_getWidget(widget, ev);
}
if(!wdest){
return true; // propaga evento per risposta standard
}
return widget.Input_widgetKeydown(ev, input, wdest);
}
 
function Input_group_setFocus(ev){
if((ev.keyCode == 9 && ev.shiftKey) || ev.keyCode == 37 || ev.keyCode == 38){ // Shift-TAB o Left arrow o Up arrow
// il primo widget in fondo alla lista
var pos = this.widgets.length - 1;
var step = -1;
}else{
// il widget in cima alla lista
var pos = 0;
var step = 1;
}
// salto i widget esclusi
while(this.widgets[pos].getAttribute('tabindex') == -1){
pos += step;
if(step == 1 ? pos >= this.widgets.length : pos < 0){
// fuori range
return null;
}
}
var widget = this.widgets[pos];
return widget.setFocus();
}
/tags/2.0/htdocs/input/checkbox.comp
0,0 → 1,43
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2017 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/checkbox.js
</%method>
<%init>
&LoadHeader('SELF');
</%init>
<%shared>
my $checked='';
</%shared>
<%args>
$id
$value => ''
$description => ''
$label_class => undef
$readonly => undef
$style => undef
</%args>
<span class="container" id="checkboxspan_<%$id%>" style="<%$style%>">
<input tabindex="-1" id="<%$id%>" type="checkbox" value-type="boolean" base_class="checkbox" <% $value ? 'CHECKED' : ''%>
label_class=<%$label_class ? 'LabelChk' : ''%>
<%&Args2HtmlTaglist(
onmouseover => 'Input_ViewDescription(event);',
onkeydown => 'return Input_keydown(event);',
onclick => 'if(this.readOnly){return false}',
onchange => 'Input_change(event);',
onmouseout => 'Input_DeleteDescription(event);'
)%>/>\
% if($label_class){
<label id="label_<%$id%>" for="<%$id%>" class="<%$label_class%>"/>\
% }
</span>
% push @Script_buffer, "var Id_$id = Input_Checkbox_Init('$id', '".$m->interp->apply_escapes($description, 'js')."', ".($readonly ? 'true':'false').");\n";
/tags/2.0/htdocs/input/checkbox.js
0,0 → 1,62
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2017 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Checkbox_Init(Objname, Descr, readOnly){
var Obj = Input_Init(Objname, Descr);
var cbs = Obj.Checkboxspan = document.getElementById('checkboxspan_'+Objname);
var lbl = document.getElementById('label_'+Objname);
if(lbl){
Obj.TooltipObj = new dijit.Tooltip({
connectId: lbl,
showDelay: Obj.TooltipShowDelay,
label: Descr
});
Obj.setTooltip(Descr);
Obj.Label = lbl;
}
cbs.Widget = Obj;
cbs.TooltipShowDelay = Obj.TooltipShowDelay;
cbs.setTooltip = Obj.setTooltip;
Obj.Readonly(readOnly);
Obj.set_status = function(status){
var classList = this.eval_status(status, true);
// non applico la variazione della lista delle classi se non cambia
if(this.Checkboxspan.className != classList){
this.Checkboxspan.className = classList;
}
}
Obj.set_display = function (){
var tooltip_text = (this.Descr ? this.Descr : 'Campo ' + this.name) + ': ' + (this.get_value() ? 'selezionato' : 'non selezionato');
this.setTooltip(tooltip_text);
this.Checkboxspan.setTooltip(tooltip_text);
}
Obj.set_status();
Obj.onfocus = function (event){
if(event){
var input = Input_Event(event);
input.Focus = true;
input.set_status();
}else{
return false;
}
}
Obj.onblur = function (event){
if(event){
var input = Input_Event(event);
input.Focus = false;
input.set_status();
}else{
return false;
}
}
Obj.set_status();
return Obj;
}
/tags/2.0/htdocs/input/number.js
0,0 → 1,127
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Number_Init(Objname, Descr, NumDec, NumCifre, ValMax, ValMin, AllNumDec, ReturnNumDec){
var Obj = Input_Init(Objname, Descr);
Obj.NumDec = NumDec;
Obj.NumCifre = NumCifre;
Obj.maxLength = Obj.NumCifre;
Obj.ValMax = ValMax;
Obj.ValMin = ValMin;
Obj.AllNumDec = AllNumDec;
Obj.ReturnNumDec = ReturnNumDec;
Obj.get_value = Input_Number_get_value;
Obj.set_value = Input_Number_set_value;
Obj.local_test = Input_Number_test_value;
Obj.set_status();
return Obj;
}
 
// metodo .local_test verifica la validità del numero presente nel campo
function Input_Number_test_value(){
with(this){
// se il campo contiene valori non numerici viene svuotato
if(value==" " || value=='NaN'){
value='';
};
if(isNaN(parseFloat(value))){
value = '';
}
if(value != ''){
try{
if(NumDec != null){
var Dec = Math.pow(10, NumDec);
var Num = '' + Math.round(Dec*value)/Dec;
if(AllNumDec && NumDec > 0){
// aggiungo eventuali zeri di cifre decimali
var pos_dec = Num.indexOf('.');
if(pos_dec == -1){
Num = '' + Num + '.';
pos_dec = Num.length -1;
}
for(I=(AllNumDec - Num.length + pos_dec + 1); I>0; I--){
Num += '0';
}
}
value = Num;
}
}catch(err){};
// verifico il rispetto di NumCifre
if(value.length > NumCifre){
return "Il valore deve avere al massimo "+NumCifre+" cifre";
}
//verifico il rispetto di ValMin e ValMax
if(parseFloat(value) > ValMax){
return "Il valore deve essere minore o uguale a "+ValMax;
}
if(parseFloat(value) < ValMin){
return "Il valore deve essere maggiore o uguale a "+ValMin;
}
}
}
}
 
function Input_Number_keypress(e){
var input = Input_Event(e);
var charcode = e.chCode;
//my_alert("charCode:"+charcode+" char="+String.fromCharCode(charcode));
if(e.normalKey && charcode){
var key = String.fromCharCode(charcode);
var reValidChars = /[\-\d\.]/;
if (!reValidChars.test(key) ) {
// alert( "Carattere ("+key+":"+charcode+") non valido");
return false;
}
// segno meno solo se campo vuoto
if(key == '-' && input.value.length){
return false;
}
// verifico se il punto è gia stato usato
re = /\.(.*)/;
if(key == '.' && input.value.search(re)!=-1){
return false;
}
}
}
 
// ritorna il valore del campo specificato
function Input_Number_get_value(){
var Num = this.value;
if(this.ReturnNumDec){
// conteggio le cifre decimali
var pos_dec = Num.indexOf('.');
if(pos_dec == -1){
Num += '.';
pos_dec = Num.length;
}
for(I=(this.ReturnNumDec - Num.length + pos_dec); I>0; I--){
// aggiungo cifre non significative
Num += '0';
}
}
return Num;
}
 
// inizializza il valore del campo selezionato
function Input_Number_set_value(value, param){
if(param != null){
this.set_param(param);
}
this.value = value;
var str_err = this.local_test();
if(str_err){
this.widgetError = 'Error';
this.set_status();
}
if(this.set_display){
this.set_display();
}
}
/tags/2.0/htdocs/input/Files.comp
0,0 → 1,93
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2011 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
#
# widget tree filesystem
#
#
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/Files.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$from => undef
$id
$description => ''
$readonly => undef
$delete_if_update => 1 # abilita la cancellazione di file/cartelle con il permesso di modifica
</%args>
% # campo nascosto utilizzato quale contenitore per tutte le voci del componente complesso
<span base_class="Files" id="<%$id%>">
<div class="container" id="<%$id%>_tree"></div>
</span>
<%perl>
push @Script_buffer, "var Id_$id = Input_Files_Init('$id', '".
$m->interp->apply_escapes($description, 'js')."', ".
($readonly ? 'true' : 'null').", ".
($from ? "'$from'" : 'null').", '".
$m->interp->apply_escapes($value, 'js')."', ".
($delete_if_update ? 'true' : 'false').");\n";
</%perl>
<%shared>
</%shared>
<%method HTML_BODY>
<div style="display:none" id="Input_Files_commons">
<div data-dojo-type="dijit/Menu" id="Input_Files_tree_menu">
<div id="Input_Files_download" data-dojo-type="dijit/MenuItem" onClick="Input_Files_TreeNodeObj.tree.download_item(null, 'save');">Scarica sul PC</div>
<div id="Input_Files_zipDownload" data-dojo-type="dijit/MenuItem" onClick="Input_Files_TreeNodeObj.tree.download_item(null, 'zipSave');">Scarica ZIP sul PC</div>
<div id="Input_Files_tgzDownload" data-dojo-type="dijit/MenuItem" onClick="Input_Files_TreeNodeObj.tree.download_item(null, 'tgzSave');">Scarica TGZ sul PC</div>
<div id="Input_Files_rename" data-dojo-type="dijit/MenuItem">Rinomina</div>
<div id="Input_Files_upload" data-dojo-type="dijit/MenuItem" >Carica nel server</div>
<div id="Input_Files_new_folder" data-dojo-type="dijit/MenuItem">Nuova cartella</div>
<div id="Input_Files_trash" data-dojo-type="dijit/MenuItem" iconClass="masonSqlIcons delete">Cestina</div>
% if($Session{Group_Admins}){
<div id="Input_Files_delete" data-dojo-type="dijit/MenuItem" iconClass="dijitEditorIcon dijitEditorIconDelete">Cancella</div>
% }
<div id="Input_Files_history" data-dojo-type="dijit/MenuItem" iconClass="dijitEditorIcon dijitEditorIconRedo">Versioni</div>
</div>
<div data-dojo-type="dijit/TooltipDialog" id="Input_Files_tree_dialog">
<input id="Input_Files_tree_dialog_name" type="text" style="width:300px;">
<button id="Input_Files_tree_dialog_btn" onclick="dijit.byId('Input_Files_tree_menu').close_tree_dialog();" data-dojo-type="dijit/form/Button">OK</button>
<button onclick="dijit.popup.close(dijit.byId('Input_Files_tree_dialog'))" data-dojo-type="dijit/form/Button">Annulla</button>
</div>
<div data-dojo-type="dijit/TooltipDialog" id="Input_Files_trash_dialog">
<div>Sei certo di voler cestinare?</div><br>
<button id="trash_dialog_btn" onclick="Input_Files_TreeNodeObj.tree.delete_item();" data-dojo-type="dijit/form/Button">Cestina</button>
<button onclick="dijit.popup.close(dijit.byId('Input_Files_trash_dialog'))" data-dojo-type="dijit/form/Button">Annulla</button>
</div>
% if($Session{Group_Admins}){
<div data-dojo-type="dijit/TooltipDialog" id="Input_Files_delete_dialog">
<div>Sei certo di voler cancellare definitivamente?</div><br>
<button id="delete_dialog_btn" onclick="Input_Files_TreeNodeObj.tree.delete_item();" data-dojo-type="dijit/form/Button">Cancella</button>
<button onclick="dijit.popup.close(dijit.byId('Input_Files_delete_dialog'))" data-dojo-type="dijit/form/Button">Annulla</button>
</div>
% }
<div data-dojo-type="dijit/TooltipDialog" id="Input_Files_upload_dialog">
<form method="post" action="/archive/upload.mason" id="Input_Files_upload_form" enctype="multipart/form-data" style="width:420px;">
<fieldset>
<legend>Carica nel server</legend>
<input class="browseButton" name="uploadedfile" multiple="true" type="file" style="width:140px;"
data-dojo-type="dojox/form/Uploader" label="Selezionare i file" id="Input_Files_uploader" />
<input type="button" id="remBtn" label="Svuota lista" onClick="dijit.byId('Input_Files_files').reset();" data-dojo-type="dijit/form/Button" />
<input type="hidden" id="Input_Files_upload_dir" name="upload_dir" />
<input type="submit" label="Invia al server" data-dojo-type="dijit/form/Button" id="Input_Files_submit"/>
<button onclick="dijit.byId('Input_Files_uploader').reset();dijit.byId('Input_Files_files').reset();dijit.popup.close(dijit.byId('Input_Files_upload_dialog'))" data-dojo-type="dijit/form/Button">Annulla</button>
<div id="Input_Files_files" data-dojo-type="dojox/form/uploader/FileList" uploaderId="Input_Files_uploader"
headerIndex="Indice" headerType="Tipo" headerFilename="Nome file" headerFilesize="Dimensione"
></div>
</fieldset>
</form>
</div>
</div>
</%method>
/tags/2.0/htdocs/input/FCKeditor.comp
0,0 → 1,52
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/lib/FCKeditor/fckeditor.js
/input/FCKeditor.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$width => '100%'
$height => '400'
$editWidth => '100%'
$editHeight => '400'
$readonly => undef
$bgcolor => undef
</%args>
%# per agganciare l'editor (verrà caricato solo alla prima occasione di modifica)
<textarea id="<%$id%>_FCKeditor" style="display:none;"></textarea><br>
%# usato per visualizzare quando il widget è in sola lettura
<div disabled base_class="inputdiv" id="<%$id%>" <%&Args2HtmlTaglist(
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
style => 'float: none; overflow:auto; display:block; white-space: normal;'.
(defined $bgcolor ? " background-color:$bgcolor;" : '')
)%>>\
</div>
<%perl>
$description = $m->interp->apply_escapes($description, 'js');
$value = $m->interp->apply_escapes($value, 'js');
$width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
$height = !$height || $height =~ m/[^\d]/ ? $height : $height.'px';
$editWidth = !$editWidth || $editWidth =~ m/[^\d]/ ? $editWidth : $editWidth.'px';
$editHeight = !$editHeight || $editHeight =~ m/[^\d]/ ? $editHeight : $editHeight.'px';
my $ro = $readonly ? 'true' : 'false';
push @Script_buffer, qq|
var Id_$id = Input_FCKeditor_Init('$id', '$value', '$description', '$width', '$height', '$editWidth', '$editHeight');
Id_$id.Readonly($ro)
|;
</%perl>
/tags/2.0/htdocs/input/FCKeditor.js
0,0 → 1,118
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2006 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
%# Force compatible test for use with Webkit browsers (Safari)
FCKeditor.prototype._IsCompatibleBrowser = function(){ return true };
 
function Input_FCKeditor_Init(Objname, Value, Descr, Width, Height, editWidth, editHeight){
var Obj = Input_Init(Objname, Descr);
Obj.Textarea = document.getElementById(Objname + '_FCKeditor');
Obj.style.width = Width;
Obj.style.height = Height;
Obj.editWidth = editWidth;
Obj.editHeight = editHeight;
Obj.FCKcontainer = Obj;
Obj.get_value = function (){
var value;
if(this.SetReadonly || !this.oEditor){
value = this.FCKcontainer.innerHTML;
}else{
value = this.oEditor.GetXHTML(true);
}
//alert('get_value of ' + this.id + ':' + value);
return value;
}
 
Obj.set_value = function (value){
//my_alert('set_value of ' + this.id + ':' + value);
if(this.SetReadonly || !this.oEditor){
this.FCKcontainer.innerHTML = value;
}else{
this.oEditor.SetHTML(value, true);
}
}
 
// stato di partenza del widget in sola lettura
Obj.SetReadonly = true;
 
// metodo per disporre in sola lettura/scrittura il widget
Obj.Readonly = function (set) {
//alert('Readonly from ' + this.SetReadonly + ' to ' + set);
if(set == null){
// senza parametro, ritorna lo stato attuale
return this.SetReadonly;
}
if(this.SetReadonly == set){
// già nello stato richiesto
return set;
}
if(set){
// set in sola lettura
if(this.oEditor){
// recupero il contenuto
this.FCKcontainer.innerHTML = this.oEditor.GetXHTML(true);
// nascondo l'editor
this.FCKeditorFrame.style.display = 'none';
}
// visualizzo il widget in lettura
this.style.display = 'block';
}else{
// set in modifica
this.style.display = 'none';
if(this.oEditor){
this.oEditor.SetHTML(this.FCKcontainer.innerHTML);
this.FCKeditorFrame.style.display = 'block';
}else{
// componente FCKeditor non ancora caricato ...
var oFCKeditor = new FCKeditor(this.id + '_FCKeditor') ;
oFCKeditor.Width = this.editWidth;
oFCKeditor.Height = this.editHeight;
// alert('Width='+oFCKeditor.Width+' Height='+oFCKeditor.Height);
oFCKeditor.BasePath = '/lib/FCKeditor/';
oFCKeditor.Config['CustomConfigurationsPath'] = '/lib/FCKeditor_config.js';
oFCKeditor.ToolbarSet = 'MyToolbar';
oFCKeditor.ReplaceTextarea(); // textarea utilizzata come ancora
this.oFCKeditor = oFCKeditor;
}
//this.oEditor = FCKeditorAPI.GetInstance(this.id + '_FCKeditor');
}
this.SetReadonly = set;
return set;
}
// funzione richiamata al termine del caricamento di FCKeditor
Obj.OnCompleteFCKeditor = function (editorInstance){
this.oEditor = FCKeditorAPI.GetInstance(editorInstance.Name);
this.oEditor.SetHTML(this.FCKcontainer.innerHTML, true);
}
Obj.set_status();
Obj.set_value(Value);
Obj.setFocus = null;
return Obj;
}
 
// ATTENZIONE: la funzione FCKeditor_OnComplete andrà spostata in una libreria generalizzata quando
// l'editor FCKeditor verrà utilizzato in widget differenti; per ora è dichiarato qui
 
// funzione richiamata al termine del caricamento del widget
function FCKeditor_OnComplete(editorInstance){
var widget_name = editorInstance.Name.replace(/_FCKeditor$/, '');
var widget = document.getElementById(widget_name);
if(widget){
// frame che contiene l'editor
widget.FCKeditorFrame = document.getElementById(editorInstance.Name + '___Frame');
if(widget.OnCompleteFCKeditor){
widget.OnCompleteFCKeditor(editorInstance);
}
}
}
/tags/2.0/htdocs/input/button.js
0,0 → 1,49
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Button_Init(Objname, Descr, Value, CaptionValue){
var Obj = Input_Init(Objname, Descr);
// metodo per la lettura del valore del componente
Obj.Readonly = Input_Button_Readonly;
Obj.get_value = function () {
return this.Value;
}
// metodo per il caricamento del valore del componente
Obj.set_value = function (value, param) {
this.Value = value;
if(param != null){
this.set_param(param);
}
// disabilito il pulsante se non c'è valore del campo
this.disabled = this.readOnly = (value == '' || value == null || value == false || value == 0);
if(this.CaptionValue){
this.value = value;
}
this.set_status();
}
Obj.set_value(Value);
Obj.setFocus = null;
Obj.CaptionValue = CaptionValue;
return Obj;
}
 
function Input_Button_Readonly(read){
if(read == null){
return (this.Hidden || this.style.display == 'none' || (this.dispSpan && this.dispSpan.style.display == 'none') || this.readOnly);
}else{
this.readOnly = read;
this.disabled = read;
this.style.cursor = read ? 'default' : 'pointer';
this.set_status && this.set_status();
return (this.Hidden || this.style.display == 'none' || read);
}
}
 
/tags/2.0/htdocs/input/color.js
0,0 → 1,175
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
 
function Input_Color_Init(Objname, Descr, ReadOnly, ConvertToHex){
var Obj = Input_Init(Objname, Descr);
Obj.convertToHex = ConvertToHex;
Obj.hexValue = '#ffffff';
Obj.icon = document.getElementById('icon_' + Objname);
Obj.get_value = Input_Color_get_value;
Obj.Readonly = Input_Color_Readonly;
Obj.Readonly(ReadOnly);
require(["dojo/_base/Color"], function(){
Obj.set_value = Input_Color_set_value;
Obj.local_test = Input_Color_local_test;
});
if(Obj.local_test()){
Obj.set_value('');
}
return Obj;
}
 
function Input_Color_Readonly(Set){
if(Set == null){
return this.readOnly;
}else{
var icon = this.icon;
require(["dojo/dom-style", "dojo/dom-class"], function(domStyle, domClass){
if(icon){
domStyle.set(icon,'cursor', Set ? 'default' : 'pointer');
domClass[Set ? 'add' : 'remove'](icon, 'dijitDisabled');
}
});
this.readOnly = Set;
this.set_status();
return Set;
}
}
 
var Input_Color_Picker;
 
function Input_Color_open_color_picker(id){
require(["dojox/widget/ColorPicker", "dijit/popup", "dojo/dom-class","dojo/domReady!"],
function(ColorPicker, popup, domClass){
if(!Input_Color_Picker){
Input_Color_Picker = new ColorPicker({
onChange: function(val){
if(Input_Color_Picker.Input){
Input_Color_Picker.Input.set_value(val);
Input_Color_Picker.Input.onchange();
Input_Color_Picker.Input = null;
popup.close(this);
}
}
}, 'Input_Color_Picker');
Input_Color_Picker.watch('focused', function(property_name, old_val, new_val){
if(!new_val){
popup.close(this);
}
});
popup.moveOffScreen(Input_Color_Picker);
if(Input_Color_Picker.startup && !Input_Color_Picker._started){
Input_Color_Picker.startup();
}
}
//console.log('Input_Color_Picker %o', Input_Color_Picker);
var input = document.getElementById(id);
//console.log('Color_Picker.set.value='+input.hexValue);
Input_Color_Picker.set('value', input.hexValue);
if(!input.readOnly){
popup.open({
popup: Input_Color_Picker,
around: input
});
Input_Color_Picker.Input = input;
Input_Color_Picker.focus();
}
});
return false;
}
 
function Input_Color_local_test(){
var value = this.value;
//console.log('value='+value);
value = value.replace(/\s/g,'');
if(!value){
return null;
}
var err_str = '';
require(["dojo/_base/Color"], function(Color){
if(/^#/.test(value)){
if(!Color.fromHex(value)){
//Incorrect color code.
err_str = "Codice del colore non corretto.";
}
}else if(/^rgb/.test(value)){
if(!Color.fromRgb(value)){
//Incorrect RGB value.
err_str = "Valore RGB non corretto.";
}
}else{
if(!Color.fromString(value.toLowerCase())){
//Unrecognized color name.
err_str = "Nome del colore sconosciuto.";
}
}
});
this.set_value(value);
//console.log('err_str='+err_str);
return err_str ? err_str : null;
}
 
function Input_Color_set_value(Value){
Value = Value.replace(/\s/g,'');
if(Value){
var color;
require(["dojo/_base/Color"], function(Color){
if(/^#/.test(Value)){
color = Color.fromHex(Value);
}else if(/^rgb/.test(Value)){
color = Color.fromRgb(Value);
}else{
color = Color.fromString(Value.toLowerCase());
}
});
if(color){
var hex = color.toHex();
this.hexValue = hex;
if(this.convertToHex){
this.value = hex;
}else{
this.value = Value;
}
//console.log('set_value='+this.value);
//console.log('hexValue='+this.hexValue);
return;
}
}
this.value = null;
this.hexValue = '#ffffff';
//console.log('set_value='+this.value);
//console.log('hexValue='+this.hexValue);
return;
}
 
function Input_Color_get_value(){
//console.log('get_value='+this.value);
if(this.value){
return this.value;
}else{
return '';
}
};
 
function Input_Color_keypress(e){
Input_Event(e);
var charcode = e.chCode;
if(e.normalKey && charcode){
var key = String.fromCharCode(charcode);
var validChars = /[#0-9a-z(),.\s]/i;
if(!validChars.test(key)){
return false;
}
}
return true;
}
 
/tags/2.0/htdocs/input/date.js
0,0 → 1,192
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
function Input_Date_Init(Objname, Descr, ReadOnly){
var Obj = Input_Init(Objname, Descr);
Obj.icon = document.getElementById('icon_' + Objname);
Obj.Readonly = function (set) {
if(set == null){
return this.readOnly;
}else{
var icon = this.icon;
require(["dojo/dom-style", "dojo/dom-class"], function(domStyle, domClass){
if(icon){
domStyle.set(icon,'cursor', set ? 'default' : 'pointer');
domClass[set ? 'add' : 'remove'](icon, 'dijitDisabled');
}
});
this.readOnly = set;
this.set_status();
return set;
}
}
Obj.Readonly(ReadOnly);
Obj.local_test = Input_Date_test_value;
return Obj;
}
 
// oggetto calendar (dijit/Calendar) in comune per tutti i widget
var Input_Date_Calendar;
 
function Input_Date_open_cal(id){
require(["dojo/ready", "dijit/CalendarLite", "dijit/popup", "dojo/dom", "dojo/date/locale"], function(ready, CalendarLite, popup, dom, locale){
ready(function(){
// un solo oggetto calendar che creo al primo richiamo del componente
if(!Input_Date_Calendar){
Input_Date_Calendar = new CalendarLite({
onChange: function(data){
if(Input_Date_Calendar.Input){
Input_Date_Calendar.Input.set_value(locale.format(data, {selector:"date", datePattern:"dd/MM/yyyy"}));
Input_Date_Calendar.Input.onchange();
Input_Date_Calendar.Input = null;
popup.close(this);
}
}
}, 'Input_Date_Calendar');
Input_Date_Calendar.watch('focused', function(property_name, old_val, new_val){
if(!new_val){
popup.close(this);
}
});
}
Input_Date_Calendar.Input = null;
var input = document.getElementById(id);
var data = input.get_value();
Input_Date_Calendar.set('value', data.match(/(\d\d)\/(\d\d)\/(\d\d\d\d)/) ?
new Date(RegExp.$3, parseInt(RegExp.$2) - 1, RegExp.$1) : new Date());
if(!input.readOnly){
popup.open({
popup: Input_Date_Calendar,
around: input
});
Input_Date_Calendar.Input = input;
Input_Date_Calendar.focus();
}
});
});
return false;
}
 
// verifico la validità del campo data
function Input_Date_test_value(){
// elimino qualunque blank nella stringa
this.value = this.value.replace(/\s/g,'');
if(this.value == ''){
return '';
}
var D = new Date();
var Anno=D.getFullYear();
var Mese=D.getMonth()+1;
var Giorno=D.getDate();
var re = /^\/*$/; /**/
if(re.test(this.value)){
//ok data odierna
}else{
var re = /^(\d+)\/*$/; /**/
if(re.test(this.value)){
Giorno=parseInt(RegExp.$1,10);
}else{
var re = /^(\d+)\/(\d+)\/*$/; /**/
if(re.test(this.value)){
Mese=parseInt(RegExp.$2,10);
Giorno=parseInt(RegExp.$1,10);
}else{
var re = /^(\d+)\/(\d+)\/(\d+)$/ ;
if(re.test(this.value)){
Anno=parseInt(RegExp.$3,10);
Mese=parseInt(RegExp.$2,10);
Giorno=parseInt(RegExp.$1,10);
//window.alert("Data="+RegExp.$1+"-"+RegExp.$2+"-"+RegExp.$3+" ("+Giorno+","+Mese+","+Anno+")");
}else{
return "Il formato della data non è corretto";
}
}
}
}
if(Anno<100){
if(Anno<49){
Anno = Anno+2000;
}else{
Anno = Anno+1900;
}
}
if(Anno < 1753 || Anno > 9999){
return "L'anno non è corretto";
}
if(Mese>12 || Mese <= 0){
return "Il mese non è corretto ("+Mese.toString()+")";
}
if(Giorno == 0){
return "Il giorno non è corretto";
}
if(Mese==2){
var Bisestile = false;
if(Anno % 4 == 0){
Bisestile = true;
if(Anno % 100 == 0 ){
Bisestile = false;
if(Anno % 400 == 0){
Bisestile=true;
}
}
}
if(Bisestile){
if(Giorno >29){
return "Il mese di febbraio ha al massimo 29 giorni";
}
}else{
if(Giorno >28){
return "Il mese di febbraio ha al massimo 28 giorni";
}
}
}
if(Giorno > 30 && (Mese == 4 || Mese == 6 || Mese == 9 || Mese == 11)){
return "Il mese ha al massimo 30 giorni";
}
if(Giorno>31){
return "Il mese ha al massimo 31 giorni";
}
if(Mese<=9){
Mese = "0"+Mese.toString();
}
if(Giorno<=9){
Giorno = "0"+Giorno.toString();
}
this.value=Giorno+'/'+Mese+'/'+Anno;
return '';
}
// filtra i tasti durante immissione in campo DATA
function Input_Date_keypress(e){
var input = Input_Event(e);
var charcode = e.chCode;
//window.alert("charCode:"+charcode+" char="+String.fromCharCode(charcode));
if(e.normalKey && charcode){
var key = String.fromCharCode(charcode);
if(key == '.' || key == '-'){
key = '/';
input.changeKeypress(key.charCodeAt(0));
}
var reValidChars = /[\d\/]/;
if (!reValidChars.test(key) ) {
var input = e.currentTarget;
if(input){
return false;
}else{
reValidChars = /[\/\.-]/;
if (reValidChars.test(key) ) {
e.keyCode = 47; // '/'
}else{
return false;
}
}
}
}
}
/tags/2.0/htdocs/input/autohandler
0,0 → 1,31
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
// MasonSQL Copyright:2002-2011 Guido Brugnara - LEADER.IT <http://www.leader.it>
<%attr>
Cache_MaxAge => 12*60*60
</%attr>
<%perl>
initBrowserDetect();
# N.B. $Ver è una variabile globale; utilizzo l'ID session
$Ver = $Session{Session};
$r->headers_out->{'Cache-Control'} = 'max-age='.$m->base_comp->attr('Cache_MaxAge');
$m->call_next;
</%perl>
<%flags>
inherit => '/init.comp'
</%flags>
<%filter>
if($PLogger->level() ne $DEBUG){
# filtra tutti i commenti Jscript
s|^\s*//\n|\n|mg;
s|^\s*//.+\n||mg;
}
</%filter>
/tags/2.0/htdocs/input/blank.html
0,0 → 1,7
<%flags>
inherit => undef # nessun parente
</%flags>
% $r->headers_out->{'Cache-Control'} = 'max-age=999999999';
<%filter>
$_='';
</%filter>
/tags/2.0/htdocs/input/image.comp
0,0 → 1,55
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
# Tarcisio Fedrizzi <tarch@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/image.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$name => ''
$description => ''
$image_style => 'height: 100%; max-width: 400px; max-height: 100px; background-color: transparent;'
$readonly => ''
</%args>
<span class="container" base_class="container" id="<%$id%>" <%&Args2HtmlTaglist(
style => "$image_style",
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);'
)%>>
<label>
<img id="Upload_Button_<%$id%>" <%&Args2HtmlTaglist(
onerror => 'Input_Image_Onerror();',
style => "$image_style"
)%>>
<input type="file" <%&Args2HtmlTaglist(
style => 'display: none;',
accept => 'image/*',
onchange => "Input_Image_Onchange('$id', event);"
)%>>
</label>
<img id="Img_<%$id%>" <%&Args2HtmlTaglist(
style => "$image_style",
ondblclick => "Input_Image_Ondblclick('$id', event);")
%>>
</span>
<%perl>
$readonly = $readonly ? 'true' : 'false';
my $descr = $m->interp->apply_escapes($description, 'js');
push @Script_buffer, qq{
var Id_$id = Input_Image_Init('$id', '$descr', '$readonly');
Id_$id.set_value('$value');
};
</%perl>
/tags/2.0/htdocs/input/image.js
0,0 → 1,115
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2016 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Image_Init(ObjName, Descr, ReadOnly){
var Obj = Input_Init(ObjName, Descr);
var img = Obj.img = document.getElementById('Img_'+ObjName);
img.Widget = Obj;
img.style.display = "inline";
var upload = Obj.upload = document.getElementById('Upload_Button_'+ObjName);
upload.Widget = Obj;
var reader = Obj.reader = Input_Image_FileReader(Obj);
Obj.set_value = Input_Image_set_value;
Obj.get_value = Input_Image_get_value;
Obj.set_style = Input_Image_set_style;
Obj.Readonly = Input_Image_Readonly;
Obj.Readonly(ReadOnly);
Obj.set_status();
return Obj;
}
 
function Input_Image_Readonly(Set){
if(Set == null){
return this.readOnly;
}else{
this.readOnly = Set;
this.set_style(Set);
this.upload.src = this.img.src;
return Set;
}
}
 
function Input_Image_set_style(readonly){
if(readonly){
//my_alert('hide button, show image', 'alert');
this.img.style.display = "inline";
this.upload.style.display = "none";
}else{
//my_alert('show button', 'alert');
this.img.style.display = "none";
this.upload.style.display = "inline";
}
return;
};
 
function Input_Image_Ondblclick(ObjName, Event){
var obj = document.getElementById(ObjName);
var popup = window.open('', '_blank');
popup.document.write('<body><img src="'+obj.get_value()+'"/></body>');
popup.document.close();
//my_alert('ondblclick event', 'alert');
return false;
};
 
function Input_Image_FileReader(Obj){
if(window.FileReader){
var reader = new FileReader();
reader.onload = function(){
Obj.set_value(reader.result);
};
require(["dojo/on"], function(on){
on(reader, "error", function(evt){
var err = evt.target.error;
my_alert(err.name+': '+err.message);
});
});
return reader;
}else{
//The FileReader API is not fully supported in this browser.');
Input_ErrorMessage(Event, 'L\'API FileReader non è completamente supportato in questo browser');
return null;
}
}
 
function Input_Image_Onchange(ObjName, Event){
var input = Event.target;
var obj = document.getElementById(ObjName);
Input_DeleteDescription();
var inputFile = input.files[0];
if(inputFile && obj.reader){
obj.reader.readAsDataURL(inputFile);
return true;
}
return false;
};
 
function Input_Image_Onerror(){
//Error: Image can not be loaded.
//my_alert('Errore: L\'immagine non può essere caricato');
return;
}
 
function Input_Image_set_value(Value, Param){
if(Value == '') Value = null;
this.value = Value;
if(Param != null){
this.set_param(Param);
}
if(Value == null) Value = '#';
this.img.src = Value;
this.upload.src = Value;
this.set_display();
};
 
function Input_Image_get_value(){
return this.value;
};
 
/tags/2.0/htdocs/input/date.comp
0,0 → 1,33
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
%# Viene inclusa nel tag HEAD del documento, richiama le librerie associate al componente
<%method LIBRARY>
/input/input.comp
/input/date.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$readonly => undef
</%args>
<input type="text" value-type="date" base_class="date" id="<%$id%>" value="<%$value%>" length="10" maxlength="10" <%&Args2HtmlTaglist(
onkeypress => 'return Input_Date_keypress(event);',
onkeydown => 'return Input_keydown(event);',
onchange => 'Input_change(event, this);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);')
%>>
<span class="dijitInline dijitIcon masonSqlIcons calendar vAlign" id="icon_<%$id%>" onClick="return Input_Date_open_cal('<%$id%>')"></span>
% push @Script_buffer, "var Id_$id = Input_Date_Init('$id', '".$m->interp->apply_escapes($description, 'js')."', ".($readonly ? 'true':'false').");\n";
/tags/2.0/htdocs/input/number.comp
0,0 → 1,43
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/number.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$length => undef # numero massimo di caratteri accettati nel campo (== NumCifre se non definito)
$size => undef # larghezza in caratteri del campo (== length se non definito)
$NumDec => 0 # numero di decimali
$NumCifre => 9 # numero di cifre totali
$ValMax => 999999999999 # valore massimo de numero accettato
$ValMin => -999999999999 # valore minimo del numero accettato
$readonly => undef
$AllNumDec => 0 # se >0 vengono mantenuti gli zeri nella parte decimale pari a AllNumDec cifre con AllNumDec < NumDec, atrimenti NumDec cifre
$ReturnNumDec => 0 # numero di cifre decimali da restituire, anche se fossero degli zeri
</%args>
% if(!$length){$length = $NumCifre}
% if(!$size){$size = int($length)}
% $AllNumDec = ($NumDec && $AllNumDec && $AllNumDec > 0) ? $AllNumDec : 0;
% if($AllNumDec > $NumDec){ $AllNumDec = $NumDec}
<input <%$readonly ? 'readOnly':''%> type="text" value-type="numeric" base_class="number" id="<%$id%>" value="<%$value%>" size="<%$size%>" <%&Args2HtmlTaglist(
onkeypress => 'return Input_Number_keypress(event);',
onkeydown => 'return Input_keydown(event);',
onchange => 'Input_change(event);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);')
%>>
<script> masonSql.once('ready', function(data){<% "window.Id_$id = Input_Number_Init('$id', '".$m->interp->apply_escapes($description, 'js')."',$NumDec,$length,$ValMax,$ValMin,$AllNumDec,$ReturnNumDec);" %>});</script>
/tags/2.0/htdocs/input/time.comp
0,0 → 1,34
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>
/input/input.comp
/input/time.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$readonly => undef
$h24_format => 1 # se '0' sara' possibile inserire piu' di 24 ore (vedi $length e $maxlength per definire i limiti delle cifre)
$numeric_value => 0 # se 1 il formato sara' numerico con unita' di misura in ore e decimali di ora, anziche' nel formato HH:MM
$NumCifre => 5
</%args>
<input <%$readonly ? 'readOnly':''%> type="text" value-type="time" base_class="time" id="<%$id%>" value="<%$value%>" size="<%$NumCifre%>" maxlength="<%$NumCifre%>" <%&Args2HtmlTaglist(
onkeypress => 'return Input_Time_keypress(event);',
onkeydown => 'return Input_keydown(event);',
onchange => 'Input_change(event);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);')
%>>
% push @Script_buffer, "var Id_$id = Input_Time_Init('$id', ".($h24_format ? 'true': 'false').", ".($numeric_value ? 'true': 'false').", '".$m->interp->apply_escapes($description, 'js')."');\n";
/tags/2.0/htdocs/input/timestamp.comp
0,0 → 1,47
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
# Tarcisio Fedrizzi <tarch@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input_group.comp
/input/timestamp.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$readonly => undef
</%args>
<span class="container" value-type="timestamp" id="<% $id %>" <%&Args2HtmlTaglist(
onchange => 'Input_change(event);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);')
%>>
<& /input/date.comp,
id => "${id}_date",
description => $description,
readonly => $readonly
&>
<& /input/time.comp,
id => "${id}_time",
description => $description,
readonly => $readonly
&>
</span>
<%perl>
my $descr = $m->interp->apply_escapes($description, 'js');
push @Script_buffer, qq{
var Id_$id = Input_Timestamp_Init('$id', '$descr', $readonly);
Id_$id.set_value('$value');
};
</%perl>
/tags/2.0/htdocs/input/input_group.comp
0,0 → 1,19
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
#
# richiamata dai componenti per inglobare il codice in comune
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/input_group.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
/tags/2.0/htdocs/input/timestamp.js
0,0 → 1,87
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2016 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
# Tarcisio Fedrizzi <tarch@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Timestamp_Init(Objname, Descr, ReadOnly){
var Obj = Input_group_Init(Objname, Descr, ' ', 'date time');
Obj.readOnly = ReadOnly;
Obj.get_value = Input_Timestamp_get_value;
Obj.set_value = Input_Timestamp_set_value;
Obj.local_test = Input_Timestamp_local_test;
Obj.group_local_test = Input_group_local_test;
Obj.set_status();
return Obj;
}
 
function Input_Timestamp_get_value(default_time){
var date = this.widgets[0].get_value();
var time = this.widgets[1].get_value();
if(date || time){
if(time == ''){
time = default_time == null ? '00:00' : default_time;
}
if(time != '' && this.seconds != null && this.seconds != ''){
time += ':' + this.seconds;
}
if(date){
var res = date + ' ' + (time ? ' ' + time : '');
return res.replace(/\s+$/, '');
}else{
var today = new Date();
return today.getDate() + '/' + (today.getMonth()+1) + '/' + today.getFullYear() + (time ? ' ' + time : '');
}
}else{
return '';
}
}
 
function Input_Timestamp_set_value(value){
var parsedDate = '';
var parsedTime = '';
var onlyDate = /^(\d+\/\d+\/\d+)\s*$/;
var onlySpaces = /^\s*$/;
if (onlySpaces.test(value)){
this.widgets[0].set_value('');
this.widgets[1].set_value('');
this.set_display();
return;
}
if (onlyDate.test(value)){
parsedDate = RegExp.$1;
parsedTime = '00:00';
this.seconds = '';
}else{
var splitTimestamp = /^(\d+\/\d+\/\d+)\s+(\d+:\d+)$/;
var splitTimestamp_sec = /^(\d+\/\d+\/\d+)\s+(\d+:\d+):(\d+)$/;
var splitTimestamp_sec_millis = /^(\d+\/\d+\/\d+)\s+(\d+:\d+):(\d+.\d+)$/;
if (splitTimestamp_sec.test(value) || splitTimestamp_sec_millis.test(value)){
parsedDate = RegExp.$1;
parsedTime = RegExp.$2;
this.seconds = RegExp.$3;
}else if (splitTimestamp.test(value)){
parsedDate = RegExp.$1;
parsedTime = RegExp.$2;
this.seconds = '';
}
}
this.widgets[0].set_value(parsedDate);
this.widgets[1].set_value(parsedTime);
this.set_display();
}
 
function Input_Timestamp_local_test(){
if(this.widgets[0].get_value() == '' && this.widgets[1].get_value() != ''){
var today = new Date();
this.widgets[0].set_value(today.getDate() + '/' + (today.getMonth()+1) + '/' + today.getFullYear());
}
return this.group_local_test();
}
 
/tags/2.0/htdocs/input/color.comp
0,0 → 1,39
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
%# Viene inclusa nel tag HEAD del documento, richiama le librerie associate al componente
<%method LIBRARY>
/input/input.comp
/input/color.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$readonly => undef
$convert_to_hex => 1
</%args>
<input type="text" base_class="color" id="<%$id%>" value="<%$value%>" length="10" maxlength="30" <%&Args2HtmlTaglist(
onkeypress => 'return Input_Color_keypress(event);',
onkeydown => 'return Input_keydown(event);',
onchange => 'Input_change(event, this);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);'
)%>>
<span class="dijitInline dijitIcon masonSqlIcons pallet vAlign" id="icon_<%$id%>" <%&Args2HtmlTaglist(
onclick => "return Input_Color_open_color_picker('$id')"
)%>></span>
% $description = $m->interp->apply_escapes($description, 'js');
% $readonly = $readonly ? 'true':'false';
% $convert_to_hex = $convert_to_hex ? 'true':'false';
% push @Script_buffer, "var Id_$id = Input_Color_Init('$id', '$description', '$readonly', $convert_to_hex);\n";
/tags/2.0/htdocs/input/document.js
0,0 → 1,127
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2016 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Document_Init(ObjName, FileName, Descr, ReadOnly, SrcPrefix){
var Obj = Input_Init(ObjName, Descr);
var upload = Obj.upload = document.getElementById('Upload_'+ObjName);
upload.Widget = Obj;
Obj.srcPrefix = SrcPrefix;
Obj.fileName = FileName;
Obj.onclick_handle = {};
Obj.add_onclick = Input_Doc_add_onclick;
Obj.remove_onclick = Input_Doc_remove_onclick;
Obj.reset_title = Input_Doc_reset_title;
Obj.set_value = Input_Doc_set_value;
Obj.get_value = Input_Doc_get_value;
Obj.set_style = Input_Doc_set_style;
Obj.Readonly = Input_Doc_Readonly;
Obj.Readonly(ReadOnly);
Obj.set_status();
Obj.reset_title();
return Obj;
}
 
function Input_Doc_Readonly(Set){
if(Set == null){
return this.readOnly;
}else{
this.readOnly = Set;
this.set_style(Set);
return Set;
}
}
 
function Input_Doc_set_style(readonly){
if(readonly){
this.remove_onclick();
}else{
this.add_onclick();
}
return;
};
 
function Input_Doc_remove_onclick(){
var handle = this.onclick_handle;
require(["dojo/on", "dojo/query"], function(on, query){
if(handle.hasOwnProperty('remove')){
handle.remove();
handle = {};
}
});
return;
}
 
function Input_Doc_add_onclick(){
var iframe = this.contentDocument;
var upload = this.upload;
var onclick_handle = {};
require(["dojo/on", "dojo/query", "dojo/domReady!"], function(on, query){
//console.log('iframe: %o', iframe);
onclick_handle = query("#canvasContainer", iframe).on("click", function(){
//console.log('evt');
upload.click();
});
});
this.onclick_handle = onclick_handle;
return;
}
 
function Input_Doc_Onchange(ObjName, Event){
var input = Event.target;
var obj = document.getElementById(ObjName);
if(!window.FileReader){
my_alert('The FileReader API is not fully supported in this browser.');
}
var reader = new FileReader();
reader.onload = function(){
var dataURL = reader.result;
//console.log('dataURL='+dataURL);
obj.set_value(dataURL);
};
var file = input.files[0];
reader.readAsDataURL(file);
obj.fileName = file.name;
//console.log('file: %o', file);
return;
};
 
function Input_Doc_reset_title(){
var obj = this;
//require(["dojo/aspect", "dojo/query", "dojo/NodeList-manipulate"], function(aspect, query){
require(["dojo/aspect"], function(aspect){
aspect.after(obj, "onload", function(){
obj.set_style(obj.readOnly);
});
});
return;
}
 
function Input_Doc_set_value(Value, Param){
if(Value){
//console.log('set_value='+Value);
//console.log('file name='+this.fileName);
var contentLocation = this.contentWindow.location;
//var uri = this.srcPrefix+'?title='+encodeURIComponent(this.fileName)+'#'+Value;
var uri = this.srcPrefix+'?title='+this.fileName+'#'+Value;
//console.log('contentLocation %o', contentLocation);
//console.log('uri='+uri);
contentLocation.href = uri;
this.src = uri;
}
this.value = Value;
return;
};
 
function Input_Doc_get_value(){
//console.log('get_value='+this.value);
return this.value;
};
 
/tags/2.0/htdocs/input/document.comp
0,0 → 1,77
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
# Tarcisio Fedrizzi <tarch@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/document.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$name => ''
$description => ''
$document_style => 'height: 100%; max-width: 800px; max-height: 600px; background-color: transparent;'
$readonly => ''
</%args>
<%perl>
my $blank_pdf = q{data:application/pdf;base64,
JVBERi0xLjQKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9G
bGF0ZURlY29kZT4+CnN0cmVhbQp4nDPQM1Qo5ypUMFAwALJMLU31jBQsTAz1LBSKUrnC
tRTyuAIVAIcdB3IKZW5kc3RyZWFtCmVuZG9iagoKMyAwIG9iago0MgplbmRvYmoKCjUg
MCBvYmoKPDwKPj4KZW5kb2JqCgo2IDAgb2JqCjw8L0ZvbnQgNSAwIFIKL1Byb2NTZXRb
L1BERi9UZXh0XQo+PgplbmRvYmoKCjEgMCBvYmoKPDwvVHlwZS9QYWdlL1BhcmVudCA0
IDAgUi9SZXNvdXJjZXMgNiAwIFIvTWVkaWFCb3hbMCAwIDU5NSA4NDJdL0dyb3VwPDwv
Uy9UcmFuc3BhcmVuY3kvQ1MvRGV2aWNlUkdCL0kgdHJ1ZT4+L0NvbnRlbnRzIDIgMCBS
Pj4KZW5kb2JqCgo0IDAgb2JqCjw8L1R5cGUvUGFnZXMKL1Jlc291cmNlcyA2IDAgUgov
TWVkaWFCb3hbIDAgMCA1OTUgODQyIF0KL0tpZHNbIDEgMCBSIF0KL0NvdW50IDE+Pgpl
bmRvYmoKCjcgMCBvYmoKPDwvVHlwZS9DYXRhbG9nL1BhZ2VzIDQgMCBSCi9PcGVuQWN0
aW9uWzEgMCBSIC9YWVogbnVsbCBudWxsIDBdCi9MYW5nKGVuLVVTKQo+PgplbmRvYmoK
CjggMCBvYmoKPDwvQ3JlYXRvcjxGRUZGMDA1NzAwNzIwMDY5MDA3NDAwNjUwMDcyPgov
UHJvZHVjZXI8RkVGRjAwNEMwMDY5MDA2MjAwNzIwMDY1MDA0RjAwNjYwMDY2MDA2OTAw
NjMwMDY1MDAyMDAwMzUwMDJFMDAzMT4KL0NyZWF0aW9uRGF0ZShEOjIwMTYxMjA4MTUx
MDUxKzAxJzAwJyk+PgplbmRvYmoKCnhyZWYKMCA5CjAwMDAwMDAwMDAgNjU1MzUgZiAK
MDAwMDAwMDIyNiAwMDAwMCBuIAowMDAwMDAwMDE5IDAwMDAwIG4gCjAwMDAwMDAxMzIg
MDAwMDAgbiAKMDAwMDAwMDM2OCAwMDAwMCBuIAowMDAwMDAwMTUxIDAwMDAwIG4gCjAw
MDAwMDAxNzMgMDAwMDAgbiAKMDAwMDAwMDQ2NiAwMDAwMCBuIAowMDAwMDAwNTYyIDAw
MDAwIG4gCnRyYWlsZXIKPDwvU2l6ZSA5L1Jvb3QgNyAwIFIKL0luZm8gOCAwIFIKL0lE
IFsgPDFFMUZBQzczRTAwRTY0RkRGRURBNUM2QjEwRjMyMkU5Pgo8MUUxRkFDNzNFMDBF
NjRGREZFREE1QzZCMTBGMzIyRTk+IF0KL0RvY0NoZWNrc3VtIC9BRDg5MTJCRUQ2M0VE
RjZEOUY0MjhGRDZFNDEwQkY2NQo+PgpzdGFydHhyZWYKNzM2CiUlRU9GCg==};
my $src_prefix = "/lib/ViewerJS/";
</%perl>
<input id="Upload_<%$id%>" type="file" <%&Args2HtmlTaglist(
style => 'display: none;',
onchange => "Input_Doc_Onchange('$id', event);"
)%>>
<iframe id="<%$id%>" src="<%$src_prefix%>" <%&Args2HtmlTaglist(
sytle => "$document_style",
width => '700',
height => '550',
allowfullscreen => "",
webkitallowfullscreen => ""
)%>>
</iframe>
<%perl>
$readonly = $readonly ? 'true' : 'false';
my $descr = $m->interp->apply_escapes($description, 'js');
unless($value){
$value = $blank_pdf;
}
$value = $m->interp->apply_escapes($value, 'js');
$name = $m->interp->apply_escapes($name, 'js');
push @Script_buffer, qq{
var Id_$id = Input_Document_Init('$id', '$name', '$descr', '$readonly', '$src_prefix');
Id_$id.set_value('$value');
};
</%perl>
/tags/2.0/htdocs/input/button.comp
0,0 → 1,44
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/button.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$caption => 'Button_'.$id # testo del pulsante
$caption_value => undef # se definito: il caption viene posto uguale a Value
$description => ''
$width => undef
$readonly => undef
$bgcolor => undef
</%args>
<%perl>
$caption = $caption_value ? $value : $caption;
$caption_value = $caption_value ? 'true' : 'false';
$width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
</%perl>
<input type="button" disabled base_class="button" tabindex="-1" id="<%$id%>" value="<%$caption|h%>" <%&Args2HtmlTaglist(
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
style => (defined($width) ? "width:$width;" : '').(defined($bgcolor) ? "background-color:$bgcolor;" : '')
)
%>>
<%perl>
my $ro = $readonly ? 'true' : 'false';
push @Script_buffer, "var Id_$id = Input_Button_Init('$id', '".$m->interp->apply_escapes($description, 'js').
"', '".$m->interp->apply_escapes($value, 'js')."', $caption_value);\n".
"Id_$id.Readonly($ro);\n";
</%perl>
/tags/2.0/htdocs/input/radio.comp
0,0 → 1,29
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/radio.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$id
$value => undef
$description => ''
$readonly => undef
</%args>
% my $name = $id; $name =~ s/_*\d*$//;
<input <% $readonly ? 'disabled' : '' %> type="radio" <% $value ? 'CHECKED' : '' %> base_class="radio" id="<%$id%>" name="<% $name %>" <%&Args2HtmlTaglist(
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);')
%>>
% push @Script_buffer, "var Id_$id = Input_Radio_Init('$id', '".$m->interp->apply_escapes($description, 'js')."');\n";
/tags/2.0/htdocs/input/string.js
0,0 → 1,90
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_String_Init(Objname, Descr, maxLength, valid_chars, trim, trans, ignore_chars){
var Obj = Input_Init(Objname, Descr);
if(maxLength == null){
maxLength = 999999;
}
Obj.maxLength = maxLength;
Obj.validChars = new RegExp(valid_chars,'');
Obj.ignoreChars = new RegExp(ignore_chars,'');
Obj.trim = trim;
Obj.trans = trans;
Obj.local_test = Input_String_local_test;
Obj.set_status();
return Obj;
}
 
// controllo del campo al termine della modifica
function Input_String_local_test(){
if(this.trim.length > 0){
// elimino blank
if(/^L.*/.test(this.trim)){ // all'inizio
this.value = this.value.replace(/^\s+/,'');
}else if(/^R.*/.test(this.trim)){ // oppure alla fine
this.value = this.value.replace(/\s+$/,'');
}else{ // oppure all'inizio ed alla fine
this.value = this.value.replace(/^\s+|\s+$/,'');
}
}
if(this.value.length > this.maxLength){
return "Caratteri immessi " + this.value.length + " maggiore del limite massimo di " + this.maxLength;
}
% if($r->dir_config('InputStringNoLongUTF')){
% # filtro i caratteri UTF multibyte (la funzione escape codifica i caratteri UTF multibyte con %uNNNN)
var noUTF = unescape(escape(this.value).replace(/%u[\dA-Ea-e]{4}/gm,'?'));
if(this.value != noUTF){
this.value = noUTF;
return 'Rilevati caratteri non compatibili!\nI caratteri sono stati sostituiti con il carattere ?.';
}
% }
return '';
}
 
// filtra i tasti durante immissione
function Input_String_keypress(e){
var input = Input_Event(e);
var charcode = e.chCode;
//window.alert("charCode:"+charcode+" char="+String.fromCharCode(charcode));
if(e.normalKey && charcode ){
var key = String.fromCharCode(charcode);
 
if(input.value.length >= input.maxLength){
return false;
}
if(input.trans){
// trasformazione dei caratteri
var newkey;
if(input.trans == 'U'){
newkey = key.toUpperCase();
}else if(input.trans == 'L'){
newkey = key.toLowerCase();
}
// se il carattere è cambiato
if(newkey != key){
key = newkey;
// provvedo a cambiarlo nell'evento corrente
input.changeKeypress(key.charCodeAt(0));
}
}
// validazione dei caratteri
if(input.validChars.test(key)){
return true;
}else{
// caratteri da ignorare
if(!input.ignoreChars.test(key)){
Input_ErrorMessage(e, "Carattere ("+key+":"+charcode+") non valido");
}
return false;
}
}
}
/tags/2.0/htdocs/input/span.comp
0,0 → 1,43
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/span.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$size => undef # parametro deprecato - è stato sostituito da $width
$width => undef
$bgcolor => undef
$disp_template => undef # funzione eval per definire la descrizione (i parametri sono disponibili con P[n])
$empty_descr => '' # descrizione da visualizzare per il campo
</%args>
% # DEPRECATED
% if(defined $size && !defined $width){
% $width = $size;
% }
% $width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
<span base_class="inputspan" id="<%$id%>" <%&Args2HtmlTaglist(
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
style => (defined($width) ? "width:$width;" : '').(defined($bgcolor) ? "background-color:$bgcolor;" : '')
)
%>><%$value|h%>&nbsp;</span>
<%perl>
if($id){
push @Script_buffer, "var Id_$id = Input_Span_Init('$id', '".$m->interp->apply_escapes($description, 'js')."','".$m->interp->apply_escapes($disp_template, 'js')."','".$m->interp->apply_escapes($empty_descr, 'js').", ".$m->interp->apply_escapes($value, 'js')."');\n";
}
</%perl>
/tags/2.0/htdocs/input/url.comp
0,0 → 1,38
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2009-2012 Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/string.comp
/input/url.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$button_descr => 'VIEW',
$id
$description => ''
$length => 40
$size => undef
$width => undef
$readonly => undef
$base_url => ''
$popup => 0 # utilizza un Popup per visualizzare la URL altrimenti usa window.open in una nuova finestra
$window_properties => 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable,alwaysRaised,dependent,titlebar=yes'
$window_width => 800,
$window_height => 600
</%args>
<span class="container" base_class="inputspan" id="container_<%$id%>">
<button class="button UrlComp" tabindex="-1" onclick="this.widget.displayURL();"
style="display:none;" id="<% $id %>_button_url"><%$button_descr%></button>
<& /input/string.comp, %ARGS &>
</span>
% push @Script_buffer, "var Id_$id = Input_Url_Init('$id', '$base_url', ".($popup ? 'true' : 'false').", $window_width, $window_height, '$window_properties');\n";
/tags/2.0/htdocs/input/Permission.js
0,0 → 1,137
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2006 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Permission_Init(Objname, Descr, Readonly){
var Obj = Input_Init(Objname, Descr);
 
// nuovi metodi associati al componente complesso
 
// metodo per la lettura del valore del componente
Obj.get_value = Permission_get_value;
 
// metodo per il caricamento del valore del componente
Obj.set_value = Permission_set_value;
 
// metodo per variare lo stato
Obj.set_status = Permission_set_status;
 
// metodo per disporre in sola lettura i campi
Obj.Readonly = Permission_Readonly;
 
// costruisco l'array dei checkbox
require(["dojo/dom"], function(dom){
var O = Objname;
Obj.checkboxes = {
% my @gru;
% for(my $row=0; $row<@{$groups}; $row++){
% my $group = $groups->[$row];
% my @per;
% for(my $col=0; $col<@{$permissions}; $col++){
% my $permission = $permissions->[$col];
% push @per, "p$permission->[0]:dom.byId(O+':$group->[0]:$permission->[0]')";
% }
% push @gru, "g$group->[0]:{".join(',', @per).'}';
% }
<% join(",\n ", @gru) %>
};
});
Obj.disabled = !Readonly; // costringo il componente a cambiare la configurazione
Obj.Readonly(Readonly);
Obj.setFocus = null;
return Obj;
}
 
function Permission_get_value(){
var value = [];
for(var row in this.checkboxes){
var cols = this.checkboxes[row];
for(var col in cols){
if(cols[col].checked){
value.push(row + ' ' + col);
}
}
}
if(value.length){
return 'perm:\n' + value.join('\n');
}else{
return 'perm:'
}
}
 
// metodo per il caricamento del valore del componente
function Permission_set_value(value){
// azzero prima tutti i checkbox
for(var row in this.checkboxes){
var cols = this.checkboxes[row];
for(var elem in cols){
cols[elem].checked = false;
}
}
// valuto il codice inviato dal server che provvede a cambiare i valori
rows = value.split(/\n/);
var prima_riga = rows.shift();
if(prima_riga == 'perm:'){
for(var row=0; row<rows.length; row++){
var cols = rows[row].split(/\s+/);
if(cols[0].length && cols[1].length){
this.checkboxes[cols[0]][cols[1]].checked = true;
}
}
return value;
}else{
alert('Errore inaspettato; campo Permission con valore [value]');
}
}
 
function Permission_set_status(status){
var classList = this.eval_status(status);
if(this._classList != classList){
this._classList = classList;
for(var row in this.checkboxes){
var cols = this.checkboxes[row];
for(var elem in cols){
cols[elem].className = classList;
}
}
}
}
 
function Permission_Readonly(set){
// senza parametro ritorna la condizione corrente
if(set == null){
return this.disabled;
}else{
if(this.disabled != set){
this.disabled = set;
for(var row in this.checkboxes){
var cols = this.checkboxes[row];
for(var elem in cols){
cols[elem].disabled = set;
}
}
this.set_status();
}
return set;
}
}
 
<%shared>
# elenco gruppi
my $sth = $Session{Dbh}->prepare(q|select id, nome from gruppi order by nome|);
$sth->execute();
my $groups = $sth->fetchall_arrayref;
 
# elenco permessi
$sth = $Session{Dbh}->prepare(q|select id, nome from autorizzazioni order by nome|);
$sth->execute();
my $permissions = $sth->fetchall_arrayref;
undef $sth;
</%shared>
/tags/2.0/htdocs/input/string.comp
0,0 → 1,72
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/string.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%once>
my $trim_default = $r->dir_config('String_TrimDefault');
use POSIX qw/ceil/;
</%once>
<%args>
$value => ''
$id
$description => ''
$length => 12 # numero massimo di caratteri accettati nel campo
$size => undef # larghezza in caratteri del campo
$trim => $trim_default # elimina gli spazi - R:spazi a destra, L: spazi a sinistra,
# <qualunque altro carattere>:all'inizio e alla fine del testo
$trans => undef # U:upper - caratteri tutti maiuscoli; L: lower - caratteri tutti minuscoli
$width => undef
$cols => undef
$rows => undef
$password => undef
$readonly => undef
$valid_chars => '.*' # espressione regolare (in linguaggio Jscript) per validare i singoli caratteri digitati
$ignore_chars => '' # espressione regolare (in linguaggio Jscript) dei caratteri da ignorare
</%args>
% if(!$size){$size = int($length)}
% $width = !$width || $width =~ m/[^\d]/ ? $width : $width.'px';
% my $style = defined $width ? "width:$width;".($width ? '' : 'display:none;') : '';
% if(defined $rows && $rows >1){
% if(!defined $cols){$cols=ceil($length/$rows)}
<textarea <%$readonly ? 'readOnly':''%> type="text" base_class="string" id="<%$id%>" rows="<%$rows--%>" cols="<%$cols%>" <%&Args2HtmlTaglist(
onkeypress => 'return Input_String_keypress(event);',
onkeydown => 'return Input_keydown(event);',
onchange => 'Input_change(event);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
style => $style)
%>><%$value%></textarea>
% }else{
<input <%$readonly ? 'readOnly':''%> type="<%$password ? 'password' : 'text'%>" base_class="string" id="<%$id%>" value="<%$value%>" size="<%$size%>" maxlength="<%$length%>" <%&Args2HtmlTaglist(
onkeypress => 'return Input_String_keypress(event);',
onkeydown => 'return Input_keydown(event);',
onchange => 'Input_change(event);',
onmouseover => 'Input_ViewDescription(event);',
onmouseout => 'Input_DeleteDescription(event);',
style => $style)
%>>
<%perl>
}
if($id){
if(!$length){ $length = 'null' }
push @Script_buffer, "var Id_$id = Input_String_Init('$id', '".$m->interp->apply_escapes($description, 'js').
"', $length, '".$m->interp->apply_escapes($valid_chars, 'js').
"','".$m->interp->apply_escapes(uc $trim, 'js').
"','".$m->interp->apply_escapes(uc $trans, 'js').
"','".$m->interp->apply_escapes($ignore_chars, 'js').
"');\n";
}
</%perl>
/tags/2.0/htdocs/input/time.js
0,0 → 1,167
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
// filtra i tasti durante immissione in campo orario XX:YY
 
function Input_Time_Init(Objname, h24_format, numeric_value, Descr){
var Obj = Input_Init(Objname, Descr);
// ritorna il valore del widget
Obj.get_numeric_value = Input_Time_get_numeric_value;
Obj.get_value = Input_Time_get_value;
// funzione per definire il valore del widget
Obj.set_numeric_value = Input_Time_set_numeric_value;
Obj.set_value = Input_Time_set_value;
Obj.local_test = Input_Time_local_test;
Obj.h24_format = h24_format;
Obj.numeric_value = numeric_value;
// per salvare il campo secondi, se presente, che non viene gestito dal widget (solo ore e minuti)
Obj.seconds = null;
Obj.set_status();
return Obj;
}
 
function Input_Time_local_test(){
var Ore;
var Minuti;
with(this){
if(value==" "){value=""};
if(value==""){return ''}
var re = /^\:*$/;
if(re.test(value)){
// aggiungo l'ora non definita
var now = new Date();
value = now.getHours() + value;
}
// verifico se solo ':'
if(value == ':'){
var now = new Date();
value = now.getHours() + ':' + now.getMinutes();
}
// verifico se solo ora
var re = /^(\d+)\:*$/;
if(re.test(value)){
Ore=parseInt(RegExp.$1,10);
Minuti=0;
}else{
re = /^(\d+)\:(\d+)$/ ;
var arr = re.exec(value);
Ore=parseInt(RegExp.$1,10);
Minuti=parseInt(RegExp.$2,10);
 
if(isNaN(Ore) || isNaN(Minuti)){
return "Formato orario ("+value+") non corretto";
}
}
if(this.h24_format && Ore>24){
return "L'ora puo' essere al massimo 24";
}
if(Minuti>59){
return "I minuti possono essere al massimo 59";
}
if(Ore<=9){
Ore = "0"+Ore.toString();
}
if(Minuti<=9){
Minuti = "0"+Minuti.toString();
}
value=Ore+":"+Minuti;
}
return '';
}
 
function Input_Time_keypress(e){
var input = Input_Event(e);
var charcode = e.chCode;
//window.alert("charCode:"+charcode+" char="+String.fromCharCode(charcode));
if(e.normalKey && charcode){
var key = String.fromCharCode(charcode);
if(key == '.' || key == '-' || key == '/'){
key = ':';
input.changeKeypress(key.charCodeAt(0));
}
var reValidChars = /[\d\:]/;
if (!reValidChars.test(key) ) {
// Input_ErrorMessage(e, "Carattere ("+key+":"+charcode+") non valido");
return false;
}
}
}
 
// ritorna il valore del campo nel formato numerico (ore e decimali di ore)
function Input_Time_get_numeric_value(){
if(this.value){
// separo ore dai minuti
re = /^(\d+)\:(\d+)$/ ;
var arr = re.exec(this.value);
var Ore = parseFloat(RegExp.$1);
var Minuti = parseFloat(RegExp.$2);
return (Ore + Minuti / 60.0).toFixed(4);
}else{
return '';
}
}
 
// ritorna il valore del campo specificato
function Input_Time_get_value(){
if(this.seconds == null){
return this.numeric_value ? this.get_numeric_value() : this.value;
}else{
if(this.value){
return '';
}else{
// mantengo la misura dei secondi solo per evitare che non si registri una variazione del valore che non c'e' stata
return this.value + ':' + this.seconds;
}
}
}
 
// inizializza il valore del campo selezionato fornito nel formato numerico (ore e decimali di ore)
function Input_Time_set_numeric_value(value, param){
if(param != null){
this.set_param(param);
}
this.seconds = null;
if(value != ''){
var Ore = Math.floor(value);
var Minuti = Math.round((value - Ore) * 60);
%# // necessario nel caso di valori simili a 12.99999888232
if(Minuti == 60){Minuti = 0; Ore +=1;}
this.value = (Ore <= 9 ? '0' : '') + Ore + (Minuti <= 9 ? ':0' : ':') + Minuti;
}else{
this.value = '';
}
if(this.set_display){
this.set_display();
}
}
 
// inizializza il valore del campo selezionato
function Input_Time_set_value(value, param){
if(this.numeric_value){
this.set_numeric_value(value, param);
}else{
if(param != null){
this.set_param(param);
}
if(value){
// separo hh:mm[:ss]
var arr = value.split(':');
this.value = arr[0] + ':' + arr[1];
this.seconds = null;
}else{
this.value = value;
this.seconds = null;
}
if(this.set_display){
this.set_display();
}
}
}
/tags/2.0/htdocs/input/codfisc_pi.js
0,0 → 1,126
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2006 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Codfisc_pi_Init(Objname, Descr, trans){
var Obj = Input_Init(Objname, Descr);
Obj.validChars = new RegExp('[a-zA-Z0-9]','');
Obj.local_test = Input_Codfisc_pi_test;
Obj.trans = trans;
Obj.set_status();
return Obj;
}
 
// filtra i tasti durante immissione
function Input_Codfisc_pi_keypress(e){
var input = Input_Event(e);
var charcode = e.chCode;
// window.alert("charCode:"+charcode+" char="+String.fromCharCode(charcode));
if(e.normalKey && charcode){
var key = String.fromCharCode(charcode);
if(input.value.length >= 16){
return false;
}
if(!input.validChars.test(key)){
return false;
}
if(input.trans){
// trasformazione dei caratteri
var newkey;
if(input.trans == 'U'){
newkey = key.toUpperCase();
}else if(input.trans == 'L'){
newkey = key.toLowerCase();
}
// se il carattere è cambiato
if(newkey != key){
key = newkey;
// provvedo a cambiarlo nell'evento corrente
input.changeKeypress(key.charCodeAt(0));
}
}
}
}
 
// Funzioni per il calcolo di Codice Fiscale e P.I. con licenza Public Domain rif: http://www.icosaedro.it/cf-pi/index.html
 
function ControllaCF(cf){
var validi, i, s, set1, set2, setpari, setdisp;
cf = cf.toUpperCase();
if( cf.length != 16 )
return "La lunghezza del codice fiscale non è\n"
+"corretta: il codice fiscale dovrebbe essere lungo\n"
+"esattamente 16 caratteri.\n";
validi = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
for( i = 0; i < 16; i++ ){
if( validi.indexOf( cf.charAt(i) ) == -1 )
return "Il codice fiscale contiene un carattere non valido `" +
cf.charAt(i) +
"'.\nI caratteri validi sono le lettere e le cifre.\n";
}
set1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
set2 = "ABCDEFGHIJABCDEFGHIJKLMNOPQRSTUVWXYZ";
setpari = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
setdisp = "BAKPLCQDREVOSFTGUHMINJWZYX";
s = 0;
for( i = 1; i <= 13; i += 2 )
s += setpari.indexOf( set2.charAt( set1.indexOf( cf.charAt(i) )));
for( i = 0; i <= 14; i += 2 )
s += setdisp.indexOf( set2.charAt( set1.indexOf( cf.charAt(i) )));
if( s%26 != cf.charCodeAt(15)-'A'.charCodeAt(0) )
return "Il codice fiscale non è corretto:\n"+
"il codice di controllo non corrisponde.\n";
return '';
}
 
function ControllaPIVA(pi){
if( pi.length != 11 )
return "La lunghezza della partita IVA non è\n" +
"corretta: la partita IVA dovrebbe essere lunga\n" +
"esattamente 11 caratteri.\n";
validi = "0123456789";
for( i = 0; i < 11; i++ ){
if( validi.indexOf( pi.charAt(i) ) == -1 )
return "La partita IVA contiene un carattere non valido `" +
pi.charAt(i) + "'.\nI caratteri validi sono le cifre.\n";
}
s = 0;
for( i = 0; i <= 9; i += 2 )
s += pi.charCodeAt(i) - '0'.charCodeAt(0);
for( i = 1; i <= 9; i += 2 ){
c = 2*( pi.charCodeAt(i) - '0'.charCodeAt(0) );
if( c > 9 ) c = c - 9;
s += c;
}
if( ( 10 - s%10 )%10 != pi.charCodeAt(10) - '0'.charCodeAt(0) )
return "La partita IVA non è valida:\n" +
"il codice di controllo non corrisponde.\n";
return '';
}
 
function Input_Codfisc_pi_test(){
var err;
this.value = this.value.toUpperCase();
if(this.value.length == 0){
}else if( this.value.length == 16 ){
err = ControllaCF(this.value);
}else if( this.value.length == 11 ){
err = ControllaPIVA(this.value);
}else{
err = "Il codice introdotto non è valido:\n" +
" - un codice fiscale deve essere lungo 16 caratteri;\n" +
" - una partita IVA deve essere lunga 11 caratteri.\n";
}
if( err > '' ){
return "VALORE ERRATO!\n" + err + "\nCorreggi e riprova!";
}
return '';
}
 
/tags/2.0/htdocs/input/Permission.comp
0,0 → 1,70
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2006 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
#
# blocco dati con form complesso in unico campo per gestire
# il campo complesso "Permission" nel form dei parametri
#
#
</%doc>
<%method LIBRARY>\
/input/input.comp
/input/Permission.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
$value => ''
$id
$description => ''
$readonly => undef
</%args>
% # campo nascosto utilizzato quale contenitore per tutte le voci del componente complesso
<div class="container" base_class="permission" id="<%$id%>">
% # organizzo in una tabella tutti i gruppi (righe) ed i permessi (colonne) e con dei checkbox agli incroci
% # che rappresentano i permessi attivati
<table border="1">
% # intestazioni
<tr>
<td></td>
% for(my $col=0; $col<@{$permissions}; $col++){
<td><%$permissions->[$col]->[1]%></td>
% }
% for(my $row=0; $row<@{$groups}; $row++){
<tr>
% my $group = $groups->[$row];
<td><%$group->[1]%></td>
% for(my $col=0; $col<@{$permissions}; $col++){
<td><input type="checkbox" <%$readonly ? 'disabled':''%> id="<%$id.':'.$group->[0].':'.$permissions->[$col]->[0]%>"></td>
% }
</tr>
% }
</tr>
<rd>
<td>
</td>
</rd>
</table>
</div>
%
% push @Script_buffer, "var Id_$id = Input_Permission_Init('$id', '".$m->interp->apply_escapes($description, 'js')."', ".($readonly ? 'true' : 'false').");\n";
%
<%shared>
# elenco gruppi
my $sth = $Session{Dbh}->prepare(q|select id, nome from gruppi order by nome|);
$sth->execute();
my $groups = $sth->fetchall_arrayref;
 
# elenco permessi
$sth = $Session{Dbh}->prepare(q|select id, nome from autorizzazioni order by nome|);
$sth->execute();
my $permissions = $sth->fetchall_arrayref;
undef $sth;
</%shared>
/tags/2.0/htdocs/input/COPYRIGHT
0,0 → 1,10
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
/tags/2.0/htdocs/input/input.comp
0,0 → 1,168
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
#
# richiamata dai componenti per inglobare il codice in comune
</%doc>
<%method LIBRARY>\
/input/input.js
</%method>
<%init>
LoadHeader 'SELF';
</%init>
<%args>
</%args>
<%once>
 
# filtra la stringa sostituendo i caratteri speciali che non possono essere messi tra ""
# come parametro di un TAG Html (es <input ... mytag="may text to filter" >
sub Tag_filter($){
$_ = $m->interp->apply_escapes($_[0], 'h');
s/\n/&#13;/sg;
return $_;
}
 
# Individua tra i parametri passati al metodo che chiama la funzione
# (normalmente è /input/xxx.comp) i parametri non dichiarati esplicitamente nel metodo
# combina i parametri dichiarati nella hash passata alla funzione con i parametri passati al metodo
# costruisce quindi una stringa di parametri del tipo
# parametro1="xxxxxx" parametro2="yyy y y yy " ...
# che viene restituita.
# per mettere davanti, dietro o sovrascrivere le definizioni passate al metodo, rispetto a quelle stabilite nell'oggetto
# valgono le seguenti regole:
# tag => 'bla bla bla' testo accodato
# tag => '|bla bla bla' testo accodato
# tag => 'bla bla bla|' testo davanti
# tag => '|bla bla bla|' testo sostituito
# tag => undef tag eliminato, anche se passato
#
sub Args2HtmlTaglist {
my %taglist = @_;
my $args = $m->caller_args(0);
my $declared = $m->current_comp->declared_args;
my $tags='';
foreach my $arg ( keys %{$args}){
if(!defined $declared->{'$'.$arg} && !defined $declared->{'@'.$arg} && !defined $declared->{'%'.$arg}){
my $str = $args->{$arg};
if(defined $taglist{$arg}){
if($str =~ m/^\|(.*)\|$/s){
$tags.=$arg.'="'.Tag_filter($1).'" ';
}elsif($str =~ m/(.*)\|$/s){
$tags.=$arg.'="'.Tag_filter($1.$taglist{$arg}).'" ';
}elsif($str =~ m/^\|(.*)/s){
$tags.=$arg.'="'.Tag_filter($taglist{$arg}.$1).'" ';
}else{
$tags.=$arg.'="'.Tag_filter($taglist{$arg}.$str).'" ';
}
delete $taglist{$arg};
}elsif(exists $taglist{$arg}){
# allora il tag è undefined
delete $taglist{$arg};
}else{
$str =~ s/^\|//;
$str =~ s/\|$//;
$tags.=$arg.'="'.Tag_filter($str).'" ';
}
}
}
foreach my $arg ( keys %taglist){
$tags.=$arg.'="'.Tag_filter($taglist{$arg}).'" ';
}
return $tags;
}
 
 
# Individua tra i parametri passati al metodo che chiama la funzione
# (normalmente è /input/xxx.comp) i parametri dichiarati esplicitamente nel metodo
# combina i parametri dichiarati nella hash passata alla funzione con i parametri passati al metodo
# costruisce quindi una stringa di parametri del tipo
# parametro1="xxxxxx" parametro2="yyy y y yy " ...
# che viene restituita.
# per mettere davanti, dietro o sovrascrivere le definizioni passate al metodo, rispetto a quelle stabilite nell'oggetto
# valgono le seguenti regole:
# tag => 'bla bla bla' testo accodato
# tag => '|bla bla bla' testo accodato
# tag => 'bla bla bla|' testo davanti
# tag => '|bla bla bla|' testo sostituito
# tag => undef tag compreso
#
sub ArgsOnly2HtmlTaglist {
my %taglist = @_;
my $args = $m->caller_args(0);
my $declared = $m->current_comp->declared_args;
my $tags='';
foreach my $arg ( keys %taglist){
my $str = $args->{$arg};
if(defined $str){
if(!defined $declared->{'$'.$arg} && !defined $declared->{'@'.$arg} && !defined $declared->{'%'.$arg}){
if($str =~ m/^\|(.*)\|$/s){
$tags.=$arg.'="'.Tag_filter($1).'" ';
}elsif($str =~ m/(.*)\|$/s){
$tags.=$arg.'="'.Tag_filter($1.$taglist{$arg}).'" ';
}elsif($str =~ m/^\|(.*)/s){
$tags.=$arg.'="'.Tag_filter($taglist{$arg}.$1).'" ';
}else{
$tags.=$arg.'="'.Tag_filter($taglist{$arg}.$str).'" ';
}
}
}else{
if(defined $taglist{$arg}){
$tags.=$arg.'="'.Tag_filter($taglist{$arg}).'" ';
}
}
}
return $tags;
}
 
# Individua tra i parametri passati al metodo che chiama la funzione
# (normalmente è /input/xxx.comp) i parametri dichiarati esplicitamente nel metodo
# combina i parametri dichiarati nella hash passata alla funzione con i parametri passati al metodo
# costruisce quindi una stringa di parametri del tipo
# Obj.parametro1 = function "xxxxxx";
# Obj.parametro2 = function "yyy y y yy " ...
#
# che viene restituita.
# per mettere davanti, dietro o sovrascrivere le definizioni passate al metodo, rispetto a quelle stabilite nell'oggetto
# valgono le seguenti regole:
# tag => 'bla bla bla' testo accodato
# tag => '|bla bla bla' testo accodato
# tag => 'bla bla bla|' testo davanti
# tag => '|bla bla bla|' testo sostituito
# tag => undef tag compreso
#
sub ArgsOnly2JscriptTaglist {
my $Obj = shift;
my %taglist = @_;
my $args = $m->caller_args(0);
my $declared = $m->current_comp->declared_args;
my $jscript='';
foreach my $arg ( keys %taglist){
my $str = $args->{$arg};
if(defined $str){
if(!defined $declared->{'$'.$arg} && !defined $declared->{'@'.$arg} && !defined $declared->{'%'.$arg}){
if($str =~ m/^\|(.*)\|$/s){
$jscript .= "$Obj.$arg = function(){\n$1\n};\n";
}elsif($str =~ m/(.*)\|$/s){
$jscript .= "$Obj.$arg = function(){\n$1".$taglist{$arg}."\n};\n";
}elsif($str =~ m/^\|(.*)/s){
$jscript .= "$Obj.$arg = function(){\n".$taglist{$arg}."$1\n};\n";
}else{
$jscript .= "$Obj.$arg = function(){\n".$taglist{$arg}."$str\n};\n";
}
}
}else{
if(defined $taglist{$arg}){
$jscript .= "$Obj.$arg = function(){\n".$taglist{$arg}."\n};\n";
}
}
}
return $jscript;
}
 
</%once>
/tags/2.0/htdocs/input/radio.js
0,0 → 1,16
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Radio_Init(Objname, Descr){
var Obj = Input_Init(Objname, Descr);
Obj.set_status();
return Obj;
}
/tags/2.0/htdocs/input/span.js
0,0 → 1,39
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
function Input_Span_Init(Objname, Descr, DispTemplate, EmptyDescr, Value){
var Obj = Input_Init(Objname, Descr);
Obj.DispTemplate = DispTemplate;
Obj.DisplayDescr = Obj;
Obj.EmptyDescr = EmptyDescr;
// inizializza il valore del campo selezionato
Obj.set_value = function (value, param){
%#DEBUG <% $JSLogger->debug(q|'Input_Span_Init.set_value value:"'+value+'" param:"'+param+'"'|) %>
Obj.Value = value;
if(param != null && param.length != 0){
this.set_param(param);
}else{
this.Parameters = null;
this.set_display();
}
}
Obj.set_value(Value);
// metodo per la lettura del valore del componente
Obj.get_value = function (){
return this.Value;
}
Obj.Readonly = function(){return true};
Obj.set_status('');
Obj.setFocus = null;
return Obj;
}
 
 
/tags/2.0/htdocs/test/test_callRemote.mql
0,0 → 1,9
 
<%method CALL_REMOTE_test_callRemote>
<%args>
$par1
$par2
</%args>
par1 = <% $par1 %><br>
par2 = <% $par2 %>
</%method>
/tags/2.0/htdocs/test/dojo/rest/dhandler
0,0 → 1,62
<%args>
</%args>
<%flags>
inherit => undef
</%flags>
<%init>
use Data::Dumper;
my $schema;
my $table;
my $id;
my $arg = $m->dhandler_arg;
if($arg =~ m|(\w+)/(\w+)/(\w+)|){
$schema = $1;
$table = $2;
$id = $3;
}elsif($arg =~ m|(\w+)/(\w+)/{0,1}|){
$schema = $1;
$table = $2;
}else{
die "URI malformed use /schema/table/id\n";
}
my $url = $r->dir_config('DataBaseUrl')."/$schema/$table.mql";
my $method = $r->method();
my $size = $r->headers_in->{'Content-length'};
my $content;
$r->read($content, $size);
if($method =~ /POST|PUT|DELETE/i){
$method = lc $method;
}
# Si veda http://www.ietf.org/rfc/rfc2616.txt
# POST --> create
# PUT --> update
# DELETE --> delete
# GET --> retrieve N.B. metodo 'select' era già utilizzato per altri scopi
if($method eq 'POST'){
$ARGS{method} = 'create';
}elsif($method eq 'PUT'){
$ARGS{method} = 'update';
}elsif($method eq 'DELETE'){
$ARGS{method} = 'delete';
}else{
$ARGS{method} = 'retrieve';
}
if(exists $ENV{HTTP_CONTENT_RANGE} && $ENV{HTTP_CONTENT_RANGE} =~ m/(\d+)-(\d+|\**)/){
my $start = $1 || 0;
$ARGS{'start'} = $start;
my $stop = $2;
if(defined $stop && $stop ne '*' && $stop ne ''){
$ARGS{'rows'} = $stop - $start + 1;
}
}
</%init>
% print STDERR "ARGS: $schema $table $id\n";
% print STDERR "URL: $url\n";
% print STDERR Dumper(\%ARGS);
% print STDERR "_______________CONTENT_______________\n\n";
% print STDERR $content;
% print STDERR "\n______________________________________\n";
<%perl>
$m->subexec($url, %ARGS, envelope_response => 'xml', envelope_request => 'xml', CRUD => 'crud');
#$m->subexec($url, %ARGS, envelope_response => 'xml', envelope_request => 'xml', CRUD => 'crud');
</%perl>
/tags/2.0/htdocs/test/dojo/test_dojo_tree_data.html
0,0 → 1,296
<%doc>
http://dojotoolkit.org/documentation/tutorials/1.6/store_driven_tree/
http://dojotoolkit.org/reference-guide/dojo/store/JsonRest.html
http://download.dojotoolkit.org/release-1.5.0/dojo-release-1.5.0/dijit/tests/tree/test_Tree_DnD.html
http://dojotoolkit.org/reference-guide/dijit/Tree.html
</%doc>
% &LoadHeader($Session{'Dojo_dir'}.'/dojox/form/resources/UploaderFileList.css');
% &LoadHeader('/test/dojo/test_dojo_tree_data.css');
<script>
dojo.require("dojo.store.JsonRest");
dojo.require("dojo.store.Observable");
dojo.require("dijit.Menu");
dojo.require("dijit.Tree");
dojo.require("dijit.TooltipDialog");
dojo.require("dijit.tree.dndSource");
dojo.require("dojox.form.Uploader");
dojo.require("dojox.form.uploader.plugins.HTML5");
dojo.require("dojox.form.uploader.FileList");
dojo.ready(function(){
Store = dojo.store.JsonRest({
target: "/test/dojo/test_dojo_tree_data/impianti/apparecchiature/1",
root: '/',
mayHaveChildren: function(object){
return object.children != null;
},
getChildren: function(object, onComplete, onError){
// retrieve the full copy of the object
this.get(object.id).then(function(fullObject){
// copy to the original object so it has the children array as well.
object.children = fullObject.children;
// now that full object, we should have an array of children
onComplete(fullObject.children);
}, function(error){
alert('ERROR:' + error.message)
// an error occurred, log it, and indicate no children
console.error(error);
onComplete([]);
});
},
getRoot: function(onItem, onError){
// get the root object, we will do a get() and callback the result
this.get(this.root).then(onItem, onError);
},
getLabel: function(object){
// just get the name
return object.name;
},
pasteItem: function(child, oldParent, newParent, bCopy, insertIndex){
var dest_dir_id = this.mayHaveChildren(newParent) ? newParent.id : newParent.id.replace(/\/[^\/]*$/, '');
if(oldParent.id == dest_dir_id){
return false;
}
// comunico al server lo spostamento
child.new_id = dest_dir_id + '/' + child.id.replace(/^.*\//, '');
child.children = null;
var store = this;
store.put(child).then(function(){
// aggiorno la cartella nell'albero
store.get(dest_dir_id).then(function(dir){
store.onChange(dir);
store.onChildrenChange(dir, dir.children);
});
store.get(oldParent.id).then(function(dir){
store.onChange(dir);
store.onChildrenChange(dir, dir.children);
});
});
},
put: function(object, options){
// fire the onChildrenChange event
this.onChildrenChange(object, object.children);
// fire the onChange event
this.onChange(object);
// execute the default action
return dojo.store.JsonRest.prototype.put.apply(this, arguments);
},
remove: function(id){
var store = this;
var id_dir = id.replace(/\/[^\/]*$/, '');
dojo.store.JsonRest.prototype.remove.apply(this, arguments).then(function(){
// ritorna l'id della directory che conteneva il file cancellato
store.get(id_dir).then(function(dir){
// notifico il cambiamento
store.onChange(dir);
store.onChildrenChange(dir, dir.children);
});
});
},
// we can also put event stubs so these methods can be
// called before the listeners are applied
onChildrenChange: function(parent, children){
// fired when the set of children for an object change
console.debug('onChildrenChange', parent, children)
},
onChange: function(object){
// fired when the properties of an object change
console.debug('onChange', object);
}
});//Store
 
var tree = new dijit.Tree({
model: Store,
autoExpand: false,
openOnClick: true,
showRoot: true, //false,
// define the drag-n-drop controller
dndController: dijit.tree.dndSource
}, "demo_tree"); // make sure you have a target HTML element with this id
tree.close_popups = function () {
// chiudo e svuoto i pannelli aperti
dijit.popup.close(dijit.byId('tree_dialog'));
dijit.popup.close(dijit.byId('delete_dialog'));
dijit.popup.close(dijit.byId('upload_dialog'));
dijit.byId('files').reset();
// console.debug('close_popups');
}
tree.onClick = function () {
this.close_popups();
// console.debug('Click tree');
};
tree.onDblClick = function (item) {
this.close_popups();
if(!item.children){
this.download_item(item, 'download');
console.debug('download ...');
}
};
tree.onClose = tree.close_popups;
tree.onOpen = tree.close_popups;
tree.startup();
 
var menu = dijit.byId("tree_menu");
// when we right-click anywhere on the tree, make sure we open the menu
menu.bindDomNode(tree.domNode);
var TreeObj;
dojo.connect(menu, "_openMyself", this, function(e) {
TreeObj = e.target;
// get a hold of, and log out, the tree node that was the source of this open event
var tn = dijit.getEnclosingWidget(e.target);
console.debug('dijit.getEnclosingWidget:', tn.item.id, tn);
// mostro le voci del menu compatibili
var children = menu.getChildren();
children.forEach(function(i) {
if(i.id == 'rename' || i.id == 'delete')
i.set('style', {'display': tn.indent > 0 ? '' : 'none'});
if(i.id == 'new_folder' || i.id == 'upload')
i.set('style', {'display': tn.item.children ? '' : 'none'});
if(i.id == 'download')
i.set('style', {'display': tn.item.children ? 'none' : ''});
});
});
menu.open_dialog = function() {
var id_cmd = dijit.getEnclosingWidget(this).id;
var tree_dialog = dijit.byId('tree_dialog');
// comando: rename / new_folder
tree_dialog.id_cmd = id_cmd;
// nome del file
dojo.byId('tree_dialog_name').value = id_cmd == 'rename' ? dijit.getEnclosingWidget(TreeObj).item.name : '';
dojo.byId('tree_dialog_btn').innerHTML = id_cmd == 'rename' ? 'Rinomina' : 'Nuova cartella';
dijit.popup.open({
popup: tree_dialog,
around: TreeObj
});
};
menu.close_dialog = function() {
var tree_dialog = dijit.byId('tree_dialog');
var new_name = dojo.byId('tree_dialog_name').value
var item = dijit.getEnclosingWidget(TreeObj).item;
// verifico che nel nome non ci siano alcuni caratteri speciali
var forbidden_chars = [];
['*', '<', '>', '#', '?', '/', '\\', '"', "'"].forEach(function (c){
if(new_name.indexOf(c) != -1){
forbidden_chars.push(c);
}
});
if(forbidden_chars.length){
if(forbidden_chars.length == 1){
alert('Il carattere (' + forbidden_chars[0] + ') non può essere utilizzato nel nome');
}else{
alert('I caratteri (' + forbidden_chars.join(', ') + ') non possono essere utilizzati nel nome');
}
return false;
}
if(tree_dialog.id_cmd == 'rename'){
console.debug('rename', new_name, item);
item.name = new_name;
Store.put(item).then(function(){
var id_dir = item.id.replace(/\/[^\/]*$/, '');
Store.get(id_dir).then(function(dir){
// notifico il cambiamento
Store.onChange(dir);
Store.onChildrenChange(dir, dir.children);
});
});
}else{
console.debug('new_folder', new_name, item);
var id_dir = dijit.getEnclosingWidget(TreeObj).item.id;
Store.add({ new_name:new_name, id:id_dir + '/' + new_name, children:1 }).then(function (){
// aggiorno la cartella nell'albero
Store.get(id_dir).then(function(dir){
Store.onChange(dir);
Store.onChildrenChange(dir, dir.children);
});
});
}
%#// console.debug('close_dialog', this);
dijit.popup.close(tree_dialog);
};
dojo.connect(dojo.byId('rename'), 'onclick', menu.open_dialog);
dojo.connect(dojo.byId('new_folder'), 'onclick', menu.open_dialog);
dojo.connect(dojo.byId('delete'), 'onclick', function() {
dijit.popup.open({
popup: dijit.byId('delete_dialog'),
around: TreeObj
});
});
dojo.connect(dojo.byId('upload'), 'onclick', function() {
var upload_dialog = dijit.byId('upload_dialog');
dojo.byId('upload_dir').value = 'impianti/apparecchiature/1' + dijit.getEnclosingWidget(TreeObj).item.id;
dijit.popup.open({
popup: upload_dialog,
around: TreeObj
});
});
 
// eventi del caricamento dei file
dojo.connect(dijit.byId('uploader'), 'onComplete', function(params) {
console.debug('uploader onComplete', unescape(dojo.toJson(params)));
dijit.byId('demo_tree').close_popups();
var dir = dijit.getEnclosingWidget(TreeObj).item.id;
Store.get(dir).then(function(dir){
Store.onChange(dir);
Store.onChildrenChange(dir, dir.children);
});
});
dojo.connect(dijit.byId('uploader'), 'onError', function(params) {
console.debug('uploader onError', dojo.toJson(params));
});
 
// richiamato dalla combo
tree.download_item = function (item, mode) {
var id_file = item ? item.id : dijit.getEnclosingWidget(TreeObj).item.id;
console.debug('download item', id_file);
var params = 'toolbar=no,location=no,status=no,menubar=no,scrollbars=yes,resizable,alwaysRaised,dependent,titlebar=no,width=800,height=600';
var url = Store.target + id_file + '?' + mode;
window.open(url, '_blank', params);
}
// richiamato alla conferma della cancellazione del file/dir
tree.delete_item = function (item) {
var id_file = item ? item.id : dijit.getEnclosingWidget(TreeObj).item.id;
console.debug('delete item', id_file);
// cancello il file nello store remoto
Store.remove(id_file); // N.B. La chiamata originale non permette di gestire il timeout
dijit.popup.close(dijit.byId('delete_dialog'));
}
 
});//dojo.ready
 
</script>
<h1>Demo: File Store</h1>
<div id="demo_tree"></div>
<div style="display:none">
<div dojoType="dijit.Menu" id="tree_menu">
<div id="download" dojoType="dijit.MenuItem" onClick="dijit.byId('demo_tree').download_item(null, 'save');">Scarica sul PC</div>
<div id="rename" dojoType="dijit.MenuItem">Rinomina</div>
<div id="upload" dojoType="dijit.MenuItem" >Carica nel server</div>
<div id="new_folder" dojoType="dijit.MenuItem">Nuova cartella</div>
<div id="delete" dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconDelete">Cancella</div>
</div>
<div data-dojo-type="dijit.TooltipDialog" id="tree_dialog">
<input id="tree_dialog_name" type="text" style="width:300px;"></input>
<button id="tree_dialog_btn" onclick="dijit.byId('tree_menu').close_dialog();" dojoType="dijit.form.Button">OK</button>
<button onclick="dijit.popup.close(dijit.byId('tree_dialog'))" dojoType="dijit.form.Button">Annulla</button>
</div>
<div data-dojo-type="dijit.TooltipDialog" id="delete_dialog">
<div>Sei certo di voler cancellare?</div><br>
<button id="delete_dialog_btn" onclick="dijit.byId('demo_tree').delete_item();" dojoType="dijit.form.Button">Cancella</button>
<button onclick="dijit.popup.close(dijit.byId('delete_dialog'))" dojoType="dijit.form.Button">Annulla</button>
</div>
<div data-dojo-type="dijit.TooltipDialog" id="upload_dialog">
<form method="post" action="test_dojo_tree_data/upload.mason" id="upload_form" enctype="multipart/form-data" style="width:420px;">
<fieldset>
<legend>Carica nel server</legend>
<input class="browseButton" name="uploadedfile" multiple="true" type="file" style="width:140px;"
force="iframe" dojoType="dojox.form.Uploader" label="Selezionare i file" id="uploader" />
<input type="button" id="remBtn" label="Clear" onClick="dijit.byId('files').reset();" dojoType="dijit.form.Button" />
<input type="hidden" id="upload_dir" name="upload_dir" />
<input type="submit" label="Submit" dojoType="dijit.form.Button" />
<button onclick="dijit.byId('files').reset();dijit.popup.close(dijit.byId('upload_dialog'))" dojoType="dijit.form.Button">Annulla</button>
<div id="files" dojoType="dojox.form.uploader.FileList" uploaderId="uploader"></div>
</fieldset>
</form>
</div>
</div>
 
/tags/2.0/htdocs/test/dojo/test_dojo_events.html
0,0 → 1,23
<%args>
</%args>
Test Events:
<hr/>
<script>
require(["dojo/ready", "dijit/registry", "dojo/on", "dojo/Evented", "dojo/dom-construct", "dojo/json"],
function(ready, registry, on, Evented, domConstruct, JSON){
ready(function(){
on(registry.byId('eventBtn'), 'click', function(evt){
masonSql.ready({pinco: 'pallo'});
});
 
masonSql.on('ready', function(data){
console.log('Event masonSql ready data:', data);
});
masonSql.on('ready', function(data){
domConstruct.place("<br>Event masonSql ready data:"+JSON.stringify(data), "print_area");
});
});
});
</script>
<button data-dojo-type="dijit/form/Button" id="eventBtn" data-dojo-props="" type="button">Fire event myevent</button>
<div id="print_area"></div>
/tags/2.0/htdocs/test/dojo/test_dojo_Select_JsonRest.html
0,0 → 1,55
% my $id = 'select_';
% my $key = 'id';
% my $key_set = "4";
<html>
<h2>test Dojo Select with dojo/store/JsonRest</h2>
<br>
S1:<div id="<% $id %>1" style="width: 150px;" data-dojo-type="dijit/form/Select"
data-dojo-props="searchAttr:'<% $key %>', labelAttr:'nome', title:'Select S1'"></div>
<script>
masonSql.once('ready', function(data){
require(["dojo/ready", "dijit/registry", "dijit/form/Select", "dojo/store/JsonRest", "dojo/store/Observable"],
function(parser, registry, Select, JsonRest, Observable){
var restStore = new JsonRest({
target: '/rest/public/anagrafiche',
idProperty: '<% $key %>',
sortParam: "sortBy"
});
var observableStore = Observable(restStore);
window.observableStore = observableStore;
registry.byId('<% $id %>1').setStore(observableStore, 'admin2');
});
});
</script>
<br>
<br>
<button onclick="window.Id_<% $id %>1.set_value(<% $key_set %>);">Set S1 with <% $key %>:<% $key_set %></button>
<button onclick="document.getElementById('contenuto').value = window.Id_<% $id %>1.get_value();" >Get S1</button>:<input id="contenuto"></input>
<button onclick="window.Id_<% $id %>1.Readonly(true);">Readonly S1</button>
<button onclick="window.Id_<% $id %>1.Readonly(false);">No readonly S1</button>
<br>
<br>
<script>
require(["dojo/dom", "dijit/registry", "dojo/_base/array", "dojo/on", "dojo/_base/event"], function (dom, registry, array, on, event){
masonSql.once('ready', function(data){
var Obj = registry.byId('<% $id %>1');
Obj.get_value = function(){
return this.get('value');
};
Obj.set_value = function(value){
this.set('value', value);
return value;
};
Obj.Readonly = function(read){
if(read == null){
return this.get('readOnly');
}else{
this.set('readOnly', read);
return read;
}
};
window.Id_<% $id %>1 = Obj;
});
});
</script>
</html>
/tags/2.0/htdocs/test/dojo/test_ContentPane_href.html
0,0 → 1,62
<%args>
$timeout => undef
</%args>
% if($timeout){
% sleep $timeout;
<span class='dijitInline dijitIconBookmark'></span>Risposta dal server con ritardo di <% $ timeout%> secondi.
% }else{
Test timeout in dojox/layout/ContentPane utilizzando l'attibuto <b>href</b>
<script>
require([
"dijit/dijit",
"dojo/parser",
"dojox/layout/ContentPane"
]);
</script>
<hr/>
% for(my $N=4; $N; $N--){
<div data-dojo-type="dojox.layout.ContentPane" id="test_xhr_timeout_container<% $N %>"
parseOnLoad="true" loadingMessage="<span class='dijitInline dijitIconTask'></span>Sto caricando 1 ..."
executeScripts="true" extractContent="true" title="Panel di test - download" doLayout="false"
style="margin-left: 24px; width: 580px; height: 30px; padding: 10px;
background-color: rgb(<% 200 - $N *10 %>,230,<% 200 + $N *10 %>);" ></div>
% }
<script>
window.launch_download = function(id, timeout){
require(["dojo/ready", "dijit/registry"], function(ready, registry){
ready(function(){
var container = registry.byId(id);
container.set('ioArgs', {
timeout: timeout * 1000 // millisecondi
});
container.set('href', '<% $ENV{SCRIPT_NAME}%>?timeout=3').then(
function(){
console.log("OK! downloaded")
},
function(err){
container.set('errorMessage', "<span class='dijitContentPaneError'>"+
"<span class='dijitInline dijitIconError'></span>"+err+' id:'+container.id+' timeout:'+timeout+"</span>");
console.log("ERRORE:"+err+' id:'+container.id+' timeout:'+timeout);
}
)
});
});
};
require(["dojo/ready", "dijit/registry", "dojo/dom-construct"], function(ready, registry, domConstruct){
ready(function(){
% for(my $N=4; $N; $N--){
registry.byId('test_xhr_timeout_container<% $N %>').watch(function(name, oldValue, value){
// Do something based on the change
var log = 'CHANGE container <% $N %> ATTRIB '+name+' from val:['+oldValue+'] to val:['+value+']'
console.log(log);
domConstruct.place('<div>'+log+'</div>', 'LAST', 'after')
});
% }
});
});
% for(my $N=4; $N; $N--){
window.launch_download('test_xhr_timeout_container<% $N %>', <% $N %>);
% }
</script>
<hr id="LAST"/>
% } # if($timeout)
/tags/2.0/htdocs/test/dojo/test_dojo_PopupMenuItem.html
0,0 → 1,37
<%doc>
</%doc>
<script>
dojo.require("dijit.Menu");
dojo.ready(function(){
 
var menu = dijit.byId("tree_menu");
});
</script>
<h1>Demo: PopupMenuItem</h1>
<div dojoType="dijit.Menu" id="tree_menu">
<div id="delete" dojoType="dijit.MenuItem" onClick="my_alert('Cancella');" iconClass="dijitEditorIcon dijitEditorIconDelete">Cancella</div>
<div id="rename_file" dojoType="dijit.PopupMenuItem">
<span>Rinomina</span>
<div data-dojo-type="dijit.TooltipDialog" data-dojo-props="title:'Rinomina'" id="rename_file_dialog">
<input id="rename_file_name" type="text" style="width:300px;"></input>
<button onclick="dijit.popup.close(dijit.byId('rename_file_dialog'));">Rinomina</button>
<script type="dojo/method" event="onOpen">
console.debug('Open rename_file_dialog');
</script>
</div>
</div>
<div dojoType="dijit.MenuItem" onClick="my_alert('Download');">Scarica sul PC</div>
<div id="upload" dojoType="dijit.MenuItem" onClick="my_alert('Carica nel server');">Carica nel server</div>
<div id="new" dojoType="dijit.PopupMenuItem" >
<span>Nuova cartella</span>
<div data-dojo-type="dijit.TooltipDialog" data-dojo-props="title:'Nuova cartella'" id="new_folder_dialog">
<input id="new_name" type="text" style="width:300px;"></input>
<button onclick="dijit.popup.close(dijit.byId('new_folder_dialog'));">Nuova cartella</button>
<script type="dojo/method" event="onOpen">
console.debug('Open new_folder_dialog');
</script>
</div>
</div>
</div>
/tags/2.0/htdocs/test/dojo/test_dojo_Select.html
0,0 → 1,45
% my $id = 'select_1';
<html>
<h2>test Dojo Select</h2>
<script src="/input/input.comp?Ver=<% $Ver %>" type="text/javascript"></script>
<script src="/input/input.js?Ver=<% $Ver %>" type="text/javascript"></script>
<script>
require(["dojo/parser", "dijit/form/Select"]);
</script>
<div id="<% $id %>" data-dojo-type="dijit/form/Select" style="width:100px; height:28px;">
<span value="TN">Tennessee</span>
<span value="VA" selected="selected"><span class="dijitInline masonSqlIcons refresh"></span><font color="blue">Virginia</font></span>
<span value="WA">Washington</span>
<span type="separator"></span>
<span value="FL">Florida</span>
<span value="CA">California</span>
</div>
<hr>
<br>
<button onclick="window.Id_<% $id %>.set_value('FL');" >Set Florida</button>
<button onclick="document.getElementById('contenuto').value = window.Id_<% $id %>.get_value();" >Get</button>:<input id="contenuto"></input>
<button onclick="window.Id_<% $id %>.Readonly(true);">Disable</button>
<button onclick="window.Id_<% $id %>.Readonly(false);">Enable</button>
<script>
require(["dojo/dom", "dijit/registry", "dojo/_base/array", "dojo/on", "dojo/_base/event"], function (dom, registry, array, on, event){
masonSql.once('ready', function(data){
var Obj = registry.byId('<% $id %>');
Obj.get_value = function(){
return this.get('value');
};
Obj.set_value = function(value){
return this.set('value', value);
};
Obj.Readonly = function(read){
if(read == null){
return this.get('readOnly');
}else{
this.set('readOnly', read);
return read;
}
};
window.Id_<% $id %> = Obj;
});
});
</script>
</html>
/tags/2.0/htdocs/test/dojo/test_dojo_buttons.css
0,0 → 1,13
<%flags>
inherit => '/init.comp'
</%flags>
 
/* Test Bottoni di controllo */
 
/*
#bodyMasonSql.claro .dijitButton .dijitButtonNode
*/
 
#bodyMasonSql.claro .myTestBtn .dijitButtonNode {
padding: 10px;
}
/tags/2.0/htdocs/test/dojo/test_dojo_tree_data/upload.mason
0,0 → 1,77
<%doc>
Vedi: http://docs.dojocampus.org/dojox/form/Uploader
Esempio: /opt/masonsql/htdocs/lib/dojo-release-1.6.1-src/dojox/form/tests/UploadFile.php.disabled
</%doc>
<%flags>
inherit => undef
</%flags>
<%args>
$upload_dir
</%args>
<%once>
# use URI::Escape;
sub uri_escape { return $_[0]}
</%once>
<%perl>
$m->clear_buffer;
use Data::Dumper;
my $base_dir = $r->dir_config('DocumentRoot').'/test/dojo/test_dojo_tree_data/data';
my $dir = $base_dir.'/'.$upload_dir;
if(! -d $dir){
die "$dir not exists.\n";
}
my $table = $r->upload; # ritorna istanza APR::Request::Param::Table
# determino il tipo di download
my @key_files = keys %{$table};
my @value_files = values %{$table};
my $upload_type = $key_files[0]; # uploadedfileFlash, uploadedfiles[], uploadedfiles1|2|...
#DEBUG print STDERR "upload_type:$upload_type", Dumper(\@value_files);
#DEBUG $upload_type='uploadedfileFlash';
 
if($upload_type eq 'uploadedfileFlash'){
my $upload = $value_files[0];
#DEBUG print STDERR "uploadedfileFlash\n".Dumper($upload);
my $name = $upload->filename;
# verifico che il nome non contenga carateri proibiti, altrimenti li converto in '_'
$name =~ s/[\*<>#\?\/\\'"]/_/g;
my $file = $dir.'/'.$name;
if(-f $file){
unlink $file or die sprintf "delete '%s' failed: $!", $file;
}
if(! $upload->link($file)){
print STDERR "uploadedfileFlash link error $! \n";
die sprintf "link 1 from '%s' failed: $!", $upload->tempname;
}
#DEBUG print STDERR "uploadedfileFlash linked\n".Dumper($upload);
my $return_data = 'file='.uri_escape($upload_dir.'/'.$name).',name='.uri_escape($name).',type='.uri_escape($upload->type).',size='.$upload->size.',width=,height=';
#DEBUG print STDERR "return_data:|$return_data|\n";
$m->out($return_data);
}else{
my @dataObject;
foreach my $upload (@value_files){ # istanze Apache2::Upload
my $name = $upload->filename;
# verifico che il nome non contenga carateri proibiti, altrimenti li converto in '_'
$name =~ s/[\*<>#\?\/\\'"]/_/g;
my $file = $dir.'/'.$name;
if(-f $file){
unlink $file or die sprintf "delete '%s' failed: $!", $file;
}
$upload->link($file) or die sprintf "link 1 from '%s' failed: $!", $upload->tempname;
push @dataObject, {
'file' => $upload_dir.'/'.$name,
'name' => $name,
'type' => $upload->type,
'size' => $upload->size,
'width' => undef,
'height' => undef
};
}
if($upload_type eq 'uploadedfiles[]'){
# HTML5
$m->out(JSON::objToJson(\@dataObject));
}else{
# Iframe
$m->out('<textarea>'.JSON::objToJson(\@dataObject).'</textarea>');
}
}
</%perl>
/tags/2.0/htdocs/test/dojo/test_dojo_tree_data/dhandler
0,0 → 1,138
<%doc>
http://dojotoolkit.org/features/1.6/object-store
http://dojotoolkit.org/reference-guide/dojo/store/JsonRest.html
aptitude install libfile-path-perl
</%doc>
<%flags>
inherit => undef
</%flags>
<%once>
use JSON;
use IPC::Run qw(run);
use File::Path qw(make_path remove_tree);
</%once>
<%init>
my $base_dir = $r->dir_config('DocumentRoot')."/test/dojo/test_dojo_tree_data/data";
use Data::Dumper;
my $arg = $r->unparsed_uri; #$r->unparsed_uri; $arg =~ s|^/test/dojo/test_dojo_tree_data/||;
$arg =~ s|^/test/dojo/test_dojo_tree_data/||;
utf8::decode($arg);
my $mode_download;
# N.B. Si usa '.' in quanto non ci sarà mai nel nome delle cartelle il carattere '.' (schema del database)
if($arg =~ m/^(.*)\?(\w+)$/){
$arg = $1;
$mode_download = $2;
}
print STDERR 'CALL '.$r->method()." [$arg] mode:$mode_download\n";
</%init>
<%perl>
# $arg corriponde al file o cartella presente in $base_dir/
my($schema, $table, $id, $path) = split /\//, $arg, 4;
$base_dir .= "/$schema/$table/$id";
if(! -d $base_dir){
make_path $base_dir;
}
my $file = "$base_dir/$path";
$path = '/'.$path;
my $name = $path;
$name =~ s|^.*/||;
my $method = $r->method();
if($mode_download && $method eq 'GET'){ # ------------------------------------ GET download
die "$schema.$table:$id $path not exists" if(! -e $file);
my $filetype;
if($mode_download eq 'save'){
$filetype = 'application/octet-stream; charset=binary';
}else{
run ['/usr/bin/file', '--mime', '--brief', $file], '>', \$filetype || die "run: $!";
chomp $filetype;
}
print STDERR "DOWNLOAD [$mode_download: $filetype] $schema.$table:$id $path\n";
$r->content_type($filetype);
sysopen FILE, $file, 'O_RDONLY' || die "sysopen $file: $!";
my $buffer;
# leggo il file generato a blocchi di 64Kbyte
while(my $numchar = sysread FILE, $buffer, 2^16){
if(undef $numchar){
die "sysread $file: $!";
};
$m->out($buffer);
$m->flush_buffer;
}
return 200;
}elsif($method eq 'DELETE'){ # --------------------------------------------------- DELETE
die "$schema.$table:$id $path not exists" if(! -e $file);
if(-d $file){
# run ['/bin/rm', '-r', $file] || die "run: $!";
remove_tree $file || die "can't delete $path: $!";
}else{
unlink $file || die "can't delete $path: $!";
}
print STDERR "DELETED $schema.$table:$id $path\n";
return 200;
}elsif($method eq 'PUT'){ # ------------------------------------------------------ PUT
my $content; $r->read($content, $r->headers_in->{'Content-length'});
utf8::decode($content);
print STDERR "PUT $content\n";
my $obj = jsonToObj($content); # {"name":"newname","id":"public/anagrafiche/1/tre/oldname"}
# modifica del nome o creazione di una cartella?
if($obj->{'new_name'}){
print STDERR "CREATE DIR $schema.$table:$id $obj->{'id'}\n";
make_path $base_dir.'/'.$obj->{'id'};
return 200;
}else{
my $dir = $obj->{'id'};
$dir =~ s|[^/]*$||;
if($obj->{'name'} ne '' && $obj->{'name'} ne $name){
die "$path not exists" if(! -e $file);
$file = $base_dir.'/'.$obj->{'id'};
# verifico che il nome non contenga carateri proibiti, altrimenti li converto in '_'
$obj->{'name'} =~ s/[\*<>#\?\/\\'"]/_/g;
my $new = $base_dir.'/'.$dir.$obj->{'name'};
rename $file, $new || die "can't rename $obj->{'id'} to $obj->{'name'}: $!";
print STDERR "RENAMED $schema.$table:$id [$obj->{'id'}] to [$dir$obj->{'name'}]\n";
return 200;
}elsif($obj->{'new_id'}){
rename $base_dir.'/'.$obj->{'id'}, $base_dir.'/'.$obj->{'new_id'}
|| die "can't move $obj->{'id'} to $obj->{'new_id'}: $!";
print STDERR "MOVE $schema.$table:$id [$obj->{'id'}] to [$dir$obj->{'new_id'}]\n";
return 200;
}else{
print STDERR "UNDEFINED PUT\n";
return 400;
}
}
}elsif($method eq 'GET'){ # ---------------------------------------------------- GET
if(-d $file){
print STDERR "RETURN DIR $schema.$table:$id $path\n";
my @children;
my %dir_obj = ('name' => $name, 'id' => $path );
my $dir;
opendir($dir, $file) || die "can't opendir $schema.$table:$id $path: $!";
if($path eq '/'){
$path = '';
}
while(my $filename = readdir $dir){
utf8::decode($filename);
next if($filename eq '.' || $filename eq '..');
my %file_obj = ( 'name' => $filename, 'id' => "$path/$filename");
if(-d "$file/$filename"){
$file_obj{'children'} = 1;
}
push @children, \%file_obj;
}
closedir $dir;
# ordinamento con le cartelle in testa
my @sorted = sort { $b->{'children'} cmp $a->{'children'} || uc $a->{'name'} cmp uc $b->{'name'} } @children;
$dir_obj{'children'} = \@sorted;
print STDERR Dumper(\%dir_obj), objToJson(\%dir_obj);
$m->print(objToJson(\%dir_obj));
}else{
print STDERR "RETURN FILE $schema.$table:$id $path\n";
my %file_obj = ( 'name' => $name, 'id' => $path );
$m->out(objToJson(\%file_obj));
}
}else{ # ---------------------------------------------------------------------- POST, ecc.
$m->out("No method '$method' is provided");
exit 501;
}
</%perl>
/tags/2.0/htdocs/test/dojo/test_dojo_tree_data/prova
0,0 → 1,0
it
/tags/2.0/htdocs/test/dojo/test_dojo_Select_JsonRest_Cache.html
0,0 → 1,75
% my $id = 'select_';
% my $key = 'id';
% my $key_set = '4';
<html>
<h2>test Dojo Select with dojo/store/JsonRest</h2>
<br>
S1:<div id="<% $id %>1" style="width: 150px;" data-dojo-type="dijit/form/Select" data-dojo-props="labelAttr:'nome', title:'Select S1'"></div>
S2:<div id="<% $id %>2" style="width: 150px;" data-dojo-type="dijit/form/Select" data-dojo-props="labelAttr:'nome', title:'Select S2'"></div>
S3:<div id="<% $id %>3" style="width: 150px;" ></div>
<script>
masonSql.once('ready', function(data){
require(["dojo/ready", "dijit/registry", "dijit/form/Select", "dojo/store/Memory", "dojo/store/JsonRest", "dojo/store/Cache", "dojo/store/Observable"],
function(parser, registry, Select, Memory, JsonRest, Cache, Observable){
var restStore = new JsonRest({
target: '/rest/public/anagrafiche',
idProperty: '<% $key %>',
sortParam: "sortBy"
});
var memoryStore = new Memory({idProperty: '<% $key %>'});
var observableStore = Observable(memoryStore);
 
var myStore = new Cache(restStore, observableStore);
myStore.query();
 
registry.byId('<% $id %>1').setStore(observableStore);
registry.byId('<% $id %>2').setStore(observableStore);
var s3 = new Select({
store: observableStore,
maxHeight: 60,
labelAttr: 'nome',
title: 'Select S3',
style: 'width:100px;'
}, '<% $id %>3');
window.s3 = s3;
// var globali per debug
window.memoryStore = memoryStore;
window.observableStore = observableStore;
window.myStore = myStore;
});
});
</script>
<br>
<br>
<button onclick="window.Id_<% $id %>1.set_value('<% $key_set %>');">Set S1 with <% $key %>:<% $key_set %>)</button>
<button onclick="document.getElementById('contenuto').value = window.Id_<% $id %>1.get_value();" >Get S1</button>:<input id="contenuto"></input>
<button onclick="window.Id_<% $id %>1.Readonly(true);">Disable S1</button>
<button onclick="window.Id_<% $id %>1.Readonly(false);">Enable S1</button>
<br>
<br>
<script>
require(["dojo/dom", "dijit/registry", "dojo/_base/array", "dojo/on", "dojo/_base/event"], function (dom, registry, array, on, event){
masonSql.once('ready', function(data){
var Obj = registry.byId('<% $id %>1');
Obj.get_value = function(){
return this.get('value');
};
Obj.set_value = function(value){
this.set('value', value);
return value;
};
Obj.Readonly = function(read){
if(read == null){
return this.get('readOnly');
}else{
this.set('readOnly', read);
return read;
}
};
window.Id_<% $id %>1 = Obj;
});
});
</script>
</html>
/tags/2.0/htdocs/test/dojo/test_dojo_buttons.html
0,0 → 1,49
<%args>
</%args>
% &LoadHeader('/test/dojo/test_dojo_buttons.css');
Test Buttons:
<script>
require(["dojo/parser", "dijit/form/Button"]);
</script>
<hr/>
<button data-dojo-type="dijit/form/Button" class="myTestBtn" data-dojo-props="iconClass:'masonSqlIcons cancel', showLabel:false, title:'Annulla le modifiche'" type="button">Annulla</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn" data-dojo-props="iconClass:'masonSqlIcons refresh', showLabel:false, title:'Ricarica i dati dal server'" type="button">Aggiorna</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn myNav" data-dojo-props="iconClass:'masonSqlIcons rewind', showLabel:false, title:'Salta all\'inizio della selezione'" type="button">Primo</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn myNav" data-dojo-props="iconClass:'masonSqlIcons down', showLabel:false, title:'Salta alla scheda precedente'" type="button">Precedente</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn myNav" data-dojo-props="iconClass:'masonSqlIcons up', showLabel:false, title:'Salta alla scheda successiva'" type="button">Successivo</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn myNav" data-dojo-props="iconClass:'masonSqlIcons forward', showLabel:false, title:'Salta alla fine della selezione'" type="button">Ultimo</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn" data-dojo-props="iconClass:'masonSqlIcons delete', showLabel:false, title:'Cancella la scheda'" type="button">Cancella</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn" data-dojo-props="iconClass:'masonSqlIcons print', showLabel:false, title:'Stampa la scheda'" type="button">Stampa</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn" data-dojo-props="iconClass:'masonSqlIcons dup', showLabel:false, title:'Esporta nel formato XLS'" type="button">XLS</button>
<button data-dojo-type="dijit/form/Button" class="myTestBtn" data-dojo-props="iconClass:'masonSqlIcons goto', showLabel:false, title:'Salta alla posizione indicata'" type="button">Salta</button>
<hr/>
<button data-dojo-type="dijit/form/Button" id="disableBtn" data-dojo-props="" type="button">Disable buttons</button>
<button data-dojo-type="dijit/form/Button" id="labelBtn" data-dojo-props="" type="button">Enable labels</button>
<button data-dojo-type="dijit/form/Button" id="hiddenBtn" data-dojo-props="" type="button">Hidden navigations</button>
<script>
require(["dojo/ready", "dojo/query", "dijit/registry", "dojo/on"], function(ready, query, registry, on){
ready(function(){
on(registry.byId('disableBtn'), 'click', function(evt){
var disable = this.get('label') == 'Disable buttons';
this.set('label', (disable ? 'Enable' : 'Disable') + ' buttons' )
query(".myTestBtn").forEach(function(node, index, arr){
registry.byNode(node).set('disabled', disable);
});
});
on(registry.byId('labelBtn'), 'click', function(evt){
var enable = this.get('label') == 'Enable labels';
this.set('label', (enable ? 'Disable' : 'Enable') + ' labels' )
query(".myTestBtn").forEach(function(node, index, arr){
registry.byNode(node).set('showLabel', enable);
});
});
on(registry.byId('hiddenBtn'), 'click', function(evt){
var hidden = this.get('label') == 'Hidden navigations';
this.set('label', (hidden ? 'Show' : 'Hidden') + ' navigations' )
query(".myNav").forEach(function(node, index, arr){
registry.byNode(node).set('style', {display: hidden ? 'none' : ''});
});
});
});
});
</script>
/tags/2.0/htdocs/test/dojo/test_dojo_Dialog.html
0,0 → 1,62
<h1>Demo: dojox/widget/DialogSimple</h1>
 
<script>
// Dialog Edit
 
// il mio dialogo di test
var myDialog;
 
// Apre un form con maggiore dettaglio del record indicato (row: riga del record)
function openDialog(dimX, dimY, title, url){
dimX = dimX || 640;
dimY = dimY || 480;
require(["dojo/io-query", "dojox/widget/DialogSimple", "dojo/dom-construct", "dojo/dom-style"], function(ioQuery, DialogSimple, domConstruct, domStyle){
if(!myDialog){
myDialog = new DialogSimple({
title: title,
executeScripts: true,
renderStyles: true,
scriptHasHooks: true,
parseOnLoad: true,
cleanContent: true,
closable: false,
ioArgs: {
headers: {
'MasonSql-body': '1'
},
timeout: <% $r->dir_config('GetFormTimeout') %>
},
onLoad: function(){
domStyle.set(myDialog.containerNode, 'height', (myDialog.Height - myDialog.titleBar.offsetHeight - 6) + 'px');
}
});
myDialog.containerNode.style.padding = '2px 2px';
domConstruct.place('<% q{
<span style="float:right;">
<button tabindex="-1" onclick="myDialog.hide()">Annulla</button>
</span>
} |js%>', myDialog.titleBar, 2 /* seconda posizione */);
}else{
myDialog.set('content', '');
}
myDialog.Height = dimY;
myDialog.set('style', 'width:' + dimX + 'px; height:' + dimY + 'px;');
myDialog.show();
 
myDialog.set('href', url).then(
function(){
console.debug('downloaded href' + url, myDialog);
},
function(err){
tab.set('errorMessage', "<span class='dijitContentPaneError'>"+
"<span class='dijitInline dijitIconError'></span>"+err+' id:'+myDialog.id+' timeout:'+<% $r->dir_config('GetFormTimeout') %>+"</span>");
console.error('ERROR href ' + url, err , myDialog);
}
);
});
}
</script>
 
<button onclick="openDialog(800, 600, 'form 800x600', '/test/test_string.html')">form 800x600</button>
<button onclick="openDialog(640, 320, 'form 640x320', '/test/test_number.html')">form 640x320</button>
<button onclick="openDialog(1000, 200, 'form 1000x200', '/test/test_date.html')">form 1000x200</button>
/tags/2.0/htdocs/test/dojo/test_dojo_uppercase.html
0,0 → 1,29
 
%# &LoadHeader('/test/dojo/test_dojo_???.css');
 
<script>
dojo.require("dijit.form.TextBox");
dojo.require("dojo.parser");
dojo.addOnLoad(function(){
dojo.parser.parse();
var box0 = dijit.byId("value0Box");
var box1 = dijit.byId("value1Box");
box1.set("value", box0.get("value").toUpperCase());
dojo.connect(box0, "onChange", function(){
box0.set("value", box0.get("value").toUpperCase());
box1.set("value", box0.get("value").toUpperCase());
});
});
</script>
 
<h2>test Dojo Toolkit - onChange event</h2>
 
<label for="value0Box">A textbox with a value:</label>
<input id="value0Box" data-dojo-type="dijit.form.TextBox" value="Some value" data-dojo-props="intermediateChanges:true"></input>
<br>
<br>
<label for="value1Box">A textbox set with Upper value<br>from the above textbox:</label>
<input id="value1Box" data-dojo-type="dijit.form.TextBox"></input>
<br>
/tags/2.0/htdocs/test/dojo/test_dojo_tree.json
0,0 → 1,46
{
identifier: 'id',
label: 'name',
items: [
{ id: 'AF', name:'Africa', type:'continent', population:'900 million', area: '30,221,532 sq km',
timezone: '-1 UTC to +4 UTC',
children:[{_reference:'EG'}, {_reference:'KE'}, {_reference:'SD'}] },
{ id: 'EG', name:'Egypt', type:'country' },
{ id: 'KE', name:'Kenya', type:'country',
children:[{_reference:'Nairobi'}, {_reference:'Mombasa'}] },
{ id: 'Nairobi', name:'Nairobi', type:'city' },
{ id: 'Mombasa', name:'Mombasa', type:'city' },
{ id: 'SD', name:'Sudan', type:'country',
children:{_reference:'Khartoum'} },
{ id: 'Khartoum', name:'Khartoum', type:'city' },
{ id: 'AS', name:'Asia', type:'continent',
children:[{_reference:'CN'}, {_reference:'IN'}, {_reference:'RU'}, {_reference:'MN'}] },
{ id: 'CN', name:'China', type:'country' },
{ id: 'IN', name:'India', type:'country' },
{ id: 'RU', name:'Russia', type:'country' },
{ id: 'MN', name:'Mongolia', type:'country' },
{ id: 'OC', name:'Oceania', type:'continent', population:'21 million',
children:{_reference:'AU'}},
{ id: 'AU', name:'Australia', type:'country', population:'21 million'},
{ id: 'EU', name:'Europe', type:'continent',
children:[{_reference:'DE'}, {_reference:'FR'}, {_reference:'ES'}, {_reference:'IT'}] },
{ id: 'DE', name:'Germany', type:'country' },
{ id: 'FR', name:'France', type:'country' },
{ id: 'ES', name:'Spain', type:'country' },
{ id: 'IT', name:'Italy', type:'country' },
{ id: 'NA', name:'North America', type:'continent',
children:[{_reference:'MX'}, {_reference:'CA'}, {_reference:'US'}] },
{ id: 'MX', name:'Mexico', type:'country', population:'108 million', area:'1,972,550 sq km',
children:[{_reference:'Mexico City'}, {_reference:'Guadalajara'}] },
{ id: 'Mexico City', name:'Mexico City', type:'city', population:'19 million', timezone:'-6 UTC'},
{ id: 'Guadalajara', name:'Guadalajara', type:'city', population:'4 million', timezone:'-6 UTC' },
{ id: 'CA', name:'Canada', type:'country', population:'33 million', area:'9,984,670 sq km',
children:[{_reference:'Ottawa'}, {_reference:'Toronto'}] },
{ id: 'Ottawa', name:'Ottawa', type:'city', population:'0.9 million', timezone:'-5 UTC'},
{ id: 'Toronto', name:'Toronto', type:'city', population:'2.5 million', timezone:'-5 UTC' },
{ id: 'US', name:'United States of America', type:'country' },
{ id: 'SA', name:'South America', type:'continent',
children:[{_reference:'BR'}, {_reference:'AR'}] },
{ id: 'BR', name:'Brazil', type:'country', population:'186 million' },
{ id: 'AR', name:'Argentina', type:'country', population:'40 million' }
]}
/tags/2.0/htdocs/test/dojo/test_dojo_menu.html
0,0 → 1,91
 
% &LoadHeader('/test/dojo/test_dojo_menu.css');
 
<script>
dojo.require("dijit.MenuBar");
dojo.require("dijit.PopupMenuBarItem");
dojo.require("dijit.Menu");
dojo.require("dijit.MenuItem");
dojo.require("dijit.PopupMenuItem");
dojo.require("dijit.ColorPalette");
dojo.addOnLoad(function(){
});
</script>
 
<h2>test Dojo Toolkit - dijit.MenuBar</h2>
 
<div dojoType="dijit.MenuBar" id="navMenu">
<div dojoType="dijit.PopupMenuBarItem">
<span>
File
</span>
<div dojoType="dijit.Menu" id="fileMenu">
<div dojoType="dijit.MenuItem" onClick="alert('file 1')">
File #1
</div>
<div dojoType="dijit.MenuItem" onClick="alert('file 2')">
File #2
</div>
</div>
</div>
<div dojoType="dijit.PopupMenuBarItem">
<span>
Edit
</span>
<div dojoType="dijit.Menu" id="editMenu">
<div dojoType="dijit.MenuItem" onClick="alert('edit 1')">
Edit #1
</div>
<div dojoType="dijit.MenuItem" onClick="alert('edit 2')">
Edit #2
</div>
</div>
</div>
</div>
<br>
<br>
<h2>test Dojo Toolkit - dijit.Menu</h2>
<br>
<div dojoType="dijit.Menu" id="windowContextMenu" contextMenuForWindow="true"
style="display: none;">
<div dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconCut"
onClick="alert('not actually cutting anything, just a test!')">
Cut
</div>
<div dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconCopy"
onClick="alert('not actually copying anything, just a test!')">
Copy
</div>
<div dojoType="dijit.MenuItem" iconClass="dijitEditorIcon dijitEditorIconPaste"
onClick="alert('not actually pasting anything, just a test!')">
Paste
</div>
<div dojoType="dijit.MenuSeparator">
</div>
<div dojoType="dijit.PopupMenuItem">
<span>
Enabled Submenu
</span>
<div dojoType="dijit.Menu" id="submenu1">
<div dojoType="dijit.MenuItem" onClick="alert('Submenu 1!')">
Submenu Item One
</div>
<div dojoType="dijit.MenuItem" onClick="alert('Submenu 2!')">
Submenu Item Two
</div>
</div>
</div>
<div dojoType="dijit.PopupMenuItem">
<span>
Popup of something other than a menu
</span>
<div dojoType="dijit.ColorPalette">
</div>
</div>
</div>
<span>
Right click anywhere on the page to see this menu.
</span>
 
 
 
/tags/2.0/htdocs/test/dojo/test_dojo_Uploader.html
0,0 → 1,40
<%doc>
</%doc>
<script>
dojo.require("dojox.form.Uploader");
dojo.require("dojox.form.uploader.FileList");
dojo.require("dojox.embed.Flash");
if(dojox.embed.Flash.available) {
dojo.require("dojox.form.uploader.plugins.Flash");
}else{
dojo.require("dojox.form.uploader.plugins.IFrame");
}
dojo.ready(function(){
var u = new dojox.form.Uploader({
label: "Select file",
multiple: false,
uploadOnSelect: true,
url: "test_dojo_Uploader_handler.mason?upload=1"
}, "uploader1");
 
var menu = dijit.byId("");
});
</script>
<h1>Demo: dojox.form.Uploader</h1>
 
<span id="uploader1" style="width:100px;"></span>
<hr>
 
<form method="post" action="test_dojo_Uploader_handler.mason?upload=2" id="myForm2" enctype="multipart/form-data" >
<fieldset>
<legend>Form Post Test</legend>
<input class="browseButton" name="uploadedfile" multiple="true" type="file" force="iframe" dojoType="dojox.form.Uploader" label="Select Some Files" id="uploader">
<input type="button" id="remBtn" label="Clear" dojoType="dijit.form.Button" />
<input type="submit" label="Submit" dojoType="dijit.form.Button" />
<div id="files" dojoType="dojox.form.uploader.FileList" uploaderId="uploader"></div>
</fieldset>
</form>
 
<textarea rows="10" cols="100"><% Dumper(\%ENV)%></textarea>
/tags/2.0/htdocs/test/dojo/test_dojo_template.html
0,0 → 1,54
<script>
dojo.require("dojo.parser");
dojo.require("dojox.dtl.Inline");
dojo.addOnLoad(function() {
setTimeout(function(){
var inline = dijit.byId("inline");
inline.context.items.push("guava");
inline.render();
}, 1000);
setTimeout(function(){
var inline = dijit.byId("inline");
inline.context = {items: ["lions", "tigers", "bears"]};
inline.render();
}, 2000);
});
</script>
 
<h2>test Dojo Toolkit - dijit.dtl.Inline</h2>
 
<script type="text/html" dojoType="dojox.dtl.Inline" id="inline" context="{items: ['apple', 'banana', 'orange']}">
<ol>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ol>
</script>
<br>
<br>
<h2>test Dojo Toolkit - dijit.dtl.ext-dojo.NodeList</h2>
<div id="updateId"></div>
<script>
var Vars = { items: ["apple", "banana", "pear"] };
var Vars2 = { items: ["mela", "ciliegia", "cocco"] };
dojo.require("dojox.dtl.ext-dojo.NodeList");
dojo.addOnLoad(function() {
dojo.query('#updateId').dtl("<div><ul>{% for item in items %}<li>{{ item }}</li>{% endfor %}</ul></div", Vars);
setTimeout(function(){
dojo.query('#updateId').dtl("<div><ul>{% for item in items %}<li>{{ item }}</li>{% endfor %}</ul></div", Vars2);
}, 1500);
});
</script>
<br>
<br>
<h2>test Dojo Toolkit - dijit.dtl.Context</h2>
<div id="updateId2"></div>
<script>
dojo.require("dojox.dtl.Context");
var tpl = new dojox.dtl.Template("<div><ul>{% for item in items %}<li>{{ item }}</li>{% endfor %}</ul></div");
</script>
/tags/2.0/htdocs/test/dojo/test_dojo_tree_data.css
0,0 → 1,7
<%flags>
inherit => '/init.comp'
</%flags>
 
.dojoxUploaderFileListHeader {
font-size: 8pt;
}
/tags/2.0/htdocs/test/dojo/test_dojo_tooltip.css
0,0 → 1,11
<%flags>
inherit => '/init.comp'
</%flags>
 
.dijitTooltipContainer {
background: none repeat scroll 0 0 #fffafb;
padding: 3px;
border: 1px solid brown;
color: blue;
font-size: 11pt;
}
/tags/2.0/htdocs/test/dojo/test_dojo_Uploader_handler.mason
0,0 → 1,13
<%doc>
</%doc>
<%flags>
inherit => undef
</%flags>
<%args>
$upload => undef
</%args>
<%perl>
$m->clear_buffer;
$m->out('xxxxxxxxxxxxxxxxxxxxx');
</%perl>
/tags/2.0/htdocs/test/dojo/test_dojo_UploaderMulti.html
0,0 → 1,33
<%doc>
</%doc>
<script>
dojo.require("dojox.form.Uploader");
dojo.require("dojox.embed.Flash");
if(dojox.embed.Flash.available) {
dojo.require("dojox.form.uploader.plugins.Flash");
}else{
dojo.require("dojox.form.uploader.plugins.IFrame");
}
dojo.ready(function(){
var u = new dojox.form.Uploader({
label: "Select multiple files",
multiple: true,
uploadOnSelect: true,
url: "test_dojo_UploaderMulti_handler.mason?upload=1"
}, "uploader1");
 
var menu = dijit.byId("");
});
</script>
<h1>Demo: dojox.form.Uploader</h1>
 
 
<div id="uploader1"></div>
<hr>
<form method="post" action="test_dojo_UploaderMulti_handler.mason?upload=2" id="myForm" enctype="multipart/form-data" >
<input name="uploadedfile" multiple="true" type="file" dojoType="dojox.form.Uploader" label="Select Some Files" id="uploader2" />
<input type="submit" label="Submit" dojoType="dijit.form.Button" />
</form>
<hr>
<textarea rows="10" cols="100"><% Dumper(\%ENV)%></textarea>
/tags/2.0/htdocs/test/dojo/test_dojo_menu.css
0,0 → 1,0
 
/tags/2.0/htdocs/test/dojo/test_dojo_tooltip.html
0,0 → 1,23
 
% &LoadHeader('/test/dojo/test_dojo_tooltip.css');
 
<script>
dojo.require("dijit.Tooltip");
dojo.addOnLoad(function() {
new dijit.Tooltip({
connectId: ['test_input_tooltip1'],
label: "Tooltip di <b>prova1!</b>"
});
new dijit.Tooltip({
connectId: ['test_input_tooltip2'],
label: "Tooltip di <b>prova2!</b>"
});
});
</script>
 
<h2>test Dojo Toolkit - dijit.Tooltip</h2>
 
<input type="text" id="test_input_tooltip1"></input>
<br>
<input type="text" id="test_input_tooltip2"></input>
 
/tags/2.0/htdocs/test/dojo/test_dojo_UploaderMulti_handler.mason
0,0 → 1,13
<%doc>
</%doc>
<%flags>
inherit => undef
</%flags>
<%args>
$upload => undef
</%args>
<%perl>
$m->clear_buffer;
$m->out('xxxxxxxxxxxxxxxxxxxxx');
</%perl>
/tags/2.0/htdocs/test/dojo/test_dojo_tree.html
0,0 → 1,21
<html>
<script>
dojo.require("dojo.data.ItemFileReadStore");
dojo.require("dijit.Tree");
</script>
 
<h2>test Dojo Toolkit - dijit.Tree</h2>
 
<div dojoType="dojo.data.ItemFileReadStore" jsId="continentStore" url="/test/dojo/test_dojo_tree.json"></div>
 
<div dojoType="dijit.tree.ForestStoreModel" jsId="continentModel" store="continentStore"
query="{type:'continent'}" rootId="continentRoot" rootLabel="Continents"
childrenAttrs="children">
</div>
<div dojoType="dijit.Tree" id="mytree" model="continentModel" openOnClick="true">
<script type="dojo/method" event="onClick" args="item">
alert("BINGO! " + continentStore.getLabel(item) + ", population=" + continentStore.getValue(item, "population"));
</script>
</div>
 
</html>
/tags/2.0/htdocs/test/test_callRemote.html
0,0 → 1,8
<h1>Test callRemote</H1>
<button onclick="Call();">call /test_callRemote.mql - test_callRemote</button>
<script>
function Call(){
var db = new DataBinding('Recordset', 'public/test_callRemote', 1);
db.callRemote('test_callRemote', {par1: 'parametro uno', par2: 'parametro due'}, 'html', {title: 'Test call remote'});
}
</script>
/tags/2.0/htdocs/test/test_hReqMason.html
0,0 → 1,42
<H1>test:</H1>
Valutazione libreria hReqMason_ClientMason.js
<form name="my_form">
<input type="button" onClick="Go()" value="OK">
 
<script>
//carico la tabella da visualizzare
hReqMason_POST = false;
start = 0;
rows=1;
 
function Go(){
hReqMason_ExecuteTimeout('<% $r->dir_config('DataBaseUrl') %>/logs.mql', 5000, TimeoutData, Load_Callback, 'remotesend.array',['start',start,'rows',rows,'name','test'], false);
hReqMason_ExecuteTimeout('<% $r->dir_config('DataBaseUrl') %>/logs.mql', 5000, TimeoutData, Load_Callback2, 'remotesend.array',['start',start,'rows',rows,'name','test'], false);
hReqMason_ExecuteTimeout('<% $r->dir_config('DataBaseUrl') %>/logs.mql', 5000, TimeoutData, Load_Callback3, 'remotesend.array',['start',start,'rows',rows,'name','test'], false);
}
 
function TimeoutData(contextID, type, str){
var contextObj = hReqMason_ContextPool[contextID];
alert('Timeout ricezione ' + contextID + ' URL='+contextObj.URL + ' type='+type + ' str='+str);
}
 
 
// richiamata al caricamento del form
function Load_Callback(str, contextID){
var contextObj = hReqMason_ContextPool[contextID];
window.alert('Callback '+contextID+' URL='+contextObj.URL+' \n'+str);
}
 
// richiamata al caricamento del form
function Load_Callback2(str, contextID){
var contextObj = hReqMason_ContextPool[contextID];
window.alert('Callback2 '+contextID+' URL='+contextObj.URL+' \n'+str);
}
 
// richiamata al caricamento del form
function Load_Callback3(str, contextID){
var contextObj = hReqMason_ContextPool[contextID];
window.alert('Callback3 '+contextID+' URL='+contextObj.URL+' \n'+str);
}
 
</script>
/tags/2.0/htdocs/test/test_htmlselect.html
0,0 → 1,47
<%args>
</%args>
<H1>test_htmlselect.html</H1>
% my $editURL='/frame.html?from=siti&form=FORM';
Html select1:
<& /input/htmlselect.comp, id =>'htmlSel1',
description=>'Elenco impianti',
value => 1, # group Admins
buffer => 'htmlSel',
remote => 1,
empty => undef,
width => '300',
size => 5,
source => $r->dir_config('DataBaseUrl').'/sel_gruppi.mql',
edit => $editURL,
empty => '-1',
empty_descr => '-- No user --',
editmessage => '*** Change users ***',
editwindowparam => "height=380,width=550,location=no,menubar=no,toolbar=no,scrollbar=yes",
onchange => q|alert('id='+this.get_value());|,
widget => 'htmlselect'
&>
- <button onclick="Id_htmlSel1.Readonly(true);">Readonly</button>
<button onclick="Id_htmlSel1.Readonly(false);">R/W</button>
<hr>
Html select2:
<& /input/htmlselect.comp, id =>'htmlSel2',
width => 140,
popup_max_height => '80px',
description=>'test componente htmlselect',
empty => '',
empty_descr => 'Nessuna selezione',
cols => 1,
readonly => 0,
source => $r->dir_config('DataBaseUrl').'/autorizzazioni.mql',
where => "nome != 'M%'",
onchange => q|alert('BINGO\nchange htmlselect')|
&>
<script>
var S1 = document.getElementById('htmlSel1');
var D1 = document.getElementById('display_htmlSel1');
var S2 = document.getElementById('htmlSel2');
var D2 = document.getElementById('display_htmlSel2');
</script>
<%flags>
inherit => '../autohandler'
</%flags>
/tags/2.0/htdocs/test/test_select.html
0,0 → 1,127
<%args>
$edit => undef
</%args>
<H1>test_select.html</H1>
% if($edit){
<script>
var loaded = false;
function OnFocus(){
if(loaded){
document.getElementById('edittest').focus();
debug('edit_focus');
loaded=false;
}
}
window.onload=function(){
debug(null);
document.body.style.backgroundColor='#aaaaff';
debug('load');
loaded=true;
OnFocus();
}
</script>
<form name="formedit">
<input id="edittest" size=40 value="">
<br>
<input type=button value="GO">
% }else{
<script>
function OnFocus(){
}
window.onload=function(){
debug(null);
document.body.style.backgroundColor='#aaaaff';
debug('load');
loaded=true;
}
</script>
% my $windowparam="height=380,width=550,location=no,menubar=no,toolbar=no,scrollbar=yes";
% my $editURL='/frame.html?from=gruppi&form=FORM';
<form name="menu">
Sel1:<br>
<& /input/select.comp, id =>'Sel1',
description=>'Elenco gruppi',
buffer => 'Sel',
#remote => 1,
empty => undef,
width => '300px',
size => 5,
style=>'width:400;',
source=>$r->dir_config('DataBaseUrl').'/gruppi.mql',
edit => $editURL,
editmessage => '*** Modifica lista gruppi ***',
editwindowparam => $windowparam &>
<br>
Sel2:<br>
<& /input/select.comp, id =>'Sel2',
description=>'Elenco gruppi',
buffer => 'Sel',
#remote => 1,
empty=> undef,
width => '300px',
size => 5,
style=>'background-color:#ffeeff; width:400;',
source=>$r->dir_config('DataBaseUrl').'/gruppi.mql',
edit => $editURL,
editmessage => '*** Modifica lista gruppi ***',
editwindowparam => $windowparam &>
<br>
SelS:<br>
<& /input/select.comp, id =>'SelS',
description=>'Elenco gruppi singola selezione',
#remote => 1,
buffer => 'Sel',
empty=> '0',
width => '300px',
size => 1,
style=>'background-color:#ffeffe; width:400;',
source=>$r->dir_config('DataBaseUrl').'/gruppi.mql',
edit => $editURL,
editmessage => '*** Modifica lista gruppi ***',
editwindowparam => $windowparam &>
<br>
<textarea id="buf" rows=1 cols=80>1738;1739;1740;1741;1742;1743</textarea>
<br>
<input type="button" value="get list" onClick="document.getElementById('buf').value=document.getElementById('Sel1').get_value()">
<br>
<input type="button" value="set list" onClick="document.getElementById('Sel1').set_value(document.getElementById('buf').value)">
<br>
<input type="button" value="disable body" onClick="document.body.disabled=true;">
<input type="button" value="disable form" onClick="document.menu.disabled=true;">
<input type="button" value="disable select" onClick="document.menu.Sel1.disabled=true;">
<input type="button" value="readonly select" onClick="document.menu.Sel1.Readonly(true);">
 
% }
<br>
<textarea id="debug" wrap rows=12 cols=12></textarea>
</form>
<hr>
<p>Tessera: <%$Session{Login}%><br>
Utente: <%$Session{Name}%></p>
<script>
var c=0;
function debug(mess){
c++;
var area = document.getElementById('debug');
if(mess){
area.value=area.value+mess+'['+c+'] ';
}else{
area.value='';
c=0;
}
}
window.onfocus=function(){
OnFocus();
document.body.style.backgroundColor='#ffaaff';
debug('focus');
}
window.onblur=function(){
document.body.style.backgroundColor='#ffaaaa';
debug('blur');
}
</script>
<script>
</script>
<%flags>
inherit => '../autohandler'
</%flags>
/tags/2.0/htdocs/test/test_select_where.html
0,0 → 1,13
<%args>
$edit => undef
</%args>
% $Session{Auth_Admin}=1;
<H1>test_select_where.html</H1>
<& /input/select.comp, width=>'140', id =>'TEST', description=>'test',
source => $r->dir_config('DataBaseUrl').'/metodi.mql',
where => "tipo like 'P%'"
&>
 
<%flags>
inherit => '/autohandler'
</%flags>
/tags/2.0/htdocs/test/test_subrequest.html
0,0 → 1,31
<%flags>
inherit => undef
</%flags>
<html>
<h2>test_variables.comp</h2>
<hr>
<% scall_component('/data/sel_gruppi.mql', F => 'selectoptions') %>
<hr>
</html>
<%once>
sub scall_component {
my $comp = shift;
my $content_type = $r->content_type;
my $buffer;
local %Session;
local $Ver;
local $DEBUG;
local %Session;
local $Ver;
local %Global;
local @Script_buffer;
local %SQL;
local $PLogger;
local $JSLogger;
my $req = $m->make_subrequest( comp => $comp, args => \@_, out_method => \$buffer );
$req->exec;
$r->content_type($content_type);
return $buffer;
}
 
</%once>
/tags/2.0/htdocs/test/test_bug_array_params.html
0,0 → 1,47
<%doc>
Call .../test/test_bug_array_params.html?Arr=uno&Arr=due&Arr=tre
 
Using Perl 5.22 on Ubuntu 16.04+Apache2.4+mod_perl it print:
 
@Array = [ 'ARRAY(0x7fadc00093e0)' ]
%ARGS = { 'Arr' => 'ARRAY(0x7fadc00093e0)' }
 
Using old perl releases:
 
@Array = [ 'uno', 'due', 'tre' ]
%ARGS = { 'Arr' => [ 'uno', 'due', 'tre' ] }
</%doc>
<%flags>
inherit => undef
</%flags>
<%args>
@Arr
</%args>
<%once>
use Data::Dumper;
</%once>
<%perl>
my @Arr2 = $r->param('Arr');
my $arr2 = $r->param;
print STDERR 'From main:', Dumper($r);
my %args;
foreach my $key ( $r->param ) {
my @values = $r->param($key);
$args{$key} = @values == 1 ? $values[0] : \@values;
}
 
my $decl = $m->current_comp->declared_args;
 
print STDERR "CALL \$m->request_args:", Dumper($m->{request_args});
my $request_args = $m->request_args;
 
</%perl>
| @Array = <% join(' | ', @Arr) %><br>
@Array = <% Dumper(@Arr) %><br>
| %ARGS = <% join(' | ', %ARGS) %><br>
%ARGS = <% Dumper(\%ARGS) %><br>
$r->param('Arr') = <% Dumper(\@Arr2) %><br>
$r->param = <% Dumper($arr2) %><br>
%args = <% Dumper(\%args) %><br>
$m->current_comp->declared_args = <% Dumper($decl) %><br>
$m->current_comp->request_args = <% Dumper($request_args) %><br>
/tags/2.0/htdocs/test/test_divselect.html
0,0 → 1,86
<%args>
$edit => undef
</%args>
<%perl>
&LoadHeader(
'/input/input.comp', '/input/divselect.comp', '/input/number.comp',
'/input/select.comp', '/input/string.comp', '/input/htmlselect.comp',
'/input/codfisc_pi.comp', '/input/checkbox.comp'
);
</%perl>
<H1>test_divselect.html</H1>
<H3>divselect.comp from anagrafiche</h3>
<& /input/divselect.comp,
width => '220',
id =>'div_id1',
value => 1,
description => 'test componente divselect',
buttons => [ MyFunc => q{alert("Bingo!")},
'Func 2' => q{alert("Bingo 2!")},
'Test RescaleDisplay' => q{Input_DivSelect_Popup.rescaleDisplay()}
], # bottoni supplementari
empty => '',
empty_descr => 'Nessuna sel.',
insert_descr => 'Nuovo utente',
insert_parameters => [ 'form' => 'FORM' ],
disp_template => q|P[0]+' '+P[1]+(P[2] ? ' ('+P[2]+')' : '')|, # P== array dei parametri del widget; viene eseguita una "eval"
rows => 20,
cols => [100, 120, 150],
readonly => 0,
from => 'anagrafiche',
XXXwhere => q|cognome ~* '^[a-m]'|,
orderby => 'lower(cognome), lower(nome)',
query_param => 'parametro supplementale', # parametro opzionale che viene inviato al server
XXXonchange => q|alert('BINGO\nchange divselect')|
&>
- <button onclick="Id_div_id1.Readonly(true);">Readonly</button>
<button onclick="Id_div_id1.Readonly(false);">R/W</button>
 
<hr>
<H3>divselect.comp from anagrafiche con dettaglio su anagrafiche</h3>
<& /input/divselect.comp,
width => '140',
id =>'div_id2',
description => 'test anagrafiche',
buttons => [ MyFunc => q{alert("Bingo!")},
'Func 2' => q{alert("Bingo 2!")}
], # bottoni supplementari
empty => '',
empty_descr => 'Nessuna sel.',
insert_descr => 'Nuovo utente',
insert_parameters => [ 'form' => 'FORM' ],
disp_template => q{P[0]+' '+P[1]}, # P== array dei parametri del widget; viene eseguita una "eval"
rows => 20,
cols => [100, 120, 150],
readonly => 0,
from => 'anagrafiche',
Detail_from => 'anagrafiche',
Detail_width => 800,
Detail_height => 600,
XXXwhere => q|cognome ~* '^[a-m]'|,
orderby => 'lower(cognome), lower(nome)',
query_param => 'parametro supplementale', # parametro opzionale che viene inviato al server
onchange => q|alert('BINGO\nchange divselect')|
&>
<H3>divselect.comp from anagrafiche con dettaglio su anagrafiche</h3>
<& /input/divselect.comp,
width => '140',
id =>'div_id3',
description => 'test anagrafiche',
empty => '',
empty_descr => 'Nessuna sel.',
insert_descr => 'Nuova funzione',
insert_parameters => [ 'form' => 'FORM' ],
disp_template => q{P[0]+' '+P[1]}, # P== array dei parametri del widget; viene eseguita una "eval"
rows => 20,
cols => [100, 100, 100],
readonly => 0,
from => 'anagrafiche',
Detail_from => 'anagrafiche',
Detail_width => 880,
Detail_height => 660
&>
 
<%flags>
inherit => '../autohandler'
</%flags>
/tags/2.0/htdocs/test/test_hello.html
0,0 → 1,6
<html>
<h2>test hello.comp</h2>
 
<& /input/hello.comp, id => 'test1', value => 'Dipen' &>
<br>
</html>
/tags/2.0/htdocs/test/test_utf8.html
0,0 → 1,4
<%flags>
inherit => undef
</%flags>
Testo utf: àèéìòù €
/tags/2.0/htdocs/test/test_span.html
0,0 → 1,18
<%args>
$edit => undef
</%args>
<H1>test_span.html</H1>
<br>
<& /input/span.comp, id =>'Span1', description=>'Test oggetto span',
bgcolor => 'red', width => 300,
style => '|color:yellow; width:400px;', value => 'BINGO</SPAN>' &>
<br>
 
<script>
function InitAll(){
var obj = document.getElementById('Span1');
obj.set_value('BENE, FUNZIONA!!!');
}
window.setTimeout(InitAll,1);
</script>
 
/tags/2.0/htdocs/test/test_UpiPrinterServer.html
0,0 → 1,67
<!DOCTYPE html "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<%args>
$Area_testo => "Esempio\nriga 2\nriga 3\nultima riga (€è[ò\@ò#°)";
</%args>
<head>
<title>test_UpiPrinterServer.html</title>
</head>
<body>
<H1>test_UpiPrinterServer.html</H1>
<hr>
Testo da inviare alla stampante:<br>
<form method="POST" action="/test/test_UpiPrinterServer.html" >
<input type="submit" value="Stampa" >
<br>
<textarea name="Area_testo" rows="5" cols="80"><% $Area_testo |h%></textarea>
<br>
Risposta dal server:<br>
<textarea id="Result"rows="2" cols="80"></textarea>
</form>
<script>
// Se definita la funzione UpiPrinterServerHandler viene richiamata per fornire
// il risultato della stampa.
// Elenco dei possibili codici di stato ritornati:
// printed | File <file< printed to <printer_name>
// print_err_1 | Print to <printer_name> with error -1: Memory allocation error
// print_err_2 | Print to <printer_name> with error -1: Error opening the file
// print_err_3 | Print to <printer_name> with error -1: Error opening the printer
// print_err_4 | Print to <printer_name> with error -1: Error startint the print job
// print_err_5 | Print to <printer_name> with error -1: Error writing to printer
// print_err_6 | Print to <printer_name> with error -1: Error ending the print job
// print_err_7 | Print to <printer_name> with error -1: Error closing printer
// remote_err_XXX | Remote server error: ......................
// no_print_default | No default printer is selected
//
function UpiPrinterServerHandler(result, comment){
document.getElementById('Result').value = result + ': ' + comment;
alert(result + ': ' + comment)
}
</script>
<%perl>
if($r->method eq 'POST'){
# preparo il file
my($fh, $filename) = tempfile(
DIR => $r->dir_config('TmpDir'),
SUFFIX => '.prn',
UNLINK => 0
);
my $file = $filename;
$file =~ s|^.*/||; # tolgo la dir
$file =~ s|\.prn$||; # tolgo .prn
print $fh $Area_testo;
close $fh;
</%perl>
<script src="https://localhost:22000/from_server/<% "$ENV{HTTP_HOST}/$file"%>"></script>
% }
<br>
Configurazione della stampante:<br>
<iframe src="https://localhost:22000/" width="650" height="320" frameborder="0"></iframe>
</body>
</html>
<%flags>
inherit => undef
</%flags>
<%once>
use File::Temp qw(tempfile);
</%once>
/tags/2.0/htdocs/test/test_keyevents.html
0,0 → 1,72
<html>
<h2>test tabs e arrows key events to move up,down, left, right</h2>
 
<input id="A1" type="text" value="A1" tabindex="-1">
<input id="A2" type="text" value="A2" tabindex="-1">
<input id="A3" type="text" value="A3" tabindex="-1"><br>
 
<input id="B1" type="text" value="B1" tabindex="-1">
<input id="B2" type="text" value="B2" tabindex="-1">
<input id="B3" type="text" value="B3" tabindex="-1"><br>
 
<input id="C1" type="text" value="C1" tabindex="-1">
<input id="C2" type="text" value="C2" tabindex="-1">
<input id="C3" type="text" value="C3" tabindex="-1">
 
<script>
 
var positions = [
[ document.getElementById('A1'), document.getElementById('A2'), document.getElementById('A3') ],
[ document.getElementById('B1'), document.getElementById('B2'), document.getElementById('B3') ],
[ document.getElementById('C1'), document.getElementById('C2'), document.getElementById('C3') ]
];
 
for(var R=0; R<positions.length;R++){
var row = positions[R];
for(var C=0; C<positions.length;C++){
row[C].Row = R;
row[C].Col = C;
}
}
dojo.query('input').connect('keypress', function(event){
// alert(this.id +': ' + event.keyCode + ' R:' + this.Row + ' C:' + this.Col);
});
 
dojo.query('input').connect('keydown', function(event){
//alert(this.id +': ' + event.keyCode + ' R:' + this.Row + ' C:' + this.Col);
var widget;
if((event.keyCode == 9 && !event.shiftKey)){
// TAB
widget = this.Col == positions[0].length - 1 ? (this.Row == positions.length - 1 ? positions[0][0] : positions[this.Row + 1][0]) : positions[this.Row][this.Col + 1];
}else if(event.keyCode == 9 && event.shiftKey){
// Shift-TAB
widget = this.Col == 0 ? (this.Row == 0 ? positions[positions.length - 1][positions[0].length -1] : positions[this.Row - 1][positions[0].length -1]) : widget = positions[this.Row][this.Col - 1];
}else if(event.keyCode == 38){ // Up arrow
// key UP
widget = this.Row == 0 ? (this.Col == 0 ? positions[positions.length - 1][positions[0].length -1] : positions[positions.length - 1][this.Col - 1]) : positions[this.Row - 1][this.Col];
}else if(event.keyCode == 13 || event.keyCode == 40){ // CR o Down arrow
widget = this.Row == positions.length - 1 ? (this.Col == positions[0].length -1 ? positions[0][0] : positions[0][this.Col + 1]) : positions[this.Row + 1][this.Col];
}else if(event.keyCode == 37){ // Left arrow
// salto solo se sono con il caret all'inizio
if(this.selectionStart == 0){
widget = this.Col == 0 ? (this.Row == 0 ? positions[positions.length - 1][positions[0].length -1] : positions[this.Row - 1][positions[0].length -1]) : widget = positions[this.Row][this.Col - 1];
}else{
return true;
}
}else if(event.keyCode == 39){ // Right arrow
// salto solo se sono con il caret alla fine
if(this.selectionStart == this.value.length){
widget = this.Col == positions[0].length - 1 ? (this.Row == positions.length - 1 ? positions[0][0] : positions[this.Row + 1][0]) : positions[this.Row][this.Col + 1];
}else{
return true;
}
}else{
return true;
}
widget.focus();
widget.setSelectionRange(0, widget.value.length);
return false;
});
 
</script>
</html>
/tags/2.0/htdocs/test/test_select_div.html
0,0 → 1,149
<%args>
$edit => undef
</%args>
<H1>test_select_div.html</H1>
<%flags>
inherit => undef #'/autohandler'
</%flags>
<h2>Prove cursore con DIV</h2>
% # campi da visualizzare
% my $num_fields = 2;
% # record da visualizzare
% my $num_records = 8;
% # numero dei record del recordset
% my $max_records = 200;
 
<div id="divtest" style="margin: 0px; background-color: #cccccc;">
<div id="divtest1" style="float:left; height:100; margin:0px; border-style: none; overflow: auto; background-color: #f0f2bf;">
<span id="info">. . .</span>
<table border="1" id="table">
% for(my $r=0;$r<$num_records;$r++){
<tr onclick="selectRow(<%$r%>)">
% for(my $c=0;$c<$num_fields;$c++){
<td style="width:75px" align="center">...</td>
% }
</tr>
% }
</table>
</div>
<div id="divtest2" style="background-color: #cccccc; margin: 0px; border-style: none; overflow:auto; width:20px;">
<div id="divtest3" style="margin: 0px; border-style: none; width:1; height:1000px;">
</div>
</div>
</div>
<hr>
<textarea id="dmess" rows="11" cols="80"></textarea>
<script>
var info = document.getElementById('info');
var table = document.getElementById('table');
var divtest = document.getElementById('divtest');
var divtest1 = document.getElementById('divtest1');
var divtest2 = document.getElementById('divtest2');
var divtest3 = document.getElementById('divtest3');
var dmess = document.getElementById('dmess');
 
// dimensiono l'altezza per contenere tutta la tabella
divtest1.style.height = divtest1.scrollHeight;
divtest2.style.height = divtest1.scrollHeight;
divtest.style.height = divtest1.scrollHeight;;
divtest1.style.width = divtest1.scrollWidth;
// set larghezza del contenitore, che adatta perfettamente all'occupazione in larghezza dell'oggetto
// contenuto comprensiva dello spazio occupato dal cursore
divtest.style.width = divtest1.offsetWidth+divtest2.offsetWidth;
 
// calcolo dimensioni documento cursore proporzionali al n° di record
divtest3.style.height = <%$max_records%> * divtest2.offsetHeight / <%$num_records%>;
 
// posizione del recordset
var start = 0;
var old_start = 0;
// ritardo in msec con cui aggiornare il recordset se si muove il cursore
var delayUpdate = 1000;
// timer per gestire il ritardo con cui si aggiorna il recordset
var delayUpdateTimer;
// evento scroll del cursore
divtest2.onscroll = function(){
// calcolo la nuova posizione del recordset
start = Math.ceil(this.scrollTop * <%$max_records%> / this.scrollHeight);
// aggiorna report delle dimensioni
ViewDimensions();
var delay;
if(Math.abs(old_start-start) < <%$num_records%> -1){
// spostamento cursore lento applico un ritardo lungo se già non è stato attivato...
delay = delayUpdate;
// predispongo campi vuoti
emptyRecordset();
}else{
// spostamento cursore veloce o a pagina; applico ritardo corto
delay = delayUpdate / 5;
// cancellando l`eventuale timer attivo
if(delayUpdateTimer){
window.clearTimeout(delayUpdateTimer);
delayUpdateTimer = null;
}
}
if(!delayUpdateTimer){
delayUpdateTimer = window.setTimeout(changeRecordset, delay);
}
info.innerHTML = start + '-' + (start+<%$num_records-1%>) + '(' + <%$max_records%> + ')';
old_start = start;
}
// var usata per evitare continui aggiornamenti con i campi vuoti (lampeggio)
var isEmpty;
function emptyRecordset(){
if(!isEmpty){
var rows = table.getElementsByTagName('tr');
for(var row=0; row<rows.length; row++){
var cols = rows[row].getElementsByTagName('td');
for(var col=0; col<cols.length; col++){
cols[col].innerHTML = '...';
}
}
}
isEmpty = true;
}
// aggiorna il recordset visualizzato; simulato con il cambio dati nelle celle pari a RxCy
// dove x è in numero di riga e y è il numero di colonna
function changeRecordset(){
delayUpdateTimer = null;
var rows = table.getElementsByTagName('tr');
for(var row=0; row<rows.length; row++){
var cols = rows[row].getElementsByTagName('td');
for(var col=0; col<cols.length; col++){
cols[col].innerHTML = 'R'+(start+row)+'C'+col;
}
}
isEmpty = false;
}
 
// stringa contenente le dimensioni degli oggetti in gioco
// mostrata nel campo textarea
function ViewDimensions(){
var mess = 'Dimensioni:\n';
mess += dim2str(divtest);
mess += dim2str(divtest1);
mess += dim2str(divtest2);
mess += dim2str(divtest3);
mess += dim2str(table);
dmess.value = mess;
}
 
function selectRow(num_row){
var value = table.getElementsByTagName('tr')[num_row].getElementsByTagName('td')[0].innerHTML;
alert('Selezionata riga '+num_row+'\ndi contenuto 1° colonna:' + value);
}
 
// stringa contenente le dimensioni dell'oggetto obj
function dim2str(obj){
return obj.id + ': start='+start+' offsetWidth='+obj.offsetWidth+' clientWidth='+obj.clientWidth+' scrollWidth='+obj.scrollWidth+'\n' +
' offsetHeight='+obj.offsetHeight+' clientHeight='+obj.clientHeight+' scrollHeight='+obj.scrollHeight+
' scrollTop='+obj.scrollTop+'\n';
}
 
// condizioni iniziali
divtest2.onscroll();
</script>
/tags/2.0/htdocs/test/test_width_divselect_span.html
0,0 → 1,30
<html>
<head>
<title>
test_width_divselect_comp.html
</title>
<link rel="stylesheet" href="/css/main.css?Ver=<%$Ver%>" type="text/css">
<link rel="stylesheet" href="/css/divselectpopup.css?Ver=<%$Ver%>" type="text/css">
<style>
 
</style>
</head>
<body>
<h1>
test_width_divselect_comp.html
</h1>
<hr>
<div id="DivSelect_Container" class="DivSelect_Container">
<div id="DivSelect_TableContainer" class="DivSelect_TableContainer">
<span class="INPUTSPAN" style="width:100;">
Super califragi listiche spiralidoso.
</span>
<span class="INPUTSPAN" style="width:200;">
SUPER PIPPO SUPER PIPPO SUPER PIPPO SUPER PIPPO SUPER PIPPO.
</span>
</div>
</div>
</html>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/test/test_width_divselect_table.html
0,0 → 1,44
<html>
<head>
<title>
test_width_divselect_comp.html
</title>
<link rel="stylesheet" href="/css/divselectpopup.css?Ver=<%$Ver%>" type="text/css">
</style>
</head>
<body>
<h1>
test_width_divselect_comp.html
</h1>
<hr>
<div id="DivSelect_Container" class="DivSelect_Container">
<div id="DivSelect_TableContainer" class="DivSelect_TableContainer">
<table class="DivSelect_Table" style="table-layout:fixed; width:0;">
<thead>
<tr class="DivSelect" style="max-width:300;">
<td class="DivSelect_Head" style="width:100;" >
Colonna 1
</td>
<td class="DivSelect_Head" style="width:200;" >
Colonna 2
</td>
</tr>
</thead>
<tbody>
<tr class="DivSelect_Dispari">
<td class="DivSelect_Column">
Super califragi listiche spiralidoso.
</td>
<td class="DivSelect_Column">
SUPER PIPPO SUPER PIPPO SUPER PIPPO SUPER PIPPO SUPER PIPPO.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</html>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/test/test_Files.html
0,0 → 1,52
<%args>
$edit => undef
$value => '31173'
$value2 => '31175'
</%args>
<H1>test_Files.html</H1>
<H3>Files.comp</h3>
<table>
<tr>
<td>
<& /input/Files.comp,
id => 'IdWidgetFilesTest1',
from => 'impianti/apparecchiature',
value => $value,
width => 400,
height => 300,
&>
</td>
 
<td>
<& /input/Files.comp,
id => 'IdWidgetFilesTest2',
from => 'impianti/apparecchiature',
value => $value2,
width => 400,
height => 300,
&>
 
</td>
</tr>
<tr>
<td>
<input id="IdWidgetFilesTest1_id" value="<%$value%>"/>
</td>
<td>
<input id="IdWidgetFilesTest2_id" value="<%$value2%>"/>
</td>
</tr>
</table>
<script>
dojo.ready(function(){
dojo.connect(dojo.byId('IdWidgetFilesTest1_id'), 'onchange', function(){
dojo.byId('IdWidgetFilesTest1').set_value(this.value);
});
dojo.connect(dojo.byId('IdWidgetFilesTest2_id'), 'onchange', function(){
dojo.byId('IdWidgetFilesTest2').set_value(this.value);
});
});
</script>
<%flags>
inherit => '/autohandler'
</%flags>
/tags/2.0/htdocs/test/test_width.html
0,0 → 1,85
<style>
.testwidthdiv
{
width: 100px;
border: thin #000000 solid;
white-space: nowrap;
overflow:hidden;
display: -moz-inline-box;
}
.testwidthspan
{
width: 100px;
border: thin #FF4400 solid;
white-space: nowrap;
overflow:hidden;
display:block;
display: -moz-inline-box;
}
</style>
 
<body>
<h1>
test_width.html
</h1>
Test con overflow in div:
<br/>
<br/>
<div class="testwidthdiv">
supercalifragilistichespiralidoso supercalifragilistichespiralidoso
</div>
<span class="dijitInline dijitIcon masonSqlIcons find vAlign"></span>
</br>
</br>
Test con overflow in span:
<br/>
<br/>
<span class="testwidthspan">
supercalifragilistichespiralidoso supercalifragilistichespiralidoso
</span>
<span class="dijitInline dijitIcon masonSqlIcons find vAlign"></span>
<br/>
<br/>
Test senza overflow in div:
<br/>
<br/>
<div class="testwidthdiv">&nbsp;
</div>
<span class="dijitInline dijitIcon masonSqlIcons find vAlign"></span>
<br/>
<br/>
Test senza overflow in span:
<br/>
<br/>
<span class="testwidthspan">&nbsp;</span>
<span class="dijitInline dijitIcon masonSqlIcons find vAlign"></span>
</body>
<script>
function getElementsByClass(searchClass,node,tag) {
var classElements = new Array();
if ( node == null )
node = document;
if ( tag == null )
tag = '*';
var els = node.getElementsByTagName(tag);
var elsLen = els.length;
var pattern = new RegExp("(^|\\s)"+searchClass+"(\\s|$)");
for (i = 0, j = 0; i < elsLen; i++) {
if ( pattern.test(els[i].className) ) {
classElements[j] = els[i];
j++;
}
}
return classElements;
}
var isIE = /MSIE/;
if (isIE.test(window.navigator.userAgent))
{
var divs = getElementsByClass("testwidthdiv", null, "div");
var divLen = divs.length;
for (var i = 0; i < divLen; i++)
{
divs[i].style.display = "inline";
}
}
</script>
/tags/2.0/htdocs/test/test_upload.html
0,0 → 1,62
<html>
<%args>
$upload => 0
</%args>
<%init>
use Apache2::Upload;
</%init>
<h2>test Upload file</h2>
<br>
<FORM ACTION="/test/test_upload.html?upload=1" XXXtarget="_blank" name="upl_sens_area"
METHOD="POST" ENCTYPE="multipart/form-data">
<input type="file" name="file1" lenght=25><br>
<input type="file" name="file2" lenght=25><br>
<input type="file" name="file3" lenght=25><br>
<INPUT TYPE="SUBMIT" VALUE="Load all files">
</FORM>
%# $m->out('Oggetto $r => ',Dumper($r));
% if($upload == 1){
% if($r->dir_config('MasonArgsMethod') eq 'CGI'){
% my $query = $m->cgi_object();
% foreach my $name qw(file1 file2 file3){
<hr>
% my $fh = $query->param($name);
% if($fh){
% my $type = $query->uploadInfo($fh)->{'Content-Type'};
% my $tempname = $query->tmpFileName($fh);
% my $disposition = $query->uploadInfo($fh)->{'Content-Disposition'};
Upload <b>type:</b><%$type%> <b>file_name:</b><%$tempname%> <b>disposition:</b><%$disposition%>:
<pre>
% while (<$fh>) {
% $m->out($_);
% }
% close($fh);
% }
</pre>
% }
<hr>end.
<%perl>
}else{
my @upload = $r->upload;
foreach my $upload (@upload){
$upload = $r->upload($upload);
$m->out('<hr>');
my $size = $upload->size;
my $type = $upload->type;
my $name = $upload->name;
my $tempname = $upload->tempname;
my $filename = $upload->filename;
my $fh = $upload->fh;
</%perl>
Upload: <b>file:</b><%$filename%></b> <b>tempname:</b><%$tempname%> <b>name:</b><%$name%> <b>type:</b><%$type%> <b>size:</b><%$size%>:
<pre>
% while (<$fh>) {
% $m->out($_);
% }
% close($fh);
</pre>
% }
% }
<hr>end.
% }
</html>
/tags/2.0/htdocs/test/test_color.html
0,0 → 1,43
<h2>test color.comp</h2>
<br>
Color: <& /input/color.comp,
id => 'TestColor',
value => '12/12/2005',
onchange => 'console.log("New color: "+this.get_value());',
description => 'Test input color',
convert_to_hex => 0,
readonly => 0
&>
&nbsp;
<button onclick="Id_TestColor.Readonly(true); document.getElementById('button_sv').disabled = true;">Readonly</button>
&nbsp;
<button onclick="Id_TestColor.Readonly(false); document.getElementById('button_sv').disabled = false;">R/W</button>
<br><br>
&nbsp;
<& /input/string.comp,
id => 'ColorVal',
description => 'Input ColorVal',
rows => 1,
cols => 30,
length => 30,
readonly => 0
&>
<br><br>
&nbsp;
<& /input/button.comp,
id => 'button_gv',
description => 'button',
value => 'button',
caption => 'Get Value',
readonly => 0,
onclick => "var color = document.getElementById('TestColor'); document.getElementById('ColorVal').set_value(color.get_value());"
&>
&nbsp;
<& /input/button.comp,
id => 'button_sv',
description => 'button',
value => 'button',
caption => 'Set Value',
readonly => 1,
onclick => "var color_val = document.getElementById('ColorVal'); document.getElementById('TestColor').set_value(color_val.get_value());"
&>
/tags/2.0/htdocs/test/test_document.html
0,0 → 1,339
<h2>Test: document.comp</h2>
 
&nbsp;
<& /input/document.comp,
id => 'test_document',
description => 'Descrizione pulsante',
readonly => '',
name => 'gruppi.odt',
value => q{data:application/vnd.oasis.opendocument.text;base64,UEsDBBQAAAgAABSQd0lexjIMJwAAACcAAAAIAAAAbWltZXR5cGVhcHBsaWNhdGlvbi92
bmQub2FzaXMub3BlbmRvY3VtZW50LnRleHRQSwMEFAAACAAAFJB3SUJn8sGrDgAAqw4A
ABgAAABUaHVtYm5haWxzL3RodW1ibmFpbC5wbmeJUE5HDQoaCgAAAA1JSERSAAAAxgAA
AQAIAwAAAN+D+XIAAAMAUExURRgZIR4nMCMtOC0yPDAtOz41LjExNDE1Pzw1NDs2ODg7
PCc2Rys8UDY9SDBCVjpMYD9RZkM0JUI9OkhAO1VDOkRDQ0hER0pKSkRKVUVQXUxQU05U
XFZIQFFMVVFRT19RSFhZWEdXZ0xeclNVYFZcZFpeZV1hWk1md1dhZFdlb1tiZF1kalxn
dGBRQWZaQWVYTGFbVmBdW2dkXXVgTnZnWGloaWRrcmJuempscmpvemtwbmlzd3NrZXhz
a3l4eFtrgVtxiWZ0hWV2iGt2gmx4hmR6k3l9hX+EfW+Cj26EmXuCiHiGln2Sn3aJon+S
ooJtWIdyXYp4ZoN6dZJ9aZJ/fIF9gYaBepSAa5WDdJWIfJqLe4aHiISLkIaKmouOko6O
m46QioqSmJOLh5KLkpeRipeXl4eZo4OZq4+WpIqZpIubrIuesZedpJCfsJugno6irYmj
s5yjqZWjspemuJaqvpmjs52ptZ2tvqaTiqOYj6uVgq2chaqcj6Gbl7CYhq2hjKijmrWj
jbaomKOjoqKkqqeopqSqq6umoKinqayqpKurq6OrsqKtuaqts62wrauyuLKmpbOrpLCu
q7iuprGusLaxq7e2tpqswpy0xqW2xqa5xaS6yq61way6xaq6yaG10bS7w7O8y7y+wbi/
yLG90L3BvavD1b3Bw7vCyr/IzrXD0rXC2LHM3LvG07rH2b3J1b3L3L3M5MOrmcuxnMa1
qMO6s8K9usq8stK9qdS+scC/wcjCu9XGrdPCsdHFu9TMvtrHuN/NtNzKut7QvuDOv+XS
usbGxsbM1MXR28zR08vT29PMw9HNytjPw9jOyNjSytbX18DN4MrW5Nbd5N7g3svk9NPi
693h49vk69zo79jn9N7x++TXyOPc1uDd4Ozhz+ni2/HizPPl0fDm2vPq2/vu1/rv2/jw
3ufn5+Xs8+/w7+Xw9OLz++zx9ez0+ev6/vDn4PLr4/Lu6ffy5vTx6/ry4vrz6v347fHx
8fL2+fX6/Pn28/z69f7+/gAAAP///6RRzxwAAAtmSURBVHja7doNdFPVHQBwdeLc1Pk1
T51nQxScZzjOhNEiHTzcqNWlMKXSOEiFNvZN5JTOqhOcyxbaSsMrObGF3OmZzhB5tmXD
uY4EZgQdh7027Su5tLGtpWmj68HkHV9NsjZLXnLP2U3aQlsKtlvBwvnfNO+8j3vvez/u
ve9+hMvIJREuAwYwgAEMYAADGMAABjCAAQxgAONSYETO2LnQ4ciz/3o8Fo1H6BNEIjbO
Ulla8fLEGfNSUu5pIUc3Jg+a5A82JXfiwqkIzfNvue11cuTrKSmzG8kPPiNk7d6Br6Wk
zOkIXp2ScldHePYUMf6eUb7+hfvyis3cr3IKECtsIDqtMlFG/OoT5PBVHcHGmAP5g9/e
6G10+ZCTlNzaGrFbEiXjvaqBeFL8B+4m5L1vkBsp45FX/n0NISV39l5LyNa7w1dOFaM0
64XcbMvqIqG4UG/CuXnOPC2OTpQxgz7YY08evP/RDN3s4Ixn6h5YdUfRjJYXr8cPZ625
k0b4dVYy3nuU8ck15MYTCcanlPHP63vp9h83TBkjFpGlbq8bExyRQxEs9WtrAk55opVq
Bn2wF1ceXPboonqF3N76twdWbSaPvPHeMuIpLbiCFupjT5Ou9PS/HLxiafpNm4cZlzHM
Ta/20u3NfwxeOR2aeLI0Hn7u4DKClnxLmddGGW8kGf+52iR+hTK23k/68aqnD96A624g
5MZOQhb+4dPLsVMivVdgl5+EpwmjTdJfJx9cpm0N3vzRvHeGGXf2flWuu7yPkPCM5/3H
bn8lUal++Bx59Cf+Q1f5E22DkN7kNnylMh1euEvvnanyk6ObmlNTd5CdqbZnShrI1oZw
6o7fpO1Ys5lGCGTPSrMQ1y/ocy8isYJ701rIQEYi5UBmkpEB3R8wgHHeg9dJCH1jhGR3
P8btgXaPfFEyhKaiIq4s2tOCRNHKCVZ960XJaOIRDVFPDXIiB99ucrRC2wAGMIBBIr7p
HSITY0jT7LG7R/9NguGeRp8zUBNkECVGomS6fCNjPpNv4muZ3JmpaOP+9DRm5pLdS5c0
0ImGFA35RsyVpREH7ws74mwxCRiDfb6YT/IIHULEF5AD0R5TxdlvYnY0BFgTkWQfbZO0
IkTpxk6zLbe1TM2bKpzm0s5esm1F3ayMBbdlq5/sWYyDKx7sZzR9iOVZjmXtxZHcB0/H
X1P5VtemNX6GuVc1f3uWulCVodGsWsbM3xhTac6+0sWsPbF1by5hSlRMevp3Uu/TzEnL
XsyoP6szbZyiF+6SvJkZS8W7FjK/l+b6vKnZz3YcLVSFmSWvarcsVv9Yk6teTpi8jlPR
f8dvjutYi75Yb9fVshzWVJjMhSazrnEgP/fsN8l78cMgu626EulsJtMTJmQtNNp2lRaS
F/hXpogR90XkmCz5IgqR6EjZH4sM5OcpIX9IjsTopUjEH2RHPKAX146fTwCLZ7+Jy43H
HxG6/FO3+BmnH4V+ovQbH2z/yTNESYQEdZT79GGcDEVIJjnHCkMsmdtQJJpiKJlCL0xR
9zfUgQToJ/E3GIKDp3y+UOD0yeHgH7EfSMT44uAfzHEw58BwssDovP6X7u8SGYzUbWQR
5lA7ks+ZMr4LtSLRZBWHaozDiUr2oSbuNTPehZHsEuwCb6+gZ3mrWE+8lqZa5LS12jTr
nVZCmi1GtxFX89r1IrJ4auzVWqE2jlwbqkQTwrvcJmLHDm0nzdVmK9wlmiwuhC2TZJSo
ZuUvzcxk7tl7TsZAjip7Tip77erPB4+16rmpzCK2iMlf+vjCe/YUzFUtzWRyVIwqR6v5
ESmwqFOzVqlsc6/TsHP7yCHNek36gocyVz+UQ++UqdKoGWaAMTEL52TmaLSL53eqixfc
cpy2Q3Uus+B7mTmZ2uXf/WxyDK9f4N0YY/7cpUFoFDvufhcNlwbmnT7eLrQmEvOyWK3O
XJ2JBTduxA5B6bU2VWPs6BBqsGjtI0HsdiL3m9jzJs2luxZjQWyMIx9v5THWbcK839Eq
CFhO5Grn6bmCCmyXJ9nEJxyi9BtLbpM7o85HIgG/T0ocxEacGxEtNirJiEDf52cEacT+
lDNGBbl/7AlJkhJPFBq+Lp8taf8XZx6aNOMSeVP1cA3e4oC20yNgURDcfJQ7MG7r4szK
/vrKHXG74CdYcH7Cvd27KaBtcwlOErZGY4gjeqzfF7QKUeJ2kyoUtdW71iVjdxcpZk45
ZhLXEXoDcswp8D6rKA/ncCyZg9dmETili2uJsW6t31PtJHFBREItN0HGAcNHlUXi3rjZ
9lQ5x61hW8xNDeONHFEZHdBypJfj9pEqznzI0Fmpc+4mXBUiwVJ/z25jL1tmJM1VXBu9
HDMa4rpCW0c/x1lI5UuKwUD0LPIrVVW7iG2bXvdE6VPkUNnpHHpMRVyu7ZfEZvA7dMYa
ykZKuCKbe8r8/ERLw3DcFxN4TGdP9OsVaGmcGLc0qkKyBzXSDpe+bXy+j7m3E8mcdGbj
wUI0jIyBqIvH3cnLmJZdyB/gBdoLYzcWKEzxhVA1PfRgZ7tXkIR28jH3Ds3BjttpDo5i
GtHnJM1ci4/YrO5ENl0sptMoPNG2ERkzBIpExx9yDUcTBUkZjOZOTB6JaJWHUrmTW0GQ
kwO0QF9iiOmlRkKiQy1V8oitkbE36o5VC8rpgV0yOEVJUs7TyshaHZvj6LRxg4PRQ5rC
PG2ZJoqqkq94fVllvl5TpD6O3k/MgMIaDavKLSgc2D2idp/cdJLbM6b3LdWoPrdxY3sJ
xEXP2wJPuWNfgf6EzTTYkTeVIb29rFixmfsShzpjVZGONRTL5ua2xOBFV7UNGbfXnNyN
Roxo0MmqP40ZoeuKDAoyj/2XNyPlPK9TCcK4x6cqsXCsb+QgodU5MrJH8E8gy0TNnexA
XZra4Buboe8cR2cP/uGdyER78allhOT/5/KZQZkYw8MWWkjXumJDSEBs1LYhEqzvKszb
oGWFRgerRcN9iLcxWZP7zlgeGrGT2Pe82zEFFVeZ/HxjhZhGSn4mfrMwdfkxtPzQiq6V
dW8sOLyofssdas+iw08ORfsgX1OszihhNeOP5/dr+gLqTM1O1U71W1/OtOmn1WmkLqua
WTg/y2POOvpQV9Zv9yxp/r5lS8F13uVHTjFmbZ63PPXn6cLKcTNekFPEqu7LzpulTf/z
l8JwMevyNJxqncm1oyRXLtH0KVvylSqvWoP8ef0mb81wpaoueHPBrTbOvXvcjA+zfSGL
EenZUq5tuv8w0NQIPwyc5x8GpvIN8iWWhpdvDJoON9SGsYTpKNMj0xPjLSnw+8IVrhqx
vx4H6BBW7kKdo/phV0vQ5GisJfRqO3YjhUcXlnGgvNO8Dr1k6jFmmjeU6nNN4XLTOCk/
KP1wfx4qfv4kc2Bl8e8qXus1jGrrhgP+nSwqNR1ZpyrbrmdYxWzou6CMLtSGQ+9KFpeb
tzqxy94+gPaMk/IT9Fccs8sWj4BMuc24/WN0fNSItLkNB62SpZsXsAtxtQRd4NKIucd0
uyH3uGsrbvfptebEJME9aiQdkDrOFv0CzcVL3+nZtP91FEPYKvK8yAtIEBtjnPHiWlI4
YOh8WWdAzxypL7VtKELZQsYulGck27mLbGWkvMEXc0fcflFyVuZLPsEn+bytF11pEEUh
F1uA/2wBDGAAAxjAAAYwgAEMYAADGMAABjCAAQxgAAMYwAAGMIABDGAAAxjAAAYwgAEM
YAADGMAABjCAAQxgAAMYwAAGMIABDGAAAxjAAAYwgAEMYAADGMAABjCAAQxgAAMYwAAG
MIABDGAAAxjAAAYwgAEMYAADGMAABjCAAQxgAAMYwAAGMIABDGAAAxjAAAYwgAEMYAAD
GMAABjCAAQxgAAMYwAAGMIABDGAAAxjAAAYwgAEMYAADGMAAxsUf/gvibjzscPCkGQAA
AABJRU5ErkJgglBLAwQUAAgICAAUkHdJAAAAAAAAAAAAAAAACwAAAGNvbnRlbnQueG1s
7Vzrjts2Fv6/TyG46P5YQLYkX8b2Zlyk2V6RpEEzARb9U3Ak2mYjkVqKGs+kKNAH2QX6
Mn2RPskekpKsu2V77EySSYBJRJ5Dfjw8V4qaJ1/cBr5xg3lEGL3s2X2rZ2DqMo/Q1WXv
zdXX5rT3xeJvT9hySVw895gbB5gK02VUwL8GcNNornsvezGnc4YiEs0pCnA0F+6chZim
XPM89VzNpVsiced3ZlfEeW6Bb0VXZklb4EXX3WdWxHluj6NNV2ZJC0LNsy9ZV+bbyDeX
DKQehEiQEopbn9C3l721EOF8MNhsNv3NsM/4amDPZrOB6s0AuxldGHNfUXnuAPtYThYN
7L49SGkDLFBXfJI2D4nGwTXmnUWDBKrsanSz6qwRN6sG0bhrxDvrhiIubu/Q6769Qy/P
GyCxbtiT6eAFdKofL55vdYEHXeeStAVRuZyEnZepqfP8jLEMqmTQBqrgOpY1GujnHPWm
lXzDicA8R+62krvIdzOJs6BOaEBnD4DCxDdSTTPFl4KIGhicge7OiCOvceh/v3j+2l3j
AG2JyW5ik9BIILqVDJeb0LjS8YDjkHGRCWbZ3WHCbjkZtrUI/GZzl70p6Yp7Xi0pwBkO
wPTB8Mwbgjef9QqevF0hZiWFUG5xF4siyvvNVgbbGkiazIxBRbZOnq+yOLRkMYVFQOxK
BIhvQ8yJ7EK+YpsXRshrvc8OGDKJXbkRCg6dYD/1GNmSaodhzAwiUCAwFBbOc9zF+MCD
227DSeNg3rI8YslRuFE0FHX6cPXjQPaZMjxCAEhmyqUFTm+R5gDaf0SDrGEJuYC5RC42
Pez60eKJ9uVZs6GfJe7L3gtEV8i3ewY47ZQkIP5d2tMbtPM/JxBY1PYYr0EAy5qB/o5C
Fv2zTKhbe0ZhcMlgrjAFAnBSnAWIFihCIlxw4zeIE6W/O8A9BTK/BlHa3jx1tCFRdMzU
+eUiGnUSC9B1kMrR0NTqjTeUQFqJjRevG7GVCbuAu4sEDo5Bl6hdoz4eP/ugyU6SdhQL
UDxBXFONkxmQ+lnAeoWuse+jb3gchiybNsGrPWzKrJ7MEHwB5oLgKCHeEE/mJZP+zBkT
0HWd0iKfrMDMA8RXENMU5hyEjnj6T2sRQWbmxwEtAdONVXxJewLT7k+mkynJbJJj3yxR
jGeT0T8ORfzlvSO2+pPxeNKGeOJYhwP++gSApxf2uA3w1BlNDwb87UkAO7N2wOPZwYCf
ThoQA00ZLzTl0S7ZPESerpwtCRAarhn3ZCFEGcV7Q3ojS2xyOjtPaAN0Z15zjN6a11hs
MKYmZxtIq5fIjw4FfSpnYO9wBuPJ/jufIL5/Z2D3h/Z42IrYGY0uDkb87N4RD0Ffhq3u
a3hhD509EL+yyyBDxNGKo3CddkCDPFJSD6bm+hYjMJtsCRlLydxkumomSg2lmKytNMMv
cSTI8s6MwBhh0A1YYU6fE7lI5oo8VJAuZHMwj2qMyDtodKahSBNkyOLnkCHD0FBuAmDP
yvdsQZdpcjPJQU0oABFNhy53yoMNH98m3d3l7tyD3A8TUYOE7OXUGrrtEkppGiR00Sqg
/eQzPEQ+V9KWfnasn5/p889oLxWFwv70CmoPTyZ+PXSj/FV39w0Y3e8GHKGrZ9C28Ueq
baez9XZnuJ/0Kznd+1A122qKHEs8cnZFDk3TZJhWu2Fae0nr4vy66mKqjoxP7hw/lD2Y
nn8PzpRANW3BEKo2e9K+BSnNWbZgdtQWyEwKZHcyn3F0tnm/wrKte5XWB6CvD28LDqq0
zqawD8zB2gfVR/csrUlL9jnuO+PWBU/2W+9x9c5DNlDndAHFaVc5Z78tOKjieS0Q9RD3
GlWt1aSmk9mFvQ/GlkJl197rY0XTx0uxPQBNGjlZrautgoWVtmsmhLwFkDb7hGJzjTW/
bVmf9xr0LG0l1AMZJgPkRCZfs0QhkveUiIeZXgHywzXKpB9TV8Tq5Zi5ge7L3hrRlVT7
hEBhUUelclZO3Ew75J0HIDQD5sH4PjfFdf4ADnaUhdF2G+pE2LS/sK71XbjGFAm896Hs
K7ul9lk80W+w1RNx85PKt+/zJfHV8R/jl73P8ET+3WfmljriwJkbBVR2B90PVCtBU47e
aGt1nuccvuOqEq1aYTbG3+4TVsLFvhMuZ/jC2mPCinPcc8LElXefsOLp9p3wAs9cd48J
q2+WuqiaepMs/RllPEiin6IVHNFIXxtTb5eSweMIoiv4QLYxFX9iRYLHuOAOWSykO0s9
Sr5LuTmx5ixerXUsKk5RJRJ3YR1NyCIi1A0S63ND++5KTK9e6KjLKGUgwEJgbkoXrl6x
5eThg5uO0QrLQy/V4LKYCg4ifvM6N166kqIcozXy5I22CvoYAglXyyzIIB1uk8SkdLxa
Th0P5G1ZQmMWR8UtuOlCVRB0E2UinLeYUyUcvd3yBSRy3664vNO01QTQG51oVLYjdV41
VzaakvJ+LktN9yHtfZclNsmGpB3PXhZHVPlO0leUZ07ULQQKe+Zba25u1DjfMuasd03K
qLOu7+pwZ73NyBtI1P7iAFIQresVFYxc5OM07ckNy7FP8LKGIVOpJrPNCBJt2PqIPTxZ
JbLfsydTFqyDv6X+PHquR8/16LkePdexnmvFK/l+UoJk3qupJIF6j73NcDVWKbpHAgY9
ReaacfKOyUu6abWaHISUCW/kXO6WLCCe56cTydLVBFvYZIVw4vpk2Qw1c9pq9e2RvnCS
dGTXgKbTUf5aR0xTu5Ry5Fjb2baYlbVvjijt0J91qNo4xJ6Z1XORFAuYe0Ay5czWA54U
5uAskNV+pRfUoeYYJCe1Lbs8V6ghKI+gBCYRmoQu/RhTF5tQz28dOpMt4IfcmBc8iQ/i
3RCxNvX3RHsW2iteKdE+Ls2yxo96dUK9GjReBk46rpl3lz3IoRZP1MdsEf6PBpNcKq42
GqrJI1Hoo7s0e4Jl38gVQmqlurUWf+f7oEQ6qZEYjxrsKr0AfdwoMrU8dpB/6Y/vlNjr
pabuR6qfyV3J2hvXuksHzzqCwkDJzbldTP2nann7832Z4knMR7NFoLkhRgJ7l73RgSN/
vXNk58CRvy3zrdWNM3XjtNgBLaUZYJh6WJATUipRTbefriAw0SS5lye16tWF2vlQ60UJ
Yvkth7J2F2wBHASk2SHWXIi64CKSccvO4Z06er5Vupc49u0cKvPIHHPhhF+f0d6s5jmv
qm9kQ1s1tMvWW+WRbTt9vlPPQ9WQrnOQrALTtfxIzTNXmAUYkkLFIb/6+pLJcQzLcOyJ
lfxMQaoVcuwKJN/XJK3ZUKH6uvGFIZmfJ+yFYYztv5bxk/FSWV5FqNtPIChlQnkdAO3O
XYhbgvHF94jid8aff0gQ2P8FRtj2SToPlHHhWPbEtKamPbmyR3PHno8dRag6k3PmCMu6
BvYHfDX438X3f/7xZFDf1agl8t1I6oZA4WrUaNJbPDXcNfE9Q37oJwvD1N0AQzvvRW/x
1+//KxgLPHfnh7llbYWIrKIMZHgY/u9jz/BJJMAqDAgsKrpBU8jJDfStVG3ODbHGhgzU
Yb8wm/5/mAtNuU3adpZNNDVaV+broCrbnsGH0DVo9UGHOCXnMKf0arZD2+ze4psf37x6
9UN+1+bGr78a3/QpWLrx22/HbdPJV2jDEhRcD8uPCt+BZp0R9ehY1FAay+8v2dGQ37+O
Hhg45S2KI2OlXRsrneZYedElVlpja/TRxcpHn5vT58PU1eotXsLGdhDlfUzV6r7BcoK8
58Y0fiCwogIsHyu//ECwoTy21YowTtEDgebmoUnTh0TugUAjeWg0kockKnI9EHgFhRMo
CJERYb//YNG1AvuYgrNzjuBsQguUcMXwrL9CfAzPD6GrqtGFloNOcFpOwyYHqvtEpeVP
W8151Fv8lDfnPQqlcyzhYoc3GuslFpcQ/Ay+PDZ2MWaLLFf3H+CCW3mG4LIha3GF8Skt
OQ7ledcntWQPdvkTWzJRydsnteQQ5hVg0J/eovdZcXuM3vl+K/1NI41ySgj2e+eT/SqQ
Pd8VZb+Q4zC+Zyd9xzR8b9n48PGo7P29VhrP7dnDea301+//Lei8fFVUeP2TvvWJIV5E
hlgjYQA5gz7Bci98jAYHc5Y3Puc79gOP+tXzr14++8F4c/XVy6vvznGyAHP6bEXomebC
ZoCIf+aTiffnC0ePvvD9nUvc74HAQRo01XnVy7SAN/STy1YHVfTHYVB2fuY5sTT3XXPu
zAobDXSU/8WVsn/7pC+ipU/l3wi/+D9QSwcIWxQLYXEMAABSXgAAUEsDBBQACAgIABSQ
d0kAAAAAAAAAAAAAAAAKAAAAc3R5bGVzLnhtbO1c3ZLbthW+71NomEkvOkOJpP7VXWXs
dJo643Xd2L7OQCQkISYJDkitVn6avEzeqwd/JEiBWkpab52d+sIe4RwAB9/5wcEB6Jsf
HpK4d49ZTmh66/h9z+nhNKQRSTe3zqeP/3Rnzg/Lv9zQ9ZqEeBHRcJfgtHDz4hDjvAed
03whibfOjqULinKSL1KU4HxRhAua4VR3WpjcCzGVbBGDde0umM3eBX4ounbmvLW+aNV9
ZsFs9o4Y2nftzHkBU7P7mnbt/JDH7pq6IU0yVJCGFA8xST/fOtuiyBaDwX6/7++Hfco2
A38+nw8EtRQ4LPmyHYsFVxQOcIz5ZPnA7/sDzZvgAnWVj/OaIqW7ZIVZZ2hQgY60mt9v
OlvE/aYFmnCLWGfbEMx19Q6j7uodRmbfBBXbFp3MBndAFH/dva1sgSVd5+K8NahCRrLO
y5TcZn9KaSkq7yAdVIgbeN5oIH8b3PuT7HtGCswM9vAke4jisEScJjbQgM8fAIeL77mZ
am7GF9068njAcEZZUQqy7h6gAJ2gdK9tkcTt7sWpmnXDosjKCuIMB+BqYOjuPcH775xa
5DytgHlDASIMPdZFMJlx6mQH3xtwntJtQCVVUGWbMuyv6S6FRcBWoQDEDxlmhJNQLLot
aiOYVhbTC4ZUe4UxQi2AEhxrDy2XZB2GUjfJXZKCYdJsYfSuRYs8HxY29X38ZcBpLt89
ID6qeYxNM3CWeodcU9gd1yjEboTDOF/eyMhWNvfkby7krXOH0g2KfacHIUyzJCQ+aIoz
ON3/LYEwK8DrfYDVri0D/RVlNP97k1G2Or3a4LyDu8EpMIDLMpqgtMaRkSKEoHaPGBHW
9Yhwr4Attkik29unzvckz6+Z2lwuSvNOsABfB1SuFk2svvcpJZBj4d7dh1bZmoxdhDvk
BU6ukU6ZXas9Xj/7oM1PVLtMLLWUEV6jXazSTT2yEmnDULYloaN51W83AxfHrCCQnvJl
5AWjnzEkCDGFjOS74WgyRiOnx+MdhIA4LinTYL4OwYXWdLGHoVyaFcK9U+ry36pLvkUR
3bsgbY4L9+HW8fq+P/NJaqUfjukFZBkuJGXYzTMUQkrobikjXygPVJLbH53ivudrCy28
sI91HveI1zaqgjuG5exJsXVlor1GcW7YUYYYEsjXcBckzu+iXUH5JGBcJMJUsqI42yI9
gZBjxTCCJBaURcJCU3gmwYVLwANunZi5xapmXiSNMN+++YHEXI0WUssImyFYEM1ybn/t
YpfsXO6j1exyDDCkXLlicmU2BdvhmlBtkRnMStBz8gXofpAVoi0Gx9qhDTThVDSEsCEW
DAzn04cSIVzAxuV+xiwVq7PO6UJeg1JrgKkY+eSa0ff646zEWsuhqV+2mqIE0oQf3x1P
zbPvGD9Yw4SYsmSQ625MWVK3pDlpSXrzzqm0VwsLXWJFqW7npN0C/NtDtsWp0JwboygC
3IUsIg7EJCGl+B3NO9ulYbGTA/I4AquEdYMeH7d/bbduRCAQpHwSrz+aB+PKO+sukgGa
lWv+346/TTs2zQzrWNW0PYYTRFKXH0q1AQZHTNku3zZYrnASeWYwgmaMTfOR5Y8VZdwn
uL3BZgHGE6Ms59Z87cQuo/vG5NDS8M7PGGduQTe42PL6Ave+xyY2J5Q2/QF8KUIsclqD
hFZejPIcxAM/qrzqeLx/YRQZ/tw6HDSUpTPXLkrKXdZk+AgNvwberysaHWxiPRbOEsQg
1gBkmdjZJxMROyrCihYFP3R7fW82FDR5ygrB5OHfHYqbm2qpBpETpCInQPEeHfLHIk9L
WBEJuo4qXz8/bwawUeXI58UgNbVivTBp193bkmdNr8Rvi4LWdZwKaEqQDixa1pK1VdqS
o13eKoRyiSvnfcRpbY4A22IWo4PhKj2TfI0jXuxjre41nwZd3UtkBFtMNtuC7zTe991h
eguZwiXrPxFnYj5kB8+uWWPQwRr9LubYeeU/InFee0Llw1IZOjPC6ih6VYQVtxSyhi7O
NXmdIsxDl9i99qjbkqnJNt4DclY4HMIRurMaJWqKaul8sZq7ZVqGDCVdSdHZTt7AefHh
Ca2EiPFOWskT6fPb8TWe8fAS/3O62nkgHh39mw1aRJoTWeYZ9keTYFKdrIpDBvKGmNeM
DZ20dZ/04VwWNLszHsMNXA1xThYiOu6JfIflUftHHkvEzYh1Y+RsvSbP82hNiS6KYvwI
nT5peFuh8POG8RuE6hgLeaJcwRm5hcaxkcnbYLwi2W9V11n7jSw7xGSTltaphvltlxdk
fXD5cQwm3cNJ7WttKXuVnKxoHNUiiyTo0NRGLgOPYDjSkxCJ7gpZ0ztS178lxWkwxvge
x4pdLoo3QHwsD1e7xOV3pwgEL2Hm2Y3q2gw2Jkn5uQt+ILZrrIuSaAVkoQ5+12QbtsGi
xhaNazg+0z2O3NVB5lkQHxxj8rIAVMUZrz9U+YXQDRHVz1vHrdpV3hHjdaHZK4StywVq
G5IdMQ5eGMajFoxHdoxHz4Hx8IVhPG7BeGzHePwcGI9eGMaTFowndownz4Hx+IVhPG3B
eGrHePocGE9eGMazFoxndoxnz4Hx9IVhPG/BeG7HeP4cGM9eFMa+FWHfhq//HOjOXxa6
/RZ8+3aE+8+Cse+9MJCDFpADO8jBlSDXSSbyKS1wDkfJdE02O3VLVBJcdaZeU1rw3zYl
+Gqt8pHNPYp3/IJdNeqOubF4cb1u9pEnZn7/zsfTTxr5ertLiNOoTUBiF1APzxGpJLBN
03rel8+TxJXgfGI8J7DBo0apYOCqVTSShky8HedpnfG6S4xWPeri97QwJgldTThZivGb
1ZVHbqZl855E/M21KMTxFcn7alUpkVZZVlwSdJBPLtwVLvYYp/yuOTceN51ROPL7r6zy
8pLULkkbYsvGY+lVu1qEKEYaemE4dhscwXQy/dvZor7+H4k6O1/UV3YzcEMcx01Joems
0iDnyFAkv3Lx+t5wpsOXfN+gSpV6FmMwkkAQqBV0j+c/VydXLbTDMs5GPrhYIEnTrwl1
nTIhUaSu3v9MenlqGORV4J8Ghrv3R4bZpcytLofOqWOLDa5DGbv7AxP1yLx+BRrM+E1Z
+c3FguUEhva8AASOPJNSCd3kMWYyL+Hk0E1iWecW5M5uePf+yPIuu184RweQh3x9DfhD
uwb89cwbhqc1oHlaNCCHbtWAIJ+hgeHTauAyuKxGpdY7PbncM+1t9ELtrcXhn8DcTvv7
mfCPnyDOfmsAXWyf/JQFp9YDnPnqMGWJ71iYjvKhDdaZ56y8TBCt5ZMqv/XEo0aHE1Xh
Ukb452Pq7EcZ7NCkMM+46s3PdDZt3AtVb36OaWUd+IjCpHQVSQpj/Qqi+nxF7Ph6wV75
hYdB08v2jI861OnWTdBDjV59HqQYcqzfOugp+p43NQDUb9PhJAU4ig4yZ5nPLExozV+A
W3mqAz4kBDQmZXhAEQ8Q8pQpz57VSUMJFYy/r15cy895PPHHMDK7yegFb4U31Z8OqzaO
BT8A1599gcJK4PrByLPWPzy7htuspczyTmeHCtMD+AU/UuvXY/I5fal9/dyi9UunChrb
4tWqxQ8riMsbWRng32/brunfDadOT7FUBQCVvwpZyxESCBBbzatMIKbyUblq5eFtObgZ
mD8rAQ6Xdz5gxPj6jhZTVTOOyxeKkKC8xKi0JNXIkarh0XxEY9qjJcJJnSxvZBlD/K1K
GvVKiWw72pf5QEZXdSRv5e6/EmWlMzq8bnZgdN8YAY4dJyb0qy9peWXLlS+m+BcwoDtV
4sp0Aazqzk8ly39APIEQjXo//fLp/fs3qkqY8XJhQ4BzRHp9sUiBs7xDOU0//OdtWfNK
IX6KzWN5E4WLkGFUULb8GaX4S++P38EYNjj+7WZg0Dgft79l4PkT15u5/uSjP1oEk4U/
FYyCeCPfj+b8wzfmkhR2B0iVlj//8fvNwE5Sgi9f9YRRSsvqG6BZRD6F6OCk2s+1g+BS
0Icigl2l8IvnHoENogItepKHK0aHZf6Rv8ks4mDJpcu4QsW+7wbDj/584XmL4bw/HgbT
aTD0wcB9fxAMB/5E6UEq/jydmC2nljI+2gjKn0Yoq6ykEfR0c+O/hln+F1BLBwituM6j
AwwAAFpGAABQSwMEFAAICAgAFJB3SQAAAAAAAAAAAAAAAAgAAABtZXRhLnhtbI2T326b
MBjF7/cUiPXW2CaUJBah0i6maeq0Scuk3UWO+UrcgY2MKdmeZi+z9yqYPyNtJo07n+93
fI4NJHfnsvCewNRSq51PA+J7oITOpMp3/rf9e7Tx79I3iX54kAJYpkVTgrKoBMu9zqpq
Nox2fmMU07yWNVO8hJpZwXQFarKwJc1c0KCcC6l+7PyTtRXDuG3boF0F2uSYbrdb7KYT
momZqxpTOCoTGAroE2pMA4ontm/4v6V6dllJaz0H9fhQ2sWFhER4WE90brKsuHaAjl3h
riG3HD1JaN/63nj8xYWHfjrdbl8jTVwZqaSVvEDCALfapB+5gl/en9+WqxyKxwRfpQav
W3W7oy4Y0pDQGJE1InRPt4zeMrINok1E3DPuc+lIMsEW1g2i8Z7G7HbjrCSerBPW8//s
uZgN7SDrOqscZY1xmemXPf0Qkk/h+uvY5hVxaRQ/RQF1Gq5e4KM+wDkoMC71Xh4NfHYX
jG8DGkRBeHMvVXM+fN/EhzjyFsChMvoRhMWUlOTmXSOLDIVjzN8dh4T5V6ht17K2UnhO
t/xYABK6UXbnr/xBlCXPZ5GMoj72WS/VakHSWTM8N7w6zftOdKtNNolxNIri1PHCgpnx
eD2OVPeS25O0UFdcdDmvyBX1cZrgiy8SX/v702dQSwcI6qkzc+0BAAA7BAAAUEsDBBQA
CAgIABSQd0kAAAAAAAAAAAAAAAAMAAAAc2V0dGluZ3MueG1stVrfd9o6DH6/f0UP7x3Q
dmzltN0BWjY2WjhA13P3ZhIBvjhWju0U+O+v7EDXUbKxJO5L2/yQbEnfJ8nK1ad1JE6e
QWmO8rpSf1ernIAMMORyfl15nHRPP1Y+3fxzhbMZD6AZYpBEIM2pBmPoEX1Cr0vdTG9f
VxIlm8g0103JItBNEzQxBrl7rfn66aZTll5ZCy6X15WFMXGzWl2tVu9W5+9Qzav1y8vL
qru7ezRAOePzY1WlT79WhYgviuwL6WKcsrNa7aKa/l852S7ylWnOKjc7O+y2f3O1VZD+
OuUGImubk+1lu7TrCqlsPnNYvVitcui9X9/5Ts+3FLAJxpXdHbOJ6Y5AOa/cnDUuGlfV
t1KOl9yHmTkoulZM7hMPzeLwmusfG+fFhH8BPl8cXna9Xjuv55M+XuBqBCGFGXQWTM5B
72mYIgpgsnJjVAL5dPRkW+FKwz2GkCV9xoQ+WvxpxOJTLkNYQ/jWWIdjzL1D6FCb40ze
C/eWqo3i1tg2nM/yuzIz9uofavWcTrRys9Dyvt7ILVXzqYDyweLE+kC3EzzKhIkFYW7P
OdltNAajw+47b3x4n0/4D8RoQqL2A26ByhTipD7bYGI6KJJI7uO6LOltxGVpwH5rly4L
DKrDa683cq6+p8cgIDAQdhVdyLH0AxdfE0zW7S1nHX6AUuTxSTW9kChmKEX/TXYdEouZ
oUIdkwE8OM3Jt5wxZF6SSbp+kt1mwXKuMJH7RF2Wkg6SM1H42kNLSjTOfQfgUwydTv5n
xeIFD3wt39GsTx932frhLTi3Wbh6dKDEoLoKozGYZD/hlBbuE1iboWABLFCEsM9WZahp
xbHYDJlic+vVe6aWXVQRMxN8SKIpOJt42twIbCMAmSgrIH/CpgMSTtuZc+lB/h2ZJuwS
jDNjtIDwcaIc+1jnP5FXxhETwoOenzxn/W/tdavYyrF9+co6gscxhEMemERlQ7uAhq5A
ZgyjYuoBI+d4H1oe5ZRapqVTswOIDz0uwsYbTTd8xdkWJDOBK09MO7Fm8kXjY7K8gK84
9YJBi7kOi/UQVEC1F6WjRsMHLFAI0gJ3UWw2HRDCQrF8g90zs2gzDbYbbwk+l/Y4p3w1
rTCtewezGRWOPvzS0302BXG7PZHylZpAFaoQBomxlu5TghP/chCh9plMe3OJCrpcadMn
rT1qBaTpSZ8qH+OQGbDlzwSiWNDfnkDepuJn6ZEAqavH1TcAHxWco/AQwltGWYnAVyik
UifTinVLhmQVudRUqFl/d5gIEuHqfR+e1jAQ4RYU90DrzS78i8SwpExELb+iKnccs8BP
2I7ZM3wWOGUvBEIGXHoKLT0C65VnmGAKyfIhMtJ8v3omP1VuLmpnlx8bOQ+NfunjR5O+
L451Ke+3fV7RtoZiV1nweeKmL5zQLW2V7mMDoavKHUVtAdEyY8OUhzDq2hTVSgymtF6+
gpREfCakA+YqfxudBakIiAc7GMXUxNghVunHq5ajvqcDsoHsCNQ+DkDtToxPj28ThiU+
O0C0TOsOdTNGHws+X5ySRVEkNo/lrQ2/gZItzZkcJpL6TI850R6SgBpM/yOOHKLmVlNZ
kZ09hCKtU0c6L5FYfCTVZ3KeEAtneAZyOqODidWfIfVxnHM6wBR5NyOKjqii2jDn0hZN
uSXcyfC37xc9vz+C6IgdDA+Y8NxqjZOpsUHWFRuqOQMiNQhb7j9//L2l7gk6Irf9sIfT
A9J1tybsSCb6wEI/qSJRily+K/3t7zEmKsgfeC0hcOVo9StOO0wGkHkmWIS20RCjWXbz
yZsWQf6qfGekPx1lFipm0l3szmdjTz22XJOeAH6AQorXP4RqsV6l5QZraZtCSl/mAbpH
bKl91LfbT0O2AUfZ8xvsJwsLnMZFm0tGeeSouQzGryJrvFC2uXs5F/EAcpTUgP0MhIGk
goCqAR/mIkUjxH1PuG7vrNa4oJ+cLG82AvQD3sKMJcKHp22LnZaZ2ePInB+SuKNMCt+x
wXhXhZXv5lt8QPM10YbPNjaQ9BM3i3smEybadhbgwWZO5Qgos1sotoxR9rSHGih7FOaj
H/g1XVF/EzEZHuhtXMDl7Gz6yMIRsRhK8QbqZdmsw2I7X7LsT1jUAzl8W9r6M1ixkTKo
g7Pkv2RBO2hr6ZcGYVe5PSl6VFH15qrGPBSV+WVJ9c0HnNWsT1tv/gdQSwcIUsuRKGUG
AAAcKwAAUEsDBBQAAAgAABSQd0kAAAAAAAAAAAAAAAAYAAAAQ29uZmlndXJhdGlvbnMy
L21lbnViYXIvUEsDBBQAAAgAABSQd0kAAAAAAAAAAAAAAAAYAAAAQ29uZmlndXJhdGlv
bnMyL2Zsb2F0ZXIvUEsDBBQAAAgAABSQd0kAAAAAAAAAAAAAAAAaAAAAQ29uZmlndXJh
dGlvbnMyL3Rvb2xwYW5lbC9QSwMEFAAACAAAFJB3SQAAAAAAAAAAAAAAABgAAABDb25m
aWd1cmF0aW9uczIvdG9vbGJhci9QSwMEFAAACAAAFJB3SQAAAAAAAAAAAAAAABwAAABD
b25maWd1cmF0aW9uczIvcHJvZ3Jlc3NiYXIvUEsDBBQACAgIABSQd0kAAAAAAAAAAAAA
AAAnAAAAQ29uZmlndXJhdGlvbnMyL2FjY2VsZXJhdG9yL2N1cnJlbnQueG1sAwBQSwcI
AAAAAAIAAAAAAAAAUEsDBBQAAAgAABSQd0kAAAAAAAAAAAAAAAAaAAAAQ29uZmlndXJh
dGlvbnMyL3N0YXR1c2Jhci9QSwMEFAAACAAAFJB3SQAAAAAAAAAAAAAAAB8AAABDb25m
aWd1cmF0aW9uczIvaW1hZ2VzL0JpdG1hcHMvUEsDBBQAAAgAABSQd0kAAAAAAAAAAAAA
AAAaAAAAQ29uZmlndXJhdGlvbnMyL3BvcHVwbWVudS9QSwMEFAAICAgAFJB3SQAAAAAA
AAAAAAAAAAwAAABtYW5pZmVzdC5yZGbNk81ugzAQhO88hWXO2EAvBQVyKMq5ap/ANYZY
BS/ymhLevo6TVlGkquqf1OOuRjPfjrSb7WEcyIuyqMFUNGMpJcpIaLXpKzq7Lrml2zra
2LYrH5od8WqDpZ8qunduKjlfloUtNwxsz7OiKHia8zxPvCLB1ThxSAzGtI4ICR6NQmn1
5HwaOc7iCWZXUXTroJB59yA9i906qaCyCmG2Ur2HtiCRgUCNCUzKhHSDHLpOS8UzlvNR
OcGh7eLHYL3Tg6I8YPArjs/Y3ogMpuVe4L2w7lyD33yVaHruY3p108Xx3yOUYJwy7k/q
uzt5/+f+Ls//GeKvtHZEbEDOo2f6kOe08h9VR69QSwcItPdo0gUBAACDAwAAUEsDBBQA
CAgIABSQd0kAAAAAAAAAAAAAAAAVAAAATUVUQS1JTkYvbWFuaWZlc3QueG1srZTBbsMg
DIbvfYqI6xTYeppQkx4q7Qm6B2DESZHARGCq9u1HorbpNHVqtNxsY/7/k7HYbE/OFkcI
0Xis2Bt/ZQWg9o3BrmKf+4/ynW3r1cYpNC1EktegyPcw3tKKpYDSq2iiROUgStLS94CN
18kBkvzZL0enW3YHsGb1qpj8WmOhzPfDeepuk7Vlr+hQMfFIZCo7aIwq6dxDxVTfW6MV
5TZxxIaPwPyekxOciIk5DPtDcl+ojI2CriHvsXvAYJzqQAzns1y0Rxr48hwfCA/kYjie
pRvpbCEuLuuA1PKsQJQXc3nancfWdCmMmxHXQmkNFnLqg9AphL8H/z+vJ1c1JhwQeDJc
3yvMfJZLjYemfcI4d71chrkRv/6A+htQSwcI9QcjhxwBAAA+BAAAUEsBAhQAFAAACAAA
FJB3SV7GMgwnAAAAJwAAAAgAAAAAAAAAAAAAAAAAAAAAAG1pbWV0eXBlUEsBAhQAFAAA
CAAAFJB3SUJn8sGrDgAAqw4AABgAAAAAAAAAAAAAAAAATQAAAFRodW1ibmFpbHMvdGh1
bWJuYWlsLnBuZ1BLAQIUABQACAgIABSQd0lbFAthcQwAAFJeAAALAAAAAAAAAAAAAAAA
AC4PAABjb250ZW50LnhtbFBLAQIUABQACAgIABSQd0mtuM6jAwwAAFpGAAAKAAAAAAAA
AAAAAAAAANgbAABzdHlsZXMueG1sUEsBAhQAFAAICAgAFJB3SeqpM3PtAQAAOwQAAAgA
AAAAAAAAAAAAAAAAEygAAG1ldGEueG1sUEsBAhQAFAAICAgAFJB3SVLLkShlBgAAHCsA
AAwAAAAAAAAAAAAAAAAANioAAHNldHRpbmdzLnhtbFBLAQIUABQAAAgAABSQd0kAAAAA
AAAAAAAAAAAYAAAAAAAAAAAAAAAAANUwAABDb25maWd1cmF0aW9uczIvbWVudWJhci9Q
SwECFAAUAAAIAAAUkHdJAAAAAAAAAAAAAAAAGAAAAAAAAAAAAAAAAAALMQAAQ29uZmln
dXJhdGlvbnMyL2Zsb2F0ZXIvUEsBAhQAFAAACAAAFJB3SQAAAAAAAAAAAAAAABoAAAAA
AAAAAAAAAAAAQTEAAENvbmZpZ3VyYXRpb25zMi90b29scGFuZWwvUEsBAhQAFAAACAAA
FJB3SQAAAAAAAAAAAAAAABgAAAAAAAAAAAAAAAAAeTEAAENvbmZpZ3VyYXRpb25zMi90
b29sYmFyL1BLAQIUABQAAAgAABSQd0kAAAAAAAAAAAAAAAAcAAAAAAAAAAAAAAAAAK8x
AABDb25maWd1cmF0aW9uczIvcHJvZ3Jlc3NiYXIvUEsBAhQAFAAICAgAFJB3SQAAAAAC
AAAAAAAAACcAAAAAAAAAAAAAAAAA6TEAAENvbmZpZ3VyYXRpb25zMi9hY2NlbGVyYXRv
ci9jdXJyZW50LnhtbFBLAQIUABQAAAgAABSQd0kAAAAAAAAAAAAAAAAaAAAAAAAAAAAA
AAAAAEAyAABDb25maWd1cmF0aW9uczIvc3RhdHVzYmFyL1BLAQIUABQAAAgAABSQd0kA
AAAAAAAAAAAAAAAfAAAAAAAAAAAAAAAAAHgyAABDb25maWd1cmF0aW9uczIvaW1hZ2Vz
L0JpdG1hcHMvUEsBAhQAFAAACAAAFJB3SQAAAAAAAAAAAAAAABoAAAAAAAAAAAAAAAAA
tTIAAENvbmZpZ3VyYXRpb25zMi9wb3B1cG1lbnUvUEsBAhQAFAAICAgAFJB3SbT3aNIF
AQAAgwMAAAwAAAAAAAAAAAAAAAAA7TIAAG1hbmlmZXN0LnJkZlBLAQIUABQACAgIABSQ
d0n1ByOHHAEAAD4EAAAVAAAAAAAAAAAAAAAAACw0AABNRVRBLUlORi9tYW5pZmVzdC54
bWxQSwUGAAAAABEAEQBwBAAAizUAAAAA}
&>
<br><br>
&nbsp;
<& /input/string.comp,
id => 'doc_val',
description => 'input doc_val',
rows => 16,
cols => 128,
length => 1048576,
readonly => 1
&>
<br><br>
&nbsp;
<& /input/button.comp,
id => 'button_ro',
description => 'button',
value => 'button',
caption => 'Readonly',
readonly => 0,
onclick => "var doc = document.getElementById('test_document'); var ro = !doc.Readonly(); doc.Readonly(ro); document.getElementById('doc_val').Readonly(ro); document.getElementById('button_gv').disabled = ro; document.getElementById('button_sv').disabled = ro;"
&>
&nbsp;
<& /input/button.comp,
id => 'button_gv',
description => 'button',
value => 'button',
caption => 'Get Value',
readonly => 1,
onclick => "var doc = document.getElementById('test_document'); document.getElementById('doc_val').set_value(doc.get_value());"
&>
&nbsp;
<& /input/button.comp,
id => 'button_sv',
description => 'button',
value => 'button',
caption => 'Set Value',
readonly => 1,
onclick => "var doc_content = document.getElementById('doc_val'); document.getElementById('test_document').set_value(doc_content.get_value());"
&>
/tags/2.0/htdocs/test/test_file.html
0,0 → 1,42
<h2>Test: file.comp</h2>
 
&nbsp;
<& /input/file.comp,
id => 'test_file',
description => 'Attached file',
prompt => 'Please select a file',
readonly => 1,
name => 'gruppi.odt',
value => q{}
&>
- <button onclick="Id_test_file.Readonly(true); document.getElementById('button_sv').disabled = true; document.getElementById('file_val').Readonly(true);">Readonly</button>
<button onclick="Id_test_file.Readonly(false); document.getElementById('button_sv').disabled = false; document.getElementById('file_val').Readonly(false);">R/W</button>
<br><br>
&nbsp;
<& /input/string.comp,
id => 'file_val',
description => 'input file_val',
rows => 12,
cols => 80,
length => 1048576,
readonly => 1
&>
<br><br>
&nbsp;
<& /input/button.comp,
id => 'button_gv',
description => 'button',
value => 'button',
caption => 'Get Value',
readonly => 0,
onclick => "var file = document.getElementById('test_file'); document.getElementById('file_val').set_value(file.get_value());"
&>
&nbsp;
<& /input/button.comp,
id => 'button_sv',
description => 'button',
value => 'button',
caption => 'Set Value',
readonly => 1,
onclick => "var doc_content = document.getElementById('file_val'); document.getElementById('test_file').set_value(doc_content.get_value());"
&>
/tags/2.0/htdocs/test/test_image.html
0,0 → 1,47
<h2>Test: image.comp</h2>
 
&nbsp;
<& /input/image.comp,
id => 'test_image',
description => 'Descrizione pulsante',
readonly => '',
value => 'data:image/gif;base64,R0lGODlhEAAQAPYAAEV50Ud70Ul90Ut90U1/00+B01GD1VeH1V2J0mWR2W+X23ub0nGZ3HOc3nSc3nmf3Xie3nmf3n+l34ODg4SEhIWFhYeHh4iIiImJiYqKioyMjI2NjY6Ojo+Pj5KSkpOTk5aWlpiYmJmZmZubm5ycnKysrLW1tbm5ubq6ury8vIGk34Ol34in2oyp2IWn4Yep4Ymp4Yut44yu4pKx5JSz5ZSz5pa05Zi05pi25pm35pq25pu35py35pu455y5552556O96KW+6aW/6afA6ajA6qvC6qvD6qzD6q3E6q7G67PI7LPI7bfM7bjM7rrN7rrO7rvO7rzP78DAwMLCwsPDw8TExMXFxcbGxsfHx8jIyMzMzM/Pz9LS0tTU1NfX193d3eLi4uTk5Ofn5+7u7gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAGQALAAAAAAQABAAAAeLgGSCg4QkJCOEiYMjYGMgiomMYiePkItgWx5kGhoZliBfVx4aJV4Wlh5eVycnVFSnhDEsHldaV1eusIMwPjgtXCYZFhMTiS89UVAyC7qJLjhQQ0FLKgiQKjZQQTY+SBEGihLZQTQ9RxEFkBFMQDM4SA4ElgpLOO8OApZkCSpHQgwA9Ak6YIBAQIGBAAA7'
&>
<br><br>
&nbsp;
<& /input/string.comp,
id => 'img_val',
description => 'input img_val',
rows => 16,
cols => 64,
length => 10240,
readonly => 1
&>
<br><br>
&nbsp;
<& /input/button.comp,
id => 'button_ro',
description => 'button',
value => 'button',
caption => 'Readonly',
readonly => 0,
onclick => "var img = document.getElementById('test_image'); var ro = !img.Readonly(); img.Readonly(ro); document.getElementById('img_val').Readonly(ro); document.getElementById('button_gv').disabled = ro; document.getElementById('button_sv').disabled = ro;"
&>
&nbsp;
<& /input/button.comp,
id => 'button_gv',
description => 'button',
value => 'button',
caption => 'Get Value',
readonly => 1,
onclick => "var img = document.getElementById('test_image'); document.getElementById('img_val').set_value(img.get_value());"
&>
&nbsp;
<& /input/button.comp,
id => 'button_sv',
description => 'button',
value => 'button',
caption => 'Set Value',
readonly => 1,
onclick => "var img_content = document.getElementById('img_val'); document.getElementById('test_image').set_value(img_content.get_value());"
&>
/tags/2.0/htdocs/test/test_errors.html
0,0 → 1,38
<%args>
$err => undef
</%args>
<html>
<h2>test_errors.html</h2>
<hr>
<pre>
Si vuole verificare come si propagano gli errori
 
Richiamare la pagina con i seguenti parametri di test:
test_errors.html?err=500 - interrompe utilizzando $m->abort(500);
test_errors.html?err=400 - interrompe utilizzando $m->abort(400);
test_errors.html?err=400 - interrompe utilizzando $m->abort(200);
test_errors.html?err=die
test_errors.html?err=ret - interrompe utilizzando return;
</pre>
<h3>Parametro err: <%$err%></h3>
<hr>
<%perl>
if($err =~ m/^\d+$/){
$m->abort($err);
}
if($err eq 'die'){
die "DIE\n";
}
if($err eq 'ret'){
return;
}
</%perl>
<br>end.
<hr>
<%once>
</%once>
</html>
<%flags>
inherit => undef
</%flags>
 
/tags/2.0/htdocs/test/test_string.html
0,0 → 1,33
<h2>test string.comp</h2>
 
Test con rows => 4, cols => 20, size => 5, length => 7
% my $value = ".12345678901234567890\n" x 4;
% chomp($value);
<br>
<& /input/string.comp, id => 'test1', rows => 4, cols => 20, value => $value &>
<br>
Test con rows => 1, size => 7, length => 10
% $value = "1234567";
<br>
<& /input/string.comp, id => 'test2', rows => 1, size => 7, length => 10, value => $value &>
<br>
Test con Espressione regolare '[a-z]'
<br>
<& /input/string.comp, id => 'test3', rows => 1, size => 20, length => 20, valid_chars => '[a-z]' &>
<br>
Test con upperCase (trans => 'U')
 
<br>
<& /input/string.comp, id => 'test3b', rows => 1, size => 20, length => 20, trans => 'U' &>
<br>
Test readonly
<br>
<& /input/string.comp, id => 'test4', rows => 1, size => 35, readonly => 1 , value => 'WIDGET STRING IN SOLA LETTURA' &>
<input type="button" value="change read/write" onclick="change_ro();">
<script>
function change_ro(){
var test4 = document.getElementById('test4');
test4.Readonly(!test4.Readonly());
}
 
</script>
/tags/2.0/htdocs/test/test_FCKeditor.html
0,0 → 1,45
<%args>
$edit => undef
</%args>
<H1>test FCKeditor.comp </H1>
<& /input/FCKeditor.comp,
id => 'fckedit',
readonly => 1,
bgcolor => 'lightgreen',
value => q{
<H1>Test FCKeditor.comp</H1>
<P>
Compliment interested discretion estimating on stimulated apartments oh. Dear so sing when in find read of call. As distrusts behaviour abilities defective is. Never at water me might. On formed merits hunted unable merely by mr whence or. Possession the unpleasing simplicity her uncommonly.
</P>
},
width => '400px',
height => '200px',
editWidth => '600px',
editHeight => '300px'
&>
<br>
<& /input/button.comp,
id => 'button_rw',
description => 'button',
value => 'button',
caption => 'Modify',
onclick => "Id_fckedit.Readonly(false); Id_button_rw.Readonly(true); Id_button_ro.Readonly(false);"
&>
<& /input/button.comp,
id => 'button_ro',
description => 'button',
readonly => 1,
value => 'button',
caption => 'Readonly',
onclick => "Id_fckedit.Readonly(true); Id_button_ro.Readonly(true); Id_button_rw.Readonly(false)"
&>
 
<%init>
# precaricamento librerie utilizzate dai componenti caricati "OnDemand"
&LoadHeader('/input/input.comp', '/input/button.comp', '/lib/FCKeditor/fckeditor.js', '/input/FCKeditor.js');
</%init>\
<%flags>
inherit => '/autohandler'
</%flags>
 
/tags/2.0/htdocs/test/test_button.html
0,0 → 1,19
<h2>test button.comp</h2>
 
<h3>Button with value = 'my value'</h3>
<& /input/button.comp,
id => 'test1',
description => 'Descrizione pulsante',
caption => 'Test button',
value => 'my value',
onclick => q|javascript: alert('Value=\''+this.get_value()+'\'')|
&>
<hr>
<h3>Button with value = ''</h3>
<& /input/button.comp,
id => 'test2',
description => 'Descrizione pulsante',
caption => 'Test button',
value => ''
&>
<br>
/tags/2.0/htdocs/test/test_number.html
0,0 → 1,10
<h2>test number.comp</h2>
<& /input/number.comp,
id => 'test',
NumCifre => 12,
ValMax => 50000,
ValMin => -5000,
description => 'Test input numerico',
Xonchange => "my_alert('Valore='+Input_Event(event).value,'txt', 150,50);"
&>
<br>
/tags/2.0/htdocs/test/test_url.html
0,0 → 1,24
<h2>test url.comp</h2>
 
Apre finestra:
<& /input/url.comp, id => 'test_url', size => 35, readonly => 1 ,
value => 'https://www.leader.it',
description => 'Sito Wed di Leader.IT network'
&>
-
<input type="button" value="change read/write" onclick="change_ro();">
<script>
function change_ro(){
var test_url = document.getElementById('test_url');
test_url.Readonly(!test_url.Readonly());
}
</script>
<br>
<hr>
<br>
Apre popup:
<& /input/url.comp, id => 'test_url_popup', popup => 1, size => 80, readonly => 1,
value => 'https://www.leader.it/Portal/TecnologieUtilizzate',
description => 'Tecnologie utilizzate'
&>
 
/tags/2.0/htdocs/test/test_form.html
0,0 → 1,39
<%args>
$edit => undef
</%args>
<H1>test_form.html</H1>
<H3>form.comp</h3>
<& /input/form.comp,
id => 'IdWidgetFormTest',
from => '/public/anagrafiche',
value => '7',
popupWidth => 840,
popupHeight => 580,
formParameters => {
form => 'FORM',
disp_print => 0,
find_area => undef,
},
size => 300,
rows => 10,
onclick => "alert('click'); |",
onchange => "alert('changed val:'+this.get_value());",
empty => '',
empty_descr => 'nessuno'
&>
<%init>
# precaricamento librerie utilizzate dai componenti caricati "OnDemand"
# servono tutti percé potrebbero essere usati dal form richiamato dal widget
&LoadHeader('/input/input.comp', '/input/string.comp', '/input/date.comp',
'/input/span.comp', '/input/number.comp', '/input/select.comp', '/input/url.comp',
'/input/radio.comp', '/input/checkbox.comp', '/input/form.comp',
'/input/select.comp', '/input/time.comp', '/input/timestamp.comp',
'/input/button.comp', '/input/Permission.comp', '/input/Files.comp',
'/input/htmlselect.comp', '/input/codfisc_pi.comp',
'/input/divselect.comp', '/lib/FCKeditor/fckeditor.js', '/input/FCKeditor.js'
);
</%init>\
<%flags>
inherit => '/autohandler'
</%flags>
/tags/2.0/htdocs/test/test_crud.html
0,0 → 1,125
<H1>Test funzioni CRUD</H1>
Schema: <input type="text" id="schema" value=""><br>
Object/table: <input type="text" id="table" value=""><br>
Father key: <input type="text" id="father_key" value=""><br>
Key: <input type="text" id="key" value=""><br>
Format: <select id="format">
<option value="">XML</option>
<option value="rest">JSON</option>
</select><br>
<br>
<input type="button" value="info" id="info" onclick="do_info();">
<input type="button" value="numrec" id="numrec" onclick="do_numrec();">
<input type="button" value="newkey" id="newkey" onclick="do_newkey();">
<input type="button" value="retrieve" id="retrieve" onclick="do_retrieve();">
<input type="button" value="update" id="update" onclick="do_update();">
<input type="button" value="create" id="create" onclick="do_create();">
<input type="button" value="delete" id="delete" onclick="do_delete();">
<br>
XML da inviare:<br>
<textarea id="xml_in" rows=12 cols=120></textarea><br>
Risposta:<br>
Url: <span id="url">...</span><br>
<textarea id="xml_out" rows=20 cols=120></textarea>
<script>
 
function alert_xml_out(){
if(http_request.readyState == 4){
var contenttype = http_request.getResponseHeader('Content-type');
var contentrange = http_request.getResponseHeader('Content-range');
var doc = document.getElementById('xml_out');
doc.style.color='';
doc.value = 'Status: ' + http_request.status + '\nContent-type: ' + contenttype + '\nContent-Range: ' + contentrange + '\n';
if(http_request.status == 200){
result = http_request.responseText;
doc.value += '\n' + result;
doc.style.color='blue';
}else{
result = http_request.responseText;
doc.value += '\n' + result;
doc.style.color='red';
}
}
}
 
function send(mode, params, xml){
var schema = document.getElementById('schema').value;
var url = '/dbms/' + (schema ? schema + '/' : '') + document.getElementById('table').value + '?' + params;
document.getElementById('url').innerHTML = url;
http_request = null;
if(window.XMLHttpRequest){
http_request = new XMLHttpRequest();
}else{
http_request = new ActiveXObject("Msxml2.XMLHTTP");
}
http_request.onreadystatechange = alert_xml_out;
http_request.open(mode, url, true);
http_request.setRequestHeader("Content-type", 'text/xml');
http_request.setRequestHeader("Content-length", xml.length);
http_request.send(xml);
}
 
function do_info(){
send('GET', 'method=info', '');
}
 
function do_newkey(){
send('GET', 'method=newkey', '');
}
 
function do_numrec(){
var father_key = document.getElementById('father_key').value;
if(!father_key){
alert('Indicare la chiave del record padre da selezionare');
return;
}
send('GET', 'method=numrec&father_key=' + father_key, '');
}
 
function do_retrieve(){
var key = document.getElementById('key').value;
var father_key = document.getElementById('father_key').value;
if((key && father_key) || (!key && !father_key)){
alert('Indicare la chiave del record oppure la chiave del record padre da selezionare');
return;
}
var format = document.getElementById('format').value;
if(format){
format = '&envelope_response=' + format;
}
if(key){
send('GET', 'method=retrieve&key=' + key + formay, '');
}else{
send('GET', 'method=retrieve&father_key=' + father_key + format, '');
}
}
 
function do_update(){
var key = document.getElementById('key').value;
if(!key){
alert('Indicare la chiave del record da aggiornare');
return;
}
send('POST', 'method=update&key=' + key, document.getElementById('xml_in').value);
}
 
function do_create(){
var key = document.getElementById('key').value;
var father_key = document.getElementById('father_key').value;
if(key){
send('POST', 'method=create&key=' + key + '&father_key=' + father_key, document.getElementById('xml_in').value);
}else{
send('POST', 'method=create&father_key=' + father_key, document.getElementById('xml_in').value);
}
}
 
function do_delete(){
var key = document.getElementById('key').value;
if(!key){
alert('Indicare la chiave del record da cancellare');
return;
}
send('GET', 'method=delete&key=' + key, '');
}
 
</script>
/tags/2.0/htdocs/test/test_date.html
0,0 → 1,21
<h2>test date.comp</h2>
<br>
Data: <& /input/date.comp,
id => 'Data',
value => '12/12/2005',
onchange => 'alert("New date Data:"+this.get_value());',
description => 'Test input data',
&>
<br>
<br>
Data2: <& /input/date.comp,
id => 'Data2',
value => '',
onchange => 'alert("New date Data2:"+this.get_value());',
description => 'Test input data',
&>
<br>
<hr>
<br>
<button onclick="Id_Data.Readonly(true);">Readonly</button>
<button onclick="Id_Data.Readonly(false);">R/W</button>
/tags/2.0/htdocs/test/test_rest.html
0,0 → 1,134
<H1>Test funzioni REST con Dojo dojo/store/JsonRest</H1>
Schema: <input type="text" id="schema" value=""><br>
Object/table: <input type="text" id="table" value=""><br>
Father key: <input type="text" id="father_key" value=""><br>
Key: <input type="text" id="key" value=""><br>
Query: <input type="text" id="query" value=""><br>
Start record: <input type="text" id="start" value=""><br>
Num rows: <input type="text" id="num_rows" value=""><br>
<br>
<input type="button" value="newkey" id="newkey" onclick="do_newkey();">
<input type="button" value="retrieve" id="retrieve" onclick="do_retrieve();">
<input type="button" value="update" id="update" onclick="do_update();">
<input type="button" value="create" id="create" onclick="do_create();">
<input type="button" value="delete" id="delete" onclick="do_delete();">
<br>
JSON da inviare:<br>
<textarea id="json_in" rows="12" cols="120"></textarea><br>
Risposta:<br>
Url: <span id="url">...</span><br>
<textarea id="json_out" rows="12" cols="120"></textarea>
<script>
 
function alert_json_out(){
if(http_request.readyState == 4){
var contenttype = http_request.getResponseHeader('Content-type');
var doc = document.getElementById('json_out');
doc.style.color='';
doc.value = 'Status: ' + http_request.status + '\nContent-type: ' + contenttype + '\n';
if(http_request.status == 200){
result = http_request.responseText;
doc.value += '\n' + result;
doc.style.color='blue';
}else{
result = http_request.responseText;
doc.value += '\n' + result;
doc.style.color='red';
}
}
}
 
function send(mode, key, params, json, headers){
var schema = document.getElementById('schema').value;
if(!schema){
schema = 'public';
}
var url = '/rest/' + schema + '/' + document.getElementById('table').value;
if(key){
url += '/' + key;
}
if(params){
url += '?' + params;
}
document.getElementById('url').innerHTML = url;
http_request = null;
if(window.XMLHttpRequest){
http_request = new XMLHttpRequest();
}else{
http_request = new ActiveXObject("Msxml2.XMLHTTP");
}
http_request.onreadystatechange = alert_json_out;
http_request.open(mode, url, true);
http_request.setRequestHeader("Content-type", 'text/json');
if(headers){
for(key in headers){
http_request.setRequestHeader(key, headers[key]);
}
}
var start = document.getElementById('start').value;
var num_rows = document.getElementById('num_rows').value;
if(start || num_rows){
if(!start){
start = 0;
}
if(!num_rows){
num_rows = 999999999999-start;
}
http_request.setRequestHeader('Range', 'items=' + start + '-' + (parseInt(start) + parseInt(num_rows) - 1).toString());
}
if(json){
http_request.setRequestHeader('Content-length', json.length);
http_request.send(json);
}else{
http_request.send();
}
}
 
function do_newkey(){
send('GET', null, 'method=newkey', null, null);
}
 
function do_retrieve(){
var key = document.getElementById('key').value;
var father_key = document.getElementById('father_key').value;
// if((key && father_key) || (!key && !father_key)){
// alert('Indicare la chiave del record oppure la chiave del record padre da selezionare');
// return;
// }
if(key){
send('GET', key, null, null, null);
}else{
// send('GET', null, 'father_key=' + father_key, null, null);
send('GET', null, null, null, null);
}
}
 
function do_update(){
var key = document.getElementById('key').value;
if(!key){
alert('Indicare la chiave del record da aggiornare');
return;
}
send('PUT', key, null, document.getElementById('json_in').value, { 'If-Match': '*'});
}
 
function do_create(){
var key = document.getElementById('key').value;
var father_key = document.getElementById('father_key').value;
if(key){
send('PUT', key, 'father_key=' + father_key, document.getElementById('json_in').value, { 'If-None-Match': '*'});
}else{
send('PUT', null, 'father_key=' + father_key, document.getElementById('json_in').value, { 'If-None-Match': '*'});
}
}
 
function do_delete(){
var key = document.getElementById('key').value;
if(!key){
alert('Indicare la chiave del record da cancellare');
return;
}
send('DELETE', key, null, null);
}
 
</script>
/tags/2.0/htdocs/test/test_charset.html
0,0 → 1,51
<%args>
$test => undef
</%args>
<%perl>
use utf8;
print STDERR 'test prima '.(utf8::is_utf8($test) ? 'utf ' : 'no utf')." [$test]\n";
print STDERR 'test test_charset '.(utf8::is_utf8($test) ? 'utf ' : 'no')." [$test]\n";
 
if(!$test){
$test = 'àèìòù';
}else{
$test .= ' is ok?';
}
$m->clear_buffer;
$r->content_type('text/html; charset=utf-8');
 
# test database
my $dbh = Auth_AC::AuthCookieHandler->connect($r);
$dbh->do(q{delete from public.logs where id=-1});
$dbh->commit;
$dbh->do(q{insert into public.logs (id, field) values (-1, 'àèìòù') });
$dbh->commit;
my $sth = $dbh->prepare(q{select field from public.logs where id=-1});
$sth->execute;
my $field = $sth->fetchrow_arrayref->[0];
$dbh->do(q{delete from public.logs where id=-1});
$dbh->commit;
</%perl>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<title>Gestione presenze sugli impianti di depurazione</title>
<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=utf-8">
<link rel="stylesheet" href="/css/main.css" type="text/css">
</head>
<body id="bodyMasonSql" scroll="">
<br>
<br>
<h2>Dal file html: àèìòù</h2>
<h2>Dal database: <%$field%></h2>
<br>
<form action="#" method="get" accept-charset="UTF-8" enctype="multipart/form-data">
<input name="test" value="<%$test%>">
<input type="submit" value="TEST">
</form>
</body>
</html>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/test/test_my_alert.html
0,0 → 1,11
<p id="bingo">BINGO ?</p>
<script>
masonSql.once('ready', function(){
var message = 'BINGO2!, \nchiamata <b>my_alert</b><br>Test.';
// my_alert('1 first ' + message);
my_alert('2 ' + message ,'html');
// my_alert('3 ' + message ,'txt');
// my_alert('4 ' + message ,'pre');
// my_alert('5 last ' + message ,'alert');
});
</script>
/tags/2.0/htdocs/test/test_simulate_keypress.html
0,0 → 1,35
 
<input id="Input" type"test"><br>
<hr>
<button onClick="emit_key('Input', 65);">emit_key('Input', 65);</button>
 
<button onClick="insert_key('Input', 65);">insert_key('Input', 65)</button>
 
<script>
 
function emit_key(target_name, charcode){
require(["dojo/on", "dojo/dom"], function(on, dom){
var target = dom.byId(target_name);
// Send event
target.focus();
on.emit(target, 'keydown', {
bubbles: true,
cancelable: true,
// keyCode: charcode,
charCode: charcode
// ,keyCodeArg : charcode
// ,charCodeArg: 0
});
});
}
 
function insert_key(target_name, charcode){
require(["dojo/on", "dojo/dom"], function(on, dom){
var target = dom.byId(target_name);
target.focus();
var evt = document.createEvent("KeyboardEvent");
evt.initKeyEvent("keypress", true, true, null, false, false, false, false, 0, charcode);
target.dispatchEvent(evt);
});
}
</script>
/tags/2.0/htdocs/test/test_json.html
0,0 → 1,146
<%once>
use JSON;
</%once>
<%perl>
</%perl>
% if (!scalar(keys(%ARGS))) {
<html>
<head>
<script src="/lib/library.js">
</script>
<script src="/lib/httpRequestMason.js">
</script>
% if(!$Session{Browser}->firefox || $Session{Browser}->version < 3.5){
% # non necessaria in Firefox 3.5+ (https://developer.mozilla.org/En/Using_native_JSON)
<script src="/lib/json.js">
</script>
% }else{
<!-- USE NATIVE JSON -->
% }
</script>
<script>
function timeoutCallback(str, contextID)
{
var parsed = JSON.parse(str);
log(dumpObj(parsed));
}
 
function log(str)
{
var visualizer = document.getElementById("visualizer");
visualizer.innerHTML += str;
}
 
function getObj()
{
var toSend = new Object();
toSend.obj = eval(document.getElementById("tArea").value);
toSend.field = document.getElementById("toMod").value;
toSend.fValue = eval(document.getElementById("newVal").value);
return toSend;
}
 
function dumpObj(obj)
{
return dObj(obj, "Object", "\t", 0);
}
 
function dObj(obj, name, indent, depth)
{
var MAX_DUMP_DEPTH = 20;
if (depth > MAX_DUMP_DEPTH)
{
return indent + name + ": <Maximum Depth Reached><br/>";
}
if (typeof obj == "object")
{
var child = null;
var output = indent + name + "<br/>";
indent += "\t";
for (var item in obj)
{
try
{
child = obj[item];
}
catch (e)
{
child = "<Unable to Evaluate>";
}
if (typeof child == "object" && (item != 'hReqMason_obj'))
{
output += dObj(child, item, indent, depth + 1);
}
else
{
output += indent + item + ": " + child + "<br/>";
}
}
return output;
}
else
{
return obj;
}
}
 
function multipleExec()
{
hReqMason_Execute('/test/test_json.html', timeoutCallback, 'prova', getObj())
hReqMason_Execute('/test/test_json.html', timeoutCallback, 'prova', getObj())
hReqMason_Execute('/test/test_json.html', timeoutCallback, 'prova', getObj())
hReqMason_Execute('/test/test_json.html', timeoutCallback, 'prova', getObj())
hReqMason_Execute('/test/test_json.html', timeoutCallback, 'prova', getObj())
}
</script>
<title>
Test JSON
</title>
</html>
<body>
<H1>test_json.html</H1>
<form id="form" name="form">
<label>
Oggetto javascript:
</label>
<br/>
<textarea id="tArea" cols="50" rows="30">new (function (){this.field = "string";})();</textarea>
<br/>
<label>
Campo da modificare:
</label>
<input type="input" id="toMod"/>
<label>
Valore:
</label>
<input type="input" id="newVal">
<br/>
<div id="visualizer"></div>
<br/>
<input type="button" value="Submit" onClick="javascript:multipleExec();"/>
</form>
</body>
</html>
<%perl>
}
else
{
my $content;
$r->read($content, $r->header_in('Content-length'));
my $obj = jsonToObj($content);
if ($obj->{"fValue"})
{
$obj->{"obj"}{"$obj->{'field'}"} = $obj->{"fValue"};
}
else
{
delete $obj->{"obj"}{"$obj->{'field'}"};
}
$r->content_type('text/plain');
$m->print(objToJson($obj));
}
</%perl>
<%flags>
inherit => undef
</%flags>
 
/tags/2.0/htdocs/test/test_tooltip.html
0,0 → 1,23
<html>
<h2>test string.comp</h2>
<br>
<& /input/string.comp, id => 'test1', rows => 4, cols => 20, size => 5, length => 7 &>
<br>
<& /input/string.comp, id => 'test2', size => 22 &>
<script>
dojo.require("dijit.Tooltip");
new dijit.Tooltip({
connectId: ['test1'],
showDelay: <% $r->dir_config('TooltipDelay') %>,
label: '<% 'Esempio di tooltip molto lungo<br>
che risiede su più righe<br>
altra riga<br>
fine ultima riga.'|js%>'
});
new dijit.Tooltip({
connectId: ['test2'],
showDelay: <% $r->dir_config('TooltipDelay') %>,
label: 'Altro esempio <b>bold</b> <font color="red">RED</font>'
});
</script>
</html>
/tags/2.0/htdocs/test/test_JST.html
0,0 → 1,48
 
<h1>Test JavaScript Dojo Templates</h1>
<p> Vedi <b><a link="http://dojotoolkit.org/reference-guide/dojox/dtl.html">http://dojotoolkit.org/reference-guide/dojox/dtl.html</a></b></p>
<br>
<br>
Template:<br>
<textarea rows="8" cols="80"><& .template1 &></textarea><br>
<br>
Textarea id:result<br>
<textarea id ="result" rows="4" cols="80">.....</textarea>
<script>
dojo.require('dojox.dtl.filter.strings');
dojo.require('dojox.dtl.Context');
 
// filtro custom vedi esempio: http://code.google.com/p/dools/source/browse/trunk/dools/docs/widget/_util.js
var masonsql_test = {
dtl: {
filter: {
js: function(/*String*/ str){
return str.replace(/\'/gm, '\\\'').replace(/\n/g, '\\n');
}
}
}
};
dojo.provide('masonsql_test.dtl.filter');
dojox.dtl.register.filters('masonsql_test.dtl', {
'filter': ['js']
});
var html = '<% $m->scomp('.template1') |js%>';
var MyData = {
MyDescr: "Descrizione (\'intelligente\')\nsu più \'righe\'"
};
var templateObj = new dojox.dtl.Template(html);
var template = templateObj.render(new dojox.dtl.Context(MyData));
document.write(template);
</script>
</body>
%#
%#
%#
<%def .template1>
<script>
var X = '\'pippo\' e \'pluto\'';
dojo.byId('result').value = 'BINGO! {{MyDescr|js|safe}} di '+ X;
</script>
</%def>
/tags/2.0/htdocs/test/test_block.html
0,0 → 1,47
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8">
<title>Test</title>
<link rel="stylesheet" href="/css/main.css" type="text/css">
<link rel="stylesheet" href="/css/menu.css" type="text/css">
<meta name="AUTHOR" content="Brugnara ing. Guido - gdo@leader.it">
<meta name="COPYRIGHT" content="Leader.IT di Guido Brugnara; Strada della Pozzata, 41 - Villazzano; 38123 TRENTO (ITALY); info@leader.it">
</head>
<body>
<form name="main" onsubmit="return false;">
<hr>
<& /input/parameters.comp, id => 'test1' &>
<hr>
<input type="button" name="visCampi" id="visCampi" value="Visualizza campi form 'main'" onClick="visualizzaCampi('main')">
</form>
<script>
 
// ritorna il valore del campo specificato
function get_value(input){
if(input.type=='checkbox'){
return(input.checked ? 1 : 0);
}
if(input.get_value){
// se definito il metodo get_value lo utilizzo ...
return input.get_value();
}
return input.value;
}
 
function visualizzaCampi(form){
var Form = document.forms[form];
var S = "Forms is "+document.forms.length+"[";
for(var I=0; I<document.forms.length; I++){
S+=document.forms[I].name+",";
}
S+="]\n";
S+="Form "+Form+" campi "+Form.elements.length+"\n\n"
for(var I = 0; I<Form.elements.length; I++){
S+=" "+I+": name='"+Form.elements[I].name+"' id='"+Form.elements[I].id+
"' value='"+get_value(Form.elements[I])+"'\n";
}
alert(S);
}
</script>
</body>
</html>
/tags/2.0/htdocs/test/test_select_multiple.html
0,0 → 1,32
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; CHARSET=utf-8">
<title>Test</title>
<link rel="stylesheet" href="/css/main.css" type="text/css">
<link rel="stylesheet" href="/css/menu.css" type="text/css">
<meta name="AUTHOR" content="Brugnara ing. Guido - gdo@leader.it">
<meta name="COPYRIGHT" content="Leader.IT di Guido Brugnara; Strada della Pozzata, 41 - Villazzano; 38123 TRENTO (ITALY); info@leader.it">
</head>
<body>
<%perl>
use Data::Dumper;
my $par = Dumper(\%ARGS, \@_);
 
</%perl>
<form name="main"> <onsubmit="return false;">
<textarea rows="12" cols="50">
<%$par%>
</textarea>
<select multiple name="sel" id="sel" xonchange="alert(this.value)">
<option value=""></option>
<option value="1">uno</option>
<option value="2">due</option>
<option value="3">tre</option>
<option value="4">quattro</option>
<option value="5">cinque</option>
 
</select>
<input type="submit" value="go">
</form>
</body>
</html>
/tags/2.0/htdocs/test/test_method_return_hash.html
0,0 → 1,27
<HTML>
<p><cite>
Esempio di utilizzo di un metodo con return di una hash
</cite></p>
<%method TEST>
<%args>
$param
</%args>
TE\
% my %H = ( Pippo => 'pluto', Minny => 99);
ST<%$param%>\
% return %H;
</%perl>#]</%method>\
% my %Test = $m->comp('SELF:TEST', param => 1);
% my $test = Dumper(\%Test);
=<% $test %><br>
% %Test = $m->current_comp->call_method('TEST', param => 2);
% $test = Dumper(\%Test);
=<% $test %><br>
<p><cite>
Qui viene intercettato l'output della chiamata:
</cite></p>
% my $store;
% %Test = $m->comp({store => \$store},'SELF:TEST', param => 3);
% $test = Dumper(\%Test);
<% $store %>=<% $test %><br>
</HTML>
/tags/2.0/htdocs/test/test_textarea.html
0,0 → 1,12
<H1>test_select.html</H1>
<hr>
<form name="menu">
Impianto:<br>
<& /input/string.comp, id =>'Area_testo',
description=>'Area di testo',
rows => 10, cols => 30, value => "Esempio\nriga 2\nriga 3\nultima riga (€è[ò@ò#°)" &>
</form>
<hr>
<%flags>
inherit => '../autohandler'
</%flags>
/tags/2.0/htdocs/test/test_variabile_detail.html
0,0 → 1,97
<%args>
$include => undef
</%args>
% if($include){
<H1>INCLUSIONE INCLUSIONE INCLUSIONE INCLUSIONE</H1>
<H2>INCLUSIONE INCLUSIONE INCLUSIONE INCLUSIONE</H2>
% }else{
<H1>test:</H1>
<h2>Valutazione caricamento dinamico record da campo <%'<div/>'|h%>, suddiviso in verticale da campi <%'<span/>'|h%></h2>
<form name="my_form">
<div id="divs" style="background-color: #3affee;">
<p>Paragrafo all'interno di <b>divs</b></p>
del testo all'interno di <b>divs</b><br>
<div id="spans" style="background-color: #ffffff;">
% $Global{'Style_span.test_variabile_detail'}="border: 2px solid blue; margin:0px; padding:0px; cursor:help;";
% for(my $I=0; $I<5; $I++){
<span id="s<%$I%>" class="test_variabile_detail">span area <%$I%></span>\
% }
</div>
<div id="div_1" style="background-color: #ffffff;">
div_1
</div>
<div id="div_2" style="background-color: #ff1faf;">
div_2
</div>
</div>
</form>
<script src=""></script>
<script>
// test manipolazione elementi div singoli
var div1 = document.getElementById('div_1');
div1.innerHTML='BINGO';
div1.style.backgroundColor='#a2a4a6';
div1.style.color='#ffffff';
 
// test gestione elenco elementi div
var divs = document.getElementById('divs');
// il nome del TAG può essere indifferentemente minuscolo o maiuscolo
var elenco = divs.getElementsByTagName('div');
for(var i=0; i<elenco.length; i++){
elenco[i].innerHTML=elenco[i].innerHTML+' ecc. ecc.';
}
// test aggiunta di un nuovo elemento
for(var i=10; i>0; i--){
var clone = div1.cloneNode(false);
clone.innerHTML='<span style="color: yellow;">duplicato</span> n° '+i;
clone.id="dup"+i;
clone.numRecord=i;
divs.appendChild(clone);
}
// test append elemento non duplicato ???
div1.innerHTML='BINGO test elemento non duplicato che si sposta di posizione';
// l'effetto in Mozilla ed IE6.0 è lo spostamento del <div>
divs.appendChild(div1);
 
// test cancellazione
divs.removeChild(document.getElementById('div_2'));
divs.removeChild(document.getElementById('dup6'));
 
// test scambio di due <div> adiacenti
var basso=document.getElementById('dup3');
basso.innerHTML=basso.innerHTML+' era basso ... test inserimento elemento di input: <select id="sel"><option>uno</option><option>due</option></select>';
var alto=document.getElementById('dup4');
alto.innerHTML=alto.innerHTML+' era alto';
divs.insertBefore(basso, alto);
 
// test duplicazione elemento di input
var sel=document.getElementById('sel');
var sel2 = sel.cloneNode(true);
sel2.id='sel2';
alto.innerHTML=alto.innerHTML+'... test inserimento elemento clonato di input:';
alto.appendChild(sel2);
 
// modifico il testo aggiungento info tra [] sull'attributo 'numRecord'
// ed i valori di offset relativi al 'parent'
var elenco = divs.getElementsByTagName('DIV');
for(var i=0; i<elenco.length; i++){
var elem=elenco[i];
elem.innerHTML=elem.innerHTML+'['+elem.numRecord+', H'+elem.offsetHeight+', L'+elem.offsetLeft+', T'+elem.offsetTop+', W'+elem.offsetWidth+']';
}
divs.innerHTML=divs.innerHTML+'['+divs.numRecord+', H'+divs.offsetHeight+', L'+divs.offsetLeft+', T'+divs.offsetTop+', W'+divs.offsetWidth+']';
 
function LoadRemote(Div, Url, params){
Div.disabled = true;
hReqMason_LoadTimeout(Div, 15000, pageTimeoutLoad, null, Url, params);
}
</script>
<hr>
<form>
<input type="button" value="Includi documento remoto nel div"
onClick="LoadRemote(document.getElementById('dup3'),'/test/test_variabile_detail.html?include=1','')">
</form>
% }
<%init>
&LoadHeader('/lib/hReqMason_ClientMason.js');
</%init>
/tags/2.0/htdocs/test/test_div_scroll2.html
0,0 → 1,61
<%flags>
inherit => undef
</%flags>
<div id="top">
Riga in cima . . . . . . . . .
</div>
<div id="DivBody" class="INPUTDIV" style="
border: inset 2px #aa0e00;
height: 100px;
width: 600;
overflow: auto;
">
<p>
% for(my $I=0; $I<100; $I++){
Pippo e Pluto vanno a spasso per la città.
% }
</p>
Una riga<br>
Due righe<br>
Tre righe<br>
Ultima riga.
</div>
<div id="bottom">
Riga centrale . . . . . . . . .
</div>
In Internet Explorer il DIV sottostante ha le barre di scorrimento bloccate.
<div disabled id="DivBody2" style="
border: inset 2px;
height: 100px;
width: 600;
overflow: auto;
">
</div>
<div id="bottom">
Riga in basso . . . . . . . . .
</div>
<script>
var DivBody = document.getElementById('DivBody');
var DivBody2 = document.getElementById('DivBody2');
DivBody2.innerHTML = DivBody.innerHTML;
 
function SetSize(){
// adatto le dimensioni
var newHeight;
if(document.body.clientHeight < document.body.offsetHeight){
newHeight = document.body.clientHeight - document.body.scrollHeight + DivBody.offsetHeight;
}else{
newHeight = document.body.clientHeight - document.body.offsetHeight + DivBody.offsetHeight;
}
DivBody.style.height = newHeight + 'px';
}
 
window.onload = function(){
// SetSize();
};
 
window.onresize = function(){
SetSize();
};
</script>
/tags/2.0/htdocs/test/test_disabled.html
0,0 → 1,68
<HTML>
<HEAD>
<STYLE type="text/css">
input[disabled], input[readonly], select[disabled], select[readonly], checkbox[disabled], checkbox[readonly], textarea[disabled], textarea[readonly]{
background-color: #dcfcfc;
border: #3532ff 1px solid;
color: #ff00ff;
cursor: default;
}
</STYLE>
</HEAD>
<BODY>
TEST:<br>
 
Disabled: <input type="text" value="PROVA TESTO DISABLED" disabled />
<br>
Readonly: <input type="text" value="PROVA TESTO DISABLED" readonly />
<br>
<br>
Disabled: <input type="checkbox" checked disabled />
<br>
Readonly su click: <input type="checkbox" checked onclick="return false;" />
<br>
Readonly su change: <input id="checkbox_ro" type="checkbox" onchange="this.ripristina();" />
<br>
<br>
Disabled: <select disabled >
<option >riga 1</option>
<option >riga 2</option>
</select>
<br>
Readonly: <select id="sel_ro" onclick="return false;" onchange="this.ripristina();" onclick="return false;">
<option value="1" >riga 1</option>
<option value="2" >riga 2</option>
<option value="3" selected >riga 3</option>
</select>
<br>
<script>
var sel_ro = document.getElementById('sel_ro');
var checkbox_ro = document.getElementById('checkbox_ro');
sel_ro.set_value = function (value){
this.widgetValue = value;
this.value = value;
}
 
sel_ro.ripristina = function (){
this.value = this.widgetValue;
}
 
checkbox_ro.set_value = function (value){
this.widgetValue = value;
this.checked = value;
}
 
checkbox_ro.ripristina = function (){
this.checked = this.widgetValue;
}
 
 
sel_ro.set_value(2);
checkbox_ro.set_value(1);
</script>
 
</BODY>
/tags/2.0/htdocs/test/test_filesystem.html
0,0 → 1,34
<h2>test ActiveX Scripting.FileSystemObject</h2>
 
test1: <& /input/string.comp, id=>'test1', rows=>20, cols=>80 &>
 
<br>
 
<script>
var test1 = document.getElementById('test1');
 
 
function ShowDriveList(){
var fso, s, n, e, x;
fso = new ActiveXObject("Scripting.FileSystemObject");
e = new Enumerator(fso.Drives);
s = "";
for (; !e.atEnd(); e.moveNext()){
x = e.item();
s = s + x.DriveLetter;
s += " - ";
if (x.DriveType == 3)
n = x.ShareName;
else if (x.IsReady)
n = x.VolumeName;
else
n = "[L'unità non è pronta]";
s += n + "\n";
}
return(s);
}
 
</script>
<input type="button" value="ShowDriveList" onClick="document.getElementById('test1').value=ShowDriveList();">
 
 
/tags/2.0/htdocs/test/test_upload_link.html
0,0 → 1,60
<html>
<%args>
$upload => 0
</%args>
<h2>test Upload link file</h2>
<br>
<FORM ACTION="/test/test_upload_link.html?upload=1" XXXtarget="_blank" name="upl_sens_area"
METHOD="POST" ENCTYPE="multipart/form-data">
<input type="file" name="my_file" lenght=25><br>
<INPUT TYPE="SUBMIT" VALUE="Load file">
</FORM>
%# $m->out('Oggetto $r => ',Dumper($r));
% if($upload == 1){
% if($r->dir_config('MasonArgsMethod') eq 'CGI'){
% my $query = $m->cgi_object();
<hr>
% my $fh = $query->param('my_file');
% if(!$fh && $query->cgi_error){
% die $query->cgi_error;
% }
% if($fh){
% my $type = $query->uploadInfo($fh)->{'Content-Type'};
% my $tempname = $query->tmpFileName($fh);
% my $disposition = $query->uploadInfo($fh)->{'Content-Disposition'};
Upload <b>type:</b><%$type%> <b>tempname:</b><%$tempname%> <b>disposition:</b><%$disposition%>:
<pre>
% link($tempname, "$tempname.test_link") or
% die sprintf "link from '%s' failed: $!", $query->tmpFileName($fh);
% open TESTFILE, "<$tempname.test_link";
% while(<TESTFILE>){
% $m->out($_);
% }
% close(TESTFILE);
% unlink "$tempname.test_link";
</pre>
<hr>end.
% }
% }else{
% my $upload = $r->upload('my_file');
<hr>
% my $size = $upload->size;
% my $type = $upload->type;
% my $name = $upload->name;
% my $filename = $upload->filename;
% my $tempname = $upload->tempname;
% $upload->link("$tempname.test_link") or
die sprintf "link from '%s' failed: $!", $tempname;
Upload <b>file:</b><%$filename%></b> <b>tempname:</b><%$tempname%> <b>name:</b><%$name%> <b>type:</b><%$type%> <b>size:</b><%$size%>:
<pre>
% open TESTFILE, "<$tempname.test_link";
% while(<TESTFILE>){
% $m->out($_);
% }
% close(TESTFILE);
% unlink "$tempname.test_link";
</pre>
% }
<hr>end.
% }
</html>
/tags/2.0/htdocs/test/test_variables.html
0,0 → 1,33
<html>
<h2>test_variables.comp</h2>
Si vuole verificare come le veriabili Mason sono visibili all'interno di un metodo Mason
<br>
Session{Test} = '<% $Session{Test} %>'<br>
<&SELF:METODO&>
<hr>
<%method METODO>
METODO->Session{Test} = '<% $Session{Test} %>'<br>
METODO->Session{AltreVar}->{Pippo} = '<% $Session{AltreVar}->{Pippo} %>'<br>
METODO->Session{ARGS} = '<% Dumper($Session{ARGS}) %>'<br>
<hr>
<&SELF:METODO2&>
</%method>
 
<%method METODO2>
METODO2->Session{Test} = '<% $Session{Test} %>'<br>
METODO2->Session{AltreVar}->{Pippo} = '<% $Session{AltreVar}->{Pippo} %>'<br>
</%method>
<%init>
$Session{ARGS} = \%ARGS;
</%init>
 
<%once>
# %Session è una variabile globase.
my %AltreVar = (Pinco => 'Pallo', Pippo => 'Pluto');
$Session{AltreVar} = \%AltreVar;
$Session{Test} = 'BINGO';
</%once>
</html>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/test/test_checkbox.html
0,0 → 1,17
<html>
<h2>test checkbox.comp</h2>
 
Test: <& /input/checkbox.comp, id => 'test1', value => 1 &>
<br>
<br>
Test readonly:
<& /input/checkbox.comp, id => 'test2', readonly => 1 , value => 1 &>
<input type="button" value="change read/write" onclick="change_ro();">
<script>
function change_ro(){
var test2 = document.getElementById('test2');
test2.Readonly(!test2.Readonly());
}
 
</script>
</html>
/tags/2.0/htdocs/test/test_span_focus.html
0,0 → 1,27
<br><br>
<span id="test_span"
onfocus="this.className = 'widgetRwRequiredFocus';alert('focus');"
onkeydown="alert('keydown');"
onblur="this.className = 'widgetRwRequired';alert('blur');"
class="widgetRwRequired"
>ESEMPIO DI SPAN CHE CAMBIA COLORE A SECONDA CHE SIA O MENO SELEZIONATA</span>
<br>
<br>
<& /input/string.comp, id => 'input_test1' &>
<br>
<& /input/string.comp, id => 'input_test2' &>
<br>
 
<div id="buf" ></div>
 
<script>
window.focus();
var test_span = document.getElementById('test_span');
var buf = document.getElementById('buf');
window.setTimeout("test_span.focus();", 1000);
document.onkeypress = function (evt){
var input = Input_Event(evt);
buf.innerHTML = 'input:' + input.id + ' ?:' + (evt.target ? evt.target.id : document.activeElement.id) + ' keyCode:' + evt.keyCode +' chCode:' + evt.chCode +'<br>';
return false;
}
</script>
/tags/2.0/htdocs/test/test_readOnly.html
0,0 → 1,39
<h2>test readOnly su componenti /input/xxxx.comp</h2>
text: <& /input/string.comp, id => 'test1', rows => 4, cols => 20, size => 5, length => 7, value => qq{riga uno\nriga 2\nriga 3} &>
<br>
select: <&| /input/select.comp, id => 'test2', &>
<option value="1">RIGA uno</option>
<option value="2">RIGA due</option>
<option value="3">RIGA tre</option>
</&>
<br>
date: <& /input/date.comp, id => 'test3', value => '25/12/2000' &>
<hr>
span:<& /input/span.comp, id =>'test4', description=>'Test oggetto span', style=>'background-color:yellow; width:400;', value => '<SPAN>BINGO</SPAN>' &>
<hr>
check:<& /input/checkbox.comp, id => 'test5', value => 1 &>
<hr>
<br>
<br>
<script>
var test1 = document.getElementById('test1');
var test2 = document.getElementById('test2');
var test3 = document.getElementById('test3');
var test4 = document.getElementById('test4');
var test5 = document.getElementById('test5');
test2.style.backgroundColor='yellow';
test2.set_value(2);
test2.style.font_color='blue';
 
function set_readonly(setting){
test1.Readonly(setting);
test2.Readonly(setting);
test3.Readonly(setting);
test4.Readonly(setting);
test5.Readonly(setting);
}
window.setTimeout("set_readonly(true);", 1);
</script>
<input type="button" value="read" onClick="set_readonly(true);">
<input type="button" value="write" onClick="set_readonly(false);">
 
/tags/2.0/htdocs/test/test_timestamp.html
0,0 → 1,49
<h2>test_timestamp.html</h2>
 
<& /input/timestamp.comp,
id => 'test_timestamp',
description => 'Descrizione timestamp',
value => '',
readonly => 1,
onchange => "alert('onchange timestamp id:'+this.id+' value:'+this.get_value());"
&>
&nbsp;
<& /input/string.comp,
id => 'string',
description => 'input string',
length => 25,
readonly => 1
&>
<br/>
<& /input/button.comp,
id => 'button_ro',
description => 'button',
value => 'button',
caption => 'Readonly',
readonly => 0,
onclick => "var ts = document.getElementById('test_timestamp'); var ro = !ts.Readonly(); ts.Readonly(ro); document.getElementById('string').Readonly(ro); document.getElementById('button_sv').disabled = ro; document.getElementById('button_gv').disabled = ro; document.getElementById('button_em').disabled = ro;"
&>
&nbsp;
<& /input/button.comp,
id => 'button_sv',
description => 'button',
value => 'button',
caption => 'Set_value',
onclick => "var ts = document.getElementById('test_timestamp'); if (document.getElementById('string').value != ''){ ts.set_value(document.getElementById('string').value); }"
&>
&nbsp;
<& /input/button.comp,
id => 'button_gv',
description => 'button',
value => 'button',
caption => 'Get_value',
onclick => "var ts = document.getElementById('test_timestamp'); if (ts.get_value() != ''){ document.getElementById('string').value = ts.get_value(); }"
&>
<& /input/button.comp,
id => 'button_em',
description => 'button',
value => 'button',
caption => 'Empty',
onclick => "document.getElementById('test_timestamp').set_value(''); document.getElementById('string').value = '';"
&>
% push @Script_buffer, "document.getElementById('button_sv').disabled = 1;\ndocument.getElementById('button_gv').disabled = 1;\ndocument.getElementById('button_em').disabled = 1;\n";
/tags/2.0/htdocs/test/test_time.html
0,0 → 1,47
<h2>test_time.html</h2>
<& /input/time.comp,
id => 'test_time',
description => 'Descrizione time',
value => '',
readonly => 1
&>
&nbsp;
<& /input/string.comp,
id => 'string',
description => 'input string',
length => 25,
readonly => 1
&>
<br/>
<& /input/button.comp,
id => 'button_ro',
description => 'button',
value => 'button',
caption => 'Readonly',
readonly => 0,
onclick => "var ts = document.getElementById('test_time'); var ro = !ts.Readonly(); ts.Readonly(ro); document.getElementById('string').Readonly(ro); document.getElementById('button_sv').disabled = ro; document.getElementById('button_gv').disabled = ro; document.getElementById('button_em').disabled = ro;"
&>
&nbsp;
<& /input/button.comp,
id => 'button_sv',
description => 'button',
value => 'button',
caption => 'Set_value',
onclick => "var ts = document.getElementById('test_time'); if (document.getElementById('string').value != ''){ ts.set_value(document.getElementById('string').value); }"
&>
&nbsp;
<& /input/button.comp,
id => 'button_gv',
description => 'button',
value => 'button',
caption => 'Get_value',
onclick => "var ts = document.getElementById('test_time'); if (ts.get_value() != ''){ document.getElementById('string').value = ts.get_value(); }"
&>
<& /input/button.comp,
id => 'button_em',
description => 'button',
value => 'button',
caption => 'Empty',
onclick => "document.getElementById('test_time').set_value(''); document.getElementById('string').value = '';"
&>
% push @Script_buffer, "document.getElementById('button_sv').disabled = 1;\ndocument.getElementById('button_gv').disabled = 1;\ndocument.getElementById('button_em').disabled = 1;\n";
/tags/2.0/htdocs/test/test_background_color.html
0,0 → 1,61
<html>
<h2>test string.comp - background color (status)</h2>
<& /input/string.comp,
id => 'Test1',
rows => 4,
cols => 20,
length => 80
&>
<br>
<& /input/string.comp,
id => 'Test2',
rows => 1,
size => 20,
length => 7
&>
<script>
// colori sfondo widget di base
window.status_colors = {
Read: '#FFFFFF',
Error: '#FFF0F0',
Edit: '#F0FFF0',
Alert: '#FFFFF0',
Disabled: '#F0F0F0'
};
// condizione di test con widget in sola lettura
var Test1 = document.getElementById('Test1');
var Test2 = document.getElementById('Test2');
 
window.onload = function(){
Test1.widget_status = 'Disabled';
Test1.backgroundColor = '#FFF0F0';
Test1.Readonly(true);
Test1.status_colors = {};
Test2.widget_status = 'Disabled';
Test2.Readonly(true);
Test2.status_colors = {};
 
// colori sfondo modificati per il widget specifico
Test2.status_colors.Error = '#FF9090';
}
// test implemetazione metodo .status
function Input_status(status){
if(status == null){
return this.widget_status;
}
this.style.backgroundColor = this.status_colors[status] ? this.status_colors[status] : window.status_colors[status];
}
 
Test1.status = Input_status;
Test2.status = Input_status;
</script>
<hr>
<input type="button" value="Change Read/write" onclick="Test1.Readonly(!Test1.Readonly()); Test2.Readonly(!Test2.Readonly());"><br>
<br>
<input type="button" value="Read" onclick="Test1.status('Read'); Test2.status('Read');"><br>
<input type="button" value="Error" onclick="Test1.status('Error'); Test2.status('Error');"><br>
<input type="button" value="Edit" onclick="Test1.status('Edit'); Test2.status('Edit');"><br>
<input type="button" value="Alert" onclick="Test1.status('Alert'); Test2.status('Alert');"><br>
<input type="button" value="Disabled" onclick="Test1.status('Disabled'); Test2.status('Disabled');"><br>
</html>
/tags/2.0/htdocs/test/test_attributes.html
0,0 → 1,32
<html>
<h2>test parameters.comp</h2>
Utilizzo di parametri quali attributi di un metodo da ricercare anche nei componenti utilizzati al suo interno:
 
<%method _attributes>
<%args>
$fetch_attrib => undef
</%args>
<%perl>
return $ARGS{$ARGS{'fetch_attrib'}};
</%perl>
</%method>
 
<%method MyMethod_2>
% my $ret = $m->comp('SELF:_attributes', fetch_continue => 0, myattrib => 'TROVATO!!!', %ARGS);
% return $ret if $ret;
CONTENUTO DEL METODO MyMethod_2<br>
</%method>
 
<%method MyMethod>
% my $ret = $m->comp('SELF:MyMethod_2', param1 => 'PARAM1', param2 => 'PARAM2', %ARGS);
% return $ret if $ret;
CONTENUTO DEL METODO MyMethod<br>
</%method>
<hr>
<& SELF:MyMethod &>
<br>
myattrib='<% $m->comp('SELF:MyMethod', fetch_attrib => 'myattrib') %>'<br>
<hr>
<br>
 
 
/tags/2.0/htdocs/test/test_widget_status.html
0,0 → 1,86
<%flags>
inherit => undef
</%flags>
<html>
<head>
<style type="text/css">
 
.widget {
border-color: red;
}
.widgetRo {
background-color: #FFFFFF;
}
.widgetRw {
background-color: #F9F9FF;
}
.widgetRoError {
background-color: #FFF0F0;
}
.widgetRwError {
background-color: #FFC0C0;
}
.widgetRoAlert {
background-color: #FFFFF0;
}
.widgetRwAlert {
background-color: #FFFFC0;
}
.widgetRoDisabled {
background-color: #F0F0F0;
}
.widgetRwDisabled {
background-color: #D0D0D0;
}
 
.MyStyleRwError {
background-color: #FF5070;
}
</style>
</head>
<h2>test widget_status - different style</h2>
<textarea id="Test1" rows="4" cols="20">
</textarea>
 
<script>
var Test1 = document.getElementById('Test1');
Test1.baseClassName = 'MyStyle';
 
// test implementazione metodo .status
Test1.set_status = function(status){
if(status != null){
this.widgetStatus = status;
}
// classe di base
var className = ' widget';
 
// classe differenziata di base per stato attivo
className += ' widget' + (this.readOnly ? 'Ro' : 'Rw') + this.widgetStatus;
// classe differenziata per classe di widget o singolo widget
className += ' ' + this.baseClassName + (this.readOnly ? 'Ro' : 'Rw') + this.widgetStatus;
this.className = className;
}
 
Test1.Readonly = function(read){
if(read == null){
return this.readOnly;
}else{
this.style.cursor = read ? 'default' : 'text';
this.readOnly = read;
this.set_status();
return read;
}
}
 
Test1.Readonly(true); // in sola lettura e
Test1.set_status(''); // nessun stato particolare
</script>
<hr>
<input type="button" value="Change Read/write" onclick="Test1.Readonly(!Test1.Readonly());"><br>
<br>
<input type="button" value="None" onclick="Test1.set_status('');"><br>
<input type="button" value="Error" onclick="Test1.set_status('Error');"><br>
<input type="button" value="Alert" onclick="Test1.set_status('Alert');"><br>
<input type="button" value="Disabled" onclick="Test1.set_status('Disabled');"><br>
</html>
/tags/2.0/htdocs/test/test_button.htmls
0,0 → 1,11
<html>
<h2>test button.comp</h2>
<& /input/button.comp,
id => 'test',
caption => 'Test button',
Value => 'BINGO',
onclick => q|javascript: alert('Value=\"'+this.Value+'\"')|
&>
<br>
 
</html>
/tags/2.0/htdocs/test/test_div_scroll.html
0,0 → 1,38
<div id="top">
Riga top . . . . . . . . .
</div>
<div id="DivBody" style="
border: solid 2px #000e00;
background: #fffffe;
color:#000000;
height: 999px;
overflow: auto;
">
% for(my $I=0; $I<300; $I++){
tigri fig gdh fvjhvg fdkjvbs dfkjvhbds kjfhvb ksdjfhbv ksdjfb vkjsdh fkvjh dfsvjhb dskjfhbv ksdj vkj dfsvkjs d<br>
% }
</div>
<div id="bottom">
Riga bottom . . . . . . . . .
</div>
<script>
var DivBody = document.getElementById('DivBody');
function SetSize(){
// adatto le dimensioni
var newHeight;
if(document.body.clientHeight < document.body.offsetHeight){
newHeight = document.body.clientHeight - document.body.scrollHeight + DivBody.offsetHeight;
}else{
newHeight = document.body.clientHeight - document.body.offsetHeight + DivBody.offsetHeight;
}
DivBody.style.height = newHeight + 'px';
}
 
window.onload = function(){
SetSize();
};
 
window.onresize = function(){
SetSize();
};
</script>
/tags/2.0/htdocs/test/test_component.html
0,0 → 1,39
<h2>test component</h2>
test1:
<& /input/string.comp,
id => 'component',
rows => 1,
cols => 20,
size => 5,
length => 7
&>
<&| /input/select.comp,
id => 'component_sel', style => 'display:none;'
&>
<option value="1">uno</option>
<option value="2">due</option>
<option value="3">tre</option>
</&>
<br>
<hr>
<br>
<script>
var component=document.getElementById('component');
component.sel=document.getElementById('component_sel');
component.SelectTypeInput = function (type){
switch(type){
case 'txt':
this.style.display='inline';
this.sel.style.display='none';
break;
case 'sel':
this.sel.style.display='inline';
this.style.display='none';
break;
default:
alert("ERROR component.SelectTypeInput: type "+type+" not defined");
}
}
</script>
<input type="button" value="TEXT" onClick="component.selectType('txt')">
<input type="button" value="SELECT" onClick="component.electType('sel')">
/tags/2.0/htdocs/test/test_get_attribute.html
0,0 → 1,16
<html>
<h2>test .getAttribute('attributename')</h2>
<input type="text" id="my_test" width="111" my_width="222" style="background-color:#fafafa;">
<textarea id="my_area" rows="6" cols="60">
</textarea>
<script>
var Input = document.getElementById("my_test");
document.getElementById("my_area").value =
'width=' + Input.getAttribute('width') +
' and my_width=' + Input.getAttribute('my_width') +
'\n width:' + Input.width + ' and my_width:' + Input.my_width +
'\n style="' + Input.getAttribute('style')+'"';
</script>
</html>
/tags/2.0/htdocs/test/test_include.include
0,0 → 1,3
<b>parte da includere</b>
!INCLUDE IGNORE
<br>parte da non includere
/tags/2.0/htdocs/test/test_iframe.html
0,0 → 1,68
<%args>
</%args>
<html>
<body>
<H1>test_iframe.html</H1>
<form name="form">
<input id="URL" value="https://localhost/">
<input value="Crea IFRAME" type="button" onClick="load_iframe(iframe, document.getElementById('URL').value); false;">
<input value="Info" type="button" onClick="display_messages('info'); false;">
</form>
<script>
function fnErrorTrap(sMsg,sUrl,sLine){
var oErrorLog = document.getElementById('oErrorLog');
oErrorLog.innerHTML="<b>An error was thrown and caught.</b><p>";
oErrorLog.innerHTML+="Error: " + sMsg + "<br>";
oErrorLog.innerHTML+="Line: " + sLine + "<br>";
oErrorLog.innerHTML+="URL: " + sUrl + "<br>";
return false;
}
window.onerror=fnErrorTrap;
 
function display_messages(mess){
var MESS = mess + '\n';
MESS += 'iframe.src='+iframe.src+'\n';
MESS += 'iframe.readyState='+iframe.readyState+'\n';
MESS += 'iframe.contentWindow.readyState='+iframe.contentWindow.readyState+'\n';
MESS += 'iframe.contentWindow.document.body.innerHTML='+iframe.contentWindow.document.body.innerHTML+'\n';
 
alert(MESS);
}
 
function attach_event(obj, obj_descr){
obj.onactivate = function () { display_messages(obj_descr+' onactivate') }
obj.onabort = function () { display_messages(obj_descr+' onabort') }
obj.onerror = function () { display_messages(obj_descr+' onerror')}
obj.onload = function () { display_messages(obj_descr+' onload')}
}
 
 
var containerName = "test";
var span = document.createElement('SPAN');
span.id = "SPAN" + containerName;
document.body.appendChild( span );
var iframe = document.createElement('IFRAME');
iframe.name = containerName;
iframe.height=300;
iframe.width=600;
span.appendChild( iframe );
attach_event(iframe, 'iframe');
attach_event(iframe.contentWindow,'iframe.contentWindow');
attach_event(iframe.contentWindow.document,'iframe.contentWindow.document');
 
function load_iframe(iframe, URL){
// iframe.location = URL;
iframe.src = URL;
 
// attach_event(iframe.contentWindow,'iframe.contentWindow');
// attach_event(iframe.contentWindow.document,'iframe.contentWindow.document');
}
 
</script>
<hr>
<DIV ID="oErrorLog">
</body>
</html>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/test/test.html
0,0 → 1,4
<script>
<& /input/divselect.js &>
</script>
Test caricamento javascript
/tags/2.0/htdocs/test/FCKeditor_2.3.tar.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/test/test_select2.html
0,0 → 1,45
<%args>
$edit => undef
</%args>
<H1>test_select.html</H1>
<input type=button value="GO">
<script>
</script>
<form name="menu">
Sel1:<br>
<&| /input/select.comp, id =>'Sel1',
description=>'Elenco impianti',
onchange => 'alert(\'BINGO\'); |',
disabled => '1',
buffer => 'Sel',
#remote => 1,
empty=>undef,
width => '400px',
# size => 5,
style=>'background-color:#ffeeff; width:400;'
&>
<option>test 1</option>
<option>test 2</option>
<option>test 3</option>
</&>
 
 
<br>
 
 
Sel2:<br>
<&| /input/select.comp, id =>'Sel2',
description=>'Elenco impianti',
onchange => 'alert(\'BINGO\'); |',
disabled => '1',
buffer => 'Sel',
#remote => 1,
empty=>undef,
width => '400px',
size => 5,
style=>'background-color:#ffeeff; width:400;'
&>
<option>test 1</option>
<option>test 2</option>
<option>test 3</option>
</&>
/tags/2.0/htdocs/test/test_codfisc_pi.html
0,0 → 1,8
<html>
<h2>test string.comp</h2>
<& /input/codfisc_pi.comp,
id => 'test',
description => 'Test inserimento P.I. o Codice Fiscale'
&>
<br>
</html>
/tags/2.0/htdocs/test/test_parameters.html
0,0 → 1,34
<html>
<h2>test parameters.comp</h2>
Esempio di chiamata di funzione(metodo) con passaggio di parametri in forma compatta dell'oggetto Object:
<script>
 
function myFunc(params_call){
// default values
var params = {
param1: 'parametro 1',
param2: 'parametro 2',
param3: 'parametro 3',
param4: 'parametro 4',
param5: 'parametro 5',
}
// overload params from call
for(var elem in params_call){
params[elem] = params_call[elem];
}
// use parameters
document.write("<br>");
for(var elem in params){
document.write(elem+": '"+params[elem]+"'<br>");
}
}
 
myFunc({
param5: 'Palla',
param8: 'Minny',
param3: 'BINGO!!!'
});
 
</script>
 
</html>
/tags/2.0/htdocs/test/test_object.html
0,0 → 1,62
<html>
<head>
</head>
 
<body>
<H1>test_object.html</H1>
 
<script>
 
function Constructor(id, descr){
this.descr = descr;
this.id = id;
this.alert = function(descr){
if(descr){
window.alert(this.id+' - '+descr);
}else{
window.alert(this.id+' - '+this.descr);
}
}
}
 
function Test(){
alert('BINGO START');
}
 
var OBJ = new Constructor('OBJ', 'Bingo Bongo');
 
window.setTimeout(Test,10);
window.setTimeout(OBJ.alert,30);
window.setTimeout(function(){OBJ.alert()},20);
var MESS = 'BINGO STOP';
window.setTimeout(function(){OBJ.alert(MESS)},10);
MESS = MESS + ' BINGONE, la variabile viene risolta all\'atto dell\'esecuzione';
 
</script>
 
 
</body>
</html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/test/test_XMLHttpRequest.html
0,0 → 1,95
<%args>
</%args>
<html>
<head>
<script src="/lib/httpRequestMason.js"></script>
<script src="/lib/library.js"></script>
</head>
<body>
<H1>test_XMLHttpRequest.html</H1>
<form name="form" action="javascript: return false;">
<input id="URL" value="test.html">
<input value="Download" type="button" onClick="load_div(document.getElementById('URL').value); false;">
<input value="Info" type="button" onClick="display_messages(httpRequest, 'info'); false;">
</form>
<div id="div"></div>
<script>
var div = document.getElementById('div');
var httpRequest;
 
function httpRequest_onload(){
display_messages(this, 'httpRequest_onload');
return true;
}
 
function httpRequest_onerror(){
display_messages(this, 'httpRequest_onerror');
return true;
}
 
function fnErrorTrap(sMsg,sUrl,sLine){
var MESS = "An error was thrown and caught.\n";
MESS +="Error: " + sMsg + "\n";
MESS +="Line: " + sLine + "\n";
MESS +="URL: " + sUrl + "\n";
alert(MESS);
return false;
}
window.onerror=fnErrorTrap;
 
function display_messages(httpRequest, mess){
var MESS = mess + '\n';
MESS += 'httpRequest.readyState='+httpRequest.readyState+' ';
switch(httpRequest.readyState) {
case 1,2,3:
MESS += 'Bad Ready State: '+httpRequest.status;
break;
case 4:
if(httpRequest.status !=200) {
MESS +='The server respond with a bad status code: '+httpRequest.status;
}
break;
}
MESS += '\n';
MESS += 'httpRequest.statusText='+httpRequest.statusText+'\n'
MESS += 'httpRequest.responseText=['+httpRequest.responseText+']\n';
alert(MESS);
}
 
function attach_event(obj, obj_descr){
obj.onactivate = function () { display_messages(obj_descr+' onactivate') }
obj.onabort = function () { display_messages(obj_descr+' onabort') }
//obj.onerror = function () { display_messages(obj_descr+' onerror')}
obj.onload = function () { display_messages(obj_descr+' onload')}
}
attach_event(window,'window');
 
function load_div(URL){
httpRequest = new XMLHttpRequest();
httpRequest.onload = httpRequest_onload;
httpRequest.onerror = httpRequest_onerror;
httpRequest.open('GET' ,URL ,true );
httpRequest.send(null);
}
 
function my_timeoutcallback(){
alert('my_timeoutcallback');
}
function my_callback(){
// alert('my_callback');
}
 
function httpRequestMasonTest(){
hReqMason_LoadTimeout(document.getElementById('div_test'), 5000, my_timeoutcallback, my_callback, '../test/test.html', null);
}
</script>
<hr>
<span onClick="httpRequestMasonTest()">Load httpRequestMason</span>
<div id="div_test">oggetto da sostituire</div>
</body>
</html>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/test/test_content.html
0,0 → 1,14
<hr>
<&| .test &>BINGO</&>
<hr>
% my $content = "my bingo";
% $m->comp({ 'content' => sub { $m->print($content) } }, '.test');
<hr>
%#
%#
<%def .test>
Content=[<%$m->content%>]
<%filter>
s/(\w+)/<font color=red>$1<\/font>/ig;
</%filter>
</%def>
/tags/2.0/htdocs/AuthCookieLoginForm.html
0,0 → 1,311
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%attr>
Cache_MaxAge => 120
</%attr>
<% $r->dir_config('HtmlDocType') %>
<html>
<head>
% my $Dojo_dir = $JSLogger->level() eq $DEBUG ? $r->dir_config('DojoDirUrlDebug') : $r->dir_config('DojoDirUrl');
<script src="<% $Dojo_dir %>/dojo/dojo.js" type="text/javascript" data-dojo-config="async: false,
isDebug:<% $JSLogger->level() eq $DEBUG ? 'true' : 'false'%>, parseOnLoad:true, locale: 'it'"></script>
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/dijit.css" type="text/css">
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/claro/document.css" type="text/css">
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/claro/claro.css" type="text/css">
<link rel="stylesheet" href="/css/main.css" type="text/css">
</head>
<body class="claro">
<br>
<br>
<& /logo.comp &>
<%perl>
# se il browser è adatto oppure è di una versione successiva a quelle testate ...
my $credential_0;
my $prev_password = '';
if($browserOkBeta){
# non si può usare %ARGS; non viene inizializzata correttamente
# in quanto i parametri vengono passati in $ENV{REDIRECT_QUERY_STRING}
my $query = new CGI($ENV{REDIRECT_QUERY_STRING});
$credential_0 = $query->param('user');
#DEBUG print STDERR "AuthCookieLoginForm user:$credential_0 - ", $ENV{REDIRECT_QUERY_STRING},"\n";
# se il form viene richiamato ripetutamente REQUEST_URI le volte successive
# contiene il riferimento al form di login e non quello di partenza che
# invece si trova in REDIRECT_URL
my $RedirectURL = $ENV{REQUEST_URI};
#DEBUG print STDERR "AuthCookieLoginForm.html",Dumper(\%ENV);
if($RedirectURL =~ m|^/logout.html?|){
my $U = int rand 1_000_000_000_000;
$RedirectURL = "/index.html?U=$U";
}
if($RedirectURL =~ m|^/AuthCookieLoginSubmit|){
$RedirectURL = $ENV{REDIRECT_URL};
}
#DEBUG print STDERR "AuthCookieLoginForm.html",Dumper(\%ENV);
if($RedirectURL =~ m/\?C=hReqMason_\d+/){
my $U = int rand 1_000_000_000_000;
# se si tratta del caricamento di un componente redirigo la richiesta alla home page ...
#
#DEBUG print STDERR "LOAD ROOT U=$U\n";
</%perl>
<script>
top.open('<%$r->dir_config('BaseUrl')%>/index.html?U=<%$U%>','_self');
</script>
<%perl>
}else{
my $reason = $r->prev->subprocess_env('AuthCookieReason');
$prev_password = $r->prev->subprocess_env('AuthCookiePassword');
# recupero sessione utente, giorni di inattività, giorni dall'ultimo cambio password e flag di esclusione dei test di scadenza password
my $sth = $dbh->prepare(q{
select date_part('day', now() - session_time) as psw_inactivity,
date_part('day', now() - last_change_password) as change_psw_days,
no_psw_expiration,
concurrent_sessions
from anagrafiche
where login = ?
});
$sth->execute($credential_0);
my $nrows = $sth->rows;
my($psw_inactivity, $change_psw_days, $no_psw_expiration, $concurrent_sessions) = $nrows ? @{$sth->fetchrow_arrayref} : undef;
#DEBUG print STDERR "AuthCookieLoginForm credential_0:$credential_0 ($session, $psw_inactivity, $change_psw_days, $no_psw_expiration)\n";
if($nrows && !$no_psw_expiration){
# valuto se va richiesto il cambio password
if(!defined $change_psw_days or $change_psw_days > $MaxPasswordDays){
$reason = 'change_psw';
}
# valuto se si tratta di un utente assente da troppo tempo
if($psw_inactivity and $psw_inactivity > $MaxPasswordInactivity){
$reason = 'psw_expiration';
}
}
</%perl>
<script>
function submitHandler(){
% if($reason eq 'change_psw'){
if(form.new_passwd.value != form.new_passwd2.value){
alert('Nuove password digitate differenti');
form.new_passwd.value = '';
form.new_passwd2.value = '';
return false;
}
% }
form.credential_1.value = form.passwd.value;
form.passwd.value = null;
% if($reason eq 'change_psw'){
form.credential_2.value = form.new_passwd.value;
form.new_passwd.value = null;
form.new_passwd2.value = null;
% }
form.action = "/AuthCookieLoginSubmit?user=" + form.credential_0.value
return true;
}
%# window.onload = function(){
%# window.setTimeout("document.getElementById('credential_0').value = ''; document.getElementById('password').value = '';", 1);
%# }
 
function RegistrazioneWin() {
window.location.replace("/UserRegistrationForm.html");
}
 
function PasswordResetWin(user) {
window.location.replace("/UserPasswordResetForm.html");
}
 
</script>
<form method="POST" name="form" action="" onsubmit="return submitHandler();">
<input type="hidden" name="credential_1">
<input type="hidden" name="credential_2">
<input type="hidden" name="destination" value="<%$RedirectURL%>">
<table align="center">
<tr><td>
<p align="center">
<br>
<%perl>
if(defined $credential_0) {
$sth = $dbh->prepare(q{
select id,user_ip,session_inactive_time
from session
where id_anagrafiche = (select id
from anagrafiche
where login = ?)
order by session_inactive_time desc
limit 1
});
$sth->execute($credential_0);
$nrows = $sth->rows;
};
#if(defined $nrows and $nrows > 0){
if((not defined $concurrent_sessions or $concurrent_sessions == 0) and $nrows > 0) {
my($id, $IP, $minutes) = @{$sth->fetchrow_arrayref};
my $time_minutes = int(time/60) - $minutes;
</%perl>
<h3>L'utente '<%$credential_0%>' risulta connesso dall'indirizzo <%$IP%> da <%$time_minutes%> minuti senza attività</h3>
</p>
<p align="center">
<input type="checkbox" name="credential_3" >
Annulla sessione precedente
</p>
<%perl>
}
</%perl>
<p align="center">
% my $ErrorChangePassword = $r->prev->subprocess_env('AuthCookieErrorChangePassword');
% if($ErrorChangePassword){
<% $ErrorChangePassword %><br>
% }
% if($reason eq 'bad_credentials'){
<% $r->dir_config('Auth_AC_bad_credentials_message') %>
% }elsif($reason eq 'no_cookie'){
<% $r->dir_config('Auth_AC_no_cookie_message') %>
% }elsif($reason eq 'psw_expiration'){
L'accesso a questo sito è stato negato!<br>
Utente <% $credential_0 %> assente da più di <% $MaxPasswordInactivity %> giorni.<br>
<button class="widget" onclick="PasswordResetWin('<% $credential_0 |js%>'); return false;">Richiedi una nuova password!</button>
% }elsif($reason eq 'change_psw'){
Prima di poter accedere è obbligatorio cambiare la password!
% }else{
L'accesso a questo sito è stato negato!
Errore: <% $reason %>.<br>
% }
<br>
</p>
</td></tr>
<tr><td>
<table align="center">
<tr>
<td align="right"><b>Login:</b></td>
<td><input class="string widget widgetRwRequired" type="text" name="credential_0" id="credential_0" value="<% $reason eq 'psw_expiration' ? '' : $credential_0 %>" size="24" length="24"
onchange="window.setTimeout('document.getElementById(\'password\').value = \'\';', 1);"></td>
</tr>
<tr>
<td align="right"><b><% $reason eq 'change_psw' ? 'Vecchia password' : 'Password' %>:</b></td>
<td><input class="string widget widgetRwRequired" type="password" name="passwd" id="password" value="<% $prev_password |js %>" size="24" length="24"></td>
</tr>
% if($reason eq 'change_psw'){
<tr>
<td align="right"><b>Nuova password:</b></td>
<td><input class="string widget widgetRwRequired" type="password" name="new_passwd" id="new_password" size="24" length="24"></td>
</tr>
<tr>
<td align="right"><b>Ripeti nuova password:</b></td>
<td><input class="string widget widgetRwRequired" type="password" name="new_passwd2" id="new_password2" size="24" length="24"></td>
</tr>
% }
<tr>
<td></td>
<td align="left">
<input class="widget button" type="submit" value="Accesso ...">
</td>
</tr>
<tr style="height:15px;"></tr>
% if($UserPasswordReset eq 'enable') {
<tr>
<td></td>
<td style="text-align: center;">
<button class="widget" onclick="PasswordResetWin(); return false;">Ho dimenticato la password ...</button>
</td>
</tr>
<tr style="height:5px;"></tr>
% }
% if($UserRegistration eq 'enable') {
<tr>
<td></td>
<td style="text-align: center;">
<button class="widget" onclick="RegistrazioneWin(); return false;">Registrazione nuovo utente ...</button>
</td>
</tr>
<tr style="height:5px;"></tr>
% }
</table>
</td></tr>
</table>
</form>
% }
% }
<& /privacy.comp &>
% if(!$browserOk){
<br>
% if($browserOkBeta){
<p align="center">ATTENZIONE: Browser parzialmente supportato.</p>
% }else{
<h3 align="center">ATTENZIONE: Browser non compatibile con l'applicazione!</h3>
% }
<p align="center">
L'applicazione è stata collaudata con i seguenti browser:
</p>
<p align="center">
<br>
<cite>
Firefox Rel. 54<br>
Chromium Rel. 59<br>
(Supporto completo)
<br>
Safari 5.1, 8, 10<br>
Microsoft Edge<br>
Internet Explorer 10 e 11<br>
(Supporto parziale)
</cite>
% if($browserOkBeta){
<br>
<br>
e probabilmente funziona correttamente anche con le versioni più recenti<br>
ma evidentemente non è garantito il funzionamento.<br>
<br>
Il funzionamento dell'applicazione con supporto parziale non è garantito!
</p>
% }else{
.</p>
<p align="center">
Per utilizzare l'applicazione è necessario installare uno dei browser sopra elencati.<br>
Il funzionamento dell'applicazione con delle versioni differenti o con supporto parziale non è garantito!
</p>
% }
% }
<br/><br/>
<& /copyright.comp &>
</body>
<%once>
my $Auth_InactivityMax = $r->dir_config('Auth_InactivityMax');
my $UserRegistration = $r->dir_config('UserRegistration');
my $UserPasswordReset = $r->dir_config('UserPasswordReset');
</%once>
<%init>
# Blocco accesso per inattività se l'utente non accede da più di MaxPasswordInactivity giorni
my $MaxPasswordInactivity = $r->dir_config('MaxPasswordInactivity');
# Scadenza password (in giorni)
my $MaxPasswordDays = $r->dir_config('MaxPasswordDays');
# connessione al database
my $dbh = $Session{Dbh};
# verifica la compatibilità del browser
my $browser = $Session{Browser};
# browser verificati
my $user_agent = $browser->user_agent;
my $trident7 = $user_agent =~ m/Trident\/7.\d+/;
my $browserOk = (
($browser->firefox && $browser->version >= 32 && $browser->version <=54) ||
($browser->chrome && $browser->version < 40)
);
# gamma dei browser Ok e più recenti probabilmente compatibili ma non verificati
my $browserOkBeta = (
$browserOk ||
($browser->ie && $trident7) ||
$browser->edge || $browser->ie10 || $browser->ie11 ||
($browser->ie && $browser->version >= 10) ||
($browser->firefox && ($browser->version >= 15)) ||
($browser->chrome && ($browser->version >= 41) ) ||
($browser->webkit && ($browser->version >= 5) )
);
### die "browserOkBeta:$browserOkBeta browserOk:$browserOk <br>trident4:$trident4 trident5:$trident5 trident6:$trident6 trident7:$trident7 <br>"." browser->ie6:".$browser->ie6." browser->ie7:".$browser->ie7." browser->ie8:".$browser->ie8." browser->ie9:".$browser->ie9." browser->ie10:".$browser->ie10." browser->ie11:".$browser->ie11." browser->ie:".$browser->ie." browser->version:".$browser->version."<br><br>".Dumper($browser);
 
#DEBUG print STDERR "AuthCookieLoginForm->connect($conn, $user, $passwd)\n";
</%init>
<%flags>
inherit => '/init.comp'
</%flags>
/tags/2.0/htdocs/logout.html
0,0 → 1,42
<%perl>
if($Session{Session_id}){
$r->auth_type->logout($r);
</%perl>
<br>
<br>
<br>
<br>
<br>
<br>
<& "/home.html", logout => 1 &>
<br>
<br>
<H3 align="center">Arrivederci!</H3>
 
<p align="center">
<A HREF="<%$r->dir_config('BaseUrl')%>/index.html?U=<% int rand 1_000_000_000_000 %>" TARGET="_top">Per riaprire la sessione ...</A> </p>
<script>
require(["dojo/ready", "dijit/registry", "dojo/_base/array"], function(ready, registry, array){
ready(function(){
var menu = document.getElementById('TopContent');
if(menu){
// elimino il menu
menu.innerHTML = '';
}
// cancello i Tab diversi dal corrente
var tabs = registry.byId('mainTab');
if(tabs){
array.forEach(tabs.getChildren(), function(tab){
if(tab != tabs.selectedChildWidget){
tabs.removeChild(tab);
tab.destroyRecursive();
}
});
}
});
});
</script>
% }else{
% # redirect alla pagina principale
% $r->internal_redirect('/index.html');
% }
/tags/2.0/htdocs/help.html
0,0 → 1,137
<%args>
$method => undef
</%args>
% if(!defined $method){
<script>
require([
"dijit/dijit",
"dojo/parser",
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane"
]);
</script>
<div data-dojo-type="dijit.layout.BorderContainer" design="sidebar" persist="false" gutters="false"
style="min-width: 1em; min-height: 1px; z-index: 0; width: 100%; height: 100%;">
<div data-dojo-type="dijit.layout.ContentPane" region="left" style="width: 240px;" extractContent="false"
id="MenuHelpContainer" class="MenuHelpContainer"
preventCache="false" preload="false" refreshOnShow="false" splitter="true" maxSize="Infinity" doLayout="false">
<H3 align="center">Documentazione</H3>
<& .MenuHelp, class => 'MenuHelpContainer' &>
</div>
<div data-dojo-type="dijit.layout.ContentPane" region="center" extractContent="true"
id="BodyHelpContainer" class="BodyHelpContainer" ioArgs="{timeout:<% $r->dir_config('GetFormTimeout') %>}"
preventCache="false" preload="false" refreshOnShow="false" splitter="false" maxSize="Infinity" doLayout="false">
<& /help.html, method => 'Home' &>
</div>
</div>
<script>
% # richiama dalla cartella /help il testo corrispondente selezionato
% # arg contiene il nome della funzione
function helpLoad(arg){
dijit.byId('BodyHelpContainer').set('href', '/help.html?method='+arg+'&Ver=<%$Ver%>').then( null, function(err){
dijit.byId('BodyHelpContainer').set('errorMessage', "<span class='dijitContentPaneError'>"+
"<span class='dijitInline dijitIconError'></span>"+err+"</span>");
console.log('ERRORE DOWNLOAD HELP <% $method %>:'+err+' id:'+container.id+' timeout:'+timeout);
});
}
</script>
% }else{
<%perl>
my $sql = q{
select distinct
f.id,
f.descrizione,
f.menu_contents,
f.help,
f.menu_father_id
from
funzioni as f,
gruppi_funzioni as gf,
anagrafiche_gruppi as ag,
autorizzazioni as a
where
f.nome = ? and
f.id = gf.id_funzioni and
gf.id_gruppi = ag.id_gruppi and
ag.id_anagrafiche = ? and
gf.id_autorizzazioni = a.id and
a.nome = 'Menu';
};
my $sth = $Session{Dbh}->prepare($sql);
$sth->execute($method, $Session{User_id});
my $row_menu = $sth->fetchrow_hashref;
if($row_menu){
# rendering dell'help
</%perl>
<H2 align="center">
<% $row_menu->{'descrizione'} %>
</H2>
<% $row_menu->{'help'} %>
% my $list_children = $m->scomp('.MenuHelp', father => $row_menu->{'id'}, class => 'BodyHelpContainer');
% if($list_children){
<hr>
<% $list_children %>
% }
% }else{
<div style="margin:20px;"><span class='dijitInline dijitIconError'></span> Menu '<%$method%>' sconosciuto!</div>
% }
% }
%################################################################################
%# costruttore dell'indice - la chiamata è recorsiva
%#
<%def .MenuHelp>\
<%args>
$liv => 0 # livello del menù (il metodo viene chiamato ricorsivamente)
$father => undef # il padre
$class
</%args>
<%perl>
my $menucount=0;
my $sql = q{
select distinct
f.id,
f.nome,
f.menu_contents,
f.menu_father_id,
f.menu_ord,
(select count(*) from funzioni where menu_father_id = f.id) as children
from
funzioni as f,
gruppi_funzioni as gf,
anagrafiche_gruppi as ag,
autorizzazioni as a
where
} . ($father ? qq {
f.menu_father_id = $father and
} : q{
menu_father_id is null and
}) . q{
f.id = gf.id_funzioni and
gf.id_gruppi = ag.id_gruppi and
ag.id_anagrafiche = ? and
gf.id_autorizzazioni = a.id and
a.nome = 'Menu'
order by f.menu_ord;
};
my $sth = $Session{Dbh}->prepare($sql);
my $rows = $sth->execute($Session{User_id});
if($rows > 0){
$m->out(qq|<ul class="$class">|);
while(my $row_menu = $sth->fetchrow_hashref){
$menucount++;
my $nome = $m->interp->apply_escapes($row_menu->{'nome'}, 'js');
my $description = $m->interp->apply_escapes($row_menu->{'descrizione'}, 'h');
my $description2 = $m->interp->apply_escapes($row_menu->{'descrizione'}, 'js');
my $menu_contents = $m->interp->apply_escapes($row_menu->{'menu_contents'}, 'h');
$menu_contents =~ s/\s/&nbsp;/gs;
 
$m->out(qq|<li class="$class"><a href="javascript:helpLoad('$nome')" alt="$description">
$menu_contents
</a></li>
|);
$m->comp('.MenuHelp', father => $row_menu->{'id'}, class => $class, liv => $liv+1);
}
$m->out('</ul>');
}
</%perl>\
</%def>
/tags/2.0/htdocs/archive/dhandler
0,0 → 1,71
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2011 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
# Interfaccia CRUD utilizzata dal widget Files per gestire l'archivio
 
# http://dojotoolkit.org/features/1.6/object-store
# http://dojotoolkit.org/reference-guide/dojo/store/JsonRest.html
#
# Moduli Debian:
# aptitude install libfile-path-perl
</%doc>
<%once>
use JSON;
use IPC::Run qw(run);
use File::Path qw(make_path remove_tree);
use URI::Escape;
</%once>
<%perl>
my $base_dir = $r->dir_config('InputFilesArchive');
my $arg = $r->unparsed_uri;
$arg =~ s|^/archive/||;
utf8::is_utf8($arg) || utf8::decode($arg);
my $mode_download;
# N.B. Si usa '?' in quanto non ci sarà mai nel nome delle cartelle il carattere riservato
if($arg =~ m/^(.*)\?(\w+)$/){
$arg = $1;
$mode_download = $2;
}
$arg = uri_unescape($arg);
# $arg corriponde al file o cartella presente in $base_dir/
my($schema, $table, $rec_id, $path) = split /\//, $arg, 4;
# elimino multipli separatori di cartella
$path =~ s/\/\/+/\//g;
$path =~ s/^\/+|\/$//g;
if(!length $schema || !length $table){
$m->out(JSON::objToJson({
error => "Bad URI: malformed schema/table/id ($arg)"
}));
}else{
my $method = $r->method();
my $obj = ();
if($method ne 'GET' && $method ne 'DELETE'){
my $content; $r->read($content, $r->headers_in->{'Content-length'});
utf8::is_utf8($content) || utf8::decode($content);
$obj = jsonToObj($content);
#DEBUG print STDERR "Method:$method Path:$schema.$table:$rec_id:$path id:$obj->{'id'} new_id:$obj->{'new_id'} name:$obj->{'name'} new_name:$obj->{'new_name'} mode_download:$mode_download\n";
}
my $url = $r->dir_config('DataBaseUrl')."/$schema/$table.mql";
$m->subexec($url,
method => 'archive_' . lc $method,
obj_id => $obj->{'id'},
obj_new_id => $obj->{'new_id'},
obj_name => $obj->{'name'},
obj_new_name => $obj->{'new_name'},
rec_id => $rec_id,
mode_download => $mode_download,
path => $path,
PermissionGroup => 'Archive' # Gruppo per l'autorizzazione all'utilizzo dell'archiviazione documenti
);
}
</%perl>\
<%flags>
inherit => undef
</%flags>
%# Ultima riga senza <CR>
/tags/2.0/htdocs/archive/upload.mason
0,0 → 1,179
<%doc>
Vedi: http://docs.dojocampus.org/dojox/form/Uploader
Esempio: /opt/masonsql/htdocs/lib/dojo-release-1.6.1-src/dojox/form/tests/UploadFile.php.disabled
 
### Gestione delle versioni ###
per ciascun file <FILE> viene creata una cartella di nome ./.<FILE> contenente le varie versioni di file.
L'ultima versione o le versioni ripristinate vengono attivate con un link alla versione con il nome del file.
Le operazioni di spostamento e cambio del nome agiscono anche sulla cartella delle versioni.
 
</%doc>
<%flags>
inherit => '/init.comp'
</%flags>
<%args>
$upload_dir
</%args>
<%once>
use URI::Escape;
use Date::Calc qw(Localtime);
use Digest::MD5;
use JSON;
 
sub Files_return_message($$){
my($upload_type, $respondResult) = @_;
if($upload_type eq 'uploadedfileFlash'){
# Flash
my @field;
for my $field (keys %$respondResult){
push @field, $field.'='.uri_escape($respondResult->{$field});
}
$m->out(join(',', @field))
}elsif($upload_type eq 'uploadedfiles[]'){
# HTML5
$m->out(JSON::objToJson($respondResult));
}else{
# Iframe
$m->out('<textarea>'.JSON::objToJson($respondResult).'</textarea>');
}
}
sub Files_version_name($$$$){
my($version, $userid, $time, $digest) = @_;
return sprintf('%04d-%02d-%02d_%02d:%02d:%02d.%d.%s.%s', (Localtime($time))[0..5], $version, $userid, $digest);
 
}
sub Files_archive_uploaded_file($$$$$){
my($Base, $rec_id, $path, $upload, $log_table_name) = @_;
my $name = $upload->filename;
# verifico che il nome non contenga caratteri proibiti, altrimenti li converto in '_'
$name =~ s/[\*:|<>\?\/\\"]/_/g;
# il "." ad inizio del nome è riservato ai file/dir nascosti
$name =~ s/^\./_/;
$path =~ s|^/||;
if($path){
$path .= '/';
}
my $file_id = "$path$name";
# il nome indicato nella configurazione "Files_Trash_dir" è riservato alla cartella cestino
if($file_id eq '/'.$r->dir_config('Files_Trash_dir')){
$name = '_'.$name;
$file_id = "$path$name";
}
my $base_dir = $r->dir_config('InputFilesArchive')."/$Base/$rec_id/$path";
my $file = $base_dir.'/'.$name;
my $v_dir = $base_dir.'/.'.$name;
if(-d $file){
return { 'name' => $file_id, 'error' => 'esiste in archivio una cartella con lo stesso nome.'};
}
if(-f $file && ! -d $v_dir ){
# attivo la gestione della versione
mkdir $v_dir || return { 'name' => $file_id, 'error' => "create dir: $!"};
my(undef,undef,undef,undef,undef,undef,undef,undef,undef,$mtime) = stat($file);
open FH, '<', $file || return { 'name' => $file_id, 'error' => "can't open: $!"};
binmode FH;
my $digest = Digest::MD5->new->addfile(\*FH)->hexdigest;
close FH;
my $v_name = Files_version_name(1, $Session{User_id}, $mtime, $digest);
my $v_file = "$v_dir/$v_name";
rename $file, $v_file || return { 'name' => $file_id, 'error' => "move file: $!"};
symlink ".$name/$v_name", $file || return { 'name' => $file_id, 'error' => "link 1: $!"};
}
if(! -d $v_dir){
mkdir $v_dir || return { 'name' => "$path/.$name", 'error' => "create dir: $!"};
}
# individuo i numeri di versione
my %version;
opendir (DIR, $v_dir) || return { 'name' => "$path/.$name", 'error' => "opendir: $!"};
my $v_num = 0;
while(my $v_name = readdir(DIR)){
next if($v_name =~ /^\./);
my($date, $ver, $userid, $hash) = split /\./, $v_name, 4;
$version{$hash} = $v_name;
$v_num = $ver > $v_num ? $ver : $v_num;
}
$v_num++;
closedir(DIR);
my $v_name = Files_version_name($v_num, $Session{User_id}, time, '');
my $v_file = "$base_dir/.$name/$v_name";
if(!$upload->link($v_file)){
return { 'name' => $file_id, 'error' => sprintf "upload: $!"};
}
# calcolo la hash md5sum del nuovo file
open FH, '<', $v_file || return {'name' => $file_id, 'error' => "can't open '$v_name': $!"};
binmode FH;
my $digest = Digest::MD5->new->addfile(\*FH)->hexdigest;
close FH;
if(exists $version{$digest}){
unlink $v_file;
# verifico se il file già presente è anche quello corrente
my $v_name = $version{$digest};
# versione corrente
my $v_name_curr = readlink $file;
$v_name_curr =~ s/.*\///;
my(undef, $ver_curr, undef, $hash_curr) = split /\./, $v_name_curr, 4;
if($digest eq $hash_curr){
return {'name' => $file_id, 'info' => "Il file è già presente nell\'archivio; versione $ver_curr corrente"};
}else{
my($date, $ver, $userid, $hash) = split /\./, $v_name, 4;
# cambio la versione corrente
unlink $file || return {'name' => $file_id, 'error' => "unlink: $!"};
symlink ".$name/$v_name", $file || return {'name' => $file_id, 'error' => "link ver. $ver: $!"};
# save logs only if $log_table_name is defined
$log_table_name and DB_log('update', $rec_id, { 'ARC.' => "$file_id:$ver" }, { 'ARC.' => "$file_id:$ver_curr" }, $log_table_name);
return {'name' => $file_id, 'info' => "Il file è già presente nell\'archivio; versione $ver, resa ora corrente"};
}
}else{
# cambio il nome del file aggiungendo la hash calcolata
rename $v_file, $v_file.$digest || return {'name' => $file_id, 'error' => "add hash to '$v_name': $!"};
$v_file .= $digest;
$v_name .= $digest;
# cambio la versione corrente
unlink $file || return {'name' => $file_id, 'error' => "unlink: $!"};
symlink ".$name/$v_name", $file || return {'name' => $file_id, 'error' => "link ver. $v_num: $!"};
# save logs only if $log_table_name is defined
$log_table_name and DB_log('update', $rec_id, { 'ARC.' => "$file_id:$v_num" }, { 'ARC.' => undef }, $log_table_name);
return {'name' => $file_id, 'type' => $upload->type, 'size' => $upload->size};
}
}
</%once>
<%perl>
$r->headers_out->{'Cache-Control'} = 'max-age=0';
$m->clear_buffer;
use Data::Dumper;
my $arg = $upload_dir;
$arg =~ s|^/archive/||;
my($schema, $table, $rec_id, $path) = split /\//, $arg, 4;
my $Base = "$schema/$table";
# verifica delle autorizzazioni
$m->comp($r->dir_config('DataBaseUrl')."/$schema/$table.mql:archive_check",
'Base' => $Base,
'rec_id' => $rec_id,
'permission' => 'Insert'
);
my $log_table_name = $m->scomp($r->dir_config('DataBaseUrl')."/$schema/$table.mql:LOG_TABLE_NAME");
my $base_dir = $r->dir_config('InputFilesArchive').'/'.$upload_dir;
my $dlist = $r->upload; # ritorna istanza APR::Request::Param::Table
# determino il tipo di download
my @key_files = keys %{$dlist};
my @value_files = values %{$dlist};
my $upload_type = $key_files[0]; # uploadedfileFlash, uploadedfiles[], uploadedfiles1|2|...
#DEBUG print STDERR "upload_type:$upload_type", Dumper(\@value_files);
#DEBUG $upload_type='uploadedfileFlash';
if(! -d $base_dir){
Files_return_message($upload_type, [{ 'error' => "$base_dir not exists"}]);
return;
}
my @respondResult;
if($upload_type eq 'uploadedfileFlash'){
my $upload = $value_files[0];
#DEBUG print STDERR "uploadedfileFlash\n".Dumper($upload);
push @respondResult, Files_archive_uploaded_file($Base, $rec_id, $path, $upload, $log_table_name);
}else{
foreach my $upload (@value_files){ # istanze Apache2::Upload
#DEBUG print STDERR "uploadedfile \n".Dumper($upload);
push @respondResult, Files_archive_uploaded_file($Base, $rec_id, $path, $upload, $log_table_name);
}
}
Files_return_message($upload_type, \@respondResult);
</%perl>
/tags/2.0/htdocs/dbms/dhandler
0,0 → 1,92
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
 
Modifica la chiamata aggiungendo il suffisso al nome della tabella nella URI e chiamando il relativo componente
nella catella DataBaseSql
</%doc>
<%args>
$envelope_response => 'xml'
</%args>
<%flags>
inherit => '/library.comp'
</%flags>
<%once>
use Data::Dumper;
</%once>
<%perl>
my $path = $m->dhandler_arg;
if($path !~ m|/|){
$path = $r->dir_config('DefaultSchema').'/'.$path;
}
my $url = $r->dir_config('DataBaseUrl').'/'.$path.'.mql';
# il metodo 'select' era già utilizzato
if(!$ARGS{method}){
$ARGS{method} = 'retrieve';
}
# verifica i metodi disponibili
if(' info keyname numrec newkey retrieve update create delete xls ' !~ m/ $ARGS{method} /){
die "Method $ARGS{method} is not know\n";
}
if(!$ARGS{xml_path}){
$ARGS{xml_path} = 'dbms';
}
if(!$ARGS{key}){
$ARGS{key} = '';
}
# lista di chiavi
if(!$ARGS{key_list}){
$ARGS{key_list} = $ARGS{key};
delete $ARGS{key}
}
if($ARGS{father_key}){
$ARGS{father_id_update} = $ARGS{father_id} = $ARGS{father_key};
delete $ARGS{father_key};
}
#
if($ARGS{method} eq 'xls'){
# nessun limite nel caso di download nel formato XLS
if(!defined $ARGS{rows}){
$ARGS{rows} = -1;
}
if(!defined $ARGS{father_id}){
$ARGS{father_id} = -2;
}
# nome del file scaricato
my $filename = $m->dhandler_arg;
$filename =~ s|^dbms/||;
$filename =~ s|/|\.|;
$filename .= '.xls';
$r->headers_out->{'Cache-Control'} = 'max-age=0';
$r->headers_out->{'Content-disposition'} = "attachment;filename=$filename";
$r->headers_out->{'Content-transfer-encodig'} = 'binary';
}else{
# se viene limitato il recordset ai record figli e non viene dichiarato il limite delle righe
# viene disabilitato il limite al numero di righe
if(defined $ARGS{father_id} && !$ARGS{rows}){
$ARGS{rows} = -1;
}
if(!defined $ARGS{father_id} && $ARGS{rows} == -1){
delete $ARGS{rows};
}
}
delete $ARGS{where2};
# verifica sul campo where
if(defined $ARGS{where} && $ARGS{method} ne 'retrieve'){
# where utilizzabile solo nelle operazioni di lettura
delete $ARGS{where};
}
if(defined $ARGS{where}){
my $where = ' '.$ARGS{where}.' ';
$ARGS{where2} = $ARGS{where};
delete $ARGS{where};
}
$m->subexec($url, %ARGS, envelope_response => $envelope_response, envelope_request => $envelope_response, PermissionGroup => 'Dbms');
</%perl>
%# Ultima riga senza <CR>
/tags/2.0/htdocs/rest/dhandler
0,0 → 1,96
<%doc>
Implementa interfaccia CRUD secondo lo standard RFC-2616
Utilizzata con Dojo: dojo/store/JsonRest
Autenticazione necessaria da MasonSQL
</%doc>
<%args>
</%args>
<%flags>
inherit => '/library.comp'
</%flags>
<%once>
use Data::Dumper;
</%once>
<%init>
my $schema;
my $table;
my $id;
my $arg = $m->dhandler_arg;
if($arg =~ m|^(\w+)/(\w+)/(\w+)|){
$schema = $1;
$table = $2;
$id = $3;
}elsif($arg =~ m|^(\w+)/(\w+)/{0,1}|){
$schema = $1;
$table = $2;
}else{
die "URI malformed use /schema/table/id\n";
}
my $url = $r->dir_config('DataBaseUrl')."/$schema/$table.mql";
my $method = uc $r->method();
my $size = $r->headers_in->{'Content-length'};
if($size){
$r->read($ARGS{'content'}, $size);
}
if($ARGS{'father_key'}){
$ARGS{'father_id_update'} = $ARGS{'father_id'} = $ARGS{'father_key'};
delete $ARGS{'father_key'};
}
# Si veda http://www.ietf.org/rfc/rfc2616.txt
# POST --> create
# PUT --> update
# DELETE --> delete
# GET --> retrieve N.B. metodo 'select' era già utilizzato per altri scopi
if($method eq 'POST' || ($method eq 'PUT' && $ENV{HTTP_IF_NONE_MATCH} eq '*')){
$ARGS{method} = 'create';
}elsif($method eq 'PUT'){
$ARGS{method} = 'update';
}elsif($method eq 'DELETE'){
$ARGS{method} = 'delete';
}elsif($method eq 'GET'){
if(exists $ARGS{'newkey'}){
$ARGS{method} = 'newkey';
}else{
$ARGS{method} = 'retrieve';
}
}else{
die "Unknow $method method\n";
}
$ARGS{'key_list'} = $id;
delete $ARGS{'key'};
delete $ARGS{'where2'};
# verifica sul campo where
if(defined $ARGS{'where'} && $ARGS{method} ne 'retrieve'){
# where utilizzabile solo nelle operazioni di lettura
delete $ARGS{'where'};
}
if(defined $ARGS{'where'}){
my $where = ' '.$ARGS{'where'}.' ';
$ARGS{'where2'} = $ARGS{'where'};
delete $ARGS{'where'};
}
 
# DEBUG print STDERR "URL: $url\n";
# DEBUG print STDERR "ARGS: schema:$schema table:$table id:$id";
if(exists $ENV{HTTP_RANGE} && ($ENV{HTTP_RANGE} =~ m/items=(\d+)-(\d+|\**)/ || $ENV{HTTP_RANGE} =~ m/(\d+)-(\d+|\**)/)){
my $start = $1 || 0;
$ARGS{'start'} = $start;
my $stop = $2;
if(defined $stop && $stop ne '*' && $stop ne ''){
$ARGS{'rows'} = $stop - $start + 1;
}
# DEBUG print STDERR "RANGE: ${start}-${stop}\n";
}else{
$ARGS{'start'} = 0;
$ARGS{'rows'} = -1; # nessun limite al numero di righe
}
</%init>
<%perl>
$m->subexec($url,
%ARGS,
envelope_response => $ARGS{'envelope_response'} || 'rest',
envelope_request => $ARGS{'envelope_request'} || 'rest',
PermissionGroup => undef
);
</%perl>
%# Ultima riga senza <CR>
/tags/2.0/htdocs/change_password.txt
0,0 → 1,20
<%doc>
# richiamato da change_password.html per effettuare il cambio password
</%doc>
<%flags>
inherit => '/init.comp'
</%flags>
<%perl>
my $ARGS = $Session{ARGS};
if($ARGS->{method} ne 'change_password'){
die "No change_password method\n";
}
my $login = $Session{Group_Admins} ? $ARGS->{Login} : $Session{Login};
my $password = $ARGS->{Password};
my $err_mess = $r->auth_type->update_password($r, $login, $password, 0);
if($err_mess){
die "$err_mess\n";
}else{
$m->out('OK: Password modificata!');
}
</%perl>
/tags/2.0/htdocs/UserPasswordResetForm.html
0,0 → 1,243
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2016-2020 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Rajesh Madaye <rajeshmadaye@yahoo.com>
# Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
<%args>
$action => undef
$user => ''
</%args>
 
<%attr>
Cache_MaxAge => 120
</%attr>
<% $r->dir_config('HtmlDocType') %>
 
<%once>
use Auth_AC::UserRegistration;
my $LoginType = $r->dir_config('LoginType');
my $UserRegTypeMessage = $r->dir_config('UserRegTypeMessage');
my $UR = Auth_AC::UserRegistration->new();
</%once>
<%init>
$m->clear_buffer;
# connessione al database
my $dbh = $Session{Dbh};
## Functional processing
my $form_submit_status = 0;
if(defined $action and $action eq "true") {
$form_submit_status = $UR->process_password_reset_form(dbh => $dbh, formdata => \%ARGS, r => $r, m => $m);
}
</%init>
 
<%flags>
inherit => '/init.comp'
</%flags>
 
<html>
<head>
 
% my $Dojo_dir = $JSLogger->level() eq $DEBUG ? $r->dir_config('DojoDirUrlDebug') : $r->dir_config('DojoDirUrl');
<script src="https://www.google.com/recaptcha/api.js?hl=it"></script>
<script src="<% $Dojo_dir %>/dojo/dojo.js" type="text/javascript" data-dojo-config="async: false,
isDebug:<% $JSLogger->level() eq $DEBUG ? 'true' : 'false'%>, parseOnLoad:true, locale: 'it'"></script>
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/dijit.css" type="text/css">
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/claro/document.css" type="text/css">
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/claro/claro.css" type="text/css">
<link rel="stylesheet" href="/css/main.css" type="text/css">
 
<script>
// Code to confirm form submission acknowledgement.
% if(defined $action and $action eq "true") {
% if($form_submit_status) {
%# alert("We have reset your password. Please check your email to get initial password to login");
alert("La password è stata modificata!\nControlla <% $UserRegTypeMessage eq 'sms' ? 'nel tuo cellulare il messaggio SMS' : 'nella posta in arrivo il messaggio' %> con la nuova password per collegarti.");
window.location.replace('/');
resetHandler();
% } else {
%# alert("Password reset failed. Please try again with valid input values.");
alert("Modifica della password fallita!\nSi prega di ripetere in tentativo con dei dati validi.");
% }
% }
 
// Code to process core functionality.
var JSLoginType = null;
function validateEmail() {
var email = document.getElementById("email");
var atpos = email.value.indexOf("@");
var dotpos = email.value.lastIndexOf(".");
var rc = false;
if (atpos<1 || dotpos<atpos+2 || dotpos+2>=email.length) {
document.getElementById("divErrEmail").innerHTML = "<p>Inserisci e-mail valido</p>";
document.getElementById("email").className = "string widget widgetRwError";
document.getElementById("email").focus();
rc = false;
} else {
document.getElementById("divErrEmail").innerHTML = "";
document.getElementById("email").className = "string widget widgetRw";
rc = true;
}
return rc;
}
function validateEmpty(sourceEleId, errorEleId) {
var element =document.getElementById(sourceEleId).value;
var rc = false;
element = element.replace(/^\s+|\s+$/g, '');
if (element.length < 1) {
document.getElementById(errorEleId).innerHTML = "<p>Si prega di inserire il valore</p>";
document.getElementById(sourceEleId).className = "string widget widgetRwError";
rc = false;
} else {
document.getElementById(errorEleId).innerHTML = "";
document.getElementById(sourceEleId).className = "string widget widgetRw";
rc = true;
}
return rc;
}
 
function isUserExists(usrId) {
usrId = usrId.toLowerCase();
var error_message = "";
var url = "/UserRegistrationResetCheck.txt";
require(["dojo/request/xhr", "dojo/dom", "dojo/dom-construct", "dojo/json", "dojo/on", "dojo/domReady!"],
function(xhr, dom, domConst, JSON, on){
xhr(url, {
handleAs: "text",
sync: true,
query: { "login": usrId }
}).then(function(response){
error_message = response;
}, function(err){
error_message = "Errore!<br>" + err.message;
});
});
return error_message;
}
 
function isEmpty(str) {
return (!str || 0 === str.length);
}
 
function validateUserID(sourceEleId, errorEleId) {
var element = document.getElementById(sourceEleId).value;
element = element.replace(/^\s+|\s+$/g, '');
rc = false;
JSLoginType = "<% $LoginType %>";
var userIDMsg = "";
if(validateEmpty(sourceEleId, errorEleId)) {
userIDMsg = isUserExists(element);
if(isEmpty(userIDMsg)) {
document.getElementById(errorEleId).innerHTML = "";
document.getElementById(sourceEleId).className = "string widget widgetRw";
rc = true;
} else {
document.getElementById(errorEleId).innerHTML = "<p>"+userIDMsg+"</p>";
document.getElementById(sourceEleId).className = "string widget widgetRwError";
document.getElementById(sourceEleId).focus();
}
}
return rc;
}
 
function validateCaptcha() {
var rc = false;
var captcha_value = document.getElementById("g-recaptcha-response").value;
if(isEmpty(captcha_value)) {
document.getElementById("divErrCaptcha").innerHTML = "<p>Si prega di risolvere i captcha</p>";
} else {
document.getElementById("divErrCaptcha").innerHTML = "";
rc = true;
}
return rc;
}
 
function validateForm(){
var rc = false;
if( validateUserID('login', 'divErrLogin') &&
validateCaptcha()
) {
rc = true;
}
return rc;
}
 
function submitHandler(){
var rc = validateForm();
if(rc) {
<!-- alert("Base:" + window.location.origin); -->
UserPasswordReset.action.value = true;
document.UserPasswordReset.submit();
}
return rc;
}
 
function resetHandler() {
document.getElementById("login").className = "string widget widgetRw";
document.getElementById("divErrLogin").innerHTML = "";
document.getElementById("divErrCaptcha").innerHTML = "";
document.UserPasswordReset.reset();
grecaptcha.reset();
document.getElementById("login").focus();
return false;
}
</script>
<style>
table tr {
height: 21px;
}
</style>
 
</head>
 
<body class="claro">
<br><br><br>
<& '/logo.comp' &><br>
<h2 align="center">Password Reset Form:</h2>
<form method="POST" name="UserPasswordReset">
<input type="hidden" id="action" name="action" value=false>
<table align="center" border="0">
<tr>
<td></td>
<td><BR><div class="g-recaptcha" data-sitekey=<% $r->dir_config('ReCaptchaAPISiteKey') %>></div></td>
<td><div id="divErrCaptcha" style="color:#FF0000;"></div></td>
</tr>
<tr style="height:10px;"></tr>
<tr>
<td style="width:33%;"></td>
<td align="center" style="width:33%; min-width:300px;"><font size="3" color="red">*</font>
Login utente:
<input name="login" id="login" size="30" maxlength="60" required=true onblur="validateUserID('login', 'divErrLogin')" class="string widget widgetRw" value="<%$user |js%>">
</td>
<td style="width:33%;"><div id="divErrLogin" style="color:#FF0000;"></div></td>
</tr>
<tr style="height:10px;"></tr>
<tr>
<td></td>
<td>
<input class="widget button" type="button" value="Invio .." onclick="submitHandler()">
&nbsp;&nbsp;
<input class="widget button" style="float: right;" type="button" value="Annulla" onclick="resetHandler()">
</td>
</tr>
<tr style="height:20px;"></tr>
<tr>
<td></td>
<td>
<p align="center">Note: <font size="3" color="red">*</font> indica i campi obbligatori.</p>
</td>
</tr>
</table>
</form>
<br/>
<br/>
<& /copyright.comp &>
</body>
</html>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/menu.js
0,0 → 1,365
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%args>
$Div
$mainTab
</%args>
<%once>
my $Timeout = $r->dir_config('GetFormTimeout');
</%once>
require(["dojo/ready", "dijit", "dijit/MenuBar", "dijit/PopupMenuBarItem", "dijit/PopupMenuItem",
"dijit/Menu", "dijit/MenuItem", "dijit/MenuBarItem", "dijit/registry", "dojo/Evented"],
function(ready, dijit, MenuBar, PopupMenuBarItem, PopupMenuItem, Menu, MenuItem, MenuBarItem, Registry, Evented){
ready(function(){
var mainMenuBar = new MenuBar({'class':'menuMasonSql', baseClass:'menuMasonSql', popupDelay:100});
var mainTab = Registry.byId('<% $mainTab %>');
mainTab.check_readOnly = function(tab, set_ro){
// set_ro: force read only if data is not changed
if(tab && tab.displayBinding){
var is_edit = false;
var db = tab.displayBinding.dataBinding;
for(var I=0; I<db.children.length; I++){
var db_child = db.children[I];
if(!db_child.readOnly()){
// check if there is a change in the child recordset
var new_data = [];
Form2Array(db_child.displayBinding.fields, new_data);
var difference = ArrayDiffKeys(db_child.keys, db_child.data, new_data, true);
if(!difference.allNull()){
is_edit = true;
break;
}
}
}
if(!is_edit && !db.readOnly()){
// check if there is a change in the main recordset
var new_data = [];
Form2Array(db.displayBinding.fields, new_data);
var difference = ArrayDiffKeys(db.keys, db.data, new_data, true);
if(!difference.allNull()){
is_edit = true;
}
}
if(is_edit){
my_alert('Prima di abbandonare la finestra si deve completare o annullare la modifica in corso');
mainTab.selectChild(tab);
return false;
}
if(set_ro){
// force read only all recordsets
for(var I=0; I<db.children.length; I++){
var db_child = db.children[I];
if(!db_child.readOnly()){
db_child.displayBinding.readOnly(true);
}
}
if(!db.readOnly()){
db.displayBinding.readOnly(true);
}
}
}
return true;
};
mainTab.watch("selectedChildWidget", function(name, oval, nval){
this.check_readOnly(oval);
});
masonSql.mainTab = mainTab;
var menuParameters = {};
// parametri del Tab
mainTab.parameterGet = function(par_or_name){
if(typeof par_or_name == 'string'){
var par = this.menuParameters[par_or_name];
if(!par){
var err = 'Menu ' + par_or_name + ' inesistente';
console.error(err);
my_alert(err);
return null;
}
return par;
}
return par_or_name;
}
// metodo per attivare il Tab
mainTab.activateMenuTab = function(par_or_name, post_handler, visible){
var par = this.parameterGet(par_or_name);
if(!par)return;
// verifico che il Tab che si abbandona non abbia recordset in modifica
if(!this.check_readOnly(mainTab.currentTab)){
return;
}
// verifico se il tab della funzione richiesta è già caricato
var tab = par.contentPane;
if(tab){
if(!post_handler && tab.displayBinding){
post_handler = function(){
tab.displayBinding.post_init();
tab.displayBinding.loadRecords('rewind');
}
}
mainTab.displayMenuTab(par, visible, post_handler);
}else{
console.debug('Loading ' + par.title);
require(["dojox/layout/ContentPane"], function(ContentPane){
tab = new ContentPane({
title: par.title,
tooltip: par.descr,
loadingMessage: 'Caricamento ' + par.title,
executeScripts: true,
scriptHasHooks: true,
parseOnLoad: true,
closable: true,
ioArgs: {
headers: {
'MasonSql-body': '1'
},
timeout: <% $Timeout %>
},
onClose: function(){
if(!mainTab.check_readOnly(this, true)){
return false;
}
masonSql.mainTab.removeChild(this);
this._visible = null;
return false;
}
});
tab.par = par;
par.contentPane = tab;
mainTab.displayMenuTab(par, visible);
if(par.type == 'u'){
tab.set('href', par.cmd).then(
function(){
console.debug('downloaded href', tab);
if(post_handler){
masonSql.once('ready', post_handler);
}
masonSql.ready(tab);
},
function(err){
tab.set('errorMessage', "<span class='dijitContentPaneError'>"+
"<span class='dijitInline dijitIconError'></span>"+err+' id:'+tab.id+' timeout:'+<% $Timeout %>+"</span>");
console.error('ERROR href',err , tab);
}
);
}else{
tab.set('content', '<script\>'+par.cmd+'</script\>');
}
});
}
mainTab.currentTab = tab;
%# BEGIN DEPRECATED
CurrentBody = tab.containerNode;
%# END DEPRECATED - usato da library/bodyLoad
return tab;
};
// metodo per cancellare il tab dalla memoria
mainTab.destroyMenuTab = function(par_or_name){
var par = this.parameterGet(par_or_name);
if(!par)return;
var tab = par.contentPane;
// verifico che la pagina da distruggere non abbia dei recordset in modifica
if(!mainTab.check_readOnly(tab, true)){
return false;
}
if(par.contentPane){
par.contentPane.destroy();
par.contentPane = null;
}
return true;
};
// visibilità del tab
mainTab.displayMenuTab = function(par_or_name, visible, post_handler){
var par = this.parameterGet(par_or_name);
if(!par)return;
var tab = par.contentPane;
if(!tab)return;
console.debug('modeMenuTab', tab);
if(visible == null && tab._visible == false){
my_alert('Menu non visibile');
return tab;
}
if(tab._visible == null && visible == null){
tab._visible = false;
visible = true;
}
if(visible == null)visible = true;
if(visible != tab._visible){
if(visible){
this.addChild(tab);
}else if(tab._visible == true){
this.removeChild(tab);
}
}
tab._visible = visible;
if(tab._visible){
this.selectChild(tab);
}
if(post_handler){
post_handler(tab);
}
return tab;
};
// Menu parameters
<& .Menu, menu_father => 'mainMenuBar' &>\
mainTab.menuParameters = menuParameters;
mainMenuBar.placeAt('<% $Div %>');
mainMenuBar.startup();
dijit.byId('<% $Div %>').getParent().resize();
});
});
%################# costruttore del menù - la chiamata è ricorsiva
<%def .Menu>\
<%args>
$liv => 0 # livello del menù (il metodo viene chiamato ricorsivamente)
$father => undef # id padre (usato per la generazione del menù a tendina)
$menu_father
</%args>
<%perl>
my $menucount=0;
my $sql = qq{
select distinct
f.id,
f.nome,
f.descrizione,
f.commento,
f.menu_contents,
f.menu_status,
f.menu_command,
f.menu_cmdtype,
f.menu_icon,
f.menu_style,
f.menu_father_id,
f.menu_ord,
(select count(*) from funzioni where menu_father_id = f.id) as children
from
funzioni as f,
gruppi_funzioni as gf,
anagrafiche_gruppi as ag,
autorizzazioni as a
where
} . ($father ? qq {
f.menu_father_id = $father and
} : q{
menu_father_id is null and
}) . q{
f.id = gf.id_funzioni and
gf.id_gruppi = ag.id_gruppi and
ag.id_anagrafiche = ? and
gf.id_autorizzazioni = a.id and
a.nome = 'Menu' and
f.menu_contents is not null
order by f.menu_ord;
};
my $sth = $Session{Dbh}->prepare($sql);
#DEBUG $PLogger->debug(sub{ "execute($Session{User_id} query=[[$sql]])\n"; });
$sth->execute($Session{User_id});
while(my $row_menu = $sth->fetchrow_hashref){
# verifico il livello di permessi per la visualizzazione del menu
if($Session{Auth}{$row_menu->{'nome'}}{Menu}){
if($menucount || $liv){
}
$menucount++;
my $command = $row_menu->{'menu_command'};
$command =~ s/^\s+|\s+$//gs;
my $type = $row_menu->{'menu_cmdtype'};
# se non è selezionato il tipo forzo uri = ''
if($type){
my $cmd = $command;
if($type eq 'u'){
# alla URL aggiungo sempre 'Ver=$Ver'
$command = $cmd . ($cmd =~ m/\?/ ? "&Ver=$Ver" : "?Ver=$Ver");
}elsif($type eq 'U'){
$type = 'u';
# alla URL aggiungo 'Ver=$Ver' se non fosse già presente
if($command !~ m/[\?\&]Ver=\$Ver/){
# verifico se c'è già quel parametro
$command .= $command =~ m/\?/ ? '&Ver=$Ver' : '?Ver=$Ver';
}
$command = eval $cmd;
if($@){
die "ERROR eval command ($type) menu $row_menu->{'nome'}\ncommand:[$cmd]\nerror:[$@]\n";
}
}elsif($type eq 'J'){
$type = 'j';
$command = eval $cmd;
if($@){
die "ERROR eval command ($type) menu $row_menu->{'nome'}\ncommand:[$cmd]\nerror:[$@]\n";
}
}
}else{
$command = '';
}
my $statusText = (length($row_menu->{'menu_status'}) == 0 ) ? "Menu $row_menu->{'menu_contents'}" : $row_menu->{'menu_status'};
my $id_sub = $row_menu->{'nome'};
$id_sub =~ tr/ \./__/;
 
# GDO DEPRECATED (periodo di transizione 2012-2013)
# Se trovo type=='j' e $command contenente "pageLoad('**', '')" converto il comando in "u"
#
if($command =~ /^\s*pageLoad\s*\(\s*'(.*)'\s*,\s*''\s*\);{0,1}\s*$/s ||
$command =~ /^\s*pageLoad\s*\(\s*'(.*)'\s*\);{0,1}\s*$/s ||
$command =~ /^\s*pageLoad\s*\(\s*'(.*)'\s*,\s*null\s*\);{0,1}\s*$/s
){
$type = 'u';
$command = $1;
}
# GDO DEPRECATED END
 
</%perl>
menuParameters['<% $row_menu->{'nome'} %>'] = {
nome: '<% $row_menu->{'nome'} |js%>',
title: '<% $row_menu->{'descrizione'} |js%>',
descr: '<% $row_menu->{'commento'} |js%>',
type: '<% $type %>',
% if($row_menu->{'menu_icon'}){
iconClass: 'masonSqlIcons <% $row_menu->{'menu_icon'} %>',
% }
style: '<% $row_menu->{'menu_style'} %>',
cmd: '<% $command |js%>'
};
% if($row_menu->{'children'}){
var taskMenu_<%$id_sub%> = new Menu({});
<% $menu_father %>.addChild(new PopupMenu<% $liv == 0 ? 'Bar' : '' %>Item({
baseClass:'menuMasonSql',
% if($row_menu->{'menu_icon'}){
iconClass: 'masonSqlIcons <% $row_menu->{'menu_icon'} %>',
% }
style: '<% $row_menu->{'menu_style'} %>',
label: '<% $row_menu->{'menu_contents'} |js%>',
tooltip: '<% $statusText |js%>',
popup: taskMenu_<%$id_sub%>
}));
% $m->comp('.Menu', father => $row_menu->{'id'}, menu_father => "taskMenu_$id_sub", liv => $liv+1);
% }else{ # children
<% $menu_father %>.addChild(new Menu<% $liv == 0 ? 'Bar' : '' %>Item({
baseClass:'menuMasonSql',
% if($row_menu->{'menu_icon'}){
iconClass: 'masonSqlIcons <% $row_menu->{'menu_icon'} %>',
% }
style: '<% $row_menu->{'menu_style'} %>',
label: '<% $row_menu->{'menu_contents'} |js%>',
tooltip: '<% $statusText |js%>',
onClick: function(ev){ // del menu
if(ev.ctrlKey){
// distruggo la pagina eventualmente presente
if(!mainTab.destroyMenuTab('<% $row_menu->{'nome'} %>')){
return;
}
}
mainTab.activateMenuTab('<% $row_menu->{'nome'} %>');
}
}));
% } #children
% }
% }
</%def>
/tags/2.0/htdocs/autohandler
0,0 → 1,151
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%attr>
Cache_MaxAge => 12*60*60 # validità in cache del Browser del documento
body_scroll => '' # TAG SCROLL dell'elemento BODY
</%attr>
<%once>
use Log::Log4perl::Level;
use POSIX qw(strftime);
</%once>
<%perl>
#DEBUG $PLogger->debug(sub{ "Cache-Control max-age=".$m->base_comp->attr('Cache_MaxAge')."\n"; });
$r->headers_out->{'Cache-Control'} = 'max-age='.$m->base_comp->attr('Cache_MaxAge');
# chiamo il componente figlio in anticipo in quanto questo permette
# di inizializzare alcune componenti del codice HTML che vanno inserite
# nella sezione HEADER
my $body = $m->scomp($m->fetch_next, @_);
# L'Header MasonSql-body se true, si invia solo il corpo del documento
# Usato in lib/library.js:bodyLoad
my $html_head = !$r->headers_in->{'MasonSql-body'};
$Session{'Dojo_dir'} = $JSLogger->level() eq $DEBUG ? $r->dir_config('DojoDirUrlDebug') : $r->dir_config('DojoDirUrl');
if($html_head){
my $expiration_date = strftime "%a %b %e %H:%M:%S %Y GMT", gmtime(time + $m->base_comp->attr('Cache_MaxAge'));
</%perl>
<% $r->dir_config('HtmlDocType') %>
<html>
<head>
<title><%$r->dir_config('ApplicationTitle')%></title>
<& /lib/head_meta.comp, http_equiv => 'Content-Type', content => 'text/html; charset=utf-8' &>\
<& /lib/head_meta.comp, http_equiv => 'Content-Language', content => 'Italian' &>\
<& /lib/head_meta.comp, http_equiv => 'Expires', content => $expiration_date &>\
<& /dojo-modules.comp, Dojo_dir => $Session{'Dojo_dir'} &>
<%perl>
# precarico librerie necessarie
&LoadHeader(
'/css/main.css', '/lib/library.js',
'/lib/httpRequestMason.js', '/lib/databinding.js', '/lib/displaybinding.js',
);
# caricamento di meta, style e codice javascript richiamato da LoadHeader(...)
# caricamento include di /lib/head_meta.comp
foreach my $meta (@{$Global{LoadHeader_Meta}}){
$m->out(' '.$meta."\n");
}
# caricamento style
foreach my $css (@{$Global{LoadHeader_Css}}){
$m->out(' '.$css."\n");
}
# caricamento in-line style
# nel code è possibile inserire definizioni stylesheet aggiuntive che verranno raccolte in questo blocco STYLE
# sintassi: <&| /lib/head_style.comp, Name => ... &>.... { tag: val; ...} </&>
if($Global{LoadHeader_Style}){
$m->out("<style type=\"text/css\">");
foreach my $elem (@{$Global{LoadHeader_Style}}){
$m->out($elem."\n");
}
$m->out("</style>\n");
}
</%perl>
<link rel="shortcut icon" href="/img/icon.ico">
<meta name="AUTHOR" content="Brugnara Guido - gdo@leader.it">
<meta name="COPYRIGHT" content="Leader.IT di Guido Brugnara; Strada della Pozzata, 41 - Villazzano; 38123 TRENTO (ITALY); info@leader.it">
<%perl>
my $Ver = $Session{Session};
if($JSLogger->level() eq $DEBUG){
foreach my $js (@{$Global{LoadHeader_Js}}){
if($js =~ m/\?/){
$js .= "\&Ver=$Ver";
}else{
$js .= "?Ver=$Ver";
}
$m->out(qq{ <script src="$js" type="text/javascript"></script>\n});
}
}else{
$m->out('<script type="text/javascript">');
foreach my $js (@{$Global{LoadHeader_Js}}){
$m->out("\n//---- [$js]\n");
$m->comp($js);
}
$m->out('</script>');
}
</%perl>
</head>
<body id="bodyMasonSql" class="claro" scroll="<% $m->base_comp->attr('body_scroll') %>">
<script>
require(["dojo/ready"], function(ready){
ready(function(){
if(window.masonSql){
window.masonSql.ready(null);
}else{
console.debug('No masonSql component');
}
});
});
</script>
<%perl>
# # caricamento librerie javascript
# if($JSLogger->level() ne $DEBUG){
# $m->out('<script>');
# foreach my $js (@{$Global{LoadHeader_Js}}){
# $m->out("\n//---- [$js]\n");
# $m->comp($js);
# }
# $m->out('</script>');
# }
#### ATTENZIONE BLOCCA SE NON ESISTE - DEBUG!!!
# if(!$Global{LoadHeader_Body}){
# die Dumper(\%Global);
# }
foreach my $hbody (@{$Global{LoadHeader_Body}}){
$m->out("\n<!-- <HTML_BODY> -->\n");
$m->out($hbody);
$m->out("\n<!-- </HTML_BODY> -->\n");
}
} # if($html_head)
</%perl>
<%$body%>\
<script>
% if(@Script_buffer){
// Script_buffer BEGIN
% $m->out(@Script_buffer);
// Script_buffer END
% @Script_buffer = ();
% }
% if($html_head){
window.onunload = function (){
try{hReqMason_abort_all()}catch(err){}
}
</script>
</body>
</html>
% }
<%flags>
inherit => '/init.comp'
</%flags>
<%shared>
%Global=();
@Script_buffer = ();
#DEBUG $PLogger->debug(sub{ "/autohandler shared\n"; });
# precarico i componenti figli in modo che vengano inizializzati così da influenzare
# la sezione <head> in base agli include richiesti dai componenti
#DEBUG $PLogger->debug(sub{ "fetch_next =>",Dumper(\@_); });
</%shared>
/tags/2.0/htdocs/home.html
0,0 → 1,37
<%args>
$logout => undef
</%args>
<br><br>
<table width="100%">
<tr>
<td width="20%"></td>
<td align="center" width="30%">
<& /logo.comp &>
</td>
<td align="center" width="30%">
<& /copyright.comp &>
</td>
<td width="20%"></td>
</tr>
</table>
<br><br>
<%perl>
if(!$logout){
# verifico se ci sono nuovi messaggi per l'utente
my $sth = $Session{Dbh}->prepare(q{
SELECT count(*)
FROM public.messages_users
WHERE notification_time IS NULL
AND id_anagrafiche = ?;
});
$sth->execute($Session{User_id});
if($sth->fetchrow_arrayref->[0]){
# Apro il form dei messaggi utente
</%perl>
<script>
masonSql.mainTab.activateMenuTab('User_messages', null, true);
</script>
<%perl>
}
}
</%perl>
/tags/2.0/htdocs/index.html
0,0 → 1,74
<%attr>
Cache_MaxAge => 1
body_scroll => 'no' # in IE non visualizza la barra di scorrimento
</%attr>
<%args>
$nome_body => "HomePage"
$bottom => "bottom.html"
</%args>
%# META per evitare i "ragni" dei motori di ricerca
<& /lib/head_meta.comp, name => 'ROBOTS', content => 'noindex' &>\
<%init>
# precaricamento librerie utilizzate dai componenti caricati "OnDemand"
&LoadHeader('/input/input.comp', '/input/string.comp', '/input/date.comp',
'/input/span.comp', '/input/number.comp', '/input/select.comp', '/input/url.comp',
'/input/radio.comp', '/input/checkbox.comp', '/input/form.comp',
'/input/select.comp', '/input/time.comp', '/input/timestamp.comp',
'/input/button.comp', '/input/Permission.comp', '/input/Files.comp',
'/input/htmlselect.comp', '/input/codfisc_pi.comp', '/input/image.comp',
'/input/file.comp', '/input/color.comp', '/input/divselect.comp',
'/lib/FCKeditor/fckeditor.js', '/input/FCKeditor.js'
);
</%init>\
<script>
require([
"dijit/dijit",
%#DOJO "dojo/parser",
"dijit/layout/BorderContainer",
"dijit/layout/ContentPane",
"dijit/layout/TabContainer"
]);
</script>
<& /index.application.comp &>\
<div data-dojo-type="dijit.layout.BorderContainer" design="headline" persist="false" gutters="false"
style="min-width: 200px; min-height: 100px; z-index: 0; width: 100%; height: 100%;">
<div data-dojo-type="dijit.layout.ContentPane" id="TopContent" style="width:100%;" extractContent="false"
preventCache="false" preload="false" refreshOnShow="false" doLayout="true"
region="top" splitter="false" maxSize="Infinity" >
</div>
<div data-dojo-type="dijit/layout/ContentPane" id="BodyContent" executeScripts="true" extractContent="true"
preventCache="false" preload="false" refreshOnShow="false" doLayout="true"
region="center" splitter="false" maxSize="Infinity">
<div data-dojo-type="dijit/layout/TabContainer" id="mainTab" style="width: 100%; height: 100%;">
</div>
</div>
<div data-dojo-type="dijit.layout.ContentPane" id="BottomContent" extractContent="false" preventCache="false"
preload="false" refreshOnShow="false" doLayout="true" region="bottom" splitter="false" maxSize="Infinity" >
<& $bottom, Ver => $Ver &>
</div>
</div>
<script>
<& /menu.js, Div => 'TopContent', mainTab => 'mainTab' &>
var Body = document.getElementById('BodyContent');
var Top = document.getElementById('TopContent');
var Bottom = document.getElementById('BottomContent');
// Current... puntano al <DIV> corrente (vedi libreria library.js --> pageLoad)
var CurrentBody;
require(["dojo/ready", "dijit/registry"], function(ready, registry){
ready(function(){
// apro il Tab iniziale
registry.byId('mainTab').activateMenuTab('<% $nome_body %>');
% if(my $timeout = $r->dir_config('CheckSessionInterval')){
window.timerSession = window.setInterval("hReqMason_ExecuteTimeout('/timerSession.html', <% $r->dir_config('GetRecordTimeout') %>, function(){}, function(){});", <% $timeout %>);
% }
window.onbeforeunload = function(event){
if(masonSql.onbeforeunload_disabled || masonSql.mainTab.currentTab.par.nome == "CloseSession"){
return null;
}
var message = "Sei certo di voler chiudere l'applicazione?";
event.returnValue = message;
return message;
};
});
});
</script>
/tags/2.0/htdocs/COPYRIGHT
0,0 → 1,17
# --------------------------------------------------------------------------- #
# Copyright: (C) 2003-2017 Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# E-mail: info@leader.it
#
# Note: The authors with the rispettive contributions are available
# in restricted access of SVN repository at
# https://www.leader.it/wsvn/masonsql
# Open Source releases are free accessible on SVN repository at:
# https://guest@www.leader.it/wsvn/masonsql/tags
# --------------------------------------------------------------------------- #
#
# Double licence are available, if requested, with differents prices and conditions:
# - Commercial licence (all releases)
# - AGPL Affero General Public Licence Rel.1 ( http://www.affero.org/oagpl.html )
# (Releases 1.6 & 1.9)
/tags/2.0/htdocs/UserRegistrationForm.html
0,0 → 1,393
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2016-2020 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Rajesh Madaye <rajeshmadaye@yahoo.com>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
 
 
<%args>
$action => undef
</%args>
 
<%attr>
Cache_MaxAge => 120
</%attr>
<% $r->dir_config('HtmlDocType') %>
 
<%once>
use Auth_AC::UserRegistration;
my $LoginType = $r->dir_config('LoginType');
my $UserRegTypeMessage = $r->dir_config('UserRegTypeMessage');
my $UR = Auth_AC::UserRegistration->new();
</%once>
<%init>
# connessione al database
my $dbh = $Session{Dbh};
## Functional processing
my $form_submit_status = 0;
if(defined $action and $action eq "true") {
$form_submit_status = $UR->process_registration_form(dbh => $dbh, formdata => \%ARGS, r => $r, m => $m);
}
</%init>
 
<%flags>
inherit => '/init.comp'
</%flags>
 
<html>
<head>
 
% my $Dojo_dir = $JSLogger->level() eq $DEBUG ? $r->dir_config('DojoDirUrlDebug') : $r->dir_config('DojoDirUrl');
<script src="https://www.google.com/recaptcha/api.js?hl=it"></script>
<script src="<% $Dojo_dir %>/dojo/dojo.js" type="text/javascript" data-dojo-config="async: false,
isDebug:<% $JSLogger->level() eq $DEBUG ? 'true' : 'false'%>, parseOnLoad:true, locale: 'it'"></script>
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/dijit.css" type="text/css">
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/claro/document.css" type="text/css">
<link rel="stylesheet" href="<% $Dojo_dir %>/dijit/themes/claro/claro.css" type="text/css">
<link rel="stylesheet" href="/css/main.css" type="text/css">
 
<script>
// Code to confirm form submission acknowledgement.
% if(defined $action and $action eq "true") {
% if($form_submit_status) {
%# alert("Thank you for registration on MasonSQL portal. Please check your <% $UserRegTypeMessage %> to get initial password to login");
alert("Grazie per esserti registrato!\nControlla <% $UserRegTypeMessage eq 'sms' ? 'nel tuo cellulare il messaggio SMS' : 'nella posta in arrivo il messaggio' %> con la password iniziale per collegarti.");
window.location.replace('/');
resetHandler();
% } else {
%# alert("Registration failed. Please try again with valid input values.");
alert("Registrazione fallita!\nSi prega di ripetere la registrazione con dei dati validi.");
% }
% }
 
// Code to process core functionality.
var JSLoginType = null;
function validateEmail() {
var email = document.getElementById("email");
var atpos = email.value.indexOf("@");
var dotpos = email.value.lastIndexOf(".");
var rc = false;
if (atpos<1 || dotpos<atpos+2 || dotpos+2>=email.length) {
document.getElementById("divErrEmail").innerHTML = "<p>Inserisci e-mail valido</p>";
document.getElementById("email").className = "string widget widgetRwError";
//document.getElementById("email").focus();
rc = false;
} else {
document.getElementById("divErrEmail").innerHTML = "";
document.getElementById("email").className = "string widget widgetRw";
rc = true;
}
return rc;
}
function validateCellSMS() {
var rc = false;
% if($UserRegTypeMessage eq 'sms') {
var cellNum = document.getElementById("cell_sms");
if (!validatePhoneNumber(cellNum)) {
document.getElementById("divErrCellSMS").innerHTML = "<p>numero di telefono invalido</p>";
document.getElementById("cell_sms").className = "string widget widgetRwError";
rc = false;
} else {
document.getElementById("divErrCellSMS").innerHTML = "";
document.getElementById("cell_sms").className = "string widget widgetRw";
rc = true;
};
% }elsif($UserRegTypeMessage eq 'email'){
rc = true;
% }
return rc;
}
function validatePhoneNumber(inputtxt) {
var rc = false;
var email = document.getElementById("cell_sms");
if(!isEmpty(inputtxt)) {
var phoneno = /^([0-9]{9,11})$/;
if(inputtxt.value.match(phoneno)) {
rc = true;
} else {
rc = false;
}
}
return rc;
}
function validateEmpty(sourceEleId, errorEleId) {
var element =document.getElementById(sourceEleId).value;
var rc = false;
element = element.replace(/^\s+|\s+$/g, '');
if (element.length < 1) {
document.getElementById(errorEleId).innerHTML = "<p>Si prega di inserire il valore</p>";
document.getElementById(sourceEleId).className = "string widget widgetRwError";
rc = false;
} else {
document.getElementById(errorEleId).innerHTML = "";
document.getElementById(sourceEleId).className = "string widget widgetRw";
rc = true;
}
return rc;
}
 
function isUserExists(usrId) {
usrId = usrId.toLowerCase();
var is_usr_exists = "";
var url = window.location.origin + "/UserRegistrationLoginCheck.txt?login=" + usrId;
require(["dojo/request/xhr", "dojo/dom", "dojo/dom-construct", "dojo/json", "dojo/on", "dojo/domReady!"],
function(xhr, dom, domConst, JSON, on){
xhr(url, {
handleAs: "text",
sync: true,
}).then(function(response){
is_usr_exists = response;
});
});
return is_usr_exists;
}
 
function isEmpty(str) {
return (!str || 0 === str.length);
}
 
function validateUserID(sourceEleId, errorEleId) {
var element = document.getElementById(sourceEleId).value;
element = element.replace(/^\s+|\s+$/g, '');
rc = false;
JSLoginType = "<% $LoginType %>";
var userIDMsg = "";
if(validateEmpty(sourceEleId, errorEleId)) {
if(JSLoginType == 'email') {
if(validateEmail()) {
userIDMsg = isUserExists(element);
if(isEmpty(userIDMsg)) {
document.getElementById(errorEleId).innerHTML = "";
document.getElementById(sourceEleId).className = "string widget widgetRw";
rc = true;
} else {
document.getElementById(errorEleId).innerHTML = "<p>"+userIDMsg+"</p>";
document.getElementById(sourceEleId).className = "string widget widgetRwError";
//document.getElementById(sourceEleId).focus();
}
}
} else if(JSLoginType == 'syslogin') {
userIDMsg = isUserExists(element);
if(isEmpty(userIDMsg)) {
document.getElementById(errorEleId).innerHTML = "";
document.getElementById(sourceEleId).className = "string widget widgetRw";
rc = true;
} else {
document.getElementById(errorEleId).innerHTML = "<p>"+userIDMsg+"</p>";
document.getElementById(sourceEleId).className = "string widget widgetRwError";
//document.getElementById(sourceEleId).focus();
}
}
}
return rc;
}
 
function validateCaptcha() {
var rc = false;
var captcha_value = document.getElementById("g-recaptcha-response").value;
if(isEmpty(captcha_value)) {
document.getElementById("divErrCaptcha").innerHTML = "<p>Si prega di risolvere i captcha</p>";
} else {
document.getElementById("divErrCaptcha").innerHTML = "";
rc = true;
}
return rc;
}
 
function validateForm(){
var rc = false;
if( validateEmpty('nome', 'divErrNome') &&
validateEmpty('cognome', 'divErrCognome') &&
validateEmail() &&
validateCellSMS() &&
validateCaptcha()
) {
var is_valid_user = null;
if(JSLoginType === "email") {
is_valid_user = validateUserID('email', 'divErrEmail');
<!-- When login type is syslogin then email will be login -->
UserRegistration.login.value = UserRegistration.email.value;
} else {
is_valid_user = validateUserID('login', 'divErrLogin');
}
if(is_valid_user) {
rc = true;
}
}
return rc;
}
 
function submitHandler(){
var rc = validateForm();
if(rc) {
<!-- alert("Base:" + window.location.origin); -->
UserRegistration.action.value = true;
document.UserRegistration.submit();
}
return rc;
}
 
function resetHandler() {
document.getElementById("nome").className = "string widget widgetRw";
document.getElementById("cognome").className = "string widget widgetRw";
document.getElementById("email").className = "string widget widgetRw";
document.getElementById("login").className = "string widget widgetRw";
document.getElementById("cell_sms").className = "string widget widgetRw";
document.getElementById("divErrNome").innerHTML = "";
document.getElementById("divErrCognome").innerHTML = "";
document.getElementById("divErrEmail").innerHTML = "";
document.getElementById("divErrLogin").innerHTML = "";
document.getElementById("divErrCaptcha").innerHTML = "";
document.getElementById("divErrCellSMS").innerHTML = "";
document.UserRegistration.reset();
grecaptcha.reset();
document.getElementById("nome").focus();
return false;
}
</script>
<style>
table tr {
height: 21px;
}
</style>
 
</head>
 
<body class="claro">
<br><br><br>
<& /logo.comp &>
<form method="POST" name="UserRegistration">
<input type="hidden" id="action" name="action" value=false>
<h2 align="center">Modulo di registrazione nuovo utente:</h2>
<table align="center" border="0">
<tr style="height:0;">
<td style="width:33%;"></td>
<td></td>
<td></td>
<td style="width:33%;"></td>
</tr>
<tr>
<td></td>
<td align="right"><font size="3" color="red">*</font>Nome:</td>
<td><input type="text" name="nome" id="nome" value="" size="30" maxlength="20" required=true onblur="validateEmpty('nome', 'divErrNome')" autofocus class="string widget widgetRw"></td>
<td><div id="divErrNome" style="color:#FF0000"></div></td>
</tr>
<tr>
<td></td>
<td align="right"><font size="3" color="red">*</font>Cognome:</td>
<td><input type="cognome" name="cognome" id="cognome" size="30" maxlength="25" required=true onblur="validateEmpty('cognome', 'divErrCognome')" class="string widget widgetRw"></td>
<td><div id="divErrCognome" style="color:#FF0000"></div></td>
</tr>
% if($LoginType eq 'syslogin'){
<tr>
<td></td>
<td align="right"><font size="3" color="red">*</font>E-Mail:</td>
<td><input name="email" id="email" size="30" maxlength="60" required=true onblur="validateEmail()" class="string widget widgetRw"></td>
<td><div id="divErrEmail" style="color:#FF0000"></div></td>
</tr>
<tr>
<td></td>
<td align="right"><font size="3" color="red">*</font>Nome utente:</td>
<td><input name="login" id="login" size="30" maxlength="60" required=true onblur="validateUserID('login', 'divErrLogin')" class="string widget widgetRw"></td>
<td><div id="divErrLogin" style="color:#FF0000"></div></td>
</tr>
% }elsif($LoginType eq 'email'){
<tr>
<td></td>
<td align="right"><font size="3" color="red">*</font>E-Mail utente:</td>
<td><input name="email" id="email" size="30" maxlength="60" required=true onblur="validateUserID('email', 'divErrEmail')" class="string widget widgetRw"></td>
<td><div id="divErrEmail" style="color:#FF0000"></div></td>
</tr>
<tr>
<td></td>
<td><input name="login" id="login" size="30" maxlength="60" required=true type="hidden" ></td>
<td><div id="divErrLogin" style="color:#FF0000" type="hidden"></div></td>
</tr>
% }
% my %UserRegOptionalFields = map { $_ => 1 } split(/\s+/, $r->dir_config('UserRegOptionalFields'));
% if($UserRegTypeMessage eq 'sms' or $UserRegOptionalFields{'cell_sms'}){
<tr>
<td></td>
<td align="right">
% if($UserRegTypeMessage eq 'sms') {
<font size="3" color="red">*</font>
% }
&nbspCell. SMS:
</td>
<td><input type="text" name="cell_sms" id="cell_sms" value="" size="30" maxlength="20" required=true onblur="validateCellSMS()" class="string widget widgetRw"></td>
<td><div id="divErrCellSMS" style="color:#FF0000"></div></td>
</tr>
% }
% if($UserRegOptionalFields{'codice_fiscale'}){
<tr>
<td></td>
<td align="right">&nbspCodice Fiscale:</td>
<td><input name="codice_fiscale" id="codice_fiscale" size="30" maxlength="16" class="string widget widgetRw"></td>
</tr>
% }
% if($UserRegOptionalFields{'descrizione'}){
<tr>
<td></td>
<td align="right">&nbspDescrizione:</td>
<td><input name="descrizione" id="descrizione" size="30" maxlength="60" class="string widget widgetRw"></td>
</tr>
% }
% if($UserRegOptionalFields{'indirizzo'}){
<tr>
<td></td>
<td align="right">&nbspIndirizzo:</td>
<td><input name="indirizzo" id="indirizzo" size="30" maxlength="60" class="string widget widgetRw"></td>
</tr>
% }
% if($UserRegOptionalFields{'provincia'}){
<tr>
<td></td>
<td align="right">&nbspProvincia:</td>
<td><input name="provincia" id="provincia" size="30" maxlength="2" class="string widget widgetRw"></td>
</tr>
% }
% if($UserRegOptionalFields{'citta'}){
<tr>
<td></td>
<td align="right">&nbspCittà:</td>
<td><input name="citta" id="citta" size="30" maxlength="20" class="string widget widgetRw"></td>
</tr>
% }
% if($UserRegOptionalFields{'tele1'}){
<tr>
<td></td>
<td align="right">&nbspTelefono:</td>
<td><input name="tele1" id="tele1" size="30" maxlength="20" class="string widget widgetRw"></td>
</tr>
% }
% if($UserRegOptionalFields{'tele2'}){
<tr>
<td></td>
<td align="right">&nbsp2° Telefono:</td>
<td><input name="tele2" id="tele2" size="30" maxlength="20" class="string widget widgetRw"></td>
</tr>
% }
<tr>
<td></td>
<td colspan="2"><div class="g-recaptcha" data-sitekey=<% $r->dir_config('ReCaptchaAPISiteKey') %>></div></td>
<td><div id="divErrCaptcha" style="color:#FF0000"></div></td>
</tr>
<tr style="height:10px;"></tr>
<tr>
<td></td>
<td><input class="widget button" type="button" value="Invio la richiesta ..." onclick="submitHandler()"></td>
<td><input class="widget button" style="float:right;" type="button" value="Annulla" onclick="resetHandler()"></td>
</tr>
</table>
<br>
<p align="center"> Note : <font size="3" color="red">*</font> indica i campi obbligatori.</p>
</form>
<br><br>
<& /copyright.comp &>
</body>
</html>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/welcome.html
0,0 → 1,5
%# Usato da ./lib/httpRequestMason.js
<& "/home.html" &>
<script>
setTimeout("window.close();", 1500);
</script>
/tags/2.0/htdocs/UpiPrinterServer.txt
0,0 → 1,37
<%doc>
# ---------------------------------------------------------------------- #
# Copyright: (C) 2007 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
#
# utilizzato da UpiPrinterServer per prelevare lo spool da inviare alla stampante locale
</%doc>
<%args>
$file #nome del file contenente lo spool da inviare
</%args>
<%perl>
if($file =~ m/\.\./){
$m->abort(FORBIDDEN);
}
my $filename = $r->dir_config('TmpDir').'/'.$file.'.prn';
if(!open(FILE, "<$filename")){
$m->abort(NOT_FOUND);
}
$m->clear_buffer;
$r->content_type('application/upi-printer-server');
while(<FILE>){
$m->out($_);
}
close FILE;
unlink $filename;
</%perl>
<%flags>
inherit => undef
</%flags>
<%init>
use Apache2::Const qw(FORBIDDEN NOT_FOUND);
</%init>
/tags/2.0/htdocs/UserRegistrationLoginCheck.txt
0,0 → 1,31
<%flags>
inherit => '/init.comp'
</%flags>
<%args>
$login
</%args>
<%perl>
$r->content_type('text/plain; charset=utf-8');
$m->clear_buffer;
#DEBUG print STDERR "Login::[$login]\n";
length($login) || return;
# verifico che la login indicata non sia già presente
my $sth = $Session{Dbh}->prepare(q{
select id from public.anagrafiche where login = ?
});
$sth->execute($login);
if($sth->rows){
</%perl>\
La login (<% $login %>) è già utilizzata.
% }
<%perl>
# verifico che la login indicata non sia tra quelle proibite
$sth = $Session{Dbh}->prepare(q{
select id from public.reserved_login where login = ?
});
$sth->execute($login);
if($sth->rows){
</%perl>\
La login (<% $login %>) è riservata.
% }
%#end.
/tags/2.0/htdocs/blank.html
0,0 → 1,7
<%flags>
inherit => undef # nessun parente
</%flags>
% $r->headers_out->{'Cache-Control'} = 'max-age=999999999';
<%filter>
$_='';
</%filter>
/tags/2.0/htdocs/bottom.html
0,0 → 1,6
Utente: <%$Session{Login}%><% $Session{Nominativo} ? " - $Session{Nominativo}" : '' %>
Gruppi: <% $Session{Groups} ? join(',', @{$Session{Groups}}) : 'nessuno' %>
Connessione: <% $browser_address %>
<%init>
my $browser_address = $ENV{HTTP_X_FORWARDED_HOST} ? $ENV{HTTP_X_FORWARDED_FOR} : $ENV{REMOTE_ADDR};
</%init>
/tags/2.0/htdocs/SMSTemplateUserRegistration.comp
0,0 → 1,21
<%flags>
inherit => '/init.comp'
</%flags>
 
<%method Subject>Successful Registration on MasonSQL</%method>
 
<%method Body>
<%args>
$nome
$baseurl
$login
$password
$regActDays
</%args>
Dear <% $nome %>:
 
Thank you for creating your account on MasonSQL. Your username is <% $login %> and password is <% $password %>. Please activate your account within next <% $regActDays %> days from today.
 
Thanks,
MasonSQL
</%method>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/MailTemplatePasswordReset.comp
0,0 → 1,37
<%flags>
inherit => '/init.comp'
</%flags>
 
<%method Subject>Successful Password Reset on MasonSQL</%method>
 
<%method Body>
<%args>
$nome
$baseurl
$login
$password
$regActDays
</%args>
_____________________________________________________
 
MasonSQL Framework
_____________________________________________________
 
Dear user,
your password has been reset and it must be activated within next <% $regActDays %> days from today.
To activate the account, please use following credentials and login into MasonSQL framework.
 
Login Page : <% $baseurl %>
User Name : <% $login %>
Password : <% $password %>
 
In case there are any questions regarding MasonSQL framework please contact the administrator.
 
Warm regards,
MasonSQL Development Team
_____________________________________________________
 
This is an auto-generated email, please DO NOT REPLY.
Any replies to this email will be disregarded.
_____________________________________________________
</%method>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/SMSTemplatePasswordReset.comp
0,0 → 1,21
<%flags>
inherit => '/init.comp'
</%flags>
 
<%method Subject>Successful Password Reset on MasonSQL</%method>
 
<%method Body>
<%args>
$nome
$baseurl
$login
$password
$regActDays
</%args>
Dear <% $nome %>:
 
Your password has been reset. Your username is <% $login %> and password is <% $password %>. Please activate your account within next <% $regActDays %> days from today.
 
Thanks,
MasonSQL
</%method>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/MailTemplateUserRegistration.comp
0,0 → 1,38
<%flags>
inherit => '/init.comp'
</%flags>
 
<%method Subject>Successful Registration on MasonSQL</%method>
 
<%method Body>
<%args>
$nome
$baseurl
$login
$password
$regActDays
</%args>
_____________________________________________________
 
MasonSQL Framework
_____________________________________________________
 
Dear user <% $nome %>,
thank you for registering at Mason based web application framework MasonSQL.
Your account is created and must be activated within next <% $regActDays %> days from today.
To activate the account, please use following credentials and login into MasonSQL framework:
 
Login Page : <% $baseurl %>
User Name : <% $login %>
Password : <% $password %>
 
In case there are any questions regarding MasonSQL framework please contact the administrator.
 
Warm regards,
MasonSQL Development Team
_____________________________________________________
 
This is an auto-generated email, please DO NOT REPLY.
Any replies to this email will be disregarded.
_____________________________________________________
</%method>
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/dojo-modules.comp
0,0 → 1,13
%# Dojo modules
<%args>
$Dojo_dir => $Session{'Dojo_dir'}
</%args>
 
<script src="<% $Dojo_dir %>/dojo/dojo.js" type="text/javascript"
data-dojo-config="async: false, isDebug:<% $JSLogger->level() eq $DEBUG ? 'true' : 'false'%>, parseOnLoad:true, locale: 'it'">
</script>
<link rel="stylesheet" href="<%$Dojo_dir%>/dijit/themes/dijit.css" type="text/css">
<link rel="stylesheet" href="<%$Dojo_dir%>/dijit/themes/claro/document.css" type="text/css">
<link rel="stylesheet" href="<%$Dojo_dir%>/dijit/themes/claro/claro.css" type="text/css">
<link rel="stylesheet" href="<%$Dojo_dir%>/dojox/widget/Dialog/Dialog.css" type="text/css">
<link rel="stylesheet" href="<%$Dojo_dir%>/dojox/widget/ColorPicker/ColorPicker.css" type="text/css">
/tags/2.0/htdocs/UserRegistrationResetCheck.txt
0,0 → 1,27
<%flags>
inherit => '/init.comp'
</%flags>
<%args>
$login
</%args>
<%once>
my $UserRegTypeMessage = $r->dir_config('UserRegTypeMessage');
</%once>
<%perl>
$r->content_type('text/plain; charset=utf-8');
$m->clear_buffer;
# verifico che la login indicata non sia già presente
my $sth = $Session{Dbh}->prepare(q{
select id, email, cell_sms from public.anagrafiche where login = ?
});
$sth->execute($login);
if($sth->rows){
my $user = $sth->fetchrow_hashref;
if(!defined $user->{$UserRegTypeMessage eq 'sms' ? 'cell_sms' : 'email'}){
$m->out(($UserRegTypeMessage eq 'sms' ? 'numero sms' : 'indirizzo e-mail').' non definito');
}
}else{
$m->out('Utente inesistente');
}
</%perl>
%#end.
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/htdocs/change_password.html
0,0 → 1,95
<%doc>
# ---------------------------------------------------------------------- #
# Copyright:2002-2015 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
</%doc>
<%attr>
Cache_MaxAge => 120
</%attr>
% my $MinPasswordChars = ''.$r->dir_config('MinPasswordChars');
<& '/logo.comp' &>
<script>
function change_password_submit_password(){
// campi di input password
var passwd1 = document.getElementById('change_password_passwd1');
var passwd2 = document.getElementById('change_password_passwd2');
% if($Session{Group_Admins}){
var login = document.getElementById('change_password_login');
% }
// verifico se le due password inserite sono uguali
if(passwd1.value != passwd2.value){
alert('Le password inserite sono differenti.\nReinserire la password correttamente!');
passwd1.value = '';
passwd2.value = '';
return false;
}
if(passwd1.length < <%$MinPasswordChars%>){
alert('La password deve essere di almeno <%$MinPasswordChars%> caratteri');
psw = '';
return false;
}
%# // trasmetto la nuova password al server
hReqMason_ExecuteTimeout(
'/change_password.txt',
<%$r->dir_config('GetRecordTimeout')%>,
function (contextID, err, str){
// timeout
alert(str);
},
function (str, contextID){
// callback
alert(str);
},
'change_password',
% if($Session{Group_Admins}){
{Login:login.value, Password:passwd1.value}
% }else{
{Password:passwd1.value}
% }
);
passwd1.value = '';
passwd2.value = '';
% if($Session{Group_Admins}){
if(login.value != '<%$Session{Login}%>'){
login.value = '';
}
% }
return false;
}
</script>
<table align="center">
<tr><td>
<p align="center">
<br><br>
</td></tr>
<tr><td>
<table align="center">
<tr>
<td align="right"><b>Cambio password utente:</b></td>
% if($Session{Group_Admins}){
<td><input type="text" id="change_password_login" size="18" length="18" value="<%$Session{Login}%>"></td>
% }else{
<td><%$Session{Login}%> <%$Session{Nominativo}%></td>
% }
</tr>
<tr>
<td align="right"><b>Password:</b></td>
<td><input type="password" id="change_password_passwd1" size="18" length="18"></td>
</tr>
<tr>
<td align="right"><b>Ripeti password:</b></td>
<td><input type="password" id="change_password_passwd2" size="18" length="18"></td>
</tr>
</table>
</td></tr>
<tr>
<td colspan="2" align="center">
<input type="button" value="Cambio password ..." onclick="change_password_submit_password();">
</td>
</tr>
</table>
/tags/2.0/htdocs/privacy.comp
--- 2.0/htdocs/release_notes.html (nonexistent)
+++ 2.0/htdocs/release_notes.html (revision 806)
@@ -0,0 +1,12 @@
+<br>
+<br>
+<br>
+<& "/logo.comp" &>
+<H3 align="center">Release Notes</H3>
+<p align="center">
+ <& /privacy.comp &>
+</p>
+<br>
+<p align="center">
+ <& /copyright.comp &>
+</p>
/tags/2.0/htdocs/favicon.ico
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/timerSession.html
0,0 → 1,6
<%doc>
Usato da index.html per rinnovare periodicamente il timer della sessione
</%doc>
<%flags>
inherit => undef
</%flags>
/tags/2.0/htdocs/copyright.comp
0,0 → 1,5
<p style="font-size: 9pt; color: #604040;" align="center">
Copyright (&copy;) framework MasonSQL: from <A href="http://www.leader.it/">Leader.IT</A>
<br>
<% $r->dir_config('CopyrightMessage') %>
</p>
/tags/2.0/htdocs/img/cerca.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/img/icon.ico
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/img/spacer.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/img/cestino.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/img/edit.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/img/add.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes:
Added: svn:mime-type
+application/octet-stream
\ No newline at end of property
/tags/2.0/htdocs/index.application.comp
--- 2.0/htdocs/release_notes.application.comp (nonexistent)
+++ 2.0/htdocs/release_notes.application.comp (revision 806)
@@ -0,0 +1,4 @@
+<%doc>
+Viene richiamata da /release_notes.comp
+Da utilizzare per l'applicazione
+</%doc>
/tags/2.0/htdocs/init.application.comp
0,0 → 1,4
<%doc>
Viene richiamata da /init.comp
Da utilizzare per l'applicazione
</%doc>
/tags/2.0/report/Xrepmand.sh
0,0 → 1,56
#!/bin/bash
# --------------------------------------------------------------------------- #
# Copyright: (C) 2020 Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# E-mail: info@leader.it
#
# Note: The authors with the rispettive contributions are available
# in restricted access of SVN repository at
# https://www.leader.it/wsvn/masonsql
# --------------------------------------------------------------------------- #
 
# The scrpt open repmand (Reportman editor) in a virtual magnified VNC server
# so you can open using VNC clients and use with usable font size
 
if [ "$USER" != "www-data" ]
then
echo "$0 deve essere eseguito dall'utente www-data" >&2
exit 1
fi
 
if [ ! -f ~/.vnc/passwd ]
then
x11vnc -storepasswd
fi
 
export DISPLAY=${1:-:1}
[[ "$DISPLAY" =~ ^: ]] || DISPLAY=":$DISPLAY"
SCREEN=${2:-1400x1000}
SCALE=${3:-1.5}
 
VNC_PORT=${DISPLAY#:}
let VNC_PORT=VNC_PORT+5900
 
Xvfb $DISPLAY -screen 0 ${SCREEN}x16 &
PID0=$!
fluxbox &
./repmand.sh &
PID1=$!
x11vnc -display $DISPLAY -rfbport $VNC_PORT -bg -xkb -scale $SCALE -reopen -rfbauth ~/.vnc/passwd -rmflag ~/.vnc/x11vnc.$$.pid -nevershared -forever
PID2=$(cat ~/.vnc/x11vnc.$$.pid)
let PID2=PID2+1
rm ~/.vnc/x11vnc.$$.pid
echo -e "\n\nPer aprire lo schermo in rete locale: vncviewer $(hostname -f)$DISPLAY"
 
trap "kill $PID0 $PID1 $PID2" SIGINT SIGTERM
 
while sleep 1
do
if ! ps -p $PID1 >/dev/null
then
kill $PID0 2>/dev/null
kill $PID2 2>/dev/null
exit
fi
done
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/report/repmand.sh
0,0 → 1,44
#!/bin/bash
#Enable this setting if you have problems starting the application
#for example in suse 7.3 starting from a vncserver
#export CLX_USE_LIBQT=true
#Enable this setting if you have not defined the LANG variable in your system
#export LANG=en_US
export LANG=it_IT.ISO-8859-15@euro
#export LC_CTYPE=""
export PGCLIENTENCODING=LATIN9
#Bug fix in some distros need LC_NUMERIC en_US or print will not work
#That is to enable a bugfix, use it only if print does not work
#export LC_NUMERIC=en_US
#Use this env.variables to override language locale
export KYLIX_DEFINEDENVLOCALES=Yes
export KYLIX_THOUSAND_SEPARATOR=.
export KYLIX_DECIMAL_SEPARATOR=,
export KYLIX_DATE_SEPARATOR=/
export KYLIX_TIME_SEPARATOR=:
#You can share libraries copying libs to a directory
#for example /opt/kylixlibs and add the path to ld.so.conf
#then run ldconfig (as root)
DIR="/opt/masonsql/report"
 
export DISPLAY
# verifico se è definita la cartella di configurazione
 
if [ ! -e "$HOME/.borland" ]
then
echo "Manca la cartella dei driver"
echo "Vedi di configurarla, ad esempio con"
echo " ln -s /opt/<MYAPPDIR>/etc/<MYHOST>.borland $HOME/.borland"
exit 1
fi
 
# file stampanti necessario, anche se vuoto
[ -f /etc/printcap ] || > /etc/printcap
 
#export HOME=$DIR
#export USER=www-data
 
export LD_LIBRARY_PATH=$DIR/:$DIR/rpdesigner-2_9a/:$LD_LIBRARY_PATH
exec $DIR/rpdesigner-2_9a/repmand $*
 
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/report/printreptopdf.wine
0,0 → 1,17
#!/bin/bash
export LANG=it_IT.UTF-8
export HOME=/opt/masonsql/report/www-data_home_dir
export USER=www-data
 
# ricerco la cartella di installazione
PATH="$HOME/.wine/drive_c/"
if [ -d "$PATH/Program Files (x86)" ]
then
PATH="Program Files (x86)"
else
PATH="Program Files"
fi
echo "# /usr/bin/wine \"C:\\$PATH\\Report Manager\\printreptopdf.exe\" "$* >/opt/masonsql/report/log
/usr/bin/wine "C:\\$PATH\\Report Manager\\printreptopdf.exe" $* >>/opt/masonsql/report/log 2>&1
 
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/report/printreptopdf.kylix
0,0 → 1,31
#!/bin/bash
#Enable this setting if you have problems starting the application
#for example in suse 7.3 starting from a vncserver
#export CLX_USE_LIBQT=true
#Enable this setting if you have not defined the LANG variable in your system
#export LANG=en_US
export LANG=it_IT.ISO-8859-15@euro
export LC_CTYPE=""
export PGCLIENTENCODING=LATIN9
#Bug fix in some distros need LC_NUMERIC en_US or print will not work
#That is to enable a bugfix, use it only if print does not work
#export LC_NUMERIC=en_US
#Use this env.variables to override language locale
export KYLIX_DEFINEDENVLOCALES=Yes
export KYLIX_THOUSAND_SEPARATOR=.
export KYLIX_DECIMAL_SEPARATOR=,
export KYLIX_DATE_SEPARATOR=/
export KYLIX_TIME_SEPARATOR=:
#You can share libraries copying libs to a directory
#for example /opt/kylixlibs and add the path to ld.so.conf
#then run ldconfig (as root)
DIR=${0%/*}
 
export HOME=$DIR
export USER=www-data
 
echo "# $DIR/rpservercline-2_9a/printreptopdf $*" >/opt/masonsql/report/log
 
# versione 2_9a
export LD_LIBRARY_PATH=$DIR:$LD_LIBRARY_PATH
exec $DIR/rpservercline-2_9a/printreptopdf $* >>/opt/masonsql/report/log 2>&1
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/report/repmandxp.sh
0,0 → 1,3
#!/bin/bash
/usr/bin/wine "C:\Program Files (x86)\Report Manager\repmandxp.exe" $*
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/report/LEGGIMI
0,0 → 1,22
 
 
"Report Manager Designer Version 2_9a"
 
Author: Toni Martir
toni@pala.com (no free support)
http://reportman.sourceforge.net
 
 
INSTALLAZIONE:
 
* Copiare i file della distribuzione ( rpservercline-2_9a.i386.tar.gz ) in /opt/masonsql/report/rpservercline-2_9a:
* Modificare lo script /opt/masonsql/report/printreptopdf.sh adattando il comando che punta all'eseguibile in /opt/masonsql/report/rpservercline-2_9a/printreptopdf
* Creare il link per eseguire da utente root i comandi di test: /root/.borland => /opt/masonsql/report/.borland
* L'applicazione crea il link /opt/masonsql/report/.borland -> /opt/APPLICAZIONE/etc/******.borland (vedi file di conf.) alla prima connessione
 
In PostgreSQL lanciare il comando:
 
CREATE DOMAIN BLOB as bytea
 
per la gestione delle immagini.
 
/tags/2.0/lib/Auth_AC/AuthCookieHandler.pm
0,0 → 1,562
############################################################################################
package Auth_AC::AuthCookieHandler;
 
use strict;
use utf8;
use DBI;
use vars qw($VERSION @ISA);
$VERSION = substr(q$Revision: 1.2 $, 10);
use base 'Apache2_4::AuthCookie';
 
use Digest::MD5 qw(md5_hex);
use String::Random;
#*******************************************************************************************
# SET DEFAULT VARIABLES
#*******************************************************************************************
my $secret = "Frase . . . per la cifratura segreta :-))";
 
#*******************************************************************************************
# Set connect method to get database handler.
#*******************************************************************************************
sub connect {
my($self, $r, $conn, $autocommit) = @_;
if(!$conn){
$conn = $r->dir_config('DBIconnect');
}
my $user;
my $passwd;
if($conn =~ s/user=(\w+)//i){
$user=$1;
}
if($conn =~ s/passw\w+=(\w+)//i){
$passwd=$1;
}
#DEBUG print STDERR "Auth_AC::AuthCookieHandler->connect($conn, $user, $passwd)\n";
my $dbh = DBI->connect($conn, $user, $passwd)
|| die "DBI Error open database: ".DBI::errstr;
$dbh->{HandleError} = sub {
# Qui si puo' modificare i messaggi di errore oppure catturare gli errori e
# quindi annullarli.
return 0;
};
$dbh->{pg_enable_utf8} = 1;
$dbh->{RaiseError} = 1;
$dbh->{ShowErrorStatement}=1;
# necessario per i database e client >=7.3 e successivi in quanto si utilizzano "prepare" di query multiple
$dbh->{'pg_server_prepare'} = 0;
$dbh->do(q|
set DateStyle to 'SQL, EUROPEAN';
set TIME ZONE LOCAL;
set client_encoding TO 'UTF-8';
SET search_path TO public;
|);
$dbh->{AutoCommit} = $autocommit ? 1 : 0;
return $dbh;
}
 
sub _get_dbh {
my $self = shift;
my(%args) = @_;
my $r = $args{r};
my $dbh = undef;
no strict;
$dbh = $self->connect($r);
$dbh->{AutoCommit} = 1;
use strict;
return $dbh;
};
 
sub _get_anagrafiche_info {
my $self = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $login = $args{login};
my($id, $password, $psw_inactivity, $change_psw_days, $no_psw_expiration, $concurrent_session);
my $sth = $dbh->prepare(q{
select
id,
password,
date_part('day', now() - session_time) as psw_inactivity,
date_part('day', now() - last_change_password) as change_psw_days,
no_psw_expiration,
concurrent_sessions
from anagrafiche
where login=?
});
if(!$sth->execute($login) || $sth->rows != 1){
return undef;
} else {
($id, $password, $psw_inactivity, $change_psw_days, $no_psw_expiration, $concurrent_session) = @{$sth->fetchrow_arrayref};
}
return ($id, $password, $psw_inactivity, $change_psw_days, $no_psw_expiration, $concurrent_session);
};
 
sub _create_session {
my $self = shift;
my $session = String::Random->new()->randpattern('s' x 32);
return $session;
};
 
sub _store_session {
my $self = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $login = $args{login};
my $password = $args{password};
my $session = $args{session};
my $ip = $args{ip};
my $ua = $args{ua};
my $id = $args{id};
my $r = $args{r};
my $rc = 0;
my $session_id = undef;
my $sth = $dbh->prepare(q{
insert into session(id_anagrafiche, user_agent , user_ip, session, session_time, previus_session_time, session_inactive_time)
values(?, ?, ?, ?, now(), now(), ?);
select lastval();
});
my $res = $sth->execute($id, $ua, $ip, $session, int(time/60));
if($res eq '0E0'){
$r->subprocess_env(AuthCookiePassword => $password);
} else {
if($res == 1){
$session_id = $sth->fetchrow_arrayref->[0];
$rc = 1;
$dbh->{AutoCommit} || $dbh->commit;
}else{
#DEBUG print STDERR $sth->errstr;
}
}
return $session_id;
};
 
sub _store_session_history {
my $self = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $id = $args{id};
my $rc = 0;
my $sth = $dbh->prepare(q{
update anagrafiche
set previus_session_time = session_time,
session_time = now()
where id = ?
});
my $res = $sth->execute($id);
if($res == 1){
$rc = 1;
$dbh->{AutoCommit} || $dbh->commit;
}else{
#DEBUG print STDERR $sth->errstr;
}
return $rc;
};
 
sub _reset_recordset_cache {
my $self = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $sid = $args{sid};
my $rc = 0;
my $sth = $dbh->prepare(q{
delete from public.recordset_rows
using session, recordset
where id_recordset = recordset.id
and recordset.id_session = session.id
and session.id = ?;
delete from public.recordset
using session
where id_session = session.id
and session.id = ?
});
$sth->execute($sid, $sid);
$dbh->{AutoCommit} || $dbh->commit;
return $rc;
};
 
sub _is_session_inactive {
my $self = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $r = $args{r};
my $sid = $args{sid};
my $minutes = $args{minutes};
my $rc = 0;
my $inactivity_minutes = int(time/60) - $minutes;
if($inactivity_minutes > $r->dir_config('Auth_InactivityMax')){
$rc = $self->_remove_session(dbh => $dbh, sid => $sid);
$self->_reset_recordset_cache(dbh => $dbh, sid => $sid);
}
return $rc;
};
 
sub _remove_session {
my $self = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $sid = $args{sid};
my $session = $args{session};
my $rc = 0;
if(defined $sid) {
#my $sth = $dbh->prepare('update session set session = null where id = ?');
my $sth = $dbh->prepare('delete from session where id = ?');
$sth->execute($sid);
$dbh->{AutoCommit} || $dbh->commit;
$rc = 1;
} elsif(defined $session) {
my ($login, $sess_key, $mac) = split /:/, $session, 3;
my $sth = $dbh->prepare('delete from session where session = ?');
$sth->execute($sess_key);
$dbh->{AutoCommit} || $dbh->commit;
$rc = 1;
}
return $rc;
};
 
sub _update_session_timestamp {
my $self = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $sid = $args{sid};
my $minutes = $args{minutes};
my $rc = 0;
my $inactivity_minutes = int(time/60) - $minutes;
if($inactivity_minutes > 0){
my $sth = $dbh->prepare('update session set session_inactive_time = ? where id = ?');
$sth->execute(int(time/60), $sid);
$dbh->{AutoCommit} || $dbh->commit;
$rc = 1;
}
return $rc;
};
 
sub _is_authorized_user {
my $self = shift;
my(%args) = @_;
my $r = $args{r};
my $login = $args{login};
my $rc = 0;
if(my $AuthRequireUser = $r->dir_config->get('AuthRequireUser')){
my %users;
foreach my $user (split /\s+/, $AuthRequireUser){
$users{$user} = 1;
}
$rc = 1 if($users{$login});
} else {
# Allow all users as authorized users
$rc = 1;
}
return $rc;
};
 
sub _is_authorized_group {
my $self = shift;
my(%args) = @_;
my $r = $args{r};
my $login = $args{login};
my $dbh = $args{dbh};
my $rc = 0;
if(my $AuthRequireGroup = $r->dir_config->get('AuthRequireGroup')){
my $sth = $dbh->prepare(q{
select gruppi.nome
from gruppi
inner join anagrafiche_gruppi on anagrafiche_gruppi.id_gruppi = gruppi.id
inner join anagrafiche on anagrafiche.id = anagrafiche_gruppi.id_anagrafiche
where anagrafiche.login = ?
});
$sth->execute($login) || die "DBI Error select groups: ".DBI::errstr;
my %groups;
foreach my $group (split /\s+/, $AuthRequireGroup){
$groups{$group} = 1;
}
while(my $group = $sth->fetchrow_arrayref->[0]){
if($groups{$group}){
$rc = 1;
}
}
} else {
# Allow access to all groups
$rc = 1;
}
return $rc;
};
 
sub _delete_inactive_sessions {
my $self = shift;
my(%args) = @_;
my $r = $args{r};
my $dbh = $args{dbh};
my $id = $args{id};
my $rc = 0;
## Delete inactive sessions for selected login
if(defined $id) {
my $sth = $dbh->prepare(q{
select id,session,session_inactive_time
from session
where id_anagrafiche = ?
});
if($sth->execute($id)){
while(my $row = $sth->fetchrow_arrayref()) {
if($row and defined $row->[0]){
my($session_id, $sess, $minutes) = ($row->[0], $row->[1], $row->[2]);
## check and delete inactive sessions.
if($self->_is_session_inactive(dbh => $dbh, sid => $session_id, minutes => $minutes, r => $r)) {
$rc = 1;
}
}
}
}
};
return $rc;
};
 
sub _delete_all_sessions {
my $self = shift;
my(%args) = @_;
my $cookie = $args{cookie};
my $dbh = $args{dbh};
my $id = $args{id};
my $rc = 0;
## Delete all sessions for selected login as it's concurrent_session flag = null or false in anagrafiche
if(defined $id) {
my $sth = $dbh->prepare(q{
delete from public.session
where id_anagrafiche = ?
});
$sth->execute($id);
$rc = 1;
};
return $rc;
};
 
sub _get_user_session_count {
my $self = shift;
my(%args) = @_;
my $cookie = $args{cookie};
my $dbh = $args{dbh};
my $id = $args{id};
my $rc = 0;
if(defined $id) {
my $sth = $dbh->prepare(q{
select id
from session
where id_anagrafiche = ?
order by session_inactive_time desc
limit 1
});
$sth->execute($id);
$rc = $sth->rows;
};
return $rc;
};
 
sub _get_session_id {
my $self = shift;
my(%args) = @_;
my $session = $args{session};
my $dbh = $args{dbh};
my $id = undef;
my $rc = 0;
if(defined $session) {
my $sth = $dbh->prepare(q{
select id
from session
where session = ?
});
$sth->execute($session);
my $row = $sth->fetchrow_arrayref;
$id = $row->[0];
};
return $id;
};
 
sub _logout_handler {
my $self = shift;
my(%args) = @_;
my $session = $args{session};
my $dbh = $args{dbh};
my $rc = 0;
# cancello la sessione e la cache dei recordset
my $sid = $self->_get_session_id(dbh => $dbh, session => $session);
$self->_remove_session(dbh => $dbh, sid => $sid);
$self->_reset_recordset_cache(dbh => $dbh, sid => $sid);
return $rc;
};
## Overwrite logout method
sub logout {
my ($self,$r) = @_;
my($dbh) = $self->_get_dbh( r => $r);
my $cookie = $self->key($r);
my ($login, $sess_id, $mac) = split /:/, $cookie, 3;
$self->_logout_handler(dbh => $dbh, session => $sess_id);
$self->SUPER::logout($r);
}
 
sub authen_cred {
my $self = shift;
my $r = shift;
$r->subprocess_env;
 
my($login, $password, $new_password, $force_login) = @_;
my($dbh) = $self->_get_dbh( r => $r);
my($id, $md5_password, $psw_inactivity, $change_psw_days, $no_psw_expiration, $concurrent_session) = $self->_get_anagrafiche_info(dbh => $dbh, login => $login);
return undef if(not defined $md5_password);
 
## Verify if password has crossed expire limit.
if(!$no_psw_expiration) {
return undef if(defined $psw_inactivity && $psw_inactivity > $r->dir_config('MaxPasswordInactivity'));
if(length($new_password) == 0 and (!defined $change_psw_days or $change_psw_days > $r->dir_config('MaxPasswordDays'))){
$r->subprocess_env(AuthCookiePassword => $password);
return undef;
}
}
 
## Remove inactive sessions for current user.
$self->_delete_inactive_sessions(dbh => $dbh, id => $id, r => $r);
## In case of force login set true, force user to always pass user & pwd.
my $session_count = $self->_get_user_session_count(dbh => $dbh, id => $id);
if((not defined $concurrent_session or $concurrent_session == 0) and $session_count > 0) {
if($r->dir_config('Auth_AC_force_login') || $force_login) {
$self->_delete_all_sessions(dbh => $dbh, id => $id)
} else {
return undef;
}
}
 
# indirizzo del mittente (valuto se c'è un reverse proxy di mezzo)
my $browser_address = $ENV{HTTP_X_FORWARDED_HOST} ? $ENV{HTTP_X_FORWARDED_FOR} : $ENV{REMOTE_ADDR};
my $user_agent = $ENV{HTTP_USER_AGENT};
 
# verify if password is matching with user input value.
return undef if(defined $password && md5_hex($password) ne $md5_password);
 
# Create new session
my $NewSess_id = $self->_create_session();
 
my $session_id = $self->_store_session(dbh => $dbh, login => $login, session => $NewSess_id,
ip => $browser_address, ua => $user_agent, id => $id,
r => $r, password => $password);
return undef if(not defined $session_id);
 
# If new session created then store session history in anagrafiche
# This value later will be used to check against MaxPasswordInactivity from config file.
$self->_store_session_history(dbh => $dbh, id => $id);
 
# Set new password
if(length $new_password) {
my $str_err = $self->update_password($r, $login, $new_password, 0);
if($str_err){
$r->subprocess_env('AuthCookieErrorChangePassword' => $str_err);
$self->_remove_session(dbh => $dbh, sid => $session_id);
return undef;
}
}
 
# Create session key to pass to apache
my $session_key = $login.':'.$NewSess_id.':'.md5_hex( $NewSess_id, $secret );
$self->_reset_recordset_cache(dbh => $dbh, sid => $session_id);
#DEBUG print STDERR "SK: [$session_key]\n";
return $session_key;
}
 
sub authen_ses_key {
my $self = shift;
my $r = shift;
my $session_key = shift;
my($dbh) = $self->_get_dbh( r => $r);
 
my ($login, $Sess_id, $mac) = split /:/, $session_key, 3;
my $sth = $dbh->prepare('select id,session,session_inactive_time from session where session = ?');
 
if($sth->execute($Sess_id)){
my $row = $sth->fetchrow_arrayref;
if($row and defined $row->[0]){
my($session_id, $sess, $minutes) = ($row->[0], $row->[1], $row->[2]);
if( md5_hex( $Sess_id, $secret ) eq $mac) {
if($self->_is_session_inactive(dbh => $dbh, sid => $session_id, minutes => $minutes, r => $r)) {
return undef;
} else {
$self->_update_session_timestamp(dbh => $dbh, sid => $session_id);
}
## Verify authorize user and groups
if($self->_is_authorized_user(r => $r, login => $login) and
$self->_is_authorized_group(r => $r, login => $login, dbh => $dbh)) {
return $session_key;
}
}
}
}
return undef;
}
 
# Modifica della password
# ritorna una stringa con la motivazione del mancato cambiamento password
sub update_password {
my($self, $r, $login, $password, $force_change_password) = @_;
 
no strict;
my $dbh = $self->connect($r);
$dbh->{AutoCommit} = 1;
use strict;
 
if(length($login) == 0){
return "Indicare la login utente";
}
if(length($password) == 0){
return "La password non può essere vuota";
}
 
# solo se la password è in chiaro possiamo fare dei controlli sulla password
# recupero alcuni parametri dell'utente utilizzati per valutare la congruità della password
my $sth = $dbh->prepare(q{
select id, login, nome, cognome, (password = ?) as psw_is_the_same, no_change_password
from public.anagrafiche
where "login"=?;
});
if(!$sth->execute(md5_hex($password), $login)){
return "Errore: ".$sth->errstr
}
my $user = $sth->fetchrow_hashref;
if(!defined $user){
return "Utente inesistente"
}
if($user->{no_change_password}){
return "La password non può cambiare";
}
if($user->{psw_is_the_same}){
return "La password deve cambiare";
}
my $MinPasswordChars = ''.$r->dir_config('MinPasswordChars');
if(length($password) < $MinPasswordChars){
return "La password deve contenere almeno $MinPasswordChars caratteri";
}
if(!($password =~ m/[A-Z]/ and $password =~ m/[0-9]/ and $password =~ m/[a-z]/)){
return "La password deve contenere almeno una lettera maiuscola, una minuscola e una cifra numerica";
}
# verifico che i primi tre caratteri di nome e cognome non siano presenti nella password
# della login verifico che non siano presenti i primi 4 caratteri
if(
length($user->{nome}) >= 3 && index(lc $password, substr(lc $user->{nome}, 0, 3)) >= 0 or
length($user->{cognome}) >= 3 && index(lc $password, substr(lc $user->{cognome}, 0, 3)) >= 0 or
length($user->{login}) >= 4 && index(lc $password, substr(lc $user->{login}, 0, 4)) >= 0
){
return "La password non deve contenere le iniziali del nome, del cognome o del nome utente";
}
# modifica password nel database
my $sth = $dbh->prepare(q{select public.change_password(?,?,?);});
my $nrows = $sth->execute($login, $password, $force_change_password);
if($nrows == 0){
return "Utente inesistente";
}elsif($nrows != 1){
return "Errore: ".$sth->errstr;
}
$dbh->{AutoCommit} || $dbh->commit;
return undef;
}
 
return 1;
 
__END__
/tags/2.0/lib/Auth_AC/AuthBasicHandler.pm
0,0 → 1,122
package Auth_AC::AuthBasicHandler;
 
use Apache2::Access ();
use Apache2::RequestUtil ();
use Apache2::Const -compile => qw(OK DECLINED HTTP_UNAUTHORIZED);
use Digest::MD5 qw(md5_hex);
 
# aggiorna la data si accesso
sub Update_session($$){
my($dbh, $login) = shift;
my $sth = $dbh->prepare(q{
update anagrafiche
set previus_session_time = session_time,
session_time = now()
where login = ?
});
$sth->execute($login) || die "DBI Error update session time: ".DBI::errstr;
$dbh->{AutoCommit} || $dbh->commit;
}
 
sub handler {
my $r = shift;
 
my ($status, $password) = $r->get_basic_auth_pw;
return $status unless $status == Apache2::Const::OK;
if(!$password || !$r->user){
$r->note_basic_auth_failure;
return Apache2::Const::HTTP_UNAUTHORIZED;
}
my $conn = $r->dir_config('DBIconnect');
my $user;
my $passwd;
if($conn =~ s/user=(\w+)//i){
$user=$1;
}
if($conn =~ s/passw\w+=(\w+)//i){
$passwd=$1;
}
#DEBUG print STDERR "Auth_AC::AuthBasicHandler->connect($conn, $user, $passwd)\n";
my $dbh = DBI->connect($conn, $user, $passwd) || die "DBI Error open database: ".DBI::errstr;
$dbh->{pg_enable_utf8} = 1;
$dbh->{RaiseError} = 1;
$dbh->{ShowErrorStatement}=1;
$dbh->do(q|set client_encoding TO 'UTF-8';|);
$dbh->{AutoCommit} = 1;
# cerco l'utente nel database
my $SQL = q{
select
password,
date_part('day', now() - session_time) as psw_inactivity,
date_part('day', now() - last_change_password) as change_psw_days,
no_psw_expiration
from anagrafiche
where login=?
};
#DEBUG print STDERR "LOGIN SQL '$SQL' '$login'\n";
my $sth = $dbh->prepare($SQL);
$sth->execute($r->user);
if($sth eq '0E0' || $sth->rows != 1){
#DEBUG print STDERR "AUTHENTICATION rows=".$sth->rows." KEY=UNDEFINED\n";
$r->note_basic_auth_failure;
return Apache2::Const::HTTP_UNAUTHORIZED;
}
my($md5_password, $psw_inactivity, $change_psw_days, $no_psw_expiration) = @{$sth->fetchrow_arrayref};
# password time expiration
if(!$no_psw_expiration and $psw_inactivity > $r->dir_config('MaxPasswordInactivity')){
# l'utente non utilizza il sistema da troppo tempo
return Apache2::Const::HTTP_UNAUTHORIZED;
}
# verifico la password
if(md5_hex($password) eq $md5_password){
# Verifico se ci sono limitazioni all'accesso in base all'utente o gruppo
# impostate nella configurazione in Apache con le variabili mod_perl
# es:
# PerlSetVar AuthRequireUser "user1 user2"
# PerlSetVar AuthRequireGroup "pruppo1 gruppo2 gruppo3"
#
if(my $AuthRequireUser = $r->dir_config->get('AuthRequireUser')){
# verifico che l'utente sia uno degli utenti elencati
my %users;
foreach my $user (split /\s+/, $AuthRequireUser){
$users{$user} = 1;
}
if($users{$login}){
Update_session($dbh, $login);
return Apache2::Const::OK;
}
return Apache2::Const::HTTP_UNAUTHORIZED;
}
if(my $AuthRequireGroup = $r->dir_config->get('AuthRequireGroup')){
# verifico che l'utente appartenga ad uno dei gruppi elencati
my $sth = $dbh->prepare(q{
select gruppi.nome
from gruppi
inner join anagrafiche_gruppi on anagrafiche_gruppi.id_gruppi = gruppi.id
inner join anagrafiche on anagrafiche.id = anagrafiche_gruppi.id_anagrafiche
where anagrafiche.login = ?
});
$sth->execute($login) || die "DBI Error select groups: ".DBI::errstr;
my %groups;
foreach my $group (split /\s+/, $AuthRequireGroup){
$groups{$group} = 1;
}
while(my $group = $sth->fetchrow_arrayref->[0]){
if($groups{$group}){
Update_session($dbh, $login);
return Apache2::Const::OK;
}
}
return Apache2::Const::HTTP_UNAUTHORIZED;
}
Update_session($dbh, $login);
return Apache2::Const::OK;
}
$r->note_basic_auth_failure;
return Apache2::Const::HTTP_UNAUTHORIZED;
}
 
1;
 
 
 
/tags/2.0/lib/Auth_AC/UserRegistration.pm
0,0 → 1,352
package Auth_AC::UserRegistration;
 
use strict;
use warnings;
use Data::Dumper;
use Exporter;
use String::Random;
use Digest::MD5 qw(md5_hex);
use Captcha::reCAPTCHA;
 
our $VERSION = 1.00;
our @ISA = qw(Exporter);
our @EXPORT = qw();
our @EXPORT_OK = qw();
our %EXPORT_TAGS = ();
 
#########################################################################################
## Define global variables ::
#########################################################################################
my ($FALSE, $TRUE) = (0, 1);
my $DEFAULT_GROUP_NAME = "Guest";
my $DEFAULT_PASSWORD_PATTERN = "Cccsssnn";
my $DEFAULT_MAX_REGISTERATION_TIME = 7;
my $MAIL_UR_TEMPLATE_NAME = "/MailTemplateUserRegistration.comp";
my $SMS_UR_TEMPLATE_NAME = "/SMSTemplateUserRegistration.comp";
my $MAIL_PR_TEMPLATE_NAME = "/MailTemplatePasswordReset.comp";
my $SMS_PR_TEMPLATE_NAME = "/SMSTemplatePasswordReset.comp";
my $DEFAULT_USR_REG_TYPE_MSG = "email";
 
#########################################################################################
## Define class methods :: Constructor
#########################################################################################
sub new {
my $class = shift;
my(%args) = @_;
my $self = {args => \%args};
bless($self, $class);
$self->_init();
return $self;
}
 
sub _init {
my $self = shift;
$self->{random} = String::Random->new();
$self->{captcha} = Captcha::reCAPTCHA->new();
$self->{userInfo} = {};
return 0;
};
 
sub disp($$) {
my($self) = shift;
#DEBUG print STDERR ("Test Data\n");
return 0;
}
 
sub _get_user_data() {
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $usrLogin = $args{login};
my $user_data;
my $query = undef;
if($usrLogin) {
$query = q{select login,id,email from anagrafiche where login = ?};
} else {
$query = q{select login,id,email from anagrafiche};
};
 
my $sth = $dbh->prepare($query);
if($usrLogin) {
$sth->execute($usrLogin);
} else {
$sth->execute();
};
my $nrows = $sth->rows;
while(my($login, $id, $email) = $sth->fetchrow_array()) {
$user_data->{$login} = {
id => $id,
email => $email
};
}
return $user_data;
}
 
sub get_user_id_list() {
my($self) = shift;
my(%args) = @_;
my $user_data = $self->_get_user_data(%args);
my $uid_list = lc(join("|", keys(%$user_data)));
return $uid_list;
}
 
sub is_uid_exists() {
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $login = $args{login};
my $user_data = $self->_get_user_data(%args);
my $is_uid_exists = exists $user_data->{$login} ? $TRUE : $FALSE;
return $is_uid_exists;
}
 
sub is_valid_captcha_response() {
my($self) = shift;
my(%args) = @_;
my $form = $args{formdata};
my $r = $args{r};
my $response = $form->{'g-recaptcha-response'};
my $remoteAddr = $ENV{REMOTE_ADDR};
my $secretKey = $r->dir_config('ReCaptchaAPISecretKey');
my $rc = $FALSE;
if(isNotEmpty($response) and isNotEmpty($remoteAddr) and isNotEmpty($secretKey)) {
my $result = $self->{captcha}->check_answer_v2($secretKey, $response, $remoteAddr);
if ( $result->{is_valid} ) {
$rc = $TRUE;
} else {
#DEBUG print STDERR Dumper($result);
my $error = $result->{error};
$rc = $FALSE;
}
}
return $rc;
}
 
sub process_registration_form() {
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $form = $args{formdata};
my $rc = $FALSE;
if($self->is_valid_captcha_response(%args)) {
if(not $self->is_uid_exists(dbh => $dbh, login => $form->{login})) {
if($self->_add_user(%args) and $self->_add_group(%args)) {
if($self->send_notification("UserRegistraion", %args)) {
$rc = $TRUE;
}
}
}
}
return $rc;
}
 
sub process_password_reset_form() {
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $form = $args{formdata};
my $rc = $FALSE;
if($self->is_valid_captcha_response(%args)) {
if($self->is_uid_exists(dbh => $dbh, login => $form->{login})) {
if($self->_update_password(%args)) {
if($self->send_notification("PasswordReset", %args)) {
$rc = $TRUE;
}
}
}
}
return $rc;
}
 
sub _get_password() {
my($self) = shift;
my(%args) = @_;
my $r = $args{r};
my $form = $args{formdata};
my $pwdpattern = $r->dir_config('PasswordRandPattern') || $DEFAULT_PASSWORD_PATTERN;
my $password = $self->{random}->randpattern($pwdpattern);
$self->{userInfo}->{$form->{login}} = $password;
return $password;
};
 
sub _add_user() {
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $form = $args{formdata};
my $rc = $TRUE;
my $query = q{
insert into anagrafiche(nome,cognome,descrizione,
indirizzo,provincia,citta,
tel1,tel2,codice_fiscale,
login,email,cell_sms)
values(?,?,?,?,?,?,?,?,?,?,?,?)
};
my $sth = $dbh->prepare($query);
no strict;
$sth->execute(
$form->{nome},$form->{cognome},$form->{descrizione},
$form->{indirizzo},$form->{provincia},$form->{citta},
$form->{tel1},$form->{tel2},$form->{codice_fiscale},
$form->{login},$form->{email},$form->{cell_sms}
) || die "DBI Error update session time: ". DBI::errstr;
$dbh->{AutoCommit} || $dbh->commit;
use strict;
$rc = $self->_update_password(%args);
return $rc;
}
 
sub _update_password() {
my($self) = shift;
my(%args) = @_;
my $form = $args{formdata};
my $r = $args{r};
my $password = $self->_get_password(%args);
my $rc = $TRUE;
my $force_chnge_pass = $TRUE;
my $str_err = Auth_AC::AuthCookieHandler->update_password($r, $form->{login}, $password, $force_chnge_pass);
if($str_err) { $rc = $FALSE; };
return $rc;
}
 
sub _is_valid_group(){
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $usrGroup = $args{param};
my $group_data = {};
my $rc = $FALSE;
if(defined $usrGroup and $usrGroup ne '') {
my $query = q{select id from gruppi where nome = ?};
my $sth = $dbh->prepare($query);
$sth->execute($usrGroup);
my $nrows = $sth->rows;
my($id) = $sth->fetchrow_array();
if($nrows and $id) {
$rc = $TRUE;
}
}
return $rc;
}
 
sub _add_group(){
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $form = $args{formdata};
my $r = $args{r};
my $rc = $TRUE;
my $usrGroup = $self->_is_valid_group(dbh => $dbh, param => $r->dir_config('NewUserRegisterGroup')) ?
$r->dir_config('NewUserRegisterGroup') : $DEFAULT_GROUP_NAME;
my $login = $form->{login};
my $query = q{
insert into anagrafiche_gruppi(id_anagrafiche,id_gruppi)
select anagrafiche.id, gruppi.id from anagrafiche, gruppi
where gruppi.nome = ? and anagrafiche.login = ?
};
my $sth = $dbh->prepare($query);
$sth->execute($usrGroup,$login);
$dbh->{AutoCommit} || $dbh->commit;
return $rc;
}
 
sub _get_next_seq_id() {
my($self) = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $sequence = $args{sequence};
my $id = 0;
my $rc = $FALSE;
if(defined $sequence and $sequence ne '') {
my $query = q{select nextval(?)};
my $sth = $dbh->prepare($query);
$sth->execute($sequence);
my $nrows = $sth->rows;
($id) = $sth->fetchrow_array();
if($nrows and $id) {
$rc = $TRUE;
}
}
return $id;
}
 
sub send_notification() {
my($self) = shift;
my $request = shift;
my(%args) = @_;
my $dbh = $args{dbh};
my $r = $args{r};
my $form = $args{formdata};
my $rc = $TRUE;
my($subject, $message) = $self->get_template($request, %args);
my $owner = 1;
my $UserRegTypeMessage = $r->dir_config('UserRegTypeMessage') || $DEFAULT_USR_REG_TYPE_MSG;
my ($email, $sms) = $UserRegTypeMessage eq "sms" ? ("false", "true") : ("true", "false");
 
### Get next sequence id.
my $msg_seq_id = $self->_get_next_seq_id(dbh => $dbh, sequence => 'messages_id_seq');
 
### insert record into messages table.
my $query1 = q{
insert into messages(id, message, owner, modification_time, transmission_time, subject, email, sms)
values(?, ?, ?, now(), now(), ?, ?, ?)
};
my $sth1 = $dbh->prepare($query1);
$sth1->execute($msg_seq_id, $message, $owner, $subject, $email, $sms);
 
### insert record into messages_users table.
my $user_data = $self->_get_user_data(%args, login => $form->{login});
my $query2 = q{
insert into messages_users(id_messages, id_anagrafiche)
values(?, ?)
};
my $sth2 = $dbh->prepare($query2);
$sth2->execute($msg_seq_id, $user_data->{$form->{login}}->{id});
 
### Commit database contents.
$dbh->{AutoCommit} || $dbh->commit;
 
return $rc;
};
 
sub get_template() {
my($self) = shift;
my $request = shift;
my(%args) = @_;
my $form = $args{formdata};
my $r = $args{r};
my $m = $args{m};
my $password = $self->{userInfo}->{$form->{login}};
my $login = $form->{login};
my $nome = $form->{nome};
my $UserRegTypeMessage = $r->dir_config('UserRegTypeMessage') || $DEFAULT_USR_REG_TYPE_MSG;
my $regActDays = $r->dir_config('MaxTimeToConfirmUserRegistration') || $DEFAULT_MAX_REGISTERATION_TIME;
my $baseurl = sprintf("http%s://%s:%s", $ENV{HTTPS} eq 'on' ? 's' : '', $ENV{HTTP_HOST}, $ENV{SERVER_PORT});
$regActDays = sprintf("%02d", $regActDays);
my $templateName = undef;
### set template for user registraion and password reset.
if($request eq "UserRegistraion") {
$templateName = $UserRegTypeMessage eq "sms" ? $SMS_UR_TEMPLATE_NAME : $MAIL_UR_TEMPLATE_NAME;
} elsif($request eq "PasswordReset") {
$templateName = $UserRegTypeMessage eq "sms" ? $SMS_PR_TEMPLATE_NAME : $MAIL_PR_TEMPLATE_NAME;
};
### set template for user registraion and password reset.
my $template = $m->fetch_comp($templateName) or die "No component $templateName\n";
my $subject = $template->scall_method('Subject');
my $body = $template->scall_method('Body',
nome => $nome,
baseurl => $baseurl,
login => $login,
password => $password,
regActDays => $regActDays
);
return ($subject, $body);
};
 
sub isNotEmpty() {
my($str) = @_;
my $rc = (defined $str and $str ne "") ? $TRUE : $FALSE;
return $rc;
}
 
1;
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/lib/MasonX/Plugin/UTF8.pm
0,0 → 1,39
# Copyright 2012 Tufts University
#
# Licensed under the Educational Community License, Version 1.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.opensource.org/licenses/ecl1.php
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
 
# Modified by Guido Brugnara <gdo@leader.it> to convert array (2019)
 
package MasonX::Plugin::UTF8;
use base qw(HTML::Mason::Plugin);
use Scalar::Util qw(readonly);
use utf8;
 
sub start_request_hook {
my ( $self, $context ) = @_;
my $args_ref = $context->args();
foreach my $arg ( @{$args_ref} ) {
return if(readonly $arg);
if(ref $arg eq 'ARRAY'){
foreach my $arg_arr ( @{$arg} ) {
my $result = utf8::decode($arg_arr);
die unless $result;
}
}else{
my $result = utf8::decode($arg);
die unless $result;
}
}
return;
}
1;
/tags/2.0/lib/MasonSQL/Escapes.pm
0,0 → 1,44
package MasonSQL::Escapes;
 
# funzione di 'escaping' per linguaggio Javascript
sub js_escape {
local $_;
$_=$_[0];
$$_=~s/\\/\\\\/sg;
$$_=~s/"/\\"/sg;
$$_=~s/\'/\\\'/sg;
$$_=~s/\n/\\n/sg;
$$_=~s/\t/\\t/sg;
$$_=~s/<\/script>/<\\\/script>/sg;
}
 
# funzione di 'escaping' per linguaggio XML
sub xml_escape {
local $_;
$_=$_[0];
$$_=~s/&/&amp;/sg;
$$_=~s/</&lt;/sg;
$$_=~s/>/&gt;/sg;
$$_=~s/"/&quot;/sg; #"
$$_=~s/'/&apos;/sg;
$$_=~s/\t/&#9;/sg;
$$_=~s/\n/&#13;/sg;
}
 
# funzione di 'escaping' per incapsulare codice (HTML e XML in un campo textarea
sub textarea_escape {
local $_;
$_=$_[0];
$$_=~s/&/&amp;/sg;
$$_=~s/</&lt;/sg;
$$_=~s/>/&gt;/sg;
}
 
# funzione di 'escaping' per incapsulare codice multiriga
sub multi_escape {
local $_;
$_=$_[0];
$$_=~s/\n/<br>/sg;
}
1;
/tags/2.0/lib/MasonSQL/Report.pm
0,0 → 1,2009
package MasonSQL::Report;
 
=pod
 
=head1 MasonSQL::Report
 
=head2 Revision
 
$Revision: $
 
=head2 Description
 
MasonSQL implementation of reporting.
 
=head2 Included Libraries and Subroutines
 
Library or Function Name | Note
---------------------------------------------
Encode |
HTML::Entities |
DBI |
ODF::lpOD |
Image::Info |
File::MimeInfo |
DTL::Fast |
File::Temp qw/ tempfile / |
Cwd qw(realpath) |
Text::Balanced |
Data::Dumper |
IPC::Run qw(run) |
IPC::Run::SafeHandles |
feature qw(say) |
 
=cut
 
use strict;
use warnings;
use feature qw(say);
use locale;
use POSIX qw(sprintf setlocale LC_NUMERIC);
use Encode;
use HTML::Entities;
use namespace::autoclean;
use DBI;
use DBD::Pg qw(:pg_types);
use ODF::lpOD;
use Image::Info;
use Image::Size;
use MIME::Base64;
use File::MimeInfo;
use File::Temp qw/ tempfile /;
use Cwd qw(realpath);
use Text::Balanced;
use Data::Dumper;
use IPC::Run qw(run);
use IPC::Run::SafeHandles;
use JSON qw(from_json);
 
setlocale(LC_NUMERIC, "it_IT.UTF-8");
 
use DTL::Fast;
package DTL::Fast::Context;
# Patch original method to ignore not defined variables
# tracing variable path
sub traverse
{
my ( $self, $variable, $path, $source_object ) = @_;
my $variable_original = $variable;
 
foreach my $step (@$path)
{
my $current_type = reftype $variable;
if (
blessed($variable)
and $variable->can($step))
{
$variable = $variable->$step();
}
elsif (not defined $current_type)
{
return undef;
}
elsif ($current_type eq 'HASH')
{
$variable = $variable->{$step};
}
elsif (
$current_type eq 'ARRAY'
and $step =~ /^\-?\d+$/x
)
{
$variable = $variable->[$step];
}
else
{
return undef;
}
}
 
while( ref $variable eq 'CODE' )
{
$variable = $variable->();
}
 
return $variable;
}
 
package MasonSQL::Report;
 
=head2 Private Variables, Global to Report Object
 
Variable Name | Description
------------------------------------------------------------------------
dbh | Database handle.
cli | A key-value pairs of reserved cli options.
cmd_parameters | A key-value pairs of command line cli options.
odt_rpt_id | A primary key value of the selected report from
| the public.odt_reports table.
odt_rpt_fields | A key-value hash used for pre-rendering ODT variables.
dtl_context | A DTL context which is global to class.
portion | A structure containing public.odt_report_portion
| records for the selected report.
content | A portion ID-content pairs, that are extracted from
| a template file.
appendable_seq | An array of portion IDs that can be inserted into report,
| sorted by ord field.
| Insertable portions are of type odt_section,
| odt_table, odt_file or pdf_report.
attachable_seq | An array of portion IDs that can be attached as a file,
| sorted by ord field.
| Attachable portions are of type pdf_file or pdf_report.
base_id | A base template portion ID.
base_file_name | A base template file name.
 
=cut
 
# A names of the reserved cli options.
my @reserved = (
'config_path',
'report_name',
'odt_filepath',
'pdf_filepath'
);
 
sub new {
my $class = shift;
my %rpt = @_;
my $self = bless \%rpt, $class;
$self->{dtl_context} = DTL::Fast::Context->new({});
$self->parse_cli($self->{Cli_options});
$self->get_odt_report;
$self->get_odt_report_fields;
$self->get_odt_report_portions;
return $self
}
 
sub say($$){
my $self = shift;
my $funct = shift;
my $str = shift;
$self->{output} .= $str ? "\n$funct(), $str" : "\n$funct()"
}
 
sub output(){
my $self = shift;
my $sent = $self->{output};
$self->{output} = '';
return $sent;
}
 
=head2 Private Static Variables
 
=head3 Temporary Image Filepaths
 
Variable Name | Description
------------------------------------------------------------------------
@tmp_image_filepath | A list of filepaths to temporary files that get deleted
| during destruction of Report object.
=cut
 
=head4 push_tmp_image()
 
Add a new temporary image filepath to the C<tmp_image_filepath>.
 
=cut
sub push_tmp_image($){
my $self = shift;
my $filepath = shift;
push @{$self->{tmp_image_filepath}}, $filepath;
return;
}
 
=head4 unlink_tmp_images()
 
Unlink each temporary image filepath from the C<tmp_image_filepath>.
 
=cut
sub unlink_tmp_images(){
my $self = shift;
$self->unlink_files($self->{tmp_image_filepath});
}
 
=head3 Hash of Pictures
 
Variable Name | Description
------------------------------------------------------------------------
pictures | A hash of images added to the C<Pictures> subdirectory in
| the B<.odt> file. It helps detect and eliminate repeated
| updates of duplicates.
=cut
 
=head4 is_in_pictures()
 
If the image file name was already updated returns 1.
Otherwise returns 0 and saves the image name to the C<pictures> hash.
 
=cut
sub is_in_pictures($){
my $self = shift;
my $picture_name = shift;
if($self->{pictures}{$picture_name}){
return 1;
}else{
$self->{pictures}{$picture_name} = 1;
return 0;
}
}
 
=head2 Interface Subroutines
 
=head3 parse_cli()
 
Parse input arguments, for example:
 
$rpt->parse_cli(\@ARGV);
 
First check if an option is L<reserved|/Private Variables, Global to Report Object> otherwise check if its L<cmd parameter|https://www.leader.it/MasonSQL/OdtReport#Parameters>.
 
Reserved options contain C<:> separator, cmd parameters contain C<=> separator.
 
=cut
sub parse_cli($){
my $self = shift;
my $args = shift;
foreach (@$args){
if(!$self->parse_reserved($_)){
$self->parse_cmd_parameter($_);
}
}
#DEBUG say 'cli: '.Dumper($self->{cli});
$self->check_mandatory_option('config_path');
$self->check_mandatory_option('odt_filepath');
}
 
=head3 get_odt_report()
 
Gets selected record from L<public.odt_reports|https://www.leader.it/MasonSQL/OdtReport#public.odt_reports_Table> table.
From the table it extracts L<odt_rpt_id|/Private Variables, Global to Report Object> and C<global_parameters> field.
The C<global_parameters> field is L<parsed|/list2cmd_parameters()> resulting parameters are stored into L<cmd_parameters|/Private Variables, Global to Report Object> hash.
Also the reference to C<%cmd_parameters> hash is added to L<DTL context|/Private Variables, Global to Report Object> as C<ARGV> thus
the resulting parameters are rendered as C<{{ ARGV.param_name }}>.
Additionaly it reads the public.odt_report_fields table. The contents of this table is used for pre-rendering of the ODT simple variables.
 
=cut
sub get_odt_report(){
my $self = shift;
my $params_statement = q{
select id,global_parameters from public.odt_reports where name = ?;
};
$self->check_mandatory_option('report_name');
#DEBUG say "report_name=$self->{cli}{'report_name'}";
my $row = $self->{Dbh}->selectrow_hashref($params_statement, undef, $self->{cli}{'report_name'});
$self->{odt_rpt_id} = $row->{'id'};
$self->list2cmd_parameters($row->{'global_parameters'});
$self->{dtl_context}->set('ARGV' => $self->{cmd_parameters});
#DEBUG say "cmd_parameters=".Dumper($self->{cmd_parameters});
return;
}
 
=head3 get_odt_report_fields()
 
Gets report's key-value pairs which are available with L<odt_rpt_fields|/Private Variables, Global to Report Object> reference.
 
=cut
sub get_odt_report_fields(){
my $self = shift;
my $fields_statement = $self->{Dbh}->prepare(q{
select key, function as fun, format from public.odt_report_fields where id_odt_reports = ?;
});
$fields_statement->execute($self->{odt_rpt_id});
$self->{odt_rpt_fields} = $fields_statement->fetchall_hashref('key');
return
}
 
=head3 get_odt_report_portions()
 
Gets records from L<public.odt_report_portions|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> table belonging to the selected report from the L<public.odt_reports|https://www.leader.it/MasonSQL/OdtReport#public.odt_reports_Table> table.
The records with empty C<type> field are skipped.
Fields from each obtained record are stored into L<portion|/Private Variables, Global to Report Object> structure.
If the record is base report L<base_id|/Private Variables, Global to Report Object> and L<base_file_name|/Private Variables, Global to Report Object> are also obtained.
It is also determined whether the portions is C<appendable> or C<attachable>.
When the base report query is defined, it retrieves the first row of the query results, then adds the base portion name with field values from the row to the DTL L<DTL context|/Private Variables, Global to Report Object>.
 
=cut
sub get_odt_report_portions(){
my $self = shift;
my $statement = $self->{Dbh}->prepare(q{
select * from public.odt_report_portions where id_odt_reports = ?;
});
$statement->execute($self->{odt_rpt_id});
while(my $row = $statement->fetchrow_hashref){
my $id = $row->{'id'};
if($row->{'type'}){
if($row->{'type'} eq 'base_report'){
$self->{base_id} = $id;
$self->{base_file_name} = $self->render_string($self->truncate_blanks($row->{'file_name'}));
if($self->{base_file_name} =~ /^\s*$/){
die $self->err_msg("No base_report file name, please specify base_report portion with file name.");
}
}
if($row->{'type'} eq 'odt_section' || $row->{type} eq 'odt_table' || $row->{type} eq 'odt_file'){
$self->{portion}{appendable}{$id} = $row->{'ord'};
}elsif($row->{'type'} eq 'pdf_file' || $row->{type} eq 'pdf_report'){
$self->{portion}{attachable}{$id} = $row->{'ord'};
}
$self->{portion}{type}{$id} = $row->{'type'};
$self->{portion}{order}{$id} = $row->{'ord'};
$self->{portion}{name}{$id} = $self->truncate_blanks($row->{'name'});
$self->{portion}{father}{$id} = $row->{'id_father'};
$self->{portion}{file_name}{$id} = $self->truncate_blanks(defined $row->{'file_name'} ? $row->{'file_name'} : '');
$self->{portion}{obj_ref}{$id} = $self->truncate_blanks(defined $row->{'obj_ref'} ? $row->{'obj_ref'} : '');
$self->{portion}{query}{$id} = defined $row->{'query'} ? $row->{'query'} : '';
#DEBUG "name($id)=$self->{portion}{name}{$id}";
#DEBUG "father($id)=$self->{portion}{father}{$id}";
#DEBUG "obj_ref{$id}=".$self->{portion}{obj_ref}{$id};
#DEBUG "query{$id}=".$self->{portion}{query}{$id};
}
}
#DEBUG 'portions: '.Dumper(\%portion);
$self->set_base_context;
return;
}
 
=head3 make_report()
 
Makes the B<.odt> report document.
Returns filepath of the main odt report.
If it can't find the base file, it does nothing and returns an empty string.
 
The procedure to make a report document:
 
=over 2
 
=item 1
 
Create L<new report|/new_report()> from the L<base template|https://www.leader.it/MasonSQL/OdtReport#base_report_portion_type> file.
 
=item 2
 
L<Read portions|/read_base_portions()> from the base template file.
 
=item 3
 
L<Delete portions|/delete_portions()> from newly created report file.
 
=item 4
 
Obtain L<sequence|/get_appendable_sequence()> in which the portions will be added to the report.
 
=item 5
 
L<Generate body|/make_body()> of the report.
 
=item 6
 
Finally save the report.
 
=back
 
=cut
sub make_report(){
my $self = shift;
unless($self->{base_file_name}){
return '';
}
my ($report, $body) = $self->new_report($self->{cli}{'odt_filepath'});
$self->read_base_portions($body);
$self->delete_portions($body);
$self->get_appendable_sequence;
if(my $base_name = $self->{portion}{name}{$self->{base_id}}){
if($self->{dtl_context}->get($base_name)){
$self->make_body($self->{base_id}, $report, $body);
}
}else{
$self->make_body($self->{base_id}, $report, $body);
}
$report->save();
return $self->{cli}{'odt_filepath'};
}
 
=head3 get_pdf_filepath()
 
Returns the target filepath, of the main report, that is needed by L<Unoconv|http://tech.rgou.net/en/php/converting-documents-odt-doc-to-pdf-on-php-with-unoconv-libreoffice/> or Libreoffice for conversion from B<.odt> to B<.pdf>.
 
Both origin and target filepaths are passed from the L<report.pdf|https://www.leader.it/MasonSQL/ReportComponent> component where they are composed.
 
=cut
sub get_pdf_filepath(){
my $self = shift;
$self->check_mandatory_option('pdf_filepath');
return $self->{cli}{'pdf_filepath'};
}
 
=head3 add_attachments()
 
Concatenates the report with the L<attachments|/attach_portion()>.
The attachments are ordered by L<attachable_seq|/Private Variables, Global to Report Object>
 
The concatenation is made with C<pdftk> executable, with the command:
 
pdftk <filepath1> <filepath2> ... <filepathN> cat output <output_filepath>
 
=cut
sub add_attachments($$){
my $self = shift;
my $main_report = shift;
my $pdf_filepath = shift;
my $pdftk = '/usr/bin/pdftk';
if(! -e $pdftk){
die "$pdftk not exists\n";
}
my @cmd = ($pdftk);
my @pdf_reports = ();
if($main_report){
push(@cmd, $main_report);
}
$self->get_attachable_sequence;
foreach my $id (@{$self->{attachable_seq}}){
$self->attach_portion(\@cmd, \@pdf_reports, $id);
}
push(@cmd, 'cat');
push(@cmd, 'output');
push(@cmd, $pdf_filepath);
#DEBUG say "cmd=".Dumper(\@cmd);
my $out_and_err = ();
if(!run \@cmd, '<', \undef, '>&', \$out_and_err){
die "add_attachments error running ".join(' ', @cmd).": $? err:[$out_and_err]\n";
}
#DEBUG say "pdftk out_and_err: $out_and_err";
$self->unlink_files(\@pdf_reports);
return;
}
 
=head3 Parsing CLI and Apache Config
 
=head4 parse_reserved()
 
Checks if the CLI option is found in L<cli|/Private Variables, Global to Report Object> hash and, in case it does, returns 1;
Otherwise returns 0.
 
=cut
sub parse_reserved($){
my $self = shift;
my $option = shift;
foreach (@reserved){
if($option =~ /$_:(.*)/){
$self->{cli}{$_} = $1;
return 1;
}
}
return 0;
}
 
=head4 parse_cmd_parameter()
 
Checks that the input CLI option is a L<cmd parameter|https://www.leader.it/MasonSQL/OdtReport#Parameters>
If its not a cmd parameter raises an error.
 
=cut
sub parse_cmd_parameter($){
my $self = shift;
my $parameter = shift;
if($parameter =~ /(.*)=(.*)/){
$self->{cmd_parameters}{$1} = $2;
}else{
die $self->err_msg("Invalid format of cmd parameter $parameter");
}
return;
}
 
=head4 list2cmd_parameters()
 
Uses L<Text::Balanced|http://perldoc.perl.org/Text/Balanced.html> to extract L<cmd parameters|https://www.leader.it/MasonSQL/OdtReport#Parameters> from the input list.
A cmd parameters without values will cause an error unless the value is empty string.
The parsed cmd parameter names and values are stored in the L<cmd_parameters|/Private Variables, Global to Report Object> hash.
 
=cut
sub list2cmd_parameters($){
my $self = shift;
my $list = shift;
unless($list){
return;
}else{
$list =~ s/\\//g;
}
my $sep = '\s+';
my $options = $list;
my @name = Text::Balanced::extract_multiple($options, [
qr/$sep([\w-]+)\s*=\s*/,
qr/^\s*([\w-]+)\s*=\s*/,
], undef, 1);
$options = $list;
my @value = Text::Balanced::extract_multiple($options, [
sub { Text::Balanced::extract_quotelike($_[0]) },
qr/\s*=\s*([\w-]+)/,
], undef, 1);
if($#name != $#value){
die $self->err_msg("Invalid format of cli parameters: $list\nUse [ param1=100 ][ MyPAR='my string data' ].");
}
for (my $I = 0; $I<@value; $I++){
$value[$I] =~ s/^("|'|`|\s)+//;
$value[$I] =~ s/("|'|`|\s)+$//;
$value[$I] =~ s/$sep$//;
my $uc_name = uc $name[$I];
unless($self->{cmd_parameters}{$uc_name}){
$self->{cmd_parameters}{$uc_name} = $value[$I];
#DEBUG say "list2cmd_parameters($uc_name)=$value[$I]";
}
}
return;
}
 
=head4 check_mandatory_option()
 
Verifies that the mandatory option is L<reserved|/parse_reserved()> and that the option exists in L<cli|/Private Variables, Global to Report Object> hash.
Otherwise raises an error.
 
=cut
sub check_mandatory_option($){
my $self = shift;
my $option = shift;
if($self->parse_reserved($option)){
unless($self->{cli}{$option}){
die $self->err_msg("Please specify mandatory option $option, use my_option_name:my_option_value format.");
}
}
return;
}
 
=head3 Handling Portions
 
=head4 append_portion()
 
=over 2
 
=item 1
 
Clones the L<content|/Private Variables, Global to Report Object> of the template portion;
 
=item 2
 
L<Renders|https://metacpan.org/pod/DTL::Fast#render> the cloned portion;
 
=item 3
 
Appends it to the body of the document.
 
=back
 
=cut
sub append_portion($$$){
my $self = shift;
my $body = shift;
my $obj_ref = shift;
my $content_key = shift;
if(my $portion = $self->{content}{$content_key}){
$portion = $portion->clone;
$self->render_text($portion);
$body->append_element($portion);
return $portion;
}else{
die $self->err_msg("Can't find portion, obj_ref='$obj_ref'");
}
}
 
=head4 attach_portion()
 
=over 2
 
=item *
 
If the portion type is L<pdf_file|https://www.leader.it/MasonSQL/OdtReport#pdf_file_portion_type> it constructs filepath with rendered portion's file name then attaches the filepath to the L<pdftk|/add_attachments()> command.
 
=item *
 
If the portion type is L<pdf_report|https://www.leader.it/MasonSQL/OdtReport#pdf_report_portion_type> it makes the pdf L<report|/make_pdf_reports()>
then attaches the report's filepath to the L<pdftk|/add_attachments()> command.
 
=back
 
=cut
sub attach_portion($$$){
my $self = shift;
my $cmd = shift;
my $pdf_reports = shift;
my $id = shift;
#DEBUG say "attach portion id=$id";
my $relative_filepath = $self->render_string($self->{portion}{file_name}{$id});
my $filename = $relative_filepath && $relative_filepath !~ /^\s*$/;
if($self->{portion}{type}{$id} eq 'pdf_file'){
if($filename && $relative_filepath =~ /\.pdf$/){
push(@{$cmd}, $self->template_filepath($relative_filepath));
}else{
die $self->err_msg("Please specify .pdf filename in portion $id.");
}
}elsif($self->{portion}{type}{$id} eq 'pdf_report'){
if($filename && $relative_filepath =~ /\.odt$/){
my $odt_template = $self->template_filepath($relative_filepath);
my $pdfs = $self->make_pdf_reports($odt_template, $id);
foreach my $pdf (@$pdfs){
push(@{$cmd}, $pdf);
push(@{$pdf_reports}, $pdf);
}
}else{
die $self->err_msg("Please specify .odt template filename in portion $id.");
}
}
return;
}
 
=head4 delete_portions()
 
Deletes all of the sections and all of the tables from the body of the current document.
 
=cut
sub delete_portions($){
my $self = shift;
my $body = shift;
my @sections = $body->get_sections();
foreach my $section (@sections){ $section->delete; }
my @tables = $body->get_tables();
foreach my $table (@tables){ $table->delete; }
return;
}
 
=head4 get_portion()
 
Checks the portion type then, accordingly to type, uses L<get_section|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/StructuredContainer.pod#Sections> or L<get_table_by_name|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/Table.pod#Table_creation_and_retrieval>.
If the portion type does not match it raises an error although the table or the section exists.
Unless portion type is L<odt_section|https://www.leader.it/MasonSQL/OdtReport#odt_section_portion_type> or L<odt_table|https://www.leader.it/MasonSQL/OdtReport#odt_table_portion_type> it is skipped.
Since the C<template> can be different from base template L<comments|/remove_comments()> are preventively removed.
 
=cut
sub get_portion($$$){
my $self = shift;
my $template = shift;
my $obj_ref = shift;
my $type = shift;
#DEBUG say "get_portion: obj_ref=$obj_ref, type=$type";
my $body = $template->get_body;
$self->remove_comments($body);
my $portion = '';
if($type eq 'odt_section'){
$portion = $body->get_section($obj_ref) or die $self->err_msg("No matching section $obj_ref");
}elsif($type eq 'odt_table'){
$portion = $body->get_table_by_name($obj_ref) or die $self->err_msg("No matching table $obj_ref");
}
#DEBUG say "got $obj_ref";
return $portion;
}
 
=head4 update_portion()
 
L<Renders|https://metacpan.org/pod/DTL::Fast#render> L<file_name|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> then checks whether to update the L<content|/Private Variables, Global to Report Object> hash or skip the update.
The update is skipped if the C<file_name> is NULL, if its a base filename, if its empty string or if the template portion is already stored in the C<content> hash.
The subroutine allways returns current L<content|/Private Variables, Global to Report Object> key.
 
=cut
sub update_portion($$){
my $self = shift;
my $obj_ref = shift;
my $id = shift;
my $file_name = $self->render_string($self->{portion}{file_name}{$id});
my $key = '';
if($file_name && $file_name !~ /^\s+$/ && $file_name ne $self->{base_file_name}){
$key = $file_name . $obj_ref;
unless($self->{content}{$key}){
my $template = odf_document->get($self->template_filepath($file_name));
$self->{content}{$key} = $self->get_portion($template, $obj_ref, $self->{portion}{type}{$id});
}
#DEBUG say "key=$key";
return $key;
}
else{
$key = $self->{base_file_name} . $obj_ref;
return $key;
}
}
 
=head4 read_base_portions()
 
The subroutine is called in the initial phase of the report creation:
Reads sections and tables into L<content|/Private Variables, Global to Report Object> hash.
 
=cut
sub read_base_portions($){
my $self = shift;
my $body = shift;
my @sections = $body->get_sections();
foreach my $section (@sections){
my $key = $self->{base_file_name} . $section->get_name;
$self->{content}{$key} = $section;
#DEBUG say "key=$key";
}
my @tables = $body->get_tables();
foreach my $table (@tables){
my $key = $self->{base_file_name} . $table->get_name;
$self->{content}{$key} = $table;
#DEBUG say "key=$key";
}
return;
}
 
=head4 set_base_context()
 
If its possible, adds the first row of the base portion to the DTL context.
The prerequisite is availability of the L<query|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> and L<name|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> field values for the base portion and the row number set to 1.
 
=cut
sub set_base_context(){
my $self = shift;
my $base_query = $self->render_string($self->{portion}{query}{$self->{base_id}});
#DEBUG say "base_query=[\n$base_query\n]";
if($base_query && $self->{portion}{name}{$self->{base_id}}){
my $statement = $self->{Dbh}->prepare($base_query);
$statement->execute();
if($statement){
if(my $record = $statement->fetchrow_hashref){
$record->{'ROW_NUMBER'} = 1;
$self->set_portion_context($self->{base_id}, $statement->{NAME}, $statement->{pg_type}, $record);
}
}
}
return;
}
 
=head4 set_portion_context()
 
Adds the portion name with field values from record to the DTL L<DTL context|/Private Variables, Global to Report Object>.
Previous entry in the C<DTL context> is overwritten with the current one.
The added field values are used during rendering of the portion's L<DTL tags|https://www.leader.it/MasonSQL/OdtReport#Django_Template_Language>.
The corresponding DTL reference can be used like this: C<{{ my_portion_name.my_field_name }}>
In case the field is of json type the content of that field is converted to JSON tree and stored to the DTL context.For example: The property of the JSON string C<{"X": {"Y": {"Z": "DATA"}}}> can be accessed with the DTL tag C<{{ myportionname.myfieldname.X.Y.Z }}>.
Additionally JSON tree is L<converted|/json2utf8()> to UTF8.
 
=cut
sub set_portion_context($$$$){
my $self = shift;
my $id = shift;
my $field_name = shift;
my $field_type = shift;
my $record = shift;
if($self->{portion}{name}{$id}){
#DEBUG $self->say("set_portion_context", "$self->{portion}{name}{$id} => ");
if($record){
for(my $idx = 0; $idx < @{$field_name}; $idx++){
my $name = $field_name->[$idx];
my $type = $field_type->[$idx];
my $field = decode_entities(defined $record->{$name} ? $record->{$name} : '');
if($type =~ /json/ && $field){
#DEBUG $self->say("set_portion_context", "field=".Dumper($field));
my $json = from_json($field);
$record->{$name} = $self->json2utf8($json);
#DEBUG say "record=".Dumper($record->{$name});
}else{
$record->{$name} = Encode::encode_utf8($field);
}
}
#DEBUG $self->say("set_portion_context", "record: ".Dumper($record));
$self->{dtl_context}->set($self->{portion}{name}{$id} => $record);
}
}
return;
}
 
=head4 json2utf8()
 
Converts encoding of all strings in the json structure to UTF8.
 
=cut
sub json2utf8($){
my $self = shift;
my $json = shift;
my $ref = ref $json;
if($ref eq 'ARRAY'){
for(my $idx = 0; $idx < @$json; $idx++){
my $val = $json->[$idx];
if(ref $val){
$self->json2utf8($val);
}else{
$json->[$idx] = $val ? Encode::encode_utf8($val) : '';
}
}
}elsif($ref eq 'HASH'){
foreach my $key (keys %$json){
my $val = $json->{$key};
if(ref $val){
$self->json2utf8($val);
}else{
$json->{$key} = $val ? Encode::encode_utf8($val) : '';
}
}
}
return $json;
}
 
=head3 Handling odt_table Portions
 
=head4 make_table()
 
Uses the following procedure to create a new table:
 
=over 2
 
=item 1
 
L<Render|https://metacpan.org/pod/DTL::Fast#render> L<obj_ref|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> field value.
 
=item 2
 
Update L<content|/Private Variables, Global to Report Object> of current portion.
 
=item 3
 
Clone the template table and append the new table to the body of the report.
Use the last row from the template table as a template row.
If the table doesn't have any rows skip to step 6.
 
=item 4
 
L<Render non-repeating table header|/render_non_repeating_header()>.
 
=item 5
 
Populate the table with the query results:
 
=over 2
 
=item a.
 
Clone the template row and append it to the new table.
 
=item b.
 
L<Updates images in the current row.|/update_images()>
 
=item c.
 
Update L<DTL context|/Private Variables, Global to Report Object> with the query results for the current row and with the current row number.
L<Render|https://metacpan.org/pod/DTL::Fast#render> the appended row.
 
=item d.
 
Check if any L<children portions|/make_body()> can be added.
 
=back
 
=item 6
 
L<Render repeating table header|/render_repeating_header()>.
 
=back
 
=cut
sub make_table($$$$){
my $self = shift;
my $report = shift;
my $body = shift;
my $statement = shift;
my $id = shift;
my $obj_ref = $self->render_string($self->{portion}{obj_ref}{$id});
if($statement && $obj_ref){
#DEBUG say "make_table: $obj_ref";
my $content_key = $self->update_portion($obj_ref, $id);
my $template_table = $self->{content}{$content_key};
unless($template_table){
die $self->err_msg("Can't find table: '$obj_ref'.");
}
my $table = $template_table->clone;
$body->append_element($table);
my ($length, $width) = $template_table->get_size;
my $template_row_id = $length - 1;
if($template_row_id >= 0){
my $template_row = $template_table->get_row($template_row_id);
$table->delete_row($template_row_id);
$self->render_non_repeating_header($table, $template_row_id);
my $row_num = 1;
my $name = $statement->{NAME};
my $type = $statement->{pg_type};
while(my $record = $statement->fetchrow_hashref){
my $row = $template_row->clone;
$self->update_images($report, $row);
$table->append_element($row);
$record->{'ROW_NUMBER'} = $row_num++;
$self->set_portion_context($id, $name, $type, $record);
$self->render_row($row);
$self->make_body($id, $report, $body);
}
}
$self->render_repeating_header($report, $table);
}
return;
}
 
=head4 render_repeating_header()
 
Gets L<table header|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/Table.pod#Table_headers> and L<renders|https://metacpan.org/pod/DTL::Fast#render> its content.
Also L<updates images|/update_images()>.
 
=cut
sub render_repeating_header($$){
my $self = shift;
my $report = shift;
my $table = shift;
if(my $header = $table->get_column_header){
$self->render_text($header);
$self->update_images($report, $header);
}
return;
}
 
=head4 render_non_repeating_header()
 
L<Renders non-header rows|/render_row()> except the last one which is reserved as a template row.
 
=cut
sub render_non_repeating_header($$){
my $self = shift;
my $table = shift;
my $template_row_id = shift;
for(my $row_id = 0; $row_id < $template_row_id; $row_id++){
my $row = $table->get_row($row_id);
$self->render_row($row);
}
return;
}
 
=head4 render_row()
 
L<Renders|https://metacpan.org/pod/DTL::Fast#render> text in each cell in the row, consecutively one by one.
 
=cut
sub render_row($){
my $self = shift;
my $row = shift;
if($row){
my @cell = $row->get_cells();
foreach my $cell (@cell){
$self->render_text($cell);
}
}
return;
}
 
=head3 Handling odt_section Portions
 
=head4 make_section()
 
Makes a query.
 
For each row from the query result:
 
=over 2
 
=item 1
 
Updates L<DTL context|/Private Variables, Global to Report Object> with the values from the current row and with the current row number.
 
=item 2
 
Appends L<a new section|/add_section()>.
 
=back
 
If there is no query it still appends one section.
 
=cut
sub make_section($$$$){
my $self = shift;
my $report = shift;
my $body = shift;
my $statement = shift;
my $id = shift;
if($statement){
my $row_num = 1;
my $name = $statement->{NAME};
my $type = $statement->{pg_type};
while(my $record = $statement->fetchrow_hashref){
$record->{'ROW_NUMBER'} = $row_num++;
$self->set_portion_context($id, $name, $type, $record);
$self->add_section($report, $body, $id);
}
}else{
$self->add_section($report, $body, $id);
}
return;
}
 
=head4 add_section()
 
Uses the rendered L<obj_ref|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> field value to find the section that is then appended to the body of the report document.
Before the section is L<appended|/append_portion()> it is L<updated|/update_portion()>.
In case the portion type is L<odt_file|https://www.leader.it/MasonSQL/OdtReport#odt_file_portion_type> the L<.odt file is appended|/append_odt_file()> to the body of the report instead of a section.
After the section is L<appended|/append_portion()> its L<images are updated|/update_images()>.
 
=cut
sub add_section($$$){
my $self = shift;
my $report = shift;
my $body = shift;
my $id = shift;
if($self->{portion}{type}{$id} eq 'odt_section'){
if(my $obj_ref = $self->render_string($self->{portion}{obj_ref}{$id})){
#DEBUG $self->say("add_section", "$obj_ref");
my $content_key = $self->update_portion($obj_ref, $id);
my $portion = $self->append_portion($body, $obj_ref, $content_key);
$self->update_images($report, $portion);
}
}elsif($self->{portion}{type}{$id} eq 'odt_file'){
$self->append_odt_file($body, $id);
}
$self->make_body($id, $report, $body);
return;
}
 
=head3 Handling odt_file Portions
 
=head4 append_odt_file()
 
L<Renders|https://metacpan.org/pod/DTL::Fast#render> the content of the template B<.odt> file then L<appends the file|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/Element.pod#Context_import> to the body of the report document.
 
=cut
sub append_odt_file($$){
my $self = shift;
my $body = shift;
my $id = shift;
my $file_name = $self->render_string($self->{portion}{file_name}{$id});
if($file_name && $file_name !~ /^\s+$/){
#DEBUG say "append_odt_file, file_name=$file_name";
my $tmp_filepath = $self->tmp_file('odt_file', '.odt');
my $template = odf_document->get($self->template_filepath($file_name));
$template->save(target => $tmp_filepath);
my $tmp_doc = odf_document->get($tmp_filepath);
my $tmp_body = $tmp_doc->get_body;
$self->render_text($tmp_body);
#DEBUG say "table: ". Dumper($table->node_info);
$body->import_children($tmp_body);
unlink $tmp_filepath;
}
return;
}
 
=head3 Handling pdf_report Portions
 
=head4 make_pdf_report()
 
The procedure to make a pdf report:
 
=over 2
 
=item 1
 
Create a new L<temporary .odt file|/tmp_file()>.
 
=item 2
 
L<Create new report from portion's ODT template|/new_pdf_report()> and store it to the temporary .odt file.
 
=item 3
 
Use L<Unoconv|http://tech.rgou.net/en/php/converting-documents-odt-doc-to-pdf-on-php-with-unoconv-libreoffice/> or Libreoffice
to convert the newly created report to B<.pdf> file format.
 
=item 4
 
Return the converted PDF filepath.
 
=back
 
=cut
sub make_pdf_report($$){
my $self = shift;
my $odt_template = shift;
my $converter = shift;
my $new_odt = $self->tmp_file('pdf_report', '.odt');
$self->new_pdf_report($odt_template, $new_odt);
my $pdf = $self->tmp_file('pdf_report', '.pdf');
my $out = $converter->convert_to_pdf($new_odt, $pdf);
#DEBUG say "convert_to_pdf out: $out";
unlink $new_odt;
return $pdf;
}
 
=head4 make_pdf_reports()
 
Query the database then use the query results to produce the L<pdf reports|https://www.leader.it/MasonSQL/OdtReport#pdf_report_portion_type>.
 
Before making each new pdf report update the L<DTL context|/Private Variables, Global to Report Object> with current record.
 
=cut
sub make_pdf_reports($$){
my $self = shift;
my $odt_template = shift;
my $portion_id = shift;
my $query = $self->render_string($self->{portion}{query}{$portion_id});
#DEBUG say "make_pdf_reports query=[\n$query\n]";
my @pdfs = ();
if($query){
my $statement = $self->{Dbh}->prepare($query);
$statement->execute();
if($statement){
my $row_num = 1;
my $converter = MasonSQL::Report::OdtConv->new(Engine => $self->{OdtConvEngine});
while(my $record = $statement->fetchrow_hashref){
$record->{'ROW_NUMBER'} = $row_num++;
$self->set_portion_context($portion_id, $statement->{NAME}, $statement->{pg_type}, $record);
#DEBUG say 'pdf context:'.Dumper($record);
push(@pdfs, $self->make_pdf_report($odt_template, $converter));
}
}
}
return \@pdfs;
}
 
=head4 new_pdf_report()
 
Open the portion's template file; Save the template file as a new report;
Then L<prepare the report|/prepare_report()> and L<render its contents|/render_text()>.
 
=cut
sub new_pdf_report($$){
my $self = shift;
my $odt_template = shift;
my $new_odt = shift;
if(my $template = odf_document->get($odt_template)){
$template->save(target => $new_odt);
}else{
die $self->err_msg("Can't find template file '$odt_template'");
}
my ($report, $body) = $self->prepare_report($new_odt);
$self->update_images($report, $body);
$self->render_text($body);
$report->save;
# Make second pass, with render_report(), in case the report contains forms
# tags which don't seem to be supported by ODF::lpOD.
$self->render_report($report, $new_odt);
# Following save is not needed since it is called in the render_report().
#$report->save;
return;
}
 
 
=head4 render_report()
 
L<Render|https://metacpan.org/pod/DTL::Fast#render> the newly created ODT template file.
 
=cut
sub render_report($$){
my $self = shift;
my $report = shift;
my $new_odt = shift;
my @parts = (CONTENT, STYLES);
my %xml = ();
foreach my $part_name (@parts){
my $part = $report->get_part($part_name);
my $xml = $part->serialize;
my $rendered = $self->render_string($xml);
#DEBUG say "xml{$part_name}: {$rendered}";
$xml{$part_name} = $rendered;
}
# Must save and reopen here.
# Following code is a workaround for set_part() function.
$report->save;
$report = odf_document->get($new_odt);
my @tmp_file = ();
foreach my $part_name (@parts){
#$report->set_part($part_name, $xml);
my $tmp_filepath = $self->tmp_file($part_name, '.xml', $xml{$part_name});
$report->del_part($part_name);
$report->add_file($tmp_filepath, path => $part_name);
push (@tmp_file, $tmp_filepath);
}
$report->save();
foreach my $tmp_filepath (@tmp_file){
unlink $tmp_filepath;
}
return;
}
=head3 Text Processing
 
=head4 remove_comments()
 
Removes all L<comments|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/TextElement.pod#Annotation_retrieval> from the report document.
 
=cut
sub remove_comments($){
my $self = shift;
my $body = shift;
my @comments = $body->get_annotations();
foreach my $comment (@comments){
$comment->delete;
}
return;
}
 
=head4 truncate_blanks()
 
Removes white spaces from the beginning and from the end of the string.
 
=cut
sub truncate_blanks($){
my $self = shift;
my $string = shift;
if($string){
$string =~ s/^\s+//;
$string =~ s/\s+$//;
}
return $string;
}
 
=head3 DTL Rendering
 
=head4 clean_dtl_tags()
 
Remove the text-spans from the xml's DTL tags.
Use the regular expressions to list the DTL tags.
 
Loop over the found tags:
 
=over 2
 
=item 1
 
Count the number of text-spans inside the tag.
 
=item 2
 
If the tag contains any text-spans remove them.
 
=item 3
 
=over 2
 
=item *
 
If the number of text-spans, inside the tag, is odd simply remove all text-spans from it.
 
=item *
 
If the number of text-spans, inside the tag, is even extract one of the spans to the left or to the right of the tag.
 
=back
 
=back
 
=cut
sub clean_dtl_tags($){
my $self = shift;
my $xml = shift;
my $span_regex = '(<|<\/)text:span[^>]*>';
my $any_spans = '('.$span_regex.')*';
my @part = ();
$part[0] = '{'.$any_spans;
$part[1] = '({|%)([^%}]*'.$any_spans.'[^%}]*)(%|})';
$part[2] = $any_spans.'}';
my $tag_regex = join('', @part);
#DEBUG say "tag_regex=$tag_regex";
my $span_beginning = '<text:span[^>]*>';
my $span_ending = '<\/text:span[^>]*>';
$xml =~ s/<text:s\/>//g;
$xml =~ s/<text:soft-page-break\/>//g;
foreach my $dirty ($xml =~ m/($tag_regex)/sg){
unless(defined $dirty){
next;
}
my @spans = ($dirty =~ m/$span_regex/g);
if(@spans){
my $cleaned = '';
if(@spans % 2){
if($dirty =~ /^[^<]*($span_ending)/){
my $keep_span = $1;
$cleaned = $dirty =~ s/$span_regex//gr;
$cleaned .= $keep_span;
#DEBUG say "with span ending=$cleaned";
}elsif($dirty =~ /($span_beginning)[^>]*$/){
my $keep_span = $1;
$cleaned = $dirty =~ s/$span_regex//gr;
$cleaned = $keep_span.$cleaned;
#DEBUG say "with span beginning=$cleaned";
}else{
die "Bad regex.";
}
}else{
$cleaned = $dirty =~ s/$span_regex//gr;
#DEBUG say "even, cleaned=$cleaned";
}
$xml =~ s/\Q$dirty\E/$cleaned/g;
}
}
return $xml;
}
 
=head4 pre_render_variables()
 
Find all simple variables inside the text element.
Simple variables are identified in the xml with 'variable-set' tag.
 
For each variable:
 
=over 2
 
=item 1
 
Obtain the variable name.
 
=over 2
 
=item a.
 
First look for variable name in the L<odt_rpt_fields|/> hash.
If the variable name is stored there, L<update|/set_variable()> with it the variable value.
 
=item b.
 
Then look for the variable name in the DTL hash.
If the variable name is found in the DTL hash, L<update|/set_variable()> with it the variable value.
 
=back
 
=back
 
=cut
sub pre_render_variables($){
my $self = shift;
my $text_element = shift;
foreach my $var ($text_element->get_fields('variable-set')){
my $var_type = $var->get_attribute('office:value-type');
if(my $var_name = $var->get_attribute('text:name')){
my $var_value = '';
my $field = $self->{odt_rpt_fields}{$var_name};
if(defined $field && defined $field->{fun}){
$var_value = $self->render_string(Encode::encode_utf8(decode_entities($field->{fun})));
}elsif(my $dtl_value = $self->{dtl_context}->get($var_name)){
$var_value = $dtl_value;
}
my $var_format = '';
if(defined $field && defined $field->{format}){
$var_format = $self->render_string(Encode::encode_utf8(decode_entities($field->{format})));
#DEBUG say "var_name=$var_name, var_type=$var_type, var_value=$var_value";
}
$self->set_variable($var, $var_type, $var_value, $var_format);
}
}
return;
}
 
=head4 set_variable()
 
Sets variable's attributes with new values. Handles simple variables of all available data types:
'string', 'float', 'currency', 'percentage', 'boolean', 'date' and 'time'.
 
For the types 'date' and 'time' there's the workaround:
Their types are changed to 'string';
The public.odt_report_field.format field value is used as a formatting string.
 
=cut
sub set_variable($$$$){
my $self = shift;
my $var = shift;
my $type = shift;
my $value = shift;
my $format = shift;
my $v = check_odf_value($value, $type);
unless(defined $v){
return undef;
}
if($type eq 'date' || $type eq 'time' || $type eq 'string'){
$value = $format ? sprintf($format, $value) : $value;
}elsif($type eq 'boolean'){
$v = odf_boolean($v);
$var->set_attribute('office:boolean-value', $v);
$var->set_attribute('text:formula', "ooow:$v");
}else{
unless($v){
$v = 0;
}
unless($value){
$value = 0;
}
if($type eq 'float'){
$var->set_attribute('office:value', sprintf("%f", $v));
$var->set_attribute('text:formula', "ooow:".sprintf("%f", $value));
}elsif($type eq 'currency'){
$v = sprintf("%f", $v);
$var->set_attribute('office:value', $v);
$var->set_attribute('text:formula', "ooow:$v");
}elsif($type eq 'percentage'){
$v /= 100;
$v = sprintf("%f", $v);
$var->set_attribute('office:value', $v);
$var->set_attribute('text:formula', "ooow:$v");
}
}
$var->set_text($value);
return $v;
}
 
=head4 render_string()
 
Uses L<DTL|https://www.leader.it/MasonSQL/OdtReport#Django_Template_Language> to L<render|https://metacpan.org/pod/DTL::Fast#render> an input string.
 
=cut
sub render_string($){
my $self = shift;
my $str = shift;
my $tpl = DTL::Fast::Template->new($str);
my $rendered = $tpl->render($self->{dtl_context});
return $rendered;
}
 
=head4 render_text()
 
L<Renders|/render_list()> all object's L<headings|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/TextElement.pod#get_headings> and L<paragraphs|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/TextElement.pod#get_paragraphs>.
 
=cut
sub render_text($){
my $self = shift;
my $object = shift;
if($object){
my @headings = $object->get_headings();
$self->render_list($object, \@headings);
my @paragraphs = $object->get_paragraphs();
$self->render_list($object, \@paragraphs);
}
}
 
=head4 render_list()
 
L<Renders|https://metacpan.org/pod/DTL::Fast#render> text from each element in the input list.
 
Steps performed on each element:
 
=over 2
 
=item 1
 
Firstly, L<pre-render variables|/pre_render_variables()> inside the element's xml.
 
=item 2
 
Secondly, serialize the element and L<decode its entities>.
 
=item 3
 
Thirdly, clean the text-spans out of the DTL tags contained in the element's xml.
 
=item 4
 
Fourthly, render the xml.
 
=item 5
 
Fifthly, create a new element from the rendered xml.
 
=item 6
 
Finally, replace the element with the new rendered element.
 
=back
 
=cut
sub render_list($$){
my $self = shift;
my $object = shift;
my $list = shift;
foreach my $text_element (@{$list}){
$self->pre_render_variables($text_element);
my $xml = decode_entities($text_element->serialize);
$xml =~ s/office:value-type=("|')(date|time)("|')/office:value-type="string"/g; #workaround
$xml = $self->clean_dtl_tags($xml);
my $rendered = $self->render_string($xml);
$rendered =~ s/\t/<text:tab\/>/gs;
$rendered =~ s/\r{0,1}\n/<text:line-break\/>/gs;
if(my $new_p = odf_element->create($rendered)){
#DEBUG say 'new_xml: '.$new_p->serialize();
$object->insert_element($new_p, before => $text_element);
$text_element->delete();
}
}
return;
}
 
=head4 render_header_footer()
 
Accesses the L<page styles|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/Style.pod#Page_styles>;
L<Renders|https://metacpan.org/pod/DTL::Fast#render> text elements found in L<page header and page footer|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/Style.pod#Page_headers_and_footers>.
 
=cut
sub render_header_footer($){
my $self = shift;
my $report = shift;
foreach my $page_style ($report->get_styles('master page')){
$self->render_text($page_style);
}
return;
}
 
=head3 Rendering Images
 
=head4 delete_old_images()
 
Deletes any previously existing image linked to the frame.
 
=cut
sub delete_old_images($$){
my $self = shift;
my $report = shift;
my $frame = shift;
my @images = $frame->get_elements('draw:image');
for(my $idx = 0; $idx < @images; $idx++){
my $old_link = ($images[$idx])->get_uri;
$report->del_part($old_link);
}
return;
}
 
=head4 conv_um2mm()
 
Convert a distance (with differentes units to millimeters
 
=cut
 
# See https://help.libreoffice.org/Common/Conversion_of_measurement_units
sub conv_um2mm($){
my $val_um = shift;
$val_um =~ m/^([\.\d]+)\s*(mm|cm|in|"|pi|pt)$/;
my $val = $1;
my $um = $2;
if($um eq 'mm'){
return $val_um;
}elsif($um eq 'cm'){
return $val*10;
}elsif($um eq 'in' || $um eq '"'){
return $val*25.4;
}elsif($um eq 'pi'){
return $val*25.4/6.0;
}elsif($um eq 'pt'){
return $val*25.4/72.0;
}else{
die "conv_um2mm: unknow value '$val_um'";
}
}
 
=head4 render_image()
 
Replaces the image with the content of its L<DTL tag|https://www.leader.it/MasonSQL/OdtReport#Django_Template_Language>.
 
Rendering steps:
 
=over 2
 
=item 1
 
Store the image content to a temporary file. If the image is already added to the C<Pictures> directory inside B<.odt> report file, skip all following steps.
 
=item 2
 
Detect the image mime type.
 
=item 3
 
Add the temporary image file to the C<Pictures> directory.
 
=item 4
 
Delete template images from the C<Pictures> directory.
 
=item 5
 
Add the temporary image file to the L<tmp_image_filepath|/Private Static Variables> list, to be deleted when object gets destroyed.
 
=item 6
 
Link newly created image to the existing frame. The frame size doesn't change.
 
=back
 
=cut
sub render_image($$$$){
my $self = shift;
my $report = shift;
my $img = shift;
my $image_name = shift;
my $content = shift;
my $frame = $img->get_parent;
my($frame_x,$frame_y) = $frame->get_size;
$frame_x = conv_um2mm($frame_x);
$frame_y = conv_um2mm($frame_y);
my $frame_ratio = $frame_x / $frame_y;
#DEBUG $self->say("render_image", "image_name=$image_name, content=$content");
if($content =~ m/^data:(\w+\/\w+);base64,(.+)/){
my $mime = $1;
$content = $2;
$img->set_content($content);
$content = decode_base64 $content;
}elsif(my $image_type = (Image::Info::image_type(\$content))->{file_type}){
#DEBUG $self->say("render_image", "image_type=$image_type");
$image_name .= ".".lc $image_type;
unless($self->is_in_pictures($image_name)){
my $tmp_filepath = "$self->{TmpDir}/$image_name";
open (my $tmp_fh, '>', $tmp_filepath) or die $self->err_msg("Could not open file: $tmp_filepath for writing.");
binmode $tmp_fh;
print $tmp_fh $content;
close $tmp_fh;
my $mime_type = mimetype($tmp_filepath);
#DEBUG $self->say("render_image", "mime_type=$mime_type");
$report->add_image_file($tmp_filepath, type => $mime_type);
$self->push_tmp_image($tmp_filepath);
}
my $link = "Pictures/$image_name";
$img->set_uri($link);
}else{
die $self->err_msg("Unknown image type!");
}
my($image_x, $image_y) = imgsize(\$content);
if($image_y && $image_x){
# con immagini di tipo SVG la funzione imgsize non ritorna le dimensioni
# nel caso di immagini SVG non è necessario scalare l'immagine
my $image_ratio = $image_x / $image_y;
if($image_ratio > $frame_ratio){ # image is wider
$frame_y *= $frame_ratio / $image_ratio;
}else{
$frame_x *= $image_ratio / $frame_ratio;
}
}
# The image remains confined in the frame without deformation
$frame->set_size(sprintf('%.4fmm', $frame_x), sprintf('%.4fmm', $frame_y));
return;
}
 
=head4 process_image()
 
Adds the image to the C<Pictures> directory inside the B<.odt> report file. A name of the new image is C<< <portion name>_<image name>_<number of row>.<suffix> >> . If the DTL tag is empty or the ROW_NUMBER is missing (indicates empty query) the subroutine simply removes the image frame. After initial processing of the image the image is L<rendered|/render_image()>.
 
=cut
sub process_image($$$$){
my $self = shift;
my $report = shift;
my $frame = shift;
my $portion_name = shift;
my $field_name = shift;
#DEBUG $self->say("process_image", "portion_name=$portion_name, field_name=$field_name");
if(my $row_number = $self->{dtl_context}->get("${portion_name}.ROW_NUMBER")){
my $image_name = "${portion_name}_${field_name}_$row_number";
#DEBUG $self->say("process_image", "row_number=$row_number, image_name=$image_name");
$self->delete_old_images($report, $frame);
if(my $content = $self->{dtl_context}->get("${portion_name}.$field_name")){
my $img = $frame->get_image;
$self->render_image($report, $img, $image_name, $content);
return;
}
}
$frame->delete;
return;
}
 
=head4 update_images()
 
L<Updates|/process_image()> each image, in object's headers and paragraphs, which contains a L<DTL tag|https://www.leader.it/MasonSQL/OdtReport#Django_Template_Language> in its name. The DTL tag must be in a C<< #<portion_name>.<field_name> >> form.
 
=cut
sub update_images($$){
my $self = shift;
my $report = shift;
my $object = shift;
my @texts = $object->get_headings();
push(@texts, $object->get_paragraphs());
foreach my $text_element (@texts){
foreach my $frame ($text_element->get_frames){
my $frame_name = $frame->get_name;
if($frame_name && $frame_name =~ m/^#(\w+)\.([a-zA-Z0-9_.]+)$/){
$self->process_image($report, $frame, $1, $2);
}
}
}
return;
}
 
=head3 Ordering
 
=head4 get_appendable_sequence()
 
Sorts the L<appendable|/get_odt_report_portions()> portion IDs into L<appendable_seq|/Private Variables, Global to Report Object> list, ordered according to L<ord|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> field.
 
=cut
sub get_appendable_sequence(){
my $self = shift;
#DEBUG say 'input order: '.Dumper(\%{$self->{portion}{obj_ref}});
my @appendable_seq = sort { $self->{portion}{appendable}{$a} <=> $self->{portion}{appendable}{$b} } keys %{$self->{portion}{appendable}};
$self->{appendable_seq} = \@appendable_seq;
#DEBUG say 'sort order:';
#DEBUG foreach (@appendable_seq){
#DEBUG say "$_=>$self->{portion}{order}{$_}";
#DEBUG }
return;
}
 
=head4 get_attachable_sequence()
 
Sorts the L<attachable|/get_odt_report_portions()> portion IDs into L<attachable_seq|/Private Variables, Global to Report Object> list, ordered according to L<ord|https://www.leader.it/MasonSQL/OdtReport#public.odt_report_portions_Table> field.
 
=cut
sub get_attachable_sequence(){
my $self = shift;
#DEBUG say 'input order: '.Dumper(\%{$self->{portion}{obj_ref}});
my @attachable_seq = sort { $self->{portion}{attachable}{$a} <=> $self->{portion}{attachable}{$b} } keys %{$self->{portion}{attachable}};
$self->{attachable_seq} = \@attachable_seq;
#DEBUG say 'sort order:';
#DEBUG foreach (@attachable_seq){
#DEBUG say "$_=>$self->{portion}{order}{$_}";
#DEBUG }
return;
}
 
=head3 Determing Inheritance
 
=head4 find_children()
 
Returns an ordered list of portion IDs of children portions.
It returns only portions that can be appended to the body of the report document.
 
=cut
sub find_children($){
my $self = shift;
my $father_id = shift;
my @children = ();
#DEBUG say "father_id=$father_id";
#DEBUG say "base_id=$self->{base_id}";
foreach my $child_id (@{$self->{appendable_seq}}){
if($self->{portion}{appendable}{$child_id}){
if($self->{portion}{father}{$child_id}){
if($self->{portion}{father}{$child_id} eq $father_id){
push (@children, $child_id);
}
}elsif($father_id == $self->{base_id}){
push (@children, $child_id);
}
}
}
#DEBUG say "children: ".Dumper(\@children);
return \@children;
}
 
=head3 Making Report
 
=head4 make_body()
 
Is a recursive subroutine. It is initally called from L<make_report|/make_report()> when the father ID is the base portion ID.
 
If first finds sibling portions then for each siblings then:
 
=over 2
 
=item 1
 
L<Renders|https://metacpan.org/pod/DTL::Fast#render> portion's query string.
 
=item 2
 
Makes the query.
 
=item 3
 
=over 2
 
=item a.
 
If the portion type is L<odt_section|https://www.leader.it/MasonSQL/OdtReport#odt_section_portion_type> or L<odt_file|https://www.leader.it/MasonSQL/OdtReport#odt_file_portion_type> L<makes a new section|/make_section()>.
 
=item b.
 
If the portion type is L<odt_table|https://www.leader.it/MasonSQL/OdtReport#odt_table_portion_type> L<makes a new table|/make_table()>.
 
=back
 
=back
 
The subroutine is recursively called from L<make_table|/make_table()> or from L<add_section|/add_section()>.
 
=cut
sub make_body($$$);
 
sub make_body($$$){
my $self = shift;
my $father_id = shift;
my $report = shift;
my $body = shift;
my $siblings = $self->find_children($father_id);
foreach my $id (@$siblings){
my $statement = ();
my $query = $self->truncate_blanks($self->render_string($self->{portion}{query}{$id}));
if($query){
#DEBUG $self->say("make_body", "query=[\n$query\n]");
$statement = $self->{Dbh}->prepare($query);
$statement->execute();
}
my $type = $self->{portion}{type}{$id};
if($type eq 'odt_section' || $type eq 'odt_file'){
$self->make_section($report, $body, $statement, $id);
}elsif($type eq 'odt_table'){
$self->make_table($report, $body, $statement, $id);
}
}
return;
}
 
=head4 new_report()
 
Open the base template file; Save it as a new report;
Then L<prepare the report|/prepare_report()> and return its references.
 
=cut
sub new_report($){
my $self = shift;
my $new_odt = shift;
if(my $base_template = odf_document->get($self->template_filepath($self->{base_file_name}))){
$base_template->save(target => $new_odt);
}else{
die $self->err_msg("Can't find base template file '$self->{base_file_name}'");
}
return $self->prepare_report($new_odt);
}
 
=head4 prepare_report()
 
Remove L<comments|/remove_comments()> from the entire document.
Initially L<Update images|/update_images()> only in STYLES part.
L<Render header and footer|/render_header_footer()>.
 
=cut
sub prepare_report($){
my $self = shift;
my $new_odt = shift;
my $report = odf_document->get($new_odt);
my @parts = (CONTENT, STYLES);
foreach my $part_name (@parts){
my $body = $self->get_bodypart($report, $part_name);
$self->remove_comments($body);
}
my $styles = $self->get_bodypart($report, STYLES);
$self->update_images($report, $styles);
$self->render_header_footer($report);
return ($report, $report->get_body);
}
 
=head3 Accessing Document
 
=head4 get_bodypart()
 
Gets body of the required L<part|http://search.cpan.org/~jmgdoc/ODF-lpOD-1.121/lpOD/Document.pod#Access_to_individual_document_parts> of the document.
 
=cut
sub get_bodypart($$){
my $self = shift;
my $document = shift;
my $part_name = shift;
my $content = $document->get_part($part_name);
return $content->get_body;
}
 
=head3 Accessing File System
 
=head4 unlink_files()
 
Unlinks files from the input list of filepaths.
 
=cut
sub unlink_files($){
my $self = shift;
my $list_of_files = shift;
foreach my $file (@{$list_of_files}){
unlink $file;
}
return;
}
 
=head4 template_filepath()
 
Constructs the filepath of a template file.
The root directory for the template files of the specific report is: C<< <InputFilesArchive>/public/odt_reports/<odt_report_id>/ >> directory.
A file name of the template file must contain relative path to the template root directory.
 
The subroutine also validates that:
 
=over 2
 
=item *
 
The checked filepath exists.
 
=item *
 
The checked file is not empty.
 
=item *
 
The file is accessable for reading.
 
=back
 
=cut
sub template_filepath($){
my $self = shift;
my $template_file_name = shift;
unless($self->{odt_rpt_id}){
die $self->err_msg("Uninitialized odt_rpt_id.");
}
my $dir = "$self->{InputFilesArchive}/public/odt_reports/$self->{odt_rpt_id}/";
my $filepath = realpath("$dir/$template_file_name");
unless($filepath){
die $self->err_msg("$template_file_name not present in the Template Files directory, please upload it.");
}
my $testpath = "\'$filepath\'";
if(-s $testpath){
die $self->err_msg("$template_file_name has zero size, please specify relative filepath to a valid file.");
}
if(-r $testpath){
die $self->err_msg("$template_file_name file is not readable, please enable access to the file.");
}
#DEBUG say "template_filepath=$filepath";
return $filepath;
}
 
=head4 tmp_file()
 
Uses L<File::Temp::tempfile|http://search.cpan.org/~dagolden/File-Temp-0.2304/lib/File/Temp.pm> to create a new temporary file.
If there is content it stores it to the temporary file.
Then closes the file, to make sure it is unlocked, finally returns its filepath.
 
=cut
sub tmp_file($$$$){
my $self = shift;
my $prefix = shift;
my $suffix = shift;
my $content = shift;
my($fh, $filepath) = tempfile(
$prefix . '_XXXXX',
DIR => $self->{TmpDir},
SUFFIX => $suffix,
UNLINK => 0
);
if($content){
print $fh $content;
}
close $fh;
#DEBUG say "tmp_filepath=$filepath";
return $filepath;
}
 
=head3 Error Handling
 
=head4 err_msg()
 
The subroutine formats every die message of this module so their detection is made easier.
 
=cut
sub err_msg($){
my $self = shift;
my $err_msg = shift;
return "Error: $err_msg";
}
 
=head3 Destructor
 
=head4 DEMOLISH()
 
Closes down the database connection during the object's destruction.
 
=cut
sub DEMOLISH{
my $self = shift;
$self->unlink_tmp_images();
return;
}
 
=head2 Copyright
 
(C) 2003 Leader.IT di Guido Brugnara <http://www.leader.it>
Strada della Pozzata, 41 - Villazzano
38123 T R E N T O (ITALY)
 
=head2 Authors
 
Guido Brugnara
Janez Stangelj
=cut
 
1;
/tags/2.0/lib/MasonSQL/SMS.pm
0,0 → 1,93
#!/usr/bin/perl -w
#**********************************************************************************
# Package created to work with SMS
#**********************************************************************************
package MasonSQL::SMS;
use utf8;
use strict;
use warnings;
use Data::Dumper;
use JSON;
use Encode qw(encode decode);
use Carp;
use Data::Dumper;
 
sub new {
my $class = shift;
my(%args) = @_;
my $self = { args => \%args };
bless($self, $class);
if($args{text}){
$self->text(delete $args{text});
}
return $self;
}
 
# restituisce o prepara la stringa
# codifica la stringa sostituendo i caratteri non ammessi con "?" e calcola il numero di messaggi SMS necessari alla trasmissione
# vedasi tabella codifica https://en.wikipedia.org/wiki/GSM_03.38#GSM_7-bit_default_alphabet_and_extension_table_of_3GPP_TS_23.038_/_GSM_03.38
sub text {
my($self, $str, $max_length) = @_;
if(!defined $str){
return $self->{text};
}
 
my $gsm0338 = encode('gsm0338', $str);
# Attenzione: length ritorna la lunghezza in byte, ovvero i caratteri rappresentati con ESC + codice vengono conteggiati 2
my $len = length $gsm0338;
 
# default max lenght
$max_length //= $self->{args}{max_length};
if(defined $max_length && $len > $max_length){
# taglio la stringa mettendo in fondo " ..." per far comprendere al destinatario che il messaggio è stato tagliato
$gsm0338 = substr($gsm0338, 0, $max_length -4);
# verifico se l'ultimo carattere è ESC (carattere speciale che occupa 2 byte tagliato a metà)
if(ord(substr($gsm0338, -1, 1)) == 27){
$gsm0338 = substr $gsm0338, 0, length($gsm0338) - 1;
}
$gsm0338 .= ' ...';
$len = length $gsm0338;
}
 
# Calcolo il costo del messaggio
my $cost = 1;
if($len > 160){
# numero di SMS necessari per trasmettere il messaggio
$cost = int((152+$len)/153);
}
# purtroppo encode('utf8', ...) non codifica correttamente il carattere @ (0x00) quando è seguito da un'altro \0x00 o da ESC.
# sono costretto a interpretare il carattere \0x00 separatamente ...
my $text;
while(1){
my $zpos = index $gsm0338, "\0";
if($zpos == -1){
$text .= decode('gsm0338', $gsm0338);
last;
}else{
my $left = substr $gsm0338, 0, $zpos;
$text .= decode('gsm0338', $left).'@';
$gsm0338 = substr $gsm0338, $zpos + 1;
}
length($gsm0338) || last;
}
$self->{gsm0338} = $gsm0338;
$self->{text} = $text;
$self->{cost} = $cost;
return $text;
}
 
# Ritorna il testo del messaggio codificato gsm0338
sub gsm0338 {
my $self = shift;
return $self->{gsm0338};
}
 
# Ritorna il costo dell'SMS
sub cost {
my $self = shift;
return $self->{cost};
}
 
# Ritorna o modifica
 
1;
/tags/2.0/lib/MasonSQL/Report/OdtConv.pm
0,0 → 1,164
package MasonSQL::Report::OdtConv;
 
use strict;
use warnings;
use IPC::Run;
use IPC::Run::SafeHandles;
use File::Basename;
use File::Copy qw(move);
 
##
# OdtConv class wrapper
#
# @author Rafael Goulart <rafaelgou@gmail.com>
# @see http://tech.rgou.net/
##
 
sub new {
my $class = shift;
my %rpt = @_;
return bless \%rpt, $class;
}
 
##
# Basic converter method
#
# @param string $origin_filepath Origin File Path
# @param string $output_format Format to export To
# @param string $output_filepath Output directory path
##
sub convert($$$){
my $self = shift;
my $origin_filepath = shift;
my $output_filepath = shift;
my $output_format = shift;
my ($err, $out);
if($self->{Engine} eq 'unoconv'){
my @cmd = (
'/usr/bin/unoconv',
'--format' => $output_format,
# '-e' => 'MaxImageResolution=300',
# '-e' => 'ReduceImageResolution=0',
# '-e' => 'Quality=90',
'--output' => $output_filepath,
$origin_filepath
);
#DEBUG print "cmd: ".join(' ', @cmd);
# Sometimes unoconv abort with error at startup, but if you rerun ... it work well!!!
my $count = 4;
my $timeout = 1;
while(1){
if($timeout != 1){
sleep $timeout;
}
$count--;
$timeout *= 2;
if(run(\@cmd, \undef, \$out, \$err, init => sub {
$ENV{LANG} = 'it_IT@UTF8';
$ENV{LC_NUMERIC} = 'it_IT@UTF8';
})
){
if(! -e $output_filepath || -z $output_filepath){
if($count <= 0){
die "unoconv error $? file output is empty or not exists cmd:[".(join ' ', @cmd)."] out:[$out] err:[$err]\n";
}else{
next;
}
}
if($out){
return "unoconv convert out=[\n$out]";
}
return '';
}
if($count <= 0){
die "unoconv run error $? cmd:[".(join ' ', @cmd)."] out:[$out] err:[$err]\n";
}
}
}elsif($self->{Engine} eq 'libreoffice'){
# purtroppo libreoffice non permette di generare il file con un nome diverso da quello cotituito dal nome del file .odt sostituito da .$output_format
my($odt_name, $odt_dirs, $odt_suffix) = fileparse($origin_filepath, qr/\.[^.]*/);
$odt_suffix =~s/^\.//;
my($out_name, $out_dirs, $out_suffix) = fileparse($output_filepath, qr/\.[^.]*/);
$out_suffix =~s/^\.//;
my $outdir = $odt_dirs eq $out_dirs && $out_suffix eq $output_format ? $out_dirs : $odt_dirs;
my @cmd = (
'/usr/bin/libreoffice',
'--headless',
'--convert-to' => $output_format,
'--outdir' => $outdir,
$origin_filepath
);
my $outfile = "$outdir/$odt_name.$output_format";
#DEBUG print "cmd: ".join(' ', @cmd);
# Sometimes libreoffice abort with error at startup, but if you rerun ... it work well!!!
my $count = 4;
my $timeout = 1;
while(1){
if($timeout != 1){
sleep $timeout;
}
$count--;
$timeout *= 2;
if(run(\@cmd, \undef, \$out, \$err, init => sub {
$ENV{LANG} = 'it_IT@UTF8';
$ENV{LC_NUMERIC} = 'it_IT@UTF8';
})
){
if(! -e $outfile || -z $outfile){
if($count <= 0){
die "libreoffice error $? file output $outfile is empty or not exists cmd:[".(join ' ', @cmd)."] out:[$out] err:[$err]\n";
}else{
next;
}
}
if($outfile ne $output_filepath){
move $outfile, $output_filepath || die "libreoffice move error $? from $outfile to $output_filepath\n";
}
if(! -e $output_filepath || -z $output_filepath){
if($count <= 0){
die "libreoffice error $? file moved is empty or not exists cmd:[".(join ' ', @cmd)."] out:[$out] err:[$err]\n";
}else{
next;
}
}
if($out){
return "libreoffice convert out=[\n$out]";
}
return '';
}
if($count <= 0){
die "libreoffice run error $? cmd:[".(join ' ', @cmd)."] out:[$out] err:[$err]\n";
}
}
}else{
die "OdtConv Engine '$self->{Engine}' non exists\n";
}
}
 
##
# Convert to PDF
#
# @param string $origin_filepath Origin File Path
# @param string $output_filepath Output directory path
##
sub convert_to_pdf($$){
my $self = shift;
my $origin_filepath = shift;
my $output_filepath = shift;
return $self->convert($origin_filepath, $output_filepath, 'pdf');
}
 
##
# Convert to TXT
#
# @param string $origin_filepath Origin File Path
# @param string $output_filepath Output directory path
##
sub convert_to_txt($$){
my $self = shift;
my $origin_filepath = shift;
my $output_filepath = shift;
return $self->convert($origin_filepath, $output_filepath, 'txt');
}
 
1;
/tags/2.0/lib/MasonSQL/JSONRPCUtils.pm
0,0 → 1,39
package MasonSQL::JSONRPCUtils;
 
use strict;
 
#use JSON;
use JSON -support_by_pp;
 
sub json_rpc_response{
my $content = shift || return;
 
my $json_response = {'version' => '1.1',
'result' => $content
};
return JSON::objToJson($json_response, {allow_unknown => 1, allow_blessed => 1, convert_blessed => 1});
}
 
sub json_rpc_error_response{
my $content = shift || return;
my $message = shift || return;
my $code = shift || 500;
my $timestamp = shift;
if(!$timestamp){
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
$timestamp = sprintf "%4d-%02d-%02d %02d:%02d:%02d", $year+1900,$mon+1,$mday,$hour,$min,$sec;
}
 
my $json_response = {'version' => 1.1,
'error' => {'name' => 'JSONRPCError',
'code' => $code,
'timestamp' => $timestamp,
'message' => $message,
'error' => $content
}
};
return JSON::objToJson($json_response, {allow_unknown => 1, allow_blessed => 1, convert_blessed => 1});
}
 
1;
 
/tags/2.0/lib/MasonSQL/ApacheHandler.pm
0,0 → 1,21
# Handler per la gestione customizzata degli errori di mason
package MasonSQL::ApacheHandler;
use strict;
use HTML::Mason::ApacheHandler;
# preparo
sub handler {
my $r = shift;
my $return = eval { HTML::Mason::ApacheHandler->handler($r) };
if(my $error = $@){
# l'oggetto $error viene poi utilizzato in /lib/error.comp
$r->pnotes( error => $error );
$r->filename( $r->document_root . '/lib/error.comp');
return HTML::Mason::ApacheHandler->handler($r);
}
return $return;
}
 
1;
/tags/2.0/lib/MasonSQL/CompRootHandler.pm
0,0 → 1,31
# utilizzato in Apache 1.3
#
package MasonSQL::CompRootHandler;
use strict;
use Apache::Constants qw(:common);
use Apache::File;
use DirHandle ();
 
sub handler {
my $r = shift;
# verifico se il file è presente nei percorsi definiti nell'ordine
my @MasonCompRoot = $r->dir_config->get('MasonCompRoot');
foreach my $root (@MasonCompRoot){
my($name, $dir) = split /\s*=>\s*/, $root, 2;
(defined $name) or die "Configurazione inaspettatata di MasonCompRoot '$root'\n";
if(-e $dir.$r->uri){
# se esiste il file nel percorso lo seleziono per il download
$r->filename($dir.$r->uri);
last;
}
}
my $fh = Apache::File->new($r->filename) or return FORBIDDEN;
$r->send_fd($fh);
close $fh;
return OK;
}
1;
 
__END__
/tags/2.0/lib/MasonSQL/CompRootHandler2.pm
0,0 → 1,34
# Usato in pache 2.0 e 2.2
#
package MasonSQL::CompRootHandler2;
use strict;
 
### Per Apache2spostati nel file di configurazione di Apache
#use Apache::Constants qw(:common);
#use Apache::File;
#use DirHandle ();
### Per Apache2
 
use Apache2::Const qw(FORBIDDEN OK);
 
sub handler {
my $r = shift;
# verifico se il file è presente nei percorsi definiti nell'ordine
my @MasonCompRoot = $r->dir_config->get('MasonCompRoot');
foreach my $root (@MasonCompRoot){
my($name, $dir) = split /\s*=>\s*/, $root, 2;
(defined $name) or die "Configurazione inaspettatata di MasonCompRoot '$root'\n";
if(-e $dir.$r->uri){
# se esiste il file nel percorso lo seleziono per il download
$r->filename($dir.$r->uri);
$r->sendfile($dir.$r->uri);
return OK;
}
}
return FORBIDDEN;
}
1;
 
__END__
/tags/2.0/lib/MasonSQL/JSLogger.pm
0,0 → 1,232
package MasonSQL::JSLogger;
 
use Data::Dumper;
 
use strict;
use warnings;
 
use vars qw(%LEVELS %VAL2LEVEL);
no strict qw(refs);
 
use constant ALL_INT => 0;
use constant DEBUG_INT => 10000;
use constant INFO_INT => 20000;
use constant WARN_INT => 30000;
use constant ERROR_INT => 40000;
use constant FATAL_INT => 50000;
use constant OFF_INT => (2 ** 31) - 1;
 
sub new{
my $class = shift;
my $current_level = shift;
$current_level = OFF_INT unless defined $current_level;
 
my $self = {'level' => $current_level, 'log_sub' => \&_log_level, 'code' => {}, 'to_dump' => ['init', 'log'], 'join_separator' => ''};
 
bless $self, $class;
return $self;
}
 
sub to_dump{
my $self = shift;
my $to_dump = shift;
 
unless (defined $to_dump){
return $self->{'to_dump'};
}else{
$self->{'to_dump'} = $to_dump;
}
}
 
sub join_separator{
my $self = shift;
my $separator = shift;
 
unless (defined $separator){
return $self->{'join_separator'};
}else{
$self->{'join_separator'} = $separator;
}
}
 
sub log_sub{
my $self = shift;
my $log_sub = shift;
 
if (defined $log_sub){
$self->{'log_sub'} = $log_sub;
}else{
return $self->{'log_sub'};
}
}
 
sub add_level{
my $level = shift || return;
my $value = shift;
 
return unless defined $value;
 
return if defined $LEVELS{$level} or defined $VAL2LEVEL{$value};
 
$level = uc $level;
$LEVELS{$level} = $value;
$VAL2LEVEL{$value} = $level;
*{__PACKAGE__ . "::$level"} = $value;
_create_log_level_methods($level);
}
 
sub delete_level{
my $level = shift;
 
return unless defined $level;
 
return unless is_valid($level);
return if is_predefined($level);
 
$level = lc (($level =~ m/^[0-9]+$/o) ? $VAL2LEVEL{$level} : $level);
my $uLevel = uc $level;
 
delete $VAL2LEVEL{$LEVELS{$uLevel}};
delete $LEVELS{$uLevel};
delete ${__PACKAGE__ . "::"}{"$uLevel"};
delete ${__PACKAGE__ . "::"}{"$level"};
delete ${__PACKAGE__ . "::"}{"is_$level"};
}
 
add_level('DEBUG', DEBUG_INT);
add_level('ALL', ALL_INT);
add_level('INFO', INFO_INT);
add_level('WARN', WARN_INT);
add_level('ERROR', ERROR_INT);
add_level('FATAL', FATAL_INT);
add_level('OFF', OFF_INT);
 
sub _create_log_level_methods{
my $level = shift || return;
 
my $uLevel = uc $level;
$level = lc $level;
 
*{__PACKAGE__ . "::$level"} = sub {
my $self = shift;
$self->{'log_sub'}->($self, $level, @_) if defined $LEVELS{uc $level};
};
*{__PACKAGE__ . "::is_$level"} = sub {
$_[0]->_is_level($uLevel) if defined $LEVELS{$uLevel};
};
}
 
sub is_predefined{
my $level = shift;
return unless defined $level;
 
return unless is_valid($level);
$level = ($level =~ m/^[0-9]+$/o) ? $VAL2LEVEL{$level} : uc $level;
return $level =~ m/^ALL|DEBUG|INFO|WARN|ERROR|FATAL|OFF$/o;
}
 
sub is_valid{
my $level = shift;
 
return unless defined $level;
 
$level = uc $level;
 
if ($level =~ m/[A-Z]+/o){
return defined $LEVELS{$level};
}else{
return defined $VAL2LEVEL{$level};
}
}
 
sub set_code{
my $self = shift;
my $codes = shift || return;
 
for my $code (keys %$codes){
unless ($codes->{$code}){
delete $self->{'code'}{lc $code} if defined $self->{'code'}{lc $code};
}else{
$self->{'code'}{lc $code} = $codes->{$code};
}
}
}
 
sub init_code{
my $self = shift;
my $types = shift || return;
my $toSubstitute = shift || return;
my $uSubs = "";
my $sRegex;
 
for my $subs (keys %{$toSubstitute}){
$uSubs = uc $subs;
$sRegex = qr/#$uSubs#/;
 
for my $type (@$types){
$type = lc $type;
 
if (defined $self->{'code'}{$type}){
$self->{'code'}{$type} =~ s/$sRegex/$toSubstitute->{$subs}/g;
}
}
}
}
 
sub dump_code{
my $self = shift;
my $types = shift || return;
my $toSubstitute = shift || return;
my $code = "";
my $uSubs = "";
 
 
for my $type (@$types){
$type = lc $type;
$code .= $self->{'code'}{$type} || "";
}
 
return "" if $code eq '';
 
for my $subs (keys %{$toSubstitute}){
$uSubs = uc $subs;
$code =~ s/#$uSubs#/$toSubstitute->{$subs}/g;
}
return $code;
}
 
sub _log_level{
my $self = shift;
my $level = shift || return;
 
if (&{__PACKAGE__ . "::is_$level"}($self)){
my $msgarr = [map { (ref $_ eq "CODE") ? $_->() : $_ } @_];
my $msg = join($self->{'join_separator'}, @$msgarr);
 
$msg =~ s/</&lt;/go;
 
$self->dump_code($self->{'to_dump'}, {'level' => $level, 'msg' => $msg});
}
}
 
sub _is_level{
my $self = shift;
my $level = shift || return;
return $self->{'level'} <= $LEVELS{$level};
}
 
sub level{
my $class = shift;
my $level = shift;
 
if (defined $level){
$class->{'level'} = ($level =~ m/^[0-9]+$/o) ? $level : $LEVELS{uc $level} if is_valid($level);
}else{
return $class->{'level'};
}
}
 
1;
 
/tags/2.0/etc/apache2.masonsql.conf
0,0 → 1,442
# ---------------------------------------------------------------------- #
# Copyright:2002-2010 Leader.IT di Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
# ---------------------------------------------------------------------- #
 
# Configurazione apache2 framework MasonSQL
 
DocumentRoot /opt/masonsql/htdocs/
 
# Mod_perl ...
 
PerlSwitches -w
PerlOptions +GlobalRequest
 
DefaultType text/html
AddDefaultCharset UTF-8
 
# Dojo Toolkit
PerlSetVar DojoDirUrl "/lib/dojo-release-1.13.0"
PerlSetVar DojoDirUrlDebug "/lib/dojo-release-1.13.0-src"
 
# HTML 5
PerlSetVar HtmlDocType '<!DOCTYPE HTML>'
 
# reportman http://reportman.sourceforge.net
# percorso per l'esecuzione del programma di creazione dei report di stampa
PerlSetVar ReportmanDir /opt/masonsql/report
# Connessione al database se si utilizza ADO (disabilitare ponendo ReportmanADOserver "0")
PerlSetVar ReportmanADOserver "127.0.0.1"
PerlSetVar ReportmanADOdatabase "masonsql"
PerlSetVar ReportmanADOuser "report"
PerlSetVar ReportmanADOpassword "<password>"
 
# Report engine (pdf|odt|rep)
PerlSetVar DefaultReportEngine "pdf"
 
# ODT conversion engine (libreoffice|unoconv)
PerlSetVar OdtConvEngine "libreoffice"
 
# Filtro l'input dei campi testo sostituendo i caratteri UTF multibyte con ? e mostrando un avviso ("0" se disabilitato)
PerlSetVar InputStringNoLongUTF "0"
 
# Archivio per allegati
PerlSetVar InputFilesArchive "/opt/masonsql/archive"
 
# Cartella TMP
PerlSetVar TmpDir /opt/masonsql/tmp
# Cartella Log
PerlSetVar LogDir /opt/masonsql/log
 
# Mason ...
 
<Perl>
use CGI qw(-private_tempfiles);
$CGI::TempFile::TMPDIRECTORY = '/opt/masonsql/tmp';
# set locale 'C' per i numeri
### DA SISTEMARE!!!
# use POSIX qw(locale_h);
# setlocale(LC_NUMERIC, 'C');
### DA SISTEMARE!!!
 
# enable extended warnings logged in the error_log file
# use Carp (); $SIG{__WARN__} = \&Carp::cluck;
# disable error log in Apache log file
$SIG{__WARN__} = sub {};
# percordo di ricerca dei package
use lib '/opt/masonsql/lib';
use DirHandle ();
</Perl>
 
# Configurazione cache (richiede package "libchi-perl" o modulo Perl "CHI")
PerlSetVar MasonDataCacheApi "chi"
PerlSetVar MasonDataCacheDefaults "{driver => 'FastMmap'}"
 
# Attivo la cache del componente /frames.html
#PerlSetVar CacheFramesExpiration "18 hours"
#PerlSetVar CacheFramesExpiration "999 years"
# Disabilitata
PerlSetVar CacheFramesExpiration "0"
 
PerlSetVar MasonPreamble "use utf8;"
PerlAddVar MasonPlugins "MasonX::Plugin::UTF8"
PerlSetVar MasonArgsMethod mod_perl
 
PerlModule JSON::XS;
PerlModule JSON;
PerlModule ModPerl::Registry
PerlModule Apache2::Request
PerlModule Apache2::Status
PerlModule Apache2::RequestRec
PerlModule Apache2::RequestIO
PerlModule Apache2::ServerUtil
PerlModule Apache2::RequestUtil
PerlModule Apache2::Log
PerlModule Apache2::Directive
PerlModule Apache2::Const
PerlModule APR::Table
PerlModule Apache2::SubRequest
PerlModule Apache2::Upload
PerlModule Apache2::AuthCookie
PerlModule Apache2_4::AuthCookie
PerlModule Apache::DBI
PerlModule Data::Dumper
PerlModule XML::Simple
 
PerlModule Auth_AC::AuthCookieHandler
# Inclusione di un modulo per la gestione dei messaggi conformi (il piu' possibile) allo standard.
PerlModule MasonSQL::JSONRPCUtils
 
PerlModule MasonSQL::CompRootHandler2
PerlModule MasonSQL::ApacheHandler
 
# cartella dove posizionare i log
PerlSetVar LogBaseDir /var/log/apache2/
# Livelli di Log: OFF, FATAL, ERROR, WARN, INFO, DEBUG, ALL
# Livello di log lato server
PerlSetVar PLogLevel INFO
# Livello di log lato client
PerlSetVar JSLogLevel OFF
# Layout nei log
PerlSetVar PLogPatternLayout "[%d] - %p - %F:%L %m%n"
 
PerlSetVar MasonDataDir /opt/masonsql/mason
# Necessario per evitare che Mason preformatti l'errore ritornato in conseguenza di un die
PerlSetVar MasonErrorMode fatal
PerlSetVar DataBaseUrl /data
# Default schema in database (default on PostgreSQL)
PerlSetVar DefaultSchema public
# Massimo numero di righe in una chiamata al recordset
PerlSetVar MaxRetrieveRows 65536
# Timeout (msec) ricezione della risposta alle operazioni di gestione del recordset
PerlSetVar GetRecordTimeout 10000
# Intervallo (msec) per il rinnovo della connessione al server (se 0 è disabilitato)
PerlSetVar CheckSessionInterval 600000
# se 1 utilizza (key=1 or k=2 ...) altrimenti utilizza (key in (1,2,...))
PerlSetVar SqlWhereKeyListOr 0
PerlSetVar GetFormTimeout 15000
PerlSetVar USEpgstattuple 0
#PerlSetVar PrintNextValQuery "select nextval('public.report_id_seq')"
 
PerlSetVar MasonAllowGlobals $DEBUG
# database handler
PerlAddVar MasonAllowGlobals %Session
PerlAddVar MasonAllowGlobals $Ver
PerlAddVar MasonAllowGlobals %Global
PerlAddVar MasonAllowGlobals @Script_buffer
PerlAddVar MasonAllowGlobals %SQL
 
PerlModule MasonSQL::Escapes
PerlSetVar MasonEscapeFlags "xml => \&MasonSQL::Escapes::xml_escape"
PerlAddVar MasonEscapeFlags "js => \&MasonSQL::Escapes::js_escape"
PerlAddVar MasonEscapeFlags "textarea => \&MasonSQL::Escapes::textarea_escape"
PerlAddVar MasonEscapeFlags "multi => \&MasonSQL::Escapes::multi_escape"
 
PerlModule Safe
PerlModule HTML::Mason
#PerlModule CGI
#PerlModule Archive::Zip
 
# Caratteri minimi per la password
# N.B. dal 1°gen2004 il Codice sulla Privacy impone almeno 8 caratteri
PerlSetVar MinPasswordChars 8
# Scadenza password (in giorni)
PerlSetVar MaxPasswordDays 180
# Blocco accesso per inattività
PerlSetVar MaxPasswordInactivity 180
 
# Comportamento componente String.comp nell'eliminazione dei caratteri "blank" dopo la modifica del campo
# se il parametro non viene eslicitamente indicato. Possibili valori: Right|Left|All Se non dichiarato
# non viene applicato
#PerlSetVar String_TrimDefault "All"
 
# Se 1 Nella navigazione delle tabelle, saltando di pagina in pagina,
# nell'ultima verrà mostrato l'ultimo record in fondo alla tabella
PerlSetVar LastUpAsForward 0
 
PerlSetVar Auth_AC_Path /
 
# Tempo di inattività (minuti) dopo la quale la sessione scade
PerlSetVar Auth_InactivityMax 240
# Scadenza dei cookie autenticazione
PerlSetVar Auth_AC_SessionTimeout +4h
PerlSetVar Auth_AC_Expires +4h
 
# Protegge il token di autenticazione dall'essere visivile da Javascript (se il browser implementa questa limitazione)
PerlSetVar Auth_AC_HttpOnly 1
# Autenticazione solo da connessione HTTPS
PerlSetVar Auth_AC_Secure 1
 
PerlSetVar Auth_AC_LoginScript /AuthCookieLoginForm.html
PerlAddAuthzProvider dwarf Auth_AC::AuthCookieHandler->dwarf
PerlAddAuthzProvider myuser Auth_AC::AuthCookieHandler->authz_handler
PerlSetVar AuthCookieDebug 0
PerlSetVar Auth_AC_bad_credentials_message "L'accesso a questo sito &egrave; stato negato. (bad_credentials).<br>Si prega di inserire nome e password:"
PerlSetVar Auth_AC_no_cookie_message "Si prega di inserire nome e password:"
# se 1 forza sempre la login
PerlSetVar Auth_AC_force_login 0
# Tempo di attesa (in msec) prima di mostrare il tooltip nei widget
PerlSetVar TooltipDelay 800
 
PerlSetVar CopyrightMessage "Copyright (&copy;) Guido Brugnara <gdo@leader.it><br>License: Affero G.P.L. rel.1"
PerlSetVar ApplicationName masonsql
PerlSetVar ApplicationTitle "MasonSql framework"
 
# nome dell'agent che verrà mostrato al server SMTP
PerlSetVar MailXMailer "MasonSql"
# E-mail mittente di sistema
PerlSetVar MailFrom "no-reply@masonsql"
# server di destinazione della posta
PerlSetVar MailSmtpServer "localhost"
# Porta del servizio SMTP da contattare
PerlSetVar MailPortServer "25"
# Numero massimo di mail trasmesse per collegamento al server SMTP
PerlSetVar MailMax4Connection "100"
# Mantiene la connessione aperta quando trasmette più messaggi
PerlSetVar MailSmtpKeepConnection "0"
# DEBUG: se configurata, forza tutte le mail generate dal framework verso questo indirizzo
# PerlSetVar MailForceTo "debug@mydomain"
# Tipo di autenticazione (PLAIN, ...)
PerlSetVar AuthType "PLAIN"
# Utente per autenticazione SMTP
PerlSetVar MailAuthid "userauth@dominio"
# Password autenticazione SMTP
PerlSetVar MailAuthpwd "*********"
 
# nome dell'agent che verrà mostrato al server HTTP del servizio di invio SMS
PerlSetVar SMSagent "MasonSql"
# SMSPlatform: piattaforma che identifica il protocollo usato dal fornitore del servizio SMS
# attualmente sono supportati "SMStrend.it" e "Comilio.it"
PerlSetVar SMSPlatform "0"
# SMSfrom: massimo 16 caratteri numerici per un numero di telefono in formato internazionale oppure 11 caratteri
# alfanumerici per una stringa di testo (Es: "+123456789012345" oppure "Azienda_Spa").
PerlSetVar SMSfrom "MasonSql"
# Lunghezza massima del messaggio (con 160 si ha la trasmissione di un solo SMS, altrimenti un SMS ogni 153 caratteri)
PerlSetVar SMSmaxLength 160
# SMSurl: indirizzo del server fornitore del servizio per l'invio di messaggi SMS
PerlSetVar SMSurl "https://www.smstrend.net/Trend"
# Prefisso internazionale da aggiungere ai n° di cellulare che ne fossero sprovvisti (codice del paese a due cifre)
PerlSetVar SMSNationPrefix "39"
# Utente dell'abbonamento al servizio
PerlSetVar SMSAuthid "myuserauth@dominio"
# Passord di accesso al servizio
PerlSetVar SMSAuthpwd "********"
# Abilita(1)/Disabilita(0) l'invio di SMS quando il mittente corrisponde al destinatario
PerlSetVar SMSsendToHimself "0"
 
# Caricamento modulo che gestisce il logger JS.
PerlModule MasonSQL::JSLogger;
PerlAddVar MasonAllowGlobals $PLogger
PerlAddVar MasonAllowGlobals $JSLogger
 
PerlModule SQL::Dialects::ANSI
 
# Widget Files.comp
# Nome della cartella su disco del cestino (senza il punto iniziale)
# Attenzione: vanno modificati i nomi delle cartelle cestino esistenti!
PerlSetVar Files_Trash_dir "Trash"
# Nome del cestino da mostrare nel widget
PerlSetVar Files_Trash_name "Cestino"
 
################################################################################################
### Nuove informazioni di registrazione utente
################################################################################################
# Registrazione Utente abilitato / disabilitato
# [enable] : Attivare la funzione di registrazione di auto
# [disable] : Disattivare la funzione di registrazione di auto
PerlSetVar UserRegistration "enable"
# reimpostazione della password di abilitazione / disabilitazione.
# [enable] : Attivare la funzione di reimpostazione password
# [disable] : funzione di reset della password Disabilitare
PerlSetVar UserPasswordReset "enable"
# Utente tipo di registrazione
# [syslogin] : Molteplici login ID univoco può essere associato a singola e-mail id
# [email] : Unico id-mail verrà utilizzato come ID di accesso
PerlSetVar LoginType "syslogin"
# Registrazione Utente nome del gruppo predefinito
# [Guest] : il nome del gruppo valido verrà assegnata al nuovo utente registrato
# [Admins] : il nome del gruppo valido verrà assegnata al nuovo utente registrato
PerlSetVar NewUserRegisterGroup "Guest"
# Tipo di notifica per l'utente
# [email] : email di notifica verrà inviata se è stato dato valido e-mail id.
# [sms] : sms di notifica verrà inviata se è stato dato sms valido.
PerlSetVar UserRegTypeMessage "email"
# Utente registrato modello di password casuali
# c Qualsiasi carattere minuscolo Latina [a-z]
# C Qualsiasi carattere maiuscolo latino [A-Z]
# n Qualsiasi cifre [0-9]
# ! Un carattere di punteggiatura [~`!@$%^&*()-_+={}[]|\:;"'.<>?/#,]
# . Qualsiasi dei precedenti
# s Un personaggio "sale" [A-Za-z0-9./]
# b Qualsiasi dati binari
PerlSetVar PasswordRandPattern "Cccsssnn"
# Il tempo massimo per la nuova conferma dell'utente in giorni
# [days] number of days in digits (ie 7, 15, 30, 60)
PerlSetVar MaxTimeToConfirmUserRegistration 7
# reCaptcha Google chiavi API registrati
# 1. registrare il tuo dominio per le chiavi API reCAPTCHA (https://www.google.com/recaptcha/admin)
# 2. Impostare la chiave del sito e la chiave segreta sotto
PerlSetVar ReCaptchaAPISecretKey 'YOUR-REGISTERED-SECRET-KEY'
PerlSetVar ReCaptchaAPISiteKey 'YOUR-REGISTERED-SITE-KEY'
# List of active optional fields (fields defined in table public.anagrafiche).
# Available fields: cell_sms codice_fiscale descrizione indirizzo provincia citta tele1 tele2
# PerlSetVar UserRegOptionalFields 'descrizione indirizzo'
#
################################################################################################
<Directory "/srv/www/icons">
Options -Indexes -MultiViews
Require all granted
SetHandler default-handler
</Directory>
 
# autenticazione Auth_AC::AuthCookieHandler
 
<Location /AuthCookieLoginForm.html >
Require all granted
Satisfy Any
</Location>
 
<Location /AuthCookieLoginSubmit >
AuthType Auth_AC::AuthCookieHandler
AuthName Auth_AC_
SetHandler perl-script
Require all granted
PerlResponseHandler Auth_AC::AuthCookieHandler->login
</Location>
# link accessibili senza autorizzazione
<LocationMatch ^(/AuthCookieLoginSubmit|/UpiPrinterServer.txt|/css/|/favicon.ico|/img/icon.ico|/UserRegistration|/UserPasswordResetForm)>
Require all granted
Satisfy Any
</LocationMatch>
 
# link accessibili con autenticazione Auth_AC::AuthCookieHandler
<LocationMatch "^/" >
DirectoryIndex index.html
Options +Indexes -MultiViews
AuthType Auth_AC::AuthCookieHandler
AuthName Auth_AC_
PerlAuthenHandler Auth_AC::AuthCookieHandler->authenticate
Require valid-user
</LocationMatch>
 
# link accessibili con autenticazione basic
<LocationMatch "^/dbms/{0,1}" >
PerlAuthenHandler Auth_AC::AuthBasicHandler
AuthType basic
AuthName "MasonSQL Authentication"
Require valid-user
SetOutputFilter DEFLATE
SetHandler perl-script
PerlHandler MasonSQL::ApacheHandler
</LocationMatch>
 
# link interfaccia CRUD (rest)
<LocationMatch "^/rest/{0,1}" >
SetOutputFilter DEFLATE
SetHandler perl-script
PerlHandler MasonSQL::ApacheHandler
</LocationMatch>
 
# GDO TEST BEGIN
<LocationMatch "^/test/dojo/test_dojo_tree_data/" >
Options Indexes
DirectoryIndex dhandler
SetHandler perl-script
PerlHandler MasonSQL::ApacheHandler
</LocationMatch>
 
# GDO TEST END
 
<Location />
Options -Indexes -MultiViews
</Location>
 
<LocationMatch "(\.ico|\.gif|\.jpg|\.png|\.jpeg)$" >
SetHandler perl-script
PerlHandler MasonSQL::CompRootHandler2
</LocationMatch>
 
<LocationMatch "(\.mql|\.xml|\.xsd|\.mason|\.html|\.txt|\.css|\.js|\.xls)$" >
SetOutputFilter DEFLATE
SetHandler perl-script
PerlHandler MasonSQL::ApacheHandler
</LocationMatch>
 
<LocationMatch "(\.m7m|\.pdf|\.zip)$" >
SetHandler perl-script
PerlHandler MasonSQL::ApacheHandler
</LocationMatch>
 
<LocationMatch "(\.mas|\.pm|handler|\.comp|^CVS|\.svn|\.META|~)$" >
SetHandler perl-script
PerlHandler "sub { use Apache2::Const qw(HTTP_NOT_FOUND); return Apache2::Const::HTTP_NOT_FOUND }"
</LocationMatch>
 
<LocationMatch "^/archive/" >
Options Indexes
DirectoryIndex dhandler
SetHandler perl-script
PerlHandler MasonSQL::ApacheHandler
</LocationMatch>
 
# escludo la cartella del componente dall'essere interpretata da Mason
<Location /lib/FCKeditor >
SetHandler default-handler
Options Indexes MultiViews
</Location>
 
# escludo le cartelle di Dojo Toolkit dall'essere interpretate da Mason e dalla necessità dell'utente
<LocationMatch "^/lib/dojo-release-">
SetHandler default-handler
Options Indexes MultiViews
Require all granted
Satisfy Any
</LocationMatch>
 
# escludo le cartelle di firebug-lite dall'essere interpretate da Mason
<LocationMatch "^/lib/firebug-lite">
SetHandler default-handler
Options Indexes MultiViews
</LocationMatch>
 
<LocationMatch ^(/logo.png)>
Require all granted
Satisfy Any
</LocationMatch>
 
# ... END Mason.
 
<Files ~ "^\.ht">
Require all denied
</Files>
 
# End.
/tags/2.0/etc/unoconvd
0,0 → 1,46
#!/bin/sh
### BEGIN INIT INFO
# Provides: unoconvd
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 5
# Default-Stop:
# Description: unoconvd - Converting documents to PDF by unoconv
### END INIT INFO
 
set -e
. /lib/lsb/init-functions
 
NAME="unoconv"
DAEMON="/usr/bin/unoconv"
DAEMON_ARGS="--listener"
PIDFILE=/var/run/$NAME.pid
USER="www-data"
GROUP="www-data"
 
test -x $DAEMON || exit 0
 
case "$1" in
start)
log_daemon_msg "Starting $NAME server" $NAME
start-stop-daemon --start --quiet --chuid $USER:$GROUP --background --exec $DAEMON --name $NAME -- $DAEMON_ARGS
pgrep -f 'python[1-9]* /usr/bin/unoconv --listener' >$PIDFILE
;;
stop)
log_daemon_msg "Stopping $NAME server" $NAME
start-stop-daemon --stop --quiet --user $USER --group $GROUP --pidfile $PIDFILE
;;
status)
status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
;;
restart)
$0 stop
sleep 1
$0 start
sleep 1
;;
*)
log_success_msg "Usage: $0 {start|stop|restart|status}"
exit 1
;;
esac
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/bin/cronjobs
0,0 → 1,586
#!/usr/bin/perl
# ---------------------------------------------------------------------- #
# Copyright: (C) 2012 Guido Brugnara <http://www.leader.it>
# Strada della Pozzata,41
# 38123 T R E N T O (ITALY)
# Authors: Guido Brugnara <gdo@leader.it>
#
# $Revision: $ info@leader.it
#
# Dual Licence:
# Affero G.P.L. Version 1, 03-2002 http://www.affero.org/oagpl.html
# Comercial - call for details <gdo@leader.it>
# ---------------------------------------------------------------------- #
 
# eseguito periodicamente da cron (vedi file /etc/crontab)
#
# * * * * * www-data /opt/masonsql/bin/cronjobs <file di configurazione>
#
# provvede all'invio dei messaggi email e sms in coda
 
 
use strict;
use Sys::RunAlone silent => 1; # mi assicuro che un solo script sia in esecuzione
use utf8;
use Encode;
use Carp;
binmode STDOUT, ':utf8';
use Data::Dumper;
use DBI;
use POSIX ();
use File::MimeInfo::Magic;
use IO::Scalar;
use lib '/opt/masonsql/lib';
 
# global variables
# [$execTime] timestamp quando eseguire il processo in formato HHMM vale a dire (0005, 0945, 1600 è pari a 12:05, 09:45, 16:00 PM)
my $execTime = ['0005'];
 
# file di configurazione dell'applicazione
my $file_conf = $ARGV[0] || die "Manca il parametro del nome del file di configurazione\n";
 
sub read_config($){
my $file_conf = shift;
# lettura dei parametri di configurazione
open my $file_params, "<$file_conf";
my %params;
while(<$file_params>){
chomp;
if(m/^\s*Include\s+(.*)\s*$/){
my $file = $1;
if($file =~ m/^"(.*)"$/){
$file = $1;
$file =~ s/""/"/gs;
}
%params = (%params, &read_config($file));
}elsif(m/^\s*PerlSetVar\s+([\w_]+)\s+(.*)\s*$/){
my $name = $1;
my $str = $2;
if($str =~ m/^"(.*)"$/){
$str = $1;
$str =~ s/""/"/gs;
}
$params{$name} = $str
}
}
close $file_params;
return %params;
}
 
my %params = read_config($file_conf);
 
use MasonSQL::SMS;
my $SMS = new MasonSQL::SMS( max_length => $params{SMSmaxLength} );
 
# autenticazione DBI
# 'DBIconnect' => 'dbi:Pg:dbname=DBMS;user=USER;password=******',
if($params{DBIconnect} !~ m/(.*);\s*user=(.*);\s*password=(.*)$/){
die "Param DBIconnect malformed\n";
}
my $dbh = DBI->connect($1, $2, $3)
or die "Cannot connect to database $1\n$DBI::errstr\n";
$dbh->{pg_enable_utf8} = 1;
$dbh->{RaiseError} = 1;
$dbh->{ShowErrorStatement} = 1;
# necessario per i database e client >=7.3 e successivi in quanto si utilizzano "prepare" di query multiple
$dbh->{'pg_server_prepare'} = 0;
$dbh->do(q{
set client_encoding TO 'UTF-8';
set DateStyle to 'SQL, EUROPEAN';
});
$dbh->{AutoCommit} = 1;
 
#--------------------------------------------------------------------------- EMAIL
if($params{MailSmtpServer}){
#use Net::SMTP;
{ # new Nov 17, 2016 - rel 0.903 is DEPRECATED!
no warnings qw(deprecated);
use Mail::Sender;
}
$Mail::Sender::NO_X_MAILER = 1;
my $countMail = 0;
my $sender;
my $paramsSender = {
#debug => \*STDERR,
#debug_level => 4,
client => $params{Auth_AC_Domain} || `hostname -f`,
from => encode('MIME-Header', $params{MailFrom}),
smtp => $params{MailSmtpServer},
port => $params{MailPortServer},
auth => $params{AuthType} eq 'NONE' ? undef : uc $params{AuthType},
authid => $params{MailAuthid},
authpwd => $params{MailAuthpwd},
keepconnection => $params{MailSmtpKeepConnection} || 0,
on_errors => 'code'
};
 
# aggiornamento messaggi di posta elettronica elaborati
my $sth_email_message = $dbh->prepare(q{
update public.messages_users
set email_result = $1,
log = CASE WHEN log is null THEN 'MAIL ' || $1 ELSE log || E'\nMAIL ' || $1 END
where id = $2
});
# verifico se ci sono messaggi da inviare per posta elettronica
my $sth_messages = $dbh->prepare(q{
select
messages.id as messages_id,
messages_users.id,
messages.subject,
CASE
WHEN messages_users.user_message is not null THEN messages_users.user_message
WHEN messages_users.user_short_message is not null THEN messages_users.user_short_message
WHEN messages.message is not null THEN messages.message
ELSE messages.short_message
END as body,
anagrafiche.nome as nome_to,
anagrafiche.cognome as cognome_to,
anagrafiche.email as email_to,
coalesce(owner.nome, 'Gestore del sistema') as nome_from,
owner.cognome as cognome_from,
owner.email as email_from
from public.messages_users
inner join public.messages on messages.id = messages_users.id_messages
inner join public.anagrafiche on anagrafiche.id = messages_users.id_anagrafiche
left join public.anagrafiche owner on owner.id = messages.owner
where messages.transmission_time is not null
and messages.email
and messages_users.notification_time is null
and ( messages_users.email_result is null
or messages_users.email_result ~* E'ERR - [^\\d]*4\\d\\d[^\\d^\\w]'
)
order by messages_users.id;
});
$sth_messages->execute;
while(my $message = $sth_messages->fetchrow_hashref){
#DEBUG print Dumper($message);
my $email_result;
if($message->{'email_to'}){
if($params{MailMax4Connection} && $countMail >= $params{MailMax4Connection}){
$countMail = 0;
# chiudo la connessione al server SMTP
$sender->Close(1);
$sender = undef;
}
if(!ref $sender){
$sender = new Mail::Sender($paramsSender);
if(!ref $sender){
die 'ERROR TO CREATE MAIL CONNECTION: '.$Mail::Sender::Error,"\n";
}
}
my $ContentType = mimetype(new IO::Scalar \$message->{'body'});
my $mailto = $params{MailForceTo}
? encode('MIME-Header', qq|"$message->{'nome_to'} $message->{'cognome_to'} force to"|)." <$params{MailForceTo}>"
: encode('MIME-Header', qq|"$message->{'nome_to'} $message->{'cognome_to'}"|)." <$message->{'email_to'}>";
$sender->Body({
charset => 'UTF-8',
encoding => '8BIT',
ctype => $ContentType
});
my $From = encode('MIME-Header', qq|"Per conto di $message->{'nome_from'} $message->{'cognome_from'}"|)." <$params{MailFrom}>";
my %headers = (
'Sender' => $From,
'X-Mailer' => "$params{MailXMailer} $message->{'messages_id'}-$message->{'id'}"
);
if($message->{'email_from'}){
$headers{'Reply-To'} = encode('MIME-Header', qq|"$message->{'nome_from'} $message->{'cognome_from'}"|)." <$message->{'email_from'}>";
}
$sender->MailMsg({
subject => encode('MIME-Header', $params{MailForceTo} ? $message->{'id'}.' '.$message->{'subject'} : $message->{'subject'}),
from => $From,
to => $mailto,
msg => encode('utf8', $message->{'body'}),
headers => \%headers
});
$email_result = $sender->{'error'} ? "ERR - $sender->{'error_msg'} ($sender->{'error'})" : 'OK - Inviato';
$sender->ClearErrors();
$countMail++;
}else{
$email_result = 'KO - No mail address';
}
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
my $datetime = sprintf '%02i/%02i/%04i %02i:%02i:%02i', $mday, $mon+1, $year+1900, $hour, $min, $sec;
#DEBUG die "$countMail++: $email_result il $datetime\n";
$sth_email_message->execute("$email_result il $datetime", $message->{'id'});
} # while message di posta elettronica
if($sender){
$sender->Close(1);
$sender = undef;
}
} # if($params{MailSmtpServer}){
 
#--------------------------------------------------------------------------- SMS
if($params{SMSPlatform}){
use JSON;
use LWP::UserAgent;
use HTTP::Request;
use HTTP::Request::Common;
use HTTP::Request::JSON;
my $SMSagent = LWP::UserAgent->new(
agent => $params{SMSagent}
);
$SMSagent->timeout($params{SMStimeout} || 10);
# query aggiornamento stato
my $sth_sms_message = $dbh->prepare(q{
update public.messages_users
set sms_result = $1,
log = CASE WHEN log IS NULL THEN 'SMS ' || $1 ELSE log || E'\nSMS ' || $1 END,
sms_cost = CASE WHEN $2::smallint IS NULL THEN sms_cost WHEN $2::smallint = 0 THEN NULL ELSE $2::smallint END
where id = $3
});
 
# pulisce un documento HTML dai tab
sub clean_html($){
$_ = shift;
s/\n+/ /gs;
s/\<\/[\w+]+\>/; /isg;
s/\<[\w+]+\>/ /isg;
s/\s+/ /gs;
s/\s;/;/gs;
s/^\s+|;*\s*$//gs;
s/;+/;/gs;
return $_;
}
 
#---------------------------------- SMS STATUS
my $sth_messages = $dbh->prepare(q{
select
messages_users.id,
sms_result
from public.messages_users
inner join public.messages on messages.id = messages_users.id_messages
where messages.sms and substr(sms_result::text, 1, 3) = 'SMS' -- use index messages_users_sms_result
order by messages_users.id;
});
$sth_messages->execute;
while(my $message = $sth_messages->fetchrow_hashref){
my $message_id = $message->{'id'};
if(lc $params{SMSPlatform} eq 'comilio.it'){
my($sms, $old_status, $old_date, $old_time, $sms_id, $old_description) = split /\s/, $message->{'sms_result'}, 6;
# get message status
# eg. SMS|TOSERVER|2018-01-31|12:00:00|F9BC589E9F2140F1BFA34D825C962F40|messaggio inviato al server
my $http_req = HTTP::Request->new(GET => $params{SMSurl}."/message/$sms_id");
$http_req->authorization_basic($params{SMSAuthid}, $params{SMSAuthpwd});
my $response = $SMSagent->request($http_req);
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
my $datetime = sprintf '%02i/%02i/%04i %02i:%02i:%02i', $mday, $mon+1, $year+1900, $hour, $min, $sec;
my $json_response = eval { from_json $response->content };
if($response->is_error){
if($json_response && exists $json_response->{error}){
$sth_sms_message->execute("ERR - ERROR $datetime $sms_id $json_response->{error}", undef, $message_id);
}else{
$sth_sms_message->execute("ERR - HTTP $datetime $sms_id (".$response->code.') '.clean_html($response->error_as_HTML), undef, $message_id);
}
}else{
if(!defined $json_response || !defined $json_response->[0]->{status}){
$sth_sms_message->execute("ERR - JSON $datetime $sms_id (".$response->content.') ', undef, $message_id);
}else{
my $status = $json_response->[0]->{status};
if(ref($json_response) eq 'ARRAY' and length(@{$json_response}) == 0){
$status = 'Deleted';
}
if($json_response->[0]->{deliver_timestamp}){
my ($sec,$min,$hour,$mday,$mon,$year) = localtime $json_response->[0]->{deliver_timestamp};
$datetime = sprintf '%02i/%02i/%04i %02i:%02i:%02i', $mday, $mon+1, $year+1900, $hour, $min, $sec;
}
if($status eq 'Deleted'){
$sth_sms_message->execute("ERR - DELETED $datetime $sms_id messaggio non presente nel database del gestore", undef, $message_id);
}elsif($status eq 'Scheduled'){
$sth_sms_message->execute("SMS SCHEDULED $datetime $sms_id messaggio pianificato per l'invio, non ancora inviato", undef, $message_id);
}elsif($status eq 'Enqueued'){
$sth_sms_message->execute("SMS ENQUEUED $datetime $sms_id messaggio in attesa di invio", undef, $message_id);
}elsif($status eq 'Sent'){
$sth_sms_message->execute("OK - SENT $datetime $sms_id messaggio inviato senza notifica di ricezione", undef, $message_id);
}elsif($status eq 'Delivering'){
$sth_sms_message->execute("SMS DELIVERING $datetime $sms_id messaggio inviato in attesa di notifica di ricezione", undef, $message_id);
}elsif($status eq 'Delivered'){
$sth_sms_message->execute("OK - DELIVERED $datetime $sms_id messaggio inviato e ricezione notificata", undef, $message_id);
}elsif($status eq 'ErrorGeneric'){
$sth_sms_message->execute("ERR - GENERIC $datetime $sms_id errore di invio", undef, $message_id);
}elsif($status eq 'ErrorPrefix'){
$sth_sms_message->execute("ERR - PREFIX $datetime $sms_id errore nel prefisso del destinatario", undef, $message_id);
}elsif($status eq 'ErrorRecipient'){
$sth_sms_message->execute("ERR - RECIPIENT $datetime $sms_id errore nel numero del destinatario", undef, $message_id);
}elsif($status eq 'FloodRecipient'){
$sth_sms_message->execute("ERR - FLOOD_RECIPIENT $datetime $sms_id non inviato per flooding ai danni di un destinatario", undef, $message_id);
}elsif($status eq 'FloodUser'){
$sth_sms_message->execute("ERR - FLOOD_USER $datetime $sms_id non inviato per flooding causato dall'utente Comilio", undef, $message_id);
}elsif($status eq 'Lost'){
$sth_sms_message->execute("ERR - LOST $datetime $sms_id nessuna informazione ricevuta dalla rete dopo 48h", undef, $message_id);
}elsif($status eq 'NoInfo'){
$sth_sms_message->execute("ERR - NOINFO $datetime $sms_id nessuna informazione sullo status del messaggio", undef, $message_id);
}else{
$sth_sms_message->execute("ERR - ??? $datetime $sms_id stato '$status' sconosciuto", undef, $message_id);
}
}
}
}elsif(lc $params{SMSPlatform} eq 'smstrend.it'){
my($sms, $old_status, $old_date, $old_time, $old_description) = split /\s/, $message->{'sms_result'}, 4;
# compatibilità precedente versione, priva del parametro old_date
if($old_date !~ m/^\d+/){
$old_description = "$old_date $old_time $old_description";
$old_date = undef;
$old_time = undef;
}
my $response = $SMSagent->post($params{SMSurl}.'/SMSSTATUS', {
'login' => $params{SMSAuthid},
'password' => $params{SMSAuthpwd},
'order_id' => 'T'.$message_id
});
# viene restituito:
# OK; - se order_id non presente (ad esempio dopo 30 gg)
# OK;%2B393487284422|WAIT4DLVR|;
# OK;%2B393487284422|DLVRD|20120708085046;
# OK;%2B393334365401|DLVRD|20180411141105;%2B393334365401|DLVRD|20180411211910;
#
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
my $datetime = sprintf '%02i/%02i/%04i %02i:%02i:%02i', $mday, $mon+1, $year+1900, $hour, $min, $sec;
if($response->is_error){
$sth_sms_message->execute("ERR - HTTP $datetime (".$response->code.') '.clean_html($response->error_as_HTML), undef, $message_id);
}else{
# Valuto soltanto il primo messaggio
my @params = split /;/, $response->content; #/
my $ok = shift @params;
if($ok eq 'OK'){
my $smsparams = shift @params;
if(!$smsparams){
# order_id non più presente (ad esempio dopo 30 gg)
$sth_sms_message->execute("KO - SMS ERASE $datetime eliminato [$old_status $old_date $old_time $old_description]", undef, $message_id);
}else{
my($recipient_number, $status, $delivery_date) = split /\|/, $smsparams;
if($delivery_date =~ m/^(\d\d\d\d)(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/){
$datetime = "$3/$2/$1 $4:$5:$6";
}
my $old_datetime = "$old_date $old_time";
if($status eq 'SCHEDULED'){
$sth_sms_message->execute("SMS SCHEDULED $datetime messaggio posticipato, non ancora inviato", undef, $message_id);
}elsif($status eq 'SENT'){
$sth_sms_message->execute("SMS SENT $datetime messaggio inviato, non attende delivery", undef, $message_id);
}elsif($status eq 'DLVRD'){
$sth_sms_message->execute("OK - SMS $datetime consegnato", undef, $message_id);
}elsif($status eq 'ERROR'){
$sth_sms_message->execute("SMS ERROR $datetime errore nella consegna dell'SMS (Es. numero non esistente)", undef, $message_id);
}elsif($status eq 'TIMEOUT'){
$sth_sms_message->execute("KO - SMS TIMEOUT $datetime l'operatore non ha fornito informazioni sull'SMS entro 48 ore", undef, $message_id);
}elsif($status eq 'TOOM4NUM'){
$sth_sms_message->execute("KO - SMS TOOM4NUM $datetime troppi SMS per lo stesso destinatario nelle ultime 24 ore", undef, $message_id);
}elsif($status eq 'TOOM4USER'){
$sth_sms_message->execute("KO - SMS TOOM4USER $datetime troppi SMS inviati dall'utente nelle ultime 24 ore", undef, $message_id);
}elsif($status eq 'UNKNPFX'){
$sth_sms_message->execute("KO - SMS UNKNPFX $datetime prefisso SMS non valido o sconosciuto", undef, $message_id);
}elsif($status eq 'UNKNRCPT'){
$sth_sms_message->execute("KO - SMS UNKNRCPT $datetime numero di telefono del destinatario non valido o sconosciuto", undef, $message_id);
}elsif($status eq 'WAIT4DLVR'){
$sth_sms_message->execute("SMS WAIT4DLVR $datetime messaggio inviato, in attesa di delivery", undef, $message_id);
}elsif($status eq 'WAITING'){
$sth_sms_message->execute("SMS WAITING $datetime messaggio in attesa, non ancora inviato", undef, $message_id);
}elsif($status eq 'UNKNOWN'){
$sth_sms_message->execute("SMS UNKNOWN $datetime stato sconosciuto", undef, $message_id);
}else{
$sth_sms_message->execute("ERR - SMS ??? $datetime ".$response->content, undef, $message_id);
}
}
}else{
$sth_sms_message->execute("ERR - SMS ??? $datetime ".$response->content, undef, $message_id);
}
}
}else{
$sth_sms_message->execute('KO - No SMS platform '.$params{SMSPlatform}, undef, $message_id);
}
}
 
#---------------------------------- SMS SEND
 
# verifico se ci sono messaggi SMS da inviare
my $sth_messages = $dbh->prepare(q{
select
messages_users.id,
messages.subject,
CASE
WHEN messages_users.user_short_message is not null THEN messages_users.user_short_message
WHEN messages.short_message is not null THEN messages.short_message
WHEN messages_users.user_message is not null THEN messages_users.user_message
ELSE messages.message
END as body,
anagrafiche.nome as nome_to,
anagrafiche.cognome as cognome_to,
anagrafiche.cell_sms as sms_to,
owner.nome as nome_from,
owner.cognome as cognome_from,
owner.cell_sms as sms_from
from public.messages_users
inner join public.messages on messages.id = messages_users.id_messages
inner join public.anagrafiche on anagrafiche.id = messages_users.id_anagrafiche
inner join public.anagrafiche owner on owner.id = messages.owner
where messages.transmission_time is not null
and messages.sms and messages_users.sms_result is null
order by messages_users.id;
});
$sth_messages->execute;
while(my $message = $sth_messages->fetchrow_hashref){
$message->{subject} =~ s/\n+$//s;
$message->{body} =~ s/^\n+//s;
my $sms_message = "$message->{subject}\n\n$message->{body}";
$sms_message =~ s/^\n+|\n+$//sg;
#DEBUG warn Dumper($message);
if(!$params{SMSsendToHimself} && $message->{'id'} eq $message->{'owner_id'}){
# scarto l'invio di SMS a se stessi
$sth_sms_message->execute('OK - No SMS to himself', undef, $message->{'id'});
next;
}
if(!$message->{'sms_to'}){
# scarto se non è definito l'indirizzo SMS del destinatario
$sth_sms_message->execute('KO - No SMS number', undef, $message->{'id'});
next;
}
# Normalizzo i numeri cellulari
$message->{'sms_to'} =~ s/\s|_|-|\///sg;
if($message->{'sms_to'} =~ m/^00/ and length($message->{'sms_to'}) > 10){
# prefisso nel formato +NN
$message->{'sms_to'} =~ s/^00/\+/;
}
if(length($message->{'sms_to'}) < 16){
# aggiungo il prefisso internazionale
$message->{'sms_to'} = '+'.$params{SMSNationPrefix}.$message->{'sms_to'};
}
if($message->{'sms_from'} !~ m/^\s*$/){
$message->{'sms_from'} =~ s/\s|_|-|\///sg;
if($message->{'sms_from'} =~ m/^00/ and length($message->{'sms_from'}) > 10){
# prefisso nel formato +NN
$message->{'sms_from'} =~ s/^00/\+/;
}
if(length($message->{'sms_from'}) < 16){
# aggiungo il prefisso internazionale
$message->{'sms_from'} = '+'.$params{SMSNationPrefix}.$message->{'sms_from'};
}
}else{
$message->{'sms_from'} = $params{SMSfrom};
}
# normalizzazione del messaggio SMS e costo (numero di messaggi da trasmettere)
my $sms_message = $SMS->text($sms_message);
my $sms_cost = $SMS->cost;
if(lc $params{SMSPlatform} eq 'comilio.it'){
my $http_req_json = HTTP::Request::JSON->new(POST => $params{SMSurl}.'/message');
$http_req_json->authorization_basic($params{SMSAuthid}, $params{SMSAuthpwd});
$http_req_json->json_content({
message_type => 'SmartPro',
phone_numbers => [ $message->{'sms_to'} ],
sender_string => $message->{'sms_from'},
text => $sms_message
});
my $response = $SMSagent->request($http_req_json);
# viene restituito un JSON { "message_id":"123xyz" }
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
my $datetime = sprintf '%02i/%02i/%04i %02i:%02i:%02i', $mday, $mon+1, $year+1900, $hour, $min, $sec;
my $json_response = eval { from_json $response->content };
if($response->is_error){
if($json_response && exists $json_response->{error}){
$sth_sms_message->execute("ERR - REST $datetime $json_response->{error}", undef, $message->{'id'});
}else{
$sth_sms_message->execute('ERR - HTTP ('.$response->code.') '.clean_html($response->error_as_HTML), undef, $message->{'id'});
}
}else{
if(defined $json_response->{message_id}){
$sth_sms_message->execute("SMS TOSERVER $datetime $json_response->{message_id} messaggio inviato al server", $sms_cost, $message->{'id'});
}elsif($json_response->{error}){
$sth_sms_message->execute("ERR - SMS TOSERVER $datetime $json_response->{error}", undef, $message->{'id'});
}else{
$sth_sms_message->execute('ERR - SMS TOSERVER $datetime ['.$response->content.']', undef, $message->{'id'});
}
}
}elsif(lc $params{SMSPlatform} eq 'smstrend.it'){
my $response = $SMSagent->post($params{SMSurl}.'/SENDSMS', {
'login' => $params{SMSAuthid},
'password' => $params{SMSAuthpwd},
'message_type' => 'GP',
'recipient' => $message->{'sms_to'},
'message' => $sms_message,
'sender' => $message->{'sms_from'},
'order_id' => 'T'.$message->{'id'}
});
# viene restituito "OK|<order_id>|1"
#
my ($sec,$min,$hour,$mday,$mon,$year) = localtime(time);
my $datetime = sprintf '%02i/%02i/%04i %02i:%02i:%02i', $mday, $mon+1, $year+1900, $hour, $min, $sec;
if($response->is_error){
$sth_sms_message->execute('ERR - HTTP ('.$response->code.') '.clean_html($response->error_as_HTML), undef, $message->{'id'});
}else{
my($ok, $order_id, $quant) = split /\|/, $response->content;
if($ok eq 'OK' && $order_id eq 'T'.$message->{'id'} && $quant == 1){
$sth_sms_message->execute("SMS TOSERVER $datetime messaggio inviato al server", $sms_cost, $message->{'id'});
}else{
$sth_sms_message->execute('ERR - SMS TOSERVER $datetime ['.$response->content.']', undef, $message->{'id'})
}
}
}else{
$sth_sms_message->execute('KO - No SMS platform '.$params{SMSPlatform}, undef, $message->{'id'});
}
} # while message SMS
} # if($params{SMSPlatform}){
 
# Disabilito gli utenti registrati che non si sono collegati entro MaxTimeToConfirmUserRegistration giorni
if($params{MaxTimeToConfirmUserRegistration}) {
my $sth_users = $dbh->prepare(q{
SELECT anagrafiche.id
FROM public.anagrafiche
WHERE last_change_password IS NULL
AND session_time is NOT NULL
AND previus_session_time IS NULL
AND to_number(to_char(now() - session_time, 'DD'), '99') > ?
AND anagrafiche.id NOT IN (
SELECT session.id_anagrafiche
FROM session
)
AND login IS NOT NULL
AND password IS NOT NULL
AND session IS NULL
AND descrizione IS NULL
AND indirizzo IS NULL
AND provincia IS NULL
AND citta IS NULL
AND tel1 IS NULL;
});
$sth_users->execute($params{MaxTimeToConfirmUserRegistration});
if($sth_users->rows > 0){
my $delete = 1;
while(my $data = $sth_users->fetchrow_arrayref){
my $id_user = $data->[0];
# Verifico che non ci siano logs di quell'utente
my $sth_logs = $dbh->prepare(q{
SELECT count(*)
FROM logs
WHERE id_anagrafiche = ?;
});
$sth_logs->execute($id_user);
next if($sth_logs->fetchrow_arrayref->[0]);
# Verifico che ci sia un solo messaggio inviato all'utente e che quel messaggio
# sia stato inviato solo a lui
my $sth_mess = $dbh->prepare(q{
SELECT messages.id,
(SELECT count(*) FROM messages_users WHERE messages_users.id_messages = messages.id) AS num
FROM messages
INNER JOIN messages_users ON messages_users.id_messages = messages.id
WHERE messages_users.id_anagrafiche = ?
});
my $num_mess = $sth_mess->execute($id_user);
next if($num_mess != 1);
my($id_message, $num_mess2) = $sth_mess->fetchrow_array;
next if($num_mess2 > 1);
# Cancello utente
my $sth_del = $dbh->prepare(q{
DELETE FROM messages_users WHERE id_messages = $1;
DELETE FROM messages WHERE id = $1;
DELETE FROM anagrafiche_gruppi WHERE id_anagrafiche = $2;
DELETE FROM anagrafiche WHERE id = $2;
});
$sth_del->execute($id_message, $id_user);
### Commit database contents.
$dbh->{AutoCommit} || $dbh->commit;
}
}
} # if($params{MaxTimeToConfirmUserRegistration})
 
# end necessario per Sys::RunAlone
__END__
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/utility/convert_iso-8859-15_to_utf-8.sh
0,0 → 1,32
#!/bin/bash
 
if [ "$1" != "--CONVERT" ]
then
find ./ -type f -exec /opt/masonsql/utility/convert_iso-8859-15_to_utf-8.sh --CONVERT {} \;
exit
fi
 
shift 1
F=$1
 
#echo CHECK $F
 
# cartelle da escludere
[ -z "${F%%*/jquery*}" ] && exit
[ -z "${F%%*/FCKeditor/*}" ] && exit
[ -z "${F%%*/bin/*}" ] && exit
 
# estensioni del file
[ -z "${F%%*.txt}" -o -z "${F%%*.htm}" -o -z "${F%%*.html}" -o -z "${F%%*.js}" \
-o -z "${F%%*.comp}" -o -z "${F%%*.css}" -o -z "${F%%*.pl}" -o -z "${F%%*.pm}" \
-o -z "${F%%*.include}" -o -z "${F%%*.mql}" -o -z "${F%%*handler}" \
-o -z "${F%%*APPUNTI}" -o -z "${F%%*.mason}" -o -z "${F%%*.conf}" ] || exit
 
[ -f "$F.ISO-8859-15" ] && exit
echo "CONVERT $F"
 
cp -a "$F" "$F.ISO-8859-15"
iconv --from-code=ISO-8859-15 --to-code=UTF-8 "$F.ISO-8859-15" > "$F"
 
 
 
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/utility/sql/create_logs_report.sql
0,0 → 1,71
-- Table: logs_report
 
-- DROP TABLE logs_report;
 
CREATE TABLE logs_report
(
id integer NOT NULL DEFAULT nextval(('logs_report_seq'::text)::regclass), -- Primary key
"timestamp" timestamp without time zone NOT NULL, -- Data e ora della modifica
table_name character varying(63) NOT NULL, -- Nome della tabella
report character varying, -- Riepilogo delle variazioni
id_anagrafiche integer, -- Utente responsabile della modifica
id_record integer NOT NULL, -- ID record modificato
CONSTRAINT logs_report_pkey PRIMARY KEY (id),
CONSTRAINT logs_report_id_anagrafiche FOREIGN KEY (id_anagrafiche)
REFERENCES anagrafiche (id) MATCH SIMPLE
ON UPDATE RESTRICT ON DELETE RESTRICT
)
WITH (
OIDS=FALSE
);
ALTER TABLE logs_report
OWNER TO postgres;
GRANT ALL ON TABLE logs_report TO postgres;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE logs_report TO heidix;
GRANT SELECT ON TABLE logs_report TO report;
COMMENT ON TABLE logs_report
IS 'Report delle operazioni di variazione dei dati effettuati dall''interfaccia Web';
COMMENT ON COLUMN logs_report.id IS 'Primary key';
COMMENT ON COLUMN logs_report."timestamp" IS 'Data e ora della modifica';
COMMENT ON COLUMN logs_report.table_name IS 'Nome della tabella';
COMMENT ON COLUMN logs_report.report IS 'Riepilogo delle variazioni';
COMMENT ON COLUMN logs_report.id_anagrafiche IS 'Utente responsabile della modifica';
COMMENT ON COLUMN logs_report.id_record IS 'ID record modificato';
 
 
-- Index: logs_report_id_anagrafiche
 
-- DROP INDEX logs_report_id_anagrafiche;
 
CREATE INDEX logs_report_id_anagrafiche
ON logs_report
USING btree
(id_anagrafiche);
 
-- Index: logs_report_id_record
 
-- DROP INDEX logs_report_id_record;
 
CREATE INDEX logs_report_id_record
ON logs_report
USING btree
(id_record);
 
-- Index: logs_report_table
 
-- DROP INDEX logs_report_table;
 
CREATE INDEX logs_report_table
ON logs_report
USING btree
(table_name COLLATE pg_catalog."default");
 
-- Index: logs_report_timestamp
 
-- DROP INDEX logs_report_timestamp;
 
CREATE INDEX logs_report_timestamp
ON logs_report
USING btree
("timestamp");
 
/tags/2.0/utility/sql/odt_report_tables.sql
0,0 → 1,78
CREATE SEQUENCE public.odt_reports_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE public.odt_reports_id_seq
OWNER TO postgres;
GRANT ALL ON SEQUENCE public.odt_reports_id_seq TO postgres;
GRANT ALL ON SEQUENCE public.odt_reports_id_seq TO masonsql;
CREATE SEQUENCE public.odt_report_portions_id_seq
INCREMENT 1
MINVALUE 1
MAXVALUE 2147483647
START 1
CACHE 1;
ALTER TABLE public.odt_report_portions_id_seq
OWNER TO postgres;
GRANT ALL ON SEQUENCE public.odt_report_portions_id_seq TO postgres;
GRANT ALL ON SEQUENCE public.odt_report_portions_id_seq TO masonsql;
CREATE TABLE public.odt_reports
(
id integer NOT NULL DEFAULT nextval('odt_reports_id_seq'::regclass),
name character varying(255),
description character varying(100),
comment character varying(1024),
cmd_parameters character varying(255),
global_parameters character varying(255),
CONSTRAINT odt_reports_pkey PRIMARY KEY (id),
CONSTRAINT odt_reports_name UNIQUE (name)
);
ALTER TABLE public.odt_reports
OWNER TO postgres;
GRANT ALL ON TABLE public.odt_reports TO postgres;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.odt_reports TO masonsql;
GRANT SELECT ON TABLE public.odt_reports TO report;
CREATE TABLE public.odt_report_portions
(
id integer NOT NULL DEFAULT nextval('odt_report_portions_id_seq'::regclass),
name character varying(20),
id_odt_reports integer NOT NULL,
id_father integer,
ord integer NOT NULL,
query character varying(10240),
type character varying(30),
file_name character varying(45),
obj_ref character varying(70),
CONSTRAINT odt_report_portions_pkey PRIMARY KEY (id),
CONSTRAINT odt_report_portions_id_father FOREIGN KEY (id_father)
REFERENCES public.odt_report_portions (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION,
CONSTRAINT odt_report_portions_id_odt_reports FOREIGN KEY (id_odt_reports)
REFERENCES public.odt_reports (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
ALTER TABLE public.odt_report_portions
OWNER TO postgres;
GRANT ALL ON TABLE public.odt_report_portions TO postgres;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.odt_report_portions TO masonsql;
GRANT SELECT ON TABLE public.odt_report_portions TO report;
CREATE TABLE public.odt_report_fields
(
id serial NOT NULL,
id_odt_reports integer NOT NULL,
key character varying(100),
function character varying(1024),
format character varying(256),
CONSTRAINT odt_report_fields_pkey PRIMARY KEY (id),
CONSTRAINT odt_report_fields_id_odt_reports FOREIGN KEY (id_odt_reports)
REFERENCES public.odt_reports (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
);
ALTER TABLE public.odt_report_fields OWNER TO postgres;
GRANT ALL ON TABLE public.odt_report_fields TO postgres;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE public.odt_report_fields TO masonsql;
GRANT SELECT ON TABLE public.odt_report_fields TO report;
ALTER SEQUENCE public.odt_report_fields_id_seq MAXVALUE 2147483647;
GRANT ALL ON SEQUENCE public.odt_reports_id_seq TO masonsql;
/tags/2.0/utility/sql/pg_dump.masonsql.template.sql
0,0 → 1,1709
--
-- PostgreSQL database dump
--
 
SET statement_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = off;
SET check_function_bodies = false;
SET client_min_messages = warning;
SET escape_string_warning = off;
 
--
-- Name: plpgsql; Type: PROCEDURAL LANGUAGE; Schema: -; Owner: postgres
--
 
CREATE PROCEDURAL LANGUAGE plpgsql;
 
 
ALTER PROCEDURAL LANGUAGE plpgsql OWNER TO postgres;
 
SET search_path = public, pg_catalog;
 
SET default_tablespace = '';
 
SET default_with_oids = false;
 
--
-- Name: anagrafiche; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE anagrafiche (
id integer NOT NULL,
nome character varying(20),
cognome character varying(25),
descrizione character varying(60),
indirizzo character varying(60),
provincia character varying(2),
citta character varying(20),
tel1 character varying(20),
tel2 character varying(20),
cell_sms character varying(20),
codice_fiscale character(16),
login character varying(60),
password character(32),
session character varying(60),
email character varying(60),
session_time timestamp without time zone,
previus_session_time timestamp without time zone
);
 
 
ALTER TABLE public.anagrafiche OWNER TO postgres;
 
--
-- Name: TABLE anagrafiche; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON TABLE anagrafiche IS 'Anagrafiche persone';
 
 
--
-- Name: COLUMN anagrafiche.session_time; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN anagrafiche.session_time IS 'Istante di login dell''utente';
 
 
--
-- Name: COLUMN anagrafiche.previus_session_time; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN anagrafiche.previus_session_time IS 'Istante della precedente login dell''utente';
 
 
--
-- Name: anagrafiche_gruppi; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE anagrafiche_gruppi (
id integer NOT NULL,
id_anagrafiche integer NOT NULL,
id_gruppi integer NOT NULL
);
 
 
ALTER TABLE public.anagrafiche_gruppi OWNER TO postgres;
 
--
-- Name: TABLE anagrafiche_gruppi; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON TABLE anagrafiche_gruppi IS 'Relazioni di appartenenza delle anagrafiche ai gruppi';
 
 
--
-- Name: anagrafiche_gruppi_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE anagrafiche_gruppi_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.anagrafiche_gruppi_id_seq OWNER TO postgres;
 
--
-- Name: anagrafiche_gruppi_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE anagrafiche_gruppi_id_seq OWNED BY anagrafiche_gruppi.id;
 
 
--
-- Name: anagrafiche_gruppi_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('anagrafiche_gruppi_id_seq', 3, true);
 
 
--
-- Name: anagrafiche_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE anagrafiche_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.anagrafiche_id_seq OWNER TO postgres;
 
--
-- Name: anagrafiche_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE anagrafiche_id_seq OWNED BY anagrafiche.id;
 
 
--
-- Name: anagrafiche_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('anagrafiche_id_seq', 3, true);
 
 
--
-- Name: autorizzazioni; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE autorizzazioni (
id integer NOT NULL,
nome character varying(16) NOT NULL,
descrizione character varying(60),
commento character varying(240)
);
 
 
ALTER TABLE public.autorizzazioni OWNER TO postgres;
 
--
-- Name: autorizzazioni_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE autorizzazioni_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.autorizzazioni_id_seq OWNER TO postgres;
 
--
-- Name: autorizzazioni_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE autorizzazioni_id_seq OWNED BY autorizzazioni.id;
 
 
--
-- Name: autorizzazioni_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('autorizzazioni_id_seq', 10, true);
 
 
--
-- Name: funzioni; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE funzioni (
id integer NOT NULL,
descrizione character varying(60),
commento character varying(240),
nome character varying(16) NOT NULL,
menu_contents character varying(24),
menu_status character varying(64),
menu_ord smallint,
menu_command character varying(1024),
menu_cmdtype character(1),
menu_father_id integer,
help character varying
);
 
 
ALTER TABLE public.funzioni OWNER TO postgres;
 
--
-- Name: funzioni_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE funzioni_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.funzioni_id_seq OWNER TO postgres;
 
--
-- Name: funzioni_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE funzioni_id_seq OWNED BY funzioni.id;
 
 
--
-- Name: funzioni_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('funzioni_id_seq', 19, true);
 
 
--
-- Name: gruppi; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE gruppi (
id integer NOT NULL,
nome character varying(16),
descrizione character varying(60),
commento character varying(240)
);
 
 
ALTER TABLE public.gruppi OWNER TO postgres;
 
--
-- Name: gruppi_and_anagrafiche; Type: VIEW; Schema: public; Owner: postgres
--
 
CREATE VIEW gruppi_and_anagrafiche AS
SELECT (- gruppi.id) AS id, gruppi.nome AS descrizione FROM gruppi UNION SELECT anagrafiche.id, (COALESCE(((anagrafiche.nome)::text || ' '::text), ''::text) || COALESCE((anagrafiche.cognome)::text, ''::text)) AS descrizione FROM anagrafiche WHERE (anagrafiche.login IS NOT NULL) ORDER BY 1;
 
 
ALTER TABLE public.gruppi_and_anagrafiche OWNER TO postgres;
 
--
-- Name: gruppi_funzioni; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE gruppi_funzioni (
id integer NOT NULL,
id_funzioni integer NOT NULL,
id_gruppi integer NOT NULL,
id_autorizzazioni integer NOT NULL
);
 
 
ALTER TABLE public.gruppi_funzioni OWNER TO postgres;
 
--
-- Name: gruppi_funzioni_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE gruppi_funzioni_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.gruppi_funzioni_id_seq OWNER TO postgres;
 
--
-- Name: gruppi_funzioni_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE gruppi_funzioni_id_seq OWNED BY gruppi_funzioni.id;
 
 
--
-- Name: gruppi_funzioni_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('gruppi_funzioni_id_seq', 396, true);
 
 
--
-- Name: gruppi_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE gruppi_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.gruppi_id_seq OWNER TO postgres;
 
--
-- Name: gruppi_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE gruppi_id_seq OWNED BY gruppi.id;
 
 
--
-- Name: gruppi_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('gruppi_id_seq', 4, true);
 
 
--
-- Name: gruppi_modifica; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE gruppi_modifica (
id integer NOT NULL,
id_gruppo integer NOT NULL,
id_gruppo_modifica integer NOT NULL
);
 
 
ALTER TABLE public.gruppi_modifica OWNER TO postgres;
 
--
-- Name: gruppi_modifica_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE gruppi_modifica_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.gruppi_modifica_id_seq OWNER TO postgres;
 
--
-- Name: gruppi_modifica_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE gruppi_modifica_id_seq OWNED BY gruppi_modifica.id;
 
 
--
-- Name: gruppi_modifica_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('gruppi_modifica_id_seq', 1, false);
 
 
--
-- Name: logs; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE logs (
id integer NOT NULL,
"timestamp" timestamp without time zone DEFAULT now(),
table_name character varying(63),
old_value character varying,
new_value character varying,
id_anagrafiche integer,
field character varying(63),
id_record integer
);
 
 
ALTER TABLE public.logs OWNER TO postgres;
 
--
-- Name: TABLE logs; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON TABLE logs IS 'Log operazioni di inserimento, modifica e cancellazione effettuati dall''interfaccia Web
';
 
 
--
-- Name: COLUMN logs.id; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN logs.id IS 'Primary key';
 
 
--
-- Name: COLUMN logs."timestamp"; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN logs."timestamp" IS 'Data e ora della modifica';
 
 
--
-- Name: COLUMN logs.table_name; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN logs.table_name IS 'Nome della tabella';
 
 
--
-- Name: COLUMN logs.old_value; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN logs.old_value IS 'Valore del campo prima della modifica';
 
 
--
-- Name: COLUMN logs.new_value; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN logs.new_value IS 'Valore del campo dopo la modifica';
 
 
--
-- Name: COLUMN logs.id_anagrafiche; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN logs.id_anagrafiche IS 'Utente responsabile della modifica';
 
 
--
-- Name: COLUMN logs.field; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN logs.field IS 'Nome del campo';
 
 
--
-- Name: logs_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE logs_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.logs_id_seq OWNER TO postgres;
 
--
-- Name: logs_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE logs_id_seq OWNED BY logs.id;
 
 
--
-- Name: logs_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('logs_id_seq', 1, true);
 
 
SET default_with_oids = true;
 
--
-- Name: messages; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE messages (
id integer NOT NULL,
message character varying NOT NULL,
owner integer NOT NULL,
modification_time timestamp without time zone NOT NULL,
transmission_time timestamp without time zone
);
 
 
ALTER TABLE public.messages OWNER TO postgres;
 
--
-- Name: messages_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE messages_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.messages_id_seq OWNER TO postgres;
 
--
-- Name: messages_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE messages_id_seq OWNED BY messages.id;
 
 
--
-- Name: messages_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('messages_id_seq', 1, false);
 
 
SET default_with_oids = false;
 
--
-- Name: messages_users; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE messages_users (
id integer NOT NULL,
id_messages integer NOT NULL,
id_anagrafiche integer NOT NULL,
notification_time timestamp without time zone
);
 
 
ALTER TABLE public.messages_users OWNER TO postgres;
 
--
-- Name: messages_users_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE messages_users_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.messages_users_id_seq OWNER TO postgres;
 
--
-- Name: messages_users_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE messages_users_id_seq OWNED BY messages_users.id;
 
 
--
-- Name: messages_users_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('messages_users_id_seq', 1, false);
 
 
--
-- Name: recordset; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE recordset (
id integer NOT NULL,
id_anagrafiche integer,
name character varying(64) NOT NULL,
size integer,
block integer,
query_numrec character varying,
query_records character varying,
query_where character varying,
query_find_records character varying
);
 
 
ALTER TABLE public.recordset OWNER TO postgres;
 
--
-- Name: TABLE recordset; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON TABLE recordset IS 'Tabella per rendere persistenti i recordset utilizzati sul browser.
Le righe precaricate (con la chiave del record) sono inserite nella tabella recordset_rows.';
 
 
--
-- Name: COLUMN recordset.name; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN recordset.name IS 'Nome del recordset.
Corrisponde a .prefix indicato nell''oggetto databinding corrispondente che a sua volta corrisponde a $Recordset nel framework MasonSql';
 
 
--
-- Name: COLUMN recordset.block; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN recordset.block IS 'Dimensione del blocco utilizzato per il caricamento delle chiavi.';
 
 
--
-- Name: recordset_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE recordset_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.recordset_id_seq OWNER TO postgres;
 
--
-- Name: recordset_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE recordset_id_seq OWNED BY recordset.id;
 
 
--
-- Name: recordset_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('recordset_id_seq', 1, true);
 
 
--
-- Name: recordset_rows; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE recordset_rows (
id integer NOT NULL,
id_recordset integer NOT NULL,
num_row integer NOT NULL,
id_record integer
);
 
 
ALTER TABLE public.recordset_rows OWNER TO postgres;
 
--
-- Name: TABLE recordset_rows; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON TABLE recordset_rows IS 'Chiavi recordset (vedi tabella recordset).
Utilizzata nella gestione dei recordset persistenti.
';
 
 
--
-- Name: COLUMN recordset_rows.num_row; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN recordset_rows.num_row IS 'Riga nel recordset';
 
 
--
-- Name: COLUMN recordset_rows.id_record; Type: COMMENT; Schema: public; Owner: postgres
--
 
COMMENT ON COLUMN recordset_rows.id_record IS 'Chiave del record';
 
 
--
-- Name: recordset_rows_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE recordset_rows_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.recordset_rows_id_seq OWNER TO postgres;
 
--
-- Name: recordset_rows_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE recordset_rows_id_seq OWNED BY recordset_rows.id;
 
 
--
-- Name: recordset_rows_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('recordset_rows_id_seq', 1, true);
 
 
--
-- Name: report_id; Type: TABLE; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE TABLE report_id (
id integer NOT NULL,
key integer NOT NULL,
group_id integer NOT NULL
);
 
 
ALTER TABLE public.report_id OWNER TO postgres;
 
--
-- Name: report_id_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres
--
 
CREATE SEQUENCE report_id_id_seq
START WITH 1
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;
 
 
ALTER TABLE public.report_id_id_seq OWNER TO postgres;
 
--
-- Name: report_id_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres
--
 
ALTER SEQUENCE report_id_id_seq OWNED BY report_id.id;
 
 
--
-- Name: report_id_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
--
 
SELECT pg_catalog.setval('report_id_id_seq', 1, true);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE anagrafiche ALTER COLUMN id SET DEFAULT nextval('anagrafiche_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE anagrafiche_gruppi ALTER COLUMN id SET DEFAULT nextval('anagrafiche_gruppi_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE autorizzazioni ALTER COLUMN id SET DEFAULT nextval('autorizzazioni_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE funzioni ALTER COLUMN id SET DEFAULT nextval('funzioni_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE gruppi ALTER COLUMN id SET DEFAULT nextval('gruppi_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE gruppi_funzioni ALTER COLUMN id SET DEFAULT nextval('gruppi_funzioni_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE gruppi_modifica ALTER COLUMN id SET DEFAULT nextval('gruppi_modifica_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE logs ALTER COLUMN id SET DEFAULT nextval('logs_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE messages ALTER COLUMN id SET DEFAULT nextval('messages_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE messages_users ALTER COLUMN id SET DEFAULT nextval('messages_users_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE recordset ALTER COLUMN id SET DEFAULT nextval('recordset_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE recordset_rows ALTER COLUMN id SET DEFAULT nextval('recordset_rows_id_seq'::regclass);
 
 
--
-- Name: id; Type: DEFAULT; Schema: public; Owner: postgres
--
 
ALTER TABLE report_id ALTER COLUMN id SET DEFAULT nextval('report_id_id_seq'::regclass);
 
 
--
-- Data for Name: anagrafiche; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY anagrafiche (id, nome, cognome, descrizione, indirizzo, provincia, citta, tel1, tel2, sell_sms, codice_fiscale, login, password, session, email, session_time, previus_session_time) FROM stdin;
3 Guest Guest \N \N \N \N \N \N \N \N guest 19ad89bc3e3c9d7ef68b89523eff1987 \N \N \N \N
1 admin \N \N \N \N \N \N \N \N \N admin 8c31523d0c7e79c2594854a2fe62d3b5 172009872beb234c8bac09961375b8b4 10.115.1.2 21228904 \N 2010-05-13 08:52:34.868345 2010-05-13 07:51:40.19512
\.
 
 
--
-- Data for Name: anagrafiche_gruppi; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY anagrafiche_gruppi (id, id_anagrafiche, id_gruppi) FROM stdin;
1 1 1
3 3 4
\.
 
 
--
-- Data for Name: autorizzazioni; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY autorizzazioni (id, nome, descrizione, commento) FROM stdin;
8 Xls Download dati in formato XLS L'autorizzazione se concessa permette all'utente di scaricare i dati in formato XLS
4 Delete Cancellazione dei dati \N
2 Select Lettura dei dati \N
7 Insert Inserimento nuovi valori \N
1 Menu Menu attivo La voce di menù viene resa disponibile
5 Print Stampa record corrente \N
6 PrintSel Stampa selezione dei record \N
3 Update Modifica dei dati \N
9 Dbms Interfaccia scambio dati /dbms L'autorizzazione se concessa permette all'utente di scambiare dati attraverso l'interfaccia /dbms
10 Log Visualizzazione delle modifiche nel tempo Visualizza le modifiche apportate nel tempo con indicazione dell'utente
\.
 
 
--
-- Data for Name: funzioni; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY funzioni (id, descrizione, commento, nome, menu_contents, menu_status, menu_ord, menu_command, menu_cmdtype, menu_father_id, help) FROM stdin;
3 Help \N Help ? Help 900 \N \N \N Menu principale Help.
7 Home Page \N HomePage Home Page Ricarica Home Page 10 "pageLoad('home.html?Ver=$Ver', '')" J 14 Home Page.
12 Ricarica form corrente \N Reload Ricarica Ricarica form corrente 30 divReload(CurrentMenu); divReload(CurrentBody); j 3 Viene ricaricata dal server la funzione corrente.
4 Cambio password \N ChangePass Cambio password \N 90 "pageLoad('change_password.html?Ver=$Ver', '')" J 14 Help funzione Cambio password
8 Autorizzazioni \N ListAuth Tipi autorizzazioni Autorizzazioni 20 "pageLoad('table.html?Ver=$Ver&from=autorizzazioni', '')" J 17 Classificazione delle autorizzazioni attribuibili ai gruppi a cui appartengono gli utenti.<br />\n<br />\n<ul>\n <li>\n <p align="left"><strong>Nome autorizzazione:&nbsp; </strong><span style=""></span></p>\n </li>\n <li>\n <p align="left"><strong>Descrizione: </strong>Descrizione autorizzazione<br />\n </p>\n </li>\n <li>\n <p align="left"><strong>Commento: </strong>Commento di utilizzo libero</p>\n </li>\n</ul>
9 Tabella funzioni \N Funzioni Funzioni e autorizz. Tabella funzioni dell'applicazione e autorizzazioni applicate 30 "pageLoad('table.html?Ver=$Ver&from=funzioni&children=TABLE&rows_child=10', '')" J 17 Definizione dei men&ugrave; dell'applicazione e relativi permessi e documentazione.<br />\n<br />\n<ul>\n <li>\n <p align="left"><strong>Nome: </strong>Nome univoco della funzione. Al nome vengono associati i profili dei permessi usati&nbsp; anche nel codice. E' quindi importante&nbsp; non modificare il codice se non si &egrave;&nbsp; in grado di modificare anche i riferimenti nel codice dell'applicazione<span style=""></span></p>\n </li>\n <li>\n <p align="left"><strong>Descrizione: </strong>Descrizione della funzione</p>\n </li>\n <li>\n <p align="left"><strong>Commento: </strong>Commento di utilizzo libero</p>\n </li>\n <li>\n <p align="left"><strong>Ord: </strong>Numero che determina l'ordine con cui le varie voci di men&ugrave; compaiono<br />\n </p>\n </li>\n <li>\n <p align="left"><strong>Menu: </strong>Nome del men&ugrave; che appare nell'applicazione<strong><br />\n </strong></p>\n </li>\n <li>\n <p align="left"><strong>Menu padre: </strong>Nome della funziona padre. La voce comparir&agrave; nel men&ugrave; sotto la voce del padre indicato. E' possibile indicare come padre delle voci di men&ugrave; che a voro volta hanno un padre.<br />\n </p>\n </li>\n <li>\n <p align="left"><strong>Menu avviso: </strong>Titolo del men&ugrave;<strong><br />\n </strong></p>\n </li>\n <li>\n <p align="left"><strong>Tipo comando:&nbsp;</strong></p>\n <ul>\n <li><strong>Link WEB: </strong>Il contenuto del campo <em>Comando Menu</em> verr&agrave; interpretato come link ad una pagina HTML<br />\n </li>\n <li><strong>Link WEB - applicando eval Perl: </strong>Al contenuto del campo viene applicata la funzione eval sul Server; utile per elaborare dei valori <em>(es. la variabile $Ver verr&agrave; sostituita con il numero di versione)</em><br />\n </li>\n <li><strong>Client Javascript: </strong>Il contenuto del campo <em>Comando Menu</em> verr&agrave; interpretato come codice javascript sul browser.<br />\n </li>\n <li><strong>Client Javascript</strong><strong> - applicando eval Perl: </strong>Al contenuto del campo viene applicata la funzione eval sul Server.</li>\n </ul>\n </li>\n <li>\n <p align="left"><strong>Comando Menu: </strong>Il comando, intepretato in funzione del campo <em>Tipo comando</em>.<strong><br />\n </strong></p>\n </li>\n <li>\n <p align="left"><strong>Permessi: </strong>Tabella di assegnazione dei permessi. In colonna vengono inseriti i vari tipi di autorizzazioni, mentre in riga troviamo le definizioni dei vari gruppi.<br />\n </p>\n </li>\n <li>\n <p align="left"><strong>Help: </strong>Documentazione della funzione a disposizione dell'utente. L'help dell'applicazione viene costruito assemblando la documentazione delle funzioni a cui l'utente ha accesso in base ai gruppi a cui appartiene.<strong><br />\n </strong></p>\n </li>\n</ul>
1 Modifiche nel database Registrazione modifiche nel database da parte degli Utenti Logs Log database Registrazione modifiche nel database da parte degli Utenti 999 "pageLoad('table.html?Ver=$Ver&from=logs', '')" J 17 Visualizza il registro delle mondifiche effettuate dagli utenti nel database.
14 Home Raggruppamento homed Home Home Home page applicazione SIDAL 1 \N \N \N <h1 align="center">Introduzione</h1>\n<p>Questo programma permette la gestione integrata ....<br />\n</p>\n<span style="font-size: 10pt; font-family: Symbol;"></span>
2 Chiusura sessione \N CloseSession Esci Chiude sessione di lavoro 999 "logout.html?Ver=$Ver" U 14 Chiusura sessione.
16 Tabella anagrafiche persone \N Anagrafiche Anagrafica utenti Tabella anagrafiche utenti 10 "pageLoad('/table.html?Ver=$Ver&from=anagrafiche&form=FORM&children=TABLE&rows_child=5', '')" J 17 <h1 align="center">Anagrafica utenti</h1>\n<p align="justify">Archivio degli Utenti che accedono all'applicazione.</p>\n<p align="justify">Solo l'Utente con diritti di amministratore &egrave; in grado di modificare i dati degli Utenti.</p>\n<p align="justify">I campi dell'archivio, visualizzati nel &ldquo;form&rdquo;, sono:</p>\n<ul>\n <li>\n <p align="justify"><strong>Nome:</strong> Nome di battesimo dell'utente </p>\n </li>\n <li>\n <p align="left"><strong>Cognome:</strong> Cognome dell'Utente</p>\n </li>\n <li>\n <p align="left"><strong>C.F.:</strong> Codice fiscale; necessario se l'Utente &egrave; abilitato a firmare i Rapporti di prova, infatti viene utilizzato per la verifica del certificato di firma che deve quindi combaciare, assieme al Nome e Cognome.</p>\n </li>\n <li>\n <p align="left"><strong>Indirizzo:</strong> Indirizzo di reperibilit&agrave;</p>\n </li>\n <li>\n <p align="left"><strong>Provincia:</strong></p>\n </li>\n <li>\n <p align="left"><strong>Citt&agrave;:</strong></p>\n </li>\n <li>\n <p align="left"><strong>Telefono:</strong></p>\n </li>\n <li>\n <p align="left"><strong>2&deg; Telefono:</strong></p>\n </li>\n <li>\n <p align="left"><strong>Indirizzo e-mail:</strong></p>\n </li>\n <li>\n <p align="left"><strong>Login:</strong> codice di accesso all'applicazione; Deve essere un codice univoco diverso quindi per ciascun Utente</p>\n </li>\n <li>\n <p align="left"><strong>Password: </strong>password di almeno 8 caratteri. La password viene salvata nel database cifrata in modo da impedire la lettura anche all'Amministratore che pu&ograve; eventualmente cambiarla se l'Utente dovesse dimenticarla</p>\n </li>\n <li>\n <p align="left"><strong>parametri su:</strong> Numero di righe da visualizzare della tabella dei parametri del form dei campioni prelevati</p>\n </li>\n <li>\n <p align="left"><strong>in tabella:</strong> Se selezionato, i dati dei parametri dei Campioni prelevati, verranno allineati in formato tabella</p>\n </li>\n <li>\n <p align="left" style="margin-bottom: 0cm;"><strong>Gruppi a cui appartiene l'utente: </strong>Lista dei gruppi a cui l'utente pu&ograve; appartenere:<br />\n </p>\n <ul>\n <li><strong>Admins: </strong>Amministratori dell'applicazione</li>\n <li><strong>Guesti</strong>: Utenti ospiti (sol alettura)</li>\n </ul>\n </li>\n</ul>
13 Manuale di riferimento Visualizza un Help dell'applicazione HelpMain Help Help Analisi Chimiche 1 "pageLoad('/help.html?F=Home&Ver=$Ver', '/help.html?Ver=$Ver')" J 3 <span style="cursor: auto;" id="Father_FORM_funzioni">L'help dell'applicazione viene costruito assemblando la documentazione delle funzioni a cui l'utente ha accesso in base ai gruppi a cui appartiene.<br />\nLe varie funzioni vengono organizzate in un men&ugrave; ad albero visibile a sinistra, con il dettaglio visualizzato sulla destra.<br />\nLa documentazione &egrave; modificabile dagli utenti abilitati dalla funzione&nbsp; <em>Funzioni e autorizz.</em></span>
17 Impostazione delle autorizzazioni \N Autorizzazioni Autorizzazioni Impostazione delle autorizzazioni 5 \N \N \N <div align="center"><font size="5"><span style="cursor: auto;" id="Father_autorizzazioni"><strong><strong>Autorizzazioni<br />\n<br />\n</strong></strong></span></font>\n<div align="left">\n<ul>\n <li><font size="5"><span style="cursor: auto;" id="Father_autorizzazioni"><strong><strong><font size="2">Nome autorizzazione: </font></strong></strong><font size="2">Nome dell'autorizzazione</font><strong><strong><font size="2">&nbsp; <br />\n </font></strong></strong></span></font></li>\n</ul>\n<ul>\n <li><font size="5"><span style="cursor: auto;" id="Father_autorizzazioni"><strong><strong><font size="2">Descrizione: </font></strong></strong><font size="2">Descrizione dell'autorizzazione<br />\n </font></span></font></li>\n</ul>\n<ul>\n <li><font size="5"><span style="cursor: auto;" id="Father_autorizzazioni"><strong><strong><font size="2">Commento: </font></strong></strong><font size="2">Eventuale commento<br />\n </font></span></font></li>\n</ul>\n<font size="5"><span style="cursor: auto;" id="Father_autorizzazioni"></span></font></div>\n</div>
6 Note di release e Copyright \N Release Release Note di release e Copyright 20 "pageLoad('release_notes.html?Ver=$Ver', '')" J 3 Note di release: ................<br />\n<br />\n<br />\n<br />\n<br />\n<div align="center"><br />\nFramework MasonSQL<br />\nCopyright (&copy;):<br />\nGuido Brugnara &lt;gdo@leader.it&gt;<br />\nLicenza G.P.L. Rel.2 <br />\n</div>\n<strong></strong>
10 Tabella gruppi \N Gruppi Gruppi Tabella gruppi 10 "pageLoad('/table.html?Ver=$Ver&from=gruppi&children=TABLE&rows_child=10', '')" J 17 <div align="center"><font size="4"><font size="5">GRUPPI</font><strong><br />\n<br />\n</strong></font></div>\nDefinizione dei gruppi a cui possono appartenere gli utenti che accedono all'applicazione.<br />\n<br />\n<ul>\n <li>\n <p align="left"><strong>Nome: </strong>Nome del gruppo<span style=""></span></p>\n </li>\n <li>\n <p align="left"><strong>Descrizione: </strong>Descrizione del gruppo</p>\n </li>\n <li>\n <p align="left"><strong>Commento: </strong>Commento di utilizzo libero</p>\n </li>\n <li>\n <p align="left"><strong>Utenti del gruppo:</strong> Elenco degli utenti che appartengono al gruppo<span style="cursor: auto;" id="Child_gruppi_modifica"></span></p>\n </li>\n <li>\n <p align="left"><span style="cursor: auto;" id="Child_gruppi_modifica"><strong><strong>Gruppi modificabili: </strong></strong>Elenco dei gruppi che utenti appartenenti al gruppo in testata possono attribuire ad altri utenti.</span></p>\n </li>\n</ul>\n<br />\n<span style="cursor: auto;" id="Child_gruppi_anagrafiche"><strong><strong>Utenti del gruppo</strong></strong></span><br />\nL'ambiente di base codifica i seguenti gruppi che non devono essere alterati:<br />\n<ul>\n <li>\n <p align="left"><strong>Admins:</strong> Gruppo&nbsp; <em>admin</em> di base dell'applicazione. E' un gruppo speciale che ha tutti i diritti.</p>\n </li>\n</ul>\n<br />\n<span style="cursor: auto;" id="Child_gruppi_modifica"><strong><strong>Gruppi modificabili<br />\n</strong></strong></span>\n<ul>\n <li>EnteAccett: Gruppo Accettazione Ente</li>\n</ul>\n<ul>\n <li>EnteAdmin: Gruppo Amministratore ditta gestione</li>\n</ul>\n<ul>\n <li>EnteChimico: Gruppo Chimico ditta gestione</li>\n</ul>\n<ul>\n <li>EntePrelievo: Gruppo Tecnico prelievo ditta gestione</li>\n</ul>\n<ul>\n <li>EnteResp: Gruppo Responsabile ditta gestione</li>\n</ul>\n<ul>\n <li>EnteUser: Utente ditta gestione</li>\n</ul>\n<ul>\n <li>PatAdmin: Gruppo Amministratore PAT</li>\n</ul>\n<ul>\n <li>PatChimico: Chimico PAT</li>\n</ul>\n<ul>\n <li>PatUser: Utente PAT</li>\n</ul>\n<br />\n<br />\n<br />\n<span style="cursor: auto;" id="Child_gruppi_modifica"><strong><strong></strong></strong></span>
18 Messaggi ed avvisi di sistema \N Messages Messaggi Messaggi ed avvisi di sistema \N "pageLoad('table.html?Ver=$Ver&from=messages&form=FORM', '')" J 17 Gestione messaggi agli utenti
19 Messaggi inviati all'utente \N User_messages Messaggi Messaggi inviati all'utente \N "pageLoad('table.html?Ver=$Ver&from=user_messages&form=DIVS', '')" J 14 Messaggi inviati all'utente
\.
 
 
--
-- Data for Name: gruppi; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY gruppi (id, nome, descrizione, commento) FROM stdin;
1 Admins Amministratori Utenti amministratori
4 Guest Utenti ospiti (sola lettura) \N
\.
 
 
--
-- Data for Name: gruppi_funzioni; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY gruppi_funzioni (id, id_funzioni, id_gruppi, id_autorizzazioni) FROM stdin;
331 13 1 1
332 13 4 1
333 14 1 1
334 14 4 1
335 17 1 1
336 17 4 1
337 7 1 1
338 7 4 1
339 10 1 4
340 10 1 7
341 10 1 1
342 10 1 5
343 10 1 6
344 10 1 2
345 10 1 3
346 10 1 8
347 10 4 1
348 10 4 2
349 16 1 4
350 16 1 7
351 16 1 1
352 16 1 5
353 16 1 6
354 16 1 2
355 16 1 3
356 16 4 1
357 16 4 2
360 8 1 4
361 8 1 7
362 8 1 1
363 8 1 2
364 8 1 3
365 8 1 8
366 9 1 4
367 9 1 7
368 9 1 1
369 9 1 2
370 9 1 3
371 9 1 8
372 12 1 1
373 12 4 1
374 4 1 1
375 4 4 1
376 3 1 1
377 3 4 1
381 2 1 1
382 2 4 1
383 1 1 1
384 1 1 2
385 1 1 8
386 18 1 4
387 18 1 7
388 18 1 1
389 18 1 2
390 18 1 3
391 19 1 1
392 19 1 2
393 19 4 1
394 19 4 2
395 6 1 1
396 6 4 1
\.
 
 
--
-- Data for Name: gruppi_modifica; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY gruppi_modifica (id, id_gruppo, id_gruppo_modifica) FROM stdin;
\.
 
 
--
-- Data for Name: logs; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY logs (id, "timestamp", table_name, old_value, new_value, id_anagrafiche, field, id_record) FROM stdin;
\.
 
 
--
-- Data for Name: messages; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY messages (id, message, owner, modification_time, transmission_time) FROM stdin;
\.
 
 
--
-- Data for Name: messages_users; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY messages_users (id, id_messages, id_anagrafiche, notification_time) FROM stdin;
\.
 
 
--
-- Data for Name: recordset; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY recordset (id, id_anagrafiche, name, size, block, query_numrec, query_records, query_where, query_find_records) FROM stdin;
\.
 
 
--
-- Data for Name: recordset_rows; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY recordset_rows (id, id_recordset, num_row, id_record) FROM stdin;
\.
 
 
--
-- Data for Name: report_id; Type: TABLE DATA; Schema: public; Owner: postgres
--
 
COPY report_id (id, key, group_id) FROM stdin;
\.
 
 
--
-- Name: anagrafiche_gruppi_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY anagrafiche_gruppi
ADD CONSTRAINT anagrafiche_gruppi_pkey PRIMARY KEY (id);
 
 
--
-- Name: anagrafiche_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY anagrafiche
ADD CONSTRAINT anagrafiche_pkey PRIMARY KEY (id);
 
 
--
-- Name: autorizzazioni_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY autorizzazioni
ADD CONSTRAINT autorizzazioni_pkey PRIMARY KEY (id);
 
 
--
-- Name: funzioni_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY funzioni
ADD CONSTRAINT funzioni_pkey PRIMARY KEY (id);
 
 
--
-- Name: gruppi_funzioni_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY gruppi_funzioni
ADD CONSTRAINT gruppi_funzioni_pkey PRIMARY KEY (id);
 
 
--
-- Name: gruppi_modifica_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY gruppi_modifica
ADD CONSTRAINT gruppi_modifica_pkey PRIMARY KEY (id);
 
 
--
-- Name: gruppi_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY gruppi
ADD CONSTRAINT gruppi_pkey PRIMARY KEY (id);
 
 
--
-- Name: id_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY messages_users
ADD CONSTRAINT id_pkey PRIMARY KEY (id);
 
 
--
-- Name: logs_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY logs
ADD CONSTRAINT logs_pkey PRIMARY KEY (id);
 
 
--
-- Name: messages_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY messages
ADD CONSTRAINT messages_pkey PRIMARY KEY (id);
 
 
--
-- Name: recordset_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY recordset
ADD CONSTRAINT recordset_pkey PRIMARY KEY (id);
 
 
--
-- Name: recordset_rows_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY recordset_rows
ADD CONSTRAINT recordset_rows_pkey PRIMARY KEY (id);
 
 
--
-- Name: report_id_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace:
--
 
ALTER TABLE ONLY report_id
ADD CONSTRAINT report_id_pkey PRIMARY KEY (id);
 
 
--
-- Name: anagrafiche_id_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX anagrafiche_id_idx ON recordset USING btree (id_anagrafiche);
 
 
--
-- Name: fki_logs_id_anagrafiche; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX fki_logs_id_anagrafiche ON logs USING btree (id_anagrafiche);
 
 
--
-- Name: fki_recordset_anagrafiche; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX fki_recordset_anagrafiche ON recordset USING btree (id_anagrafiche);
 
 
--
-- Name: fki_recordset_rows; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX fki_recordset_rows ON recordset_rows USING btree (id_recordset);
 
 
--
-- Name: logs_id_anagrafiche; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX logs_id_anagrafiche ON logs USING btree (id_anagrafiche);
 
 
--
-- Name: logs_table; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX logs_table ON logs USING btree (table_name);
 
 
--
-- Name: logs_timestamp; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX logs_timestamp ON logs USING btree ("timestamp");
 
 
--
-- Name: messages_date; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX messages_date ON messages USING btree (modification_time);
 
 
--
-- Name: messages_owner; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX messages_owner ON messages USING btree (owner);
 
 
--
-- Name: messages_users_id_anagrafiche; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX messages_users_id_anagrafiche ON messages_users USING btree (id_anagrafiche);
 
 
--
-- Name: messages_users_id_messages; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX messages_users_id_messages ON messages_users USING btree (id_messages);
 
 
--
-- Name: messages_users_notification_time; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX messages_users_notification_time ON messages_users USING btree (notification_time);
 
 
--
-- Name: prefix_idx; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX prefix_idx ON recordset USING btree (name);
 
 
--
-- Name: recordset_rows_id_record; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX recordset_rows_id_record ON recordset_rows USING btree (id_record);
 
 
--
-- Name: recordset_rows_id_recordset; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX recordset_rows_id_recordset ON recordset_rows USING btree (id_recordset);
 
 
--
-- Name: recordset_rows_num_row; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE INDEX recordset_rows_num_row ON recordset_rows USING btree (num_row);
 
 
--
-- Name: recordset_rows_unique; Type: INDEX; Schema: public; Owner: postgres; Tablespace:
--
 
CREATE UNIQUE INDEX recordset_rows_unique ON recordset_rows USING btree (id_recordset, id_record);
 
 
--
-- Name: anagrafiche_gruppi_id_anagrafiche; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY anagrafiche_gruppi
ADD CONSTRAINT anagrafiche_gruppi_id_anagrafiche FOREIGN KEY (id_anagrafiche) REFERENCES anagrafiche(id) ON UPDATE RESTRICT ON DELETE CASCADE;
 
 
--
-- Name: anagrafiche_gruppi_id_gruppi; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY anagrafiche_gruppi
ADD CONSTRAINT anagrafiche_gruppi_id_gruppi FOREIGN KEY (id_gruppi) REFERENCES gruppi(id) ON UPDATE RESTRICT ON DELETE CASCADE;
 
 
--
-- Name: gruppi_funzioni_id_autorizzazioni; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY gruppi_funzioni
ADD CONSTRAINT gruppi_funzioni_id_autorizzazioni FOREIGN KEY (id_autorizzazioni) REFERENCES autorizzazioni(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
 
 
--
-- Name: gruppi_funzioni_id_funzioni; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY gruppi_funzioni
ADD CONSTRAINT gruppi_funzioni_id_funzioni FOREIGN KEY (id_funzioni) REFERENCES funzioni(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
 
 
--
-- Name: gruppi_funzioni_id_gruppi; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY gruppi_funzioni
ADD CONSTRAINT gruppi_funzioni_id_gruppi FOREIGN KEY (id_gruppi) REFERENCES gruppi(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
 
 
--
-- Name: gruppi_modifica_id_gruppo; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY gruppi_modifica
ADD CONSTRAINT gruppi_modifica_id_gruppo FOREIGN KEY (id_gruppo) REFERENCES gruppi(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
 
 
--
-- Name: gruppi_modifica_id_gruppo_modifica; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY gruppi_modifica
ADD CONSTRAINT gruppi_modifica_id_gruppo_modifica FOREIGN KEY (id_gruppo_modifica) REFERENCES gruppi(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
 
 
--
-- Name: logs_id_anagrafiche; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY logs
ADD CONSTRAINT logs_id_anagrafiche FOREIGN KEY (id_anagrafiche) REFERENCES anagrafiche(id) ON UPDATE RESTRICT ON DELETE RESTRICT;
 
 
--
-- Name: messages_users_messages; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY messages_users
ADD CONSTRAINT messages_users_messages FOREIGN KEY (id_messages) REFERENCES messages(id) ON UPDATE RESTRICT ON DELETE CASCADE;
 
 
--
-- Name: recordset_anagrafiche; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY recordset
ADD CONSTRAINT recordset_anagrafiche FOREIGN KEY (id_anagrafiche) REFERENCES anagrafiche(id) ON DELETE CASCADE;
 
 
--
-- Name: recordset_rows; Type: FK CONSTRAINT; Schema: public; Owner: postgres
--
 
ALTER TABLE ONLY recordset_rows
ADD CONSTRAINT recordset_rows FOREIGN KEY (id_recordset) REFERENCES recordset(id) ON DELETE CASCADE;
 
 
--
-- Name: public; Type: ACL; Schema: -; Owner: postgres
--
 
REVOKE ALL ON SCHEMA public FROM PUBLIC;
REVOKE ALL ON SCHEMA public FROM postgres;
GRANT ALL ON SCHEMA public TO postgres;
GRANT USAGE ON SCHEMA public TO PUBLIC;
 
 
--
-- Name: anagrafiche; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE anagrafiche FROM PUBLIC;
REVOKE ALL ON TABLE anagrafiche FROM postgres;
GRANT ALL ON TABLE anagrafiche TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE anagrafiche TO masonsql;
GRANT SELECT ON TABLE anagrafiche TO report;
 
 
--
-- Name: anagrafiche_gruppi; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE anagrafiche_gruppi FROM PUBLIC;
REVOKE ALL ON TABLE anagrafiche_gruppi FROM postgres;
GRANT ALL ON TABLE anagrafiche_gruppi TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE anagrafiche_gruppi TO masonsql;
GRANT SELECT ON TABLE anagrafiche_gruppi TO report;
 
 
--
-- Name: anagrafiche_gruppi_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE anagrafiche_gruppi_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE anagrafiche_gruppi_id_seq FROM postgres;
GRANT ALL ON SEQUENCE anagrafiche_gruppi_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE anagrafiche_gruppi_id_seq TO masonsql;
 
 
--
-- Name: anagrafiche_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE anagrafiche_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE anagrafiche_id_seq FROM postgres;
GRANT ALL ON SEQUENCE anagrafiche_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE anagrafiche_id_seq TO masonsql;
 
 
--
-- Name: autorizzazioni; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE autorizzazioni FROM PUBLIC;
REVOKE ALL ON TABLE autorizzazioni FROM postgres;
GRANT ALL ON TABLE autorizzazioni TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE autorizzazioni TO masonsql;
GRANT SELECT ON TABLE autorizzazioni TO report;
 
 
--
-- Name: autorizzazioni_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE autorizzazioni_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE autorizzazioni_id_seq FROM postgres;
GRANT ALL ON SEQUENCE autorizzazioni_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE autorizzazioni_id_seq TO masonsql;
 
 
--
-- Name: funzioni; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE funzioni FROM PUBLIC;
REVOKE ALL ON TABLE funzioni FROM postgres;
GRANT ALL ON TABLE funzioni TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE funzioni TO masonsql;
GRANT SELECT ON TABLE funzioni TO report;
 
 
--
-- Name: funzioni_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE funzioni_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE funzioni_id_seq FROM postgres;
GRANT ALL ON SEQUENCE funzioni_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE funzioni_id_seq TO masonsql;
 
 
--
-- Name: gruppi; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE gruppi FROM PUBLIC;
REVOKE ALL ON TABLE gruppi FROM postgres;
GRANT ALL ON TABLE gruppi TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE gruppi TO masonsql;
GRANT SELECT ON TABLE gruppi TO report;
 
 
--
-- Name: gruppi_and_anagrafiche; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE gruppi_and_anagrafiche FROM PUBLIC;
REVOKE ALL ON TABLE gruppi_and_anagrafiche FROM postgres;
GRANT ALL ON TABLE gruppi_and_anagrafiche TO postgres;
GRANT SELECT ON TABLE gruppi_and_anagrafiche TO report;
GRANT SELECT ON TABLE gruppi_and_anagrafiche TO masonsql;
 
 
--
-- Name: gruppi_funzioni; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE gruppi_funzioni FROM PUBLIC;
REVOKE ALL ON TABLE gruppi_funzioni FROM postgres;
GRANT ALL ON TABLE gruppi_funzioni TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE gruppi_funzioni TO masonsql;
GRANT SELECT ON TABLE gruppi_funzioni TO report;
 
 
--
-- Name: gruppi_funzioni_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE gruppi_funzioni_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE gruppi_funzioni_id_seq FROM postgres;
GRANT ALL ON SEQUENCE gruppi_funzioni_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE gruppi_funzioni_id_seq TO masonsql;
 
 
--
-- Name: gruppi_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE gruppi_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE gruppi_id_seq FROM postgres;
GRANT ALL ON SEQUENCE gruppi_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE gruppi_id_seq TO masonsql;
 
 
--
-- Name: gruppi_modifica; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE gruppi_modifica FROM PUBLIC;
REVOKE ALL ON TABLE gruppi_modifica FROM postgres;
GRANT ALL ON TABLE gruppi_modifica TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE gruppi_modifica TO masonsql;
GRANT SELECT ON TABLE gruppi_modifica TO report;
 
 
--
-- Name: gruppi_modifica_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE gruppi_modifica_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE gruppi_modifica_id_seq FROM postgres;
GRANT ALL ON SEQUENCE gruppi_modifica_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE gruppi_modifica_id_seq TO masonsql;
 
 
--
-- Name: logs; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE logs FROM PUBLIC;
REVOKE ALL ON TABLE logs FROM postgres;
GRANT ALL ON TABLE logs TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE logs TO masonsql;
GRANT SELECT ON TABLE logs TO report;
 
 
--
-- Name: logs_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE logs_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE logs_id_seq FROM postgres;
GRANT ALL ON SEQUENCE logs_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE logs_id_seq TO masonsql;
 
 
--
-- Name: messages; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE messages FROM PUBLIC;
REVOKE ALL ON TABLE messages FROM postgres;
GRANT ALL ON TABLE messages TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE messages TO masonsql;
GRANT SELECT ON TABLE messages TO report;
 
 
--
-- Name: messages_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE messages_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE messages_id_seq FROM postgres;
GRANT ALL ON SEQUENCE messages_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE messages_id_seq TO masonsql;
 
 
--
-- Name: messages_users; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE messages_users FROM PUBLIC;
REVOKE ALL ON TABLE messages_users FROM postgres;
GRANT ALL ON TABLE messages_users TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE messages_users TO masonsql;
GRANT SELECT ON TABLE messages_users TO report;
 
 
--
-- Name: messages_users_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE messages_users_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE messages_users_id_seq FROM postgres;
GRANT ALL ON SEQUENCE messages_users_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE messages_users_id_seq TO masonsql;
 
 
--
-- Name: recordset; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE recordset FROM PUBLIC;
REVOKE ALL ON TABLE recordset FROM postgres;
GRANT ALL ON TABLE recordset TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE recordset TO masonsql;
 
 
--
-- Name: recordset_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE recordset_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE recordset_id_seq FROM postgres;
GRANT ALL ON SEQUENCE recordset_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE recordset_id_seq TO masonsql;
 
 
--
-- Name: recordset_rows; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE recordset_rows FROM PUBLIC;
REVOKE ALL ON TABLE recordset_rows FROM postgres;
GRANT ALL ON TABLE recordset_rows TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE recordset_rows TO masonsql;
 
 
--
-- Name: recordset_rows_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE recordset_rows_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE recordset_rows_id_seq FROM postgres;
GRANT ALL ON SEQUENCE recordset_rows_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE recordset_rows_id_seq TO masonsql;
 
 
--
-- Name: report_id; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON TABLE report_id FROM PUBLIC;
REVOKE ALL ON TABLE report_id FROM postgres;
GRANT ALL ON TABLE report_id TO postgres;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE report_id TO masonsql;
GRANT SELECT ON TABLE report_id TO report;
 
 
--
-- Name: report_id_id_seq; Type: ACL; Schema: public; Owner: postgres
--
 
REVOKE ALL ON SEQUENCE report_id_id_seq FROM PUBLIC;
REVOKE ALL ON SEQUENCE report_id_id_seq FROM postgres;
GRANT ALL ON SEQUENCE report_id_id_seq TO postgres;
GRANT SELECT,UPDATE ON SEQUENCE report_id_id_seq TO masonsql;
 
 
--
-- PostgreSQL database dump complete
--
 
CREATE TABLE logs_report
(
id integer NOT NULL DEFAULT nextval(('logs_report_seq'::text)::regclass), -- Primary key
"timestamp" timestamp without time zone NOT NULL, -- Data e ora della modifica
table_name character varying(63) NOT NULL, -- Nome della tabella
report character varying(64000), -- Riepilogo delle variazioni
id_anagrafiche integer, -- Utente responsabile della modifica
id_record integer NOT NULL, -- ID record modificato
CONSTRAINT logs_report_pkey PRIMARY KEY (id ),
CONSTRAINT logs_report_id_anagrafiche FOREIGN KEY (id_anagrafiche)
REFERENCES anagrafiche (id) MATCH SIMPLE
ON UPDATE RESTRICT ON DELETE RESTRICT
)
WITH (
OIDS=FALSE
);
ALTER TABLE logs_report
OWNER TO postgres;
GRANT ALL ON TABLE logs_report TO postgres;
GRANT SELECT, UPDATE, INSERT, DELETE ON TABLE logs_report TO masonsql;
GRANT SELECT ON TABLE logs_report TO report;
COMMENT ON TABLE logs_report IS 'Report delle operazioni di variazione dei dati effettuati dall''interfaccia Web';
COMMENT ON COLUMN logs_report.id IS 'Primary key';
COMMENT ON COLUMN logs_report."timestamp" IS 'Data e ora della modifica';
COMMENT ON COLUMN logs_report.table_name IS 'Nome della tabella';
COMMENT ON COLUMN logs_report.report IS 'Riepilogo delle variazioni';
COMMENT ON COLUMN logs_report.id_anagrafiche IS 'Utente responsabile della modifica';
COMMENT ON COLUMN logs_report.id_record IS 'ID record modificato';
 
 
-- Index: logs_report_id_anagrafiche
 
-- DROP INDEX logs_report_id_anagrafiche;
 
CREATE INDEX logs_report_id_anagrafiche
ON logs_report
USING btree
(id_anagrafiche );
 
-- Index: logs_report_id_record
 
-- DROP INDEX logs_report_id_record;
 
CREATE INDEX logs_report_id_record
ON logs_report
USING btree
(id_record );
 
-- Index: logs_report_table
 
-- DROP INDEX logs_report_table;
 
CREATE INDEX logs_report_table
ON logs_report
USING btree
(table_name );
 
-- Index: logs_report_timestamp
 
-- DROP INDEX logs_report_timestamp;
 
CREATE INDEX logs_report_timestamp
ON logs_report
USING btree
("timestamp" );
 
GRANT SELECT ON TABLE funzioni TO report;
GRANT SELECT ON TABLE gruppi_funzioni TO report;
GRANT SELECT ON TABLE autorizzazioni TO report;
 
/tags/2.0/utility/sql/backuppc_cmd
0,0 → 1,109
#!/bin/bash
# Utility per effettuare il backup di PostgreSQL con BackupPC ( http://backuppc.sourceforge.net/ )
#
 
# Data del backup
DATE="$(date +%Y-%m-%d)"
 
# Esce immediatamente in caso di errore
set -e
 
# Versione del database
PSQL_VER="$1"
 
# Comando Pre / Post
CMD="$2"
if [ "$CMD" != "Pre" -a "$CMD" != "Post" ]
then
echo "ERROR: Command '$CMD' is not 'Pre' or 'Post'." >&2
exit 2
fi
 
# Cartella base dell'archivio PostgreSQL
PSQL_DIR="/var/lib/postgresql/$PSQL_VER"
 
if [ ! -d "$PSQL_DIR" ]
then
echo "ERROR: Directory $PSQL_DIR inexistent." >&2
exit 1
fi
 
if [ ! -d "$PSQL_DIR/archive" ]
then
mkdir "$PSQL_DIR/archive"
chown postgres.postgres "$PSQL_DIR/archive"
chmod 700 "$PSQL_DIR/archive"
fi
 
# tolgo l'eventuale "/" in fondo al nome della share
SHARE="${3%/}"
 
# Lanciato da BackuPC con la seguente configurazione
# $Conf{BackupFilesExclude} = {
# '/var/lib/postgresql/$PSQL_VER/main' => [
# '/pg_xlog/',
# '/postmaster.opts',
# '/postmaster.pid'
# ],
# '/' => [
# '/var/lib/postgresql/$PSQL_VER/'
# ]
# };
# $Conf{RsyncShareName} = [
# '/',
# '/var/lib/postgresql/$PSQL_VER/main',
# '/var/lib/postgresql/$PSQL_VER/archive'
# ];
# $Conf{DumpPreShareCmd} = '$sshPath -q -x -l root $host /opt/masonsql/utility/sql/backuppc_cmd $PSQL_VER Pre $share';
# $Conf{DumpPostShareCmd} = '$sshPath -q -x -l root $host /opt/masonsql/utility/sql/backuppc_cmd $PSQL_VER Post $share';
#
# Da creare
# mkdir /var/lib/postgresql/$PSQL_VER/archive
# chown postgres.postgres /var/lib/postgresql/$PSQL_VER/archive
# chmod 700 /var/lib/postgresql/$PSQL_VER/archive
# Configurazione nel file /etc/postgresql/$PSQL_VER/main/postgresql.conf
# wal_level = archive
# archive_command = 'test ! -f /var/lib/postgresql/$PSQL_VER/backup_in_progress || (test ! -f /var/lib/postgresql/$PSQL_VER/archive/%f && cp %p /var/lib/postgresql/$PSQL_VER/archive/%f)'
# archive_mode = on
# Da eseguire dopo modifica file:
# /etc/init.d/postgresql restart
#
# See: http://www.postgresql.org/docs/$PSQL_VER/static/continuous-archiving.html
#
# Ripristino
# Dopo aver recuperato gli archivi:
# Togliere eventuali file da /var/lib/postgresql/$PSQL_VER/main/pg_xlog/
# Verificare che non esista il file /var/lib/postgresql/$PSQL_VER/backup_in_progress - se esiste vuol dire che l'ultimo backup
# ha avuto problemi, quindi verificare i log in backuppc!
# Se non ci sono problemi:
# Copiare i file da /var/lib/postgresql/$PSQL_VER/archive/* a /var/lib/postgresql/$PSQL_VER/main/pg_xlog/
# Modificare pg_hba.conf per impedire l'accesso agli utenti
# Copiare /usr/share/postgresql/$PSQL_VER/recovery.conf.sample in /var/lib/postgresql/$PSQL_VER/main/recovery.conf
# Modificare la riga:
# restore_command = 'cp /var/lib/postgresql/$PSQL_VER/archive/%f %p'
# Lanciare postgresql e attendere il ripristino (il file recovery.conf viere rinominato in recovery.done)
# Verificare il contenuto del database
# Ripristinare gli accessi in pg_hba.conf e rilanciare il server
#
 
# Share del database
if [ "$SHARE" = "$PSQL_DIR/main" ]
then
cd "$PSQL_DIR"
if [ "$CMD" = "Pre" ]
then
touch $PSQL_DIR/backup_in_progress
echo "SELECT pg_start_backup('BackupPC_${DATE}');" | su -c 'psql postgres' postgres
fi
if [ "$CMD" = "Post" ]
then
rm $PSQL_DIR/backup_in_progress
echo "SELECT pg_stop_backup();" | su -c 'psql postgres' postgres
fi
fi
 
# Cancello i file archivio dopo averli copianti nella share .../archive
if [ "$SHARE" = "$PSQL_DIR/archive" -a "$CMD" = "Post" -a ! -f $PSQL_DIR/backup_in_progress ]
then
rm $PSQL_DIR/archive/*
fi
Property changes:
Added: svn:executable
+*
\ No newline at end of property
/tags/2.0/utility/sql/roles.sql
0,0 → 1,5
-- Utenti utilizzati nel framework
CREATE ROLE masonsql LOGIN PASSWORD '<password>' NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE;
CREATE ROLE report LOGIN PASSWORD '<password>' NOSUPERUSER INHERIT NOCREATEDB NOCREATEROLE;
/tags/2.0/utility/sql/create_database.sql
0,0 → 1,2
-- Creazione del database per il framework MasonSql
create database masonsql ENCODING = 'UTF8' LC_COLLATE = 'it_IT.UTF-8' LC_CTYPE = 'it_IT.UTF-8' TEMPLATE=template0;
/tags/2.0/utility/UpiPrinterServer/UpiPrinterServer.pl
0,0 → 1,451
# Copyright 2007 Guido Brugnara <gdo@leader.it>
#
# Il programma è distribuito con licenza duale:
# Commerciale oppure GPL (http://www.gnu.org/copyleft/gpl.html).
#
# L'autore è disponibile ad integrare le modifiche proposte da Terzi solo se il
# contributo viene rilasciato con licenza Perl Artistic Licence al fine di
# garantire all'autore la possibilità di applicare la licenza duale alla nuova
# versione.
 
my $release = '0.15';
$|=1;
use Win32;
use Win32::Daemon;
use Win32::EventLog;
use Win32::TieRegistry;
 
use IO::Select;
use URI::Escape;
use LWP::UserAgent;
use HTML::Entities;
use HTTP::Status;
use HTTP::Daemon::SSL;
 
use Win32::Printer::Direct;
use Win32::Printer::Enum;
 
my %print_errors = (
-1 => 'Memory allocation error',
-2 => 'Error opening the file',
-3 => 'Error opening the printer',
-4 => 'Error startint the print job',
-5 => 'Error writing to printer',
-6 => 'Error ending the print job',
-7 => 'Error closing printer'
);
 
use Data::Dumper;
use File::Temp qw(tempfile);
 
my $nameService = 'UpiPrinterServer';
 
# Nome del server HTTP che viene inviato al client
sub HTTP::Daemon::product_tokens {
"$nameService Rel:$release";
}
 
# Chiave di registry del servizio
$RegistryKeyName = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\$nameService";
# nome della stampante di default
$DefaultPrinterName = '';
# path file certificati
$CertsPath = '';
 
my $PORTNO = 22000; # porta di ascolto del server HTTPS
my $LOOP_PERIOD = 20; # millisecondi di intervallo per la verifica di chiamate pendenti
my $COUNT=0; # conteggio delle chiamate
 
# invio i messaggi di errore e warn al file Log di Windows
use Win32::EventLog::Carp { Source => $nameService };
 
my $Select = IO::Select->new();
 
# cartella certificati nello stesso percorso dell'eseguibile
$CertsDefaultDir = $0;
$CertsDefaultDir =~ s/[^\\]*$//;
$CertsDefaultDir .= 'certs';
 
 
if($ARGV[0] eq '-install'){
use Win32::GUI::Carp 'warningsToDialog';
# visualizza immediatamente il warning
$Win32::GUI::Carp::ImmediateWarnings = 1;
%Hash = (
machine => '',
name => $nameService,
display => 'UPI Printer Server',
path => $^X,
user => '',
pwd => '',
description => 'Server stampa via HTTPS',
parameters =>"\"$0\"",
);
if($0 =~ m/\.exe/i){
$Hash{'path'} = $0;
$Hash{'parameters'} = '';
}
if(Win32::Daemon::CreateService(\%Hash)){
# modifico nel Registry la configurazione del servizio
my $RegistryKeyService = new Win32::TieRegistry $RegistryKeyName or die "Can't access $RegistryKeyName key: $^E\n";
# con 0x110 l'applicazione può interagire con il desktop
$RegistryKeyService->SetValue('Type', '0x010', REG_DWORD) or die "Error on set Type entry: $^E\n";
# imposto la chiave per la stampate di default
$RegistryKeyService->SetValue('DefaultPrinterName', '', REG_SZ) or die "Error on set DefaultPrinterName entry: $^E\n";
# chiave percorso certificati
my $CertsDir = $ARGV[1] eq '-certs' ? $ARGV[2] : $CertsDefaultDir;
$RegistryKeyService->SetValue('CertsPath', $CertsDir, REG_SZ) or die "Error on set CertsPath entry: $^E\n";
# lancio il servizio
use Win32::Service;
Win32::Service::StartService('', $nameService);
warn "Servizio $nameService attivato!\n";
}else{
warn "Attivazione servizio $nameService fallito!:\n" . Win32::FormatMessage( Win32::Daemon::GetLastError() ) . "\n";
}
exit;
}elsif($ARGV[0] eq '-remove'){
use Win32::GUI::Carp 'warningsToDialog';
# visualizza immediatamente il warning
$Win32::GUI::Carp::ImmediateWarnings = 1;
my $name = $nameService;
 
# fermo il servizio prima di disinstallarlo
use Win32::Service;
Win32::Service::StopService('', $nameService);
 
if( Win32::Daemon::DeleteService('', $name ) ) {
warn "Servizio $nameService disinstallato.\n";
} else {
warn "Disattivazione servizio $nameService fallito:\n" . Win32::FormatMessage( Win32::Daemon::GetLastError() ) . "\n";
}
exit;
}elsif($ARGV[0] eq '-debug'){
# esecuzione demone da riga di comando (si presuppone che i parametri nel registry siano presenti)
InitVariables();
openHTTPS();
while(1){
runningHTTPS();
}
closeHTTPS();
exit;
}
 
# EVENTLOG_ERROR_TYPE: An Error event is being logged.
# EVENTLOG_WARNING_TYPE: A Warning event is being logged.
# EVENTLOG_INFORMATION_TYPE: An Information event is being logged.
#
 
sub Log($;$) {
my ($mess,$type) = @_;
defined $type or $type = EVENTLOG_INFORMATION_TYPE;
my $EventLog = new Win32::EventLog( $nameService ) || die $!;
$EventLog->Report({ EventType => $type,
Strings => $mess,
}) || die $!;
}
 
# MB_ICONSTOP "X" in a red circle
# MB_ICONQUESTION question mark in a bubble
# MB_ICONEXCLAMATION exclamation mark in a yellow triangle
# MB_ICONINFORMATION "i" in a bubble
#
 
sub Die($;$){
my ($mess, $type) = @_;
Log $mess;
AlertFork $mess, $type;
die $mess."\n";
}
 
sub Alert($;$){
my ($mess, $type) = @_;
defined $type or $type = MB_ICONEXCLAMATION;
Log $mess;
Win32::MsgBox($mess, $type, $nameService);
}
 
sub AlertFork($;$){
my ($mess, $type) = @_;
defined $type or $type = MB_ICONEXCLAMATION;
if(!defined(my $pid = fork)){
Win32::MsgBox("Error to start kild process", MB_ICONEXCLAMATION, "UPI Printer Server");
die "Error to start kild process";
}else{
if($pid == 0){
# processo figlio
Alert($mess, $type);
exit;
}
}
}
 
sub openHTTPS(){
my $SSL_key_file = $CertsPath.'\server-key.pem';
my $SSL_cert_file = $CertsPath.'\server-cert.pem';
# verifico la presenza dei certificati
if(! -e $SSL_key_file){
Die "File $SSL_key_file don't exist\n";
}
if(! -e $SSL_cert_file){
Die "File $SSL_cert_file don't exist\n";
}
my $daemon = new HTTP::Daemon::SSL(
LocalAddr => '127.0.0.1',
SSL_key_file => $SSL_key_file,
SSL_cert_file => $SSL_cert_file,
LocalPort => $PORTNO
);
if(!$daemon){
Die("HTTPS server: error on open [$@]\n");
}
$Select->add($daemon);
Log "Start local HTTPS server on port $PORTNO\n";
}
sub closeHTTPS(){
for my $daemon ($Select->handles){
$Select->remove($daemon);
undef $daemon;
}
Log "Stop local HTTPS server on port $PORTNO\n";
}
 
sub runningHTTPS(){
if(my @ready = $Select->can_read(int($LOOP_PERIOD * 0.1))){
foreach my $daemon (@ready){
$COUNT++;
if(my $connect = $daemon->accept){
$connect->autoflush(1);
my $from = $connect->peerhost;
if($from ne '127.0.0.1'){
# solo le chiamate locali vengono accettate
$connect->send_error(RC_FORBIDDEN);
}else{
my $request = $connect->get_request(1);
if(!$request){
# in IE con SSL alla richiesta del certificato non attendibile non è definito l'oggetto request
next;
}
my $url = $request->url; #->path;
my $content = $request->content;
my $method = $request->method;
if($url =~ m|^/printers$|i || $url =~ m|^/set_default/.*|i || $url =~ m|^/$|){
if($url =~ m|^/set_default/(.*)|i){
$DefaultPrinterName = uri_unescape($1);
# imposto la chiave per la stampate di default
my $RegistryKeyService = new Win32::TieRegistry $RegistryKeyName or die "Can't access $RegistryKeyName key: $^E\n";
$RegistryKeyService->SetValue('DefaultPrinterName', $DefaultPrinterName, REG_SZ) or die "Error on set DefaultPrinterName entry: $^E\n";
undef $RegistryKeyService;
}
my $message = qq|
<html>
<head><title>UPI Printer Server - Lista stampanti disponibili</title></head>
<body>
<h1>UPI Printer Server</h1>
<h2>Lista stampanti disponibili</h2>
<p>Selezionare la stampante che si desidera venga utilizzata (<cite>default</cite>):</p>
<ul>
|;
my @printers = Printers();
foreach my $printer (@printers){
$message .= '<li><A href="/set_default/' . uri_escape($printer->{PrinterName}) . '">'
. encode_entities($printer->{PrinterName}) . "</A></li>\n";
}
$message .= qq|
</ul>
<p>Attuale stampante selezionata (<cite>default</cite>): <b>| .
encode_entities($DefaultPrinterName) . q|</b></p>
</body>
<script>
//document.domain = 'leader.it';
</script>
</html>
|;
$message =~ s/^\s+//m;
my $response = HTTP::Response->new(RC_OK, 'List printers');
$response->header( 'Content-Type' => 'text/html');
$response->content($message);
$connect->send_response($response);
}elsif($url =~ m|^/print/(.*)|i || $url =~ m|^/print$|i){
my $printer_name = $1 ? uri_unescape($1) : $DefaultPrinterName;
if($printer_name){
if($request->method eq 'POST'){
my ($fh, $file_name) = tempfile();
# copio dal buffer nel file temporaneo.
print $fh $request->content;
close $fh;
my $err = Printfile($printer_name, $file_name);
if($err == 1){
my $response = HTTP::Response->new(RC_ACCEPT, 'Print OK');
$response->header( 'Content-Type' => 'text/plain');
$response->content('Print OK');
$connect->send_response($response);
}else{
$connect->send_error(RC_INTERNAL_SERVER_ERROR, "Print to $printer_name with error $err: $print_errors{$err}")
}
}else{
$connect->send_error(RC_METHOD_NOT_ALLOWED, 'Only POST method is allowed');
}
}else{
$connect->send_error(RC_NOT_FOUND, 'No default printer');
}
}elsif($url =~ m|^/from_server/([\w\.]+)/(\w+)/(.+)$|i || $url =~ m|^/from_server/([\w\.]+)/(\w+)|i){
my $file = $2;
my $URL = "https://$1/UpiPrinterServer.txt?file=$file";
my $printer_name = $3 ? uri_unescape($3) : $DefaultPrinterName;
if($printer_name){
# effettuo la chiamata indicata
my $user_agent = LWP::UserAgent->new;
$user_agent->agent($daemon->product_tokens);
$user_agent->timeout(5);
my $user_request = HTTP::Request->new(GET => $URL);
my $user_response = $user_agent->request($user_request);
if($user_response->is_success){
my ($fh, $file_name) = tempfile();
# copio dal buffer nel file temporaneo.
print $fh $user_response->content;
close $fh;
my $err = Printfile($printer_name, $file_name);
if($err == 1){
$connect->send_response(Response('printed', "File $file printed to $printer_name"));
}else{
my $code = -$err;
$connect->send_response(Response("print_err_$code", "Print to $printer_name with error $err: $print_errors{$err}"));
}
}else{
$connect->send_response(Response('remote_err_'.$user_response->code, 'Remote server error: '.$user_response->status_line."\n"));
}
}else{
$connect->send_response(Response('no_print_default', 'No default printer is selected'));
}
}else{
$connect->send_error(RC_NOT_FOUND, 'Command mismatch');
}
}
$connect->close;
}else{
Log "Error to connect: $@\n";
}
}
}
}
 
# prepara la risposta da inviare
sub Response($$){
my($status, $status_mess) = @_;
$status =~ s/'/\\'/sg;
$status_mess =~ s/'/\\'/sg;
$status_mess =~ s/\n/\\n/sg;
my $response = HTTP::Response->new(RC_ACCEPT, 'Print OK');
$response->header( 'Content-Type' => 'text/plain');
$response->content(qq|
if(UpiPrinterServerHandler){
UpiPrinterServerHandler('$status', '$status_mess');
}else{
alert('printed!\\nFile $file printed to $printer_name');
}
|);
return $response;
}
 
#---------------------------------------------- Callbacks
sub Callback_Running {
my( $Event, $Context ) = @_;
# Note that here you want to check that the state
# is indeed SERVICE_RUNNING. Even though the Running
# callback is called it could have done so before
# calling the "Start" callback.
if( SERVICE_RUNNING == Win32::Daemon::State() )
{
# ... process your main stuff here...
# ... note that here there is no need to
# change the state
# AlertFork('Running '.$count++.' ...');
runningHTTPS();
# AlertFork("Running $count.");
}
}
 
sub InitVariables(){
# impostazione stampate di default
my $RegistryKeyService = new Win32::TieRegistry $RegistryKeyName or die "Can't access $RegistryKeyName key: $^E\n";
$DefaultPrinterName = $RegistryKeyService->GetValue('DefaultPrinterName');
# Path cartella dei certificati
$CertsPath = $RegistryKeyService->GetValue('CertsPath');
undef $RegistryKeyService;
}
 
sub Callback_Start {
my( $Event, $Context ) = @_;
# Initialization code
# ...do whatever you need to do to start...
#AlertFork('Callback_Start ...');
InitVariables();
openHTTPS();
$Context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State( SERVICE_RUNNING );
#AlertFork('Callback_Start.');
}
 
sub Callback_Pause {
my( $Event, $Context ) = @_;
#AlertFork('Callback_Pause ...');
closeHTTPS();
$Context->{last_state} = SERVICE_PAUSED;
Win32::Daemon::State( SERVICE_PAUSED );
#AlertFork('Callback_Pause.');
}
 
sub Callback_Continue {
my( $Event, $Context ) = @_;
#AlertFork('Callback_Continue ...');
openHTTPS();
$Context->{last_state} = SERVICE_RUNNING;
Win32::Daemon::State( SERVICE_RUNNING );
#AlertFork('Callback_Continue.');
}
 
sub Callback_Stop {
my( $Event, $Context ) = @_;
#AlertFork('Callback_Stop ...');
closeHTTPS();
$Context->{last_state} = SERVICE_STOPPED;
Win32::Daemon::State( SERVICE_STOPPED );
# We need to notify the Daemon that we want to stop callbacks and the service.
Win32::Daemon::StopService();
#AlertFork('Callback_Stop.');
}
 
Win32::Daemon::RegisterCallbacks( {
start => \&Callback_Start,
running => \&Callback_Running,
stop => \&Callback_Stop,
pause => \&Callback_Pause,
continue => \&Callback_Continue,
} );
 
%Context = (
last_state => SERVICE_STOPPED,
start_time => time(),
);
 
if(! defined $ENV{'USERNAME'}){
Win32::Daemon::StartService(undef, $LOOP_PERIOD);
}else{
warn qq|
Utilizzare il parametro -install per installare il servizio
oppure -remove per disinstallarlo.
 
Aggiungere una seconda opzione [-certs <percorso>] per
indicare la cartella contenente i certificati SSL del server
(default: $CertsDefaultDir)
 
In caso di errore è possibile lanciare il server con l'opzione
[-debug] da riga di comando (si presuppone che il servizio
sia installato e che i parametri siano stati configurati nel
registry).
|;
}
exit;
 
/tags/2.0/utility/UpiPrinterServer/INSTALLAZIONE.txt
0,0 → 1,67
UpiPrinterServer versione 0.15
 
 
PREREQUISITI
---------------------------------------------------------------
Il driver è stato verificato su Windows XP SP2.
 
Verificare che sul browser utilizzato (Internet Explorer o Mozilla Firefox)
sia installato il certificato che autentica il servizio:
 
 
Per Internet Explorer:
- aprire la pagina web https://srl.leader.it/ca.leader.it/ca.leader.it.cert.der
- selezionare [Apri] nella maschera che compare
- installare il certificato con il pulsante che compare nella maschera
successiva
- confermare tutte le successive maschere fino a conclusione
 
 
Per FireFox:
- aprire la pagina web https://srl.leader.it/ca.leader.it/ca.leader.it.cert.der
- selezionare [Accetta questo certificato in modo permanente] e
confermare
- scegliere la voce [Dai fiducia a questo CA per l'identificazione dei siti
WEB] e confermare
 
 
 
AGGIORNAMENTO
---------------------------------------------------------------
Per aggiornare è necessario prima disinstallare e
successivamente installare.
 
 
 
DISINSTALLAZIONE
---------------------------------------------------------------
Eseguire il comando di disinstallazione:
C:\Programmi\UpiPrinterServer\UpiPrinterServer.exe -remove
 
Cancellare la cartella C:\Programmi\UpiPrinterServer
 
 
 
INSTALLAZIONE
---------------------------------------------------------------
Spostare la cartella UpiPrinterServer contenuta nel file
UpiPrinterServer.zip nella cartella del PC: C:\Programmi
 
 
Eseguire il comando di installazione:
C:\Programmi\UpiPrinterServer\UpiPrinterServer.exe -install
 
 
Verificare che il servizio "UpiPrinterServer" sia attivo:
https://localhost:22000
 
 
Selezionare la stampante desiderata per la stampa dalla pagina Web visualizzata.
 
 
Verificare se il servizio lavora utilizzando la pagina di test:
 
https://sois.provincia.tn.it/test/test_UpiPrinterServer.html
 
 
/tags/2.0/utility/UpiPrinterServer/LEGGIMI.txt
0,0 → 1,85
UpiPrinterServer versione 0.15
 
Installare il Perl di ActiveState 5.8.8 Build 822
 
Repository utilizzati per reperire i package installati:
 
ppm rep add theoryx5.uwinnipeg.ca http://theoryx5.uwinnipeg.ca/ppms/
ppm rep add trouchelle.com http://trouchelle.com/ppm/
ppm rep add www.bribes.org http://www.bribes.org/perl/ppm
 
#ppm rep add "ActiveState PPM2 Repository" #http://ppm.ActiveState.com/cgibin/PPM/ppmserver-5.8-windows.pl?urn:/PPMServer
#ppm rep down "ActiveState Package Repository"
#ppm rep down "ActiveState Package Repository"
#ppm rep down "ActiveState Package Repository"
#ppm rep down "ActiveState Package Repository"
http://ppm4.activestate.com/MSWin32-x86/5.8/822/package.xml
 
 
Package da installare oltre la base standard di ActiveState:
 
#ppm install Net_SSLeay.pm
ppm install Net-SSLeay
ppm install HTTP-Daemon-SSL
ppm install Win32-Printer
ppm install Win32-EventLog-Carp
ppm install Win32-GUI-Carp
 
# http://www.roth.net/perl/Daemon/
ppm install http://www.roth.net/perl/packages/win32-daemon.ppd
 
L'applicazione è reperibile nel repository SVN:
https://svn.leader.it/wsvn/masonsql/utility/UpiPrinterServer/
 
 
 
 
COMPILAZIONE
---------------------------------------------------------------
Installare i package per la compilazione
 
ppm install Getopt-ArgvFile
ppm install PAR-Packer
 
# Se si vuole offuscare il codice:
ppm install B-Deobfuscate
 
 
utilizzare lo script di compilazione:
 
compile.bat UpiPrinterServer
 
Verrà creato il file: UpiPrinterServer.exe
 
 
 
INSTALLAZIONE
---------------------------------------------------------------
Creare la cartella "C:\Programmi\UpiPrinterServer"
Copiare nella cartella il file "UpiPrinterServer.exe" e la
cartella "certs" contenente i certificati:
server-cert.pem
server-key.pem
 
Eseguire il comando di installazione:
C:\Programmi\UpiPrinterServer\UpiPrinterServer.exe -install
 
Verificare che il servizio "UpiPrinterServer" sia attivo:
 
Selezionare la stampante dalla pagina Web:
https://localhost:22000
e selezionando dalla pagina il link della stampante desiderata.
 
Verificare se il servizio lavora utilizzando https://<SERVER>/test/test_UpiPrinterServer.html
 
Per disinstallare il servizio:
C:\Programmi\UpiPrinterServer\UpiPrinterServer.exe -remove
 
 
Per verificare il servizio nel caso si blocchi durante l'utilizzo.
Assicurarsi che il servizio "Upi Printer Server" sia fermo; lanciare da una console il comando:
 
C:\Programmi\UpiPrinterServer\UpiPrinterServer.exe -debug
 
e utilizzare il servizio.
 
/tags/2.0/utility/UpiPrinterServer/compile.bat
0,0 → 1,8
REM compila il file .pl in .exe
REM NOTA: le DLL ssleay32.dll e libeay32.dll non si trovano in C:/WINDOWS/system32 copiarle da C:\Perl\site\lib\auto\Net\SSLeay\
 
perl -x -S pp -B -f Bleach -f Obfuscate --gui -p -l C:/WINDOWS/system32/ssleay32.dll -l C:/WINDOWS/system32/libeay32.dll -o %1.par %1.pl
 
parl -B -O./%1.exe %1.par
 
del %1.par
/tags/2.0/utility/UpiPrinterServer/certs/server-cert.pem
0,0 → 1,16
-----BEGIN CERTIFICATE-----
MIIChjCCAe8CCQDL59rbpzVtpTANBgkqhkiG9w0BAQQFADCBiDELMAkGA1UEBhMC
SVQxETAPBgNVBAgTCFRyZW50aW5vMRIwEAYDVQQKEwlMZWFkZXIuSVQxGTAXBgNV
BAsTEFBvbG8gVGVjbm9sb2dpY28xFTATBgNVBAMTDGNhLmxlYWRlci5pdDEgMB4G
CSqGSIb3DQEJARYRc3VwcG9ydEBsZWFkZXIuaXQwHhcNMDcwNTAyMDk1OTI2WhcN
MDkwNTAxMDk1OTI2WjCBhTELMAkGA1UEBhMCSVQxETAPBgNVBAgTCFRyZW50aW5v
MRIwEAYDVQQKEwlMZWFkZXIuSVQxGTAXBgNVBAsTEFBvbG8gVGVjbm9sb2dpY28x
EjAQBgNVBAMTCWxvY2FsaG9zdDEgMB4GCSqGSIb3DQEJARYRc3VwcG9ydEBsZWFk
ZXIuaXQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBALAD3+y9vCaorWUtIfb+
UCAh5lLDGporU6WcN1xsEAfRxACM6YeKdLRqsulOGrIPRpqiGE87NNTe+20gTvRi
WuBCAkDXf7QegnTPhJ+Jsg9XnjlGs+hAIRDQ7zY0C7KqQ0hMWoPpJ72viObk9XcR
3uQS4fGMpiFAWc1UhfJtzXcnAgMBAAEwDQYJKoZIhvcNAQEEBQADgYEAfI51q/ZP
UihpTTaIsOZY62x00OdqRN5YpTyHx1gkkte3kXq7A50Pm0b2qLcYSeR9smUVoH9p
bKCqrqyUBbpAqkBAPJzTj2jg1K0ZUscMaeuZ/B3/SY0GmJfuwgyEhHnqXYOPMJyT
y4DYA4/zT1F+IgZ1HOOzfqtAI6mCV/2mC24=
-----END CERTIFICATE-----
/tags/2.0/utility/UpiPrinterServer/certs/server-key.pem
0,0 → 1,15
-----BEGIN RSA PRIVATE KEY-----
MIICWwIBAAKBgQCwA9/svbwmqK1lLSH2/lAgIeZSwxqaK1OlnDdcbBAH0cQAjOmH
inS0arLpThqyD0aaohhPOzTU3vttIE70YlrgQgJA13+0HoJ0z4SfibIPV545RrPo
QCEQ0O82NAuyqkNITFqD6Se9r4jm5PV3Ed7kEuHxjKYhQFnNVIXybc13JwIDAQAB
AoGAO8mFJVApeeQvyb8z20b1BoUdTB1zisyOxCE0+NLH+y/4aMt0g5K3I5Veojri
fHsN23aV1UviHTCErMOdrgs+nH97r/0mH2R8X1T3BqF8Y0oi7rx6vF63FePm3Nlk
hxSCREIwcOIFFFxTABMXbpozAS6J68tNETjC8gScAY08fCECQQDmlevxGWzYuQyG
4sY+QGH3q3dv4AEf/D3Af9nNFDBnaC9LlHKLsc2rnZETPJVbuIYS2TfwY09sclbr
9jBnE+oXAkEAw2o4wvSYaLzc72Zu7Qp3ymObhEOpMXgQxeI/hd/TNXFkmSycpZ+K
OYoQcGdofraVXbYbDuq8UykVbFJeknLVcQJAIlCjWTD4ctQvGg+7gt4f9jStRJfo
cvMd2XztU8iyX2Ew0KWZ2lIukmCTi3JTo9+1DC8JVRviYPgvGVR85YogJwJAE6D8
2KBnGsY1zxpT9B2EEOFWgr+lJCHyVV43kUP9XDXqq/QuO/i9krAKnK/WcDv43vPm
3eW4SwYqb7oKY92DEQJAHCAHKwZ7KwPL40ZviRYJgcd8oqIm3VfLxYHiHLduzGZc
EsQe+I9LObfAJjiiwYvonyVbro0koR9dmeJ6quTeOA==
-----END RSA PRIVATE KEY-----
/tags/2.0/COPYRIGHT
0,0 → 1,14
# --------------------------------------------------------------------------- #
# Copyright: (C) 2003-2017 Guido Brugnara <http://www.leader.it>
# Strada della Pozzata, 41 - Villazzano
# 38123 T R E N T O (ITALY)
# E-mail: info@leader.it
#
# Note: The authors with the rispettive contributions are available
# in restricted access of SVN repository at
# https://www.leader.it/wsvn/masonsql
# --------------------------------------------------------------------------- #
#
Double licence are available, if requested, with differents prices and conditions:
- AGPL Affero General Public Licence Rel.1 ( http://www.affero.org/oagpl.html )
- Commercial licence
/tags/2.0/doc/MasonSQL_CRUD.txt
0,0 → 1,416
 
MasonSQL - interfaccia CRUD - versione 1.6.1
 
Nel documento viene descritta l'interfaccia per lo scambio dei dati per le classiche operazioni di Creazione(Create), Lettura(Retrieve), Aggiornamento(Update) e Cancellazione(Delete).
 
L'interfaccia di comunicazione tra il client di accesso ed il server è disponibile esclusivamente con il protocollo standard HTTPS, con autenticazione basic.
 
Per esigenze di compatibilità con le versioni precedenti di MasonSQL e per agevolare lo sviluppo dei client di accesso sono stati utilizzati esclusivamente i metodi di accesso GET e POST.
 
Nella URI viene codificata la classe dell'oggetto che si vuole leggere, modificare, ecc.
 
Esempi:
https://masonsql.leader.it/dbms/campionamenti
https://masonsql.leader.it/dbms/parametri
https://masonsql.leader.it/dbms/formulari/siti
 
Nella URL (Uniform Resource Locator) della chiamata viene codificato anche il metodo richiesto e la chiave univoca dell'oggetto richiesto.
 
Esempi:
https://masonsql.leader.it/dbms/campionamenti?method=update&key=12
https://masonsql.leader.it/dbms/parametri?key=888
https://masonsql.leader.it/dbms/parametri?method=select&key=23
https://masonsql.leader.it/dbms/campionamenti?method=delete&key=4
https://masonsql.leader.it/dbms/parametri?method=newkey
https://masonsql.leader.it/dbms/parametri?method=insert&key=33
https://masonsql.leader.it/dbms/campionamenti?method=xls
 
Ciascuna chiamata è di tipo atomico, o "stateless"; ovvero si conclude con una operazione completata con la risposta del server; non richiede successive interazioni.
 
Unica eccezione, se così si può dire impropriamente, è data dal metodo "newkey" che ritorna una chiave utilizzabile per l'inserimento successivo di un nuovo oggetto.
Se la chiave non viene poi utilizzata per inserire un nuovo oggetto, ciò non costituisce un problema.
 
I dati degli oggetti (record delle tabelle) vengono scambiati nel formato XML con charset UTF-8.
 
Per compatibilità con le versioni precedenti di MasonSQL lo schema utilizzato per la risposta è il seguente:
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="retrieve" user="administrator" timestamp="28/04/2010 07:45:17.997114 CEST" start="0" rows="1" max_rows="1529">
<campionamenti id="..." ... />
</dbms>
 
Il TAG <dbms ... > identifica il percorso iniziale della URI e racchiude il TAG il cui nome identifica la classe dell'oggetto (il nome della tabella è rappresentato nel formato "schema.tabella" con un punto come separatore ).
Nel TAG <dbms ... > sono definiti alcuni attributi:
method - metodo richiesto
user - corrisponde all'utente che ha effettuato la richiesta
timestamp - data di riferimento della transazione.
Attributi presenti solo con method=retrieve:
start - offset del primo record restituito
rows - numero di record restituiti
max_rows - numero dei record elaborati
 
Nella URI il nome della tabella da "schema.tabella" viene codificato con "schema/tabella".
In mancanza di indicazione dello schema si intende che la tabella è presente nello schema di "default" (Schema: "public").
 
ATTENZIONE: Nelle operazioni di modifica ed inserimento è obbligatorio utilizzare il TAG corrispondente all'oggetto identificato nella URI.
 
I campi della tabella vengono rappresentati nello schema XML utilizzando parametri del TAG:
 
Esempio:
<?xml version="1.0" encoding="utf-8"?>
<dbms method="retrieve" user="administrator" timestamp="28/04/2010 07:48:19.200846 CEST" start="0" rows="1" max_rows="1">
<campionamenti stato_rapporto="firmato" data_ingresso="01/01/2010" persona_prelievo="1135"
persona_responsabile3="" id_laboratorio="12" data_inizio_prova="01/01/2010"
persona_responsabile2="" stato="Completato" durata_prelievo="" id="1136"
id_tipi_campionamenti="514" osservazioni="" persona_responsabile="41" id_sito="41"
data_fine_prova="09/10/2000" codice="[555444/03]" ora_prelievo="11:40"
data_prelievo="03/10/2000" id_rapporto="1114"/>
</dbms>
 
I parametri (campi della tabella) contenenti caratteri riservati e/o proibiti (Es: '<' '&' <CR> ) devono essere codificati (Es: '&lt;' '&amp;' '\n').
 
 
Gestione dei permessi
 
L'interfaccia è accessibile con autenticazione basic (password protetta dal canale cifrato SSL del protocollo HTTPS).
L'utente che accede eredita i diritti in base ai gruppi di appartenenza, così come gestiti nelle applicazioni. Se l'utente appartiene ad una ditta di gestione o ad un laboratorio avrà diritto di accedere agli oggetti inerenti, così come accade attraverso l'interfaccia nel browser.
 
 
NOME CHIAVE
 
Le classi di oggetti (le tabelle) utilizzano come chiave univoca un campo che non ha un nome univoco ma può cambiare in ciascuna tabella, anche se è comunque un parametro di progetto e quindi non cambia nel tempo.
Il nome di "default" è "id", ma per esser certi è possibile reperire il nome della chiave univoca utilizzata nell'oggetto utilizzando il metodo "keyname":
 
https://masonsql.leader.it/dbms/campionamenti?method=keyname
 
Verrà restituito il seguente documento XML contenente il nome del campo chiave:
 
Esempio:
Codice: 200 OK
Content-Type: text/xml; charset=utf-8
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="keyname" user="admin" timestamp="28/04/2010 12:03:10" >
<campionamenti keyname="id" />
</dbms>
 
In caso di errore il server risponderà con errore (400) accompagnato da un documento contenente il messaggio dell'errore.
 
 
INFO
 
Con il metodo "info" viene restituito un documento XML contenenete una serie di informazioni utili sull'oggetto.
 
https://masonsql.leader.it/dbms/campionamenti?method=info
 
Verrà restituito il seguente documento XML:
 
Esempio:
Codice: 200 OK
Content-Type: text/xml; charset=utf-8
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="info" user="admin" timestamp="28/04/2010 12:00:00" >
<campionamenti keyname="id" log="0" delete="1" print="1" insert="1" dbms="1" xls="1"
printsel="1" update="1" select="1" father_name="" father_id_name="" father_key_name="" >
<field size="4" name="id" type="integer" descr="" primary_key="1" notnull="1" />
<field size="4" name="id_sito" type="integer" descr="Sito prelievo" notnull="1" />
<field size="4" name="data_prelievo" type="date" descr="Data di prelievo" />
......
<field size="500" name="osservazioni" type="character" descr="Osservazioni" />
<child field="id" table="parametri" key="id_campione" />
<relation field="persona_responsabile" table="anagrafiche" />
<relation field="id_sito" table="siti" />
......
<relation field="cod_campionamenti" table="cod_campionamenti" key="codice" />
</campionamenti>
</dbms>
 
<field/> identifica le caratteristiche di un attributo
<child/> identifica la relazione con un oggetto figlio (relazione n:1)
<relation/> identifica la relazione con un diverso oggetto (relazione 1:n)
 
Attenzione che <child/> e <relation/> compaiono se nella dichiarazione degli oggetti vengono descritte le rispettive relazioni (metodi ENTITY_CHILDREN e ENTITY_RELATIONS).
 
 
NUMERO DEI RECORD PRESENTI
 
Con il metodo "numrec" viene restituito un documento XML contenente la quantità di record presente in archivio che l'utente può recuperare.
 
https://masonsql.leader.it/dbms/campionamenti?method=numrec
 
Metodo della chiamata: GET
Parametri:
method => 'numrec'
father_key => 'FFFF' - chiave univoca del "padre" (obbligatoria se l'oggetto ha un padre)
 
Esempio:
Codice: 200 OK
Content-Type: text/xml; charset=utf-8
 
<dbms method="numrec" user="admin" timestamp="28/04/2010 12:00:00" >
<campionamenti numrec="1780" />
</dbms>
 
 
LETTURA
 
La URL per effettuare una operazione di lettura di un oggetto è costruita nel modo seguente:
 
https://masonsql.leader.it/dbms/parametri?method=retrieve&key=NNNN
oppure
https://masonsql.leader.it/dbms/parametri?method=retrieve&father_key=NNNN
 
E' possibile inoltre ricercare più oggetti utilizzando la seguente forma
https://masonsql.leader.it/dbms/parametri?method=retrieve&rows=10&where=campione like 'mycode%'
 
Attenzione: Nell'esempio i caratteri come ad esempio lo spazio nella URL vanno convertiti (lo spazio viene convertito con %20).
Per maggior chiarezza questi caratteri vengono mostrati nell'esempio senza conversione, anche perché alcuni browser ne permettono l'utilizzo in quanto effettuano la conversione prima della trasmissione al server.
 
Metodo della chiamata: GET
Parametri:
method => 'retrieve'
key => 'NNNN' - chiave univoca dell'oggetto da recuperare (generalmente è un numero naturale)
father_key => 'FFFF' - chiave univoca del "padre"
rows => 'RRR' - Numero di righe di record da ritornare
(quando non si utilizza il parametro 'key', limitato a 65536)
start => 'SSS' - Posizione da cui mostrare i dati (0 corrisponde alla prima riga)
where => "codice='XXX'" - query di ricerca limitata agli operatori di confronto =, !=, <, >, <=, >=, like, *~ e l'operatore "and"
 
Esempi:
https://masonsql.leader.it/dbms/parametri?key=888
https://masonsql.leader.it/dbms/parametri?method=retrieve&key=23
https://masonsql.leader.it/dbms/parametri?method=retrieve&father_key=700
https://masonsql.leader.it/dbms/parametri?method=retrieve&father_key=700&where=cod_campionamenti='biogas'
 
La risposta del server sarà un documento XML contenente il record richiesto (con parametro "key") o i record collegati all'oggetto "padre" oppure il risultato della query di ricerca.
 
Esempio:
Codice: 200 OK
Content-Type: text/xml; charset=utf-8
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="retrieve" user="admin" timestamp="28/04/2010 12:00:00" start="0" rows="2" max_rows="1801">
<parametri parametro="Quantità media dei liquami" risultato="22" id_campione="11111" ord="0"
id_metodo="321" um="mc/h" cod_parametri="Qmedia" incertezza="" tipo="N" metodo="Portata"
parametro_metodo="" id="24335" sinal="0" valore="20" />
<parametri parametro="Coefficente Rip. Portata" risultato="0.17" id_campione="11111" ord="1"
id_metodo="313" um="." cod_parametri="coeff_ripp" incertezza="" tipo="K" metodo="CoeffRPot"
parametro_metodo="" id="243334" valore="0.2225" />
</dbms>
 
 
In caso di errore il server risponderà con errore (400) accompagnato da un documento contenente il messaggio dell'errore.
La chiave del padre è obbligatoria se è dichiarato il padre.
Per accedere ad un intero set di record di grande dimensione, maggiore del limite imposto a rows di 65536 record utilizzare il parametro start.
Per recuperare gli ultimi record del recordset, utilizzare il metodo "numrec" per conoscere il numero di record presenti e poi eseguire un metodo retrieve con start = numrec - rows.
 
 
 
NUOVA CHIAVE
 
E' possibile inserire un nuovo oggetto sia fornendo la chiave univoca oppure non fornendo la chiave univoca.
Nel primo caso è possibile reperire una chiave univoca utilizzabile effettuando una chiamata (GET) con URI la classe dell'oggetto (la tabella) e con metodo newkey:
 
https://masonsql.leader.it/dbms/campionamenti?method=newkey
 
Verrà restituito il seguente documento XML contenente il codice univoco utilizzabile per inserire un nuovo documento:
 
Esempio:
Codice: 200 OK
Content-Type: text/xml; charset=utf-8
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="newkey" user="admin" timestamp="28/04/2010 12:00:00" >
<campionamenti key="1136" keyname="id" />
</dbms>
 
In caso di errore il server risponderà con errore (400) accompagnato da un documento contenente il messaggio dell'errore.
 
 
CREAZIONE
 
La URL per effettuare l'operazione di inserimento di un nuovo oggetto è costruita nel modo seguente:
 
https://masonsql.leader.it/dbms/campionamenti?method=create&key=NNNN&father_key=FFFF
 
Metodo della chiamata: POST
Parametri:
method => 'create'
key => 'NNNN' chiave univoca del nuovo oggetto (parametro opzionale)
father_key => 'FFFF' chiave univoca dell'oggetto "padre" (parametro opzionale)
Esempi:
https://masonsql.leader.it/dbms/campionamenti?method=create&key=1136
https://masonsql.leader.it/dbms/parametri?method=create&key=1137&father_key=12
https://masonsql.leader.it/dbms/parametri?method=create&father_key=120
 
<dbms>
<campionamenti stato_rapporto="firmato" persona_prelievo="134"
id_tipi_campionamenti="491" osservazioni="" persona_responsabile="241" id_sito="101" />
</dbms>
 
 
Nel caso non venga fornita la chiave univoca il server inserirà un nuovo record attribuendo una chiave univoca reperibile nel documento contenente il record creato.
I campi non forniti resteranno vuoti oppure inizializzati con i valori di "default" se previsti.
 
ATTENZIONE: Si sconsiglia di effettuare creazioni senza la chiave univoca in quanto in caso di problemi nella comunicazione c'è il rischio di inserire più record uguali, oppure di non conoscere la chiave del record appena inserito.
 
La risposta del server sarà un documento XML contenente il record generato
 
Esempio:
Codice: 200 OK
Content-Type: text/xml; charset=utf-8
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="create" user="admin" timestamp="28/04/2010 12:00:00" >
<campionamenti stato_rapporto="firmato" ... id="1136" />
</dbms>
 
In caso di errore il server risponderà con errore (400) accompagnato da un documento contenente il messaggio dell'errore.
 
 
MODIFICA
 
La URL per effettuare una operazione di lettura di un oggetto è costruita nel modo seguente:
 
https://masonsql.leader.it/dbms/parametri?method=update&key=NNNN
 
Metodo della chiamata: POST
Parametri:
method => 'update'
key => 'NNNN' chiave univoca dell'oggetto da recuperare (generalmente è un numero naturale)
 
Esempio:
https://masonsql.leader.it/dbms/campionamenti?method=update&key=123
 
<?xml version="1.0" encoding="utf-8"?>
<dbms>
<campionamenti stato_rapporto="firmato" ... id="123" />
</dbms>
 
I campi non forniti non verranno modificati.
 
La risposta del server sarà un documento XML contenente il record modificato
 
Esempio:
Codice: 200 OK
Content-Type: text/xml; charset=utf-8
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="update" user="admin" timestamp="28/04/2010 12:00:00" >
<campionamenti data_ingresso="02/03/2010" codice="AX400/2" id="123"
osservazioni="Commento\nsu\npiù\nrighe" />
</dbms>
 
In caso di errore il server risponderà con errore (400) accompagnato da un documento contenente il messaggio dell'errore.
 
 
CANCELLAZIONE
 
La URL per effettuare una operazione di cancellazione di un oggetto è costruita nel modo seguente:
 
https://masonsql.leader.it/dbms/parametri?method=delete&key=NNNN
 
Metodo della chiamata: GET
Parametri:
method => 'delete'
key => 'NNNN' chiave univoca dell'oggetto da recuperare (generalmente è un numero naturale)
 
Esempio:
https://masonsql.leader.it/dbms/parametri?method=delete&key=23
 
<?xml version="1.0" encoding="utf-8"?>
<dbms method="delete" user="admin" timestamp="28/04/2010 12:00:00" >
<parametri id="23" />
</dbms>
 
 
La risposta del server sarà OK (200) con invio di un documento XML contenente i record cancellati, oppure errore (400) accompagnato da un documento contenente il messaggio dell'errore.
 
Nel caso si faccia riferimento a record inesistenti o non accessibili dall'utente autenticato essi non verranno riportati nel documento XML di risposta.
 
XLS
 
La URL per effettuare il download di un file nel formato XLS contenente i record selezionati è costruita nel modo seguente:
 
https://masonsql.leader.it/dbms/parametri?method=xls
 
Metodo della chiamata: GET
Parametri:
method => 'xls'
key => 'NNNN' - chiave univoca dell'oggetto da recuperare (generalmente è un numero naturale)
father_key => 'FFFF' - chiave univoca del "padre"
rows => 'RRR' - Numero di righe di record da ritornare
(quando non si utilizza il parametro 'key', limitato a 65536)
start => 'SSS' - Posizione da cui mostrare i dati (0 corrisponde alla prima riga)
where => "codice='XXX'" - query di ricerca limitata agli operatori di confronto =, !=, <, >, <=, >=, like, *~ e l'operatore "and"
 
 
PERMESSI DI ACCESSO
 
L'accesso ai metodi e lle cassli degli oggetti/tabelle è controllato dall'autorizzazione "Dbms" per tutti i metodi e dalle autorizzazioni "Select", "Update", "Insert" e "Delete" per gli omonimi metodi.
Tramite il metodo "info" è possibile verificare le autorizzazioni concesse sugli oggetti/tabelle.
MESSAGGI DI ERRORE
 
In caso di errore nella richiesta, violazione dei diritti o nella risposta del database il messaggio di errore viene inviato al client con errore "400 Bad Request" ed un documento XML contenente l'errore e, se abilitato il livello di debug, anche lo stack-trace dell'errore nel codice:
 
<error user="administrator" timestamp="28/04/2010 13:10:22.434 CEST" >
<message>No access to record or record not exists</message>
<debug row="1">
Stack: [/opt/masonsql/htdocs/lib/my_library.comp:300], [/usr/local/share/perl ...n.comp:1112]\n
</debug>
</error>
 
Di seguito alcuni messaggi di errore, tra i più significativi:
 
No Dbms permission | L'utente non ha diritto di accesso alla funzionalità
No insert permission | L'utente non ha diritto di inserire nuovi oggetti
No delete permission | L'utente non ha diritto di cancellare oggetti
No update permission | L'utente non ha diritto di modificare oggetti
No father retrieve permission | L'utente non ha diritto di leggere il padre
No related 'OOO' retrieve permission | L'utente non ha diritto di leggere l'oggetto collegato 'OOO'
No father record retrieve | L'utente non ha diritto di leggere lo specifico oggetto padre
No related 'OOO' record retrieve | L'utente non ha diritto di leggere lo specifico oggetto collegato 'OOO'
No key param | Manca nella richiesta il parametro 'key'
No multiple key in param key | E' stato fornito un elenco di chiavi nella richiesta
No record retrieve or record not exists | L'oggetto fornito non esiste o non si hanno sufficienti diritti di accesso all'oggetto
Delete record return N rows | La cancellazione dell'oggetto ha restituito un numero di oggetti diverso da uno
No father_id param with father 'FATHER' | Manca il parametro father_id relativo all'oggetto PADRE
No father_id == -1 | La chiave di valore "-1" è riservata dal framework e se utilizzata genera errore
No key == -1 | La chiave di valore "-1" è riservata dal framework e se utilizzata genera errore
Defined father_id param without father definition | Fornito il parametro father_id nella chiamata di un oggetto senza padre
Key already used | In inserimento, la chiave fornita è già utilizzata (non è detto che l'utente abbia comunque accesso a quell'oggetto)
Key greater last key | In inserimento, la chiave fornita è maggiore dell'ultima chiave generata
No content | Chiamata POST senza contenuto
Malformed xml content: no <dbms> tag | Il documento trasmesso non contiene il blocco XML: <dbms ... >....</dbms>
 
Errori segnalati relativi al campo 'where', utilizzabile con il metodo 'retrieve':
Utilizzo della parola riservata '***' non autorizzata
Utilizzo dell'operatore '$value' non autorizzato
Utilizzo del campo '***' non autorizzato
Utilizzo della funzione '***' non autorizzata
Errore di sintassi: termine '***' sconosciuto
Errore di sintassi: manca un delimitatore di stringa
Errore di sintassi: mancante/i N parentesi di chiusura
Errore di sintassi: parentesi di chiusura senza la corrispondente parentesi di apertura
___
 
 
TEST & DEBUG
 
Per valutare il comportamento dell'interfaccia è possibile utilizzare la pagina html:
 
https://masonsql.leader.it/test/test_crud.html
 
E' possibile indicare lo schema, tabella, chiave ed il documento XML (per "update" e "insert") su cui eseguire le operazioni di: info, numrec, newkey, update, insert e delete. Viene restituito il record di risposta nel riquadro sottostante.
 
 
 
Nota: Il documento è stato creato utilizzando il charset UTF-8.
 
--------------------------------------------------------------------------------
 
 
 
/tags/2.0
Property changes:
Added: svn:mergeinfo
Merged /branches/janez/copy_paste:r302-303
Merged /branches/karan/masonsql_apache2.4:r346-386
Merged /masonsql_self_registration:r201-223
Merged /masonsql_session_management:r264-293
Merged /branches/rajesh/session_management:r294-305,357-358