<commit_before>$(document).ready(function() {
    displayOverallStatsBarGraph();
    chrome.identity.getProfileUserInfo(function(data) {
        var userInfo = {
            username: data.email
        };
        loadListedSites(userInfo);
        google.charts.load('current', {packages: ['corechart']});
        $('#toggle_graphs').click(function() {
            displayOverallStatsBarGraph();
        });
    });
});

function loadListedSites(userInfo) {
    $.ajax({
        type: 'GET',
        url: 'https://desktab.me/ListedSite/GetListedSites',
        data: userInfo,
        success: function(listedSites, textStatus, jqXHR) {
            var newHtml = '';
            var timeCapButtons = new Array();
            var deleteButtons = new Array();
            var piGraphButtons = new Array();
            var lineGraphButtons = new Array();

            var timeCapForms = new Array();
            var blockCheckBoxes = new Array();

            var siteHtml = '';
            siteHtml += '
';
            siteHtml += ' Status 	';
            siteHtml += ' Domain Name 	';
            siteHtml += ' Daily Time 	';
            siteHtml += ' Time Cap (minutes) 	';
            siteHtml += '
';

            newHtml += siteHtml;
            siteHtml = '';

            // Construct HTML
            for (var i = 0; i < listedSites.length; ++i) {
                var listedSiteOwner = listedSites[i].owner;
                var listedSiteDomainName = listedSites[i].domainName;
                var listedSiteDailyTime = Math.floor(listedSites[i].dailyTime/60);
                var listedSiteBlockedTime = listedSites[i].blockedTime;
                var listedSiteIsBlocked = listedSites[i].isBlocked;
                var listedSiteTimeCap = listedSites[i].timeCap / 60;

                // IMPORTANT: Since IDs in HTML cannot have '.', we replace it with '_'
                var trID = 'tr_' + listedSiteDomainName.replace(/\./g, '_');
                var deleteButtonID = 'deleteButton_' + listedSiteDomainName.replace(/\./g, '_');
                var piGraphButtonID = 'piGraphButton_' + listedSiteDomainName.replace(/\./g, '_');
                var lineGraphButtonID = 'lineGraphButton_' + listedSiteDomainName.replace(/\./g, '_');

                var timeCapFormID = 'timeCapForm_' + listedSiteDomainName.replace(/\./g, '_');
                var blockCheckBoxID = 'blockCheckBox_' + listedSiteDomainName.replace(/\./g, '_');

                siteHtml += '
';

                if (listedSiteIsBlocked == 1) {
                    siteHtml += ' <input type="checkbox" id="' + blockCheckBoxID;
                    siteHtml += '"checked></input> 	';
                }
                else {
                    siteHtml += ' <input type="checkbox" id="' + blockCheckBoxID;
                    siteHtml += '"></input> 	';
                }

                siteHtml += '' + listedSiteDomainName + '	';
                siteHtml += '' + listedSiteDailyTime + ' minutes	';
                siteHtml += '<input type="text" class="form-control" id="' + timeCapFormID + '"';
                siteHtml += 'value="' + listedSiteTimeCap + '"></input>	';
                siteHtml += '<button id=' + piGraphButtonID + ' class="task_buttons" style="width:90%;">Pie</button>	';
                siteHtml += '<button id=' + lineGraphButtonID + ' class="task_buttons" style="width:90%;">Line</button>	';
                siteHtml += '<button class="delete_button" id=' + deleteButtonID + '> Delete </button>	';
                siteHtml += '
';

                timeCapForms.push(timeCapFormID);
                blockCheckBoxes.push(blockCheckBoxID);
                deleteButtons.push(deleteButtonID);
                piGraphButtons.push(piGraphButtonID);
                lineGraphButtons.push(lineGraphButtonID);

                newHtml += siteHtml;
                siteHtml = '';
            }

            // Load HTML
            $('#sites_table').html(newHtml);

            // Bind to HTML
            for (var i = 0;i < deleteButtons.length && piGraphButtons.length; ++i) {

                $('#' + timeCapForms[i]).keypress(function(e) {
                    if (e.keyCode == 13) { // 'Enter'
                        var timeCapInput = $(this).val();

                        var listedSiteTR = $(this).parents('tr').get(0);
                        var listedSiteFirstTD = $(listedSiteTR).find('td:first').get(0);
                        var listedSiteCheckBox = $(listedSiteFirstTD).find('input').get(0);
                        var isChecked = $(listedSiteCheckBox).is(':checked');

                        updateListedSite(this.id.replace(/timeCapForm_/g, '').replace(/_/g, '.'),
                                         isChecked, timeCapInput, listedSiteTR);

                    }
                });

                $('#' + blockCheckBoxes[i]).change(function() {
                    var isChecked = $(this).is(':checked');

                    var listedSiteTR = $(this).parents('tr').get(0);
                    var listedSiteFourthTD = $(listedSiteTR).find('td:nth-child(4)').get(0);
                    var listedSiteForms = $(listedSiteFourthTD).find('input').get(0);
                    var timeCapInput = $(listedSiteForms).val();

                    updateListedSite(this.id.replace(/blockCheckBox_/g, '').replace(/_/g, '.'),
                                     isChecked, timeCapInput, listedSiteTR);
                });

                $('#' + deleteButtons[i]).click(function() {
                    deleteListedSite(this.id.replace(/deleteButton_/g, '').replace(/_/g, '.'));
                });

                $('#' + piGraphButtons[i]).click(function() {
                    displayBasicPiGraph(this.id.replace(/piGraphButton_/g, '').replace(/_/g, '.'));
                });

                $('#' + lineGraphButtons[i]).click(function() {
                    displayBasicLineGraph(this.id.replace(/lineGraphButton_/g, '').replace(/_/g, '.'));
                });
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(textStatus, errorThrown);
        }
    });
}

// This can be optimized to only reload that particular tr if anyone wants to do it, I passed in the tr
function updateListedSite(domainName, isBlocked, timeCap, listedSiteTR) {
    console.log(domainName, isBlocked, timeCap, listedSiteTR);
    console.log(listedSiteTR.id);

    if (timeCap.match(/[a-z]/i)) {
        return;
    }

    chrome.identity.getProfileUserInfo(function(data) {
        var listedSiteInfo = {
            username: data.email,
            domainName: domainName,
            isBlocked: isBlocked ? 1 : 0,
            timeCap: parseInt(timeCap * 60, 10)
        };
        console.log(listedSiteInfo);
        $.ajax({
            type: 'POST',
            url: 'https://desktab.me/ListedSite/EditListedSite',
            data: listedSiteInfo,
            success: function(data, textStatus, jqXHR) {
                chrome.identity.getProfileUserInfo(function(identity) {
                    var userInfo = {
                        username: identity.email
                    };
                    loadListedSites(userInfo);
                });
            },
            error: function(jqXHR, textStatus, errorThrown) {

            }
        });
    });

}

function deleteListedSite(domainName) {
    chrome.identity.getProfileUserInfo(function(data) {
        var listedSiteInfo = {
            username: data.email,
            domainName: domainName
        };
        $.ajax({
            type: 'DELETE',
            url: 'https://desktab.me/ListedSite/DeleteListedSite',
            data: listedSiteInfo,
            success: function(data, textStatus, jqXHR) {
                chrome.identity.getProfileUserInfo(function(identity) {
                    var userInfo = {
                        username: identity.email
                    };
                    loadListedSites(userInfo);
                });
            },
            error: function(jqXHR, textStatus, errorThrown) {
                alert(textStatus, errorThrown);
            }
        });
    });
}

function displayBasicPiGraph(domainName) {
	google.charts.setOnLoadCallback(drawChart);
    function drawChart() {
        chrome.identity.getProfileUserInfo(function(login) {
	        var graphData = { username: login.email,
                          domainName: domainName };
			    $.ajax({
                    type:'GET',
                    url:'https://desktab.me/ListedSite/GetASiteTimeHistory',
                    data: graphData,
                    success: function( data ) {
					    var graph = new google.visualization.arrayToDataTable([
                                    ['Day', 'Time Spent'	],
                                    ['Yesterday', Math.floor(data.dailyTime_0/60)],
                                    ['2 days ago', Math.floor(data.dailyTime_1/60)],
                                    ['3 days ago', Math.floor(data.dailyTime_2/60)],
                                    ['4 days ago', Math.floor(data.dailyTime_3/60)],
                                    ['5 days ago', Math.floor(data.dailyTime_4/60)],
                                    ['6 days ago', Math.floor(data.dailyTime_5/60)],
                                    ['7 days ago', Math.floor(data.dailyTime_6/60)]
					    ]);

					    var options = {
                            title: 'Time (mins) spent on ' + domainName.toUpperCase() + ' in the past 7 days',
                            height: 250,
                            width: 750,
					    };

                        var chart = new google.visualization.PieChart(document.getElementById('draw_graph'));
                        chart.draw(graph, options);
                    },
				    error: function(jqXHR, textStatus, errorThrown) {
                        alert('Error: Pie Chart');
                    }
                });
        });
    }
}

function displayBasicLineGraph(domainName) {
    google.charts.setOnLoadCallback(drawLineGraph);
    function drawLineGraph() {
        chrome.identity.getProfileUserInfo(function(login) {
	        var graphData = { username: login.email,
                              domainName: domainName };
			$.ajax({
                type:'GET',
                url:'https://desktab.me/ListedSite/GetATimeHistory',
                data: graphData,
                success: function(timeHistory) {
                    var graph = new google.visualization.arrayToDataTable([
                        ['Day', 'Active Time', 'Idle Time'],
                        ['Yesterday', Math.floor(timeHistory[0].dailyTime_0/60),
                            Math.floor(timeHistory[1].idleTime_0/60)],
                        ['2 days Ago', Math.floor(timeHistory[0].dailyTime_1/60),
                            Math.floor(timeHistory[1].idleTime_1/60)],
                        ['3 days Ago', Math.floor(timeHistory[0].dailyTime_2/60),
                            Math.floor(timeHistory[1].idleTime_2/60)],
                        ['4 days Ago', Math.floor(timeHistory[0].dailyTime_3/60),
                            Math.floor(timeHistory[1].idleTime_3/60)],
                        ['5 days Ago', Math.floor(timeHistory[0].dailyTime_4/60),
                            Math.floor(timeHistory[1].idleTime_4/60)],
                        ['6 days Ago', Math.floor(timeHistory[0].dailyTime_5/60),
                            Math.floor(timeHistory[1].idleTime_5/60)],
                        ['7 days Ago', Math.floor(timeHistory[0].dailyTime_6/60),
                            Math.floor(timeHistory[1].idleTime_6/60)]
				    ]);

                    var options = {
                        title: 'Time spent on ' + domainName.toUpperCase() + ' in the past 7 days',
                        height: 250,
                        width: 750,
                        vAxis: {
                            title: 'Time (minutes)'
                        },
                        hAxis: {
                            direction: -1
                        },
                        animation:{
				  			startup: true,
				  			duration: 1000,
				  			easing: 'out'
				  		},
                    };

                    var chart = new google.visualization.LineChart(document.getElementById('draw_graph'));
                    chart.draw(graph, options);
                },
				error: function(jqXHR, textStatus, errorThrown) {
                    alert('Error: Line Chart');
                }
            });
        });
    }
}

function displayOverallStatsBarGraph() {
    google.charts.setOnLoadCallback(drawBasic);
	function drawBasic() {
		  chrome.identity.getProfileUserInfo(function(login) {
			  var graphData = { username: login.email };

			  $.ajax({
			  	type:'GET',
			  	url:'https://desktab.me/ListedSite/GetListedSites',
			  	data: graphData,
			  	success: function( data ) {
			  		var graph = new google.visualization.DataTable();
			  		var size = Object.keys(data).length
			  		graph.addColumn('string', 'Sites');
			  		graph.addColumn('number', 'Time');
			  		for (var i = 0; i < size; ++i) {
			  			graph.addRows([
			  			[data[i].domainName, Math.floor(data[i].dailyTime/60)]]);
			  		}
					var options = {
				  		title: 'Time spent today',
				  		height: 250,
                        width: 750,
				  		orientation: 'horizontal',
				  		animation:{
				  			startup: true,
				  			duration: 1000,
				  			easing: 'out'
				  		},
				  		vAxis:{
				  			title: 'Time (minutes)'
				  		},
				  		hAxis:{
				  			title: 'Websites'
				  		},
				  	};

				  var chart = new google.visualization.BarChart(document.getElementById('draw_graph'));
				  chart.draw(graph, options);

			  	},
			  	error: function(jqXHR, textStatus, errorThrown) {
			  		alert('Error: Bar Graph');
			  	}
			});
        });
	}
}

<commit_msg>made sites button refresh on reclick<commit_after>$(document).ready(function() {
    google.charts.load('current', {packages: ['corechart']});
    chrome.identity.getProfileUserInfo(function(data) {
        var userInfo = {
            username: data.email
        };
        $('#site_button').click(function() {
        		loadListedSites(userInfo);
        });

        $('#toggle_graphs').click(function() {
            displayOverallStatsBarGraph();
        });
    });
});

function loadListedSites(userInfo) {
    $.ajax({
        type: 'GET',
        url: 'https://desktab.me/ListedSite/GetListedSites',
        data: userInfo,
        success: function(listedSites, textStatus, jqXHR) {
            var newHtml = '';
            var timeCapButtons = new Array();
            var deleteButtons = new Array();
            var piGraphButtons = new Array();
            var lineGraphButtons = new Array();

            var timeCapForms = new Array();
            var blockCheckBoxes = new Array();

            var siteHtml = '';
            siteHtml += '
';
            siteHtml += ' Status 	';
            siteHtml += ' Domain Name 	';
            siteHtml += ' Daily Time 	';
            siteHtml += ' Time Cap (minutes) 	';
            siteHtml += '
';

            newHtml += siteHtml;
            siteHtml = '';

            // Construct HTML
            for (var i = 0; i < listedSites.length; ++i) {
                var listedSiteOwner = listedSites[i].owner;
                var listedSiteDomainName = listedSites[i].domainName;
                var listedSiteDailyTime = Math.floor(listedSites[i].dailyTime/60);
                var listedSiteBlockedTime = listedSites[i].blockedTime;
                var listedSiteIsBlocked = listedSites[i].isBlocked;
                var listedSiteTimeCap = listedSites[i].timeCap / 60;

                // IMPORTANT: Since IDs in HTML cannot have '.', we replace it with '_'
                var trID = 'tr_' + listedSiteDomainName.replace(/\./g, '_');
                var deleteButtonID = 'deleteButton_' + listedSiteDomainName.replace(/\./g, '_');
                var piGraphButtonID = 'piGraphButton_' + listedSiteDomainName.replace(/\./g, '_');
                var lineGraphButtonID = 'lineGraphButton_' + listedSiteDomainName.replace(/\./g, '_');

                var timeCapFormID = 'timeCapForm_' + listedSiteDomainName.replace(/\./g, '_');
                var blockCheckBoxID = 'blockCheckBox_' + listedSiteDomainName.replace(/\./g, '_');

                siteHtml += '
';

                if (listedSiteIsBlocked == 1) {
                    siteHtml += ' <input type="checkbox" id="' + blockCheckBoxID;
                    siteHtml += '"checked></input> 	';
                }
                else {
                    siteHtml += ' <input type="checkbox" id="' + blockCheckBoxID;
                    siteHtml += '"></input> 	';
                }

                siteHtml += '' + listedSiteDomainName + '	';
                siteHtml += '' + listedSiteDailyTime + ' minutes	';
                siteHtml += '<input type="text" class="form-control" id="' + timeCapFormID + '"';
                siteHtml += 'value="' + listedSiteTimeCap + '"></input>	';
                siteHtml += '<button id=' + piGraphButtonID + ' class="task_buttons" style="width:90%;">Pie</button>	';
                siteHtml += '<button id=' + lineGraphButtonID + ' class="task_buttons" style="width:90%;">Line</button>	';
                siteHtml += '<button class="delete_button" id=' + deleteButtonID + '> Delete </button>	';
                siteHtml += '
';

                timeCapForms.push(timeCapFormID);
                blockCheckBoxes.push(blockCheckBoxID);
                deleteButtons.push(deleteButtonID);
                piGraphButtons.push(piGraphButtonID);
                lineGraphButtons.push(lineGraphButtonID);

                newHtml += siteHtml;
                siteHtml = '';
            }

            // Load HTML
            $('#sites_table').html(newHtml);

            // Bind to HTML
            for (var i = 0;i < deleteButtons.length && piGraphButtons.length; ++i) {

                $('#' + timeCapForms[i]).keypress(function(e) {
                    if (e.keyCode == 13) { // 'Enter'
                        var timeCapInput = $(this).val();

                        var listedSiteTR = $(this).parents('tr').get(0);
                        var listedSiteFirstTD = $(listedSiteTR).find('td:first').get(0);
                        var listedSiteCheckBox = $(listedSiteFirstTD).find('input').get(0);
                        var isChecked = $(listedSiteCheckBox).is(':checked');

                        updateListedSite(this.id.replace(/timeCapForm_/g, '').replace(/_/g, '.'),
                                         isChecked, timeCapInput, listedSiteTR);

                    }
                });

                $('#' + blockCheckBoxes[i]).change(function() {
                    var isChecked = $(this).is(':checked');

                    var listedSiteTR = $(this).parents('tr').get(0);
                    var listedSiteFourthTD = $(listedSiteTR).find('td:nth-child(4)').get(0);
                    var listedSiteForms = $(listedSiteFourthTD).find('input').get(0);
                    var timeCapInput = $(listedSiteForms).val();

                    updateListedSite(this.id.replace(/blockCheckBox_/g, '').replace(/_/g, '.'),
                                     isChecked, timeCapInput, listedSiteTR);
                });

                $('#' + deleteButtons[i]).click(function() {
                    deleteListedSite(this.id.replace(/deleteButton_/g, '').replace(/_/g, '.'));
                });

                $('#' + piGraphButtons[i]).click(function() {
                    displayBasicPiGraph(this.id.replace(/piGraphButton_/g, '').replace(/_/g, '.'));
                });

                $('#' + lineGraphButtons[i]).click(function() {
                    displayBasicLineGraph(this.id.replace(/lineGraphButton_/g, '').replace(/_/g, '.'));
                });
            }
        },
        error: function(jqXHR, textStatus, errorThrown) {
            alert(textStatus, errorThrown);
        }
    });
}

// This can be optimized to only reload that particular tr if anyone wants to do it, I passed in the tr
function updateListedSite(domainName, isBlocked, timeCap, listedSiteTR) {
    console.log(domainName, isBlocked, timeCap, listedSiteTR);
    console.log(listedSiteTR.id);

    if (timeCap.match(/[a-z]/i)) {
        return;
    }

    chrome.identity.getProfileUserInfo(function(data) {
        var listedSiteInfo = {
            username: data.email,
            domainName: domainName,
            isBlocked: isBlocked ? 1 : 0,
            timeCap: parseInt(timeCap * 60, 10)
        };
        console.log(listedSiteInfo);
        $.ajax({
            type: 'POST',
            url: 'https://desktab.me/ListedSite/EditListedSite',
            data: listedSiteInfo,
            success: function(data, textStatus, jqXHR) {
                chrome.identity.getProfileUserInfo(function(identity) {
                    var userInfo = {
                        username: identity.email
                    };
                    loadListedSites(userInfo);
                });
            },
            error: function(jqXHR, textStatus, errorThrown) {

            }
        });
    });

}

function deleteListedSite(domainName) {
    chrome.identity.getProfileUserInfo(function(data) {
        var listedSiteInfo = {
            username: data.email,
            domainName: domainName
        };
        $.ajax({
            type: 'DELETE',
            url: 'https://desktab.me/ListedSite/DeleteListedSite',
            data: listedSiteInfo,
            success: function(data, textStatus, jqXHR) {
                chrome.identity.getProfileUserInfo(function(identity) {
                    var userInfo = {
                        username: identity.email
                    };
                    loadListedSites(userInfo);
                });
            },
            error: function(jqXHR, textStatus, errorThrown) {
                alert(textStatus, errorThrown);
            }
        });
    });
}

function displayBasicPiGraph(domainName) {
	google.charts.setOnLoadCallback(drawChart);
    function drawChart() {
        chrome.identity.getProfileUserInfo(function(login) {
	        var graphData = { username: login.email,
                          domainName: domainName };
			    $.ajax({
                    type:'GET',
                    url:'https://desktab.me/ListedSite/GetASiteTimeHistory',
                    data: graphData,
                    success: function( data ) {
					    var graph = new google.visualization.arrayToDataTable([
                                    ['Day', 'Time Spent'	],
                                    ['Yesterday', Math.floor(data.dailyTime_0/60)],
                                    ['2 days ago', Math.floor(data.dailyTime_1/60)],
                                    ['3 days ago', Math.floor(data.dailyTime_2/60)],
                                    ['4 days ago', Math.floor(data.dailyTime_3/60)],
                                    ['5 days ago', Math.floor(data.dailyTime_4/60)],
                                    ['6 days ago', Math.floor(data.dailyTime_5/60)],
                                    ['7 days ago', Math.floor(data.dailyTime_6/60)]
					    ]);

					    var options = {
                            title: 'Time (mins) spent on ' + domainName.toUpperCase() + ' in the past 7 days',
                            height: 250,
                            width: 750,
                            backgroundColor: '#F4F2F2',
					    };

                        var chart = new google.visualization.PieChart(document.getElementById('draw_graph'));
                        chart.draw(graph, options);
                    },
				    error: function(jqXHR, textStatus, errorThrown) {
                        alert('Error: Pie Chart');
                    }
                });
        });
    }
}

function displayBasicLineGraph(domainName) {
    google.charts.setOnLoadCallback(drawLineGraph);
    function drawLineGraph() {
        chrome.identity.getProfileUserInfo(function(login) {
	        var graphData = { username: login.email,
                              domainName: domainName };
			$.ajax({
                type:'GET',
                url:'https://desktab.me/ListedSite/GetATimeHistory',
                data: graphData,
                success: function(timeHistory) {
                    var graph = new google.visualization.arrayToDataTable([
                        ['Day', 'Active Time', 'Idle Time'],
                        ['Yesterday', Math.floor(timeHistory[0].dailyTime_0/60),
                            Math.floor(timeHistory[1].idleTime_0/60)],
                        ['2 days Ago', Math.floor(timeHistory[0].dailyTime_1/60),
                            Math.floor(timeHistory[1].idleTime_1/60)],
                        ['3 days Ago', Math.floor(timeHistory[0].dailyTime_2/60),
                            Math.floor(timeHistory[1].idleTime_2/60)],
                        ['4 days Ago', Math.floor(timeHistory[0].dailyTime_3/60),
                            Math.floor(timeHistory[1].idleTime_3/60)],
                        ['5 days Ago', Math.floor(timeHistory[0].dailyTime_4/60),
                            Math.floor(timeHistory[1].idleTime_4/60)],
                        ['6 days Ago', Math.floor(timeHistory[0].dailyTime_5/60),
                            Math.floor(timeHistory[1].idleTime_5/60)],
                        ['7 days Ago', Math.floor(timeHistory[0].dailyTime_6/60),
                            Math.floor(timeHistory[1].idleTime_6/60)]
				    ]);

                    var options = {
                        title: 'Time spent on ' + domainName.toUpperCase() + ' in the past 7 days',
                        height: 250,
                        width: 750,
                        backgroundColor: '#F4F2F2',
                        vAxis: {
                            title: 'Time (minutes)'
                        },
                        hAxis: {
                            direction: -1
                        },
                        animation:{
				  			startup: true,
				  			duration: 1000,
				  			easing: 'out'
				  		},
                    };

                    var chart = new google.visualization.LineChart(document.getElementById('draw_graph'));
                    chart.draw(graph, options);
                },
				error: function(jqXHR, textStatus, errorThrown) {
                    alert('Error: Line Chart');
                }
            });
        });
    }
}

function displayOverallStatsBarGraph() {
    google.charts.setOnLoadCallback(drawBasic);
	function drawBasic() {
		  chrome.identity.getProfileUserInfo(function(login) {
			  var graphData = { username: login.email };

			  $.ajax({
			  	type:'GET',
			  	url:'https://desktab.me/ListedSite/GetListedSites',
			  	data: graphData,
			  	success: function( data ) {
			  		var graph = new google.visualization.DataTable();
			  		var size = Object.keys(data).length
			  		graph.addColumn('string', 'Sites');
			  		graph.addColumn('number', 'Time');
			  		for (var i = 0; i < size; ++i) {
			  			graph.addRows([
			  			[data[i].domainName, Math.floor(data[i].dailyTime/60)]]);
			  		}
					var options = {
				  		title: 'Time spent today',
				  		height: 250,
              width: 750,
              backgroundColor: '#F4F2F2',
				  		orientation: 'horizontal',
				  		animation:{
				  			startup: true,
				  			duration: 1000,
				  			easing: 'out'
				  		},
				  		vAxis:{
				  			title: 'Time (minutes)'
				  		},
				  		hAxis:{
				  			title: 'Websites'
				  		},
				  	};

				  var chart = new google.visualization.BarChart(document.getElementById('draw_graph'));
				  chart.draw(graph, options);

			  	},
			  	error: function(jqXHR, textStatus, errorThrown) {
			  		alert('Error: Bar Graph');
			  	}
			});
        });
	}
}
<|endoftext|>


<commit_before>(function($, UI) {

    "use strict";

    var $tooltip,   // tooltip container
        tooltipdelay;

    var Tooltip = function(element, options) {

        var $this = this, $element = $(element);

        if($element.data("tooltip")) return;

        this.options = $.extend({}, Tooltip.defaults, options);

        this.element = $element.on({
            "focus"     : function(e) { $this.show(); },
            "blur"      : function(e) { $this.hide(); },
            "mouseenter": function(e) { $this.show(); },
            "mouseleave": function(e) { $this.hide(); }
        });

        this.tip = typeof(this.options.src) === "function" ? this.options.src.call(this.element) : this.options.src;

        // disable title attribute
        this.element.attr("data-cached-title", this.element.attr("title")).attr("title", "");

        this.element.data("tooltip", this);
    };

    $.extend(Tooltip.prototype, {

        tip: "",

        show: function() {

            if (tooltipdelay)     clearTimeout(tooltipdelay);
            if (!this.tip.length) return;

            $tooltip.stop().css({"top": -2000, "visibility": "hidden"}).show();
            $tooltip.html('
' + this.tip + '
');

            var $this    = this,
                pos      = $.extend({}, this.element.offset(), {width: this.element[0].offsetWidth, height: this.element[0].offsetHeight}),
                width    = $tooltip[0].offsetWidth,
                height   = $tooltip[0].offsetHeight,
                offset   = typeof(this.options.offset) === "function" ? this.options.offset.call(this.element) : this.options.offset,
                position = typeof(this.options.pos) === "function" ? this.options.pos.call(this.element) : this.options.pos,
                tcss     = {
                    "display": "none",
                    "visibility": "visible",
                    "top": (pos.top + pos.height + height),
                    "left": pos.left
                },
                tmppos = position.split("-");

            if ((tmppos[0] == "left" || tmppos[0] == "right") && $.UIkit.langdirection == 'right') {
                tmppos[0] = tmppos[0] == "left" ? "right" : "left";
            }

            var variants =  {
                "bottom"  : {top: pos.top + pos.height + offset, left: pos.left + pos.width / 2 - width / 2},
                "top"     : {top: pos.top - height - offset, left: pos.left + pos.width / 2 - width / 2},
                "left"    : {top: pos.top + pos.height / 2 - height / 2, left: pos.left - width - offset},
                "right"   : {top: pos.top + pos.height / 2 - height / 2, left: pos.left + pos.width + offset}
            };

            $.extend(tcss, variants[tmppos[0]]);

            if (tmppos.length == 2) tcss.left = (tmppos[1] == 'left') ? (pos.left) : ((pos.left + pos.width) - width);

            var boundary = this.checkBoundary(tcss.left, tcss.top, width, height);

            if(boundary) {

                switch(boundary) {
                    case "x":

                        if (tmppos.length == 2) {
                            position = tmppos[0]+"-"+(tcss.left < 0 ? "left": "right");
                        } else {
                            position = tcss.left < 0 ? "right": "left";
                        }

                        break;

                    case "y":
                        if (tmppos.length == 2) {
                            position = (tcss.top < 0 ? "bottom": "top")+"-"+tmppos[1];
                        } else {
                            position = (tcss.top < 0 ? "bottom": "top");
                        }

                        break;

                    case "xy":
                        if (tmppos.length == 2) {
                            position = (tcss.top < 0 ? "bottom": "top")+"-"+(tcss.left < 0 ? "left": "right");
                        } else {
                            position = tcss.left < 0 ? "right": "left";
                        }

                        break;

                }

                tmppos = position.split("-");

                $.extend(tcss, variants[tmppos[0]]);

                if (tmppos.length == 2) tcss.left = (tmppos[1] == 'left') ? (pos.left) : ((pos.left + pos.width) - width);
            }

            tcss.left -= $("body").position().left;

            tooltipdelay = setTimeout(function(){

                $tooltip.css(tcss).attr("class", "uk-tooltip uk-tooltip-" + position);

                if ($this.options.animation) {
                    $tooltip.css({opacity: 0, display: 'block'}).animate({opacity: 1}, parseInt($this.options.animation, 10) || 400);
                } else {
                    $tooltip.show();
                }

                tooltipdelay = false;
            }, parseInt(this.options.delay, 10) || 0);
        },

        hide: function() {
            if(this.element.is("input") && this.element[0]===document.activeElement) return;

            if(tooltipdelay) clearTimeout(tooltipdelay);

            $tooltip.stop();

            if (this.options.animation) {
                $tooltip.fadeOut(parseInt(this.options.animation, 10) || 400);
            } else {
                $tooltip.hide();
            }
        },

        content: function() {
            return this.tip;
        },

        checkBoundary: function(left, top, width, height) {

            var axis = "";

            if(left < 0 || left+width > window.innerWidth) {
                axis += "x";
            }

            if(top < 0 || top+height > window.innerHeight) {
                axis += "y";
            }

            return axis;
        }

    });

    Tooltip.defaults = {
        "offset": 5,
        "pos": "top",
        "animation": false,
        "delay": 0, // in miliseconds
        "src": function() { return this.attr("title"); }
    };

    UI["tooltip"] = Tooltip;

    $(function() {
        $tooltip = $('

').appendTo("body");
    });

    // init code
    $(document).on("mouseenter.tooltip.uikit focus.tooltip.uikit", "[data-uk-tooltip]", function(e) {
        var ele = $(this);

        if (!ele.data("tooltip")) {
            var obj = new Tooltip(ele, UI.Utils.options(ele.attr("data-uk-tooltip")));
            ele.trigger("mouseenter");
        }
    });

})(jQuery, jQuery.UIkit);<commit_msg>tooltip boundary check fixed<commit_after>(function($, UI, $win) {

    "use strict";

    var $tooltip,   // tooltip container
        tooltipdelay;

    var Tooltip = function(element, options) {

        var $this = this, $element = $(element);

        if($element.data("tooltip")) return;

        this.options = $.extend({}, Tooltip.defaults, options);

        this.element = $element.on({
            "focus"     : function(e) { $this.show(); },
            "blur"      : function(e) { $this.hide(); },
            "mouseenter": function(e) { $this.show(); },
            "mouseleave": function(e) { $this.hide(); }
        });

        this.tip = typeof(this.options.src) === "function" ? this.options.src.call(this.element) : this.options.src;

        // disable title attribute
        this.element.attr("data-cached-title", this.element.attr("title")).attr("title", "");

        this.element.data("tooltip", this);
    };

    $.extend(Tooltip.prototype, {

        tip: "",

        show: function() {

            if (tooltipdelay)     clearTimeout(tooltipdelay);
            if (!this.tip.length) return;

            $tooltip.stop().css({"top": -2000, "visibility": "hidden"}).show();
            $tooltip.html('
' + this.tip + '
');

            var $this    = this,
                pos      = $.extend({}, this.element.offset(), {width: this.element[0].offsetWidth, height: this.element[0].offsetHeight}),
                width    = $tooltip[0].offsetWidth,
                height   = $tooltip[0].offsetHeight,
                offset   = typeof(this.options.offset) === "function" ? this.options.offset.call(this.element) : this.options.offset,
                position = typeof(this.options.pos) === "function" ? this.options.pos.call(this.element) : this.options.pos,
                tcss     = {
                    "display": "none",
                    "visibility": "visible",
                    "top": (pos.top + pos.height + height),
                    "left": pos.left
                },
                tmppos = position.split("-");

            if ((tmppos[0] == "left" || tmppos[0] == "right") && $.UIkit.langdirection == 'right') {
                tmppos[0] = tmppos[0] == "left" ? "right" : "left";
            }

            var variants =  {
                "bottom"  : {top: pos.top + pos.height + offset, left: pos.left + pos.width / 2 - width / 2},
                "top"     : {top: pos.top - height - offset, left: pos.left + pos.width / 2 - width / 2},
                "left"    : {top: pos.top + pos.height / 2 - height / 2, left: pos.left - width - offset},
                "right"   : {top: pos.top + pos.height / 2 - height / 2, left: pos.left + pos.width + offset}
            };

            $.extend(tcss, variants[tmppos[0]]);

            if (tmppos.length == 2) tcss.left = (tmppos[1] == 'left') ? (pos.left) : ((pos.left + pos.width) - width);

            var boundary = this.checkBoundary(tcss.left, tcss.top, width, height);

            if(boundary) {

                switch(boundary) {
                    case "x":

                        if (tmppos.length == 2) {
                            position = tmppos[0]+"-"+(tcss.left < 0 ? "left": "right");
                        } else {
                            position = tcss.left < 0 ? "right": "left";
                        }

                        break;

                    case "y":
                        if (tmppos.length == 2) {
                            position = (tcss.top < 0 ? "bottom": "top")+"-"+tmppos[1];
                        } else {
                            position = (tcss.top < 0 ? "bottom": "top");
                        }

                        break;

                    case "xy":
                        if (tmppos.length == 2) {
                            position = (tcss.top < 0 ? "bottom": "top")+"-"+(tcss.left < 0 ? "left": "right");
                        } else {
                            position = tcss.left < 0 ? "right": "left";
                        }

                        break;

                }

                tmppos = position.split("-");

                $.extend(tcss, variants[tmppos[0]]);

                if (tmppos.length == 2) tcss.left = (tmppos[1] == 'left') ? (pos.left) : ((pos.left + pos.width) - width);
            }

            tcss.left -= $("body").position().left;

            tooltipdelay = setTimeout(function(){

                $tooltip.css(tcss).attr("class", "uk-tooltip uk-tooltip-" + position);

                if ($this.options.animation) {
                    $tooltip.css({opacity: 0, display: 'block'}).animate({opacity: 1}, parseInt($this.options.animation, 10) || 400);
                } else {
                    $tooltip.show();
                }

                tooltipdelay = false;
            }, parseInt(this.options.delay, 10) || 0);
        },

        hide: function() {
            if(this.element.is("input") && this.element[0]===document.activeElement) return;

            if(tooltipdelay) clearTimeout(tooltipdelay);

            $tooltip.stop();

            if (this.options.animation) {
                $tooltip.fadeOut(parseInt(this.options.animation, 10) || 400);
            } else {
                $tooltip.hide();
            }
        },

        content: function() {
            return this.tip;
        },

        checkBoundary: function(left, top, width, height) {

            var axis = "";

            if(left < 0 || ((left-$win.scrollLeft())+width) > window.innerWidth) {
               axis += "x";
            }

            if(top < 0 || ((top-$win.scrollTop())+height) > window.innerHeight) {
               axis += "y";
            }

            return axis;
        }

    });

    Tooltip.defaults = {
        "offset": 5,
        "pos": "top",
        "animation": false,
        "delay": 0, // in miliseconds
        "src": function() { return this.attr("title"); }
    };

    UI["tooltip"] = Tooltip;

    $(function() {
        $tooltip = $('

').appendTo("body");
    });

    // init code
    $(document).on("mouseenter.tooltip.uikit focus.tooltip.uikit", "[data-uk-tooltip]", function(e) {
        var ele = $(this);

        if (!ele.data("tooltip")) {
            var obj = new Tooltip(ele, UI.Utils.options(ele.attr("data-uk-tooltip")));
            ele.trigger("mouseenter");
        }
    });

})(jQuery, jQuery.UIkit, jQuery(window));<|endoftext|>


<commit_before>/**
 * Created by Miguel on 26/01/2015.
 */
(function ($) {
    var warn = require("./warn");
    var getDefaults = require("./options");
    var observe = require("./observe");

    $.fn.jsTreeBind = function (target, options) {

        //Main variables
        options = options || {};
        //template is the element that has associated data bindings that we're basing the tree off
        var template = $(target);
        //tree is the actual tree element that $().jstree will be called on
        var tree = this;

        //Perform error checking
        if (typeof $.fn.jstree != "function")
            throw new Error("jsTree must be installed for jsTree-bind to work!");
        if (template[0] instanceof Element === false)
            throw new Error("You need to pass in a valid jQuery selector or DOM element as the first element of jsTreeBind()");
        if (template.length > 1)
            warn("You can only define one root element to bind to the jsTree. Additional elements ignored.");

        //Merge this configuration object with whatever the user has passed in
        var merged = $.extend(getDefaults(template), options);

        //Actually call jstree()
        tree.jstree(merged);

        //Observe the template for changes
        observe(template[0], tree.jstree(merged));
    };
}(jQuery));<commit_msg>use deep copy when merging options<commit_after>/**
 * Created by Miguel on 26/01/2015.
 */
(function ($) {
    var warn = require("./warn");
    var getDefaults = require("./options");
    var observe = require("./observe");

    $.fn.jsTreeBind = function (target, options) {

        //Main variables
        options = options || {};
        //template is the element that has associated data bindings that we're basing the tree off
        var template = $(target);
        //tree is the actual tree element that $().jstree will be called on
        var tree = this;

        //Perform error checking
        if (typeof $.fn.jstree != "function")
            throw new Error("jsTree must be installed for jsTree-bind to work!");
        if (template[0] instanceof Element === false)
            throw new Error("You need to pass in a valid jQuery selector or DOM element as the first element of jsTreeBind()");
        if (template.length > 1)
            warn("You can only define one root element to bind to the jsTree. Additional elements ignored.");

        //Merge this configuration object with whatever the user has passed in
        var merged = $.extend(true, getDefaults(template), options);

        //Actually call jstree()
        tree.jstree(merged);

        //Observe the template for changes
        observe(template[0], tree.jstree(merged));
    };
}(jQuery));
<|endoftext|>


<commit_before>"use strict";

var krusovice = krusovice || {};

krusovice.version = "trunk" // $VERSION_LINE

/**
 * Dynamicaly load Krusovice Javascript code for debug mode.
 *
 * @param {Function} doneCallback Called after the loading is complete.
 *
 * @param {Boolean} includeDependencies Include dependency libraries also
 *
 */
krusovice.load = function(doneCallback, includeDependencies) {

	var deps = [
        "../thirdparty/jquery.js",
        "../thirdparty/jquery.easing.1.3.js",
        "../thirdparty/Three.js"
    ]

	var files = [
	     "utils.js",
	     "design.js",
	     "inputelement.js",
	     "loader.js",
	     "rhytmanalysis.js",
	     "showobjects.js",
	     "timeliner.js",
	     "timelinevisualizer.js",
	     "show.js",
	     "renderers/three.js",
	     "effects/base.js",
	     "effects/linear.js"
	]

	if(includeDependencies) {
		deps.reverse().forEach(function(f) {
			files.unshift(f);
		});
	}

	// Get krusovise/bootstrap.js URL
	function getMyURL() {
	      var scripts = document.getElementsByTagName("script");

	      for(var i=0; i<scripts.length; i++) {
	          var script = scripts[i];

	          // Found our script tag
	          var src = script.getAttribute("src");
	          if(!src) {
	              // Inline script tag
	              continue;
	          }

	          src = src.toLowerCase();

	          if(src.indexOf("krootstrap.js") >= 0) {
	              // Current 'script' ok
	              return src;;
	          }
	      }

	      throw "Could not know where to Krusovice";
	}

	// Get URL folder part
	function getBaseURL(aUrl) {

        var end;
        var url;

        end = aUrl.indexOf('?');

        if(end <= 0) {
            end = aUrl.length-1;
        }

        url = aUrl.slice(0, end);
        // Ignore slash at the end of url
        if(url[url.length-1] == "/" ) {
            url = url.slice(0,url.length-2);
        }

        // But add the slash to result for convenient concat
        end = url.lastIndexOf("/") + 1;
        url = url.slice(0,end);

        return url;
	}

	var myURL = getMyURL();
	var base = getBaseURL(myURL);
	var head = document.getElementsByTagName("head")[0];
	var loadCount = 0;
	var totalCount  = files.length;

	// Load single script
	function loadJS(file) {

		var url = base + file;
		 // Using script tag injection to have JS debugger show the source
        console.log("Injecting <script> tag to load:" + url);
        var script = document.createElement("script");
        script.type = "text/javascript";
        script.setAttribute("src", url);
        script.src = url;

        function bump() {
            console.log("Script onload handler for " + url);

            loadCount += 1;
            console.log("Loaded:" + loadCount + "/" + files.length);
            if(loadCount >= totalCount) {
            	console.log("Krusovice loaded");
            	doneCallback();
            } else {
            	loadJS(files.shift());
            }
        }

        function heady(script) {

            script.onerror = function(e, a, b, c) {
            	console.error("Script contained errors:" + url);
            	console.exception(e);
            }

	        script.onload = function() {
	            if ( ! script.onloadDone ) {
	                script.onloadDone = true;
	                bump();
	            }
	        };
	        script.onreadystatechange = function() {
	            if ( ( "loaded" === script.readyState || "complete" === script.readyState ) && ! script.onloadDone ) {
	            	script.onloadDone = true;
	                bump();
	            }
	        }

	        head.appendChild(script);
        }

        heady(script);
	}

	loadJS(files.shift());

}
<commit_msg>Tried to fix formatting errors. Added comments.<commit_after>"use strict";

var krusovice = krusovice || {};

krusovice.version = "trunk" // $VERSION_LINE

/**
 * Dynamicaly load Krusovice Javascript code for debug mode (not merged/compressed)
 *
 * Load library own files and dependencies if needed.
 *
 * @param {Function} doneCallback Called after the loading is complete.
 *
 * @param {Boolean} includeDependencies Include dependency libraries also
 *
 */
krusovice.load = function(doneCallback, includeDependencies) {

        // Someone elses code
	var deps = [
        "../thirdparty/jquery.js",
        "../thirdparty/jquery.easing.1.3.js",
        "../thirdparty/Three.js"
        ]

	// Our code
	var files = [
	     "utils.js",
	     "design.js",
	     "inputelement.js",
	     "loader.js",
	     "rhytmanalysis.js",
	     "showobjects.js",
	     "timeliner.js",
	     "timelinevisualizer.js",
	     "show.js",
	     "renderers/three.js",
	     "effects/base.js",
	     "effects/linear.js"
	]

	if(includeDependencies) {
		deps.reverse().forEach(function(f) {
			files.unshift(f);
		});
	}

	// Get krusovise/bootstrap.js URL
	function getMyURL() {
	      var scripts = document.getElementsByTagName("script");

	      for(var i=0; i<scripts.length; i++) {
	          var script = scripts[i];

	          // Found our script tag
	          var src = script.getAttribute("src");
	          if(!src) {
	              // Inline script tag
	              continue;
	          }

	          src = src.toLowerCase();

	          if(src.indexOf("krootstrap.js") >= 0) {
	              // Current 'script' ok
	              return src;;
	          }
	      }

	      throw "Could not know where to Krusovice";
	}

	// Get URL folder part
	function getBaseURL(aUrl) {

	        var end;
	        var url;

	        end = aUrl.indexOf('?');

	        if(end <= 0) {
	            end = aUrl.length-1;
	        }

	        url = aUrl.slice(0, end);
	        // Ignore slash at the end of url
	        if(url[url.length-1] == "/" ) {
	            url = url.slice(0,url.length-2);
	        }

	        // But add the slash to result for convenient concat
	        end = url.lastIndexOf("/") + 1;
	        url = url.slice(0,end);

	        return url;
	}

	var myURL = getMyURL();
	var base = getBaseURL(myURL);
	var head = document.getElementsByTagName("head")[0];
	var loadCount = 0;
	var totalCount  = files.length;

	// Load single script
	function loadJS(file) {

		var url = base + file;
		 // Using script tag injection to have JS debugger show the source
	        console.log("Injecting <script> tag to load:" + url);
	        var script = document.createElement("script");
	        script.type = "text/javascript";
	        script.setAttribute("src", url);
	        script.src = url;

	        function bump() {
	            console.log("Script onload handler for " + url);

	            loadCount += 1;
	            console.log("Loaded:" + loadCount + "/" + files.length);
	            if(loadCount >= totalCount) {
	            	console.log("Krusovice loaded");
	            	doneCallback();
	            } else {
	            	loadJS(files.shift());
	            }
	        }

	        // Insert script to <head> with proper callbacks
	        function heady(script) {

	            script.onerror = function(e, a, b, c) {
	            	console.error("Script contained errors:" + url);
	            	console.exception(e);
	            }

		        script.onload = function() {
		            if ( ! script.onloadDone ) {
		                script.onloadDone = true;
		                bump();
		            }
		        };
		        script.onreadystatechange = function() {
		            if ( ( "loaded" === script.readyState || "complete" === script.readyState ) && ! script.onloadDone ) {
		            	script.onloadDone = true;
		                bump();
		            }
		        }

		        head.appendChild(script);
	        }

	         heady(script);

	   }

	   loadJS(files.shift());

}
<|endoftext|>


<commit_before>/* Based on Alex Arnell's inheritance implementation. */
var Class = {
  create: function() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      this.initialize.apply(this, arguments);
    }

    Object.extend(klass, Class.Methods);
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      var subclass = function() { };
      subclass.prototype = parent.prototype;
      klass.prototype = new subclass;
      parent.subclasses.push(klass);
    }

    for (var i = 0; i < properties.length; i++)
      klass.addMethods(properties[i]);

    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    klass.prototype.constructor = klass;

    return klass;
  }
};

Class.Methods = {
  addMethods: function(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = Object.keys(source);

    if (!Object.keys({ toString: true }).length)
      properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value;
        value = (function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property).wrap(method);

        value.valueOf = method.valueOf.bind(method);
        value.toString = method.toString.bind(method);
      }
      this.prototype[property] = value;
    }

    return this;
  }
};
<commit_msg>Refactored class.js.<commit_after>/* Based on Alex Arnell's inheritance implementation. */
var Class = (function() {
  function create() {
    var parent = null, properties = $A(arguments);
    if (Object.isFunction(properties[0]))
      parent = properties.shift();

    function klass() {
      this.initialize.apply(this, arguments);
    }

    Object.extend(klass, Class.Methods);
    klass.superclass = parent;
    klass.subclasses = [];

    if (parent) {
      var subclass = function() {};
      subclass.prototype = parent.prototype;
      klass.prototype = new subclass;
      parent.subclasses.push(klass);
    }

    for (var i = 0; i < properties.length; i++)
      klass.addMethods(properties[i]);

    if (!klass.prototype.initialize)
      klass.prototype.initialize = Prototype.emptyFunction;

    klass.prototype.constructor = klass;
    return klass;
  }

  function addMethods(source) {
    var ancestor   = this.superclass && this.superclass.prototype;
    var properties = Object.keys(source);

    if (!Object.keys({ toString: true }).length)
      properties.push("toString", "valueOf");

    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value;
        value = (function(m) {
          return function() { return ancestor[m].apply(this, arguments); };
        })(property).wrap(method);

        value.valueOf = method.valueOf.bind(method);
        value.toString = method.toString.bind(method);
      }
      this.prototype[property] = value;
    }

    return this;
  }

  return {
    create: create,
    Methods: {
      addMethods: addMethods
    }
  };
})();<|endoftext|>


