davidarellano / Extended Options for tamtamGo

// ==UserScript==
// @namespace     https://openuserjs.org/users/davidarellano
// @name          Extended Options for tamtamGo
// @description   Extended Options for tamtamGo
// @copyright     2020, davidarellano (https://openuserjs.org/users/davidarellano)
// @license       MIT
// @version       0.1.4
// @include       https://emergya.myteam2go.com/pages/employeePortal/workAssistanceList*
// @grant none
// ==/UserScript==

// ==OpenUserJS==
// @author davidarellano
// ==/OpenUserJS==

(function() {
    'use strict';
    console.log("Loading Extended Options for tamtamGo");
    // Static texts
    var CURRENT_WORKDAY = "Jornada actual en progreso";
    var EXTENDED_OPTIONS = "Opciones extendidas:";
    var TOTAL_TIMEFRAME_HOURS = "Horas totales del rango mostrado:";
    var DESCRIPTION = "<div>- Este total depende de la paginación y los filtros de la tabla de abajo.</div>"
    +"<div>- Las jornadas con descanso se marcan juntas para facilitar la lectura del tiempo total de ese día.</div>"
    +"<div>- Durante una jornada en progreso, el tiempo de la jornada y el total del rango mostrado se actualizan automáticamente.</div>";
    var RECALCULATE_HOURS = "Recalcular horas";
    var HOURS = "Horas";
    var TIME = "Tiempo";

    // Data values
    var BREAK_START = "3. Inicio de Descanso";
    var BREAK_FINISH = "4. Fin de descanso";

    // UI selectors
    var MAIN_FORM = "#tabView\\:workAssistanceForm";

    var style = `
#extendedOptions,
#extendedOptions *,
#hoursHeader,
#timeHeader,
.custom-time,
.custom-hours {
font-style: italic;
}
#hoursHeader{
width: 51px;
}
#timeHeader {
width: 62px;
}
.with-break-top {
background-color: beige;
}
.with-break-top td {
border-top: solid 1px #585849 !important;
}
.with-break-bottom {
background-color: beige;
border-bottom: solid 1px #585849 !important;
}

.running:after{
	content: "";
	position: absolute;
	top: 0; left: 0; bottom: 0; right: 0;
	background-image:
	   -webkit-gradient(linear, 0 0, 100% 100%,
	      color-stop(.25, rgba(200, 200, 200, .2)),
	      color-stop(.25, transparent), color-stop(.5, transparent),
	      color-stop(.5, rgba(200, 200, 200, .2)),
	      color-stop(.75, rgba(200, 200, 200, .2)),
	      color-stop(.75, transparent), to(transparent)
	   );
	background-image:
		-moz-linear-gradient(
		  -45deg,
	      rgba(200, 200, 200, .2) 25%,
	      transparent 25%,
	      transparent 50%,
	      rgba(200, 200, 200, .2) 50%,
	      rgba(200, 200, 200, .2) 75%,
	      transparent 75%,
	      transparent
	   );
	z-index: 1;
	-webkit-background-size: 50px 50px;
	-moz-background-size: 50px 50px;
	background-size: 50px 50px;
	-webkit-animation: move 2s linear infinite;

	overflow: hidden;
}

@-webkit-keyframes move {
    0% {
       background-position: 0 0;
    }
    100% {
       background-position: 50px 50px;
    }
}

@-moz-keyframes move {
    0% {
       background-position: 0 0;
    }
    100% {
       background-position: 50px 50px;
    }
}
.custom-time,
.custom-hours {
	position: relative;
}
.running {
	position: absolute;
	top: 0;
	bottom: 0;
	left: 0;
	right: 0;
}

`;
    var countdown;

    $(document).ready(function() {
        // Page has changed, now it loads async, this is a temporary solution
        setTimeout(function(){
        // Add css classes
        $("<style type='text/css'></style>").html(style).appendTo("head");

        var extendedOptions = $.parseHTML('<div id="extendedOptions" class="col-xs-12 ui-panel ui-widget ui-widget-content ui-corner-all"><h4>'+EXTENDED_OPTIONS+'</h4></div>');
        $(extendedOptions).append('<div><strong>'+TOTAL_TIMEFRAME_HOURS+' </strong><span id="timeFrameHours"></span></div>');
        //$(extendedOptions).append('<div id="recalculateHours" class="btn btn-secondary">'+RECALCULATE_HOURS+'</div>');
        $(extendedOptions).append(DESCRIPTION);
        $(extendedOptions).append('<hr/>');
        $("#tabView\\:homeForm").after(extendedOptions);

        // Bind function to the button
        /*$(document).on("click", "#recalculateHours", function() {
            calculateHours();
        });*/

        // Listen for changes in the table
        var observerConfig = {childList: true, characterData: true, subtree: true};
        var observer = new MutationObserver(function(mutations) {
            // Recalculate hours if results changed
            calculateHours();
        });
        var targetNode = document.querySelector(MAIN_FORM);
        function observeChanges() {
            if(targetNode) {
                observer.observe(targetNode, observerConfig);
            }
        }

        // Auto refresh hours if workday is running
        function startAutoRefresh() {
            countdown = setInterval(function(){
                calculateHours();
            }, 36000); // Every 0.01 hours
        }
        function stopAutoRefresh() {
            clearInterval(countdown);
        }

        function calculateHours() {
            var timeFrameHours = 0;
            // Stop watching changes in table
            observer.disconnect();
            // Stop autorefresh
            stopAutoRefresh();

            // Modify table to add 2 new columns
            // Set width auto to Colectivo column
            var colectivoHeader = $("[id='tabView:workAssistanceForm:workAssistance:column_producer']");
            colectivoHeader.css("width", "81px")
            // Add column headers if they don't exist already
            if(!(colectivoHeader.siblings("#timeHeader").length && colectivoHeader.siblings("#hoursHeader").length)){
                colectivoHeader.after('<th id="hoursHeader" class="ui-state-default ui-filter-column ui-resizable-column">'
                                      +'<span class="ui-column-title"><div class="textColum"><span title="'+HOURS+'">'+HOURS+'</span></div></span></th>')
                    .after('<th id="timeHeader"class="ui-state-default ui-filter-column ui-resizable-column">'
                           +'<span class="ui-column-title"><div class="textColum"><span title="'+TIME+'">'+TIME+'</span></div></span></th>')
            }

            // Iterate the displayed rows
            $(".ui-datatable-data [role='row']").each(function(index){
                var element = $(this)[0];
                // Get existing fields
                var colectivoField = $(element).find("[role='gridcell']")[4];
                var tipoEntradaField = $(element).find("[role='gridcell']")[8];
                var tiposalidaField = $(element).find("[role='gridcell']")[13];
                // Mark rows with resting time
                if($(tipoEntradaField).find("span").html() == BREAK_FINISH) {
                    $(this).addClass("with-break-top");
                } else if($(tiposalidaField).find("span").html() == BREAK_START) {
                    $(this).addClass("with-break-bottom");
                }

                // Initialize custom fields if they don't exist
                var timeElement;
                var hoursElement;
                if(!($(colectivoField).siblings(".custom-time").length && $(colectivoField).siblings(".custom-hours").length)) {
                    timeElement = $.parseHTML('<td class="custom-time"><span></span></td>');
                    hoursElement = $.parseHTML('<td class="custom-hours"><span></span></td>');
                } else {
                    timeElement = $(colectivoField).siblings(".custom-time")[0];
                    hoursElement = $(colectivoField).siblings(".custom-hours")[0];
                }

                var from = $($($(element).find("[role='gridcell']")[6]).find("span")[0]);
                if (from) {
                    var fromValue = from.attr("title");
                    var fromDate = new Date(fromValue);

                    var to = $($($(element).find("[role='gridcell']")[11]).find("span")[0]);
                    if (fromDate && to) {

                        var toValue = to.attr("title");
                        var toDate;
                        // If no ending time (current workday)
                        if (!toValue || toValue == "") {
                            // Set current time as temporary ending time
                            toDate = new Date();
                            // Mark as red
                            $(timeElement).css("color", "red");
                            $(hoursElement).css("color", "red");
                            if(!$(timeElement).find(".running").length) {
                                $(timeElement).prepend($.parseHTML('<div class="running"></div>'));
                                $(hoursElement).prepend($.parseHTML('<div class="running"></div>'));
                            }
                            $(timeElement).attr("title", CURRENT_WORKDAY);
                            $(hoursElement).attr("title", CURRENT_WORKDAY);
                            // Start auto refresh
                            startAutoRefresh();
                        } else {
                            toDate = new Date(toValue);
                        }

                        var diff = toDate - fromDate;

                        var diffSeconds = diff/1000;
                        var HH = Math.floor(diffSeconds/3600);
                        var MM = Math.floor(Math.floor(diffSeconds%3600)/60);

                        var formatted = ((HH < 10)?("0" + HH):HH) + ":" + ((MM < 10)?("0" + MM):MM)
                        var totalHours = Math.round(diffSeconds/3600 *100) / 100;

                        $(timeElement).find("span").html(formatted);
                        $(hoursElement).find("span").html(totalHours);
                        timeFrameHours += totalHours;
                    }
                }
                if(!($(colectivoField).siblings(".custom-time").length && $(colectivoField).siblings(".custom-hours").length)){
                    $(colectivoField).after(hoursElement).after(timeElement);
                }
            });

            // Restore observing changes in table
            observeChanges();

            $("#timeFrameHours").html(Math.round(timeFrameHours*100) / 100);
        }

        // Run on page load
        calculateHours();
        }, 2000);
    });

})();