MediaWiki:Gadget-dosage-calculator.js

De Wikimedica

Note : après avoir enregistré vos modifications, il se peut que vous deviez forcer le rechargement complet du cache de votre navigateur pour voir les changements.

/* This modal dialog displays a tool for drug dosage calculations. */

console.log("Loading dosage calculator ...");

// Static variables
let frequency_to_division = {'DIE': 1, 'BID': 2, 'TID': 3, 'QID': 4, 'q 2h': 12, 'q 3h': 8, 'q 4h': 6, 'q 5h': 4.8, 'q 6h': 4, 'q 8h': 3, 'q 10h': 2.4, 'q 12h': 2, 'q 24h': 1};
let broselow_to_weight_kg = {'Rose': 6, 'Rouge': 8, 'Mauve': 10, 'Jaune': 13, 'Blanc': 16, 'Bleu': 21, 'Orange': 26, 'Vert': 33};
let broselow_to_weight_kg_min = {'Rose': 6, 'Rouge': 8, 'Mauve': 10, 'Jaune': 12, 'Blanc': 15, 'Bleu': 19, 'Orange': 24, 'Vert': 30};
let broselow_to_weight_kg_max = {'Rose': 7, 'Rouge': 9, 'Mauve': 11, 'Jaune': 14, 'Blanc': 18, 'Bleu': 23, 'Orange': 29, 'Vert': 36};
let broselow_to_weight_lb = {'Rose': 14, 'Rouge': 18, 'Mauve': 23, 'Jaune': 28, 'Blanc': 36, 'Bleu': 46, 'Orange': 58, 'Vert': 77};
let broselow_to_weight_lb_min = {'Rose': 13, 'Rouge': 17, 'Mauve': 22, 'Jaune': 26, 'Blanc': 33, 'Bleu': 42, 'Orange': 53, 'Vert': 66};
let broselow_to_weight_lb_max = {'Rose': 15, 'Rouge': 20, 'Mauve': 24, 'Jaune': 30, 'Blanc': 40, 'Bleu': 50, 'Orange': 64, 'Vert': 80};
let broselow_dropdown_options_kg = [
	{
		icon: 'map',
		data: 0,
		label: ''
	},
	{
		optgroup: '6-7 kg, 3-5 mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Rose'],
		label: 'Rose'
	},
	{
		optgroup: '8-9 kg, 6-11 mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Rouge'],
		label: 'Rouge'
	},
	{
		optgroup: '10-11 kg, 12-24 mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Mauve'],
		label: 'Mauve'
	},
	{
		optgroup: '12-14 kg, 2 ans mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Jaune'],
		label: 'Jaune'
	},
	{
		optgroup: '15-18 kg, 3-4 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Blanc'],
		label: 'Blanc'
	},
	{
		optgroup: '19-23 kg, 5-6 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Bleu'],
		label: 'Bleu'
	},
	{
		optgroup: '24-29 kg, 7-9 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Orange'],
		label: 'Orange'
	},
	{
		optgroup: '30-36 kg, 10-11 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_kg['Vert'],
		label: 'Vert'
	},
];
let broselow_dropdown_options_lb = [
	{
		icon: 'map',
		data: "0",
		label: ''
	},
	{
		optgroup: '13-15 lb, 3-5 mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Rose'],
		label: 'Rose'
	},
	{
		optgroup: '17-20 lb, 6-11 mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Rouge'],
		label: 'Rouge'
	},
	{
		optgroup: '22-24 lb, 12-24 mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Mauve'],
		label: 'Mauve'
	},
	{
		optgroup: '26-30 lb, 2 ans mois'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Jaune'],
		label: 'Jaune'
	},
	{
		optgroup: '33-40 lb, 3-4 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Blanc'],
		label: 'Blanc'
	},
	{
		optgroup: '42-50 lb, 5-6 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Bleu'],
		label: 'Bleu'
	},
	{
		optgroup: '53-64 lb, 7-9 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Orange'],
		label: 'Orange'
	},
	{
		optgroup: '66-80 lb, 10-11 ans'
	},
	{
		icon: 'stop',
		data: broselow_to_weight_lb['Vert'],
		label: 'Vert'
	},
];

function getCookie(name) {
  const value = `; ${document.cookie}`;
  const parts = value.split(`; ${name}=`);
  if (parts.length === 2) return parts.pop().split(';').shift();
}

