Have you implemented OpenMRS? Please participate in the Implementation Site Survey. If you already have, thank you!
Page tree
Skip to end of metadata
Go to start of metadata

This guide is targeted for openmrs developers who are looking to Embed HTML Form Entry module generated Form into a Separate OpenMRS module view/jsp

Something look like this: -->

 

Actually we need only two files to get things done:   

  1. HtmlFormEntryController.java : https://github.com/openmrs/openmrs-module-htmlformentry/blob/master/omod/src/main/java/org/openmrs/module/htmlformentry/web/controll/HtmlFormEntryController.java


    But to backup the HTML form entry dependent files, you have to add the HTML form entry API maven dependency into the POM

     

        <properties>
          ...
            <htmlformentryModuleVersion>2.1.1</htmlformentryModuleVersion>
          ...
        </properties>
     
            <dependency>
                <groupId>org.openmrs.module</groupId>
                <artifactId>htmlformentry-api</artifactId>
                <version>${htmlformentryModuleVersion}</version>
                <scope>provided</scope>
            </dependency>
  2. htmlFormEntry.jsp : https://github.com/openmrs/openmrs-module-htmlformentry/blob/master/omod/src/main/webapp/htmlFormEntry.jsp
     Notice the  ${command.htmlToDisplay}  <%-- THIS is where the Magic happens: Rendering the HTML form and displaying on this particular Div --%>
package org.openmrs.module.patientnarratives.web.controller;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Collections;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.Encounter;
import org.openmrs.Form;
import org.openmrs.Patient;
import org.openmrs.api.context.Context;
import org.openmrs.module.htmlformentry.BadFormDesignException; // <------- these imports will be taken after you update the maven dependencies in POM
import org.openmrs.module.htmlformentry.FormEntryContext.Mode;
import org.openmrs.module.htmlformentry.FormEntrySession;
import org.openmrs.module.htmlformentry.FormSubmissionError;
import org.openmrs.module.htmlformentry.HtmlForm;
import org.openmrs.module.htmlformentry.HtmlFormEntryUtil;
import org.openmrs.module.htmlformentry.ValidationException;
import org.openmrs.util.OpenmrsUtil;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.StringUtils;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.view.RedirectView;
/**
 * The controller for entering/viewing a form.
 * <p/>
 * Handles {@code htmlFormEntry.form} requests. Renders view {@code htmlFormEntry.jsp}.
 * <p/>
 * TODO: This has a bit too much logic in the onSubmit method. Move that into the FormEntrySession.
 */
