summaryrefslogtreecommitdiff
path: root/public/ui-edit-item.php
diff options
context:
space:
mode:
authorGeo Halkiadakis <gchalkiadakis@sklavenitis.co.gr>2026-07-12 15:51:52 +0300
committerGeo Halkiadakis <gchalkiadakis@sklavenitis.co.gr>2026-07-12 15:51:52 +0300
commit02608271bb2a9f3a65ed536984d306ee14b48e34 (patch)
tree3f23ec48a694ec014e845c4f70d9b5f1c065403c /public/ui-edit-item.php
downloadkalassa-02608271bb2a9f3a65ed536984d306ee14b48e34.tar.gz
kalassa-02608271bb2a9f3a65ed536984d306ee14b48e34.tar.bz2
kalassa-02608271bb2a9f3a65ed536984d306ee14b48e34.zip
initialize repository; add docker config; migrate configuration to new specsHEADmaster
Diffstat (limited to 'public/ui-edit-item.php')
-rw-r--r--public/ui-edit-item.php629
1 files changed, 629 insertions, 0 deletions
diff --git a/public/ui-edit-item.php b/public/ui-edit-item.php
new file mode 100644
index 0000000..df2ee1f
--- /dev/null
+++ b/public/ui-edit-item.php
@@ -0,0 +1,629 @@
+<?php
+// 00. INITIALIZATION ----------------------------------------------------------
+// * Load Parametres, Session and Functions;
+// * Check User Permitions
+// * Check Script Call
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+ include("config/parametres.php");
+ include("includes/sessions.php");
+ include("includes/functions.php");
+
+ // if visitor has no ROLE -or- if ADMIN : then redirect to Login|Panel
+ // ---------------------------------------------------------------------------
+ if (!ROLE || (ROLE == ADMIN)) {
+ header("Cache-Control: no-store, no-cache, must-revalidate, max-age=0");
+ header("Cache-Control: post-check=0, pre-check=0", false);
+ header("Pragma: no-cache");
+ header("Location: /");
+ die();
+ }
+
+ // if item ID not passed redirec to to Control-Panel (or login)
+ // ---------------------------------------------------------------------------
+ if (isset($_GET['id'])) $item_id = $_GET['id'];
+ else {
+ $pi_Error = array('url' => '/', 'msg' => ERR_NEED_ID);
+ // include ("includes/show-error.php");
+ }
+
+
+// 01. GET DATA NEEDED ---------------------------------------------------------
+// * Load Parametres, Session and Functions;
+// * Check User Permitions
+// * Check Script Call
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+ // get totals of categories
+ // ---------------------------------------------------------------------------
+ $totals = get_totals();
+
+ // read fields options (json format)
+ // ---------------------------------------------------------------------------
+ $formARRAY = json_decode(FORMJSON);
+
+ // get item record
+ // ---------------------------------------------------------------------------
+ // init database connection
+ $_dbc = new mysqli(DB_HOST, DB_USER, DB_PASS, DB_DBMS);
+ if ($_dbc->connect_errno) {
+ echo "Database connection failed; Please try in a few minutes. ";
+ if (TESTING) echo $_dbc->connect_error;
+ $_dbc->close(); die();
+ }
+ $_dbc->set_charset("utf8");
+
+ // prepare statemet
+ $_stm = $_dbc->prepare("SELECT identity, operator, `timestamp`, record FROM items WHERE id = ?");
+ $_stm->bind_param("d", $item_id); // bind values
+ $_stm->execute(); // execute query
+ $_stm->store_result(); // store result
+
+ if ($_stm->num_rows) {
+
+ $_stm->bind_result($idnt, $opr, $tm, $serREC); // bind result variables
+ $_stm->fetch(); // fetch FIRST record values
+ // unserialize main record to variable
+ $record = unserialize($serREC);
+
+ // edit record
+ $record['id'] = $item_id;
+ $record['identity'] = $idnt;
+ $record['operator'] = $opr;
+ $record['itemid'] = end(explode('.', $idnt));
+ $record['totalitems'] = $totals[$record['ccode']];
+ date_default_timezone_set('Europe/Athens');
+ setlocale(LC_ALL, 'el_GR.UTF-8', 'grc');
+ $record['timestamp'] = local_dt($tm);
+ }
+ else {
+ return array('success' => false, 'data' => "No items found"); // return error(s)
+ }
+
+ $_stm->close(); // close statement
+ $_dbc->close(); // close connection
+
+
+// 02. RENDER HTML and DATA ----------------------------------------------------
+// * Draw fileds from Json Array per section
+// * Prepare JS needed
+// * Put data from Record
+// * Generate JS (prepared + static)
+// ---
+// Script is based on on ui-new-item.php
+// More information about the script workflow can be found there.
+////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+ // Init strigns for JS generator (needed to handle everything) ///////////////
+ // ---------------------------------------------------------------------------
+ $checkFilledJS = ""; // JS for checking empty fields
+ $ref2Select2JS = ""; // references to Select2-controls Javascript
+ $initSelectsJS = ""; // js to initialize select fields (single or multiple)
+ // --- depricated (added static into js) : $addJSreadonly = ""; // js to add readonly fields and their values to port-object
+
+?><!DOCTYPE html>
+<html prefix="og: http://ogp.me/ns#" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-GB" lang="en-GB" dir="ltr">
+ <head>
+ <!-- Metas + Title -->
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="viewport" content="width=device-width, initial-scale=1">
+ <meta http-equiv="content-type" content="text/html; charset=utf-8" />
+
+ <title><?=PROJECT?> : Επεξεργασία Εγγραφής <?=$idnt?></title>
+
+ <!-- CSS needed -->
+ <link href="https://fonts.googleapis.com/css?family=Ubuntu:400,700&display=swap" rel="stylesheet">
+ <link rel="stylesheet" href="/css/bootstrap.min.css" /><!-- v4.4.1 -->
+ <link rel="stylesheet" href="/css/select2.min.css" /><!-- v4.0.10 -->
+ <link rel="stylesheet" href="/css/pi.css" />
+ </head>
+ <body>
+
+ <?php // Menu ----------------------------------------------------------------
+ include("includes/menu.php");
+ ?>
+
+
+<div class="pi-container">
+<h2>Επεξεργασία Εγγραφής <?=$idnt?></h2>
+
+<form id="post-form" method="POST">
+
+ <!-- TABS (start) -->
+ <div id="tabsContainer">
+ <div class="tabArea">
+
+<?php $i = 1; ?>
+<?php foreach ($formARRAY as $key => $section) : ?>
+ <!-- START fields group (section) ////////////////////////////////////////// -->
+
+ <input id="tab<?=$i?>" type="radio" name="tabs" value="<?=$i?>"<?=($i == 1) ? ' checked' : ''?>>
+ <label for="tab<?=$i?>"><?=$section->label?></label>
+ <div id="content<?=$i?>" class="tab--content">
+ <div class="form-row">
+
+
+ <?php foreach ($section->childs as $kk => $field) : ?>
+ <?php
+
+ // get atributes of field
+ $atrs = explode('|', $field->atr); // attributes array
+ $ak = in_array('append-key', $atrs) ? true : false; // append key (for selects)
+ $rq = in_array('required', $atrs) ? 'required' : ''; // required
+ $class = (isset($field->len)) ? ' col-md-'.$field->len : 'col-md-12'; // column class (for width)
+
+ ?>
+
+ <!-- form group -->
+ <div class="form-group <?=$class?>">
+ <label for="<?=$field->nam?>">
+ <?=$field->lab?>
+ <?php if (($field->typ == 'select') && C_LABEL) : ?>
+ <span><?=$field->nam?></span>
+ <?php endif; ?>
+ </label>
+
+ <?php
+
+ switch ($field->typ) {
+
+ case 'select':
+
+ // exclude CCODE from default select behaviour
+ // because CCODE SHALL NOT CHANGE
+ if ($field->nam == 'ccode') {
+
+ $fdata = parse_any($field->nam, $record['ccode']); // parse field + current value
+
+ $txt = $fdata['multi'] ? implode(", ", $fdata['value']) : $fdata['value']; // if array of values, implode values
+
+ echo '<input class="form-control" type="text" name="ccode" value="'. $txt .'" readonly>';
+
+ $checkFilledJS .= "
+ values.ccode = '". $record['ccode'] ."';
+ ";
+
+ }
+ else {
+
+ // if MULTIPLE select
+ // ( deferantiate class for multi or single this will allow the { allowClear: true } option )
+ // ( see: https://select2.org/placeholders )
+ if (in_array('multiple', $atrs)) {
+ // MULTIPLE control: set name and multiple attribute
+ $name_n_multi = 'name="'. $field->nam .'[]" multiple="multiple">';
+
+ // prepare initialization of select2 (multiple)
+ $initSelectsJS .= "
+ var ". $field->nam ." = $('#". $field->nam ."');
+ ". $field->nam .".select2({ width: '100%' });
+ "; // depricated: ". $field->nam .".select2({ placeholder: '". $field->lab ."', width: '100%' });
+
+ // and set init value
+ if ($record[$field->nam] !="") {
+ $initSelectsJS .= "
+ ". $field->nam .".val( ['". str_replace(",", "','", $record[$field->nam]) ."'] );
+ ". $field->nam .".trigger('change');
+ ";
+ }
+
+ // prepare check if empty field
+ $checkFilledJS .= "
+ if (getValues(".$field->nam.") =='') {
+ empty += '<span>". $section->label .":</span> ". $field->lab . (($rq == '') ? "" : " **") ."<br />';
+ ". (($rq == '') ? "" : "needit.push('". $section->label .":". $field->lab ."');") ."
+ }
+ values.". $field->nam ." = getValues(".$field->nam.");
+ ";
+ }
+ else {
+ // is SINGLE control: only name needed
+ $name_n_multi = 'name="'. $field->nam .'"';
+
+ // prepare initialization of select2 (single)
+ $initSelectsJS .= "
+ var ". $field->nam ." = $('#". $field->nam ."');
+ ". $field->nam .".select2({ placeholder: ' ', allowClear: true });
+ "; // depricated: ". $field->nam .".select2({ placeholder: '". $field->lab ."', allowClear: true });
+
+ // and set init value
+ if ($record[$field->nam] !="") {
+ $initSelectsJS .= "
+ ". $field->nam .".val( ['". str_replace(",", "','", $record[$field->nam]) ."'] );
+ ". $field->nam .".trigger('change');
+ ";
+ }
+
+ // prepare check if empty field
+ $checkFilledJS .= "
+ if (getValues(".$field->nam.") =='') {
+ empty += '<span>". $section->label .":</span> ". $field->lab . (($rq == '') ? "" : " **") ."<br />';
+ ". (($rq == '') ? "" : "needit.push('". $section->label .":". $field->lab ."');") ."
+ }
+ values.". $field->nam ." = getValues(".$field->nam.");
+ ";
+ }
+ ?>
+ <select id="<?=$field->nam?>" class="select-field" <?=$name_n_multi?> style="width:100%;">
+
+ <?php if (!in_array('multiple', $atrs)) : ?>
+ <option></option>
+ <?php endif; ?>
+ <?php foreach ($field->opt as $kkk => $val): ?>
+ <option value="<?=$val->id?>"><?=(($ak) ? $val->id.' : ' : '' ) .$val->tag?></option>
+ <?php endforeach; ?>
+ </select>
+ <?php
+ }
+ break;
+
+ case 'text':
+ $checkFilledJS .= "
+ if ($('input[name=". $field->nam ."]').val() =='') {
+ empty += '<span>". $section->label .":</span> ". $field->lab . (($rq == '') ? "" : " **") ."<br />';
+ ". (($rq == '') ? "" : "needit.push('". $section->label .":". $field->lab ."');") ."
+ }
+ values.". $field->nam ." = $('input[name=". $field->nam ."]').val();
+ ";
+ ?>
+ <input class="form-control" type="text" name="<?=$field->nam?>" value="<?=$record[$field->nam]?>" <?=$rq?>>
+ <?php break;
+
+ case 'integer':
+ $checkFilledJS .= "
+ if ($('input[name=". $field->nam ."]').val() =='') {
+ empty += '<span>". $section->label .":</span> ". $field->lab . (($rq == '') ? "" : " **") ."<br />';
+ ". (($rq == '') ? "" : "needit.push('". $section->label .":". $field->lab ."');") ."
+ }
+ values.". $field->nam ." = $('input[name=". $field->nam ."]').val();
+ ";
+ ?>
+ <input class="form-control" type="number" name="<?=$field->nam?>" value="<?=$record[$field->nam]?>" min="0" step="1" <?=$rq?>>
+ <?php break;
+
+ case 'float':
+ // credit: https://stackoverflow.com/questions/19011861/is-there-a-float-input-type-in-html5
+ $checkFilledJS .= "
+ if ($('input[name=". $field->nam ."]').val() =='') {
+ empty += '<span>". $section->label .":</span> ". $field->lab . (($rq == '') ? "" : " **") ."<br />';
+ ". (($rq == '') ? "" : "needit.push('". $section->label .":". $field->lab ."');") ."
+ }
+ values.". $field->nam ." = $('input[name=". $field->nam ."]').val();
+ ";
+ ?>
+ <input class="form-control" type="number" name="<?=$field->nam?>" value="<?=$record[$field->nam]?>" min="0" step="0.1" <?=$rq?>>
+ <?php break;
+
+ case 'textarea':
+ $checkFilledJS .= "
+ if ($('textarea[name=". $field->nam ."]').val() =='') {
+ empty += '<span>". $section->label .":</span> ". $field->lab . (($rq == '') ? "" : " **") ."<br />';
+ ". (($rq == '') ? "" : "needit.push('". $section->label .":". $field->lab ."');") ."
+ }
+ values.". $field->nam ." = $('textarea[name=". $field->nam ."]').val();
+ ";
+ ?>
+ <textarea class="form-control" name="<?=$field->nam?>" <?=$rq?>><?=$record[$field->nam]?></textarea>
+ <?php break;
+
+ case 'auto':
+ // On EDIT mode the 'auto' fields have already their (read-only) value
+ ?>
+ <input class="form-control" type="text" name="<?=$field->nam?>" value="<?=$record[$field->nam]?>" readonly>
+ <?php break;
+
+ default: ?>
+ <?=$field->nam?> (<?=$field->lab?>) : UNKNOWN TYPE
+
+ <?php
+ } // end switch
+
+ unset($atrs); // free array to re-use (on next field)
+ ?>
+ </div>
+ <!-- end /form group -->
+
+ <?php endforeach; ?>
+
+ </div><!-- /form-row -->
+ </div><!-- /tab-.-content -->
+ <?php $i++; ?>
+
+ <!-- END fields group (section) -->
+<?php endforeach; ?>
+
+
+ </div>
+ </div>
+ <!-- TABS (end) -->
+
+ <!-- footer of form -->
+
+ <div class="row">
+
+ <div class="col-md-4 line-right">
+ <h3>Δεν έχουν συμπληρωθεί:</h3>
+ <div id="empty-fields"></div>
+ </div>
+
+ <div class="col-md-8">
+
+ <!-- custom field -->
+ <div class="form-group">
+ <label for="more">Συμπληρωματική Πληροφορία</label>
+ <?php
+ $fdata = parse_any($field->nam, $record['note']); // parse field + current value
+ $txt = $fdata['value']; // if array of values, implode values
+ ?>
+ <textarea name="note" class="form-control tall"><?=$txt?></textarea>
+ <?php
+ // append js code
+ // for checking if field is empty
+ // and attaching value to json data
+ $checkFilledJS .= "
+ if ($('textarea[name=note]').val() =='') {
+ empty += '<span>Γενικά:</span>Συμπληρωματική Πληροφορία<br />';
+ }
+ values.note = $('textarea[name=note]').val();
+ ";
+ ?>
+ </div>
+
+ <div class="form-group">
+ <input class="btn btn-primary" type="submit" value="Καταχώρηση Εγγραφής">
+ </div>
+ </div>
+
+ </div>
+
+</form>
+</div>
+<!-- DOM ENDS HERE -->
+
+ <!-- scripts and libraries
+ load and register one by one, so you don't need to worry about if they are ready -->
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/1.4.1/jquery-migrate.min.js"></script>
+<script src="/js/bootstrap.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/select2.full.min.js"></script>
+<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.10/js/i18n/el.js"></script>
+<script>
+// NOW RUN EVERYTHING AFTER JQUERY (AND DOM ready)
+// -----------------------------------------------------------------------------
+////////////////////////////////////////////////////////////////////////////////
+
+ // 00. FLAGS and NEEDED FUNCTIONS
+ // ---------------------------------------------------------------------------
+ //////////////////////////////////////////////////////////////////////////////
+
+ var waitingResponse = false; // flag for an ajax request that was sent and still waiting response
+
+ // pure JS ajax GET request
+ // return data as JSON
+ // no fancy things like UTF8; if needed use base64 ---------------------------
+ function ajax_get(url, callback) {
+ var xmlhttp = new XMLHttpRequest();
+ xmlhttp.onreadystatechange = function() {
+ if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
+
+ try {
+ var data = JSON.parse(xmlhttp.responseText);
+ } catch(err) {
+ console.log(err.message + " in " + xmlhttp.responseText);
+ return;
+ }
+ callback(data);
+ }
+ };
+
+ xmlhttp.open("GET", url, true);
+ xmlhttp.send();
+ }
+
+
+ // 01. MENU MANAGEMENT
+ // ---------------------------------------------------------------------------
+ //////////////////////////////////////////////////////////////////////////////
+
+ // menu management
+ // ---------------------------------------------------------------------------
+ $('.dropdown-item').on('click', function(e){
+ e.preventDefault();
+
+ if (!waitingResponse) {
+ waitingResponse = true;
+
+ var r = confirm("Δεν έχετε αποθηκεύσει το τρέχον αντικείμενο!\nΕίστε σίγουροι ότι θέλετε να εγκαταλείψετε τη σελίδα;");
+ if (r == true) {
+
+ // all data-goto have the format: 'method,uri_address'
+ // uri_address is the url to call
+ // method options:
+ // * url : means goto url (redirect)
+ // * ajax : means call url via ajax; if 'success = true' then goto '/' after that
+ // -----------------------------------------------------------------------
+ var opt = $(this).data('goto').split(','); // split data-goto
+
+ if (opt[0] == 'url') { // if method = url
+ window.location.href = opt[1];
+ }
+ else { // else, method = ajax
+ ajax_get(opt[1], function(response) {
+ if (response.success) {
+ window.location.href = '/';
+ }
+ });
+ }
+
+ }
+ else {
+ // user did not confirmed the selection; do nothing
+ }
+
+ waitingResponse = false;
+ }
+
+ });
+
+ // 02. USER INTERFACE
+ // ---------------------------------------------------------------------------
+ //////////////////////////////////////////////////////////////////////////////
+
+ // tabs to accorderon --------------------------------------------------------
+ //////////////////////////////////////////////////////////////////////////////
+
+ // FUNCTION: Set tabsContainer height
+ // acording to which tab is visible
+ // and tab mode (tabs|acordeon)
+ // ---------------------------------------------------------------------------
+ function set_tabsContainer_height() {
+ var ch_; // content height
+ var tc_base; // tabs-container base height
+ tc_base = ($(window).width() > 650) ? 100 : 400;
+ if ($('#content1').is(':visible')) ch_ = $('#content1').height();
+ if ($('#content2').is(':visible')) ch_ = $('#content2').height();
+ if ($('#content3').is(':visible')) ch_ = $('#content3').height();
+ if ($('#content4').is(':visible')) ch_ = $('#content4').height();
+ if ($('#content5').is(':visible')) ch_ = $('#content5').height();
+ if ($('#content6').is(':visible')) ch_ = $('#content6').height();
+
+ $('#tabsContainer').height(ch_ + tc_base);
+
+ }
+ set_tabsContainer_height(); // init (run for 1st time)
+
+ // on tab selection
+ // calculate tabsContainer height
+ $('input:radio[name="tabs"]').change( function(){
+ set_tabsContainer_height()
+ });
+
+ // on window change
+ // set tabsContainer height
+ $( window ).resize(function() {
+ set_tabsContainer_height();
+ });
+
+
+
+ // 03. FORM-CONTROLS
+ // ---------------------------------------------------------------------------
+ //////////////////////////////////////////////////////////////////////////////
+
+ // Select2 controls
+ //////////////////////////////////////////////////////////////////////////////
+
+ // FUNCTION: Get selected value(s) of Select2 control
+ // pass arg: source-element
+ // return: value(s) comma-separated
+ // ---------------------------------------------------------------------------
+ function getValues(srcElm) {
+ var res;
+ var obj = srcElm.select2('data'); // get delected data array
+
+ if (obj.length === 0) return ''; // if empty list then nothig is selected
+ else {
+ var i = 0;
+ obj.forEach(function(elm){ // loop through object elements array
+
+ if (i) res += ',' + elm.id; // if not first item, prepend ',' befor value(id)
+ else res = elm.id; // else set (first) checked value
+
+ i++;
+ });
+ }
+ return res;
+ }
+
+ // patch select2-multiple widths
+ // ---------------------------------------------------------------------------
+ $('.select-field').select2({ width: '100%' });
+
+ // init select2 fields
+ // (embed from php)
+ // ---------------------------------------------------------------------------
+ <?=$initSelectsJS?>
+
+
+ // 04. FORM-LOGIC
+ // ---------------------------------------------------------------------------
+ //////////////////////////////////////////////////////////////////////////////
+
+ // FUNCTION: Report empty fields
+ // ---------------------------------------------------------------------------
+ function reportEmpty() {
+ var empty = '';
+ var needit = [];
+ var values = {};
+
+ // embed if-conditions from php
+ <?=$checkFilledJS?>
+
+ $("#empty-fields").html(empty); // render empty fields
+
+ // console.log(JSON.stringify(values));
+
+ return { need : needit, data: values }; // return all fields
+ }
+ reportEmpty();
+
+ $('form').on('keyup change paste', 'input, select, textarea', function(){
+ console.log('Form changed!');
+ reportEmpty();
+ });
+
+ // validation?
+ // check: https://www.sitepoint.com/instant-validation/
+
+
+ $('#post-form').on('submit', function(e){
+ e.preventDefault();
+ if (!waitingResponse) {
+ waitingResponse = true;
+ var resp = reportEmpty();
+
+ // add static (readonly) data to resp.data object
+ resp.data.id = <?=$item_id?>;
+ resp.data.identity = '<?=$idnt?>';
+
+ if (resp.need.length > 0) alert("Tα πεδία:\n\n" + resp.need.join(',\n') + "\n\nείναι υποχρεωτικά!");
+ else {
+ // alert('sending: '+JSON.stringify(resp.data));
+
+ var postUrl = "/ajax.php?do=upditem&id=<?=$item_id?>"; // url to post form
+ var data2send = resp.data; // parse data to send
+
+ $.ajax({
+ type: 'POST',
+ url: postUrl, // make sure you respect the same origin policy with this url
+ data: data2send,
+ dataType: "text",
+
+ success: function(data) { // server replies
+ var json = $.parseJSON(data);
+ if (json.success == true) { // good! post accepted
+ // alert(json.id)
+ window.location.href = '/ui-show-item.php?id=<?=$item_id?>'
+ }
+ else {
+ alert("Post not accepted.\nPlease check the data you submit.");
+ }
+ },
+
+ error: function() {
+ alert('Some ajax error! :(');
+ }
+ });
+
+ }
+
+ waitingResponse = false;
+ }
+
+ });
+</script>
+ </body>
+</html>