Search the OSCAR Documentation
< All Topics
Print

eForm From Scratch/Tweaking eForm Programming Tips

Share this

Documentation Copyright © 2024 by Adrian Starzynski under the Creative Commons Attribution-Share Alike 3.0 Unported License

The purpose of this article is to give you a “copy and paste” tool to make your own eForms the advanced manual method (the easier and method is to use OSCAR’s built-in eForm generator). If you want to learn more advanced stuff, check out online tutorials such as W3 Schools.

Need to order an eForm to be created? Need help with programming? Custom RTL Templates? Need OSCAR help? Contact us

Basics

eForms are programmed using html and javascript. There are countless online resources for ways to tweak your eForms.

Here’s the basic skeleton of a webpage:

<html>
<head>
<title> </title>

</head>
<body>

</body>
</html>

Copy and paste the above into a text editor such as Visual Studio Coded (the author of this article recommends this program).

Save the file as “filename.html”. Make sure you select “all files” under the “save as type”.

Everything is enclosed between an “opening tag” that look like <tag> and a “closing tag” that looks like </tag>.

The <html></html> tells the browser that it’s an html file, aka a webpage.

The <head></head> contains extra information that is useful for displaying the page

You can put in a title between the <title></title>, and it’ll show up in the title bar

All the code inside the <body></body> are the actual contents that you get to see in the browser.

Make sure you don’t overlap different opening and closing tags. For example,
<tag1> <tag2></tag2> </tag1> is ok, but
<tag1> <tag2> </tag1> </tag2> is not ok.

Inserting the eForm image file

The best way to get the eForm image file is to get it in electronic form – .docx, pdf, png, or jpg/jpeg. It is very bad to scan a paper copy and use that for your eForm – that will have the paper’s fold marks/shading visible on print/fax, will waste more printer ink and will be less visible. 90% of the time a quick Google search for the form you are converting into an eForm will result in a PDF file of the organization. For example, most hospitals and larger have a referral forms directory on their websites which will provide you with a PDF of the form. If you have a Word document file of the referral form, it can easily be exported to PDF.

This PDF needs to be converted to a png or jpg file for it to be used in an OSCAR eForm. There are many ways to convert PDF to image file but I personally use https://pdf2jpg.net/ which is quick and doesn’t require any complex converter software download. Here is an older presentation on preparing eForm image files which may come in handy.

After you’ve converted your PDF to image file, you need to reference it in the eForm like this:

Now, it’s time to put in the image file:

<div style="position: absolute; left: 10px; top: 10px;" >
	<img src="${oscar_image_path}imagename.png" width="750">
</div>
<!-- You can remove ${oscar_image_path} as you develop the eForm, but make sure you put it back before uploading to OSCAR otherwise the image wouldn't show. -->
<!-- Also note: the image filename IS CASE SENSITIVE INCLUDING THE EXTENSION. It may work otherwise in Windows, but not in OSCAR because it's based on a Linux platform -->

Copy the above and paste between the <body> and </body>

Make sure you put the image file and the html file in the same folder while you’re editing the eForm

Temporarily delete the ${oscar_image_path} inside the <img> tag if you’re editing the file locally. You’ll need to put it back in after you upload it onto OSCAR.

Note: I find that having an image with a width of 750 pixels fits a letter-sized paper the best. I usually prepare the image file so that it’s 1500 pixels wide, so that it scales down by 50% in the browser.

Inserting the ‘form’ element

<form method="post" action="" name="FormName">
<!--  put all the form inputs here-->


<div class="DoNotPrint" style="position: absolute; top: 1000px; left: 10px;">
<table>
	<tr>
		<td>
			Subject: <input name="subject" size="40" type="text">
			<input value="Submit" name="SubmitButton" type="submit">
			<input value="Reset" name="ResetButton" type="reset">
			<input value="Print" name="PrintButton" type="button" onclick="window.print()">
		</td>
	</tr>
</table>
</div>
</form>

Copy the above and paste between the <body> and </body>

You can customize the position of the submit buttons by changing the numbers in blue

Install the tools to help with placement of the input boxes

Copy above and paste between <head></head>

This script will give you the mouse coordinates in the titlebar, so you can find out where to put the input boxes

I simply delete the above script when I’m done with putting in the input boxes.

<!-- SCRIPT GIVES THE MOUSE COORDINATES - Hold SHIFT and click two points for distance between -->
<script type="text/javascript" language="javascript">
var isIE = document.all?true:false;
if (!isIE) document.captureEvents(Event.MOUSEMOVE);
document.onmousemove = getMousePosition;
document.onclick = captureposition;
var capX = 0;
var capY = 0;
var sy = 0;
var sx = 0;

function getMousePosition(e) {
var _x;
var _y;
if (!isIE) {
_x = e.pageX;
_y = e.pageY;
}
  document.title = _x + " " + _y;
  return true;
}
function captureposition(e) {

  if (e.shiftKey) {
     if ((capX == 0) && (capY == 0)) {
        capX = e.pageX;
        capY = e.pageY;
     } else {
        var diffX = e.pageX-capX;
        var diffY = e.pageY-capY;
        if (Math.abs(diffX) > Math.abs(diffY)) {
            alert('X-coordinate distance: ' + diffX + 'px');
        } else {
            alert('Y-coordinate distance: ' + diffY + 'px');
        }
        capX = 0;
        capY = 0;
     }
   }
}
</script>
<!-- ----------End coordinate script--------------------------------------------------------- -->

Manual Field Alignment Refresh

If you add the following code <meta http-equiv=”refresh” content=”3″> near the top of your eForm, you will force the page to auto-refresh every 3 seconds. Now you can manually tweak the left and top pixel values, save the changes and view the result in a few seconds. Make sure you remove the line after you finish making your changes.

The Inputs

Rules:

  • Each input needs a name. If not, the contents of the input won’t be saved and/or won’t display on print!
  • Each input name has to be unique
  • The input name cannot contain spaces or symbols
  • Only inputs with type=”checkbox”, “radio”, and “text” get saved when you submit the eForm (OSCAR won’t save type=”date” or type=”number” etc.)

Single-line text input

<div style="position: absolute; left: 100px; top: 100px;"> 
	<input name="SingleLineInputName" type="text" class="noborder" style="width: 100px;">
</div>

Copy above and paste under the <!– put all the form inputs here–> inside the <form></form>.

Move your mouse to the top left corner of the form input box and note the x and y coordinate. Substitute these numbers into the “left: Xpx” and the “top: Ypx;”.

Move your mouse to the left edge of the form input box, press-and-hold the shift key, click on the left edge then click on the right edge of the input box. A pop-up box will come up showing you the width of the box. Input this number into the “width: Wpx;”.

Multi-line text input

<div style="position: absolute; left: 100px; top:100px;"> 
	<textarea name="MultiLineInputName" class="noborder" style="width:100px; height:100px;"></textarea>
</div>

Again, you’ll have to customize the “left:”, “top:”, “width:”, and “height:” numbers to the form.

Checkboxes

<div style="position: absolute; left: 100px; top: 100px;">
        <input name="CheckboxName" type="checkbox">
</div>

The actual X and Y coordinates of the checkboxes are somehow about 4 pixels less than the indicated numbers

X-Box

The X-Box is a replacement for the checkbox. Instead of a checkmark, we use a black outline with an X. If your xBox has 2 exclusive choices, such as [ ] Yes or [ ] No, you can use the following code to only allow a single choice:

<input name="FldNameY" id="FldNameY" type="text" class="Xbox" style="position:absolute; left:382px; top:580px; width:12px; height:12px;" onkeypress="javascript:return displayKeyCode(event,this.id);" onClick="document.FormName.FldNameN.value='';">
<input name="FldNameN" id="FldNameN" type="text" class="Xbox" style="position:absolute; left:435px; top:580px; width:12px; height:12px;" onkeypress="javascript:return displayKeyCode(event,this.id);" onClick="document.FormName.FldNameY.value='';">

Radio Buttons

<div style="position: absolute; left: 100px; top: 100px;">
        <input name="RadioName" type="radio" value="value1">
</div>
<div style="position: absolute; left: 100px; top: 110px;">
        <input name="RadioName" type="radio" value="value2">
</div>

The actual X and Y coordinates of the checkboxes are somehow about 4 pixels less than the indicated numbers

Auto-populating input fields from the OSCAR database

A list of database info that you can auto-populate into eForms can be found here.

