summaryrefslogtreecommitdiff
path: root/public/ui-new-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-new-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-new-item.php')
-rw-r--r--public/ui-new-item.php560
1 files changed, 560 insertions, 0 deletions
diff --git a/public/ui-new-item.php b/public/ui-new-item.php
new file mode 100644
index 0000000..04124e5
--- /dev/null
+++ b/public/ui-new-item.php
@@ -0,0 +1,560 @@
+<?php
+include("config/parametres.php");
+include("includes/sessions.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();
+}
+ // Script Workflow:
+ // ---------------------------------------------------------------------------
+ // 1. read fields options
+ // 2. generate HTML
+ // 3. generate JS needed
+
+ // the UI
+ // ---------------------------------------------------------------------------
+ // Fields are grouped in sections
+ // These sections presented in tabs (or accordion if mobile device)
+ // Two (2) sections incduded to inform the user of empty fields or errors
+
+ // Libraries and FrameWorks used
+ // ---------------------------------------------------------------------------
+ // Bootstrap 4.3 is used for easy responsive HTML code
+ // JQuery 3.3 is used to handle user interation
+ // Select2 is used to make select-boxes (single or multiple) easier to use
+
+
+ // read fields options (json format) /////////////////////////////////////////
+ // ---------------------------------------------------------------------------
+ $formJSON = file_get_contents('config/kallassa.json');
+ $formARRAY = json_decode($formJSON);
+ unset($formJSON); // free some memory
+
+
+ // 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)
+
+?><!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?> : Εισαγωγή Εγγραφής</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");
+ ?>
+
+
+
+<?php if (filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST') : ?>
+ <pre>
+ <?php print_r($_POST); ?>
+ </pre>
+ <hr />
+<?php endif; ?>
+
+
+
+
+<div class="pi-container">
+<h2>Εισαγωγή Εγγραφής</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 = isset($field->atr) ? 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)
+ $sm_hide = $field->typ == 'null' ? ' d-sm-none' : ''; // hide null div on small devices
+
+ ?>
+
+ <!-- form group -->
+ <div class="form-group <?=$class?> <?=$sm_hide?>">
+ <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':
+
+ // check if multiple or single
+ // ( 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%' });
+
+ // 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 {
+ // 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 });
+
+ // 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?>" <?=$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?>" 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?>" 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?>></textarea>
+ <?php break;
+
+ case 'auto': ?>
+ <p>Το πεδίο <span class="auto-field"><?=$field->lab?></span> θα συμπληρωθεί από το σύστημα.</p>
+ <?php break;
+
+ case 'info': ?>
+ <p id="<?=$field->ccode?>">
+ <span class="auto-field">Αυτόματη συμπλήρωση …</span>
+ </p>
+ <?php break;
+
+ case 'null': ?>
+ <p>&nbsp;</p>
+ <?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>
+ <textarea name="note" class="form-control tall"></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();
+
+ 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=additem"; // 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='+ json.id;
+ }
+ else {
+ alert("Post not accepted.\nPlease check the data you submit.");
+ // $('#oc-company-form')[0].reset();
+ }
+ },
+
+ error: function() {
+ alert('Some ajax error! :(');
+ }
+ });
+ }
+
+ waitingResponse = false;
+ }
+
+ });
+
+<?php
+ // bibliography and References
+ //
+ // WHICH JQUERY:
+ // read: https://jquery.com/download/
+ //
+ // SELECT2
+ // https://stackoverflow.com/questions/12889309/get-selected-value-from-multi-value-select-boxes-by-jquery-select2
+ //
+ // tests:
+ // https://jsfiddle.net/3nd1gL8o/1/
+ // https://jsfiddle.net/3nd1gL8o/5/
+ //
+ // EXAMPLE with ALL CASES NEEDed:
+ // https://jsfiddle.net/v684h0g2/2/
+?>
+</script>
+ </body>
+</html>