From 059e0d95d0c28bc5060e87e146eaf7411f51bf90 Mon Sep 17 00:00:00 2001 From: George Halkiadakis Date: Thu, 27 Apr 2023 03:47:30 +0300 Subject: skeleton commit; based on an anom project --- public/.htaccess | 99 + public/app/config/.gitkeep | 0 public/app/config/app_constants.php | 171 + public/app/config/init_routes.php | 12 + public/app/controllers/.gitkeep | 0 public/app/controllers/Admin.php | 58 + public/app/controllers/Auth.php | 382 + public/app/controllers/admin/.gitkeep | 0 public/app/controllers/admin/Course_admin.php | 676 + public/app/controllers/admin/Users_admin.php | 42 + public/app/controllers/api/.gitkeep | 0 public/app/controllers/api/Common_api.php | 281 + public/app/controllers/api/Doc_api.php | 34 + public/app/controllers/cli/CliContoller.php | 55 + public/app/controllers/cms/Course.php | 252 + public/app/extends/.gitkeep | 0 public/app/extends/Cache_service.php | 82 + public/app/extends/Classroom_manager.php | 106 + public/app/extends/Classroom_user.php | 121 + public/app/extends/Send_mail.php | 212 + public/app/models/.gitkeep | 0 public/app/models/Jorge.php | 172 + public/app/models/_info.md | 150 + public/app/models/admin/History_model.php | 34 + public/app/models/admin/Privilege_model.php | 42 + public/app/models/admin/User_model.php | 299 + public/app/models/cms/Course_model.php | 314 + public/app/models/cms/Media_model.php | 36 + public/app/models/cms/Page_model.php | 18 + public/app/models/market/Market_repository.php | 235 + public/app/models/market/Payment_template.txt | 98 + .../app/models/market/ProductCategories_model.php | 199 + public/app/models/market/Product_model.php | 49 + public/app/models/todo.md | 132 + public/app/routes/.gitkeep | 0 public/app/routes/api.php | 81 + public/app/routes/backend.php | 221 + public/app/routes/frontend.php | 169 + public/app/routes/user.php | 84 + public/app/views/.gitkeep | 0 public/app/views/admin/admin-menu.php | 47 + public/app/views/admin/categories.php | 91 + public/app/views/admin/edit_lesson.php | 159 + public/app/views/admin/edit_page.php | 139 + public/app/views/admin/files.php | 96 + public/app/views/admin/lessons.php | 126 + public/app/views/admin/pages.php | 109 + public/app/views/admin/panel.php | 4 + public/app/views/admin/privileges.php | 93 + public/app/views/admin/skeleton.php | 45 + public/app/views/components/breadcrumbs.php | 30 + public/app/views/components/courses_menu.php | 97 + public/app/views/components/footer.php | 240 + public/app/views/components/header_includes.php | 59 + public/app/views/components/lessons_list.php | 54 + public/app/views/components/subcategories.php | 19 + public/app/views/components/top_bar.php | 40 + public/app/views/components/user-management.php | 65 + public/app/views/error/404.php | 65 + public/app/views/error/general.php | 64 + public/app/views/group.php | 13 + public/app/views/item.php | 4 + public/app/views/simple/Model.php | 887 + public/app/views/simple/Render.php | 182 + public/app/views/simple/category.php | 156 + public/app/views/simple/index.php | 123 + public/app/views/simple/lorem-dates.php | 18 + public/app/views/simple/lorem-intros.php | 721 + public/app/views/simple/lorem-posts.php | 93 + public/app/views/simple/post.php | 236 + public/app/views/templates/course.php | 93 + public/app/views/templates/lesson.php | 82 + public/app/views/templates/page.php | 64 + public/app/views/user/login.php | 91 + public/app/views/user/new-password.php | 65 + public/app/views/user/registration.php | 120 + public/app/views/welcome.php | 71 + public/assets/css/admin.css | 150 + public/assets/css/class.css | 394 + public/assets/css/email.css | 478 + public/assets/css/main.css | 9 + public/assets/css/normalize.css | 349 + public/assets/css/overides.css | 148 + .../Buttons-2.3.6/css/buttons.bootstrap.css | 386 + .../Buttons-2.3.6/css/buttons.bootstrap.min.css | 1 + .../Buttons-2.3.6/css/buttons.bootstrap4.css | 430 + .../Buttons-2.3.6/css/buttons.bootstrap4.min.css | 1 + .../Buttons-2.3.6/css/buttons.bootstrap5.css | 432 + .../Buttons-2.3.6/css/buttons.bootstrap5.min.css | 1 + .../DataTables/Buttons-2.3.6/css/buttons.bulma.css | 429 + .../Buttons-2.3.6/css/buttons.bulma.min.css | 1 + .../Buttons-2.3.6/css/buttons.dataTables.css | 560 + .../Buttons-2.3.6/css/buttons.dataTables.min.css | 1 + .../Buttons-2.3.6/css/buttons.foundation.css | 371 + .../Buttons-2.3.6/css/buttons.foundation.min.css | 1 + .../Buttons-2.3.6/css/buttons.jqueryui.css | 387 + .../Buttons-2.3.6/css/buttons.jqueryui.min.css | 1 + .../Buttons-2.3.6/css/buttons.semanticui.css | 409 + .../Buttons-2.3.6/css/buttons.semanticui.min.css | 1 + .../js/DataTables/Buttons-2.3.6/css/common.scss | 106 + .../js/DataTables/Buttons-2.3.6/css/mixins.scss | 228 + .../Buttons-2.3.6/js/buttons.bootstrap.js | 106 + .../Buttons-2.3.6/js/buttons.bootstrap.min.js | 4 + .../Buttons-2.3.6/js/buttons.bootstrap4.js | 106 + .../Buttons-2.3.6/js/buttons.bootstrap4.min.js | 4 + .../Buttons-2.3.6/js/buttons.bootstrap5.js | 106 + .../Buttons-2.3.6/js/buttons.bootstrap5.min.js | 4 + .../DataTables/Buttons-2.3.6/js/buttons.bulma.js | 117 + .../Buttons-2.3.6/js/buttons.bulma.min.js | 4 + .../DataTables/Buttons-2.3.6/js/buttons.colVis.js | 250 + .../Buttons-2.3.6/js/buttons.colVis.min.js | 5 + .../Buttons-2.3.6/js/buttons.dataTables.js | 92 + .../Buttons-2.3.6/js/buttons.dataTables.min.js | 4 + .../Buttons-2.3.6/js/buttons.foundation.js | 134 + .../Buttons-2.3.6/js/buttons.foundation.min.js | 4 + .../DataTables/Buttons-2.3.6/js/buttons.html5.js | 1494 + .../Buttons-2.3.6/js/buttons.html5.min.js | 8 + .../Buttons-2.3.6/js/buttons.jqueryui.js | 92 + .../Buttons-2.3.6/js/buttons.jqueryui.min.js | 4 + .../DataTables/Buttons-2.3.6/js/buttons.print.js | 238 + .../Buttons-2.3.6/js/buttons.print.min.js | 5 + .../Buttons-2.3.6/js/buttons.semanticui.js | 104 + .../Buttons-2.3.6/js/buttons.semanticui.min.js | 4 + .../Buttons-2.3.6/js/dataTables.buttons.js | 2538 + .../Buttons-2.3.6/js/dataTables.buttons.min.js | 4 + .../ColReorder-1.6.2/css/colReorder.bootstrap.css | 11 + .../css/colReorder.bootstrap.min.css | 1 + .../ColReorder-1.6.2/css/colReorder.bootstrap4.css | 11 + .../css/colReorder.bootstrap4.min.css | 1 + .../ColReorder-1.6.2/css/colReorder.bootstrap5.css | 11 + .../css/colReorder.bootstrap5.min.css | 1 + .../ColReorder-1.6.2/css/colReorder.bulma.css | 11 + .../ColReorder-1.6.2/css/colReorder.bulma.min.css | 1 + .../ColReorder-1.6.2/css/colReorder.dataTables.css | 11 + .../css/colReorder.dataTables.min.css | 1 + .../ColReorder-1.6.2/css/colReorder.foundation.css | 11 + .../css/colReorder.foundation.min.css | 1 + .../ColReorder-1.6.2/css/colReorder.jqueryui.css | 11 + .../css/colReorder.jqueryui.min.css | 1 + .../ColReorder-1.6.2/css/colReorder.semanticui.css | 11 + .../css/colReorder.semanticui.min.css | 1 + .../ColReorder-1.6.2/js/colReorder.bootstrap.js | 58 + .../js/colReorder.bootstrap.min.js | 4 + .../ColReorder-1.6.2/js/colReorder.bootstrap4.js | 58 + .../js/colReorder.bootstrap4.min.js | 4 + .../ColReorder-1.6.2/js/colReorder.bootstrap5.js | 92 + .../js/colReorder.bootstrap5.min.js | 4 + .../ColReorder-1.6.2/js/colReorder.bulma.js | 58 + .../ColReorder-1.6.2/js/colReorder.bulma.min.js | 4 + .../ColReorder-1.6.2/js/colReorder.dataTables.js | 58 + .../js/colReorder.dataTables.min.js | 4 + .../ColReorder-1.6.2/js/colReorder.foundation.js | 58 + .../js/colReorder.foundation.min.js | 4 + .../ColReorder-1.6.2/js/colReorder.jqueryui.js | 58 + .../ColReorder-1.6.2/js/colReorder.jqueryui.min.js | 4 + .../ColReorder-1.6.2/js/colReorder.semanticui.js | 58 + .../js/colReorder.semanticui.min.js | 4 + .../ColReorder-1.6.2/js/dataTables.colReorder.js | 1518 + .../js/dataTables.colReorder.min.js | 4 + .../DataTables-1.13.4/css/dataTables.bootstrap.css | 416 + .../css/dataTables.bootstrap.min.css | 1 + .../css/dataTables.bootstrap4.css | 423 + .../css/dataTables.bootstrap4.min.css | 1 + .../css/dataTables.bootstrap5.css | 430 + .../css/dataTables.bootstrap5.min.css | 5 + .../DataTables-1.13.4/css/dataTables.bulma.css | 379 + .../DataTables-1.13.4/css/dataTables.bulma.min.css | 3 + .../css/dataTables.dataTables.css | 0 .../css/dataTables.dataTables.min.css | 0 .../css/dataTables.foundation.css | 357 + .../css/dataTables.foundation.min.css | 1 + .../DataTables-1.13.4/css/dataTables.jqueryui.css | 673 + .../css/dataTables.jqueryui.min.css | 1 + .../css/dataTables.semanticui.css | 348 + .../css/dataTables.semanticui.min.css | 1 + .../DataTables-1.13.4/css/jquery.dataTables.css | 584 + .../css/jquery.dataTables.min.css | 1 + .../DataTables-1.13.4/images/sort_asc.png | Bin 0 -> 160 bytes .../DataTables-1.13.4/images/sort_asc_disabled.png | Bin 0 -> 148 bytes .../DataTables-1.13.4/images/sort_both.png | Bin 0 -> 201 bytes .../DataTables-1.13.4/images/sort_desc.png | Bin 0 -> 158 bytes .../images/sort_desc_disabled.png | Bin 0 -> 146 bytes .../DataTables-1.13.4/js/dataTables.bootstrap.js | 200 + .../js/dataTables.bootstrap.min.js | 4 + .../DataTables-1.13.4/js/dataTables.bootstrap4.js | 202 + .../js/dataTables.bootstrap4.min.js | 4 + .../DataTables-1.13.4/js/dataTables.bootstrap5.js | 212 + .../js/dataTables.bootstrap5.min.js | 4 + .../DataTables-1.13.4/js/dataTables.bulma.js | 214 + .../DataTables-1.13.4/js/dataTables.bulma.min.js | 4 + .../DataTables-1.13.4/js/dataTables.dataTables.js | 55 + .../js/dataTables.dataTables.min.js | 4 + .../DataTables-1.13.4/js/dataTables.foundation.js | 200 + .../js/dataTables.foundation.min.js | 4 + .../DataTables-1.13.4/js/dataTables.jqueryui.js | 95 + .../js/dataTables.jqueryui.min.js | 4 + .../DataTables-1.13.4/js/dataTables.semanticui.js | 228 + .../js/dataTables.semanticui.min.js | 4 + .../DataTables-1.13.4/js/jquery.dataTables.js | 15686 +++ .../DataTables-1.13.4/js/jquery.dataTables.min.js | 4 + .../DateTime-1.4.0/css/dataTables.dateTime.css | 218 + .../DateTime-1.4.0/css/dataTables.dateTime.min.css | 1 + .../DateTime-1.4.0/js/dataTables.dateTime.js | 1708 + .../DateTime-1.4.0/js/dataTables.dateTime.min.js | 6 + .../css/fixedColumns.bootstrap.css | 42 + .../css/fixedColumns.bootstrap.min.css | 1 + .../css/fixedColumns.bootstrap4.css | 42 + .../css/fixedColumns.bootstrap4.min.css | 1 + .../css/fixedColumns.bootstrap5.css | 42 + .../css/fixedColumns.bootstrap5.min.css | 1 + .../FixedColumns-4.2.2/css/fixedColumns.bulma.css | 35 + .../css/fixedColumns.bulma.min.css | 1 + .../css/fixedColumns.dataTables.css | 19 + .../css/fixedColumns.dataTables.min.css | 1 + .../css/fixedColumns.foundation.css | 23 + .../css/fixedColumns.foundation.min.css | 1 + .../css/fixedColumns.jqueryui.css | 37 + .../css/fixedColumns.jqueryui.min.css | 1 + .../css/fixedColumns.semanticui.css | 46 + .../css/fixedColumns.semanticui.min.css | 1 + .../js/dataTables.fixedColumns.js | 613 + .../js/dataTables.fixedColumns.min.js | 4 + .../js/fixedColumns.bootstrap.js | 58 + .../js/fixedColumns.bootstrap.min.js | 4 + .../js/fixedColumns.bootstrap4.js | 58 + .../js/fixedColumns.bootstrap4.min.js | 4 + .../js/fixedColumns.bootstrap5.js | 58 + .../js/fixedColumns.bootstrap5.min.js | 4 + .../FixedColumns-4.2.2/js/fixedColumns.bulma.js | 58 + .../js/fixedColumns.bulma.min.js | 4 + .../js/fixedColumns.dataTables.js | 58 + .../js/fixedColumns.dataTables.min.js | 4 + .../js/fixedColumns.foundation.js | 58 + .../js/fixedColumns.foundation.min.js | 4 + .../FixedColumns-4.2.2/js/fixedColumns.jqueryui.js | 58 + .../js/fixedColumns.jqueryui.min.js | 4 + .../js/fixedColumns.semanticui.js | 58 + .../js/fixedColumns.semanticui.min.js | 4 + .../css/fixedHeader.bootstrap.css | 16 + .../css/fixedHeader.bootstrap.min.css | 1 + .../css/fixedHeader.bootstrap4.css | 16 + .../css/fixedHeader.bootstrap4.min.css | 1 + .../css/fixedHeader.bootstrap5.css | 16 + .../css/fixedHeader.bootstrap5.min.css | 1 + .../FixedHeader-3.3.2/css/fixedHeader.bulma.css | 16 + .../css/fixedHeader.bulma.min.css | 1 + .../css/fixedHeader.dataTables.css | 18 + .../css/fixedHeader.dataTables.min.css | 1 + .../css/fixedHeader.foundation.css | 16 + .../css/fixedHeader.foundation.min.css | 1 + .../FixedHeader-3.3.2/css/fixedHeader.jqueryui.css | 14 + .../css/fixedHeader.jqueryui.min.css | 1 + .../css/fixedHeader.semanticui.css | 13 + .../css/fixedHeader.semanticui.min.css | 1 + .../FixedHeader-3.3.2/js/dataTables.fixedHeader.js | 1103 + .../js/dataTables.fixedHeader.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.bootstrap.js | 58 + .../js/fixedHeader.bootstrap.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.bootstrap4.js | 58 + .../js/fixedHeader.bootstrap4.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.bootstrap5.js | 58 + .../js/fixedHeader.bootstrap5.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.bulma.js | 58 + .../FixedHeader-3.3.2/js/fixedHeader.bulma.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.dataTables.js | 58 + .../js/fixedHeader.dataTables.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.foundation.js | 58 + .../js/fixedHeader.foundation.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.jqueryui.js | 58 + .../js/fixedHeader.jqueryui.min.js | 4 + .../FixedHeader-3.3.2/js/fixedHeader.semanticui.js | 58 + .../js/fixedHeader.semanticui.min.js | 4 + public/assets/js/DataTables/JSZip-2.5.0/jszip.js | 9155 ++ .../assets/js/DataTables/JSZip-2.5.0/jszip.min.js | 14 + .../KeyTable-2.8.2/css/keyTable.bootstrap.css | 11 + .../KeyTable-2.8.2/css/keyTable.bootstrap.min.css | 1 + .../KeyTable-2.8.2/css/keyTable.bootstrap4.css | 11 + .../KeyTable-2.8.2/css/keyTable.bootstrap4.min.css | 1 + .../KeyTable-2.8.2/css/keyTable.bootstrap5.css | 11 + .../KeyTable-2.8.2/css/keyTable.bootstrap5.min.css | 1 + .../KeyTable-2.8.2/css/keyTable.bulma.css | 11 + .../KeyTable-2.8.2/css/keyTable.bulma.min.css | 1 + .../KeyTable-2.8.2/css/keyTable.dataTables.css | 11 + .../KeyTable-2.8.2/css/keyTable.dataTables.min.css | 1 + .../KeyTable-2.8.2/css/keyTable.foundation.css | 11 + .../KeyTable-2.8.2/css/keyTable.foundation.min.css | 1 + .../KeyTable-2.8.2/css/keyTable.jqueryui.css | 11 + .../KeyTable-2.8.2/css/keyTable.jqueryui.min.css | 1 + .../KeyTable-2.8.2/css/keyTable.semanticui.css | 11 + .../KeyTable-2.8.2/css/keyTable.semanticui.min.css | 1 + .../KeyTable-2.8.2/js/dataTables.keyTable.js | 1419 + .../KeyTable-2.8.2/js/dataTables.keyTable.min.js | 4 + .../KeyTable-2.8.2/js/keyTable.bootstrap.js | 58 + .../KeyTable-2.8.2/js/keyTable.bootstrap.min.js | 4 + .../KeyTable-2.8.2/js/keyTable.bootstrap4.js | 58 + .../KeyTable-2.8.2/js/keyTable.bootstrap4.min.js | 4 + .../KeyTable-2.8.2/js/keyTable.bootstrap5.js | 58 + .../KeyTable-2.8.2/js/keyTable.bootstrap5.min.js | 4 + .../DataTables/KeyTable-2.8.2/js/keyTable.bulma.js | 58 + .../KeyTable-2.8.2/js/keyTable.bulma.min.js | 4 + .../KeyTable-2.8.2/js/keyTable.dataTables.js | 58 + .../KeyTable-2.8.2/js/keyTable.dataTables.min.js | 4 + .../KeyTable-2.8.2/js/keyTable.foundation.js | 58 + .../KeyTable-2.8.2/js/keyTable.foundation.min.js | 4 + .../KeyTable-2.8.2/js/keyTable.jqueryui.js | 58 + .../KeyTable-2.8.2/js/keyTable.jqueryui.min.js | 4 + .../KeyTable-2.8.2/js/keyTable.semanticui.js | 58 + .../KeyTable-2.8.2/js/keyTable.semanticui.min.js | 4 + .../Responsive-2.4.1/css/responsive.bootstrap.css | 185 + .../css/responsive.bootstrap.min.css | 1 + .../Responsive-2.4.1/css/responsive.bootstrap4.css | 185 + .../css/responsive.bootstrap4.min.css | 1 + .../Responsive-2.4.1/css/responsive.bootstrap5.css | 190 + .../css/responsive.bootstrap5.min.css | 1 + .../Responsive-2.4.1/css/responsive.bulma.css | 191 + .../Responsive-2.4.1/css/responsive.bulma.min.css | 1 + .../Responsive-2.4.1/css/responsive.dataTables.css | 182 + .../css/responsive.dataTables.min.css | 1 + .../Responsive-2.4.1/css/responsive.foundation.css | 185 + .../css/responsive.foundation.min.css | 1 + .../Responsive-2.4.1/css/responsive.jqueryui.css | 182 + .../css/responsive.jqueryui.min.css | 1 + .../Responsive-2.4.1/css/responsive.semanticui.css | 185 + .../css/responsive.semanticui.min.css | 1 + .../Responsive-2.4.1/js/dataTables.responsive.js | 1533 + .../js/dataTables.responsive.min.js | 4 + .../Responsive-2.4.1/js/responsive.bootstrap.js | 102 + .../js/responsive.bootstrap.min.js | 4 + .../Responsive-2.4.1/js/responsive.bootstrap4.js | 102 + .../js/responsive.bootstrap4.min.js | 4 + .../Responsive-2.4.1/js/responsive.bootstrap5.js | 118 + .../js/responsive.bootstrap5.min.js | 4 + .../Responsive-2.4.1/js/responsive.bulma.js | 104 + .../Responsive-2.4.1/js/responsive.bulma.min.js | 4 + .../Responsive-2.4.1/js/responsive.dataTables.js | 58 + .../js/responsive.dataTables.min.js | 4 + .../Responsive-2.4.1/js/responsive.foundation.js | 88 + .../js/responsive.foundation.min.js | 4 + .../Responsive-2.4.1/js/responsive.jqueryui.js | 80 + .../Responsive-2.4.1/js/responsive.jqueryui.min.js | 4 + .../Responsive-2.4.1/js/responsive.semanticui.js | 97 + .../js/responsive.semanticui.min.js | 4 + .../RowReorder-1.3.3/css/rowReorder.bootstrap.css | 26 + .../css/rowReorder.bootstrap.min.css | 1 + .../RowReorder-1.3.3/css/rowReorder.bootstrap4.css | 26 + .../css/rowReorder.bootstrap4.min.css | 1 + .../RowReorder-1.3.3/css/rowReorder.bootstrap5.css | 26 + .../css/rowReorder.bootstrap5.min.css | 1 + .../RowReorder-1.3.3/css/rowReorder.bulma.css | 26 + .../RowReorder-1.3.3/css/rowReorder.bulma.min.css | 1 + .../RowReorder-1.3.3/css/rowReorder.dataTables.css | 26 + .../css/rowReorder.dataTables.min.css | 1 + .../RowReorder-1.3.3/css/rowReorder.foundation.css | 26 + .../css/rowReorder.foundation.min.css | 1 + .../RowReorder-1.3.3/css/rowReorder.jqueryui.css | 26 + .../css/rowReorder.jqueryui.min.css | 1 + .../RowReorder-1.3.3/css/rowReorder.semanticui.css | 26 + .../css/rowReorder.semanticui.min.css | 1 + .../RowReorder-1.3.3/js/dataTables.rowReorder.js | 850 + .../js/dataTables.rowReorder.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.bootstrap.js | 59 + .../js/rowReorder.bootstrap.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.bootstrap4.js | 58 + .../js/rowReorder.bootstrap4.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.bootstrap5.js | 58 + .../js/rowReorder.bootstrap5.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.bulma.js | 58 + .../RowReorder-1.3.3/js/rowReorder.bulma.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.dataTables.js | 58 + .../js/rowReorder.dataTables.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.foundation.js | 58 + .../js/rowReorder.foundation.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.jqueryui.js | 58 + .../RowReorder-1.3.3/js/rowReorder.jqueryui.min.js | 4 + .../RowReorder-1.3.3/js/rowReorder.semanticui.js | 58 + .../js/rowReorder.semanticui.min.js | 4 + .../Scroller-2.1.1/css/scroller.bootstrap.css | 37 + .../Scroller-2.1.1/css/scroller.bootstrap.min.css | 1 + .../Scroller-2.1.1/css/scroller.bootstrap4.css | 37 + .../Scroller-2.1.1/css/scroller.bootstrap4.min.css | 1 + .../Scroller-2.1.1/css/scroller.bootstrap5.css | 37 + .../Scroller-2.1.1/css/scroller.bootstrap5.min.css | 1 + .../Scroller-2.1.1/css/scroller.bulma.css | 33 + .../Scroller-2.1.1/css/scroller.bulma.min.css | 1 + .../Scroller-2.1.1/css/scroller.dataTables.css | 33 + .../Scroller-2.1.1/css/scroller.dataTables.min.css | 1 + .../Scroller-2.1.1/css/scroller.foundation.css | 17 + .../Scroller-2.1.1/css/scroller.foundation.min.css | 1 + .../Scroller-2.1.1/css/scroller.jqueryui.css | 33 + .../Scroller-2.1.1/css/scroller.jqueryui.min.css | 1 + .../Scroller-2.1.1/css/scroller.semanticui.css | 33 + .../Scroller-2.1.1/css/scroller.semanticui.min.css | 1 + .../Scroller-2.1.1/js/dataTables.scroller.js | 1353 + .../Scroller-2.1.1/js/dataTables.scroller.min.js | 4 + .../Scroller-2.1.1/js/scroller.bootstrap.js | 58 + .../Scroller-2.1.1/js/scroller.bootstrap.min.js | 4 + .../Scroller-2.1.1/js/scroller.bootstrap4.js | 58 + .../Scroller-2.1.1/js/scroller.bootstrap4.min.js | 4 + .../Scroller-2.1.1/js/scroller.bootstrap5.js | 58 + .../Scroller-2.1.1/js/scroller.bootstrap5.min.js | 4 + .../DataTables/Scroller-2.1.1/js/scroller.bulma.js | 58 + .../Scroller-2.1.1/js/scroller.bulma.min.js | 4 + .../Scroller-2.1.1/js/scroller.dataTables.js | 58 + .../Scroller-2.1.1/js/scroller.dataTables.min.js | 4 + .../Scroller-2.1.1/js/scroller.foundation.js | 58 + .../Scroller-2.1.1/js/scroller.foundation.min.js | 4 + .../Scroller-2.1.1/js/scroller.jqueryui.js | 58 + .../Scroller-2.1.1/js/scroller.jqueryui.min.js | 4 + .../Scroller-2.1.1/js/scroller.semanticui.js | 58 + .../Scroller-2.1.1/js/scroller.semanticui.min.js | 4 + .../Select-1.6.2/css/select.bootstrap.css | 61 + .../Select-1.6.2/css/select.bootstrap.min.css | 1 + .../Select-1.6.2/css/select.bootstrap4.css | 61 + .../Select-1.6.2/css/select.bootstrap4.min.css | 1 + .../Select-1.6.2/css/select.bootstrap5.css | 64 + .../Select-1.6.2/css/select.bootstrap5.min.css | 1 + .../DataTables/Select-1.6.2/css/select.bulma.css | 61 + .../Select-1.6.2/css/select.bulma.min.css | 1 + .../Select-1.6.2/css/select.dataTables.css | 61 + .../Select-1.6.2/css/select.dataTables.min.css | 1 + .../Select-1.6.2/css/select.foundation.css | 61 + .../Select-1.6.2/css/select.foundation.min.css | 1 + .../Select-1.6.2/css/select.jqueryui.css | 61 + .../Select-1.6.2/css/select.jqueryui.min.css | 1 + .../Select-1.6.2/css/select.semanticui.css | 61 + .../Select-1.6.2/css/select.semanticui.min.css | 1 + .../Select-1.6.2/js/dataTables.select.js | 1366 + .../Select-1.6.2/js/dataTables.select.min.js | 4 + .../DataTables/Select-1.6.2/js/select.bootstrap.js | 58 + .../Select-1.6.2/js/select.bootstrap.min.js | 4 + .../Select-1.6.2/js/select.bootstrap4.js | 58 + .../Select-1.6.2/js/select.bootstrap4.min.js | 4 + .../Select-1.6.2/js/select.bootstrap5.js | 58 + .../Select-1.6.2/js/select.bootstrap5.min.js | 4 + .../js/DataTables/Select-1.6.2/js/select.bulma.js | 58 + .../DataTables/Select-1.6.2/js/select.bulma.min.js | 4 + .../Select-1.6.2/js/select.dataTables.js | 58 + .../Select-1.6.2/js/select.dataTables.min.js | 4 + .../Select-1.6.2/js/select.foundation.js | 58 + .../Select-1.6.2/js/select.foundation.min.js | 4 + .../DataTables/Select-1.6.2/js/select.jqueryui.js | 58 + .../Select-1.6.2/js/select.jqueryui.min.js | 4 + .../Select-1.6.2/js/select.semanticui.js | 58 + .../Select-1.6.2/js/select.semanticui.min.js | 4 + .../css/stateRestore.bootstrap.css | 200 + .../css/stateRestore.bootstrap.min.css | 1 + .../css/stateRestore.bootstrap4.css | 231 + .../css/stateRestore.bootstrap4.min.css | 1 + .../css/stateRestore.bootstrap5.css | 231 + .../css/stateRestore.bootstrap5.min.css | 1 + .../StateRestore-1.2.2/css/stateRestore.bulma.css | 226 + .../css/stateRestore.bulma.min.css | 1 + .../css/stateRestore.dataTables.css | 174 + .../css/stateRestore.dataTables.min.css | 1 + .../css/stateRestore.foundation.css | 214 + .../css/stateRestore.foundation.min.css | 1 + .../css/stateRestore.jqueryui.css | 216 + .../css/stateRestore.jqueryui.min.css | 1 + .../css/stateRestore.semanticui.css | 264 + .../css/stateRestore.semanticui.min.css | 1 + .../js/dataTables.stateRestore.js | 2365 + .../js/dataTables.stateRestore.min.js | 4 + .../js/stateRestore.bootstrap.js | 71 + .../js/stateRestore.bootstrap.min.js | 4 + .../js/stateRestore.bootstrap4.js | 70 + .../js/stateRestore.bootstrap4.min.js | 4 + .../js/stateRestore.bootstrap5.js | 73 + .../js/stateRestore.bootstrap5.min.js | 4 + .../StateRestore-1.2.2/js/stateRestore.bulma.js | 71 + .../js/stateRestore.bulma.min.js | 4 + .../js/stateRestore.dataTables.js | 58 + .../js/stateRestore.dataTables.min.js | 4 + .../js/stateRestore.foundation.js | 73 + .../js/stateRestore.foundation.min.js | 4 + .../StateRestore-1.2.2/js/stateRestore.jqueryui.js | 74 + .../js/stateRestore.jqueryui.min.js | 4 + .../js/stateRestore.semanticui.js | 76 + .../js/stateRestore.semanticui.min.js | 4 + public/assets/js/DataTables/datatables.css | 1743 + public/assets/js/DataTables/datatables.js | 94225 +++++++++++++++++++ public/assets/js/DataTables/datatables.min.css | 52 + public/assets/js/DataTables/datatables.min.js | 257 + .../assets/js/DataTables/pdfmake-0.1.36/pdfmake.js | 50468 ++++++++++ .../js/DataTables/pdfmake-0.1.36/pdfmake.min.js | 3 + .../js/DataTables/pdfmake-0.1.36/vfs_fonts.js | 6 + public/assets/js/admin/categories.js | 288 + public/assets/js/admin/edit_lesson.js | 600 + public/assets/js/admin/edit_page.js | 382 + public/assets/js/admin/files.js | 302 + public/assets/js/admin/lessons.js | 364 + public/assets/js/admin/pages.js | 240 + public/assets/js/admin/panel.js | 1 + public/assets/js/admin/privileges.js | 291 + public/assets/js/chart.js/Plugin.Subtitle.js | 221 + public/assets/js/chart.js/chart.min.js | 10 + .../js/chart.js/chartjs-plugin-annotation.js | 928 + .../js/chart.js/chartjs-plugin-datalabels.min.js | 7 + public/assets/js/classroom.js | 27 + public/assets/js/cookie.js | 78 + public/assets/js/edit-post.js | 612 + public/assets/js/lesson-features.js | 218 + public/assets/js/manage-category.js | 287 + public/assets/js/manage-posts.js | 177 + public/assets/js/manage-tags.js | 163 + public/assets/js/marked/marked.cjs | 2723 + public/assets/js/marked/marked.esm.js | 2824 + public/assets/js/marked/marked.min.js | 6 + public/assets/js/marked/marked.umd.js | 2729 + public/assets/js/pdfmake/fonts/Roboto.js | 27 + .../js/pdfmake/fonts/Roboto/Roboto-Italic.ttf | Bin 0 -> 152384 bytes .../js/pdfmake/fonts/Roboto/Roboto-Medium.ttf | Bin 0 -> 146884 bytes .../pdfmake/fonts/Roboto/Roboto-MediumItalic.ttf | Bin 0 -> 152572 bytes .../js/pdfmake/fonts/Roboto/Roboto-Regular.ttf | Bin 0 -> 146768 bytes public/assets/js/pdfmake/pdfmake.js | 74980 +++++++++++++++ public/assets/js/pdfmake/pdfmake.js.map | 1 + public/assets/js/pdfmake/pdfmake.min.js | 3 + public/assets/js/pdfmake/pdfmake.min.js.map | 1 + public/assets/js/pdfmake/standard-fonts/Courier.js | 27 + .../assets/js/pdfmake/standard-fonts/Helvetica.js | 27 + public/assets/js/pdfmake/standard-fonts/Symbol.js | 21 + public/assets/js/pdfmake/standard-fonts/Times.js | 27 + .../js/pdfmake/standard-fonts/ZapfDingbats.js | 21 + public/assets/js/pdfmake/vfs_fonts.js | 7 + public/assets/js/select2/css/select2_4.0.6.min.css | 1 + public/assets/js/select2/i18n/el.js | 3 + public/assets/js/select2/js/select2_4.0.6.min.js | 1 + public/favicon.ico | Bin 0 -> 15086 bytes public/files/.gitkeep | 0 public/index.php | 63 + 529 files changed, 309479 insertions(+) create mode 100644 public/.htaccess create mode 100644 public/app/config/.gitkeep create mode 100644 public/app/config/app_constants.php create mode 100644 public/app/config/init_routes.php create mode 100644 public/app/controllers/.gitkeep create mode 100644 public/app/controllers/Admin.php create mode 100644 public/app/controllers/Auth.php create mode 100644 public/app/controllers/admin/.gitkeep create mode 100644 public/app/controllers/admin/Course_admin.php create mode 100644 public/app/controllers/admin/Users_admin.php create mode 100644 public/app/controllers/api/.gitkeep create mode 100644 public/app/controllers/api/Common_api.php create mode 100644 public/app/controllers/api/Doc_api.php create mode 100644 public/app/controllers/cli/CliContoller.php create mode 100644 public/app/controllers/cms/Course.php create mode 100644 public/app/extends/.gitkeep create mode 100644 public/app/extends/Cache_service.php create mode 100644 public/app/extends/Classroom_manager.php create mode 100644 public/app/extends/Classroom_user.php create mode 100644 public/app/extends/Send_mail.php create mode 100644 public/app/models/.gitkeep create mode 100644 public/app/models/Jorge.php create mode 100644 public/app/models/_info.md create mode 100644 public/app/models/admin/History_model.php create mode 100644 public/app/models/admin/Privilege_model.php create mode 100644 public/app/models/admin/User_model.php create mode 100644 public/app/models/cms/Course_model.php create mode 100644 public/app/models/cms/Media_model.php create mode 100644 public/app/models/cms/Page_model.php create mode 100644 public/app/models/market/Market_repository.php create mode 100644 public/app/models/market/Payment_template.txt create mode 100644 public/app/models/market/ProductCategories_model.php create mode 100644 public/app/models/market/Product_model.php create mode 100644 public/app/models/todo.md create mode 100644 public/app/routes/.gitkeep create mode 100644 public/app/routes/api.php create mode 100644 public/app/routes/backend.php create mode 100644 public/app/routes/frontend.php create mode 100644 public/app/routes/user.php create mode 100644 public/app/views/.gitkeep create mode 100644 public/app/views/admin/admin-menu.php create mode 100644 public/app/views/admin/categories.php create mode 100644 public/app/views/admin/edit_lesson.php create mode 100644 public/app/views/admin/edit_page.php create mode 100644 public/app/views/admin/files.php create mode 100644 public/app/views/admin/lessons.php create mode 100644 public/app/views/admin/pages.php create mode 100644 public/app/views/admin/panel.php create mode 100644 public/app/views/admin/privileges.php create mode 100644 public/app/views/admin/skeleton.php create mode 100644 public/app/views/components/breadcrumbs.php create mode 100644 public/app/views/components/courses_menu.php create mode 100644 public/app/views/components/footer.php create mode 100644 public/app/views/components/header_includes.php create mode 100644 public/app/views/components/lessons_list.php create mode 100644 public/app/views/components/subcategories.php create mode 100644 public/app/views/components/top_bar.php create mode 100644 public/app/views/components/user-management.php create mode 100644 public/app/views/error/404.php create mode 100644 public/app/views/error/general.php create mode 100644 public/app/views/group.php create mode 100644 public/app/views/item.php create mode 100644 public/app/views/simple/Model.php create mode 100644 public/app/views/simple/Render.php create mode 100644 public/app/views/simple/category.php create mode 100644 public/app/views/simple/index.php create mode 100644 public/app/views/simple/lorem-dates.php create mode 100644 public/app/views/simple/lorem-intros.php create mode 100644 public/app/views/simple/lorem-posts.php create mode 100644 public/app/views/simple/post.php create mode 100644 public/app/views/templates/course.php create mode 100644 public/app/views/templates/lesson.php create mode 100644 public/app/views/templates/page.php create mode 100644 public/app/views/user/login.php create mode 100644 public/app/views/user/new-password.php create mode 100644 public/app/views/user/registration.php create mode 100644 public/app/views/welcome.php create mode 100644 public/assets/css/admin.css create mode 100644 public/assets/css/class.css create mode 100644 public/assets/css/email.css create mode 100644 public/assets/css/main.css create mode 100644 public/assets/css/normalize.css create mode 100644 public/assets/css/overides.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.min.css create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/common.scss create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/css/mixins.scss create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bulma.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bulma.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.colVis.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.colVis.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.dataTables.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.dataTables.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.foundation.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.foundation.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.html5.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.html5.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.jqueryui.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.jqueryui.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.print.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.print.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.semanticui.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/buttons.semanticui.min.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/dataTables.buttons.js create mode 100644 public/assets/js/DataTables/Buttons-2.3.6/js/dataTables.buttons.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bootstrap.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bootstrap.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bootstrap4.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bootstrap5.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bulma.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.bulma.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.dataTables.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.dataTables.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.foundation.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.foundation.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.jqueryui.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.jqueryui.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.semanticui.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/css/colReorder.semanticui.min.css create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bootstrap.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bootstrap.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bootstrap4.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bootstrap5.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bulma.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.bulma.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.dataTables.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.dataTables.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.foundation.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.foundation.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.jqueryui.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.jqueryui.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.semanticui.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/colReorder.semanticui.min.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/dataTables.colReorder.js create mode 100644 public/assets/js/DataTables/ColReorder-1.6.2/js/dataTables.colReorder.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bootstrap.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bootstrap.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bootstrap4.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bootstrap5.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bulma.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.bulma.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.dataTables.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.dataTables.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.foundation.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.foundation.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.jqueryui.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.jqueryui.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.semanticui.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/dataTables.semanticui.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/jquery.dataTables.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/css/jquery.dataTables.min.css create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/images/sort_asc.png create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/images/sort_asc_disabled.png create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/images/sort_both.png create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/images/sort_desc.png create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/images/sort_desc_disabled.png create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bootstrap.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bootstrap.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bootstrap4.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bootstrap5.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bulma.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.bulma.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.dataTables.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.dataTables.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.foundation.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.foundation.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.jqueryui.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.jqueryui.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.semanticui.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/dataTables.semanticui.min.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/jquery.dataTables.js create mode 100644 public/assets/js/DataTables/DataTables-1.13.4/js/jquery.dataTables.min.js create mode 100644 public/assets/js/DataTables/DateTime-1.4.0/css/dataTables.dateTime.css create mode 100644 public/assets/js/DataTables/DateTime-1.4.0/css/dataTables.dateTime.min.css create mode 100644 public/assets/js/DataTables/DateTime-1.4.0/js/dataTables.dateTime.js create mode 100644 public/assets/js/DataTables/DateTime-1.4.0/js/dataTables.dateTime.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bootstrap.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bootstrap.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bootstrap4.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bootstrap5.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bulma.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.bulma.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.dataTables.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.dataTables.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.foundation.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.foundation.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.jqueryui.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.jqueryui.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.semanticui.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/css/fixedColumns.semanticui.min.css create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/dataTables.fixedColumns.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/dataTables.fixedColumns.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bootstrap.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bootstrap.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bootstrap4.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bootstrap5.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bulma.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.bulma.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.dataTables.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.dataTables.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.foundation.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.foundation.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.jqueryui.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.jqueryui.min.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.semanticui.js create mode 100644 public/assets/js/DataTables/FixedColumns-4.2.2/js/fixedColumns.semanticui.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bootstrap.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bootstrap.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bootstrap4.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bootstrap5.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bulma.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.bulma.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.dataTables.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.dataTables.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.foundation.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.foundation.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.jqueryui.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.jqueryui.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.semanticui.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/css/fixedHeader.semanticui.min.css create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/dataTables.fixedHeader.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/dataTables.fixedHeader.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bootstrap.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bootstrap.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bootstrap4.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bootstrap5.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bulma.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.bulma.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.dataTables.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.dataTables.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.foundation.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.foundation.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.jqueryui.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.jqueryui.min.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.semanticui.js create mode 100644 public/assets/js/DataTables/FixedHeader-3.3.2/js/fixedHeader.semanticui.min.js create mode 100644 public/assets/js/DataTables/JSZip-2.5.0/jszip.js create mode 100644 public/assets/js/DataTables/JSZip-2.5.0/jszip.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bootstrap.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bootstrap.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bootstrap4.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bootstrap5.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bulma.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.bulma.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.dataTables.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.dataTables.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.foundation.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.foundation.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.jqueryui.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.jqueryui.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.semanticui.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/css/keyTable.semanticui.min.css create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/dataTables.keyTable.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/dataTables.keyTable.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bootstrap.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bootstrap.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bootstrap4.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bootstrap5.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bulma.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.bulma.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.dataTables.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.dataTables.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.foundation.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.foundation.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.jqueryui.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.jqueryui.min.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.semanticui.js create mode 100644 public/assets/js/DataTables/KeyTable-2.8.2/js/keyTable.semanticui.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bootstrap.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bootstrap.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bootstrap4.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bootstrap5.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bulma.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.bulma.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.dataTables.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.dataTables.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.foundation.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.foundation.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.jqueryui.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.jqueryui.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.semanticui.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/css/responsive.semanticui.min.css create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/dataTables.responsive.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/dataTables.responsive.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bootstrap.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bootstrap.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bootstrap4.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bootstrap5.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bulma.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.bulma.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.dataTables.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.dataTables.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.foundation.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.foundation.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.jqueryui.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.jqueryui.min.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.semanticui.js create mode 100644 public/assets/js/DataTables/Responsive-2.4.1/js/responsive.semanticui.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bootstrap.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bootstrap.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bootstrap4.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bootstrap5.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bulma.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.bulma.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.dataTables.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.dataTables.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.foundation.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.foundation.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.jqueryui.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.jqueryui.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.semanticui.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/css/rowReorder.semanticui.min.css create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/dataTables.rowReorder.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/dataTables.rowReorder.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bootstrap.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bootstrap.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bootstrap4.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bootstrap5.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bulma.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.bulma.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.dataTables.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.dataTables.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.foundation.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.foundation.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.jqueryui.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.jqueryui.min.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.semanticui.js create mode 100644 public/assets/js/DataTables/RowReorder-1.3.3/js/rowReorder.semanticui.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bootstrap.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bootstrap.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bootstrap4.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bootstrap5.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bulma.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.bulma.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.dataTables.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.dataTables.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.foundation.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.foundation.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.jqueryui.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.jqueryui.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.semanticui.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/css/scroller.semanticui.min.css create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/dataTables.scroller.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/dataTables.scroller.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bootstrap.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bootstrap.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bootstrap4.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bootstrap5.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bulma.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.bulma.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.dataTables.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.dataTables.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.foundation.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.foundation.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.jqueryui.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.jqueryui.min.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.semanticui.js create mode 100644 public/assets/js/DataTables/Scroller-2.1.1/js/scroller.semanticui.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bootstrap.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bootstrap.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bootstrap4.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bootstrap5.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bulma.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.bulma.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.dataTables.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.dataTables.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.foundation.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.foundation.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.jqueryui.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.jqueryui.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.semanticui.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/css/select.semanticui.min.css create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/dataTables.select.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/dataTables.select.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bootstrap.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bootstrap.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bootstrap4.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bootstrap5.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bulma.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.bulma.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.dataTables.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.dataTables.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.foundation.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.foundation.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.jqueryui.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.jqueryui.min.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.semanticui.js create mode 100644 public/assets/js/DataTables/Select-1.6.2/js/select.semanticui.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bootstrap.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bootstrap.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bootstrap4.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bootstrap4.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bootstrap5.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bootstrap5.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bulma.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.bulma.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.dataTables.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.dataTables.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.foundation.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.foundation.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.jqueryui.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.jqueryui.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.semanticui.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/css/stateRestore.semanticui.min.css create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/dataTables.stateRestore.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/dataTables.stateRestore.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bootstrap.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bootstrap.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bootstrap4.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bootstrap4.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bootstrap5.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bootstrap5.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bulma.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.bulma.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.dataTables.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.dataTables.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.foundation.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.foundation.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.jqueryui.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.jqueryui.min.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.semanticui.js create mode 100644 public/assets/js/DataTables/StateRestore-1.2.2/js/stateRestore.semanticui.min.js create mode 100644 public/assets/js/DataTables/datatables.css create mode 100644 public/assets/js/DataTables/datatables.js create mode 100644 public/assets/js/DataTables/datatables.min.css create mode 100644 public/assets/js/DataTables/datatables.min.js create mode 100644 public/assets/js/DataTables/pdfmake-0.1.36/pdfmake.js create mode 100644 public/assets/js/DataTables/pdfmake-0.1.36/pdfmake.min.js create mode 100644 public/assets/js/DataTables/pdfmake-0.1.36/vfs_fonts.js create mode 100644 public/assets/js/admin/categories.js create mode 100644 public/assets/js/admin/edit_lesson.js create mode 100644 public/assets/js/admin/edit_page.js create mode 100644 public/assets/js/admin/files.js create mode 100644 public/assets/js/admin/lessons.js create mode 100644 public/assets/js/admin/pages.js create mode 100644 public/assets/js/admin/panel.js create mode 100644 public/assets/js/admin/privileges.js create mode 100644 public/assets/js/chart.js/Plugin.Subtitle.js create mode 100644 public/assets/js/chart.js/chart.min.js create mode 100644 public/assets/js/chart.js/chartjs-plugin-annotation.js create mode 100644 public/assets/js/chart.js/chartjs-plugin-datalabels.min.js create mode 100644 public/assets/js/classroom.js create mode 100644 public/assets/js/cookie.js create mode 100644 public/assets/js/edit-post.js create mode 100644 public/assets/js/lesson-features.js create mode 100644 public/assets/js/manage-category.js create mode 100644 public/assets/js/manage-posts.js create mode 100644 public/assets/js/manage-tags.js create mode 100644 public/assets/js/marked/marked.cjs create mode 100644 public/assets/js/marked/marked.esm.js create mode 100644 public/assets/js/marked/marked.min.js create mode 100644 public/assets/js/marked/marked.umd.js create mode 100644 public/assets/js/pdfmake/fonts/Roboto.js create mode 100644 public/assets/js/pdfmake/fonts/Roboto/Roboto-Italic.ttf create mode 100644 public/assets/js/pdfmake/fonts/Roboto/Roboto-Medium.ttf create mode 100644 public/assets/js/pdfmake/fonts/Roboto/Roboto-MediumItalic.ttf create mode 100644 public/assets/js/pdfmake/fonts/Roboto/Roboto-Regular.ttf create mode 100644 public/assets/js/pdfmake/pdfmake.js create mode 100644 public/assets/js/pdfmake/pdfmake.js.map create mode 100644 public/assets/js/pdfmake/pdfmake.min.js create mode 100644 public/assets/js/pdfmake/pdfmake.min.js.map create mode 100644 public/assets/js/pdfmake/standard-fonts/Courier.js create mode 100644 public/assets/js/pdfmake/standard-fonts/Helvetica.js create mode 100644 public/assets/js/pdfmake/standard-fonts/Symbol.js create mode 100644 public/assets/js/pdfmake/standard-fonts/Times.js create mode 100644 public/assets/js/pdfmake/standard-fonts/ZapfDingbats.js create mode 100644 public/assets/js/pdfmake/vfs_fonts.js create mode 100644 public/assets/js/select2/css/select2_4.0.6.min.css create mode 100644 public/assets/js/select2/i18n/el.js create mode 100644 public/assets/js/select2/js/select2_4.0.6.min.js create mode 100644 public/favicon.ico create mode 100644 public/files/.gitkeep create mode 100644 public/index.php (limited to 'public') diff --git a/public/.htaccess b/public/.htaccess new file mode 100644 index 0000000..f4ddf81 --- /dev/null +++ b/public/.htaccess @@ -0,0 +1,99 @@ +## Introduce the Server +Header add Origin-Name geone + +### Deny access to specific folders + + ## deny all files too + RedirectMatch 403 ^/app/.*$ + RedirectMatch 403 ^/cache/.*$ + RedirectMatch 403 ^/processed-views/.*$ + + ## deny folders only + RedirectMatch 403 ^/css/?$ + RedirectMatch 403 ^/js/?$ + + + RewriteEngine On + RewriteBase / + + # Remove trailing slash + RewriteRule ^(.*)/$ /$1 [L,R=301,E=limitcache:1] + # Header always set Cache-Control "max-age=5400" env=limitcache + + # Remove index.php from Application Engine URLs + # and set 301 Redirects not indefinitely permanent (cache for 1:30h) + RewriteCond %{THE_REQUEST} ^GET.*index\.php [NC] + RewriteRule (.*?)index\.php/*(.*) /$1$2 [R=301,NE,L,QSA,E=limitcache:1] + + # Define some cache-control max-age for environment = limitcache + # but ExpiresDefault on mod_expires will create a duplicate header_-) + Header always set Cache-Control "max-age=30" env=limitcache + + # Direct all non-file/directory web requests through the site index file_\\) + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule ^(.*)$ /index.php/$1 [L,QSA] + + + +# +# +# Header set Access-Control-Allow-Origin "*" +# +# + + +### SERVER SIDE OPTIMIZATIONS + +### COMPRESSION + +# COMPRESS text-anything output +AddOutputFilterByType DEFLATE text/plain +AddOutputFilterByType DEFLATE text/html +AddOutputFilterByType DEFLATE text/xml +AddOutputFilterByType DEFLATE text/css +AddOutputFilterByType DEFLATE application/xml +AddOutputFilterByType DEFLATE application/xhtml+xml +AddOutputFilterByType DEFLATE application/rss+xml +AddOutputFilterByType DEFLATE application/javascript +AddOutputFilterByType DEFLATE application/x-javascript +AddOutputFilterByType DEFLATE application/json + +### ### CACHE-CONTROL HEADERS +### +### # CACHE-CONTROL IMAGES 100days +### #: +### +### Header set Cache-Control "max-age=8640000, public" +### +### +### # CACHE-CONTROL CSS and JS 30days +### #: +### #: Header set Cache-Control "max-age=2592000, public" +### #: +### +### ### EXPIRATION DATES +### +### # EXPIRATION DATE BY TYPE +### +### ExpiresActive On +### +### # Default directive +### ExpiresDefault "access plus 0 seconds" +### +### # My Fav-icon and Images +### ExpiresByType image/x-icon "access plus 1 month" +### ExpiresByType image/gif "access plus 1 month" +### ExpiresByType image/png "access plus 1 month" +### ExpiresByType image/jpg "access plus 1 month" +### ExpiresByType image/jpeg "access plus 1 month" +### +### # CSS +### #: ExpiresByType text/css "access plus 1 month" +### # Javascript +### #: ExpiresByType application/javascript "access plus 1 year" +### +### +### +### # Remove Server's Signature +### ServerSignature Off diff --git a/public/app/config/.gitkeep b/public/app/config/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/app/config/app_constants.php b/public/app/config/app_constants.php new file mode 100644 index 0000000..b46bc51 --- /dev/null +++ b/public/app/config/app_constants.php @@ -0,0 +1,171 @@ + 'Login', + 2 => 'Account', + 3 => 'Payment' +]); + + + +// ERRORS AND ERROR MESSAGES /////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- + +define('EMPTY_REQUIRED_FIELDS', 'Δεν έχουν συμπληρωθεί όλα τα υποχρεωτικά πεδία'); + + + +// ASSETS: PATHS USED HEAVILY ////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- +// these paths are used in order to easily find and autoload useful elemets + + +// JAVASCRIPT LIBRARY PATHS +// ----------------------------------------------------------------------------- +define('JS_DIR', '/content/'); // path to contruct link +define('JS_LIBRARIES', array( // path after to the actual file + 'jquery' => 'lib/jquery/dist/jquery.min.js', + + 'require/files' => 'lib/require/require.files.js', + 'require/slim' => 'lib/require/require.slim.js', + + 'plugins' => 'lib/plugins/plugins.min.js', + 'plugins/setup' => 'lib/plugins/plugins.setup.js' + ) +); + + +// CSS ASSET PATHS +// ----------------------------------------------------------------------------- +define('CSS_DIR', '/content/css/'); // path to contruct link +define('CSS_FILES', array( // path after to the actual file + 'main' => 'main.min.css', + 'filter' => 'filter.css', + 'overides' => 'overides.css', + ) +); + + +// FONTS +// ----------------------------------------------------------------------------- +define('FONTS_DIR', '/content/fonts/'); +define('FONT_FILES', array( + 'iconfont' => 'iconfont.woff2', + 'CFAstyStdBold' => 'CFAstyStd-Bold.woff2', + 'CFAstyStdBook' => 'CFAstyStd-Book.woff2', + 'CFAstyStdMedium' => 'CFAstyStd-Medium.woff2' + ) +); + + + + +// Mesagges //////////////////////////////////////////////////////////////////// +// ----------------------------------------------------------------------------- + +// 404 +// --- +define('PAGE_404_TITLE', '404: Not Found'); + +// registration +// --- +define('REGISTRATION_SUCCESS', "