@Controller
public class HtmlFormEntryEmbedController {
    protected final Log log = LogFactory.getLog(getClass());
//    public final static String closeDialogView = "/module/htmlformentry/closeDialog";
    public final static String FORM_IN_PROGRESS_KEY = "HTML_FORM_IN_PROGRESS_KEY";
    public final static String FORM_IN_PROGRESS_VALUE = "HTML_FORM_IN_PROGRESS_VALUE";
    public final static String FORM_PATH = "/module/patientnarratives/htmlFormEntry";
    @RequestMapping(method=RequestMethod.GET, value=FORM_PATH)
    public void showForm() {
        // Intentionally blank. All work is done in the getFormEntrySession method
    }
    @ModelAttribute("command")
    public FormEntrySession getFormEntrySession(HttpServletRequest request,
                                                // @RequestParam doesn't pick up query parameters (in the url) in a POST, so I'm handling encounterId, modeParam, and which specially
                                                /*@RequestParam(value="mode", required=false) String modeParam,*/
                                                /*@RequestParam(value="encounterId", required=false) Integer encounterId,*/
                                                /*@RequestParam(value="which", required=false) String which,*/
                                                @RequestParam(value="patientId", required=false) Integer patientId,
                                                /*@RequestParam(value="personId", required=false) Integer personId,*/
                                                @RequestParam(value="formId", required=false) Integer formId,
                                                @RequestParam(value="htmlformId", required=false) Integer htmlFormId,
                                                @RequestParam(value="returnUrl", required=false) String returnUrl,
                                                @RequestParam(value="formModifiedTimestamp", required=false) Long formModifiedTimestamp,
                                                @RequestParam(value="encounterModifiedTimestamp", required=false) Long encounterModifiedTimestamp,
                                                @RequestParam(value="hasChangedInd", required=false) String hasChangedInd) throws Exception {
        long ts = System.currentTimeMillis();
        Mode mode = Mode.VIEW;
        Integer personId = null;
        patientId   = 2;
        formId = 3; // <-----------------------this is where you need to mention the FORM ID or HTML Form id in below variable
        htmlFormId = 1; //<--------------------|
         //Integer.parseInt(request.getParameter("formId"));
//        if (StringUtils.hasText(request.getParameter("personId"))) {
//            personId = Integer.valueOf(request.getParameter("personId"));
//        }
        String modeParam = request.getParameter("mode");
        if ("enter".equalsIgnoreCase(modeParam)) {
            mode = Mode.ENTER;
        }
        else if ("edit".equalsIgnoreCase(modeParam)) {
            mode = Mode.EDIT;
        }
        Patient patient = null;
        Encounter encounter = null;
        Form form = null;
        HtmlForm htmlForm = null;
        if (StringUtils.hasText(request.getParameter("encounterId"))) {
            Integer encounterId = Integer.valueOf(request.getParameter("encounterId"));
            encounter = Context.getEncounterService().getEncounter(encounterId);
            if (encounter == null)
                throw new IllegalArgumentException("No encounter with id=" + encounterId);
            patient = encounter.getPatient();
            patientId = patient.getPatientId();
            personId = patient.getPersonId();
            if (formId != null) { // I think formId is allowed to differ from encounter.form.id because of HtmlFormFlowsheet
                form = Context.getFormService().getForm(formId);
                htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(form);
                if (htmlForm == null)
                    throw new IllegalArgumentException("No HtmlForm associated with formId " + formId);
            } else {
                form = encounter.getForm();
                htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(encounter.getForm());
                if (htmlForm == null)
                    throw new IllegalArgumentException("The form for the specified encounter (" + encounter.getForm() + ") does not have an HtmlForm associated with it");
            }
        } else { // no encounter specified
            // get person from patientId/personId (register module uses patientId, htmlformentry uses personId)
            if (patientId != null) {
                personId = patientId;
            }
            if (personId != null) {
                patient = Context.getPatientService().getPatient(personId);
            }
            // determine form
            if (htmlFormId != null) {
                htmlForm = HtmlFormEntryUtil.getService().getHtmlForm(htmlFormId);
            } else if (formId != null) {
                form = Context.getFormService().getForm(formId);
                htmlForm = HtmlFormEntryUtil.getService().getHtmlFormByForm(form);
            }
            if (htmlForm == null) {
                throw new IllegalArgumentException("You must specify either an htmlFormId or a formId for a valid html form");
            }
            String which = request.getParameter("which");
            if (StringUtils.hasText(which)) {
                if (patient == null)
                    throw new IllegalArgumentException("Cannot specify 'which' without specifying a person/patient");
                List<Encounter> encs = Context.getEncounterService().getEncounters(patient, null, null, null, Collections.singleton(form), null, null, false);
                if (which.equals("first")) {
                    encounter = encs.get(0);
                } else if (which.equals("last")) {
                    encounter = encs.get(encs.size() - 1);
                } else {
                    throw new IllegalArgumentException("which must be 'first' or 'last'");
                }
            }
        }
        if (mode != Mode.ENTER && patient == null)
            throw new IllegalArgumentException("No patient with id of personId=" + personId + " or patientId=" + patientId);
        FormEntrySession session = null;
        if (mode == Mode.ENTER && patient == null) {
            patient = new Patient();
        }
        if (encounter != null) {
            session = new FormEntrySession(patient, encounter, mode, htmlForm, request.getSession());
        }
        else {
            session = new FormEntrySession(patient, htmlForm, request.getSession());
        }
        if (StringUtils.hasText(returnUrl)) {
            session.setReturnUrl(returnUrl);
        }
        // Since we're not using a sessionForm, we need to check for the case where the underlying form was modified while a user was filling a form out
        if (formModifiedTimestamp != null) {
            if (!OpenmrsUtil.nullSafeEquals(formModifiedTimestamp, session.getFormModifiedTimestamp())) {
                throw new RuntimeException(Context.getMessageSourceService().getMessage("htmlformentry.error.formModifiedBeforeSubmission"));
            }
        }
        // Since we're not using a sessionForm, we need to make sure this encounter hasn't been modified since the user opened it
        if (encounter != null) {
            if (encounterModifiedTimestamp != null && !OpenmrsUtil.nullSafeEquals(encounterModifiedTimestamp, session.getEncounterModifiedTimestamp())) {
                throw new RuntimeException(Context.getMessageSourceService().getMessage("htmlformentry.error.encounterModifiedBeforeSubmission"));
            }
        }
        if (hasChangedInd != null) session.setHasChangedInd(hasChangedInd);
        Context.setVolatileUserData(FORM_IN_PROGRESS_KEY, session);
        log.info("Took " + (System.currentTimeMillis() - ts) + " ms");
        return session;
    }
    /*
     * I'm using a return type of ModelAndView so I can use RedirectView rather than "redirect:" and preserve the fact that
     * returnUrl values from the pre-annotated-controller days will have the context path already
     */
    @RequestMapping(method=RequestMethod.POST, value=FORM_PATH)
    public ModelAndView handleSubmit(@ModelAttribute("command") FormEntrySession session,
                                     Errors errors,
                                     HttpServletRequest request,
                                     Model model) throws Exception {
        try {
            List<FormSubmissionError> validationErrors = session.getSubmissionController().validateSubmission(session.getContext(), request);
            if (validationErrors != null && validationErrors.size() > 0) {
                errors.reject("Fix errors");
            }
        } catch (Exception ex) {
            log.error("Exception during form validation", ex);
            errors.reject("Exception during form validation, see log for more details: " + ex);
        }
        if (errors.hasErrors()) {
            return new ModelAndView(FORM_PATH, "command", session);
        }
        // no form validation errors, proceed with submission
        session.prepareForSubmit();
        if (session.getContext().getMode() == Mode.ENTER && session.hasPatientTag() && session.getPatient() == null
                && (session.getSubmissionActions().getPersonsToCreate() == null || session.getSubmissionActions().getPersonsToCreate().size() == 0))
            throw new IllegalArgumentException("This form is not going to create an Patient");
        if (session.getContext().getMode() == Mode.ENTER && session.hasEncouterTag() && (session.getSubmissionActions().getEncountersToCreate() == null || session.getSubmissionActions().getEncountersToCreate().size() == 0))
            throw new IllegalArgumentException("This form is not going to create an encounter");
        try {
            session.getSubmissionController().handleFormSubmission(session, request);
            HtmlFormEntryUtil.getService().applyActions(session);
            String successView = session.getReturnUrlWithParameters();
            if (successView == null)
                successView = request.getContextPath() + "/patientDashboard.form" + getQueryPrameters(request, session);
            if (StringUtils.hasText(request.getParameter("closeAfterSubmission"))) {
//                return new ModelAndView(closeDialogView, "dialogToClose", request.getParameter("closeAfterSubmission"));
            } else {
                return new ModelAndView(new RedirectView(successView));
            }
        } catch (ValidationException ex) {
            log.error("Invalid input:", ex);
            errors.reject(ex.getMessage());
        } catch (BadFormDesignException ex) {
            log.error("Bad Form Design:", ex);
            errors.reject(ex.getMessage());
        } catch (Exception ex) {
            log.error("Exception trying to submit form", ex);
            StringWriter sw = new StringWriter();
            ex.printStackTrace(new PrintWriter(sw));
            errors.reject("Exception! " + ex.getMessage() + "<br/>" + sw.toString());
        }
        // if we get here it's because we caught an error trying to submit/apply
        return new ModelAndView(FORM_PATH, "command", session);
    }
    protected String getQueryPrameters(HttpServletRequest request, FormEntrySession formEntrySession) {
        return "?patientId=" + formEntrySession.getPatient().getPersonId();
    }
}
<%@ include file="/WEB-INF/template/include.jsp" %>