/*
	@param string drug (ex: 'Amoxiciline')
	@param float dose_per_kg (ex: 90, 7.5)
	@param string dose_unit (ex: 'mg, 'mcg')
	@param string roa (ex: 'PO', 'IR', 'IV')
	@param string frequency (ex: 'BID', 'q 12h')
	@param float max_daily_dose (default: 0) (ex: 3000, 30)
	@param string prn (default: '') (ex: 'prn', 'prn No/Vo')
	@param float duration (default: 0) (ex: 7, 14)
	@param float duration_unit (default: '') (ex: 'jours', 'semaines')
	
	Example Call: drugKgDosageCalculator('Amoxiciline', 90, 'mg', 'PO', 'BID', 3000, '', 7, 'jours');
*/

drugKgDosageCalculator = function(drug, dose_per_kg, dose_unit, roa, frequency, max_daily_dose = 0, prn = '', duration = 0, duration_unit = '') 
{
	// Lazy load the following librairies
	$.when( mw.loader.using( [ 'mediawiki.api', 'oojs-ui-core', 'oojs-ui-windows' ] )).then( function() {
		// Subclass DosageDialog.
		function DosageDialog( config ) {
			DosageDialog.super.call( this, config );
		}
		OO.inheritClass( DosageDialog, OO.ui.ProcessDialog );
		
		// Specify a name for .addWindows()
		DosageDialog.static.name = 'dosageDialog';
		// Specify a static title and actions.
		DosageDialog.static.title = 'Calculateur de dose';
		DosageDialog.static.actions = [
			{
				action: 'accept',
				label: 'Fermer',
				flags: 'primary'
			}
		];
		
		// Initialize main panel widgets and set up event handlers.
		DosageDialog.prototype.initialize = function () {
			DosageDialog.super.prototype.initialize.call( this );
			this.panel = new OO.ui.PanelLayout( { 
				padded: true, 
				expanded: false 
			} );
			
			// Initialize Dosage Information Message
			this.dosageInformationMessage = new OO.ui.MessageWidget( {
				type: 'notice',
				icon: 'article',
				label: drug + ' ' + dose_per_kg.toString() + ' ' + dose_unit + '/kg/j'
			} );
			
			// Initialize Horizontal Layout
			this.horizontalLayout = new OO.ui.HorizontalLayout( {
			} );
			
			// Initialize Weight Input Field Set
			this.weightInputFieldset = new OO.ui.FieldsetLayout();
			// Initialize Weight Input
			this.weightInput = new OO.ui.NumberInputWidget({
				min: 0,
				max: 500,
				step: 0.001,
				buttonStep: 1,
				placeholder: 'Poids',
				icon: 'userAvatar'
			});
			// Set Weight Input Field
			this.weightInputField = new OO.ui.FieldLayout( this.weightInput, { 
				label: 'Poids', 
				align: 'left',
			} );
			// Add Weight Input Field to Weight Input Field Set
			this.weightInputFieldset.addItems( [ this.weightInputField ] );
			
			// Initialize Unit Radio Input
			this.unitRadioInput = new OO.ui.RadioSelectInputWidget( {
			    options: [
			        { data: 'kg', label: 'kg' },
			        { data: 'lb', label: 'lb'}
			    ]
			} );
			
			// Set Elements to Horizontal Layout
			this.horizontalLayout.addItems([this.weightInputFieldset, this.unitRadioInput]);
			
			// Initialize Broselow Label
			this.broselowLabel = new OO.ui.LabelWidget( {
		        label: 'Échelle de Broselow'
		    } ),
			
			// Initialize Dropdown Broselow Input
			this.dropdownBroselowInput = new OO.ui.DropdownInputWidget( {
				options: broselow_dropdown_options_kg,
				value: ''
			} );
			
			// Intialize changing flag
			this.changing = false;
			
			// Initialize Spacer Label
			this.spacerLabel = new OO.ui.LabelWidget( {
		        label: ' ',
		        classes: [ 'mw-headline'],
		    } );
			
			// Initialize Dosage Result Message
			this.dosageResultMessage = new OO.ui.MessageWidget( {
				type: 'success',
				icon: 'labFlask',
				label: ''
			} );
			
			// Intialize Copy Paste Button
			this.copyPasteButton = new OO.ui.ButtonWidget( {
				label: 'Copier-coller',
				icon: 'copy'
			} );
			
			// Add Copy-Paste Button to Dosage Result Message
			this.dosageResultMessage.$element.append( this.copyPasteButton.$element );
			
			// Changing CSS
			this.weightInputFieldset.$element[0].setAttribute('style', 'width: 75%; margin-bottom: -0.4em;');
			this.weightInputField.$element[0].firstChild.firstChild.setAttribute('style', 'width: inherit;');
			this.weightInputField.$element[0].firstChild.lastChild.setAttribute('style', 'width: inherit;');
			this.dosageResultMessage.$label[0].setAttribute('style', "display:inline-block;");
			this.dosageResultMessage.$element[0].lastChild.setAttribute('style', "float:right;");
			this.dosageResultMessage.$element[0].lastChild.firstChild.setAttribute("style", "display: inline;");
			
			// Add Horizontal Input, Dropdown Broselow Input and Dosage Result Label to Panel
			this.panel.$element.append( this.dosageInformationMessage.$element );
			this.panel.$element.append( this.horizontalLayout.$element );
			this.panel.$element.append( this.broselowLabel.$element );
			this.panel.$element.append( this.dropdownBroselowInput.$element );
			this.panel.$element.append( this.spacerLabel.$element );
			this.panel.$element.append( this.dosageResultMessage.$element );
			
			// Toggle Dosage Result Message visibility
			this.dosageResultMessage.toggle();
			
			// Add Panel to Body
			this.$body.append( this.panel.$element );
		
			// Add Event Handler to Weight Input, Unit Radio Input and Dropdown Broselow
			this.weightInput.connect( this, { 'change': 'onWeightInputChange' } );
			this.unitRadioInput.connect( this, { 'change': 'onUnitRadioInputChange' } );
			this.dropdownBroselowInput.connect( this, { 'change': 'onDropdownBroselowInputChange' } );
			this.copyPasteButton.connect( this, { 'click': 'onCopyPasterButtonClick' } );
		};
		
		// Specify any additional functionality required by the window (disable opening an empty URL, in this case)
		function updateDosageResult(dosageDialog){
			// Get weight input
			var weight_input_number = parseFloat(dosageDialog.weightInput.value);
			if (!Number.isNaN(weight_input_number) && weight_input_number > 0) {
				var multiplier;
				if (dosageDialog.unitRadioInput.value === 'kg'){
					multiplier = 1.0;
				} else {
					multiplier = 0.453592;
				}
				var daily_dose = Math.round(multiplier * dose_per_kg * weight_input_number / frequency_to_division[frequency]);
				var dose;
				if (max_daily_dose !== 0) {
					dose = Math.round((Math.min(max_daily_dose, daily_dose)) / frequency_to_division[frequency]);
				} else {
					dose = Math.round(daily_dose / frequency_to_division[frequency]);
				}
				
				// Update Broselow
				var broselow_color, broselow_weight;
				if (dosageDialog.unitRadioInput.value === 'kg') {
					broselow_color = Object.keys(broselow_to_weight_kg).find(color => broselow_to_weight_kg_min[color] <= weight_input_number && broselow_to_weight_kg_max[color] >= weight_input_number);
					broselow_weight = broselow_to_weight_kg[broselow_color] ? broselow_to_weight_kg[broselow_color]: 0;
				} else {
					broselow_color = Object.keys(broselow_to_weight_lb).find(color => broselow_to_weight_lb_min[color] <= weight_input_number && broselow_to_weight_lb_max[color] >= weight_input_number);
					broselow_weight = broselow_to_weight_lb[broselow_color] ? broselow_to_weight_lb[broselow_color]: 0;
				}

				dosageDialog.changing = true;
				dosageDialog.dropdownBroselowInput.setValue(broselow_weight);
				dosageDialog.changing = false;
				
				// Update Result Message
				var dosageResultMessageString = drug + ' ' + dose.toString() + ' ' + dose_unit + ' ' + roa + ' ' + frequency + ' ' + prn + ((prn) ? ' ' : '' ) + ((duration) ? '×' + ' ' + duration.toString() + ' ' + duration_unit : '');
				dosageDialog.dosageResultMessage.setLabel(dosageResultMessageString);
				if (!dosageDialog.dosageResultMessage.isVisible()) dosageDialog.dosageResultMessage.toggle();
				
			} else {
				// Update Broselow
				dosageDialog.dropdownBroselowInput.setValue(0);
				
				// Update Result Message
				dosageDialog.dosageResultMessage.setLabel('');
				if (dosageDialog.dosageResultMessage.isVisible()) dosageDialog.dosageResultMessage.toggle();
				
			}
		}
		
		
		DosageDialog.prototype.onWeightInputChange = function ( value ) {
			updateDosageResult(this);
		};
		
		DosageDialog.prototype.onUnitRadioInputChange = function ( value ) {
			var weight_input_number = parseFloat(this.weightInput.value) ? parseFloat(this.weightInput.value) : 0;
			if (this.unitRadioInput.value === 'kg') {
				this.dropdownBroselowInput.setOptions(broselow_dropdown_options_kg);
				this.weightInput.setValue(Math.round(10 * weight_input_number * 0.453592) / 10);
			} else {
				this.dropdownBroselowInput.setOptions(broselow_dropdown_options_lb);
				this.weightInput.setValue(Math.round(10 * weight_input_number * 2.20462) / 10);
			}
		};
		
		DosageDialog.prototype.onDropdownBroselowInputChange = function ( value ) {
			var broselow_weight = parseFloat(this.dropdownBroselowInput.getValue());
			if (dosageDialog.changing === true) {
				dosageDialog.changing = false;
			} else {
				this.weightInput.setValue(broselow_weight);
			}
		};
		
		DosageDialog.prototype.onCopyPasterButtonClick = function ( value ) {
			// Copy the text inside the text field
			navigator.clipboard.writeText(this.dosageResultMessage.label);
		};
		
		// Use the getActionProcess() method to specify a process to handle the
		// actions (for the 'save' action, in this example).
		DosageDialog.prototype.getActionProcess = function ( action ) {
			
			var weight_input_number = parseFloat(this.weightInput.value) ? parseFloat(this.weightInput.value) : 0;
			var weightUnit = this.unitRadioInput.value;
			var broselow_weight = parseFloat(this.dropdownBroselowInput.getValue());
			
			document.cookie = "wikimedica-dosage-weight=" + weight_input_number + "; expires=Thu, 18 Dec 2030 12:00:00 UTC; path=/"; 
			document.cookie = "wikimedica-dosage-weight-unit=" + weightUnit + "; expires=Thu, 18 Dec 2030 12:00:00 UTC; path=/"; 
			document.cookie = "wikimedica-dosage-broselow-weight=" + broselow_weight + "; expires=Thu, 18 Dec 2030 12:00:00 UTC; path=/"; 
			
			var dialog = this;
			if ( action ) {
				return new OO.ui.Process( function () {
					dialog.close( {
						action: action
					} );
				} );
			}
		// Fallback to parent handler.
			return DosageDialog.super.prototype.getActionProcess.call( this, action );
		};
		
		
		// Specify the dialog height (or don't to use the automatically generated height).
		DosageDialog.prototype.getBodyHeight = function () {
			// Note that "expanded: false" must be set in the panel's configuration for this to work.
			// When working with a stack layout, you can use:
			//   return this.panels.getCurrentItem().$element.outerHeight( true );

			if (this.dosageResultMessage.isVisible()) {
				return this.panel.$element.outerHeight( true );
			} else {
				return this.panel.$element.outerHeight( true ) + 60;
			}
			
		};
		
		// Create and append the window manager.
		var windowManager = new OO.ui.WindowManager();
		$( document.body ).append( windowManager.$element );
		
		// Create a new dialog window.
		var dosageDialog = new DosageDialog({
		});
		
		// Add windows to window manager using the addWindows() method.
		windowManager.addWindows( [ dosageDialog ] );
		
		// Get cookie parameters
		var weight_input_number = parseFloat(getCookie('wikimedica-dosage-weight')) ? parseFloat(getCookie('wikimedica-dosage-weight')) : 0;
		var weightUnit = getCookie('wikimedica-dosage-weight-unit') ? getCookie('wikimedica-dosage-weight-unit') : 'kg';
		var broselow_weight = parseFloat(getCookie('wikimedica-dosage-broselow-weight')) ? parseFloat(getCookie('wikimedica-dosage-broselow-weight')) : 0;
		
		
		
		// Initialize parameters according to cookies
		dosageDialog.dropdownBroselowInput.setValue(broselow_weight);
		dosageDialog.unitRadioInput.setValue(weightUnit);
		dosageDialog.weightInput.setValue(weight_input_number);
		
		
		// Open the window.
		windowManager.openWindow( dosageDialog );
	});
};