To use these, just put the oscarDB=xxxx inside the input tag. I usually put it right before the closing “>”.

For Example, the following will auto-populate the textarea with the clinic label.

<div style="position: absolute; left: 100px; top:100px;"> 
	<textarea name="MultiLineInputName" class="noborder" style="width:100px; height:100px;" oscarDB=clinic_label></textarea>
</div>

Please note that you DON’T need the quotes around the oscarDB database tag.

Some of the things you’ll need to do to make the eForm print properly

You probably don’t want to print out some of the things on the screen such as the border around the input boxes and the submit/print buttons at the bottom.

To take these away:

1. Copy the following and paste it into the between the <head> and </head>

<style type="text/css" media="print">
<!-- CSS Script that removes the whole division when printing -->
.DoNotPrint {
	display: none;
}
<!-- CSS Script that removes textarea and textbox borders when printing -->
.noborder {
	border : 0px;
	background: transparent;
	scrollbar-3dlight-color: transparent;
	scrollbar-3dlight-color: transparent;
	scrollbar-arrow-color: transparent;
	scrollbar-base-color: transparent;
	scrollbar-darkshadow-color: transparent;
	scrollbar-face-color: transparent;
	scrollbar-highlight-color: transparent;
	scrollbar-shadow-color: transparent;
	scrollbar-track-color: transparent;
	background: transparent;
	overflow: hidden;
}
</style>

2. To remove a whole division (i.e. everything between a <DIV> and </DIV>) when printing, add class=”DoNotPrint” as an attribute in the opening tag of <div>. For example:

<form method="post" action="" name="FormName">
<!--  put all the form inputs under here-->


<div class="DoNotPrint" style="position: absolute; top: 1000px; left: 10px;">
<table>
	<tr>
		<td>
			Subject: <input name="subject" size="40" type="text">
			<input value="Submit" name="SubmitButton" type="submit">
			<input value="Reset" name="ResetButton" type="reset">
			<input value="Print" name="PrintButton" type="button" onclick="window.print()">
			<input value="Print and Submit" name="PrintSubmitButton" type="button" onClick="window.print(); document.FormName.submit()">
			</td>
	</tr>
</table>
</div>
</form>

3. To remove the outline of an input box when printing, add class=”noborder” as an attribute in the <input>. For example:

<div style="position: absolute; left: 100px; top: 100px;"> 
	<input name="SingleLineInputName" type="text" class="noborder" style="width: 100px;">
</div>

Pre-filling an input box with your customized value

Single-line text input

<div style="position: absolute; left: 100px; top: 100px;"> 
	<input name="SingleLineInputName" type="text" class="noborder" style="width: 100px;" value="Substitute your pre-filled text here" >
</div>

Multi-line text input

<div style="position: absolute; left: 100px; top:100px;"> 
	<textarea name="MultiLineInputName" class="noborder" style="width:100px; height:100px;"> Substitute your pre-filled text here </textarea>
</div>

Checkboxes

<div style="position: absolute; left: 100px; top: 100px;">
        <input name="CheckboxName" type="checkbox" checked>
</div>

Radio Buttons

<div style="position: absolute; left: 100px; top: 100px;">
        <input name="RadioName" type="radio" value="value1" checked >
</div>
<div style="position: absolute; left: 100px; top: 110px;">
        <input name="RadioName" type="radio" value="value2">
</div>

Pre-checking the gender checkboxes in some eForms

This one is a bit tricky, you’ll have to do a few different things

1. Put the following in between <head> and </head>

<!-- Pre-checking Gender script -->
<script type="text/javascript" language="javascript">
function checkGender(){
	if (document.getElementById('PatientGender').value == 'M'){
		document.getElementById('Male').checked = true;
	}else if (document.getElementById('PatientGender').value == 'F'){
		document.getElementById('Female').checked = true;
	}
}
</script>

2. Put onload=”checkGender();” within the opening <body> tag

<body onload="checkGender();">

3. Put the following with the other input boxes within the <form></form>

<div style="position:absolute; left:100px; top: 100px;">
	<input name="Male" id="Male" type="checkbox" class="noborder">
</div>
<div style="position:absolute; left:110px; top: 100px;">
	<input name="Female" id="Female" type="checkbox" class="noborder">
</div>
<input name="PatientGender" id="PatientGender" type="hidden" oscarDB=sex >

Calendar/Date Selection in eForms (datepicker)

When you add an input through the eForm generator and have the option “Add calendar date picker for fields labeled date or day”, a calendar date picker will appear. The default date format is YYYY-MM-DD, for example 2023-01-31.

If you want to customize the date picker, so that a selected date is displayed any another format such as MMM/DD/YY (Jan/01/2023), then you can see this video on date calendar customization for eForms. Video is also shown below (by John Robertson):

Here is the code to add to <head> for calendars:

<!-- main calendar program -->
<script src="../share/calendar/calendar.js"></script>
<script src="../share/calendar/lang/calendar-en.js"></script>
<script src="../share/calendar/calendar-setup.js"></script>
<link rel="stylesheet" type="text/css" media="all" href="../share/calendar/calendar.css" title="win2k-cold-1" />

And add this after </form> but before </body> (the element ID goes instead of “today” if you have it different, and for multiple date selection fields copy the line and change the element ID):

<!-- Define Date Calendars -->
<script>
Calendar.setup( { inputField : "today", ifFormat : "%Y-%m-%d", button : "today" } );
</script>

Only One Check

If you want to have several checkboxes but only one can be checked, like this:

You must add this to the <head> of the eForm:

<script>
$(document).ready(function() {
	$('[class^="child-"]').hide();
	$('.parent-field').click(function() {
		$('[class^="child-"]').hide();
		$('.parent-field').each(function() {
			if ( $(this).is('input:checkbox') ){
				if(this.checked){
					$('.child-' +  $(this).prop('id')).show();
				}else{
				$('.child-' + $(this).val()).show();
				}
			}
			if ( $(this).is('input:text') ){
				if($(this).val()=='X'){
					$('.child-' +  $(this).prop('id')).show();
				}else{
				$('.child-' + $(this).val()).show();
				}
			}
		});
	});
	$('[class^="only-one-"]').click(function() {
		if ( $(this).is('input:checkbox') ){
			$('.'+$(this).attr('class')).prop('checked', false);
			$(this).prop('checked', true);
		}

		if ( $(this).is('input:text') ){
			$('.'+$(this).attr('class')).val('');
			$( this ).val('X');
		}
	});
});
</script>

Make sure you have some version of jQuery loaded as well. For eForm compatibility and security, reference jQuery 3.6.4. The below snippet references jQuery 3.6.4 and if it’s not available on your OSCAR then it will fallback to the older jQuery 1.12.3.

<script type="text/javascript" src="../library/jquery/jquery-3.6.4.min.js" ></script>
<script> window.jQuery || document.write('<script src="../js/jquery-1.12.3.js">< \/script>') </script>

If the above jQuery does not work for your OSCAR version, it may not have those files so you could use the below older version.

<!-- jQuery for greater functionality -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script> window.jQuery || document.write('<script src="../js/jquery-1.7.1.min.js">< \/script>') </script>
<script> window.jQuery || document.write('<script src="jquery-1.7.1.min.js">< \/script>') </script>

Then follow this pattern for the input checkboxes:

<input name="severe_condition" id="severe_condition" class="only-one-condition" type="checkbox" style="position:absolute; left:53px; top:321px; ">
<input name="serious_condition" id="serious_condition" class="only-one-condition" type="checkbox" style="position:absolute; left:53px; top:360px; ">
<input name="moderate_condition" id="moderate_condition" class="only-one-condition" type="checkbox" style="position:absolute; left:53px; top:408px; ">
<input name="mild_condition" id="mild_condition" class="only-one-condition" type="checkbox" style="position:absolute; left:53px; top:455px; ">
<input name="negligible_condition" id="negligible_condition" class="only-one-condition" type="checkbox" style="position:absolute; left:53px; top:491px; ">
  • Name/ID should be “X_Y” where X is whatever you want and Y is constant value which will be the same for the rest of the checkboxes for only one check.
  • Class needs to be “only-one-X” where X is the constant value as above

To maximize the eForm window when it opens

(How to make the eForm open full-screen by default)

Put the following between the <head> and </head>

<script language="JavaScript">
  top.window.moveTo(0,0);
  top.window.resizeTo(screen.availWidth,screen.availHeight);
