mirror of
https://github.com/FH-Complete/FHC-Core.git
synced 2026-07-22 09:22:22 +00:00
primevue esm & search & favorites
This commit is contained in:
@@ -63,6 +63,9 @@ $route['api/v1/system/[S|s]prache/(:any)'] = 'api/v1/system/sprache2/$1';
|
||||
|
||||
$route['studentenverwaltung/(:any)/(:any)'] = 'Studentenverwaltung/index';
|
||||
|
||||
$route['public/js/components/primevue/(:any)/(:any)'] = 'public/Primevue/index/$1/$2';
|
||||
$route['public/js/components/primevue/(:any)/(:any)/(:any)'] = 'public/Primevue/index/$2/$3/$1';
|
||||
|
||||
// load routes from extensions
|
||||
$subdir = 'application/config/extensions';
|
||||
$dirlist = scandir($subdir);
|
||||
|
||||
@@ -67,6 +67,7 @@ class Verband extends FHC_Controller
|
||||
$this->StudiengangModel->addSelect('erhalter_kz');
|
||||
$this->StudiengangModel->addSelect('typ');
|
||||
$this->StudiengangModel->addSelect('kurzbz');
|
||||
$this->StudiengangModel->addSelect('studiengang_kz');
|
||||
|
||||
$this->StudiengangModel->addOrder('erhalter_kz');
|
||||
$this->StudiengangModel->addOrder('typ');
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
if (! defined('BASEPATH')) exit('No direct script access allowed');
|
||||
|
||||
class Primevue extends FHC_Controller
|
||||
{
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function index($path, $file, $extrapath = null)
|
||||
{
|
||||
if ($extrapath)
|
||||
$path = $extrapath . '/' . $path;
|
||||
$target = FHCPATH . 'vendor/npm-asset/primevue/' . $path . '/' . $file;
|
||||
if (!file_exists($target))
|
||||
return show_404();
|
||||
|
||||
$newUrl = '../../';
|
||||
if ($extrapath)
|
||||
$newUrl .= '../';
|
||||
|
||||
$ext = substr($file, -7) == '.min.js' ? '.esm.min.js' : '.esm.js';
|
||||
|
||||
$contents = file_get_contents($target);
|
||||
|
||||
$contents = preg_replace_callback('/import([^;]*)from\s*[\'"]vue[\'"];/i', function ($matches) {
|
||||
return 'let ' . str_replace(' as ', ': ', $matches[1]) . ' = Vue;';
|
||||
}, $contents);
|
||||
|
||||
$contents = preg_replace_callback('/(import[^;]*[\'"])(primevue[^\'"]+)([\'"])/i', function ($matches) use ($ext, $newUrl) {
|
||||
if (is_file(FHCPATH . 'vendor/npm-asset/' . $matches[2])) {
|
||||
$newUrl .= $matches[2];
|
||||
} else {
|
||||
$testfile = $matches[2] . '/index' . $ext;
|
||||
if (file_exists(FHCPATH . 'vendor/npm-asset/' . $testfile))
|
||||
$newUrl .= $testfile;
|
||||
else
|
||||
$newUrl .= $matches[2] . strrchr($matches[2], '/') . $ext;
|
||||
}
|
||||
return $matches[1] . $newUrl . $matches[3];
|
||||
}, $contents);
|
||||
|
||||
$this->output->set_content_type('text/javascript');
|
||||
$this->output->set_output($contents);
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
'bootstrap5' => true,
|
||||
'fontawesome6' => true,
|
||||
'vue3' => true,
|
||||
'primevue3' => true,
|
||||
#'primevue3' => true,
|
||||
'filtercomponent' => true,
|
||||
'tabulator5' => true,
|
||||
'phrases' => [],
|
||||
@@ -14,7 +14,8 @@
|
||||
'public/css/components/vue-datepicker.css'
|
||||
],
|
||||
'customJSs' => [
|
||||
'vendor/npm-asset/primevue/toast/toast.min.js'
|
||||
#'vendor/npm-asset/primevue/tree/tree.min.js',
|
||||
#'vendor/npm-asset/primevue/toast/toast.min.js'
|
||||
],
|
||||
'customJSModules' => [
|
||||
'public/js/apps/Studentenverwaltung.js'
|
||||
@@ -28,6 +29,7 @@
|
||||
<router-view
|
||||
default-semester="<?= $variables['semester_aktuell']; ?>"
|
||||
active-addons="<?= defined('ACTIVE_ADDONS') ? ACTIVE_ADDONS : ''; ?>"
|
||||
stv-root="<?= site_url('Studentenverwaltung'); ?>"
|
||||
cis-root="<?= CIS_ROOT; ?>"
|
||||
:permissions="<?= htmlspecialchars(json_encode($permissions)); ?>"
|
||||
:config="<?= htmlspecialchars(json_encode(['generateAlias' => !defined('GENERATE_ALIAS_STUDENT') ? true : GENERATE_ALIAS_STUDENT])); ?>"
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
{
|
||||
generateCSSsInclude('vendor/fortawesome/font-awesome6/css/fontawesome.min.css');
|
||||
generateCSSsInclude('vendor/fortawesome/font-awesome6/css/solid.min.css');
|
||||
generateCSSsInclude('vendor/fortawesome/font-awesome6/css/regular.min.css'); // NOTE(chris): for favorites in stv
|
||||
generateCSSsInclude('vendor/fortawesome/font-awesome6/css/brands.min.css');
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -422,7 +422,7 @@
|
||||
"nategood/httpful": "0.2.*",
|
||||
"netcarver/textile": "3.7.*",
|
||||
"nicolaskruchten/pivottable": "2.23.0",
|
||||
"npm-asset/primevue": "3.15.*",
|
||||
"npm-asset/primevue": "3.29.*",
|
||||
"npm-asset/primeicons": "5.0.0",
|
||||
|
||||
"olifolkerd/tabulator4": "4.9.*",
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
@import './components/searchbar.css';
|
||||
@import './components/verticalsplit.css';
|
||||
@import '../../vendor/npm-asset/primevue/resources/themes/bootstrap4-light-blue/theme.css';
|
||||
@import '../../vendor/npm-asset/primevue/resources/primevue.min.css';
|
||||
@import '../../vendor/npm-asset/primeicons/primeicons.css';
|
||||
|
||||
.navbar-dark .navbar-brand:focus {
|
||||
box-shadow: 0 0 0 .25rem rgba(13,110,253,.25);
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.searchbar {
|
||||
margin-right: 0!important;
|
||||
@@ -23,6 +31,10 @@
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
#sidebarMenu {
|
||||
width: 0%;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
#sidebarMenu {
|
||||
visibility: visible!important;
|
||||
@@ -39,6 +51,8 @@
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.stv-verband .p-treetable-tbody > tr > td {
|
||||
display: flex;
|
||||
padding-top: .25rem!important;
|
||||
@@ -51,6 +65,15 @@
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
|
||||
.stv-verband.p-tree {
|
||||
/*overflow: auto;*/
|
||||
}
|
||||
.stv-verband.p-tree .p-treenode-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
.stv-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
import FhcStudentenverwaltung from "../components/Stv/Studentenverwaltung.js";
|
||||
import fhcapifactory from "./api/fhcapifactory.js";
|
||||
|
||||
import PvConfig from "../../../index.ci.php/public/js/components/primevue/config/config.esm.min.js";
|
||||
|
||||
Vue.$fhcapi = fhcapifactory;
|
||||
|
||||
const ciPath = FHC_JS_DATA_STORAGE_OBJECT.app_root.replace(/(https:|)(^|\/\/)(.*?\/)/g, '') + FHC_JS_DATA_STORAGE_OBJECT.ci_router;
|
||||
@@ -35,6 +37,7 @@ const app = Vue.createApp();
|
||||
|
||||
app
|
||||
.use(router)
|
||||
.use(primevue.config.default)
|
||||
.use(PvConfig)
|
||||
.use(ErrorHandling)
|
||||
.mount('#main');
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ export default {
|
||||
defaultSemester: String,
|
||||
config: Object,
|
||||
permissions: Object,
|
||||
stvRoot: String,
|
||||
cisRoot: String,
|
||||
activeAddons: String // semicolon separated list of active addons
|
||||
},
|
||||
@@ -107,7 +108,7 @@ export default {
|
||||
},
|
||||
template: `
|
||||
<header class="navbar navbar-expand-lg navbar-dark bg-dark flex-md-nowrap p-0 shadow">
|
||||
<a class="navbar-brand col-md-4 col-lg-3 col-xl-2 me-0 px-3" href="<?= site_url('Studentenverwaltung'); ?>">FHC 4.0</a>
|
||||
<a class="navbar-brand col-md-4 col-lg-3 col-xl-2 me-0 px-3" :href="stvRoot">FHC 4.0</a>
|
||||
<button class="navbar-toggler d-md-none m-1 collapsed" type="button" data-bs-toggle="offcanvas" data-bs-target="#sidebarMenu" aria-controls="sidebarMenu" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
|
||||
<fhc-searchbar :searchoptions="searchbaroptions" :searchfunction="searchfunction" class="searchbar w-100"></fhc-searchbar>
|
||||
</header>
|
||||
|
||||
@@ -2,11 +2,15 @@ import VueDatePicker from '../../../vueDatepicker.js.php';
|
||||
import FormUploadImage from '../../../Form/Upload/Image.js';
|
||||
import {CoreRESTClient} from '../../../../RESTClient.js';
|
||||
|
||||
|
||||
import PvToast from "../../../../../../index.ci.php/public/js/components/primevue/toast/toast.esm.min.js";
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VueDatePicker,
|
||||
FormUploadImage,
|
||||
PvToast: primevue.toast
|
||||
PvToast
|
||||
},
|
||||
inject: {
|
||||
showBpk: {
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
import {CoreRESTClient} from '../../../RESTClient.js';
|
||||
|
||||
|
||||
import PvTree from "../../../../../index.ci.php/public/js/components/primevue/tree/tree.esm.min.js";
|
||||
import PvTreetable from "../../../../../index.ci.php/public/js/components/primevue/treetable/treetable.esm.min.js";
|
||||
import PvColumn from "../../../../../index.ci.php/public/js/components/primevue/column/column.esm.min.js";
|
||||
|
||||
|
||||
export default {
|
||||
components: {
|
||||
TreeTable: primevue.treetable,
|
||||
TreeColumn: primevue.column
|
||||
PvTree,
|
||||
PvTreetable,
|
||||
PvColumn
|
||||
},
|
||||
emits: [
|
||||
'selectVerband'
|
||||
],
|
||||
data() {
|
||||
return {
|
||||
debug_version: 1, // NOTE(chris): switch between tree/treetable and filter/favorites...
|
||||
loading: true,
|
||||
selected: {}, // NOTE(chris): tree only
|
||||
nodes: []
|
||||
}
|
||||
},
|
||||
@@ -18,6 +27,12 @@ export default {
|
||||
onExpandTreeNode(node) {
|
||||
if (!node.children) {
|
||||
if (node.data.link) {
|
||||
let activeEl = null;
|
||||
this.$nextTick(() => {
|
||||
this.$nextTick(() => {
|
||||
activeEl = document.activeElement;
|
||||
});
|
||||
});
|
||||
this.loading = true;
|
||||
CoreRESTClient
|
||||
.get("components/stv/verband/" + node.data.link)
|
||||
@@ -25,6 +40,21 @@ export default {
|
||||
.then(result => {
|
||||
const subNodes = result.map(this.mapResultToTreeData);
|
||||
node.children = subNodes;
|
||||
|
||||
let treeitem = this.$refs.tree.$el.querySelector('[data-tree-item-key="' + node.key + '"]');
|
||||
if (!this.debug_version) // NOTE(chris): tree only
|
||||
treeitem = treeitem.closest('[role="treeitem"]');
|
||||
else // NOTE(chris): treetable only
|
||||
treeitem = treeitem.closest('[role="row"]');
|
||||
|
||||
this.$nextTick(() => {
|
||||
if (activeEl == document.activeElement)
|
||||
treeitem.dispatchEvent(new KeyboardEvent('keydown', {
|
||||
code: 'ArrowDown',
|
||||
key: 'ArrowDown'
|
||||
}));
|
||||
});
|
||||
|
||||
this.loading = false;
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -40,7 +70,8 @@ export default {
|
||||
mapResultToTreeData(el) {
|
||||
const cp = {
|
||||
key: ("" + el.link).replace('/', '-'),
|
||||
data: el
|
||||
data: el,
|
||||
label: el.name
|
||||
};
|
||||
|
||||
if (el.children)
|
||||
@@ -49,6 +80,15 @@ export default {
|
||||
cp.leaf = el.leaf || false;
|
||||
|
||||
return cp;
|
||||
},
|
||||
onFilterKeydown(data) {
|
||||
// NOTE(chris): tree only
|
||||
// TODO(chris): we can online search here
|
||||
},
|
||||
markFav(key) {
|
||||
// NOTE(chris): treetable only
|
||||
// TODO(chris): IMPLEMENT
|
||||
// TODO(chris): make clickable with keyboard
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
@@ -64,7 +104,48 @@ export default {
|
||||
});
|
||||
},
|
||||
template: `
|
||||
<tree-table class="stv-verband p-treetable-sm" :value="nodes" lazy @node-expand="onExpandTreeNode" selection-mode="single" @node-select="onSelectTreeNode" scrollable scroll-height="flex">
|
||||
<tree-column field="name" header="Verband" expander></tree-column>
|
||||
</tree-table>`
|
||||
<div v-if="!debug_version" class="overflow-auto" tabindex="-1">
|
||||
<pv-tree
|
||||
ref="tree"
|
||||
class="stv-verband p-0"
|
||||
v-model:selectionKeys="selected"
|
||||
:value="nodes"
|
||||
selection-mode="single"
|
||||
@node-select="onSelectTreeNode"
|
||||
@node-expand="onExpandTreeNode"
|
||||
:loading="loading"
|
||||
filter
|
||||
:pt="{input:{onKeydown:onFilterKeydown}}"
|
||||
>
|
||||
<template #default="{node}">
|
||||
<span :data-tree-item-key="node.key" :title="node.data.studiengang_kz">{{node.label}}</span>
|
||||
</template>
|
||||
</pv-tree>
|
||||
</div>
|
||||
<div v-else class="overflow-auto" tabindex="-1">
|
||||
<pv-treetable
|
||||
ref="tree"
|
||||
class="stv-verband p-treetable-sm"
|
||||
:value="nodes"
|
||||
lazy
|
||||
@node-expand="onExpandTreeNode"
|
||||
selection-mode="single"
|
||||
@node-select="onSelectTreeNode"
|
||||
scrollable
|
||||
scroll-height="flex"
|
||||
>
|
||||
<pv-column field="name" header="Verband" expander>
|
||||
<template #body="{node}">
|
||||
<span :data-tree-item-key="node.key" :title="node.data.studiengang_kz">
|
||||
{{node.data.name}}
|
||||
</span>
|
||||
</template>
|
||||
</pv-column>
|
||||
<pv-column field="fav" header="FAV" headerStyle="flex: 0 0 auto" style="flex: 0 0 auto">
|
||||
<template #body="{node}">
|
||||
<i :class="node.data.fav ? 'fa-solid' : 'fa-regular'" class="fa-star" @click="markFav(node.key)"></i>
|
||||
</template>
|
||||
</pv-column>
|
||||
</pv-treetable>
|
||||
</div>`
|
||||
};
|
||||
Reference in New Issue
Block a user