Επιτυχής Εγγραφή

+

+ Παρακαλώ ελέγξτε το email σας και ακολουθήστε το σύνδεσμο ενεργοποίησης + που σας 'εχει αποσταλεί, ώστε να έχετε πρόσβαση σε επιπλέον περιεχόμενο του site +

" +); +define ('REGISTRATION_USER_EXISTS', "

Αποτυχία Εγγραφής

+

+ Υπάρχει ήδη χρήστης με αυτό το email. Αν δεν θυμάστε το password + μπορείτε να κάνετε επαναφορά του ακολουθώντας + αυτό το σύνδεσμο. +

" +); + + +// activation +// --- +define('ACCOUNT_ACTIVATED_TITLE', 'Ο λογαριασμός σας έχει ενεργοποιηθεί'); +define('ACCOUNT_ACTIVATED_MESSAGE', 'Τώρα μπορείτε να κάνετε + Είσοδο στο σύστημα + για να δείτε περισσότερο περιεχόμενο'); +define('NOT_VALID_ACTIVATION_TITLE', 'Σφάλμα!'); +define('NOT_VALID_ACTIVATION_MESSAGE', 'Ο κωδικός ενεργοποίησης δεν είναι σωστός. + Μήπως τον έχετε ενεργοποιήσει στο παρελθόν;'); \ No newline at end of file diff --git a/public/app/config/init_routes.php b/public/app/config/init_routes.php new file mode 100644 index 0000000..22d6ec0 --- /dev/null +++ b/public/app/config/init_routes.php @@ -0,0 +1,12 @@ +POST['email']); + + // if no user exists, return false + if ($record === false) return false; + + // user is valid; check user password + // create a user object + $user = (new Classroom_user()) + ->setID($record['id']) + ->setUserName($record['email']) + ->setName($record['first_name'] .' '. $record['last_name']) + ->setPassword($record['password']) + ->setEnabled($record['active']); + + // let user manager to validate user credentials + $userManager = new Classroom_manager(); + + if ($userManager->isPasswordValid($user, $req->POST['password'])) { + + // get user's security attributes + $attributes = User_Model::getUser($record['id']); + $roles = json_decode($attributes['Roles_json']); + $user + ->setRoles($roles) + ->setPrivileges( + array_merge( + json_decode($attributes['RootPrivileges_json']), + self::merge_lists_array( + json_decode($attributes['SubPrivileges_json']) + ) + ) + ); + + // regeneration session ID (prevent session fixation) + session_regenerate_id(); + // set cookie for connected user + setcookie( + 'cluser', + 'connected;'. $user->getName(), + time()+60*60*8, // 8 hours + '/' + ); + + // check if admin (and redirect differently) + $is_admin = (!empty(array_intersect([1,2,3], $roles))); + + // login OK, set Token in session + $userManager->createUserToken($user); + return [ + 'success' => true, + 'goto' => $is_admin ? '/admin/lessons' : '/user/profile', + ]; + + } else { + return false; + } + } + + + /** + * merges an array of lists to one list + */ + private static function merge_lists_array( $list ) + { + $current = []; + foreach($list as $sublist) { + $current = array_merge($current, $sublist); + } + return $current; + } + + + /** activate + * resolves a call like: /account/activate?ticket=ca42d68cfba5fbbafeacc010b8e3a551 + */ + public static function activate() + { + $req = Registry::get('REQUEST'); + + // get the record of the target user + $check = User_model::activate($req->GET['ticket']); + + if ($check == true) { + Render::view('/error/general', [ + 'title' => ACCOUNT_ACTIVATED_TITLE, + 'message' => ACCOUNT_ACTIVATED_MESSAGE + ]); + + } else { + Render::view('/error/general', [ + 'title' => NOT_VALID_ACTIVATION_TITLE, + 'message' => NOT_VALID_ACTIVATION_MESSAGE + ]); + } + + } + + /** register + * + * Method for new user registration + * + */ + public static function register() + { + $userManager = new Classroom_manager(); + $req = Registry::get('REQUEST'); + + // create a salted password hash + $password = $userManager->cryptPassword($req->POST['password']); + + // echo $password; print_r($req->POST); die(); // OK! + + $user = (new Classroom_user()) + ->setUserName($req->POST['email']) + ->setName($req->POST['name'] .' '. $req->POST['surname']) + ->setPassword($password) + ->setRoles([ READER ]) // Role: authorized reader + ->setPrivileges([]); // none privilege until acount confirmation + + // create user record + $activation_code = User_model::registerUser($req->POST, $password); + + // TODO: + // handle error on user registration + // ... + // + // if ($activatopn_code[] == -1) { + // return [ + // 'success' => false, + // 'message' => REGISTRATION_USER_EXISTS + // ]; + // } + + $send_mail = Send_mail::send_activation_code([ + 'email' => $req->POST['email'], + 'name' => $req->POST['name'] .' '. $req->POST['surname'], + 'code' => $activation_code['activation'] + ]); + + // Send replies + if ($send_mail) { + return [ + 'success' => true, + 'message' => REGISTRATION_SUCCESS + ]; + + } else { + return [ + 'success' => false, + 'message' => 'error on sending email' + ]; + } + + } + + /** is_connected + * checks if the user is connected + * + * @return true|false + */ + public static function is_connected() + { + $manager = new Classroom_manager(); + if ($manager->hasUserToken()) { + + // user is connected; + $token = $manager->getUserToken(); + $user = $token->getUser(); + + return $user; + + } else { + // user is not connected; + return false; + } + } + + + /** logout + * + * performs a secure logout; + * regenerates session; deletes cookies; + */ + public static function logout() + { + $userManager = new Classroom_manager(); + $userManager->logout(); + + // regeneration session ID (prevent session fixation) + session_regenerate_id(); + + // remove user-conected cookie + if (isset($_COOKIE['cluser'])) { + unset($_COOKIE['cluser']); + setcookie('cluser', '', -1, '/'); + return true; + + } else { + return false; + } + } + + + + /** hasPermition( PERMIT ) + * + * checks if the user owns the specified permition + * to access the source + * + */ + public static function hasPermition($permit = [0]) + { + if (in_array(0, $permit)) { // permision 0 means public + return true; // permision 0 is always granted + } + + if ($user = self::is_connected() === false) { // if not connected + return false; // then no other permition is granted + } + + if ($user instanceof UserInterface) { + return ( !empty( array_intersect($permit, $user->getPrivileges()) ) ); + } + } + + + /** isAuthenticated() + * + * chechs if the user's roles and permitions + * satisfy the specified requirements + * to access the source + * + * @param $requirements (array of rules-array) + * + * example: + * [ + * [ + * role => [2, 3] + * permition => ['10', '12', '18'] + * ], + * [ + * role => [1 , 4] + * ], + * [ + * permition => [ 3 ] + * ] + * ] + * + * defines (and parses to) a requirements rule of: + * [ + * user should be creator or editor + * _AND_ have permition 10 or 12 or 18 + * ] + * OR + * [ + * user should be an administrator or developer + * ] + * OR + * [ + * user should have permition #3 + * ] + * + * + */ + public static function isAuthorized($requirements) + { + $authorized = false; + foreach($requirements as $required) { + + if (isset($required['role'])) { // if a role is required + if ( (self::isGranted($required['role'])) // authorize both role + && (self::hasPermition($required['permition'] ?? [ 0 ])) ) { // and permition + // $authorized = true; + return true; + } + + } else { // else, if not is not required + if (self::hasPermition($required['permition'] ?? [ 0 ])) { // authorize permition + // $authorized = true; + return true; + } + } + } + return $authorized; + } + + + public static function forgot_pass() + { + } + + + + public static function validate_otp() + { + } + + + /** allowRoles + * + * method filters access for certain roles + * if user is not grented acces, a forbiden message is sent and app ends._ + * otherwise the method returns true (app will continue) + * + * @param $allowed (array) : array of allowed roles + * @return true or die(); + */ + public static function allowRoles($allowed) + { + $manager = new Classroom_manager(); + if ($manager->isGranted($allowed)) { // if valid, return true (continue) + return true; + + } else { // no user, no access; die._ + Render::view('error/general', [ + 'title' => 'Forbidden', + 'message' => 'Access is forbidden' + ]); + die(); + return false; // this line will never run + } + } + + + /** hasValidRole + * like allowRoles() but dowes not stop execution + * + * @return true|false + */ + public static function hasValidRole($allowed) + { + $manager = new Classroom_manager(); + return ($manager->isGranted($allowed)); + } + + + public static function in_admin_group() + { + $manager = new Classroom_manager(); + return ($manager->isGranted([1, 2, 3])); + } + + + +} + + +// NOTE: +// check: https://netcorecloud.com/tutorials/send-an-email-via-gmail-smtp-server-using-php/ \ No newline at end of file diff --git a/public/app/controllers/admin/.gitkeep b/public/app/controllers/admin/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/app/controllers/admin/Course_admin.php b/public/app/controllers/admin/Course_admin.php new file mode 100644 index 0000000..fcf38c9 --- /dev/null +++ b/public/app/controllers/admin/Course_admin.php @@ -0,0 +1,676 @@ +query( + "INSERT INTO course (parent_id, label) VALUES (:parent, :label)", + [ + ':parent' => Registry::get('REQUEST')->POST['parent_id'], + ':label' => Registry::get('REQUEST')->POST['label'] + ] + )->lastInsertID(); + + $cache = self::update_courses_cache(); // update category caches + return $cache['breadcrumbs']; // return + } + + + /** update course + * --- + * @param void (get data from POST) + */ + public static function update_course() + { + Registry::use('database')->query( + "UPDATE course SET parent_id = :parent, label = :label + WHERE id = :id", + [ + ':id' => Registry::get('REQUEST')->POST['id'], + ':parent' => Registry::get('REQUEST')->POST['parent_id'], + ':label' => Registry::get('REQUEST')->POST['label'] + ] + ); + $cache = self::update_courses_cache(); + return $cache['breadcrumbs']; + } + + + /** update courses cache + * --- -- -- - - - + * Forces re-caching of courses tree + * Shall run if anything changes to courses + * + * @param void + * @return (array): ['tree' => ..., 'breadcrumbs' => ... ] + */ + public static function update_courses_cache() + { + return Cache_service::courses_struct(PROXY_IGNORE_CACHE); + } + + + ## ------------------------------------------------------------------------- + ## + ## LESSON METHODS + ## + ## ------------------------------------------------------------------------- + + + /** 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 + */ + public static function get_lesson($id) + { + // get (first) lesson with id = $id; render as json + Render::json(Registry::use('database')->query( + "SELECT lesson.*, + ( SELECT + CONCAT('[', GROUP_CONCAT(JSON_OBJECT( + 'id', media.id, + 'label', media.label, + 'type', media.type, + 'path', media.path )), + ']') + FROM media + LEFT JOIN lesson_media ON lesson_media.media_id = media.id + WHERE lesson_media.lesson_id = :id + ) AS medias_json, + lesson_privilege.privilege_id + FROM lesson + LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id + WHERE lesson.id = :id", + [ ':id' => $id] + )->getFirst()); + } + + + /** add_lesson + * insert a new lesson + * + * all parametres are passed via $_POST array + * + * POST @param title + * POST @param course_id + * POST @param intro + * POST @param body + * POST @param published + */ + public static function add_lesson() + { + $post = Registry::get('REQUEST')->POST; + + // insert lesson content into daabase + $id = Registry::use('database')->query( + "INSERT INTO lesson (title, course_id, intro, `body`, `status`) + VALUES (:title, :courseid, :intro, :body, :status)", + [ + ':title' => $post['title'], + ':courseid' => $post['course_id'], + ':intro' => $post['intro'], + ':body' => $post['body'], + 'status' => $post['status'] + ] + )->lastInsertID(); + + // set lesson privileges to database + Registry::use('database')->runQuery( + "INSERT INTO lesson_privilege (lesson_id, privilege_id) + VALUES (:lesson_id, :privilege_id)", + [ + ':lesson_id' => $id, + ':privilege_id' => $post['privilege_id'] + ] + ); + + if (isset($post['media'])) { + // update media's privileges; NOTE: media table + self::update_medias_privileges($post['media'], $post['privilege_id']); + + // set lesson's media files; NOTE: lesson_media table + // ERROR: self::create_medias_for_lesson($post['media'], $id, $post['privilege_id']); + self::create_medias_for_lesson($post['media'], $id); + + // recache media + Cache_service::files_attributes(PROXY_IGNORE_CACHE); + } + + return true; + } + + + public static function update_lesson() + { + $post = Registry::get('REQUEST')->POST; + + // print_r($post); die(); + + // update lesson's content + Registry::use('database')->query( + "UPDATE lesson + SET title = :title, + course_id = :courseid, + intro = :intro, `body` = :body, + `status` = :status + WHERE id = :id", + [ + ':id' => $post['id'], + ':title' => $post['title'], + ':courseid' => $post['course_id'], + ':intro' => $post['intro'], + ':body' => $post['body'], + ':status' => $post['status'] + ] + ); + + // update lesson's privileges + Registry::use('database')->runQuery( + "UPDATE lesson_privilege SET privilege_id = :privilege_id + WHERE lesson_id = :lesson_id", + [ + ':lesson_id' => $post['id'], + ':privilege_id' => $post['privilege_id'] + ] + ); + + if (isset($post['media'])) { + // update media's privileges + self::update_medias_privileges($post['media'], $post['privilege_id']); + } + + // remove all old lesson's links to media files + Registry::use('database')->runQuery( + "DELETE from lesson_media WHERE lesson_id = :lesson", + [ ':lesson' => $post['id'] ] + ); + + if (isset($post['media'])) { + // update lesson's media files + // ERROR: self::create_medias_for_lesson($post['media'], $post['id'], $post['privilege_id']); + self::create_medias_for_lesson($post['media'], $post['id']); + + // recache media + Cache_service::files_attributes(PROXY_IGNORE_CACHE); + } + + return true; + } + + + ## ------------------------------------------------------------------------- + ## + ## FILE METHODS + ## + ## ------------------------------------------------------------------------- + + + /** files + * echo all files + * + * @return (array) + */ + public static function files() + { + return Cache_service::files_attributes(); + } + + + /** upload_file + * upload the file to the file system + * + * the method reads the POST and FILES array + * to retrieve all needed parametres + * + * FILES @param file + * POST @param folder : lesson's ID or somthing random + * POST @param reference : reference type + * POST @param + */ + public static function upload_file() + { + $request = Registry::get('REQUEST'); + + $uploaded = self::upload_to_fs(); // upload file to file-system + + if ($uploaded['success']) { + + $media_id = self::define_media([ // define media in database; get id + 'title' => $request->POST['title'], + 'type' => $uploaded['type'], + 'path' => $uploaded['path'] + ]); + + Render::json([ // render results as json + 'success' => true, + 'id' => $media_id, + 'title' => $request->POST['title'], + 'path' => $uploaded['path'], + 'type' => $uploaded['type'] + ]); + + } else { + Render::json(['success' => false ]); + } + } + + + /** upload to fs + * upload file to File-System + * + * POST @param folder + * FILES @param file + */ + private static function upload_to_fs() + { + $post = Registry::get('REQUEST')->POST; + $files = Registry::get('REQUEST')->FILES; + + + // Checks before uploading the file + //////////////////////////////////////////////////////////////////////// + + // ** 1: file is upladed to temporary folder --------------------------- + if (! is_uploaded_file($files['file']['tmp_name'])) { + return ['success' => false]; // bye! + } + + // ** 2: File belongs to the allowed MIME types ------------------------ + $allowed_file_types = array( + 'application/pdf', + 'image/png', 'image/jpeg', + 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + // Recomended MIME type checking via mime_content_type(): + $mime_type = mime_content_type($files['file']['tmp_name']); + if (! in_array($mime_type, $allowed_file_types)) { // File type NOT allowed ... + return ['success' => false]; // bye! + } + + $file_name = $files['file']['name']; + $file_type = $files['file']['type']; // do not take it for granted + $file_size = $files['file']['size']; + $file_tmp = $files['file']['tmp_name']; + + $bare_name = pathinfo($file_name, PATHINFO_FILENAME); + $file_ext = pathinfo($file_name, PATHINFO_EXTENSION); + + + // ** 3: filename or size checks may be added -------------------------- + if ($file_name == "") { + return ['success' => false]; // bye! + } + + + // READY to finaly save/upload the file to CDN ///////////////////////// + + $folder = MEDIA_STORAGE_ROOT . $post['folder']; + if (!file_exists($folder)) { // create folder if not exists + mkdir($folder, 0757, true); + } + + // print_r([ + // 'dir' => $folder, + // 'file' => $bare_name, + // 'ext' => $file_ext, + // 'type' => $file_type + // ]); die(); + + $relative_filename = $post['folder'] + .'/' + . strtolower(self::clear_file_name($bare_name) .'.'. $file_ext); + $store_filename = MEDIA_STORAGE_ROOT . $relative_filename; + + if (move_uploaded_file($files["file"]["tmp_name"], $store_filename)) { + return [ + 'success' => true, + 'path' => $relative_filename, + 'type' => $mime_type + ]; + + } else { return ['success' => false]; } + + } + + + /** clear_file_name + * replace greek characters and strip symbols + */ + private static function clear_file_name($str) + { + $el = mb_split( "ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάέήίόύώϊϋς ", ""); + $en = str_split("ABGDEZHUIKLMNJOPRSTYFXCVabgdezhuiklmnjoprstyfxcvaehioyviys-"); + $strip = str_split("!@#$%^&*()+~`[]{};'/<>?=\""); + + return str_replace($strip, '', str_replace($el, $en, $str)); + } + + + /** define_media + * + * create a record in media table + * + * @param $data (array): [title => , path => , type => mime-type] + * @return id (int): id of created media record + */ + private static function define_media($data) + { + $request = Registry::get('REQUEST'); + + $media_id = Registry::use('database')->query( + "INSERT INTO media (label, `type`, `path`) + VALUES (:label, :mimetype, :filepath)", + [ + 'label' => $data['title'], + 'mimetype' => $data['type'], + 'filepath' => $data['path'] + ] + )->lastInsertID(); + return $media_id; + } + + + /** create media for lesson + * + * links lesson to each media-file of the media `id`s array + * + * @param $media (array): a list of media-file `id`s + * @param $lesson_id (int) + */ + private static function create_medias_for_lesson($medias, $lesson_id) + { + foreach($medias as $key => $medi) { + self::link_media_to_lesson($medi, $lesson_id); // link to lesson + } + return true; + } + + + /** create media for page + * + * links page to each media-file of the media `id`s array + * + * @param $media (array): a list of media-file `id`s + * @param $page_id (int) + */ + private static function create_medias_for_page($medias, $page_id) + { + foreach($medias as $key => $medi) { + self::link_media_to_page($medi, $page_id); // link to page + } + return true; + } + + + /** link one media-file to a specific post + * + * NOTE: + * the method does not check if media is linked already + * so be sure that the pair of (media_id,post_id) not exist + * + * @param $media_id (int) + * @param $lesson_id (int) + */ + private static function link_media_to_lesson( $media_id, $lesson_id ) + { + Registry::use('database')->runQuery( + "INSERT INTO lesson_media (lesson_id, media_id) + VALUES (:lesson, :media)", + [ + 'lesson' => $lesson_id, + 'media' => $media_id, + ] + ); + return true; + } + + /** link one media-file to a specific page + * + * NOTE: + * the method does not check if media is linked already + * so be sure that the pair of (media_id, page_id) not exist + * + * @param $media_id (int) + * @param $page_id (int) + */ + private static function link_media_to_page( $media_id, $page_id ) + { + Registry::use('database')->runQuery( + "INSERT INTO page_media (page_id, media_id) + VALUES (:page, :media)", + [ + 'page' => $page_id, + 'media' => $media_id, + ] + ); + return true; + } + + + /** update medias privileges + * + * UPDATE media SET privige WHERE IN {list} + * + * @param $medias (array) : array of media id(s) + * @param $privilege (int) : privilege id + * @return true (always) + */ + private static function update_medias_privileges($medias, $privilege) + { + // create WHERE IN (LIST) holders and params for prepare statement + $params = [ ':privilege' => $privilege]; + $holders = []; + foreach($medias as $key => $media) { + $params[':id'.$key] = $media; + $holders[] = ':id'.$key; + } + $list = '('. implode(',', $holders) .')'; + + // print_r(['params' => $params, 'list' => $list]); die(); + + Registry::use('database')->runQuery( + "UPDATE media SET privilege_id = :privilege + WHERE id IN {$list}", + $params + ); + + return true; + } + + + + + + + ## ------------------------------------------------------------------------- + ## + ## PAGE METHODS + ## + ## ------------------------------------------------------------------------- + + + /** all pages + * + */ + public static function all_pages() + { + Render::json(Registry::use('database')->runQuery( + "SELECT * FROM page", [] + )); + } + + + /** get_page + * + * @param $id (int) : page's id + */ + public static function get_page($id) + { + // get (first) page with id = $id; render as json + Render::json(Registry::use('database')->query( + "SELECT page.*, + ( SELECT + CONCAT('[', GROUP_CONCAT(JSON_OBJECT( + 'id', media.id, + 'label', media.label, + 'type', media.type, + 'path', media.path )), + ']') + FROM media + LEFT JOIN page_media ON page_media.media_id = media.id + WHERE page_media.page_id = :id + ) AS medias_json + FROM page + WHERE page.id = :id", + [ ':id' => $id] + )->getFirst()); + } + + + /** add_page + * insert a new page + * + * all parametres are passed via $_POST array + * + * POST @param title + * POST @param body + * POST @param status (int): 0 = draft , 1 = published + */ + public static function add_page() + { + $post = Registry::get('REQUEST')->POST; + + // insert page content into daabase + $id = Registry::use('database')->query( + "INSERT INTO page (title, `body`, `status`) + VALUES (:title, :body, :status)", + [ + ':title' => $post['title'], + ':body' => $post['body'], + 'status' => $post['status'] + ] + )->lastInsertID(); + + + if (isset($post['media'])) { + // update media's privileges; + // NOTE: media table; pages have public files (privilege_id=0) + self::update_medias_privileges($post['media'], 0); + + // set page's media files + // NOTE: page_media table + self::create_medias_for_page($post['media'], $id); + } + + self::update_pages_cache(); // update pages cache + + return true; + } + + + /** update_page + * + * POST @param id (int) + * POST @param title + * POST @param body + * POST @param status (int): 0 = draft , 1 = published + */ + public static function update_page() + { + $post = Registry::get('REQUEST')->POST; + + // print_r($post); die(); + + // update page's content + Registry::use('database')->query( + "UPDATE page + SET title = :title, `body` = :body, `status` = :status + WHERE id = :id", + [ + ':id' => $post['id'], + ':title' => $post['title'], + ':body' => $post['body'], + ':status' => $post['status'] + ] + ); + + if (isset($post['media'])) { + // update media's privileges + self::update_medias_privileges($post['media'], 0); + } + + // remove all old page's links to media files + Registry::use('database')->runQuery( + "DELETE from page_media WHERE page_id = :page", + [ ':page' => $post['id'] ] + ); + + if (isset($post['media'])) { + // update page's media files + self::create_medias_for_page($post['media'], $post['id']); + } + + self::update_pages_cache(); // update pages cache + + return true; + } + + + /** update pages cache + * --- -- -- - - - + * Forces re-caching of pages tree + * Shall run if anything changes to courses + * + * @param void + * @return (array): ['tree' => ..., 'breadcrumbs' => ... ] + */ + public static function update_pages_cache() + { + return Cache_service::pages_list(PROXY_IGNORE_CACHE); + } + +} \ No newline at end of file diff --git a/public/app/controllers/admin/Users_admin.php b/public/app/controllers/admin/Users_admin.php new file mode 100644 index 0000000..4e335c1 --- /dev/null +++ b/public/app/controllers/admin/Users_admin.php @@ -0,0 +1,42 @@ +runQuery( + "SELECT * FROM privilege",[] + ); + } + + /** edit privileges + * --- + */ + public static function edit_privileges() + { + // TODO: ... + } + + + /** update course + * --- + */ + public static function update_course() + { + // TODO: ... + } + +} \ No newline at end of file diff --git a/public/app/controllers/api/.gitkeep b/public/app/controllers/api/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/app/controllers/api/Common_api.php b/public/app/controllers/api/Common_api.php new file mode 100644 index 0000000..a8bd75f --- /dev/null +++ b/public/app/controllers/api/Common_api.php @@ -0,0 +1,281 @@ + data-source] pairs + * where 'label' is a friendly name of the datasource + * (and 'datasource' the actual table/data-source) + */ + public static function APITables() + { + /** allowed tables for api call + * @return: (array) an of api-call arrays + * each api-call array has the folloing form: + * [ label => [ + * 'table' => (string) actual table in database, + * (optional) 'filter' => (array) of allowed filtering fields, + * (optional) 'sort' => (array) of allowed sorting fields, + * ] + * ] + */ + return [ + 'page' => [ + 'table' => 'pages', + 'filter' => ['Title'] + ], + 'product' => [ + 'table' => 'products', + 'filter' => [ 'ID', 'Title' ], + 'sort' => ['ID'] + ], + 'category' => [ + 'table' => 'product_categories', + 'filter' => ['Title', 'Hierarchy', 'Level'] + ] + ]; + } + + + /** select anything on any (allowed table) + * + supports filtering and sorting + * check self::parse_Where_OrderBy() for options; + * sets a limti of 1000 records + */ + public static function table($table) + { + $sources = self::APITables(); + if (array_key_exists($table, $sources)) { + + $query = Registry::get('REQUEST')->QUERY; + + // Get parametres? => parse filters + if ($query !== false) { + + $parsed = self::parse_Where_OrderBy( + $query, + ($sources[$table]['filter'] ?? []), + ($sources[$table][ 'sort' ] ?? []) + ); + $where = $parsed['filter'] ? (' WHERE ' . $parsed['filter']) : ''; + $orderBy = $parsed['sort'] ? (' ORDER BY '. $parsed['sort']) : '' ; + $bindArguments = $parsed['bind']; + + } else { + $where = ''; + $orderBy = ''; + $bindArguments = []; + } + + $db = Registry::use('database'); + $result = $db->runQuery('SELECT * + FROM '. $sources[$table]['table'] + . $where + . $orderBy + .' LIMIT 1000', + $bindArguments + ); + + reply_json([ + 'success' => true, + 'client' => Registry::get('REQUEST')->SIGNATURE, + 'result' => $result + ]); + + } else { + reply_json(['success' => false]); + } + die(); + } + + + /** get record of {table} by ID + * (if table has no ID then return false) + */ + public static function record($table, $id) + { + $sources = self::APITables(); + if (array_key_exists($table, $sources)) { + + $db = Registry::use('database'); + $result = $db->runQuery("SELECT * + FROM ". $sources[$table]['table'] ." + WHERE ID = :id", + [':id' => $id] + ); + reply_json([ + 'success' => true, + 'data' => $result[0] + ]); + + } else { + reply_json(['status' => false]); + + } + die(); + } + + + /** category_by_url + * product categorie by full-friendly-URL + * @param $url (string): full friendly url + */ + public static function category_by_url($url) + { + $category = proxy( + [\app\models\market\ProductCategories_model::class, 'categoryFromUrl'], + [ $url ], CACHE_CATEGORY_TTL + ); + if ($category !== false) { + reply_json([ + 'success' => true, + 'result' => $category + ]); + + } else { + reply_json(['status' => false]); + + } + die(); + } + + /** parse Where & OrderBy + * ------------------------------------------------------------------------- + * parses SAFELY the query string to Where {CONDITIONS} and ORDER BY clauses + * according to the specified rules. + * + * The rules: + * ** filters: ?fieldname=[operator]:value &... + * where operators:[ like | startlike | endlike | eq | gt | gteq | lt |t leq ] + * + * ** Order by: ?_sort=fieldname[:[asc|desc]][,field[,]] + * + * for example: ?id=gt:4&active=1&_sort:reputation:desc,category + * parses to WHERE id > 4 AND active = 4 ORDER BY reputation desc, catetory asc + * + * ------------------------------------------------------------------------- + * arguments: + * @param $query (string): string to be parsed + * @param $filters (array): the allowed fields to apply filters + * @param $sortings (array): the allowed fields to sort the result + * @return array('filter'=>(string) , 'sort'=>(string) , 'bind'=>(array)) + */ + private static function parse_Where_OrderBy($query, $filters=[], $sortings=[]) + { + // break query to [key => value] pairs + parse_str($query, $queryArray); + + $filterClause = []; // array to hold filter/WHERE clauses + $sortClause = []; // array to hold sort/ORDER-BY caluses + $bindings = []; // array to hold variable bindigs + + // parse filers + // --------------------------------------------------------------------- + foreach($queryArray as $filter => $value) { + + if (in_array($filter, $filters)) { + + $parts = explode(':', $value ); // that is => [operator], value + if (count($parts) == 0) { + // forget it + + } else if (count($parts) == 1) { + $filterClause[] = "{$filter} = :{$filter}"; + $bindings[$filter] = $parts[0]; + + } else { + + switch ($parts[0]) { + case 'like': + $filterClause[] = "{$filter} LIKE :{$filter}"; + $bindings[':'.$filter] = '%'.$parts[1].'%'; + break; + + case 'startlike': + $filterClause[] = "{$filter} LIKE :{$filter}"; + $bindings[':'.$filter] = $parts[1].'%'; + break; + + case 'endlike': + $filterClause[] = "{$filter} LIKE :{$filter}"; + $bindings[':'.$filter] = '%'.$parts[1]; + break; + + case 'gt': + $filterClause[] = "{$filter} > :{$filter}"; + $bindings[':'.$filter] = $parts[1]; + break; + + case 'gteq': + $filterClause[] = "{$filter} >= :{$filter}"; + $bindings[':'.$filter] = $parts[1]; + break; + + case 'lt': + $filterClause[] = "{$filter} < :{$filter}"; + $bindings[':'.$filter] = $parts[1]; + break; + + case 'lteq': + $filterClause[] = "{$filter} <= :{$filter}"; + $bindings[':'.$filter] = $parts[1]; + break; + + case 'eq': + default: + $filterClause[] = "{$filter} = :{$filter}"; + $bindings[':'.$filter] = $parts[1]; + } + } + } + } + $whereSQL = ($filterClause == []) + ? false + : implode(' AND ', $filterClause); + + + // parse sort options + // --------------------------------------------------------------------- + if (isset($queryArray['_sort'])) { + $sortTerms = explode(',', $queryArray['_sort']); + + foreach($sortTerms as $term) { + + $parts = explode(':', $term); + if ($parts != [] && in_array($parts[0], $sortings) ) { + $sortClause[] = (count($parts)==1) + ? $parts[0] + : $parts[0] .' '. (($parts[1] == 'desc') ? 'desc' : 'asc'); + } + } + + } + $sortSQL = ($sortClause == []) + ? false + : implode(', ', $sortClause); + + return ([ + 'filter' => $whereSQL, + 'sort' => $sortSQL, + 'bind' => $bindings + ]); + + } + +} \ No newline at end of file diff --git a/public/app/controllers/api/Doc_api.php b/public/app/controllers/api/Doc_api.php new file mode 100644 index 0000000..e893552 --- /dev/null +++ b/public/app/controllers/api/Doc_api.php @@ -0,0 +1,34 @@ + true, 'result' => $tree ]); + die(); + } + + + public static function dbDoc() + { + $j = new Jorge(); + reply_json([ + 'success' => true, + 'result' => $j->databaseDocumentation() + ]); + die(); + + } +} \ No newline at end of file diff --git a/public/app/controllers/cli/CliContoller.php b/public/app/controllers/cli/CliContoller.php new file mode 100644 index 0000000..4549b50 --- /dev/null +++ b/public/app/controllers/cli/CliContoller.php @@ -0,0 +1,55 @@ +GET['type']; // get media-type + $real_path = MEDIA_STORAGE_ROOT . $file_path; // construct real path + + if (!file_exists($real_path)) { + Render::view('error/404'); + + } else { + Render::file($real_path, $media_type); + } + + } else { + Render::view('error/404', [ + 'error_code' => 403, + 'moto' => 'Forbidden', + 'message' => '' + ]); + } + } + + + /** get_file_attributes + * + * returns attributes of a file + * (medias are proxied for speed optimization) + * + * @param $path (string) : file path + * @return $file attributes --or-- false + */ + private static function get_file_attributes($path) + { + $medias = Cache_service::files_attributes(); + + foreach($medias as $key => $medi) { + + if ($medi['path'] == $path) { + + return $medi; + } + } + + return false; + } + + + + /** COURSES + * ------------------------------------------------------------------------- + */ + + /** course + * prepare and render the course view + * + * @param $id : course id + */ + public static function course($id) + { + $id = intval($id); // course id + + // collect all data needed for course view + // --- -- -- - - - + $cache = Cache_service::courses_struct(); + $tree = $cache['tree']; + $breadcrumbs = $cache['breadcrumbs']; + $lessons = Course_model::lessons_of_course(intval($id)); + + // find parent_ids of current category (to open the menu tree) + // --- + $course_path = []; + foreach($breadcrumbs[$id]['parents'] as $key => $parent) { + $course_path[] = intval($parent['id']); + } + $course_path[] = $id; + + // then Render + // --- -- -- - - - + Render::view('templates/course', [ + 'id' => $id, + 'title' => $breadcrumbs[ $id ]['rec']['label'], + 'categories' => $tree, + 'breadcrumbs' => $breadcrumbs, + 'lessons' => $lessons, + 'course_path' => $course_path, + // needed by footer + 'entity' => Cache_service::pages_list() + ]); + } + + + + /** LESSONS + * ------------------------------------------------------------------------ + */ + + + /** lesson + * + * check if user is authorized to view the content; + * if so, prepare and render the lesson view + * + * @param $id : lesson id + */ + public static function lesson($id) + { + $id = intval($id); // lesson id + + $lesson = Course_model::lesson($id); // get lesson + $course_id = $lesson['course_id']; // get course id + $pri_id = $lesson['privilege_id']; // privilege needed + + + if (self::is_admin_or_permited($pri_id)) { + + // collect all data needed for course view + // --- -- -- - - - + $cache = Cache_service::courses_struct(); + $tree = $cache['tree']; + $breadcrumbs = $cache['breadcrumbs']; + + // find parent_ids of current category (to open the menu tree) + // --- + $course_path = []; + foreach($breadcrumbs[$course_id]['parents'] as $key => $parent) { + $course_path[] = intval($parent['id']); + } + $course_path[] = intval($course_id); + + // NOTE: CRITICAL: + // do not pass Class::method directly to the eported variables + // $entity = Cache_service::pages_list(); + + // var_dump($entity); die(); + + // then Render + // --- -- -- - - - + Render::view('templates/lesson', [ + // main content + 'id' => $id, + 'course_id' => $course_id, + 'title' => $lesson['title'], + 'lesson' => $lesson, + // needed for side panel and breadcrunbs + 'categories' => $tree, + 'breadcrumbs' => $breadcrumbs, + 'course_path' => $course_path, + // needed by footer + 'entity' => Cache_service::pages_list() + ]); + + } else { // user is not authorized + Render::view('error/general', [ + 'title' => 'Δεν έχετε πρόσβαση', + 'message' => 'Θα πρέπει να αγοράσετε το πακέτο πρόσβασης ' + . $pri_id + .' για να δείτε το περιεχόμενο! +

