// //// // ==UserScript==
// @name updateEditorProgress
// @namespace http://tampermonkey.net/
// @version 2019.05.19
// @description for each discord editor in your region's channel, this script will open the associated editor's profile, capture relevant information, and download that information into
// @description comma separated value (CSV) file. The contents of the file can then be programmaticaly added to a google sheet (using a separate script)
// @description With the script installed, open any WME editor profile page to execute the script.
// @author ramblinwreck_81
// @match https://www.waze.com/user/editor*
// @require https://gf.qytechs.cn/scripts/24851-wazewrap/code/WazeWrap.js
// @grant none
// ==/UserScript==
// TO DO:
// add code that removes editors based on inactivity
// fix bot code to avoid editor name errors
(function() {
'use strict';
var discordEditors = [];
var tableUnlockedEditors = [];
var tableLockedEditors = [];
var CLIENT_ID = '533057355164-2m80uia4u5pedq0dteiia47k3ff6als8.apps.googleusercontent.com'
var DISCOVERY_DOCS = ["https://sheets.googleapis.com/$discovery/rest?version=v4"];
var SCOPES = "https://www.googleapis.com/auth/spreadsheets";
var spreadsheetId = '15TYXaO7iYRNNDUkkavG-2X75yP6iPobPV-VNBGhVjIU';
var ssRange = 'discordEditors!A:D';
var authorizeButton;
var signoutButton;
var blnReadyToBuildTable = false;
var blnWrite = false;
var blnLockChange = false;
var blnHomeRegionChange = false;
var blnNotHomeRegion = false;
var regionSpecificEditors = true;
var blnIsAM = false;
var editors = [];
function bootstrap(tries) {
if (W && W.Map &&
W.Model &&
$) {
init();
} else if (tries < 100) {
setTimeout(function() {
tries += 1;
bootstrap(tries);
}, 200);
}
} // end of bootstrap
function init()
{
console.log("initializing editor progress script");
createUploadElements();
function createUploadElements()
{
var y = document.createElement("div");
y.setAttribute("id", "csv-info");
document.getElementsByClassName("user-headline")[0].appendChild(y);
var z = document.createElement("button");
z.setAttribute("type", "button");
z.setAttribute("value", "Run");
z.setAttribute("id", "run-editor-update");
var aa = document.createTextNode("Editor Update");
z.appendChild(aa);
document.getElementById("csv-info").appendChild(z);
document.getElementById("run-editor-update").style.height = "20px";
document.getElementById("run-editor-update").style.width = "100px";
var node = document.createElement('div');
node.innerHTML = '<input type="checkbox" id="select-region" name="check"><label for="region-specific">My Region Only</label>';
document.getElementById('csv-info').appendChild(node);
$('#select-region').attr('autofocus', 'true')
// $('#select-region').attr('label','Only SER Editors?');
$('#select-region').attr('checked', 'true');
$('#csv-info').append('<button id="authorize_button" style="display: none;">Authorize</button><button id="signout_button" style="display: none;">Sign Out</button>');
authorizeButton = document.getElementById('authorize_button');
signoutButton = document.getElementById('signout_button');
} // end of createUploadElements
document.getElementById("select-region").addEventListener("click", setEditorFilter, false);
document.getElementById("run-editor-update").addEventListener("click", handleClientLoad, false);
// checkPointStatus();
function checkPointStatus()
{
var pageNew = window.open("http://status.waze.com");
checkForOpen();
function checkForOpen()
{
var timer;
if(pageNew.document.getElementsByClassName('tg-i6eq').length>0){
console.log('success');
clearTimeout(timer);
} else {
console.log('waiting');
timer = setTimeout(checkForOpen,250);
}
}
}
} // end of init
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}
function initClient() {
gapi.client.init({
//apiKey: API_KEY,
clientId: CLIENT_ID,
discoveryDocs: DISCOVERY_DOCS,
scope: SCOPES
}).then(function() {
// Listen for sign-in state changes.
gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);
// Handle the initial sign-in state.
updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
authorizeButton.onclick = handleAuthClick;
signoutButton.onclick = handleSignoutClick;
});
}
function updateSigninStatus(isSignedIn)
{
if (isSignedIn) {
authorizeButton.style.display = 'none';
signoutButton.style.display = 'block';
if (blnWrite === false) {
executionSequence();
} else {
if(blnHomeRegionChange) {
handleNonRegionEditors();
blnHomeRegionChange = false;
}
if(blnLockChange) {
addLockedEditors();
blnLockChange = false;
}
if(blnIsAM) {
// console.log('handling AMs');
handleAMEditors();
blnIsAM = false;
}
}
} else {
authorizeButton.style.display = 'block';
signoutButton.style.display = 'none';
}
} // end of update signin status
function handleAuthClick(event)
{
gapi.auth2.getAuthInstance().signIn();
}
/**
* Sign out the user upon button click.
*/
function handleSignoutClick(event)
{
gapi.auth2.getAuthInstance().signOut();
}
$('body').append('<script async defer src="https://apis.google.com/js/api.js" onload="this.onload=function(){};handleClientLoad()" onreadystatechange="if (this.readyState === complete) this.onload()"></script>');
function setEditorFilter()
{
if ($('#select-region').prop('checked')) {
regionSpecificEditors = true;
} else {
regionSpecificEditors = false;
alert('If the table is already displayed below, refresh the page, deselect the checkbox and run the editor update again.');
}
};
function executionSequence()
{
let lockedArray = localStorage.getItem('lockedEditors') ? JSON.parse(localStorage.getItem('lockedEditors')) : [];
var validatedProfileCount = 0;
var profilePageErrors = 0;
var rangeLength = 0;
var inactiveEditors = 0;
var L1Editors = 0;
var L2Editors = 0;
var L3Editors = 0;
var L4Editors = 0;
var L5Editors = 0;
var L6Editors = 0;
var L7Editors = 0;
var totalEditors = 0;
var L1Edits = 0;
var L2Edits = 0;
var L3Edits = 0;
var L4Edits = 0;
var L5Edits = 0;
var L6Edits = 0;
var L7Edits = 0;
var sumRegionEdits = 0;
var alreadyWarned = false;
var totalNotInRegion = 0;
var duplicatesRemoved = 0;
var skipCount = 0;
connectGoogleAPI();
function connectGoogleAPI()
{
var params = {
// The ID of the spreadsheet to retrieve data from.
spreadsheetId: spreadsheetId, //TODO: Update placeholder value.
// The A1 notation of the values to retrieve.
ranges: ssRange,
// How values should be represented in the output.
// The default render option is ValueRenderOption.FORMATTED_VALUE.
valueRenderOption: 'UNFORMATTED_VALUE', // TODO: Update placeholder value.
// How dates, times, and durations should be represented in the output.
// This is ignored if value_render_option is
// FORMATTED_VALUE.
// The default dateTime render option is [DateTimeRenderOption.SERIAL_NUMBER].
dateTimeRenderOption: 'FORMATTED_STRING', // TODO: Update placeholder value.
}; // end of params variable
var request = gapi.client.sheets.spreadsheets.values.batchGet(params);
request.then(function(response) {
var apiEditors = response.result.valueRanges[0].values
rangeLength = response.result.valueRanges[0].values.length;
var filteredArr = apiEditors.filter(notSERFilter);
function notSERFilter(element, index, array)
{
return array[index][2] !== true;
}
// console.log('At line 237, filtered array is ' + filteredArr + ' and filtered array length is ' + filteredArr.length);
totalNotInRegion = rangeLength - filteredArr.length;
apiEditors.forEach(function(element, index, array)
{
var string = array[index][0].toString().toLowerCase().trim();
array[index][0] = string;
discordEditors.push(array[index]);
if (apiEditors[index][1] === true) {}
if (apiEditors[index][1] === true) {
discordEditors[index][1] = true;
} else {
discordEditors[index][1] = '';
}
if (regionSpecificEditors === false) {
if (apiEditors[index][2] === true) {
discordEditors[index][2] = true;
} else {
discordEditors[index][2] = '';
}
} else {
// discordEditors[index][2] = '';
}
if(apiEditors[index][3] === true) {
discordEditors[index][3] = true;
} else {
discordEditors[index][3] = '';
}
}); // end of .forEach
var stringArr = [];
var testArr = [];
var a = discordEditors.reduce(function(accum, value, idx, array) // get rid of duplicate editor names
{
var string = array[idx][0].toString().trim().toLowerCase();
if (stringArr.indexOf(string) < 0) {
stringArr.push(string);
testArr.push(value);
accum = testArr;
return accum;
}
}, []);
duplicatesRemoved = discordEditors.length - testArr.length;
// console.log('duplicate editors removed: ' + duplicatesRemoved);
discordEditors = testArr;
}, function(reason) {
console.error('error: ' + reason.result.error.message);
});
} // end of function connectGoogleAPI
var timeoutCounter = 0;
checkDiscordEditorArr();
function checkDiscordEditorArr() {
// var waitTime = 400;
var g_Wait;
if (((discordEditors.length + duplicatesRemoved) === rangeLength) && rangeLength > 300) {
clearTimeout(g_Wait);
connectWazeAPI();
} else {
timeoutCounter += 1;
g_Wait = setTimeout(function ()
{
checkDiscordEditorArr();
}, 400);
}
} // end of checkdiscordeditorarr function
timeoutCounter = 0;
checkWazeAPIReturns();
function checkWazeAPIReturns() {
var wait;
// var waitTime = 1000;
if ((profilePageErrors + validatedProfileCount + inactiveEditors + skipCount === discordEditors.length) && discordEditors.length > 0) {
clearTimeout(wait);
blnReadyToBuildTable = true;
buildWebDisplay();
} else {
// console.log('profilepageerrors: ' + profilePageErrors + ' and validatedprofileCount: ' + validatedProfileCount + ' and inactiveEditors: ' + inactiveEditors + ' and totalNotInRegion: ' + totalNotInRegion + ' and skipCount: ' + skipCount + ' and discordEditors.length: ' + discordEditors.length);
wait = setTimeout(function() {
timeoutCounter += 1;
checkWazeAPIReturns();
}, 1000);
}
} // end of checkWazeAPIReturns function
function connectWazeAPI() {
function Editor(name, rank, firstEditDate, totalEdits, editHistory, milestone, rate, lastEditDate, milliFirstEditDate, sevenDayEdits, rankLocked, blnNotHomeRegion, blnIsAM, sevenDayRate, thirtyDayRate,sixtyDayRate, ninetyDayRate)
{
this.name = name;
this.rank = rank;
this.firstEditDate = firstEditDate;
this.totalEdits = totalEdits;
// the function findLastEditDate below will reverse the order of the editHistory array. until then, it is in reverse chronological order
this.editHistory = editHistory; // note that edit history is reverse chronological. so edit history at index 0 is actually 91 days ago. at index 91 is today.
this.sevenDayEdits = sevenDayEdits;
this.milestone = milestone;
this.rate = rate;
this.lastEditDate = lastEditDate;
this.milliFirstEditDate = milliFirstEditDate;
this.rankLocked = rankLocked;
this.notHomeRegion = blnNotHomeRegion;
this.AM = blnIsAM;
this.rate7 = sevenDayRate;
this.rate30 = thirtyDayRate;
this.rate60 = sixtyDayRate;
this.rate90 = ninetyDayRate;
}
function pullEditorInfo(element, index, array)
{
if((array[index][2] !== true) || (regionSpecificEditors === false)) { // if filter on region editors is false OR an editor NOT is marked as out of this region...
var wazeURL = 'https://www.waze.com/user/editor/';
$.ajax({
url: wazeURL + array[index][0],
success: function(data, status, xhr)
{
var $result = $.parseHTML(xhr.responseText, true)[9].text;
var cdata = JSON.parse($result.split(";")[1].replace("gon.data=", ""));
var userdata = "\nUsername: " + cdata.username + "\nRank: " + parseInt(cdata.rank + 1) + "\nEdits: " + cdata.edits + "\nFirst Edit Date: " + cdata.firstEditDate;
if (cdata.firstEditDate === undefined) {
profilePageErrors += 1;
console.log(`${cdata.username} has no valid date.`);
return;
}
editors[validatedProfileCount] = new Editor(cdata.username, parseInt(cdata.rank + 1), cdata.firstEditDate, cdata.edits, cdata.editingActivity);
var active = -1;
editors[validatedProfileCount].lastEditDate = findLastEditDate(editors[validatedProfileCount]);
editors[validatedProfileCount].milliFirstEditDate = cdata.firstEditDate;
if (array[index][1] === true) {
editors[validatedProfileCount].rankLocked = true;
} else {
editors[validatedProfileCount].rankLocked = false;
}
if (array[index][2] === true) {
editors[validatedProfileCount].notHomeRegion = true;
} else {
editors[validatedProfileCount].notHomeRegion = false;
}
if(array[index][3] === true) {
editors[validatedProfileCount].AM = true;
} else {
editors[validatedProfileCount].AM = false;
}
function findLastEditDate(curEditor)
{
var arr = curEditor.editHistory;
var foundFirst = false;
var lastDay;
debugger;
arr = arr.reverse();
curEditor.editHistory = arr // editHistory (array) is now reversed. Most recent edits appear nearest beginning of array index value of zero.
console.log(curEditor.name + curEditor.editHistory);
arr.forEach(function(element, index, array) {
if ((array[index] > 0) && (foundFirst === false)) {
foundFirst = true;
active = index;
}
});
var today = new Date();
var lastDayMS = 0;
if (active > -1) {
lastDayMS = active * 24 * 60 * 60 * 1000;
} else {
lastDayMS = 92 * 24 * 60 * 60 * 1000;
inactiveEditors += 1;
}
var lastDate = new Date(today - lastDayMS);
return lastDate.toLocaleDateString();
} // end of findLastEditDate
if (active > -1) {
validatedProfileCount += 1;
switch (parseInt(cdata.rank + 1)) {
case 1:
L1Editors += 1;
L1Edits += cdata.editingActivity.reduce(reducer, 0);
break;
case 2:
L2Editors += 1;
L2Edits += cdata.editingActivity.reduce(reducer, 0);
break;
case 3:
L3Editors += 1;
L3Edits += cdata.editingActivity.reduce(reducer, 0);
break;
case 4:
L4Editors += 1;
L4Edits += cdata.editingActivity.reduce(reducer, 0);
break;
case 5:
L5Editors += 1;
L5Edits += cdata.editingActivity.reduce(reducer, 0);
break;
case 6:
L6Editors += 1;
L6Edits += cdata.editingActivity.reduce(reducer,0);
break;
case 7:
L7Editors += 1;
L7Edits += cdata.editingActivity.reduce(reducer,);
break;
default:
console.log('no rank found for editor ' + cdata.username);
} // end of switch
function reducer(accumulator, value) {
return accumulator + value;
}
totalEditors = L1Editors + L2Editors + L3Editors + L4Editors + L5Editors + L6Editors;
sumRegionEdits = L1Edits + L2Edits + L3Edits + L4Edits + L5Edits + L6Edits + L7Edits;
} // end of if(active > -1)
}, // end of success
error: function(XMLHttpRequest, textStatus, errorThrown) {
profilePageErrors += 1;
}
}); // end of ajax
} else {
skipCount += 1;
} // end if (array[index][2] !==2)
} // end of pullEditorInfo
discordEditors.forEach(pullEditorInfo);
} // end of connectWazeAPI
function buildWebDisplay()
{
var editorHTML = '';
//**********regionEditorsHTML is the table header info*********
//<input class = ' + AMStatus + ' type = "checkbox" />
var regionEditorsHTML = '<div class = "table-area1"><button type = "button" id = "save-locked">Save Locked Editors</button>' +
'<button type ="button" id = "save-nonRegion">Save Non-region Editors</button>' +
'<button type = "button" id = "save-AM">Save AM Editors</button>' +
'<input id = "seven-day" name = "edit-rates" class = "rate-7" value = "seven" type = "radio" /><label for = "seven-day">Last 7 Days Edits</label>' +
'<input id = "thirty-day" name = "edit-rates" class = "rate-30" value = "thirty" type = "radio" /><label for = "thirty-day">Last 30 Days Edits</label>' +
'<input id = "sixty-day" name = "edit-rates" class = "rate-60" value = "sixty" type = "radio" /><label for = "sixty-day">Last 60 Days Edits</label>' +
'<input id = "ninety-day" name = "edit-rates" class = "rate-90" value = "ninety" type = "radio" /><label for = "ninety-day">Last 90 Days Edits</label>' +
'<div id = "total-editors"></div><div id = regions-edits></div>' +
'<pre tr:nth-child(even) {background: #CCC} tr:nth-child(odd) {background: #FFF}</pre> <table id= "region-table">' +
'<thead id = "the-head"><tr><th id= "name" class = "hdr col1 columz"><button type="button" id="sort-name" ' +
'>Name</button></th><th id="level" class = "col2 columz"><button type = "button" id = "sort-level">Level</button></th><th id= "locked" class = ' +
'"col3 columz"><button type = "button" id = "sort-locked">Locked</button></th><th id="began" class = "col4 columz">' +
'<button type = "button" id= "sort-began">Started</button>' +
'</th><th id="total-edits" class = "col5 columz"><button type = "button" id= "sort-edits">Total Edits</button>' +
'</th><th id="milestone" class = "col6 columz"><button type = "button" id = "sort-milestone">Milestone</button></th>' +
'<th id = "last-edit" class = "col6A columz"><button type = "button" id = "sort-last-edit-date">Last Edit</button></th>' +
'<th id="rate" class = "col7 columz"><button type = "button" id = "sort-rate">Edit Rate</button></th>' +
'<th id = "outside-SER" class = "col7A columz"><button type = "button" id = "sort-outsideSER">Non-SER</button></th>' +
'<th id = AM-stat" class = "col7B columz"><button type = "button" id = "sort-AMs">Is AM</button></th>' +
'<th id = "milliDate" class = "col8 columz">msDate</tr></thead><tbody id = "theTable-body">';
//************regionEditorsHTML is the table header info
editors.forEach(addStatsToTable);
function addStatsToTable(element, index, array)
{
function convertSecondsToDate(sec)
{
var a = new Date(sec).toLocaleDateString();
if (array[index].firstEditDate !== NaN) {
array[index].firstEditDate = a;
return a;
} else {
console.log(`array[index] first edit date is not a number. array[index].name`);
}
} // end of convertSecondsToDate
var startDate = convertSecondsToDate(editors[index].firstEditDate);
var rate = editRate(editors[index]);
function editRate(rateEditor)
{
if (rateEditor.rank !== NaN || rateEditor.editHistory.length !== 0) {
var period = [7, 30, 60, 90];
period.forEach(function (element, index, array) {
function sumEdits(accumulator, currentValue)
{
return accumulator + currentValue;
}
var editHistoryArray = rateEditor.editHistory;
// var a = editHistoryArray.slice(editHistoryArray.length - element);
var a = editHistoryArray.slice(0, element);
var b = a.reduce(sumEdits);
if (element === 7) {
rateEditor.rate = b;
}
switch (element) {
case 7:
rateEditor.rate7 = rateEditor.rate
break;
case 30:
rateEditor.rate30 = b;
break;
case 60:
rateEditor.rate60 = b;
break;
case 90:
rateEditor.rate90 = b;
break;
default:
console.log('rate period does not make sense');
} // end of switch
});
} else {
console.log(rateEditor.name + ' does not have a valid rank or has no valid edit history.');
}
} // end of editRate function
var mileStr = milestone(editors[index]);
function milestone(curEditor)
{
switch (curEditor.rank) {
case 1:
if (curEditor.totalEdits > 1000 && curEditor.rate7 > 0) {
return curEditor.milestone = 'true, total edits';
} else if ((curEditor.totalEdits + curEditor.rate7) > 2000) {
return curEditor.milestone = 'true, edit rate';
} else if (curEditor.rate7 > 1000) {
return curEditor.milestone = 'true, edit rate';
} else if (curEditor.totalEdits > 400 && curEditor.rate7 > 0) {
return curEditor.milestone = 'initial review';
} else {
return curEditor.milestone = 'false';
}
break;
case 2:
if (curEditor.totalEdits > 20000) {
return curEditor.milestone = 'true, edits';
} else if ((curEditor.totalEdits + curEditor.rate30) > 25000) {
return curEditor.milestone = 'true, edit rate'
} else {
return curEditor.milestone = 'false';
}
break;
default:
return curEditor.milestone = 'false';
} // end of switch
} // end of milestone function
var regionStatus = '';
if (editors[index].notHomeRegion === true) {
regionStatus = 'not-home';
} else {
regionStatus = 'home';
}
var lockStatus = '';
if (editors[index].rankLocked === true) {
lockStatus = 'locked';
} else {
lockStatus = 'not-locked';
}
var AMStatus = '';
if(editors[index].AM === true) {
AMStatus = "is-AM";
} else {
AMStatus = "Not-AM";
}
function numberWithCommas(n) {
var parts=n.toString().split(".");
return parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",") + (parts[1] ? "." + parts[1] : "");
}
editors[index].commaTotalEdits = numberWithCommas(editors[index].totalEdits);
editors[index].commaRateSeven = numberWithCommas(editors[index].rate7);
editors[index].commaRateThirty = numberWithCommas(editors[index].rate30);
editors[index].commaRateSixty = numberWithCommas(editors[index].rate60);
editors[index].commaRateNinety = numberWithCommas(editors[index].rate90);
editorHTML += '<tr class = "table-rows"><td headers= "name" class = "col1 all-cells"><a class= tbl-link href=https://www.waze.com/user/editor/' +
editors[index].name + '>' + editors[index].name + "</a>" + '</td><td headers = "level" class = "col2">' + editors[index].rank +
'</td><td headers = "locked" class = "col3" ><input class = ' + lockStatus + ' type = "checkbox" /><td headers="began" class = "col4">' + startDate + '</td><td headers="total-edits" ' +
'class = "col5">' + editors[index].commaTotalEdits +
'</td>' + '<td headers="milestone" class = "col6">' + mileStr + '</td><td headers = "last-edit" class = "col6A">' + editors[index].lastEditDate + '</td><td headers="rate" class = "col7 num">' + 0 + '</td>' +
'<td headers = "outside-SER" class = "col7A"><input class = ' + regionStatus + ' type = "checkbox" />' +
'<td headers = "AM" class = "col7B"><input class = ' + AMStatus + ' type = "checkbox" />' +
'<td headers="msDate" class = "col8">' + editors[index].milliFirstEditDate + '</td></tr>';
} // end of addStatsToTable
var closingHTML = '</tbody></table></div>';
$(".recent-edits-content").remove()
$('#recent-edits').append(regionEditorsHTML + editorHTML + closingHTML);
// $('#header').after(regionEditorsHTML + editorHTML + closingHTML);
$('.tbl-link').attr('target', '_blank');
$('.table-area1').css({
// "display": "inline-block",
// "max-height": "500px",
// "overflow": "auto"
});
$('#region-table').css({
"table-layout": "fixed",
// "text-align":"left"
"max-width":"1100px",
"width":"880px",
"white-space": "nowrap"
});
$('#the-head').css({
"max-height": "75px",
"display": "block",
"margin-bottom": "3px",
// "overflow": "hidden"
"border":"2px solid red"
});
$('#theTable-body').css({
"max-height": "500px",
"margin-bottom": "5px",
"overflow-y": "auto",
// "overflow-x": "hidden",
"display": "block",
"border": "2px solid black"
});
$('.col1').css({
"width": "120px",
"min-width":"120px",
"max-width":"120px",
"text-align":"left"
});
$('#sort-name').css({
"width": "119px"
});
$('.all-cells').css({
"white-space": "nowrap",
"overflow": "hidden",
"text-overflow": "ellipsis"
});
$('.col2').css({
"width": "50px",
"max-width":"50px",
"min-width":"50px",
"text-align":"center"
});
$('#sort-level').css({
"width": "49px"
});
$('.col3').css({
"width":"50px",
"max-width":"50px",
"min-width":"50px",
"text-align":"center"
});
$('#sort-locked').css({
"width": "49px"
});
$('.col4').css({
"width":"100px",
"max-width":"100px",
"min-width":"100px",
"text-align": "center"
});
$('#sort-began').css({
"width": "99px"
});
$('.col5').css({
"width":"100px",
"max-width":"100px",
"min-width":"100px",
"text-align":"center"
});
$('#sort-edits').css({
"width": "99px"
});
$('.col6').css({
"width":"120px",
"min-width":"120px",
"max-width":"120px",
"text-align": "left"
});
$('#sort-milestone').css({
"width": "119px"
});
$('.col6A').css({
"width": "120px",
"text-align":"right",
"min-width":"120px",
"max-width":"120px"
});
$('#sort-last-edit-date').css({
"width": "119px"
});
$('.col7').css({
"width": "100px",
"text-align":"right",
"min-width":"100px",
"max-width":"100px"
});
$('#sort-rate').css({
"width": "99px"
});
$('.col7A').css({
"width": "60px",
"text-align":"right",
"min-width":"60px",
"max-width":"60px"
});
$('#sort-outsideSER').css({
"width": "59px"
});
$('.col7B').css({
"width": "42px",
"text-align":"right",
"min-width":"42px",
"max-width":"42px"
});
$('#sort-AMs').css({
"width": "41px"
});
$('.col8').css({
"width": "0px",
"display": "none"
});
$('.table-rows').css({
"border": "solid thin"
});
// $('#sort-rate').css('fontSize', '8px');
$('.columz').attr('title', 'Click to sort. After the sort is complete, a second click will sort in reverse order.');
var tbl = document.getElementById("region-table");
if (tbl != null) {
for (var i = 1; i < tbl.rows.length; i++) {
tbl.rows[i].style.cursor = "pointer";
tbl.rows[i].onmousemove = function() {
this.style.backgroundColor = "#FFFF00";
this.style.color = "black";
};
tbl.rows[i].onmouseout = function() {
this.style.backgroundColor = "";
this.style.color = "";
$("tr:even").css("background-color", "#CCC");
$("tr:odd").css("background-color", "#fff");
};
}
} // end of if(tbl !=null)
$("tr:even").css("background-color", "#CCC");
$('#total-editors').html(`Total Editors: ${totalEditors} (L1: ${L1Editors}, L2: ${L2Editors}, L3: ${L3Editors}, L4: ${L4Editors}, L5: ${L5Editors}, L6: ${L6Editors})`);
$('#regions-edits').html(`Total Edits last 90 days... (L1: ${L1Edits.toLocaleString()}, L2: ${L2Edits.toLocaleString()}, L3: ${L3Edits.toLocaleString()}, L4: ${L4Edits.toLocaleString()}, L5: ${L5Edits.toLocaleString()}, L6: ${L6Edits.toLocaleString()}, L7: ${L7Edits.toLocaleString()}, Total Edits: ${sumRegionEdits.toLocaleString()})`);
$('.locked').prop('checked', true);
$('.not-locked').prop('checked', false);
$('.not-home').prop('checked', true);
$('.home').prop('checked', false);
$('.is-AM').prop('checked',true);
$('.Not-AM').prop('checked',false);
$('.rate-30').prop('checked',true);
rateChange();
$(document).on('change','.rate-7', rateChange);
$(document).on('change','.rate-30',rateChange);
$(document).on('change','.rate-60',rateChange);
$(document).on('change','.rate-90',rateChange);
function rateChange()
{
var whoIndex = 0;
var names = [];
var testName ='';
var rows = document.getElementsByTagName('tr');
var rowEditorName =[];
for(i=0; i<rows.length; i ++ ) {
// console.log("i: ", i);
rowEditorName.push(rows[i].children[0].textContent.toLowerCase().trim()); //add each row editor's name to an array
// console.log(rows[i].children[0].textContent);
}
editors.forEach(function (element, index, array)
{
testName = (editors[index].name).toLowerCase().trim(); // prep each editors object name for creating an array of editor names
names.push(testName);
});
rowEditorName.forEach(function(element,index,array)
{
whoIndex = names.indexOf(rowEditorName[index]) // find index in editors object corresponding to editor name from row
if(whoIndex < 0 && rowEditorName[index] !== 'name') {
alert('Editor: ' + rowEditorName[index] + 'not found in editor object.');
}
if(index === 0) {
// console.log("rowEditorName[0]: ", rowEditorName[index]);
}
if(index > 0) {
if ($('.rate-7').prop('checked')) {
// console.log('rate 7');
rows[index].children[7].textContent = editors[whoIndex].commaRateSeven;
}
if ($('.rate-30').prop('checked')) {
// console.log('rate 30')
rows[index].children[7].textContent = editors[whoIndex].commaRateThirty;
}
if ($('.rate-60').prop('checked')) {
// console.log('rate 60');
rows[index].children[7].textContent = editors[whoIndex].commaRateSixty;
}
if ($('.rate-90').prop('checked')) {
// console.log('rate 90');
rows[index].children[7].textContent = editors[whoIndex].commaRateNinety;
}
}
});
} // end of rateChange function
$(document).on('change', '.locked', function()
{
if ($(this).prop('checked')) {
blnLockChange = true;
} else {
blnLockChange = true;
}
beCareful();
}); // end of (document).on('change','.locked')
$(document).on('change', '.not-locked', function()
{
if ($(this).prop('checked')) {
blnLockChange = true;
} else {
blnLockChange = true;
}
beCareful();
}); // end of document on change not-locked
$(document).on('change', '.not-home', function()
{
if ($(this).prop('checked')) {
blnHomeRegionChange = true;
} else {
blnHomeRegionChange = true;
}
beCareful();
});
$(document).on('change', '.home', function() {
if ($(this).prop('checked')) {
blnHomeRegionChange = true;
} else {
blnHomeRegionChange = true;
}
beCareful();
});
$(document).on('change','.Not-AM', function()
{
// console.log('not-Am changed');
if($(this).prop('checked')) {
blnIsAM = true;
} else {
blnIsAM = true;
}
beCareful();
});
$(document).on('change', '.is-AM', function()
{
// console.log('is-am changed');
if($(this).prop('checked')) {
blnIsAM = true;
} else {
blnIsAM = true;
}
beCareful();
});
function beCareful() {
if (alreadyWarned === false) {
alert('Changes will not be saved unless you click on the appropriate save button before refreshing or leaving this page!');
alreadyWarned = true;
}
}
var nameAscending = false;
var levelAscending = false;
var startAscending = false;
var totalAscending = false;
var milestoneAscending = true;
var rateAscending = false;
var lockedAscending = false;
var insideOutsideAsc = false;
var lastEditAsc = false;
var AMAscending = false;
document.getElementById("name").addEventListener("click", function()
{
if (nameAscending) {
nameAscending = false;
} else {
nameAscending = true;
}
sort(nameAscending, 'col1', 'region-table');
}, false);
document.getElementById("level").addEventListener("click", function()
{
if (levelAscending) {
levelAscending = false;
} else {
levelAscending = true;
}
sort(levelAscending, 'col2', 'region-table');
}, false);
document.getElementById("began").addEventListener("click", function()
{
if (startAscending) {
startAscending = false;
} else {
startAscending = true;
}
sort(startAscending, 'col8', 'region-table');
}, false);
document.getElementById("sort-locked").addEventListener("click", function()
{
if (lockedAscending) {
lockedAscending = false;
} else {
lockedAscending = true;
}
sort(lockedAscending, 'col3', 'region-table');
}, false);
document.getElementById("total-edits").addEventListener("click", function()
{
if (totalAscending) {
totalAscending = false;
} else {
totalAscending = true;
}
sort(totalAscending, 'col5', 'region-table');
}, false);
document.getElementById("milestone").addEventListener("click", function()
{
if (milestoneAscending) {
milestoneAscending = false;
} else {
milestoneAscending = true;
}
sort(milestoneAscending, 'col6', 'region-table');
}, false);
document.getElementById("rate").addEventListener("click", function()
{
if (rateAscending) {
rateAscending = false;
} else {
rateAscending = true;
}
sort(rateAscending, 'col7', 'region-table');
}, false);
//last-edit outside-SER
document.getElementById('last-edit').addEventListener('click', function()
{
if (lastEditAsc) {
lastEditAsc = false;
} else {
lastEditAsc = true;
}
sort(lastEditAsc, 'col6A', 'region-table');
}, false);
document.getElementById('outside-SER').addEventListener('click', function()
{
if (insideOutsideAsc) {
insideOutsideAsc = false;
} else {
insideOutsideAsc = true;
}
sort(insideOutsideAsc, 'col7A', 'region-table');
}, false);
document.getElementById('sort-AMs').addEventListener('click', function ()
{
if(AMAscending) {
AMAscending = false;
} else {
AMAscending = true;
}
sort(AMAscending, 'col7B', 'region-table');
}, false);
function sort(ascending, columnClassName, tableId)
{
var tbody = document.getElementById(tableId).getElementsByTagName(
"tbody")[0];
var rows = tbody.getElementsByTagName("tr");
var unsorted = true;
while (unsorted) {
unsorted = false;
for (var r = 0; r < rows.length - 1; r++) {
var row = rows[r];
var nextRow = rows[r + 1];
if (columnClassName !== 'col3') {
var value = row.getElementsByClassName(columnClassName)[0].innerHTML;
var nextValue = nextRow.getElementsByClassName(columnClassName)[0].innerHTML;
value = value.replace(/,/g, ''); // in case a comma is used in float number
nextValue = nextValue.replace(/,/g, '');
if (!isNaN(value)) {
value = parseFloat(value);
nextValue = parseFloat(nextValue);
}
} else { // element is a checkbox
var chk = row.getElementsByClassName(columnClassName)[0];
var nextChk = nextRow.getElementsByClassName(columnClassName)[0];
if (chk.querySelector("input[type=checkbox]") !== null) { // checkbox case
value = chk.querySelector('input[type=checkbox]').checked;
nextValue = nextChk.querySelector("input[type=checkbox]").checked;
}
} // end of if(columnClassName !== 'col3')
if (ascending ? value > nextValue : value < nextValue) {
tbody.insertBefore(nextRow, row);
unsorted = true;
}
} // end of for
} // end of while
$("tr:even").css("background-color", "#CCC");
$("tr:odd").css("background-color", "#fff");
} //end of sort function
function storageSave()
{
lockedArray = [];
localStorage.setItem('lockedEditors', JSON.stringify(lockedArray));
var a = $('.col3 input:checked').map(function() {
return $(this).closest('tr').find('td:eq(0)').text();
}).get();
if (a.length > 0) {
a.forEach(function(element, index, array) {
lockedArray.push(array[index]);
});
}
localStorage.setItem('lockedEditors', JSON.stringify(lockedArray));
} // end of storageSave
} // end of buildWebDisplay
} // end of executionSequence
listenMore();
function listenMore()
{
// console.log('listenMore');
if (blnReadyToBuildTable) {
console.log('save button loaded');
blnWrite = true;
document.getElementById("save-locked").addEventListener("click", handleClientLoad);
document.getElementById("save-nonRegion").addEventListener("click", handleClientLoad);
document.getElementById("save-AM").addEventListener("click", handleClientLoad);
} else {
setTimeout(function() {
listenMore();
}, 10000);
}
} // end of listenMore
function addLockedEditors()
{
if (document.getElementById('save-locked') !== null) {
idLockedEditors();
} else {
setTimeout(function() {
addLockedEditors();
}, 500);
}
function idLockedEditors()
{
var pleaseConfirm = false;
tableUnlockedEditors = [];
tableLockedEditors = [];
$.each($("input[class = 'not-locked']:checked"), function() {
tableLockedEditors.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'not-locked']:not(:checked"), function() {
tableUnlockedEditors.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'locked']:not(:checked)"), function() {
tableUnlockedEditors.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'locked']:checked"), function() {
tableLockedEditors.push($(this).closest('tr').find('td:eq(0)').text());
});
var introText = '';
var moreText = '';
if (tableLockedEditors.length > 0 && tableUnlockedEditors.length === 0) {
introText = 'You are about to change the lock status of editors. With your changes, the following editors will be locked: ' + tableLockedEditors.join(", ") + ". ";
}
if (tableUnlockedEditors.length > 0 && tableLockedEditors.length > 0) {
introText = 'You are about to change the lock status of editors. With your changes, the following editors will be locked: ' + tableLockedEditors.join(", ") + ". ";
moreText = '';
} else if (tableUnlockedEditors.length > 0 && tableLockedEditors.length === 0) {
introText = 'You are about to change the lock status of editors. ';
}
var finishText = 'Please do not make these changes unless you are absolutely certain of these editors lock status. Click cancel to remove these changes. ';
pleaseConfirm = window.confirm(introText + moreText + finishText);
var blnMatch = false;
if (pleaseConfirm) {
if (tableLockedEditors.length > 0) {
tableLockedEditors.forEach(function(element, index, array) {
var test = element.trim();
test = test.toLowerCase();
var idx = discordEditors.findIndex(function(element1, index1, array1) {
if (element1.length > 0) {
return element1[0] === test;
} else {
console.log('When adding lock for ' + test + ', this editor does not have the correct sub-array elements');
}
});
if (idx < 0) {
console.log('no match for ' + test + 'while adding lock status.');
} else {
var testArr = [test, true, discordEditors[idx][2], discordEditors[idx][3]];
console.log('At tableLocked Editors.length >0, removing ' + discordEditors[idx] + ' and adding ' + testArr);
discordEditors.splice(idx, 1, testArr);
}
}); // end of tableLockedEditors forEach function
} // end of tableLockedEditors > 0 if statement
blnMatch = false;
if (tableUnlockedEditors.length > 0) {
tableUnlockedEditors.forEach(function(element, index, array) {
var test = element.trim();
test = test.toLowerCase();
var idx = discordEditors.findIndex(function(element1, index1, array1) {
if (element1.length > 0) {
return element1[0] === test;
} else {
console.log('while removing lock status for ' + test + ', found this editor does not have the correct sub-array elements');
}
});
if (idx < 0) {
console.log('no match for ' + test + ' while removing lock status.');
} else {
var testArr = [test,'', discordEditors[idx][2], discordEditors[idx][3]];
console.log('At tableUnlocked Editors.length >0, removing ' + discordEditors[idx] + ' and adding ' + testArr);
discordEditors.splice(idx, 1, testArr);
}
}); // end of tableUnlockedEditors forEach function
} // end of tableUnlockedEditors > 0 if statement
tableLockedEditors = [];
tableUnlockedEditors = [];
} else {
$('.locked').prop('checked', true);
$('.not-locked').prop('checked', false);
tableLockedEditors = [];
tableUnlockedEditors = [];
}
} // end of idLockedEditors
var valueRangeBody = {
values: discordEditors
};
var params = {
spreadsheetId: spreadsheetId, //TODO: Update placeholder value.
range: ssRange,
valueInputOption: 'RAW'
};
var request = gapi.client.sheets.spreadsheets.values.update(params, valueRangeBody);
// console.log('here');
request.then(function(response) {
// TODO: Change code below to process the `response` object:
// console.log('response is ' + response.result);
}, function(reason) {
console.error('google sheets error: ' + reason.result.error.message);
});
} // end of addLockedEditors
function handleNonRegionEditors() {
debugger;
if (document.getElementById('save-nonRegion') !== null) {
idNonRegionEditors();
} else {
setTimeout(function() {
handleNonRegionEditors();
}, 500);
}
function idNonRegionEditors()
{
var moveIn = [];
var moveOut = [];
var pleaseConfirm = false;
moveOut = [];
moveIn = [];
$.each($("input[class = 'not-home']:not(:checked)"), function() {
// these are editors moving back into SER as primary region
moveIn.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'not-home']:checked"), function() {
// these are editors moving out of the SER as primary region
moveOut.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'home']:checked"), function() {
// these are editors moving out of the SER as their primary region
moveOut.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'home']:not(:checked)"), function() {
moveIn.push($(this).closest('tr').find('td:eq(0)').text()); // these are editors already in or moving back into the SER as their primary region
});
var introText = '';
var moreText = '';
if (moveOut.length > 0 && moveIn.length === 0) {
introText = 'You are about to change the status of editors that edit primarily in the SER. ';
moreText = '';
}
if (moveIn.length > 0 && moveOut.length > 0) {
introText = 'You are about to change the status of editors, indicating additional editors that do not edit primarily in the SER. ';
moreText = 'Additional changes will add editors to the list of those that primarily edit in the SER. '
} else if (moveIn.length > 0 && moveOut.length === 0) {
introText = 'You are about to change the status of editors, indicating additional editors that do not edit primarily in the SER. ';
moreText = '';
}
var finishText = 'Please do not make these changes unless you are absolutely certain of these editors status. Click cancel to remove these changes. '
pleaseConfirm = window.confirm(introText + moreText + finishText);
var blnMatch = false;
if (pleaseConfirm) {
if (moveOut.length > 0) {
//
moveOut.forEach(function(element, index, array)
{
var test = element.trim();
test = test.toLowerCase();
blnMatch = false;
var idx = discordEditors.findIndex(function(element1, index1, array1) {
if (element1.length > 0) {
return element1[0] === test;
} else {
console.log('While setting this editor(' + test + ') as a non-region editor, found this editor does not have the correct sub-array elements');
}
});
if (idx < 0) {
console.log('no match for ' + test + 'while moving this editor outside the region.');
} else {
var testArr = [test, discordEditors[idx][1], true, discordEditors[idx][3]];
// console.log('At moveOut.length >0, removing ' + discordEditors[idx] + ' and adding ' + testArr);
discordEditors.splice(idx, 1, testArr);
}
}); // end of notHomeRegion forEach function
} // end of moveOut.length > 0 if statement
blnMatch = false;
if (moveIn.length > 0) {
moveIn.forEach(function(element, index, array)
// this code runs each time save button depressed even when there is no change in home-region status.
{
var test = element.trim();
test = test.toLowerCase();
blnMatch = false;
var idx = discordEditors.findIndex(function(element1, index1, array1) {
if (element1.length > 0) {
return element1[0] === test;
} else {
console.log('While setting this editor(' + test + ') as a native to this region, this editor does not have the correct sub-array elements');
}
});
if (idx < 0) {
console.log('no match for ' + test);
} else {
var testArr = [test, discordEditors[idx][1], '', discordEditors[idx][3]];
// console.log('At moveIn.length >0, removing ' + discordEditors[idx] + ' and adding ' + testArr);
discordEditors.splice(idx, 1, testArr);
}
}); // end of forEach function
} // end of moveIn.length > 0 if statement
moveOut = [];
moveIn = [];
} else {
$('.not-home').prop('checked', true);
$('.home').prop('checked', false);
// homeRegion = [];
// notHomeRegion = [];
} //end // of if(pleaseConfirm)
} // end of idNonRegionEditors
var valueRangeBody = {
values: discordEditors
};
var params =
{
spreadsheetId: spreadsheetId, //TODO: Update placeholder value.
range: ssRange,
valueInputOption: 'RAW'
};
var request = gapi.client.sheets.spreadsheets.values.update(params, valueRangeBody);
// console.log('here');
request.then(function(response)
{
// TODO: Change code below to process the `response` object:
// console.log('response is ' + response.result);
}, function(reason) {
console.error('google sheets error: ' + reason.result.error.message);
});
} // end of handleNonRegionEditors
function handleAMEditors() {
if (document.getElementById('save-AM') !== null) {
idAMEditors();
} else {
setTimeout(function() {
handleAMEditors();
}, 500);
}
function idAMEditors()
{
var isAM = [];
var notAM = [];
var pleaseConfirm = false;
$.each($("input[class = 'Not-AM']:not(:checked)"), function() {
// these editors are not AMs
notAM.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'Not-AM']:checked"), function() {
// these editors are now SER AMs
isAM.push($(this).closest('tr').find('td:eq(0)').text());
//console.log(isAM);
});
$.each($("input[class = 'is-AM']:checked"), function() {
// these are editors that are already SER AMs
isAM.push($(this).closest('tr').find('td:eq(0)').text());
});
$.each($("input[class = 'is-AM']:not(:checked)"), function() {
notAM.push($(this).closest('tr').find('td:eq(0)').text()); // these are current AMs that are no longer an AM
});
// console.log('notAM: ' + notAM + '. and isAM: ' + isAM);
var introText = '';
var moreText = '';
if (notAM.length > 0 && isAM.length === 0) {
introText = 'You are about to change the status of editors assigned as Area Managers (AM) in the SER. ';
moreText = '';
}
// if (isAM.length > 0 && notAM.length > 0) {
// introText = 'You are about to change the status of editors, indicating additional editors that do not edit primarily in the SER. ';
// moreText = 'Additional changes will add editors to the list of those that primarily edit in the SER. '
// } else if (isAM.length > 0 && notAM.length === 0) {
// introText = 'You are about to change the status of editors, indicating additional editors that do not edit primarily in the SER. ';
// moreText = '';
// }
var finishText = 'Please do not make these changes unless you are absolutely certain of these editors status. Click cancel to remove these changes. '
pleaseConfirm = window.confirm(introText + moreText + finishText);
var blnMatch = false;
if (pleaseConfirm) {
if (notAM.length > 0) {
//
notAM.forEach(function(element, index, array)
{
var test = element.trim();
test = test.toLowerCase();
blnMatch = false;
var idx = discordEditors.findIndex(function(element1, index1, array1) {
if (element1.length > 0) {
return element1[0] === test;
} else {
console.log('While setting this editor(' + test + ') as a non-region editor, found this editor does not have the correct sub-array elements');
}
});
if (idx < 0) {
console.log('no match for ' + test + 'while removing SER AM status.');
} else {
var testArr = [test, discordEditors[idx][1], discordEditors[idx][2], ''];
console.log('At notAM.length >0, editor: ' + discordEditors[idx] + ' changed to not an AM');
discordEditors.splice(idx, 1, testArr);
}
}); // end of notAM forEach function
} // end of notAM.length > 0 if statement
blnMatch = false;
if (isAM.length > 0) {
isAM.forEach(function(element, index, array)
{
var test = element.trim();
test = test.toLowerCase();
blnMatch = false;
var idx = discordEditors.findIndex(function(element1, index1, array1) {
if (element1.length > 0) {
return element1[0] === test;
} else {
console.log('While setting this editor(' + test + ') as an SER AM, this editor does not have the correct sub-array elements');
}
});
if (idx < 0) {
console.log('no match for ' + test);
} else {
var testArr = [test, discordEditors[idx][1], discordEditors[idx][2], true];
// console.log('At isAM.length >0, editor: ' + discordEditors[idx] + ' added as SER AM');
discordEditors.splice(idx, 1, testArr);
}
}); // end of forEach function
} // end of isAM.length > 0 if statement
// console.log('notAM: ' + notAM);
// console.log('is-AM: ' + isAM);
// console.log(discordEditors);
notAM = [];
isAM = [];
} else {
// $('.is-AM').prop('checked', true);
// $('.Not-AM').prop('checked', false);
// homeRegion = [];
// notHomeRegion = [];
} // end // of if(pleaseConfirm)
} // end of idAMEditors
var valueRangeBody = {
values: discordEditors
};
var params =
{
spreadsheetId: spreadsheetId, //TODO: Update placeholder value.
range: ssRange,
valueInputOption: 'RAW'
};
var request = gapi.client.sheets.spreadsheets.values.update(params, valueRangeBody);
// console.log('here');
request.then(function(response)
{
// TODO: Change code below to process the `response` object:
// console.log('response is ' + response.result);
}, function(reason) {
console.error('google sheets error: ' + reason.result.error.message);
});
} // end of handleAMEditors
bootstrap();
})();