<openmrs:htmlInclude file="${pageContext.request.contextPath}/moduleResources/patientnarratives/css/styles.css"/>

<%@ page import="net.tanesha.recaptcha.ReCaptcha" %>
<%@ page import="net.tanesha.recaptcha.ReCaptchaFactory" %>

<c:set var="OPENMRS_DO_NOT_SHOW_PATIENT_SET" scope="request" value="true"/>
<c:set var="pageFragment" value="${param.pageFragment != null && param.pageFragment}"/>
<c:set var="inPopup" value="${pageFragment || (param.inPopup != null && param.inPopup)}"/>

<c:if test="${not pageFragment}">
    <c:set var="DO_NOT_INCLUDE_JQUERY" value="true"/>
    <c:choose>
        <c:when test="${inPopup}">
            <%@ include file="/WEB-INF/template/headerMinimal.jsp" %>
        </c:when>
        <c:otherwise>
            <%@ include file="/WEB-INF/template/header.jsp" %>
        </c:otherwise>
    </c:choose>

    <openmrs:htmlInclude file="/dwr/engine.js" />
    <openmrs:htmlInclude file="/dwr/util.js" />
    <openmrs:htmlInclude file="/dwr/interface/DWRHtmlFormEntryService.js" />
    <openmrs:htmlInclude file="/moduleResources/htmlformentry/htmlFormEntry.js" />
    <openmrs:htmlInclude file="/moduleResources/htmlformentry/htmlFormEntry.css" />
    <openmrs:htmlInclude file="/moduleResources/htmlformentry/jquery-ui-1.8.17.custom.css" />
    <openmrs:htmlInclude file="/moduleResources/htmlformentry/jquery-1.4.2.min.js" />
    <script type="text/javascript">
        $j = jQuery.noConflict();
    </script>
    <openmrs:htmlInclude file="/moduleResources/htmlformentry/jquery-ui-1.8.17.custom.min.js" />