</script>

To hide headers and footers on print

By default when you print a page, it will include the page’s “headers and footers”, and browsers will print the web address of the page you printed.
For example:

There are several reasons why you wouldn’t want headers and footers to show on the eForms you print.
For example, that prints your OSCAR’s link/IP address on the page, which isn’t normally something you’d want the public to know of.

To have your printed eForms not show the headers and footers by default, add the following between the <head></head>

*NOTE: This snippet currently works fine on Chrome and Firefox. Other browsers ignore these settings and still print headers/footers and malforms the page. Chrome and Firefox are the recommended browsers for using OSCAR because others sometimes don’t display certain elements correctly (e.g. certain icons and css).
If you find that an extra page is being added to print, you may want to adjust the padding-top and padding-bottom settings below as necessary.

<style type="text/css" media="print">
@media print {
    @page {
        margin-top: 0;
        margin-bottom: 0;
    }
    body {
        padding-top: 36px;
        padding-bottom: 36px;
    }
}
</style>

Signatures

Automatic Signatures

This shows image of the current user’s signature based on placement of the image alignment…

In order for this to work, the user has to have a signature image file set.

Add the following into <head> of the eForm:

<script language="javascript">
    function SignForm() {
        var provNum = $('#current_user_id').val();
        document.getElementById('signature').src = "../eform/displayImage.do?imagefile=consult_sig_" + provNum + ".png";
        $('#signature').attr(onerror, "this.style.display='none'");
        document.getElementById('signature').alt = provNum;
    }
</script>

Then add the function to body onload (note – if you’re experiencing problems like the signature not showing on a specific eForm, try moving the SignForm(); function to be the first function in onload):

<body onload="SignForm();">

And then add this after the image reference in the eForm:

This will show the image of the current user’s signature where the position of this image is…

<img id="signature" name="signature" src="${oscar_image_path}BNK.png" width="150" height="25" style="position: absolute; left: 49px; top: 721px; z-index: 20">
<input type="hidden" id="current_user_id" name="current_user_id" oscardb=current_user_id>

You can change the width/height and position of where the signature image gets inserted by changing the bolded values.

If you have an eForm that requires multiple spots for the signature, just copy the function and change the name and then add that into onload and also add the below again but with the second function’s name in the ID and name.

e.g.:

<head>
<script language="javascript">
    function SignForm() {
        var provNum = $('#current_user_id').val();
        document.getElementById('signature').src = "../eform/displayImage.do?imagefile=consult_sig_" + provNum + ".png";
        $('#signature').attr(onerror, "this.style.display='none'");
        document.getElementById('signature').alt = provNum;
    }
</script>
<script language="javascript">
    function SignForm2() {
        var provNum = $('#current_user_id').val();
        document.getElementById('signature2').src = "../eform/displayImage.do?imagefile=consult_sig_" + provNum + ".png";
        $('#signature2').attr(onerror, "this.style.display='none'");
        document.getElementById('signature2').alt = provNum;
    }
</script>
</head>
<body onload="SignForm();SignForm2();">
<img id="signature" name="signature" src="${oscar_image_path}BNK.png" width="150" height="25"  style="position: absolute; left: 49px; top: 721px;z-index: 20">
<img id="signature2" name="signature2" src="${oscar_image_path}BNK.png" width="150" height="25"  style="position: absolute; left: 49px; top: 721px;z-index: 20">
<input type="hidden" id="current_user_id" name="current_user_id" oscardb=current_user_id>

Multiple Signature Options

The Postnatal Cytogenetics Lab Req eForm allows the user to select between using the signature image file, wet signature (drawing with mouse), or “Electronically Signed” for signature.  Similar code omitting the “Electronically Signed” option is used in the Disability Tax Credit (CRA T2201)

To start I would suggest referencing the newest jQuery currently available in OSCAR and all its major forks and the jSignature plugin.

<script src="../js/jquery-1.12.3.js"></script>
<script src="../share/javascript/jquery/jSignature.min.js"></script>

The following javascript handles the options

<script language="javascript" type="text/javascript">
/****************************
Signature functions - 1 signature
****************************/
jQuery(document).ready(function() {
	$("#CanvasSignature1").jSignature({'decor-color':'rgba(255, 255, 255, 0.0)'})
})

function saveSig() {
	var $sig=$("#CanvasSignature1");
	var datapair=new Array();
	datapair=$sig.jSignature("getData","base30");
	document.getElementById("StoreSignature1").value=datapair.join(",");
}

function clearSig() {
	$("#CanvasSignature1").jSignature("reset");
}

function loadSig() {
	var $sig=$("#CanvasSignature1");
	var data
	data=document.getElementById("StoreSignature1").value;
	try {
		$sig.jSignature("setData","data:"+ data);
	} catch (e) {
		console.log("jSignature failed to load signature.")
	}
}

/****************************
Script to enable signature stamps. No Array needed.  
Signature assigned to ProviderNumber in the format:
consult_sig_+ProviderNumber+.png
****************************/
function SignForm() {
	var ProviderNumber = document.getElementById('current_user_id').value;
	document.getElementById('StampSignature').src = "../eform/displayImage.do?imagefile=consult_sig_"+ProviderNumber+".png";
}

/****************************
Script to add/remove signature
adapts to signature type
****************************/  
function AddSig(id) {
	if (id == 'Wet') {
		var id2 = "CanvasSignature1";
		var Cl_Name = "sig";}
	else if (id == 'Stamp'){
		SignForm();
		var id2 = "Signature_Stamp" ;
		var Cl_Name = "Show";}
	else {
		var id2 = "Signature_Electronic" ;
		var Cl_Name = "Show";}
	document.getElementById(id2).className = Cl_Name ;
	id3 = ["CanvasSignature1", "Signature_Stamp", "Signature_Electronic"];
	for ( i=0; i<id3.length; i++ ){
		var SigName = id3[i];
		if (SigName != id2){
		document.getElementById(SigName).className = 'Hide'; }
		}
		id4 = ["Wet", "Stamp", "Electronic"];
		for ( j=0; j<id4.length; j++ ){
		var SigName2 = id4[j];
		if (SigName2 != id){
		document.getElementById(SigName2).checked = false ;}
			}
		document.getElementById('SignatureChoice').value = id ;
}
		
function removeSig(id) {
	if (id == "Wet") {
		var id2 = "CanvasSignature1";}
	else {
		var id2 = ("Signature_" + id); }
	document.getElementById(id2).className = 'Hide';
	document.getElementById('SignatureChoice').value = 'None';
}

/****************************
Script to load None signature option
****************************/
function Add_None() {
	document.getElementById('CanvasSignature1').className = 'Hide';
	document.getElementById('Signature_Stamp').className = 'Hide';
	document.getElementById('Signature_Electronic').className = 'Hide';
}

/****************************
Script to reload signature option selected on submit
****************************/
function reloadSignature() {
	// show chosen signature format on submit: e.g.  Wet, Stamp, Electronic, None
	var chosenSig = document.getElementById('SignatureChoice').value;
	document.getElementById(chosenSig).checked = true;
	if (chosenSig === 'Stamp' || chosenSig === 'Wet' || chosenSig === 'Electronic' ) {
		AddSig(chosenSig);
	} else if (chosenSig === 'None') {
		Add_None();
	}
}
</script>

Finally you have some divs for the signature and control buttons to control the options for signature:

<!-- Signature Wet Script -->
<div id="CanvasSignature1" class="sig" style="position:absolute; left:20px; top:765px; width:290px; height:30px;"></div>
<!-- Signature Stamp -->
<div id="Signature_Stamp" class="Hide" style="position:absolute; left:20px; top:765px;">
	<img id="StampSignature" src="" style="width:130px; height:30px;" />
