OSCAR EMR + Greasemonkey = Amazing Customizability

As users, we all gripe about software and how software is "poorly designed" or "hard to use". In practice, there's usually a good reason, whether it's legacy code that can't be easily rewritten, or the simple fact that a single piece of software needs to meet the needs of diverse individuals with different requirements.

Accordingly, one of the advantages of OSCAR EMR, the electronic medical record system that we've selected as a platform for our organization, is that it is highly customizable and so we can adapt it to meet our organization's unique needs.  (This is not to say that we're the only organization with unique needs - the fundamental issue is that every organization will have unique needs and the challenge when it comes to procuring software is finding the right software for you.)

One particular advantageous aspect of OSCAR is that it is built as a web application, and as a result, common web tools can be used to adapt and customize OSCAR.  One particular tool is called Greasemonkey - a Firefox extension that enables users to dynamically insert javascript into webpages.  A whole slew of scripts have already been developed by OSCAR community members, but we've been writing a few of our own to resolve certain issues that our physicians or staff complain about.  Hopefully the below can help other OSCAR users down the road, whether as inspiration, or as a starting point for your own scripts.  There may be errors though we warn; everything remains a work in progress and we are constantly revising.

  • Resizing most windows to a consistent spot in the screen.  For example, the echart is automatically moved and resized to the right half of the screen, whereas eforms, consults, ticklers, forms, preventions, Rxs, etc... are moved/resized to the left half of the screen.  Just adapt the code below as required.
if (url.indexOf('labDisplay.jsp') != - 1) {
window.moveTo(0, 0);
window.resizeTo(screen.width / 2, screen.height - 40);
}
  • Making more of the patient's name show up in the scheduling screen.   Our receptionists were having trouble because the patient's name was being truncated
if (url.indexOf('provider/providercontrol.jsp') != - 1) {

var links = document.evaluate("//a[contains(@class,'apptLink')]",document,null,XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,null);

for (var j =0 ;j < links.snapshotLength; j++){

var thisLink = links.snapshotItem(j);

thisLink.innerHTML = thisLink.title.split("reason:")[0].trim();

}

}
  • Making it so that when the "tickler" link is clicked from the calendar view, a report of the user's ticklers is automatically run
//changing tickler link so that providerNum is passed in when tickler link clicked
if (url.indexOf('provider/providercontrol.jsp') != - 1) {
var tareas = document.getElementsByTagName('a'); 
var providerNum;
for (var i = 0;i <tareas.length; i++){ 
if (tareas[i].title=="View lab reports"){
var onclickValue = tareas[i].getAttribute('onclick');
 providerNum = onclickValue.substr(79,3); 
}
}

for (var i = 0;i <tareas.length; i++){ 
if (tareas[i].title=="Tickler"){
var onclickValue = tareas[i].getAttribute('onclick');
var split = onclickValue.split(',');
var newStr = split[0].substring(0,38) + "?customProviderNum=" + providerNum + "'," +split[1]; 
tareas[i].setAttribute('onclick',newStr);
}
}
}

//automatically running report of relevant ticklers
if (url.indexOf('Oscar12_1/tickler/ticklerMain.jsp?customProviderNum') != - 1) { 
var provider = getUrlParameters("customProviderNum","",true);
if (provider){ 
 var assignedTo = document.getElementsByName('assignedTo')[0];
 for (var i=0; i<assignedTo.length; i++){
if (assignedTo.options[i].value == provider){
 assignedTo.selectedIndex = i;
}
 }
 eval("document.forms['serviceform'].Submit.value='Create Report'; document.forms['serviceform'].submit();");
} 
}
  • changing the functionality of the ticklers in the echart so that a) if viewTicklers is clicked, a report of all completed ticklers is displayed, and b) if a particular active tickler is clicked, then the corresponding tickler in editable form is opened.

//echart to rewrite the tickler links
if (url.indexOf('Oscar12_1/casemgmt/forward.jsp') != -1){
setTimeout(redirectTicklers,3000);
}