</c:if>

<script type="text/javascript">
    var propertyAccessorInfo = new Array();
    
    // individual forms can define their own functions to execute before a form validation or submission by adding them to these lists
    // if any function returns false, no further functions are called and the validation or submission is cancelled
    var beforeValidation = new Array();     // a list of functions that will be executed before the validation of a form
    var beforeSubmit = new Array();         // a list of functions that will be executed before the submission of a form

    // boolean to track whether or not jquery document ready function fired
    var initInd = true;

   // booleans used to track whether we are in the process of submitted or discarding a formk
   var isSubmittingInd = false;
   var isDiscardingInd = false;

    $j(document).ready(function() {
        $j('#deleteButton').click(function() {
            // display a "deleting form" message
            $j('#confirmDeleteFormPopup').children("center").html('<spring:message code="htmlformentry.deletingForm"/>');
            
            // do the post that does the actual delete
            $j.post("<c:url value="/module/htmlformentry/deleteEncounter.form"/>", 
                {     encounterId: "${command.encounter.encounterId}", 
                    htmlFormId: "${command.htmlFormId}",
                    returnUrl: "${command.returnUrlWithParameters}", 
                    reason: $j('#deleteReason').val()
                 }, 
                 function(data) {
                     var url = "${command.returnUrlWithParameters}";
                     if (url == null || url == "") {
                         url = "${pageContext.request.contextPath}/patientDashboard.form?patientId=${command.patient.patientId}";
                     }
                     window.parent.location.href = url;
                 }
             );
        });

        // triggered whenever any input with toggleDim attribute is changed.  Currently, only supports
        // checkbox style inputs.
        $j('input[toggleDim]').change(function () {
            var target = $j(this).attr("toggleDim");
            if ($j(this).is(":checked")) {
                $j("#" + target + " :input").removeAttr('disabled');
                $j("#" + target).animate({opacity:1.0}, 0);
                restoreContainerInputs($j("#" + target));
            } else {
                $j("#" + target + " :input").attr('disabled', true);
                $j("#" + target).animate({opacity:0.5}, 100);
                clearContainerInputs($j("#" + target));
            }
        })
        .change();

        // triggered whenever any input with toggleHide attribute is changed.  Currently, only supports
        // checkbox style inputs.
        $j('input[toggleHide]').change(function () {
            var target = $j(this).attr("toggleHide");
            if ($j(this).is(":checked")) {
                $j("#" + target).fadeIn();
                restoreContainerInputs($j("#" + target));
            } else {
                $j("#" + target).hide();
                clearContainerInputs($j("#" + target));
            }
        })
        .change();

        // triggered whenever any input widget on the page is changed
           $j(':input').change(function () {
            $j(':input.has-changed-ind').val('true');
        });

        // warn user that his/her changes will be lost if he/she leaves the page
        $j(window).bind('beforeunload', function(){
            var hasChangedInd = $j(':input.has-changed-ind').val();
            if (hasChangedInd == 'true' && !isSubmittingInd && !isDiscardingInd) {
                return '<spring:message code="htmlformentry.loseChangesWarning"/>';
            }
        });

        // catch form submit button (not currently used)
        $j('form').submit(function() {
            isSubmittingInd = true;
            return true;
        });

        // catch when button with class submitButton is clicked (currently used)
        $j(':input.submitButton').click(function() {
            isSubmittingInd = true;
            return true;
        });

        // catch when discard link clicked
        $j('.html-form-entry-discard-changes').click(function() {
            isDiscardingInd = true;
            return true;
        });

        // indicates this function has completed
        initInd = false;
        
        //managing the id of the newly generated id's of dynamicAutocomplete widgets
        $j('div .dynamicAutocomplete').each(function(index) {
            var string=((this.id).split("_div",1))+"_hid";
            if(!$j('#'+string).attr('value'))
                $j('#'+this.id).data("count",0);
            else
                $j('#'+this.id).data("count",parseInt($j('#'+string).attr('value')));
            });
        //add button for dynamic autocomplete
        $j(':button.addConceptButton').click(function() {
                  var string=(this.id).replace("_button","");
                var conceptValue=$j('#'+string+'_hid').attr('value')
                if($j('#'+string).css('color')=='green'){
                    var    divId=string+"_div";
                     var spanid=string+'span_'+ $j('#'+divId).data("count");
                     var count= $j('#'+divId).data("count");
                     $j('#'+divId).data("count",++count);
                     $j('#'+string+'_hid').attr('value',$j('#'+divId).data("count"));
                     var hidId=spanid+'_hid';
                       var v='<span id="'+spanid+'"></br>'+$j('#'+string).val()+'<input id="'+hidId+'"  class="autoCompleteHidden" type="hidden" name="'+hidId+'" value="'+conceptValue+'">';
                     var q='<input id="'+spanid+'_button" type="button" value="Remove" onClick="$j(\'#'+spanid+'\').remove();openmrs.htmlformentry.refresh(this.id)"></span>';
                     $j('#'+divId).append(v+q);
                     $j('#'+string).val('');
            } 
            });
    });

    // clear toggle container's inputs but saves the input values until form is submitted/validated in case the user
    // re-clicks the trigger checkbox.  Note: These "saved" input values will be lost if the form fails validation on submission.
    function clearContainerInputs($container) {
        if (!initInd) {
            $container.find('input:text, input:password, input:file, select, textarea').each( function() {
                $j(this).data('origVal',this.value);
                $j(this).val("");
            });
            $container.find('input:radio, input:checkbox').each( function() {
                if ($j(this).is(":checked")) {
                    $j(this).data('origState','checked');
                    $j(this).removeAttr("checked");
                } else {
                    $j(this).data('origState','unchecked');
                }
            });
        }
    }
    
    // restores toggle container's inputs from the last time the trigger checkbox was unchecked
    function restoreContainerInputs($container) {
        if (!initInd) {
            $container.find('input:text, input:password, input:file, select, textarea').each( function() {
                $j(this).val($j(this).data('origVal'));
            });
            $container.find('input:radio, input:checkbox').each( function() {
                if ($j(this).data('origState') == 'checked') {
                    $j(this).attr("checked", "checked");
                } else {
                    $j(this).removeAttr("checked");
                }
            });
        }
    }

    var tryingToSubmit = false;
    
    function submitHtmlForm() {
        if (!tryingToSubmit) {
            tryingToSubmit = true;
            DWRHtmlFormEntryService.checkIfLoggedIn(checkIfLoggedInAndErrorsCallback);
        }
    }

    function findAndHighlightErrors(){
        /* see if there are error fields */
        var containError = false;
        var ary = $j(".autoCompleteHidden");
        $j.each(ary,function(index, value){
            if(value.value == "ERROR"){
                if(!containError){
                    alert("<spring:message code='htmlformentry.error.autoCompleteAnswerNotValid'/>");
                    var id = value.id;
                    id = id.substring(0,id.length-4);
                    $j("#"+id).focus();                     
                }
                containError=true;
            }
        });
        return containError;
    }

    function findOptionAutoCompleteErrors() {
        /* see if there are  errors in option fields */
        var containError = false;
        var ary = $j(".optionAutoCompleteHidden");
        $j.each(ary,function(index, value){
            if(value.value == "ERROR"){
                if(!containError){
                    alert("<spring:message code='htmlformentry.error.autoCompleteOptionNotValid'/>");
                    var id = value.id;
                    id = id.substring(0,id.length-4);
                    $j("#"+id).focus();
                }
                containError=true;
            }
        });
        return containError;
    }

    /*
        It seems the logic of  showAuthenticateDialog and 
        findAndHighlightErrors should be in the same callback function.
        i.e. only authenticated user can see the error msg of
    */
    function checkIfLoggedInAndErrorsCallback(isLoggedIn) {
        
        var state_beforeValidation=true;
        
        if (!isLoggedIn) {
            showAuthenticateDialog();
        }else{
            
            // first call any beforeValidation functions that may have been defined by the html form
            if (beforeValidation.length > 0){
                for (var i=0, l = beforeValidation.length; i < l; i++){
                    if (state_beforeValidation){
                        var fncn=beforeValidation[i];                        
                        state_beforeValidation=eval(fncn);
                    }
                    else{
                        // forces the end of the loop
                        i=l;
                    }
                }
            }
            
            // only do the validation if all the beforeValidationk functions returned "true"
            if (state_beforeValidation){
                var anyErrors = findAndHighlightErrors();
                var optionSelectErrors = findOptionAutoCompleteErrors();
            
                if (anyErrors || optionSelectErrors) {
                    tryingToSubmit = false;
                    return;
                }else{
                    doSubmitHtmlForm();
                }
            }
        }
    }

    function showAuthenticateDialog() {
        $j('#passwordPopup').show();
        tryingToSubmit = false;
    }

    function loginThenSubmitHtmlForm() {
        
        $j('#passwordPopup').hide();
        var username = $j('#passwordPopupUsername').val();
        var password = $j('#passwordPopupPassword').val();
        $j('#passwordPopupUsername').val('');
        $j('#passwordPopupPassword').val('');
        DWRHtmlFormEntryService.authenticate(username, password, submitHtmlForm); 
    }

    function doSubmitHtmlForm() {
        
        // first call any beforeSubmit functions that may have been defined by the form
        var state_beforeSubmit=true;
        if (beforeSubmit.length > 0){
            for (var i=0, l = beforeSubmit.length; i < l; i++){
                if (state_beforeSubmit){
                    var fncn=beforeSubmit[i];                        
                    state_beforeSubmit=fncn();                    
                }
                else{
                    // forces the end of the loop
                    i=l;
                }
            }
        }
        
        // only do the submit if all the beforeSubmit functions returned "true"
        if (state_beforeSubmit){
            var form = document.getElementById('htmlform');
            form.submit();            
        }
        tryingToSubmit = false;
    }

    function handleDeleteButton() {
        $j('#confirmDeleteFormPopup').show();
    }

    function cancelDeleteForm() {
        $j('#confirmDeleteFormPopup').hide();
    }
    
    
