HEX
Server: LiteSpeed
System: Linux houston.panomity.com 6.8.0-100-generic #100-Ubuntu SMP PREEMPT_DYNAMIC Tue Jan 13 16:40:06 UTC 2026 x86_64
User: nudepix (1011)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /home/timetracker.panomity.com/templates/quick-entry/index.html.twig
{% extends 'base.html.twig' %}

{% block page_class %}quick-entry-page{% endblock %}

{% block main %}
    {% embed '@theme/embeds/card.html.twig' %}
        {% import "macros/widgets.html.twig" as widgets %}
        {% block box_attributes %}id="quick_entry_box"{% endblock %}
        {% block box_before %}
            {{ form_start(form, {attr: {id: 'quick-entries-form', class: 'form-dataTable quick-entries'}}) }}
            {{ form_widget(form._token) }}
        {% endblock %}
        {% block box_after %}{{ form_end(form) }}{% endblock %}
        {% block box_title %}
            {{ form_widget(form.date) }}
        {% endblock %}
        {# "table-responsive" does not work, because that would render dropdowns at the bottom behind the container #}
        {% block box_body_class %}p-0 maybe-table-responsive{% endblock %}
        {% block box_body %}
            <table class="table dataTable">
                <thead class="sticky-top">
                    <tr>
                        <th>{{ 'project'|trans }}</th>
                        <th>{{ 'activity'|trans }}</th>
                        {% for id, week in days %}
                        <th class="text-center{% if week.day is weekend %} weekend{% endif %}{% if week.day is today %} today{% endif %}">
                            {{ week.day|date_weekday }}
                        </th>
                        {% endfor %}
                        <th class="summary">{{ 'duration'|trans }}</th>
                    </tr>
                </thead>
                <tbody id="ts-collection" data-index="{{ form.rows.children|length }}">
                    {{ form_widget(form.rows) }}
                </tbody>
                <tfoot>
                    <tr class="summary">
                        <td>{{ 'stats.durationTotal'|trans }}</td>
                        <td></td>
                        {% for id, week in days %}
                            <td class="text-center" id="qe-totals-day-{{ loop.index0 }}"></td>
                        {% endfor %}
                        <td class="text-center" id="qe-totals-week"></td>
                    </tr>
                </tfoot>
            </table>
        {% endblock %}
        {% block box_footer %}
            <input type="submit" value="{{ 'action.save'|trans }}" class="btn btn-primary" />
            <button type="button" class="btn btn-success add-item-link" data-collection-prototype="{{ form.rows.vars.id }}" data-collection-holder="ts-collection">
                {{ icon('create', true) }}
                {{ 'action.add'|trans }}
            </button>
        {% endblock %}
    {% endembed %}
{% endblock %}

{% block javascripts %}
    {{ parent() }}
    <script type="text/javascript">
        document.addEventListener('kimai.initialized', function(event) {
            const kimai = event.detail.kimai;
            const DATES = kimai.getPlugin('date');
            /** @type {KimaiFormSelect} FORM_SELECT */
            const FORM_SELECT = kimai.getPlugin('form-select');

            if (window.matchMedia("(max-width: 1000px)").matches) {
                for (let dropdowns of document.querySelectorAll('tr.qe-entry-week-row .btn-duration-preset')) {
                    dropdowns.style.display = 'none';
                }

                for (let tmp of document.querySelectorAll('tr.qe-entry-week-row .duration-widget .input-group')) {
                    tmp.style.maxWidth = '50px';
                    tmp.style.minWidth = '50px';
                }
                for (let input of document.querySelectorAll('tr.qe-entry-week-row input.duration-input')) {
                    input.style.maxWidth = '50px';
                }
                document.querySelector('form[name=quick_entry_form] div.maybe-table-responsive').classList.replace('maybe-table-responsive', 'table-responsive');
            }

            const recalculateTotals = () => {
                const allFields = document.getElementsByClassName('duration-input');
                let totalsPerDay = {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0};
                let fullTotals = 0;
                for (let durationInput of allFields) {
                    // turn a string like "quick_entry_form_rows_16_timesheets_3_duration" into "3"
                    // we can safely use -1 because there are only 0 (monday) to 6 (sunday) indexes
                    let id = durationInput.id.replace(/_duration/, '').slice(-1);
                    totalsPerDay[id] += DATES.getSecondsFromDurationString(durationInput.value);
                }
                for (const [id, total] of Object.entries(totalsPerDay)) {
                    document.getElementById('qe-totals-day-' + id).innerText = DATES.formatSeconds(total);
                    fullTotals += total;
                }
                document.getElementById('qe-totals-week').innerText = DATES.formatSeconds(fullTotals);

                const allRows = document.getElementsByClassName('qe-entry-week-row');
                for (let qeWeekRow of allRows) {
                    let qeWeekRowFields = qeWeekRow.getElementsByClassName('duration-input');
                    let totalsRow = 0;
                    for (let durationInput of qeWeekRowFields) {
                        totalsRow += DATES.getSecondsFromDurationString(durationInput.value);
                    }
                    qeWeekRow.getElementsByClassName('qe-totals-row')[0].innerText = DATES.formatSeconds(totalsRow);
                }
            };
            recalculateTotals();

            document.getElementById('{{ form.date.vars.id }}').addEventListener('change', function(ev) {
                location.href = '{{ path('quick_entry', {'begin': '__BEGIN__'}) }}'.replace('__BEGIN__', ev.target.value);
            });

            document.getElementById('quick-entries-form').addEventListener('click', recalculateTotals);
            document.getElementById('quick-entries-form').addEventListener('change', recalculateTotals);

            const addFormToCollection = function(e) {
                const collectionHolder = document.getElementById(e.currentTarget.dataset.collectionHolder);
                const collectionPrototype = document.getElementById(e.currentTarget.dataset.collectionPrototype);

                const fakeNode = document.createElement('table');
                fakeNode.innerHTML = collectionPrototype
                    .dataset
                    .prototype
                    .replace(
                        /__name__/g,
                        collectionHolder.dataset.index
                    );

                let node = fakeNode.children[0];
                if (node.nodeName.toUpperCase() === 'TBODY') {
                    node = node.children[0];
                }

                collectionHolder.appendChild(node);


                [].slice.call(node.querySelectorAll('.selectpicker')).map((element) => {
                    FORM_SELECT.activateSelectPickerByElement(element);
                });

                collectionHolder.dataset.index++;
                recalculateTotals();
            };

            document.querySelectorAll('.add-item-link').forEach(btn => btn.addEventListener("click", addFormToCollection));
        });
    </script>
{% endblock %}