<commit_before>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project
 * See README.md for more information
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific
 *
 */

import _ from "lodash";
import {CORE_API} from "../../../common/services/core-api-utils";
import {initialiseData} from "../../../common";
import {kindToViewState} from "../../../common/link-utils";
import {getDateAsUtc, loadAllData, loadDecommData, mkTabs} from "../../measurable-rating-utils";
import {indexRatingSchemes, mkRatingsKeyHandler} from "../../../ratings/rating-utils";

import template from "./measurable-rating-edit-panel.html";
import {displayError} from "../../../common/error-utils";

const bindings = {
    allocations: "<",
    allocationSchemes: "<",
    parentEntityRef: "<",
    startingCategoryId: "<?",
    plannedDecommissions: "<?",
    replacementApps: "<?",
    replacingDecommissions: "<?",
    application: "<"
};

const initialState = {
    activeTab: null,
    allocations: [],
    allocationSchemes: [],
    categories: [],
    measurables: [],
    plannedDecommissions: [],
    ratings: [],
    ratingSchemesById: {},
    ratingItemsBySchemeIdByCode: {},
    replacementApps: [],
    replacingDecommissions: [],
    saveInProgress: false,
    selected: null,
    startingCategoryId: null,
    tabs: [],
    unusedCategories: [],
    visibility: {
        ratingEditor: false,
        showDescriptionInPicker: false,
        instructions: true,
        schemeOverview: false,
        showAllCategories: false,
        tab: null
    }
};