</script>

<%-- yes you see, these are not nessasary!.. 
<div id="htmlFormEntryBanner">--%>
    <%--<spring:message var="backMessage" code="htmlformentry.goBack"/>--%>
    <%--<c:if test="${!inPopup && (command.context.mode == 'ENTER' || command.context.mode == 'EDIT')}">--%>
        <%--<spring:message var="backMessage" code="htmlformentry.discard"/>--%>
    <%--</c:if>--%>
    <%--<div style="float: left" id="discardAndPrintDiv">--%>
        <%--<c:if test="${!inPopup}">--%>
            <%--<span id="discardLinkSpan"><a href="<c:choose><c:when test="${not empty command.returnUrlWithParameters}">${command.returnUrlWithParameters}</c:when><c:otherwise>${pageContext.request.contextPath}/patientDashboard.form?patientId=${command.patient.patientId}</c:otherwise></c:choose>" class="html-form-entry-discard-changes">${backMessage}</a></span> | --%>
        <%--</c:if>--%>
        <%--<span id="printLinkSpan"><a href="javascript:window.print();"><spring:message code="htmlformentry.print"/></a></span> &nbsp;<br/>--%>
    <%--</div>--%>
    <%--<div style="float:right">--%>
        <%--<c:if test="${command.context.mode == 'VIEW'}">--%>
            <%--<c:if test="${!inPopup}">--%>
                <%--<openmrs:hasPrivilege privilege="Edit Encounters,Edit Observations">--%>
                    <%--<c:url var="editUrl" value="/module/htmlformentry/htmlFormEntry.form">--%>
                        <%--<c:forEach var="p" items="${param}">--%>
                            <%--<c:if test="${p.key != 'mode'}">--%>
                                <%--<c:param name="${p.key}" value="${p.value}"/>--%>
                            <%--</c:if>--%>
                        <%--</c:forEach>--%>
                        <%--<c:param name="mode" value="EDIT"/>--%>
                    <%--</c:url>--%>
                    <%--<a href="${editUrl}"><spring:message code="general.edit"/></a> |--%>
                <%--</openmrs:hasPrivilege>--%>
            <%--</c:if>--%>
            <%--<openmrs:hasPrivilege privilege="Delete Encounters,Delete Observations">--%>
                <%--<a onClick="handleDeleteButton()"><spring:message code="general.delete"/></a>--%>
                <%--<div id="confirmDeleteFormPopup" style="position: absolute; z-axis: 1; right: 0px; background-color: #ffff00; border: 2px black solid; display: none; padding: 10px">--%>
                    <%--<center>--%>
                        <%--<spring:message code="htmlformentry.deleteReason"/>--%>
                        <%--<br/>--%>
                        <%--<textarea name="reason" id="deleteReason"></textarea>--%>
                        <%--<br/><br/>--%>
                        <%--<input type="button" value="<spring:message code="general.cancel"/>" onClick="cancelDeleteForm()"/>--%>
                        <%--&nbsp;&nbsp;&nbsp;&nbsp;--%>
                        <%--<input type="button" value="<spring:message code="general.delete"/>" id="deleteButton"/>--%>
                    <%--</center>--%>
                <%--</div>--%>
            <%--</openmrs:hasPrivilege>--%>
        <%--</c:if>--%>
    <%--</div>--%>
    <%--<c:if test="${!inPopup}">--%>
        <%--<b>--%>
            <%--${command.patient.personName} |--%>
            <%--<c:choose>--%>
                <%--<c:when test="${not empty command.form}">--%>
                    <%--${command.form.name} (${command.form.encounterType.name})--%>
                <%--</c:when>--%>
                <%--<c:otherwise>--%>
                    <%--<c:if test="${not empty command.encounter}">--%>
                        <%--${command.encounter.form.name} (${command.encounter.encounterType.name})--%>
                    <%--</c:if>--%>
                <%--</c:otherwise> --%>
            <%--</c:choose>--%>
            <%----%>
            <%--|--%>
            <%--<c:if test="${not empty command.encounter}">--%>
                <%--<openmrs:formatDate date="${command.encounter.encounterDatetime}"/> | ${command.encounter.location.name} --%>
            <%--</c:if>--%>
            <%--<c:if test="${empty command.encounter}">--%>
                <%--<spring:message code="htmlformentry.newForm"/>--%>
            <%--</c:if>--%>
        <%--</b>--%>
    <%--</c:if>--%>