+ Αγόρασε τώρα το ' + ]); + } + + } + + + /** lesson + * + * check if user is authorized to view the content; + * if so, prepare and render the lesson view + * + * @param $id : lesson id + */ + public static function page($id) + { + $id = intval($id); // lesson id + + $pages = Cache_service::pages_list(); + $page = $pages[$id]; + + // then Render + // --- -- -- - - - + Render::view('templates/page', [ + // main content + 'id' => $id, + 'page' => $page, + // needed by footer + 'entity' => $pages + ]); + + } + + + + +} \ No newline at end of file diff --git a/public/app/extends/.gitkeep b/public/app/extends/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/app/extends/Cache_service.php b/public/app/extends/Cache_service.php new file mode 100644 index 0000000..52311f3 --- /dev/null +++ b/public/app/extends/Cache_service.php @@ -0,0 +1,82 @@ +POST + * + */ + public function register_user() + { + $req = Registry::get('REQUEST'); + $register = User_model::registerUser($req->POST); + + if ($register['success']) { + + //create OTP; + $otp = $this->create_OPT($register['id']); + + // send for account confirmation + + + } else { + print_r($register); + } + + } + + + public function login_user() + { + + } + + + /** forgot password + * + * send an otp + * (then verify) + * + */ + public function forgot_password() + { + + } + + + /** create OTP + * + * create a random OTP + * keep it into User's database Table + * + * @param $id (int): user id + * + */ + public function create_OTP($id) + { + $otp = rand(100000,999999); + User_model::set_OTP($id, $otp); + + return true; + } + + + /** Verify Account + * + * check if posted OTP matched the one sent to the user + * + * @param $identity (array): pair of [index_key => identity_value] + * example: [ 'email' => 'geo@roptron.gr' ] + * + */ + public function verify_otp($identity, $otp) + { + + } + + +} \ No newline at end of file diff --git a/public/app/extends/Classroom_user.php b/public/app/extends/Classroom_user.php new file mode 100644 index 0000000..c27c4bf --- /dev/null +++ b/public/app/extends/Classroom_user.php @@ -0,0 +1,121 @@ +id; + } + + /** setID() + * + * @param int : user id + * + * @return User + */ + public function setID(int $id): self + { + $this->id = $id; + return $this; + } + + + // name + // --- -- -- - - - + + /** getName + * @return int + */ + public function getName(): string + { + return $this->name; + } + + /** setName() + * + * @param string : user's full name + * + * @return User + */ + public function setName(string $name): self + { + $this->name = $name; + return $this; + } + + + // privileges + // --- -- -- - - - + + /** getPrivileges + * + * @return privileges (array) + */ + public function getPrivileges(): array + { + return $this->privileges; + } + + + /** setPrivileges() + * + * @param array $privileges + * + * @return User + */ + public function setPrivileges(array $privileges): self + { + $this->privileges = $privileges; + return $this; + } + + +} \ No newline at end of file diff --git a/public/app/extends/Send_mail.php b/public/app/extends/Send_mail.php new file mode 100644 index 0000000..52eab53 --- /dev/null +++ b/public/app/extends/Send_mail.php @@ -0,0 +1,212 @@ + user email + * name => user full name + * subject => subject + * body => email message body + * ] + * + * then send the email; + * + * @param $activator (array): [ + * email => user email, + * name => user full name, + * code => activation code + * ] + * + * @return success_starus (boolean) + * + * TODO: + * check for email templating: + * + https://stackoverflow.com/questions/2391171/how-to-get-output-from-local-script-in-php + * + https://stackoverflow.com/questions/171318/how-do-i-capture-php-output-into-a-variable + */ + public static function send_activation_code($activator) + { + $activation_url = SITE_URL ."/account/activate?ticket=". $activator['code']; + $envelope = [ + 'email' => $activator['email'], + 'name' => $activator['name'], + 'subject' => 'Εγγραφή στο Classroom', + 'body' => "Χαίρετε,
+ το παρόν αυτοποιημένο email σάς έχει σταλεί + γιατί έχει γίνει αίτημα εγγραφής σας στο Classroom.
+
+ Όνομα επαφής: ". $activator['name'] ."
+ Email : ". $activator['email'] ."
+
+ Για να ενεργοποιήσετε την πρόσβασή σας στο site + θα πρέπει ακολουθήσετε τον παρακάτω σύνδεσμο: + ". $activation_url .". +
+
+ Μετά την ενεργοποίηση θα έχετε πρόσσβαση + στο περιεχόμενο του site.
+ Μην απαντήσετε στο email, + δεν υπάρχει φυσική επαφή η οποία να λαμβάνει τυχόν replies." + ]; + + switch (DEFAULT_MAIL_SERVICE) { + case 'mailjet': + $reply = self::send_mailjet($envelope); + break; + + case 'phpMailer': + $reply = self::send_phpMailer($envelope); + break; + } + + return $reply; + + } + + + /** send phpMailer + * + * send email using phpMailer class; + * optional SMTP server configuration; + * + * @param $envelope + * @return success_starus (boolean) + */ + public static function send_phpMailer($envelope) + { + $mail = new PHPMailer(); + + # // setup smpt + $mail->SMTPDebug = 3; + $mail->IsSMTP(); + $mail->Host = MAIL_HOST; + # $mail->SMPTAuth = false; + $mail->SMTPSecure = MAIL_ENCRYPTION; + # // $mail->Protocol = 'mail'; + + $mail->Mailer = MAIL_MAILER; + $mail->Port = MAIL_PORT; + $mail->Username = MAIL_USERNAME; + $mail->Password = MAIL_PASSWORD; + + // setup format + $mail->CharSet = 'utf-8'; + $mail->IsHTML(true); + + // setup THE mail + // --- -- -- - - - + // It's important not to use the submitter's address as the from address + // as it's forgery, which will cause your messages to fail SPF checks. + // Use an address in your own domain as the from address; + // put the submitter's address in a reply-to + + $mail->setFrom(NO_REPLY_EMAIL, MAIL_FROM_NAME); + $mail->addAddress($envelope['email'], $envelope['name']); + $mail->addReplyTo(REPLY_TO_EMAIL, MAIL_FROM_NAME); + $mail->Subject = $envelope['subject']; + $mail->Body = $envelope['body']; + + return (!$mail->send()) ? false : true; + + } + + + /** send_mailjet + * + * send email using CURL mail-relay of Mailjet + * + * @param $envelope + * @return success_starus (boolean) + */ + public static function send_mailjet($envelope) + { + $body = [ + 'Messages' => [ + [ + 'From' => [ + 'Email' => REPLY_TO_EMAIL, + 'Name' => MAIL_FROM_NAME + ], + 'To' => [ + [ + 'Email' => $envelope['email'], + 'Name' => $envelope['name'] + ] + ], + 'Subject' => $envelope['subject'], + 'HTMLPart' => $envelope['body'] + ] + ] + ]; + + $ch = curl_init(); + + curl_setopt($ch, CURLOPT_URL, "https://api.mailjet.com/v3.1/send"); + curl_setopt($ch, CURLOPT_POST, 1); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($body)); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HTTPHEADER, array( + 'Content-Type: application/json') + ); + curl_setopt( + $ch, + CURLOPT_USERPWD, + MAILJET_APIKEY. ':'. MAILJET_SECRET + ); + $server_output = curl_exec($ch); + curl_close ($ch); + + $response = json_decode($server_output); + + return ($response->Messages[0]->Status == 'success'); + + } + + + +} + + + + + +/** NOTE: + * ----------------------------------------------------------------------------- + * (brainstorming) + * + +Optimization per concept alternative technologies +--- -- -- - - - + +## Session +File Session +Database Session +Redis Session +Memcached Session + +--- + +## Cache +File Cache +Database Cache +Redis Cache +Memcashed Cache + +--- + +## Log +File Log +Database Log +Log event to Slack +Log event to Email + + * ----------------------------------------------------------------------------- + */ diff --git a/public/app/models/.gitkeep b/public/app/models/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/app/models/Jorge.php b/public/app/models/Jorge.php new file mode 100644 index 0000000..5d79007 --- /dev/null +++ b/public/app/models/Jorge.php @@ -0,0 +1,172 @@ + [], + 'relate' => [], + 'fields' => [] + ]; + + public function __construct() + { + $db = Registry::use('database'); + + // get all tables + $tableList = $db->runQuery("SHOW TABLES", []); + + // get all CREATE TABLE statements + foreach($tableList as $tableArray) { + $table = array_shift($tableArray); + $create = $db->runQuery("SHOW CREATE TABLE {$table}", []); + $this->tables['create'][$table] = $create[0]['Create Table']; + } + + // define relations + $this->tables['relate'] = [ + + 'lesson' => [ + 'course' => 'course.id = lesson.course_id', + 'lesson_media' => 'lesson_media.lesson_id = lesson.id', + 'lesson_privilege' => 'lesson_privilege.lesson_id = lesson.id' + ], + + 'page' => [ + 'page_media' => 'page_media.page_id = page.id' + ], + + 'user' => [ + 'user_privilege' => 'user_privilege.user_id = user.id' + ], + + 'privilege' => [ + 'user_privilege' => 'user_privilege.privilege_id = privilege.id' + ], + + ]; + + $this->extractTableFields(); + + // return true; + } + + + /** Create... + * one or more database tables + * --- + * @param $datasource (string|void) : table name or none + * if none then all tables will be created + * @return (boolean) + * + * NOTE: + * for safety reasons this method is not executing SQL; + * it just echoes the SQL that needs to be executed in + * order to crate all database tables. + */ + public function create($datasource = '') + { + // if no datasource passed then datasource is all tables + if ($datasource == '') { + $datasource = array_keys(self::$tables['create']); + + } else { + // if datasource exist, make it an array + if (array_key_exists($datasource, self::$tables['create'])) { + $datasource = [ $datasource ]; + + } else { + // table does not exist + return fasle; + } + } + + $sql = ""; + foreach( $datasource as $table ) { + $sql .= "-- CREATE ". $table .";\n". self::$tables['create'][$table] . "\n\n"; + } + + return ['sql' => $sql]; + } + + + /** Calculate fields of every table + * --- + * Parse every CREATE SQL statement and extract list of fields; + * Algorithm implements linear-parsing (faster than a recursive one) + */ + private function extractTableFields() + { + // words used by SQL that can not be field names + $nonFields = ['PRIMARY', 'KEY', '(', ')', 'CONSTRAINT', 'UNIQUE']; // reduced list (used on CREATE) + + foreach( $this->tables['create'] as $table => $sqlCreate ) { + + $fields = []; // variable to hold the extracted fields + + // get text between first open-parentesis and last close-parentesis + // this is waht lies between 'CREATE TABLE table(' and ') [ENGINE whatever]' + // (including the patenteses) + preg_match_all( + "/\((((?>[^()]+)|(?R))*)\)/", + str_replace("\n", '', $sqlCreate), + $match + ); + // remove 1st+last parentesis + $mainDefinitions = substr($match[0][0], 1, -1); + + // replace comma (,) on sub-parenthesis + // ex: 'decimal(18, 2)' turns to 'decimal(18: 2)' + // or: 'PRIMARY KEY (id1, id2)' turns to 'PRIMARY KEY (id1: id2)' + $sentences = preg_replace( + '/\\(([0-9a-zA-Z_`]*)[ ,]([0-9a-zA-Z_` ]*)\\)/', + '($1:$2)', + $mainDefinitions, + -1 + ); + + // devide the banth of sentences to field definitions + $defines = explode(',', $sentences); + + // now each denine holds a full field definition + // like: `ID` int(11) NOT NULL AUTO_INCREMENT + + foreach($defines as $def) { + // check the first term of each sentence + $terms = explode(' ', trim($def,)); + $term = array_shift($terms); + + if (!in_array($term, $nonFields)) { + $fields[ str_replace('`', '', $term) ] = implode(' ', $terms); + } + } + + $this->tables['fields'][$table] = $fields; + } + + return; + } + + public function databaseDocumentation() + { + return $this->tables['fields']; + } + +} \ No newline at end of file diff --git a/public/app/models/_info.md b/public/app/models/_info.md new file mode 100644 index 0000000..5504523 --- /dev/null +++ b/public/app/models/_info.md @@ -0,0 +1,150 @@ + +# info about the structrure of the models + +According to the former impementation (atcom) the project will need to handle 200+ tables. +The former project includes 209 tables with 5 or more rows (and 325 tables totaly) + + + +## Database schema + +Main tables and recomended constraints: + +``` +SET NAMES utf8; +SET time_zone = '+00:00'; +SET foreign_key_checks = 0; +SET sql_mode = 'NO_AUTO_VALUE_ON_ZERO'; + +SET NAMES utf8mb4; + +DROP TABLE IF EXISTS `course`; +CREATE TABLE `course` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `parent_id` int(11) NOT NULL COMMENT 'if 0 then this is a root course', + `label` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `lesson`; +CREATE TABLE `lesson` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `course_id` int(11) NOT NULL, + `title` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, + `body` text COLLATE utf8mb4_unicode_ci NOT NULL, + `published` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0 = unpublished, 1 = published', + PRIMARY KEY (`id`), + KEY `course_id` (`course_id`), + CONSTRAINT `lesson_ibfk_1` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`), + CONSTRAINT `lesson_ibfk_2` FOREIGN KEY (`course_id`) REFERENCES `course` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `lesson_media`; +CREATE TABLE `lesson_media` ( + `lesson_id` int(11) NOT NULL, + `media_id` int(11) NOT NULL, + PRIMARY KEY (`lesson_id`,`media_id`), + KEY `media_id` (`media_id`), + CONSTRAINT `lesson_media_ibfk_1` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), + CONSTRAINT `lesson_media_ibfk_2` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), + CONSTRAINT `lesson_media_ibfk_3` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), + CONSTRAINT `lesson_media_ibfk_4` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`), + CONSTRAINT `lesson_media_ibfk_5` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`) ON DELETE NO ACTION, + CONSTRAINT `lesson_media_ibfk_6` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`) ON DELETE NO ACTION, + CONSTRAINT `lesson_media_ibfk_7` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`) ON DELETE NO ACTION, + CONSTRAINT `lesson_media_ibfk_8` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`) ON DELETE NO ACTION +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `lesson_privilege`; +CREATE TABLE `lesson_privilege` ( + `lesson_id` int(11) NOT NULL, + `privilege_id` int(11) NOT NULL COMMENT 'minimum privilege required to access the lesson', + KEY `lesson_id` (`lesson_id`), + KEY `privilege_id` (`privilege_id`), + CONSTRAINT `lesson_privilege_ibfk_1` FOREIGN KEY (`lesson_id`) REFERENCES `lesson` (`id`), + CONSTRAINT `lesson_privilege_ibfk_2` FOREIGN KEY (`privilege_id`) REFERENCES `privilege` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `media`; +CREATE TABLE `media` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `label` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, + `type` varchar(64) COLLATE utf8mb4_unicode_ci NOT NULL, + `path` varchar(320) COLLATE utf8mb4_unicode_ci NOT NULL, + `referable` tinyint(4) NOT NULL DEFAULT '1' COMMENT '0 = hidden, 1 = referable', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `page`; +CREATE TABLE `page` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `title` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, + `body` text COLLATE utf8mb4_unicode_ci NOT NULL, + `published` tinyint(4) NOT NULL DEFAULT '0' COMMENT '0 = unpublished; 1 = published', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `page_media`; +CREATE TABLE `page_media` ( + `page_id` int(11) NOT NULL, + `media_id` int(11) NOT NULL, + KEY `page_id` (`page_id`), + KEY `media_id` (`media_id`), + CONSTRAINT `page_media_ibfk_1` FOREIGN KEY (`page_id`) REFERENCES `page` (`id`) ON DELETE NO ACTION, + CONSTRAINT `page_media_ibfk_2` FOREIGN KEY (`media_id`) REFERENCES `media` (`id`) ON DELETE NO ACTION +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `privilege`; +CREATE TABLE `privilege` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `alias` varchar(8) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT 'keep it simple; use latin', + `label` varchar(140) COLLATE utf8mb4_unicode_ci NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `alias` (`alias`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `privilege_inherit`; +CREATE TABLE `privilege_inherit` ( + `higher_id` int(11) NOT NULL COMMENT 'higher priviledges inherit (include) lower ones', + `lower_id` int(11) NOT NULL, + PRIMARY KEY (`higher_id`,`lower_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `user`; +CREATE TABLE `user` ( + `id` int(11) NOT NULL AUTO_INCREMENT, + `first_name` int(11) NOT NULL, + `last_name` int(11) NOT NULL, + `email` int(11) NOT NULL, + `expiration` int(11) NOT NULL COMMENT 'account expiration date; 0 = never', + `password` int(11) NOT NULL, + `salt` int(11) NOT NULL, + `otp` int(11) NOT NULL COMMENT 'one time password for reset password', + `otp_expiration` int(11) NOT NULL, + `active` int(11) NOT NULL COMMENT 'account flag; 1=active, 0=inactive', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + + +DROP TABLE IF EXISTS `user_privilege`; +CREATE TABLE `user_privilege` ( + `user_id` int(11) NOT NULL, + `privilege_id` int(11) NOT NULL, + PRIMARY KEY (`user_id`,`privilege_id`), + KEY `privilege_id` (`privilege_id`), + CONSTRAINT `user_privilege_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `user` (`id`), + CONSTRAINT `user_privilege_ibfk_2` FOREIGN KEY (`privilege_id`) REFERENCES `privilege` (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci; + +``` + + diff --git a/public/app/models/admin/History_model.php b/public/app/models/admin/History_model.php new file mode 100644 index 0000000..04ce630 --- /dev/null +++ b/public/app/models/admin/History_model.php @@ -0,0 +1,34 @@ +query( + "INSERT INTO history + (user_id, `type`, `message`, `note`, `ip`) + VALUES + (:uid, :type, :msg, :note, :ip)", + [ + ':uid' => $user_id, + ':type' => $type, + ':msg' => $message, + ':note' => $note, + ':ip' => Registry::get('REQUEST')->IP + ] + )->lastInsertID(); + + } + + + +} \ No newline at end of file diff --git a/public/app/models/admin/Privilege_model.php b/public/app/models/admin/Privilege_model.php new file mode 100644 index 0000000..c385484 --- /dev/null +++ b/public/app/models/admin/Privilege_model.php @@ -0,0 +1,42 @@ +runQuery( + "SELECT * FROM privilege",[] + ); + } + + /** edit privileges + * --- + */ + public static function edit_privileges() + { + // TODO: ... + } + + + /** update course + * --- + */ + public static function update_course() + { + // TODO: ... + } + +} \ No newline at end of file diff --git a/public/app/models/admin/User_model.php b/public/app/models/admin/User_model.php new file mode 100644 index 0000000..2885dc1 --- /dev/null +++ b/public/app/models/admin/User_model.php @@ -0,0 +1,299 @@ +query( + "SELECT * FROM user WHERE email = :email AND active = 1", + [ ':email' => $email ] + )->getFirst(); + + // if no user, return false + if ($user === false) return false; + + return $user; + } + + + /** get user (by index key) + * + * user detailed array + * includes all user properties + granted roles + privileges + * + * @param $id (int) : user id + * @param $value (string) + */ + public static function getUser($id) + { + $user = Registry::use('database')->query( + "SELECT user.*, + ( -- construct array (json) of roles granted to user + SELECT CONCAT( + '[', + GROUP_CONCAT(role.id), + ']' + ) + FROM `role` + WHERE role.id IN ( + SELECT user_role.role_id + FROM user_role + WHERE user_role.user_id = :id + ) + ) AS Roles_json, + ( -- construct array of (root-)privileges granted to user + SELECT CONCAT( + '[', + GROUP_CONCAT(privilege.id), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_privilege.user_id = :id + ) + ) AS RootPrivileges_json, + ( -- construct array of (root-)privileges granted to user + SELECT CONCAT( + '[', + GROUP_CONCAT(privilege.includes), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_privilege.user_id = :id + ) + ) AS SubPrivileges_json + FROM user + WHERE id = :id", + [ ':id' => $id ] + )->getFirst(); + + + // if no user, return false + if ($user === false) return false; + + + // TODO: + // * merge root+sub privilede lists + // * convert json strings to php arrays + + + // TODO: + // cache user super array + + return $user; + } + + + /** create user + * + * creates user record; + * assigns privileged (usualy defaults); + * creates activation_code + * + * @param $data (array): Request->POST array + * @param $password (string): secure hashed password + * + * @return $activation_code + * + */ + public static function registerUser($data, $password, $privileges = DEFAULT_PRIVILEGES) + { + $required_fields = [ + 'name', + 'surname', + 'email', + 'password' + ]; + + // check required fields + $isOK = true; + foreach($required_fields as $fi) { + if (empty($data[$fi])) $isOK = false; + } + // if empty required fields exists ... return false + if (!$isOK) { + return [ "success" => false, 'error' => EMPTY_REQUIRED_FIELDS ]; + } + + + // TODO: + // check if email exists + // ... + + // create an activation code + $activation_code = md5($data['email'].time().rand(0, 10000)); + + // if isOK go on and... + // create user record + $new_user_id = Registry::use('database')->query( + "INSERT INTO user + (`first_name`, `last_name`, `email`, `password`, `active`, `activation`) + VALUES + (:nam, :surname, :email, :pass, :act, :actcode)", + [ + ':nam' => $data['name'], + ':surname' => $data['surname'], + ':email' => $data['email'], + ':pass' => $password, + ':act' => 0, // needs email confirmation to be activated ... + ':actcode' => $activation_code // ... with the activation code + ] + )->lastInsertID(); + + // set default privileges + self::set_user_privileges($new_user_id, $privileges); + + // set reader role + self::set_user_role($new_user_id, 5); + + // update history + History::trackUserAccess($new_user_id, TRACK_ACCOUNT, 'Create User Account'); + + // return success and user id + return [ + "success" => true, + 'id' => $new_user_id , + 'activation' => $activation_code + ]; + } + + + /** set_user_privileges + * + * @param $privileges (array) + */ + public static function set_user_privileges($user, $privileges) + { + $db = Registry::use('database'); // database connection + foreach($privileges as $pri) { // pri = privilege id + $db->runQuery( + "INSERT INTO user_privilege (user_id, privilege_id) VALUES (:user, :pri)", + [ ':user' => $user, ":pri" => $pri ] + ); + } + return true; + } + + + /** set_user_role + * + * user, role are (int) IDs + */ + public static function set_user_role($user, $role) + { + + Registry::use('database')->runQuery( + "INSERT INTO user_role (user_id, role_id) VALUES (:user, :role)", + [ ':user' => $user, ":role" => $role ] + ); + + return true; + } + + + /** activate + * + * check if activation code is valid; + * if valid, set account active; + * + * @param $ticket (hex/MD5): activation code; + * + */ + public static function activate($ticket) + { + $user = Registry::use('database')->query( + "SELECT * FROM user WHERE activation = :ticket", + [ 'ticket' => $ticket ] + )->getFirst(); + + // if no user with this activation code, return false + if ($user === false) return false; + + // remove activation code from user record + Registry::use('database')->runQuery( + "UPDATE user + SET active = 1, `activation` = NULL + WHERE activation = :ticket", + [ 'ticket' => $ticket ] + ); + + // update history + History::trackUserAccess($user['id'], TRACK_ACCOUNT, 'User Account Activated'); + + return true; + + } + + +} + +/* example query getUser (super-array) +--- -- -- - - - + +SELECT user.*, +( -- array (json) of roles granted to user + SELECT CONCAT('[', GROUP_CONCAT(role.id), ']') + FROM `role` + WHERE role.id IN ( + SELECT user_role.role_id + FROM user_role + WHERE user_role.user_id = 1 + ) +) AS Roles_json, +( + SELECT CONCAT( + '[', + GROUP_CONCAT(privilege.id), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_privilege.user_id = 1 + ) +) AS RootPrivileges_json, +( + SELECT CONCAT( -- array of array of sub-privileges + '[', + GROUP_CONCAT( -- array (json) of subprivileges + ( + SELECT CONCAT( + '[', + GROUP_CONCAT(included_id), + ']' + ) + FROM privilege_includes + WHERE privilege_id = privilege.id + ) + ), + ']' + ) + FROM privilege + WHERE privilege.id IN ( + SELECT user_privilege.privilege_id + FROM user_privilege + WHERE user_id = 1 + ) +) AS SubPrivileges_json +FROM user +WHERE id = 1 +--- */ \ No newline at end of file diff --git a/public/app/models/cms/Course_model.php b/public/app/models/cms/Course_model.php new file mode 100644 index 0000000..6614993 --- /dev/null +++ b/public/app/models/cms/Course_model.php @@ -0,0 +1,314 @@ +runQuery( + "SELECT * FROM course ORDER BY label", + [] + ); + } + + /** courses struct + * + * a super array with almost any info needed about courses + * + * @return (array) ['tree' => ..., 'breadcrumbs' => ... ] + */ + public static function courses_struct() + { + $tree = self::category_tree(); + return [ + 'tree' => $tree, + 'breadcrumbs' => self::breadcrumbs($tree) + ]; + } + + + /** constuct a category_tree + * + * returns a tree representation of the categories + * + * NOTE: + * category_tree() is an expensive method; + * it calls 2 other methods implementing recursive algorithms + * thus it uses many sources to run (particularly RAM). + * Caching the result is strogly recommended. + * + */ + public static function category_tree() + { + $categories = self::get_categories(); // get all categories + + $tree = self::to_tree($categories); // format to a tree + + $tree_wParents = self::tree_parents($tree); // add parents section for each tree-node + + return $tree_wParents; + } + + + /** to_tree + * + * constructs a tree from raw-table data; + * this is a private method and uses a recursive algorithm + * + * @param $dataset (array): flar array of records with id/parent-id pairs + * @return $root (array): id of root category + * + * (**) each node has 2 parts: + * .... .. rec : all record attributes/data as passed into $dataset + * .... .. childs : array of (children) nodes + */ + private static function to_tree($dataset, $root = 0) + { + $return = []; + + // loop data ; search for direct children of root + foreach($dataset as $key => $rec) { + + $child = $rec['id']; + $parent = $rec['parent_id']; + + if ($parent == $root) { // a direct child is found + + unset($dataset[$key]); // remove item (no need to traverse again) + + // Append the child into result array ; parse its children + $return[] = [ + 'rec' => [ + 'id' => $rec['id'], + 'label' => $rec['label'], + 'order' => $rec['order'], + 'parent' => $rec['parent_id'] + ], + 'childs' => self::to_tree($dataset, $child) // recursively + ]; + } + } + return empty($return) ? [] : $return; + } + + + /** tree_parents + * + * adds a section to each tree node with all parents of each node + * + * @param $tree (array) : nodes array (each node has `rec` and `childs` sections ) + * @param $parents (array); DO NOT SET IT (takes values automaticaly) + * @return array of nodes with an extra node[parents] section + * + */ + private static function tree_parents($tree, $parents = []) + { + $tree_with_parents = []; + + foreach($tree as $key => $node) { + // parents to be pushed for node's children + $push_parents = $parents; // parents so far + $push_parents[] = $node['rec']; // this record will be a new parent + + $tree_with_parents[$key] = [ + 'rec' => $node['rec'], + 'parents' => $parents, + 'childs' => ($node['childs'] == []) + ? [] + : self::tree_parents($node['childs'], $push_parents) + ]; + } + + return $tree_with_parents; + } + + + /** all_breadcrumbs + * ------------------------------------------------------------------------- + * + * returns an array of all breadcrumbs + * where array-key of each record is category[id] + * + * NOTE: + * --- + * Course_model::all_breadcrumbs returns an indexed super-array; + * each array item includes a banch of information: [ + * breadcrumb, + * rec: [ id , title ], + * parents: [ [id, title] , ... ] + * childs: [ [id, title] , ... ], + * level + * ] + * + * Use Cases: + * --- + * as a super-array, the output can be used in many cases + * for example... + * into form elements + * .. while selecting category for a post + * .. or editing a category + * or directry referring to category's parents/childs + * + * Arguments: + * --- + * @param $tree (array) : category tree (with childs and parents parts) + * @param $detimiter (string, optional) : string to split breadcrumb's path-nodes + * @param $exception (int, optional) : id of category to exclude (subcategories shall be excluded too) + * @param $l (int, not-pass) : depth level of the node; DO NOT SET (takes values automaticaly) + * @return array of breadcrumbs + * ------------------------------------------------------------------------- + */ + static public function breadcrumbs($tree, $delimiter = " / ", $exception = 0, $l = 0) + { + $all = []; // results array + + foreach($tree as $node) { // loop through all nodes + + if (intval($node['rec']['id']) != $exception) { // if node is not exception + + // construct breadcrumb html of node + // --- -- -- - - - + $breadcrumb = ""; + foreach($node['parents'] as $par) { // first: join path titles + $breadcrumb .= $par['label'] . $delimiter; + } + $breadcrumb .= $node['rec']['label']; // last: append title + + // make a new super record + // --- -- -- - - - + $all[$node['rec']['id']] = [ // set record is as key + 'breadcrumb' => $breadcrumb, // add breadcrump to results + 'rec' => $node['rec'], // + node info + 'parents' => $node['parents'], // + parents array + 'childs' => self::first_level_childs($node), // + direct childs + 'level' => $l // + level + ]; + + // recursively traverse children nodes + // --- -- -- - - - + if (isset($node['childs']) && $node['childs'] != []) { + $child_breadcrumbs = self::breadcrumbs( + $node['childs'], + $delimiter, + $exception, + $l+1 + ); + + $all = $all + $child_breadcrumbs; // concatenate arrays (keep array-keys) + } + } + + } + return $all; + + } + + /** first_level_childs + * --- -- -- - - - + * used by all_breadcrumbs() + */ + static private function first_level_childs($node) + { + $childs = []; + if ($node['childs'] == []) { + return []; + } + foreach($node['childs'] as $key => $kid) { + $childs[] = [ + 'id' => $kid['rec']['id'], + 'label' => $kid['rec']['label'] + ]; + } + return $childs; + } + + + + + /** LESSONS + * ------------------------------------------------------------------------- + */ + + + /** lessons of course + * + * @param $id (int) : course_id + */ + public static function lessons_of_course($id) + { + // TODO: order results in some way + + return Registry::use('database')->runQuery( + "SELECT lesson.*, lesson_privilege.privilege_id FROM lesson + LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id + WHERE lesson.status = 1 AND lesson.course_id = :id + ORDER BY lesson_privilege.privilege_id ASC", + [':id' => $id] + ); + } + + /** lesson + * + * @param $id (int) : lesson id + */ + public static function lesson($id) + { + // TODO: order results in some way + + return Registry::use('database')->query( + "SELECT lesson.*, lesson_privilege.privilege_id FROM lesson + LEFT JOIN lesson_privilege ON lesson_privilege.lesson_id = lesson.id + WHERE lesson.status = 1 AND lesson.id = :id", + [':id' => $id] + )->getFirst(); + } + + + + /** files + * return all files + * @param void + * @return array + */ + public static function files() + { + return Registry::use('database')->runQuery("SELECT * from media", []); + } + + + /** pages + * + * return all pages as array; + * array key of each item shall be the page-id + * + * @param void + * @return array + */ + public static function pages() + { + $result = []; + $pages = Registry::use('database')->runQuery("SELECT * FROM page", []); + foreach($pages as $key => $page) { + $result[ $page['id'] ] = [ + 'title' => $page['title'], + 'body' => $page['body'], + 'status' => $page['status'] + ]; + } + // print_r($result); die(); + return $result; + } + +} diff --git a/public/app/models/cms/Media_model.php b/public/app/models/cms/Media_model.php new file mode 100644 index 0000000..6a4a681 --- /dev/null +++ b/public/app/models/cms/Media_model.php @@ -0,0 +1,36 @@ +, rights =>, path => ] + + // validate ticket + // ValidateAccess::for($ticket) + + // serve + // header("Content-type: type"); + // passthru('cat $media_path'); + + + return Registry::use('database')->query( + "SELECT * FROM pages + WHERE FullFriendlyUrl = :url AND IsActive = 1", + [ ':url' => $url ] + )->getFirst(); + } + +} + + + +// check: +// https://stackoverflow.com/questions/1353850/serve-image-with-php-script-vs-direct-loading-an-image \ No newline at end of file diff --git a/public/app/models/cms/Page_model.php b/public/app/models/cms/Page_model.php new file mode 100644 index 0000000..fda5fb1 --- /dev/null +++ b/public/app/models/cms/Page_model.php @@ -0,0 +1,18 @@ +query( + "SELECT * FROM pages + WHERE FullFriendlyUrl = :url AND IsActive = 1", + [ ':url' => $url ] + )->getFirst(); + } + +} \ No newline at end of file diff --git a/public/app/models/market/Market_repository.php b/public/app/models/market/Market_repository.php new file mode 100644 index 0000000..1338426 --- /dev/null +++ b/public/app/models/market/Market_repository.php @@ -0,0 +1,235 @@ + "SELECT * FROM cars WHERE age = :Age" + * ... won't make your code sexier nor easier to read; it will just increase + * your label's entropy and make trickier to pick your next sensable label; + * + * repository classes include two methods (inherited by the abstract, so + * you do not need to implement something more than just construct + * the $repository array) + * ** pull: for pulling a query by a friendly name + * ** echo: optional method used by some devolopment tools + * + * TODO: development tool using echo is still in progress + */ +class Market_repository extends Repository +{ + //// use Repository; // repository trait includes + //// // a method to pull an entity of the gathering + //// // and method to (TODO:) ... + + /** repository is an array of Prepare SWL queries; + * each query is attached to the array via a friendly label; + * + * NOTE: (PROPOSAL) + * --- + * about the label: + * 1. keep names short descriptive but not too long + * 2. main entity/entities shall be UPPERCASED + * 3. determinands/adjectives shall be Cappitalized + * 4. words are connected with underscore (_) + * 5. if SQL inludes bind-holderd, label shall be suffixed with '_by:' + * followed by holder names connected with undercores (case-sensitively) + * + * about the data-bind holders (if present): + * 1. all holders are prefixed with ':' + * 2. holder name shall begin with a letter and contain one word. + * + * example: + * 'Active_EMPLOYEES_by:Age_CityID' => "SELECT Em.*, c.* + * FROM employee Em LEFT JOIN city c ON c.id = Em.city_id + * WHERE c.id = :CityID AND Em.age = :Age" + * + * It is recommended to leave a descriptive comment befor each declaration + * and you may also include sql-comments inside the query. + */ + public static $repository = [ + + // PRODUCTS by: storeID, ProductUrl + // picks all product properties + // + default image + price for certain store + 'Active_PRODUCT_by:storeID_ProductUrl' => + "SELECT p.*, + pc.ID AS ProductCategory, + pc.Hierarchy, + pc.FullFriendlyUrl AS `Path`, + prices.ProductPrice_OriginalPrice AS Price, + prices.ProductPrice_DiscountedPrice AS DiscountPrice, + prices.UnitMeasurePrice_OriginalPrice AS PerUnitPrice, + prices.UnitMeasurePrice_DiscountedPrice AS PerUnitDiscountPrice, + b.Title BrandName + FROM products p + LEFT JOIN products_to_product_categories p2pc ON p.ID = p2pc.SimpleProductID + LEFT JOIN product_categories pc ON p2pc.ProductCategoryID = pc.ID + LEFT JOIN prices ON p.SKU = prices.SKU + LEFT JOIN products_to_images p2i ON p2i.SimpleProductID = p.ID + LEFT JOIN assets ON assets.ID = p2i.ImageID + LEFT JOIN brands b ON b.ID = p.BrandID + WHERE pc.IsActive = 1 AND pc.IsCurrentlyActive = 1 + AND p2i.Order = 1 + AND p.IsActive = 1 + AND p.Published = 1 + AND prices.PriceListID = :storeID + AND p.FriendlyUrl = :ProductUrl" + , + + // PRODUCTS by: storeID, ProductID + // picks all product properties + // + default image + price for certain store + 'Active_PRODUCT_by:storeID_ProductID' => + "SELECT p.*, + pc.ID AS ProductCategory, + pc.Hierarchy, + pc.FullFriendlyUrl AS `Path`, + prices.ProductPrice_OriginalPrice AS Price, + prices.ProductPrice_DiscountedPrice AS DiscountPrice, + prices.UnitMeasurePrice_OriginalPrice AS PerUnitPrice, + prices.UnitMeasurePrice_DiscountedPrice AS PerUnitDiscountPrice, + b.Title BrandName + FROM products p + LEFT JOIN products_to_product_categories p2pc ON p.ID = p2pc.SimpleProductID + LEFT JOIN product_categories pc ON p2pc.ProductCategoryID = pc.ID + LEFT JOIN prices ON p.SKU = prices.SKU + LEFT JOIN products_to_images p2i ON p2i.SimpleProductID = p.ID + LEFT JOIN assets ON assets.ID = p2i.ImageID + LEFT JOIN brands b ON b.ID = p.BrandID + WHERE pc.IsActive = 1 AND pc.IsCurrentlyActive = 1 + AND p2i.Order = 1 + AND p.IsActive = 1 + AND p.Published = 1 + AND prices.PriceListID = :storeID + AND p.ID = :ProductID" + , + + // CATEGORY-PRODUCTS by: storeID, likeHierarchy + // traverses all products from category and subcategories + // picke price and default image + 'CATEGORY-PRODUCTS_by:storeID_likeHierarchy' => + "SELECT p.*, + assets.Url AS ImageUrl, + pc.FullFriendlyUrl AS `Path`, + prices.ProductPrice_OriginalPrice AS Price, + prices.ProductPrice_DiscountedPrice AS DiscountPrice, + prices.UnitMeasurePrice_OriginalPrice AS PerUnitPrice, + prices.UnitMeasurePrice_DiscountedPrice AS PerUnitDiscountPrice + FROM products p + LEFT JOIN prices ON p.SKU = prices.SKU + LEFT JOIN products_to_product_categories p2pc ON p2pc.SimpleProductID = p.ID + LEFT JOIN product_categories pc ON pc.ID = p2pc.ProductCategoryID + LEFT JOIN products_to_images p2i ON p2i.SimpleProductID = p.ID + LEFT JOIN assets ON assets.ID = p2i.ImageID + WHERE p2pc.ProductCategoryID IN ( + SELECT `ID` FROM product_categories + WHERE Hierarchy LIKE :likeHierarchy + ) + AND p2i.Order = 1 + AND p.IsActive = 1 + AND p.Published = 1 + AND prices.PriceListID = :storeID" + , + + // Count Products + // of all last-lever Product categories + // by StoreID + // --- + // used on creating product_categories tree + // ProductCategories_model::tree() + 'Count_Last_Level_PRODUCTS_by:storeID' => + "SELECT pc.ID, COUNT(p.ID) as `Counter` + FROM product_categories pc + LEFT JOIN products_to_product_categories p2pc ON pc.ID = p2pc.ProductCategoryID + LEFT JOIN products p ON p2pc.SimpleProductID = p.ID + LEFT JOIN prices ON p.SKU = prices.SKU + LEFT JOIN products_to_images p2i ON p2i.SimpleProductID = p.ID + LEFT JOIN assets ON assets.ID = p2i.ImageID + WHERE pc.IsActive = 1 AND pc.IsCurrentlyActive = 1 + AND p2i.Order = 1 + AND pc.Level = 2 + AND p.IsActive = 1 + AND p.Published = 1 + AND prices.PriceListID = :storeID + GROUP BY pc.ID" + , + + // PRODUCT by: ProductID + // Join images array (json string) + // Join prices for all stores (json string) + 'Active_PRODUCT_complete_by:ProductID' => + "SELECT p.*, pc.ID AS ProductCategory, + pc.Hierarchy, pc.FullFriendlyUrl AS `Path`, + ( -- get all store prices as Json + SELECT JSON_ARRAYAGG(JSON_OBJECT( + 'Store', prices.PriceListID, + 'Price', prices.ProductPrice_OriginalPrice, + 'DiscountPrice', prices.ProductPrice_DiscountedPrice, + 'PerUnitPrice', prices.UnitMeasurePrice_OriginalPrice, + 'PerUnitDiscountPrice', prices.UnitMeasurePrice_DiscountedPrice + )) + FROM prices + WHERE prices.SKU = p.SKU + ) as pricesJson, + ( -- get all images as Json + SELECT JSON_ARRAYAGG(JSON_OBJECT( + 'Order', p2i.Order, + 'Url', assets.Url, + 'Title', assets.Title, + 'Description', assets.Description + )) + FROM products_to_images p2i + LEFT JOIN assets ON assets.ID = p2i.ImageID + WHERE p2i.SimpleProductID = p.ID + ) AS imagesJson, + b.Title BrandName + FROM products p + LEFT JOIN products_to_product_categories p2pc ON p.ID = p2pc.SimpleProductID + LEFT JOIN product_categories pc ON p2pc.ProductCategoryID = pc.ID + LEFT JOIN products_to_images p2i ON p2i.SimpleProductID = p.ID + LEFT JOIN assets ON assets.ID = p2i.ImageID + LEFT JOIN brands b ON b.ID = p.BrandID + WHERE pc.IsActive = 1 AND pc.IsCurrentlyActive = 1 + AND p2i.Order = 1 + AND p.IsActive = 1 + AND p.Published = 1 + AND p.ID = :ProductID" + , + + // Product images by: ProductID + // (sorted by 'order' field) + 'PRODUCT_IMAGES_by:productID' => + "SELECT a.Url, a.Title, a.Description + FROM products p + LEFT JOIN products_to_images p2i ON p2i.SimpleProductID = p.ID + LEFT JOIN assets a ON a.ID = p2i.ImageID + WHERE p.IsActive = 1 + AND p.Published = 1 + AND p.ID = :productID + ORDER BY p2i.Order" + + ]; + + /* no need to impement anything else; + * you can overide if needed the default methods: + * + public static function pull($entity){ } + * + public static function echo($content =false){ } + */ + +} diff --git a/public/app/models/market/Payment_template.txt b/public/app/models/market/Payment_template.txt new file mode 100644 index 0000000..4a66a1a --- /dev/null +++ b/public/app/models/market/Payment_template.txt @@ -0,0 +1,98 @@ +class WC_Piraeusbank_Gateway extends WC_Payment_Gateway { + + public function __construct() + + function pb_get_pages($title = false, $indent = true) + + function pb_get_installments($title = false, $indent = true) + + function generate_piraeusbank_form($order_id) + + function process_payment($order_id) + + function receipt_page($order) + + function check_piraeusbank_response() + + function piraeusbank_message() + + function woocommerce_add_piraeusbank_gateway($methods) + + function piraeusbank_plugin_action_links($links, $file) + +} + + + +class WC_NBG_Gateway extends WC_Payment_Gateway { + + public function __construct() + + public function admin_options() + + function init_form_fields() + + function nbg_get_pages($title = false, $indent = true) + + function nbg_get_installments($title = false, $indent = true) + + function generate_nbg_form($order_id) + + function process_payment($order_id) + + function receipt_page($order) { + + function check_nbg_response() + + function nbg_message() + + function woocommerce_add_nbg_gateway($methods) + + function nbg_plugin_action_links($links, $file) + +} + + + +global $wc; + + $this->id = 'nbg_gateway'; + $this->icon = apply_filters('nbg_icon', plugins_url('assets/nbg.png', __FILE__)); + $this->has_fields = false; + $this->notify_url = WC()->api_request_url('WC_NBG_Gateway'); + $this->method_description = __('National Bank Greece Payment Gateway allows you to accept payment through various channels such as Maestro, Mastercard and Visa cards On your Woocommerce Powered Site.', 'woocommerce-nbg-payment-gateway'); + $this->redirect_page_id = $this->get_option('redirect_page_id'); + $this->method_title = 'National Bank of Greece Gateway'; + + // Load the form fields. + $this->init_form_fields(); + + //dhmioyrgia vashs + + global $wpdb; + + if ($wpdb->get_var("SHOW TABLES LIKE '" . $wpdb->prefix . "nbg_transactions'") === $wpdb->prefix . 'nbg_transactions') { + // The database table exist + } else { + // Table does not exist + $query = 'CREATE TABLE IF NOT EXISTS ' . $wpdb->prefix . 'nbg_transactions (id int(11) unsigned NOT NULL AUTO_INCREMENT,merchantreference varchar(30) not null, reference varchar(100) not null, orderid varchar(100) not null , timestamp datetime default null, PRIMARY KEY (id))'; + $wpdb->query($query); + } + + + // Load the settings. + $this->init_settings(); + + + // Define user set variables + $this->title = $this->get_option('title'); + $this->description = $this->get_option('description'); + $this->nbg_Username = $this->get_option('nbg_Username'); + $this->nbg_Password = $this->get_option('nbg_Password'); + + $this->nbg_description= $this->get_option('nbg_description'); + $this->mode = $this->get_option('mode'); + $this->nbg_installments= $this->get_option('nbg_installments'); + //Actions + add_action('woocommerce_receipt_nbg_gateway', array($this, 'receipt_page')); + add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this diff --git a/public/app/models/market/ProductCategories_model.php b/public/app/models/market/ProductCategories_model.php new file mode 100644 index 0000000..d8c274e --- /dev/null +++ b/public/app/models/market/ProductCategories_model.php @@ -0,0 +1,199 @@ +query( "SELECT * FROM product_categories + WHERE FullFriendlyUrl = :url AND IsActive = 1", + [ ':url' => $url ] + )->getFirst(); + + if ($category === false) { return false; } // no category? -> false + + // GET PRODUCTS of category + $category['products'] = self::categoryProductsByHierarchy($category['Hierarchy']); + return $category; + } + + + /** Get (product_) category from ID + * --- (self explanatory) + * @param $id (int): Catgory ID (usualy from products) + * @return $category (array); also includes all category products + */ + public static function categoryFromID($id) + { + return Registry::use('database')->query( "SELECT * FROM product_categories + WHERE `ID` = :url AND IsActive = 1", + [':id' => $id] + )->getFirst(); + + } + + + /** categoryProductsByHierarchy + * --- + * This method returns the products belonging to a certain + * category (and all it's the children/sub-categories); + * It uses category.Hierarchy in a WHERE LIKE condition to + * make it fast. + * + * The method is category.Level agnostic + * + * @param $category (array) + * @return $products (array) + */ + public static function categoryProductsByHierarchy($hierarchy, $store = 904) + { + // GET PRODUCTS of category + // NOTE: + // category.Hierarchy is used + + return Registry::use('database')->runQuery( + Market_repository::pull('CATEGORY-PRODUCTS_by:storeID_likeHierarchy'), + [ + ':likeHierarchy' => $hierarchy.'%', + ':storeID' => 904 + ] + ); + } + + + # depricated: + # now Proxy has the responsibility to cache whatever + # --- + # /** GET tree of product_categories + # * --- + # * get from cache or cache it after creation + # */ + # public static function tree($store = 904) + # { + # $cacheKey = get_called_class() . $store .'/tree'; + # + # // IF category CACHED + # $cache = Registry::use('cache'); + # $tree = $cache->get($cacheKey); + # if ($tree !== false) { + # return $tree; + # } + # + # // (not cached) Create and Cache it + # $tree = self::createCategoriesTree(); + # $cache->set($cacheKey, $tree, CACHE_ROOT_TTL); + # + # return $tree; + # } + + + /** CREATE product_categories tree + * NOTE: includes active categories only; + * + * Algorith uses 'Hierarchy' for category path-positioning, + * implementing a linear conctruction of the requested tree; + * (faster and less source-consuming than a recursive algo) + */ + public static function tree($store = 904) + { + $tree = []; // variable to hold results + + $db = Registry::use('database'); + + // get raw categories data --------------------------------------------- + + $raw = $db->runQuery( "SELECT `ID`, Title, `Level`, Hierarchy, + ParentID, `Order`, FullFriendlyUrl + FROM product_categories pc + WHERE IsActive = 1 AND IsCurrentlyActive = 1 + ORDER BY pc.Level asc, pc.Order asc, pc.Hierarchy asc", + [] + ); + + // count products per 3rd level category ------------------------------- + + $countProducts = $db->runQuery( + Market_repository::pull('Count_Last_Level_PRODUCTS_by:storeID'), + [ ':storeID' => $store ] + ); + // map categoryID -> Counter + $mapCounter = []; + foreach($countProducts as $rec) $mapCounter[$rec['ID']] = $rec['Counter']; + + // parse raw data to hierarchical tree (2 pass) ------------------------ + + // 1st pass: parse raw data, construct and fill the $tree array ........ + foreach($raw as $rec) { + + // create category path from Hierarchy (format: .10.10100. ) + // so remove 1st and last dots (.) from Hierarchy string + // then explode via dot-character (.) + $categoryPath = explode('.', substr($rec['Hierarchy'], 1, -1)); + + switch ($rec['Level']) { + case 0: + $tree[$categoryPath[0]] = [ + 'info' => $rec, + 'childs' => [] + ]; break; + + case 1: + $tree[$categoryPath[0]]['childs'][$categoryPath[1]] = [ + 'info' => $rec, + 'childs' => [] + ]; break; + + case 2: + $tree[$categoryPath[0]]['childs'][$categoryPath[1]]['childs'][$categoryPath[2]] = [ + 'info' => $rec, + 'count' => isset($mapCounter[$categoryPath[2]]) ? $mapCounter[$categoryPath[2]] : 0 + ]; break; + + default: + // nothing... + } + + } + + // 2nd pass: remove categories with no products ........................ + foreach($tree as $id0 => $rec0) { + $count0 = 0; + + foreach($rec0['childs'] as $id1 => $rec1) { + $count1 = 0; + + foreach($rec1['childs'] as $id2 => $rec2) { + if ($rec2['count']>0) $count1++; + else unset($tree[$id0]['childs'][$id1]['childs'][$id2]); + } + + if ($count1 > 0) $count0++; + else unset($tree[$id0]['childs'][$id1]); + } + + if (!$count0) unset($tree[$id0]); + } + + return $tree; + } + + +} \ No newline at end of file diff --git a/public/app/models/market/Product_model.php b/public/app/models/market/Product_model.php new file mode 100644 index 0000000..aa554a1 --- /dev/null +++ b/public/app/models/market/Product_model.php @@ -0,0 +1,49 @@ +query( + Market::pull('Active_PRODUCT_by:storeID_ProductUrl'), + [ + ':storeID' => $store, + ':ProductUrl' => $url + ] + )->getFirst(); + + // if no product, return false + if ($product === false) return false; + + // inject product's images + $product['Images'] = self::getProductImages($product['ID']); + + return $product; + } + + + public static function getProductImages($id) + { + ## return Registry::use('database')->runQuery( + ## "SELECT a.Url, a.Title, a.Description + ## FROM products p + ## LEFT JOIN products_to_images p2i ON p2i.SimpleProductID = p.ID + ## LEFT JOIN assets a ON a.ID = p2i.ImageID + ## WHERE p.IsActive = 1 AND p.Published = 1 + ## AND p.ID = :id + ## ORDER BY p2i.Order", + ## [ ':id' => $id ] + ## ); + + return Registry::use('database')->runQuery( + Market::pull('PRODUCT_IMAGES_by:productID'), + ['productID' => $id ] + ); + } + +} \ No newline at end of file diff --git a/public/app/models/todo.md b/public/app/models/todo.md new file mode 100644 index 0000000..defd21e --- /dev/null +++ b/public/app/models/todo.md @@ -0,0 +1,132 @@ + + +Privilege +--- + +Privilege::list_of_privileges( privilege_id ) + +Privilege::privileges_tree() + + + + + +User +--- + +User::get_privileges + + +User::has_privilege( privilege_id ) + + +User::reset_password() + -> create otp + -> send email + + +User::set_privilege( privilege_id ) + + +User::track_action() + -> user_id + -> action : Contoller::method(args) + -> timestamp + + + +Lesson: +--- + +Lesson::create_lesson( POST ) + +Lesson::get_lesson( lesson_id ) + + + +Course +--- + +Course::create_course( POST ) + +Course::courses_tree() + + + +Upgrades (??) +--- + + +A1 + +A2 : includes A1 + +A3 : includes A1, A2 + +A4 : includes A1, A2, A3 + + +A1 100 +A2 200 +A3 350 +A4 500 + +B1 100 +B2 200 +B3 400 +B4 800 + + +:1 -> 0% +:2 -> 15% +:3 -> 20% + + + + +A1 -> A2 +A1 -> A3 +A1 -> A4 + +A2 -> A3 +A2 -> A4 + +A3 -> A4 + +A1 < A2 < A3 < A4 + + + +B1 -> B2 +B1 -> B3 +B1 -> B4 + +B2 -> B3 +B2 -> B4 + +B3 -> B4 + + +A1+B1 + +A2+B2 + +A3+B3 + + +A1+B1 -> A2+B2 +A1+B1 -> A3+B3 +A1+B1 -> A4+B4 + +A2+B2 -> A3+B3 +A2+B2 -> A4+B4 + +A3+B3 -> A4+B4 + + + +UPGRADE PRICE = upper_priv_price - own_priv_price + +buy 1 item : -0% +buy 2 items : -10% +buy 3 items : -15% diff --git a/public/app/routes/.gitkeep b/public/app/routes/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/app/routes/api.php b/public/app/routes/api.php new file mode 100644 index 0000000..61e485b --- /dev/null +++ b/public/app/routes/api.php @@ -0,0 +1,81 @@ + 'Διαχείριση Classroom', + 'action' => 'panel', + ]); +}); +Route::add('/admin/panel', function () { // admin panel #2 + Auth::allowRoles([1, 2, 3]); + Render::view('admin/skeleton', [ + 'title' => 'Διαχείριση Classroom', + 'action' => 'panel', + ]); +}); + + +// admin categories (=courses) +//////////////////////////////////////////////////////////////////////////////// + + +Route::add('/admin/categories', function () { // manage categories page + Auth::allowRoles([1, 2, 3]); + Render::view('admin/skeleton', [ + 'title' => 'Διαχείριση Κεφαλαίων', + 'action' => 'categories', + ]); +}); + +Route::add('/admin/api/categories', function () { // ajax: get all courses; with breadcrumbs + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::breadcrumbs(); +}); + +Route::add('/admin/api/categories/add', function () { // ajax: add new category (course) + Auth::allowRoles([1, 2, 3]); + Course_admin::add_course(); +}, 'post'); + +Route::add('/admin/api/categories/update', function () { // ajax: edit category (course) + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::update_course(); +}, +'post'); + + +// admin privileges +//////////////////////////////////////////////////////////////////////////////// + + +Route::add('/admin/privileges', function () { // manage privileges page + Auth::allowRoles([1, 2, 3]); + Render::view('admin/skeleton', [ + 'title' => 'Διαχείριση Δικαιωμάτων Πρόσβασης', + 'action' => 'privileges', + ]); +}); + +// ajax: get all privileges (courses; with breadcrumbs) +// use proxy (cache results); send as json +Route::add('/admin/api/privileges', function () { + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::json( Cache_service::privileges_hierarchy() ); +}); + +// add privilege + +// update privilege + + + +// admin lessons +//////////////////////////////////////////////////////////////////////////////// + +Route::add('/admin/lessons', function () { // request admin-lessons page + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::view('admin/skeleton', [ + 'title' => 'Διαχείριση Μαθημάτων', + 'action' => 'lessons', + ]); +}); + +Route::add('/admin/edit_lesson', function () { // new lesson form + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::view('admin/skeleton', [ + 'title' => 'Νέο Μάθημα', + 'action' => 'edit_lesson', + ]); +}); + +Route::add('/admin/edit_lesson/([0-9]*)', function ($id) { // edit lesson form + Auth::allowRoles([1, 2, 3]); + Render::view('admin/skeleton', [ + 'title' => 'Επεξεργασία Μαθήματος', + 'action' => 'edit_lesson', + 'id' => intval($id) + ]); +}); + + +Route::add('/admin/api/lesson/([0-9]*)', function ($id) { // ajax: get lesson + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::get_lesson($id); +}); + + +Route::add('/admin/api/lesson/add', function () { // ajax: add lesson + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::json(['success' => Course_admin::add_lesson()]); +}, 'post'); + + +Route::add('/admin/api/lesson/update', function () { // ajax: update lesson + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::json(['success' => Course_admin::update_lesson()]); +}, 'post'); + + +Route::add('/admin/api/lessons', function () { // ajax: get all lessons + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::all_lessons(); +}); + + + +// admin files +//////////////////////////////////////////////////////////////////////////////// + +Route::add('/admin/files', function () { // admin-files panel + Auth::allowRoles([1, 2, 3]); + Render::view('admin/skeleton', [ + 'title' => 'Διαχείριση Μέσων (media)', + 'action' => 'files', + ]); +}); + + +Route::add('/admin/api/files', function () { // ajax: get lesson + Auth::allowRoles([1, 2, 3]); + Render::json(Course_admin::files()); +}); + +// ajax: file-upload +// --- +Route::add('/admin/api/file_upload', function () { + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::json(Course_admin::upload_file()); +}, 'post'); + + + + +// admin page +//////////////////////////////////////////////////////////////////////////////// + +Route::add('/admin/pages', function () { // request admin-lessons page + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::view('admin/skeleton', [ + 'title' => 'Διαχείριση Σελίδων', + 'action' => 'pages', + ]); +}); + + +Route::add('/admin/edit_page', function () { // new page form + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::view('admin/skeleton', [ + 'title' => 'Νέα Σελίδα', + 'action' => 'edit_page', + ]); +}); + +Route::add('/admin/edit_page/([0-9]*)', function ($id) { // edit page form + Auth::allowRoles([1, 2, 3]); + Render::view('admin/skeleton', [ + 'title' => 'Επεξεργασία Σελίδας', + 'action' => 'edit_page', + 'id' => intval($id) + ]); +}); + + +Route::add('/admin/api/page/([0-9]*)', function ($id) { // ajax: get page + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::get_page($id); +}); + + +Route::add('/admin/api/page/add', function () { // ajax: add page + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::json(['success' => Course_admin::add_page()]); +}, 'post'); + + +Route::add('/admin/api/page/update', function () { // ajax: update page + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Render::json(['success' => Course_admin::update_page()]); +}, 'post'); + + +Route::add('/admin/api/pages', function () { // ajax: get all pages + Auth::allowRoles([1, 2, 3]); // allow few admin-panel roles + Course_admin::all_pages(); +}); + diff --git a/public/app/routes/frontend.php b/public/app/routes/frontend.php new file mode 100644 index 0000000..be06b1c --- /dev/null +++ b/public/app/routes/frontend.php @@ -0,0 +1,169 @@ + Cache_service::courses_struct()['tree'], + 'entity' => Cache_service::pages_list() + ]); + // need redirect?... header('Location: /some/default/url', true, 302); +}); + + +// Error pages +//////////////////////////////////////////////////////////////////////////////// + +Route::notFound( function() { // 404 error page + header("HTTP/1.0 404 Not Found"); + Render::view('error/404', ['message' => 'nobody knows it (but you got a secret smile;)']); +}); + + + +// Common content +//////////////////////////////////////////////////////////////////////////////// + + +Route::add('/course/([0-9]*)', // request course by course-id + function($id) { Course::course($id); } +); + +Route::add('/lesson/([0-9]*)', // request lesson by lesson-id + function($id) { Course::lesson($id); } +); + +Route::add('/page/([0-9]*)', // request lesson by lesson-id + function($id) { Course::page($id); } +); + +Route::add('/serve/file/([0-9a-zA-Z-_\.\/]*)', // serve file by path + function ($path) { Course::serve_file($path); } // (also ?type= is sent) +); + + + + + +// Account +/////////////////////////////////////////////////////////////////////////////////////////////// + +// [ok] login +// [ok] register +// [ok] activate +// [..] ask-reset +// [..] reset +// [..] profile +// [..] edit-profile +// [..] subscriptions +// [..] payments +// [..] pay +// [..] order + + + + +/** URL-format Proposals and common Route regex solutions + * ----------------------------------------------------------------------------- + * + * Page (almost-static content): + * /about/{url} +# Route::add('/about/([0-9a-zA-Z-_\/]*)', function($url) { Page::fromUrl($url); }); + * + * Product: + * /{level-1}/{level-2}/{level-3}/{friendly-url}-{id} +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)-([0-9]*)', +# function($category, $subcategory, $group, $label, $id) { +# Product::fromID([$$category, $subcategory, $group, $label], $id); +# } +# ); + * + * Category + * /{category}/[ {subcategory}[ /{group}]] +# Route::add('/([0-9a-zA-Z-_]*)', function($a) { Category::url([$a]); }; +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b) { Category::url([$a, $b]); }); +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b, $c) { Category::url([$a, $b, $c]); }); + * + * othet routes used in some user-cases + +# Route::add('/lesson/([0-9a-f]*)/([0-9a-zA-Z-_]*)', +# function($ticket, $lesson) { Lesson::show([$lesson, $ticket]); } +# ); +# +# Route::add('/media/([0-9a-f]*)/([0-9a-zA-Z-_]*)/([0-9]*)/', +# function($ticket, $type, $id) { Media::serve([$type, $id, $ticket]); } +# ); + * + * 4-th level paths belong to products +# Route::add('/about/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', +# function($a, $b, $c) { Page::show([$a, $b, $c]); } +# ); + * + * + * OTHER EXAMPLES (use it for brainsrtorming) + * ----------------------------------------------------------------------------- + * + * +# // Typical Use +# // --- +# Route::add('/art', function() { Art::blah(); }); +# Route::add('/art/db', function() { Art::fromDatabase(); }); +# Route::add('/art/([0-9]*)', function($id) { Art::getInfo($id); }); + * + * Get-Post route example +# Route::add('/contact-form', function() { +# echo '
'; +# }, 'get'); + + Route::add('/contact-form', function() { + echo 'Hey! The form has been sent:
'; print_r($_POST); + }, 'post'); + * + * Accept number as parameter +# Route::add('/foo/([0-9]*)/bar', function($var1) { +# // echo $var1.' is a number!'; + echo "{$var1} is a number!"; +# }); + * + * About pages +# Route::add('/about/([0-9a-zA-Z-_]*)', function($page) { +# InfoPage::render('about/'.page); +# }); + * + * handle a request like: /foo/123/bar/3254-lefki-zaxari-marata-1kg + * where first-numeric-part of last-uri-section (3254) is the product number +# Route::add('/foo/([0-9]*)/bar/([0-9]*)-([0-9a-zA-Z-_]*)', function($num, $id, $name) { +# echo $num .' is some nomber, id = '. $id .' and label = '. $name; +# }); + * + * handle a request like: /zaxares-glykantika/lefki-zaxari-year-2022-45678 + * where last-numeric-part of last-uri-section (45678) is the product number +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)-([0-9]*)', +# function($category, $subcategory, $group, $label, $id) { +# Shop::product([$$category, $subcategory, $group, $label], $id); +# }); + * + * last chance to resolve (some friendly url) +# Route::add('/([0-9a-zA-Z-_]*)', function($a) { Resolve::uri([$a]); }); +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b) { Resolve::uri([$a, $b]); }); +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)', function($a, $b, $c) { Resolve::uri([$a, $b, $c]); }); + * + * + * Product page + * handle a request like: /pantopoleio/zaxares/lefki-zaxari/lefki-zaxari-year-2022-45678 + * where last-numeric-part of last-uri-section (45678) is the product number +# Route::add('/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)/([0-9a-zA-Z-_]*)-([0-9]*)', +# function($category, $subcategory, $group, $label, $id) { +# Shop::product([$$category, $subcategory, $group, $label], $id); +# }); + * + * ------------------------------------------------------------------------------ + */ diff --git a/public/app/routes/user.php b/public/app/routes/user.php new file mode 100644 index 0000000..7ad0fa6 --- /dev/null +++ b/public/app/routes/user.php @@ -0,0 +1,84 @@ + then sends to POST:/account/check-login +Route::add('/login', function() { Render::view('user/login'); }); + +// request registration ... -> then sends to POST:/account/register +Route::add('/registration', function() { Render::view('user/registration'); }); + +// request logout +Route::add('/logout', function() { + Auth::logout(); + header('Location: /'); die(); +}); + +// request activation +Route::add('/account/activate', function() { Auth::activate(); } ); + +// request password reset +Route::add('/account/reset_password', function() { Auth::reset_password(); } ); + + + +// Replies to common requests (POST method) +// --- -- -- - - - + +// user sends login form +Route::add('/account/check-login', function() { + $response = Auth::login(); + Render::json(['status' => $response]); + }, + 'post' +); + +// user sends a registration form +Route::add('/account/register', function() { + $response = Auth::register(); + Render::json($response); + }, + 'post' +); + + +// Account Management +// --- -- -- - - - + +// user profile +Route::add('/account/profile', function() { + $user = Auth::is_connected(); + if ($user === false) { + Render::view('error/general', + [ + 'title' => 'Nope!', + 'message' => "