function controller($q,
                    $state,
                    notification,
                    serviceBroker,
                    userService) {
    const vm = initialiseData(this, initialState);

    const loadData = (force) => {
        return loadAllData($q, serviceBroker, vm.parentEntityRef, true, force)
            .then((r) => {
                Object.assign(vm, r);
                recalcTabs();
                vm.categoriesById = _.keyBy(vm.categories, "id");
                vm.ratingItemsBySchemeIdByCode = indexRatingSchemes(_.values(vm.ratingSchemesById) || []);
                if (vm.startingCategoryId) {
                    vm.activeTab = _.find(vm.tabs, t => t.category.id === vm.startingCategoryId)
                } else if (!vm.activeTab) {
                    vm.activeTab = vm.tabs[0];
                }
                vm.onTabChange();
            })
    };

    const recalcTabs = function () {
        const hasNoRatings = vm.ratings.length === 0;
        const showAllCategories = hasNoRatings || vm.visibility.showAllCategories;
        const allTabs = mkTabs(vm, showAllCategories);
        vm.tabs = _.filter(allTabs, t => _.includes(vm.userRoles, t.category.ratingEditorRole));

        vm.hasHiddenTabs = vm.categories.length !== allTabs.length;
        if (vm.activeTab) {
            vm.activeTab = _.find(vm.tabs, t => t.category.id === vm.activeTab.category.id);
        }
    };

    const getDescription = () => _.get(
        vm.selected,
        ["rating", "description"]);

    const getRating = () => _.get(
        vm.selected,
        ["rating", "rating"]);

    const doRatingSave = (rating, description) => {
        const currentRating = !_.isEmpty(vm.selected.rating) ? vm.selected.rating.rating : null;
        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingStore.save,
                [vm.parentEntityRef, vm.selected.measurable.id, rating, currentRating, description])
            .then(r => { vm.ratings = r.data })
            .then(() => recalcTabs())
            .then(() => {
                vm.saveInProgress = false;
                const newRating = { rating, description };
                vm.selected = Object.assign({}, vm.selected, { rating: newRating });
            })
            .catch(e => displayError(notification, "Could not save rating", e))
    };

    const doRemove = () => {
        if (! vm.selected.rating) return $q.reject();

        vm.saveInProgress = true;

        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingStore.remove,
                [vm.parentEntityRef, vm.selected.measurable.id])
            .then(r => {
                vm.saveInProgress = false;
                vm.ratings = r.data;
                vm.selected.rating = null;
                recalcTabs();
            });
    };

    const deselectMeasurable = () => {
        vm.saveInProgress = false;
        vm.selected = Object.assign({}, vm.selected, { measurable: null });
        vm.visibility = Object.assign({}, vm.visibility, {schemeOverview: true, ratingEditor: false});
    };

    const selectMeasurable = (node) => {
        const { measurable, allocations } = node;
        const category = vm.categoriesById[measurable.categoryId];
        const ratingScheme = vm.ratingSchemesById[category.ratingSchemeId];
        const hasWarnings = !_.isEmpty(allocations);

        vm.selected = Object.assign({}, node, { category, hasWarnings, ratingScheme });
        vm.visibility = Object.assign({}, vm.visibility, {schemeOverview: false, ratingEditor: true});
    };

    const reloadDecommData = () => {
        return loadDecommData($q, serviceBroker, vm.parentEntityRef, true)
            .then(r => Object.assign(vm, r));
    };

    // -- BOOT --

    vm.$onInit = () => {

        userService
            .whoami()
            .then(user => vm.userRoles = user.roles)
            .then(() => loadData(true));

        vm.backUrl = $state
            .href(
                kindToViewState(vm.parentEntityRef.kind),
                { id: vm.parentEntityRef.id });
        vm.allocationsByMeasurableId = _.groupBy(vm.allocations, a => a.measurableId);
        vm.allocationSchemesById = _.keyBy(vm.allocationSchemes, s => s.id);
    };

    // -- INTERACT ---

    vm.onRemoveReplacementApp = (replacement) => {
        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingReplacementStore.remove,
                [replacement.decommissionId, replacement.id])
            .then(r => {
                vm.selected = Object.assign({}, vm.selected, { replacementApps: r.data });
                notification.success("Replacement app removed")
            })
            .catch(e  => displayError(notification, "Could not remove replacement app", e))
            .finally(reloadDecommData);
    };

    vm.onAddReplacementApp = (replacement) => {
        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingReplacementStore.save,
                [replacement.decommissionId, replacement])
            .then(r => {
                vm.selected = Object.assign({}, vm.selected, { replacementApps: r.data });
                notification.success("Successfully added replacement app")
            })
            .catch(e  => displayError(notification, "Could not add replacement app", e))
            .finally(reloadDecommData);
    };

    vm.checkPlannedDecomDateIsValid = (decomDate) => {

        const appDate = new Date(vm.application.plannedRetirementDate);
        const newDecomDate = new Date(decomDate);

        const sameDate = appDate.getFullYear() === newDecomDate.getFullYear()
            && appDate.getMonth() === newDecomDate.getMonth()
            && appDate.getDate() === newDecomDate.getDate();

        return appDate > newDecomDate || sameDate;
    };

    vm.onSaveDecommissionDate = (dateChange) => {

        if (vm.application.entityLifecycleStatus === 'REMOVED'){
            notification.error("Decommission date cannot be set. This application is no longer active");
            return;
        }

        if (_.isNull(vm.application.plannedRetirementDate) || vm.checkPlannedDecomDateIsValid(dateChange.newVal)){

            dateChange.newVal = getDateAsUtc(dateChange.newVal);

            serviceBroker
                .execute(
                    CORE_API.MeasurableRatingPlannedDecommissionStore.save,
                    [vm.parentEntityRef, vm.selected.measurable.id, dateChange])
                .then(r => {
                    const decom = Object.assign(r.data, {isValid: true});
                    vm.selected = Object.assign({}, vm.selected, { decommission: decom});
                    notification.success(`Saved decommission date for ${vm.selected.measurable.name}`);
                })
                .catch(e => displayError(notification, "Could not save decommission date", e))
                .finally(reloadDecommData);

        } else {
            const appDate = new Date(vm.application.plannedRetirementDate).toDateString();
            notification.error("Decommission date cannot be later than the planned retirement date of the application: " + appDate);
        }
    };

    vm.onRemoveDecommission = () => {
        if (!confirm("Are you sure you want to remove this decommission and any replacement apps?")) {
            notification.info("Revocation of decommission cancelled");
            return;
        }
        serviceBroker
            .execute(
                CORE_API.MeasurableRatingPlannedDecommissionStore.remove,
                [vm.selected.decommission.id])
            .then(() => {
                vm.selected = Object.assign({}, vm.selected, { decommission: null, replacementApps: [] });
                notification.success(`Removed decommission date and replacement applications for: ${vm.selected.measurable.name}`);
            })
            .catch(e => displayError(notification, "Could not remove decommission date", e))
            .finally(reloadDecommData);
    };

    vm.onMeasurableSelect = (node) => {
        selectMeasurable(node);
    };

    vm.onRatingSelect = r => {
        if (! vm.selected.measurable) return; // nothing selected
        if (! vm.selected.measurable.concrete) return; // not concrete
        if (r === getRating()) return; // rating not changed

        return r === "X"
            ? doRemove()
                .then(() => notification.success(`Removed: ${vm.selected.measurable.name}`))
            : doRatingSave(r, getDescription())
                .then(() => notification.success(`Saved: ${vm.selected.measurable.name}`));
    };

    vm.onSaveComment = (comment) => {
        return doRatingSave(getRating(), comment)
            .then(() => notification.success(`Saved Comment for: ${vm.selected.measurable.name}`))
    };

    vm.doCancel = () => {
        deselectMeasurable();
    };

    vm.onRemoveAll = (categoryId) => {
        if (confirm("Do you really want to remove all ratings in this category ?")) {
            serviceBroker
                .execute(
                    CORE_API.MeasurableRatingStore.removeByCategory,
                    [vm.parentEntityRef, categoryId])
                .then(r => {
                    notification.info("Removed all ratings for category");
                    vm.ratings = r.data;
                    recalcTabs();
                })
                .catch(e => {
                    const message = "Error removing all ratings for category: " + e.message;
                    notification.error(message);
                });
        }
    };

    vm.onTabChange = () => {
        deselectMeasurable();

        if(_.isUndefined(vm.activeTab)){
            vm.activeTab = _.first(vm.tabs);
        }

        vm.onKeypress = mkRatingsKeyHandler(
            vm.activeTab.ratingScheme.ratings,
            vm.onRatingSelect,
            vm.doCancel);
    };

    vm.onShowAllTabs = () => {
        vm.visibility.showAllCategories = true;
        recalcTabs();
    };

}

controller.$inject = [
    "$q",
    "$state",
    "Notification",
    "ServiceBroker",
    "UserService"
];

const component = {
    template,
    bindings,
    controller
};

export default {
    component,
    id: "waltzMeasurableRatingEditPanel"
};
<commit_msg>Allow users to save a decom beyond retirement date of the application if confirmed<commit_after>/*
 * Waltz - Enterprise Architecture
 * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project
 * See README.md for more information
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific
 *
 */

import _ from "lodash";
import {CORE_API} from "../../../common/services/core-api-utils";
import {initialiseData} from "../../../common";
import {kindToViewState} from "../../../common/link-utils";
import {getDateAsUtc, loadAllData, loadDecommData, mkTabs} from "../../measurable-rating-utils";
import {indexRatingSchemes, mkRatingsKeyHandler} from "../../../ratings/rating-utils";

import template from "./measurable-rating-edit-panel.html";
import {displayError} from "../../../common/error-utils";

const bindings = {
    allocations: "<",
    allocationSchemes: "<",
    parentEntityRef: "<",
    startingCategoryId: "<?",
    plannedDecommissions: "<?",
    replacementApps: "<?",
    replacingDecommissions: "<?",
    application: "<"
};

const initialState = {
    activeTab: null,
    allocations: [],
    allocationSchemes: [],
    categories: [],
    measurables: [],
    plannedDecommissions: [],
    ratings: [],
    ratingSchemesById: {},
    ratingItemsBySchemeIdByCode: {},
    replacementApps: [],
    replacingDecommissions: [],
    saveInProgress: false,
    selected: null,
    startingCategoryId: null,
    tabs: [],
    unusedCategories: [],
    visibility: {
        ratingEditor: false,
        showDescriptionInPicker: false,
        instructions: true,
        schemeOverview: false,
        showAllCategories: false,
        tab: null
    }
};

