Last active
August 29, 2015 14:15
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==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