Skip to content

Instantly share code, notes, and snippets.

@se7ensoft
Last active August 29, 2015 14:15
Show Gist options
  • Save se7ensoft/398a56b9f9a13479e894 to your computer and use it in GitHub Desktop.
Save se7ensoft/398a56b9f9a13479e894 to your computer and use it in GitHub Desktop.
Makes the new "features", on oDesk, easier to cope with. Also, adds a few extra things just to enhance usability of the site.
// ==UserScript==
// @name oDesk Site Patch
// @namespace http://se7en-soft.com
// @author Scott Michaels : scott@se7en-soft.com
// @description Makes oDesk just a little bit easier to use.
// @include https://*.odesk.com/jobs/*
// @include https://*.odesk.com/d/home*
// @include https://*.odesk.com/d/contracts*
// @include https://*.odesk.com/earnings-history*
// @include https://*.odesk.com/find-work-home/*
// @include https://*.odesk.com/reports/in-progress*
// @include https://*.odesk.com/reports/in-review*
// @include https://*.odesk.com/reports/pending*
// @include https://*.odesk.com/reports/available*
// @created 02/20/2015
// @modified 02/21/2015
// @version 1.0.7
// @grant metadata
// ==/UserScript==
/***********************************************************************
This script is provided 'As-Is'.
I am not responsible for any negative consequences
that may arise from the use of this script.
***********************************************************************/
const oDeskFee = 0.1; //10% fee that oDesk charges.
var oDeskTransactionTypes = Object.freeze({
Bonus: "Bonus",
FixPrice: "Fixed Price",
Hourly: "Hourly",
Refund: "Refund",
SvcFee: "Service Fee",
Withdrawal: "Withdrawal",
Unknown: "",
GetType : function(input){
input = input.toLowerCase();
if(input == this.Bonus.toLowerCase())
return this.Bonus;
if(input == this.FixPrice.toLowerCase())
return this.FixPrice;
if(input == this.Hourly.toLowerCase())
return this.Hourly;
if(input == this.Refund.toLowerCase())
return this.Refund;
if(input == this.SvcFee.toLowerCase())
return this.SvcFee;
if(input == this.Withdrawal.toLowerCase())
return this.Withdrawal;
return this.Unknown;
}
});
//This is a "transaction", as appears on in the Transaction History table in your earnings history.
function oDeskTransaction() {}
oDeskTransaction.prototype = {
TransactionType: oDeskTransactionTypes.Unknown,
TransactionRow: null,
SetRowVisibility : function(visible){
if(visible)
this.TransactionRow.style.display = "table-row";
else
this.TransactionRow.style.display = "none";
},
AdjustAmount : function(){
var cells = this.TransactionRow.querySelectorAll("td");
var date = Date.parse(cells[0].textContent.trim());
var beginDate = Date.parse("February 10, 2015");
if(date < beginDate)
return;
var amountText = cells[4].textContent.trim();
var currencySymbol = amountText[0];
var amount = parseFloat(amountText.substring(1));
amount = (amount - (amount * oDeskFee)).toFixed(2);
try{
if(amount.toString() != "NaN")
cells[4].textContent = currencySymbol + amount;
} catch(e){
}
if(this.TransactionType == oDeskTransactionTypes.Hourly){
var cell = cells[2];
var content = cell.textContent.trim();
var atIdx = content.lastIndexOf("@");
amountText = content.substring(atIdx + 1).replace("/hr", "").trim();
currencySymbol = amountText[0];
amount = parseFloat(amountText.substring(1));
amount = (amount - (amount * oDeskFee)).toFixed(2);
var nAmountText = currencySymbol + amount;
content = content.replace(amountText, nAmountText);
cell.textContent = content;
} else if (this.TransactionType == oDeskTransactionTypes.Withdrawal){
var cell = cells[4];
var content = cell.textContent.replace('(', '').replace(')', '').trim();
currencySymbol = content[0];
amount = parseFloat(content.substring(1));
amount = (amount - (amount * oDeskFee)).toFixed(2);
cell.textContent = "(" + currencySymbol + amount + ")";
}
}
};
//Primary 'class' object.
var ODeskFixer = {
//Reorders "Recommended Jobs" to in a time-ordered list.
ReorderRecommendedJobs : function(){
var jobResults = document.getElementById("jsJobResults");
var articleArray = [];
if(jobResults){
var articles = jobResults.getElementsByTagName("article");
if(articles){
for(var i = 0; i < articles.length; i++){
var article = articles[i];
var supportInfo = article.querySelector("div.oSupportInfo");
if(supportInfo){
var jsAutoRelativeTime = supportInfo.querySelector("span.jsPosted span.jsAutoRelativeTime");
if(jsAutoRelativeTime){
var timeStamp = jsAutoRelativeTime.getAttribute("data-timestamp");
if(timeStamp){
try{
var ts = parseInt(timeStamp);
var dt = new Date(ts*1000);
var day = parseInt(dt.getDay());
if(day <= 4)
articleArray.push([article, timeStamp]);
} catch(e){
//alert(e);
}
}
}
}
}
}
}
if(articleArray.length){
articleArray.sort(function(a, b){
if(a[1] > b[1])
return -1;
if(a[1] < b[1])
return 1;
return 0;
});
while(jobResults.childNodes.length)
jobResults.removeChild(jobResults.firstChild);
for(var i = 0; i < articleArray.length; i++)
jobResults.appendChild(articleArray[i][0]);
}
},
//Fixes the oDesk web site header so that it remains at the top of the
//page and content can scroll under it.
FixHeader : function(){
var header = document.getElementsByClassName("oHeader")[0];
if(header != null){
header.style.position = "fixed";
header.style.width = "100%";
header.style.zIndex = 10001;
var main = document.getElementById("main");
if(main != null)
main.style.paddingTop = (header.clientHeight + 30) + "px";
}
},
//Fixes project search result links so that they open in a new tab.
FixProjectLinks : function(){
var resultLinks = document.getElementsByClassName('oVisitedLink');
for(var i = 0; i < resultLinks.length; i++)
{
var lnk = resultLinks[i];
if(lnk.getAttribute('onclick') == undefined)
lnk.setAttribute('onclick',"window.open('" + lnk.href + "');return false;");
}
},
//Fixes amounts for both hourly and fixed projects.
FixMyJobs : function(){
var hourlyContractsDiv = document.getElementById("hourlyContracts");
var fixedPriceContractsDiv = document.getElementById("fixedPriceContracts");
if(hourlyContractsDiv){
var contractRows = hourlyContractsDiv.querySelectorAll("tr");
var contractsCount = contractRows.length;
//fixup numbers for contract jobs.
if(contractsCount != 0){
for(var i = 0; i < contractsCount; i++){
var row = contractRows[i];
var txtRight = row.getElementsByClassName("txtRight")[0];
if(txtRight){
var oMute = txtRight.getElementsByClassName("oMute")[0];
if(oMute){
var mText = oMute.textContent.trim();
var parts = mText.split('=');
var currencySymbol = parts[0][1];
var perHour = parseFloat(parts[0].split('/')[0].trim().substring(2));
var total = parseFloat(parts[1].trim().substring(1));
var tenPercent = (perHour * oDeskFee).toFixed(2);
var realPerHour = perHour - tenPercent;
var realTotal = total > 0.00 ? (total - tenPercent) : total;
var addPerHourZeros = false;
var addTotalZeros = false;
if(realPerHour.toString().indexOf(".") == -1)
addPerHourZeros = true;
if(realTotal.toString().indexOf(".") == -1)
addTotalZeros = true;
var span = document.createElement("span");
span.style.float = "right";
var content = "@" + currencySymbol + realPerHour + (addPerHourZeros ? ".00" : "") + "/hr = " + currencySymbol + realTotal + (addTotalZeros ? ".00" : "");
span.textContent = content;
oMute.textContent = "";
oMute.appendChild(span);
}
}
}
}
}
//fixup numbers for fixed prices jobs.
if(fixedPriceContractsDiv){
var fpjRows = fixedPriceContractsDiv.getElementsByClassName("jsFixedPriceTile");
var rowLength = fpjRows.length;
if(rowLength != 0){
for(var i = 0; i < rowLength; i++){
var row = fpjRows[i];
var txtRight = row.getElementsByClassName("txtRight")[0];
if(txtRight){
var div = txtRight.querySelector("div.nowrap");
var strongElm = div.querySelector("strong.oTxtMed");
var currencySymbol;
var strongHtml;
var content = strongElm.textContent.trim();
currencySymbol = content.substring(0, 1);
var strongValue = parseFloat(strongElm.textContent.trim().substring(1));
strongValue = (strongValue - (strongValue * oDeskFee)).toFixed(2);
strongElm.textContent = currencySymbol + strongValue;
strongHtml = strongElm.outerHTML;
var divContent = div.textContent.trim();
var idx = divContent.indexOf(" ");
var lidx = divContent.lastIndexOf(" ");
var paidOf = divContent.substring(idx, lidx).trim();
var payTotal = parseFloat(divContent.substring(lidx).trim().substring(1));
payTotal = (payTotal - (payTotal * oDeskFee)).toFixed(2);
var newContent = strongHtml + " " + paidOf + " " + currencySymbol + payTotal;
div.innerHTML = newContent;
}
}
}
}
},
//Fixes the Transaction History table to reflect monetary amounts as expected by the freelancer.
FixTransactionHistory : function(){
////////////////////////////////////////////////////////////////
// We don't owe oDesk anything, fix this shit up...
////////////////////////////////////////////////////////////////
var oNeg = document.getElementsByClassName("oNeg")[0];
if(oNeg){
var curSym = oNeg.textContent.trim()[1];
oNeg.textContent = curSym + "0.00";
oNeg.style.color = "black";
}
////////////////////////////////////////////////////////////////
var sIdx = document.getElementById("jumpTo").selectedIndex;
if(sIdx <= 0 || sIdx > 4)
return;
var trxTable = document.getElementById("trxTable");
var tableRows = trxTable.querySelectorAll("tr");
var rowCount = tableRows.length;
var transactionRows = [];
if(rowCount > 0){
for(var i = 0; i < rowCount; i++){
var row = tableRows[i];
var cells = row.querySelectorAll("td");
if(cells.length > 0){
var cellContent = cells[1].textContent.trim();
try{
var txn = new oDeskTransaction();
txn.TransactionType = oDeskTransactionTypes.GetType(cellContent);
txn.TransactionRow = row;
} catch (e){
alert(e);
}
transactionRows.push(txn);
}
}
var firstHiddenTransaction, firstVisibleTransaction,
transactionCount = transactionRows.length;
for(var i = 0; i < transactionCount; i++){
var transaction = transactionRows[i];
if(transaction.TransactionType == oDeskTransactionTypes.SvcFee){
if(firstHiddenTransaction == null)
firstHiddenTransaction = transaction;
transaction.SetRowVisibility(false);
}
else {
if(firstVisibleTransaction == null)
firstVisibleTransaction = transaction;
transaction.AdjustAmount();
}
}
if(firstHiddenTransaction && firstVisibleTransaction){
firstHiddenTransaction.TransactionRow.innerHTML = firstVisibleTransaction.TransactionRow.innerHTML;
firstVisibleTransaction.SetRowVisibility(false);
firstHiddenTransaction.SetRowVisibility(true);
}
}
var oTableLite = document.getElementsByClassName("oTableLite")[0];
if(oTableLite){
var rows = oTableLite.querySelectorAll("tr");
var rowCount = rows.length;
for(var i = 0; i < rowCount; i++){
var cells = rows[i].querySelectorAll("td");
var cellCount = cells.length;
for(var j = 0; j < cellCount; j++){
if(j%2 != 0){
var cell = cells[j];
var content = cell.textContent.trim();
if(content.indexOf("(") == -1){
var currencySymbol = content[0];
var amtContent = content.substring(1);
while(amtContent.indexOf(',') != -1)
amtContent = amtContent.replace(',', '');
var amount = parseFloat(amtContent);
if(amount > 0.00){
amount = (amount - (amount * oDeskFee)).toFixed(2);
cell.textContent = currencySymbol + amount;
}
} else {
//we don't owe oDesk anything.. make this zero.
var curSym = content[1];
cell.textContent = curSym + "0.00";
}
}
}
}
}
},
//Fixes the Work In Progress tab to show amounts as expected by the freelancer.
FixReport_WorkInProgress : function(){
var timeSheetTable = document.getElementsByClassName("oTableTimesheet")[0];
if(timeSheetTable){
var rows = timeSheetTable.querySelectorAll("tr");
var rowCount = rows.length;
for(var i = 0; i < rowCount; i++){
var row = rows[i];
var cells = row.querySelectorAll("td");
if(cells.length == 0) continue;
var opCells = [];
opCells.push(cells[cells.length - 2]);
opCells.push(cells[cells.length - 1]);
var isSumRow = row.classList.contains("oSumRow");
for(var j = 0; j < opCells.length; j++){
var cell = opCells[j];
var content = cell.textContent.trim();
var currencySymbol = content[0];
var amountText = content.substring(1);
while(amountText.indexOf(",") != -1)
amountText = amountText.replace(",", "");
var isHourly = amountText.indexOf("/hr") != -1;
if(isHourly)
amountText = amountText.substring(0, amountText.indexOf("/hr"));
var amount = parseFloat(amountText);
amount = (amount - (amount * oDeskFee)).toFixed(2);
if(!isSumRow){
amountText = currencySymbol + amount + (isHourly ? "/hr" : "");
cell.textContent = amountText;
} else {
var oHelpDot;
var firstIndex = j == 0;
if(firstIndex){
oHelpDot = row.querySelector("td.txtCenter span.oHelpDot");
oHelpDot.parentNode.removeChild(oHelpDot);
}
amountText = currencySymbol + amount + (isHourly ? "/hr" : "");
cell.textContent = amountText;
if(firstIndex)
cell.appendChild(oHelpDot);
}
}
}
}
},
//Fixes monetary amounds in the In Review tab to show them as the freelancer expects.
FixReport_InReview : function(){
var timeSheetTable = document.getElementsByClassName("oTableTimesheet")[0];
var oTableFixedPrice = document.getElementsByClassName("oTableFixedPrice")[0];
var tables = [];
if(timeSheetTable)
tables.push(timeSheetTable);
if(oTableFixedPrice)
tables.push(oTableFixedPrice);
for(var n = 0; n < tables.length; n++){
var table = tables[n];
var rows = table.querySelectorAll("tr");
var rowCount = rows.length;
for(var i = 0; i < rowCount; i++){
var row = rows[i];
var cells = row.querySelectorAll("td");
if(cells.length == 0) continue;
var opCells = [];
if(n > 0)
opCells.push(cells[cells.length - 2]);
opCells.push(cells[cells.length - 1]);
var isSumRow = row.classList.contains("oSumRow");
for(var j = 0; j < opCells.length; j++){
var cell = opCells[j];
var content = cell.textContent.trim();
var currencySymbol = content[0];
var amountText = content.substring(1);
while(amountText.indexOf(",") != -1)
amountText = amountText.replace(",", "");
var isHourly = amountText.indexOf("/hr") != -1;
if(isHourly)
amountText = amountText.substring(0, amountText.indexOf("/hr"));
var amount = parseFloat(amountText);
amount = (amount - (amount * oDeskFee)).toFixed(2);
if(!isSumRow){
amountText = currencySymbol + amount + (isHourly ? "/hr" : "");
cell.textContent = amountText;
} else {
amountText = currencySymbol + amount + (isHourly ? "/hr" : "");
cell.textContent = amountText;
}
}
}
}
},
//Fixes the Pending tab to reflect amounts in the way freelancers expect.
FixReport_Pending : function(){
var timeSheetTable = document.getElementsByClassName("oTableTimesheet")[0];
var fixedPricetable = document.getElementsByClassName("oTableFixedPrice")[0];
var tables = [];
if(timeSheetTable)
tables.push(timeSheetTable);
if(fixedPricetable)
tables.push(fixedPricetable);
for(var i = 0; i < tables.length; i++){
var table = tables[i];
var rows = table.querySelectorAll("tr");
var rowCount = rows.length;
var isTimesheetTable = table.classList.contains("oTableTimesheet");
var isFixedPriceTable = table.classList.contains("oTableFixedPrice");
for(var rc = 0; rc < rowCount; rc++){
var row = rows[rc];
var cells = row.querySelectorAll("td");
if(cells.length == 0) continue;
var opCells = [];
var isSumRow = row.classList.contains("oSumRow");
if(isTimesheetTable){
opCells.push(cells[cells.length - 2]);
opCells.push(cells[cells.length - 1]);
} else if (isFixedPriceTable){
opCells.push(cells[cells.length - 1]);
}
for(var j = 0; j < opCells.length; j++){
var cell = opCells[j];
var content = cell.textContent.trim();
var currencySymbol = content[0];
var amountText = content.substring(1);
while(amountText.indexOf(",") != -1)
amountText = amountText.replace(",", "");
var isHourly = amountText.indexOf("/hr") != -1;
if(isHourly)
amountText = amountText.substring(0, amountText.indexOf("/hr"));
var amount = parseFloat(amountText);
amount = (amount - (amount * oDeskFee)).toFixed(2);
if(!isSumRow){
amountText = currencySymbol + amount + (isHourly ? "/hr" : "");
cell.textContent = amountText;
} else {
var oHelpDot;
var firstIndex = j == 0;
if(firstIndex){
oHelpDot = row.querySelector("td.txtCenter span.oHelpDot");
if(oHelpDot)
oHelpDot.parentNode.removeChild(oHelpDot);
}
amountText = currencySymbol + amount + (isHourly ? "/hr" : "");
cell.textContent = amountText;
if(firstIndex && oHelpDot)
cell.appendChild(oHelpDot);
}
}
}
}
},
//Fixes tab headers to appear properly for freelancers.
FixReport_PatchTabHeaders : function(){
var main = document.getElementById("main");
var oDataNavDatas = main.querySelectorAll("ul li a span.oDataNavData");
var navLength = oDataNavDatas.length;
for(var i = 0; i < navLength; i++){
if(i >= navLength-2)
continue;
var oDataNavData = oDataNavDatas[i];
var content = oDataNavData.textContent.trim();
var currencySymbol = content[0];
var amountText = content.substring(1);
while(amountText.indexOf(",") != -1)
amountText = amountText.replace(",", "");
var amount = parseFloat(amountText);
amount = (amount - (amount * oDeskFee)).toFixed(2);
oDataNavData.textContent = currencySymbol + amount;
}
},
FixContracts : function(){
var lister = document.getElementById("contractsListerTable");
if(lister){
var rows = lister.querySelectorAll("tr");
var rowCount = rows.length;
for(var i = 0; i < rowCount; i++){
var row = rows[i];
var cells = row.querySelectorAll("td");
if(cells.length == 0) continue;
var priceCell = cells[2];
var div = priceCell.firstChild;
var content = div.textContent.trim();
var isFixedJob = content.indexOf(" fixed") != -1;
var amountText = isFixedJob ? content.split(" ")[0] : content.substring(0, content.indexOf('/'));
var currencySymbol = amountText[0];
var amtStr = amountText;
while(amtStr.indexOf(",") != -1)
amtStr = amtStr.replace(",", "");
var amount = parseFloat(amtStr.substring(1));
amount = (amount - (amount * oDeskFee)).toFixed(2);
div.textContent = div.textContent.replace(amountText, (currencySymbol + amount));
}
}
},
};
(function(){
var pathPart = document.location.pathname;
setInterval(ODeskFixer.FixHeader, 10);
if(pathPart.indexOf("/find-work-home/") != -1)
setTimeout(function(){ ODeskFixer.ReorderRecommendedJobs(); }, 10);
if(pathPart.indexOf("/jobs/") != -1)
setInterval(ODeskFixer.FixProjectLinks, 1500);
if(pathPart.indexOf("/d/home") != -1)
setTimeout(function(){ ODeskFixer.FixMyJobs(); }, 10);
if(pathPart.indexOf("/d/contracts") != -1)
setTimeout(function(){ ODeskFixer.FixContracts(); }, 1500);
if(pathPart.indexOf("/earnings-history") != -1)
setTimeout(function(){ ODeskFixer.FixTransactionHistory(); }, 10);
if(pathPart.indexOf("/reports/") != -1){
setTimeout(function(){ ODeskFixer.FixReport_PatchTabHeaders(); }, 10);
if(pathPart.indexOf("/in-progress") != -1)
setTimeout(function(){ ODeskFixer.FixReport_WorkInProgress(); }, 10);
else if (pathPart.indexOf("/in-review") != -1)
setTimeout(function(){ ODeskFixer.FixReport_InReview(); }, 10);
else if (pathPart.indexOf("/pending") != -1) {
setTimeout(function(){ ODeskFixer.FixReport_Pending(); }, 10);
}
}
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment