├── img ├── umd_logo.gif ├── umd_logo.png ├── hcil_logo.jpg └── sharpc_logo.jpg ├── css ├── images │ ├── animated-overlay.gif │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_228ef1_256x240.png │ ├── ui-icons_ef8c08_256x240.png │ ├── ui-icons_ffd27a_256x240.png │ ├── ui-icons_ffffff_256x240.png │ ├── ui-bg_flat_10_000000_40x100.png │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ └── ui-bg_highlight-soft_100_eeeeee_1x100.png ├── summary.css ├── log_summary.css ├── style.css └── jquery-ui-1.10.2.custom.css ├── summary.html ├── README.md ├── js ├── index.js ├── main.js ├── summary.js ├── panels.js ├── utils.js ├── logger.js ├── jquery.transit.min.js ├── sample_JSON_dataset.js ├── log_summary.js └── model.js ├── log_summary.html ├── Original_License.txt ├── LICENSE ├── Original_README.txt ├── main.html └── index.html /img/umd_logo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/img/umd_logo.gif -------------------------------------------------------------------------------- /img/umd_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/img/umd_logo.png -------------------------------------------------------------------------------- /img/hcil_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/img/hcil_logo.jpg -------------------------------------------------------------------------------- /img/sharpc_logo.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/img/sharpc_logo.jpg -------------------------------------------------------------------------------- /css/images/animated-overlay.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/animated-overlay.gif -------------------------------------------------------------------------------- /css/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /css/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /css/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /css/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /css/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /css/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jddamore/twinlist/master/css/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /css/summary.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Georgia, serif; 3 | margin: 3% 8%; 4 | } 5 | 6 | table { 7 | border-collapse: collapse; 8 | width: 100%; 9 | } 10 | 11 | td { 12 | padding: 0.25em 0.5em; 13 | width: 10%; 14 | } 15 | 16 | td:first-child { 17 | width: 13%; 18 | } 19 | 20 | tr:nth-child(odd) { 21 | background: #f5f5f5; 22 | } 23 | -------------------------------------------------------------------------------- /summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Patient summary 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |

John Doe

14 |
15 |
16 | 17 |
18 | 19 | 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # twinlist 2 | Twinlist Medication Reconciliation App 3 | 4 | This is an app developed by researchers as part of the SHARP project for medication reconciliation. The original code for the available is available from: http://www.cs.umd.edu/hcil/sharp/twinlist/dev/ 5 | 6 | For more information on the original application, please see information at http://www.cs.umd.edu/hcil/sharp/twinlist/ 7 | 8 | Commits on or before September 2, 2017 are simple copies of the code as-is (originally developed 2011-2013) 9 | 10 | For original license, see: ./Original_License.text 11 | For original readme, see: ./Original_README.txt 12 | 13 | Commits after September 2, 2017 are designed for integration with Diameter Health. They may not reflect the original intent of the research, but at least we've kept it open-source. 14 | 15 | 16 | -------------------------------------------------------------------------------- /css/log_summary.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: Georgia, serif; 3 | margin: 2% 2%; 4 | } 5 | 6 | table { 7 | border-collapse: collapse; 8 | width: 100%; 9 | margin-bottom: 3%; 10 | } 11 | 12 | td { 13 | padding: 0.25em 0.5em; 14 | /*width: 10%;*/ 15 | } 16 | 17 | /* 18 | td:first-child { 19 | width: 24%; 20 | } 21 | */ 22 | tr:nth-child(odd) { 23 | background: #f5f5f5; 24 | } 25 | 26 | #time { 27 | margin: 3%; 28 | } 29 | 30 | #raw_log_header { 31 | margin: 3%; 32 | font-size: 110%; 33 | } 34 | /* 35 | .keep { 36 | font-weight: bold; 37 | background: 38 | } 39 | 40 | .reject { 41 | text-decoration: line-through; 42 | } 43 | */ 44 | .keep { 45 | font-weight: bold; 46 | border-radius: 0.2em; 47 | } 48 | 49 | .reject { 50 | color:#777777; 51 | text-decoration: line-through; 52 | } -------------------------------------------------------------------------------- /js/index.js: -------------------------------------------------------------------------------- 1 | // TODO: refactor 2 | var SIGN_OFF_SUCCESS_MSG = "reconciled list submitted."; 3 | 4 | 5 | $(function() { 6 | 7 | console.log("url: " + utils.getURLParameter("case")); 8 | console.log("url: " + utils.getURLParameter("version")); 9 | console.log("url: " + utils.getURLParameter("animate")); 10 | 11 | // TODO input validation for query params 12 | var dataset = utils.getURLParameter("case") || model.DATASET_DEFAULT; 13 | var version = utils.getURLParameter("version") || controller.versionDefault; 14 | var autoAnimate = utils.getURLParameter("animate") || controller.autoAnimateDefault; 15 | 16 | model.init(dataset); 17 | 18 | // Note: controller assumes model has been initialized already 19 | controller.init(false, version, autoAnimate); 20 | 21 | logger.init(); 22 | }); 23 | 24 | -------------------------------------------------------------------------------- /log_summary.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Log summary 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
time
15 |
16 |
17 | CSV Format:
18 |
19 |
20 | Raw Log:
21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /Original_License.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2011 Human-Computer Interaction Lab, University of Maryland, 2 | Tiffany Chao, Catherine Plaisant and Ben Shneiderman, 3 | http://www.cs.umd.edu/hcil/sharp 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 9 | of the Software, and to permit persons to whom the Software is furnished to do 10 | so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /js/main.js: -------------------------------------------------------------------------------- 1 | 2 | $(function() { 3 | 4 | // set up handler for clicking to the demo 5 | // open a new tab with particular url 6 | $(".to_demo").click(function() { 7 | 8 | var dataset = $("select[name='dataset']").val(); 9 | var version = $("select[name='version']").val(); 10 | var animate = $("select[name='autoAnimate']").val(); 11 | 12 | window.open("index.html?case=" + dataset + "&version=" + version + "&animate=" + animate); 13 | }); 14 | 15 | $("select[name='version']").change(function() { 16 | if ($(this).val() === "__VERSION_FULL__") { 17 | $("select[name='autoAnimate']").prop('disabled', false); 18 | } else { 19 | $("select[name='autoAnimate']").prop('disabled', true); 20 | } 21 | }); 22 | 23 | logger.init(); 24 | 25 | $(window).unbind("keydown")// for some reason, multiple keydowns firing, remove previous ones 26 | .keydown(function(event) { 27 | switch (event.which) { 28 | case 76: 29 | // the 'l' key 30 | logger.dump(); 31 | window.open("log_summary.html"); 32 | break; 33 | } 34 | }); 35 | }); 36 | 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | -- Original copyright -- 4 | Copyright (c) 2011 Human-Computer Interaction Lab, University of Maryland, 5 | Tiffany Chao, Catherine Plaisant and Ben Shneiderman, 6 | http://www.cs.umd.edu/hcil/sharp 7 | -- Appended copyright --- 8 | Copyright (c) 2017 John D'Amore 9 | 10 | Permission is hereby granted, free of charge, to any person obtaining a copy 11 | of this software and associated documentation files (the "Software"), to deal 12 | in the Software without restriction, including without limitation the rights 13 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 14 | copies of the Software, and to permit persons to whom the Software is 15 | furnished to do so, subject to the following conditions: 16 | 17 | The above copyright notice and this permission notice shall be included in all 18 | copies or substantial portions of the Software. 19 | 20 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 23 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 24 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 26 | SOFTWARE. 27 | -------------------------------------------------------------------------------- /js/summary.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | populatePatientName(); 3 | populateTable("stop"); 4 | populateTable("start"); 5 | populateTable("continue"); 6 | 7 | $("#btn_close").click(function () { 8 | window.close(); 9 | }); 10 | }); 11 | 12 | function populatePatientName() { 13 | var name = utils.getStorageItem("patient_name"); 14 | $("#patient_name").html(name); 15 | } 16 | 17 | function populateTable(name) { 18 | var list = utils.getStorageItem(name); 19 | 20 | if (list.length > 0) { 21 | var $data = $("#data"); 22 | var $header = $("

Please " + name + " taking

"); 23 | var $table = $("
"); 24 | $table.attr("id", name); 25 | 26 | var medications = list.split("\n"); 27 | 28 | var modifiedStr; 29 | 30 | for (var i = 0; i < medications.length; i++) { 31 | var $tr = $(""); 32 | modifiedStr = ""; 33 | 34 | var attributes = medications[i].split("\t"); 35 | 36 | for (var j = 1; j < attributes.length; j++) { 37 | // j=0 contains info on which list it is from 38 | if(attributes[j] == "undefined") // from session storage, so is just the string 39 | attributes[j] = ""; 40 | if(attributes[j].indexOf("*") == 0) { 41 | // Note: modified items have a name that start with * 42 | modifiedStr = "modified"; 43 | } 44 | 45 | $tr.append("" + attributes[j] + ""); 46 | 47 | } 48 | $tr.append(""); 51 | $table.append($tr); 52 | } 53 | $data.append($header); 54 | $data.append($table); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /js/panels.js: -------------------------------------------------------------------------------- 1 | var panels = function(panels, jQuery) { 2 | var visible = {}; 3 | 4 | ////// visible /////////////////////////////////////////////////////////// 5 | visible.showCenter = function() { 6 | if ($(".center.panel").hasClass("hide-left")) { 7 | rotate(RIGHT_TO_CENTER); 8 | } else if ($(".center.panel").hasClass("hide-right")) { 9 | rotate(LEFT_TO_CENTER); 10 | } 11 | }; 12 | 13 | visible.showLeft = function() { 14 | rotate(CENTER_TO_LEFT); 15 | }; 16 | 17 | visible.showRight = function(panel) { 18 | rotate(CENTER_TO_RIGHT, panel); 19 | }; 20 | 21 | 22 | ////// hidden //////////////////////////////////////////////////////////// 23 | var CENTER_TO_LEFT = 0; 24 | var CENTER_TO_RIGHT = 1; 25 | var LEFT_TO_CENTER = 2; 26 | var RIGHT_TO_CENTER = 3; 27 | 28 | 29 | function rotate(direction, panel) { 30 | var panel = panel ? "#" + panel : ""; 31 | 32 | /* 33 | * No arbitrary movement, only continuous rotation -- as if the 34 | * three panels were drawn on the same sheet of paper. 35 | */ 36 | switch(direction) { 37 | case CENTER_TO_LEFT: 38 | $(".right.panel").addClass("hide-right"); 39 | $(".center.panel").addClass("hide-right"); 40 | $(".left.panel").removeClass("hide-left"); 41 | break; 42 | case LEFT_TO_CENTER: 43 | $(".right.panel").addClass("hide-right"); 44 | $(".left.panel").addClass("hide-left"); 45 | $(".center.panel").removeClass("hide-left hide-right"); 46 | break; 47 | case CENTER_TO_RIGHT: 48 | $(".left.panel").addClass("hide-left"); 49 | $(".center.panel").addClass("hide-left"); 50 | 51 | // multiple right panels exist 52 | if (panel) { 53 | $(panel).parent(".right.panel") 54 | .removeClass("hide-right"); 55 | } else { 56 | $(".right.panel").removeClass("hide-right"); 57 | } 58 | break; 59 | case RIGHT_TO_CENTER: 60 | $(".right.panel").addClass("hide-right"); 61 | $(".left.panel").addClass("hide-left"); 62 | $(".center.panel").removeClass("hide-left hide-right"); 63 | break; 64 | } 65 | } 66 | 67 | 68 | // expose interface ////////////////////////////////////////////////// 69 | return visible; 70 | }(window.panels = window.panels || {}, $, undefined); 71 | -------------------------------------------------------------------------------- /js/utils.js: -------------------------------------------------------------------------------- 1 | var utils = function(utils, undefined) { 2 | ////// visible /////////////////////////////////////////////////////////// 3 | var visible = {}; 4 | 5 | // TODO consider using GAE datastore 6 | 7 | visible.getStorageItem = function(key) { 8 | if (localStorageSupported) { 9 | return window.localStorage.getItem(key); 10 | } else { 11 | return getCookie(key); 12 | } 13 | }; 14 | 15 | visible.setStorageItem = function(key, value, days) { 16 | if (localStorageSupported) { 17 | window.localStorage.setItem(key, value); 18 | } else { 19 | setCookie(key, value, days); 20 | } 21 | }; 22 | 23 | visible.adjustCase = function(str) { 24 | return str[0].toUpperCase() + str.slice(1).toLowerCase(); 25 | }; 26 | 27 | // TODO remove instances? 28 | visible.debug = function(str, marker) { 29 | var mark = marker || ""; 30 | console.log("begin: " + mark); 31 | console.log(str); 32 | console.log("end: " + mark); 33 | }; 34 | 35 | // utility function to remove duplicates from an array 36 | visible.getUniqueElements = function(arr) { 37 | var u = {}, a = []; 38 | for (var i = 0, l = arr.length; i < l; ++i) { 39 | if (u.hasOwnProperty(arr[i])) { 40 | continue; 41 | } 42 | a.push(arr[i]); 43 | u[arr[i]] = 1; 44 | } 45 | return a; 46 | }; 47 | 48 | // from http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values-in-javascript/901144#901144 49 | // retrieve query parameters from URL by name 50 | visible.getURLParameter = function(name) { 51 | name = name.replace(/[\[]/, "\\\[").replace(/[\]]/, "\\\]"); 52 | var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"), 53 | results = regex.exec(location.search); 54 | return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " ")); 55 | }; 56 | 57 | ////// hidden //////////////////////////////////////////////////////////// 58 | var localStorageSupported = window.localStorage || false; 59 | 60 | function getCookie(name) { 61 | var cookies = document.cookie.split(";"); 62 | 63 | for (var i = 0; i < cookies.length; i++) { 64 | var key = cookies[i].slice(0, cookies[i].indexOf("=")); 65 | var value = cookies[i].slice(cookies[i].indexOf("=") + 1); 66 | key = key.trim(); 67 | 68 | if (key === name) { 69 | return unescape(value); 70 | } 71 | } 72 | return null; 73 | } 74 | 75 | function setCookie(name, value, days) { 76 | var expires = new Date(); 77 | expires.setDate(expires.getDate() + days); 78 | value = escape(value) + ((days) ? "" : "; expires=" + expires.toUTCString()); 79 | document.cookie = name + "=" + value; 80 | } 81 | 82 | // expose interface ////////////////////////////////////////////////// 83 | return visible; 84 | }(window.utils = window.utils || {}); 85 | -------------------------------------------------------------------------------- /js/logger.js: -------------------------------------------------------------------------------- 1 | var logger = function(logger, undefined) { 2 | // visible /////////////////////////////////////////////////////////////// 3 | var visible = {}; 4 | 5 | // TODO consider refactor elsewhere 6 | // constants for events 7 | visible.EVENT_ANIMATION_SPEED_CHANGE = "CHANGED_ANIMATION_SPEED"; 8 | visible.EVENT_CLICKED = "CLICKED"; // user clicked on something 9 | visible.EVENT_DATASET_CHANGE = "CHANGED_DATASET"; 10 | visible.EVENT_DEMO_RESUME = "RESUMED_DEMO"; 11 | visible.EVENT_DEMO_START = "STARTED_DEMO"; 12 | visible.EVENT_LIST_ACCEPTED = "ACCEPTED_LIST"; 13 | visible.EVENT_LIST_REJECTED = "REJECTED_LIST"; 14 | visible.EVENT_LIST_UNDECIDED = "UNDECIDED_LIST"; 15 | visible.DATA_DEMO_END_STATE = "DEMO_END_STATE"; // state of dataset + what was accepted - Note: assumes that demo end does not include undecided items 16 | visible.EVENT_SIGNED_OFF = "SIGNED_OFF"; // user finished demo 17 | visible.EVENT_STATE_CHANGE = "CHANGED_STATE"; 18 | visible.EVENT_SCROLLED = "SCROLLED"; // user scrolled in some direction 19 | visible.EVENT_VERSION_CHANGE = "CHANGED_VERSION"; 20 | visible.EVENT_MODIFY_PANEL_START = "MODIFY_PANEL_START"; 21 | visible.EVENT_MODIFY_PANEL_END = "MODIFY_PANEL_END"; 22 | visible.EVENT_COLUMN_ACTION = "COLUMN_ACTION"; 23 | 24 | visible.init = function() { 25 | if (utils.getStorageItem(LOG) === null) { 26 | utils.setStorageItem(LOG, ""); 27 | } 28 | 29 | if (utils.getStorageItem(ENTRY_NUMBER) === null) { 30 | utils.setStorageItem(ENTRY_NUMBER, 0); 31 | } 32 | } 33 | 34 | visible.log = function(eventType, entry) { 35 | if (utils.getStorageItem(LOG) === null) { 36 | utils.setStorageItem(LOG, ""); 37 | } 38 | 39 | utils.setStorageItem(LOG, utils.getStorageItem(LOG) + 40 | '[' + entryID() + ']' + "\t" + visible.dateString(new Date()) + "\t" + 41 | eventType + "\t" + entry + "\n"); 42 | }; 43 | 44 | visible.dump = function() { 45 | console.log("-- START LOG DUMP --------------------------------" + 46 | "\n" + utils.getStorageItem(LOG) + 47 | "-- END LOG DUMP ----------------------------------" + 48 | "\n"); 49 | }; 50 | 51 | visible.dateString = function(date) { 52 | var year = date.getFullYear(); 53 | var month = date.getMonth() + 1; 54 | var day = date.getDate(); 55 | var ms = date.getUTCMilliseconds(); 56 | 57 | month = month < 10 ? "0" + month : month; 58 | day = day < 10 ? "0" + day : day; 59 | ms = ms < 10 ? "00" + ms : (ms < 100 ? "0" + ms : ms); 60 | 61 | return year + "-" + month + "-" + day + " " + 62 | date.toLocaleTimeString() + ":" + ms; 63 | }; 64 | 65 | /* Given a item's id, return a human-readable string of the item: 66 | * e.g. "temazepam 15 mg PO qHS" 67 | */ 68 | visible.simpleItemString = function(id) { 69 | var item = model.items[id]; 70 | 71 | var str = item.getNames().recorded; 72 | 73 | for (var attributeName in item.attributes) { 74 | if (model.attributes[attributeName].display) { 75 | str += " " + item.attributes[attributeName].toString(); 76 | } 77 | } 78 | return str; 79 | } 80 | 81 | /* Given a item's id, return a human-readable string of the item, 82 | * with information about the source list and whether it is modified 83 | * e.g. "(Hospital) * temazepam 15 mg PO qHS" 84 | */ 85 | visible.itemString = function(id) { 86 | var item = model.items[id]; 87 | var list = item.listID === model.list1.id ? model.list1.name : 88 | model.list2.name; 89 | 90 | var star = ""; 91 | if(item.isModified) 92 | star = " * " 93 | 94 | return "(" + list + ") " + star + visible.simpleItemString(id); 95 | } 96 | 97 | // hidden //////////////////////////////////////////////////////////////// 98 | var LOG = "__LOG__"; 99 | var ENTRY_NUMBER = "__ENTRY_NUMBER__"; 100 | 101 | /* increment and return a log entry number (unique for each log entry) */ 102 | function entryID() { 103 | var entryNumber = utils.getStorageItem(ENTRY_NUMBER); 104 | utils.setStorageItem(ENTRY_NUMBER, ++entryNumber); 105 | 106 | return entryNumber; 107 | } 108 | 109 | // expose interface ////////////////////////////////////////////////// 110 | return visible; 111 | }(window.logger = window.logger || {}); -------------------------------------------------------------------------------- /js/jquery.transit.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Transit - CSS3 transitions and transformations 3 | * Copyright(c) 2011 Rico Sta. Cruz 4 | * MIT Licensed. 5 | * 6 | * http://ricostacruz.com/jquery.transit 7 | * http://github.com/rstacruz/jquery.transit 8 | */ 9 | (function(d){function k(a){var b=["Moz","Webkit","O","ms"],c=a.charAt(0).toUpperCase()+a.substr(1);if(a in i.style)return a;for(a=0;a=b;++b)a[b]&&(a[b]=parseFloat(a[b]));a[3]&&(a[3]=g(a[3],"deg"));return a}},parse:function(a){var b=this;a.replace(/([a-zA-Z0-9]+)\((.*?)\)/g,function(a,d, 17 | e){b.setFromString(d,e)})},toString:function(a){var b=[],c;for(c in this)if(this.hasOwnProperty(c)&&(e.transform3d||!("rotateX"===c||"rotateY"===c||"perspective"===c||"transformOrigin"===c)))"_"!==c[0]&&(a&&"scale"===c?b.push(c+"3d("+this[c]+",1)"):a&&"translate"===c?b.push(c+"3d("+this[c]+",0)"):b.push(c+"("+this[c]+")"));return b.join(" ")}};d.fn.transition=d.fn.transit=function(a,b,c,f){var h=this,g=0,i=!0;"function"===typeof b&&(f=b,b=void 0);"function"===typeof c&&(f=c,c=void 0);"undefined"!== 18 | typeof a.easing&&(c=a.easing,delete a.easing);"undefined"!==typeof a.duration&&(b=a.duration,delete a.duration);"undefined"!==typeof a.complete&&(f=a.complete,delete a.complete);"undefined"!==typeof a.queue&&(i=a.queue,delete a.queue);"undefined"!==typeof a.delay&&(g=a.delay,delete a.delay);"undefined"===typeof b&&(b=d.fx.speeds._default);"undefined"===typeof c&&(c=d.cssEase._default);var b=n(b),j=q(a,b,c,g),l=d.transit.enabled&&e.transition?parseInt(b,10)+parseInt(g,10):0;if(0===l)return p(h,i,function(b){h.css(a); 19 | f&&f.apply(h);b&&b()}),h;var k={},m=function(b){var c=false,g=function(){c&&h.unbind(o,g);l>0&&h.each(function(){this.style[e.transition]=k[this]||null});typeof f==="function"&&f.apply(h);typeof b==="function"&&b()};if(l>0&&o&&d.transit.useTransitionEnd){c=true;h.bind(o,g)}else window.setTimeout(g,l);h.each(function(){l>0&&(this.style[e.transition]=j);d(this).css(a)})};p(h,i,function(a){var b=0;e.transition==="MozTransition"&&b<25&&(b=25);window.setTimeout(function(){m(a)},b)});return this};d.transit.getTransitionValue= 20 | q})(jQuery); 21 | -------------------------------------------------------------------------------- /js/sample_JSON_dataset.js: -------------------------------------------------------------------------------- 1 | var sampleJSONStr = '{ "original_list_2": [ "Warfarin Sodium 2.5 MG Tablet;TAKE AS DIRECTED.; Rx", " Warfarin Sodium 5 MG Tablet;TAKE 1 TABLET DAILY AS DIRECTED.; Rx", " Carvedilol 25 MG Tablet;TAKE 1 TABLET TWICE DAILY, WITH MORNING AND EVENING MEAL; Rx", " Lipitor 10 MG Tablet;TAKE 1 TABLET DAILY.; Rx", " Lisinopril 5 MG Tablet;TAKE 1 TABLET TWICE DAILY; Rx", " Synthroid 100 MCG Tablet;TAKE 1 TABLET DAILY.; Rx", " Pantoprazole Sodium 40 MG Tablet Delayed Release;TAKE 1 TABLET DAILY.; Rx", " Sertraline HCl 50 MG Tablet;TAKE 1 TABLET DAILY.; Rx", " Mirapex 0.5 MG Tablet;TAKE 1 TABLET 3 TIMES DAILY.; Rx" ], "reconciled": [ { "med2": { "original_string": "Carvedilol 25 MG Tablet;TAKE 1 TABLET TWICE DAILY, WITH MORNING AND EVENING MEAL; Rx", "medicationName": "CARVEDILOL", "dose": "25", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET TWICE DAILY, WITH MORNING AND EVENING MEAL; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Coreg 25 MG Tablet;TAKE 1 TABLET TWICE DAILY, WITH MORNING AND EVENING MEAL; RPT", "medicationName": "COREG", "dose": "25", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET TWICE DAILY, WITH MORNING AND EVENING MEAL; RPT", "provenance": "Patient", "startDate": "2011.12.24", "parsed": true }, "score": 1.0, "mechanism": "brand name" }, { "med2": { "original_string": "Warfarin Sodium 2.5 MG Tablet;TAKE AS DIRECTED.; Rx", "medicationName": "WARFARIN SODIUM", "dose": "2.5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE AS DIRECTED.; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Warfarin Sodium 2.5 MG Tablet;TAKE AS DIRECTED.; Rx", "medicationName": "WARFARIN SODIUM", "dose": "2.5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE AS DIRECTED.; RX", "provenance": "Patient", "parsed": true }, "score": 1.0, "mechanism": "string matching" }, { "med2": { "original_string": "Lipitor 10 MG Tablet;TAKE 1 TABLET DAILY.; Rx", "medicationName": "LIPITOR", "dose": "10", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET DAILY.; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Lipitor 10 MG Tablet;TAKE 1 TABLET DAILY.; Rx", "medicationName": "LIPITOR", "dose": "10", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET DAILY.; RX", "provenance": "Patient", "parsed": true }, "score": 1.0, "mechanism": "string matching" }, { "med2": { "original_string": "Warfarin Sodium 5 MG Tablet;TAKE 1 TABLET DAILY AS DIRECTED.; Rx", "medicationName": "WARFARIN SODIUM", "dose": "5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET DAILY AS DIRECTED.; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Warfarin Sodium 5 MG Tablet;TAKE 1 TABLET DAILY AS DIRECTED.; Rx", "medicationName": "WARFARIN SODIUM", "dose": "5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET DAILY AS DIRECTED.; RX", "provenance": "Patient", "parsed": true }, "score": 1.0, "mechanism": "string matching" }, { "med2": { "original_string": "Mirapex 0.5 MG Tablet;TAKE 1 TABLET 3 TIMES DAILY.; Rx", "medicationName": "MIRAPEX", "dose": "0.5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET 3 TIMES DAILY.; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Mirapex 0.5 MG Tablet;TAKE 1 TABLET 3 TIMES DAILY.; Rx", "medicationName": "MIRAPEX", "dose": "0.5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET 3 TIMES DAILY.; RX", "provenance": "Patient", "parsed": true }, "score": 1.0, "mechanism": "string matching" }, { "med2": { "original_string": "Sertraline HCl 50 MG Tablet;TAKE 1 TABLET DAILY.; Rx", "medicationName": "SERTRALINE HCL", "dose": "50", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET DAILY.; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Zoloft 50 MG Tablet;TAKE 1 TABLET DAILY.; RPT", "medicationName": "ZOLOFT", "dose": "50", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET DAILY.; RPT", "provenance": "Patient", "parsed": true }, "score": 1.0, "mechanism": "ingredients list" }, { "med2": { "original_string": "Pantoprazole Sodium 40 MG Tablet Delayed Release;TAKE 1 TABLET DAILY.; Rx", "medicationName": "PANTOPRAZOLE SODIUM", "dose": "40", "formulation": "TABLET DELAYED RELEASE", "units": "MG", "instructions": "TAKE 1 TABLET DAILY.; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Protonix 40 MG Tablet Delayed Release;TAKE 1 TABLET DAILY.; Rx", "medicationName": "PROTONIX", "dose": "40", "formulation": "TABLET DELAYED RELEASE", "units": "MG", "instructions": "TAKE 1 TABLET DAILY.; RX", "provenance": "Patient", "parsed": true }, "score": 0.6666666666666666, "mechanism": "ingredients list" }, { "med2": { "original_string": "Lisinopril 5 MG Tablet;TAKE 1 TABLET TWICE DAILY; Rx", "medicationName": "LISINOPRIL", "dose": "5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE 1 TABLET TWICE DAILY; RX", "provenance": "EHR", "parsed": true }, "med1": { "original_string": "Lisinopril 5 MG Tablet;TAKE TABLET TWICE DAILY; Rx", "medicationName": "LISINOPRIL", "dose": "5", "formulation": "TABLET", "units": "MG", "instructions": "TAKE TABLET TWICE DAILY; RX", "provenance": "Patient", "parsed": true }, "score": 1.0, "mechanism": "ingredients list" } ], "original_list_1": [ "Zoloft 50 MG Tablet;TAKE 1 TABLET DAILY.; RPT", " Warfarin Sodium 2.5 MG Tablet;TAKE AS DIRECTED.; Rx", " Lipitor 10 MG Tablet;TAKE 1 TABLET DAILY.; Rx", " Protonix 40 MG Tablet Delayed Release;TAKE 1 TABLET DAILY.; Rx", " Warfarin Sodium 5 MG Tablet;TAKE 1 TABLET DAILY AS DIRECTED.; Rx", " Mirapex 0.5 MG Tablet;TAKE 1 TABLET 3 TIMES DAILY.; Rx", " Lisinopril 5 MG Tablet;TAKE TABLET TWICE DAILY; Rx", " Coreg 25 MG Tablet;TAKE 1 TABLET TWICE DAILY, WITH MORNING AND EVENING MEAL; RPT", " " ], "new_list_2": [ { "original_string": "Synthroid 100 MCG Tablet;TAKE 1 TABLET DAILY.; Rx", "medicationName": "SYNTHROID", "dose": "100", "formulation": "TABLET", "units": "MCG", "instructions": "TAKE 1 TABLET DAILY.; RX", "provenance": "EHR", "parsed": true } ], "new_list_1": [] }'; -------------------------------------------------------------------------------- /Original_README.txt: -------------------------------------------------------------------------------- 1 | 2 | Contents: 3 | - [1] Dataset format and how to add datasets 4 | - [2] Twinlist url format 5 | - [3] Handler information (for control changes) 6 | 7 | 8 | 9 | 10 | 11 | [1] Dataset format and how to add datasets 12 | 13 | Datasets are currently hard-coded in model.js in the "DATASETS" array 14 | (search for "var DATASETS" in model.js). The following describes the expected 15 | format for each dataset in "DATASETS": 16 | 17 | : { 18 | "patientFirstName": , 19 | "patientLastName": , 20 | "patientAge": , 21 | "patientGender": , 22 | 23 | "unique1": , 25 | "unique2": , 27 | "identical": , 31 | "similar": , 41 | 42 | "csv": , 63 | 64 | "other_data": 88 | } // end of dataset object 89 | 90 | 91 | Adding the above to "DATASETS" adds a dataset to Twinlist. However, the following 92 | additional changes may also be necessary: 93 | 94 | - updating model.js:visible.getDatasetShortName 95 | This function is used to retrieve dataset short names during log generation 96 | If logging isn't used, this is unnecessary. 97 | 98 | - updating main.html 99 | If users will be accessing the dataset through main.html, adding another 100 | option to the set of available datasets (search main.html for: 103 | 106 | 109 | 112 | 115 | 118 | 121 | 124 | 127 | 130 | 133 | 134 | 135 | 136 | read narratives 137 | 138 | 139 |
  • 140 | 141 | 158 |
  • 159 |
  • 160 | 161 | 172 |
  • 173 |
  • 174 | TO THE DEMO 175 |
  • 176 | 177 | 178 | 179 |
    180 |

    Desktop controls :

    181 |
      182 |
    • 183 | click on a drug to decide : 184 |
        185 |
      • 186 | left-click once to 187 | keep 188 |
      • 189 |
      • 190 | right-click once to 191 | reject 192 |
      • 193 |
      • 194 | click repeatedly to 195 | undo 196 |
      • 197 |
      198 |
    • 199 |
    200 |

    Touch-device controls :

    201 |
      202 |
    • 203 | tap on a drug to highlight and see additional information 204 |
        205 |
      • 206 | left-swipe once to 207 | keep 208 |
      • 209 |
      • 210 | right-swipe once to 211 | reject 212 |
      • 213 |
      • 214 | swipe repeatedly to 215 | undo 216 |
      • 217 |
      218 |
    • 219 |
    220 |

    Common controls :

    221 |
      222 |
    • 223 | you can also use "keep rest" 224 | and "reject rest" 225 | to decide on multiple items in a column 226 |
    • 227 |
    • 228 | click 229 | sign off when finished 230 |
    • 231 |
    • 232 | (additional options also available by clicking "show options") 233 |
    • 234 |
    235 |
    236 | 237 | 238 | 239 | to the DEMO! >> 240 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | twinlist demo 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |
    25 |
    26 | 49 | 50 |
    51 |
    52 |
    53 |
    54 |
    55 |
    56 |
    57 |
    58 |
    59 |
    60 | 61 |
    62 | Detail 63 | 64 | Nothing to display. 65 | 66 |
    67 | 68 |
    69 |
    70 |
    71 |
    72 | 73 |
    74 | 75 | add 76 | edit 77 |
    78 | 79 |
    80 | test 81 |
    82 | 83 | 87 | 88 | 198 | 199 | 236 | 237 | 238 | 239 | 242 | 252 | 253 | 256 | 278 | 279 | 282 | 301 | 302 | 303 | 306 | 317 | 318 | 321 | 324 | 325 | 328 | 342 | 343 |
    240 | Display: 241 | 243 | 248 |
    249 | 250 | item details 251 |
    254 | Speed: 255 | 257 | 277 | 280 | Jump to step: 281 | 283 | 300 |
    304 | Group by: 305 | 307 | 313 |
    314 | 315 | multigroup 316 |
    319 | Filter on: 320 | 322 | 323 | 326 | After action: 327 | 329 |
      330 |
    • 331 | grayout 332 |
    • 333 |
    • 334 | remove 335 |
    • 336 |
    • 337 | 338 | show patient tab 339 |
    • 340 |
    341 |
    344 | 345 | [ case : appendectomy ] 346 | 347 | 354 |
    355 |
    356 | 357 | -------------------------------------------------------------------------------- /css/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | * Basic global adjustments: margin, padding, and overflow. 3 | */ 4 | body, div, header, nav, footer, 5 | h1, h2, h3, h4, p, span, a, 6 | #app ul, #app li, 7 | label, input, textarea, 8 | img { 9 | margin: 0; 10 | padding: 0; 11 | } 12 | 13 | body { 14 | /* 15 | * Panel transitions are cleaner when background and foreground colors 16 | * are defined here. 17 | * 18 | * Hidden overflow maintains the panel illusion (no scroll bars). 19 | */ 20 | background: #fafafa; 21 | color: #333333; 22 | overflow: hidden; 23 | height: 100%; 24 | } 25 | 26 | 27 | 28 | 29 | a { 30 | text-decoration: none; 31 | 32 | -webkit-user-select: none; 33 | -moz-user-select: none; 34 | -ms-user-select: none; 35 | -o-user-select: none; 36 | user-select: none; 37 | } 38 | 39 | a:hover { 40 | cursor: pointer; /* for placeholder anchors */ 41 | text-decoration: underline; 42 | } 43 | 44 | /* 45 | * Enable horizontal panels. 46 | */ 47 | .panel { 48 | position: absolute; 49 | width: 100%; 50 | height: 100%; 51 | 52 | -webkit-transition: all 0.8s cubic-bezier(0.3, 0.3, 0.1, 0.99); 53 | -webkit-backface-visibility: hidden; /* avoid odd flicker */ 54 | -moz-transition: all 0.8s cubic-bezier(0.3, 0.3, 0.1, 0.99); 55 | -ms-transition: all 0.8s cubic-bezier(0.3, 0.3, 0.1, 0.99); 56 | -o-transition: all 0.8s cubic-bezier(0.3, 0.3, 0.1, 0.99); 57 | transition: all 0.8s cubic-bezier(0.3, 0.3, 0.1, 0.99); 58 | } 59 | 60 | .hide-left { 61 | -webkit-transform: translateX(-100%); 62 | -moz-transform: translateX(-100%); 63 | -ms-transform: translateX(-100%); 64 | -o-transform: translateX(-100%); 65 | transform: translateX(-100%); 66 | } 67 | 68 | .hide-right { 69 | -webkit-transform: translateX(100%); 70 | -moz-transform: translateX(100%); 71 | -ms-transform: translateX(100%); 72 | -o-transform: translateX(100%); 73 | transform: translateX(100%); 74 | } 75 | 76 | .forward { 77 | font-family: "Andale Mono", monospace; 78 | 79 | padding: 0.5em; 80 | position: absolute; 81 | 82 | -webkit-transition: all 0.2s; 83 | -moz-transition: all 0.2s; 84 | -ms-transition: all 0.2s; 85 | -o-transition: all 0.2s; 86 | transition: all 0.ss; 87 | 88 | border-left: 0.4em solid #999999; 89 | right: 0; 90 | } 91 | 92 | .forward:hover { 93 | padding-right: 3em; 94 | text-decoration: none; 95 | } 96 | 97 | .top { 98 | top: 5%; 99 | } 100 | 101 | .bottom { 102 | bottom: 5%; 103 | } 104 | 105 | /* 106 | * Intro panel (hides to the left). 107 | */ 108 | #intro h1, #intro h2 { 109 | margin: 3% 0; 110 | } 111 | 112 | #intro h1 { 113 | letter-spacing: 0.25em; 114 | } 115 | 116 | #intro a, #intro h4 { 117 | color: #666666; 118 | } 119 | 120 | #ul_config li { 121 | height: 2em; 122 | } 123 | 124 | #intro select { 125 | height: 2em; 126 | } 127 | 128 | .column { 129 | height: 100%; 130 | 131 | position: absolute; 132 | } 133 | 134 | .column.left { 135 | padding: 7.5% 5%; 136 | width: 30%; 137 | } 138 | 139 | .column.right { 140 | padding: 5% 7.5%; 141 | width: 45%; 142 | right: 0; 143 | } 144 | 145 | .sub-blurb { 146 | margin: 15% 0; 147 | } 148 | 149 | .sub-blurb p { 150 | text-align: justify; 151 | margin: 5% 0; 152 | } 153 | 154 | 155 | /* 156 | * Main panel. Hides to the left or right, depending. 157 | */ 158 | .banner { 159 | background: #333333; 160 | line-height: 250%; 161 | } 162 | 163 | .logo, .nav-item { 164 | display: inline; 165 | } 166 | 167 | .logo { 168 | font-size: 175%; 169 | font-weight: normal; 170 | color: #f0f0f0; 171 | letter-spacing: 0.25em; 172 | 173 | margin-left: 5%; 174 | } 175 | 176 | .main-nav { 177 | font-size: 90%; 178 | float: right; 179 | margin-right: 5%; 180 | } 181 | 182 | .nav-link { 183 | color: #999999; 184 | margin: 0 1em; 185 | } 186 | 187 | .nav-link:hover { 188 | color: #f0f0f0; 189 | } 190 | 191 | .active { 192 | text-decoration: underline; 193 | } 194 | 195 | .inactive { 196 | color: #666666 !important; 197 | text-decoration: line-through !important; 198 | } 199 | 200 | 201 | 202 | 203 | #app > .content { 204 | position: absolute; 205 | margin: 0.75em 5%; 206 | height: 70%; /* fallback */ 207 | width: 90%; 208 | 209 | -webkit-user-select: none; 210 | -moz-user-select: none; 211 | -ms-user-select: none; 212 | -o-user-select: none; 213 | user-select: none; 214 | } 215 | 216 | .scrolling_content { 217 | position: absolute; 218 | overflow-x: hidden; 219 | height: 70%; /* fallback */ 220 | width: 100%; 221 | 222 | -webkit-user-select: none; 223 | -moz-user-select: none; 224 | -ms-user-select: none; 225 | -o-user-select: none; 226 | user-select: none; 227 | } 228 | 229 | .backdrop { 230 | border-bottom: 0.3em solid #f3f3f3; 231 | border-collapse: collapse; 232 | width: 100%; 233 | } 234 | 235 | .backdrop th { 236 | color: #f0f0f0; 237 | font-weight: normal; 238 | text-align: left; 239 | 240 | padding: 0.75em 1em 0.5em 1em; 241 | width: 20%; 242 | } 243 | 244 | .backdrop th:first-child { 245 | border-top-left-radius: 0.2em; 246 | } 247 | 248 | .backdrop th:last-child { 249 | border-top-right-radius: 0.2em; 250 | } 251 | 252 | .col-header .name { 253 | margin-bottom: 0.4em; 254 | } 255 | 256 | .col-header .action { 257 | font-size: 65%; 258 | } 259 | 260 | .col-header .action ul, .col-header .action li { 261 | display: inline; 262 | } 263 | 264 | .col-header .action li:first-child::after { 265 | opacity: 0.6; 266 | content: "|"; 267 | } 268 | 269 | .col-header .action li:last-child::before { 270 | opacity: 0.6; 271 | content: "["; 272 | } 273 | 274 | .col-header .action li:last-child::after { 275 | opacity: 0.6; 276 | content: "]"; 277 | } 278 | 279 | .col-header .action li:last-child { 280 | float: right; 281 | } 282 | 283 | .col-header .action a { 284 | opacity: 0.6; 285 | } 286 | 287 | .col-header .action a:hover { 288 | opacity: 1; 289 | } 290 | 291 | .keep { 292 | margin-right: 0.3em; 293 | } 294 | 295 | .reject { 296 | margin-left: 0.3em; 297 | } 298 | 299 | .clear { 300 | margin: 0 0.5em; 301 | } 302 | 303 | .backdrop tr { 304 | -webkit-transition: background 0.8s ease-in-out; 305 | -moz-transition: background 0.8s ease-in-out; 306 | -ms-transition: background 0.8s ease-in-out; 307 | -o-transition: background 0.8s ease-in-out; 308 | transition: background 0.8s ease-in-out; 309 | } 310 | 311 | .backdrop td, .item .header, .item .detail, .diagnosis .header { 312 | white-space: nowrap; 313 | overflow: hidden; 314 | text-overflow: ellipsis; 315 | } 316 | 317 | .backdrop td, .item { 318 | width: 18%; 319 | height: 2.5em; 320 | padding: 0.6em 0.5em 0.4em 0.5em; 321 | 322 | -webkit-transition: background 0.8s; 323 | -moz-transition: background 0.8s; 324 | -ms-transition: background 0.8s; 325 | -o-transition: background 0.8s; 326 | transition: background 0.8s; 327 | } 328 | 329 | 330 | .diagnosis { 331 | width: 18%; 332 | height: 1.5em; 333 | padding: 0.6em 0.5em 0.4em 0.5em; 334 | -webkit-transition: background 0.8s; 335 | -moz-transition: background 0.8s; 336 | -ms-transition: background 0.8s; 337 | -o-transition: background 0.8s; 338 | transition: background 0.8s; 339 | } 340 | 341 | 342 | .item, .diagnosis { 343 | position: absolute; 344 | 345 | -webkit-transition: -webkit-transform 0.2s ease-in-out, 346 | opacity 0.2s; 347 | -moz-transition: -moz-transform 0.2s ease-in-out, 348 | opacity 0.2s; 349 | -ms-transition: -ms-transform 0.2s ease-in-out, 350 | opacity 0.2s; 351 | -o-transition: -o-transform 0.2s ease-in-out, 352 | opacity 0.2s; 353 | transition: transform 0.2s ease-in-out, 354 | opacity 0.2s; 355 | 356 | z-index: 10; /* > 1 to be above shadows (ghosts) */ 357 | } 358 | 359 | .item:hover, .item-hover, .diagnosis:hover { 360 | -webkit-transform: translateX(2%); 361 | -moz-transform: translateX(2%); 362 | -ms-transform: translateX(2%); 363 | -o-transform: translateX(2%); 364 | transform: translateX(2%); 365 | 366 | text-overflow: ellipsis; 367 | } 368 | 369 | .item .header, .diagnosis .header { 370 | margin-bottom: 0.15em; 371 | } 372 | 373 | .item .name { 374 | font-weight: bold; 375 | margin: 0 0.2em; 376 | padding: 0 0.2em; 377 | 378 | -webkit-transition: background 0.4s; /* match .name .difference */ 379 | -moz-transition: background 0.4s; 380 | -ms-transition: background 0.4s; 381 | -o-transition: background 0.4s; 382 | transition: background 0.4s; 383 | } 384 | 385 | .diagnosis .name { 386 | font-weight: lighter; 387 | font-style: italic; 388 | margin: 0 0.2em; 389 | padding: 0 0.2em; 390 | 391 | -webkit-transition: background 0.4s; /* match .name .difference */ 392 | -moz-transition: background 0.4s; 393 | -ms-transition: background 0.4s; 394 | -o-transition: background 0.4s; 395 | transition: background 0.4s; 396 | } 397 | 398 | .item .detail span { 399 | font-size: 80%; 400 | margin: 0 0.3em; 401 | padding: 0 0.2em; 402 | } 403 | 404 | .shadow { 405 | color: #bbbbbb; 406 | opacity: 0.6; 407 | z-index: 1; /* > 0 to be above the backdrop */ 408 | } 409 | 410 | 411 | /* TODO ellipsis coloring issues here... */ 412 | .undecided-hover { 413 | background: #555555; 414 | border-radius: 0.2em; 415 | color: #f0f0f0; 416 | } 417 | 418 | .third-col-anchor-hover { 419 | background: rgb(223, 243, 235); 420 | border-radius: 0.2em; 421 | color: #333333; 422 | } 423 | 424 | .diagnosis-hover { 425 | background: rgb(21, 99, 77); 426 | border-radius: 0.2em; 427 | color: #f0f0f0; 428 | } 429 | 430 | .accepted { 431 | background: #8fbe00; 432 | border-radius: 0.2em; 433 | color: #f0f0f0; 434 | } 435 | 436 | .rejected { 437 | color: #bbbbbb; 438 | text-decoration: line-through; 439 | } 440 | 441 | .modified .name::before { 442 | content: "*"; 443 | margin-right: 0.5em; 444 | } 445 | 446 | 447 | .difference { 448 | -webkit-transition: background 0.4s; 449 | -moz-transition: background 0.4s; 450 | -ms-transition: background 0.4s; 451 | -o-transition: background 0.4s; 452 | transition: background 0.4s; 453 | } 454 | 455 | .highlight { 456 | color: #333333; 457 | background: #f2e4ac; 458 | border: 1px solid #f0e0a3; 459 | border-radius: 0.2em; 460 | 461 | -webkit-transition: all 0.4s; 462 | -moz-transition: all 0.4s; 463 | -ms-transition: all 0.4s; 464 | -o-transition: all 0.4s; 465 | transition: all 0.4s; 466 | } 467 | 468 | 469 | .groups .label { 470 | color: #333333; 471 | font-size: 60%; 472 | font-style: italic; 473 | position: absolute; 474 | 475 | opacity: 0; 476 | 477 | -webkit-transition: all 0.8s; 478 | -moz-transition: all 0.8s; 479 | -ms-transition: all 0.8s; 480 | -o-transition: all 0.8s; 481 | transition: all 0.8s; 482 | } 483 | 484 | .diagnoses .diagnosis { 485 | position: absolute; 486 | } 487 | 488 | .groups .label.show { 489 | opacity: 1; 490 | } 491 | 492 | 493 | #app > .detail { 494 | position: absolute; 495 | bottom: 3em; 496 | margin: 0 5%; 497 | width: 90%; 498 | } 499 | 500 | .label, #app > .detail .content { 501 | display: table-cell; 502 | margin: 0; 503 | padding: 0.75em; 504 | } 505 | 506 | .label { 507 | color: #f0f0f0; 508 | border-top-left-radius: 0.2em; 509 | border-bottom-left-radius: 0.2em; 510 | } 511 | 512 | #app > .detail .content { 513 | font-size: 95%; 514 | width: 100%; 515 | 516 | border-top-right-radius: 0.2em; 517 | border-bottom-right-radius: 0.2em; 518 | } 519 | 520 | #app .annotation { 521 | position: absolute; 522 | bottom: 1em; 523 | left: 5%; 524 | } 525 | 526 | 527 | .branding { 528 | position: absolute; 529 | bottom: 0; 530 | right: 0; 531 | 532 | margin: 0.5em 5%; 533 | width: 20%; 534 | 535 | text-align: right; 536 | display: inline; 537 | } 538 | 539 | .branding ul, .branding li { 540 | display: inline; 541 | } 542 | 543 | .branding .logo { 544 | height: 1em; 545 | } 546 | 547 | 548 | .scrolltip { 549 | background: #54787d; 550 | border-radius: 0.2em; 551 | color: #f0f0f0; 552 | text-align: right; 553 | 554 | overflow: hidden; 555 | text-overflow: ellipsis; 556 | 557 | padding: 0.25em; 558 | width: 7.5em; 559 | 560 | position: absolute; 561 | right: 5%; 562 | 563 | opacity: 0; 564 | 565 | -webkit-transform: translateY(50%); 566 | -webkit-transition: all 0.2s; 567 | -moz-transform: translateY(50%); 568 | -moz-transition: all 0.2s; 569 | -ms-transform: translateY(50%); 570 | -ms-transition: all 0.2s; 571 | -o-transform: translateY(50%); 572 | -o-transition: all 0.2s; 573 | transform: translateY(50%); 574 | transition: all 0.2s; 575 | } 576 | 577 | 578 | #app > .modify { 579 | font-size: 90%; 580 | } 581 | 582 | #app > .modify a { 583 | position: absolute; 584 | right: 0; 585 | 586 | padding: 0.5em; 587 | width: 3%; 588 | 589 | -webkit-transition: all 0.2s; 590 | -moz-transition: all 0.2s; 591 | -ms-transition: all 0.2s; 592 | -o-transition: all 0.2s; 593 | transition: all 0.2s; 594 | } 595 | 596 | #app > .modify a:hover { 597 | width: 5%; 598 | } 599 | 600 | #app > .review_button { 601 | font-size: 90%; 602 | } 603 | 604 | .disabled_button { 605 | color: #BBBBBB; 606 | } 607 | 608 | #app > .review_button a { 609 | position: absolute; 610 | right: 0; 611 | 612 | padding: 0.5em; 613 | width: 3%; 614 | 615 | overflow-x: hidden; 616 | overflow-y: hidden; 617 | white-space: nowrap; 618 | 619 | -webkit-transition: all 0.2s; 620 | -moz-transition: all 0.2s; 621 | -ms-transition: all 0.2s; 622 | -o-transition: all 0.2s; 623 | transition: all 0.2s; 624 | } 625 | 626 | #app > .review_button a:hover { 627 | width: 10em; 628 | } 629 | 630 | #app > .cancel_button { 631 | font-size: 90%; 632 | } 633 | 634 | #app > .cancel_button a { 635 | position: absolute; 636 | right: 0; 637 | 638 | padding: 0.5em; 639 | width: 3%; 640 | 641 | overflow-x: hidden; 642 | overflow-y: hidden; 643 | white-space: nowrap; 644 | 645 | -webkit-transition: all 0.2s; 646 | -moz-transition: all 0.2s; 647 | -ms-transition: all 0.2s; 648 | -o-transition: all 0.2s; 649 | transition: all 0.2s; 650 | } 651 | 652 | #app > .cancel_button a:hover { 653 | width: 5%; 654 | } 655 | 656 | .patient_name { 657 | font-size: 80%; 658 | /* TODO figure out ellipses */ 659 | } 660 | 661 | 662 | 663 | .modal { 664 | padding: 2em; 665 | border: 1px solid #999999; 666 | border-bottom-left-radius: 0.5em; 667 | border-bottom-right-radius: 0.5em; 668 | 669 | background: #f8f8f8; 670 | background: -webkit-gradient(linear, left top, left bottom, from(#ffffff), to(#f8f8f8)); 671 | background: -webkit-linear-gradient(top, #ffffff, #f8f8f8); 672 | background: -moz-linear-gradient(top, #ffffff, #f8f8f8); 673 | background: -ms-linear-gradient(top, #ffffff, #f8f8f8); 674 | background: -o-linear-gradient(top, #ffffff, #f8f8f8); 675 | 676 | color: #333333; 677 | 678 | -webkit-transition: all 0.2s; 679 | -webkit-backface-visibility: hidden; 680 | -moz-transition: all 0.2s; 681 | -ms-transition: all 0.2s; 682 | -o-transition: all 0.2s; 683 | 684 | z-index: -100; 685 | opacity: 0; 686 | } 687 | 688 | .modal a { 689 | font-weight: bold; 690 | color: #333333; 691 | } 692 | 693 | .modal a:hover { 694 | color: #777777; 695 | } 696 | 697 | .alert-modal { 698 | position: absolute; 699 | width: 30%; 700 | top: 25%; 701 | left: 32.5%; 702 | border-radius: 0.5em; 703 | 704 | -webkit-transform: translateY(-100%); 705 | -moz-transform: translateY(-100%); 706 | -ms-transform: translateY(-100%); 707 | -o-transform: translateY(-100%); 708 | } 709 | 710 | .alert-modal a { 711 | color: #333333; 712 | } 713 | 714 | .alert-modal strong { 715 | color: #dd4b39; 716 | } 717 | 718 | .help-modal { 719 | display: block; 720 | position: absolute; 721 | left: 12.5%; 722 | top: 0; 723 | width: 70%; 724 | height: 80%; 725 | overflow: auto; 726 | 727 | -webkit-transform: translateY(-100%); 728 | -moz-transform: translateY(-100%); 729 | -ms-transform: translateY(-100%); 730 | -o-transform: translateY(-100%); 731 | } 732 | 733 | .modify-modal { 734 | display: block; 735 | position: absolute; 736 | left: 12.5%; 737 | top: 0; 738 | width: 70%; 739 | height: 80%; 740 | overflow: auto; 741 | 742 | -webkit-transform: translateY(-100%); 743 | -moz-transform: translateY(-100%); 744 | -ms-transform: translateY(-100%); 745 | -o-transform: translateY(-100%); 746 | } 747 | 748 | #app .help-modal li { 749 | margin-left: 2em; 750 | } 751 | 752 | .show { 753 | -webkit-transform: translateY(0); 754 | -moz-transform: translateY(0); 755 | -ms-transform: translateY(0); 756 | -o-transform: translateY(0); 757 | 758 | z-index: 500; 759 | opacity: 1; 760 | } 761 | 762 | .close { 763 | margin-top: 1em; 764 | width: 5em; 765 | float: right; 766 | } 767 | 768 | 769 | 770 | .options-panel { 771 | background: #333333; 772 | color: #999999; 773 | font-size: 80%; 774 | 775 | border-collapse: collapse; 776 | 777 | position: absolute; 778 | right: 0; 779 | width: 97%; 780 | 781 | border-bottom-left-radius: 0.2em; 782 | 783 | opacity: 0; 784 | 785 | -webkit-transform: translateY(-200%); 786 | -moz-transform: translateY(-200%); 787 | -ms-transform: translateY(-200%); 788 | -o-transform: translateY(-200%); 789 | transform: translateY(-200%); 790 | } 791 | 792 | .options-panel td:nth-child(odd) { 793 | padding: 0.25em 0 0.25em 2em; 794 | } 795 | 796 | .options-panel td:nth-child(even) { 797 | padding: 0.25em 0 0.25em 0.5em; 798 | } 799 | 800 | .options-panel select, .options-panel input[type="text"] { 801 | width: 100%; 802 | } 803 | 804 | .options-panel li { 805 | display: inline; 806 | padding: 0; 807 | margin: 0; 808 | } 809 | 810 | .options-panel a { 811 | color: #999999; 812 | } 813 | 814 | .options-panel a:hover { 815 | color: #f0f0f0; 816 | } 817 | 818 | 819 | /* 820 | * Review panel (hides to the right). 821 | */ 822 | #review h1 { 823 | display: inline; 824 | } 825 | 826 | #review table { 827 | width: 100%; 828 | border-collapse: collapse; 829 | table-layout: fixed; 830 | } 831 | 832 | #review th { 833 | padding: 0.5em 0.4em; 834 | text-align: left; 835 | } 836 | 837 | #review .content th { 838 | padding: 0.4em; 839 | } 840 | 841 | #review td { 842 | white-space: nowrap; 843 | overflow: hidden; 844 | text-overflow: ellipsis; 845 | 846 | height: 2.5em; 847 | margin: 0; 848 | padding: 0.5em 0; 849 | } 850 | 851 | #review .content { 852 | position: absolute; 853 | margin: 0 0 0 10%; 854 | } 855 | 856 | #review .content { 857 | top: 25%; 858 | width: 80%; 859 | } 860 | 861 | #review .content { 862 | overflow-x: hidden; 863 | 864 | top: 30%; 865 | height: 55%; 866 | width: 80%; 867 | } 868 | 869 | #review .item { 870 | position: inherit; 871 | } 872 | 873 | #review .annotation { 874 | margin-left: 2em; 875 | } 876 | 877 | 878 | /* 879 | * Add / edit panel (hides to the right). 880 | */ 881 | #modify, #review { 882 | margin: 10% 5%; 883 | } 884 | 885 | #modify h1, #review header { 886 | position: absolute; 887 | top: 12%; 888 | margin: 3% 0; 889 | } 890 | 891 | .fields { 892 | margin-top: 10%; 893 | position: absolute; 894 | right: 5%; 895 | width: 31%; 896 | } 897 | 898 | .fields label { 899 | float: left; 900 | padding: 1%; 901 | margin: 2% 1% 2% 0; 902 | text-align: right; 903 | width: 30%; 904 | } 905 | 906 | .fields input, .fields textarea { 907 | border: 0.1em solid #bbbbbb; 908 | border-radius: 0.2em; 909 | 910 | font-size: 90%; 911 | font-family: "Andale Mono", monospace; 912 | 913 | margin: 2% 0 2% 1%; 914 | padding: 1%; 915 | width: 60%; 916 | } 917 | 918 | .fields textarea { 919 | resize: vertical; 920 | } 921 | 922 | .fields ::-webkit-input-placeholder { 923 | font-style: italic; 924 | opacity: 0.8; 925 | } 926 | 927 | .fields :-moz-placeholder { 928 | font-style: italic; 929 | opacity: 0.8; 930 | } 931 | 932 | .fields :-ms-input-placeholder { 933 | font-style: italic; 934 | opacity: 0.8; 935 | } 936 | 937 | .fields :-o-placeholder { 938 | font-style: italic; 939 | opacity: 0.8; 940 | } 941 | 942 | .preview { 943 | background: white; 944 | border: 0.1em dashed #bbbbbb; 945 | border-radius: 0.2em; 946 | 947 | position: absolute; 948 | top: 40%; 949 | left: 20%; 950 | } 951 | 952 | #modify .action, #review .action { 953 | position: absolute; 954 | right: 5%; 955 | 956 | top: 70%; 957 | width: 35%; 958 | } 959 | 960 | .save, .response { 961 | float: right; 962 | padding: 0.5em; 963 | } 964 | 965 | .save { 966 | border-left: 0.4em solid #999999; 967 | width: 90%; 968 | 969 | -webkit-transition: all 0.2s; 970 | -moz-transition: all 0.2s; 971 | -ms-transition: all 0.2s; 972 | -o-transition: all 0.2s; 973 | transition: all 0.2s; 974 | } 975 | 976 | .save:hover { 977 | width: 100%; 978 | text-decoration: none; 979 | } 980 | 981 | .response { 982 | font-size: 95%; 983 | opacity: 0; 984 | 985 | -webkit-transition: all 0.4s; 986 | -moz-transition: all 0.4s; 987 | -ms-transition: all 0.4s; 988 | -o-transition: all 0.4s; 989 | transition: all 0.4s; 990 | } 991 | 992 | .response .back::before { 993 | content: "[ "; 994 | } 995 | 996 | .response .back::after { 997 | content: " ]"; 998 | } 999 | 1000 | .watermark { 1001 | font-size: 300%; 1002 | 1003 | position: absolute; 1004 | bottom: 15%; 1005 | 1006 | opacity: 0.4; 1007 | pointer-events: none; 1008 | } 1009 | 1010 | 1011 | /* 1012 | * Utility: colors, fonts, ... 1013 | */ 1014 | .content-text { 1015 | font-family: "Lucida Grande", "Lucida Sans", Helvetica, sans-serif; 1016 | } 1017 | 1018 | .explanatory-text { 1019 | font-family: "Andale Mono", monospace; 1020 | } 1021 | 1022 | .keyword { 1023 | font-weight: normal; 1024 | } 1025 | 1026 | .link { 1027 | text-decoration: underline; 1028 | } 1029 | 1030 | .warning { 1031 | color: #dd4b39; 1032 | } 1033 | 1034 | .annotation { 1035 | font-size: 80%; 1036 | font-style: italic; 1037 | font-weight: normal; 1038 | } 1039 | 1040 | .bg-accent { 1041 | background: #54787d; 1042 | } 1043 | 1044 | thead { 1045 | z-index: 999; /* > 10 to be above items, > 500 to be above .show */ 1046 | } 1047 | 1048 | .bg-contrast-light { 1049 | background: #f0f0f0; 1050 | } 1051 | 1052 | .bg-contrast-dark { 1053 | background: #e5e5e5; 1054 | } 1055 | 1056 | .show { 1057 | opacity: 1; 1058 | -webkit-transform: translate(0, 0); 1059 | -moz-transform: translate(0, 0); 1060 | -ms-transform: translate(0, 0); 1061 | -o-transform: translate(0, 0); 1062 | transform: translate(0, 0); 1063 | } 1064 | 1065 | /* TODO better place to put this stuff */ 1066 | .num_remaining { 1067 | text-decoration: underline; 1068 | } 1069 | -------------------------------------------------------------------------------- /css/jquery-ui-1.10.2.custom.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.10.2 - 2013-03-25 2 | * http://jqueryui.com 3 | * Includes: jquery.ui.core.css, jquery.ui.resizable.css, jquery.ui.button.css, jquery.ui.dialog.css 4 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px 5 | * Copyright 2013 jQuery Foundation and other contributors Licensed MIT */ 6 | 7 | /* Layout helpers 8 | ----------------------------------*/ 9 | .ui-helper-hidden { 10 | display: none; 11 | } 12 | .ui-helper-hidden-accessible { 13 | border: 0; 14 | clip: rect(0 0 0 0); 15 | height: 1px; 16 | margin: -1px; 17 | overflow: hidden; 18 | padding: 0; 19 | position: absolute; 20 | width: 1px; 21 | } 22 | .ui-helper-reset { 23 | margin: 0; 24 | padding: 0; 25 | border: 0; 26 | outline: 0; 27 | line-height: 1.3; 28 | text-decoration: none; 29 | font-size: 100%; 30 | list-style: none; 31 | } 32 | .ui-helper-clearfix:before, 33 | .ui-helper-clearfix:after { 34 | content: ""; 35 | display: table; 36 | border-collapse: collapse; 37 | } 38 | .ui-helper-clearfix:after { 39 | clear: both; 40 | } 41 | .ui-helper-clearfix { 42 | min-height: 0; /* support: IE7 */ 43 | } 44 | .ui-helper-zfix { 45 | width: 100%; 46 | height: 100%; 47 | top: 0; 48 | left: 0; 49 | position: absolute; 50 | opacity: 0; 51 | filter:Alpha(Opacity=0); 52 | } 53 | 54 | .ui-front { 55 | z-index: 100; 56 | } 57 | 58 | 59 | /* Interaction Cues 60 | ----------------------------------*/ 61 | .ui-state-disabled { 62 | cursor: default !important; 63 | } 64 | 65 | 66 | /* Icons 67 | ----------------------------------*/ 68 | 69 | /* states and images */ 70 | .ui-icon { 71 | display: block; 72 | text-indent: -99999px; 73 | overflow: hidden; 74 | background-repeat: no-repeat; 75 | } 76 | 77 | 78 | /* Misc visuals 79 | ----------------------------------*/ 80 | 81 | /* Overlays */ 82 | .ui-widget-overlay { 83 | position: fixed; 84 | top: 0; 85 | left: 0; 86 | width: 100%; 87 | height: 100%; 88 | } 89 | .ui-resizable { 90 | position: relative; 91 | } 92 | .ui-resizable-handle { 93 | position: absolute; 94 | font-size: 0.1px; 95 | display: block; 96 | } 97 | .ui-resizable-disabled .ui-resizable-handle, 98 | .ui-resizable-autohide .ui-resizable-handle { 99 | display: none; 100 | } 101 | .ui-resizable-n { 102 | cursor: n-resize; 103 | height: 7px; 104 | width: 100%; 105 | top: -5px; 106 | left: 0; 107 | } 108 | .ui-resizable-s { 109 | cursor: s-resize; 110 | height: 7px; 111 | width: 100%; 112 | bottom: -5px; 113 | left: 0; 114 | } 115 | .ui-resizable-e { 116 | cursor: e-resize; 117 | width: 7px; 118 | right: -5px; 119 | top: 0; 120 | height: 100%; 121 | } 122 | .ui-resizable-w { 123 | cursor: w-resize; 124 | width: 7px; 125 | left: -5px; 126 | top: 0; 127 | height: 100%; 128 | } 129 | .ui-resizable-se { 130 | cursor: se-resize; 131 | width: 12px; 132 | height: 12px; 133 | right: 1px; 134 | bottom: 1px; 135 | } 136 | .ui-resizable-sw { 137 | cursor: sw-resize; 138 | width: 9px; 139 | height: 9px; 140 | left: -5px; 141 | bottom: -5px; 142 | } 143 | .ui-resizable-nw { 144 | cursor: nw-resize; 145 | width: 9px; 146 | height: 9px; 147 | left: -5px; 148 | top: -5px; 149 | } 150 | .ui-resizable-ne { 151 | cursor: ne-resize; 152 | width: 9px; 153 | height: 9px; 154 | right: -5px; 155 | top: -5px; 156 | } 157 | .ui-button { 158 | display: inline-block; 159 | position: relative; 160 | padding: 0; 161 | line-height: normal; 162 | margin-right: .1em; 163 | cursor: pointer; 164 | vertical-align: middle; 165 | text-align: center; 166 | overflow: visible; /* removes extra width in IE */ 167 | } 168 | .ui-button, 169 | .ui-button:link, 170 | .ui-button:visited, 171 | .ui-button:hover, 172 | .ui-button:active { 173 | text-decoration: none; 174 | } 175 | /* to make room for the icon, a width needs to be set here */ 176 | .ui-button-icon-only { 177 | width: 2.2em; 178 | } 179 | /* button elements seem to need a little more width */ 180 | button.ui-button-icon-only { 181 | width: 2.4em; 182 | } 183 | .ui-button-icons-only { 184 | width: 3.4em; 185 | } 186 | button.ui-button-icons-only { 187 | width: 3.7em; 188 | } 189 | 190 | /* button text element */ 191 | .ui-button .ui-button-text { 192 | display: block; 193 | line-height: normal; 194 | } 195 | .ui-button-text-only .ui-button-text { 196 | padding: .4em 1em; 197 | } 198 | .ui-button-icon-only .ui-button-text, 199 | .ui-button-icons-only .ui-button-text { 200 | padding: .4em; 201 | text-indent: -9999999px; 202 | } 203 | .ui-button-text-icon-primary .ui-button-text, 204 | .ui-button-text-icons .ui-button-text { 205 | padding: .4em 1em .4em 2.1em; 206 | } 207 | .ui-button-text-icon-secondary .ui-button-text, 208 | .ui-button-text-icons .ui-button-text { 209 | padding: .4em 2.1em .4em 1em; 210 | } 211 | .ui-button-text-icons .ui-button-text { 212 | padding-left: 2.1em; 213 | padding-right: 2.1em; 214 | } 215 | /* no icon support for input elements, provide padding by default */ 216 | input.ui-button { 217 | padding: .4em 1em; 218 | } 219 | 220 | /* button icon element(s) */ 221 | .ui-button-icon-only .ui-icon, 222 | .ui-button-text-icon-primary .ui-icon, 223 | .ui-button-text-icon-secondary .ui-icon, 224 | .ui-button-text-icons .ui-icon, 225 | .ui-button-icons-only .ui-icon { 226 | position: absolute; 227 | top: 50%; 228 | margin-top: -8px; 229 | } 230 | .ui-button-icon-only .ui-icon { 231 | left: 50%; 232 | margin-left: -8px; 233 | } 234 | .ui-button-text-icon-primary .ui-button-icon-primary, 235 | .ui-button-text-icons .ui-button-icon-primary, 236 | .ui-button-icons-only .ui-button-icon-primary { 237 | left: .5em; 238 | } 239 | .ui-button-text-icon-secondary .ui-button-icon-secondary, 240 | .ui-button-text-icons .ui-button-icon-secondary, 241 | .ui-button-icons-only .ui-button-icon-secondary { 242 | right: .5em; 243 | } 244 | 245 | /* button sets */ 246 | .ui-buttonset { 247 | margin-right: 7px; 248 | } 249 | .ui-buttonset .ui-button { 250 | margin-left: 0; 251 | margin-right: -.3em; 252 | } 253 | 254 | /* workarounds */ 255 | /* reset extra padding in Firefox, see h5bp.com/l */ 256 | input.ui-button::-moz-focus-inner, 257 | button.ui-button::-moz-focus-inner { 258 | border: 0; 259 | padding: 0; 260 | } 261 | .ui-dialog { 262 | position: absolute; 263 | top: 0; 264 | left: 0; 265 | padding: .2em; 266 | outline: 0; 267 | } 268 | .ui-dialog .ui-dialog-titlebar { 269 | padding: .4em 1em; 270 | position: relative; 271 | } 272 | .ui-dialog .ui-dialog-title { 273 | float: left; 274 | margin: .1em 0; 275 | white-space: nowrap; 276 | width: 90%; 277 | overflow: hidden; 278 | text-overflow: ellipsis; 279 | } 280 | .ui-dialog .ui-dialog-titlebar-close { 281 | position: absolute; 282 | right: .3em; 283 | top: 50%; 284 | width: 21px; 285 | margin: -10px 0 0 0; 286 | padding: 1px; 287 | height: 20px; 288 | } 289 | .ui-dialog .ui-dialog-content { 290 | position: relative; 291 | border: 0; 292 | padding: .5em 1em; 293 | background: none; 294 | overflow: auto; 295 | } 296 | .ui-dialog .ui-dialog-buttonpane { 297 | text-align: left; 298 | border-width: 1px 0 0 0; 299 | background-image: none; 300 | margin-top: .5em; 301 | padding: .3em 1em .5em .4em; 302 | } 303 | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { 304 | float: right; 305 | } 306 | .ui-dialog .ui-dialog-buttonpane button { 307 | margin: .5em .4em .5em 0; 308 | cursor: pointer; 309 | } 310 | .ui-dialog .ui-resizable-se { 311 | width: 12px; 312 | height: 12px; 313 | right: -5px; 314 | bottom: -5px; 315 | background-position: 16px 16px; 316 | } 317 | .ui-draggable .ui-dialog-titlebar { 318 | cursor: move; 319 | } 320 | 321 | /* Component containers 322 | ----------------------------------*/ 323 | .ui-widget { 324 | font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; 325 | font-size: 1.1em; 326 | } 327 | .ui-widget .ui-widget { 328 | font-size: 1em; 329 | } 330 | .ui-widget input, 331 | .ui-widget select, 332 | .ui-widget textarea, 333 | .ui-widget button { 334 | font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; 335 | font-size: 1em; 336 | } 337 | .ui-widget-content { 338 | border: 1px solid #dddddd; 339 | background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; 340 | color: #333333; 341 | } 342 | .ui-widget-content a { 343 | color: #333333; 344 | } 345 | .ui-widget-header { 346 | border: 1px solid #e78f08; 347 | background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; 348 | color: #ffffff; 349 | font-weight: bold; 350 | } 351 | .ui-widget-header a { 352 | color: #ffffff; 353 | } 354 | 355 | /* Interaction states 356 | ----------------------------------*/ 357 | .ui-state-default, 358 | .ui-widget-content .ui-state-default, 359 | .ui-widget-header .ui-state-default { 360 | border: 1px solid #cccccc; 361 | background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; 362 | font-weight: bold; 363 | color: #1c94c4; 364 | } 365 | .ui-state-default a, 366 | .ui-state-default a:link, 367 | .ui-state-default a:visited { 368 | color: #1c94c4; 369 | text-decoration: none; 370 | } 371 | .ui-state-hover, 372 | .ui-widget-content .ui-state-hover, 373 | .ui-widget-header .ui-state-hover, 374 | .ui-state-focus, 375 | .ui-widget-content .ui-state-focus, 376 | .ui-widget-header .ui-state-focus { 377 | border: 1px solid #fbcb09; 378 | background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; 379 | font-weight: bold; 380 | color: #c77405; 381 | } 382 | .ui-state-hover a, 383 | .ui-state-hover a:hover, 384 | .ui-state-hover a:link, 385 | .ui-state-hover a:visited { 386 | color: #c77405; 387 | text-decoration: none; 388 | } 389 | .ui-state-active, 390 | .ui-widget-content .ui-state-active, 391 | .ui-widget-header .ui-state-active { 392 | border: 1px solid #fbd850; 393 | background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; 394 | font-weight: bold; 395 | color: #eb8f00; 396 | } 397 | .ui-state-active a, 398 | .ui-state-active a:link, 399 | .ui-state-active a:visited { 400 | color: #eb8f00; 401 | text-decoration: none; 402 | } 403 | 404 | /* Interaction Cues 405 | ----------------------------------*/ 406 | .ui-state-highlight, 407 | .ui-widget-content .ui-state-highlight, 408 | .ui-widget-header .ui-state-highlight { 409 | border: 1px solid #fed22f; 410 | background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; 411 | color: #363636; 412 | } 413 | .ui-state-highlight a, 414 | .ui-widget-content .ui-state-highlight a, 415 | .ui-widget-header .ui-state-highlight a { 416 | color: #363636; 417 | } 418 | .ui-state-error, 419 | .ui-widget-content .ui-state-error, 420 | .ui-widget-header .ui-state-error { 421 | border: 1px solid #cd0a0a; 422 | background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; 423 | color: #ffffff; 424 | } 425 | .ui-state-error a, 426 | .ui-widget-content .ui-state-error a, 427 | .ui-widget-header .ui-state-error a { 428 | color: #ffffff; 429 | } 430 | .ui-state-error-text, 431 | .ui-widget-content .ui-state-error-text, 432 | .ui-widget-header .ui-state-error-text { 433 | color: #ffffff; 434 | } 435 | .ui-priority-primary, 436 | .ui-widget-content .ui-priority-primary, 437 | .ui-widget-header .ui-priority-primary { 438 | font-weight: bold; 439 | } 440 | .ui-priority-secondary, 441 | .ui-widget-content .ui-priority-secondary, 442 | .ui-widget-header .ui-priority-secondary { 443 | opacity: .7; 444 | filter:Alpha(Opacity=70); 445 | font-weight: normal; 446 | } 447 | .ui-state-disabled, 448 | .ui-widget-content .ui-state-disabled, 449 | .ui-widget-header .ui-state-disabled { 450 | opacity: .35; 451 | filter:Alpha(Opacity=35); 452 | background-image: none; 453 | } 454 | .ui-state-disabled .ui-icon { 455 | filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ 456 | } 457 | 458 | /* Icons 459 | ----------------------------------*/ 460 | 461 | /* states and images */ 462 | .ui-icon { 463 | width: 16px; 464 | height: 16px; 465 | } 466 | .ui-icon, 467 | .ui-widget-content .ui-icon { 468 | background-image: url(images/ui-icons_222222_256x240.png); 469 | } 470 | .ui-widget-header .ui-icon { 471 | background-image: url(images/ui-icons_ffffff_256x240.png); 472 | } 473 | .ui-state-default .ui-icon { 474 | background-image: url(images/ui-icons_ef8c08_256x240.png); 475 | } 476 | .ui-state-hover .ui-icon, 477 | .ui-state-focus .ui-icon { 478 | background-image: url(images/ui-icons_ef8c08_256x240.png); 479 | } 480 | .ui-state-active .ui-icon { 481 | background-image: url(images/ui-icons_ef8c08_256x240.png); 482 | } 483 | .ui-state-highlight .ui-icon { 484 | background-image: url(images/ui-icons_228ef1_256x240.png); 485 | } 486 | .ui-state-error .ui-icon, 487 | .ui-state-error-text .ui-icon { 488 | background-image: url(images/ui-icons_ffd27a_256x240.png); 489 | } 490 | 491 | /* positioning */ 492 | .ui-icon-blank { background-position: 16px 16px; } 493 | .ui-icon-carat-1-n { background-position: 0 0; } 494 | .ui-icon-carat-1-ne { background-position: -16px 0; } 495 | .ui-icon-carat-1-e { background-position: -32px 0; } 496 | .ui-icon-carat-1-se { background-position: -48px 0; } 497 | .ui-icon-carat-1-s { background-position: -64px 0; } 498 | .ui-icon-carat-1-sw { background-position: -80px 0; } 499 | .ui-icon-carat-1-w { background-position: -96px 0; } 500 | .ui-icon-carat-1-nw { background-position: -112px 0; } 501 | .ui-icon-carat-2-n-s { background-position: -128px 0; } 502 | .ui-icon-carat-2-e-w { background-position: -144px 0; } 503 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 504 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 505 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 506 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 507 | .ui-icon-triangle-1-s { background-position: -64px -16px; } 508 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 509 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 510 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 511 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 512 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 513 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 514 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 515 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 516 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 517 | .ui-icon-arrow-1-s { background-position: -64px -32px; } 518 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 519 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 520 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 521 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 522 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 523 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 524 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 525 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 526 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 527 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 528 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 529 | .ui-icon-arrowthick-1-n { background-position: 0 -48px; } 530 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 531 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 532 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 533 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 534 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 535 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 536 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 537 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 538 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 539 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 540 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 541 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 542 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 543 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 544 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 545 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 546 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 547 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 548 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 549 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 550 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 551 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 552 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 553 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 554 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 555 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 556 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 557 | .ui-icon-arrow-4 { background-position: 0 -80px; } 558 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 559 | .ui-icon-extlink { background-position: -32px -80px; } 560 | .ui-icon-newwin { background-position: -48px -80px; } 561 | .ui-icon-refresh { background-position: -64px -80px; } 562 | .ui-icon-shuffle { background-position: -80px -80px; } 563 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 564 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 565 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 566 | .ui-icon-folder-open { background-position: -16px -96px; } 567 | .ui-icon-document { background-position: -32px -96px; } 568 | .ui-icon-document-b { background-position: -48px -96px; } 569 | .ui-icon-note { background-position: -64px -96px; } 570 | .ui-icon-mail-closed { background-position: -80px -96px; } 571 | .ui-icon-mail-open { background-position: -96px -96px; } 572 | .ui-icon-suitcase { background-position: -112px -96px; } 573 | .ui-icon-comment { background-position: -128px -96px; } 574 | .ui-icon-person { background-position: -144px -96px; } 575 | .ui-icon-print { background-position: -160px -96px; } 576 | .ui-icon-trash { background-position: -176px -96px; } 577 | .ui-icon-locked { background-position: -192px -96px; } 578 | .ui-icon-unlocked { background-position: -208px -96px; } 579 | .ui-icon-bookmark { background-position: -224px -96px; } 580 | .ui-icon-tag { background-position: -240px -96px; } 581 | .ui-icon-home { background-position: 0 -112px; } 582 | .ui-icon-flag { background-position: -16px -112px; } 583 | .ui-icon-calendar { background-position: -32px -112px; } 584 | .ui-icon-cart { background-position: -48px -112px; } 585 | .ui-icon-pencil { background-position: -64px -112px; } 586 | .ui-icon-clock { background-position: -80px -112px; } 587 | .ui-icon-disk { background-position: -96px -112px; } 588 | .ui-icon-calculator { background-position: -112px -112px; } 589 | .ui-icon-zoomin { background-position: -128px -112px; } 590 | .ui-icon-zoomout { background-position: -144px -112px; } 591 | .ui-icon-search { background-position: -160px -112px; } 592 | .ui-icon-wrench { background-position: -176px -112px; } 593 | .ui-icon-gear { background-position: -192px -112px; } 594 | .ui-icon-heart { background-position: -208px -112px; } 595 | .ui-icon-star { background-position: -224px -112px; } 596 | .ui-icon-link { background-position: -240px -112px; } 597 | .ui-icon-cancel { background-position: 0 -128px; } 598 | .ui-icon-plus { background-position: -16px -128px; } 599 | .ui-icon-plusthick { background-position: -32px -128px; } 600 | .ui-icon-minus { background-position: -48px -128px; } 601 | .ui-icon-minusthick { background-position: -64px -128px; } 602 | .ui-icon-close { background-position: -80px -128px; } 603 | .ui-icon-closethick { background-position: -96px -128px; } 604 | .ui-icon-key { background-position: -112px -128px; } 605 | .ui-icon-lightbulb { background-position: -128px -128px; } 606 | .ui-icon-scissors { background-position: -144px -128px; } 607 | .ui-icon-clipboard { background-position: -160px -128px; } 608 | .ui-icon-copy { background-position: -176px -128px; } 609 | .ui-icon-contact { background-position: -192px -128px; } 610 | .ui-icon-image { background-position: -208px -128px; } 611 | .ui-icon-video { background-position: -224px -128px; } 612 | .ui-icon-script { background-position: -240px -128px; } 613 | .ui-icon-alert { background-position: 0 -144px; } 614 | .ui-icon-info { background-position: -16px -144px; } 615 | .ui-icon-notice { background-position: -32px -144px; } 616 | .ui-icon-help { background-position: -48px -144px; } 617 | .ui-icon-check { background-position: -64px -144px; } 618 | .ui-icon-bullet { background-position: -80px -144px; } 619 | .ui-icon-radio-on { background-position: -96px -144px; } 620 | .ui-icon-radio-off { background-position: -112px -144px; } 621 | .ui-icon-pin-w { background-position: -128px -144px; } 622 | .ui-icon-pin-s { background-position: -144px -144px; } 623 | .ui-icon-play { background-position: 0 -160px; } 624 | .ui-icon-pause { background-position: -16px -160px; } 625 | .ui-icon-seek-next { background-position: -32px -160px; } 626 | .ui-icon-seek-prev { background-position: -48px -160px; } 627 | .ui-icon-seek-end { background-position: -64px -160px; } 628 | .ui-icon-seek-start { background-position: -80px -160px; } 629 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 630 | .ui-icon-seek-first { background-position: -80px -160px; } 631 | .ui-icon-stop { background-position: -96px -160px; } 632 | .ui-icon-eject { background-position: -112px -160px; } 633 | .ui-icon-volume-off { background-position: -128px -160px; } 634 | .ui-icon-volume-on { background-position: -144px -160px; } 635 | .ui-icon-power { background-position: 0 -176px; } 636 | .ui-icon-signal-diag { background-position: -16px -176px; } 637 | .ui-icon-signal { background-position: -32px -176px; } 638 | .ui-icon-battery-0 { background-position: -48px -176px; } 639 | .ui-icon-battery-1 { background-position: -64px -176px; } 640 | .ui-icon-battery-2 { background-position: -80px -176px; } 641 | .ui-icon-battery-3 { background-position: -96px -176px; } 642 | .ui-icon-circle-plus { background-position: 0 -192px; } 643 | .ui-icon-circle-minus { background-position: -16px -192px; } 644 | .ui-icon-circle-close { background-position: -32px -192px; } 645 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 646 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 647 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 648 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 649 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 650 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 651 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 652 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 653 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 654 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 655 | .ui-icon-circle-check { background-position: -208px -192px; } 656 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 657 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 658 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 659 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 660 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 661 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 662 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 663 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 664 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 665 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 666 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 667 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 668 | 669 | 670 | /* Misc visuals 671 | ----------------------------------*/ 672 | 673 | /* Corner radius */ 674 | .ui-corner-all, 675 | .ui-corner-top, 676 | .ui-corner-left, 677 | .ui-corner-tl { 678 | border-top-left-radius: 4px; 679 | } 680 | .ui-corner-all, 681 | .ui-corner-top, 682 | .ui-corner-right, 683 | .ui-corner-tr { 684 | border-top-right-radius: 4px; 685 | } 686 | .ui-corner-all, 687 | .ui-corner-bottom, 688 | .ui-corner-left, 689 | .ui-corner-bl { 690 | border-bottom-left-radius: 4px; 691 | } 692 | .ui-corner-all, 693 | .ui-corner-bottom, 694 | .ui-corner-right, 695 | .ui-corner-br { 696 | border-bottom-right-radius: 4px; 697 | } 698 | 699 | /* Overlays */ 700 | .ui-widget-overlay { 701 | background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; 702 | opacity: .5; 703 | filter: Alpha(Opacity=50); 704 | } 705 | .ui-widget-shadow { 706 | margin: -5px 0 0 -5px; 707 | padding: 5px; 708 | background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; 709 | opacity: .2; 710 | filter: Alpha(Opacity=20); 711 | border-radius: 5px; 712 | } 713 | -------------------------------------------------------------------------------- /js/model.js: -------------------------------------------------------------------------------- 1 | var model = function(model, jQuery) { 2 | ////// visible /////////////////////////////////////////////////////////// 3 | var visible = {}; 4 | 5 | // pseudo constants ////////////////////////////////////////////////// 6 | visible.ATTR_NAME = "__ATTR_NAME__"; 7 | visible.ATTR_GENERIC_NAME = "__ATTR_GENERIC_NAME__"; 8 | visible.ATTR_RECORDED_NAME = "__ATTR_RECORDED_NAME__"; 9 | visible.ATTR_BRAND_NAME = "__ATTR_BRAND_NAME__"; 10 | visible.ATTR_ROUTE = "__ATTR_ROUTE__"; 11 | visible.ATTR_FREQUENCY = "__ATTR_FREQUENCY__"; 12 | visible.ATTR_DOSE = "__ATTR_DOSE__"; 13 | visible.ATTR_DRUG_CLASS = "__ATTR_DRUG_CLASS__"; 14 | visible.ATTR_DIAGNOSES = "__ATTR_DIAGNOSES__"; 15 | visible.ATTR_SUBITEM = "__ATTR_SUBITEM__"; 16 | visible.ATTR_DATE_STARTED = "__ATTR_DATE_STARTED__"; 17 | visible.ATTR_INSTRUCTIONS = "__ATTR_INSTRUCTIONS__"; 18 | 19 | visible.ATTR_TYPE_NUMERIC = "__ATTR_TYPE_NUMERIC__"; 20 | visible.ATTR_TYPE_GENERAL = "__ATTR_TYPE_GENERAL__"; 21 | visible.ATTR_TYPE_CATEGORICAL = "__ATTR_TYPE_CATEGORICAL__"; 22 | 23 | // config - dataset 24 | visible.DATASET_APP = "__DATASET_APPENDECTOMY__"; 25 | visible.DATASET_CHF1 = "__DATASET_CONGESTIVE_HEART_FAILURE_1__"; 26 | visible.DATASET_CHF2 = "__DATASET_CONGESTIVE_HEART_FAILURE_2__"; 27 | visible.DATASET_PD1 = "__DATASET_PULMONARY_DISEASE_1__"; 28 | visible.DATASET_PD2 = "__DATASET_PULMONARY_DISEASE_2__"; 29 | visible.DATASET_OTHER_SIMPLE = "__DATASET_OTHER_SIMPLE__"; 30 | visible.DATASET_OTHER_COMPLEX = "__DATASET_OTHER_COMPLEX__"; 31 | visible.DATASET_OTHER_EXTRA = "__DATASET_OTHER_EXTRA__"; 32 | visible.DATASET_PD2_CORRECTED = "__DATASET_PULMONARY_DISEASE_2_CORRECTED__"; 33 | visible.DATASET_CHF1_MODIFIED = "__DATASET_CONGESTIVE_HEART_FAILURE_1_MODIFIED__"; 34 | visible.DATASET_DEFAULT = visible.DATASET_APP; 35 | 36 | visible.RECORDED_NAME = "recorded"; 37 | visible.GENERIC_NAME = "generic"; 38 | visible.BRAND_NAME = "brand"; 39 | 40 | visible.AFTER_ACTION_GRAYOUT = "__AFTER_ACTION_GRAYOUT__"; 41 | visible.AFTER_ACTION_REMOVE = "__AFTER_ACTION_REMOVE__"; 42 | 43 | visible.FILTER_DELAY_SCALE = 4; 44 | 45 | // data ////////////////////////////////////////////////////////////// 46 | visible.patientFirstName = ""; 47 | visible.patientLastName = ""; 48 | visible.patientAge = 0; 49 | visible.patientGender = ""; 50 | 51 | visible.dataset = ""; 52 | visible.items = {}; 53 | 54 | // diagnoses for items 55 | visible.diagnoses = {}; 56 | 57 | // relationship between items and diagnoses 58 | visible.diagnosisSet = {}; 59 | 60 | 61 | // drug classes for the current dataset 62 | visible.drugClasses = {}; 63 | visible.drugClassSet = {}; 64 | 65 | visible.shadows = {}; 66 | visible.itemsToShadows = {}; 67 | visible.shadowsToItems = {}; 68 | visible.hidden = {}; 69 | 70 | visible.list1 = { 71 | id : "list0", 72 | name : "Intake", 73 | source : [] 74 | }; 75 | visible.list2 = { 76 | id : "list1", 77 | name : "Hospital", 78 | source : [] 79 | }; 80 | 81 | visible.getDatasetShortName = function(dataset) { 82 | switch(dataset) { 83 | case visible.DATASET_APP: 84 | return "APPNDCTMY"; 85 | case visible.DATASET_CHF1: 86 | return "CHF1"; 87 | case visible.DATASET_CHF2: 88 | return "CHF2"; 89 | case visible.DATASET_PD1: 90 | return "PD1"; 91 | case visible.DATASET_PD2: 92 | return "PD2"; 93 | case visible.DATASET_OTHER_SIMPLE: 94 | return "O_SIMPLE"; 95 | case visible.DATASET_OTHER_COMPLEX: 96 | return "O_COMPLEX"; 97 | case visible.DATASET_OTHER_EXTRA: 98 | return "O_EXTRA"; 99 | case visible.DATASET_PD2_CORRECTED: 100 | return "PD2_C"; 101 | case visible.DATASET_CHF1_MODIFIED: 102 | return "CHF1_M"; 103 | } 104 | return undefined; 105 | }; 106 | 107 | /* 108 | * Create and return viewData object (contains information on what to display) 109 | * 110 | * Arguments: 111 | * boolean sort - whether to sort data 112 | * boolean filter - whether to filter data 113 | * 114 | * Preconditions: 115 | * visible.multigroup - indicates whether to include shadows 116 | * visible.groupBy - indicates what (if any) grouping to use 117 | * visible.shadows - shadows populated (e.g. during loadData) 118 | * 119 | * visible.unique1 - contains ids that will end up in unique1 120 | * visible.unique2 - contains ids that will end up in unique2 121 | * visible.identical - contains ids that will end up in identical 122 | * 123 | * Returns: 124 | * viewData object (see viewData in controller for object description) 125 | * 126 | * Algorithm summary: 127 | * build a list of relevantIds (includes shadows if multigroup on) 128 | * filter and sort the list 129 | * bucket into groups and compute metadata in viewData (e.g. lengths) 130 | */ 131 | visible.viewData = function(sort, filter) { 132 | 133 | var viewData = {}; 134 | 135 | // get every id we need to care about (e.g. list1 + list2 + shadows (if any)) 136 | var relevantIds = visible.list1.source.concat(visible.list2.source); 137 | 138 | // get or hide shadows 139 | if (visible.multigroup && visible.groupBy) { 140 | for (var shadowID in visible.shadows) { 141 | var shadow = visible.shadows[shadowID]; 142 | if (visible.groupBy in shadow.attributes && shadow.attributes[visible.groupBy].length > 1 && shadow.attributes[visible.groupBy][shadow.groupByOffset]) { 143 | // if shadow should be shown, update accordingly: 144 | relevantIds.push(shadowID); 145 | 146 | // update information about what is hidden 147 | if ( shadowID in visible.hidden) { 148 | controller.toggleItem($("#" + shadowID), controller.toggleOnDelay, true); 149 | if (visible.hidden[shadowID]) 150 | delete visible.hidden[shadowID]; 151 | } 152 | } else { 153 | // otherwise, hide the shadow 154 | controller.toggleItem($("#" + shadowID), controller.toggleOffDelay, false); 155 | visible.hidden[shadowID] = true; 156 | } 157 | } 158 | } else { 159 | // no multigroup + groupBy = no shadows 160 | for (var shadowID in visible.shadows) { 161 | controller.toggleItem($("#" + shadowID), controller.toggleOffDelay, false); 162 | visible.hidden[shadowID] = true; 163 | } 164 | } 165 | 166 | // filter based on unified filter 167 | if (filter) { 168 | relevantIds = relevantIds.filter(unifiedFilter); 169 | } 170 | 171 | // sort data 172 | if (sort || filter) { 173 | relevantIds = relevantIds.sort(groupThenSort); 174 | } 175 | 176 | // initialize default group 177 | var groups = {}; 178 | viewData.groups = groups; 179 | 180 | groups[visible.DEFAULT_GROUP] = []; 181 | 182 | var groupNames = []; 183 | // names of groups, used for ranking 184 | 185 | // for calculating lengths of groups 186 | var groupLengths = {}; 187 | viewData.groupLengths = groupLengths; 188 | 189 | // Note: identicalMarker is a hash to keep track of distinct groups of 190 | // identical objects 191 | groupLengths[""] = { 192 | "unique1" : [], 193 | "identicalMarker" : {}, 194 | "unique2" : [] 195 | }; 196 | 197 | for (var i in relevantIds) { 198 | var id = relevantIds[i]; 199 | var item = visible.items[id]; 200 | 201 | var trueId = item.isShadow ? parseInt(visible.shadowsToItems[id]) : id; 202 | 203 | // populate "groups" 204 | 205 | var itemGroup = visible.DEFAULT_GROUP; 206 | if (item.attributes.hasOwnProperty(visible.groupBy)) { 207 | // put id into its group if it has the grouped attribute 208 | // groupByOffset = offset into attribute list to get the primary group 209 | itemGroup = item.attributes[visible.groupBy][item.groupByOffset]; 210 | 211 | // initialize array for group if needed 212 | if (!groups.hasOwnProperty(itemGroup)) { 213 | groups[itemGroup] = []; 214 | groupNames.push(itemGroup); 215 | groupLengths[itemGroup] = { 216 | "unique1" : [], 217 | "identicalMarker" : {}, 218 | "unique2" : [] 219 | }; 220 | } 221 | } 222 | 223 | // put into retrieved (possibly just created) (or default) group 224 | groups[itemGroup].push(id); 225 | 226 | // update groupLengths depending on where if will end up 227 | 228 | if (visible.unique1.indexOf(trueId) >= 0) { 229 | groupLengths[itemGroup].unique1.push(id); 230 | } else if (visible.unique2.indexOf(trueId) >= 0) { 231 | groupLengths[itemGroup].unique2.push(id); 232 | } else if ( trueId in visible.identical) { 233 | // get identical set, see if group marker already there, if not, add this 234 | var idenList = visible.identical[trueId]; 235 | var j = 0; 236 | for (; j < idenList.length; j++) { 237 | if (idenList[j] in groupLengths[itemGroup].identicalMarker) 238 | break; 239 | } 240 | 241 | if (j == idenList.length) { 242 | // if didn't find group marker, add this to identicalMarker 243 | groupLengths[itemGroup].identicalMarker[trueId] = idenList; 244 | } 245 | } // else in similar 246 | 247 | }// end of grouping ids 248 | 249 | // delete default group if unused (all other groups only exist if created) 250 | if (groups[visible.DEFAULT_GROUP].length == 0) { 251 | delete groups[visible.DEFAULT_GROUP]; 252 | } else { 253 | groupNames.push(visible.DEFAULT_GROUP); 254 | } 255 | 256 | // specify group ranking // assumed item traversal order is equivalent, so is just groupNames 257 | viewData['groupRank'] = groupNames; 258 | 259 | // add method to get everything in rank order (for convenience) 260 | viewData.getAll = function() { 261 | var ret = []; 262 | for (var i in viewData['groupRank']) { 263 | var groupName = viewData['groupRank'][i]; 264 | if (viewData['groups'].hasOwnProperty(groupName)) 265 | ret = ret.concat(viewData['groups'][groupName]); 266 | } 267 | return ret; 268 | }; 269 | 270 | return viewData; 271 | }; 272 | 273 | visible.attributes = {}; 274 | 275 | visible.groupBy = ""; 276 | 277 | // constant for default grouping 278 | visible.DEFAULT_GROUP = ""; 279 | 280 | visible.sortBy = visible.ATTR_NAME; 281 | visible.filterOn = ""; 282 | visible.multigroup = false; 283 | 284 | visible.afterAction = visible.AFTER_ACTION_GRAYOUT; 285 | 286 | visible.unique1 = []; 287 | visible.unique2 = []; 288 | visible.identical = {}; 289 | 290 | // number of identical sets (each set will take 1 row in compact view) 291 | visible.numIdenticalSets = 0; 292 | visible.similar = {}; 293 | 294 | // next id to use when adding items (e.g. if items added dynamically) 295 | visible.nextID = 0; 296 | 297 | // arrays to preserve order of actions 298 | visible.accepted = []; 299 | visible.rejected = []; 300 | visible.undecided = []; 301 | 302 | visible.displayName = visible.RECORDED_NAME; 303 | 304 | // methods /////////////////////////////////////////////////////////// 305 | visible.init = function(dataset) { 306 | resetState(); 307 | loadData(dataset); 308 | }; 309 | 310 | visible.decide = function(id, src, dst) { 311 | var index = visible[src].indexOf(parseFloat(id)); 312 | 313 | if (index !== -1) {// shadows not included 314 | visible[src].splice(index, 1); 315 | visible[dst].push(parseFloat(id)); 316 | } 317 | }; 318 | 319 | visible.getIdentical = function(id, includeShadows, applyFilter) { 320 | var identical = []; 321 | var checkID = visible.items[id].isShadow ? visible.getShadowed(id) : id; 322 | 323 | if ( checkID in visible.identical) { 324 | identical = visible.identical[checkID].slice(); 325 | } 326 | identical.splice(identical.indexOf(parseFloat(checkID)), 1); 327 | 328 | if (includeShadows) { 329 | var shadows = []; 330 | 331 | for (var i = 0; i < identical.length; i++) { 332 | shadows = shadows.concat(visible.getShadows(identical[i])); 333 | } 334 | identical = identical.concat(shadows); 335 | } 336 | return applyFilter ? identical.filter(unifiedFilter) : identical; 337 | }; 338 | 339 | visible.getSimilar = function(id, includeShadows, applyFilter) { 340 | var similar = []; 341 | var checkID = visible.items[id].isShadow ? visible.getShadowed(id) : id; 342 | 343 | if ( checkID in visible.similar) { 344 | similar = visible.similar[checkID].items.slice(); 345 | } 346 | similar.splice(similar.indexOf(parseFloat(checkID)), 1); 347 | 348 | if (includeShadows) { 349 | var shadows = []; 350 | 351 | for (var i = 0; i < similar.length; i++) { 352 | shadows = shadows.concat(visible.getShadows(similar[i])); 353 | } 354 | similar = similar.concat(shadows); 355 | } 356 | return applyFilter ? similar.filter(unifiedFilter) : similar; 357 | }; 358 | 359 | // given an id, return item ids that are related 360 | visible.getRelated = function(id, includeShadows) { 361 | if (("" + id)[0] == 'd') { 362 | // this is for 3 column view for a drug class or diagnosis "group item" 363 | if (("" + id)[1] == 'c') 364 | return visible.drugClassSet[id]; 365 | // drug class 366 | else 367 | return visible.diagnosisSet[id]; 368 | // diagnosis 369 | } else { 370 | var identical = visible.getIdentical(id, includeShadows, true); 371 | var similar = visible.getSimilar(id, includeShadows, true); 372 | var hash = {}; 373 | var length = Math.min(identical.length, similar.length); 374 | 375 | // remove duplicates 376 | for (var i = 0; i < length; i++) { 377 | hash[identical[i]] = true; 378 | hash[similar[i]] = true; 379 | } 380 | 381 | if (length < identical.length) { 382 | for (; i < identical.length; i++) { 383 | hash[identical[i]] = true; 384 | } 385 | } else if (length < similar.length) { 386 | for (; i < similar.length; i++) { 387 | hash[similar[i]] = true; 388 | } 389 | } 390 | 391 | // convert results into array format 392 | var related = []; 393 | 394 | for (var hashedID in hash) { 395 | related.push(hashedID); 396 | } 397 | return related; 398 | } 399 | }; 400 | 401 | visible.getIdenticalSet = function(id, includeShadows) { 402 | return visible.getShadowSet(id).concat(visible.getIdentical(id, includeShadows)); 403 | }; 404 | 405 | visible.getSimilarSet = function(id, includeShadows) { 406 | return visible.getShadowSet(id).concat(visible.getSimilar(id, includeShadows, true)); 407 | }; 408 | 409 | visible.getRelatedSet = function(id, includeShadows) { 410 | return visible.getShadowSet(id).concat(visible.getRelated(id, includeShadows)); 411 | }; 412 | 413 | visible.getShadows = function(id) { 414 | if ( id in visible.itemsToShadows) { 415 | return visible.itemsToShadows[id]; 416 | } 417 | return []; 418 | }; 419 | 420 | visible.getShadowed = function(id) { 421 | return visible.shadowsToItems[id]; 422 | }; 423 | 424 | visible.getShadowSet = function(id) { 425 | if (("" + id)[0] == 'd')// TODO diagnosis version doesn't support multigroup right now 426 | return []; 427 | 428 | var checkID = visible.items[id].isShadow ? visible.getShadowed(id) : id; 429 | 430 | return [checkID].concat(visible.getShadows(checkID)); 431 | }; 432 | 433 | ////// hidden //////////////////////////////////////////////////////////// 434 | 435 | // initialization 436 | function resetState() { 437 | visible.items = {}; 438 | visible.list1.source = []; 439 | visible.list2.source = []; 440 | visible.diagnoses = {}; 441 | visible.diagnosisSet = {}; 442 | 443 | visible.shadows = {}; 444 | visible.itemsToShadows = {}; 445 | visible.shadowsToItems = {}; 446 | visible.hidden = {}; 447 | 448 | visible.attributes = {}; 449 | 450 | visible.unique1 = []; 451 | visible.unique2 = []; 452 | visible.identical = {}; 453 | visible.similar = {}; 454 | visible.nextID = 0; 455 | 456 | visible.accepted = []; 457 | visible.rejected = []; 458 | visible.undecided = []; 459 | } 460 | 461 | function loadData(dataset) { 462 | visible.dataset = dataset; 463 | 464 | populatePatientInformation(dataset); 465 | populateLists(dataset); 466 | detectAttributes(); 467 | detectRelationships(dataset); 468 | detectDiagnoses(); 469 | detectDrugClasses(); 470 | 471 | // create "shadows", copies, to show n-group affiliation 472 | populateShadows(); 473 | } 474 | 475 | // expected column names of csv format - all items have these attributes given in the csv 476 | var CSVC = {}; 477 | CSVC.ID = "id"; 478 | CSVC.ORIGIN = "origin"; 479 | CSVC.R_NAME = "recorded name"; 480 | CSVC.G_NAME = "generic name"; 481 | CSVC.B_NAME = "brand name"; 482 | CSVC.DOSE = "dose"; 483 | CSVC.ROUTE = "route"; 484 | CSVC.FREQUENCY = "frequency"; 485 | CSVC.DRUG_CLASSES = "drug classes"; 486 | CSVC.DIAGNOSES = "diagnoses"; 487 | 488 | /* 489 | * Hard-coded datasets used by Twinlist, in future, should retrieve from other data source 490 | * Assumptions 491 | * patient information contained in dataset 492 | * item relationships present as a list of unique1, list of unique2, list of lists of identical items, 493 | * similar items given as a list of objects where each object describes what items are similar and what 494 | * the differences are 495 | * csv format for data with specific column names (see CSVC) 496 | * any addtional information not present in the csv format can be given as "other_data" 497 | * Assumes the keys match the attribute constants used by Twinlist (e.g. see visible.ATTR_ROUTE, etc.) 498 | */ 499 | var DATASETS = { 500 | "__DATASET_APPENDECTOMY__": { 501 | // patient data 502 | patientFirstName: "David", 503 | patientLastName: "Doe", 504 | patientAge: 55, 505 | patientGender: "M", 506 | 507 | // item relationships 508 | unique1: [0, 5], 509 | unique2: [9, 10], 510 | identical: [[1, 11], [4, 8]], 511 | similar: [ 512 | { items: [2, 7], differences: [visible.ATTR_NAME, visible.ATTR_DOSE] }, 513 | { items: [3, 6], differences: [visible.ATTR_NAME] } ], 514 | 515 | // item data 516 | csv: 517 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 518 | '0,list0,aspirin,aspirin,Bayer,81 mg,PO,daily,"non-steroidal anti-inflammatory drug,analgesic,antiplatelet,antipyretic",atherosclerotic vascular disease\n' + 519 | '1,list0,Chantix,varenicline,Chantix,81 mg,PO,daily,antismoking,nicotine dependence\n' + 520 | '2,list0,Lipitor,atorvastatin,Lipitor,20 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 521 | '3,list0,Capoten,captopril,Capoten,25 mg,PO,BID,antihypertensive,hypertension\n' + 522 | '4,list0,multivitamin,multivitamin,multivitamin,1 tablet,PO,daily,dietary supplement,vitamin deficiency\n' + 523 | '5,list0,Sonata,zaleplon,Sonata,10 mg,PO,qHS prn,sedative,insomnia\n' + 524 | '6,list1,captopril,captopril,Capoten,25 mg,PO,BID,antihypertensive,hypertension\n' + 525 | '7,list1,atorvastatin,atorvastatin,Lipitor,25 mg,PO,qAM,anticholesterol,hypercholesterolemia\n' + 526 | '8,list1,multivitamin,multivitamin,multivitamin,1 tablet,PO,daily,dietary supplement,vitamin deficiency\n' + 527 | '9,list1,temazepam,temazepam,Restoril,15 mg,PO,qHS,"sedative,antianxiety",insomnia\n' + 528 | '10,list1,tramadol,tramadol,Ultram,50 mg,PO,q4h prn pain,analgesic,pain\n' + 529 | '11,list1,Chantix,varenicline,Chantix,81 mg,PO,daily,antismoking,nicotine dependence' 530 | }, // end of APP 531 | 532 | 533 | 534 | "__DATASET_CONGESTIVE_HEART_FAILURE_1__": { 535 | // patient data 536 | patientFirstName: "Jim", 537 | patientLastName: "Jones", 538 | patientAge: 74, 539 | patientGender: "M", 540 | 541 | // item relationships 542 | unique1: [3, 8], 543 | unique2: [16, 18, 20], 544 | identical: [[5, 12], [7, 13]], 545 | similar: [ 546 | { items : [0, 11], differences : [visible.ATTR_FREQUENCY] }, 547 | { items : [1, 22], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 548 | { items : [2, 17], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 549 | { items : [4, 15], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 550 | { items : [6, 14], differences : [visible.ATTR_FREQUENCY] }, 551 | { items : [9, 21], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 552 | { items : [10, 19], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] } ], 553 | 554 | // item data 555 | csv: 556 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 557 | '0,list0,acetaminophen,acetaminophen,Tylenol,650 mg,PO,q4h prn,"analgesic,antipyretic",pain\n' + 558 | '1,list0,Aldactone,spironolactone,Aldactone,100 mg,PO,daily,antihypertensive,hypertension\n' + 559 | '2,list0,Amaryl,glimepiride,Amaryl,4 mg,PO,daily,antidiabetic,diabetes\n' + 560 | '3,list0,Ambien,zolpidem,Ambien,10 mg,PO,qHS prn,sedative,insomnia\n' + 561 | '4,list0,Aricept,donepezil,Aricept,10 mg,PO,daily,acetylcholinesterase inhibitor,dementia\n' + 562 | '5,list0,aspirin,aspirin,Bayer,81 mg,PO,daily,"non-steroidal anti-inflammatory drug,analgesic,antiplatelet,antipyretic","atherosclerotic vascular disease, pain"\n' + 563 | '6,list0,cimetidine,cimetidine,Tagamet,800 mg,PO,BID,antacid,GERD\n' + 564 | '7,list0,Coreg,carvedilol,Coreg,6.25 mg,PO,BID,antihypertensive,hypertension\n' + 565 | '8,list0,Colace,ducosate,Colace,100 mg,PO,BID,stool softener,constipation\n' + 566 | '9,list0,Crestor,rosuvastatin,Crestor,20 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 567 | '10,list0,Hyzaar,losartan + hydrochlorothiazide,Hyzaar,100 / 25 mg,PO,daily,"antihypertensive,diuretic","antihypertensive, diuretic"\n' + 568 | '11,list1,acetaminophen,acetaminophen,Tylenol,650 mg,PO,q4h prn headache or pain,"analgesic,antipyretic",pain\n' + 569 | '12,list1,aspirin,aspirin,Bayer,81 mg,PO,daily,"non-steroidal anti-inflammatory drug,analgesic,antiplatelet,antipyretic",atherosclerotic vascular disease\n' + 570 | '13,list1,Coreg,carvedilol,Coreg,6.25 mg,PO,BID,antihypertensive,hypertension\n' + 571 | '14,list1,cimetidine,cimetidine,Tagamet,800 mg,PO,q12h,antacid,GERD\n' + 572 | '15,list1,donepezil,donepezil,Aricept,10 mg,PO,qAM,acetylcholinesterase inhibitor,dementia\n' + 573 | '16,list1,furosemide,furosemide,Lasix,40 mg,PO,BID,"diuretic,antihypertensive",congestive heart failure\n' + 574 | '17,list1,glimepiride,glimepiride,Amaryl,4 mg,PO,qAM,antidiabetic,diabetes\n' + 575 | '18,list1,lorazepam,lorazepam,Ativan,1 mg,PO,qHS prn insomnia,"sedative,antianxiety",insomnia\n' + 576 | '19,list1,losartan,losartan,Cozaar,50 mg,PO,qAM,antihypertensive,hypertension\n' + 577 | '20,list1,magnesium hydroxide,magnesium hydroxide,Milk of magnesia,30 ml,PO,daily prn constipation,"laxative,antacid",constipation\n' + 578 | '21,list1,rosuvastatin,rosuvastatin,Crestor,20 mg,PO,qAM,anticholesterol,hypercholesterolemia\n' + 579 | '22,list1,spironolactone,spironolactone,Aldactone,100 mg,PO,qAM,antihypertensive,hypertension', 580 | 581 | // optional data (Note: displayed in item details but not really used) 582 | other_data: { 583 | 10: { 584 | "__ATTR_SUBITEM__": [ 585 | { name : "losartan", attributes : {"__ATTR_DOSE__" : "100 mg"} }, 586 | { name : "hydrochlorothiazide", attributes : {"__ATTR_DOSE__" : "25 mg"} } ] 587 | } 588 | } 589 | }, // end of CHF1 590 | 591 | 592 | 593 | '__DATASET_CONGESTIVE_HEART_FAILURE_2__': { 594 | // patient data 595 | patientFirstName: "Mary", 596 | patientLastName: "Smith", 597 | patientAge: 65, 598 | patientGender: "F", 599 | 600 | // item relationships 601 | unique1: [5, 6, 8], 602 | unique2: [14, 21], 603 | identical: [[7, 15], [9, 16]], 604 | similar: [ 605 | { items : [0, 11], differences : [visible.ATTR_NAME] }, 606 | { items : [1, 12], differences : [visible.ATTR_NAME, visible.ATTR_DOSE] }, 607 | { items : [2, 13], differences : [visible.ATTR_NAME, visible.ATTR_DOSE] }, 608 | { items : [3, 18], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 609 | { items : [4, 19, 20], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] }, 610 | { items : [10, 17], differences : [visible.ATTR_FREQUENCY] } ], 611 | 612 | // item data 613 | csv: 614 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 615 | '0,list0,Coreg,carvedilol,Coreg,25 mg,PO,BID,antihypertensive,hypertension\n' + 616 | '1,list0,HCTZ,hydrochlorothiazide,Hydrodiuril,25 mg,PO,daily,"diuretic,antihypertensive",congestive heart failure\n' + 617 | '2,list0,Coumadin,warfarin,Coumadin,5 mg,PO,daily,anticoagulant,thrombosis\n' + 618 | '3,list0,Lasix,furosemide,Lasix,40 mg,PO,daily,"diuretic,antihypertensive",congestive heart failure\n' + 619 | '4,list0,Percocet,acetaminophen + oxycodone,Percocet,1 tablet,PO,q4h prn pain,analgesic,pain\n' + 620 | '5,list0,Zantac,ranitidine,Zantac,150 mg,PO,BID,antacid,GERD\n' + 621 | '6,list0,Dulcolax,bisacodyl,Dulcolax,10 mg,PO,daily prn,laxative,constipation\n' + 622 | '7,list0,loratadine,loratadine,Claritin,10 mg,PO,daily prn,antihistamine,nasal congestion\n' + 623 | '8,list0,Metamucil,psyllium husk,Metamucil,1 tbsp,PO,daily,stool softener,constipation\n' + 624 | '9,list0,pravastatin,pravastatin,Pravachol,40 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 625 | '10,list0,zaleplon,zaleplon,Sonata,10 mg,PO,qHS prn,sedative,insomnia\n' + 626 | '11,list1,carvedilol,carvedilol,Coreg,25 mg,PO,BID,antihypertensive,hypertension\n' + 627 | '12,list1,hydrochlorothiazide,hydrochlorothiazide,Hydrodiuril,50 mg,PO,daily,"diuretic,antihypertensive",congestive heart failure\n' + 628 | '13,list1,warfarin,warfarin,Coumadin,4 mg,PO,daily,anticoagulant,thrombosis\n' + 629 | '14,list1,magnesium hydroxide,magnesium hydroxide,Milk of Magnesia,30 ml,PO,daily prn constipation,"laxative,antacid",constipation\n' + 630 | '15,list1,loratadine,loratadine,Claritin,10 mg,PO,daily prn,antihistamine,nasal congestion\n' + 631 | '16,list1,pravastatin,pravastatin,Pravachol,40 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 632 | '17,list1,zaleplon,zaleplon,Sonata,10 mg,PO,qHS prn insomnia,sedative,insomnia\n' + 633 | '18,list1,furosemide,furosemide,Lasix,40 mg,PO,BID,"diuretic,antihypertensive",congestive heart failure\n' + 634 | '19,list1,oxycodone,oxycodone,Oxycontin,5 mg,PO,q4-6h prn pain,analgesic,pain\n' + 635 | '20,list1,acetaminophen,acetaminophen,Tylenol,650 mg,PO,q4h prn pain,analgesic,pain\n' + 636 | '21,list1,pantoprazole,pantoprazole,Protonix,20 mg,PO,BID,antacid,GERD', 637 | 638 | other_data: { 639 | 4: { 640 | "__ATTR_SUBITEM__": [ 641 | { name : "acetaminophen", attributes : {"__ATTR_DOSE__" : ""} }, 642 | { name : "oxycodone", attributes : {"__ATTR_DOSE__" : ""} } ] 643 | } 644 | } 645 | }, // end of CHF2 646 | 647 | 648 | 649 | '__DATASET_PULMONARY_DISEASE_1__': { 650 | // patient data 651 | patientFirstName: "Penny", 652 | patientLastName: "Pfeifer", 653 | patientAge: 63, 654 | patientGender: "F", 655 | 656 | // item relationships 657 | unique1: [0, 2, 5, 6, 10, 11, 12, 14], 658 | unique2: [16, 19, 22, 23, 25, 27], 659 | identical: [[3, 26], [15, 18]], 660 | similar: [ 661 | { items : [1, 28], differences : [visible.ATTR_NAME] }, 662 | { items : [4, 13, 17], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] }, 663 | { items : [7, 20], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 664 | { items : [8, 24], differences : [visible.ATTR_DOSE] }, 665 | { items : [9, 21], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] } ], 666 | 667 | // item data 668 | csv: 669 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 670 | '0,list0,Abilify,aripiprazole,Abilify,5 mg,PO,daily,"antipsychotic,antidepressant",depression\n' + 671 | '1,list0,Advair,salmeterol + fluticasone,Advair,250 / 50 mg,PO,BID,bronchodilator,COPD\n' + 672 | '2,list0,Bactrim,trimethoprim + sulfamethoxazole,Bactrim,2 tablets,PO,q12h,antibiotic,pneumonia\n' + 673 | '3,list0,multivitamin,multivitamin,multivitamin,1 tablet,PO,daily,dietary supplement,vitamin deficiency\n' + 674 | '4,list0,Fosamax+D,alendronate + vitamin D,Fosamax+D,1 tablet,PO,daily,bone resorption inhibitor,osteoporosis\n' + 675 | '5,list0,Hygroton,chlorthalidone,Hygroton,50 mg,PO,daily,"diuretic,antihypertensive",hypertension\n' + 676 | '6,list0,Lunesta,eszopiclone,Lunesta,2 mg,PO,qHS prn,sedative,insomnia\n' + 677 | '7,list0,Plavix,clopidogrel,Plavix,75 mg,PO,daily,antiplatelet,atherosclerotic vascular disease\n' + 678 | '8,list0,prednisone,prednisone,Deltasone,40 mg,PO,taper,corticosteroid,COPD\n' + 679 | '9,list0,Premarin,conjugated estrogens,Premarin,0.3 mg,PO,daily,sex hormone,menopause symptoms\n' + 680 | '10,list0,Metamucil,psyllium husk,Metamucil,1 tbsp,PO,daily,stool softener,constipation\n' + 681 | '11,list0,Nexium,esomeprazole,Nexium,20 mg,PO,daily,antacid,GERD\n' + 682 | '12,list0,Senokot,sennosides,Senokot,2 tablets,PO,daily prn constipation,laxative,constipation\n' + 683 | '13,list0,vitamin D,vitamin D,Calciferol,800 IU,PO,daily,dietary supplement,vitamin deficiency\n' + 684 | '14,list0,Zestril,lisinopril,Zestril,20 mg,PO,daily,antihypertensive,hypertension\n' + 685 | '15,list0,bupropion,bupropion,Zyban,150 mg,PO,BID,"antidepressant,antismoking",antidepressant\n' + 686 | '16,list1,acetaminophen,acetaminophen,Tylenol,650 mg,PO,q4h prn headache,"analgesic,antipyretic",pain\n' + 687 | '17,list1,alendronate,alendronate,Fosamax,10 mg,PO,daily,bone resorption inhibitor,osteoporosis\n' + 688 | '18,list1,bupropion,bupropion,Zyban,150 mg,PO,BID,"antidepressant,antismoking",antidepressant\n' + 689 | '19,list1,moxifloxacin,moxifloxacin,Avelox,400 mg,PO,daily,antibiotic,pneumonia\n' + 690 | '20,list1,clopidogrel,clopidogrel,Plavix,75 mg,PO,qAM,antiplatelet,atherosclerotic vascular disease\n' + 691 | '21,list1,conjugated estrogens,conjugated estrogens,Premarin,0.3 mg,PO,qAM,sex hormone,menopause symptoms\n' + 692 | '22,list1,hydrochlorthiazide,hydrochlorthiazide,Hydrodiuril,50 mg,PO,qAM,"diuretic,antihypertensive",hypertension\n' + 693 | '23,list1,lorazepam,lorazepam,Ativan,0.5 mg,PO,qHS prn,"sedative,antianxiety",anxiety\n' + 694 | '24,list1,prednisone,prednisone,Deltasone,30 mg,PO,taper,corticosteroid,COPD\n' + 695 | '25,list1,magnesium hydroxide,magnesium hydroxide,Milk of Magnesia,30 ml,PO,daily prn constipation,"laxative,antacid",constipation\n' + 696 | '26,list1,multivitamin,multivitamin,multivitamin,1 tablet,PO,daily,dietary supplement,vitamin deficiency\n' + 697 | '27,list1,pantoprazole,pantoprazole,Protonix,40 mg,PO,qAM,antacid,GERD\n' + 698 | '28,list1,salmeterol + fluticasone,salmeterol + fluticasone,Advair,250 / 50 mg,PO,BID,bronchodilator,bronchodilator', 699 | 700 | other_data: { 701 | 1: { 702 | "__ATTR_SUBITEM__": [ 703 | { name : "salmeterol", attributes : {"__ATTR_DOSE__" : "250 mg"} }, 704 | { name : "fluticasone", attributes : {"__ATTR_DOSE__" : "50 mg"} } ] 705 | }, 706 | 2: { 707 | "__ATTR_SUBITEM__": [ 708 | { name : "trimethoprim", attributes : {"__ATTR_DOSE__" : ""} }, 709 | { name : "sulfamethoxazole", attributes : {"__ATTR_DOSE__" : ""} } ], 710 | "__ATTR_DATE_STARTED__": ["started 3 days ago"] 711 | }, 712 | 4: { 713 | "__ATTR_SUBITEM__": [ 714 | { name : "alendronate", attributes : {"__ATTR_DOSE__" : ""} }, 715 | { name : "vitamin D", attributes : {"__ATTR_DOSE__" : ""} } ] 716 | }, 717 | 28: { 718 | "__ATTR_SUBITEM__": [ 719 | { name : "salmeterol", attributes : {"__ATTR_DOSE__" : "250 mg"} }, 720 | { name : "fluticasone", attributes : {"__ATTR_DOSE__" : "50 mg"} } ] 721 | } 722 | } 723 | }, // end of PD1 724 | 725 | 726 | 727 | '__DATASET_PULMONARY_DISEASE_2__': { 728 | // patient data 729 | patientFirstName: "Richard", 730 | patientLastName: "White", 731 | patientAge: 80, 732 | patientGender: "M", 733 | 734 | // item relationships 735 | unique1: [0, 2, 3, 10, 11, 12, 15], 736 | unique2: [16, 18, 19, 20, 29], 737 | identical: [[5, 22], [6, 23], [13, 27]], 738 | similar: [ 739 | { items : [1, 17], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] }, 740 | { items : [4, 21], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] }, 741 | { items : [7, 24], differences : [visible.ATTR_NAME] }, 742 | { items : [8, 25], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 743 | { items : [9, 26], differences : [visible.ATTR_NAME] }, 744 | { items : [14, 28], differences : [visible.ATTR_NAME] }], 745 | 746 | // item data 747 | csv: 748 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 749 | '0,list0,dabigatran,dabigatran,Pradaxa,150 mg,PO,BID,anticoagulant,atrial fibrillation\n' + 750 | '1,list0,Zestoretic,hydrochlorothiazide + lisinopril,Zestoretic,20 / 12.5 mg,PO,daily,"antihypertensive,diuretic",hypertension\n' + 751 | '2,list0,metformin,metformin,Glucophage,850 mg,PO,daily,antidiabetic,diabetes\n' + 752 | '3,list0,Micronase,glyburide,glyburide,5 mg,PO,daily,antidiabetic,diabetes\n' + 753 | '4,list0,Toprol XL,metoprolol,Toprol XL,25 mg,PO,daily,antihypertensive,hypertension\n' + 754 | '5,list0,acetaminophen,acetaminophen,Tylenol,1 g,PO,q6h prn pain,"analgesic,antipyretic",pain\n' + 755 | '6,list0,tramadol,tramadol,Ultram,50 mg,PO,q6h prn pain,analgesic,pain\n' + 756 | '7,list0,Plavix,clopidogrel,Plavix,75 mg,PO,daily,antiplatelet,atherosclerotic vascular disease\n' + 757 | '8,list0,Aricept,donepezil,Aricept,10 mg,PO,daily,acetylcholinesterase inhibitor,dementia\n' + 758 | '9,list0,Prozac,fluoxetine,Prozac,20 mg,PO,daily,antidepressant,depression\n' + 759 | '10,list0,vitamin B12,vitamin B12,vitamin B12,1000 mcg,SC,qMonth,dietary supplement,vitamin deficiency\n' + 760 | '11,list0,Calciferol,vitamin D,Calciferol,600 IU,PO,daily,dietary supplement,osteoporosis\n' + 761 | '12,list0,calcium carbonate,calcium carbonate,Tums,500 mg,PO,QID,dietary supplement,osteoporosis\n' + 762 | '13,list0,lorazepam,lorazepam,Ativan,1 mg,PO,q8h prn anxiety,"sedative,antianxiety",anxiety\n' + 763 | '14,list0,Lipitor,rosuvastatin,Lipitor,40 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 764 | '15,list0,Tirosint,levothyroxine,Tirosint,100 mcg,PO,daily,thyroid,hypothyroidism\n' + 765 | '16,list1,enoxaparin,enoxaparin,Lovenox,40 mg,SC,daily,anticoagulant,atrial fibrillation\n' + 766 | '17,list1,lisinopril,lisinopril,Zestril,20 mg,PO,daily,antihypertensive,hypertension\n' + 767 | '18,list1,hydrochlorothiazide,hydrochlorothiazide,Hydrodiuril,12.5 mg,PO,daily,"diuretic,antihypertensive",hypertension\n' + 768 | '19,list1,insulin sliding scale,insulin sliding scale,Humulin,,SC,q4h prn,antidiabetic,diabetes\n' + 769 | '20,list1,Lantus,insulin glargine,Lantus,20 mg,SC,qHS,antidiabetic,diabetes\n' + 770 | '21,list1,metoprolol,metoprolol,Toprol XL,50 mg,PO,BID,antihypertensive,hypertension\n' + 771 | '22,list1,acetaminophen,acetaminophen,Tylenol,1 g,PO,q6h prn pain,"analgesic,antipyretic",pain\n' + 772 | '23,list1,tramadol,tramadol,Ultram,50 mg,PO,q6h prn pain,analgesic,pain\n' + 773 | '24,list1,clopidogrel,clopidogrel,Plavix,75 mg,PO,daily,antiplatelet,atherosclerotic vascular disease\n' + 774 | '25,list1,donepezil,donepezil,Aricept,10 mg,PO,qHS,acetylcholinesterase inhibitor,dementia\n' + 775 | '26,list1,fluoxetine,fluoxetine,Prozac,20 mg,PO,daily,antidepressant,depression\n' + 776 | '27,list1,lorazepam,lorazepam,Ativan,1 mg,PO,q8h prn anxiety,"sedative,antianxiety",anxiety\n' + 777 | '28,list1,rosuvastatin,rosuvastatin,Lipitor,40 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 778 | '29,list1,cephalexin,cephalexin,Biocef,500 mg,PO,q6h,antibiotic,cellulitis', 779 | 780 | other_data: { 781 | 1: { 782 | "__ATTR_SUBITEM__": [ 783 | { name : "hydrochlorothiazide", attributes : {"__ATTR_DOSE__" : "20 mg"} }, 784 | { name : "lisinopril", attributes : {"__ATTR_DOSE__" : "12.5 mg"} } ] 785 | }, 786 | 29: { 787 | "__ATTR_DATE_STARTED__": ["started 1 day ago"] 788 | }, 789 | } 790 | }, // end of PD2 791 | 792 | 793 | 794 | '__DATASET_OTHER_SIMPLE__': { 795 | // patient data 796 | patientFirstName: "John", 797 | patientLastName: "Doe", 798 | patientAge: 30, 799 | patientGender: "M", 800 | 801 | // item relationships 802 | unique1: [4], 803 | unique2: [9, 10, 13], 804 | identical: [[1, 7], [2, 12], [3, 11]], 805 | similar: [ 806 | { items : [0, 6], differences : [visible.ATTR_FREQUENCY, visible.ATTR_DOSAGE] }, 807 | { items : [5, 8], differences : [visible.ATTR_NAME] } ], 808 | 809 | // item data 810 | csv: 811 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 812 | '0,list0,Acetaminophen,Acetaminophen,Acetaminophen,325 mg,PO,q6h,"analgesic,antipyretic",\n' + 813 | '1,list0,Darbepoetin,Darbepoetin,Darbepoetin,60 mg,SC,qFriday,ESA,\n' + 814 | '2,list0,Calcitrol,Calcitrol,Calcitrol,0.25 mg,PO,daily,supplement,\n' + 815 | '3,list0,Ramipril,Ramipril,Ramipril,5 mg,PO,daily,ACE inhibitor,\n' + 816 | '4,list0,Meloxicam,Meloxicam,Meloxicam,7.5 mg,PO,daily,"analgesic,NSAID",\n' + 817 | '5,list0,Folvite,Folvite,Folvite,1 mg,PO,daily,supplement,\n' + 818 | '6,list1,Acetaminophen,Acetaminophen,Acetaminophen,325 mg,PO,q4h,"analgesic,antipyretic",\n' + 819 | '7,list1,Darbepoetin,Darbepoetin,Darbepoetin,60 mg,SC,qFriday,ESA,\n' + 820 | '8,list1,Folic acid,Folic acid,Folic acid,1 mg,PO,daily,supplement,\n' + 821 | '9,list1,Omeprazole,Omeprazole,Omeprazole,40 mg,PO,daily,proton-pump inhibitor,\n' + 822 | '10,list1,Ciprofloxacin,Ciprofloxacin,Ciprofloxacin,500 mg,PO,daily,antibiotic,\n' + 823 | '11,list1,Ramipril,Ramipril,Ramipril,5 mg,PO,daily,ACE inhibitor,\n' + 824 | '12,list1,Calcitrol,Calcitrol,Calcitrol,0.25 mg,PO,daily,supplement,\n' + 825 | '13,list1,Ferrous Gloconate,Ferrous Gloconate,Ferrous Gloconate,300 mg,PO,TID,supplement,', 826 | 827 | other_data: { 828 | 10: { 829 | "__ATTR_DATE_STARTED__": ["started 4 days ago"] 830 | } 831 | } 832 | }, // end of O_SIMPLE 833 | 834 | 835 | 836 | '__DATASET_OTHER_COMPLEX__': { 837 | // patient data 838 | patientFirstName: "Jane", 839 | patientLastName: "Doe", 840 | patientAge: 30, 841 | patientGender: "F", 842 | 843 | // item relationships 844 | unique2: [14], 845 | unique1: [2, 7, 8], 846 | identical: [[0, 4, 13], [5, 16]], 847 | similar: [ 848 | { items : [0, 1, 4, 11, 13, 15], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY, visible.ATTR_DOSAGE] }, 849 | { items : [3, 6, 10], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY, visible.ATTR_DOSAGE] }, 850 | { items : [9, 12], differences : [visible.ATTR_NAME] } ], 851 | 852 | // item data 853 | csv: 854 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 855 | '0,list0,Acetaminophen,Acetaminophen,Acetaminophen,325 mg,PO,q4h,"analgesic,antipyretic",\n' + 856 | '1,list0,Tylenol,Tylenol,Tylenol,325 mg,PO,q6h,"analgesic,antipyretic",\n' + 857 | '2,list0,Zyrtec,Zyrtec,Zyrtec,10 mg,PO,daily,"antihistamine",\n' + 858 | '3,list0,Allegra-D,Allegra-D,Allegra-D,60 / 120 mg,PO,BID,"antihistamine,decongestant",\n' + 859 | '4,list0,Acetaminophen,Acetaminophen,Acetaminophen,325 mg,PO,q4h,"analgesic,antipyretic",\n' + 860 | '5,list0,Darbepoetin,Darbepoetin,Darbepoetin,60 mg,SC,qFriday,"ESA",\n' + 861 | '6,list0,Sudafed,Sudafed,Sudafed,30 mg,PO,q6h,"decongestant",\n' + 862 | '7,list0,Aspirin,Aspirin,Aspirin,81 mg,PO,daily,"salicylate",\n' + 863 | '8,list0,Claritin,Claritin,Claritin,10 mg,PO,daily,"antihistamine",\n' + 864 | '9,list0,Advil,Advil,Advil,200 mg,PO,q4h,"NSAID",\n' + 865 | '10,list1,Fexofenadine,Fexofenadine,Fexofenadine,60 mg,PO,daily,"antihistamine",\n' + 866 | '11,list1,Acetaminophen,Acetaminophen,Acetaminophen,3325 mg,PO,q4h,"analgesic,antipyretic",\n' + 867 | '12,list1,Ibuprofen,Ibuprofen,Ibuprofen,200 mg,PO,q4h,"NSAID",\n' + 868 | '13,list1,Acetaminophen,Acetaminophen,Acetaminophen,325 mg,PO,q4h,"analgesic,antipyretic",\n' + 869 | '14,list1,Prednisone,Prednisone,Prednisone,30 mg,PO,daily,"corticosteroid",\n' + 870 | '15,list1,Acetaminophen,Acetaminophen,Acetaminophen,325 mg,PO,q6h,"analgesic,antipyretic",\n' + 871 | '16,list1,Darbepoetin,Darbepoetin,Darbepoetin,60 mg,SC,qFriday,"ESA",', 872 | 873 | other_data: { 874 | 3: { 875 | '__ATTR_SUBITEM__': [ 876 | { name : "Fexofenadine", attributes : {"__ATTR_DOSAGE__" : ["60 mg"]} }, 877 | { name : "Pseudoephedrine", attributes : {"__ATTR_DOSAGE__" : ["120 mg"]} }] 878 | } 879 | } 880 | 881 | }, // end of O_COMPLEX 882 | 883 | 884 | 885 | '__DATASET_OTHER_EXTRA__': { 886 | // patient data 887 | patientFirstName: "Jim", 888 | patientLastName: "Jones", 889 | patientAge: 74, 890 | patientGender: "M", 891 | 892 | // item relationships 893 | unique1: [2, 7], 894 | unique2: [14, 15, 17], 895 | identical: [[4, 10], [6, 11]], 896 | similar: [ 897 | { items : [1, 20], differences : [visible.ATTR_NAME] }, 898 | { items : [0, 19], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 899 | { items : [3, 13], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 900 | { items : [5, 12], differences : [visible.ATTR_FREQUENCY] }, 901 | { items : [8, 18], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 902 | { items : [9, 16], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] }], 903 | 904 | // item data 905 | csv: 906 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 907 | '0,list0,Aldactone,spironolactone,Aldactone,100 mg,PO,daily,"antihypertensive",hypertension\n' + 908 | '1,list0,Avelox,moxifloxacin,Avelox,400 mg,PO,daily,"antibiotic",pneumonia\n' + 909 | '2,list0,Ambien,zolpidem,Ambien,10 mg,PO,qHS prn,"sedative",insomnia\n' + 910 | '3,list0,Aricept,donepezil,Aricept,10 mg,PO,daily,"acetylcholinesterase inhibitor",dementia\n' + 911 | '4,list0,aspirin,aspirin,Bayer,81 mg,PO,daily,"non-steroidal anti-inflammatory drug,analgesic,antiplatelet,antipyretic","atherosclerotic vascular disease, pain"\n' + 912 | '5,list0,cimetidine,cimetidine,Tagamet,800 mg,PO,BID,"antacid",GERD\n' + 913 | '6,list0,Coreg,carvedilol,Coreg,6.25 mg,PO,BID,"antihypertensive",hypertension\n' + 914 | '7,list0,Colace,ducosate,Colace,100 mg,PO,BID,"stool softener",constipation\n' + 915 | '8,list0,Crestor,rosuvastatin,Crestor,20 mg,PO,daily,"anticholesterol",hypercholesterolemia\n' + 916 | '9,list0,Hyzaar,losartan + hydrochlorothiazide,Hyzaar,100 / 25 mg,PO,daily,"antihypertensive,diuretic","antihypertensive, diuretic"\n' + 917 | '10,list1,aspirin,aspirin,Bayer,81 mg,PO,daily,"non-steroidal anti-inflammatory drug,analgesic,antiplatelet,antipyretic",atherosclerotic vascular disease\n' + 918 | '11,list1,Coreg,carvedilol,Coreg,6.25 mg,PO,BID,"antihypertensive",hypertension\n' + 919 | '12,list1,cimetidine,cimetidine,Tagamet,800 mg,PO,q12h,"antacid",GERD\n' + 920 | '13,list1,donepezil,donepezil,Aricept,10 mg,PO,qAM,"acetylcholinesterase inhibitor",dementia\n' + 921 | '14,list1,furosemide,furosemide,Lasix,40 mg,PO,BID,"diuretic,antihypertensive",congestive heart failure\n' + 922 | '15,list1,lorazepam,lorazepam,Ativan,1 mg,PO,qHS prn insomnia,"sedative,antianxiety",insomnia\n' + 923 | '16,list1,losartan,losartan,Cozaar,50 mg,PO,qAM,"antihypertensive",hypertension\n' + 924 | '17,list1,magnesium hydroxide,magnesium hydroxide,Milk of magnesia,30 ml,PO,daily prn constipation,"laxative,antacid",constipation\n' + 925 | '18,list1,rosuvastatin,rosuvastatin,Crestor,20 mg,PO,qAM,"anticholesterol",hypercholesterolemia\n' + 926 | '19,list1,spironolactone,spironolactone,Aldactone,100 mg,PO,qAM,"antihypertensive",hypertension\n' + 927 | '20,list1,moxifloxacin,moxifloxacin,Avelox,400 mg,PO,daily,"antibiotic",pneumonia', 928 | 929 | other_data: { 930 | 1: { 931 | '__ATTR_DATE_STARTED__': // always 2 days ago 932 | ["Started " + 933 | new Date(Date.now() - 172800000).toDateString().split(" ")[1] + ". " + 934 | new Date(Date.now() - 172800000).toDateString().split(" ")[2] + ", " + 935 | new Date(Date.now() - 172800000).toDateString().split(" ")[3] + " (2 days ago)"] 936 | }, 937 | 9: { 938 | '__ATTR_SUBITEM__': [ 939 | { name : "losartan", attributes : {"__ATTR_DOSE__" : "100 mg"} }, 940 | { name : "hydrochlorothiazide", attributes : {"__ATTR_DOSE__" : "25 mg"} }], 941 | }, 942 | 20: { 943 | '__ATTR_DATE_STARTED__': // always 1 day ago 944 | ["Started " + 945 | new Date(Date.now() - 86400000).toDateString().split(" ")[1] + ". " + 946 | new Date(Date.now() - 86400000).toDateString().split(" ")[2] + ", " + 947 | new Date(Date.now() - 86400000).toDateString().split(" ")[3] + " (1 day ago)"] 948 | }, 949 | } 950 | }, // end of O_EXTRA 951 | // (Note: was only used to generate a compact screenshot with grouping by drug class + showing dates on antibiotics) 952 | 953 | 954 | 955 | '__DATASET_PULMONARY_DISEASE_2_CORRECTED__': { 956 | // patient data 957 | patientFirstName: "Richard", 958 | patientLastName: "White", 959 | patientAge: 80, 960 | patientGender: "M", 961 | 962 | // item relationships 963 | unique1: [0, 2, 3, 10, 11, 12, 15], 964 | unique2: [16, 19, 20, 29], 965 | 966 | identical: [[5, 22], [6, 23], [13, 27]], 967 | 968 | similar: [ 969 | { items : [1, 17, 18], differences : [visible.ATTR_NAME, visible.ATTR_DOSE] }, 970 | { items : [4, 21], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] }, 971 | { items : [7, 24], differences : [visible.ATTR_NAME] }, 972 | { items : [8, 25], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 973 | { items : [9, 26], differences : [visible.ATTR_NAME] }, 974 | { items : [14, 28], differences : [visible.ATTR_NAME] }], 975 | 976 | // item data 977 | csv: 978 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 979 | '0,list0,dabigatran,dabigatran,Pradaxa,150 mg,PO,BID,anticoagulant,atrial fibrillation\n' + 980 | '1,list0,Zestoretic,hydrochlorothiazide + lisinopril,Zestoretic,20 / 12.5 mg,PO,daily,"antihypertensive,diuretic",hypertension\n' + 981 | '2,list0,metformin,metformin,Glucophage,850 mg,PO,daily,antidiabetic,diabetes\n' + 982 | '3,list0,Micronase,glyburide,glyburide,5 mg,PO,daily,antidiabetic,diabetes\n' + 983 | '4,list0,Toprol XL,metoprolol,Toprol XL,25 mg,PO,daily,antihypertensive,hypertension\n' + 984 | '5,list0,acetaminophen,acetaminophen,Tylenol,1 g,PO,q6h prn pain,"analgesic,antipyretic",pain\n' + 985 | '6,list0,tramadol,tramadol,Ultram,50 mg,PO,q6h prn pain,analgesic,pain\n' + 986 | '7,list0,Plavix,clopidogrel,Plavix,75 mg,PO,daily,antiplatelet,atherosclerotic vascular disease\n' + 987 | '8,list0,Aricept,donepezil,Aricept,10 mg,PO,daily,acetylcholinesterase inhibitor,dementia\n' + 988 | '9,list0,Prozac,fluoxetine,Prozac,20 mg,PO,daily,antidepressant,depression\n' + 989 | '10,list0,vitamin B12,vitamin B12,vitamin B12,1000 mcg,SC,qMonth,dietary supplement,vitamin deficiency\n' + 990 | '11,list0,Calciferol,vitamin D,Calciferol,600 IU,PO,daily,dietary supplement,osteoporosis\n' + 991 | '12,list0,calcium carbonate,calcium carbonate,Tums,500 mg,PO,QID,dietary supplement,osteoporosis\n' + 992 | '13,list0,lorazepam,lorazepam,Ativan,1 mg,PO,q8h prn anxiety,"sedative,antianxiety",anxiety\n' + 993 | '14,list0,Lipitor,rosuvastatin,Lipitor,40 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 994 | '15,list0,Tirosint,levothyroxine,Tirosint,100 mcg,PO,daily,thyroid,hypothyroidism\n' + 995 | '16,list1,enoxaparin,enoxaparin,Lovenox,40 mg,SC,daily,anticoagulant,atrial fibrillation\n' + 996 | '17,list1,lisinopril,lisinopril,Zestril,20 mg,PO,daily,antihypertensive,hypertension\n' + 997 | '18,list1,hydrochlorothiazide,hydrochlorothiazide,Hydrodiuril,12.5 mg,PO,daily,"diuretic,antihypertensive",hypertension\n' + 998 | '19,list1,insulin sliding scale,insulin sliding scale,Humulin,,SC,q4h prn,antidiabetic,diabetes\n' + 999 | '20,list1,Lantus,insulin glargine,Lantus,20 mg,SC,qHS,antidiabetic,diabetes\n' + 1000 | '21,list1,metoprolol,metoprolol,Toprol XL,50 mg,PO,BID,antihypertensive,hypertension\n' + 1001 | '22,list1,acetaminophen,acetaminophen,Tylenol,1 g,PO,q6h prn pain,"analgesic,antipyretic",pain\n' + 1002 | '23,list1,tramadol,tramadol,Ultram,50 mg,PO,q6h prn pain,analgesic,pain\n' + 1003 | '24,list1,clopidogrel,clopidogrel,Plavix,75 mg,PO,daily,antiplatelet,atherosclerotic vascular disease\n' + 1004 | '25,list1,donepezil,donepezil,Aricept,10 mg,PO,qHS,acetylcholinesterase inhibitor,dementia\n' + 1005 | '26,list1,fluoxetine,fluoxetine,Prozac,20 mg,PO,daily,antidepressant,depression\n' + 1006 | '27,list1,lorazepam,lorazepam,Ativan,1 mg,PO,q8h prn anxiety,"sedative,antianxiety",anxiety\n' + 1007 | '28,list1,rosuvastatin,rosuvastatin,Lipitor,40 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 1008 | '29,list1,cephalexin,cephalexin,Biocef,500 mg,PO,q6h,antibiotic,cellulitis', 1009 | 1010 | other_data: { 1011 | 1: { 1012 | "__ATTR_SUBITEM__": [ 1013 | { name : "hydrochlorothiazide", attributes : {"__ATTR_DOSE__" : "20 mg"} }, 1014 | { name : "lisinopril", attributes : {"__ATTR_DOSE__" : "12.5 mg"} } ] 1015 | }, 1016 | 29: { 1017 | "__ATTR_DATE_STARTED__": ["Started " + 1018 | new Date(Date.now() - 86400000).toDateString().split(" ")[1] + ". " + 1019 | new Date(Date.now() - 86400000).toDateString().split(" ")[2] + ", " + 1020 | new Date(Date.now() - 86400000).toDateString().split(" ")[3] + " (1 day ago)"] 1021 | }, 1022 | } 1023 | }, // end of PD2_C 1024 | 1025 | "__DATASET_CONGESTIVE_HEART_FAILURE_1_MODIFIED__": { 1026 | // patient data 1027 | patientFirstName: "Jim", 1028 | patientLastName: "Jones", 1029 | patientAge: 74, 1030 | patientGender: "M", 1031 | 1032 | // item relationships 1033 | unique1: [3, 8], 1034 | unique2: [16, 18, 20], 1035 | identical: [[5, 12], [7, 13]], 1036 | similar: [ 1037 | { items : [0, 11], differences : [visible.ATTR_FREQUENCY] }, 1038 | { items : [1, 22], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 1039 | { items : [2, 17], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 1040 | { items : [4, 15], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 1041 | { items : [6, 14], differences : [visible.ATTR_FREQUENCY] }, 1042 | { items : [9, 21], differences : [visible.ATTR_NAME, visible.ATTR_FREQUENCY] }, 1043 | { items : [10, 19], differences : [visible.ATTR_NAME, visible.ATTR_DOSE, visible.ATTR_FREQUENCY] } ], 1044 | 1045 | // item data 1046 | csv: 1047 | 'id,origin,recorded name,generic name,brand name,dose,route,frequency,drug classes,diagnoses\n' + 1048 | '0,list0,acetaminophen,acetaminophen,Tylenol,650 mg,PO,q4h prn,"analgesic,antipyretic",pain\n' + 1049 | '1,list0,Aldactone,spironolactone,Aldactone,100 mg,PO,daily,antihypertensive,hypertension\n' + 1050 | '2,list0,Amaryl,glimepiride,Amaryl,4 mg,PO,daily,antidiabetic,diabetes\n' + 1051 | '3,list0,Ambien,zolpidem,Ambien,10 mg,PO,qHS prn,sedative,insomnia\n' + 1052 | '4,list0,Aricept,donepezil,Aricept,10 mg,PO,daily,acetylcholinesterase inhibitor,dementia\n' + 1053 | '5,list0,aspirin,aspirin,Bayer,81 mg,PO,daily,"non-steroidal anti-inflammatory drug,analgesic,antiplatelet,antipyretic","atherosclerotic vascular disease"\n' + 1054 | '6,list0,cimetidine,cimetidine,Tagamet,800 mg,PO,BID,antacid,GERD\n' + 1055 | '7,list0,Coreg,carvedilol,Coreg,6.25 mg,PO,BID,antihypertensive,hypertension\n' + 1056 | '8,list0,Colace,ducosate,Colace,100 mg,PO,BID,stool softener,constipation\n' + 1057 | '9,list0,Crestor,rosuvastatin,Crestor,20 mg,PO,daily,anticholesterol,hypercholesterolemia\n' + 1058 | '10,list0,Cozaar,losartan,Cozaar,25 mg,PO,daily,"antihypertensive","hypertension,congestive heart failure"\n' + 1059 | '11,list1,acetaminophen,acetaminophen,Tylenol,650 mg,PO,q4h prn headache or pain,"analgesic,antipyretic",pain\n' + 1060 | '12,list1,aspirin,aspirin,Bayer,81 mg,PO,daily,"non-steroidal anti-inflammatory drug,analgesic,antiplatelet,antipyretic",atherosclerotic vascular disease\n' + 1061 | '13,list1,Coreg,carvedilol,Coreg,6.25 mg,PO,BID,antihypertensive,hypertension\n' + 1062 | '14,list1,cimetidine,cimetidine,Tagamet,800 mg,PO,q12h,antacid,GERD\n' + 1063 | '15,list1,donepezil,donepezil,Aricept,10 mg,PO,qAM,acetylcholinesterase inhibitor,dementia\n' + 1064 | '16,list1,furosemide,furosemide,Lasix,40 mg,PO,BID,"diuretic,antihypertensive",congestive heart failure\n' + 1065 | '17,list1,glimepiride,glimepiride,Amaryl,4 mg,PO,qAM,antidiabetic,diabetes\n' + 1066 | '18,list1,lorazepam,lorazepam,Ativan,1 mg,PO,qHS prn insomnia,"sedative,antianxiety",insomnia\n' + 1067 | '19,list1,losartan,losartan,Cozaar,50 mg,PO,qAM,antihypertensive,"hypertension,congestive heart failure"\n' + 1068 | '20,list1,magnesium hydroxide,magnesium hydroxide,Milk of magnesia,30 ml,PO,daily prn constipation,"laxative,antacid",constipation\n' + 1069 | '21,list1,rosuvastatin,rosuvastatin,Crestor,20 mg,PO,qAM,anticholesterol,hypercholesterolemia\n' + 1070 | '22,list1,spironolactone,spironolactone,Aldactone,100 mg,PO,qAM,antihypertensive,hypertension', 1071 | }, // end of CHF1_M 1072 | }; 1073 | 1074 | /* 1075 | * Given a dataset, populate patient information attributes for visible 1076 | */ 1077 | function populatePatientInformation(dataset) { 1078 | var data = DATASETS[dataset]; 1079 | visible.patientFirstName = data.patientFirstName; 1080 | visible.patientLastName = data.patientLastName; 1081 | visible.patientAge = data.patientAge; 1082 | visible.patientGender = data.patientGender; 1083 | } 1084 | 1085 | /* 1086 | * Given a dataset, populate the list1, list2, and undecided lists 1087 | */ 1088 | function populateLists(dataset) { 1089 | var objId = 0, name = {}, attributes = {}, item = {}; 1090 | 1091 | var data = DATASETS[dataset]; 1092 | 1093 | // read csv data into array of arrays 1094 | var csv_data = CSVToArray(data['csv']); 1095 | 1096 | // convert from array of arrays into array of objects 1097 | var extractedItems = arrOfArrsToArrOfObjects(csv_data); 1098 | 1099 | // for each item, save the attributes into a ListItem object 1100 | for(var csvi = 0; csvi < extractedItems.length; csvi++) { 1101 | var obj = extractedItems[csvi]; 1102 | objId = parseInt(obj[CSVC.ID][0]); 1103 | 1104 | name = { 1105 | recorded: obj[CSVC.R_NAME][0], 1106 | generic: obj[CSVC.G_NAME][0], 1107 | brand: obj[CSVC.B_NAME][0] 1108 | }; 1109 | 1110 | attributes = {}; 1111 | attributes[visible.ATTR_DOSE] = obj[CSVC.DOSE]; 1112 | attributes[visible.ATTR_ROUTE] = obj[CSVC.ROUTE]; 1113 | attributes[visible.ATTR_FREQUENCY] = obj[CSVC.FREQUENCY]; 1114 | attributes[visible.ATTR_DRUG_CLASS] = obj[CSVC.DRUG_CLASSES]; 1115 | attributes[visible.ATTR_DIAGNOSES] = obj[CSVC.DIAGNOSES]; 1116 | 1117 | // grab other data if present 1118 | if(data.other_data && data.other_data.hasOwnProperty(objId)) { 1119 | // add information for each optional attribute 1120 | for(var key in data.other_data[objId]) { 1121 | attributes[key] = data.other_data[objId][key]; 1122 | } 1123 | } 1124 | 1125 | item = new ListItem(objId, obj[CSVC.ORIGIN][0], name, attributes); 1126 | 1127 | if(item.listID == visible.list1.id) { 1128 | visible.list1.source.push(item.id); 1129 | } else { 1130 | visible.list2.source.push(item.id); 1131 | } 1132 | visible.items[item.id] = item; 1133 | } 1134 | 1135 | visible.undecided = visible.list1.source.concat(visible.list2.source); 1136 | visible.nextID = objId + 1; // indicate next id to use if adding new items 1137 | } 1138 | 1139 | /* 1140 | * Postconditions: 1141 | * populate shadows based on groupby - or retrieve if cached 1142 | * all possible shadows populated since shadows can be reused 1143 | * 1144 | * Also, continue intializing some item attributes 1145 | * (e.g. isShadow, isShadowed, groupByOffset) 1146 | */ 1147 | function populateShadows() { 1148 | // detect all possible groups 1149 | var potentialGroups = {}; 1150 | var potentialGroupByAttributes = []; 1151 | 1152 | for (var attribute in visible.attributes) { 1153 | if (visible.attributes[attribute].type === visible.ATTR_TYPE_CATEGORICAL) { 1154 | potentialGroupByAttributes.push(attribute); 1155 | } 1156 | } 1157 | 1158 | for (var id in visible.items) { 1159 | for (var i = 0; i < potentialGroupByAttributes.length; i++) { 1160 | var attributes = visible.items[id].attributes; 1161 | var attribute = potentialGroupByAttributes[i]; 1162 | 1163 | if ( attribute in attributes) { 1164 | var values = attributes[attribute]; 1165 | 1166 | for (var j = 0; j < values.length; j++) { 1167 | var value = values[j]; 1168 | 1169 | if (potentialGroups[value] === undefined) { 1170 | potentialGroups[value] = []; 1171 | } 1172 | potentialGroups[value].push(id); 1173 | } 1174 | } 1175 | } 1176 | } 1177 | 1178 | // slight optimization: remove 1-item groups when multigrouping 1179 | for (var groupByAttribute in potentialGroups) { 1180 | if (potentialGroups[groupByAttribute].length < 2) { 1181 | delete potentialGroups[groupByAttribute]; 1182 | } 1183 | } 1184 | 1185 | // create shadows 1186 | for (var id in visible.items) { 1187 | var item = visible.items[id]; 1188 | 1189 | // originals will always be associated with the primary group 1190 | item.groupByOffset = 0; 1191 | 1192 | // originals are not shadows, and currently have no shadows 1193 | item.isShadow = false; 1194 | item.isShadowed = false; 1195 | 1196 | // search for potential shadows 1197 | for (var attributeName in visible.attributes) { 1198 | var attribute = visible.attributes[attributeName]; 1199 | 1200 | if (attribute.type === visible.ATTR_TYPE_CATEGORICAL) { 1201 | if ( attributeName in item.attributes) { 1202 | var values = item.attributes[attributeName]; 1203 | 1204 | if (values.length > 1) { 1205 | /* 1206 | * Prepare shadows; these "shadows" will only appear 1207 | * when the user groups by this particular 1208 | * attribute. 1209 | * 1210 | * For group affiliation [ A, B, C ]: 1211 | * - the original will be grouped with A, 1212 | * - shadow 0 will be grouped with B, and 1213 | * - shadow 1 will be grouped with C. 1214 | * 1215 | * Acting on the original will act on all shadows; 1216 | * acting on a shadow will similarly act on the 1217 | * original (and all other shadows). 1218 | */ 1219 | for (var i = 1; i < values.length; i++) { 1220 | var value = values[i]; 1221 | 1222 | // don't create unnecessary shadows 1223 | if (potentialGroups[value] === undefined) { 1224 | continue; 1225 | } 1226 | 1227 | // convention: originalID_shadowID 1228 | var shadowID = id + "_" + (i - 1); 1229 | 1230 | // create the shadow from the original 1231 | var shadow = new ListItem(shadowID, item.listID, item.getNames(), item.attributes); 1232 | shadow.isShadow = true; 1233 | shadow.isShadowed = false; 1234 | shadow.groupByOffset = i; 1235 | 1236 | visible.shadows[shadowID] = shadow; 1237 | 1238 | // original now has a shadow 1239 | item.isShadowed = true; 1240 | 1241 | // for convenience, hash in items as well 1242 | visible.items[shadowID] = shadow; 1243 | 1244 | // hash from original to shadow 1245 | if ( id in visible.itemsToShadows) { 1246 | visible.itemsToShadows[id].push(shadowID); 1247 | } else { 1248 | visible.itemsToShadows[id] = [shadowID]; 1249 | } 1250 | 1251 | // hash from shadow to original 1252 | visible.shadowsToItems[shadowID] = id; 1253 | 1254 | } 1255 | } 1256 | } 1257 | } 1258 | } 1259 | } 1260 | } 1261 | 1262 | function detectAttributes() { 1263 | visible.attributes[visible.ATTR_NAME] = { 1264 | type : visible.ATTR_TYPE_GENERAL, 1265 | display : true 1266 | }; 1267 | visible.attributes[visible.ATTR_DOSE] = { 1268 | type : visible.ATTR_TYPE_NUMERIC, 1269 | display : true 1270 | }; 1271 | visible.attributes[visible.ATTR_ROUTE] = { 1272 | type : visible.ATTR_TYPE_CATEGORICAL, 1273 | display : true, 1274 | rank : [] 1275 | }; 1276 | visible.attributes[visible.ATTR_FREQUENCY] = { 1277 | type : visible.ATTR_TYPE_GENERAL, 1278 | display : true 1279 | }; 1280 | visible.attributes[visible.ATTR_DRUG_CLASS] = { 1281 | type : visible.ATTR_TYPE_CATEGORICAL, 1282 | display : false, 1283 | rank : ["antipyretic", "antibiotic", "analgesic", "antidiabetic", "sedative", "antianxiety", "diuretic", "bronchodilator", "corticosteroid", "antipsychotic", "antihypertensive", "anticoagulant", "antihistamine", "thyroid", "antiplatelet", "non-steroidal anti-inflammatory drug", "antacid", "antidepressant", "acetylcholinesterase inhibitor", "antismoking", "sex hormone", "anticholesterol", "bone resorption inhibitor", "dietary supplement", "laxative", "stool softener", "unknown"] 1284 | }; 1285 | visible.attributes[visible.ATTR_DIAGNOSES] = { 1286 | type : visible.ATTR_TYPE_CATEGORICAL, 1287 | display : false 1288 | }; 1289 | visible.attributes[visible.ATTR_DATE_STARTED] = { 1290 | type : visible.ATTR_TYPE_GENERAL, 1291 | display : false 1292 | }; 1293 | visible.attributes[visible.ATTR_SUBITEM] = { 1294 | type : visible.ATTR_TYPE_GENERAL, 1295 | display : false 1296 | }; 1297 | visible.attributes[visible.ATTR_INSTRUCTIONS] = { 1298 | type : visible.ATTR_TYPE_GENERAL, 1299 | display : false 1300 | }; 1301 | } 1302 | 1303 | /* 1304 | * Given a dataset, extract relationship information between items and 1305 | * populate relationship data structures 1306 | */ 1307 | function detectRelationships(dataset) { 1308 | var identical, similar; 1309 | 1310 | visible.unique1 = DATASETS[dataset].unique1; 1311 | visible.unique2 = DATASETS[dataset].unique2; 1312 | identical = DATASETS[dataset].identical; 1313 | similar = DATASETS[dataset].similar; 1314 | 1315 | if (identical || similar) { 1316 | visible.numIdenticalSets = identical.length; 1317 | 1318 | for (var i = 0; i < identical.length; i++) { 1319 | var set = identical[i]; 1320 | 1321 | for (var j = 0; j < set.length; j++) { 1322 | visible.identical[set[j]] = set; 1323 | } 1324 | } 1325 | 1326 | for (var i = 0; i < similar.length; i++) { 1327 | set = similar[i]; 1328 | 1329 | for (var j = 0; j < set.items.length; j++) { 1330 | visible.similar[set.items[j]] = set; 1331 | } 1332 | } 1333 | } 1334 | } 1335 | 1336 | function detectDrugClasses() { 1337 | // hash to remove duplicates 1338 | var tempDrugClasses = {}; 1339 | 1340 | // drug classes have ids like: "dc0" 1341 | var i = 0; 1342 | 1343 | visible.drugClasses = {}; 1344 | visible.drugClassSet = {}; 1345 | 1346 | for (var id in visible.items) { 1347 | var item = visible.items[id]; 1348 | 1349 | var drugClasses = item["attributes"][visible.ATTR_DRUG_CLASS]; 1350 | 1351 | for (var drugClassIndex in drugClasses) { 1352 | var drugClass = drugClasses[drugClassIndex]; 1353 | 1354 | // look up drug class id if there (to add this item to the set) 1355 | 1356 | // drug class id 1357 | var dcid; 1358 | 1359 | if (!tempDrugClasses[drugClass]) { 1360 | dcid = "dc" + i; 1361 | i++; 1362 | visible.drugClasses[dcid] = drugClass; 1363 | visible.drugClassSet[dcid] = []; 1364 | tempDrugClasses[drugClass] = dcid; 1365 | } else { 1366 | dcid = tempDrugClasses[drugClass]; 1367 | } 1368 | 1369 | visible.drugClassSet[dcid].push(id); 1370 | } 1371 | 1372 | } 1373 | } 1374 | 1375 | function detectDiagnoses() { 1376 | var tempDrugClasses = {}; 1377 | // hash to remove duplicates 1378 | var i = 0; 1379 | // drug classes have ids like: "dc0" 1380 | 1381 | visible.diagnoses = {}; 1382 | visible.diagnosisSet = {}; 1383 | 1384 | for (var id in visible.items) { 1385 | var item = visible.items[id]; 1386 | 1387 | var diagnoses = item["attributes"][visible.ATTR_DIAGNOSES]; 1388 | 1389 | // TODO cleaning - rename 1390 | for (var drugClassIndex in diagnoses) { 1391 | var drugClass = diagnoses[drugClassIndex]; 1392 | 1393 | // look up drug class id if there (to add this item to the set) 1394 | var dcid; 1395 | // drug class id 1396 | if (!tempDrugClasses[drugClass]) { 1397 | dcid = "d" + i; 1398 | i++; 1399 | visible.diagnoses[dcid] = drugClass; 1400 | visible.diagnosisSet[dcid] = []; 1401 | tempDrugClasses[drugClass] = dcid; 1402 | } else { 1403 | dcid = tempDrugClasses[drugClass]; 1404 | } 1405 | 1406 | visible.diagnosisSet[dcid].push(id); 1407 | } 1408 | 1409 | } 1410 | } 1411 | 1412 | // sort 1413 | function groupThenSort(a, b) { 1414 | // if a groupBy is set (e.g. from controller) sort by the grouped by attribute 1415 | var groupOrder = visible.groupBy ? attributeSort(a, b, visible.groupBy, visible.attributes[visible.groupBy].rank) : 0; 1416 | 1417 | // if no groupOrder, try sortOrder 1418 | // if no sortOrder, just sort by ids 1419 | if (groupOrder === 0) { 1420 | var sortOrder = visible.sortBy ? attributeSort(a, b, visible.sortBy) : visible.items[a].id - visible.items[b].id; 1421 | 1422 | // if equal based on sort order, tiebreak with ids 1423 | if (visible.sortBy && sortOrder === 0) { 1424 | return visible.items[a].id - visible.items[b].id; 1425 | } 1426 | return sortOrder; 1427 | } 1428 | return groupOrder; 1429 | } 1430 | 1431 | // sort id a and id b by a given attribute with (if given) ranking for that attribute 1432 | function attributeSort(a, b, attribute, rank) { 1433 | var itemA = visible.items[a]; 1434 | var itemB = visible.items[b]; 1435 | var attributeA, attributeB; 1436 | 1437 | if (attribute === visible.ATTR_NAME) {// case-insensitive 1438 | attributeA = itemA.name.toLowerCase(); 1439 | attributeB = itemB.name.toLowerCase(); 1440 | } else { 1441 | if (itemA.attributes[attribute]) { 1442 | attributeA = itemA.attributes[attribute][(visible.multigroup ? itemA.groupByOffset : 0)]; 1443 | } else { 1444 | attributeA = undefined; 1445 | } 1446 | 1447 | if (itemB.attributes[attribute]) { 1448 | attributeB = itemB.attributes[attribute][(visible.multigroup ? itemB.groupByOffset : 0)]; 1449 | } else { 1450 | attributeB = undefined; 1451 | } 1452 | } 1453 | 1454 | // check undefined, i.e. missing attributes 1455 | if (attributeA == undefined || attributeB == undefined) { 1456 | 1457 | if (attributeA == undefined) 1458 | console.log("WARNING: undefined attr: item[" + a + "]['attributes'][" + attribute + "] = undefined"); 1459 | if (attributeB == undefined) 1460 | console.log("WARNING: undefined attr: item[" + b + "]['attributes'][" + attribute + "] = undefined"); 1461 | 1462 | if (attributeA == undefined && attributeB == undefined) 1463 | return 0; 1464 | return attributeB == undefined ? -1 : 1; 1465 | } 1466 | 1467 | if (visible.attributes[attribute].type === visible.ATTR_TYPE_NUMERIC) { 1468 | attributeA = parseFloat(attributeA); 1469 | attributeB = parseFloat(attributeB); 1470 | } 1471 | 1472 | if (rank) { 1473 | var rankA = rank.indexOf(attributeA); 1474 | var rankB = rank.indexOf(attributeB); 1475 | 1476 | if (rankA < rankB) { 1477 | return -1; 1478 | } else if (rankA > rankB) { 1479 | return 1; 1480 | } 1481 | // if ranks equal, default to alphanumeric order (below) 1482 | } 1483 | 1484 | if (attributeA < attributeB) { 1485 | return -1; 1486 | } else if (attributeA > attributeB) { 1487 | return 1; 1488 | } else { 1489 | return 0; 1490 | } 1491 | } 1492 | 1493 | // filter - remove decided items if option to remove after decisions is set 1494 | function actionFilter(element, index, array) { 1495 | var $item = $("#" + element); 1496 | 1497 | if (visible.afterAction === visible.AFTER_ACTION_REMOVE && !$item.hasClass("undecided")) { 1498 | return false; 1499 | } 1500 | return true; 1501 | } 1502 | 1503 | // filter - remove items based on a name filter 1504 | function nameFilter(element, index, array) { 1505 | var $item = $("#" + element); 1506 | 1507 | if (visible.filterOn.length > 0 && visible.items[element].name.toLowerCase().indexOf(visible.filterOn.toLowerCase()) === -1) { 1508 | return false; 1509 | } 1510 | return true; 1511 | } 1512 | 1513 | // unified filted - apply action filter and name filter 1514 | function unifiedFilter(element, index, array) { 1515 | var keep = actionFilter(element, index, array); 1516 | 1517 | if (keep) { 1518 | keep = nameFilter(element, index, array); 1519 | } 1520 | controller.toggleItem($("#" + element), keep ? controller.toggleOnDelay * visible.FILTER_DELAY_SCALE : controller.toggleOffDelay / visible.FILTER_DELAY_SCALE, keep); 1521 | return keep; 1522 | } 1523 | 1524 | // expose interface ////////////////////////////////////////////////// 1525 | return visible; 1526 | }(window.model = window.model || {}, $, undefined); 1527 | 1528 | // helper object ///////////////////////////////////////////////////////// 1529 | function ListItem(id, listID, name, attributes) { 1530 | var visible = {}; 1531 | var name = name; 1532 | 1533 | visible.id = id; 1534 | visible.listID = listID; 1535 | visible.__defineGetter__("name", function() {// TODO: note: defineGetter deprecated 1536 | return name[model.displayName ? model.displayName : "recorded"]; 1537 | }); 1538 | visible.attributes = attributes; 1539 | 1540 | visible.getNames = function() { 1541 | return name; 1542 | }; 1543 | visible.setName = function(value) { 1544 | name = value; 1545 | }; 1546 | 1547 | visible.isModified = false; 1548 | 1549 | return visible; 1550 | } 1551 | 1552 | 1553 | // This will parse a delimited string into an array of 1554 | // arrays. The default delimiter is the comma, but this 1555 | // can be overriden in the second argument. 1556 | // from http://stackoverflow.com/questions/1293147/javascript-code-to-parse-csv-data 1557 | function CSVToArray(strData, strDelimiter ){ 1558 | // Check to see if the delimiter is defined. If not, 1559 | // then default to comma. 1560 | strDelimiter = (strDelimiter || ","); 1561 | 1562 | // Create a regular expression to parse the CSV values. 1563 | var objPattern = new RegExp( 1564 | ( 1565 | // Delimiters. 1566 | "(\\" + strDelimiter + "|\\r?\\n|\\r|^)" + 1567 | 1568 | // Quoted fields. 1569 | "(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" + 1570 | 1571 | // Standard fields. 1572 | "([^\"\\" + strDelimiter + "\\r\\n]*))" 1573 | ), 1574 | "gi" 1575 | ); 1576 | 1577 | 1578 | // Create an array to hold our data. Give the array 1579 | // a default empty first row. 1580 | var arrData = [[]]; 1581 | 1582 | // Create an array to hold our individual pattern 1583 | // matching groups. 1584 | var arrMatches = null; 1585 | 1586 | 1587 | // Keep looping over the regular expression matches 1588 | // until we can no longer find a match. 1589 | while (arrMatches = objPattern.exec( strData )){ 1590 | 1591 | // Get the delimiter that was found. 1592 | var strMatchedDelimiter = arrMatches[ 1 ]; 1593 | 1594 | // Check to see if the given delimiter has a length 1595 | // (is not the start of string) and if it matches 1596 | // field delimiter. If id does not, then we know 1597 | // that this delimiter is a row delimiter. 1598 | if ( 1599 | strMatchedDelimiter.length && 1600 | (strMatchedDelimiter != strDelimiter) 1601 | ){ 1602 | 1603 | // Since we have reached a new row of data, 1604 | // add an empty row to our data array. 1605 | arrData.push( [] ); 1606 | 1607 | } 1608 | 1609 | 1610 | // Now that we have our delimiter out of the way, 1611 | // let's check to see which kind of value we 1612 | // captured (quoted or unquoted). 1613 | if (arrMatches[ 2 ]){ 1614 | 1615 | // We found a quoted value. When we capture 1616 | // this value, unescape any double quotes. 1617 | var strMatchedValue = arrMatches[ 2 ].replace( 1618 | new RegExp( "\"\"", "g" ), 1619 | "\"" 1620 | ); 1621 | 1622 | } else { 1623 | 1624 | // We found a non-quoted value. 1625 | var strMatchedValue = arrMatches[ 3 ]; 1626 | 1627 | } 1628 | 1629 | 1630 | // Now that we have our value string, let's add 1631 | // it to the data array. 1632 | arrData[ arrData.length - 1 ].push( strMatchedValue ); 1633 | } 1634 | 1635 | // Return the parsed data. 1636 | return( arrData ); 1637 | } 1638 | 1639 | /* 1640 | * convert array of arrays to array of objects (with keys = column names) 1641 | * assumes 0th entry of array is an array of column names 1642 | * 1643 | * e.g. 1644 | * [ 1645 | * ['id', 'origin'], 1646 | * ['0', 'list0'], 1647 | * ['1', 'list0'] 1648 | * ] 1649 | * 1650 | * -> 1651 | * 1652 | * [ 1653 | * { 1654 | * id: 0, 1655 | * origin: 'list0' 1656 | * }, 1657 | * { 1658 | * id: 1, 1659 | * origin: 'list0' 1660 | * } 1661 | * ] 1662 | */ 1663 | function arrOfArrsToArrOfObjects(arrOfArrs) { 1664 | // 0th row is attribute names in the object 1665 | var ret = []; 1666 | 1667 | var attributeArr = arrOfArrs[0]; 1668 | 1669 | for(var i = 1; i < arrOfArrs.length; i++) { 1670 | var currentArr = arrOfArrs[i]; 1671 | var obj = new Object(); 1672 | for(var j = 0; j < currentArr.length; j++) { 1673 | 1674 | var dataArray = currentArr[j].split(","); 1675 | 1676 | obj[attributeArr[j]] = dataArray; 1677 | } 1678 | ret.push(obj); 1679 | } 1680 | 1681 | return ret; 1682 | } --------------------------------------------------------------------------------