// TO DO:

// FIX CSS FOR ICONS
// ADD COLORS TO BROSELOW

/*
	@param string drug (ex: 'Amoxiciline')
	@param float dose_per_m2 (ex: 90, 7.5)
	@param string dose_unit (ex: 'mg, 'mcg')
	@param string roa (ex: 'PO', 'IR', 'IV')
	@param string frequency (ex: 'BID', 'q 12h')
	@param float max_daily_dose (default: 0) (ex: 3000, 30)
	@param string prn (default: '') (ex: 'prn', 'prn No/Vo')
	@param float duration (default: 0) (ex: 7, 14)
	@param float duration_unit (default: '') (ex: 'jours', 'semaines')
	
	Example Call: drugSurfaceDosageCalculator('Médicament', 40, 'mg', 'IV', 'q 12h', 300, '', 7, 'jours');
*/

drugSurfaceDosageCalculator = function(drug, dose_per_m2, dose_unit, roa, frequency, max_daily_dose = 0, prn = '', duration = 0, duration_unit = '') 
{
	// Lazy load the following librairies
	$.when( mw.loader.using( [ 'mediawiki.api', 'oojs-ui-core', 'oojs-ui-windows' ] )).then( function() {
		// Subclass DosageSurfaceDialog.
		function DosageSurfaceDialog( config ) {
			DosageSurfaceDialog.super.call( this, config );
		}
		OO.inheritClass( DosageSurfaceDialog, OO.ui.ProcessDialog );
		
		// Specify a name for .addWindows()
		DosageSurfaceDialog.static.name = 'dosageSurfaceDialog';
		// Specify a static title and actions.
		DosageSurfaceDialog.static.title = 'Calculateur de dose';
		DosageSurfaceDialog.static.actions = [
			{
				action: 'accept',
				label: 'Fermer',
				flags: 'primary'
			}
		];
		
		// Initialize main panel widgets and set up event handlers.
		DosageSurfaceDialog.prototype.initialize = function () {
			DosageSurfaceDialog.super.prototype.initialize.call( this );
			this.panel = new OO.ui.PanelLayout( { 
				padded: true, 
				expanded: false 
			} );
			
			// Initialize Dosage Information Message
			this.dosageInformationMessage = new OO.ui.MessageWidget( {
				type: 'notice',
				icon: 'article',
				label: drug + ' ' + dose_per_m2.toString() + ' ' + dose_unit + '/m²/j'
			} );
			
			// Initialize Weight Horizontal Layout
			this.weightHorizontalLayout = new OO.ui.HorizontalLayout( {
			} );
			
			// Initialize Weight Input Field Set
			this.weightInputFieldset = new OO.ui.FieldsetLayout();
			// Initialize Weight Input
			this.weightInput = new OO.ui.NumberInputWidget({
				min: 0,
				max: 500,
				step: 0.001,
				buttonStep: 1,
				placeholder: 'Poids',
				icon: 'userAvatar'
			});
			// Set Weight Input Field
			this.weightInputField = new OO.ui.FieldLayout( this.weightInput, { 
				label: 'Poids', 
				align: 'left',
			} );
			// Add Weight Input Field to Weight Input Field Set
			this.weightInputFieldset.addItems( [ this.weightInputField ] );
			
			// Initialize Weight Unit Radio Input
			this.weightUnitRadioInput = new OO.ui.RadioSelectInputWidget( {
			    options: [
			        { data: 'kg', label: 'kg' },
			        { data: 'lb', label: 'lb'}
			    ]
			} );
			
			// Set Elements to Horizontal Layout
			this.weightHorizontalLayout.addItems([this.weightInputFieldset, this.weightUnitRadioInput]);
			
			// Initialize Height Horizontal Layout
			this.heightHorizontalLayout = new OO.ui.HorizontalLayout( {
			} );
			
			// Initialize Height Input Field Set
			this.heightInputFieldset = new OO.ui.FieldsetLayout();
			// Initialize Weight Input
			this.heightInput = new OO.ui.NumberInputWidget({
				min: 0,
				max: 3,
				step: 0.0001,
				buttonStep: 0.1,
				placeholder: 'Taille',
				icon: 'userAvatar'
			});
			// Set Height Input Field
			this.heightInputField = new OO.ui.FieldLayout( this.heightInput, { 
				label: 'Taille', 
				align: 'left',
			} );
			// Add Weight Input Field to Weight Input Field Set
			this.heightInputFieldset.addItems( [ this.heightInputField ] );
			
			// Initialize Height Unit Radio Input
			this.heightUnitRadioInput = new OO.ui.RadioSelectInputWidget( {
			    options: [
			        { data: 'm', label: 'm' },
			        { data: 'pi + po', label: 'pi + po'}
			    ]
			} );
			
			// Set Elements to Horizontal Layout
			this.heightHorizontalLayout.addItems([this.heightInputFieldset, this.heightUnitRadioInput]);
			

			// Initialize Spacer Label
			this.spacerLabel = new OO.ui.LabelWidget( {
		        label: ' ',
		        classes: [ 'mw-headline'],
		    } );
			
			// Initialize Dosage Result Message
			this.dosageResultMessage = new OO.ui.MessageWidget( {
				type: 'success',
				icon: 'labFlask',
				label: ''
			} );
			
			// Intialize Copy Paste Button
			this.copyPasteButton = new OO.ui.ButtonWidget( {
				label: 'Copier-coller',
				icon: 'copy'
			} );
			
			// Add Copy-Paste Button to Dosage Result Message
			this.dosageResultMessage.$element.append( this.copyPasteButton.$element );
			
			// Changing CSS
			this.weightInputFieldset.$element[0].setAttribute('style', 'width: 75%; margin-bottom: -0.4em;');
			this.weightInputField.$element[0].firstChild.firstChild.setAttribute('style', 'width: inherit;');
			this.weightInputField.$element[0].firstChild.lastChild.setAttribute('style', 'width: inherit;');
			this.heightInputFieldset.$element[0].setAttribute('style', 'width: 75%; margin-bottom: -0.4em;');
			this.heightInputField.$element[0].firstChild.firstChild.setAttribute('style', 'width: inherit;');
			this.heightInputField.$element[0].firstChild.lastChild.setAttribute('style', 'width: inherit;');
			this.dosageResultMessage.$label[0].setAttribute('style', "display:inline-block;");
			this.dosageResultMessage.$element[0].lastChild.setAttribute('style', "float:right;");
			this.dosageResultMessage.$element[0].lastChild.firstChild.setAttribute("style", "display: inline;");
			
			// Add Weight Horizontal Input, Height Horizontal Input and Dosage Result Label to Panel
			this.panel.$element.append( this.dosageInformationMessage.$element );
			this.panel.$element.append( this.weightHorizontalLayout.$element );
			this.panel.$element.append( this.heightHorizontalLayout.$element );
			this.panel.$element.append( this.spacerLabel.$element );
			this.panel.$element.append( this.dosageResultMessage.$element );
			
			// Toggle Dosage Result Message visibility
			this.dosageResultMessage.toggle();
			
			// Add Panel to Body
			this.$body.append( this.panel.$element );
		
			// Add Event Handler to Weight Input, Height Input, Weight Unit Radio Input and Height Unit Radio Input
			this.weightInput.connect( this, { 'change': 'onWeightInputChange' } );
			//this.heightInput.connect( this, { 'change': 'onHeightInputChange' } );
			this.weightUnitRadioInput.connect( this, { 'change': 'onWeightUnitRadioInputChange' } );
			//this.heightUnitRadioInput.connect( this, { 'change': 'onHeightUnitRadioInputChange' } );
			this.copyPasteButton.connect( this, { 'click': 'onCopyPasterButtonClick' } );
		};
		
		// Specify any additional functionality required by the window (disable opening an empty URL, in this case)
		function updateDosageSurfaceResult(dosageDialog){
			// TODO: COMPLETE FORMULA HERE
			// Get weight input
			var weight_input_number = parseFloat(dosageDialog.weightInput.value);
			if (!Number.isNaN(weight_input_number) && weight_input_number > 0) {
				var multiplier;
				if (dosageDialog.weightUnitRadioInput.value === 'kg'){
					multiplier = 1.0;
				} else {
					multiplier = 0.453592;
				}
				var daily_dose = Math.round(multiplier * dose_per_m2 * weight_input_number / frequency_to_division[frequency]);
				var dose;
				if (max_daily_dose !== 0) {
					dose = Math.round((Math.min(max_daily_dose, daily_dose)) / frequency_to_division[frequency]);
				} else {
					dose = Math.round(daily_dose / frequency_to_division[frequency]);
				}
				
				// Update Result Message
				var dosageResultMessageString = drug + ' ' + dose.toString() + ' ' + dose_unit + ' ' + roa + ' ' + frequency + ' ' + prn + ((prn) ? ' ' : '' ) + ((duration) ? '×' + ' ' + duration.toString() + ' ' + duration_unit : '');
				dosageDialog.dosageResultMessage.setLabel(dosageResultMessageString);
				if (!dosageDialog.dosageResultMessage.isVisible()) dosageDialog.dosageResultMessage.toggle();
				
			} else {
				// Update Result Message
				dosageDialog.dosageResultMessage.setLabel('');
				if (dosageDialog.dosageResultMessage.isVisible()) dosageDialog.dosageResultMessage.toggle();
			}
		}
		
		
		DosageSurfaceDialog.prototype.onWeightInputChange = function ( value ) {
			updateDosageSurfaceResult(this);
		};
		
		DosageSurfaceDialog.prototype.onWeightUnitRadioInputChange = function ( value ) {
			var weight_input_number = parseFloat(this.weightInput.value) ? parseFloat(this.weightInput.value) : 0;
			if (this.unitRadioInput.value === 'kg') {
				this.weightInput.setValue(Math.round(10 * weight_input_number * 0.453592) / 10);
			} else {
				this.weightInput.setValue(Math.round(10 * weight_input_number * 2.20462) / 10);
			}
		};
		
		DosageSurfaceDialog.prototype.onCopyPasterButtonClick = function ( value ) {
			// Copy the text inside the text field
			navigator.clipboard.writeText(this.dosageResultMessage.label);
		};
		
		// Use the getActionProcess() method to specify a process to handle the
		// actions (for the 'save' action, in this example).
		DosageSurfaceDialog.prototype.getActionProcess = function ( action ) {
			
			var weight_input_number = parseFloat(this.weightInput.value) ? parseFloat(this.weightInput.value) : 0;
			var weightUnit = this.weightUnitRadioInput.value;
			
			document.cookie = "wikimedica-dosage-weight=" + weight_input_number + "; expires=Thu, 18 Dec 2030 12:00:00 UTC; path=/"; 
			document.cookie = "wikimedica-dosage-weight-unit=" + weightUnit + "; expires=Thu, 18 Dec 2030 12:00:00 UTC; path=/"; 
			// TODO: Set height cookies here
			
			
			var dialog = this;
			if ( action ) {
				return new OO.ui.Process( function () {
					dialog.close( {
						action: action
					} );
				} );
			}
		// Fallback to parent handler.
			return DosageSurfaceDialog.super.prototype.getActionProcess.call( this, action );
		};
		
		// Specify the dialog height (or don't to use the automatically generated height).
		DosageSurfaceDialog.prototype.getBodyHeight = function () {
			// Note that "expanded: false" must be set in the panel's configuration for this to work.
			// When working with a stack layout, you can use:
			//   return this.panels.getCurrentItem().$element.outerHeight( true );
			console.log("HERE")
			console.log(this.dosageResultMessage.isVisible());
			if (this.dosageResultMessage.isVisible()) {
				return this.panel.$element.outerHeight( true );
			} else {
				return this.panel.$element.outerHeight( true ) + 60;
			}
			
		};
		
		// Create and append the window manager.
		var windowManager = new OO.ui.WindowManager();
		$( document.body ).append( windowManager.$element );
		
		// Create a new dialog window.
		var dosageDialog = new DosageSurfaceDialog({
		});
		
		// Add windows to window manager using the addWindows() method.
		windowManager.addWindows( [ dosageDialog ] );
		
		// Get cookie parameters
		var weight_input_number = parseFloat(getCookie('wikimedica-dosage-weight')) ? parseFloat(getCookie('wikimedica-dosage-weight')) : 0;
		var weightUnit = getCookie('wikimedica-dosage-weight-unit') ? getCookie('wikimedica-dosage-weight-unit') : 'kg';
		// TODO: Get height cookies here
		
		// Initialize parameters according to cookies
		dosageDialog.weightUnitRadioInput.setValue(weightUnit);
		dosageDialog.weightInput.setValue(weight_input_number);
		
		
		// Open the window.
		windowManager.openWindow( dosageDialog );
	});
};