<%--</div>--%>

<c:if test="${command.context.mode != 'VIEW'}">
    <spring:hasBindErrors name="command">
        <spring:message code="fix.error"/>
        <div class="error">
            <c:forEach items="${errors.allErrors}" var="error">
                <spring:message code="${error.code}" text="${error.code}"/><br/>
            </c:forEach>
        </div>
        <br />
    </spring:hasBindErrors>
</c:if>

<c:if test="${command.context.mode != 'VIEW'}">
    <form id="htmlform" method="post" onSubmit="submitHtmlForm(); return false;">
        <input type="hidden" name="personId" value="${ command.patient.personId }"/>
        <input type="hidden" name="htmlFormId" value="${ command.htmlFormId }"/>
        <input type="hidden" name="formModifiedTimestamp" value="${ command.formModifiedTimestamp }"/>
        <input type="hidden" name="encounterModifiedTimestamp" value="${ command.encounterModifiedTimestamp }"/>
        <c:if test="${ not empty command.encounter }">
            <input type="hidden" name="encounterId" value="${ command.encounter.encounterId }"/>
        </c:if>
        <input type="hidden" name="closeAfterSubmission" value="${param.closeAfterSubmission}"/>
        <input type="hidden" name="hasChangedInd" class="has-changed-ind" value="${ command.hasChangedInd }" />