</div>
<!-- Signature Electronic -->
<span id="Signature_Electronic" class="Hide" style="position:absolute; left:20px; top:765px; font-size:16px;"><b><i>&ldquo;Electronically signed&rdquo;</i></b></span>
<!-- Signature Control -->
<div id="signatureControl" class="DoNotPrint" style="position:absolute; left:730px; top:730px;">
	<input name="Stamp" id="Stamp" type="checkbox" class="DoNotPrint" style="position:absolute; left:0px; top:0px; color:#26374a;"
	onclick="
	document.getElementById('Wet').checked = false;
	if (this.checked == true) { 
		AddSig(this.id);
	} else {
		removeSig(this.id);
	}" />
	<span class="DoNotPrint" style="position:absolute; left:25px; top:3px; width:80px; font-size:12px; color:#26374a;">Stamp</span>

	<input name="Wet" id="Wet" type="checkbox" class="DoNotPrint" style="position:absolute; left:0px; top:20px; color:#26374a;"
		onclick="
			document.getElementById('Stamp').checked = false;
			if (this.checked == true) {
				AddSig(this.id);
			} else {
				removeSig(this.id);
			}" />
	<span class="DoNotPrint" style="position:absolute; left:25px; top:23px; width:150px; font-size:12px; color:#26374a;">Wet</span>
	<input name="ClearButton" id="ClearButton" type="button" class="DoNotPrint" style="position:absolute; left:55px; top:23px; font-size:12px; color:#3d6e84;" onclick="clearSig();" value="Clear Sig" /> 

	<input name="Electronic" id="Electronic" type="checkbox" class="DoNotPrint" style="position:absolute; left:0px; top:40px; color:#26374a;"
	onclick="
	document.getElementById('Wet').checked = false;
	if (this.checked == true) {
		AddSig(this.id);
	} else {
		removeSig(this.id);
	}" />
	<span class="DoNotPrint" style="position:absolute; left:25px; top:43px; width:80px; font-size:12px; color:#26374a;">Electronic</span>
</div>

Wet Signatures or Drawing Pad for Circling Affected Area

If you need a “wet” signature option that displays correctly on faxing and PDF, I have code for one that works but it involves a bit more work. I also used this for an MRI referral checklist that required the doctor to circle affects areas, and I modified this wet signature box to be superimposed on the eForm’s image and be transparent to allow drawing.

This version simply encodes the signature pad’s canvas as .png and stores the encoded value in a hidden input. Then on eForm display it gets decoded. This sticks on PDF and fax because the functions correctly make the image decode before it is generated into fax or PDF thus making it stay.

I have created eForms with several of these signature boxes each for either wet sign use or for drawing over an eForm image. Just use different element ID’s for the imagestore and canvases etc. i.e. “gen_signatureData1”, “gen_signatureData2”…

In the below example of this used as a drawing pad, the doctor wanted the drawing pen to show red color so I created a copy of signature_pad.min.js as signature_padRED.min.js and changed that to show the color as red:penColor||”red” and then referenced signature_padRED.min.js in the eForm. It looks like this when superimposed on the eForm image and used as transparent drawing tool/signature pad:

First, upload the signature_pad.min.js file to your eForm images folder.

Next, here is the code you need to add to the eForm:

Add this to <head> of the eForm:

<script src="${oscar_image_path}signature_pad.min.js"></script>
<style>
  /* signature pad styling */
  .signaturePad {
    opacity: 0.8;
    width: auto !important;
  }

  .signaturePad canvas {
    position: absolute;
    height: 100%;
  }

  .signaturePad .canvas_frame {
    position: relative;
    width: 210px;
    height: 100%;
    float: left;
    background-color: transparent;
    margin-right: 6px;
  }

  .signaturePad .clearBtn {
    position: relative;
    float: right;
    height: 50px;
    line-height: 50px;
    font-size: 1em;
    font-family: Verdana, Arial, sans-serif;
    text-align: center;
    border: 1px solid #ddd;
    background: #ddd url(images/ui-bg_highlight-soft_60_dddddd_1x100.png) 50%
      50% repeat-x;
    font-weight: normal;
    color: #000;
    padding: 0 1em;
    border-radius: 5px;
    font-size: 20px;
    cursor: pointer;
  }
  .signaturePad .clearBtn:hover,
  .signaturePad .clearBtn:active {
    color: red;
  }

  .signaturePad .signature_image {
    display: inline-block;
    position: absolute;
  }

  /* print only styling */
  @media print {
    .signaturePad {
      background-color: transparent;
      opacity: 1;
    }

    .signaturePad canvas {
      /* always hide canvas for printing. print image instead */
      display: none !important;
    }

    .signature_image {
      /* always show signature image when printing */
      display: inline-block !important;
    }
  }
</style>

<script>
/** This function is called when the eform has been loaded */
function onEformLoad() {
	var $input_elements = $(".input_elements");
}
  /** This function is called when the print button is clicked */
  function onEformPrint() {
    if ($(".signature_data").length > 0) {
      for (var i = 0; i < $(".signature_data").length; i++) {
        var $obj = $($(".signature_data")[i]);
        var imgData = $obj.val();
        var imgWidth = $obj.parent().find("canvas").attr("width");
        var imgHeight = $obj.parent().find("canvas").attr("height");
        var imgValue =
          "<img width='" +
          imgWidth +
          "' height='" +
          imgHeight +
          "' src='" +
          imgData +
          "' />";
        $obj.parent().find("canvas").parent().append(imgValue);
      }
    }
    window.print();

    if ($(".signature_data").length > 0) {
      for (var i = 0; i < $(".signature_data").length; i++) {
        $($(".signature_data")[i]).parent().find("img").remove();
      }
    }
  }
  /** This function is called when the eform submit button is clicked */
  function onEformSubmit() {
    for (var i = 0; i < $(".gen_input.radioBox").length; i++) {
      if ($(".gen_input.radioBox")[i].type == "password") {
        $(".gen_input.radioBox")[i].type = "text";
        if ($(".gen_input.radioBox")[i].value.length > 0) {
          $($(".gen_input.radioBox")[i]).attr(
            "value",
            $(".gen_input.radioBox")[i].id +
              "_" +
              $(".gen_input.radioBox")[i].value
          );
        }
      }
    }

    releaseDirtyFlag();
    document.forms[0].submit();
  }
  /** This function is called when the eform print & submit button is clicked */
  function onEformPrintSubmit() {
    onEformPrint();
    releaseDirtyFlag();
    setTimeout("document.forms[0].submit()", 2000);
  }

  /** this function is run on page load to make signature pads work. */
  $(function () {
    $(".signaturePad").each(function () {
      var $this = $(this);
      var $canvasFrame = $this.children(".canvas_frame");
      var $clearBtn = $this.children(".clearBtn");
      var canvas = $canvasFrame.children("canvas").get(0);
      var $data = $canvasFrame.children(".signature_data");
      var src = $data.val();
      // the image is needed even when signature pads are loaded for printing/faxing
      var $img = $("<img>", {
        src: src,
        class: "signature_image",
      });
      if (src && src.length > 0) {
        $img.appendTo($canvasFrame);
      }

      // if signature pad loaded correctly and eform viewed on screen
      /* NOTE: media type does not currently work in wkhtmltopdf
                                                                    See https://github.com/wkhtmltopdf/wkhtmltopdf/issues/1737 */
      if (
        typeof SignaturePad !== "undefined" &&
        window.matchMedia("screen").matches
      ) {
        console.info("editable signature pad initializing ");
        $img.hide();
        var updateSlaveSignature = function (src_canvas, dest_canvas) {
          // write to the destination with image scaling
          var dest_context = dest_canvas.getContext("2d");
          dest_context.clearRect(0, 0, dest_canvas.width, dest_canvas.height);
          dest_context.drawImage(
            src_canvas,
            0,
            0,
            dest_canvas.width,
            dest_canvas.height
          );
        };
        // initialize the signature pad
        var signPad = new SignaturePad(canvas, {
          minWidth: 1,
          maxWidth: 2,
          onEnd: function () {
            $this.trigger("signatureChange");
          },
        });
        // load the image data to the canvas ofter initialization
        if (src != null && src != "") {
          signPad.fromDataURL(src);
        }
        // define a custom update trigger action. this allows the eform to store the signature.
        $this.on("signatureChange", function () {
          $data.val(signPad.toDataURL());
          $img.prop("src", signPad.toDataURL());
          if ($this.attr("slaveSigPad")) {
            var $slavePad = $("#" + $this.attr("slaveSigPad")); // get slave pad by id
            updateSlaveSignature(canvas, $slavePad.find("canvas").get(0));
            $slavePad.trigger("signatureChange"); // be careful of infinite loops
          }
          return false;
        });
        // init the clear button
        $clearBtn.on("click", function () {
          signPad.clear();
          $this.trigger("signatureChange");
          return false;
        });
      }
      // not using the canvas, show signature as an image instead.
      else {
        console.info("static signature pad initializing");
        $img.show();
      }
    });
  });
</script>

Next, add the function to the body onload:

<body onload="onEformLoad();">

In the <body> of the eForm, add this. You can change the bolded values uniformly to where you want the signature canvas to display (i.e. if you want to change the width then change all 3 width values to be the same), and adjust the width/height as necessary:

<canvas id="canvase" style="position:absolute; left:508px; top:705px; width:180px; height:180px;"></canvas>
<div id="gen_widgetId39" class="signaturePad"
    style="position:absolute; left:508px; top:705px; width:180px; height:180px; z-index: 13;">
    <div class="canvas_frame">
        <canvas width="180" height="180" style="touch-action: none;">
        </canvas>
        <input type="hidden" class="signature_data" id="gen_signatureData1" name="gen_signatureData1">
    </div>
    <button type="button" class="clearBtn DoNotPrint" id="gen_inputId39" name="gen_inputId39">clear</button>
</div>

These are the bottom buttons that call the signature pad functions. You already have these buttons coded in your eForm, so just adjust the onclick function to the bolded values as below, so that they call the functions that save the signature pad image (if you don’t adjust this then the signature image won’t save):

<input value="Submit" name="SubmitButton" id="SubmitButton" type="submit" onclick="onEformSubmit();">
<input value="Reset" name="ResetButton" id="ResetButton" type="reset">
<input value="Print" name="PrintButton" id="PrintButton" type="button" onclick="onEformPrint();">
<input value="Print & Submit" name="PrintSubmitButton" id="PrintSubmitButton" type="button"
    onclick="onEformPrintSubmit();">

Faxing

Adding fax capability

Your OSCAR must have FAX enabled (via the properties file) and set up to use faxing.

Add the following between the <head></head>
Note: if you already have jQuery added, then you can omit the first 2 lines shown below.

<!-- jQuery for greater functionality -->
<script type="text/javascript" src="../library/jquery/jquery-3.6.4.min.js" ></script>
<script> window.jQuery || document.write('<script src="../js/jquery-1.12.3.js">< \/script>') </script>

<!-- faxControl for faxing capability -->
<script type="text/javascript" src="${oscar_javascript_path}eforms/faxControl.js"></script>

<!-- printControl for PDF capability -->
<script language="javascript" type="text/javascript" src="${oscar_javascript_path}eforms/printControl.js"></script>

This will show the fax controls in the eForm:

NOTE: If the above code does not add the fax options to the eForm, then it’s likely a jQuery compatibility issue on your Oscar system. Use the below code instead (uses an older jQuery, unfortunately has security risks):

<!-- jQuery for greater functionality -->
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script> window.jQuery || document.write('<script src="../js/jquery-1.7.1.min.js">< \/script>') </script>
<script> window.jQuery || document.write('<script src="jquery-1.7.1.min.js">< \/script>') </script>

<!-- faxControl for faxing capability -->
<script language="javascript" type="text/javascript" src="${oscar_javascript_path}eforms/faxControl.js"></script>

<!-- printControl for PDF capability -->
<script language="javascript" type="text/javascript" src="${oscar_javascript_path}eforms/printControl.js"></script>

Add a one-touch Submit & Fax to destination button

You must already have added the code above (“Adding fax capability”) for the following to work.

If you want to add a button that will submit the eForm and also fax it to a specific fax number, add the code bolded shown below just above the Subject line:

Note: where it says value=”Submit & Fax to Xray Department” you put the name of the place you are faxing to. In the value=’555-555-5555′; you put the fax number where you want the eForm to be faxed once the one-touch Submit & Fax button is pressed.

<div class="DoNotPrint" style="position: absolute; top: 1000px; left: 10px;">
    <table>
        <tr>
            <td>
                <input type="button" value="Submit & Fax to Xray Department" onClick="document.getElementById('otherFaxInput').value='555-555-5555';
    AddOtherFax();submitFaxButtonAjax(true);  ">
                <br>
                <br>
                Subject: <input name="subject" size="40" type="text">
                <input value="Submit" name="SubmitButton" type="submit">
                <input value="Reset" name="ResetButton" type="reset">
                <input value="Print" name="PrintButton" type="button" onclick="window.print()">
                <input value="Print and Submit" name="PrintSubmitButton" type="button"
                    onClick="window.print(); document.FormName.submit()">
            </td>
        </tr>
    </table>
</div>
</form>

You can also be fancy and add several of these buttons. I have created a MyHealth Centre Requisition eForm that can be one-touch faxed to a specific destination out of a list just by clicking the desired destination’s button.

Example of how this can look:

Simple only 1 one-touch fax option

Example of the code for multiple one-touch fax options:

Several one-touch fax options
<div class="DoNotPrint" id="BottomButtons" style="position: absolute; top:1000px; left:0px;">
    <table>
        <tr>
            <td>
                <br>
                <input type="button" value="Submit & Fax to LifeLabs General Fax" onClick="document.getElementById('otherFaxInput').value='905-795-9891';
AddOtherFax();submitFaxButtonAjax(true);  ">
                <input type="button" value="Submit & Fax to Dynacare General Fax" onClick="document.getElementById('otherFaxInput').value='888-333-8044';
AddOtherFax();submitFaxButtonAjax(true);  ">
                <input type="button" value="Submit & Fax to Alpha Lab Nixon" onClick="document.getElementById('otherFaxInput').value='519-668-6428';
AddOtherFax();submitFaxButtonAjax(true);  ">
                <br>
                <br>
                Subject: <input name="subject" size="40" type="text"> <br>
                <!-- the rest of the form goes here... (not shown for simplicity purposes) -->

Pre-fill the “Other Fax Number” Box

Paste this code into <head> of the eForm.

Change the 5555555555 to the fax number you want pre-filled automatically, and change the Fax To Name to the description if you want this to show up in the “Providers” fax dropdown.

<script language="javascript">
    function setFaxNo() {
        setTimeout(function () {
            document.getElementById("otherFaxInput").value = "5555555555"
            AddOtherFax();
            return false;
        }, 1000);

        setTimeout(function () {
            $('#otherFaxSelect').prepend('<option value="5555555555">Fax To Name</option>');
            $('select option[value="5555555555"]').attr("selected", true);
            return false;
        }, 500);
    } 
</script>

Next, include setFaxNo(); in body onload. For example: <body onload=”setFaxNo();”>

Then the eForm will have the “Other Fax Recipient” field pre-filled, the “Add Other Fax Recipient” button will be pre-clicked automatically, so you can just press “Submit & Fax” to fax and save the eForm.

For example:

Copy to Clipboard Button

Sometimes there are parts of the eForm that you want to copy.  You can select and copy but you risk capturing unwanted white space. Here are two different ways to do this in Code:

<script>
	function copyToClipboard(id) {
	    var range = document.createRange();
	    range.selectNode(document.getElementById(id));
	    window.getSelection().removeAllRanges(); // clear current selection
	    window.getSelection().addRange(range); // to select text
	    document.execCommand("copy");
	    window.getSelection().removeAllRanges();// to deselect
	}
</script>

<span id="fax" onclick="copyToClipboard(this.id)" title="click to copy">
555-555-1234</span>

Note that the second way below has a jQuery dependency but works well with inputs:

<script>
	/****************************
		Copy to Clipboard
	****************************/
	$(document).ready(function() {
		var y = document.getElementsByClassName('copyable');
		$(y).click(function() {
		this.select();
		document.execCommand('copy');
		$(this).css('background', 'transparent').fadeIn("slow");
		})
	})
</script>

And in the <form> block:

<input name="Copy_Fax" id="Copy_Fax1" type="text" class="copyable DoNotPrint" 
style="position:absolute; cursor:pointer; left:499px; top:100px; width:100px; font-size:14px; font-weight:bold; border:0px; background:white;" 
title="click to copy" value="555-555-5555">

Linking to other OSCAR Pages for the Patient

If you need to add links to other pages within OSCAR from the eForm (i.e. button to “Check patient’s labs”, etc.), use the below functions. This is available in a JS file here.

In the button you have to reference the function like this example: <input type=”button” value=”Labs” name=”labs” onclick=”onBodyLoad(); labs();” />

<!-- Script to allow linking to other Oscar pages for active patient -->

function onBodyLoad() {
	var re = new RegExp( "[?&]" + 'demographic_no' + "=([^&$]*)", "i" );
	var offset=window.opener.location.search.search(re);
	if(offset==-1){ 
	re = new RegExp( "[?&]" + 'demographicNo' + "=([^&$]*)", "i" );
	offset=window.opener.location.search.search(re);
  }
}