No profile

User is not connected" + ] + ); + + } else { + Render::json(['success' => true, 'status' => 'user is connected']); + } + } +); + + +// temporary (on development) +// --- -- -- - -- +// NOTE: these is only for testing purposes + +// test connection +if (!PRODUCTION) { + Route::add('/check/connection', function() { Auth::is_connected(); }); +} + + + diff --git a/public/app/views/.gitkeep b/public/app/views/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/public/app/views/admin/admin-menu.php b/public/app/views/admin/admin-menu.php new file mode 100644 index 0000000..52e8522 --- /dev/null +++ b/public/app/views/admin/admin-menu.php @@ -0,0 +1,47 @@ + 'posts', + * 'id' => 4 + * ]) + * ----------------------------------------------------------------------------- + */ + +$admin_options = [ + 'panel' => 'Διαχείριση', + 'edit_lesson' => 'Νέο Μάθημα', + 'lessons' => 'Μαθήματα', + 'categories' => 'Κεφάλαια', + 'pages' => 'Σελίδες', + 'files' => 'Αρχεία', + 'privileges' => 'Πρόσβαση', + 'users' => 'Χρήστες' +]; +?> + +
+ + $label) : ?> + + + + + + + + + + + + Logout + +
\ No newline at end of file diff --git a/public/app/views/admin/categories.php b/public/app/views/admin/categories.php new file mode 100644 index 0000000..26fd5a2 --- /dev/null +++ b/public/app/views/admin/categories.php @@ -0,0 +1,91 @@ + +
+
Διαχείριση Κατηγοριών
+
+ + +
+
+ +
+
+
+ +
+ + + + + + +
Κατηγορία/Κεφάλαιο
+ +
+ + +
+
+
+ + + + + + diff --git a/public/app/views/admin/edit_lesson.php b/public/app/views/admin/edit_lesson.php new file mode 100644 index 0000000..ef875b4 --- /dev/null +++ b/public/app/views/admin/edit_lesson.php @@ -0,0 +1,159 @@ + + + +
+
+
+ +
+
+ + +
+
+
+ + +
+ + + + + + +
+ +
+ +
+
+ +
+ +
+ +
+
+ + +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+ +
+ + + + +
    +