</c:if>

<c:if test="${command.context.guessingInd == 'true'}">
    <div class="error">
        <spring:message code="htmlformentry.form.reconstruct.warning" />
    </div>
</c:if>



<div id="main-wrap">

    <div id="sidebar">
        <div>

            ${command.htmlToDisplay}  <%-- THIS is where the Magic happens: Rendering the HTML form and displaying on this particular Div --%>
        </div>

    </div>
    <div id="content-wrap">
        <div id="info-wrap">
            <center>
                <canvas id="myCanvas" width="400" height="200" style="border:1px solid #000000;">
                    Your browser does not support the HTML5 canvas tag.
                </canvas>
            </center>

        </div>
        <div id="info-wrap">
            </br></br><span>Patient Narrative</span>
            <textarea rows="4" cols="50">
                Describe your narrative here.
            </textarea>
        </div>
        <div id="info-wrap">
            </br></br><span>Upload file (X-ray, reports, etc)</span>
            <input type="file" name="file" id="file" size="40"/>
        </div>
        <div id="info-wrap">
            </br></br>
            <%--<form action="" method="post">--%>
            <%
                ReCaptcha c = ReCaptchaFactory.newReCaptcha("6LdAWuMSAAAAAD3RQXMNBKgI9-1OiYjDx_sl0xYy", "6LdAWuMSAAAAALxWgnM5yRj_tGVRQCk4lit8rLHb", false);
                out.print(c.createRecaptchaHtml(null, null));
            %>

            </br>
            <input id="submit" type="button" value="Submit" />
            <%--</form>--%>
        </div>
    </div>


