mirror of
https://github.com/dalbodeule/snap-admin.git
synced 2025-08-14 23:51:12 +00:00
0.0.1 Alpha version
This commit is contained in:
157
src/main/resources/static/css/dbadmin.css
Normal file
157
src/main/resources/static/css/dbadmin.css
Normal file
@@ -0,0 +1,157 @@
|
||||
form.delete-form {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
form.delete-form button {
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.dbfieldtype {
|
||||
font-weight: normal;
|
||||
font-family: monospace;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
|
||||
a .bi, button .bi {
|
||||
color: #007fd0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #007fd0;
|
||||
}
|
||||
|
||||
.disable {
|
||||
pointer-events: none;
|
||||
background: #EDECEF;
|
||||
}
|
||||
|
||||
.null-label {
|
||||
background-color: #EEE;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #DDD;
|
||||
display: inline-block;
|
||||
padding: 3px;
|
||||
color: #333;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
ul.pagination {
|
||||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
tr.table-data-row td, tr.table-data-row th {
|
||||
border-right: 1px solid #DDD;
|
||||
}
|
||||
|
||||
tr.table-data-row td:last-child, tr.table-data-row th:last-child {
|
||||
border-right: 0px;
|
||||
}
|
||||
|
||||
.row-icons {
|
||||
font-size: 1.2rem;
|
||||
width: 128px;
|
||||
}
|
||||
|
||||
h1 .bi {
|
||||
font-size: 2rem;
|
||||
}
|
||||
|
||||
h1 a {
|
||||
color: #222;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1 a:hover {
|
||||
color: #007fd0;
|
||||
}
|
||||
|
||||
|
||||
.inner-navigation {
|
||||
border-top-right-radius: 5px;
|
||||
border-top-left-radius: 5px;
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
.inner-navigation a:first-child {
|
||||
border-top-left-radius: 5px;
|
||||
background-color: #FAFAFA;
|
||||
}
|
||||
|
||||
.inner-navigation-border {
|
||||
border-bottom: 4px solid #F0F0F0;
|
||||
}
|
||||
|
||||
.inner-navigation a {
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
border-bottom: 4px solid #F0F0F0;
|
||||
}
|
||||
|
||||
.inner-navigation a.active {
|
||||
border-bottom: 4px solid #007fd0 !important;
|
||||
}
|
||||
|
||||
|
||||
.inner-navigation a:hover {
|
||||
background-color: #FFF;
|
||||
border-bottom: 4px solid #ADDEFF;
|
||||
}
|
||||
|
||||
|
||||
.suggestions {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
background-color: white;
|
||||
border: 1px solid #DADADA;
|
||||
border-bottom-right-radius: 5px;
|
||||
border-bottom-left-radius: 5px;
|
||||
top: 100%;
|
||||
max-height: 300px;
|
||||
overflow: auto;
|
||||
z-index: 999;
|
||||
}
|
||||
|
||||
.suggestion {
|
||||
padding: 1rem;
|
||||
background-color: #FAFAFA;
|
||||
padding-bottom: 0;
|
||||
margin: 0;
|
||||
border-bottom: 2px solid #FAFAFA;
|
||||
}
|
||||
|
||||
.suggestion:hover {
|
||||
cursor: pointer;
|
||||
background-color: #FFF;
|
||||
border-bottom: 2px solid #ADDEFF;
|
||||
}
|
||||
|
||||
td.table-checkbox, th.table-checkbox {
|
||||
width: 36px;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
AUTOCOMPLETE
|
||||
**/
|
||||
.badge-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.value-badge {
|
||||
cursor: pointer; -webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.value-badge .badge {
|
||||
font-size: 1rem;
|
||||
padding: 8px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.clear-all-badge {
|
||||
padding: 0.4rem;
|
||||
}
|
372
src/main/resources/static/css/style.css
Normal file
372
src/main/resources/static/css/style.css
Normal file
@@ -0,0 +1,372 @@
|
||||
body {
|
||||
font-family: "Poppins", "Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h1, h2, h3, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||
font-family: "Roboto", "Segoe UI", sans-serif;
|
||||
}
|
||||
|
||||
.bg-lighter {
|
||||
background-color: #F2F2F2;
|
||||
}
|
||||
|
||||
#map { height: 100%; }
|
||||
|
||||
.bg-lightest {
|
||||
background-color: #F8F8F8;
|
||||
}
|
||||
|
||||
.bg-red {
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.bg-white {
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.box {
|
||||
border-radius: 5px;
|
||||
width: 100%;
|
||||
background-color: #FAFAFA;
|
||||
padding: 25px;
|
||||
-webkit-box-shadow: 10px 10px 84px -44px rgba(0,0,0,0.27);
|
||||
-moz-box-shadow: 10px 10px 84px -44px rgba(0,0,0,0.27);
|
||||
box-shadow: 10px 10px 84px -44px rgba(0,0,0,0.27);
|
||||
}
|
||||
|
||||
|
||||
.box.with-navigation {
|
||||
border-radius: 5px;
|
||||
border-top-right-radius: 0px;
|
||||
border-top-left-radius: 0px;
|
||||
width: 100%;
|
||||
background-color: #FAFAFA;
|
||||
padding: 25px;
|
||||
-webkit-box-shadow: 10px 10px 84px -44px rgba(0,0,0,0.27);
|
||||
-moz-box-shadow: 10px 10px 84px -74px rgba(0,0,0,0.27);
|
||||
box-shadow: 10px 10px 84px -74px rgba(0,0,0,0.27);
|
||||
}
|
||||
|
||||
|
||||
.box.with-telegram-embed {
|
||||
padding: 10px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
|
||||
.box.with-footer-button {
|
||||
position: relative;
|
||||
padding-bottom: 70px;
|
||||
}
|
||||
|
||||
.box.box-h-300 {
|
||||
height: 300px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.navbar-brand .bi-activity {
|
||||
color: green;
|
||||
}
|
||||
|
||||
.navbar {
|
||||
opacity: 0.90;
|
||||
}
|
||||
|
||||
.navbar-brand .bi-hexagon-fill {
|
||||
color: #3fb95f;
|
||||
}
|
||||
|
||||
.bg-complementary {
|
||||
background-color: #3fb95f;
|
||||
}
|
||||
|
||||
div.main-wrapper {
|
||||
height: 100vh;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
div.sidebar {
|
||||
width: 200px;
|
||||
min-height: 100vh;
|
||||
padding: 56px 0px 25px 0px;
|
||||
-webkit-box-shadow: 10px 2px 67px -30px rgba(0,0,0,0.25);
|
||||
-moz-box-shadow: 10px 2px 67px -30px rgba(0,0,0,0.25);
|
||||
box-shadow: 10px 2px 67px -30px rgba(0,0,0,0.25);
|
||||
}
|
||||
|
||||
.sidebar-top {
|
||||
width: 200px;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
div.main-content {
|
||||
padding: 50px;
|
||||
width: calc(100% - 200px);
|
||||
padding-top: 80px;
|
||||
}
|
||||
|
||||
div.main-content.full-screen {
|
||||
padding: 0px;
|
||||
padding-top: 56px;
|
||||
}
|
||||
|
||||
|
||||
ul.sidebar-menu {
|
||||
list-style-type: none;
|
||||
padding-left: 0px;
|
||||
|
||||
}
|
||||
|
||||
ul.sidebar-menu li {
|
||||
background-color: #F8F8F8;
|
||||
border-left: 5px solid #F2F2F2;
|
||||
}
|
||||
|
||||
ul.sidebar-menu li.active {
|
||||
border-left: 5px solid #0092ee;
|
||||
}
|
||||
|
||||
ul.sidebar-menu li:hover {
|
||||
border-left: 5px solid #7fc8f6;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
ul.sidebar-menu li a {
|
||||
text-decoration: none;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
ul.sidebar-menu .menu-icon {
|
||||
padding: 8px;
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
.navbar.fixed-top {
|
||||
-webkit-box-shadow: 0px 5px 67px -30px rgba(0,0,0,1);
|
||||
-moz-box-shadow: 0px 5px 67px -30px rgba(0,0,0,1);
|
||||
box-shadow: 0px 5px 67px -30px rgba(0,0,0,1);
|
||||
}
|
||||
|
||||
em {
|
||||
background-color: #f1f4d0;
|
||||
}
|
||||
|
||||
.label {
|
||||
font-weight: bold;
|
||||
color: #444
|
||||
}
|
||||
|
||||
.label a {
|
||||
text-decoration: none;
|
||||
color: #0293c9;
|
||||
}
|
||||
|
||||
.label-gray {
|
||||
background-color: #EEE;
|
||||
border-radius: 5px;
|
||||
border: 1px solid #DDD;
|
||||
padding: 3px 6px 0px 6px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.message-text {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.form-date {
|
||||
border: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.form-select {
|
||||
border: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.separator {
|
||||
height: 2px;
|
||||
border-bottom: 1px solid #CCC;
|
||||
}
|
||||
|
||||
.menu-subheading {
|
||||
text-transform: uppercase;
|
||||
color: #444;
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.btn-outline-left {
|
||||
border-top-left-radius: 0px;
|
||||
border-bottom-left-radius: 0px;
|
||||
border-left: 0px;
|
||||
}
|
||||
|
||||
.channel-about {
|
||||
font-size: 0.9rem;
|
||||
color: #555;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
p.fine {
|
||||
font-size: 0.9rem;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
|
||||
div.sidebar-bottom {
|
||||
position: fixed;
|
||||
bottom: 0px;
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
.fs-smaller {
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.fs-bigger {
|
||||
text-align: center;
|
||||
color: #0092ee;
|
||||
font-weight: bold;
|
||||
font-size: 2.3rem;
|
||||
}
|
||||
|
||||
.fs-big {
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.form-control:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-check:focus+.btn-outline-primary, .btn-outline-primary:focus {
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.color-telegram {
|
||||
color: #0092ee;
|
||||
}
|
||||
|
||||
.bg-accent {
|
||||
background-color: #007fd0;
|
||||
}
|
||||
|
||||
.bg-accent a.navbar-brand {
|
||||
color: #EEE;
|
||||
}
|
||||
|
||||
.bg-accent a.navbar-brand:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility height classes
|
||||
*/
|
||||
|
||||
.h-200 {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.h-300 {
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.h-400 {
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.h-500 {
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
.h-600 {
|
||||
height: 600px;
|
||||
}
|
||||
|
||||
.h-700 {
|
||||
height: 700px;
|
||||
}
|
||||
|
||||
.h-800 {
|
||||
height: 800px;
|
||||
}
|
||||
|
||||
.h-1000 {
|
||||
height: 1000px;
|
||||
}
|
||||
|
||||
.h-fill {
|
||||
height: calc(100vh - 56px);
|
||||
}
|
||||
|
||||
.overflow-auto {
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.color-white {
|
||||
color:white !important;
|
||||
}
|
||||
|
||||
.ui-text-input {
|
||||
border: 0px;
|
||||
border-bottom: 2px solid #52b5f3;
|
||||
background-color: white;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
span.input-group-text {
|
||||
background-color: #F0F0F0;
|
||||
border:0px;
|
||||
border-bottom: 2px solid #0768a5;
|
||||
border-radius: 0px;
|
||||
}
|
||||
|
||||
.ui-btn {
|
||||
border-radius: 0px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: #21a0f0;
|
||||
border: 1px solid #21a0f0;
|
||||
}
|
||||
|
||||
.w-10 {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.w-5 {
|
||||
width: 5%;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 767px) {
|
||||
div.sidebar {
|
||||
width: 53px;
|
||||
}
|
||||
|
||||
.sidebar-top {
|
||||
width: 53px;
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
|
||||
div.main-content {
|
||||
width: calc(100% - 53px);
|
||||
padding: 15px;
|
||||
padding-top: 70px;
|
||||
}
|
||||
|
||||
div.box {
|
||||
padding: 15px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
div.sidebar-bottom {
|
||||
width: 53px;
|
||||
}
|
||||
|
||||
.extra-toolbar {
|
||||
left: 53px;
|
||||
}
|
||||
|
||||
.extra-toolbar ul {
|
||||
padding-left: 0px;
|
||||
}
|
||||
}
|
123
src/main/resources/static/js/autocomplete-multi.js
Normal file
123
src/main/resources/static/js/autocomplete-multi.js
Normal file
@@ -0,0 +1,123 @@
|
||||
/* Request to the autocomplete REST endpoit */
|
||||
async function getSuggestions(className, query) {
|
||||
const response = await fetch(`/dbadmin/api/autocomplete/${className}?query=${query}`);
|
||||
const suggestions = await response.json();
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
function hideSuggestions(inputElement) {
|
||||
let suggestionsDiv = inputElement.parentElement.querySelector("div.suggestions");
|
||||
suggestionsDiv.classList.remove('d-block');
|
||||
suggestionsDiv.classList.add('d-none');
|
||||
}
|
||||
|
||||
function showSuggestions(inputElement) {
|
||||
let suggestionsDiv = inputElement.parentElement.querySelector("div.suggestions");
|
||||
suggestionsDiv.classList.remove('d-none');
|
||||
suggestionsDiv.classList.add('d-block');
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
let rootElements = document.querySelectorAll(".autocomplete-multi-input");
|
||||
|
||||
/* Instead of using onBlur, which takes precedence over onClick
|
||||
/* and causes the click event to disappear, we detect click
|
||||
/* on outside elements and close all the autocomplete manually */
|
||||
document.querySelector("body").addEventListener('click', function(e) {
|
||||
if (!e.target.classList.contains("suggestion") && !e.target.classList.contains("autocomplete")) {
|
||||
rootElements.forEach(root => {
|
||||
hideSuggestions(root.querySelector("input.autocomplete"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
rootElements.forEach(root => {
|
||||
/* Event listener to delete badge on click
|
||||
*/
|
||||
root.querySelectorAll(".selected-values .value-badge").forEach(badge => {
|
||||
badge.addEventListener('click', function() {
|
||||
badge.remove();
|
||||
});
|
||||
});
|
||||
|
||||
root.querySelector(".clear-all-badge").addEventListener('click', function(e) {
|
||||
e.target.classList.add('d-none');
|
||||
e.target.classList.remove('d-inline-block');
|
||||
root.querySelectorAll(".selected-values .value-badge").forEach(badge => {
|
||||
badge.remove();
|
||||
});
|
||||
});
|
||||
|
||||
let input = root.querySelector("input.autocomplete");
|
||||
if (input == undefined) return;
|
||||
|
||||
input.addEventListener('focus', function() {
|
||||
showSuggestions(input);
|
||||
});
|
||||
|
||||
let fieldName = input.dataset.fieldname;
|
||||
|
||||
input.parentElement.querySelector("div.suggestions").innerHTML =
|
||||
`<div class="suggestion p-2 m-0">Start typing for suggestions</div>`;
|
||||
|
||||
input.addEventListener('keyup', async function(e) {
|
||||
let suggestions = await getSuggestions(e.target.dataset.classname, e.target.value);
|
||||
input.parentElement.querySelector("div.suggestions").innerHTML = "";
|
||||
|
||||
if (e.target.value.length <= 1) {
|
||||
input.parentElement.querySelector("div.suggestions").innerHTML =
|
||||
`<div class="suggestion p-2 m-0">Start typing for suggestions</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
suggestions.forEach(suggestion => {
|
||||
let suggestionDiv = document.createElement('div');
|
||||
suggestionDiv.innerHTML =
|
||||
`<div class="suggestion p-2 m-0">
|
||||
<strong>${suggestion.id}</strong>
|
||||
<p class="p-0 m-0">${suggestion.value}</p>
|
||||
</div>`;
|
||||
|
||||
input.parentElement.querySelector("div.suggestions").appendChild(suggestionDiv);
|
||||
|
||||
suggestionDiv.addEventListener('click', function(e) {
|
||||
hideSuggestions(input);
|
||||
input.value = '';
|
||||
|
||||
// Check if we need to add the 'Clear all' button back
|
||||
root.querySelector(".clear-all-badge").classList.add('d-inline-block');
|
||||
root.querySelector(".clear-all-badge").classList.remove('d-none');
|
||||
|
||||
|
||||
root.querySelector(".selected-values")
|
||||
.innerHTML += `
|
||||
<span class="value-badge">
|
||||
<input type="checkbox" class="badge-checkbox" checked="checked"
|
||||
name="${fieldName}" value="${suggestion.id}">
|
||||
<span class="badge bg-primary me-2">
|
||||
${suggestion.value}
|
||||
</span>
|
||||
</span>`
|
||||
|
||||
root.querySelectorAll(".selected-values .value-badge").forEach(badge => {
|
||||
badge.addEventListener('click', function() {
|
||||
badge.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
if (suggestions.length == 0) {
|
||||
let suggestionDiv = document.createElement('div');
|
||||
suggestionDiv.innerHTML =
|
||||
`<div class="suggestion p-2 m-0">
|
||||
<p class="p-0 m-0">No results</p>
|
||||
</div>`;
|
||||
|
||||
input.parentElement.querySelector("div.suggestions").appendChild(suggestionDiv);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
83
src/main/resources/static/js/autocomplete.js
Normal file
83
src/main/resources/static/js/autocomplete.js
Normal file
@@ -0,0 +1,83 @@
|
||||
/* Request to the autocomplete REST endpoit */
|
||||
async function getSuggestions(className, query) {
|
||||
const response = await fetch(`/dbadmin/api/autocomplete/${className}?query=${query}`);
|
||||
const suggestions = await response.json();
|
||||
return suggestions;
|
||||
}
|
||||
|
||||
function hideSuggestions(inputElement) {
|
||||
let suggestionsDiv = inputElement.parentElement.querySelector("div.suggestions");
|
||||
suggestionsDiv.classList.remove('d-block');
|
||||
suggestionsDiv.classList.add('d-none');
|
||||
}
|
||||
|
||||
function showSuggestions(inputElement) {
|
||||
let suggestionsDiv = inputElement.parentElement.querySelector("div.suggestions");
|
||||
suggestionsDiv.classList.remove('d-none');
|
||||
suggestionsDiv.classList.add('d-block');
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
/* Instead of using onBlur, which takes precedence over onClick
|
||||
/* and causes the click event to disappear, we detect click
|
||||
/* on outside elements and close all the autocomplete manually */
|
||||
document.querySelector("body").addEventListener('click', function(e) {
|
||||
if (!e.target.classList.contains("suggestion") && !e.target.classList.contains("autocomplete")) {
|
||||
rootElements.forEach(root => {
|
||||
hideSuggestions(root.querySelector("input.autocomplete"));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
let rootElements = document.querySelectorAll(".autocomplete-input");
|
||||
|
||||
rootElements.forEach(root => {
|
||||
let input = root.querySelector("input.autocomplete");
|
||||
if (input == undefined) return;
|
||||
|
||||
input.addEventListener('focus', function() {
|
||||
showSuggestions(input);
|
||||
});
|
||||
|
||||
input.parentElement.querySelector("div.suggestions").innerHTML =
|
||||
`<div class="suggestion p-2 m-0">Enter a valid ID or start typing for suggestions</div>`;
|
||||
|
||||
input.addEventListener('keyup', async function(e) {
|
||||
let suggestions = await getSuggestions(e.target.dataset.classname, e.target.value);
|
||||
input.parentElement.querySelector("div.suggestions").innerHTML = "";
|
||||
|
||||
if (e.target.value.length <= 0) {
|
||||
input.parentElement.querySelector("div.suggestions").innerHTML =
|
||||
`<div class="suggestion p-2 m-0">Enter a valid ID or start typing for suggestions</div>`;
|
||||
return;
|
||||
}
|
||||
|
||||
suggestions.forEach(suggestion => {
|
||||
let suggestionDiv = document.createElement('div');
|
||||
suggestionDiv.innerHTML =
|
||||
`<div class="suggestion p-2 m-0">
|
||||
<strong>${suggestion.id}</strong>
|
||||
<p class="p-0 m-0">${suggestion.value}</p>
|
||||
</div>`;
|
||||
|
||||
input.parentElement.querySelector("div.suggestions").appendChild(suggestionDiv);
|
||||
|
||||
suggestionDiv.addEventListener('click', function(e) {
|
||||
input.value = suggestion.id;
|
||||
hideSuggestions(input);
|
||||
});
|
||||
});
|
||||
|
||||
if (suggestions.length == 0) {
|
||||
let suggestionDiv = document.createElement('div');
|
||||
suggestionDiv.innerHTML =
|
||||
`<div class="suggestion p-2 m-0">
|
||||
<p class="p-0 m-0">No results</p>
|
||||
</div>`;
|
||||
|
||||
input.parentElement.querySelector("div.suggestions").appendChild(suggestionDiv);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
66
src/main/resources/static/js/table.js
Normal file
66
src/main/resources/static/js/table.js
Normal file
@@ -0,0 +1,66 @@
|
||||
function updateBulkActions(table, selected) {
|
||||
let divs = document.querySelectorAll(".bulk-actions");
|
||||
divs.forEach(div => {
|
||||
div.innerHTML = `${selected} items selected <input type="submit" form="delete-form" class="ui-btn btn btn-secondary" value="Delete">`;
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
let selected = 0;
|
||||
|
||||
if (document.getElementById('delete-form') != null) {
|
||||
document.getElementById('delete-form').addEventListener('submit', function(e) {
|
||||
if (selected == 0) {
|
||||
e.preventDefault();
|
||||
alert('No items selected');
|
||||
return;
|
||||
}
|
||||
|
||||
if (!confirm('Are you sure you want to delete these items?')) {
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll("div.table-selectable").forEach(table => {
|
||||
let tableInputs = table.querySelectorAll("table input[type=\"checkbox\"]");
|
||||
|
||||
tableInputs.forEach(input => {
|
||||
if (input.checked && !input.classList.contains('check-all')) selected++;
|
||||
|
||||
input.addEventListener('change', function(e) {
|
||||
if (e.target.classList.contains('check-all')) {
|
||||
if (e.target.checked) {
|
||||
selected = tableInputs.length - 1;
|
||||
tableInputs.forEach(input => {
|
||||
input.checked = true;
|
||||
});
|
||||
} else {
|
||||
selected = 0;
|
||||
tableInputs.forEach(input => {
|
||||
input.checked = false;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (e.target.checked) {
|
||||
selected++;
|
||||
} else {
|
||||
selected--;
|
||||
}
|
||||
}
|
||||
|
||||
updateBulkActions(table, selected);
|
||||
});
|
||||
});
|
||||
|
||||
updateBulkActions(table, selected);
|
||||
});
|
||||
|
||||
if (document.querySelector("div.table-selectable select.page-size") != null) {
|
||||
document.querySelector("div.table-selectable select.page-size").addEventListener('change', function(e) {
|
||||
this.parentElement.querySelector("input[name=\"pageSize\"]").value = e.target.value;
|
||||
this.parentElement.submit();
|
||||
});
|
||||
}
|
||||
|
||||
});
|
Reference in New Issue
Block a user