+ +
+
+ + +
+ +
+
+
+ + +
+ +
+ +
+ +
+
+ + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+
+ + + + + diff --git a/public/app/views/admin/edit_page.php b/public/app/views/admin/edit_page.php new file mode 100644 index 0000000..46c47bc --- /dev/null +++ b/public/app/views/admin/edit_page.php @@ -0,0 +1,139 @@ + + + +
+
+
+ +
+
+ + +
+
+
+ + +
+ + + + + + +
+ +
+ +
+
+ + +
+ +
+ +
+
+ +
+ +
+ +
+ +
+ +
+
+ +
+ +
+ + + + +
    +
+ +
+
+ + + + + +
+ +
+ +
+ +
+
+ + +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + +
+
+ + + + + diff --git a/public/app/views/admin/files.php b/public/app/views/admin/files.php new file mode 100644 index 0000000..c6d2771 --- /dev/null +++ b/public/app/views/admin/files.php @@ -0,0 +1,96 @@ + +
+
Διαχείριση Επιπέδων Πρόσβασης
+
+ +
+
+ +
+
+
+ +
+ + + + + + + + + + +
α/αΠεριγραφήΔιαδρομήMedia-TypeΠρόσβαση
+ +
+ + +
+
+
+ + + + + + diff --git a/public/app/views/admin/lessons.php b/public/app/views/admin/lessons.php new file mode 100644 index 0000000..d1cd3ae --- /dev/null +++ b/public/app/views/admin/lessons.php @@ -0,0 +1,126 @@ + +
+
Διαχείριση Μαθημάτων
+
+ + +   Νέο Μάθημα + +
+
+ +
+
+
+ +
+ + + + + + + + + +
α/αΤίτλοςΚεφάλαιοΠρόσβαση
+ +
+ +
+
+
+ + + + + + diff --git a/public/app/views/admin/pages.php b/public/app/views/admin/pages.php new file mode 100644 index 0000000..dd8f954 --- /dev/null +++ b/public/app/views/admin/pages.php @@ -0,0 +1,109 @@ + +
+
Διαχείριση Μαθημάτων
+
+ + +   Νέα Σελίδα + +
+
+ +
+
+
+ +
+ + + + + + + +
α/αΤίτλος
+ +
+ +
+
+
+ + + + + + diff --git a/public/app/views/admin/panel.php b/public/app/views/admin/panel.php new file mode 100644 index 0000000..59b8cba --- /dev/null +++ b/public/app/views/admin/panel.php @@ -0,0 +1,4 @@ +
+
+
+

Admin panel

