- Remove pageBase global from all liquid templates - Change " to ' for all liquid tags
399 lines
No EOL
12 KiB
Text
Executable file
399 lines
No EOL
12 KiB
Text
Executable file
---
|
|
title: Table
|
|
tags:
|
|
- ui
|
|
---
|
|
{% assign bodyClass = 'body_frame' -%}
|
|
{% layout 'hippie/app.liquid' %}
|
|
|
|
{% block body %}
|
|
{% render 'hippie/partials/frame-header.liquid' %}
|
|
<main class="io">
|
|
<section>
|
|
<header class="io">
|
|
<nav>
|
|
<div class="group-input">
|
|
<button id="addEntry" title="Add entry">
|
|
<i class="bi bi-plus-circle"></i>
|
|
</button>
|
|
<div class="group-input-wrap"><input id="setScroll" type="checkbox"></div>
|
|
<label for="setScroll">Scroll to new entry</label>
|
|
</div>
|
|
</nav>
|
|
<nav>
|
|
<button id="tglIndex" title="Toggle index column">
|
|
<i class="bi bi-hash"></i>
|
|
</button>
|
|
<div class="group-input">
|
|
<select id="sltNum" name="position-number">
|
|
<option value="" selected>None</option>
|
|
<option value="numeric">123</option>
|
|
<option value="latin">ABC</option>
|
|
<option value="roman">IVX</option>
|
|
</select>
|
|
<button id="setPosNum" title="Set numbering" type="button"><i class="bi bi-list-ol"></i></button>
|
|
</div>
|
|
{% comment %}TODO: Auswahl für ziehbares Element hinzufügen{% endcomment %}
|
|
</nav>
|
|
</header>
|
|
<table id="content" class="draggable">
|
|
<thead>
|
|
<tr>
|
|
<th scope="col" title="Index">#</th>
|
|
<th scope="col"></th>
|
|
<th scope="col" title="Position">#</th>
|
|
<th scope="col">Number</th>
|
|
<th scope="col">Name</th>
|
|
<th scope="col">Description</th>
|
|
<th scope="col">Amount</th>
|
|
<th scope="col">Unit</th>
|
|
<th scope="col">Price</th>
|
|
<th scope="col">Sum</th>
|
|
<th scope="col"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="positions"></tbody>
|
|
</table>
|
|
{% render 'hippie/partials/frame-status.liquid' %}
|
|
</section>
|
|
</main>
|
|
<template id="rowDefault">
|
|
<tr draggable="true">
|
|
<th scope="row"></th>
|
|
<td class="io">
|
|
<nav>
|
|
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
|
</nav>
|
|
</td>
|
|
<td class="pos-num"></td>
|
|
<td class="rigid"></td>
|
|
<td></td>
|
|
{% comment %}<td class="ellipsis"></td>{% endcomment %}
|
|
<td>
|
|
<textarea class="fit" name="description" cols="64" rows="2"></textarea>
|
|
</td>
|
|
<td><input name="amount" type="number"></td>
|
|
<td>
|
|
<select name="units">
|
|
<option value="">None</option>
|
|
<option value="piece">Piece(s)</option>
|
|
<option value="hour">Hour(s)</option>
|
|
</select>
|
|
</td>
|
|
<td class="unit"></td>
|
|
<td class="unit"></td>
|
|
<td class="io">
|
|
<nav>
|
|
<button title="Event"><i class="bi bi-calendar-event"></i></button>
|
|
<button title="Note"><i class="bi bi-journal"></i></button>
|
|
<button title="Delete"><i class="bi bi-trash"></i></button>
|
|
</nav>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
<template id="rowArticle">
|
|
<tr draggable="true">
|
|
<th scope="row"></th>
|
|
<td class="io">
|
|
<nav>
|
|
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
|
</nav>
|
|
</td>
|
|
<td class="pos-num"></td>
|
|
<td class="rigid"></td>
|
|
<td></td>
|
|
{% comment %}<td class="ellipsis"></td>{% endcomment %}
|
|
<td>
|
|
<textarea class="fit" name="description" cols="64" rows="2"></textarea>
|
|
</td>
|
|
<td><input name="amount" type="number"></td>
|
|
<td>
|
|
<select name="units">
|
|
<option value="">None</option>
|
|
<option value="piece">Piece(s)</option>
|
|
<option value="hour">Hour(s)</option>
|
|
</select>
|
|
</td>
|
|
<td class="unit"></td>
|
|
<td class="unit"></td>
|
|
<td class="io">
|
|
<nav>
|
|
<button title="Event"><i class="bi bi-calendar-event"></i></button>
|
|
<button title="Note"><i class="bi bi-journal"></i></button>
|
|
<button title="Delete"><i class="bi bi-trash"></i></button>
|
|
</nav>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
<template id="rowText">
|
|
<tr draggable="true">
|
|
<th scope="row"></th>
|
|
<td class="io">
|
|
<nav>
|
|
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
|
</nav>
|
|
</td>
|
|
<td class="pos-num"></td>
|
|
<td class="rigid"></td>
|
|
<td colspan="6">
|
|
<textarea class="fit" name="description" cols="64" rows="2"></textarea>
|
|
</td>
|
|
<td class="io">
|
|
<nav>
|
|
<button title="Event"><i class="bi bi-calendar-event"></i></button>
|
|
<button title="Note"><i class="bi bi-journal"></i></button>
|
|
<button title="Delete"><i class="bi bi-trash"></i></button>
|
|
</nav>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
<template id="rowGroup">
|
|
<tr draggable="true">
|
|
<th scope="row"></th>
|
|
<td class="io">
|
|
<nav>
|
|
<span class="a_button" data-action="drag"><i class="bi bi-grip-horizontal" title="Drag"></i></span>
|
|
<button title="Expand"><i class="bi bi-arrows-expand"></i></button>
|
|
</nav>
|
|
</td>
|
|
<td class="pos-num"></td>
|
|
<td class="rigid"></td>
|
|
<td></td>
|
|
{% comment %}<td class="ellipsis"></td>{% endcomment %}
|
|
<td>
|
|
<textarea class="fit" name="description" cols="64" rows="2"></textarea>
|
|
</td>
|
|
<td><input name="amount" type="number"></td>
|
|
<td>
|
|
<select name="units">
|
|
<option value="">None</option>
|
|
<option value="piece">Piece(s)</option>
|
|
<option value="hour">Hour(s)</option>
|
|
</select>
|
|
</td>
|
|
<td class="unit"></td>
|
|
<td class="unit"></td>
|
|
<td class="io">
|
|
<nav>
|
|
<button title="Event"><i class="bi bi-calendar-event"></i></button>
|
|
<button title="Note"><i class="bi bi-journal"></i></button>
|
|
<button title="Delete"><i class="bi bi-trash"></i></button>
|
|
</nav>
|
|
</td>
|
|
</tr>
|
|
</template>
|
|
|
|
{% render 'hippie/partials/frame-mode.liquid' %}
|
|
{% endblock %}
|
|
|
|
{%- block script %}
|
|
{{ block.super -}}
|
|
<script>
|
|
const placeholderNames = [
|
|
'Mac',
|
|
'Sonic',
|
|
'Furiosa',
|
|
'Leia',
|
|
'Frisbee',
|
|
'Ripley',
|
|
'Motoko',
|
|
'Lupin',
|
|
'Yoda',
|
|
'Spike',
|
|
'Obelix',
|
|
'Samus',
|
|
'Plisken'
|
|
];
|
|
const placeholderAttributes = [
|
|
'blue',
|
|
'tall',
|
|
'clever',
|
|
'true'
|
|
];
|
|
const placeholderContents = [
|
|
'Description - At vero eos et accusam et justo duo dolores et ea rebum.',
|
|
'',
|
|
"Content with linebreaks - \nPhasellus finibus mollis diam non posuere. Vestibulum porttitor volutpat consectetur. Duis neque sapien, tincidunt ac odio vel, laoreet ultricies ligula. Suspendisse erat eros, volutpat vel fringilla at, placerat ac nisi. \nNulla arcu elit, facilisis egestas risus ac, aliquet varius sapien. Sed et nisi fringilla nibh ultrices sagittis ac in nisl. \nPellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam porta lectus ac pharetra feugiat. In ligula nunc, porttitor non arcu vel, feugiat tempor mi. Aenean pellentesque ipsum ac ligula pulvinar, vel auctor diam vehicula. Sed at arcu lacus.",
|
|
'Very long content - Suspendisse lectus orci, convallis vitae sapien et, iaculis cursus magna. Pellentesque ultrices sodales eros eget vehicula. Aliquam tincidunt nulla non finibus ullamcorper. Ut accumsan nisi non aliquam fermentum. Vestibulum sit amet purus eu dolor vulputate pretium in eget libero. Donec vitae quam in leo eleifend semper. Cras mollis orci augue, vitae aliquam quam consequat quis. Donec sed nisi sed nulla ultricies ultricies quis ac erat. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Mauris euismod mollis neque sit amet varius. In malesuada nibh faucibus orci tincidunt, in elementum sapien pretium. Cras vel urna felis. Proin cursus tempor egestas. Nulla facilisis justo enim. Mauris fermentum, tortor a malesuada facilisis, leo tortor aliquam elit, sed sodales ipsum tortor et tellus.',
|
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum facilisis condimentum quam, bibendum tristique odio.'
|
|
];
|
|
|
|
const currencyEuro = new Intl.NumberFormat('de-DE', {style: 'currency', currency: 'EUR'});
|
|
|
|
const content = document.querySelector('main.io section > table');
|
|
const tbodyPosition = document.getElementById('positions');
|
|
|
|
tbodyPosition.addEventListener('click', (event) => {
|
|
const rows = tbodyPosition.querySelectorAll('tr');
|
|
const rowTarget = event.target.closest('tr');
|
|
|
|
if (rowTarget && event.button === 0) {
|
|
for (row of rows) {
|
|
row.classList.remove('active');
|
|
}
|
|
|
|
rowTarget.classList.add('active');
|
|
}
|
|
});
|
|
|
|
for (let i = 0; i < 256; i++) {
|
|
const clone = cloneRow();
|
|
const tr = clone.querySelector('tr');
|
|
const th = clone.querySelector('th');
|
|
const td = clone.querySelectorAll('td');
|
|
|
|
const j = i % placeholderNames.length;
|
|
const k = randomIntFrom(0, placeholderContents.length - 1);
|
|
const amount = randomIntFrom(1, 100);
|
|
const price = randomFloatFrom(1, 10000, 2);
|
|
const sum = amount * price;
|
|
|
|
tr.setAttribute('data-id', i);
|
|
th.textContent = i + 1;
|
|
td[2].textContent = getRandomFormattedString();
|
|
td[3].textContent = placeholderNames[j];
|
|
// td[2].innerHTML = replaceLineBreaks(placeholderContents[k]);
|
|
td[4].firstElementChild.textContent = placeholderContents[k];
|
|
td[5].firstElementChild.value = amount;
|
|
td[5].firstElementChild.style.width = '4em';
|
|
td[7].textContent = currencyEuro.format(price);
|
|
td[8].textContent = currencyEuro.format(sum);
|
|
|
|
tbodyPosition.appendChild(clone);
|
|
}
|
|
|
|
const selectNum = document.getElementById('sltNum');
|
|
const buttonPosNum = document.getElementById('setPosNum');
|
|
|
|
buttonPosNum.addEventListener('click', () => {
|
|
const numType = selectNum.value;
|
|
const cells = tbodyPosition.querySelectorAll('td.pos-num');
|
|
let num = '';
|
|
|
|
for (let i = 0; i < cells.length; i++) {
|
|
switch (numType) {
|
|
case 'numeric':
|
|
num = (i + 1).toString();
|
|
break;
|
|
case 'roman':
|
|
num = convertToRomanNumeral((i + 1)).toString();
|
|
break;
|
|
case '':
|
|
default:
|
|
}
|
|
|
|
cells[i].textContent = num;
|
|
}
|
|
});
|
|
|
|
const buttonIndex = document.getElementById('tglIndex');
|
|
|
|
buttonIndex.addEventListener('click', () => {
|
|
const cells = content.querySelectorAll('th:first-child');
|
|
const isHidden = cells[0].classList.contains('di_none');
|
|
|
|
for (cell of cells) {
|
|
if (isHidden) {
|
|
cell.classList.remove('di_none');
|
|
} else {
|
|
cell.classList.add('di_none');
|
|
}
|
|
}
|
|
});
|
|
|
|
const buttonAdd = document.getElementById('addEntry');
|
|
const checkScroll = document.getElementById('setScroll');
|
|
|
|
buttonAdd.addEventListener('click', () => {
|
|
const clone = cloneRow();
|
|
const viewportHeight = window.innerHeight;
|
|
const elementActive = tbodyPosition.querySelector('tr.active');
|
|
let elementNew = undefined;
|
|
let elementBound = undefined;
|
|
|
|
if (elementActive) {
|
|
elementActive.after(clone);
|
|
elementNew = elementActive.nextElementSibling;
|
|
} else {
|
|
tbodyPosition.appendChild(clone);
|
|
elementNew = tbodyPosition.lastElementChild;
|
|
}
|
|
|
|
if (checkScroll.checked) {
|
|
elementBound = elementNew.getBoundingClientRect();
|
|
|
|
if (elementBound.bottom > viewportHeight || elementBound.top < 0) {
|
|
elementNew.scrollIntoView({behavior: 'smooth', block: 'nearest'});
|
|
}
|
|
}
|
|
|
|
reindexRows(tbodyPosition);
|
|
});
|
|
|
|
let draggedRow = null;
|
|
|
|
tbodyPosition.addEventListener('dragstart', (event) => {
|
|
const rowTarget = event.target.closest('tr[draggable="true"]');
|
|
|
|
if (rowTarget) {
|
|
draggedRow = rowTarget;
|
|
rowTarget.classList.add('dragging');
|
|
event.dataTransfer.effectAllowed = 'move';
|
|
|
|
console.debug('Drag', rowTarget);
|
|
}
|
|
});
|
|
|
|
tbodyPosition.addEventListener('dragend', () => {
|
|
if (draggedRow) {
|
|
draggedRow.classList.remove('dragging');
|
|
draggedRow = null;
|
|
}
|
|
});
|
|
|
|
tbodyPosition.addEventListener('dragover', (event) => {
|
|
event.preventDefault();
|
|
event.dataTransfer.dropEffect = 'move';
|
|
|
|
const rowTarget = event.target.closest('tr');
|
|
|
|
if (rowTarget && rowTarget !== draggedRow) {
|
|
const rows = [...tbodyPosition.querySelectorAll('tr')];
|
|
const draggedIndex = rows.indexOf(draggedRow);
|
|
const targetIndex = rows.indexOf(rowTarget);
|
|
|
|
if (draggedIndex < targetIndex) {
|
|
rowTarget.parentNode.insertBefore(draggedRow, rowTarget.nextSibling);
|
|
} else {
|
|
rowTarget.parentNode.insertBefore(draggedRow, rowTarget);
|
|
}
|
|
}
|
|
});
|
|
|
|
tbodyPosition.addEventListener('drop', (event) => {
|
|
event.preventDefault();
|
|
reindexRows(event.currentTarget);
|
|
|
|
console.debug('Drop');
|
|
});
|
|
|
|
function cloneRow(type = 'default') {
|
|
type = 'row' + capitalizeFirstLetter(type);
|
|
|
|
const rowFragment = document.getElementById(type).content;
|
|
// TODO: Datenübergabe ergänzen und direkt hier in die Node aufnehmen
|
|
|
|
return document.importNode(rowFragment, true);
|
|
}
|
|
|
|
function reindexRows(parent, selector = 'tr') {
|
|
const rows = parent.querySelectorAll(selector);
|
|
let th = undefined;
|
|
|
|
for (let i = 0; i < rows.length; i++) {
|
|
th = rows[i].querySelector('th');
|
|
th.textContent = i + 1;
|
|
}
|
|
}
|
|
</script>
|
|
{% endblock %} |