function doIFrameOnLoad() {
	var re = new RegExp( "[?&]" + 'demographic_no' + "=([^&$]*)", "i" );
	var offset=window.opener.location.search.search(re);
	if(offset==-1){ 
	re = new RegExp( "[?&]" + 'demographicNo' + "=([^&$]*)", "i" );
	offset=window.opener.location.search.search(re);
	}
	var demographic=RegExp.$1;
}

function Rx() {
window.open("../oscarRx/choosePatient.do?providerNo=&demographicNo="+RegExp.$1+"");
}

function allergy() {
window.open("../oscarRx/showAllergy.do?demographicNo="+RegExp.$1+"");
}

function prevention() {
window.open("../oscarPrevention/index.jsp?demographic_no="+RegExp.$1+"");
}

function tickler() {
window.open(" ../tickler/ticklerAdd.jsp?name=&chart_no=&bFirstDisp=false&demographic_no="+RegExp.$1+"&messageID=null&doctor_no=");
}

function diseaseRegistry() {
window.open("../oscarResearch/oscarDxResearch/setupDxResearch.do?demographicNo="+RegExp.$1+"&providerNo=&quickList=");
}

function message() {
window.open("../oscarMessenger/SendDemoMessage.do?demographic_no="+RegExp.$1+"");
}

function consult() {
window.open("../oscarEncounter/oscarConsultationRequest/ConsultationFormRequest.jsp?de="+RegExp.$1+"&teamVar=");
}

function eGFR() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=EGFR");
}

function Weight() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=WT");
}

function Height() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=HT");
}

function BMI() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=BMI");
}

function WC() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=WC");
}

function WAIS() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=WAIS");
}

function HgbA1C() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=A1C");
}

function CholLDL() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=LDL");
}

function ACR() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=ACR");
}

function SMK() {
window.open("../oscarEncounter/oscarMeasurements/SetupDisplayHistory.do?type=SMK");
}

function labGrid() {
window.open("../lab/CumulativeLabValues3.jsp?demographic_no="+RegExp.$1+"");
}

function labRow() {
window.open("../lab/CumulativeLabValues.jsp?demographic_no="+RegExp.$1+"");
}

function labs() {
window.open("../lab/DemographicLab.jsp?demographicNo="+RegExp.$1+"");
}

function HBPFlowsheet() {
window.open("../oscarEncounter/oscarMeasurements/TemplateFlowSheet.jsp?demographic_no="+RegExp.$1+"&template=hyptension");
}

function CHFFlowsheet() {
window.open("../oscarEncounter/oscarMeasurements/TemplateFlowSheet.jsp?demographic_no="+RegExp.$1+"&template=chf");
}

function DMFlowsheet() {
window.open("../oscarEncounter/oscarMeasurements/TemplateFlowSheet.jsp?demographic_no="+RegExp.$1+"&template=diab2");
}

function billing() {
window.open("../billing.do?billRegion=BC&billForm=DA&hotclick=&appointment_no=&demographic_name=&status=c&demographic_no="+RegExp.$1+"&providerview=&user_no=&apptProvider_no=&appointment_date=&start_time=12:0&bNewForm=1");
}

function billingGP() {
window.open("../billing.do?billRegion=BC&billForm=GP&hotclick=&appointment_no=&demographic_name=&status=c&demographic_no="+RegExp.$1+"&providerview=&user_no=&apptProvider_no=&appointment_date=&start_time=12:0&bNewForm=1");
}

function documents_all() {
window.open("../dms/documentReport.jsp?function=demographic&functionid="+RegExp.$1+"&view=all");
}

function documents_consult() {
window.open("../dms/documentReport.jsp?function=demographic&functionid="+RegExp.$1+"&view=consult");
}

Pasting into Encounter Window After Submit

Shared by Yehia Qaisy:

The e-chart target textarea is “caseNote_note”. You can create a hidden input to save the text or data that you want to paste into chart then when you press submit it will copy it into the chart. The target textarea is in a parent window that is one or two levels above the current eform popup windows.

Example below.

Function saveNote() {
    try {
        // Reference to the direct parent window (opener) from the current popup window
        const parentWindow = window.opener;

        // Check if the direct parent window contains the required form
        if (parentWindow && parentWindow.document.forms["caseManagementEntryForm"]) {
            // If the form is found in the direct parent window, update the textarea
            const targetTextareaDirect = parentWindow.document.forms["caseManagementEntryForm"].elements["caseNote_note"];
            
            if (targetTextareaDirect) {
                targetTextareaDirect.value += document.getElementById("transferBox").value;
                return; // Early return as we found the textarea and updated it
            }
        }

        // If the direct parent didn't have the form, check the main parent (two levels above)
        const mainParentWindow = parentWindow.opener;

        if (mainParentWindow && mainParentWindow.document.forms["caseManagementEntryForm"]) {
            const targetTextareaMain = mainParentWindow.document.forms["caseManagementEntryForm"].elements["caseNote_note"];
            
            // If the textarea is found in the main parent window, update it
            if (targetTextareaMain) {
                targetTextareaMain.value += document.getElementById("transferBox").value;
            } else {
                alert("Target textarea not found.");
            }
        } else {
            alert("Target form not found.");
        }
    } catch(e) {
        console.error(e);
        alert("The note could not be copied to the encounter note.");
    }
}

This function first checks if the direct parent window (`window.opener`) contains the required form. If it does, it updates the textarea If not, it proceeds to check the main parent window that is two levels above. If the required form is found there, it updates the textarea in that window.

Customizing fonts in the input fields

Put the following between the <head></head>

<style type="text/css">
    .style1 {
        font-family: arial, sans-serif;
        font-size: 12px;
        font-weight: normal;
    }
</style>

For more styling, check out the css fonts page at W3schools.com

Insert class=”style1″ as an attribute into the <tag> that you want to customize the text. For example:

<div style="position: absolute; left: 100px; top: 100px;"> 
	<input name="SingleLineInputName" type="text" class="style1" style="width: 100px;">
</div>

If you want to apply multiple styles to the same element, just separate the classes by a space. For example:

<div style="position: absolute; left: 100px; top: 100px;"> 
	<input name="SingleLineInputName" type="text" class="noborder style1" style="width: 100px;">
</div>

Autocomplete Text Boxes

You can provide autocomplete options from a predefined list to both increase speed and accuracy for eForm completion. Important bits for the code compatibility are referencing internal jQuery and jQuery UI versions that are present in all three OSCAR 19, Open OSP and OscarPro in the <head></head> block

<script src="../js/jquery-1.12.3.js"></script>
<link href="../js/jquery_css/smoothness/jquery-ui-1.10.2.custom.min.css" rel="stylesheet">
<script src="../js/jquery-ui-1.10.2.custom.min.js"></script>

Full details of the options exist at https://jqueryui.com/autocomplete/

The quick and dirty is to set up an javascript array for subsequent sourcing of options for the autocomplete initialization thusly:

<script>
var tests=["Adenovirus (virus detection only)", "Antimicrobial Susceptibility - Bacteria"]
$(document).ready(function() {
        $("#test1").autocomplete( {
      source: tests
      });
});
</script>

don’t forget the matching element later in the <form></form>

<input name="test1" id="test1" type="text" class="noborder" style="position:absolute; left:415px; top:608px; width:291px; height:21px; " >

Copy to Encounter

It’s often useful to copy a summary of a filled eForm to the encounter. 

function copyToEncounter(text) {
	  try {
		if( window.parent.opener.document.forms["caseManagementEntryForm"] != undefined ) {
			window.parent.opener.pasteToEncounterNote(text);
		  }else if( window.parent.opener.document.encForm != undefined ){
			window.parent.opener.document.encForm.enTextarea.value = window.parent.opener.document.encForm.enTextarea.value + text;
		  }else if( window.parent.opener.document.getElementById(noteEditor) != undefined ){
			window.parent.opener.document.getElementById(noteEditor).value = window.parent.opener.document.getElementById(noteEditor).value + text;
		  }else if(window.parent.opener.parent.opener.document.forms["caseManagementEntryForm"] != undefined){
			  window.parent.opener.parent.opener.pasteToEncounterNote(text);
		  }else if( window.parent.opener.parent.opener.document.encForm != undefined ){
			window.parent.opener.parent.opener.document.encForm.enTextarea.value = window.parent.opener.parent.opener.document.encForm.enTextarea.value + text;
		  }else if( window.parent.opener.parent.opener.document.getElementById(noteEditor) != undefined ){
			window.parent.opener.parent.opener.document.getElementById(noteEditor).value = window.parent.opener.parent.opener.document.getElementById(noteEditor).value + text;
			}
	} catch(e) {
		alert(text + " could not be copied to the encounter note.");
	}
}