//to simulate clicking on correct tickler edit button if certain parameters passed
if (url.indexOf('CustomTicklerTitle') != -1 && url.indexOf('tickler/ticklerMain.jsp') != -1){ 
var pN = getUrlParameters("CustomPatientName","",true);
var tT = getUrlParameters("CustomTicklerTitle","",true); 
var trs = document.getElementById('sortableTable0').getElementsByTagName('tr'); 

for (var i= 0;i < trs.length; i++){
if (trs[i].textContent.indexOf(pN.split(", ")[0] + "," + pN.split(", ")[1])!=-1 && trs[i].textContent.indexOf(tT) != -1){
var tds = trs[i].getElementsByTagName('td');
tds[1].childNodes[0].click();
window.close();
}
}
}

//to delete all ticklers except for those related to a particular patient
if (url.indexOf('CustomShowAllForPatient') != -1 && url.indexOf('tickler/ticklerMain.jsp') != -1){
var mainPatientName = getUrlParameters("CustomShowAllForPatient","",true);
var trs = document.getElementById('sortableTable0').getElementsByTagName('tr'); 
var markDelete = new Array(trs.length);
var mostRecentPatientName = "";
for (var i= 2;i < trs.length; i++){if (trs[i].childNodes[1].childNodes.length > 0){mostRecentPatientName = trs[i].childNodes[5].textContent.trim(); } 
if (mostRecentPatientName.indexOf(mainPatientName.split(", ")[0] + "," + mainPatientName.split(", ")[1])==-1){ 
 markDelete[i] = true;
}else {
markDelete[i] = false;
}
markDelete[0] = false;
markDelete[1] = false;
} 
for (i = trs.length-1; i>=2; i--){
if (markDelete[i]){
trs[i].parentElement.removeChild(trs[i]);
}
}
}

function redirectTicklers(){
var tareas = document.getElementsByTagName('a'); 
var patientName;
for (var i = 0;i <tareas.length; i++){ 
var title = tareas[i].title;
if (title == "Master File"){ 
 patientName = tareas[i].textContent;
i = tareas.length;
}
}

for ( i = 0;i <tareas.length; i++){ 
var onclickvalue = tareas[i].getAttribute('onclick'); 
var ticklerTitle;
var ticklerDate; 
if (onclickvalue != null){
 if (onclickvalue.indexOf("ticklerDemoMain") != -1 && onclickvalue.indexOf("ViewTickler") == -1){ 
 var ticklerTitle = tareas[i].title.split("...")[0].trim(); 
 var ticklerDate = tareas[i].title.split("...")[1].trim(); 
var newStr = "window.open('../tickler/ticklerMain.jsp?xml_vdate=1900-01-01&xml_appointment_date=8888-12-31&ticklerview=A&mrpview=all&providerview=all&assignedTo=all&Submit=Create+Report";
newStr += "&CustomPatientName=" +encodeURIComponent(patientName);
newStr += "&CustomTicklerTitle=" +encodeURIComponent(ticklerTitle);
newStr += "&CustomTicklerDate=" +encodeURIComponent(ticklerDate);
newStr += "','MagentaCustom','height=100,width=100');return false;"; 
tareas[i].setAttribute('onclick',newStr);
} else if (onclickvalue.indexOf("ticklerDemoMain") != -1 && onclickvalue.indexOf("ViewTickler") != -1){ 
var newStr = "window.open('../tickler/ticklerMain.jsp?xml_vdate=1900-01-01&xml_appointment_date=8888-12-31&ticklerview=C&mrpview=all&providerview=all&assignedTo=all&Submit=Create+Report";
newStr += "&CustomShowAllForPatient=" +encodeURIComponent(patientName);
newStr += "','MagentaCustom2','height=100,width=100');return false;"; 
tareas[i].setAttribute('onclick',newStr);
}
}
}
}
//helper function
function getUrlParameters(parameter, staticURL, decode){
 /*
Function: getUrlParameters
Description: Get the value of URL parameters either from
 current URL or static URL
Author: Tirumal
URL: www.code-tricks.com
 */

 var currLocation = (staticURL.length)? staticURL : window.location.search,
 parArr = currLocation.split("?")[1].split("&"),
 returnBool = true;

 for(var i = 0; i < parArr.length; i++){
parr = parArr[i].split("=");
if(parr[0] == parameter){
return (decode) ? decodeURIComponent(parr[1]) : parr[1];
returnBool = true;
}else{
returnBool = false; 
}
 }
 if(!returnBool) return false; 
}