\ No newline at end of file diff --git a/public/app/views/admin/privileges.php b/public/app/views/admin/privileges.php new file mode 100644 index 0000000..587c363 --- /dev/null +++ b/public/app/views/admin/privileges.php @@ -0,0 +1,93 @@ + +
+
Διαχείριση Επιπέδων Πρόσβασης
+
+ + +
+
+ +
+
+
+ +
+ + + + + + + + +
ΚωδικόςΕπίπεδο ΠρόσβασηςΠεριλαμβάνει
+ +
+ + +
+
+
+ + + + + + diff --git a/public/app/views/admin/skeleton.php b/public/app/views/admin/skeleton.php new file mode 100644 index 0000000..927bd2d --- /dev/null +++ b/public/app/views/admin/skeleton.php @@ -0,0 +1,45 @@ + + + + + + Classroom - <?=$title?> + + true] + ); + ?> + + + + + +
+ + $action, + 'id' => $id + ]); + + // render main content + //////////////////////////////////////////////////////////////////// + Render::view("admin/{$action}",[ 'id' => $id ]); //////////////// + ?> +
+ + + + + + + diff --git a/public/app/views/components/breadcrumbs.php b/public/app/views/components/breadcrumbs.php new file mode 100644 index 0000000..59c0fca --- /dev/null +++ b/public/app/views/components/breadcrumbs.php @@ -0,0 +1,30 @@ + + \ No newline at end of file diff --git a/public/app/views/components/courses_menu.php b/public/app/views/components/courses_menu.php new file mode 100644 index 0000000..6539f8c --- /dev/null +++ b/public/app/views/components/courses_menu.php @@ -0,0 +1,97 @@ + $category_tree, + * 'open_path' => [1 ,2] + * ]); + * + * ----------------------------------------------------------------------------- + */ + +/** tree_ul + * creates (recursively) a nested ul-li tree of categories + * --- -- -- - - - + * @param $tree (array) : categories array formated as tree + * @param $open_nodes (array) : array of categor ids that shall be marked open/selected + * @return $html (string) + */ +function tree_li($tree, $open_nodes = [], $l = 0) +{ + $html = ""; + + foreach($tree as $node) { + + // if has childs ... + // write li ; traverse children recursively + if ((isset($node['childs'])) && ( $node['childs']!= [])) { + + if (in_array(intval($node['rec']['id']), $open_nodes)) { + $inner_class = "inner show"; + $sign = "–"; + $a_class = "has-childs selected"; + + } else { + $inner_class = "inner"; + $sign = "+"; + $a_class = "has-childs"; + } + + $html .= "
  • + + {$node['rec']['label']} + {$sign} + +
      " + . tree_li($node['childs'], $open_nodes, $l+1) + ."
    +
  • "; + + + } else { // else just write the li + + if (in_array(intval($node['rec']['id']), $open_nodes)) { + $u_in = ""; + $u_out = ""; + $a_class = "selected"; + + } else { + $u_in = ""; + $u_out = ""; + $a_class = ""; + + } + + $html .= "
  • + + {$node['rec']['label']} + +
  • "; + } + } + + return $html; + +} + + +// draw the menu (hidden on XS screens) +// ----------------------------------------------------------------------------- +echo "

    Διαθέσιμη ύλη

    "; +echo ""; + + + +// TODO: +// draw menu for XS screens (for example, just the 1st-level categories) +// (maybe in an accordion so it won;t take too much area on small screens) diff --git a/public/app/views/components/footer.php b/public/app/views/components/footer.php new file mode 100644 index 0000000..7cd4a5a --- /dev/null +++ b/public/app/views/components/footer.php @@ -0,0 +1,240 @@ +#footer>row` + * + * + * Each sub-structure has 2-5 properties: + * + * @var title (string) : title of the sub-section + * @var entity (string) : type of entity (ex: page/lesson/etc; TODO: method of CMS_model?) + * @var list (array) : list of entity id(s) + * @var template (string) : template that is used to draw the listed pages' info + * @var width (string) : class that relates to sub-structure's width + * + * NOTE: + * designer parsing and rendering can be a quite expensive proccess + * thus it is strongly recommented to use cached entities + * + * + * Example structure: + { + "class" : "row", # container class + "struct" : [ + { # block 1 + "title" : "", + "entity" : "page", + "list" : [2, 1, 3], # pages to be listed + "template" : "list", # list page titles with link to the pages + "width" : "col-md-4" + }, + { + "template" : "null", # list nothing + "width" : "col-md-3" + }, + { + "entity" : "page", + "list" : [4], # list content of page 4; + "template" : "content", # set title to page-title + "width" : "col-md-5" + } + + TODO: (wish) + ,{ + "template": "struct", + "struct" : [ + { + title, entity, list, template, width + }, + ... + ] + } + ] + } + * + * brainstormin: (TODO:) + * use some document-describe stucture like the one on the pdfmake js-library + * ----------------------------------------------------------------------------- + */ + + +/** check imported variables / data + * ----------------------------------------------------------------------------- + */ +if (!isset($designer)) { + + // default designer (and first case-study) + $designer = '{ + "class" : "row", + "struct" : [ + { + "title" : "Πληροφορίες", + "entity" : "page", + "list" : [2, 1, 3, 4], + "template" : "list", + "width" : "col-md-4 no-list-mark" + }, + { + "entity" : "page", + "list" : [6], + "template" : "content", + "width" : "col-md-3 no-list-mark" + }, + { + "entity" : "page", + "list" : [5], + "template" : "content", + "width" : "col-md-5 no-list-mark" + } + ] + }'; +} + +// $entity list shall be passed +// entity link url shall be passed + + +/** templating functions + * ----------------------------------------------------------------------------- + */ + +/** List template + * --- -- -- - - - + * + * lists entity titles with links + * in a `ul>li` html-structure + * + * @param $title + * @param $list + * @param $container + */ +function list_template($title, $list, $container, $entity) { + + $result = '
    +

    '. $title .'

    +
      '; + + foreach($list as $id) { + + if ($entity[$id]['status'] == 1) { // if entity is published + $result .= ' +
    • + + ' . $entity[$id]['title'] .' + +
    • '; + } + + } + return $result . '
    '; +} + +/** content_template + * + * lists whole title and content of entity + * + * @param $list + * @param $container + */ +function content_template($list, $container, $entity) { + + $parsedown = new Parsedown(); + + $result = '
      '; + + foreach($list as $id) { + + if ($entity[$id]['status'] == 1) { // if entity is published + + $result .= ' +
    • +

      '. $entity[$id]['title'] .'

      +
      '. $parsedown->text($entity[$id]['body']) .'
      +
    • '; + } + + } + return $result .'
    '; +} + + +/** ready to start the proccessing + * ----------------------------------------------------------------------------- + */ + +// decode ... +$parse = json_decode($designer); + +/** then start parse-proccessing ... + * ----------------------------------------------------------------------------- + */ +?> + + + +
    + + struct as $section ) { + + switch ($section->template) { + + case 'list': + echo list_template( + $section->title, + $section->list, + $section->width, + $entity + ); + break; + + case 'content': + echo content_template( + $section->list, + $section->width, + $entity + ); + break; + + default: // ex. 'null' + + echo '
    +

    '. $section->title.'

    +
    '; + } + + } + ?> + +
    + + diff --git a/public/app/views/components/header_includes.php b/public/app/views/components/header_includes.php new file mode 100644 index 0000000..62dc616 --- /dev/null +++ b/public/app/views/components/header_includes.php @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/app/views/components/lessons_list.php b/public/app/views/components/lessons_list.php new file mode 100644 index 0000000..a778d59 --- /dev/null +++ b/public/app/views/components/lessons_list.php @@ -0,0 +1,54 @@ + $category_tree, + * 'fieldset' => ['date', 'intro'] + * ]) + * ----------------------------------------------------------------------------- + */ +?> + + + + + +
    + + + + + +
    + +

    + +

    + + +

    (επίπεδο πρόσβασης )

    + + + +

    + + + +

    + + +
    + +
    + + + + diff --git a/public/app/views/components/subcategories.php b/public/app/views/components/subcategories.php new file mode 100644 index 0000000..5c05a94 --- /dev/null +++ b/public/app/views/components/subcategories.php @@ -0,0 +1,19 @@ + + + + +
    Υποκεφάλαια
    + +
    + + $child) : ?> + + + + + + + +
    + + \ No newline at end of file diff --git a/public/app/views/components/top_bar.php b/public/app/views/components/top_bar.php new file mode 100644 index 0000000..eaffe76 --- /dev/null +++ b/public/app/views/components/top_bar.php @@ -0,0 +1,40 @@ + +
    + + $id, + 'label' => $label, + 'parents' => $parents + ]); + ?> + + + +
    \ No newline at end of file diff --git a/public/app/views/components/user-management.php b/public/app/views/components/user-management.php new file mode 100644 index 0000000..636f2ff --- /dev/null +++ b/public/app/views/components/user-management.php @@ -0,0 +1,65 @@ +
    + + + + + +
    + + + diff --git a/public/app/views/error/404.php b/public/app/views/error/404.php new file mode 100644 index 0000000..a085830 --- /dev/null +++ b/public/app/views/error/404.php @@ -0,0 +1,65 @@ + + + + + + 404: Not Found + + + + +
    +
    +

    +
    + +
    +
    + + diff --git a/public/app/views/error/general.php b/public/app/views/error/general.php new file mode 100644 index 0000000..6ed984b --- /dev/null +++ b/public/app/views/error/general.php @@ -0,0 +1,64 @@ + + + + + + <?= isset($title) + ? (SITE_TITLE .": ". $title) + : PAGE_404_TITLE + ?> + + + + + +
    +
    +

    +
    +
    + +
    +
    + + diff --git a/public/app/views/group.php b/public/app/views/group.php new file mode 100644 index 0000000..5d5dea0 --- /dev/null +++ b/public/app/views/group.php @@ -0,0 +1,13 @@ +
    +
    + + + +
    + $item]) ?> +
    + + + +
    +
    diff --git a/public/app/views/item.php b/public/app/views/item.php new file mode 100644 index 0000000..2354c81 --- /dev/null +++ b/public/app/views/item.php @@ -0,0 +1,4 @@ +

    +

    + +

    \ No newline at end of file diff --git a/public/app/views/simple/Model.php b/public/app/views/simple/Model.php new file mode 100644 index 0000000..6ea1e7d --- /dev/null +++ b/public/app/views/simple/Model.php @@ -0,0 +1,887 @@ +pdo_pythia= $db->connect(); + + /// // database for wiki + /// $this->pdo = new PDO('mysql:unix_socket=/cloudsql/pythia-251711:europe-west4:pythia-db-eu;dbname=' . DB_DATABASE . ';charset=utf8', DB_USERNAME, DB_PASSWORD, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC)); + /// $this->user_id = $_SESSION['user_session']; + + $this->pdo = $GLOBALS['DB_con']; + + } + + + /** Close Instance + * --------------------------------------------------- (probably not needed) + */ + public function close() + { + // Default + // $this->pdo=Database::disconnect(); + } + + + + ## ------------------------------------------------------------------------- + ## + ## CATEGORY METHODS + ## + ## ------------------------------------------------------------------------- + + + /** get all categories + * + * raw table data (simplest SELECT) + * + */ + public function get_categories() + { + $sql = "SELECT * FROM wiki_category ORDER BY title"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(); + + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + + /** constuct a category_tree + * + * returns a tree representation of the categories + * + * NOTE: + * category_tree() is an expensive method; + * it calls 2 other methods implementing recursive algorithms + * thus it uses many sources to run (particularly RAM). + * Caching the result is strogly recommended. + * + */ + public function category_tree() + { + $categories = $this->get_categories(); // get all categories + + $tree = $this->to_tree($categories); // format to a tree + + $tree_wParents = $this->tree_parents($tree); // add parents section for each tree-node + + return $tree_wParents; + } + + + /** to_tree + * + * constructs a tree from raw-table data; + * this is a private method and uses a recursive algorithm + * + * @param $dataset (array): flar array of records with id/parent-id pairs + * @return $root (array): id of root category + * + * (**) each node has 2 parts: + * .... .. rec : all record attributes/data as passed into $dataset + * .... .. childs : array of (children) nodes + */ + public function to_tree($dataset, $root = 0) + { + $return = []; + + // loop data ; search for direct children of root + foreach($dataset as $key => $rec) { + + $child = $rec['id']; + $parent = $rec['parent_id']; + + if ($parent == $root) { // a direct child is found + + unset($dataset[$key]); // remove item (no need to traverse again) + + // Append the child into result array ; parse its children + $return[] = [ + 'rec' => [ + 'id' => $rec['id'], + 'title' => $rec['title'], + 'parent' => $rec['parent_id'] + ], + 'childs' => $this->to_tree($dataset, $child) // recursively + ]; + } + } + return empty($return) ? [] : $return; + } + + + /** tree_parents + * + * adds a section to each tree node with all parents of each node + * + * @param $tree (array) : nodes array (each node has `rec` and `childs` sections ) + * @param $parents (array); DO NOT SET IT (takes values automaticaly) + * @return array of nodes with an extra node[parents] section + * + */ + private function tree_parents($tree, $parents = []) + { + $tree_with_parents = []; + + foreach($tree as $key => $node) { + // parents to be pushed for node's children + $push_parents = $parents; // parents so far + $push_parents[] = $node['rec']; // this record will be a new parent + + $tree_with_parents[$key] = [ + 'rec' => $node['rec'], + 'parents' => $parents, + 'childs' => ($node['childs'] == []) + ? [] + : $this->tree_parents($node['childs'], $push_parents) + ]; + } + + return $tree_with_parents; + } + + + /** add_category() + * + * add new category + * + * @param $recuest (array): [ title => , parent_id => ] + * @return true; + * + * TODO: catch database error -> return succes => false + */ + public function add_category($request) + { + $sql = "INSERT INTO wiki_category (title, parent_id) VALUES (:title, :parent_id)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ + 'title' => $request['title'], + 'parent_id' => $request['parent_id'] + ]); + $inserted_id = $this->pdo->lastInsertId(); + + return [ "success" => true, 'id' => $inserted_id ]; + } + + + /** update_category() + * + * update an existing category + * + * @param $recuest (array): [ id => , title => , parent_id => ] + * @return true; + * + * TODO: catch database error -> return false + */ + public function update_category($request) + { + $sql = "UPDATE wiki_category SET title = :title, parent_id = :parent_id WHERE id = :id"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ + 'title' => $request['title'], + 'parent_id' => $request['parent_id'], + 'id' => $request['id'] + ]); ; + + return true; + } + + + + ## ------------------------------------------------------------------------- + ## + ## POST (ARTICLE) METHODS + ## + ## ------------------------------------------------------------------------- + + + /** get_post + * + * get a certain post (given the post's `id`) + * + * @param $id (int) + * @param $only_publised (bool): should the post be published? (default=true) + */ + public function get_post($id, $only_published = true) { + + $where_clause = ($only_published) ? ' AND post.status = 1' : ''; + + // depricated: $sql = "SELECT * FROM post WHERE id = :id {$where_clause}"; + // Select post + // + inject tags json + // TODO: + inject media + // --- + $sql = "SELECT wiki_post.*, + ( SELECT CONCAT('[', GROUP_CONCAT(JSON_OBJECT('id', wiki_tag.id, 'name', wiki_tag.name)), ']') + FROM wiki_tag + WHERE wiki_tag.id IN ( SELECT tag_id FROM wiki_post_tags WHERE post_id = :id ) + ) AS tags_json, + ( SELECT + CONCAT('[', GROUP_CONCAT(JSON_OBJECT( + 'id', wiki_media.id, + 'title', wiki_media.title, + 'type', wiki_media.type, + 'path', wiki_media.path, + 'reference', wiki_post_media.reference )), + ']') + FROM wiki_media + LEFT JOIN wiki_post_media ON wiki_post_media.media_id = wiki_media.id + WHERE wiki_post_media.post_id = :id + ) AS medias_json + FROM wiki_post + WHERE wiki_post.deleted IS NULL AND wiki_post.id = :id"; + + $stmt = $this->pdo->prepare($sql); + $stmt->execute(['id' => $id]); + + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); + + return ($result == []) + ? false // no result? false + : $result[0]; // else return 1st record + } + + + /** add post + * + * insert post to database + * + * @param $data (array): an array with all post-properties + * @return: an array with `status` (bool), `id` (int) given to post + */ + public function add_post($data) + { + $post = [ + 'title' => $data['title'], + 'category_id' => $data['category_id'], + 'body' => $data['body'], + 'intro' => $data['intro'], + 'status' => $data['status'], + 'userid' => $this->user_id + ]; + + $sql = "INSERT INTO wiki_post (`title`, category_id, `body`, intro, `status`, user_id) + VALUES (:title, :category_id, :body, :intro, :status, :userid)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute($post); + + $inserted_id = $this->pdo->lastInsertId(); + + // create + link tags to the post + // --- -- -- - - - + if (isset($data['tags'])) { // existing tags... + $this->set_post_tags($inserted_id, $data['tags']); + } + if (isset($data['new_tags'])) { // new tags... + $this->create_tags_for_post($data['new_tags'], $inserted_id); + } + + // set medias for post + // --- -- -- - - - + if (isset($data['media'])) { // new tags... + $this->create_medias_for_post($data['media'], $inserted_id); + } + + return [ "success" => true, 'id' => $inserted_id ]; + } + + + /** update post + * + * update post record to database + * + * @param $data (array): an array with all post-properties + */ + public function update_post($data) + { + $post = [ + 'id' => $data['id'], + 'title' => $data['title'], + 'category_id' => $data['category_id'], + 'body' => $data['body'], + 'intro' => $data['intro'], + 'status' => $data['status'] + ]; + $sql = "UPDATE wiki_post + SET `title` = :title, category_id = :category_id, + `body` = :body, intro = :intro, + `status` = :status + WHERE id = :id"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute($post); + + // create + link tags to the post + // --- -- -- - - - + if (isset($data['tags'])) { // old tags... + $this->set_post_tags($post['id'], $data['tags']); + } + if (isset($data['new_tags'])) { // new tags... + $this->create_tags_for_post($data['new_tags'], $post['id']); + } + + // set medias for post + // --- -- -- - - - + if (isset($data['media'])) { + $this->remove_media_from_post($post['id']); // remove old + $this->create_medias_for_post($data['media'], $post['id']); // re-create new + } + + return true; + } + + + /** latest_published_posts + * + * latest PUBLISHED posts of a category (by category_id) + * + * TODO: handle sorting + * + * @param $category_id (int) ; if 0 then no category is specified + * @param $limit (int) ; 0 = no limit + * @param $fieldset (string): list of fields; default all = '*' + */ + public function latest_published_posts($category_id, $limit = 10, $fieldset = '*') + { + + $where_clause = ($category_id) + ? " AND category_id = :categoryid " + : " "; + + $limit_clause = ($limit) + ? " LIMIT ". $limit + : ""; + + $sql = "SELECT {$fieldset} FROM wiki_post + WHERE `status` = 1 AND deleted IS NULL ". $where_clause + ." ORDER BY creation_date DESC ". $limit_clause; + + $stmt = $this->pdo->prepare($sql); + + if (!$category_id) { + $stmt->execute(); + + } else { + $stmt->execute(['categoryid' => $category_id]); + } + + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); + + return ($result === null) + ? false // no result? return false + : $result; // else return results + } + + + /** delete post + * + * NOTE: + * post is *marked* as deleted; + * a cron-job will make the actual deletions in a later time + * + * @param $id (int): post id + */ + public function delete_post($id) + { + if (intval($id) == 0) { // no valid id? + return ["success" => false]; // return false + } + + $sql = "UPDATE wiki_post SET deleted = 1 WHERE id = :id"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(['id' => $id]); + + return ["success" => true]; + } + + + /** all posts + * published + unpublished ; any category ; no limit + * + * @param $filedset (string): list of fields; default all = '*' + */ + public function all_posts($fieldset = '*') + { + + $sql = "SELECT {$fieldset} FROM wiki_post WHERE deleted IS NULL"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(); + + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); + + return ($result === null) + ? false // no result? return false + : $result; // else return results + } + + + + ## ------------------------------------------------------------------------- + ## + ## MEDIA METHODS + ## + ## ------------------------------------------------------------------------- + + /** create media for post + * + * links post to each media-file of the media `id`s array + * @param $media (array): a list of media-file `id`s + * @param $post_id (int) + */ + private function create_medias_for_post( $medias, $post_id ) + { + foreach($medias as $medi_string) { + $medi = explode(';', $medi_string); // [0]: media_id, [1]: reference + $this->link_media_to_post($medi[0], $post_id, $medi[1]); // link to post + } + return true; + } + + /** remove_media_from_post + * + * remove all media records/attachments from post + * + * @param $post_id (int) + */ + private function remove_media_from_post( $post_id ) + { + $sql = "DELETE FROM wiki_post_media WHERE post_id = :postid"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(['postid' => $post_id]); + return true; + } + + /** link one media-file to a specific post + * + * NOTE: + * the method does not check if media is linked already + * so be sure that the pair of (media_id,post_id) not exist + * + * @param $media_id (int) + * @param $post_id (int) + * @param $reference (int|bit) + */ + private function link_media_to_post( $media_id, $post_id, $reference ) + { + $sql = "INSERT INTO wiki_post_media (post_id, media_id, reference) VALUES (:postid, :mediaid, :reference)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ + 'postid' => $post_id, + 'mediaid' => $media_id, + 'reference' => $reference + ]); + return true; + } + + + + + + ## ------------------------------------------------------------------------- + ## + ## FILE METHODS + ## + ## ------------------------------------------------------------------------- + + + /** upload_file_to_folder + * + * upload the file to CloudStorage + * in a virtual folder + * + * @param $folder + */ + public function upload_file_to_folder($folder) + { + // Checks before uploading the file + //////////////////////////////////////////////////////////////////////// + + // ** 1: file is upladed to temporary folder --------------------------- + if (! is_uploaded_file($_FILES['file']['tmp_name'])) { + return false; // bye! + } + + // ** 2: File belongs to the allowed MIME types ------------------------ + $allowed_file_types = array( + 'application/pdf', + 'image/png', 'image/jpeg', + 'application/msword', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', + 'application/vnd.ms-excel', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + ); + // Recomended MIME type checking via mime_content_type(): + $mime_type = mime_content_type($_FILES['file']['tmp_name']); + if (! in_array($mime_type, $allowed_file_types)) { // File type NOT allowed ... + return false; // bye! + } + + $file_name = $_FILES['file']['name']; + $file_type = $_FILES['file']['type']; // do not take it for granted + $file_size = $_FILES['file']['size']; + $file_tmp = $_FILES['file']['tmp_name']; + + $bare_name = pathinfo($file_name, PATHINFO_FILENAME); + $file_ext = pathinfo($file_name, PATHINFO_EXTENSION); + + + // ** 3: filename or size checks may be added -------------------------- + if ($file_name == "") { + return false; // bye! + } + + // READY to finaly save/upload the file to CDN ///////////////////////// + + $store_filename = $folder .'/'. strtolower($this->clear_file_name($bare_name) .'.'. $file_ext); + + $file_destination = $this->wiki_files_root .'/'. $store_filename; + + // depricated; it is autoloaded include_once CLOUDSTORAGE; + $cloudstorage = new CloudStorage(); + + if ($cloudstorage->upload_object($file_destination, $file_tmp)) { + + return [ + 'path' => $file_destination, + 'type' => $mime_type + ]; + + } else { return false; } + } + + /** uc_split + * + * this is an mb_str_split polyfill because + * pythia uses a php version < 7.4 + * + * CHECK: https://www.php.net/manual/en/function.mb-str-split.php + */ + private function uc_split($string, $length = 1, $encoding = 'UTF-8' ) + { + if(!empty($string)){ + $split = array(); + $mb_strlen = mb_strlen($string,$encoding); + for($pi = 0; $pi < $mb_strlen; $pi += $length){ + $substr = mb_substr($string, $pi,$length,$encoding); + if( !empty($substr)) { + $split[] = $substr; + } + } + } + return $split; + } + + /** clear_file_name + * replace greek characters and strip symbols + */ + private function clear_file_name($str) + { + $el = $this->uc_split("ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρστυφχψωάέήίόύώϊϋς "); + $en = str_split( "ABGDEZHUIKLMNJOPRSTYFXCVabgdezhuiklmnjoprstyfxcvaehioyviys-"); + $strip = str_split("!@#$%^&*()+~`[]{};'/<>?=\""); + + return str_replace($strip, '', str_replace($el, $en, $str)); + } + + + /** define_media + * + * create a record in media table + * + * @param $data + * @return id (int): id of created media record + */ + public function define_media($data) + { + $sql = "INSERT INTO wiki_media (`title`, `type`, `path`) + VALUES (:title, :mimetype, :filepath)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ + 'title' => $data['title'], + 'mimetype' => $data['type'], + 'filepath' => $data['path'] + ]); + $inserted_id = $this->pdo->lastInsertId(); + + return $inserted_id; + } + + + ## ------------------------------------------------------------------------- + ## + ## TAG METHODS + ## + ## ------------------------------------------------------------------------- + + /** all tags + * + * @return: (array) all tags + */ + public function all_tags() + { + $sql = "SELECT * FROM wiki_tag"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(); + + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); + + return ($result === null) + ? false // no result? return false + : $result; // else return results + } + + + /** create_tag + * + * @param $tag (string): the tag label + * @return : id (int) given to tag + */ + public function create_tag($tag) + { + $sql = "INSERT INTO wiki_tag (`name`) VALUES (:label)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ 'label' => $tag ]); + + $tag_id = $this->pdo->lastInsertId(); + + return $tag_id; + } + + /** destroy_tag + * + * @param $tag_id (int) + */ + public function destroy_tag($id) + { + // remove all post-links to this tag + $clean_posts = "DELETE FROM wiki_post_tags WHERE tag_id = :tagid"; + $clean = $this->pdo->prepare($clean_posts); + $clean->execute([ 'tagid' => $id ]); + + // remove tag from tags table + $sql = "DELETE FROM wiki_tag WHERE id = :tagid"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ 'tagid' => $id ]); + + return true; + } + + /** posts_of_tag + * + * return posts linked to the specified tag (by tag-id) + * + * @param tag_id + * @param limit + * @param fieldset (string): list of post field-names separated with a comma (,) + * @param only_published (bool) + */ + public function posts_of_tag($tag_id, $limit = 0, $fieldset = '*', $only_published = true) + { + // format post field-names for SELECT SQL + // post_fields will be somethning like... `post.*` + // or... `post.id, post.title, post.into` + // --- -- -- - - - + $fields = explode(',', str_replace(' ', '', $fieldset)); + $fields_arr = []; + foreach($fields as $f) { $fields_arr[] = 'wiki_post.'. $f; } + $post_fields = implode(', ', $fields_arr); + + $limit_clause = ($limit) + ? " LIMIT ". $limit + : ""; + + $filter = ($only_published) + ? " AND post.status = 1 " + : ""; + + $sql = "SELECT {$post_fields} FROM wiki_post + LEFT JOIN wiki_post_tags ON wiki_post_tags.post_id = wiki_post.id + LEFT JOIN wiki_tag ON wiki_tag.id = wiki_post_tags.tag_id + WHERE wiki_post.deleted IS NULL AND wiki_tag.id = :tagid {$filter} + {$limit_clause}"; + + $stmt = $this->pdo->prepare($sql); + $stmt->execute(['tagid' => $tag_id]); + + $result = $stmt->fetchAll(PDO::FETCH_ASSOC); + + return $result; + } + + + /** tag_name + * return tag name (name = label / title / text) + * by tag_id + * + * @param $id (int): given tag-id + * @return (string) + */ + public function tag_name($id) { + $sql = "SELECT `name` FROM wiki_tag WHERE id = :id LIMIT 1"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(['id' => $id]); + + $result = $stmt->fetch(); + + return $result['name']; + + } + + /** set_tags_to_post() + * + * REMOVE OLD tags from post; + * then SET NEW tags + * + * NOTE: + * make sure that any old tags are removed from post; + * new tags should not be linked in a later cycle + * + */ + private function set_post_tags($post_id, $tags) + { + $this->remove_tags_from_post($post_id); // remobve any old tags + + foreach($tags as $tag) { // set each tag to post + $this->link_tag_to_post($tag, $post_id); + } + } + + /** remove_tags_from_post + * + * @param $post_id (int) + */ + private function remove_tags_from_post( $post_id ) + { + $sql = "DELETE FROM wiki_post_tags WHERE post_id = :postid"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(['postid' => $post_id]); + return true; + } + + /** set one tag to a specific post + * + * NOTE: + * the method does not check if tag is linked already + * + */ + private function link_tag_to_post( $tag_id, $post_id ) + { + $sql = "INSERT INTO wiki_post_tags (post_id, tag_id) VALUES (:postid, :tagid)"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ + 'postid' => $post_id, + 'tagid' => $tag_id + ]); + return true; + } + + /** create tags for post + * + * creates an array of tags; links post to each one; + * @param $tags (array): a list of tags (labels/texts) + * @param $post_id (int) + */ + private function create_tags_for_post( $tags, $post_id ) + { + foreach($tags as $tag) { + $tag_id = $this->create_tag($tag); // create tag + $this->link_tag_to_post($tag_id, $post_id); // link to post + } + return true; + } + + + public function tags_stats() + { + $sql = "SELECT tag.id, tag.name, COUNT(post_tags.post_id) as totals + FROM wiki_tag + LEFT JOIN wiki_post_tags ON wiki_post_tags.tag_id = wiki_tag.id + GROUP BY wiki_tag.id"; + $stmt = $this->pdo->prepare($sql); + $stmt->execute(); + + return $stmt->fetchAll(PDO::FETCH_ASSOC); + } + + + ## ------------------------------------------------------------------------- + ## + ## USER METHODS + ## + ## ------------------------------------------------------------------------- + + /** user_info + * + * no user is passed; user info are exrtacted from Session + * + */ + private function user_info() + { + $user = []; + $keys = [ + 'user_session' => 'user', + 'employee_id' => 'employee', + 'store_id' => 'store', + 'site_id' => 'site', + 'unit_id' => 'unit', + 'employee_rID' => 'rid' + ]; + + foreach($keys as $key => $attribute) { + if (isset($_SESSION[$key]) && ($_SESSION[$key] != '')) { + $user[$attribute] = $_SESSION[$key]; + } + } + return $wiki_user; + } + + + /** update post stats + * + */ + public function update_post_stats($post_id) + { + + $user_id = $_SESSION['user_session']; // get user from session + + $sql = "INSERT INTO wiki_stats + (post_id, user_id, views) VALUES (:post, :user, 1) + ON DUPLICATE KEY UPDATE views = views + 1"; + + $stmt = $this->pdo->prepare($sql); + $stmt->execute([ + 'user' => $user_id, + 'post' => $post_id + ]); + + return true; + + } + +} diff --git a/public/app/views/simple/Render.php b/public/app/views/simple/Render.php new file mode 100644 index 0000000..79a93a0 --- /dev/null +++ b/public/app/views/simple/Render.php @@ -0,0 +1,182 @@ +"; + } + + } + + + /** all_breadcrumbs + * ------------------------------------------------------------------------- + * + * returns an array of all breadcrumbs + * where array-key of each record is category[id] + * + * NOTE: + * --- + * Render::all_breadcrumbs returns an indexed super-array; + * each array item includes a banch of information: [ + * breadcrumb, + * rec: [ id , title ], + * parents: [ [id, title] , ... ] + * childs: [ [id, title] , ... ], + * level + * ] + * + * Use Cases: + * --- + * as a super-array, the output can be used in many cases + * for example... + * into form elements + * .. while selecting category for a post + * .. or editing a category + * or directry referring to category's parents/childs + * + * Arguments: + * --- + * @param $tree (array) : category tree (with childs and parents parts) + * @param $detimiter (string, optional) : string to split breadcrumb's path-nodes + * @param $exception (int, optional) : id of category to exclude (subcategories shall be excluded too) + * @param $l (int, not-pass) : depth level of the node; DO NOT SET (takes values automaticaly) + * @return array of breadcrumbs + * ------------------------------------------------------------------------- + */ + static public function all_breadcrumbs($tree, $delimiter = " / ", $exception = 0, $l = 0) + { + $all = []; // results array + + foreach($tree as $node) { // loop through all nodes + + if (intval($node['rec']['id']) != $exception) { // if node is not exception + + // construct breadcrumb html of node + // --- -- -- - - - + $breadcrumb = ""; + foreach($node['parents'] as $par) { // first: join path titles + $breadcrumb .= $par['title'] . $delimiter; + } + $breadcrumb .= $node['rec']['title']; // last: append title + + // make a new super record + // --- -- -- - - - + $all[$node['rec']['id']] = [ // set record is as key + 'breadcrumb' => $breadcrumb, // add breadcrump to results + 'rec' => $node['rec'], // + node info + 'parents' => $node['parents'], // + parents array + 'childs' => self::first_level_childs($node), // + direct childs + 'level' => $l // + level + ]; + + // recursively traverse children nodes + // --- -- -- - - - + if (isset($node['childs']) && $node['childs'] != []) { + $child_breadcrumbs = self::all_breadcrumbs( + $node['childs'], + $delimiter, + $exception, + $l+1 + ); + + $all = $all + $child_breadcrumbs; // concatenate arrays (keep array-keys) + } + } + + } + return $all; + + } + + /** first_level_childs + * --- -- -- - - - + * used by all_breadcrumbs() + */ + static private function first_level_childs($node) + { + $childs = []; + if ($node['childs'] == []) { + return []; + } + foreach($node['childs'] as $key => $kid) { + $childs[] = [ + 'id' => $kid['rec']['id'], + 'title' => $kid['rec']['title'] + ]; + } + return $childs; + } + + + /** date_box + * creates a pretty date box; outputs greek months + * + * @param $date (string) in 'Y-m-d H:i:s' format + * @return html (string) of the date-box + */ + static public function date_box($date) + { + $months_Gr = ['', + 'Ιαν', 'Φεβ', 'Μαρ', 'Απρ', + 'Μάι', 'Ιουν', 'Ιουλ', 'Αυγ', + 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ' + ]; + $date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $date); + $day = $date->format("j"); + $month = $months_Gr[intval($date->format("m"))]; + $year = $date->format("Y"); + + // print_r([$date, $day, $month, $year]); die(); + + return "
    +

    {$day}

    +

    {$month}

    +

    {$year}

    +
    "; + } + + /** date_friendly + * outputs an unformated greek-language date string + * + * @param $date (string) in 'Y-m-d H:i:s' format + */ + static public function date_friendly($date, $display_time = false) + { + $months_Gr = ['', + 'Ιαν', 'Φεβ', 'Μαρ', 'Απρ', 'Μάι', 'Ιουν', + 'Ιουλ', 'Αυγ', 'Σεπ', 'Οκτ', 'Νοε', 'Δεκ' + ]; + $date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $date); + $day = $date->format("j"); + $month = $months_Gr[intval($date->format("m"))]; + $year = $date->format("Y"); + $time = ($display_time) ? $date->format("H:i") : ''; + + return "{$day} {$month} {$year} {$time}"; + } + +} diff --git a/public/app/views/simple/category.php b/public/app/views/simple/category.php new file mode 100644 index 0000000..15d8b5e --- /dev/null +++ b/public/app/views/simple/category.php @@ -0,0 +1,156 @@ +category_tree(); +$breadcrumbs = Render::all_breadcrumbs($categories); + +// get ALL posts of category +$posts = $wiki->latest_published_posts($category_id, 0); + + +// special case: +// ----------------------------------------------------------------------------- +// ONE post + NO subcaegories ..then redirect to the only post +if (($breadcrumbs[ $category_id ]['childs'] == []) && (count($posts) == 1)) { + header('Location: /wiki/post?id='. $posts[0]['id'], true, 302); + die(); +} + + +// find parent_ids of current category (to open the menu tree) +$category_path = []; +foreach($breadcrumbs[$category_id]['parents'] as $parent) { + $category_path[] = intval($parent['id']); +} +$category_path[] = intval($category_id); + + +// format $posts array +// --- +$posts_formated = []; +foreach($posts as $post) { + $date = DateTimeImmutable::createFromFormat('Y-m-d H:i:s', $post['creation_date']); + $posts_formated[] = [ + 'id' => $post['id'], + 'title' => $post['title'], + 'intro' => $post['intro'] ?? false, + 'date' => Render::date_box($post['creation_date']) + ]; +} + + +// then render the page ... +// ----------------------------------------------------------------------------- +?> + + + + Wiki + + false ]); ?> + + + + + +
    + +
    + + +
    + +
    + +
    + +
    + +
    + +
    + + +

    + +

    + + + + + + +

    Υποκατηγορίες

    +
    + + $child) : ?> + + + + + + + +
    + + + + + + + + +

    Άρθρα / Δημοσιεύσεις

    + + $posts_formated, + 'fieldset' => ['intro', 'date'] + ]); + //////////////////////////////////////////////////// + ?> + + + +
    + +
    +
    +
    + + + + diff --git a/public/app/views/simple/index.php b/public/app/views/simple/index.php new file mode 100644 index 0000000..9860db0 --- /dev/null +++ b/public/app/views/simple/index.php @@ -0,0 +1,123 @@ +category_tree(); +$breadcrumbs = Render::all_breadcrumbs($categories); +$posts = $wiki->latest_published_posts(0, 7); // 0 = no category ; 7 = posts limit + +// format posts array; inject breadcrumbs +// --- +$posts_formated = []; +foreach($posts as $post) { + $posts_formated[] = [ + 'id' => $post['id'], + 'title' => $post['title'], + 'category' => $breadcrumbs[ $post['category_id'] ]['breadcrumb'], + 'intro' => $post['intro'] ?? false, + 'date' => Render::date_box($post['creation_date']) + ]; +} + +// optional fields to be printed into post-list +// --- +$fieldset = [ + 'date', + 'intro', + 'category' +]; + +// then render the page ... +// ----------------------------------------------------------------------------- +?> + + + + Wiki + + false ]); ?> + + + + + +
    + +
    + + + +
    + +
    + +
    + +
    + + + +
    + + +
    + +

    + Welcome to Wiki! +

    + + +

    Ίσως κάποιο εισαγωγικό κείμενο, στατικό ή δυναμικό. + Pellentesque non mauris ut orci volutpat sollicitudin ut vel ligula. Nullam et leo eu ante ornare ultrices a a leo. Proin non accumsan ex, sit amet finibus purus. +

    + Vestibulum posuere maximus nisl eget consequat. Etiam venenatis lectus sed libero vestibulum viverra. Sed nec nibh ac nulla venenatis tincidunt eu ut diam. Sed tincidunt, arcu sit amet pharetra ornare, libero nunc placerat nunc, at dictum dui diam sit amet metus. Sed venenatis vehicula nisl at hendrerit. +

    + + +

    Τελευταίες Δημοσιεύσεις

    + + $posts_formated, + 'fieldset' => $fieldset + ]); + //////////////////////////////////////////////////////// + ?> + +
    + + +
    + +
    + +
    + + + + diff --git a/public/app/views/simple/lorem-dates.php b/public/app/views/simple/lorem-dates.php new file mode 100644 index 0000000..7a7c000 --- /dev/null +++ b/public/app/views/simple/lorem-dates.php @@ -0,0 +1,18 @@ +setTimestamp(time() - rand(0,30000)*1000 + rand(1,1000) ); + + // return time() - rand(0,30000)*1000 + rand(1,1000); + return $dt->format('Y-m-d H:i:s'); +} + + +include 'pythia.php'; + +$posts = $wiki->latest_posts(0, 900); + +foreach($posts as $post) { + $wiki->set_date($post['id'], some_date()); +} +echo "done!"; \ No newline at end of file diff --git a/public/app/views/simple/lorem-intros.php b/public/app/views/simple/lorem-intros.php new file mode 100644 index 0000000..a3629e1 --- /dev/null +++ b/public/app/views/simple/lorem-intros.php @@ -0,0 +1,721 @@ +latest_published_posts(0, 900, 'id, title, intro'); +$tags = $wiki->all_tags(); + +shuffle($posts); +shuffle($titles); + + +for ($i = 0 ; $i < 500 ; $i++) { + // $wiki->set_intro($posts[$i]['id'], some_lorem_intro()); + // $wiki->set_status($posts[$i]['id'], 0); + // $wiki->set_title($posts[$i]['id'], $titles[$i]); + shuffle($tags); + $c = ($i % 3) + 1; + for ($j = 0; $j < $c; $j ++) { $wiki->link_tag_to_post($tags[$j]['id'], $posts[$i]['id']); } +} +echo "done!"; + + + diff --git a/public/app/views/simple/lorem-posts.php b/public/app/views/simple/lorem-posts.php new file mode 100644 index 0000000..5f7fccb --- /dev/null +++ b/public/app/views/simple/lorem-posts.php @@ -0,0 +1,93 @@ +". $lorem[$i] ."

    "; + } + + return $html; +} + +function some_lorem_title() { + // make an array of + $lorem = explode(".", // sentences only + str_replace(". ", ".", + implode(" ", LOREM) // made from all Lorem-ipsums + ) + ); + shuffle($lorem); + return $lorem[0]; +} + + +include 'pythia.php'; + + +$categories = $wiki->get_categories(); + +$non_root = []; +foreach($categories as $node) { + if (intval($node['parent_id']) > 0) { $non_root[] = $node['id']; } + // if (intval($node['parent_id']) > 5) { $non_root[] = $node['id']; } +} +// print_r($non_root); die(); + +echo "
    ";
    +for( $i = 0 ; $i < 250 ; $i++ ) {
    +
    +    $temp = $non_root;
    +    shuffle($temp);
    +
    +    $post = [
    +        'title' => some_lorem_title(),
    +        'category' => intval($temp[0]),
    +        'body' => some_lorem_html()
    +    ];
    +    print_r($post);
    +
    +    $wiki->add_post($post);
    +}
    +echo "
    "; \ No newline at end of file diff --git a/public/app/views/simple/post.php b/public/app/views/simple/post.php new file mode 100644 index 0000000..9e37cd9 --- /dev/null +++ b/public/app/views/simple/post.php @@ -0,0 +1,236 @@ +get_post($post_id); +$categories = $wiki->category_tree(); +$breadcrumbs = Render::all_breadcrumbs($categories); + +if ($post == false) { // when post not found + $post = [ // create a virtual record with error messages + 'id' => 0, + 'title' => 'Το άρθρο που αναζητήσατε δεν υπάρχει', + 'category_id' => 0, + 'intro' => 'Για να βρειτε το άρθρο που ψάχνετε χρησιμοποιήστε την αναζήτηση + του wiki ή πλοηγηθείτε στο δέντρο των κατηγοριών.', + 'body' => "" + ]; + +} else { // post found; prepare article's data to render + + $category_id = $post['category_id']; + + // find parent_ids of current category (to open the menu tree) + $category_path = []; + foreach($breadcrumbs[$category_id]['parents'] as $parent) { + $category_path[] = intval($parent['id']); + } + $category_path[] = intval($category_id); + +} + + +// format special parts of post +$parsedown = new Parsedown(); +$body_html = $parsedown->text($post['body']); // body: markdown to html + +// decode json output (tags + medias) +if ($post['tags_json'] != null) { $tags = json_decode($post['tags_json']); } +if ($post['medias_json'] != null) { $medias = json_decode($post['medias_json']); } + + +// then render the page ... +// ----------------------------------------------------------------------------- +?> + + + + Wiki + + false ]); ?> + + + + +
    + +
    + + +
    + +
    + +
    + +
    + + + +
    + + +
    + + +

    + + + + + + + + +

    + + + + + + +

    + + + +
    + +
    + + + +
    +

    Συνημμένα:

    +
      + + reference == 1) : ?> +
    1. + + title?> + +
    2. + + +
    +
    + + + + +
    + Επικέτες: + + name?> + +
    + + +
    + +
    + +
    +
    + + + + + + + + + + + + + + diff --git a/public/app/views/templates/course.php b/public/app/views/templates/course.php new file mode 100644 index 0000000..1d212b8 --- /dev/null +++ b/public/app/views/templates/course.php @@ -0,0 +1,93 @@ + + + + + <?=SITE_TITLE?> - <?=$title?> + + + + + + + $id, + 'label' => $breadcrumbs[ $id ]['rec']['label'], + 'parents' => $breadcrumbs[ $id ]['parents'] + ]); + ?> + + +
    +
    + + + +
    + + +

    + +

    + + + + $id, + 'breadcrumbs' => $breadcrumbs + ]) + ?> + + + + + +
    Μαθήματα
    + + $lessons, + 'fieldset' => ['intro', 'level'] // ['intro', 'date'] + ]); + ?> + + + + + +
    + +
    +
    + +
    +
    + + $entity ]); + ?> + +
    +
    + + + + + diff --git a/public/app/views/templates/lesson.php b/public/app/views/templates/lesson.php new file mode 100644 index 0000000..0867cd3 --- /dev/null +++ b/public/app/views/templates/lesson.php @@ -0,0 +1,82 @@ + + + + + <?=SITE_TITLE?> - <?=$title?> + + + + + + + $id, + 'label' => $breadcrumbs[ $course_id ]['rec']['label'], + 'parents' => $breadcrumbs[ $course_id ]['parents'] + ]); + ?> + + +
    +
    + + + +
    + + +

    + +

    + + + +

    + + + +
    + text($lesson['body']); + + ?> +
    + + +
    + +
    +
    + +
    +
    + + $entity ]); + ?> + +
    +
    + + + + + diff --git a/public/app/views/templates/page.php b/public/app/views/templates/page.php new file mode 100644 index 0000000..6afe45e --- /dev/null +++ b/public/app/views/templates/page.php @@ -0,0 +1,64 @@ + + + + + <?=SITE_TITLE?> - <?=$page['title']?> + + + + + + + 0, + 'label' => '', + 'parents' => [] + ]); + ?> + + +
    + + +
    + + +

    + +

    + + +
    + text($page['body']); + + ?> +
    + + +
    + +
    + +
    +
    + + $entity ]); + ?> + +
    +
    + + + + + diff --git a/public/app/views/user/login.php b/public/app/views/user/login.php new file mode 100644 index 0000000..1a59d43 --- /dev/null +++ b/public/app/views/user/login.php @@ -0,0 +1,91 @@ + + + + + <?=SITE_TITLE?> - Είσοδος Χρήστη + + + + + + +
    +
    +

    Είσοδος Χρήστη

    +
    +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +
    + + + + + diff --git a/public/app/views/user/new-password.php b/public/app/views/user/new-password.php new file mode 100644 index 0000000..06e7fac --- /dev/null +++ b/public/app/views/user/new-password.php @@ -0,0 +1,65 @@ + + + + + <?=SITE_TITLE?> - Επαναφορά κωδικού πρόσβασης + + + + + + + + + + + + +
    +
    +

    Επαναφορά κωδικού πρόσβασης

    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +
    + + diff --git a/public/app/views/user/registration.php b/public/app/views/user/registration.php new file mode 100644 index 0000000..f0a110c --- /dev/null +++ b/public/app/views/user/registration.php @@ -0,0 +1,120 @@ + + + + + <?=SITE_TITLE?> - Εγγραφή + + + + + + +
    +
    +
    +

    Classroom: Εγγραφή

    +
    +
    +
    +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + + +
    +
    + +
    +
    +
    +
    +

    Αν έχετε ήδη λογαρισμό συνδεθείτε.

    +

    Σε κάθε περίπτωση μπορείτε να επιστρέψετε στην αρχική σελίδα.

    +
    +
    +
    + + + + + diff --git a/public/app/views/welcome.php b/public/app/views/welcome.php new file mode 100644 index 0000000..c5552a8 --- /dev/null +++ b/public/app/views/welcome.php @@ -0,0 +1,71 @@ + + + + + <?=SITE_TITLE?> - Welcome! + + + + + + + + + +
    +
    + + + +
    + the content goes here +
    + +
    +
    + + + + + + + + + +
    +
    + + $entity ]); + ?> + +
    +
    + + + + + \ No newline at end of file diff --git a/public/assets/css/admin.css b/public/assets/css/admin.css new file mode 100644 index 0000000..4bd8718 --- /dev/null +++ b/public/assets/css/admin.css @@ -0,0 +1,150 @@ +:root { + --class-btn-blue: #337ab7; + --class-btn-cyan: #5bc0de; + --class-btn-grey: #c9c9c9; + --class-btn-grey-light: #c9c9c999; +} + +.classroom .manage { + width: 100%; + max-width: 1600px; + margin: 0 auto 2em; +} +.classroom .manage.maximized { max-width: 1960px; } +.classroom .manage.minimized { max-width: 960px; } +.classroom .manage.edit-post { max-width: 1420px; } + +.classroom .edit-post textarea[name=intro] { height: 12vh; } +.classroom .edit-post textarea[name=body] { + height: calc(100vh - 492px); + min-height:320px; + font-family: Consolas, 'Ubuntu Mono','Courier New', Courier, monospace; + color: #333; +} + +.classroom .edit-post .post-media button.over-bar { margin: -26px 0 0 0; } +.classroom .edit-post .post-media ul { + border: 1px solid #ccc; + border-radius: 4px; + padding: 6px; +} + +.classroom .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; +} +.classroom .edit-post .post-media ul li:last-child { border-bottom: none ;} +.classroom .edit-post .post-media ul li:hover { background: #eee; } + +.classroom .manage h2 { + font-size: 20px; + color: #445; + margin: 20px 0; +} + +.classroom .manage.edit-post textarea { width: 100% !important;} +.classroom .manage.edit-post .select2-selection { min-height: 34px; } + +.classroom .manage.edit-post select#status.published { + background-color: #5cb85c; + border-color: #4cae4c; + color: #fff; + text-align: center; +} +.classroom .manage.edit-post select#status option { + background: #fff; + color: #333; +} + +/* --- optional fields: defaut=hide --- */ + +.classroom .edit-post .optional label { + margin-bottom: 1em; + padding-bottom: .5em; + border-bottom: 1px solid var(--class-btn-grey-light) +} +.classroom .edit-post .optional label.show { + margin-bottom: unset; + border: none; +} + + +.classroom .edit-post .optional label:hover { + cursor: pointer; + color: var(--class-btn-blue); +} +.classroom .edit-post .optional label::after { float: right; content: "+"; } +.classroom .edit-post .optional label.show::after { content: "–"; } +.classroom .edit-post .optional label + div { display: none; } +.classroom .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; } + +.classroom .title-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 8px 8px 16px; +} + +.classroom .action-btn button { float: right; } + +.classroom .top-bar { padding: 4px 0; } + +.classroom .top-bar .breadcrumb .btn { + margin-left: 0; + margin-right: 8px; + border-radius: 3px; + color: var(--class-btn-blue); +} + +.classroom .top-bar .btn:hover { + background-color: var(--class-btn-grey-light); +} +.classroom .top-bar .btn.selected { + color: #fff; + background-color: var(--class-btn-blue); +} + + +/* --- dataTables --- */ + +.classroom .manage .dataTable tbody tr:hover { background: #f8f8f8; } +.classroom .manage .dataTable .dt-actions { width: 48px; text-align: right } + +/* --- unpublished posts -- */ +.classroom .manage .dataTable .fa-eye-slash { color: #999; } + + +.classroom .js-copy:hover::after { + opacity: 0; + pointer-events: none; + background: #ddd7; + border-radius: 2px; + content: "Copy"; + padding: .25em .75em; + position: absolute; + z-index: 10; + transform-origin: top; + margin-top: -16px; + transform: translate(-50%, 0); +} + +.classroom .js-copy.copied:hover::after { + content: "Αντιγράφηκε"; + opacity: 1; + margin-top: -22px; + transform: translate(-50%, 0); + transition: all 0.18s ease-out 0.18s; + background: #eee; + border: 1px solid #ddd9; +} + + \ No newline at end of file diff --git a/public/assets/css/class.css b/public/assets/css/class.css new file mode 100644 index 0000000..5252975 --- /dev/null +++ b/public/assets/css/class.css @@ -0,0 +1,394 @@ +/** Classroom sections + * (main layout css-classes) + * ----------------------------------------------------------------------------- + * .classroom { + * .top-bar { + * .breadcrumb + * .admin + * } + * .side-bar { + * .search + * .categories + * } + * .content + * } + * ----------------------------------------------------------------------------- + */ + + +/* Variables + * ---------------------------------------------------------------------------- + */ + +:root { + --class-blue: #337ab7; + --class-blue-opaque: #337ab799; + --class-blue-dark: #082e44; + --class-orange: #f47920; + --class-orange-opaque: #f4792099; + --class-grey-background: #eeedeb; + --class-red: #d13; + --light-grey-bgr: #f2f3f8; +} + + + +/* main layout classes + * ---------------------------------------------------------------------------- + */ + +.classroom .top-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 14px; + border-bottom: 1px solid #ddd; + box-shadow: 1px 1px 7px #9997; + background: var(--light-grey-bgr); +} + +.classroom .top-bar .breadcrumb { margin: 0; padding: 0; background: none; } + +.classroom .top-bar .fa, +.classroom .top-bar .fas { + width: 32px; + text-align: center; +} + + + +.classroom .main-content { + padding: 1.5em; + max-width: 1440px; + min-height: calc(100vh - 345px); +} + + +/* category list menu + * ----------------------------------------------------------------------------- + */ + +.classroom .side-bar { padding-right: 1em; } + + +.classroom .side-bar h3 { + font-weight: 600; font-size: 1em; + color: var(--class-blue); +} + + /* --- ul > li > a --- */ + +.classroom .side-bar ul { list-style: none; padding: 0; } +.classroom .side-bar ul li { margin: 0.5em 0; } +.classroom .side-bar ul li a { + display: flex; + padding: .2em; + background: #4442; + border-radius: 6px; + transition: background 0.3s; +} +.classroom .side-bar ul li a:hover, +.classroom .side-bar ul li a:active { + background: #cde; + text-decoration: none; +} + +/* --- li > a > span --- */ + +.classroom .side-bar ul li a span { + display: block; + align-self: center; + padding: .3em; +} +.classroom .side-bar ul li a .label { + font-size: 13px; + color: var(--class-blue-dark); + flex-grow: 1; + text-align: left; + padding-left: 1em; + border-radius: 6px; + white-space: normal; + font-weight: 400; +} + +/* --- inner --- */ + +.classroom .side-bar ul .inner { + padding-left: 1em; + overflow: hidden; + display: none; +} +.classroom .side-bar ul .inner.show { display: block; } + +/* --- has-childs | toggler --- */ + +.classroom .side-bar ul li a.has-childs { background: #9bf4; } +.classroom .side-bar ul li a.has-childs:hover { background: #cde;} + +.classroom .side-bar ul li a.has-childs .label { + font-weight: 600; + border-radius: 6px 0 0 6px; + width: calc(100% - 36px); +} + +.classroom .side-bar ul li a.has-childs .toggler { + text-align: center; + width: 32px; + font-size: 15px; + border-radius: 4px; + background: #7774; + font-weight: 700; +} +.classroom .side-bar ul li a.has-childs .toggler:hover { + background: var(--class-blue); + color: #fff; +} +.classroom .side-bar ul li a.selected { + background: var(--class-orange-opaque); +} +.classroom .side-bar ul li a:hover, +.classroom .side-bar ul li a:active, +.classroom .side-bar ul li a:focus, +.classroom .side-bar ul li a:visited, +.classroom .side-bar ul li a:link, +.classroom .side-bar ul li a span:hover, +.classroom .side-bar ul li a span:active, +.classroom .side-bar ul li a span:focus, +.classroom .side-bar ul li a span:visited, +.classroom .side-bar ul li a span:link, +.classroom .side-bar ul li a span:target { text-decoration: none !important; } + + + +.classroom .lesson-view img { max-width: 100%; } + + + +/** breadcrumb + * ----------------------------------------------------------------------------- + */ + +.classroom .breadcrumb a { counter-reset: var(--class-blue); font-size: 14px; } +.classroom .breadcrumb i.fas { padding-top: 7px; font-size: 12px; } + + + + +/** content + * ----------------------------------------------------------------------------- + */ + +.classroom .content--wrapper { + max-width: 1024px; + width: 100%; + margin: 1em auto; + padding: 0 2em 2em 2em; +} +.classroom .content h2 { + font-weight: 700; + font-size: 24px; + padding: 8px 3em 1em 0; /* 1em 3em 1em 0; */ + color: var(--class-blue-dark); +} +.classroom .content h3 { + font-weight: 600; font-size: 1.4em; + padding: 1em 3em 1em 0; + color: var(--class-blue); + border-bottom: 1px dashed var(--class-blue-opaque); +} +.classroom .content h3 span { font-weight: 400; color: #444; } +.classroom .content p { + line-height: 150%; + padding: 5px 0; +} + +/* --- post: medias -- */ +/* DEPRICATED: not needed +.classroom .content--wrapper .medias { + padding: 2em 0 1em; + border-top: 1px solid var(--class-grey-background); +} +.classroom .content--wrapper .medias ol li { + margin-left: -12px; + padding: 2px 8px; +} +.classroom .content--wrapper .medias ol li::marker { + font-size: 12px; + color: #999; +} +*/ + +/* --- post: tags --- */ + +.classroom .content--wrapper .tags { + padding: 2em 0 1em; + border-top: 1px solid var(--class-grey-background); +} +.classroom .content--wrapper .tags a { + color: #444; + background-color: var(--class-grey-background); + padding: 6px 12px; + margin: 6px; + border-radius: 3px; +} + + + +.classroom .course-view h5 { padding-top: 2em; } + +/** sub-categories on category page + * ----------------------------------------------------------------------------- + */ +/* +.classroom .category-childs { margin: 1em; padding: 1em; } + +.classroom .category-childs a { + display: inline-block; + margin: .5em; + padding: .2em 2em; + border-radius: 2em; + border: 1px solid var(--class-blue); + line-height: 2em; + font-weight: 600; + transition: background 0.3s; +} + +.classroom .category-childs a:hover { + background-color: var(--class-blue); + color: #fffe; + text-decoration: none; +} + +*/ + + + +/** articles-list + * ----------------------------------------------------------------------------- + * 22 | Title of artivle + * July | path / of / categories + * 2023 | * some intro of article + * ----------------------------------------------------------------------------- + */ +.classroom .post-card { + padding-top: .75em; + margin: 0; + border-bottom: 1px solid #7773; + display: flex; +} +.classroom .post-card .post-card--content { + flex-grow: 1; + width: calc(100% - 90px); +} +.classroom .post-card h3 { padding: 0; margin: 0; border: none; font-size: 20px; } +.classroom .post-card h3 a { display: block; } +.classroom .post-card h3 a:hover { color: #f47920; } +.classroom .post-card .category { color: #566; } +.classroom .post-card .intro { + font-style: italic; + font-size: 16px; +} +/* --- date block --- */ +.classroom .date { + display: flex; + flex-direction: column; + width: 90px; +} +.classroom .date p { + padding: 0; margin: 0; + line-height: 115%; + text-align: center; +} +.classroom .date .day { font-size: 24px; color: var(--class-blue-opaque); } +.classroom .date .month { font-size: 16px; color: #555; } +.classroom .date .year { font-size: 12px; color: #666; } + + + + +.classroom .content-form h3 { color: #369; opacity: 0.9; } + + + + +/** post (article) + * ----------------------------------------------------------------------------- + */ + + + +.classroom .lesson-view h2 { padding-bottom: 0; font-size: 24px; } + +.classroom .lesson-view h2 span { float:right; margin-right: -3em;} + +.classroom .lesson-view pre { padding: 1em; background: #f5f5f6;} + +.classroom .lesson-view .intro { + font-style: italic; + font-size: 18px; + color: var(--class-blue-dark); + padding-bottom: 1em; +} + +.classroom .lesson-view .post--date { + padding: 0; + color: var(--class-blue); +} + +.classroom .article-body img { + display: block; + max-width: 100%; + margin: 1em auto; +} +/* +.classroom .article-body a.modal-toggler { + padding: 0 16px; + background: #def; + color: #334; + border-radius: 3px; + text-decoration: none; + border: 1px solid var(--class-blue-opaque); +} +.classroom .article-body a.modal-toggler:hover { background: var(--class-blue); color: #fff; } +*/ +.classroom .article-body table { + margin: 20px auto; + min-width: 67%; + border-spacing: 6px 0; + border-collapse: separate; +} +.classroom .article-body table tr { margin: 4px; } +.classroom .article-body table thead th { + color: var(--class-btn-blue); + border-bottom: 3px solid var(--class-blue); + padding: 0 8px; + text-align: revert-layer; +} +.classroom .article-body table tbody td { + padding: 6px 8px; + border-bottom: 1px solid var(--class-grey-background); +} + + + +.classroom footer { + margin: 2em 0 0 0; + padding: 2.5em 0; + font-size: .87em; + background: #f5f6f7; +} +.classroom footer a { + color: #024; + text-decoration: none; + padding: 2px 36px 2px 4px; + border-radius: 3px; +} +.classroom footer a:hover { color: #fff; background: #369 ; } +.classroom footer h4 { font-size: 20px; } +.classroom footer .no-list-mark ul { padding-left: 0; margin-left: 0; list-style: none; } +.classroom footer .no-list-mark ul li { margin: 0 0 4px 0; } + + +.classroom .page-container { max-width: 1024px; } + +iframe .ytp-chrome-top-buttons { display: none !important; } \ No newline at end of file diff --git a/public/assets/css/email.css b/public/assets/css/email.css new file mode 100644 index 0000000..0bb6d48 --- /dev/null +++ b/public/assets/css/email.css @@ -0,0 +1,478 @@ +p { + margin: 10px 0; + padding: 0; + color: #0E0C0C; + font-family: Arial, Helvetica, sans-serif; + font-style: normal; + font-weight: normal; + font-size: 15px; + line-height: 24px; + letter-spacing: normal; +} + +table { + border-collapse: collapse; +} + +h1, h2, h3, h4, h5, h6 { + display: block; + margin: 0; + padding: 0; +} + +img, a img { + border: 0; + height: auto; + outline: none; + text-decoration: none; +} + +body, #bodyTable, #bodyCell { + height: 100%; + margin: 0; + padding: 0; + width: 100%; +} + +.mcnPreviewText { + display: none !important; +} + +#outlook a { + padding: 0; +} + +img { + -ms-interpolation-mode: bicubic; +} + +table { + mso-table-lspace: 0pt; + mso-table-rspace: 0pt; +} + +.ReadMsgBody { + width: 100%; +} + +.ExternalClass { + width: 100%; +} + +p, a, li, td, blockquote { + mso-line-height-rule: exactly; +} + + a[href^=tel], a[href^=sms] { + color: inherit; + cursor: default; + text-decoration: none; + } + +p, a, li, td, body, table, blockquote { + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} + +.ExternalClass, .ExternalClass p, .ExternalClass td, .ExternalClass div, .ExternalClass span, .ExternalClass font { + line-height: 100%; +} + +a[x-apple-data-detectors] { + color: inherit !important; + text-decoration: none !important; + font-size: inherit !important; + font-family: inherit !important; + font-weight: inherit !important; + line-height: inherit !important; +} + +.templateContainer { + max-width: 700px !important; +} + +a.mcnButton { + display: block; +} + +.mcnImage, .mcnRetinaImage { + vertical-align: bottom; +} + +.mcnTextContent { + word-break: break-word; +} + + .mcnTextContent img { + height: auto !important; + } + +.mcnDividerBlock { + table-layout: fixed !important; +} + +.noBorder { + border: none !important; +} + +h1 { + color: #333333; + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + font-style: normal; + font-weight: bold; + line-height: 24px; + letter-spacing: -0.02em; + text-align: center; + padding-bottom: 14px; +} + +h2 { + color: #0E0C0C; + font-family: Arial, Helvetica, sans-serif; + font-size: 22px; + font-style: normal; + font-weight: bold; + line-height: 30px; + letter-spacing: normal; + text-align: center; + text-transform: uppercase; + padding-bottom: 8px; +} + +h3 { + color: #0E0C0C; + font-family: Arial, Helvetica, sans-serif; + font-size: 22px; + font-style: normal; + font-weight: bold; + line-height: 30px; + letter-spacing: normal; + text-align: center; + text-transform: uppercase; + padding-bottom: 8px; +} + +h4 { + color: #0E0C0C; + font-family: Arial, Helvetica, sans-serif; + font-size: 22px; + font-style: normal; + font-weight: bold; + line-height: 30px; + letter-spacing: normal; + text-align: center; + text-transform: uppercase; + padding-bottom: 8px; +} + + h1 span, + h2 span, + h3 span, + h4 span { + font-weight: normal; + text-transform: none; + } + +#templateHeader { + background-color: #ffffff; + background-image: none; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + border-top: 0; + border-bottom: 1px solid #e3e3e3; + padding-top: 0px; + padding-bottom: 20px; +} + + #templateHeader.default { + border: none; + padding: 0; + } + +.headerContainer { + background-color: transparent; + background-image: none; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + border-top: 0; + border-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} + + .headerContainer .mcnTextContent, .headerContainer .mcnTextContent p { + color: #757575; + font-family: Arial, Helvetica, sans-serif; + font-size: 16px; + line-height: 150%; + text-align: left; + } + + .headerContainer .mcnTextContent a, .headerContainer .mcnTextContent p a { + color: #007C89; + font-weight: normal; + text-decoration: underline; + } + +#templateBody { + background-color: #ffffff; + background-image: none; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + border-top: 0; + border-bottom: 0; + padding-top: 24px; + padding-bottom: 32px; +} + + #templateBody a { + color: #F47920; + text-decoration: none; + } + + #templateBody p { + margin: 0; + color: #333333; + font-family: Arial, Helvetica, sans-serif; + font-size: 15px; + font-style: normal; + font-weight: normal; + line-height: 22px; + letter-spacing: -0.02em; + padding-bottom: 5px; + } + +#templateBodyMsg p { + max-width: 586px; +} + +.bodyContainer { + background-color: transparent; + background-image: none; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + border-top: 0; + border-bottom: 0; + padding-top: 0; + padding-bottom: 0; +} + + .bodyContainer .mcnTextContent, + .bodyContainer .mcnTextContent p { + color: #333333; + font-family: Arial, Helvetica, sans-serif; + font-size: 15px; + line-height: 150%; + text-align: left; + } + + .bodyContainer .mcnTextContent a, + .bodyContainer .mcnTextContent p a { + color: #F47920; + font-weight: normal; + text-decoration: underline; + } + +#templateAfterFooter p { + margin: 0; + color: #333333; + font-family: Arial, Helvetica, sans-serif; + font-size: 13px; + font-style: normal; + font-weight: normal; + line-height: 24px; + letter-spacing: 0.02em; +} + + #templateAfterFooter p a { + margin: 0; + color: #F47920; + font-family: Arial, Helvetica, sans-serif; + font-size: 13px; + font-style: normal; + font-weight: normal; + line-height: 24px; + letter-spacing: 0.02em; + } + +#templateFooter { + background-color: #333333; + background-image: none; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + border-top: 0; + border-bottom: 0; + padding-top: 16px; + padding-bottom: 16px; +} + +.footerContainer { + background-color: transparent; + background-image: none; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + border-top: 0; + border-bottom: 0; + padding-top: 0px; + padding-bottom: 0px; + max-width: 700px !important; +} + + .footerContainer .bodyContainer { + padding: 0 30px; + } + + .footerContainer ul { + padding: 0; + margin: 0; + list-style-type: none; + text-align: center; + } + + .footerContainer ul li { + display: inline-block; + margin-right: 30px; + } + + .footerContainer ul li:last-child { + margin-right: 0; + } + + .footerContainer .mcnTextBlockInner, + .footerContainer .mcnTextBlockInner p { + color: #FFF; + font-family: Arial, Helvetica, sans-serif; + font-size: 15px; + line-height: 24px; + letter-spacing: 0.02em; + } + + .footerContainer .mcnTextBlockInner a, + .footerContainer .mcnTextBlockInner p a { + color: #FFF; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + line-height: 18px; + text-decoration: none; + } + +.templateHeroContainer { + max-width: 700px; +} + +.heroContainer { + position: relative; +} + + .heroContainer img { + display: block; + width: 100%; + height: auto; + } + + .heroContainer p { + color: #FFF; + font-family: Arial, Helvetica, sans-serif; + font-size: 40px; + line-height: 50px; + letter-spacing: -0.02em; + text-transform: uppercase; + padding: 0 120px; + position: absolute; + left: 0; + bottom: 80px; + width: 100%; + text-align: center; + font-weight: normal; + margin: 0; + } + +#templateProducts { + padding: 0 0 90px; +} + + #templateProducts .mcnTextBlockInner { + padding: 0 20px; + } + + #templateProducts span { + display: block; + font-family: Arial, Helvetica, sans-serif; + font-size: 15px; + line-height: 24px; + font-weight: bold; + text-transform: uppercase; + padding-top: 10px; + } + +.column { + display: inline-block; + vertical-align: top; + width: 50%; +} + +.label { + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + line-height: 24px; + font-weight: bold; + text-transform: uppercase; + color: #0E0C0C; + padding-bottom: 2px; +} + +strong { + font-family: Arial, Helvetica, sans-serif; + font-weight: bold; +} + +.tdMinWidth { + max-width: 310px; +} + +@media only screen and (max-width:700px) { + .templateContainer { + width: 360px !important; + } + + .bodyContainer { + padding-left: 0 !important; + padding-right: 0 !important; + } + + .footerContainer ul li { + display: block; + margin-right: 0; + margin-bottom: 16px; + } + + .footerContainer ul li:last-child { + margin-bottom: 0; + } + + .heroContainer p { + font-size: 30px; + line-height: 40px; + padding: 0 30px; + bottom: 30px; + } + + .tdMinWidth { + max-width: 200px; + } + + .halfColumn { + padding: 20px 10px 0 !important; + } +} + +/* td { + outline: 1px solid red; +}*/ \ No newline at end of file diff --git a/public/assets/css/main.css b/public/assets/css/main.css new file mode 100644 index 0000000..016e0ab --- /dev/null +++ b/public/assets/css/main.css @@ -0,0 +1,9 @@ +: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 new file mode 100644 index 0000000..192eb9c --- /dev/null +++ b/public/assets/css/normalize.css @@ -0,0 +1,349 @@ +/*! 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/css/overides.css b/public/assets/css/overides.css new file mode 100644 index 0000000..f9d351c --- /dev/null +++ b/public/assets/css/overides.css @@ -0,0 +1,148 @@ +:root { + --bs-heading-color: #679; +} + +html, body { font-family: "Roboto Slab", serif; font-weight: 400; } + +.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 { font-weight: 400; }; + +.content { text-align: unset; } + +.form-control { border: 1px solid #7777; } + +.form-label { font-size: .72em; color: var(--bs-heading-color); } + + + + +/* main.min.css */ +.product__img { + /* max-width: 320px; */ + max-width: 240px; +} + +.footer__listLink { + color: #bbb; +} +.footer__listLink:hover { + color: #eee; +} + +.footer__title { color: #bbb7; } + +/* .user .dropdown button { min-width: 256px; } */ +.user .dropdown ul.dropdown-menu { + right: 0 !important; + left: unset !important; + transform: translate(0, 34px) !important; +} + +.admin-container { font-size: .96em; } +.admin-container .top-bar a:hover { background: #ddd; } + +.admin-container .manage { padding: 1em; } + +.admin-container .title-bar { + display: flex; + justify-content: space-between; + align-items: center; + padding: 1.5em 1em 1.5em 1em; + } + +.admin-container .dt-table { font-size: 14px; } + +.admin-container .dt-table .btn-sm { + --bs-btn-padding-y: .2rem; + --bs-btn-padding-x: .35rem; + --bs-btn-font-size: .65rem; + } + +.admin-container .modal .form-group { padding: .35em 0;} +/*.admin-container .modal .form-control { padding: 1px 8px; border-radius: 4px; font-size: 15px; } */ + +.admin-container .table > :not(caption) > * > * { padding: .35rem .35rem; } +.admin-container .table tbody tr:hover { background: #eee; } + +ul.select2-results__options li { font-size: 14px; padding: 4px 8px; } + +.admin-container .modal-footer .form-actions { display: flex; gap: 8px; } + +.admin-container .title-bar h5 { margin-bottom: 0; color: #333; } + +.admin-container table.dataTable { margin-top: 1em !important; margin-bottom: 1em !important;} + +.admin-container .title-bar .btn { border: 1px solid #7772; } +.admin-container .title-bar .btn:hover { background: #ddd; } + +.admin-container form label { padding: 8px 1em 2px 1em; } + +.admin-container .form-control { border-radius: 4px; } + +.admin-container select[data-chosen='one'] { + font-weight: 700; + color: #0d6efd; + border: 1px solid #0d6efd; +} + +/* hack select2 caret styling + * (like bootstrap5 select caret) + * ----------------------------------------------------------------------- start + */ +.select2-container--default .select2-selection--single .select2-selection__arrow b { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); + background-color: transparent; + background-size: contain; + border: none !important; + height: 16 !important; + width: 12px !important; + margin: auto !important; + top: 9px !important; + left: auto !important; + height: 14px; +} +.select2-container--default .select2-selection--single .select2-selection__arrow { width: 24px; } +.select2-container--default .select2-selection--single { height: 31px; } +/* ------------------------------------------------------------------------- end +*/ + +.admin-container .edit-post textarea[name=body] { + height: calc(100vh - 420px); /* almost all avialable height */ +} + +.admin-container .edit-page textarea[name=body] { + height: calc(100vh - 380px); /* almost all avialable height */ +} + +.admin-container .edit-post textarea[name=intro] { height: 94px ;} /* almost 3 (half-)lines */ + +.admin-container .edit-post textarea[name=body] { + height: calc(100vh - 420px); /* almost all avialable height */ +} + +.admin-container .post-media button.over-bar { margin: -26px 0 0 0; float: right; } +.admin-container .post-media ul { + border: 1px solid #ccc; + border-radius: 4px; + padding: 6px; +} + +.admin-container .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; +} +.admin-container .post-media ul li:last-child { border-bottom: none ;} +.admin-container .post-media ul li:hover { background: #eee; } + +.admin-container .post-media li .btn-xs { font-size: 14px; width: 24px; height: 24px; padding:0; } + +.classroom .edit-post textarea[name=body], +.classroom .edit-page textarea[name=body] { + min-height:320px; + font-family: Consolas, 'Ubuntu Mono','Courier New', Courier, monospace; + color: #333; + } \ No newline at end of file diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.css new file mode 100644 index 0000000..c1445d4 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.css @@ -0,0 +1,386 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + background-color: white; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + padding: 0.5rem; + min-width: 200px; +} +div.dt-button-collection div.dropdown-menu, +div.dt-button-collection ul.dropdown-menu { + position: relative; + display: block; + z-index: 2002; + min-width: 100%; + background-color: transparent; + border: none; + box-shadow: none; + margin: 2px 0; + padding: 0; + border-radius: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; + display: inline-flex; + padding-left: 5px; + padding-right: 5px; +} +div.dt-button-collection button.dt-btn-split-drop-button { + width: 100%; + border: none; + border-radius: 0px; + margin-left: 0px !important; +} +div.dt-button-collection button.dt-btn-split-drop-button:focus { + border: none; + border-radius: 0px; + outline: none; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection .dt-button { + min-width: 200px; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 2001; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +div.dt-btn-split-wrapper button.dt-btn-split-drop { + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button { + background-color: #e6e6e6; + border-color: #adadad; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #fff; + border-color: rgb(173, 173, 173); +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover { + background-color: #e6e6e6; + border-color: #adadad; +} + +span.dt-down-arrow { + color: rgba(70, 70, 70, 0.9); + font-size: 10px; + padding-left: 10px; +} + +div.dataTables_wrapper div.dt-buttons.btn-group button.btn:last-of-type:first-of-type { + border-radius: 4px !important; +} + +span.dt-down-arrow { + display: none; +} + +span.dt-button-spacer { + float: left; +} +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + padding-left: 1rem !important; + text-align: left; +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.min.css new file mode 100644 index 0000000..54e96b6 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;background-color:white;border:1px solid rgba(0, 0, 0, 0.15);border-radius:4px;box-shadow:0 6px 12px rgba(0, 0, 0, 0.175);padding:.5rem;min-width:200px}div.dt-button-collection div.dropdown-menu,div.dt-button-collection ul.dropdown-menu{position:relative;display:block;z-index:2002;min-width:100%;background-color:transparent;border:none;box-shadow:none;margin:2px 0;padding:0;border-radius:0}div.dt-button-collection div.dt-btn-split-wrapper{width:100%;display:inline-flex;padding-left:5px;padding-right:5px}div.dt-button-collection button.dt-btn-split-drop-button{width:100%;border:none;border-radius:0px;margin-left:0px !important}div.dt-button-collection button.dt-btn-split-drop-button:focus{border:none;border-radius:0px;outline:none}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection .dt-button{min-width:200px}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:2001}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-btn-split-wrapper button.dt-btn-split-drop{border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button{background-color:#e6e6e6;border-color:#adadad}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#fff;border-color:rgb(173, 173, 173)}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover{background-color:#e6e6e6;border-color:#adadad}span.dt-down-arrow{color:rgba(70, 70, 70, 0.9);font-size:10px;padding-left:10px}div.dataTables_wrapper div.dt-buttons.btn-group button.btn:last-of-type:first-of-type{border-radius:4px !important}span.dt-down-arrow{display:none}span.dt-button-spacer{float:left}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{padding-left:1rem !important;text-align:left} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.css new file mode 100644 index 0000000..b5d9244 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.css @@ -0,0 +1,430 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + background-color: white; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + padding: 0.5rem; + width: 218px; +} +div.dt-button-collection div.dropdown-menu { + position: relative; + display: block; + z-index: 2002; + min-width: 100%; + background-color: transparent; + border: none; + box-shadow: none; + padding: 0; + border-radius: 0; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection.fixed:before, div.dt-button-collection.fixed:after { + display: none; +} +div.dt-button-collection .btn-group { + flex: 1 1 auto; +} +div.dt-button-collection .dt-button { + min-width: 200px; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; + padding-left: 5px; + padding-right: 5px; +} +div.dt-button-collection button.dt-btn-split-drop-button { + width: 100%; + color: #212529; + border: none; + background-color: white; + border-radius: 0px; + margin-left: 0px !important; +} +div.dt-button-collection button.dt-btn-split-drop-button:focus { + border: none; + border-radius: 0px; + outline: none; +} +div.dt-button-collection button.dt-btn-split-drop-button:hover { + background-color: #e9ecef; +} +div.dt-button-collection button.dt-btn-split-drop-button:active { + background-color: #007bff !important; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons div.btn-group { + position: initial; +} + +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button { + background-color: #5a6268; + border-color: #545b62; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #6c757d; + border-color: #6c757d; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover { + background-color: #5a6268; + border-color: #545b62; +} + +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group { + border-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid rgb(108, 117, 125); +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +div.dt-button-collection div.btn-group { + border-radius: 4px !important; +} +div.dt-button-collection div.btn-group button { + border-radius: 4px; +} +div.dt-button-collection div.btn-group button:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid rgb(108, 117, 125); +} +div.dt-button-collection div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + padding-left: 1rem !important; + text-align: left; +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.min.css new file mode 100644 index 0000000..1d97a24 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap4.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;background-color:white;border:1px solid rgba(0, 0, 0, 0.15);border-radius:4px;box-shadow:0 6px 12px rgba(0, 0, 0, 0.175);padding:.5rem;width:218px}div.dt-button-collection div.dropdown-menu{position:relative;display:block;z-index:2002;min-width:100%;background-color:transparent;border:none;box-shadow:none;padding:0;border-radius:0}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection.fixed:before,div.dt-button-collection.fixed:after{display:none}div.dt-button-collection .btn-group{flex:1 1 auto}div.dt-button-collection .dt-button{min-width:200px}div.dt-button-collection div.dt-btn-split-wrapper{width:100%;padding-left:5px;padding-right:5px}div.dt-button-collection button.dt-btn-split-drop-button{width:100%;color:#212529;border:none;background-color:white;border-radius:0px;margin-left:0px !important}div.dt-button-collection button.dt-btn-split-drop-button:focus{border:none;border-radius:0px;outline:none}div.dt-button-collection button.dt-btn-split-drop-button:hover{background-color:#e9ecef}div.dt-button-collection button.dt-btn-split-drop-button:active{background-color:#007bff !important}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons div.btn-group{position:initial}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button{background-color:#5a6268;border-color:#545b62}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#6c757d;border-color:#6c757d}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover{background-color:#5a6268;border-color:#545b62}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group{border-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child{border:1px solid rgb(108, 117, 125)}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper{border:none}div.dt-button-collection div.btn-group{border-radius:4px !important}div.dt-button-collection div.btn-group button{border-radius:4px}div.dt-button-collection div.btn-group button:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dt-button-collection div.btn-group button:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dt-button-collection div.btn-group button:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child{border:1px solid rgb(108, 117, 125)}div.dt-button-collection div.btn-group div.dt-btn-split-wrapper{border:none}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{padding-left:1rem !important;text-align:left} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.css new file mode 100644 index 0000000..7e26228 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.css @@ -0,0 +1,432 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + background-color: white; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: 4px; + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.175); + padding: 0.5rem; + width: 218px; +} +div.dt-button-collection div.dropdown-menu { + position: relative; + display: block; + background-color: transparent; + border: none; + box-shadow: none; + padding: 0; + border-radius: 0; + z-index: 2002; + min-width: 100%; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection.fixed:before, div.dt-button-collection.fixed:after { + display: none; +} +div.dt-button-collection .btn-group { + flex: 1 1 auto; +} +div.dt-button-collection .dt-button:not(.dt-btn-split-drop) { + min-width: 200px; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; +} +div.dt-button-collection button.dt-btn-split-drop-button { + width: 100%; + color: #212529; + border: none; + background-color: white; + border-radius: 0px; + margin-left: 0px !important; +} +div.dt-button-collection button.dt-btn-split-drop-button:focus { + border: none; + border-radius: 0px; + outline: none; +} +div.dt-button-collection button.dt-btn-split-drop-button:hover { + background-color: #e9ecef; +} +div.dt-button-collection button.dt-btn-split-drop-button:active { + background-color: #007bff !important; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons div.btn-group { + position: initial; +} + +div.dt-btn-split-wrapper button.dt-btn-split-drop { + border-top-right-radius: 0.25rem !important; + border-bottom-right-radius: 0.25rem !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button { + background-color: #5a6268; + border-color: #545b62; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #6c757d; + border-color: #6c757d; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover { + background-color: #5a6268; + border-color: #545b62; +} + +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group { + border-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid rgb(108, 117, 125); +} +div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +div.dt-button-collection div.btn-group { + border-radius: 4px !important; +} +div.dt-button-collection div.btn-group button { + border-radius: 4px; +} +div.dt-button-collection div.btn-group button:last-child { + border-top-left-radius: 0px !important; + border-bottom-left-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:first-child { + border-top-right-radius: 0px !important; + border-bottom-right-radius: 0px !important; +} +div.dt-button-collection div.btn-group button:last-child:first-child { + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; +} +div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child { + border: 1px solid rgb(108, 117, 125); +} +div.dt-button-collection div.btn-group div.dt-btn-split-wrapper { + border: none; +} + +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + padding-left: 1rem !important; + text-align: left; +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.min.css new file mode 100644 index 0000000..3103eef --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bootstrap5.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;background-color:white;border:1px solid rgba(0, 0, 0, 0.15);border-radius:4px;box-shadow:0 6px 12px rgba(0, 0, 0, 0.175);padding:.5rem;width:218px}div.dt-button-collection div.dropdown-menu{position:relative;display:block;background-color:transparent;border:none;box-shadow:none;padding:0;border-radius:0;z-index:2002;min-width:100%}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection.fixed:before,div.dt-button-collection.fixed:after{display:none}div.dt-button-collection .btn-group{flex:1 1 auto}div.dt-button-collection .dt-button:not(.dt-btn-split-drop){min-width:200px}div.dt-button-collection div.dt-btn-split-wrapper{width:100%}div.dt-button-collection button.dt-btn-split-drop-button{width:100%;color:#212529;border:none;background-color:white;border-radius:0px;margin-left:0px !important}div.dt-button-collection button.dt-btn-split-drop-button:focus{border:none;border-radius:0px;outline:none}div.dt-button-collection button.dt-btn-split-drop-button:hover{background-color:#e9ecef}div.dt-button-collection button.dt-btn-split-drop-button:active{background-color:#007bff !important}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons div.btn-group{position:initial}div.dt-btn-split-wrapper button.dt-btn-split-drop{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button{background-color:#5a6268;border-color:#545b62}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#6c757d;border-color:#6c757d}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover{background-color:#5a6268;border-color:#545b62}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group{border-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group button.dt-btn-split-drop:last-child{border:1px solid rgb(108, 117, 125)}div.dataTables_wrapper div.dt-buttons.btn-group div.btn-group div.dt-btn-split-wrapper{border:none}div.dt-button-collection div.btn-group{border-radius:4px !important}div.dt-button-collection div.btn-group button{border-radius:4px}div.dt-button-collection div.btn-group button:last-child{border-top-left-radius:0px !important;border-bottom-left-radius:0px !important}div.dt-button-collection div.btn-group button:first-child{border-top-right-radius:0px !important;border-bottom-right-radius:0px !important}div.dt-button-collection div.btn-group button:last-child:first-child{border-top-left-radius:4px !important;border-bottom-left-radius:4px !important;border-top-right-radius:4px !important;border-bottom-right-radius:4px !important}div.dt-button-collection div.btn-group button.dt-btn-split-drop:last-child{border:1px solid rgb(108, 117, 125)}div.dt-button-collection div.btn-group div.dt-btn-split-wrapper{border:none}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{padding-left:1rem !important;text-align:left} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.css new file mode 100644 index 0000000..9d711c5 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.css @@ -0,0 +1,429 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2001; + min-width: 200px; + background: white; + max-width: none; + display: block; + box-shadow: 0 0.5em 1em -0.125em rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.02); + border-radius: 4; + padding: 0.5rem; +} +div.dt-button-collection div.dropdown-menu { + display: block; + z-index: 2002; + min-width: 100%; +} +div.dt-button-collection div.dt-btn-split-wrapper { + width: 100%; + padding-left: 5px; + padding-right: 5px; + margin-bottom: 0px; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-content: flex-start; + align-items: stretch; +} +div.dt-button-collection div.dt-btn-split-wrapper button { + margin-right: 0px; + display: inline-block; + width: 0; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50px; + margin-top: 0px; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + overflow: hidden; + text-overflow: ellipsis; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-button { + min-width: 30px; + margin-left: -1px; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 0; + border-bottom-left-radius: 0px; + border-top-left-radius: 0px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + padding: 0px; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection .dropdown-content { + box-shadow: none; + padding-top: 0; + border-radius: 0; +} +div.dt-button-collection.fixed:before, div.dt-button-collection.fixed:after { + display: none; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 999; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.btn.processing, +div.dt-buttons div.btn.processing, +div.dt-buttons a.btn.processing { + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.btn.processing:after, +div.dt-buttons div.btn.processing:after, +div.dt-buttons a.btn.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons button.button { + margin-left: 5px; +} +div.dt-buttons button.button:first-child { + margin-left: 0px; +} + +span.dt-down-arrow { + display: none; +} + +span.dt-button-spacer { + display: inline-flex; + margin: 0.5em; + white-space: nowrap; + align-items: center; + font-size: 1rem; +} +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + text-align: left; + font-size: 0.875rem; + padding-left: 1rem !important; +} + +div.dt-btn-split-wrapper { + padding-left: 5px; + padding-right: 5px; + margin-bottom: 0px; + margin-bottom: 0px !important; +} +div.dt-btn-split-wrapper button { + margin-right: 0px; + display: inline-block; + margin-top: 0px; + border-bottom-left-radius: 3px; + border-top-left-radius: 3px; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; + overflow: hidden; + text-overflow: ellipsis; +} +div.dt-btn-split-wrapper button.dt-button { + min-width: 30px; + margin-left: -1px; + border-bottom-left-radius: 0px; + border-top-left-radius: 0px; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; + padding: 0px; +} +div.dt-btn-split-wrapper:active:not(.disabled) button, div.dt-btn-split-wrapper.active:not(.disabled) button, div.dt-btn-split-wrapper.is-active:not(.disabled) button { + background-color: #eee; + border-color: transparent; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button { + box-shadow: none; + background-color: rgb(245, 245, 245); + border-color: transparent; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button:hover, div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover { + background-color: #eee; + border-color: transparent; +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.min.css new file mode 100644 index 0000000..c4a08cd --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.bulma.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;z-index:2001;min-width:200px;background:white;max-width:none;display:block;box-shadow:0 .5em 1em -0.125em rgba(10, 10, 10, 0.1),0 0 0 1px rgba(10, 10, 10, 0.02);border-radius:4;padding:.5rem}div.dt-button-collection div.dropdown-menu{display:block;z-index:2002;min-width:100%}div.dt-button-collection div.dt-btn-split-wrapper{width:100%;padding-left:5px;padding-right:5px;margin-bottom:0px;display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:stretch}div.dt-button-collection div.dt-btn-split-wrapper button{margin-right:0px;display:inline-block;width:0;flex-grow:1;flex-shrink:0;flex-basis:50px;margin-top:0px;border-bottom-left-radius:3px;border-top-left-radius:3px;border-top-right-radius:0px;border-bottom-right-radius:0px;overflow:hidden;text-overflow:ellipsis}div.dt-button-collection div.dt-btn-split-wrapper button.dt-button{min-width:30px;margin-left:-1px;flex-grow:0;flex-shrink:0;flex-basis:0;border-bottom-left-radius:0px;border-top-left-radius:0px;border-top-right-radius:3px;border-bottom-right-radius:3px;padding:0px}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection .dropdown-content{box-shadow:none;padding-top:0;border-radius:0}div.dt-button-collection.fixed:before,div.dt-button-collection.fixed:after{display:none}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:999}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.btn.processing,div.dt-buttons div.btn.processing,div.dt-buttons a.btn.processing{color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.btn.processing:after,div.dt-buttons div.btn.processing:after,div.dt-buttons a.btn.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons button.button{margin-left:5px}div.dt-buttons button.button:first-child{margin-left:0px}span.dt-down-arrow{display:none}span.dt-button-spacer{display:inline-flex;margin:.5em;white-space:nowrap;align-items:center;font-size:1rem}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{text-align:left;font-size:.875rem;padding-left:1rem !important}div.dt-btn-split-wrapper{padding-left:5px;padding-right:5px;margin-bottom:0px;margin-bottom:0px !important}div.dt-btn-split-wrapper button{margin-right:0px;display:inline-block;margin-top:0px;border-bottom-left-radius:3px;border-top-left-radius:3px;border-top-right-radius:0px;border-bottom-right-radius:0px;overflow:hidden;text-overflow:ellipsis}div.dt-btn-split-wrapper button.dt-button{min-width:30px;margin-left:-1px;border-bottom-left-radius:0px;border-top-left-radius:0px;border-top-right-radius:3px;border-bottom-right-radius:3px;padding:0px}div.dt-btn-split-wrapper:active:not(.disabled) button,div.dt-btn-split-wrapper.active:not(.disabled) button,div.dt-btn-split-wrapper.is-active:not(.disabled) button{background-color:#eee;border-color:transparent}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button{box-shadow:none;background-color:rgb(245, 245, 245);border-color:transparent}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button:hover,div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover{background-color:#eee;border-color:transparent} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.css new file mode 100644 index 0000000..adf98f2 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.css @@ -0,0 +1,560 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +button.dt-button, +div.dt-button, +a.dt-button, +input.dt-button { + position: relative; + display: inline-block; + box-sizing: border-box; + margin-left: 0.167em; + margin-right: 0.167em; + margin-bottom: 0.333em; + padding: 0.5em 1em; + border: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 2px; + cursor: pointer; + font-size: 0.88em; + line-height: 1.6em; + color: black; + white-space: nowrap; + overflow: hidden; + background-color: rgba(0, 0, 0, 0.1); /* Fallback */ + background: linear-gradient(to bottom, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(230, 230, 230, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + text-decoration: none; + outline: none; + text-overflow: ellipsis; +} +button.dt-button:first-child, +div.dt-button:first-child, +a.dt-button:first-child, +input.dt-button:first-child { + margin-left: 0; +} +button.dt-button.disabled, +div.dt-button.disabled, +a.dt-button.disabled, +input.dt-button.disabled { + cursor: default; + opacity: 0.4; +} +button.dt-button.active:not(.disabled), +div.dt-button.active:not(.disabled), +a.dt-button.active:not(.disabled), +input.dt-button.active:not(.disabled) { + background-color: rgba(0, 0, 0, 0.1); /* Fallback */ + background: linear-gradient(to bottom, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(179, 179, 179, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); + box-shadow: inset 1px 1px 3px #999999; +} +button.dt-button.active:not(.disabled):hover:not(.disabled), +div.dt-button.active:not(.disabled):hover:not(.disabled), +a.dt-button.active:not(.disabled):hover:not(.disabled), +input.dt-button.active:not(.disabled):hover:not(.disabled) { + box-shadow: inset 1px 1px 3px #999999; + background-color: rgba(0, 0, 0, 0.1); /* Fallback */ + background: linear-gradient(to bottom, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(128, 128, 128, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); +} +button.dt-button:hover, +div.dt-button:hover, +a.dt-button:hover, +input.dt-button:hover { + text-decoration: none; +} +button.dt-button:hover:not(.disabled), +div.dt-button:hover:not(.disabled), +a.dt-button:hover:not(.disabled), +input.dt-button:hover:not(.disabled) { + border: 1px solid #666; + background-color: rgba(0, 0, 0, 0.1); /* Fallback */ + background: linear-gradient(to bottom, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(153, 153, 153, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)"); +} +button.dt-button:focus:not(.disabled), +div.dt-button:focus:not(.disabled), +a.dt-button:focus:not(.disabled), +input.dt-button:focus:not(.disabled) { + border: 1px solid #426c9e; + text-shadow: 0 1px 0 #c4def1; + outline: none; + background-color: rgb(121, 172, 233); /* Fallback */ + background: linear-gradient(to bottom, #d1e2f7 0%, rgb(121, 172, 233) 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#d1e2f7", EndColorStr="rgb(121, 172, 233)"); +} +button.dt-button.active:focus:not(.disabled), +div.dt-button.active:focus:not(.disabled), +a.dt-button.active:focus:not(.disabled), +input.dt-button.active:focus:not(.disabled) { + background: linear-gradient(to bottom, #d1e2f7 0%, rgb(121, 172, 233) 100%) !important; +} +button.dt-button span.dt-down-arrow, +div.dt-button span.dt-down-arrow, +a.dt-button span.dt-down-arrow, +input.dt-button span.dt-down-arrow { + position: relative; + top: -2px; + color: rgba(70, 70, 70, 0.75); + font-size: 8px; + padding-left: 10px; + line-height: 1em; +} + +.dt-button embed { + outline: none; +} + +div.dt-buttons { + float: left; +} +div.dt-buttons.buttons-right { + float: right; +} + +div.dataTables_layout_cell div.dt-buttons { + float: none; +} +div.dataTables_layout_cell div.dt-buttons.buttons-right { + float: none; +} + +div.dt-btn-split-wrapper { + display: inline-block; +} + +div.dt-button-collection { + position: absolute; + top: 0; + left: 0; + width: 200px; + margin-top: 3px; + margin-bottom: 3px; + padding: 4px 4px 2px 4px; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.4); + background-color: white; + overflow: hidden; + z-index: 2002; + border-radius: 5px; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + box-sizing: border-box; +} +div.dt-button-collection button.dt-button, +div.dt-button-collection div.dt-button, +div.dt-button-collection a.dt-button { + position: relative; + left: 0; + right: 0; + width: 100%; + display: block; + float: none; + margin: 4px 0 2px 0; +} +div.dt-button-collection button.dt-button:active:not(.disabled), div.dt-button-collection button.dt-button.active:not(.disabled), +div.dt-button-collection div.dt-button:active:not(.disabled), +div.dt-button-collection div.dt-button.active:not(.disabled), +div.dt-button-collection a.dt-button:active:not(.disabled), +div.dt-button-collection a.dt-button.active:not(.disabled) { + background-color: #dadada; /* Fallback */ + background: linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada"); + box-shadow: inset 1px 1px 3px #666; +} +div.dt-button-collection button.dt-button:first-child, +div.dt-button-collection div.dt-button:first-child, +div.dt-button-collection a.dt-button:first-child { + margin-top: 0; + border-top-left-radius: 3px; + border-top-right-radius: 3px; +} +div.dt-button-collection button.dt-button:last-child, +div.dt-button-collection div.dt-button:last-child, +div.dt-button-collection a.dt-button:last-child { + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: flex-start; + align-content: flex-start; + align-items: stretch; + margin: 4px 0 2px 0; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-button { + margin: 0; + display: inline-block; + width: 0; + flex-grow: 1; + flex-shrink: 0; + flex-basis: 50px; + border-radius: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop { + min-width: 20px; + flex-grow: 0; + flex-shrink: 0; + flex-basis: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper:first-child { + margin-top: 0; +} +div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-button { + border-top-left-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-btn-split-drop { + border-top-right-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-button { + border-bottom-left-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-btn-split-drop { + border-bottom-right-radius: 3px; +} +div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button, div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button { + background-color: #dadada; /* Fallback */ + background: linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada"); + box-shadow: inset 0px 0px 4px #666; +} +div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; +} +div.dt-button-collection.fixed .dt-button:first-child { + margin-top: 0; + border-top-left-radius: 0; + border-top-right-radius: 0; +} +div.dt-button-collection.fixed .dt-button:last-child { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); /* Fallback */ + background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); /* W3C Markup, IE10 Release Preview */ + z-index: 2001; +} + +@media screen and (max-width: 640px) { + div.dt-buttons { + float: none !important; + text-align: center; + } +} +button.dt-button.processing, +div.dt-button.processing, +a.dt-button.processing { + color: rgba(0, 0, 0, 0.2); +} +button.dt-button.processing:after, +div.dt-button.processing:after, +a.dt-button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +button.dt-btn-split-drop { + margin-left: calc(-1px - 0.333em); + padding-bottom: calc(0.5em - 1px); + border-radius: 0px 1px 1px 0px; + color: rgba(70, 70, 70, 0.9); + border-left: none; +} +button.dt-btn-split-drop span.dt-btn-split-drop-arrow { + position: relative; + top: -1px; + left: -2px; + font-size: 8px; +} +button.dt-btn-split-drop:hover { + z-index: 2; +} + +button.buttons-split { + border-right: 1px solid rgba(70, 70, 70, 0); + border-radius: 1px 0px 0px 1px; +} + +button.dt-btn-split-drop-button { + background-color: rgb(255, 255, 255); +} +button.dt-btn-split-drop-button:hover { + background-color: rgb(255, 255, 255); +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.min.css new file mode 100644 index 0000000..02094ef --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.dataTables.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}button.dt-button,div.dt-button,a.dt-button,input.dt-button{position:relative;display:inline-block;box-sizing:border-box;margin-left:.167em;margin-right:.167em;margin-bottom:.333em;padding:.5em 1em;border:1px solid rgba(0, 0, 0, 0.3);border-radius:2px;cursor:pointer;font-size:.88em;line-height:1.6em;color:black;white-space:nowrap;overflow:hidden;background-color:rgba(0, 0, 0, 0.1);background:linear-gradient(to bottom, rgba(230, 230, 230, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(230, 230, 230, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)");-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;text-decoration:none;outline:none;text-overflow:ellipsis}button.dt-button:first-child,div.dt-button:first-child,a.dt-button:first-child,input.dt-button:first-child{margin-left:0}button.dt-button.disabled,div.dt-button.disabled,a.dt-button.disabled,input.dt-button.disabled{cursor:default;opacity:.4}button.dt-button.active:not(.disabled),div.dt-button.active:not(.disabled),a.dt-button.active:not(.disabled),input.dt-button.active:not(.disabled){background-color:rgba(0, 0, 0, 0.1);background:linear-gradient(to bottom, rgba(179, 179, 179, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(179, 179, 179, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)");box-shadow:inset 1px 1px 3px #999}button.dt-button.active:not(.disabled):hover:not(.disabled),div.dt-button.active:not(.disabled):hover:not(.disabled),a.dt-button.active:not(.disabled):hover:not(.disabled),input.dt-button.active:not(.disabled):hover:not(.disabled){box-shadow:inset 1px 1px 3px #999;background-color:rgba(0, 0, 0, 0.1);background:linear-gradient(to bottom, rgba(128, 128, 128, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(128, 128, 128, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)")}button.dt-button:hover,div.dt-button:hover,a.dt-button:hover,input.dt-button:hover{text-decoration:none}button.dt-button:hover:not(.disabled),div.dt-button:hover:not(.disabled),a.dt-button:hover:not(.disabled),input.dt-button:hover:not(.disabled){border:1px solid #666;background-color:rgba(0, 0, 0, 0.1);background:linear-gradient(to bottom, rgba(153, 153, 153, 0.1) 0%, rgba(0, 0, 0, 0.1) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="rgba(153, 153, 153, 0.1)", EndColorStr="rgba(0, 0, 0, 0.1)")}button.dt-button:focus:not(.disabled),div.dt-button:focus:not(.disabled),a.dt-button:focus:not(.disabled),input.dt-button:focus:not(.disabled){border:1px solid #426c9e;text-shadow:0 1px 0 #c4def1;outline:none;background-color:rgb(121, 172, 233);background:linear-gradient(to bottom, #d1e2f7 0%, rgb(121, 172, 233) 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#d1e2f7", EndColorStr="rgb(121, 172, 233)")}button.dt-button.active:focus:not(.disabled),div.dt-button.active:focus:not(.disabled),a.dt-button.active:focus:not(.disabled),input.dt-button.active:focus:not(.disabled){background:linear-gradient(to bottom, #d1e2f7 0%, rgb(121, 172, 233) 100%) !important}button.dt-button span.dt-down-arrow,div.dt-button span.dt-down-arrow,a.dt-button span.dt-down-arrow,input.dt-button span.dt-down-arrow{position:relative;top:-2px;color:rgba(70, 70, 70, 0.75);font-size:8px;padding-left:10px;line-height:1em}.dt-button embed{outline:none}div.dt-buttons{float:left}div.dt-buttons.buttons-right{float:right}div.dataTables_layout_cell div.dt-buttons{float:none}div.dataTables_layout_cell div.dt-buttons.buttons-right{float:none}div.dt-btn-split-wrapper{display:inline-block}div.dt-button-collection{position:absolute;top:0;left:0;width:200px;margin-top:3px;margin-bottom:3px;padding:4px 4px 2px 4px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.4);background-color:white;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);box-sizing:border-box}div.dt-button-collection button.dt-button,div.dt-button-collection div.dt-button,div.dt-button-collection a.dt-button{position:relative;left:0;right:0;width:100%;display:block;float:none;margin:4px 0 2px 0}div.dt-button-collection button.dt-button:active:not(.disabled),div.dt-button-collection button.dt-button.active:not(.disabled),div.dt-button-collection div.dt-button:active:not(.disabled),div.dt-button-collection div.dt-button.active:not(.disabled),div.dt-button-collection a.dt-button:active:not(.disabled),div.dt-button-collection a.dt-button.active:not(.disabled){background-color:#dadada;background:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada");box-shadow:inset 1px 1px 3px #666}div.dt-button-collection button.dt-button:first-child,div.dt-button-collection div.dt-button:first-child,div.dt-button-collection a.dt-button:first-child{margin-top:0;border-top-left-radius:3px;border-top-right-radius:3px}div.dt-button-collection button.dt-button:last-child,div.dt-button-collection div.dt-button:last-child,div.dt-button-collection a.dt-button:last-child{border-bottom-left-radius:3px;border-bottom-right-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:flex-start;align-content:flex-start;align-items:stretch;margin:4px 0 2px 0}div.dt-button-collection div.dt-btn-split-wrapper button.dt-button{margin:0;display:inline-block;width:0;flex-grow:1;flex-shrink:0;flex-basis:50px;border-radius:0}div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop{min-width:20px;flex-grow:0;flex-shrink:0;flex-basis:0}div.dt-button-collection div.dt-btn-split-wrapper:first-child{margin-top:0}div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-button{border-top-left-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:first-child button.dt-btn-split-drop{border-top-right-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-button{border-bottom-left-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:last-child button.dt-btn-split-drop{border-bottom-right-radius:3px}div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button,div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-button{background-color:#dadada;background:linear-gradient(to bottom, #f0f0f0 0%, #dadada 100%);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr="#f0f0f0", EndColorStr="#dadada");box-shadow:inset 0px 0px 4px #666}div.dt-button-collection div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-button-collection div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none}div.dt-button-collection.fixed .dt-button:first-child{margin-top:0;border-top-left-radius:0;border-top-right-radius:0}div.dt-button-collection.fixed .dt-button:last-child{border-bottom-left-radius:0;border-bottom-right-radius:0}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0, 0, 0, 0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}button.dt-btn-split-drop{margin-left:calc(-1px - .333em);padding-bottom:calc(.5em - 1px);border-radius:0px 1px 1px 0px;color:rgba(70, 70, 70, 0.9);border-left:none}button.dt-btn-split-drop span.dt-btn-split-drop-arrow{position:relative;top:-1px;left:-2px;font-size:8px}button.dt-btn-split-drop:hover{z-index:2}button.buttons-split{border-right:1px solid rgba(70, 70, 70, 0);border-radius:1px 0px 0px 1px}button.dt-btn-split-drop-button{background-color:rgb(255, 255, 255)}button.dt-btn-split-drop-button:hover{background-color:rgb(255, 255, 255)} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.css new file mode 100644 index 0000000..d68021c --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.css @@ -0,0 +1,371 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +ul.dt-buttons li { + margin: 0; +} +ul.dt-buttons li.active a { + box-shadow: inset 0 0 10px rgba(0, 0, 0, 0.6); +} + +ul.dt-buttons.button-group a { + margin-bottom: 0; +} + +div.dt-button-collection { + position: absolute; + z-index: 2002; + max-width: none; + border: 1px solid #cacaca; + padding: 0.5rem; + background-color: white; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection .button-group.stacked { + position: relative; + border: none; + padding: 0; + margin: 0; +} +div.dt-button-collection.columns .button-group.stacked { + flex-direction: row; + padding: 0; +} +div.dt-button-collection.columns .dt-button { + flex-basis: 200px; +} +div.dt-button-collection div.dt-btn-split-wrapper a.button { + flex-grow: 1; +} +div.dt-button-collection div.dt-btn-split-wrapper a.button, +div.dt-button-collection div.dt-btn-split-wrapper button.button { + display: inline-block !important; + white-space: nowrap; + height: 40px; + flex-basis: auto; + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 88; +} + +@media screen and (max-width: 767px) { + ul.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5rem; + } + ul.dt-buttons li { + float: none; + } +} +div.button-group.stacked.dropdown-pane { + margin-top: 2px; + padding: 1px; + z-index: 89; +} +div.button-group.stacked.dropdown-pane a.button { + display: block; + margin-bottom: 1px; + border-right: none; +} +div.button-group.stacked.dropdown-pane a.button:last-child { + margin-bottom: 0; + margin-right: 1px; +} + +div.dt-buttons button.button.processing, +div.dt-buttons div.button.processing, +div.dt-buttons a.button.processing { + color: rgba(0, 0, 0, 0.2); + color: rgba(255, 255, 255, 0.2); + border-top-color: white; + border-bottom-color: white; +} +div.dt-buttons button.button.processing:after, +div.dt-buttons div.button.processing:after, +div.dt-buttons a.button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #1779ba; + border-color: transparent; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop:hover, div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop:hover { + background-color: #14679e; + border-color: transparent; +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.min.css new file mode 100644 index 0000000..19a0bd0 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.foundation.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}ul.dt-buttons li{margin:0}ul.dt-buttons li.active a{box-shadow:inset 0 0 10px rgba(0, 0, 0, 0.6)}ul.dt-buttons.button-group a{margin-bottom:0}div.dt-button-collection{position:absolute;z-index:2002;max-width:none;border:1px solid #cacaca;padding:.5rem;background-color:white}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection .button-group.stacked{position:relative;border:none;padding:0;margin:0}div.dt-button-collection.columns .button-group.stacked{flex-direction:row;padding:0}div.dt-button-collection.columns .dt-button{flex-basis:200px}div.dt-button-collection div.dt-btn-split-wrapper a.button{flex-grow:1}div.dt-button-collection div.dt-btn-split-wrapper a.button,div.dt-button-collection div.dt-btn-split-wrapper button.button{display:inline-block !important;white-space:nowrap;height:40px;flex-basis:auto;overflow:hidden;text-overflow:ellipsis}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:88}@media screen and (max-width: 767px){ul.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5rem}ul.dt-buttons li{float:none}}div.button-group.stacked.dropdown-pane{margin-top:2px;padding:1px;z-index:89}div.button-group.stacked.dropdown-pane a.button{display:block;margin-bottom:1px;border-right:none}div.button-group.stacked.dropdown-pane a.button:last-child{margin-bottom:0;margin-right:1px}div.dt-buttons button.button.processing,div.dt-buttons div.button.processing,div.dt-buttons a.button.processing{color:rgba(0, 0, 0, 0.2);color:rgba(255, 255, 255, 0.2);border-top-color:white;border-bottom-color:white}div.dt-buttons button.button.processing:after,div.dt-buttons div.button.processing:after,div.dt-buttons a.button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#1779ba;border-color:transparent}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop:hover,div.dt-btn-split-wrapper.secondary:not(.disabled) button.dt-btn-split-drop:hover{background-color:#14679e;border-color:transparent} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.css new file mode 100644 index 0000000..70e1734 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.css @@ -0,0 +1,387 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-buttons { + position: relative; + float: left; +} +div.dt-buttons .dt-button { + margin-right: 0; +} +div.dt-buttons .dt-button span.ui-icon { + display: inline-block; + vertical-align: middle; + margin-top: -2px; +} +div.dt-buttons .dt-button:active { + outline: none; +} +div.dt-buttons .dt-button:hover > span { + background-color: rgba(0, 0, 0, 0.05); +} + +div.dt-button-collection { + position: absolute; + top: 0; + left: 0; + width: 150px; + margin-top: 3px; + padding: 8px 8px 4px 8px; + border: 1px solid #ccc; + border: 1px solid rgba(0, 0, 0, 0.4); + background-color: #f3f3f3; + overflow: hidden; + z-index: 2002; + border-radius: 5px; + box-shadow: 3px 3px 5px rgba(0, 0, 0, 0.3); + z-index: 2002; + -webkit-column-gap: 0; + -moz-column-gap: 0; + -ms-column-gap: 0; + -o-column-gap: 0; + column-gap: 0; +} +div.dt-button-collection .dt-button { + position: relative; + left: 0; + right: 0; + width: 100%; + box-sizing: border-box; + display: block; + float: none; + margin-right: 0; + margin-bottom: 4px; +} +div.dt-button-collection .dt-button:hover > span { + background-color: rgba(0, 0, 0, 0.05); +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} + +div.dt-btn-split-wrapper { + padding: 0px !important; + background-color: transparent !important; + display: flex; + border: none !important; + margin: 0px; +} +div.dt-btn-split-wrapper:hover { + border: none; +} +div.dt-btn-split-wrapper button.dt-btn-split-drop { + width: 24px; + padding-left: 6px; + padding-right: 6px; + font-size: 10px; + height: 29.5px; + border-radius: 0px; + margin-left: -1px; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-button, div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button { + background-color: #007fff; + border-color: #003eff; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: #f6f6f6; + border-color: #c5c5c5; +} +div.dt-btn-split-wrapper:active:not(.disabled) button:hover, div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button:hover, div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover { + background-color: #ededed; + border-color: #cccccc; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.7); /* Fallback */ + background: radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%); /* W3C Markup, IE10 Release Preview */ + z-index: 2001; +} + +@media screen and (max-width: 640px) { + div.dt-buttons { + float: none !important; + text-align: center; + } +} +button.dt-button.processing, +div.dt-button.processing, +a.dt-button.processing { + color: rgba(0, 0, 0, 0.2); +} +button.dt-button.processing:after, +div.dt-button.processing:after, +a.dt-button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} + +span.dt-down-arrow { + display: none; +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.min.css new file mode 100644 index 0000000..42ab77e --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.jqueryui.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-buttons{position:relative;float:left}div.dt-buttons .dt-button{margin-right:0}div.dt-buttons .dt-button span.ui-icon{display:inline-block;vertical-align:middle;margin-top:-2px}div.dt-buttons .dt-button:active{outline:none}div.dt-buttons .dt-button:hover>span{background-color:rgba(0, 0, 0, 0.05)}div.dt-button-collection{position:absolute;top:0;left:0;width:150px;margin-top:3px;padding:8px 8px 4px 8px;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.4);background-color:#f3f3f3;overflow:hidden;z-index:2002;border-radius:5px;box-shadow:3px 3px 5px rgba(0, 0, 0, 0.3);z-index:2002;-webkit-column-gap:0;-moz-column-gap:0;-ms-column-gap:0;-o-column-gap:0;column-gap:0}div.dt-button-collection .dt-button{position:relative;left:0;right:0;width:100%;box-sizing:border-box;display:block;float:none;margin-right:0;margin-bottom:4px}div.dt-button-collection .dt-button:hover>span{background-color:rgba(0, 0, 0, 0.05)}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-btn-split-wrapper{padding:0px !important;background-color:transparent !important;display:flex;border:none !important;margin:0px}div.dt-btn-split-wrapper:hover{border:none}div.dt-btn-split-wrapper button.dt-btn-split-drop{width:24px;padding-left:6px;padding-right:6px;font-size:10px;height:29.5px;border-radius:0px;margin-left:-1px}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-button,div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-button{background-color:#007fff;border-color:#003eff}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.is-active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:#f6f6f6;border-color:#c5c5c5}div.dt-btn-split-wrapper:active:not(.disabled) button:hover,div.dt-btn-split-wrapper.ui-state-active:not(.disabled) button:hover,div.dt-btn-split-wrapper.is-active:not(.disabled) button:hover{background-color:#ededed;border-color:#ccc}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0, 0, 0, 0.7);background:radial-gradient(ellipse farthest-corner at center, rgba(0, 0, 0, 0.3) 0%, rgba(0, 0, 0, 0.7) 100%);z-index:2001}@media screen and (max-width: 640px){div.dt-buttons{float:none !important;text-align:center}}button.dt-button.processing,div.dt-button.processing,a.dt-button.processing{color:rgba(0, 0, 0, 0.2)}button.dt-button.processing:after,div.dt-button.processing:after,a.dt-button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}span.dt-down-arrow{display:none} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.css new file mode 100644 index 0000000..7549ea2 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.css @@ -0,0 +1,409 @@ +@keyframes dtb-spinner { + 100% { + transform: rotate(360deg); + } +} +@-o-keyframes dtb-spinner { + 100% { + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-ms-keyframes dtb-spinner { + 100% { + -ms-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-webkit-keyframes dtb-spinner { + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@-moz-keyframes dtb-spinner { + 100% { + -moz-transform: rotate(360deg); + transform: rotate(360deg); + } +} +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; +} +div.dt-buttons .dt-button { + overflow: hidden; + text-overflow: ellipsis; +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; +} +div.dt-button-info h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; +} +div.dt-button-info > div { + padding: 1em; +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; +} +span.dt-button-spacer.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; +} +span.dt-button-spacer.bar:empty { + height: 1em; + width: 1px; + padding-left: 0; +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; +} +div.dt-button-collection span.dt-button-spacer:empty { + height: 0; + width: 100%; +} +div.dt-button-collection span.dt-button-spacer.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; +} + +div.dt-button-collection { + position: absolute; + top: 0; + left: 0; + min-width: 200px; + margin-top: 3px !important; + margin-bottom: 3px !important; + z-index: 2002; + background: white; + border: 1px solid rgba(34, 36, 38, 0.15); + font-size: 1em; + padding: 0.5rem; +} +div.dt-button-collection.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; +} +div.dt-button-collection.fixed.two-column { + margin-left: -200px; +} +div.dt-button-collection.fixed.three-column { + margin-left: -225px; +} +div.dt-button-collection.fixed.four-column { + margin-left: -300px; +} +div.dt-button-collection.fixed.columns { + margin-left: -409px; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.fixed.columns { + margin-left: -308px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.fixed.columns { + margin-left: -203px; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.fixed.columns { + margin-left: -100px; + } +} +div.dt-button-collection.fixed > :last-child { + max-height: 100vh; + overflow: auto; +} +div.dt-button-collection.two-column > :last-child, div.dt-button-collection.three-column > :last-child, div.dt-button-collection.four-column > :last-child { + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; +} +div.dt-button-collection.two-column > :last-child > *, div.dt-button-collection.three-column > :last-child > *, div.dt-button-collection.four-column > :last-child > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; +} +div.dt-button-collection.two-column { + width: 400px; +} +div.dt-button-collection.two-column > :last-child { + padding-bottom: 1px; + column-count: 2; +} +div.dt-button-collection.three-column { + width: 450px; +} +div.dt-button-collection.three-column > :last-child { + padding-bottom: 1px; + column-count: 3; +} +div.dt-button-collection.four-column { + width: 600px; +} +div.dt-button-collection.four-column > :last-child { + padding-bottom: 1px; + column-count: 4; +} +div.dt-button-collection .dt-button { + border-radius: 0; +} +div.dt-button-collection.columns { + width: auto; +} +div.dt-button-collection.columns > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + width: 818px; + padding-bottom: 1px; +} +div.dt-button-collection.columns > :last-child .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; +} +div.dt-button-collection.columns.dtb-b3 > :last-child, div.dt-button-collection.columns.dtb-b2 > :last-child, div.dt-button-collection.columns.dtb-b1 > :last-child { + justify-content: space-between; +} +div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 1 1 32%; +} +div.dt-button-collection.columns.dtb-b2 .dt-button { + flex: 1 1 48%; +} +div.dt-button-collection.columns.dtb-b1 .dt-button { + flex: 1 1 100%; +} +@media screen and (max-width: 1024px) { + div.dt-button-collection.columns > :last-child { + width: 612px; + } +} +@media screen and (max-width: 640px) { + div.dt-button-collection.columns > :last-child { + width: 406px; + } + div.dt-button-collection.columns.dtb-b3 .dt-button { + flex: 0 1 32%; + } +} +@media screen and (max-width: 460px) { + div.dt-button-collection.columns > :last-child { + width: 200px; + } +} +div.dt-button-collection div.dt-button-collection-title { + font-size: 1rem; +} +div.dt-button-collection.columns div.ui.basic.buttons span.dt-button-spacer { + background: transparent !important; + border: none; + flex: 1 1 100%; +} +div.dt-button-collection.columns div.ui.basic.buttons span.dt-button-spacer:hover { + background: transparent !important; +} +div.dt-button-collection:not(.columns) .ui.vertical.buttons { + width: 100%; + border: none; +} +div.dt-button-collection.columns .ui.vertical.buttons { + flex-direction: row; + border: none; +} +div.dt-button-collection button.dt-button { + border: 1px solid rgba(34, 36, 38, 0.15) !important; +} +div.dt-button-collection div.dt-btn-split-wrapper { + display: flex; +} +div.dt-button-collection div.dt-btn-split-wrapper button { + flex-grow: 1 !important; + flex-basis: auto !important; + width: auto !important; + border-top-right-radius: 0px !important; +} +div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop { + flex-grow: 0 !important; + flex-basis: auto !important; + border-bottom-left-radius: 0px !important; + border-bottom-right-radius: 0px !important; + border-top-right-radius: 4px !important; +} + +button.buttons-collection.ui.button span:after { + display: inline-block; + content: "▾"; + padding-left: 0.5em; +} + +div.dt-button-background { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + z-index: 2001; +} + +@media screen and (max-width: 767px) { + div.dt-buttons { + float: none; + width: 100%; + text-align: center; + margin-bottom: 0.5em; + } + div.dt-buttons a.btn { + float: none; + } +} +div.dt-buttons button.button.processing, +div.dt-buttons div.button.processing, +div.dt-buttons a.button.processing { + position: relative; + color: rgba(0, 0, 0, 0.2); +} +div.dt-buttons button.button.processing:after, +div.dt-buttons div.button.processing:after, +div.dt-buttons a.button.processing:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + display: block; + content: " "; + border: 2px solid rgb(40, 40, 40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; +} +div.dt-buttons.ui.buttons { + flex-wrap: wrap; +} +div.dt-buttons.ui.basic.buttons .ui.button { + border-bottom: 1px solid rgba(34, 36, 38, 0.15); + margin-bottom: -1px; +} +div.dt-buttons.ui.basic.buttons .ui.button:hover { + background: transparent !important; +} + +span.dt-down-arrow { + display: none; +} + +span.dt-button-spacer { + cursor: inherit; +} +span.dt-button-spacer.bar { + padding-left: 1.5em; +} +span.dt-button-spacer.bar:empty { + height: inherit; +} + +div.dt-button-collection span.dt-button-spacer { + border-top: 1px solid rgba(34, 36, 38, 0.15); +} +div.dt-button-collection span.dt-button-spacer.bar { + border-bottom: none; + padding-left: 1.5em; +} + +div.dt-buttons.ui.basic.buttons .button.dt-button-spacer { + background: rgba(34, 36, 38, 0.05) !important; + box-shadow: none; + cursor: initial; +} +div.dt-buttons.ui.basic.buttons .button.dt-button-spacer:hover { + background-color: rgba(34, 36, 38, 0.05) !important; +} + +div.dt-btn-split-wrapper:active:not(.disabled) button.button, div.dt-btn-split-wrapper.active:not(.disabled) button.button { + background-color: #f8f8f8 !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop, div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop { + box-shadow: none; + background-color: transparent !important; +} +div.dt-btn-split-wrapper:active:not(.disabled) button.button:hover, div.dt-btn-split-wrapper.active:not(.disabled) button.button:hover { + background-color: transparent !important; +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.min.css b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.min.css new file mode 100644 index 0000000..093e7a9 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/buttons.semanticui.min.css @@ -0,0 +1 @@ +@keyframes dtb-spinner{100%{transform:rotate(360deg)}}@-o-keyframes dtb-spinner{100%{-o-transform:rotate(360deg);transform:rotate(360deg)}}@-ms-keyframes dtb-spinner{100%{-ms-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dtb-spinner{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-moz-keyframes dtb-spinner{100%{-moz-transform:rotate(360deg);transform:rotate(360deg)}}div.dataTables_wrapper{position:relative}div.dt-buttons{position:initial}div.dt-buttons .dt-button{overflow:hidden;text-overflow:ellipsis}div.dt-button-info{position:fixed;top:50%;left:50%;width:400px;margin-top:-100px;margin-left:-200px;background-color:white;border:2px solid #111;box-shadow:3px 4px 10px 1px rgba(0, 0, 0, 0.3);border-radius:3px;text-align:center;z-index:21}div.dt-button-info h2{padding:.5em;margin:0;font-weight:normal;border-bottom:1px solid #ddd;background-color:#f3f3f3}div.dt-button-info>div{padding:1em}div.dtb-popover-close{position:absolute;top:10px;right:10px;width:22px;height:22px;border:1px solid #eaeaea;background-color:#f9f9f9;text-align:center;border-radius:3px;cursor:pointer;z-index:2003}button.dtb-hide-drop{display:none !important}div.dt-button-collection-title{text-align:center;padding:.3em 0 .5em;margin-left:.5em;margin-right:.5em;font-size:.9em}div.dt-button-collection-title:empty{display:none}span.dt-button-spacer{display:inline-block;margin:.5em;white-space:nowrap}span.dt-button-spacer.bar{border-left:1px solid rgba(0, 0, 0, 0.3);vertical-align:middle;padding-left:.5em}span.dt-button-spacer.bar:empty{height:1em;width:1px;padding-left:0}div.dt-button-collection span.dt-button-spacer{width:100%;font-size:.9em;text-align:center;margin:.5em 0}div.dt-button-collection span.dt-button-spacer:empty{height:0;width:100%}div.dt-button-collection span.dt-button-spacer.bar{border-left:none;border-bottom:1px solid rgba(0, 0, 0, 0.3);padding-left:0}div.dt-button-collection{position:absolute;top:0;left:0;min-width:200px;margin-top:3px !important;margin-bottom:3px !important;z-index:2002;background:white;border:1px solid rgba(34, 36, 38, 0.15);font-size:1em;padding:.5rem}div.dt-button-collection.fixed{position:fixed;display:block;top:50%;left:50%;margin-left:-75px;border-radius:5px;background-color:white}div.dt-button-collection.fixed.two-column{margin-left:-200px}div.dt-button-collection.fixed.three-column{margin-left:-225px}div.dt-button-collection.fixed.four-column{margin-left:-300px}div.dt-button-collection.fixed.columns{margin-left:-409px}@media screen and (max-width: 1024px){div.dt-button-collection.fixed.columns{margin-left:-308px}}@media screen and (max-width: 640px){div.dt-button-collection.fixed.columns{margin-left:-203px}}@media screen and (max-width: 460px){div.dt-button-collection.fixed.columns{margin-left:-100px}}div.dt-button-collection.fixed>:last-child{max-height:100vh;overflow:auto}div.dt-button-collection.two-column>:last-child,div.dt-button-collection.three-column>:last-child,div.dt-button-collection.four-column>:last-child{display:block !important;-webkit-column-gap:8px;-moz-column-gap:8px;-ms-column-gap:8px;-o-column-gap:8px;column-gap:8px}div.dt-button-collection.two-column>:last-child>*,div.dt-button-collection.three-column>:last-child>*,div.dt-button-collection.four-column>:last-child>*{-webkit-column-break-inside:avoid;break-inside:avoid}div.dt-button-collection.two-column{width:400px}div.dt-button-collection.two-column>:last-child{padding-bottom:1px;column-count:2}div.dt-button-collection.three-column{width:450px}div.dt-button-collection.three-column>:last-child{padding-bottom:1px;column-count:3}div.dt-button-collection.four-column{width:600px}div.dt-button-collection.four-column>:last-child{padding-bottom:1px;column-count:4}div.dt-button-collection .dt-button{border-radius:0}div.dt-button-collection.columns{width:auto}div.dt-button-collection.columns>:last-child{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:center;gap:6px;width:818px;padding-bottom:1px}div.dt-button-collection.columns>:last-child .dt-button{min-width:200px;flex:0 1;margin:0}div.dt-button-collection.columns.dtb-b3>:last-child,div.dt-button-collection.columns.dtb-b2>:last-child,div.dt-button-collection.columns.dtb-b1>:last-child{justify-content:space-between}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:1 1 32%}div.dt-button-collection.columns.dtb-b2 .dt-button{flex:1 1 48%}div.dt-button-collection.columns.dtb-b1 .dt-button{flex:1 1 100%}@media screen and (max-width: 1024px){div.dt-button-collection.columns>:last-child{width:612px}}@media screen and (max-width: 640px){div.dt-button-collection.columns>:last-child{width:406px}div.dt-button-collection.columns.dtb-b3 .dt-button{flex:0 1 32%}}@media screen and (max-width: 460px){div.dt-button-collection.columns>:last-child{width:200px}}div.dt-button-collection div.dt-button-collection-title{font-size:1rem}div.dt-button-collection.columns div.ui.basic.buttons span.dt-button-spacer{background:transparent !important;border:none;flex:1 1 100%}div.dt-button-collection.columns div.ui.basic.buttons span.dt-button-spacer:hover{background:transparent !important}div.dt-button-collection:not(.columns) .ui.vertical.buttons{width:100%;border:none}div.dt-button-collection.columns .ui.vertical.buttons{flex-direction:row;border:none}div.dt-button-collection button.dt-button{border:1px solid rgba(34, 36, 38, 0.15) !important}div.dt-button-collection div.dt-btn-split-wrapper{display:flex}div.dt-button-collection div.dt-btn-split-wrapper button{flex-grow:1 !important;flex-basis:auto !important;width:auto !important;border-top-right-radius:0px !important}div.dt-button-collection div.dt-btn-split-wrapper button.dt-btn-split-drop{flex-grow:0 !important;flex-basis:auto !important;border-bottom-left-radius:0px !important;border-bottom-right-radius:0px !important;border-top-right-radius:4px !important}button.buttons-collection.ui.button span:after{display:inline-block;content:"▾";padding-left:.5em}div.dt-button-background{position:fixed;top:0;left:0;width:100%;height:100%;z-index:2001}@media screen and (max-width: 767px){div.dt-buttons{float:none;width:100%;text-align:center;margin-bottom:.5em}div.dt-buttons a.btn{float:none}}div.dt-buttons button.button.processing,div.dt-buttons div.button.processing,div.dt-buttons a.button.processing{position:relative;color:rgba(0, 0, 0, 0.2)}div.dt-buttons button.button.processing:after,div.dt-buttons div.button.processing:after,div.dt-buttons a.button.processing:after{position:absolute;top:50%;left:50%;width:16px;height:16px;margin:-8px 0 0 -8px;box-sizing:border-box;display:block;content:" ";border:2px solid rgb(40, 40, 40);border-radius:50%;border-left-color:transparent;border-right-color:transparent;animation:dtb-spinner 1500ms infinite linear;-o-animation:dtb-spinner 1500ms infinite linear;-ms-animation:dtb-spinner 1500ms infinite linear;-webkit-animation:dtb-spinner 1500ms infinite linear;-moz-animation:dtb-spinner 1500ms infinite linear}div.dt-buttons.ui.buttons{flex-wrap:wrap}div.dt-buttons.ui.basic.buttons .ui.button{border-bottom:1px solid rgba(34, 36, 38, 0.15);margin-bottom:-1px}div.dt-buttons.ui.basic.buttons .ui.button:hover{background:transparent !important}span.dt-down-arrow{display:none}span.dt-button-spacer{cursor:inherit}span.dt-button-spacer.bar{padding-left:1.5em}span.dt-button-spacer.bar:empty{height:inherit}div.dt-button-collection span.dt-button-spacer{border-top:1px solid rgba(34, 36, 38, 0.15)}div.dt-button-collection span.dt-button-spacer.bar{border-bottom:none;padding-left:1.5em}div.dt-buttons.ui.basic.buttons .button.dt-button-spacer{background:rgba(34, 36, 38, 0.05) !important;box-shadow:none;cursor:initial}div.dt-buttons.ui.basic.buttons .button.dt-button-spacer:hover{background-color:rgba(34, 36, 38, 0.05) !important}div.dt-btn-split-wrapper:active:not(.disabled) button.button,div.dt-btn-split-wrapper.active:not(.disabled) button.button{background-color:#f8f8f8 !important}div.dt-btn-split-wrapper:active:not(.disabled) button.dt-btn-split-drop,div.dt-btn-split-wrapper.active:not(.disabled) button.dt-btn-split-drop{box-shadow:none;background-color:transparent !important}div.dt-btn-split-wrapper:active:not(.disabled) button.button:hover,div.dt-btn-split-wrapper.active:not(.disabled) button.button:hover{background-color:transparent !important} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/common.scss b/public/assets/js/DataTables/Buttons-2.3.6/css/common.scss new file mode 100644 index 0000000..1c2cb17 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/common.scss @@ -0,0 +1,106 @@ + +div.dataTables_wrapper { + position: relative; +} + +div.dt-buttons { + position: initial; + + .dt-button { + overflow: hidden; + text-overflow: ellipsis; + } +} + +div.dt-button-info { + position: fixed; + top: 50%; + left: 50%; + width: 400px; + margin-top: -100px; + margin-left: -200px; + background-color: white; + border: 2px solid #111; + box-shadow: 3px 4px 10px 1px rgba(0, 0, 0, 0.3); + border-radius: 3px; + text-align: center; + z-index: 21; + + h2 { + padding: 0.5em; + margin: 0; + font-weight: normal; + border-bottom: 1px solid #ddd; + background-color: #f3f3f3; + } + + > div { + padding: 1em; + } +} + +div.dtb-popover-close { + position: absolute; + top: 10px; + right: 10px; + width: 22px; + height: 22px; + border: 1px solid #eaeaea; + background-color: #f9f9f9; + text-align: center; + border-radius: 3px; + cursor: pointer; + z-index: 2003; +} + +button.dtb-hide-drop { + display: none !important; +} + +div.dt-button-collection-title { + text-align: center; + padding: 0.3em 0 0.5em; + margin-left: 0.5em; + margin-right: 0.5em; + font-size: 0.9em; +} + +div.dt-button-collection-title:empty { + display: none; +} + +span.dt-button-spacer { + display: inline-block; + margin: 0.5em; + white-space: nowrap; + + &.bar { + border-left: 1px solid rgba(0, 0, 0, 0.3); + vertical-align: middle; + padding-left: 0.5em; + + &:empty { + height: 1em; + width: 1px; + padding-left: 0; + } + } +} + +div.dt-button-collection span.dt-button-spacer { + width: 100%; + font-size: 0.9em; + text-align: center; + margin: 0.5em 0; + + &:empty { + height: 0; + width: 100%; + } + + &.bar { + border-left: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + padding-left: 0; + } +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/css/mixins.scss b/public/assets/js/DataTables/Buttons-2.3.6/css/mixins.scss new file mode 100644 index 0000000..3fee4ec --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/css/mixins.scss @@ -0,0 +1,228 @@ + +@function dtb-tint( $color, $percent ) { + @return mix(white, $color, $percent); +} + +@function dtb-shade( $color, $percent ) { + @return mix(black, $color, $percent); +} + +@mixin dtb-two-stop-gradient($fromColor, $toColor) { + background-color: $toColor; /* Fallback */ + background: linear-gradient(to bottom, $fromColor 0%, $toColor 100%); + filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#{nth( $fromColor, 1 )}', EndColorStr='#{nth( $toColor, 1 )}'); +} + +@mixin dtb-radial-gradient ($fromColor, $toColor ) { + background: $toColor; /* Fallback */ + background: radial-gradient(ellipse farthest-corner at center, $fromColor 0%, $toColor 100%); /* W3C Markup, IE10 Release Preview */ +} + + +@mixin dtb-fixed-collection { + // Fixed positioning feature + &.fixed { + position: fixed; + display: block; + top: 50%; + left: 50%; + margin-left: -75px; + border-radius: 5px; + background-color: white; + + &.two-column { + margin-left: -200px; + } + + &.three-column { + margin-left: -225px; + } + + &.four-column { + margin-left: -300px; + } + + &.columns { + // Four column + margin-left: -409px; + + @media screen and (max-width: 1024px) { + margin-left: -308px; + } + + @media screen and (max-width: 640px) { + margin-left: -203px; + } + + @media screen and (max-width: 460px) { + margin-left: -100px; + } + } + + > :last-child { + max-height: 100vh; + overflow: auto; + } + } + + &.two-column > :last-child, + &.three-column > :last-child, + &.four-column > :last-child { + > * { + -webkit-column-break-inside: avoid; + break-inside: avoid; + } + + // Multi-column layout feature + display: block !important; + -webkit-column-gap: 8px; + -moz-column-gap: 8px; + -ms-column-gap: 8px; + -o-column-gap: 8px; + column-gap: 8px; + } + + &.two-column { + width: 400px; + + > :last-child { + padding-bottom: 1px; + column-count: 2; + } + } + + &.three-column { + width: 450px; + + > :last-child { + padding-bottom: 1px; + column-count: 3; + } + } + + &.four-column { + width: 600px; + + > :last-child { + padding-bottom: 1px; + column-count: 4; + } + } + + // Chrome fix - 531528 + .dt-button { + border-radius: 0; + } + + &.columns { + // Four column layout + width: auto; + + > :last-child { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + align-items: center; + gap: 6px; + + width: 818px; + padding-bottom: 1px; + + .dt-button { + min-width: 200px; + flex: 0 1; + margin: 0; + } + } + + &.dtb-b3, + &.dtb-b2, + &.dtb-b1 { + > :last-child { + justify-content: space-between; + } + } + + &.dtb-b3 .dt-button { + flex: 1 1 32%; + } + &.dtb-b2 .dt-button { + flex: 1 1 48%; + } + &.dtb-b1 .dt-button { + flex: 1 1 100%; + } + + @media screen and (max-width: 1024px) { + // Three column layout + > :last-child { + width: 612px; + } + } + + @media screen and (max-width: 640px) { + // Two column layout + > :last-child { + width: 406px; + } + + &.dtb-b3 .dt-button { + flex: 0 1 32%; + } + } + + @media screen and (max-width: 460px) { + // Single column + > :last-child { + width: 200px; + } + } + } +} + + +@mixin dtb-processing { + color: rgba(0, 0, 0, 0.2); + + &:after { + position: absolute; + top: 50%; + left: 50%; + width: 16px; + height: 16px; + margin: -8px 0 0 -8px; + box-sizing: border-box; + + display: block; + content: ' '; + border: 2px solid rgb(40,40,40); + border-radius: 50%; + border-left-color: transparent; + border-right-color: transparent; + animation: dtb-spinner 1500ms infinite linear; + -o-animation: dtb-spinner 1500ms infinite linear; + -ms-animation: dtb-spinner 1500ms infinite linear; + -webkit-animation: dtb-spinner 1500ms infinite linear; + -moz-animation: dtb-spinner 1500ms infinite linear; + } +} + +@keyframes dtb-spinner { + 100%{ transform: rotate(360deg); } +} + +@-o-keyframes dtb-spinner { + 100%{ -o-transform: rotate(360deg); transform: rotate(360deg); } +} + +@-ms-keyframes dtb-spinner { + 100%{ -ms-transform: rotate(360deg); transform: rotate(360deg); } +} + +@-webkit-keyframes dtb-spinner { + 100%{ -webkit-transform: rotate(360deg); transform: rotate(360deg); } +} + +@-moz-keyframes dtb-spinner { + 100%{ -moz-transform: rotate(360deg); transform: rotate(360deg); } +} diff --git a/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.js b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.js new file mode 100644 index 0000000..3edd363 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.js @@ -0,0 +1,106 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + var jq = require('jquery'); + var cjsRequires = function (root, $) { + if ( ! $.fn.dataTable ) { + require('datatables.net-bs')(root, $); + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + }; + + if (typeof window !== 'undefined') { + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = jq( root ); + } + + cjsRequires( root, $ ); + return factory( $, root, root.document ); + }; + } + else { + cjsRequires( window, jq ); + module.exports = factory( jq, window, window.document ); + } + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons btn-group' + }, + button: { + className: 'btn btn-default' + }, + collection: { + tag: 'ul', + className: 'dropdown-menu', + closeButton: false, + button: { + tag: 'li', + className: 'dt-button', + active: 'active', + disabled: 'disabled' + }, + buttonLiner: { + tag: 'a', + className: '' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper btn-group', + closeButton: false, + }, + splitDropdown: { + tag: 'button', + text: '▼', + className: 'btn btn-default dt-btn-split-drop dropdown-toggle', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button btn btn-default', + closeButton: false + } + } +} ); + +DataTable.ext.buttons.collection.text = function ( dt ) { + return dt.i18n('buttons.collection', 'Collection '); +}; + + +return DataTable; +})); diff --git a/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.min.js b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.min.js new file mode 100644 index 0000000..d581ce8 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap.min.js @@ -0,0 +1,4 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ +!function(e){var o,a;"function"==typeof define&&define.amd?define(["jquery","datatables.net-bs","datatables.net-buttons"],function(t){return e(t,window,document)}):"object"==typeof exports?(o=require("jquery"),a=function(t,n){n.fn.dataTable||require("datatables.net-bs")(t,n),n.fn.dataTable.Buttons||require("datatables.net-buttons")(t,n)},"undefined"!=typeof window?module.exports=function(t,n){return t=t||window,n=n||o(t),a(t,n),e(n,0,t.document)}:(a(window,o),module.exports=e(o,window,window.document))):e(jQuery,window,document)}(function(t,n,e,o){"use strict";var a=t.fn.dataTable;return t.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group"},button:{className:"btn btn-default"},collection:{tag:"ul",className:"dropdown-menu",closeButton:!1,button:{tag:"li",className:"dt-button",active:"active",disabled:"disabled"},buttonLiner:{tag:"a",className:""}},splitWrapper:{tag:"div",className:"dt-btn-split-wrapper btn-group",closeButton:!1},splitDropdown:{tag:"button",text:"▼",className:"btn btn-default dt-btn-split-drop dropdown-toggle",closeButton:!1,align:"split-left",splitAlignClass:"dt-button-split-left"},splitDropdownButton:{tag:"button",className:"dt-btn-split-drop-button btn btn-default",closeButton:!1}}}),a.ext.buttons.collection.text=function(t){return t.i18n("buttons.collection",'Collection ')},a}); \ No newline at end of file diff --git a/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.js b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.js new file mode 100644 index 0000000..8277853 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.js @@ -0,0 +1,106 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs4', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + var jq = require('jquery'); + var cjsRequires = function (root, $) { + if ( ! $.fn.dataTable ) { + require('datatables.net-bs4')(root, $); + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + }; + + if (typeof window !== 'undefined') { + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = jq( root ); + } + + cjsRequires( root, $ ); + return factory( $, root, root.document ); + }; + } + else { + cjsRequires( window, jq ); + module.exports = factory( jq, window, window.document ); + } + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons btn-group flex-wrap' + }, + button: { + className: 'btn btn-secondary' + }, + collection: { + tag: 'div', + className: 'dropdown-menu', + closeButton: false, + button: { + tag: 'a', + className: 'dt-button dropdown-item', + active: 'active', + disabled: 'disabled' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper btn-group', + closeButton: false, + }, + splitDropdown: { + tag: 'button', + text: '', + className: 'btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button btn btn-secondary', + closeButton: false + } + }, + buttonCreated: function ( config, button ) { + return config.buttons ? + $('
    ').append(button) : + button; + } +} ); + +DataTable.ext.buttons.collection.className += ' dropdown-toggle'; +DataTable.ext.buttons.collection.rightAlignClassName = 'dropdown-menu-right'; + + +return DataTable; +})); diff --git a/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.min.js b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.min.js new file mode 100644 index 0000000..4685697 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap4.min.js @@ -0,0 +1,4 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ +!function(e){var o,a;"function"==typeof define&&define.amd?define(["jquery","datatables.net-bs4","datatables.net-buttons"],function(t){return e(t,window,document)}):"object"==typeof exports?(o=require("jquery"),a=function(t,n){n.fn.dataTable||require("datatables.net-bs4")(t,n),n.fn.dataTable.Buttons||require("datatables.net-buttons")(t,n)},"undefined"!=typeof window?module.exports=function(t,n){return t=t||window,n=n||o(t),a(t,n),e(n,0,t.document)}:(a(window,o),module.exports=e(o,window,window.document))):e(jQuery,window,document)}(function(e,t,n,o){"use strict";var a=e.fn.dataTable;return e.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group flex-wrap"},button:{className:"btn btn-secondary"},collection:{tag:"div",className:"dropdown-menu",closeButton:!1,button:{tag:"a",className:"dt-button dropdown-item",active:"active",disabled:"disabled"}},splitWrapper:{tag:"div",className:"dt-btn-split-wrapper btn-group",closeButton:!1},splitDropdown:{tag:"button",text:"",className:"btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split",closeButton:!1,align:"split-left",splitAlignClass:"dt-button-split-left"},splitDropdownButton:{tag:"button",className:"dt-btn-split-drop-button btn btn-secondary",closeButton:!1}},buttonCreated:function(t,n){return t.buttons?e('
    ').append(n):n}}),a.ext.buttons.collection.className+=" dropdown-toggle",a.ext.buttons.collection.rightAlignClassName="dropdown-menu-right",a}); \ No newline at end of file diff --git a/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.js b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.js new file mode 100644 index 0000000..6730cc4 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.js @@ -0,0 +1,106 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bs5', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + var jq = require('jquery'); + var cjsRequires = function (root, $) { + if ( ! $.fn.dataTable ) { + require('datatables.net-bs5')(root, $); + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + }; + + if (typeof window !== 'undefined') { + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = jq( root ); + } + + cjsRequires( root, $ ); + return factory( $, root, root.document ); + }; + } + else { + cjsRequires( window, jq ); + module.exports = factory( jq, window, window.document ); + } + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons btn-group flex-wrap' + }, + button: { + className: 'btn btn-secondary' + }, + collection: { + tag: 'div', + className: 'dropdown-menu', + closeButton: false, + button: { + tag: 'a', + className: 'dt-button dropdown-item', + active: 'active', + disabled: 'disabled' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper btn-group', + closeButton: false, + }, + splitDropdown: { + tag: 'button', + text: '', + className: 'btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button btn btn-secondary', + closeButton: false + } + }, + buttonCreated: function ( config, button ) { + return config.buttons ? + $('
    ').append(button) : + button; + } +} ); + +DataTable.ext.buttons.collection.className += ' dropdown-toggle'; +DataTable.ext.buttons.collection.rightAlignClassName = 'dropdown-menu-right'; + + +return DataTable; +})); diff --git a/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.min.js b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.min.js new file mode 100644 index 0000000..a641a61 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bootstrap5.min.js @@ -0,0 +1,4 @@ +/*! Bootstrap integration for DataTables' Buttons + * ©2016 SpryMedia Ltd - datatables.net/license + */ +!function(e){var o,a;"function"==typeof define&&define.amd?define(["jquery","datatables.net-bs5","datatables.net-buttons"],function(t){return e(t,window,document)}):"object"==typeof exports?(o=require("jquery"),a=function(t,n){n.fn.dataTable||require("datatables.net-bs5")(t,n),n.fn.dataTable.Buttons||require("datatables.net-buttons")(t,n)},"undefined"!=typeof window?module.exports=function(t,n){return t=t||window,n=n||o(t),a(t,n),e(n,0,t.document)}:(a(window,o),module.exports=e(o,window,window.document))):e(jQuery,window,document)}(function(e,t,n,o){"use strict";var a=e.fn.dataTable;return e.extend(!0,a.Buttons.defaults,{dom:{container:{className:"dt-buttons btn-group flex-wrap"},button:{className:"btn btn-secondary"},collection:{tag:"div",className:"dropdown-menu",closeButton:!1,button:{tag:"a",className:"dt-button dropdown-item",active:"active",disabled:"disabled"}},splitWrapper:{tag:"div",className:"dt-btn-split-wrapper btn-group",closeButton:!1},splitDropdown:{tag:"button",text:"",className:"btn btn-secondary dt-btn-split-drop dropdown-toggle dropdown-toggle-split",closeButton:!1,align:"split-left",splitAlignClass:"dt-button-split-left"},splitDropdownButton:{tag:"button",className:"dt-btn-split-drop-button btn btn-secondary",closeButton:!1}},buttonCreated:function(t,n){return t.buttons?e('
    ').append(n):n}}),a.ext.buttons.collection.className+=" dropdown-toggle",a.ext.buttons.collection.rightAlignClassName="dropdown-menu-right",a}); \ No newline at end of file diff --git a/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bulma.js b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bulma.js new file mode 100644 index 0000000..2197c58 --- /dev/null +++ b/public/assets/js/DataTables/Buttons-2.3.6/js/buttons.bulma.js @@ -0,0 +1,117 @@ +/*! Bulma integration for DataTables' Buttons + * ©2021 SpryMedia Ltd - datatables.net/license + */ + +(function( factory ){ + if ( typeof define === 'function' && define.amd ) { + // AMD + define( ['jquery', 'datatables.net-bm', 'datatables.net-buttons'], function ( $ ) { + return factory( $, window, document ); + } ); + } + else if ( typeof exports === 'object' ) { + // CommonJS + var jq = require('jquery'); + var cjsRequires = function (root, $) { + if ( ! $.fn.dataTable ) { + require('datatables.net-bm')(root, $); + } + + if ( ! $.fn.dataTable.Buttons ) { + require('datatables.net-buttons')(root, $); + } + }; + + if (typeof window !== 'undefined') { + module.exports = function (root, $) { + if ( ! root ) { + // CommonJS environments without a window global must pass a + // root. This will give an error otherwise + root = window; + } + + if ( ! $ ) { + $ = jq( root ); + } + + cjsRequires( root, $ ); + return factory( $, root, root.document ); + }; + } + else { + cjsRequires( window, jq ); + module.exports = factory( jq, window, window.document ); + } + } + else { + // Browser + factory( jQuery, window, document ); + } +}(function( $, window, document, undefined ) { +'use strict'; +var DataTable = $.fn.dataTable; + + + +$.extend( true, DataTable.Buttons.defaults, { + dom: { + container: { + className: 'dt-buttons field is-grouped' + }, + button: { + className: 'button is-light', + active: 'is-active', + disabled: 'is-disabled' + }, + collection: { + tag: 'div', + closeButton: false, + className: 'dropdown-content', + button: { + tag: 'a', + className: 'dt-button dropdown-item', + active: 'is-active', + disabled: 'is-disabled' + } + }, + splitWrapper: { + tag: 'div', + className: 'dt-btn-split-wrapper dropdown-trigger buttons has-addons', + closeButton: false + }, + splitDropdownButton: { + tag: 'button', + className: 'dt-btn-split-drop-button button is-light', + closeButton: false + }, + splitDropdown: { + tag: 'button', + text: '▼', + className: 'button is-light', + closeButton: false, + align: 'split-left', + splitAlignClass: 'dt-button-split-left' + } + }, + buttonCreated: function ( config, button ) { + // For collections + if (config.buttons) { + // Wrap the dropdown content in a menu element + config._collection = $('