An example eform that uses this function to copy the ordered lab tests to the encounter is Ontario Lab v15 requisition eForm.

Validation

Simple Field Validation

Do you ever get a form sent back because its incomplete?  Add code to the eForm so that all needed fields are identified and will turn off when filled. The form depends on the pseudo class “invalid” style element.  Place this code in the <head></head> section to set all “required” elements to a red outline.

</style>
<style type="text/css" media="screen" >
.noborder {
    border: 1px solid #d2d2d2 !important;
}
input:invalid {
    background-color: ivory;
    border: none;
    outline: 1px solid red;
}
</style>

Then in the <form></form> section place elements with the required attribute such as:

<input name="senses" id="senses_y" type="text" required>

When the form element gets input the red outline disappears indicating to the user that the requirement is met.  The Ontario MTO Driver’s Physical eForm uses this code extensively with some additional tweaks that will add or remove the required attribute depending on other form input (eg non snellen is not required if snellen is indicated)

<input name="snellen" id="snellen" type="text" class="Xbox" style="position:absolute; left:392px; top:193px;" required onmousedown="getElementById('nonsnellen').removeAttribute('required');">

Validation Of Text Based on X box

Not uncommonly there is a form where you check a box and then are expected to supply the “Other” text.  You can validate that with this snippet. In the <head></head> block put the following script

<script>
function changeAndCheck(id) {
// Subsequent text field must be name of Xbox + _Text so Other and Other_Text
var id2 = id + '_Text';
// toggle required attribute of text field and report on if it is required - alert will appear if the field is required
document.getElementById(id2).toggleAttribute('required');
document.getElementById(id2).reportValidity();
}
</script>

And for the <form></form> you might have Interpreter as the Xbox id which on mouseup will set a required attribute for the id Interpreter_Text and on reportValidity fire the invalid event and alert the user that it is invalid.  If you are using this with the first technique (“Simple Field Validation”) where you highlight invalid inputs you can replace reportValidity() in the code above with checkValidity() which just fires the invalid event and outline the element.

<input name="Interpreter" id="Interpreter" type="text" class="Xbox" style="left:518px; top:332px;" onmouseup="changeAndCheck(this.id);" >
<input name="Interpreter_Text" id="Interpreter_Text" type="text" class="noborder" style="position:absolute; left:595px; top:345px; width:123px; " >

Not So Simple Form Validation

This form validation uses a jQuery plugin and checks the form elements for what you want, and will indicate a message next to the incorrect form element.  If you want to require any input at all use required attribute as above in simple validation.  This plugin uses data-validation-required-message attributes for display required validation error. The advantages of the plugin are

  • that custom validations can be done with a pattern attribute like pattern=”^[0-9]{10}$”
  • that error messages can be used to specify what you are looking for. 
  • that multiple error messages can apply.  For the pattern example use the data-validation-pattern-message=”must be a 10 digit number”

For a full list of supported validators see the plugin documentation at https://reactiveraven.github.io/jqBootstrapValidation/

NOTE: eForms do not necessarily handle every HTML5 input type that is used in the examples documentation.  It often is safer to write a pattern for a text input than depend on inputs of type email, number, date and so on to save properly in OSCAR.

First reference the jQuery and validation plugin and initialise the fields you want checked in <head></head>

<script src="../js/jquery-1.12.3.js"></script>
<script src="../js/jqBootstrapValidation-1.3.7.min.js"></script>
<script> $(function () { $(“input,select,textarea”).not(“[type=submit]”).jqBootstrapValidation(); } ); </script>

Finally add attributes to trigger the correct error.

<div class="controls" style="position:absolute; left:92px; top:93px;">
<input type="text" pattern="a.*z" data-validation-pattern-message="Must start with 'a' and end with 'z'!" name="some_text_field" >
<p class="help-block">Must start with 'a' and end with 'z'</p>
</div>
<div class="controls" style="position:absolute; left:92px; top:193px;">
<input type="text" name="some_field" required>
<p class="help-block"></p>
</div>

Ticklers generated by eForm

The eForm generator allows for eForms to set Ticklers to allow the loop to be closed on important lab results.  The following code is used.  Put the script in the <head> portion </head> and the inputs in the <form> portion </form>.

<!-- Tickler Support -->

<script language="javascript">
function setDate(weeks){
   var now = new Date();
   now.setDate(now.getDate() + weeks * 7);
   return (now.toISOString().substring(0,10));
}

function setAtickler(){
    var today = new Date().toISOString().slice(0, 10);
    var subject=( $('#subject').val() ? $('#subject').val() : 'test');
    var demographicNo = ($('#tickler_patient_id').val() ? $('#tickler_patient_id').val() : '-1'); // patient_id
    var taskAssignedTo = ($('#tickler_send_to').val() ? $('#tickler_send_to').val() : '-1'); // -1 is reserved for the system user
    var weeks = ($('#tickler_weeks').val() ? $('#tickler_weeks').val() : '6');
    var message = ($('#tickler_message').val() ? $('#tickler_message').val() : 'Check for results of '+subject+' ordered ' + today);
    var ticklerDate = setDate(weeks);
    var urgency = ($('#tickler_priority').val() ? $('#ticklerpriority').val() : 'Normal'); // case sensitive: Low Normal High
    var ticklerToSend = {};
    ticklerToSend.demographicNo = demographicNo;
    ticklerToSend.message = message;
    ticklerToSend.taskAssignedTo = taskAssignedTo;
    ticklerToSend.serviceDate = ticklerDate;
    ticklerToSend.priority = urgency;
    return $.ajax({
       type: 'POST',
       url: '../ws/rs/tickler/add',
       dataType:'json',
       contentType:'application/json',
       data: JSON.stringify(ticklerToSend)
    });
}
</script>

<input id="tickler_patient_id" type="hidden" oscarDB=patient_id>
<input id="tickler_send_to" type="hidden" oscarDB=doctor_provider_no>
<input id="tickler_weeks" type="hidden" value="6">
<input id="tickler_priority" type="hidden" value="Normal">

One example of the code in action is BC PAP Smear Requisition

From the eForm notes:  A tickler is generated to remind the user to ensure results are received.

Metric Conversion and BMI

In many OSCAR forms a purple highlighted field can be double clicked for conversion.  This is accomplished by something like the following

<input type="text" name="wt" onDblClick="wtEnglish2Metric(this)"
 title="Enter a value in pounds(lbs) then double click to convert to kilograms(kg)"> 

<input type="text" name="ht" onDblClick="htEnglish2Metric(this)"
 title="Enter a value as feet and inches in the format ft'in"+'"'+" then double click to convert to centimeters (cm)">

<input type="text" name="bmi" onDblClick="calcBMIMetric(this,document.forms[0].wt,document.forms[0].ht)"
 title="Double click to calculate BMI">

To finish up put the following functions into the head block

<script>

function isNumber(ss){
	var s = ss.value;
    var i;
    for (i = 0; i < s.length; i++){
        // Check that current character is number.
        var c = s.charAt(i);
		if (c == '.') {
			continue;
		} else if (((c < "0") || (c > "9"))) {
            alert('Invalid '+s+' in field ' + ss.name);
            ss.focus();
             return false;
		}
    }
    // All characters are numbers.
    return true;
}

function wtEnglish2Metric(obj) {
	if(isNumber(obj) ) {
		weight = obj.value;
		weightM = Math.round(weight * 10 * 0.4536) / 10 ;
		if(confirm("Are you sure you want to change " + weight + " pounds to " + weightM +"kg?") ) {
			obj.value = weightM;
		}
	}
}

function htEnglish2Metric(obj) {
	height = obj.value;
	if(height.length > 1 && height.indexOf("'") > 0 ) {
		feet = height.substring(0, height.indexOf("'"));
		inch = height.substring(height.indexOf("'"));
		if(inch.length == 1) {
			inch = 0;
		} else {
			inch = inch.charAt(inch.length-1)=='"' ? inch.substring(0, inch.length-1) : inch;
			inch = inch.substring(1);
		}
			height = Math.round((feet * 30.48 + inch * 2.54) * 10) / 10 ;
			if(confirm("Are you sure you want to change " + feet + " feet " + inch + " inch(es) to " + height +"cm?") ) {
				obj.value = height;
			}
	}
}

