diff options
| author | Geo Halkiadakis <gchalkiadakis@sklavenitis.co.gr> | 2023-04-24 18:02:13 +0300 |
|---|---|---|
| committer | Geo Halkiadakis <gchalkiadakis@sklavenitis.co.gr> | 2023-04-24 18:02:13 +0300 |
| commit | 13753d58d6aceaea8f246040518d50f2eb06a8d9 (patch) | |
| tree | b2e21751cab566182f48775d4b902c6e4c2dd017 | |
| parent | 41d3b5fb68829bbc61ef13ed127dcfb86fa124a0 (diff) | |
| download | classroom-13753d58d6aceaea8f246040518d50f2eb06a8d9.tar.gz classroom-13753d58d6aceaea8f246040518d50f2eb06a8d9.tar.bz2 classroom-13753d58d6aceaea8f246040518d50f2eb06a8d9.zip | |
several hot-fixes; working on lessons flash-management
| -rw-r--r-- | public/app/controllers/admin/Course_admin.php | 13 | ||||
| -rw-r--r-- | public/app/routes/backend.php | 12 | ||||
| -rw-r--r-- | public/app/views/admin/lessons.php | 11 | ||||
| -rw-r--r-- | public/assets/js/admin/edit_lesson.js | 2 | ||||
| -rw-r--r-- | public/assets/js/admin/lessons.js | 386 | ||||
| -rw-r--r-- | tests/service/lorem-md.php | 71 |
6 files changed, 485 insertions, 10 deletions
diff --git a/public/app/controllers/admin/Course_admin.php b/public/app/controllers/admin/Course_admin.php index 90aaa53..bb4deb0 100644 --- a/public/app/controllers/admin/Course_admin.php +++ b/public/app/controllers/admin/Course_admin.php @@ -105,6 +105,19 @@ class Course_admin { ## ------------------------------------------------------------------------- + /** all lessons + * + */ + public static function all_lessons() + { + Render::json(Registry::use('database')->runQuery( + "SELECT lesson.*, lesson_privilege.privilege_id FROM lesson + LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id", + [] + )); + } + + /** get_lesson * * @param $id (int) : lesson's id diff --git a/public/app/routes/backend.php b/public/app/routes/backend.php index 7f4717d..5d6189d 100644 --- a/public/app/routes/backend.php +++ b/public/app/routes/backend.php @@ -135,18 +135,26 @@ Route::add('/admin/api/lesson/([0-9]*)', function ($id) { Course_admin::get_lesson($id); }); - +// ajax: add lesson +// --- Route::add('/admin/api/lesson/add', function () { Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Course_admin::add_lesson(); }, 'post'); - +// ajax: update lesson +// --- Route::add('/admin/api/lesson/update', function () { Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles Course_admin::update_lesson(); }, 'post'); +// ajax: get all lessons +// --- +Route::add('/admin/api/lessons', function () { + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::all_lessons(); +}); // admin files ///////////////////////////////////////////////////////////////// diff --git a/public/app/views/admin/lessons.php b/public/app/views/admin/lessons.php index 6e7afeb..d1cd3ae 100644 --- a/public/app/views/admin/lessons.php +++ b/public/app/views/admin/lessons.php @@ -6,9 +6,6 @@ <a type="button" class="btn pull-right" href="/admin/edit_lesson"> <i class="fas fa-plus"></i> Νέο Μάθημα </a> - <button type="button" class="btn" - data-bs-toggle="modal" data-bs-target="#manageLessons" data-action="preview"> - test</button> </div> </div> @@ -20,8 +17,9 @@ <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-breadcrumb">Κεφάλαιο</th> + <th class="dt-course">Κεφάλαιο</th> <th class="dt-privileges">Πρόσβαση</th> <th class="dt-actions"></th> </thead> @@ -29,7 +27,6 @@ </div> - </div> </div> </div><!-- /manage --> @@ -62,9 +59,9 @@ </div> <div class="row form-group"> - <label class="control-label col-sm-12" for="parent_id">Γονική Κατηγορία</label> + <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="parent_id" name="parent_id" required></select> + <select class="form-control form-control-sm form-select form-select-sm" id="course_id" name="course_id" required></select> </div> </div> diff --git a/public/assets/js/admin/edit_lesson.js b/public/assets/js/admin/edit_lesson.js index c5b0501..89e464f 100644 --- a/public/assets/js/admin/edit_lesson.js +++ b/public/assets/js/admin/edit_lesson.js @@ -154,7 +154,7 @@ $(document).ready(function() { // inti category (select2) // ... $("#course_id").select2({ - placeholder: 'Γονική Κατηγορία', + placeholder: 'Κεφάλαιο', width: '100%' }); diff --git a/public/assets/js/admin/lessons.js b/public/assets/js/admin/lessons.js new file mode 100644 index 0000000..8391f4d --- /dev/null +++ b/public/assets/js/admin/lessons.js @@ -0,0 +1,386 @@ +// Globals +// ----------------------------------------------------------------------------- +var categories = []; +var privileges = []; +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; + }; +} + + +// 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; +} + + +// 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; +} + + +// 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: 'Επίπεδο Πρόσβασης', + 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, + privilege_id: 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_id' }, + { data: 'privilege_id' }, + { 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 + */ + $('#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_select_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/tests/service/lorem-md.php b/tests/service/lorem-md.php new file mode 100644 index 0000000..c7b8d0f --- /dev/null +++ b/tests/service/lorem-md.php @@ -0,0 +1,71 @@ +<?php + +use Registry; + +define("LIMIT", 50); // number of random records to make + +function lorem_md() { + // create curl resource + $ch = curl_init(); + + // set url + curl_setopt($ch, CURLOPT_URL, "https://jaspervdj.be/lorem-markdownum/markdown.txt"); + + //return the transfer as a string + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + + // $output contains the output string + $output = curl_exec($ch); + + + $title = substr($output, 2, strpos( $output, "\n" )-1); + $body = trim(substr($output, strpos( $output, "\n" )+1)); + $intro = str_replace("\n", " ", (substr($body, 3, strpos( $body, "\n" )-2) . $title)); + + + + // close curl resource to free up system resources + curl_close($ch); + + return [ + 'title' => $title, + 'intro' => $intro, + 'body' => $body + ]; + +} + +$rand_content = lorem_md(); + + +for ($i=0; $i < LIMIT ; $i++) { + + $rand_content = lorem_md(); + + $id = Registry::use('database')->query( + "INSERT INTO lesson (title, course_id, intro, `body`, `status`) + VALUES (:title, :courseid, :intro, :body, :status)", + [ + ':title' => $rand_content['title'], + ':courseid' => rand(3,11), + ':intro' => $rand_content['intro'], + ':body' => $rand_content['body'], + 'status' => rand(0,1) + ] + )->lastInsertID(); + + Registry::use('database')->runQuery( + "INSERT INTO lesson_privilege (lesson_id, privilege_id) + VALUES (:lesson_id, :privilege_id)", + [ + ':lesson_id' => $id, + ':privilege_id' => rand(1,2) + ] + ); + +} + + +?> + +done!
\ No newline at end of file |
