DrM Heallthland

Productivity enhancements to Healthland Centriq EHR

  1. // ==UserScript==
  2. // @name DrM Heallthland
  3. // @namespace jewelmirror.com
  4. // @include http://hlapp/Healthlandweb/*
  5. // @include https://pmp.doj.ca.gov/pdmp/*
  6. // @version 1.1
  7. // @description Productivity enhancements to Healthland Centriq EHR
  8. // @grant GM_setValue
  9. // @grant GM_getValue
  10. // @grant GM_setClipboard
  11. // @grant GM_xmlhttpRequest
  12. // @require https://code.jquery.com/jquery-2.0.3.min.js
  13. // @require https://code.jquery.com/ui/1.8.2/jquery-ui.js
  14. // @requre http://hlapp/Healthlandweb/Scripts/telerik/Input/DateInput/RadDateInputScript.js
  15. // ==/UserScript==
  16.  
  17. /*
  18. * $Source: /Users/cvsroot/DrM_Heallthland/DrM_Heallthland.user.js,v $
  19. * $Author: marcin $
  20. * $Revision: 1.11 $
  21. *
  22. * History
  23. * Version 1.0
  24. * Original release. Support for keyboard shortcuts, calculator for Mini Mental and ED Outpatient Level of
  25. * service, CURES
  26. * Version 1.1
  27. * CURES
  28. * DrM Logo in cures
  29. * New shortcuts
  30. * p - problem list
  31. * m - home medications
  32. * Calculators
  33. * Warfarin dosing calculator
  34. *---------------------------------------------------------------------------
  35. @licstart The following is the entire license notice for the
  36. JavaScript code in this page.
  37.  
  38. Copyright (C) 2025 Marcin Matuszkiewicz - marcin@jewelmirror.com
  39.  
  40. The JavaScript code in this page is free software: you can
  41. redistribute it and/or modify it under the terms of the GNU
  42. General Public License (GNU GPL) as published by the Free Software
  43. Foundation, either version 3 of the License, or (at your option)
  44. any later version. The code is distributed WITHOUT ANY WARRANTY;
  45. without even the implied warranty of MERCHANTABILITY or FITNESS
  46. FOR A PARTICULAR PURPOSE. See the GNU GPL for more details.
  47.  
  48. As additional permission under GNU GPL version 3 section 7, you
  49. may distribute non-source (e.g., minimized or compacted) forms of
  50. that code without the copy of the GNU GPL normally required by
  51. section 4, provided you include this license notice and a URL
  52. through which recipients can access the Corresponding Source.
  53.  
  54.  
  55. @licend The above is the entire license notice
  56. for the JavaScript code in this page
  57. */
  58.  
  59.  
  60. /********************************************************************
  61. * CURES Specific functions and data
  62. ********************************************************************/
  63. var CURESpages = {
  64. index : 'index.do',
  65. search_input : 'list.do',
  66. search_results : 'search.do',
  67. report: 'listPatients.do'
  68. };
  69.  
  70. function CURESSelectAllOnChange() {
  71. cb = document.getElementById('checkall_id');
  72. if (cb.checked) {
  73. CURESSelectAll();
  74. } else {
  75. CURESDeselectAll();
  76. }
  77. }
  78.  
  79. function CURESSelectAll() {
  80. ids = document.getElementsByName('ids');
  81.  
  82. for ( i = 0; i < ids.length; i++) {
  83. ids[i].checked = true;
  84. }
  85. }
  86.  
  87. function CURESDeselectAll() {
  88. ids = document.getElementsByName('ids');
  89.  
  90. for ( i = 0; i < ids.length; i++) {
  91. ids[i].checked = false;
  92. }
  93. }
  94.  
  95. function CURESIndex() {
  96. // You prefill your USERNAME
  97. document.getElementById('j_username').value = '';
  98. var pass = document.getElementById('j_password');
  99. pass.focus();
  100. // You can set pass.value to fill you PASSWROD
  101. pass.value = '';
  102. // Auto login
  103. // $('input:submit').click();
  104. // var inputs = document.getElementsByTagName('input');
  105. // for (var i in inputs) {
  106. // if (i.getAttribute('type') == 'submit') {
  107. // i.click();
  108. // }
  109. // }
  110. }
  111.  
  112. function CURESSearchInput() {
  113. var patientId = GM_getValue('patientId');
  114. var visitId = GM_getValue('visitId');
  115. if (patientId && visitId) {
  116. // var btn = $('#middleColumn').prepend('<input id="loadDemo" type="button" value="Load from HL">');
  117. $('[name="search"]').before('<input id="loadDemo" type="button" value="Load from HL">');
  118. $('#loadDemo').bind('click', loadDemographics);
  119. $('#loadDemo').before('<div id="loadingDemo">Loading</div>');
  120. $('#loadingDemo').css('background', 'yellow');
  121. // Load demographics by default
  122. loadDemographics();
  123. }
  124. var period_sel = document.getElementById('period');
  125. period_sel.value = '12';
  126.  
  127. var disclaimer_cb = document.getElementsByName('disclaimer');
  128. disclaimer_cb[0].setAttribute('checked', true);
  129. }
  130.  
  131. function CURESSearchResults(){
  132. var tab = document.getElementById('resultsTable');
  133.  
  134. var thead = tab.getElementsByTagName('thead');
  135.  
  136. var r = thead[0].insertRow(-1);
  137.  
  138. var cell0 = r.insertCell(0);
  139. var cell1 = r.insertCell(1);
  140. //cell0.setAttribute('colspan', '2');
  141.  
  142. var checkall_cb = document.createElement('input');
  143. checkall_cb.setAttribute('type', 'checkbox');
  144. checkall_cb.id = "checkall_id";
  145. checkall_cb.checked = true;
  146. checkall_cb.value = "SELECTALL";
  147.  
  148. cell0.appendChild(checkall_cb);
  149. cell1.innerHTML = 'Select All';
  150.  
  151. checkall_cb.addEventListener("click", CURESSelectAllOnChange, true);
  152.  
  153. CURESSelectAll();
  154. }
  155.  
  156.  
  157. /********************************************************************
  158. * Healthland specifiction fuctions
  159. ********************************************************************/
  160. function loadDemographics() {
  161. console.log('DrM: loading demographics');
  162. $('#loadDemo').hide();
  163. $('#loadingDemo').show();
  164. var href = 'http://hlapp/Healthlandweb/Demographics/FillDemographics?area=Demographics&patientId=';
  165. href += GM_getValue('patientId');
  166. href += '&visitId=';
  167. href += GM_getValue('visitId');
  168. console.log(href);
  169. GM_xmlhttpRequest({
  170. method: "GET",
  171. url: href,
  172. onload: processDemographics
  173. });
  174. }
  175.  
  176. function processDemographics(response) {
  177. console.log('processing Demographics');
  178. var demoDOM = new DOMParser().parseFromString(response.responseText, 'text/html');
  179. var dob = demoDOM.getElementById('Actual-DOB').value;
  180. var labels = demoDOM.getElementsByTagName('label');
  181. var lastName = labels[1].nextSibling.nextSibling.innerHTML.trim();
  182. var firstName = labels[2].nextSibling.nextSibling.innerHTML.trim();
  183. $('#lastName').val(lastName);
  184. $('#firstName').val(firstName);
  185. $('#dob').val(dob);
  186.  
  187. $('#loadDemo').show();
  188. $('#loadingDemo').hide();
  189. console.log(lastName);
  190. console.log(firstName);
  191. console.log(dob);
  192. }
  193.  
  194. function addCURES() {
  195. var ptChartMenu = document.getElementsByClassName('lineBlock')[1];
  196. if (!ptChartMenu) {
  197. return;
  198. }
  199. var wr = document.createElement('div');
  200. wr.setAttribute('class', 'main-button-wrapper');
  201. var el = document.createElement('input');
  202. el.setAttribute('type', 'button');
  203. el.setAttribute('id', 'CURES');
  204. // el.setAttribute('class', 'mainButtons');
  205. el.setAttribute('title', 'CURES');
  206. el.setAttribute('value', 'CURES');
  207. wr.appendChild(el);
  208. ptChartMenu.appendChild(wr);
  209. el.addEventListener('click', function() {
  210. var patientId = $('#current-patient-id').text().trim();
  211. var visitId = $('#current-visit-id').text().trim();
  212. if (!patientId.length || !visitId) {
  213. console.log('Select a ptient');
  214. return;
  215. }
  216. GM_setValue('patientId', patientId);
  217. GM_setValue('visitId', visitId);
  218. win = window.open('https://pmp.doj.ca.gov/pdmp/index.do');
  219. win.focus();
  220. });
  221. }
  222.  
  223. /********************************************************************
  224. * ASSESSMENT FUNCTIONS
  225. ********************************************************************/
  226. function addAssessMiniMentalButton() {
  227. $('#N_AFControl_18').after('<input id="idCalcScore" type="button" value="Calculate Score">');
  228. $('#idCalcScore').bind('click', calcAssessMiniMentalScore);
  229. console.log(btn);
  230. }
  231.  
  232. function calcAssessMiniMentalScore() {
  233. console.log('Calculating Minimental');
  234. var miniMentalTotal = 0;
  235. var orientationCheckboxes = $('input[groupid="286"]:checkbox');
  236. var orientationTotalInput = $('input[groupid="286"]:text');
  237. var miniMentalTotalInput = $('#N_AFControl_18');
  238. var tmpTotal = 0;
  239. for (var i=0; i < orientationCheckboxes.length; i++) {
  240. if (orientationCheckboxes[i].checked) {
  241. miniMentalTotal++;
  242. tmpTotal++;
  243. }
  244. }
  245. orientationTotalInput.val(tmpTotal);
  246. var sel = $('#N_AFControl_4 option:selected').text();
  247. if (sel.indexOf('-select-') >= 0) {
  248. tmpTotal = 0;
  249. } else {
  250. tmpTotal = parseInt(sel.split('=')[0]);
  251. }
  252. miniMentalTotal += tmpTotal;
  253. // Update Registration total input
  254. $('#N_AFControl_5').val(tmpTotal);
  255. var sel = $('#N_AFControl_6 option:selected').text();
  256. if (sel.indexOf('-select-') >= 0) {
  257. tmpTotal = 0;
  258. } else {
  259. tmpTotal = parseInt(sel.split('=')[0]);
  260. }
  261. miniMentalTotal += tmpTotal;
  262. // Update Attention total input
  263. $('#N_AFControl_7').val(tmpTotal);
  264.  
  265. var sel = $('#N_AFControl_8 option:selected').text();
  266. if (sel.indexOf('-select-') >= 0) {
  267. tmpTotal = 0;
  268. } else {
  269. tmpTotal = parseInt(sel.split('=')[0]);
  270. }
  271. miniMentalTotal += tmpTotal;
  272. // Update Attention total input
  273. $('#N_AFControl_10').val(tmpTotal);
  274.  
  275. tmpTotal = 0;
  276. for (var i = 11; i < 17; i++) {
  277. var sel = $('#N_AFControl_'+i+' option:selected').text();
  278. console.log(sel);
  279. if (sel.indexOf('-select-') >= 0) {
  280. tmpTotal += 0;
  281. } else {
  282. tmpTotal += parseInt(sel.split('=')[0]);
  283. }
  284. }
  285. miniMentalTotal += tmpTotal;
  286. // Update Attention total input
  287. $('#N_AFControl_17').val(tmpTotal);
  288. miniMentalTotalInput.val(miniMentalTotal);
  289. }
  290.  
  291. function addEDOutpatientLevelButton() {
  292. $('#N_AFControl_73').after('<input id="idCalcScore" type="button" value="Calculate Score">');
  293. $('#idCalcScore').bind('click', calcEDOutpatientLevel);
  294. }
  295.  
  296. function calcEDOutpatientLevel() {
  297. var total = 0;
  298. for (var i = 1; i < 73; i++) {
  299. var sel = $('#N_AFControl_'+i+' option:selected').text();
  300. console.log(i+': '+sel);
  301. if (sel.indexOf('-select-') >= 0) {
  302. total += 0;
  303. } else {
  304. total += parseInt(sel);
  305. }
  306. }
  307. $('#N_AFControl_73').val(total);
  308. }
  309.  
  310. function addDMVAudiometryButton() {
  311. $('#N_AFControl_1').after('<input id="idCalcScore" type="button" value="Calculate Score">');
  312. $('#idCalcScore').bind('click', calcDMVAudiometry);
  313. }
  314.  
  315. function calcDMVAudiometry() {
  316. var avgRt = 0, avgLt = 0;
  317. for (var i = 2; i < 5; i++) {
  318. var sel = $('#N_AFControl_'+i+' option:selected').text();
  319. if (sel.indexOf('-select-') >= 0) {
  320. avgRt += 0;
  321. } else {
  322. avgRt += parseInt(sel);
  323. }
  324. }
  325. avgRt = Math.round(avgRt/3);
  326. console.log(avgLt);
  327. for (var i = 6; i < 9; i++) {
  328. var sel = $('#N_AFControl_'+i+' option:selected').text();
  329. if (sel.indexOf('-select-') >= 0) {
  330. avgLt += 0;
  331. } else {
  332. avgLt += parseInt(sel);
  333. }
  334. }
  335. console.log(avgLt);
  336. avgLt = Math.round(avgLt/3);
  337. $('#N_AFControl_5').val(avgRt);
  338. $('#N_AFControl_9').val(avgLt);
  339. var yes = $('#N_AFControl_1 option:nth-child(2)').val();
  340. var no = $('#N_AFControl_1 option:nth-child(3)').val();
  341. if (avgRt <= 40 || avgLt <= 40) {
  342. $('#N_AFControl_1').val(yes); // Select YES
  343. } else {
  344. $('#N_AFControl_1').val(no); // Select NO
  345. }
  346. }
  347.  
  348. function KeyboardShortcuts(event) {
  349. console.log('DrM: Processing Shortcuts');
  350. if ($('INPUT:focus, SELECT:focus, TEXTAREA:focus').length) // disable hotkeys if focused on a form control
  351. return;
  352.  
  353. var patientId = $('#current-patient-id').text().trim();
  354. var visitId = $('#current-visit-id').text().trim();
  355. var loc = '';
  356. var ch = String.fromCharCode(event.which).toLowerCase();
  357. console.log(ch);
  358. if (ch == 'v') {
  359. // key - 'v'
  360. loc = 'http://hlapp/Healthlandweb/PatientChart/Chart/VitalSigns?patientId='+patientId;
  361. loc += '&visitId='+visitId;
  362. } else if (ch == 'a') {
  363. // key - 'a'
  364. loc = 'http://hlapp/Healthlandweb/PatientChart/Chart/Assessments?patientId='+patientId;
  365. loc += '&visitId='+visitId;
  366. } else if (ch == 'n') {
  367. // key - 'n'
  368. loc = 'http://hlapp/Healthlandweb/PatientChart/Chart/ChartNotes?patientId='+patientId;
  369. loc += '&visitId='+visitId;
  370. } else if (ch == 'l') {
  371. // key - 'l'
  372. loc = 'http://hlapp/Healthlandweb/PatientChart/Chart/LabResults?patientId='+patientId;
  373. loc += '&visitId='+visitId;
  374. } else if (ch == 'd') {
  375. // key - 'd'
  376. loc = 'http://hlapp/Healthlandweb/PatientChart/Chart/Documents?patientId='+patientId;
  377. loc += '&visitId='+visitId;
  378. } else if (ch == 'o') {
  379. // key - 'o'
  380. loc = 'http://hlapp/Healthlandweb/CPOE/WHOrders/Orders?patientId='+patientId;
  381. loc += '&visitId='+visitId;
  382. } else if (ch == 'p') {
  383. // key = - 'p'
  384. loc = 'http://hlapp/Healthlandweb/History/MedicalHistory?patientId='+patientId;
  385. loc += '&initialTab=Problem';
  386. } else if (ch == 'm') {
  387. // key = - 'm'
  388. loc = 'http://hlapp/Healthlandweb/History/MedicalHistory?patientId='+patientId;
  389. loc += '&initialTab=HomeMedication';
  390. } else if (ch == 's') {
  391. // key = 's'
  392. console.log('Launching summary');
  393. // $('#current-patient-bar-quick-view').click();
  394. $('.quick-view').click();
  395. return;
  396. } else if (ch == 'c') {
  397. // key = 'c';
  398. // Will try to assessment calculator
  399. var assessTitleCtrl = $('label.header:first');
  400. console.log(assessTitleCtrl);
  401. if (!assessTitleCtrl.length) {
  402. console.log('DrM: No assesement found');
  403. return;
  404. }
  405. var assessTitle = assessTitleCtrl.text().trim();
  406. console.log('"'+assessTitle+'"');
  407. console.log(assessTitle == 'Warfarin Flowsheet - INR 2.0 - 3.0');
  408. if (assessTitle == 'Mini Mental Status Exam') {
  409. console.log('DrM: Detected Mini Mental Status Exam');
  410. addAssessMiniMentalButton();
  411. } else if (assessTitle == 'ED Outpatient Level Of Acuity Assignment') {
  412. console.log('DrM: Dected ED Outpatient Level Of Acuity Assignment');
  413. addEDOutpatientLevelButton();
  414. } else if (assessTitle == 'DMV Audiometry') {
  415. console.log('DrM: Detected DMV Audiometry Assessment');
  416. addDMVAudiometryButton();
  417. } else if (assessTitle == 'Warfarin Flowsheet - INR 2.0 - 3.0') {
  418. console.log('DrM: Detected Warfarin Flowsheet - INR 2.0 - 3.0');
  419. Warfarin.UI.initINRCalc1();
  420. }
  421. return;
  422. } else {
  423. return;
  424. }
  425. window.location.href = loc;
  426. }
  427.  
  428. function createHelp() {
  429. $('body').append('<div id="msg"></div>');
  430. $('#msg').hide();
  431. $('#msg').append('<table id="tblHelp"></table>');
  432. var tb = $('#tblHelp');
  433. tb.append('<tr><td colspan="2" class="helpheader">Shortcuts</td><td></td></tr>');
  434. tb.append('<tr><td class="helpshortcut">a</td><td>Assesments</td></tr>');
  435. tb.append('<tr><td class="helpshortcut">c</td><td>Add Assement Calculator</td></tr>');
  436. tb.append('<tr><td class="helpshortcut">d</td><td>Documents</td></tr>');
  437. tb.append('<tr><td class="helpshortcut">l</td><td>Lab Results</td></tr>');
  438. tb.append('<tr><td class="helpshortcut">n</td><td>Lab Results</td></tr>');
  439. tb.append('<tr><td class="helpshortcut">o</td><td>CPOE</td></tr>');
  440. tb.append('<tr><td class="helpshortcut">p</td><td>Problem List</td></tr>');
  441. tb.append('<tr><td class="helpshortcut">m</td><td>Home Medications (good place to lauch ePrescribe)</td></tr>');
  442. tb.append('<tr><td class="helpshortcut">s</td><td>Patietn Summary</td></tr>');
  443. tb.append('<tr><td colspan="2" class="helpheader">Assessments Calculators</td><td></td></tr>');
  444. tb.append('<tr><td colspan="2">ED Outpatient Level Of Acuity Assignment</td><td></td></tr>');
  445. tb.append('<tr><td colspan="2">Mini Mental Status Exam</td><td></td></tr>');
  446. $('.helpheader').css('font-weight', 'bold');
  447. $('.helpshortcut').css('color', 'blue');
  448. $('.helpshortcut').css('font-weight', 'bold');
  449. }
  450.  
  451.  
  452. /********************************************************************
  453. * MAIN script
  454. ********************************************************************/
  455.  
  456. console.log('DrM: Loading');
  457.  
  458. // Add DrM to pages so users know functionality is avaiable
  459. $('body').append('<div id="logoDrM">DrM</div>');
  460. var style = {position:'absolute',
  461. top: '1px',
  462. left: '1px',
  463. border:'1px solid black',
  464. padding:'10px',
  465. background: 'lightblue',
  466. 'z-index': '3000'
  467. };
  468. $('#logoDrM').css(style);
  469. $('#logoDrM').on('click', function() {
  470. $('#msg').dialog({title: "DrM Enhancements v1.1", draggable: true});
  471. });
  472.  
  473. createHelp();
  474.  
  475. var loc = window.location.href;
  476.  
  477. if (loc.indexOf('doj.ca.gov') >= 0) { // we are handling CURES
  478. if (loc.indexOf(CURESpages['index']) >= 0) {
  479. CURESIndex();
  480. } else if (loc.indexOf(CURESpages['search_input']) >= 0) {
  481. CURESSearchInput();
  482. } else if (loc.indexOf(CURESpages['search_results']) >= 0) {
  483. CURESSearchResults();
  484. } else if (loc.indexOf(CURESpages['report']) >= 0) {
  485. var th = document.getElementById('ReportDate');
  486. var tbody = th.parentNode.parentNode;
  487. var row_header = tbody.children[0];
  488. var row_pt = tbody.children[1];
  489. console.log(tbody);
  490. var row = tbody.insertRow(-1);
  491. cell0 = row.insertCell(0);
  492. cell1 = row.insertCell(1);
  493. cell1.setAttribute('colspan', '3');
  494. cell0.innerHTML = "PDF Name";
  495. var LastName = row_pt.children[1].innerHTML.trimLeft().trimRight();
  496. var FirstName = row_pt.children[2].innerHTML.trimLeft().trimRight();
  497. var DOB = row_pt.children[3].innerHTML.trimLeft().trimRight();
  498. var ReportDate = row_pt.children[0].innerHTML.trimLeft().trimRight().split(" ")[0];
  499. var PDFName = LastName+" "+FirstName+" "+DOB+" "+ReportDate;
  500. cell1.innerHTML = PDFName;
  501. GM_setClipboard(PDFName);
  502. }
  503. } else { // we are handling Healthland
  504. console.log('DrM: about to add cures');
  505. addCURES();
  506. var counter = GM_getValue('counter');
  507. console.log(counter);
  508. GM_setValue('counter', ++counter);
  509. // Keyboard shortcuts
  510. console.log('DrM: Binding keyboard shortcuts');
  511. document.addEventListener('keypress', KeyboardShortcuts);
  512. }
  513.  
  514. /***************************************************************************
  515. * WARFARIN
  516. */
  517. /*
  518. * Module: warfarin.js
  519. * Version: 1.0
  520. *
  521. * Description: This modules calculates warfarin dose based on INR results and INR target
  522. *
  523. * Reference: http://www.aafp.org/fpm/2005/0500/p77.html
  524. *
  525. * History: Original revision
  526. *
  527. * API functions
  528. * Warfarin.UI.initCalc1() - INR target of 2.0 - 3.0
  529. *
  530. */
  531.  
  532.  
  533. var Warfarin;
  534.  
  535. if (!Warfarin) {
  536. Warfarin = {};
  537. } else {
  538. throw new Error('Warfarin already exists');
  539. }
  540.  
  541. if (!Warfarin.UI) {
  542. Warfarin.UI = {};
  543. } else {
  544. throw new Error('Warfarin.UI already exists');
  545. }
  546.  
  547. Warfarin.dosingSchedule = {
  548. // "2.5": ["0.5","0","0","0","0","0","0"],
  549. // "5.0": ["0.5","0","0","0","0.5","0","0"],
  550. // "7.5": ["0.5","0","0.5","0","0.5","0","0"],
  551. "10.0": ["0.5","0","0.5","0","0.5","0","0.5"],
  552. "12.5": ["0.5","0","0.5","0","0.5","0.5","0.5"],
  553. "15.0": ["0.5","0","0.5","0.5","0.5","0.5","0.5"],
  554. "17.5": ["0.5","0.5","0.5","0.5","0.5","0.5","0.5"],
  555. "20.0": ["1","0.5","0.5","0.5","0.5","0.5","0.5"],
  556. "22.5": ["1","0.5","0.5","0.5","1","0.5","0.5"],
  557. "25.0": ["1","0.5","1","0.5","1","0.5","0.5"],
  558. "27.5": ["0.5","1","0.5","1","0.5","1","1"],
  559. "30.0": ["0.5","1","1","1","0.5","1","1"],
  560. "32.5": ["0.5","1","1","1","1","1","1"],
  561. "35.0": ["1","1","1","1","1","1","1"],
  562. "37.5": ["1.5","1","1","1","1","1","1"],
  563. "40.0": ["1.5","1","1","1","1.5","1","1"],
  564. "42.5": ["1.5","1","1.5","1","1.5","1","1"],
  565. "45.0": ["1","1.5","1","1.5","1","1.5","1.5"],
  566. "47.5": ["1","1.5","1.5","1.5","1","1.5","1.5"],
  567. "50.0": ["1","1.5","1.5","1.5","1.5","1.5","1.5"],
  568. "52.5": ["1.5","1.5","1.5","1.5","1.5","1.5","1.5"],
  569. "55.0": ["2","1.5","1.5","1.5","1.5","1.5","1.5"],
  570. "57.5": ["2","1.5","1.5","1.5","2","1.5","1.5"],
  571. "60.0": ["2","1.5","2","1.5","2","1.5","1.5"],
  572. "62.5": ["1.5","2","1.5","2","1.5","2","2"],
  573. "65.0": ["1.5","2","2","2.0","1.5","2","2"],
  574. "67.5": ["1.5","2","2","2","2","2","2"],
  575. "70.0": ["2","2","2","2","2","2","2"],
  576. "72.5": ["2.5","2","2","2","2","2","2"],
  577. "75.0": ["2.5","2","2","2","2.5","2","2"],
  578. "77.5": ["2.5","2","2.5","2","2.5","2","2"],
  579. "80.0": ["2","2.5","2","2.5","2","2.5","2.5"]
  580. };
  581.  
  582. /*
  583. * getDoseString
  584. *
  585. * Returns string with daily warfarin dosing based on a weekly dose
  586. */
  587. Warfarin.getDoseString = function(dose) {
  588. var weeklySchedule, str;
  589. if (typeof dose == 'number') {
  590. dose = dose.toFixed(1);
  591. }
  592. if (!(dose in Warfarin.dosingSchedule)) {
  593. throw "getDoseString: Invalid dose: "+dose;
  594. }
  595. weeklySchedule = Warfarin.dosingSchedule[dose];
  596. str = 'Mon: '+weeklySchedule[0]+', ';
  597. str += 'Tue: '+weeklySchedule[1]+', ';
  598. str += 'Wed: '+weeklySchedule[2]+', ';
  599. str += 'Thr: '+weeklySchedule[3]+', ';
  600. str += 'Fri: '+weeklySchedule[4]+', ';
  601. str += 'Sat: '+weeklySchedule[5]+', ';
  602. str += 'Sun: '+weeklySchedule[6];
  603. return str;
  604. };
  605.  
  606. /*
  607. * calcNewDose1
  608. *
  609. * This function will calculate a new weekly warfarin dose and determine schedule
  610. * for next INR check INR goal of 2.0 - 3.0
  611. * Reference: http://www.aafp.org/fpm/2005/0500/p77.html
  612. *
  613. * Reteruns
  614. * {
  615. * dose: - new weekly warfarin dose
  616. * nextInr - num of days in which next INR should be drawn
  617. * instructions - special instructiosn
  618. * }
  619. *
  620. */
  621. Warfarin.calcNewDose1 = function(inrRange, dose) {
  622. var newDose = {dose: null, instructions: null, nextInr: null};
  623. var min, max;
  624.  
  625. if (typeof dose == 'number') {
  626. dose = dose.toFixed(1);
  627. }
  628. if (!(dose in Warfarin.dosingSchedule)) {
  629. throw "getDoseString: Invalid dose: "+dose;
  630. }
  631. if (inrRange == '< 1.5') {
  632. // Increase dose by 10-20%;
  633. min = dose*1.10;
  634. max = dose*1.20;
  635. var a = Math.round(min/2.5)*2.5;
  636. var b = Math.round(max/2.5)*2.5;
  637. console.log(min+' '+max);
  638. console.log(a+' '+b);
  639. if (a > min) {
  640. newDose.dose = a;
  641. } else {
  642. newDose.dose = b;
  643. }
  644. newDose.nextInr = 7;
  645. } else if (inrRange == '1.5 - 1.9') {
  646. // Increase dose by 5-10%;
  647. min = dose*1.05;
  648. max = dose*1.10;
  649. var a = Math.round(min/2.5)*2.5;
  650. var b = Math.round(max/2.5)*2.5;
  651. console.log(min+' '+max);
  652. console.log(a+' '+b);
  653. if (a > min) {
  654. newDose.dose = a;
  655. } else {
  656. newDose.dose = b;
  657. }
  658. newDose.nextInr = 14;
  659. } else if (inrRange == '2.0 - 3.0') {
  660. newDose.dose = dose;
  661. newDose.nextInr = 28;
  662. } else if (inrRange == '3.1 - 3.9') {
  663. // Decrease dose by 5-10%;
  664. min = dose*0.9;
  665. max = dose*0.95;
  666. var a = Math.round(min/2.5)*2.5;
  667. var b = Math.round(max/2.5)*2.5;
  668. console.log(min+' '+max);
  669. console.log(a+' '+b);
  670. if (b < max) {
  671. newDose.dose = b;
  672. } else {
  673. newDose.dose = a;
  674. }
  675. newDose.nextInr = 14;
  676. } else if (inrRange == '4.0 - 4.9') {
  677. // Decrease dose by 10%;
  678. min = dose*0.9;
  679. newDose.dose = Math.round(min/2.5)*2.5;
  680. newDose.instructions = "Hold 1 dose";
  681. newDose.nextInr = 7;
  682. } else if (inrRange == '>= 5.0') {
  683. newDose.instructions = "Please check the protocol. Patient may need Vitamin K and/or ER evaluation";
  684. }
  685. return newDose;
  686. };
  687.  
  688. /*****************
  689. * UI FUNCTION
  690. *****************/
  691.  
  692. Warfarin.UI.id = {
  693. dosing5mg: 'N_AFControl_4',
  694. currentWeeklyDose5mg: 'N_AFControl_5',
  695. currentWeeklyDoseText: 'N_AFControl_6',
  696. inrResult: 'N_AFControl_7',
  697. inrDate: 'N_AFControl_8_Date_dateInput',
  698. inrTime: 'N_AFControl_8_Time_dateInput',
  699. doseAdjustment: 'N_AFControl_9',
  700. newWeeklyDose5mg: 'N_AFControl_10',
  701. newWeeklyDoseText: 'N_AFControl_11',
  702. nextINRDate: 'N_AFControl_12_Date_dateInput',
  703. nextINRTime: 'N_AFControl_12_Time_dateInput',
  704. nextINRComment: 'N_AFControl_13',
  705. calcScore: 'calcScore',
  706. ref: 'ref',
  707. today: 'today',
  708. inrMsg: 'inrMsg'
  709. };
  710.  
  711. Warfarin.UI.refURI = 'http://www.aafp.org/fpm/2005/0500/p77.html';
  712.  
  713. // Use with Healthand centriq and Use Telerik for time and date controls
  714. Warfarin.UI.hl = true;
  715.  
  716.  
  717. Warfarin.UI.isDosing5mg = function() {
  718. if ($('#'+Warfarin.UI.id.dosing5mg+' option:selected').text() == 'Yes') {
  719. return true;
  720. }
  721. return false;
  722. };
  723.  
  724.  
  725. /*
  726. * status - true or false
  727. */
  728. Warfarin.UI.setDosing5mg = function(status) {
  729. var yes = $('#'+Warfarin.UI.id.dosing5mg+' option:eq(1)').val();
  730. var no = $('#'+Warfarin.UI.id.dosing5mg+' option:eq(2)').val();
  731. if (status) {
  732. $('#'+Warfarin.UI.id.dosing5mg).val(yes);
  733. } else {
  734. $('#'+Warfarin.UI.id.dosing5mg).val(no);
  735. }
  736. };
  737.  
  738. /*
  739. * Returns current weekly dose base on 5 mg pills in string format
  740. */
  741. Warfarin.UI.getCurrentWeeklyDose5mg = function() {
  742. var dose = $('#'+Warfarin.UI.id.currentWeeklyDose5mg+' option:selected').text();
  743. if (dose == '-select-') {
  744. return;
  745. } else {
  746. return dose.split(' ')[0];
  747. }
  748. };
  749.  
  750. Warfarin.UI.setCurrentWeeklyDose5mg = function(dose) {
  751. var val, txt;
  752. dose = parseFloat(dose);
  753. for (var i = 0; i < $('#'+Warfarin.UI.id.currentWeeklyDose5mg+' option').length; i++) {
  754. txt = $('#'+Warfarin.UI.id.currentWeeklyDose5mg+' option:eq('+i+')').text();
  755. if (parseFloat(txt) == dose) {
  756. val = $('#'+Warfarin.UI.id.currentWeeklyDose5mg+' option:eq('+i+')').val();
  757. $('#'+Warfarin.UI.id.currentWeeklyDose5mg).val(val);
  758. break;
  759. }
  760. }
  761. };
  762.  
  763.  
  764. Warfarin.UI.setCurrentWeeklyDose = function(dose) {
  765. $('#'+Warfarin.UI.id.currentWeeklyDoseText).val(dose);
  766. };
  767.  
  768. Warfarin.UI.onCurrentWeeklyDose5mgChange = function() {
  769. if (!Warfarin.UI.isDosing5mg()) {
  770. return;
  771. }
  772. dose = Warfarin.UI.getCurrentWeeklyDose5mg();
  773. console.log(dose);
  774. if (dose) {
  775. Warfarin.UI.setCurrentWeeklyDose(Warfarin.getDoseString(dose));
  776. }
  777. };
  778.  
  779. /*
  780. * Returns current weekly dose base on 5 mg pills in string format
  781. */
  782. Warfarin.UI.getNewWeeklyDose5mg = function() {
  783. var dose = $('#'+Warfarin.UI.id.newWeeklyDose5mg+' option:selected').text();
  784. if (dose == '-select-') {
  785. return;
  786. } else {
  787. return dose.split(' ')[0];
  788. }
  789. };
  790.  
  791. Warfarin.UI.setNewWeeklyDose5mg = function(dose) {
  792. var val, txt;
  793. dose = parseFloat(dose);
  794. for (var i = 0; i < $('#'+Warfarin.UI.id.newWeeklyDose5mg+' option').length; i++) {
  795. txt = $('#'+Warfarin.UI.id.newWeeklyDose5mg+' option:eq('+i+')').text();
  796. if (parseFloat(txt) == dose) {
  797. val = $('#'+Warfarin.UI.id.newWeeklyDose5mg+' option:eq('+i+')').val();
  798. $('#'+Warfarin.UI.id.newWeeklyDose5mg).val(val);
  799. break;
  800. }
  801. }
  802. };
  803.  
  804. Warfarin.UI.onNewWeeklyDose5mgChange = function () {
  805. if (!Warfarin.UI.isDosing5mg()) {
  806. return;
  807. }
  808. dose = Warfarin.UI.getNewWeeklyDose5mg();
  809. console.log(dose);
  810. if (dose) {
  811. Warfarin.UI.setNewWeeklyDose(Warfarin.getDoseString(dose));
  812. }
  813. };
  814.  
  815. Warfarin.UI.setNewWeeklyDose = function(dose) {
  816. $('#'+Warfarin.UI.id.newWeeklyDoseText).val(dose);
  817. };
  818.  
  819. Warfarin.UI.getINRResult = function() {
  820. return $('#'+Warfarin.UI.id.inrResult+' option:selected').text();
  821. };
  822.  
  823. Warfarin.UI.setINRResult = function(index) {
  824. var tmp = $('#'+Warfarin.UI.id.inrResult+' option:eq('+index+')').val();
  825. $('#'+Warfarin.UI.id.inrResult).val(tmp);
  826. };
  827.  
  828. Warfarin.UI.getINRDate = function() {
  829. var dateTxt, date;
  830. dateTxt = $('#'+Warfarin.UI.id.inrDate).val();
  831. return new Date(dateTxt);
  832. };
  833.  
  834. Warfarin.UI.setINRDate = function(date) {
  835. console.log(date);
  836. if (Warfarin.UI.hl) {
  837. if (!(date instanceof Date)) {
  838. date = new Date(date);
  839. }
  840. var dCtl = $find(Warfarin.UI.id.inrDate);
  841. var tCtl = $find(Warfarin.UI.id.inrTime);
  842. dCtl.set_selectedDate(date);
  843. tCtl.set_selectedDate(date);
  844. } else {
  845. if (date instanceof Date) {
  846. $('#'+Warfarin.UI.id.inrDate).val(date.toLocaleDateString()).change();
  847. } else {
  848. $('#'+Warfarin.UI.id.inrDate).val(date).change();
  849. }
  850. }
  851. };
  852.  
  853. Warfarin.UI.getDoseAdjustment = function() {
  854. var yes = $('#'+Warfarin.UI.id.doseAdjustment+' option:eq(1)').val();
  855. return ($('#'+Warfarin.UI.id.doseAdjustment+' option:selected').val() == yes);
  856. };
  857.  
  858. Warfarin.UI.setDoseAdjustment = function(status) {
  859. var yes = $('#'+Warfarin.UI.id.doseAdjustment+' option:eq(1)').val();
  860. var no = $('#'+Warfarin.UI.id.doseAdjustment+' option:eq(2)').val();
  861. $('#'+Warfarin.UI.id.doseAdjustment).val(status ? yes : no);
  862. };
  863.  
  864. Warfarin.UI.getNextINRDate = function() {
  865. var dateTxt, date;
  866. dateTxt = $('#'+Warfarin.UI.id.nextINRDate).val();
  867. return new Date(dateTxt);
  868. };
  869.  
  870. Warfarin.UI.setNextINRDate = function(date) {
  871. console.log(date);
  872. if (Warfarin.UI.hl) {
  873. if (!(date instanceof Date)) {
  874. date = new Date(date);
  875. }
  876. var dCtl = $find(Warfarin.UI.id.nextINRDate);
  877. var tCtl = $find(Warfarin.UI.id.nextINRTime);
  878. dCtl.set_selectedDate(date);
  879. tCtl.set_selectedDate(date);
  880. } else {
  881. if (date instanceof Date) {
  882. $('#'+Warfarin.UI.id.nextINRDate).val(date.toLocaleDateString()).change();
  883. } else {
  884. $('#'+Warfarin.UI.id.nextINRDate).val(date).change();
  885. }
  886. }
  887. };
  888.  
  889. Warfarin.UI.getNextINRDateComment = function() {
  890. return $('#'+Warfarin.UI.id.nextINRComment).val();
  891. };
  892.  
  893. Warfarin.UI.setNextINRDateComment = function(text) {
  894. $('#'+Warfarin.UI.id.nextINRComment).val(text);
  895. };
  896.  
  897. Warfarin.UI.clearNewWekklyDose = function() {
  898. var val = $('#'+Warfarin.UI.id.newWeeklyDose5mg+' option:eq(0)').val();
  899. $('#'+Warfarin.UI.id.newWeeklyDose5mg).val(val);
  900. Warfarin.UI.setNewWeeklyDose('');
  901. Warfarin.UI.setDoseAdjustment(true);
  902. Warfarin.UI.setNextINRDate('');
  903. Warfarin.UI.setNextINRDateComment('');
  904. };
  905.  
  906. Warfarin.UI.addINRButton1 = function() {
  907. $('#'+Warfarin.UI.id.newWeeklyDose5mg).after('<input id="'+Warfarin.UI.id.calcScore+'" type="button" value="Calculate Score">');
  908. $('#'+Warfarin.UI.id.calcScore).bind('click', Warfarin.UI.calcINR1);
  909. };
  910.  
  911. Warfarin.UI.addRefButton = function() {
  912. $('#'+Warfarin.UI.id.calcScore).after('<input id="'+Warfarin.UI.id.ref+'" type="button" value="Reference">');
  913. $('#'+Warfarin.UI.id.ref).bind('click', Warfarin.UI.onRef);
  914. };
  915.  
  916. Warfarin.UI.addTodayButton = function() {
  917. // $('#'+Warfarin.UI.id.inrDate).before('<input id="'+Warfarin.UI.id.today+'" type="button" value="Today">');
  918. $('#N_AFControl_8_Time_wrapper').after('<input id="'+Warfarin.UI.id.today+'" type="button" value="Today">');
  919. $('#'+Warfarin.UI.id.today).bind('click', Warfarin.UI.onToday);
  920. };
  921.  
  922. Warfarin.UI.calcINR1 = function() {
  923. var dose, doseText, inrRange, newDose, inrDate;
  924. if (!Warfarin.UI.isDosing5mg()) {
  925. Warfarin.UI.msgInr('To use dosing calculator you must use 5 mg dosing schedule.');
  926. return;
  927. }
  928. dose = Warfarin.UI.getCurrentWeeklyDose5mg();
  929. if (dose == '-select-') {
  930. Warfarin.UI.msgInr('You must select current dose.');
  931. return;
  932. }
  933. inrRange = Warfarin.UI.getINRResult();
  934. if (inrRange == '-select-') {
  935. Warfarin.UI.msgInr('You must select INR result.');
  936. return;
  937. }
  938.  
  939. newDose = Warfarin.calcNewDose1(inrRange, dose);
  940. if (newDose.dose) {
  941. Warfarin.UI.setNewWeeklyDose5mg(newDose.dose);
  942. if (newDose.instructions) {
  943. doseText = newDose.instructions+' then\n';
  944. doseText += Warfarin.getDoseString(newDose.dose);
  945. } else {
  946. doseText = Warfarin.getDoseString(newDose.dose);
  947. }
  948. if (newDose.dose-dose > 0) {
  949. doseText += '\nIncrease: ';
  950. doseText += ((newDose.dose-dose)/dose*100).toFixed(1)+'%';
  951. } else if(newDose.dose-dose < 0) {
  952. doseText += '\nDecrease: ';
  953. doseText += ((dose-newDose.dose)/dose*100).toFixed(1)+'%';
  954. }
  955. Warfarin.UI.setNewWeeklyDose(doseText);
  956. Warfarin.UI.setDoseAdjustment(dose != newDose.dose);
  957. if (newDose.nextInr) {
  958. Warfarin.UI.setNextINRDateComment('Check INR in '+newDose.nextInr+' days');
  959. inrDate = Warfarin.UI.getINRDate();
  960. if (inrDate.valueOf() !== NaN) {
  961. inrDate.setDate(inrDate.getDate()+newDose.nextInr);
  962. Warfarin.UI.setNextINRDate(inrDate);
  963. }
  964. }
  965. } else {
  966. Warfarin.UI.clearNewWekklyDose();
  967. Warfarin.UI.msgInr(newDose.instructions);
  968. return;
  969. }
  970. };
  971.  
  972. Warfarin.UI.onRef = function() {
  973. var win = window.open(Warfarin.UI.refURI);
  974. win.focus();
  975. };
  976.  
  977. Warfarin.UI.onToday = function() {
  978. Warfarin.UI.setINRDate(new Date());
  979. };
  980.  
  981. Warfarin.UI.msgInr = function(txt) {
  982. $('#'+Warfarin.UI.id.inrMsg).dialog('option', 'title', 'INR Message');
  983. if (typeof txt == 'string') {
  984. $('#'+Warfarin.UI.id.inrMsg).text(txt);
  985. }
  986. $('#'+Warfarin.UI.id.inrMsg).dialog('open');
  987. };
  988.  
  989. Warfarin.UI.initINRCalc1 = function() {
  990. Warfarin.UI.addINRButton1();
  991. Warfarin.UI.addRefButton();
  992. Warfarin.UI.addTodayButton();
  993. $('#'+Warfarin.UI.id.currentWeeklyDose5mg).bind('change', Warfarin.UI.onCurrentWeeklyDose5mgChange);
  994. $('#'+Warfarin.UI.id.newWeeklyDose5mg).bind('change', Warfarin.UI.onNewWeeklyDose5mgChange);
  995. $('<div id="inrMsg"></div>').appendTo('body').dialog({autoOpen: false});
  996. /*
  997. * Testing initalization
  998. */
  999. Warfarin.UI.setDosing5mg(true);
  1000. Warfarin.UI.setCurrentWeeklyDose5mg(30);
  1001. Warfarin.UI.setCurrentWeeklyDose(Warfarin.getDoseString(30));
  1002. Warfarin.UI.setINRResult(3);
  1003. Warfarin.UI.setINRDate(new Date());
  1004. };
  1005.  
  1006.