diff options
34 files changed, 157 insertions, 5413 deletions
diff --git a/public/app/config/setup_application.php b/public/app/config/setup_application.php index 2c8b756..45c6712 100644 --- a/public/app/config/setup_application.php +++ b/public/app/config/setup_application.php @@ -206,9 +206,13 @@ define('GENDERED_ARTICLE',[ // gendered (grammar) articles +## ----------------------------------------------------------------------------- +## +## t h e f o r m s +## +## ----------------------------------------------------------------------------- + -// the forms /////////////////////////////////////////////////////////////////// -// ----------------------------------------------------------------------------- // registration/activation form (from invitation) // --- @@ -295,7 +299,8 @@ define('REGISTRATION_FORM', [ ]); - +// (edit) user properties +// --- define('USER_PROPERTIES_FORM', [ 'defaults' => [ 'outer_class' => 'col-12', @@ -365,7 +370,8 @@ define('USER_PROPERTIES_FORM', [ ]); - +// (re-)set password +// --- define('SET_PASSWORD_FORM', [ 'defaults' => [ 'outer_class' => 'col-12', @@ -395,6 +401,7 @@ define('SET_PASSWORD_FORM', [ ] ]); + // Application (common request) form // --- define('APPLICATION_FORM', [ @@ -488,9 +495,9 @@ define('APPLICATION_FORM', [ ] ]); + // penalty form // --- - define('PENALTY_FORM', [ 'defaults' => [ 'outer_class' => 'col-12', diff --git a/public/app/controllers/Office.php b/public/app/controllers/Office.php index c67249a..7a542eb 100644 --- a/public/app/controllers/Office.php +++ b/public/app/controllers/Office.php @@ -23,7 +23,6 @@ class Office { ## PERMITION ## ------------------------------------------------------------------------- - /** is admin or permited * * shortcut method for checking access authorization @@ -52,7 +51,6 @@ class Office { ## SERVE FILE ## ------------------------------------------------------------------------- - /** serve file by file_path * (request is valid only for admin users) * @@ -116,7 +114,6 @@ class Office { ## secretarial support / serve forms for teachers' requests and applications ## ------------------------------------------------------------------------- - /** request any (empty/new) petition form * * The method acts as an authorization checker and internal router @@ -268,7 +265,6 @@ class Office { ## handle submits of forms ## ------------------------------------------------------------------------- - /** add_petition * * handle an add petition request (petition form is submited) @@ -309,7 +305,6 @@ class Office { ## LIST PETITIONS ## ------------------------------------------------------------------------- - public static function user_petitions() { $manager = new App_manager(); // use APP Manager @@ -326,7 +321,6 @@ class Office { } - public static function all_petitions() { if (Auth::in_admin_group()) { @@ -338,7 +332,6 @@ class Office { } - public static function petition_copy($sign) { if (Auth::in_admin_group()) { @@ -359,6 +352,7 @@ class Office { + ## TICKET METHODS (create, remove) ## tickets eliminate CSRF attacks ## ------------------------------------------------------------------------- @@ -415,7 +409,6 @@ class Office { - ## ADMIN METHODS (insert, updated etc.) ## ------------------------------------------------------------------------- diff --git a/public/app/routes/user.php b/public/app/routes/user.php index e43eaa9..67032e6 100644 --- a/public/app/routes/user.php +++ b/public/app/routes/user.php @@ -187,10 +187,15 @@ if (Auth::in_admin_group()) { Office::set_protocol(); }, 'post'); + // invite user(s) // --- -- -- - - - Route::add('/admin/invite', function() { - Render::view('admin/invite'); + $teachers = Registry::use('database')->runQuery( + "SELECT id, concat(last_name, ' ', first_name) as TeacherName + FROM user ORDER BY TeacherName", [] + ); + Render::view('templates/invite', ['teachers' => $teachers]); }); } diff --git a/public/app/views/components/own_petitions.php b/public/app/views/components/own_petitions.php index 41e59b4..c4f84fe 100644 --- a/public/app/views/components/own_petitions.php +++ b/public/app/views/components/own_petitions.php @@ -2,7 +2,7 @@ <!-- title bar --> <div class="title-bar"> <div class="row"> - <h5 class="col-md-10">Διαχείριση Αιτήσεων και Δοικητικών Εγγράφων</h5> + <h4 class="col-md-10">Διαχείριση Αιτήσεων και Δοικητικών Εγγράφων</h4> <div class="col-md-2"> <a type="button" class="btn btn-sm btn-back2panel pull-right" href="/panel"> Επιστροφή diff --git a/public/app/views/templates/invite.php b/public/app/views/templates/invite.php new file mode 100644 index 0000000..637697f --- /dev/null +++ b/public/app/views/templates/invite.php @@ -0,0 +1,133 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="utf-8"> + <title><?=SITE_TITLE?> - Είσοδος Χρήστη</title> + + <?php // header includes + //////////////////////////////////////////////////////////////////////// + Render::view('components/header_includes'); + ?> +<style> +:root { /* login-form overides */ + --form-content-font-size: 1rem; + --form-input-height: 34px; + --select2-arrow-top: 1px; +} +</style> +</head> +<body class="office central-form"> + + <div class='container'> + <div class='content max420px'> + + + <div class="content-form"> + <h4> + Αποστολή προσκλήσεων + <span> + <a type="button" class="btn btn-sm btn-back2panel pull-right" href="/panel"> + Επιστροφή + </a> + </span> + </h4> + <hr /> + + <form method="post"> + + <div class='row'> + <div class='form-group '> + <label for='members'>Μέλη *</label> + + <select id='members' class='form-select form-select-sm' name='members[]' multiple='multiple' style='width:100%'> + <?php foreach($teachers as $key => $item) :?> + <option value="<?=$item['id']?>"><?=$item['TeacherName']?></option> + <?php endforeach; ?> + </select> + </div> + </div> + + + <br /> + + <div class="row justify-content-center"> + <div class="col-6"> + <button type="submit" class="btn btn-primary btn-sm col-12">Σύνδεση</button> + </div> + </div> + + </form> + </div> + + <div class="info"> + <!-- + <p>Αν ξεχάσατε τον κωδικό πρόσβασης μπορείτε να δημιουργήσετε ένα νέο (υπο κατασκευή).</p> + --> + <p> + Εαν δικαιούστε αλλά δεν έχετε πρόσβαση στο site, παρακαλούμε επικοινωνήστε + με τη διεύθυνση του σχολείου προκειμένου να σας αποσταλεί σχετική πρόσκληση. + </p> + <p> + Ο ιστότοπος χρησιμοποιεί cookies τα οποία έχουν αποκλειστικά λειτουργικό ρόλο. + Η χρήση των υπηρεσιών του site συνεπάγεται την αποδοχή διατήρησης αυτών των cookies. + </p> + </div> + + </div> + </div> + +</body> + +<?php // include select2 supplementary functions + //////////////////////////////////////////////////////////////////////////// + Render::view('js/select2-supplementary'); +?> + +<script> + +$(document).ready(function() { + + // initialize select2 control + var members = $('#members'); + members.select2({ width: '100%' }); + members.val(null).trigger('change'); + + + // When form is submited + // ------------------------------------------------------------------------- + + $('.content form').submit( event => { + event.preventDefault(); + + + // prepare data to POST + var data = { + email: $('input[name=email]').val(), + password: $('input[name=password]').val() + }; + + // select action url (add or update) + var request = '/account/check-login'; + + // send POST request + $.post(request, data) + .done(function( data ) { + if (data.status !== false) { + window.location.href = data.status.goto; + + } else { + alert('Τα στοιχεία πρόσβασης που δώσατε είναι λάθος. Παρακαλώ προσπαθήστε ξανά.'); + } + }); + + + }); + +}); +</script> + +<?php // credits + ////////////////////////////////////////////////////////////////////////////// + Render::view('js/credits'); +?> +</html> diff --git a/public/app/views/user/panel.php b/public/app/views/user/panel.php index 9ac7908..304237b 100644 --- a/public/app/views/user/panel.php +++ b/public/app/views/user/panel.php @@ -43,60 +43,7 @@ </div> </div> - -<?php if (($is_admin) && ($content == 'admin_petitions')) : ?> - - <!-- MODAL for set protocol number --> - <div class="modal fade" id="managePetition" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - - <form method="post" action=""> - - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Ενημέρωση αριθμού πρωτόκολλου</h4> - <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> - </div><!-- /modal-header --> - - <!-- modal-body --> - <div class="modal-body"> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="protocol">Τίτλος</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="protocol" value="" required=""> - </div> - </div> - - <div class="row form-group"><!-- hiddens --> - <input type="hidden" name="id" value="0"><!-- petition-id --> - <input type="hidden" name="signature" value=""><!-- signature --> - </div> - - </div><!-- /modal body --> - - <div class="modal-footer"> - <div class="row" style="width: 50%;"> - <div class="form-actions"> - <div class="col-4"> - <button type="button" class="btn btn-default js-modal-close col-sm-12" data-bs-dismiss="modal">Κλείσιμο</button> - </div> - <div class="col-8"> - <button class="btn btn-success col-sm-12" type="submit">Καταχώριση</button> - </div> - </div> - </div> - </div><!-- /modal-footer --> - - </form><!-- /form --> - - </div> - </div> - </div> - -<?php endif; ?> - - </body> +</body> <script src="/assets/js/panel/<?=$content?>.js"></script> diff --git a/public/app/views/xx--admin/admin-menu.php b/public/app/views/xx--admin/admin-menu.php deleted file mode 100644 index 52e8522..0000000 --- a/public/app/views/xx--admin/admin-menu.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php -/** admin panel - * ----------------------------------------------------------------------------- - * - * imported variables: - * --- - * @param $action (string): array of articles - * @param $id (int): id of entity (when editing entity) | 0: new entity - * - * example call: - * --- - * Render::template("sections/admin_panel.php",[ - * 'action' => 'posts', - * 'id' => 4 - * ]) - * ----------------------------------------------------------------------------- - */ - -$admin_options = [ - 'panel' => 'Διαχείριση', - 'edit_lesson' => 'Νέο Μάθημα', - 'lessons' => 'Μαθήματα', - 'categories' => 'Κεφάλαια', - 'pages' => 'Σελίδες', - 'files' => 'Αρχεία', - 'privileges' => 'Πρόσβαση', - 'users' => 'Χρήστες' -]; -?> - -<div class="top-bar"> - - <?php foreach($admin_options as $opt => $label) : ?> - - <?php if (($opt == $action) & (!$id)) : ?> - <span class="btn btn-primary selected"><?=$label?></span> - - <?php else : ?> - <a href="/admin/<?= $opt ?>" class="btn"><?= $label ?></a> - - <?php endif; ?> - - <?php endforeach ?> - - <a href="/logout" class="btn">Logout</a> - -</div>
\ No newline at end of file diff --git a/public/app/views/xx--admin/categories.php b/public/app/views/xx--admin/categories.php deleted file mode 100644 index 26fd5a2..0000000 --- a/public/app/views/xx--admin/categories.php +++ /dev/null @@ -1,91 +0,0 @@ - <!-- title bar --> - <div class="title-bar"> - <div><h5>Διαχείριση Κατηγοριών</h5></div> - <div> - <!-- Button trigger modal --> - <button type="button" class="btn pull-right" - data-bs-toggle="modal" data-bs-target="#manageCategory" data-id="0"> - <i class="fas fa-plus"></i> Νέο Κεφάλαιο - </button> - </div> -</div> - -<div class="manage"> - <div class="row"> - <div class="col-md-12"> - - <div id="categories-tree"> - - <table id="dt-categories" class="table table-responsive dt-table" style="width:100%"> - <thead> - <th class="dt-breadcrumb">Κατηγορία/Κεφάλαιο</th> - <th class="dt-actions"></th> - </thead> - </table> - - </div> - - - </div> - </div> -</div><!-- /manage --> - - - -<!-- MODAL for new/edit category --> -<!-- NOTE: tabindex="-1" removed, ref:https://github.com/select2/select2-bootstrap-theme/issues/41 --> -<div class="modal fade" id="manageCategory" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - - <form method="post" action=""> - - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Modal title</h4> - <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> - </div><!-- /modal-header --> - - <!-- modal-body --> - <div class="modal-body"> - - <!-- form fields --> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="label">Όνομα κατηγορίας</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="label" value="" required=""> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="parent_id">Γονική Κατηγορία</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" id="parent_id" name="parent_id" required></select> - </div> - </div> - - <div class="row form-group"> - <input type="hidden" name="id" value="0"><!-- action = (0) ? 'new' : 'edit' --> - </div> - - - </div><!-- /modal body --> - - <div class="modal-footer"> - <div class="row" style="width: 50%;"> - <div class="form-actions"> - <div class="col-4"> - <button type="button" class="btn btn-default js-modal-close col-sm-12" data-bs-dismiss="modal">Κλείσιμο</button> - </div> - <div class="col-8"> - <button class="btn btn-success col-sm-12" type="submit">Καταχώριση</button> - </div> - </div> - </div> - </div><!-- /modal-footer --> - - </form><!-- /form --> - - </div> - </div> -</div> diff --git a/public/app/views/xx--admin/edit_lesson.php b/public/app/views/xx--admin/edit_lesson.php deleted file mode 100644 index ef875b4..0000000 --- a/public/app/views/xx--admin/edit_lesson.php +++ /dev/null @@ -1,159 +0,0 @@ -<?php - // some labels (if editing new or existing record) - // --- -- -- - - - - if ($id == 0) { - $action_title = "Δημιουργία Μαθήματος"; - $action_button = "Δημιουργία"; - - } else { - $action_title = "Επεξεργασία Μαθήματος"; - $action_button = "Αποθήκευση Αλλαγών"; - } -?> - -<!-- title bar --> -<div class="title-bar"> - <div><h5><?=$action_title?></h5></div> - <div> - <button type="button" class="btn pull-right" - data-bs-toggle="modal" data-bs-target="#editorModal" data-action="preview"> - <i class="fas fa-search"></i> Προεπισκόπηση - </button> - </div> -</div> - -<!-- manage --> -<div class="manage edit-post"> - <form> - <div class="row"> - - - <div class="col col-8"> - - <!-- id (hidden) --> - <input type="hidden" name="id" value="0"><!-- action = (0) ? 'new' : 'edit' --> - - <!-- - <div class="row form-group"> - <input type="date" name="date" value="" readonly=""> - </div> - --> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="title">Τίτλος</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="title" value="" required=""> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="category_id">Κεφάλαιο</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm" id="course_id" name="course_id" required></select> - </div> - </div> - - <!-- Post body --> - <div class="row form-group"> - <label class="control-label col-sm-12" for="body">Κείμενο</label> - <div class="col-sm-12"> - <textarea class="form-control form-control-sm" type="text" name="body" value="" required=""></textarea> - </div> - </div> - - </div> - - <div class="col"> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="status">Κατάσταση</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" name="status" onchange="this.dataset.chosen = this.value;"> - <option value="0">Αδημοσίευτο</option> - <option value="one">ΔΗΜΟΣΙΕΥΜΕΝΟ</option> - </select> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="privilege_id">Επίπεδο Πρόσβασης</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" id="privilege_id" name="privilege_id"> - </select> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="intro">Σύντομη Περιγραφή</label> - <div class="col-sm-12"> - <textarea class="form-control form-control-sm" type="text" name="intro" value=""></textarea> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="media">Αρχεία</label> - <div class="col-sm-12 post-media"> - - <!-- Button trigger modal --> - <button type="button" class="btn btn-sm btn-success pull-right over-bar" - data-bs-toggle="modal" data-bs-target="#editorModal" data-action="upload_file"> - <i class="fas fa-plus"></i> Προσθήκη - </button> - - <ul id="files_list"> - </ul> - - </div> - </div> - - <?php if ($id != 0) : ?> - <div class="row form-group"> - <label class="control-label col-sm-12">Πληροφορίες</label> - <div class="col-sm-12" id="post-info"> - </div> - </div> - <?php endif; ?> - - </div> - - </div> - - <div class="row"> - - <div class="col"> - <hr/> - <!-- close | submit buttons --> - - <div class="form-actions row justify-content-md-center"> - - <div class="col-3"> - <button type="button" id="go-back" class="btn btn-light col-sm-12"> - Επιστροφή - </button> - </div> - - <div class="col-4"> - <button class="btn btn-primary col-sm-12" type="submit"> - <?=$action_button?> - </button> - </div> - - </div> - - </div> - - </form> - - </div> -</div><!-- /manage --> - - -<!-- MODAL for file uploads and preview --> -<div class="modal fade" id="editorModal" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - <!-- content will be dynamic --> - </div> - </div> -</div> - diff --git a/public/app/views/xx--admin/edit_page.php b/public/app/views/xx--admin/edit_page.php deleted file mode 100644 index 46c47bc..0000000 --- a/public/app/views/xx--admin/edit_page.php +++ /dev/null @@ -1,139 +0,0 @@ -<?php - // some labels (if editing new or existing record) - // --- -- -- - - - - if ($id == 0) { - $action_title = "Δημιουργία Σελίδας"; - $action_button = "Δημιουργία"; - - } else { - $action_title = "Επεξεργασία Σελίδας"; - $action_button = "Αποθήκευση Αλλαγών"; - } -?> - -<!-- title bar --> -<div class="title-bar"> - <div><h5><?=$action_title?></h5></div> - <div> - <button type="button" class="btn pull-right" - data-bs-toggle="modal" data-bs-target="#editorModal" data-action="preview"> - <i class="fas fa-search"></i> Προεπισκόπηση - </button> - </div> -</div> - -<!-- manage --> -<div class="manage edit-page"> - <form> - <div class="row"> - - - <div class="col col-8"> - - <!-- id (hidden) --> - <input type="hidden" name="id" value="0"><!-- action = (0) ? 'new' : 'edit' --> - - <!-- - <div class="row form-group"> - <input type="date" name="date" value="" readonly=""> - </div> - --> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="title">Τίτλος</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="title" value="" required=""> - </div> - </div> - - <!-- Post body --> - <div class="row form-group"> - <label class="control-label col-sm-12" for="body">Κείμενο</label> - <div class="col-sm-12"> - <textarea class="form-control form-control-sm" type="text" name="body" value="" required=""></textarea> - </div> - </div> - - </div> - - <div class="col"> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="status">Κατάσταση</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" name="status" onchange="this.dataset.chosen = this.value;"> - <option value="0">Αδημοσίευτο</option> - <option value="one">ΔΗΜΟΣΙΕΥΜΕΝΟ</option> - </select> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="media">Αρχεία</label> - <div class="col-sm-12 post-media"> - - <!-- Button trigger modal --> - <button type="button" class="btn btn-sm btn-success pull-right over-bar" - data-bs-toggle="modal" data-bs-target="#editorModal" data-action="upload_file"> - <i class="fas fa-plus"></i> Προσθήκη - </button> - - <ul id="files_list"> - </ul> - - </div> - </div> - - <?php if ($id != 0) : ?> - <!-- - <div class="row form-group"> - <label class="control-label col-sm-12">Πληροφορίες</label> - <div class="col-sm-12" id="post-info"> - </div> - </div> - --> - <?php endif; ?> - - </div> - - </div> - - <div class="row"> - - <div class="col"> - <hr/> - <!-- close | submit buttons --> - - <div class="form-actions row justify-content-md-center"> - - <div class="col-3"> - <button type="button" id="go-back" class="btn btn-light col-sm-12"> - Επιστροφή - </button> - </div> - - <div class="col-4"> - <button class="btn btn-primary col-sm-12" type="submit"> - <?=$action_button?> - </button> - </div> - - </div> - - </div> - - </form> - - </div> -</div><!-- /manage --> - - -<!-- MODAL for file uploads and preview --> -<div class="modal fade" id="editorModal" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - <!-- content will be dynamic --> - </div> - </div> -</div> - diff --git a/public/app/views/xx--admin/files.php b/public/app/views/xx--admin/files.php deleted file mode 100644 index c6d2771..0000000 --- a/public/app/views/xx--admin/files.php +++ /dev/null @@ -1,96 +0,0 @@ - <!-- title bar --> - <div class="title-bar"> - <div><h5>Διαχείριση Επιπέδων Πρόσβασης</h5></div> - <div> - <!-- Button trigger modal - <button type="button" class="btn pull-right" - data-bs-toggle="modal" data-bs-target="#managePrivileges" data-id="0"> - <i class="fas fa-plus"></i> Νέο Επίπεδο - </button> - --> - </div> -</div> - -<div class="manage"> - <div class="row"> - <div class="col-md-12"> - - <div id="files"> - - <table id="dt-files" class="table table-responsive dt-table" style="width:100%"> - <thead> - <th class="dt-id">α/α</th> - <th class="dt-label">Περιγραφή</th> - <th class="dt-path">Διαδρομή</th> - <th class="dt-type">Media-Type</th> - <th class="dt-privilege">Πρόσβαση</th> - <th class="dt-actions"></th> - </thead> - </table> - - </div> - - - </div> - </div> -</div><!-- /manage --> - - - -<!-- MODAL for new/edit category --> -<!-- NOTE: tabindex="-1" removed, ref:https://github.com/select2/select2-bootstrap-theme/issues/41 --> -<div class="modal fade" id="manageFiles" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - - <form method="post" action=""> - - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Πρόσβαση αρχείου</h4> - <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> - </div><!-- /modal-header --> - - <!-- modal-body --> - <div class="modal-body"> - - <!-- form fields --> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="label">Κατηγορία Επιπέδου Πρόσβασης</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="label" value="" required=""> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="included_id">Κατηγορία Επιπέδου Πρόσβασης</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" id="privilege_id" name="privilege_id" required></select> - </div> - </div> - - <div class="row form-group"> - <input type="hidden" name="id" value="0"><!-- action = (0) ? 'new' : 'edit' --> - </div> - - - </div><!-- /modal body --> - - <div class="modal-footer"> - <div class="row form-actions"> - - <div class="col"> - <button type="button" class="btn btn-default js-modal-close col-sm-12" data-bs-dismiss="modal">Κλείσιμο</button> - </div> - <div class="col"> - <button class="btn btn-success col-sm-12" type="submit">Καταχώριση</button> - </div> - - </div> - </div><!-- /modal-footer --> - - </form><!-- /form --> - - </div> - </div> -</div> diff --git a/public/app/views/xx--admin/lessons.php b/public/app/views/xx--admin/lessons.php deleted file mode 100644 index d1cd3ae..0000000 --- a/public/app/views/xx--admin/lessons.php +++ /dev/null @@ -1,126 +0,0 @@ - <!-- title bar --> - <div class="title-bar"> - <div><h5>Διαχείριση Μαθημάτων</h5></div> - <div> - <!-- Button trigger modal --> - <a type="button" class="btn pull-right" href="/admin/edit_lesson"> - <i class="fas fa-plus"></i> Νέο Μάθημα - </a> - </div> -</div> - -<div class="manage"> - <div class="row"> - <div class="col-md-12"> - - <div id="lessons"> - - <table id="dt-lessons" class="table table-responsive dt-table" style="width:100%"> - <thead> - <th class="dt-id">α/α</th> - <th class="dt-title">Τίτλος</th> - <th class="dt-course">Κεφάλαιο</th> - <th class="dt-privileges">Πρόσβαση</th> - <th class="dt-actions"></th> - </thead> - </table> - - </div> - - </div> - </div> -</div><!-- /manage --> - - - -<!-- MODAL for new/edit category --> -<!-- NOTE: tabindex="-1" removed, ref:https://github.com/select2/select2-bootstrap-theme/issues/41 --> -<div class="modal fade" id="manageLessons" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - - <form method="post" action=""> - - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Παράμετροι Μαθήματος</h4> - <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> - </div><!-- /modal-header --> - - <!-- modal-body --> - <div class="modal-body"> - - <!-- form fields --> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="label">Τίτλος</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="title" value="" required=""> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="course_id">Κεφάλαιο</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" id="course_id" name="course_id" required></select> - </div> - </div> - - <!-- one line, two fields (privilege, status) --> - <div class="row"> - <div class="col-md-8"> - - <!-- privilege level --> - <div class="row form-group"> - <label class="control-label col-sm-12" for="privilege_id">Επίπεδο Πρόσβασης</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" id="privilege_id" name="privilege_id"> - </select> - </div> - </div> - - </div> - <div class="col-md-4"> - - <!-- status: published|unpublished --> - <div class="row form-group"> - <label class="control-label col-sm-12" for="status">Κατάσταση</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" name="status" onchange="this.dataset.chosen = this.value;"> - <option value="0">Αδημοσίευτο</option> - <option value="one">ΔΗΜΟΣΙΕΥΜΕΝΟ</option> - </select> - </div> - </div> - - - </div> - </div> - - - - - <div class="row form-group"> - <input type="hidden" name="id" value="0"><!-- lesson-id --> - </div> - - - </div><!-- /modal body --> - - <div class="modal-footer"> - <div class="row" style="width: 50%;"> - <div class="form-actions"> - <div class="col-4"> - <button type="button" class="btn btn-default js-modal-close col-sm-12" data-bs-dismiss="modal">Κλείσιμο</button> - </div> - <div class="col-8"> - <button class="btn btn-success col-sm-12" type="submit">Καταχώριση</button> - </div> - </div> - </div> - </div><!-- /modal-footer --> - - </form><!-- /form --> - - </div> - </div> -</div> diff --git a/public/app/views/xx--admin/pages.php b/public/app/views/xx--admin/pages.php deleted file mode 100644 index dd8f954..0000000 --- a/public/app/views/xx--admin/pages.php +++ /dev/null @@ -1,109 +0,0 @@ - <!-- title bar --> - <div class="title-bar"> - <div><h5>Διαχείριση Μαθημάτων</h5></div> - <div> - <!-- Button trigger modal --> - <a type="button" class="btn pull-right" href="/admin/edit_page"> - <i class="fas fa-plus"></i> Νέα Σελίδα - </a> - </div> -</div> - -<div class="manage"> - <div class="row"> - <div class="col-md-12"> - - <div id="pages"> - - <table id="dt-pages" class="table table-responsive dt-table" style="width:100%"> - <thead> - <th class="dt-id">α/α</th> - <th class="dt-title">Τίτλος</th> - <th class="dt-actions"></th> - </thead> - </table> - - </div> - - </div> - </div> -</div><!-- /manage --> - - - -<!-- MODAL for new/edit category --> -<!-- NOTE: tabindex="-1" removed, ref:https://github.com/select2/select2-bootstrap-theme/issues/41 --> -<div class="modal fade" id="managePages" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - - <form method="post" action=""> - - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Παράμετροι Μαθήματος</h4> - <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> - </div><!-- /modal-header --> - - <!-- modal-body --> - <div class="modal-body"> - - <!-- form fields --> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="label">Τίτλος</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="title" value="" required=""> - </div> - </div> - - - <!-- one line / two parts; status: pull right --> - <div class="row"> - <div class="col-md-8"> -  <!-- nothing --> - </div> - <div class="col-md-4"> - - <!-- status: published|unpublished --> - <div class="row form-group"> - <label class="control-label col-sm-12" for="status">Κατάσταση</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" name="status" onchange="this.dataset.chosen = this.value;"> - <option value="0">Αδημοσίευτο</option> - <option value="one">ΔΗΜΟΣΙΕΥΜΕΝΟ</option> - </select> - </div> - </div> - - - </div> - </div> - - - - - <div class="row form-group"> - <input type="hidden" name="id" value="0"><!-- page-id --> - </div> - - - </div><!-- /modal body --> - - <div class="modal-footer"> - <div class="row" style="width: 50%;"> - <div class="form-actions"> - <div class="col-4"> - <button type="button" class="btn btn-default js-modal-close col-sm-12" data-bs-dismiss="modal">Κλείσιμο</button> - </div> - <div class="col-8"> - <button class="btn btn-success col-sm-12" type="submit">Καταχώριση</button> - </div> - </div> - </div> - </div><!-- /modal-footer --> - - </form><!-- /form --> - - </div> - </div> -</div> diff --git a/public/app/views/xx--admin/panel.php b/public/app/views/xx--admin/panel.php deleted file mode 100644 index 59b8cba..0000000 --- a/public/app/views/xx--admin/panel.php +++ /dev/null @@ -1,4 +0,0 @@ -<br/> -<br/> -<br/> -<h4>Admin panel</h4>
\ No newline at end of file diff --git a/public/app/views/xx--admin/privileges.php b/public/app/views/xx--admin/privileges.php deleted file mode 100644 index 587c363..0000000 --- a/public/app/views/xx--admin/privileges.php +++ /dev/null @@ -1,93 +0,0 @@ - <!-- title bar --> - <div class="title-bar"> - <div><h5>Διαχείριση Επιπέδων Πρόσβασης</h5></div> - <div> - <!-- Button trigger modal --> - <button type="button" class="btn pull-right" - data-bs-toggle="modal" data-bs-target="#managePrivileges" data-id="0"> - <i class="fas fa-plus"></i> Νέο Επίπεδο - </button> - </div> -</div> - -<div class="manage"> - <div class="row"> - <div class="col-md-12"> - - <div id="categories-tree"> - - <table id="dt-privileges" class="table table-responsive dt-table" style="width:100%"> - <thead> - <th class="dt-id">Κωδικός</th> - <th class="dt-privilege">Επίπεδο Πρόσβασης</th> - <th class="dt-includes">Περιλαμβάνει</th> - <th class="dt-actions"></th> - </thead> - </table> - - </div> - - - </div> - </div> -</div><!-- /manage --> - - - -<!-- MODAL for new/edit category --> -<!-- NOTE: tabindex="-1" removed, ref:https://github.com/select2/select2-bootstrap-theme/issues/41 --> -<div class="modal fade" id="managePrivileges" aria-labelledby="myModalLabel" aria-hidden="true"> - <div class="modal-dialog modal-lg" role="document"> - <div class="modal-content"> - - <form method="post" action=""> - - <div class="modal-header"> - <h4 class="modal-title" id="myModalLabel">Modal title</h4> - <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> - </div><!-- /modal-header --> - - <!-- modal-body --> - <div class="modal-body"> - - <!-- form fields --> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="label">Όνομα Επιπέδου Πρόσβασης</label> - <div class="col-sm-12"> - <input class="form-control form-control-sm" type="text" name="label" value="" required=""> - </div> - </div> - - <div class="row form-group"> - <label class="control-label col-sm-12" for="included_id">Περιλαμβάνει μέχρι και το Επίπεδο</label> - <div class="col-sm-12"> - <select class="form-control form-control-sm form-select form-select-sm" id="included_id" name="included_id" required></select> - </div> - </div> - - <div class="row form-group"> - <input type="hidden" name="id" value="0"><!-- action = (0) ? 'new' : 'edit' --> - </div> - - - </div><!-- /modal body --> - - <div class="modal-footer"> - <div class="row form-actions"> - - <div class="col"> - <button type="button" class="btn btn-default js-modal-close col-sm-12" data-bs-dismiss="modal">Κλείσιμο</button> - </div> - <div class="col"> - <button class="btn btn-success col-sm-12" type="submit">Καταχώριση</button> - </div> - - </div> - </div><!-- /modal-footer --> - - </form><!-- /form --> - - </div> - </div> -</div> diff --git a/public/app/views/xx--admin/skeleton.php b/public/app/views/xx--admin/skeleton.php deleted file mode 100644 index 927bd2d..0000000 --- a/public/app/views/xx--admin/skeleton.php +++ /dev/null @@ -1,45 +0,0 @@ -<?php ob_start(); ?><!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="utf-8" /> - <meta name="viewport" content="width=device-width, initial-scale=1.0" /> - <title>Classroom - <?=$title?></title> - - <?php // header includes - //////////////////////////////////////////////////////////////////////// - Render::view('components/header_includes', //////////////////////////// - ['administration' => true] - ); - ?> - - -</head> -<body> - - <div class="classroom admin-container"> - - <?php - // sometimes an ID (int) is needed - // ex. editing a page or a lesson we need page-ID or lesson-ID - // --- -- -- - - - - if (!isset($id)) $id=0; - - // render menu - //////////////////////////////////////////////////////////////////// - Render::view('admin/admin-menu',[ //////////////////////////// - 'action' => $action, - 'id' => $id - ]); - - // render main content - //////////////////////////////////////////////////////////////////// - Render::view("admin/{$action}",[ 'id' => $id ]); //////////////// - ?> - </div> - - <!-- js admin script --> - <script>var entity_id = <?= $id ?>;</script> - <script src="/assets/js/admin/<?= $action ?>.js"></script> - -</body> -</html><?php ob_flush(); ?> diff --git a/public/assets/css/admin.css b/public/assets/css/admin.css deleted file mode 100644 index 58fcc45..0000000 --- a/public/assets/css/admin.css +++ /dev/null @@ -1,124 +0,0 @@ -:root { - --class-btn-blue: #337ab7; - --class-btn-cyan: #5bc0de; - --class-btn-grey: #c9c9c9; - --class-btn-grey-light: #c9c9c999; -} - -.office .manage { - width: 100%; - max-width: 1600px; - margin: 0 auto 2em; -} -.office .manage.maximized { max-width: 1960px; } -.office .manage.minimized { max-width: 960px; } -.office .manage.edit-post { max-width: 1420px; } - -.office .edit-post textarea[name=intro] { height: 12vh; } -.office .edit-post textarea[name=body] { - height: calc(100vh - 492px); - min-height:320px; - font-family: Consolas, 'Ubuntu Mono','Courier New', Courier, monospace; - color: #333; -} - -.office .edit-post .post-media button.over-bar { margin: -26px 0 0 0; } -.office .edit-post .post-media ul { - border: 1px solid #ccc; - border-radius: 4px; - padding: 6px; -} - -.office .edit-post .post-media ul li { - border-bottom: 1px solid #ddd; - list-style-type: none; - padding: 3px 6px; - - display: flex; - justify-content: space-between; - align-items: center; -} -.office .edit-post .post-media ul li:last-child { border-bottom: none ;} -.office .edit-post .post-media ul li:hover { background: #eee; } - -.office .manage h2 { - font-size: 20px; - color: #445; - margin: 20px 0; -} - -.office .manage.edit-post textarea { width: 100% !important;} -.office .manage.edit-post .select2-selection { min-height: 34px; } - -.office .manage.edit-post select#status.published { - background-color: #5cb85c; - border-color: #4cae4c; - color: #fff; - text-align: center; -} -.office .manage.edit-post select#status option { - background: #fff; - color: #333; -} - -/* --- optional fields: defaut=hide --- */ - -.office .edit-post .optional label { - margin-bottom: 1em; - padding-bottom: .5em; - border-bottom: 1px solid var(--class-btn-grey-light) -} -.office .edit-post .optional label.show { - margin-bottom: unset; - border: none; -} - - -.office .edit-post .optional label:hover { - cursor: pointer; - color: var(--class-btn-blue); -} -.office .edit-post .optional label::after { float: right; content: "+"; } -.office .edit-post .optional label.show::after { content: "–"; } -.office .edit-post .optional label + div { display: none; } -.office .edit-post .optional label.show + div { display: block; } - - -.alert.alert-info.title-bar { min-height: 52px; margin-top: 20px; } -.alert.alert-info.title-bar button { margin-left: 8px; } - -.office .title-bar { - display: flex; - justify-content: space-between; - align-items: center; - padding: 8px 8px 8px 16px; -} - -.office .action-btn button { float: right; } - -.office .top-bar { padding: 4px 0; } - -.office .top-bar .breadcrumb .btn { - margin-left: 0; - margin-right: 8px; - border-radius: 3px; - color: var(--class-btn-blue); -} - -.office .top-bar .btn:hover { - background-color: var(--class-btn-grey-light); -} -.office .top-bar .btn.selected { - color: #fff; - background-color: var(--class-btn-blue); -} - - -/* --- dataTables --- */ - -.office .manage .dataTable tbody tr:hover { background: #f8f8f8; } -.office .manage .dataTable .dt-actions { width: 48px; text-align: right } - -/* --- unpublished posts -- */ -.office .manage .dataTable .fa-eye-slash { color: #999; } - diff --git a/public/assets/css/class.css b/public/assets/css/class.css index d1e7715..6e44227 100644 --- a/public/assets/css/class.css +++ b/public/assets/css/class.css @@ -201,4 +201,6 @@ html, body { } .image-credits a:hover { color: var(--img-credit-hover-color); } -.manage .table tbody tr:hover { background: #eeea; }
\ No newline at end of file +.manage .table tbody tr:hover { background: #eeea; } + +.select2-results__option--selected { display: none; }
\ No newline at end of file diff --git a/public/assets/css/main.css b/public/assets/css/main.css deleted file mode 100644 index 016e0ab..0000000 --- a/public/assets/css/main.css +++ /dev/null @@ -1,9 +0,0 @@ -:root { - - --wrapperXXS: 816px; - --wrapperXS: 984px; - --wrapperS: 1142px; - --wrapper: 1240px; - --wrapperL: 1514px; - --wrapperFull: 1920px; -}
\ No newline at end of file diff --git a/public/assets/css/normalize.css b/public/assets/css/normalize.css deleted file mode 100644 index 192eb9c..0000000 --- a/public/assets/css/normalize.css +++ /dev/null @@ -1,349 +0,0 @@ -/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ - -/* Document - ========================================================================== */ - -/** - * 1. Correct the line height in all browsers. - * 2. Prevent adjustments of font size after orientation changes in iOS. - */ - -html { - line-height: 1.15; /* 1 */ - -webkit-text-size-adjust: 100%; /* 2 */ -} - -/* Sections - ========================================================================== */ - -/** - * Remove the margin in all browsers. - */ - -body { - margin: 0; -} - -/** - * Render the `main` element consistently in IE. - */ - -main { - display: block; -} - -/** - * Correct the font size and margin on `h1` elements within `section` and - * `article` contexts in Chrome, Firefox, and Safari. - */ - -h1 { - font-size: 2em; - margin: 0.67em 0; -} - -/* Grouping content - ========================================================================== */ - -/** - * 1. Add the correct box sizing in Firefox. - * 2. Show the overflow in Edge and IE. - */ - -hr { - box-sizing: content-box; /* 1 */ - height: 0; /* 1 */ - overflow: visible; /* 2 */ -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -pre { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/* Text-level semantics - ========================================================================== */ - -/** - * Remove the gray background on active links in IE 10. - */ - -a { - background-color: transparent; -} - -/** - * 1. Remove the bottom border in Chrome 57- - * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. - */ - -abbr[title] { - border-bottom: none; /* 1 */ - text-decoration: underline; /* 2 */ - text-decoration: underline dotted; /* 2 */ -} - -/** - * Add the correct font weight in Chrome, Edge, and Safari. - */ - -b, -strong { - font-weight: bolder; -} - -/** - * 1. Correct the inheritance and scaling of font size in all browsers. - * 2. Correct the odd `em` font sizing in all browsers. - */ - -code, -kbd, -samp { - font-family: monospace, monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - -/** - * Add the correct font size in all browsers. - */ - -small { - font-size: 80%; -} - -/** - * Prevent `sub` and `sup` elements from affecting the line height in - * all browsers. - */ - -sub, -sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -sub { - bottom: -0.25em; -} - -sup { - top: -0.5em; -} - -/* Embedded content - ========================================================================== */ - -/** - * Remove the border on images inside links in IE 10. - */ - -img { - border-style: none; -} - -/* Forms - ========================================================================== */ - -/** - * 1. Change the font styles in all browsers. - * 2. Remove the margin in Firefox and Safari. - */ - -button, -input, -optgroup, -select, -textarea { - font-family: inherit; /* 1 */ - font-size: 100%; /* 1 */ - line-height: 1.15; /* 1 */ - margin: 0; /* 2 */ -} - -/** - * Show the overflow in IE. - * 1. Show the overflow in Edge. - */ - -button, -input { /* 1 */ - overflow: visible; -} - -/** - * Remove the inheritance of text transform in Edge, Firefox, and IE. - * 1. Remove the inheritance of text transform in Firefox. - */ - -button, -select { /* 1 */ - text-transform: none; -} - -/** - * Correct the inability to style clickable types in iOS and Safari. - */ - -button, -[type="button"], -[type="reset"], -[type="submit"] { - -webkit-appearance: button; -} - -/** - * Remove the inner border and padding in Firefox. - */ - -button::-moz-focus-inner, -[type="button"]::-moz-focus-inner, -[type="reset"]::-moz-focus-inner, -[type="submit"]::-moz-focus-inner { - border-style: none; - padding: 0; -} - -/** - * Restore the focus styles unset by the previous rule. - */ - -button:-moz-focusring, -[type="button"]:-moz-focusring, -[type="reset"]:-moz-focusring, -[type="submit"]:-moz-focusring { - outline: 1px dotted ButtonText; -} - -/** - * Correct the padding in Firefox. - */ - -fieldset { - padding: 0.35em 0.75em 0.625em; -} - -/** - * 1. Correct the text wrapping in Edge and IE. - * 2. Correct the color inheritance from `fieldset` elements in IE. - * 3. Remove the padding so developers are not caught out when they zero out - * `fieldset` elements in all browsers. - */ - -legend { - box-sizing: border-box; /* 1 */ - color: inherit; /* 2 */ - display: table; /* 1 */ - max-width: 100%; /* 1 */ - padding: 0; /* 3 */ - white-space: normal; /* 1 */ -} - -/** - * Add the correct vertical alignment in Chrome, Firefox, and Opera. - */ - -progress { - vertical-align: baseline; -} - -/** - * Remove the default vertical scrollbar in IE 10+. - */ - -textarea { - overflow: auto; -} - -/** - * 1. Add the correct box sizing in IE 10. - * 2. Remove the padding in IE 10. - */ - -[type="checkbox"], -[type="radio"] { - box-sizing: border-box; /* 1 */ - padding: 0; /* 2 */ -} - -/** - * Correct the cursor style of increment and decrement buttons in Chrome. - */ - -[type="number"]::-webkit-inner-spin-button, -[type="number"]::-webkit-outer-spin-button { - height: auto; -} - -/** - * 1. Correct the odd appearance in Chrome and Safari. - * 2. Correct the outline style in Safari. - */ - -[type="search"] { - -webkit-appearance: textfield; /* 1 */ - outline-offset: -2px; /* 2 */ -} - -/** - * Remove the inner padding in Chrome and Safari on macOS. - */ - -[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; -} - -/** - * 1. Correct the inability to style clickable types in iOS and Safari. - * 2. Change font properties to `inherit` in Safari. - */ - -::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - -/* Interactive - ========================================================================== */ - -/* - * Add the correct display in Edge, IE 10+, and Firefox. - */ - -details { - display: block; -} - -/* - * Add the correct display in all browsers. - */ - -summary { - display: list-item; -} - -/* Misc - ========================================================================== */ - -/** - * Add the correct display in IE 10+. - */ - -template { - display: none; -} - -/** - * Add the correct display in IE 10. - */ - -[hidden] { - display: none; -} diff --git a/public/assets/js/admin/categories.js b/public/assets/js/admin/categories.js deleted file mode 100644 index e4d2955..0000000 --- a/public/assets/js/admin/categories.js +++ /dev/null @@ -1,288 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var categories = []; -var table; - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// array.indexOf polyfill -// --- -- -- - - - -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - - for (; from < len; from++) - { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; -} - - -// function for sorting an array by 'breadcrumb' attribute -// --- -- -- - - - -function compare_breadcrumb (a,b) { - if ( a.breadcrumb < b.breadcrumb ) { return -1; } - if ( a.breadcrumb > b.breadcrumb ) { return 1; } - return 0; -} - -// return category record by category-id -// --- -- -- - - - -function category_record(id) { - var record = 0; - categories.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - - -// return children of parent -// --- -- -- - - - -function childs_of_parents(list) { - // if 'list' is integer then make it an one-item list - parents = (Number.isInteger(list)) ? [ list ] : list; - - var childs = []; - - if (parents.length == 0) { return []; } - - parents.forEach( pid => { - categories.forEach( el => { if (el.parent == pid) childs.push(el.id)}); - }); - - var grandchilds = childs_of_parents(childs); - - return childs.concat(grandchilds); -} - - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(id) { - - var del, edit; - - del = ""; - - edit = [ - '<button type="button" class="btn btn-sm btn-warning"', - 'data-bs-toggle="modal" data-bs-target="#manageCategory"', - 'data-id="'+ id +'">', - '<i class="fas fa-pencil-alt"></i>', - '</button>' - ].join('\n'); - - return edit +' '+ del; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - /** init selec2 element (used to specify parent-category) - * --- -- -- - - - - */ - $("#parent_id").select2({ - placeholder: 'Γονική Κατηγορία', - dropdownParent: $('#manageCategory'), - width: '100%', - // dropdownParent: "#manageCategory" // ref: https://github.com/select2/select2-bootstrap-theme/issues/41 - }); - - - /** init_table - * --- -- -- - - - - * get categories - * constuct categories array - * render dataTable - */ - function init_table() { - - // get all categories from server (ajax) - $.getJSON( "/admin/api/categories") - .done(function( json ) { - // then ... - - // reset categories - categories.length = 0; - - // construct (new) categories data - Object.keys(json).forEach( key => { - el = json[key]; - categories.push({ - id: parseInt(el.rec.id), - label: el.rec.label, - breadcrumb: el.breadcrumb.replaceAll('\t', ' / '), - parent: parseInt(el.rec.parent), - actions: create_actions_html(el.rec.id) - }); - }); - - // sort by breadcrumb - categories.sort( compare_breadcrumb ); - - // destroy previous datatable table instances - $('#dt-categories').dataTable().fnClearTable(); - $('#dt-categories').dataTable().fnDestroy(); - - // (re-)create categories datatable - table = $('#dt-categories').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: categories, - ordering: false, - columns: [ - { data: 'breadcrumb' }, - { data: 'actions' } - ] - }); - - }) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed (" + error +")" ); - }); - - } - init_table(); // init table on first run - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#manageCategory').on('show.bs.modal', event => { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = parseInt( button.data('id') ); // category_id from data-id - // var modal = $(this); // modal object - - // update modal literature - // --- - $('#manageCategory .modal-title').html( // modal title - (id) ? 'Ενημέρωση Κατηγορίας' : 'Δημιουργία Κατηγορίας' - ); - $('#manageCategory form input[name=id]').val( id ); // category id (hidden) - $('#manageCategory form input[name=label]').val( // category label - (id) ? category_record(id).label : "" - ); - prepare_parents_element(id); // prepare <select> for parents - }) - - /** prepare_parents_element() - * --- - * @param id (int) : id of selected category - * -> Get all posible parents - * -> call set_parent_options() to render the options - */ - function prepare_parents_element(id) { - var parents = []; - - if (id) { // get all possible parents - - // id-category and subcategories are fobiden parents - var forbiden = childs_of_parents(id); - forbiden.push(id); - - // filter catogories adn prepare parents - categories.forEach( el => { - if (!forbiden.includes(el.id)) { - parents.push({ - id: el.id, - breadcrumb: el.breadcrumb, - }); - } - }); - set_parent_options(parents, category_record(id).parent); - - - } else { // new record; all categories are possible parrents - categories.forEach( el => { - parents.push({ - id: el.id, - breadcrumb: el.breadcrumb, - }); - }) - set_parent_options(parents, -1); - } - } - - /** set_parent_options() - * -> create options for parents <select> - * -> choose selected parent - * @param parents (array): array of parents - * @param selected (int): selected parent - */ - function set_parent_options(parents, selected) { - // sort parents by breadcrumb - parents.sort( compare_breadcrumb ); - - // remove any olded options from select2 - $('#parent_id option').each(function() { $(this).remove(); }); - - // first option is the root category - $('#parent_id').append('<option value="0">Root</option>') - - // add all other parent options - parents.forEach( i => { - $('#parent_id').append(`<option value="${i.id}">${i.breadcrumb}</option>`); - }); - - if (selected == -1) { // new category; remove any parent pre-selection - $('#parent_id').val(null).trigger('change'); - - } else { // category exists; choose selected parent - $('#parent_id').val(selected).trigger('change'); - } - } - - - - - // When form is submited - // ------------------------------------------------------------------------- - - $('#manageCategory form').submit( event => { - event.preventDefault(); - - // prepare data to POST - var data = { - id: parseInt($('#manageCategory form input[name=id]').val()), - label: $('#manageCategory form input[name=label]').val(), - parent_id: parseInt($('#parent_id').select2('data')[0].id) - }; - - // select action url (add or update) - var request = '/admin/api/categories/' + ((data.id == 0) ? 'add' : 'update'); - - // send POST request - $.post(request, data) - .done(function( data ) { - - $('#manageCategory').modal('hide'); // when done, close modal - - init_table(); // reload table of categories - }); - - }); - -}); diff --git a/public/assets/js/admin/edit_lesson.js b/public/assets/js/admin/edit_lesson.js deleted file mode 100644 index 367c3b7..0000000 --- a/public/assets/js/admin/edit_lesson.js +++ /dev/null @@ -1,600 +0,0 @@ -/** NOTE: - * depricated code for tag-system is commented-out and kept in the source-code - * as case-study; the code is operational; - */ - - -// Globals -// ----------------------------------------------------------------------------- - -// NOTE: -// Variable `entity_id` is defined before evaluating this script -// id (int) : the id of edited post (or 0 if new post) - -var lesson; - -var id = (entity_id == 0) ? false : entity_id; - -var categories = [ - // Nope! root can not be a post's category ... { id: 0 , label: 'Ρίζα (root)' } -]; - -var privileges = [ - { id: 0, label: '_Δημόσιο_'} -]; - -var files = []; // array of { id:.., title:.., type:.., path:.. } records - -// TODO: support tags -// var tags = []; // array of integers - - -// an alternative--id when a lesson_id not exists (needed for file-upload) -// ... consist of a 6-digit date string + random number up to 999 -const yymmdd = new Date().toISOString().slice(2, 10).replaceAll('-',''); -var rnd999 = Math.floor(Math.random() * 1000); -var altID = (id == 0) ? ( yymmdd +'-'+ rnd999.toString() ) : id; - - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// function for sorting an array by 'label' attribute -// --- -- -- - - - -function compare_label (a,b) { - if ( a.label < b.label ) { return -1; } - if ( a.label > b.label ) { return 1; } - return 0; -} - -// return course record by course-id -// --- -- -- - - - -function course_record(id) { - var record = 0; - categories.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - - - - -// Modal HTML Creators -// ----------------------------------------------------------------------------- - -const modal_header = (title) => { - return [ - '<div class="modal-header">', - '<h4 class="modal-title" id="myModalLabel">', - title, - '</h4>', - '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">', - '<span aria-hidden="true"></span>', - '</button>', - '</div>' - ].join('\n'); -} - - -const upload_file_form = () => { - return [ - '<form method="POST" id="file_upload_form" name="upload_file_form">', - - '<div class="modal-body">', - - '<input type="hidden" name="folder" value="'+ altID +'">', - - '<div class="form-group">', - '<label for="title">Τίτλος/Περιγραφή για το Αρχείο</label>', - '<input type="text" class="form-control " value="" name="title" id="title" placeholder="Τίτλος για το Αρχείο" required="">', - '</div>', - - '<div class="form-group">', - '<label class="control-label" for="file">Εισαγωγή Αρχείου</label>', - '<input class="form-control" type="file" id="file" name="file" required="">', - '</div>', - - '</div>', - - '<div class="modal-footer">', - '<div class="row" style="width: 50%;">', - '<div class="form-actions">', - '<div class="col col-4">', - '<buton type="button" class="btn btn-default js-modal-close col-12" data-bs-dismiss="modal">', - 'Κλείσιμο', - '</button>', - '</div>', - '<div class="col-8">', - '<button class="btn btn-success col-12" type="submit">Καταχώριση</button>', - '</div>', - '</div>', - '</div>', - '</div>', - - '</form>' - ].join('\n'); -} - - -const preview_article = (title, intro, body) => { - return [ - '<div class="modal-body">', - '<div class="post">', - - '<h2>'+ title +'</h2>', - - ((intro == '') ? '' : ('<div class="intro">'+ intro +'</div>')), - - '<div class="article-body">', - marked.parse(body, { sanitize: true }), - '</div>', - - '</div>', - '</div>', - '<div class="modal-footer">', - '<div class="row" style="width: 50%;">', - '<div class="form-actions">', - '<div class="col-md-4 col-md-offset-4 col-6 col-offset-3">', - '<buton type="button" class="btn btn-default js-modal-close col-12" data-bs-dismiss="modal">', - 'Κλείσιμο', - '</button>', - '</div>', - '</div>', - '</div>', - '</div>' - ].join('\n'); -} - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - // inti category (select2) - // ... - $("#course_id").select2({ - placeholder: 'Κεφάλαιο', - width: '100%' - }); - - // inti category (select2) - // ... - $("#privilege_id").select2({ - placeholder: 'Επίπεδο Πρόσβασης', - width: '100%' - }); - - - /** DEPRICATED: (tag system) - * - * // init tags (select2) - * // ... - * $('#tags').select2({ - * placeholder: 'Ετικέτες (tags/keywords)', - * width: '100%', - * tags: true - * }); - */ - - /** DEPRICATED: - * - * // TINY-MCE EDITOR - * init editor (tiny MCE) - * tinymce.init({ - * selector: 'form textarea[name=body]', - * language: 'el', - * menubar: true - * }); - */ - - - /** preload content - * --- -- -- - - - - * get post - * get categories - * get tags - * update content (form-elements) - */ - if (id) { // if an `id` is given, load post .. then init_form - - $.getJSON( "/admin/api/lesson/" + id ) - .done( function (data) { - lesson = data; // keep post - - // update fields' values - $('input[name=id]').val(lesson.id); // id - $('input[name=title]').val(lesson.title); // title - $('textarea[name=intro]').val(lesson.intro); // intro - $('textarea[name=body]').val(lesson.body); // body - $('select[name=status]').val( - (lesson.status == 0) ? '0' : "one" - ).trigger('change'); - // $('input[name=status]').prop( // status - // 'checked', - // ((lesson.status==1)? true : false)) - // .trigger('change'); - - // $('#post-info').html('Δημιουργία: '+post.creation_date+'<br>Τελευταία Ενημέρωση: '+ post.update_date); - - // parse media files; then draw - if (lesson.medias_json != null) { - files = JSON.parse(lesson.medias_json); - } - draw_files_list(); // then draw the files list - - init_form_values(); // init all (other) values - }); - - } else { // else ... just init_form - init_form_values(); - } - - - - /** - * load categories and tags; - * if not a new post (id!=0) update form elemnts with post's values - */ - function init_form_values() { - - $.when( // when loaded posts and categories - - $.getJSON( "/admin/api/categories" ), - - $.getJSON( "/admin/api/privileges" ) - - ).done( function( categories_response, privileges_response ) { - - // construct categories data - // --- - Object.keys(categories_response[0]).forEach( key => { - cat = categories_response[0][key]; - categories.push({ - id: cat.rec.id, - label: cat.breadcrumb.replaceAll('\t', ' / ') - }); - }); - categories.sort( compare_label ); // sort categories by breadcrumb - - /** DEPRICATED: (tag system) - * - * // construct tags data - * // --- - * Object.keys(tags_response[0]).forEach( key => { - * tag = tags_response[0][key]; - * tags.push({ - * id: tag.id, - * label: tag.name - * }); - * }); - */ - - // construct provileges data - // --- - Object.keys(privileges_response[0]).forEach( key => { - priv = privileges_response[0][key]; - privileges.push({ - id: priv.id, - label: priv.label - }); - }); - privileges.sort( compare_label ); // sort categories by breadcrumb - - // pass categories and tags options onto select2 elements - // --- -- -- - - - - if (id == 0) { - set_parent_options( $('#course_id'), categories ); - set_parent_options( $('#privilege_id'), privileges ); - - } else { - // setup category_id options; select post's chosen category-id - set_parent_options( $('#course_id'), categories, lesson.course_id ); - - /*** DEPRICATED: (tag system) - * - * // parse selected tags - * // --- - * var selected_tag_ids = []; - * if (post.tags_json != null) { - * var selected_tags = JSON.parse(post.tags_json); - * selected_tags.forEach( itag => { selected_tag_ids.push(itag.id); }) - * } - */ - - // setup tags options; select post's chosen tags - set_parent_options( $('#privilege_id'), privileges, lesson.privilege_id ); - - // DEPRICATED: ALSO: if tags selectd, show tags field - // if (selected_tag_ids.length != 0) { $('.optional label[for=tags]').addClass('show'); } - } - - }); - - } - - - /** set_parent_options() - * - * -> create options for parents <select> - * -> choose selected parent - * - * NOTE: - * the targer <select> should be a select2 control - * - * @param parents (array): array of parents - * @param selected (int): selected parent - */ - function set_parent_options(selector, list, selected_value = false) { - - list.forEach( li => { // attach options into <select> control - selector.append(`<option value="${li.id}">${li.label}</option>`); - }); - - if (selected_value !== false) { // mark selected option(s) - selector.val(selected_value).trigger('change'); - } - else { selector.val(null).trigger('change'); } - } - - - /** draw_files_list - * --- -- -- - - - - */ - function draw_files_list() { - var li_list = []; - var ref_icon, ref_class; - - files.forEach( item => { - var copy = [ // copy button - '<button type="button" class="btn btn-xs btn-default js-copy"', - ' data-url="' + item.path +'"', - ' data-type="' + item.type + '"', - '>', - '<i class="far fa-clone"></i>', - '</button>' - ].join(''); - - var del = [ // delete button - '<button type="button" class="btn btn-xs btn-danger js-delete"', - 'data-id="' + item.id + '">', - '<i class="fas fa-trash-alt"></i>', - '</button>' - ].join(''); - var option = [ // li html - '<li>', - '<div class="text">' + item.label + '</div>', - '<div class="actions">', - copy, ' ', del, - '</div>', - '</li>' - ].join(''); - li_list.push(option); // push to li_list - }); - $('#files_list').html( li_list.join('\n') ); - - } - - - - // When form's action-buttons are clicked - // ------------------------------------------------------------------------- - - - // form submit - // --- -- -- - - - - $('.edit-post form').submit( event => { - event.preventDefault(); - - /** DEPRICATED: - * - ### TAG SYSTEM - # // rearrange tags to old and new ones - # // --- - # var old_tags = []; - # var new_tags = []; - # var tags = $('#tags').select2('data'); - # tags.forEach( t => { - # if (!parseInt(t.id)) { - # new_tags.push(t.text); - # } else { old_tags.push(t.id); } - # }) - */ - - var attachments = []; - // attachments (array) of "`media_id`;`reference`" strings - files.forEach( f => { attachments.push( f.id ) }); - - // prepare data to POST - // --- - var data = { - id: parseInt($('.edit-post form input[name=id]').val()), - title: $('.edit-post form input[name=title]').val(), - course_id: parseInt($('#course_id').select2('data')[0].id), - intro: $('.edit-post form textarea[name=intro]').val(), - body: $('.edit-post form textarea[name=body]').val(), - status: ( ($('select[name=status]').val() == "0") ? 0 : 1 ), - privilege_id: parseInt($('#privilege_id').select2('data')[0].id), - // tags: old_tags, - // new_tags: new_tags, - media: attachments - }; - - // select action url (add or update) - // --- - var request = '/admin/api/lesson/' + ((data.id == 0) ? 'add' : 'update'); - - // send POST (ajax) request - $.post(request, data) - .done(function( data ) { - // console.log(data); - window.location.href = '/admin/lessons'; // seems ok; bach to articles - }); - - }); - - - // go-back (to lessons) - // --- -- -- - - - - $('#go-back').click( event => { - if (confirm('Θέλετε να ακυρώσετε τις όποιες αλλαγές και να φύγτε από τη σελίδα;')) { - window.location.href = '/admin/lessons'; - } - }); - - - // copy url button - // --- -- -- - - - - $('.admin-container').on('click', 'button.js-copy', function (e) { - var copytext = ''; // default: copy nothing - - if ($(this).data('id') !== undefined) { - copytext = window.location.origin +'/lesson/' + $(this).data('id'); - } - - if ($(this).data('url') !== undefined) { - copytext = window.location.origin + '/serve/file/' + $(this).data('url') + '?type=' + $(this).data('type'); - } - - navigator.clipboard - .writeText(copytext) - .then(() => { // notify the copy event - $(this).addClass('copied'); - setTimeout( () => { $(this).removeClass('copied'); }, 700); - console.log(copytext, ' copied!'); - }) - .catch(() => { - console.log("error on coping text"); - }); - }); - - - - // delete (remove) file button - // --- -- -- - - - - $('.admin-container').on('click', 'button.js-delete', function (e) { - console.log('delete!'); - var media_id = $(this).data('id'); - - // remove from files array the one with id == media_id - // --- - var temp = []; - files.forEach( it => { if (it.id != media_id) temp.push(it); }); - - files = temp; // re-define files - draw_files_list(); // then re-draw files list - }); - - - - /** DEPRICATED: - * - # // show|hide file as referece button - # // --- -- -- - - - - # $('.admin-container').on('click', 'button.js-reference', function (e) { - # var id = $(this).data('id'); - # - # // toggle reference attribute of item with `id` = id - # // --- - # var temp = []; - # files.forEach( it => { - # if (it.id == id) { - # it.reference = (it.reference==0) ? 1 : 0; - # } - # temp.push(it) - # }); - # - # files = temp; // re-define files - # draw_files_list(); // then re-draw files list - # }); - */ - - - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#editorModal').on('show.bs.modal', event => { - let button = $(event.relatedTarget); // Button that triggered the modal - let action = button.data('action'); // action - // var modal = $(this); // modal object - - // update modal literature - - switch (action) { - case 'upload_file': - $("#editorModal .modal-content").html( - modal_header('Εισαγωγή Αρχείου') + upload_file_form() - ); - break; - - case 'preview': - let preview = preview_article( - $('.edit-post form input[name=title]').val(), - $('.edit-post form textarea[name=intro]').val(), - $('.edit-post form textarea[name=body]').val() - ); - $("#editorModal .modal-content").html( modal_header('Προεπισκόπηση') + preview); - break; - - default: - // do nothing - } - - }); - - - - /** submit upload file event - * ------------------------------------------------------------------------- - */ - $('#editorModal').on('submit', 'form[name=upload_file_form]', function (event) { - event.preventDefault(); - - // create the FormData object - // --- -- -- - - - - var fd = new FormData(document.getElementById('file_upload_form')); - - // post the form (via ajax) - $.ajax({ - url: '/admin/api/file_upload', - type: 'POST', - data: fd, - contentType: false, - processData: false, - dataType: 'json', - success: function(response) { // on success - - if (response.success) { - files.push({ // ... update files array - id: response.id, - label: response.title, - path: response.path, - type: response.type - }); - draw_files_list(); - - $('#editorModal').modal('hide'); - - } else { - console.log('File not uploaded'); - } - } - }); - }); - - - // TODO: - // disable links while previewing the article - // OR add a target="_blank" - - -}); - diff --git a/public/assets/js/admin/edit_page.js b/public/assets/js/admin/edit_page.js deleted file mode 100644 index ec0e84e..0000000 --- a/public/assets/js/admin/edit_page.js +++ /dev/null @@ -1,382 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- - -// NOTE: -// Variable `entity_id` is defined before evaluating this script -// id (int) : the id of edited post (or 0 if new post) - -var page; - -var id = (entity_id == 0) ? false : entity_id; - -var files = []; // array of { id:.., title:.., type:.., path:.. } records - -// TODO: support tags -// var tags = []; // array of integers - - - -// an alternative--id when a page_id not exists (needed for file-upload) -// ... consist of a 6-digit date string + random number up to 999 -const yymmdd = new Date().toISOString().slice(2, 10).replaceAll('-',''); -var rnd999 = Math.floor(Math.random() * 1000); -var altID = (id == 0) ? ( yymmdd +'-'+ rnd999.toString() ) : id; - - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// function for sorting an array by 'label' attribute -// --- -- -- - - - -function compare_label (a,b) { - if ( a.label < b.label ) { return -1; } - if ( a.label > b.label ) { return 1; } - return 0; -} - -// return course record by course-id -// --- -- -- - - - -function course_record(id) { - var record = 0; - categories.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - - - - -// Modal HTML Creators -// ----------------------------------------------------------------------------- - -const modal_header = (title) => { - return [ - '<div class="modal-header">', - '<h4 class="modal-title" id="myModalLabel">', - title, - '</h4>', - '<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close">', - '<span aria-hidden="true"></span>', - '</button>', - '</div>' - ].join('\n'); -} - - -const upload_file_form = () => { - return [ - '<form method="POST" id="file_upload_form" name="upload_file_form">', - - '<div class="modal-body">', - - '<input type="hidden" name="folder" value="'+ altID +'">', - - '<div class="form-group">', - '<label for="title">Τίτλος/Περιγραφή για το Αρχείο</label>', - '<input type="text" class="form-control " value="" name="title" id="title" placeholder="Τίτλος για το Αρχείο" required="">', - '</div>', - - '<div class="form-group">', - '<label class="control-label" for="file">Εισαγωγή Αρχείου</label>', - '<input class="form-control" type="file" id="file" name="file" required="">', - '</div>', - - '</div>', - - '<div class="modal-footer">', - '<div class="row" style="width: 50%;">', - '<div class="form-actions">', - '<div class="col col-4">', - '<buton type="button" class="btn btn-default js-modal-close col-12" data-bs-dismiss="modal">', - 'Κλείσιμο', - '</button>', - '</div>', - '<div class="col-8">', - '<button class="btn btn-success col-12" type="submit">Καταχώριση</button>', - '</div>', - '</div>', - '</div>', - '</div>', - - '</form>' - ].join('\n'); -} - - -const preview_article = (title, body) => { - return [ - '<div class="modal-body">', - '<div class="post">', - - '<h2>'+ title +'</h2>', - - '<div class="article-body">', - marked.parse(body, { sanitize: true }), - '</div>', - - '</div>', - '</div>', - '<div class="modal-footer">', - '<div class="row" style="width: 50%;">', - '<div class="form-actions">', - '<div class="col-md-4 col-md-offset-4 col-6 col-offset-3">', - '<buton type="button" class="btn btn-default js-modal-close col-12" data-bs-dismiss="modal">', - 'Κλείσιμο', - '</button>', - '</div>', - '</div>', - '</div>', - '</div>' - ].join('\n'); -} - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - /** preload content - * --- -- -- - - - - * get page - * update content (form-elements) - */ - if (id) { // if an `id` is given, load post .. then init_form - - $.getJSON( "/admin/api/page/" + id ) - .done( function (data) { - page = data; // keep post - - // update fields' values - $('input[name=id]').val(page.id); // id - $('input[name=title]').val(page.title); // title - $('textarea[name=body]').val(page.body); // body - $('select[name=status]').val( - (page.status == 0) ? '0' : "one" - ).trigger('change'); - - // $('#post-info').html('Δημιουργία: '+post.creation_date+'<br>Τελευταία Ενημέρωση: '+ post.update_date); - - // parse media files; then draw - if (page.medias_json != null) { - files = JSON.parse(page.medias_json); - } - draw_files_list(); // then draw the files list - - }); - - } - - - /** draw_files_list - * --- -- -- - - - - */ - function draw_files_list() { - var li_list = []; - var ref_icon, ref_class; - - files.forEach( item => { - var copy = [ // copy button - '<button type="button" class="btn btn-xs btn-default js-copy"', - ' data-url="' + item.path +'"', - ' data-type="' + item.type + '"', - '>', - '<i class="far fa-clone"></i>', - '</button>' - ].join(''); - - var del = [ // delete button - '<button type="button" class="btn btn-xs btn-danger js-delete"', - 'data-id="' + item.id + '">', - '<i class="fas fa-trash-alt"></i>', - '</button>' - ].join(''); - var option = [ // li html - '<li>', - '<div class="text">' + item.label + '</div>', - '<div class="actions">', - copy, ' ', del, - '</div>', - '</li>' - ].join(''); - li_list.push(option); // push to li_list - }); - $('#files_list').html( li_list.join('\n') ); - - } - - - - // When form's action-buttons are clicked - // ------------------------------------------------------------------------- - - - // form submit - // --- -- -- - - - - $('.edit-page form').submit( event => { - event.preventDefault(); - - var attachments = []; - // attachments (array) of "`media_id`;`reference`" strings - files.forEach( f => { attachments.push( f.id ) }); - - // prepare data to POST - // --- - var data = { - id: parseInt($('.edit-page form input[name=id]').val()), - title: $('.edit-page form input[name=title]').val(), - body: $('.edit-page form textarea[name=body]').val(), - status: ( ($('select[name=status]').val() == "0") ? 0 : 1 ), - media: attachments - }; - - // select action url (add or update) - // --- - var request = '/admin/api/page/' + ((data.id == 0) ? 'add' : 'update'); - - // send POST (ajax) request - $.post(request, data) - .done(function( data ) { - console.log(data); - window.location.href = '/admin/pages'; // seems ok; bach to articles - }); - - }); - - - // go-back (to pages) - // --- -- -- - - - - $('#go-back').click( event => { - if (confirm('Θέλετε να ακυρώσετε τις όποιες αλλαγές και να φύγτε από τη σελίδα;')) { - window.location.href = '/admin/pages'; - } - }); - - - // copy url button - // --- -- -- - - - - $('.admin-container').on('click', 'button.js-copy', function (e) { - var copytext = ''; // default: copy nothing - - if ($(this).data('id') !== undefined) { - copytext = window.location.origin +'/page/' + $(this).data('id'); - } - - if ($(this).data('url') !== undefined) { - copytext = window.location.origin + '/serve/file/' + $(this).data('url') + '?type=' + $(this).data('type'); - } - - navigator.clipboard - .writeText(copytext) - .then(() => { // notify the copy event - $(this).addClass('copied'); - setTimeout( () => { $(this).removeClass('copied'); }, 700); - console.log(copytext, ' copied!'); - }) - .catch(() => { - console.log("error on coping text"); - }); - }); - - - - // delete (remove) file button - // --- -- -- - - - - $('.admin-container').on('click', 'button.js-delete', function (e) { - console.log('delete!'); - var media_id = $(this).data('id'); - - // remove from files array the one with id == media_id - // --- - var temp = []; - files.forEach( it => { if (it.id != media_id) temp.push(it); }); - - files = temp; // re-define files - draw_files_list(); // then re-draw files list - }); - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#editorModal').on('show.bs.modal', event => { - let button = $(event.relatedTarget); // Button that triggered the modal - let action = button.data('action'); // action - // var modal = $(this); // modal object - - // update modal literature - - switch (action) { - case 'upload_file': - $("#editorModal .modal-content").html( - modal_header('Εισαγωγή Αρχείου') + upload_file_form() - ); - break; - - case 'preview': - let preview = preview_article( - $('.edit-page form input[name=title]').val(), - $('.edit-page form textarea[name=body]').val() - ); - $("#editorModal .modal-content").html( modal_header('Προεπισκόπηση') + preview); - break; - - default: - // do nothing - } - - }); - - - - /** submit upload file event - * ------------------------------------------------------------------------- - */ - $('#editorModal').on('submit', 'form[name=upload_file_form]', function (event) { - event.preventDefault(); - - // create the FormData object - // --- -- -- - - - - var fd = new FormData(document.getElementById('file_upload_form')); - - // post the form (via ajax) - $.ajax({ - url: '/admin/api/file_upload', - type: 'POST', - data: fd, - contentType: false, - processData: false, - dataType: 'json', - success: function(response) { // on success - - if (response.success) { - files.push({ // ... update files array - id: response.id, - label: response.title, - path: response.path, - type: response.type - }); - draw_files_list(); - - $('#editorModal').modal('hide'); - - } else { - console.log('File not uploaded'); - } - } - }); - }); - - - // TODO: - // disable links while previewing the article - // OR add a target="_blank" - - -}); - diff --git a/public/assets/js/admin/files.js b/public/assets/js/admin/files.js deleted file mode 100644 index e100b30..0000000 --- a/public/assets/js/admin/files.js +++ /dev/null @@ -1,302 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var privileges = [ { id: 0, label: 'Δημόσιο' } ]; -var files = []; -var table; - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// array.indexOf polyfill -// --- -- -- - - - -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - - for (; from < len; from++) - { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; -} - - -// function for sorting an array by 'label' attribute -// --- -- -- - - - -function compare_label (a,b) { - if ( a.label < b.label ) { return -1; } - if ( a.label > b.label ) { return 1; } - return 0; -} - - -// return file record by file-id -// --- -- -- - - - -function privilege_record(id) { - var record = 0; - files.forEach(el => { if (el.id == id) record = el; }); - return record; -} - - -/** privilege(id) - * label of privilege with - * @param id (int) - */ -function privilege_(id) { - let reply = false; - privileges.forEach( pri => { if (pri.id == id) reply = pri.label; }); - return reply; -} - - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(id) { - - var del, edit; - - del = ""; - - edit = [ - '<button type="button" class="btn btn-sm btn-warning"', - 'data-bs-toggle="modal" data-bs-target="#manageFiles"', - 'data-id="'+ id +'">', - '<i class="fas fa-pencil-alt"></i>', - '</button>' - ].join('\n'); - - return edit +' '+ del; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - /** init selec2 element (used to specify parent-category) - * --- -- -- - - - - */ - $("#privilege_id").select2({ - placeholder: 'Επίπεδο πρόσβασης', - dropdownParent: $('#manageFiles'), - width: '100%', - }); - - - /** init_table - * --- -- -- - - - - * get categories - * constuct categories array - * render dataTable - */ - function init_table() { - - // get all categories from server (ajax) - $.getJSON( "/admin/api/files") - .done(function( json ) { - // then ... - - // reset categories - files.length = 0; - - // construct (new) categories data - Object.keys(json).forEach( key => { - el = json[key]; - files.push({ - id: el.id, - label: el.label, - path: el.path, - type: el.type, - privilege_id: ((el.privilege_id == null) ? 0 : el.privilege_id), - privilege: privilege_( ((el.privilege_id == null) ? 0 : el.privilege_id) ), - actions: create_actions_html(el.id) - }); - }); - - // sort by breadcrumb - // categories.sort( compare_breadcrumb ); - - // destroy previous datatable table instances - $('#dt-files').dataTable().fnClearTable(); - $('#dt-files').dataTable().fnDestroy(); - - // (re-)create categories datatable - table = $('#dt-files').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: files, - ordering: false, - columns: [ - { data: 'id' }, - { data: 'label' }, - { data: 'path' }, - { data: 'type' }, - { data: 'privilege' }, - { data: 'actions' } - ] - }); - - }) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed (" + error +")" ); - }); - - } - - - - $.getJSON( "/admin/api/privileges" ) - .done( function( response ) { - - // construct provileges data - // --- - response.forEach( el => { - privileges.push({ - id: el.id, - label: el.label - }); - }); - privileges.sort( compare_label ); // sort categories by breadcrumb - - init_table(); // init table on first run - }); - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#managePrivileges').on('show.bs.modal', event => { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = parseInt( button.data('id') ); // category_id from data-id - // var modal = $(this); // modal object - - // update modal literature - // --- - $('#managePrivileges .modal-title').html( // modal title - (id) ? 'Ενημέρωση Επιπέδου Πρόσβασης' : 'Δημιουργία Επιπέδου Πρόσβασης' - ); - $('#managePrivileges form input[name=id]').val( id ); // category id (hidden) - $('#managePrivileges form input[name=label]').val( // category label - (id) ? privilege_record(id).label : "" - ); - prepare_included_element(id); // prepare <select> for parents - }) - - /** prepare_included_element() - * --- - * @param id (int) : id of selected privilege - * -> Get all posible included privileges - * -> call set_included_options() to render the options - */ - function prepare_included_element(id) { - var may_included = []; - - if (id) { // get all possible parents - - // TODO: - // specify forbiden privilege IDs for being included - - // filter privileges adn prepare possible included privileges - privileges.forEach( el => { - if (id != el.id) { - may_included.push({ - id: el.id, - label: el.label - }); - } - }); - console.log(may_included); - set_included_options(may_included, privilege_record(id).included_id); - - - } else { // new record; all categories are possible parrents - privileges.forEach( el => { - may_included.push({ - id: el.id, - label: el.label, - }); - }) - set_included_options(may_included, -1); - } - } - - /** set_included_options() - * -> create options for parents <select> - * -> choose selected parent - * @param may_included (array): array of possible included privileges - * @param selected (int): selected included privilege - */ - function set_included_options(may_included, selected) { - // sort parents by breadcrumb - // parents.sort( compare_breadcrumb ); - - // remove any olded options from select2 - $('#included_id option').each(function() { $(this).remove(); }); - - // first option is the root category - $('#included_id').append('<option value="0">— κανένα —</option>') - - // add all other parent options - may_included.forEach( i => { - $('#included_id').append(`<option value="${i.id}">${i.label}</option>`); - }); - - if (selected == -1) { // new category; remove any parent pre-selection - $('#included_id').val(0).trigger('change'); - - } else { // category exists; choose selected parent - $('#included_id').val(selected).trigger('change'); - } - } - - - - - // When form is submited - // ------------------------------------------------------------------------- - - $('#manageCategory form').submit( event => { - event.preventDefault(); - - // prepare data to POST - var data = { - id: parseInt($('#manageCategory form input[name=id]').val()), - label: $('#manageCategory form input[name=label]').val(), - parent_id: parseInt($('#parent_id').select2('data')[0].id) - }; - - // select action url (add or update) - var request = '/admin/api/category/' + ((data.id == 0) ? 'add' : 'update'); - - // send POST request - $.post(request, data) - .done(function( data ) { - - $('#manageCategory').modal('hide'); // when done, close modal - - init_table(); // reload table of categories - }); - - }); - -}); diff --git a/public/assets/js/admin/lessons.js b/public/assets/js/admin/lessons.js deleted file mode 100644 index 1a08875..0000000 --- a/public/assets/js/admin/lessons.js +++ /dev/null @@ -1,364 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var categories = []; -var privileges = [ { id: 0, label: 'Δημόσιο' } ]; -var lessons = []; -var table; - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// array.indexOf polyfill -// --- -- -- - - - -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - - for (; from < len; from++) - { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; -} - - -// function for sorting an array by 'label' attribute -// --- -- -- - - - -function compare_label (a,b) { - if ( a.label < b.label ) { return -1; } - if ( a.label > b.label ) { return 1; } - return 0; -} - - -// function for sorting an array by 'breadcrumb' attribute -// --- -- -- - - - -function compare_breadcrumb (a,b) { - if ( a.breadcrumb < b.breadcrumb ) { return -1; } - if ( a.breadcrumb > b.breadcrumb ) { return 1; } - return 0; -} - -// return category record by category-id -// --- -- -- - - - -function lesson_record(id) { - var record = 0; - lessons.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - -/** course(id) - * label of course with - * @param id (int) - */ -function course_(id) { - let reply = false; - categories.forEach( cat => { if (cat.id == id) reply = cat.label; }) - return reply; -} - -/** privilege(id) - * label of privilege with - * @param id (int) - */ -function privilege_(id) { - let reply = false; - privileges.forEach( pri => { if (pri.id == id) reply = pri.label; }); - return reply; -} - - -//// return children of parent -//// --- -- -- - - - -//function childs_of_parents(list) { -// // if 'list' is integer then make it an one-item list -// parents = (Number.isInteger(list)) ? [ list ] : list; -// -// var childs = []; -// -// if (parents.length == 0) { return []; } -// -// parents.forEach( pid => { -// categories.forEach( el => { if (el.parent == pid) childs.push(el.id)}); -// }); -// -// var grandchilds = childs_of_parents(childs); -// -// return childs.concat(grandchilds); -//} - - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(el) { - - var pub, del, edit; - - // preapre [show|hide]-file as reference - if (el.status == 1) { - pub = '<span class="btn btn-sm"><i class="fas fa-eye"></i></span>'; - - } else { - pub = '<span class="btn btn-sm"><i class="fas fa-eye-slash"></i></span>'; - } - - del = ""; - - fast_edit = [ - '<button type="button" class="btn btn-sm btn-light"', - 'data-bs-toggle="modal" data-bs-target="#manageLessons"', - 'data-id="'+ el.id +'">', - '<i class="fa-solid fa-bolt"></i>', - '</button>' - ].join('\n'); - - edit = [ - '<a type="button" class="btn btn-sm btn-warning "', - 'href="/admin/edit_lesson/'+ el.id +'">', - '<i class="fas fa-pencil-alt"></i>', - '</a>' - ].join('\n'); - - return pub +' '+ fast_edit +' '+ edit +' '+ del; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - // inti category (select2) - // ... - $("#privilege_id").select2({ - placeholder: 'Επίπεδο Πρόσβασης', - dropdownParent: $('#manageLessons'), - width: '100%' - }); - - /** init selec2 element (used to specify parent-category) - * --- -- -- - - - - */ - $("#course_id").select2({ - placeholder: 'Κεφάλαιο', - dropdownParent: $('#manageLessons'), - width: '100%', - }); - - - /** init_table - * --- -- -- - - - - * get categories - * constuct categories array - * render dataTable - */ - function init_table() { - - // get all categories from server (ajax) - $.getJSON( "/admin/api/lessons") - .done(function( json ) { - // then ... - - // reset categories - lessons.length = 0; - - // construct (new) categories data - Object.keys(json).forEach( key => { - el = json[key]; - lessons.push({ - id: parseInt(el.id), - title: el.title, - course_id: el.course_id, - course: course_(el.course_id), - privilege_id: el.privilege_id, - privilege: privilege_(el.privilege_id), - actions: create_actions_html(el) - }); - }); - - // sort by breadcrumb - // categories.sort( compare_breadcrumb ); - - // destroy previous datatable table instances - $('#dt-lessons').dataTable().fnClearTable(); - $('#dt-lessons').dataTable().fnDestroy(); - - // (re-)create categories datatable - table = $('#dt-lessons').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: lessons, - ordering: false, - columns: [ - { data: 'id' }, - { data: 'title' }, - { data: 'course' }, - { data: 'privilege' }, - { data: 'actions' } - ] - }); - - }) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed (" + error +")" ); - }); - - } - - - $.when( // when loaded posts and categories - - $.getJSON( "/admin/api/categories" ), - - $.getJSON( "/admin/api/privileges" ) - - ).done( function( categories_response, privileges_response ) { - - // construct categories data - // --- - Object.keys(categories_response[0]).forEach( key => { - cat = categories_response[0][key]; - categories.push({ - id: cat.rec.id, - label: cat.breadcrumb.replaceAll('\t', ' / ') - }); - }); - categories.sort( compare_label ); // sort categories by breadcrumb - - // construct provileges data - // --- - Object.keys(privileges_response[0]).forEach( key => { - priv = privileges_response[0][key]; - privileges.push({ - id: priv.id, - label: priv.label - }); - }); - privileges.sort( compare_label ); // sort categories by breadcrumb - - set_parent_options( $('#course_id'), categories ); - set_parent_options( $('#privilege_id'), privileges ); - - init_table(); // init table on first run - }); - - - /** set_parent_options() - * - * -> create options for parents <select> - * -> choose selected parent - * - * NOTE: - * the targer <select> should be a select2 control - * - * @param parents (array): array of parents - * @param selected (int): selected parent - */ - function set_parent_options(selector, list, selected_value = false) { - - list.forEach( li => { // attach options into <select> control - selector.append(`<option value="${li.id}">${li.label}</option>`); - }); - - if (selected_value !== false) { // mark selected option(s) - selector.val(selected_value).trigger('change'); - } - else { selector.val(null).trigger('change'); } - } - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#manageLesson').on('show.bs.modal', event => { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = parseInt( button.data('id') ); // category_id from data-id - // var modal = $(this); // modal object - - //// update modal literature - //// --- - //$('#manageCategory .modal-title').html( // modal title - // (id) ? 'Ενημέρωση Κατηγορίας' : 'Δημιουργία Κατηγορίας' - //); - //$('#manageCategory form input[name=id]').val( id ); // category id (hidden) - //$('#manageCategory form input[name=label]').val( // category label - // (id) ? category_record(id).label : "" - //); - //prepare_parents_element(id); // prepare <select> for parents - }) - - - /** set_parent_options() - * - * -> create options for parents <select> - * -> choose selected parent - * - * NOTE: - * the targer <select> should be a select2 control - * - * @param parents (array): array of parents - * @param selected (int): selected parent - */ - function set_parent_options(selector, list, selected_value = false) { - - list.forEach( li => { // attach options into <select> control - selector.append(`<option value="${li.id}">${li.label}</option>`); - }); - - if (selected_value !== false) { // mark selected option(s) - selector.val(selected_value).trigger('change'); - } - else { selector.val(null).trigger('change'); } - } - - - - - - // When form is submited - // ------------------------------------------------------------------------- - - $('#manageCategory form').submit( event => { - event.preventDefault(); - - // prepare data to POST - var data = { - id: parseInt($('#manageCategory form input[name=id]').val()), - label: $('#manageCategory form input[name=label]').val(), - parent_id: parseInt($('#parent_id').select2('data')[0].id) - }; - - // select action url (add or update) - var request = '/admin/api/categories/' + ((data.id == 0) ? 'add' : 'update'); - - // send POST request - $.post(request, data) - .done(function( data ) { - - $('#manageCategory').modal('hide'); // when done, close modal - - init_table(); // reload table of categories - }); - - }); - -}); diff --git a/public/assets/js/admin/pages.js b/public/assets/js/admin/pages.js deleted file mode 100644 index 4aa02ca..0000000 --- a/public/assets/js/admin/pages.js +++ /dev/null @@ -1,240 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var categories = []; -var privileges = [ { id: 0, label: 'Δημόσιο' } ]; -var pages = []; -var table; - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// array.indexOf polyfill -// --- -- -- - - - -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - - for (; from < len; from++) - { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; -} - - -// function for sorting an array by 'label' attribute -// --- -- -- - - - -function compare_label (a,b) { - if ( a.label < b.label ) { return -1; } - if ( a.label > b.label ) { return 1; } - return 0; -} - - -// function for sorting an array by 'breadcrumb' attribute -// --- -- -- - - - -function compare_breadcrumb (a,b) { - if ( a.breadcrumb < b.breadcrumb ) { return -1; } - if ( a.breadcrumb > b.breadcrumb ) { return 1; } - return 0; -} - -// return category record by category-id -// --- -- -- - - - -function page_record(id) { - var record = 0; - pages.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(el) { - - var pub, del, edit; - - // preapre [show|hide]-file as reference - if (el.status == 1) { - pub = '<span class="btn btn-sm"><i class="fas fa-eye"></i></span>'; - - } else { - pub = '<span class="btn btn-sm"><i class="fas fa-eye-slash"></i></span>'; - } - - del = ""; - - fast_edit = [ - '<button type="button" class="btn btn-sm btn-light"', - 'data-bs-toggle="modal" data-bs-target="#managePages"', - 'data-id="'+ el.id +'">', - '<i class="fa-solid fa-bolt"></i>', - '</button>' - ].join('\n'); - - edit = [ - '<a type="button" class="btn btn-sm btn-warning "', - 'href="/admin/edit_page/'+ el.id +'">', - '<i class="fas fa-pencil-alt"></i>', - '</a>' - ].join('\n'); - - return pub +' '+ fast_edit +' '+ edit +' '+ del; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - /** init_table - * --- -- -- - - - - * get categories - * constuct categories array - * render dataTable - */ - function init_table() { - - // get all categories from server (ajax) - $.getJSON( "/admin/api/pages") - .done(function( json ) { - // then ... - - // reset categories - pages.length = 0; - - // construct (new) categories data - Object.keys(json).forEach( key => { - el = json[key]; - pages.push({ - id: parseInt(el.id), - title: el.title, - actions: create_actions_html(el) - }); - }); - - // sort by breadcrumb - // categories.sort( compare_breadcrumb ); - - // destroy previous datatable table instances - $('#dt-pages').dataTable().fnClearTable(); - $('#dt-pages').dataTable().fnDestroy(); - - // (re-)create categories datatable - table = $('#dt-pages').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: pages, - ordering: false, - columns: [ - { data: 'id' }, - { data: 'title' }, - { data: 'actions' } - ] - }); - - }) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed (" + error +")" ); - }); - - } - init_table(); // init table on first run - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#managePages').on('show.bs.modal', event => { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = parseInt( button.data('id') ); // category_id from data-id - // var modal = $(this); // modal object - - //// update modal literature - //// --- - //$('#manageCategory .modal-title').html( // modal title - // (id) ? 'Ενημέρωση Κατηγορίας' : 'Δημιουργία Κατηγορίας' - //); - //$('#manageCategory form input[name=id]').val( id ); // category id (hidden) - //$('#manageCategory form input[name=label]').val( // category label - // (id) ? category_record(id).label : "" - //); - //prepare_parents_element(id); // prepare <select> for parents - }) - - - /** set_parent_options() - * - * -> create options for parents <select> - * -> choose selected parent - * - * NOTE: - * the targer <select> should be a select2 control - * - * @param parents (array): array of parents - * @param selected (int): selected parent - */ - function set_parent_options(selector, list, selected_value = false) { - - list.forEach( li => { // attach options into <select> control - selector.append(`<option value="${li.id}">${li.label}</option>`); - }); - - if (selected_value !== false) { // mark selected option(s) - selector.val(selected_value).trigger('change'); - } - else { selector.val(null).trigger('change'); } - } - - - - - - // When form is submited - // ------------------------------------------------------------------------- - - $('#manageCategory form').submit( event => { - event.preventDefault(); - - // prepare data to POST - var data = { - id: parseInt($('#manageCategory form input[name=id]').val()), - label: $('#manageCategory form input[name=label]').val(), - parent_id: parseInt($('#parent_id').select2('data')[0].id) - }; - - // select action url (add or update) - var request = '/admin/api/categories/' + ((data.id == 0) ? 'add' : 'update'); - - // send POST request - $.post(request, data) - .done(function( data ) { - - $('#manageCategory').modal('hide'); // when done, close modal - - init_table(); // reload table of categories - }); - - }); - -}); diff --git a/public/assets/js/admin/panel.js b/public/assets/js/admin/panel.js deleted file mode 100644 index 24b465e..0000000 --- a/public/assets/js/admin/panel.js +++ /dev/null @@ -1 +0,0 @@ -console.log('Admin Panel!');
\ No newline at end of file diff --git a/public/assets/js/admin/privileges.js b/public/assets/js/admin/privileges.js deleted file mode 100644 index e4355c5..0000000 --- a/public/assets/js/admin/privileges.js +++ /dev/null @@ -1,291 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var privileges = []; -var table; - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// array.indexOf polyfill -// --- -- -- - - - -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - - for (; from < len; from++) - { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; -} - -/* -// function for sorting an array by 'breadcrumb' attribute -// --- -- -- - - - -function compare_breadcrumb (a,b) { - if ( a.breadcrumb < b.breadcrumb ) { return -1; } - if ( a.breadcrumb > b.breadcrumb ) { return 1; } - return 0; -} -*/ - -// return category record by category-id -// --- -- -- - - - -function privilege_record(id) { - var record = 0; - privileges.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - -/* -// return children of parent -// --- -- -- - - - -function childs_of_parents(list) { - // if 'list' is integer then make it an one-item list - parents = (Number.isInteger(list)) ? [ list ] : list; - - var childs = []; - - if (parents.length == 0) { return []; } - - parents.forEach( pid => { - categories.forEach( el => { if (el.parent == pid) childs.push(el.id)}); - }); - - var grandchilds = childs_of_parents(childs); - - return childs.concat(grandchilds); -} -*/ - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(id) { - - var del, edit; - - del = ""; - - edit = [ - '<button type="button" class="btn btn-sm btn-warning"', - 'data-bs-toggle="modal" data-bs-target="#managePrivileges"', - 'data-id="'+ id +'">', - '<i class="fas fa-pencil-alt"></i>', - '</button>' - ].join('\n'); - - return edit +' '+ del; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - /** init selec2 element (used to specify parent-category) - * --- -- -- - - - - */ - $("#included_id").select2({ - placeholder: 'Περιλαμβάνει τα δικαιώματα της', - dropdownParent: $('#managePrivileges'), - width: '100%', - // dropdownParent: "#manageCategory" // ref: https://github.com/select2/select2-bootstrap-theme/issues/41 - }); - - - /** init_table - * --- -- -- - - - - * get categories - * constuct categories array - * render dataTable - */ - function init_table() { - - // get all categories from server (ajax) - $.getJSON( "/admin/api/privileges") - .done(function( json ) { - // then ... - - // reset categories - privileges.length = 0; - - // construct (new) categories data - Object.keys(json).forEach( key => { - el = json[key]; - privileges.push({ - id: el.id, - label: el.label, - includes: ((el.includes == null) ? [] : el.includes), - included_id: ((el.included_id == null) ? 0 : el.included_id), - actions: create_actions_html(el.id) - }); - }); - - // sort by breadcrumb - // categories.sort( compare_breadcrumb ); - - // destroy previous datatable table instances - $('#dt-privileges').dataTable().fnClearTable(); - $('#dt-privileges').dataTable().fnDestroy(); - - // (re-)create categories datatable - table = $('#dt-privileges').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: privileges, - ordering: false, - columns: [ - { data: 'id' }, - { data: 'label' }, - { data: 'includes' }, - { data: 'actions' } - ] - }); - - }) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed (" + error +")" ); - }); - - } - init_table(); // init table on first run - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#managePrivileges').on('show.bs.modal', event => { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = parseInt( button.data('id') ); // category_id from data-id - // var modal = $(this); // modal object - - // update modal literature - // --- - $('#managePrivileges .modal-title').html( // modal title - (id) ? 'Ενημέρωση Επιπέδου Πρόσβασης' : 'Δημιουργία Επιπέδου Πρόσβασης' - ); - $('#managePrivileges form input[name=id]').val( id ); // category id (hidden) - $('#managePrivileges form input[name=label]').val( // category label - (id) ? privilege_record(id).label : "" - ); - prepare_included_element(id); // prepare <select> for parents - }) - - /** prepare_included_element() - * --- - * @param id (int) : id of selected privilege - * -> Get all posible included privileges - * -> call set_included_options() to render the options - */ - function prepare_included_element(id) { - var may_included = []; - - if (id) { // get all possible parents - - // TODO: - // specify forbiden privilege IDs for being included - - // filter privileges adn prepare possible included privileges - privileges.forEach( el => { - if (id != el.id) { - may_included.push({ - id: el.id, - label: el.label - }); - } - }); - console.log(may_included); - set_included_options(may_included, privilege_record(id).included_id); - - - } else { // new record; all categories are possible parrents - privileges.forEach( el => { - may_included.push({ - id: el.id, - label: el.label, - }); - }) - set_included_options(may_included, -1); - } - } - - /** set_included_options() - * -> create options for parents <select> - * -> choose selected parent - * @param may_included (array): array of possible included privileges - * @param selected (int): selected included privilege - */ - function set_included_options(may_included, selected) { - // sort parents by breadcrumb - // parents.sort( compare_breadcrumb ); - - // remove any olded options from select2 - $('#included_id option').each(function() { $(this).remove(); }); - - // first option is the root category - $('#included_id').append('<option value="0">— κανένα —</option>') - - // add all other parent options - may_included.forEach( i => { - $('#included_id').append(`<option value="${i.id}">${i.label}</option>`); - }); - - if (selected == -1) { // new category; remove any parent pre-selection - $('#included_id').val(0).trigger('change'); - - } else { // category exists; choose selected parent - $('#included_id').val(selected).trigger('change'); - } - } - - - - - // When form is submited - // ------------------------------------------------------------------------- - - $('#manageCategory form').submit( event => { - event.preventDefault(); - - // prepare data to POST - var data = { - id: parseInt($('#manageCategory form input[name=id]').val()), - label: $('#manageCategory form input[name=label]').val(), - parent_id: parseInt($('#parent_id').select2('data')[0].id) - }; - - // select action url (add or update) - var request = '/admin/api/category/' + ((data.id == 0) ? 'add' : 'update'); - - // send POST request - $.post(request, data) - .done(function( data ) { - - $('#manageCategory').modal('hide'); // when done, close modal - - init_table(); // reload table of categories - }); - - }); - -}); diff --git a/public/assets/js/classroom.js b/public/assets/js/classroom.js deleted file mode 100644 index b1947f8..0000000 --- a/public/assets/js/classroom.js +++ /dev/null @@ -1,27 +0,0 @@ -$(document).ready(function() { - - - /** Categories Menu Toggler - * ------------------------------------------------------------------------- - */ - $('.toggler').click(function(e) { - e.preventDefault(); - - // inner div (contains children of this category) - var inner = $(this).parent().parent().find("ul.inner").first(); - - // toggle 'show' class on/off - if (inner.hasClass('show')) { - inner.removeClass('show'); - inner.slideUp(350); - $(this).html("+"); - } else { - inner.addClass('show'); - inner.slideDown(350); - $(this).html("–"); - } - }); - - - -}); diff --git a/public/assets/js/edit-post.js b/public/assets/js/edit-post.js deleted file mode 100644 index 49446ce..0000000 --- a/public/assets/js/edit-post.js +++ /dev/null @@ -1,612 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- - -// NOTE: -// Variable `id` is defined before evaluating this script -// id (int) : the id of edited post (or 0 if new post) - -var post; -var categories = [ - // Nope! root can not be a post's category ... { id: 0 , label: 'Ρίζα (root)' } -]; -var tags = []; // array of integers -var files = []; // array of { id:.., title:.., type:.., path:.. } records - -const files_root = 'https://cdn.sklavenitis.co.gr/'; // files root firectory - - - -var pageUrl = new URL(window.location.href); - -// an alternative--id when a post id not exists (needed for file-upload) -// ... consist of a 6-digit date string + random number up to 999 -const yymmdd = new Date().toISOString().slice(2, 10).replaceAll('-',''); -var rnd999 = Math.floor(Math.random() * 1000); -var altID = (id == 0) ? ( yymmdd +'-'+ rnd999.toString() ) : id; - - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// function for sorting an array by 'label' attribute -// --- -- -- - - - -function compare_label (a,b) { - if ( a.label < b.label ) { return -1; } - if ( a.label > b.label ) { return 1; } - return 0; -} - -// return category record by category-id -// --- -- -- - - - -function category_record(id) { - var record = 0; - categories.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - - - - -// Modal HTML Creators -// ----------------------------------------------------------------------------- - -const modal_header = (title) => { - return [ - '<div class="modal-header">', - '<button type="button" class="close" data-dismiss="modal" aria-label="Close">', - '<span aria-hidden="true">×</span>', - '</button>', - '<h4 class="modal-title" id="myModalLabel">', - title, - '</h4>', - '</div>' - ].join('\n'); -} - - -const upload_file_form = () => { - return [ - '<form method="POST" id="file_upload_form" name="upload_file_form">', - - '<div class="modal-body">', - - '<input type="hidden" name="folder" value="'+ altID +'">', - - '<div class="form-group">', - '<label for="title">Τίτλος/Περιγραφή για το Αρχείο</label>', - '<input type="text" class="form-control " value="" name="title" id="title" placeholder="Τίτλος για το Αρχείο" required="">', - '</div>', - - '<div class="row">', - - '<div class="form-group col-md-7">', - '<label class="control-label" for="file">Εισαγωγή Αρχείου</label>', - '<input class="form-control" type="file" id="file" name="file" required="">', - '</div>', - - '<div class="form-group col-md-5">', - '<label class="control-label" for="category_id">Είδος</label>', - '<select class="form-control" id="reference" name="reference" required="">', - '<option"></option>', - '<option value="1">Παραπομπή (εμφανίζεται)</option>', - '<option value="0">Βοηθητικό αρχείο (κρυφό)</option>', - '</select>', - '</div>', - - '</div>', - - '</div>', - - '<div class="modal-footer">', - '<div class="row">', - '<div class="form-actions">', - '<div class="col-lg-3 col-lg-offset-6 col-md-4 col-md-offset-4 col-xs-6">', - '<buton type="button" class="btn btn-default js-modal-close col-xs-12" data-dismiss="modal">', - 'Κλείσιμο', - '</button>', - '</div>', - '<div class="col-lg-3 col-md-4 col-xs-6">', - '<button class="btn btn-success col-xs-12" type="submit">Καταχώριση</button>', - '</div>', - '</div>', - '</div>', - '</div>', - - '</form>' - ].join('\n'); -} - - -const preview_article = (title, intro, body) => { - return [ - '<div class="modal-body">', - '<div class="post">', - - '<h2>'+ title +'</h2>', - - ((intro == '') ? '' : ('<div class="intro">'+ intro +'</div>')), - - '<div class="article-body">', - marked.parse(body, { sanitize: true }), - '</div>', - - '</div>', - '</div>', - '<div class="modal-footer">', - '<div class="row">', - '<div class="form-actions">', - '<div class="col-md-4 col-md-offset-4 col-xs-6 col-xs-offset-3">', - '<buton type="button" class="btn btn-default js-modal-close col-xs-12" data-dismiss="modal">', - 'Κλείσιμο', - '</button>', - '</div>', - '</div>', - '</div>', - '</div>' - ].join('\n'); -} - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - // inti category (select2) - // ... - $("#category_id").select2({ - placeholder: 'Γονική Κατηγορία', - width: '100%' - }); - - - // init tags (select2) - // ... - $('#tags').select2({ - placeholder: 'Ετικέτες (tags/keywords)', - width: '100%', - tags: true - }); - - - // init editor (tiny MCE) - // tinymce.init({ - // selector: 'form textarea[name=body]', - // language: 'el', - // menubar: true - // }); - // --- -- -- - - - - - - /** preload content - * --- -- -- - - - - * get post - * get categories - * get tags - * update content (form-elements) - */ - if (id) { // if an `id` is given, load post .. then init_form - - $.getJSON( "/wiki/ajax", { action: "get_post", id: id } ) - .done( function (data) { - post = data; // keep post - - // update fields' values - $('input[name=id]').val(post.id); // id - $('input[name=title]').val(post.title); // title - $('textarea[name=intro]').val(post.intro); // intro - $('textarea[name=body]').val(post.body); // body - $('input[name=status]').prop( // status - 'checked', - ((post.status==1)? true : false)) - .trigger('change'); - - $('#post-info').html('Δημιουργία: '+post.creation_date+'<br>Τελευταία Ενημέρωση: '+ post.update_date); - - $('#delete').prop( "disabled", false ); // enable delete button - - // if intro exist, show intro (optinal) field - if ((post.intro != null) && (post.intro != '')) { - $('.optional label[for=intro]').addClass('show'); // unhide section - } - - // parse media files; then draw - if (post.medias_json != null) { - files = JSON.parse(post.medias_json); - $('.optional label[for=media]').addClass('show'); // unhide section - } - draw_files_list(); // then draw the files list - - init_form_values(); // init all (other) values - }); - - } else { // else ... just init_form - $('#delete').prop( "disabled", true ); // disable delete button for new post attempt - // depricated $('select[name=status').val('0').trigger('change'); // pre-selecd unpublished - init_form_values(); - } - - - - /** - * load categories and tags; - * if not a new post (id!=0) update form elemnts with post's values - */ - function init_form_values() { - - $.when( // when loaded posts and categories - - $.getJSON( "/wiki/ajax", { action: "get_categories_array", exclude: '0' } ), - - $.getJSON( "/wiki/ajax", { action: "get_all_tags" } ) - - ).done( function( categories_response, tags_response ) { - - // construct categories data - // --- - Object.keys(categories_response[0]).forEach( key => { - cat = categories_response[0][key]; - categories.push({ - id: cat.rec.id, - label: cat.breadcrumb.replaceAll('\t', ' / ') - }); - }); - categories.sort( compare_label ); // sort categories by breadcrumb - - // construct tags data - // --- - Object.keys(tags_response[0]).forEach( key => { - tag = tags_response[0][key]; - tags.push({ - id: tag.id, - label: tag.name - }); - }); - - // pass categories and tags options onto select2 elements - // --- -- -- - - - - if (id == 0) { - set_parent_options( $('#category_id'), categories ); - set_parent_options( $('#tags'), tags ); - - } else { - // setup category_id options; select post's chosen category-id - set_parent_options( $('#category_id'), categories, post.category_id ); - - // parse selected tags - // --- - var selected_tag_ids = []; - if (post.tags_json != null) { - var selected_tags = JSON.parse(post.tags_json); - selected_tags.forEach( itag => { selected_tag_ids.push(itag.id); }) - } - // setup tags options; select post's chosen tags - set_parent_options( $('#tags'), tags, selected_tag_ids ); - - // ALSO: if tags selectd, show tags field - if (selected_tag_ids.length != 0) { $('.optional label[for=tags]').addClass('show'); } - } - - }); - - } - - - /** set_parent_options() - * - * -> create options for parents <select> - * -> choose selected parent - * - * NOTE: - * the targer <select> should be a select2 control - * - * @param parents (array): array of parents - * @param selected (int): selected parent - */ - function set_parent_options(selector, list, selected_value = false) { - - list.forEach( li => { // attach options into <select> control - selector.append(`<option value="${li.id}">${li.label}</option>`); - }); - - if (selected_value !== false) { // mark selected option(s) - selector.val(selected_value).trigger('change'); - } - else { selector.val(null).trigger('change'); } - } - - - /** draw_files_list - * --- -- -- - - - - */ - function draw_files_list() { - var li_list = []; - var ref_icon, ref_class; - - files.forEach( item => { - // preapre [show|hide]-file as reference - if (item.reference == 1) { - ref_icon = '<i class="fas fa-eye"></i>'; - ref_class = 'btn-default'; - - } else { - ref_icon = '<i class="fas fa-eye-slash"></i>'; - ref_class = 'btn-disabled'; - } - - var copy = [ // copy button - '<button type="button" class="btn btn-xs btn-default js-copy"', - 'data-url="' + item.path + '">', - '<i class="far fa-clone"></i>', - '</button>' - ].join(''); - var ref = [ // show|hide (is_reference) - '<button type="button" class="btn btn-xs '+ ref_class +' js-reference"', - 'data-id="' + item.id + '">', - ref_icon, - '</button>' - ].join(''); - var del = [ // delete button - '<button type="button" class="btn btn-xs btn-danger js-delete"', - 'data-id="' + item.id + '">', - '<i class="fas fa-trash-alt"></i>', - '</button>' - ].join(''); - var option = [ // li html - '<li>', - '<div class="text">' + item.title + '</div>', - '<div class="actions">', - ref, ' ', copy, ' ', del, - '</div>', - '</li>' - ].join(''); - li_list.push(option); // push to li_list - }); - $('#files_list').html( li_list.join('\n') ); - - } - - - - // When form's action-buttons are clicked - // ------------------------------------------------------------------------- - - - // form submit - // --- -- -- - - - - $('.edit-post form').submit( event => { - event.preventDefault(); - - // rearrange tags to old and new ones - // --- - var old_tags = []; - var new_tags = []; - var tags = $('#tags').select2('data'); - tags.forEach( t => { - if (!parseInt(t.id)) { - new_tags.push(t.text); - } else { old_tags.push(t.id); } - }) - - var attachments = []; - // attachments (array) of "`media_id`;`reference`" strings - files.forEach( f => { attachments.push( f.id +';'+ f.reference ) }); - - // prepare data to POST - // --- - var data = { - id: parseInt($('.edit-post form input[name=id]').val()), - title: $('.edit-post form input[name=title]').val(), - category_id: parseInt($('#category_id').select2('data')[0].id), - intro: $('.edit-post form textarea[name=intro]').val(), - body: $('.edit-post form textarea[name=body]').val(), - status: (($('input[name=status]').is(":checked")) ? 1 : 0), - tags: old_tags, - new_tags: new_tags, - media: attachments - }; - - // select action url (add or update) - // --- - var request = '/wiki/ajax?action=' + ((data.id == 0) ? 'add_post' : 'update_post'); - - // send POST (ajax) request - $.post(request, data) - .done(function( data ) { - window.location.href = '/wiki/admin?action=posts'; // seems ok; bach to articles - }); - - }); - - - // go-back (to posts) - // --- -- -- - - - - $('#go-back').click( event => { - window.location.href = '/wiki/admin?action=posts'; - }); - - - // delete - // --- -- -- - - - - $('#delete').click( event => { - // ask before deletion - swal({ - title: 'Είστε βέβαιος;', - html: "Ζητήσατε να διαγραφεί το άρθρο.<br>Παρακαλώ επιβεβαιώστε την διαγραφή.<br>ΠΡΟΣΟΧΗ: Δεν θα έχετε την δυνατότητα αναίρεσης!", - type: 'warning', - showCancelButton: true, - confirmButtonColor: '#3085d6', - cancelButtonColor: '#d33', - cancelButtonText: 'Ακύρωση', - confirmButtonText: 'Ναι, να διαγραφεί', - showLoaderOnConfirm: true, - preConfirm: function() { - return new Promise(function(resolve) { - $.getJSON( "/wiki/ajax", { action: "delete_post", id: id } ) - .done( function (data) { - // return to posts-administration - window.location.href = '/wiki/admin?action=posts'; - }); - }); - }, - allowOutsideClick: false - }).catch(swal.noop); - - }); - - - - // copy url button - // --- -- -- - - - - $('.wiki').on('click', 'button.js-copy', function (e) { - var copytext = ''; // default: copy nothing - - if ($(this).data('id') !== undefined) { - copytext = pageUrl.origin +'/wiki/post?id=' + $(this).data('id'); - } - - if ($(this).data('url') !== undefined) { - copytext = files_root + $(this).data('url'); - } - - navigator.clipboard - .writeText(copytext) - .then(() => { // notify the copy event - $(this).addClass('copied'); - setTimeout( () => { $(this).removeClass('copied'); }, 700); - }) - .catch(() => { - console.log("error on coping text"); - }); - }); - - - - // delete (remove) file button - // --- -- -- - - - - $('.wiki').on('click', 'button.js-delete', function (e) { - var media_id = $(this).data('id'); - - // remove from files array the one with id == media_id - // --- - var temp = []; - files.forEach( it => { if (it.id != media_id) temp.push(it); }); - - files = temp; // re-define files - draw_files_list(); // then re-draw files list - }); - - - - - - // show|hide file as referece button - // --- -- -- - - - - $('.wiki').on('click', 'button.js-reference', function (e) { - var id = $(this).data('id'); - - // toggle reference attribute of item with `id` = id - // --- - var temp = []; - files.forEach( it => { - if (it.id == id) { - it.reference = (it.reference==0) ? 1 : 0; - } - temp.push(it) - }); - - files = temp; // re-define files - draw_files_list(); // then re-draw files list - }); - - - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#editorModal').on('show.bs.modal', event => { - let button = $(event.relatedTarget); // Button that triggered the modal - let action = button.data('action'); // action - // var modal = $(this); // modal object - - // update modal literature - - switch (action) { - case 'upload_file': - $("#editorModal .modal-content").html( - modal_header('Εισαγωγή Αρχείου') + upload_file_form() - ); - break; - - case 'preview': - let preview = preview_article( - $('.edit-post form input[name=title]').val(), - $('.edit-post form textarea[name=intro]').val(), - $('.edit-post form textarea[name=body]').val() - ); - $("#editorModal .modal-content").html( modal_header('Προεπισκόπηση') + preview); - break; - - default: - // do nothing - } - - }); - - - - /** submit upload file event - * ------------------------------------------------------------------------- - */ - $('#editorModal').on('submit', 'form[name=upload_file_form]', function (event) { - event.preventDefault(); - - // create the FormData object - // --- -- -- - - - - var fd = new FormData(document.getElementById('file_upload_form')); - - // post the form (via ajax) - $.ajax({ - url: '/wiki/ajax?action=file_upload', - type: 'POST', - data: fd, - contentType: false, - processData: false, - dataType: 'json', - success: function(response) { // on success - - if (response.success) { - files.push({ // ... update files array - id: response.id, - title: response.title, - path: response.path, - type: response.type, - reference: $('#reference').val() - }); - draw_files_list(); - - $('#editorModal').modal('hide'); - - } else { - console('File not uploaded'); - } - } - }); - }); - - - // TODO: - // disable links while previewing the article - // OR add a target="_blank" - - -}); - diff --git a/public/assets/js/lesson-features.js b/public/assets/js/lesson-features.js deleted file mode 100644 index 189b301..0000000 --- a/public/assets/js/lesson-features.js +++ /dev/null @@ -1,218 +0,0 @@ -const valid_codeblocks = [ // supported sort-code keys - 'youtube', - 'spotify', - 'spotify-track', - 'world-data', - 'vimeo', - 'dailymotion' -]; - - -const symbol_escapes = [ - { esc: '>', chr: '>' }, - { esc: '<', chr: '<' }, - { esc: '&', chr: '&' }, - { esc: '"', chr: '\"' }, - { esc: ''', chr: '\'' }, - { esc: '€', chr: '€' }, - { esc: '©', chr: '©' }, - { esc: '®', chr: '®' } -]; - - -var youtube_template = ( id => { - return '<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/'+ id +'?rel=0&controls=0" title="YouTube video player" frameborder="0" allow="clipboard-write; encrypted-media; picture-in-picture; web-share" allowfullscreen></iframe>'; -}); - - -var spotify_template = ( id => { - return '<iframe style="border-radius:12px" src="https://open.spotify.com/embed/episode/'+ id +'?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>'; -}); - -var spotify_track = ( id => { - return '<iframe style="border-radius:12px" src="https://open.spotify.com/embed/track/'+ id +'?utm_source=generator" width="100%" height="152" frameBorder="0" allowfullscreen="" allow="autoplay; clipboard-write; encrypted-media; fullscreen; picture-in-picture" loading="lazy"></iframe>'; -}); - -var owid_template = ( id => { // our world in data (explorer) - return '<iframe src="https://ourworldindata.org/explorers/'+ id +'?zoomToSelection=true&hideControls=true" loading="lazy" style="width: 100%; height: 480px; border: 0px none;"></iframe>' -}); - -var vimeo_template = ( id => { - return '<div style="padding:56.25% 0 0 0;position:relative;"><iframe src="https://player.vimeo.com/video/'+ id +'?h=2e7bdb3901&title=0&byline=0&portrait=0" style="position:absolute;top:0;left:0;width:100%;height:100%;" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe></div><script src="https://player.vimeo.com/api/player.js"></script>' -}); - -var dailymotion_template = ( id => { - return '<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;"> <iframe style="width:100%;height:100%;position:absolute;left:0px;top:0px;overflow:hidden" frameborder="0" type="text/html" src="https://www.dailymotion.com/embed/video/'+ id +'" width="100%" height="100%" allowfullscreen title="Dailymotion Video Player" > </iframe> </div>' -}); - - - -/** inject_codeblocks - * --- -- -- - - - - * - * NOTE: - * a short-code is a mustache block of 3 parametres: - * {{ object = someID ; some label description }} - * ex. `{{product=1507175; Coca Cola Zero}}` - * - * The short-code is parsed to a code-block: - * an `a` modal-toggler link with certain data-attributes (+label), ex: - * `<a class='modal-toggler view-product' data-id='1507175'>Coca Cola Zero</a>` - * - * @param code (string): original content html with short-codes - * @returns (string): html content with code-blocks - */ -function inject_codeblocks(code) { - // isolate all mustache blocks - const regexp = /{{(.*?)}}/g; // regex makes multiple-matching easier - const matches = [...code.matchAll(regexp)]; - // console.log(matches); - - var output = code; // use a copy of (source) code - - console.log(matches); - - matches.forEach( match => { - // parse (every) match - // NOTE: - // match array has 3 items; example: - // match[0] : `{{youtube=6EA-MIYY1bg}}` - // match[1] : `youtube=6EA-MIYY1bg` - // match[3] : the (source) code string - - // let blockparts = unescaped_str( match[1] ).trim().split('='); - let blockparts = match[1].trim().split('='); - let target = blockparts[0].toLowerCase(); - let id = blockparts[1]; - // let label = escaped_str(blockparts[1]); - if (valid_codeblocks.includes(target)) { - - var codeblock = ''; - - console.log(target, id); - - switch (target) { - - case 'youtube': - codeblock = youtube_template(id); - break; - - case 'spotify': - codeblock = spotify_template(id); - break; - - case 'spotify-track': - codeblock = spotify_track(id); - break; - - case 'world-data': - codeblock = owid_template(id); - break; - - case 'vimeo': - codeblock = vimeo_template(id); - break; - - case 'dailymotion': - codeblock = dailymotion_template(id); - break; - - default: - codeblock = id; - - } - - output = output.replaceAll(match[0], codeblock); - - } - }); - - return output; -} - - -// pair of function to escepe/unescape special html symbols -// --- -- -- - - - -function unescaped_str(txt) { - symbol_escapes.forEach( pair => { txt = txt.replaceAll(pair.esc, pair.chr); }) - return txt; -} - -function escaped_str(txt) { - symbol_escapes.forEach( pair => { txt = txt.replaceAll(pair.chr, pair.esc); }) - return txt; -} - - -$(document).ready(function() { - - - /** translate short-codes to code-blocks - * ------------------------------------------------------------------------- - */ - var content = $('.main-content .article-body').html(); // get code with shorts - $('.main-content .article-body').html( inject_codeblocks(content) ); // put code with blocks - - - - /** modal listeners - * ------------------------------------------------------------------------- - */ -/* DEPRICATED: not needed - // open store modal listener - // --- -- -- - - - - $(document).on('click', '.js-get_store', function (e) { - e.preventDefault(); - var id = $(this).data('id'); // id for requesting content via ajax - - $('#dynamic-content').html(''); - $('#modal-loader').show(); - - $.ajax({ - url: '/libs/modals/modalStore.php', - type: 'POST', - cache: false, - data: 'id=' + id, - dataType: 'html' - }) - .done(function (data) { - $('#dynamic-content').html(''); - $('#dynamic-content').html(data); - $('#modal-loader').hide(); - }) - .fail(function () { - $('#dynamic-content').html('<i class="glyphicon glyphicon-info-sign"></i> Υπήρξε κάποιο πρόβλημα, παρακαλώ προσπαθήστε ξανά.'); - $('#modal-loader').hide(); - }); - }); - - // open product modal listener - // --- - $(document).on('click', '.js-get_product', function (e) { - e.preventDefault(); - var id = $(this).data('id'); // id for requesting content via ajax - - $('#dynamic-product').html(''); - $('#modal-loader').show(); - - $.ajax({ - url: '/products/ajax/get_product_full', - cache: false, - type: 'POST', - data: { id: id }, - dataType: 'html' - }) - .done(function (data) { - $('#dynamic-product').html(''); - $('#dynamic-product').html(data); - $('#modal-loader').hide(); - - }) - .fail(function () { - $('#dynamic-product').html('<i class="glyphicon glyphicon-info-sign"></i> Υπήρξε κάποιο πρόβλημα, παρακαλώ προσπαθήστε ξανά.'); - $('#modal-loader').hide(); - - }); - }); -*/ -}); diff --git a/public/assets/js/manage-category.js b/public/assets/js/manage-category.js deleted file mode 100644 index 85a4851..0000000 --- a/public/assets/js/manage-category.js +++ /dev/null @@ -1,287 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var categories = []; -var table; - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// array.indexOf polyfill -// --- -- -- - - - -if (!Array.prototype.indexOf) -{ - Array.prototype.indexOf = function(elt /*, from*/) - { - var len = this.length >>> 0; - - var from = Number(arguments[1]) || 0; - from = (from < 0) - ? Math.ceil(from) - : Math.floor(from); - if (from < 0) - from += len; - - for (; from < len; from++) - { - if (from in this && - this[from] === elt) - return from; - } - return -1; - }; -} - - -// function for sorting an array by 'breadcrumb' attribute -// --- -- -- - - - -function compare_breadcrumb (a,b) { - if ( a.breadcrumb < b.breadcrumb ) { return -1; } - if ( a.breadcrumb > b.breadcrumb ) { return 1; } - return 0; -} - -// return category record by category-id -// --- -- -- - - - -function category_record(id) { - var record = 0; - categories.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - - -// return children of parent -// --- -- -- - - - -function childs_of_parents(list) { - // if 'list' is integer then make it an one-item list - parents = (Number.isInteger(list)) ? [ list ] : list; - - var childs = []; - - if (parents.length == 0) { return []; } - - parents.forEach( pid => { - categories.forEach( el => { if (el.parent == pid) childs.push(el.id)}); - }); - - var grandchilds = childs_of_parents(childs); - - return childs.concat(grandchilds); -} - - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(id) { - - var del, edit; - - del = ""; - - edit = [ - '<button type="button" class="btn btn-xs btn-warning"', - 'data-toggle="modal" data-target="#manageCategory"', - 'data-id="'+ id +'">', - '<i class="fas fa-pencil-alt"></i>', - '</button>' - ].join('\n'); - - return edit +' '+ del; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - /** init selec2 element (used to specify parent-category) - * --- -- -- - - - - */ - $("#parent_id").select2({ - placeholder: 'Γονική Κατηγορία', - width: '100%', - // dropdownParent: "#manageCategory" // ref: https://github.com/select2/select2-bootstrap-theme/issues/41 - }); - - - /** init_table - * --- -- -- - - - - * get categories - * constuct categories array - * render dataTable - */ - function init_table() { - - // get all categories from server (ajax) - $.getJSON( "/wiki/ajax", { action: "get_categories_array", exclude: '0' } ) - .done(function( json ) { - // then ... - - // reset categories - categories.length = 0; - - // construct (new) categories data - Object.keys(json).forEach( key => { - el = json[key]; - categories.push({ - id: parseInt(el.rec.id), - title: el.rec.title, - breadcrumb: el.breadcrumb.replaceAll('\t', ' / '), - parent: parseInt(el.rec.parent), - actions: create_actions_html(el.rec.id) - }); - }); - - // sort by breadcrumb - categories.sort( compare_breadcrumb ); - - // destroy previous datatable table instances - $('#dt-categories').dataTable().fnClearTable(); - $('#dt-categories').dataTable().fnDestroy(); - - // (re-)create categories datatable - table = $('#dt-categories').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: categories, - ordering: false, - columns: [ - { data: 'breadcrumb' }, - { data: 'actions' } - ] - }); - - }) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed (" + error +")" ); - }); - - } - init_table(); // init table on first run - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#manageCategory').on('show.bs.modal', event => { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = parseInt( button.data('id') ); // category_id from data-id - // var modal = $(this); // modal object - - // update modal literature - // --- - $('#manageCategory .modal-title').html( // modal title - (id) ? 'Ενημέρωση Κατηγορίας' : 'Δημιουργία Κατηγορίας' - ); - $('#manageCategory form input[name=id]').val( id ); // category id (hidden) - $('#manageCategory form input[name=title]').val( // category title - (id) ? category_record(id).title : "" - ); - prepare_parents_element(id); // prepare <select> for parents - }) - - /** prepare_parents_element() - * --- - * @param id (int) : id of selected category - * -> Get all posible parents - * -> call set_parent_options() to render the options - */ - function prepare_parents_element(id) { - var parents = []; - - if (id) { // get all possible parents - - // id-category and subcategories are fobiden parents - var forbiden = childs_of_parents(id); - forbiden.push(id); - - // filter catogories adn prepare parents - categories.forEach( el => { - if (!forbiden.includes(el.id)) { - parents.push({ - id: el.id, - breadcrumb: el.breadcrumb, - }); - } - }); - set_parent_options(parents, category_record(id).parent); - - - } else { // new record; all categories are possible parrents - categories.forEach( el => { - parents.push({ - id: el.id, - breadcrumb: el.breadcrumb, - }); - }) - set_parent_options(parents, -1); - } - } - - /** set_parent_options() - * -> create options for parents <select> - * -> choose selected parent - * @param parents (array): array of parents - * @param selected (int): selected parent - */ - function set_parent_options(parents, selected) { - // sort parents by breadcrumb - parents.sort( compare_breadcrumb ); - - // remove any olded options from select2 - $('#parent_id option').each(function() { $(this).remove(); }); - - // first option is the root category - $('#parent_id').append('<option value="0">Root</option>') - - // add all other parent options - parents.forEach( i => { - $('#parent_id').append(`<option value="${i.id}">${i.breadcrumb}</option>`); - }); - - if (selected == -1) { // new category; remove any parent pre-selection - $('#parent_id').val(null).trigger('change'); - - } else { // category exists; choose selected parent - $('#parent_id').val(selected).trigger('change'); - } - } - - - - - // When form is submited - // ------------------------------------------------------------------------- - - $('#manageCategory form').submit( event => { - event.preventDefault(); - - // prepare data to POST - var data = { - id: parseInt($('#manageCategory form input[name=id]').val()), - title: $('#manageCategory form input[name=title]').val(), - parent_id: parseInt($('#parent_id').select2('data')[0].id) - }; - - // select action url (add or update) - var request = '/wiki/ajax?action=' + ((data.id == 0) ? 'add_category' : 'update_category'); - - // send POST request - $.post(request, data) - .done(function( data ) { - - $('#manageCategory').modal('hide'); // when done, close modal - - init_table(); // reload table of categories - }); - - }); - -}); diff --git a/public/assets/js/manage-posts.js b/public/assets/js/manage-posts.js deleted file mode 100644 index 028c773..0000000 --- a/public/assets/js/manage-posts.js +++ /dev/null @@ -1,177 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var categories = []; -var posts = []; -var table; - -var pageUrl = new URL(window.location.href); - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - -// function for sorting an array by 'breadcrumb' attribute -// --- -- -- - - - -function compare_breadcrumb (a,b) { - if ( a.breadcrumb < b.breadcrumb ) { return -1; } - if ( a.breadcrumb > b.breadcrumb ) { return 1; } - return 0; -} - -// return category record by category-id -// --- -- -- - - - -function category_record(id) { - var record = 0; - categories.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(id) { - - var copy, edit; - - edit = [ - '<button type="button" class="btn btn-xs btn-warning js-edit"', - 'data-id="'+ id +'">', - '<i class="fas fa-pencil-alt"></i>', - '</button>' - ].join('\n'); - - copy = [ - '<button type="button" class="btn btn-xs btn-dafault js-copy"', - 'data-id="'+ id +'">', - '<i class="far fa-clone"></i>', - '</button>' - ].join('\n'); - - return copy +' '+ edit; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - /** init_table for 1st time - * --- -- -- - - - - * get posts + categories - * constuct posts + categories array - * render dataTable - */ - // function init_table() { - - $.when( // when loaded posts and categories - - $.getJSON( "/wiki/ajax", { action: "all_posts_props" } ), - - $.getJSON( "/wiki/ajax", { action: "get_categories_array", exclude: '0' } ) - - ).done( function( posts_response, categories_response ) { - - // each response is an array of 3 items: - // [0] => data (array) - // [1] => [success|fail] - // [2] => xhr object - - // construct categories data - Object.keys(categories_response[0]).forEach( key => { - cat = categories_response[0][key]; - categories.push({ - id: cat.rec.id, - breadcrumb: cat.breadcrumb.replaceAll('\t', ' / ') - }); - }); - - // construct posts data - Object.keys(posts_response[0]).forEach( key => { - po = posts_response[0][key]; - posts.push({ - id: po.id, - title: po.title, - category: category_record(po.category_id).breadcrumb, - updated: po.update_date, - status: ((po.status == 1) ? '<i class="fas fa-eye"></i>' : '<i class="fas fa-eye-slash"></i>'), - actions: create_actions_html(po.id) - }); - }); - - // (re-)create categories datatable - table = $('#dt-posts').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: posts, - order: [[2, 'desc']], - columns: [ - { data: 'title' }, - { data: 'category' }, - { // update date - data: 'updated', - render: { - _: function (data, row, full) { return data; }, - display: function (data, row, full) { return mini_date(data); } - } - }, - { data: 'status' }, - { data: 'actions', width: '64px' } - ], - columnDefs: [{ - 'targets': [3,4], - 'orderable': false - }] - }); - - }); - - - function mini_date(d){ - let yy = d.substring(2,4); // year 2digit - let mo = d.substring(5,7); // month - let dd = d.substring(8,10); // dat - let h = d.substring(11,13); // hour - let m = d.substring(14,16); // minute - return dd +'/'+ mo +'/'+ yy +' '+ h +':'+ m; - } - - - - /** When user ckicks button - * ------------------------------------------------------------------------- - */ - - - /** on(click, .edit-btn) - * --- -- -- - - - - * We need to attach the event handler to some element - * higher up in the DOM tree that will remain present; - * so the handled attached on #dt-posts - * - * get post-id ; load editpost - */ - $('#dt-posts').on('click', 'button.js-edit', function (e) { - - var id = $(this).data('id'); - window.location.href = '/wiki/admin?action=editpost&id=' + id - - }); - - - $('#dt-posts').on('click', 'button.js-copy', function (e) { - var postUrl = pageUrl.origin +'/wiki/post?id=' + $(this).data('id'); - - navigator.clipboard - .writeText(postUrl) - .then(() => { - $(this).addClass('copied'); - setTimeout( () => { $(this).removeClass('copied'); }, 700); - }) - .catch(() => { - console.log("error on coping text"); - }); - }); - - -}); diff --git a/public/assets/js/manage-tags.js b/public/assets/js/manage-tags.js deleted file mode 100644 index c287849..0000000 --- a/public/assets/js/manage-tags.js +++ /dev/null @@ -1,163 +0,0 @@ -// Globals -// ----------------------------------------------------------------------------- -var tags = []; -var table; - - - -// Supplamentary functions -// ----------------------------------------------------------------------------- - - - -// return category record by category-id -// --- -- -- - - - -function category_record(id) { - var record = 0; - categories.forEach(el => { if (el.id == id) record = el; }); - - return record; -} - -// create actions html (edit and delete buttons) -// --- -- -- - - - -function create_actions_html(id) { - - var del, edit; - - del = [ - '<button type="button" class="btn btn-xs btn-danger"', - 'data-toggle="modal" data-target="#manageCategory"', - 'data-id="'+ id +'" disabled>', - '<i class="fas fa-times"></i>', - '</button>' - ].join('\n'); - - edit = [ - '<button type="button" class="btn btn-xs btn-warning"', - 'data-toggle="modal" data-target="#manageCategory"', - 'data-id="'+ id +'" disabled>', - '<i class="fas fa-pencil-alt"></i>', - '</button>' - ].join('\n'); - - return edit +' '+ del; -} - - - -$(document).ready(function() { - - // When document is ready - // ------------------------------------------------------------------------- - - - - /** init_table - * --- -- -- - - - - * get categories - * constuct categories array - * render dataTable - */ - function init_table() { - - // get all categories from server (ajax) - $.getJSON( "/wiki/ajax", { action: "tags_stats" } ) - .done(function( json ) { - // then ... - - // reset tags - tags.length = 0; - - // construct tags data - Object.keys(json).forEach( key => { - el = json[key]; - tags.push({ - id: parseInt(el.id), - title: el.name, - counter: parseInt(el.totals), - actions: create_actions_html(el.id) - }); - }); - - // destroy previous datatable table instances - $('#dt-tags').dataTable().fnClearTable(); - $('#dt-tags').dataTable().fnDestroy(); - - // (re-)create categories datatable - table = $('#dt-tags').DataTable({ - language: { url: '/libs/DataTables/localization/Greek.json' }, - data: tags, - order: [[1, 'desc']], - columns: [ - { data: 'title' }, - { data: 'counter' }, - { data: 'actions', width: '64px' } - ], - columnDefs: [{ - 'targets': [2], - 'orderable': false - }] - }); - - }) - .fail(function( jqxhr, textStatus, error ) { - console.log( "Request Failed (" + error +")" ); - }); - - } - init_table(); // init table on first run - - - - /** When modal show-up - * ------------------------------------------------------------------------- - * ... prepare the manage-category form - * ... update select2 with possible parents - */ - $('#manageCategory').on('show.bs.modal', event => { - var button = $(event.relatedTarget); // Button that triggered the modal - var id = parseInt( button.data('id') ); // category_id from data-id - // var modal = $(this); // modal object - - // update modal literature - // --- - $('#manageCategory .modal-title').html( // modal title - (id) ? 'Ενημέρωση Κατηγορίας' : 'Δημιουργία Κατηγορίας' - ); - $('#manageCategory form input[name=id]').val( id ); // category id (hidden) - $('#manageCategory form input[name=title]').val( // category title - (id) ? category_record(id).title : "" - ); - prepare_parents_element(id); // prepare <select> for parents - }) - - - // When form is submited - // ------------------------------------------------------------------------- - - $('#manageCategory form').submit( event => { - event.preventDefault(); - - // prepare data to POST - var data = { - id: parseInt($('#manageCategory form input[name=id]').val()), - title: $('#manageCategory form input[name=title]').val(), - parent_id: parseInt($('#parent_id').select2('data')[0].id) - }; - - // select action url (add or update) - var request = '/wiki/ajax?action=' + ((data.id == 0) ? 'add_category' : 'update_category'); - - // send POST request - $.post(request, data) - .done(function( data ) { - - $('#manageCategory').modal('hide'); // when done, close modal - - init_table(); // reload table of categories - }); - - }); - -}); |