function calcBMIMetric(obj,wtobj,htobj) {
   	if(isNumber(document.forms[0].c_ppwt) && isNumber(document.forms[0].c_ppht)) {
   		weight = wtobj.value / 1;
   		height = htobj.value / 100;
   		if(weight!="" && weight!="0" && height!="" && height!="0") {
   			obj.value = Math.round(weight * 10 / height / height) / 10;
   		} else obj.value = '0.0';
   	}
}

</script>

Customizing Fonts in the Input Fields

Put the following between the <head></head>

<style type="text/css">
.style1 {
	font-family: arial, sans-serif;
	font-size: 12px;
	font-weight: normal;
	}
</style>

For more styling, check out the css fonts page at W3schools.com

Insert class=”style1″ as an attribute into the <tag> that you want to customize the text. For example:

<div style="position: absolute; left: 100px; top: 100px;"> 
	<input name="SingleLineInputName" type="text" class="style1" style="width: 100px;">
</div>

If you want to apply multiple styles to the same element, just separate the classes by a space. For example:

<div style="position: absolute; left: 100px; top: 100px;"> 
	<input name="SingleLineInputName" type="text" class="noborder style1" style="width: 100px;">
</div>

Sniffing Data

Date Joined

A specialist will often need to reference the date that the patient was referred, however there is no way (short of writing a custom apconfig.xml!) to get that information from a eForm database tag. But we often can find the information in OSCAR if we sniff for it!

<!---  Script to get "Date Joined" from the demographic to use as the date referred --->
<script>

    function getDateJoined() {
        xmlhttp = new XMLHttpRequest();
        var pathArray = window.location.href;
        var mydemographic = /demographic_no=(.*?)&appointment/;
        var demoNumber = (mydemographic.exec(pathArray))[1];
        var myURL = /^(.*?)\/eform/;
        var URL = (myURL.exec(pathArray))[1];
        var newURL = URL + "/demographic/demographiccontrol.jsp?demographic_no=" + demoNumber + "&displaymode=edit&dboperation=search_detail";
        xmlhttp.onreadystatechange = function() {
            if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
                var str = xmlhttp.responseText;
                if (!str) {
                    return;
                }
                var demoArray = /Date Joined:<\/span>\s*<span class="info">([0-9,-]+)<\/span>/g;
                var demo = (demoArray.exec(str))[1];
                getDemographicById('dateJoined').value = demo;

            }
        }
        xmlhttp.open("GET", newURL, false);
        xmlhttp.send();
    } 
</script>

Another Date Format

The date format from the oscarDB=today tag is yyyy-mm-dd.  However what if you want dd-mm-yyyy?  Here is a way with options for numeric or text month (current example is for numeric month with text month commented out)

NOTE that this code uses a hidden input to set a flag on save so that the date is not re-parsed (and scrambled!) when the eForm is reopened after save.  This code uses a few jQuery lines so either ensure that jQuery is referenced before this code block, or replace the selector with vanilla getElementById().

For the <head> block:

<script>
    function submission() { // requires type="submit" in submit button input to allow for validity testing
        setFlag();
        saveSig();
        releaseDirtyFlag();
    }

function setFlag() {
    // indicate that the form has been submitted
    if (document.getElementById("newForm").value == 'True')
        document.getElementById("newForm").value = 'False';
}

function setDefaults() {
    // check the newform flag to ensure this is the initial load of the form
    if (document.getElementById("newForm").value == 'True') {

        parseDate('today', 0, 1, 2, '-', '/');

    } else { // actions if eForm is reopened
    }
}


/****************************
Create date in dd/mm/yyyy format;
Oscar default is yyyy-mm-dd
****************************/

function parseDate(id, x, y, z, D, d) {
    // Now included code to remove time from dates
    // Change date field to dd/mmm/yyyy format
    //The element that you want to change is passed via the id
    // If the initial order is  YYYY  MM  DD then x should be 0,y should be 1, and z should be 2
    // If the initial order is  DD  MM and YYYY then x should be 2,y should be 1, and z should be 0
    // Delimiter (between the digits for day month and year) is passed as D - usually either a "-"  or a "/"
    // Output Delimiter (between the digits for day month and year) is passed as d - usually either a "-"  or a "/"
    // Get the date
    var fullMeasurementDate = $("#" + id).val();
    var fullDate = fullMeasurementDate.split(' ')[0];

    if (fullDate) {
        // Split the value
        var year = fullDate.split(D)[x];
        var monthNum = fullDate.split(D)[y];
        var monthNumArray = monthNum - 1;
        var day = fullDate.split(D)[z];
        // Convert Numeric Month to 3 letter month using toLocaleString
        var date = new Date(year, monthNumArray, day);
        var month = date.toLocaleString('default', {
            month: 'short'
        });
        var mixedDate = day + d + month + d + year;
        var numericDate = day + d + monthNum + d + year;
        // Show the fields on the page
        //  $("#" + id).val(mixedDate);
        $("#" + id).val(numericDate);
    } else {
        $("#" + id).attr("placeholder", "d/m/yyyy");
    }
}

</script>

For the <form> block:

<input name = "today" id = "today" type = "text" class = "noborder"
style = "position:absolute; left:600px; top:300px; width:100px; "
oscarDB = today >

    <table> < tr > < td >
    <input type = "hidden" name = "newForm" id = "newForm" value = "True" >
    Subject: < input name = "subject" size = "40" type = "text" > < br >
    <input value = "Reset" name = "ResetButton" id = "ResetButton" type = "reset" style = "color:red;" onclick = "history.go(0);" / >
    <input value = "Print" name = "PrintButton" id = "PrintButton" type = "button" onclick = "printLetter();" / >
    <input value = "Submit" name = "SubmitButton" id = "SubmitButton" type = "submit" onclick = "submission();" / >
    </td></tr > < /table>

Reformatting Tags – Initialing a Form

As long as the source tags are in the form, you can reformat them in code to populate a custom input

For the <head> in <script>:

inItials("initials");

function inItials(id) {
    // Use charAt() to get first and last initial of current user
    var FirstLast = document.getElementById("current_user_fname_lname").value;
    var LastFirst = document.getElementById("current_user").value;
    var F = FirstLast.charAt(0);
    var L = LastFirst.charAt(0);
    var Initials = ( F + "." + L + "." );
    document.getElementById(id).
    value = Initials;
}

in the <body>:

<input type = "hidden" name = "current_user_fname_lname" id = "current_user_fname_lname" oscarDB = current_user_fname_lname >
<input type = "hidden" name = "current_user" id = "current_user" oscarDB = current_user >
<input name="initials" id="initials" type="text" class=" noborder" style="width:35px; font-family:sans-serif; font-style:normal; font-weight:normal; font-size:14px; text-align:left; background-color:transparent;"  />

That’s it.

Uploading it to your OSCAR server

Almost done! Make sure you save the file first.

Upload your eForm image file onto OSCAR first:

  1. Click on “Administration”
  2. Under “Manage eForms”, click on “Upload an Image”
  3. Browse to your image file, and click “Upload”

Now upload your html file:

  1. Under “Manage eForms”, click on “Upload”
  2. Type in the “eForm name”, and “Additional Information”
  3. Click “Choose File”, browse to you eForm html file
  4. Click on “Upload”

Once the html file is uploaded, make sure you add the ${oscar_image_path} back into the <img> tag

<div style="position: absolute; left: 10px; top: 10px;" >
	<img src="${oscar_image_path}imagename.png" width="750">
</div >
<!-- You can remove ${oscar_image_path} as you develop the eForm, but make sure you put it back before uploading to OSCAR otherwise the image wouldn't show. -->
<!-- Also note: the image filename IS CASE SENSITIVE INCLUDING THE EXTENSION. It may work otherwise in Windows, but not in OSCAR because it's based on a Linux platform -->

That’s it! Now you can make your own eForm for your office!

Just a few reminders:

  • Make sure you have a unique name for each input element
  • The filenames and image names are case sensitive
  • You can upload js/css files to the Oscar eForm images folder as well

Acknowledgements

Some info contributed by Peter Hutten-Czapski. Most is by Adrian Starzynski.

Table of Contents