</div>



<c:if test="${command.context.mode != 'VIEW'}">
    <div id="passwordPopup" style="position: absolute; z-axis: 1; bottom: 25px; background-color: #ffff00; border: 2px black solid; display: none; padding: 10px">
        <center>
            <table>
                <tr>
                    <td colspan="2"><b><spring:message code="htmlformentry.loginAgainMessage"/></b></td>
                </tr>
                <tr>
                    <td align="right"><b>Username:</b></td>
                    <td><input type="text" id="passwordPopupUsername"/></td>
                </tr>
                <tr>
                    <td align="right"><b>Password:</b></td>
                    <td><input type="password" id="passwordPopupPassword"/></td>
                </tr>
                <tr>
                    <td colspan="2" align="center"><input type="button" value="Submit" onClick="loginThenSubmitHtmlForm()"/></td>
                </tr>
            </table>
        </center>
    </div>
</form>
</c:if>

<c:if test="${not empty command.fieldAccessorJavascript}">
    <script type="text/javascript">
        ${command.fieldAccessorJavascript}
    </script>
</c:if>
<c:if test="${not empty command.setLastSubmissionFieldsJavascript || not empty command.lastSubmissionErrorJavascript}"> 
    <script type="text/javascript">
        $j(document).ready( function() {
            ${command.setLastSubmissionFieldsJavascript}
            ${command.lastSubmissionErrorJavascript}

            $j('input[toggleDim]:not(:checked)').each(function () {
                var target = $j(this).attr("toggleDim");
                $j("#" + target + " :input").attr('disabled', true);
                $j("#" + target).animate({opacity:0.5}, 100);
            });

            $j('input[toggleDim]:checked').each(function () {
                var target = $j(this).attr("toggleDim");
                $j("#" + target + " :input").removeAttr('disabled');
                $j("#" + target).animate({opacity:1.0}, 0);
            });

            $j('input[toggleHide]:not(:checked)').each(function () {
                var target = $j(this).attr("toggleHide");
                $j("#" + target).hide();
            });

            $j('input[toggleHide]:checked').each(function () {
                var target = $j(this).attr("toggleHide");
                $j("#" + target).fadeIn();
            });

        });
    </script>
</c:if>

<c:if test="${!pageFragment}">
    <c:choose>
        <c:when test="${inPopup}">
            <%@ include file="/WEB-INF/template/footerMinimal.jsp" %>
        </c:when>
        <c:otherwise>
            <%@ include file="/WEB-INF/template/footer.jsp" %>
        </c:otherwise>
    </c:choose>
</c:if>