function controller($q,
                    $state,
                    notification,
                    serviceBroker,
                    userService) {
    const vm = initialiseData(this, initialState);

    const loadData = (force) => {
        return loadAllData($q, serviceBroker, vm.parentEntityRef, true, force)
            .then((r) => {
                Object.assign(vm, r);
                recalcTabs();
                vm.categoriesById = _.keyBy(vm.categories, "id");
                vm.ratingItemsBySchemeIdByCode = indexRatingSchemes(_.values(vm.ratingSchemesById) || []);
                if (vm.startingCategoryId) {
                    vm.activeTab = _.find(vm.tabs, t => t.category.id === vm.startingCategoryId)
                } else if (!vm.activeTab) {
                    vm.activeTab = vm.tabs[0];
                }
                vm.onTabChange();
            })
    };

    const recalcTabs = function () {
        const hasNoRatings = vm.ratings.length === 0;
        const showAllCategories = hasNoRatings || vm.visibility.showAllCategories;
        const allTabs = mkTabs(vm, showAllCategories);
        vm.tabs = _.filter(allTabs, t => _.includes(vm.userRoles, t.category.ratingEditorRole));

        vm.hasHiddenTabs = vm.categories.length !== allTabs.length;
        if (vm.activeTab) {
            vm.activeTab = _.find(vm.tabs, t => t.category.id === vm.activeTab.category.id);
        }
    };

    const getDescription = () => _.get(
        vm.selected,
        ["rating", "description"]);

    const getRating = () => _.get(
        vm.selected,
        ["rating", "rating"]);

    const doRatingSave = (rating, description) => {
        const currentRating = !_.isEmpty(vm.selected.rating) ? vm.selected.rating.rating : null;
        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingStore.save,
                [vm.parentEntityRef, vm.selected.measurable.id, rating, currentRating, description])
            .then(r => { vm.ratings = r.data })
            .then(() => recalcTabs())
            .then(() => {
                vm.saveInProgress = false;
                const newRating = { rating, description };
                vm.selected = Object.assign({}, vm.selected, { rating: newRating });
            })
            .catch(e => displayError(notification, "Could not save rating", e))
    };

    const doRemove = () => {
        if (! vm.selected.rating) return $q.reject();

        vm.saveInProgress = true;

        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingStore.remove,
                [vm.parentEntityRef, vm.selected.measurable.id])
            .then(r => {
                vm.saveInProgress = false;
                vm.ratings = r.data;
                vm.selected.rating = null;
                recalcTabs();
            });
    };

    const deselectMeasurable = () => {
        vm.saveInProgress = false;
        vm.selected = Object.assign({}, vm.selected, { measurable: null });
        vm.visibility = Object.assign({}, vm.visibility, {schemeOverview: true, ratingEditor: false});
    };

    const selectMeasurable = (node) => {
        const { measurable, allocations } = node;
        const category = vm.categoriesById[measurable.categoryId];
        const ratingScheme = vm.ratingSchemesById[category.ratingSchemeId];
        const hasWarnings = !_.isEmpty(allocations);

        vm.selected = Object.assign({}, node, { category, hasWarnings, ratingScheme });
        vm.visibility = Object.assign({}, vm.visibility, {schemeOverview: false, ratingEditor: true});
    };

    const reloadDecommData = () => {
        return loadDecommData($q, serviceBroker, vm.parentEntityRef, true)
            .then(r => Object.assign(vm, r));
    };

    const saveDecommissionDate = (dateChange)  => {

        dateChange.newVal = getDateAsUtc(dateChange.newVal);

        serviceBroker
            .execute(
                CORE_API.MeasurableRatingPlannedDecommissionStore.save,
                [vm.parentEntityRef, vm.selected.measurable.id, dateChange])
            .then(r => {
                const decom = Object.assign(r.data, {isValid: true});
                vm.selected = Object.assign({}, vm.selected, {decommission: decom});
                notification.success(`Saved decommission date for ${vm.selected.measurable.name}`);
            })
            .catch(e => displayError(notification, "Could not save decommission date", e))
            .finally(reloadDecommData);
    };

    // -- BOOT --

    vm.$onInit = () => {

        userService
            .whoami()
            .then(user => vm.userRoles = user.roles)
            .then(() => loadData(true));

        vm.backUrl = $state
            .href(
                kindToViewState(vm.parentEntityRef.kind),
                { id: vm.parentEntityRef.id });
        vm.allocationsByMeasurableId = _.groupBy(vm.allocations, a => a.measurableId);
        vm.allocationSchemesById = _.keyBy(vm.allocationSchemes, s => s.id);
    };

    // -- INTERACT ---

    vm.onRemoveReplacementApp = (replacement) => {
        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingReplacementStore.remove,
                [replacement.decommissionId, replacement.id])
            .then(r => {
                vm.selected = Object.assign({}, vm.selected, { replacementApps: r.data });
                notification.success("Replacement app removed")
            })
            .catch(e  => displayError(notification, "Could not remove replacement app", e))
            .finally(reloadDecommData);
    };

    vm.onAddReplacementApp = (replacement) => {
        return serviceBroker
            .execute(
                CORE_API.MeasurableRatingReplacementStore.save,
                [replacement.decommissionId, replacement])
            .then(r => {
                vm.selected = Object.assign({}, vm.selected, { replacementApps: r.data });
                notification.success("Successfully added replacement app")
            })
            .catch(e  => displayError(notification, "Could not add replacement app", e))
            .finally(reloadDecommData);
    };

    vm.checkPlannedDecomDateIsValid = (decomDate) => {

        const appDate = new Date(vm.application.plannedRetirementDate);
        const newDecomDate = new Date(decomDate);

        const sameDate = appDate.getFullYear() === newDecomDate.getFullYear()
            && appDate.getMonth() === newDecomDate.getMonth()
            && appDate.getDate() === newDecomDate.getDate();

        return appDate > newDecomDate || sameDate;
    };

    vm.onSaveDecommissionDate = (dateChange) => {

        if (vm.application.entityLifecycleStatus === 'REMOVED'){
            notification.error("Decommission date cannot be set. This application is no longer active");
            return;
        }

        if (_.isNull(vm.application.plannedRetirementDate) || vm.checkPlannedDecomDateIsValid(dateChange.newVal)){
            saveDecommissionDate(dateChange);

        } else {
            const appDate = new Date(vm.application.plannedRetirementDate).toDateString();

            if (!confirm(`This decommission date is later then the planned retirement date of the application: ${appDate}. Are you sure you want to save it?`)){
                notification.error("Decommission date was not saved");
                return;
            }
            saveDecommissionDate(dateChange)
        }
    };

    vm.onRemoveDecommission = () => {
        if (!confirm("Are you sure you want to remove this decommission and any replacement apps?")) {
            notification.info("Revocation of decommission cancelled");
            return;
        }
        serviceBroker
            .execute(
                CORE_API.MeasurableRatingPlannedDecommissionStore.remove,
                [vm.selected.decommission.id])
            .then(() => {
                vm.selected = Object.assign({}, vm.selected, { decommission: null, replacementApps: [] });
                notification.success(`Removed decommission date and replacement applications for: ${vm.selected.measurable.name}`);
            })
            .catch(e => displayError(notification, "Could not remove decommission date", e))
            .finally(reloadDecommData);
    };

    vm.onMeasurableSelect = (node) => {
        selectMeasurable(node);
    };

    vm.onRatingSelect = r => {
        if (! vm.selected.measurable) return; // nothing selected
        if (! vm.selected.measurable.concrete) return; // not concrete
        if (r === getRating()) return; // rating not changed

        return r === "X"
            ? doRemove()
                .then(() => notification.success(`Removed: ${vm.selected.measurable.name}`))
            : doRatingSave(r, getDescription())
                .then(() => notification.success(`Saved: ${vm.selected.measurable.name}`));
    };

    vm.onSaveComment = (comment) => {
        return doRatingSave(getRating(), comment)
            .then(() => notification.success(`Saved Comment for: ${vm.selected.measurable.name}`))
    };

    vm.doCancel = () => {
        deselectMeasurable();
    };

    vm.onRemoveAll = (categoryId) => {
        if (confirm("Do you really want to remove all ratings in this category ?")) {
            serviceBroker
                .execute(
                    CORE_API.MeasurableRatingStore.removeByCategory,
                    [vm.parentEntityRef, categoryId])
                .then(r => {
                    notification.info("Removed all ratings for category");
                    vm.ratings = r.data;
                    recalcTabs();
                })
                .catch(e => {
                    const message = "Error removing all ratings for category: " + e.message;
                    notification.error(message);
                });
        }
    };

    vm.onTabChange = () => {
        deselectMeasurable();

        if(_.isUndefined(vm.activeTab)){
            vm.activeTab = _.first(vm.tabs);
        }

        vm.onKeypress = mkRatingsKeyHandler(
            vm.activeTab.ratingScheme.ratings,
            vm.onRatingSelect,
            vm.doCancel);
    };

    vm.onShowAllTabs = () => {
        vm.visibility.showAllCategories = true;
        recalcTabs();
    };

}

controller.$inject = [
    "$q",
    "$state",
    "Notification",
    "ServiceBroker",
    "UserService"
];

const component = {
    template,
    bindings,
    controller
};

export default {
    component,
    id: "waltzMeasurableRatingEditPanel"
};
<|endoftext|>