PageSourceSearch

https://aileronpilotlog.com/dashboard/_code_54.js

js aileronpilotlog.com collected 2026-10-02 01:21:36 UTC 348,071 bytes, 8,734 lines download raw bytes

1var log_home = "/dashboard/";
2
3var dashboard_total_titles = [];
4var dashboard_total_button_titles = [];
5var dashboard_totals = [];
6var dashboard_provisional_totals = [];
7var dashboard_total_percentages = [];
8var dashboard_total_provisional_percentages = [];
9var dashboard_total_duty_titles = [];
10var dashboard_total_duty_button_titles = [];
11var dashboard_duty_totals = [];
12var dashboard_provisional_duty_totals = [];
13var dashboard_total_duty_percentages = [];
14var dashboard_total_provisional_duty_percentages = [];
15var current_dashboard_total_tab = 0;
16var current_dashboard_duty_total_tab = 0;
17var block_total_theme_colour = 1;
18var duty_total_theme_colour = 2;
19
20var share_quote = "";
21
22var dashboard_config_section_order = "";
23var dashboard_config_totals_order = "";
24
25var drag_start_x;
26var drag_last_x;
27var drag_position_x;
28var drag_start_y;
29var drag_last_y;
30var drag_position_y;
31var dragging_element_index = -1;
32var dragging_element_height;
33var drag_context;
34var allow_hide_message;
35
36var last_log_highlight = "";
37var validation_reference = 0;
38
39var fade_delay = 250;
40var confirm_discard_changes = false;
41var confirm_discard_changes_overlay = false;
42var loading_logbook = false;
43var notification_message = "";
44
45var loading_list = "<div class='dashboard_large_text centre'><br />loading...<br /><br /></div>";
46
47var flight_fields = false;
48var sim_fields = false;
49var duty_fields = false;
50var user_fields = false;
51var settings_fields = false;
52var prev_fields = false;
53
54var signature_locked = true;
55var signature_canvas, signature_context, signature_field_ref;
56var signature_display_canvas, signature_display_context;
57var signature_mouse_x, signature_mouse_y, signature_mouse_down;
58var signature_touch_x, signature_touch_y;
59var signature_last_x, signature_last_y;
60var signature_line_width = 3;
61var no_signature = "data:image/png;base64,";
62var editing_locked = false;
63
64var aircraft_search_window = null;
65var aircraft_caa_window = null;
66var airport_search_window = null;
67var airport_map_window = null;
68
69var auto_update_limitations = false;
70
71// subscription variables
72var subscription_token = false;
73var subscription_mode = "undefined";
74var subscription_stripe = false;
75var subscription_stripe_card_element = false;
76var subscription_card_validation_error = false;
77var subscription_pro_lite = "Pro";
78var subscription_alias = "Pro";
79var subscription_payment_frequency = "Annual";
80var subscription_amount = "";
81var subscription_amount_today = "";
82var cardValidationError = false;
83var current_page = "";
84var back_page = "";
85var inhibit_dismiss = false;
86// end subscription variables
87
88var block_charts = [];
89var duty_charts = [];
90var current_chart_type = "flying";
91var current_chart_index = 0;
92var current_chart_range = 1;
93var current_chart_point_highlight = -1;
94var chart_resize_timer;
95
96var current_totals_type;
97var current_totals_prov;
98var totals_styles;
99var totals_styles_options;
100var totals_names;
101
102var prev_flight_styles_options;
103var prev_width_styles_options;
104
105var current_top_entries_tab = "airports";
106
107var calendar_callback;
108
109// initialiseDashboardMenu is called from every page (except login screen)
110// includes code to setup menu, also heartbeat for login timeout, and alert bell
111function initialiseDashboardMenu() {
112	if(document.getElementById("dashboard_button_menu")) {
113		document.getElementById("dashboard_button_menu").addEventListener("click", preventDefaults, false);
114		// First we get the viewport height and we multiple it by 1% to get a value for a vh unit
115		let vh = window.innerHeight * 0.01;
116		// Then we set the value in the --vh custom property to the root of the document
117		document.documentElement.style.setProperty('--vh', `${vh}px`);
118		// We listen to the resize event
119		window.addEventListener('resize', () => {
120			// We execute the same script as before
121			let vh = window.innerHeight * 0.01;
122			document.documentElement.style.setProperty('--vh', `${vh}px`);
123		});
124		heartbeat();				//start heartbeat check for login timeout
125		checkAlerts();				//check for messages and display bell alert if required
126	}
127	return true;				//continue with initialisation of page
128}
129
130function checkAlerts() {
131	var xmlHttp = createXMLHttpRequest();
132	if(xmlHttp) {
133		xmlHttp.onreadystatechange = function(){checkAlertsResult(xmlHttp);};
134		xmlHttp.open("post", "/log/ajax/checkAlerts.php", true);
135		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
136		xmlHttp.send();
137	}
138}
139
140function checkAlertsResult(xmlHttp) {
141	var xml = getXmlContent(xmlHttp);
142	if(xml[3]) {
143		notification_message = getXmlField(xml[0], "message");
144		var number = getXmlField(xml[0], "number");
145		document.getElementById("dashboard_bell_number").innerHTML = number;
146		if(number > 0) {
147			document.getElementById("dashboard_bell_icon").className = "";	
148		} else {
149			document.getElementById("dashboard_bell_icon").className = "hidden";	
150		}
151	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
152	} else if(xml[0]) {
153		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
154			window.location.reload(true);			//will display login screen
155		} else if(xml[0].toUpperCase() == "SUSPENDED") {
156			showSubscriptionPopup(true);
157		} else {
158			dashboardErrorMessage(xml[0]);
159		}
160	}
161}
162
163function initialiseHelp() {
164	initialiseDashboardMenu();
165}
166
167function initialiseDashboard() {
168	if(initialiseDashboardMenu()) {
169		//prevent default actions for all popup buttons, to prevent the popup being hidden in the same action
170		//add dashboardBodyClicked() to these button functions to close any other open popups first
171		document.getElementById("dashboard_bottom_link_summary").addEventListener("click", preventDefaults, false);
172		document.getElementById("dashboard_bottom_link_totals").addEventListener("click", preventDefaults, false);
173		document.getElementById("dashboard_bottom_link_aircraft").addEventListener("click", preventDefaults, false);
174		document.getElementById("dashboard_bottom_link_airports").addEventListener("click", preventDefaults, false);
175		document.getElementById("dashboard_bottom_link_distance").addEventListener("click", preventDefaults, false);
176		document.getElementById("dashboard_bottom_link_milestones").addEventListener("click", preventDefaults, false);
177		document.getElementById("configure_dashboard").addEventListener("click", preventDefaults, false);
178		document.getElementById("dashboard_configure_button").addEventListener("click", preventDefaults, false);
179		document.getElementById("configure_dashboard_totals").addEventListener("click", preventDefaults, false);
180		document.getElementById("dashboard_top_link_totals").addEventListener("click", preventDefaults, false);
181		document.getElementById("dashboard_configure_totals_button").addEventListener("click", preventDefaults, false);
182		document.getElementById("dashboard_top_link_aircraft").addEventListener("click", preventDefaults, false);
183		document.getElementById("dashboard_top_airports_link").addEventListener("click", preventDefaults, false);
184		document.getElementById("dashboard_distances_link").addEventListener("click", preventDefaults, false);
185		dashboard_config_section_order = document.getElementById('dashboard_config_order').value;
186		for(n=0; n<dashboard_config_section_order.length; n++) {
187			document.getElementById("configure_dashboard_reorder_"+n).addEventListener('touchstart', dashboardTouchStart);
188			document.getElementById("configure_dashboard_reorder_"+n).addEventListener('mousedown', dashboardMouseStart);
189		}
190		document.getElementById("configure_dashboard").addEventListener('touchmove', dashboardTouchMove);
191		document.getElementById("configure_dashboard").addEventListener('touchend', dashboardUniversalMoveEnd);
192		document.getElementById("configure_dashboard").addEventListener('mousemove', dashboardMouseMove);
193		document.getElementById("configure_dashboard").addEventListener('mouseleave', dashboardUniversalMoveEnd);
194		document.getElementById("configure_dashboard").addEventListener('mouseup', dashboardUniversalMoveEnd);
195		dashboard_config_totals_order = document.getElementById('dashboard_config_totals_order').value;
196		var totals_array = dashboard_config_totals_order.split("^");
197		for(n=0; n<totals_array.length; n++) {
198			document.getElementById("configure_dashboard_reorder_totals_"+n).addEventListener('touchstart', dashboardTouchStart);
199			document.getElementById("configure_dashboard_reorder_totals_"+n).addEventListener('mousedown', dashboardMouseStart);
200		}
201		document.getElementById("configure_dashboard_totals").addEventListener('touchmove', dashboardTouchMove);
202		document.getElementById("configure_dashboard_totals").addEventListener('touchend', dashboardUniversalMoveEnd);
203		document.getElementById("configure_dashboard_totals").addEventListener('mousemove', dashboardMouseMove);
204		document.getElementById("configure_dashboard_totals").addEventListener('mouseleave', dashboardUniversalMoveEnd);
205		document.getElementById("configure_dashboard_totals").addEventListener('mouseup', dashboardUniversalMoveEnd);
206
207		if(window.matchMedia) {
208			if(window.matchMedia('(prefers-color-scheme: dark)')) {
209				if(window.matchMedia('(prefers-color-scheme: dark)').addEventListener) {
210					window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', darkModeDetect);
211				}
212			}
213		}
214
215		document.getElementById('dashboard_nav_menu').className = "hidden";
216		showDashboardTotal(0);
217		showDashboardDutyTotal(0, true);
218		loadDashboardTopTen();
219		loadDashboardUpcoming();
220		loadDashboardUncompleted();
221		loadDashboardExpiries(false);
222		loadDashboardRecency(false);
223		loadDashboardMilestones(false);
224		loadDashboardMapData();
225		if(document.getElementById("dashboard_container_col2_admin_users")) {
226			loadDashboardNewUsers();
227		}
228		if(document.getElementById("dashboard_container_col2_admin_aircraft")) {
229			loadDashboardNewAircraft();
230		}
231		if(document.getElementById("dashboard_container_col2_admin_airports")) {
232			loadDashboardNewAirports();
233		}
234	}
235}
236
237function darkModeDetect(event) {
238	showDashboardTotal(current_dashboard_total_tab);
239	showDashboardDutyTotal(current_dashboard_duty_total_tab, true);
240	drawDashboardMilestoneCharts();
241	if (event.matches) {
242		//dark mode
243		//debug("dark");
244	} else {
245		//light mode
246		//debug("light");
247	}
248}
249
250function initialiseCharts(block, duty, show_type, show_index) {
251	if(initialiseDashboardMenu()) {
252		block_charts = block;
253		duty_charts = duty;
254		current_chart_type = show_type;
255		current_chart_index = show_index;
256		setChartRange(1);
257		showChart(show_type, show_index);
258		window.addEventListener('resize', chartsResize);
259	}
260}
261
262function initialiseTotals(show) {
263	if(initialiseDashboardMenu()) {
264		document.getElementById("filter_date_from").addEventListener("click", preventDefaults, false);
265		document.getElementById("filter_date_to").addEventListener("click", preventDefaults, false);
266		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
267		loadDashboardDetailedTotals(show);
268		totals_styles_options = [];
269		totals_styles_options[0] = "div.totals_distance {display: none;} div.totals_sectors {display: none;}";		//show only hours
270		totals_styles_options[1] = "div.totals_hours {display: none;} div.totals_sectors {display: none;}";			//show only distance
271		totals_styles_options[2] = "div.totals_hours {display: none;} div.totals_distance {display: none;}";		//show only sectors
272		totals_styles_options[3] = "div.totals_distance {display: none;} div.totals_sectors {display: none;}";		//show only hours (sim)
273		totals_styles_options[4] = "div.totals_hours {display: none;} div.totals_distance {display: none;}";		//show only sectors (sim)
274		totals_styles = document.createElement('style');
275		totals_styles.innerHTML = totals_styles_options[0];
276		document.body.appendChild(totals_styles);
277		showFilterBlockOnLargeScreen();
278	}
279}
280
281function initialisePrevious() {
282	if(initialiseDashboardMenu()) {
283		setPreviousVariables();
284	}
285}
286
287function initialiseAddPrevious() {
288	if(initialiseDashboardMenu()) {
289		setPreviousVariables();
290	}
291}
292
293function setPreviousVariables() {
294	prev_flight_styles_options = [];
295	prev_flight_styles_options[0] = "label.prev_flight_only, input.prev_flight_only, div.prev_flight_only {}";					// show all
296	prev_flight_styles_options[1] = "label.prev_flight_only, input.prev_flight_only, div.prev_flight_only {display: none;}";		// hide flight-specific fields
297	prev_width_styles_options = [];
298	prev_width_styles_options[0] = "@media all and (max-width: 820px) {.prev_col_takeoffs, .prev_col_landings {display: none;}}";
299	prev_width_styles_options[0] += "@media all and (max-width: 500px) {.prev_col_sectors, .prev_col_takeoffs, .prev_col_landings {display: none;}}";
300	prev_width_styles_options[1] = "@media all and (max-width: 820px) {.prev_col_takeoffs, .prev_col_landings {display: none;}}";
301	prev_width_styles_options[1] += "@media all and (max-width: 500px) {.prev_col_hours, .prev_col_takeoffs, .prev_col_landings {display: none;}}";
302	prev_width_styles_options[2] = "@media all and (max-width: 820px) {.prev_col_hours, .prev_col_sectors {display: none;}}";
303	prev_width_styles_options[2] += "@media all and (max-width: 500px) {.prev_col_hours, .prev_col_sectors, .prev_col_landings {display: none;}}";
304	prev_width_styles_options[3] = "@media all and (max-width: 820px) {.prev_col_hours, .prev_col_sectors {display: none;}}";
305	prev_width_styles_options[3] += "@media all and (max-width: 500px) {.prev_col_hours, .prev_col_sectors, .prev_col_takeoffs {display: none;}}";
306
307}
308
309function showPrevColumn(index) {
310	var style_index = index;
311	if(index == 4) {
312		style_index = 0;
313	} else if(index == 5) {
314		style_index = 2;
315	}
316	document.getElementById("width_style").innerHTML = prev_width_styles_options[style_index];
317	//prev_width_styles.innerHTML = prev_width_styles_options[style_index];
318	for(n=0; n<6; n++) {
319		element = document.getElementById("button_prev_width_"+n);
320		if(element) {
321			element.classList.remove("dashboard_chart_block_text_button_active");
322		}
323	}
324	var button_index = 0;		//select associated button on second bar
325	if(index == 0) {
326		button_index = 4;
327	} else if(index == 1) {
328		button_index = 4;
329	} else if(index == 2) {
330		button_index = 5;
331	} else if(index == 3) {
332		button_index = 5;
333	} else if(index == 4) {
334		button_index = 0;
335	} else if(index == 5) {
336		button_index = 2;
337	}
338	document.getElementById("button_prev_width_"+index).classList.add("dashboard_chart_block_text_button_active");
339	document.getElementById("button_prev_width_"+button_index).classList.add("dashboard_chart_block_text_button_active");
340}
341
342function initialiseMilestones() {
343	if(initialiseDashboardMenu()) {
344		loadDashboardMilestones(true);
345	}
346}
347
348function initialiseAddMilestone(id, edit_child_id) {
349	if(initialiseDashboardMenu()) {
350		loadDashboardMilestone(id, edit_child_id);
351	}
352}
353
354function initialiseRecency() {
355	if(initialiseDashboardMenu()) {
356		loadDashboardRecency(true);
357	}
358}
359
360function initialiseAddRecency() {
361	if(initialiseDashboardMenu()) {
362		//no further initialisation required as yet
363	}
364}
365
366function initialiseReports() {
367	if(initialiseDashboardMenu()) {
368		//no further initialisation required as yet
369	}
370}
371
372function initialiseImport() {
373	if(initialiseDashboardMenu()) {
374		//no further initialisation required as yet
375	}
376}
377
378function initialiseExport() {
379	if(initialiseDashboardMenu()) {
380		//no further initialisation required as yet
381	}
382}
383
384function initialiseAddUser() {
385	if(initialiseDashboardMenu()) {
386		document.getElementById("user_trial_expiry").addEventListener("click", preventDefaults, false);
387		document.getElementById("user_date_of_joining").addEventListener("click", preventDefaults, false);
388		document.getElementById("user_subscription_date").addEventListener("click", preventDefaults, false);
389		document.getElementById("user_last_payment").addEventListener("click", preventDefaults, false);
390		document.getElementById("user_next_payment").addEventListener("click", preventDefaults, false);
391		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
392		checkUserChanges();
393	}
394}
395
396function initialiseExpiries() {
397	if(initialiseDashboardMenu()) {
398		loadDashboardExpiries(true);
399	}
400}
401
402function initialiseAddExpiry() {
403	if(initialiseDashboardMenu()) {
404		document.getElementById("exp_date").addEventListener("click", preventDefaults, false);
405		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
406	}
407}
408
409function initialiseAddFlight() {
410	if(initialiseDashboardMenu()) {
411		document.getElementById("flight_date").addEventListener("click", preventDefaults, false);
412		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
413		document.getElementById("edit_aircraft").addEventListener("click", function() {quickHideOverlay("edit_aircraft");}, false);
414		document.getElementById("edit_aircraft_container").addEventListener("click", preventDefaults, false);
415		document.getElementById("edit_airport").addEventListener("click", function() {quickHideOverlay("edit_airport");}, false);
416		document.getElementById("edit_airport_container").addEventListener("click", preventDefaults, false);
417		signature_canvas = document.getElementById('flight_signature_canvas');
418		signature_context = false;
419		signature_field_ref = "flight_signature";
420		if(signature_canvas.getContext) {
421			signature_context = signature_canvas.getContext('2d');
422		}
423		if(signature_context) {
424			signature_canvas.addEventListener('mousedown', signature_mouseDown, false);
425			signature_canvas.addEventListener('mousemove', signature_mouseMove, false);
426			window.addEventListener('mouseup', signature_mouseUp, false);
427			signature_canvas.addEventListener('touchstart', signature_touchStart, false);
428			signature_canvas.addEventListener('touchmove', signature_touchMove, false);
429			signature_canvas.addEventListener('touchend', signature_touchEnd, false);
430		}
431		signature_display_canvas = document.getElementById('flight_signature_display_canvas');
432		signature_display_context = false;
433		if(signature_display_canvas.getContext) {
434			signature_display_context = signature_display_canvas.getContext('2d');
435		}
436		if(signature_display_context) {
437			showSignature();
438		}
439		checkFlightChanges();
440	}
441}
442
443function initialiseAddSim() {
444	if(initialiseDashboardMenu()) {
445		document.getElementById("sim_date").addEventListener("click", preventDefaults, false);
446		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
447		signature_canvas = document.getElementById('sim_signature_canvas');
448		signature_context = false;
449		signature_field_ref = "sim_signature";
450		if(signature_canvas.getContext) {
451			signature_context = signature_canvas.getContext('2d');
452		}
453		if(signature_context) {
454			signature_canvas.addEventListener('mousedown', signature_mouseDown, false);
455			signature_canvas.addEventListener('mousemove', signature_mouseMove, false);
456			window.addEventListener('mouseup', signature_mouseUp, false);
457			signature_canvas.addEventListener('touchstart', signature_touchStart, false);
458			signature_canvas.addEventListener('touchmove', signature_touchMove, false);
459			signature_canvas.addEventListener('touchend', signature_touchEnd, false);
460		}
461		signature_display_canvas = document.getElementById('sim_signature_display_canvas');
462		signature_display_context = false;
463		if(signature_display_canvas.getContext) {
464			signature_display_context = signature_display_canvas.getContext('2d');
465		}
466		if(signature_display_context) {
467			showSimSignature();
468		}
469		checkSimChanges();
470	}
471}
472
473function initialiseAddDuty() {
474	if(initialiseDashboardMenu()) {
475		document.getElementById("duty_date").addEventListener("click", preventDefaults, false);
476		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
477		checkDutyChanges();
478	}
479}
480
481function initialiseDistances() {
482	if(initialiseDashboardMenu()) {
483		loadDashboardTotals(0);			//0 to load all entries
484	}
485}
486
487function initialiseSettings() {
488	initialiseDashboardMenu();
489}
490
491function initialiseTopEntries(show) {
492	if(initialiseDashboardMenu()) {
493		totals_names = [];
494		totals_names[0] = "airports";
495		totals_names[1] = "routes";
496		totals_names[2] = "aircraft";
497		totals_names[3] = "types";
498		totals_names[4] = "pilots";
499		loadDashboardTopEntries(show);
500	}
501}
502
503function initialisePrintLog() {
504	if(initialiseDashboardMenu()) {
505		document.getElementById("split_start").addEventListener("click", preventDefaults, false);
506		document.getElementById("split_end").addEventListener("click", preventDefaults, false);
507		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
508	}
509}
510
511function initialiseRoster() {
512	if(initialiseDashboardMenu()) {
513		//document.getElementById("importFromDate").addEventListener("click", preventDefaults, false);
514		//document.getElementById("importToDate").addEventListener("click", preventDefaults, false);
515		//document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
516	}
517}
518
519function initialiseLogbook() {
520	if(initialiseDashboardMenu()) {
521		window.addEventListener("beforeunload", function() {saveScrollPosition("logbook");}, false);
522		loadDashboardLogbook(0);
523		document.getElementById("filter_date_from").addEventListener("click", preventDefaults, false);
524		document.getElementById("filter_date_to").addEventListener("click", preventDefaults, false);
525		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
526		if(document.getElementById("filter_icon").className == "log_filter_icon filter_icon_active") {
527			showFilterBlockOnLargeScreen();
528		}
529	}
530}
531
532function initialiseLogbookFlying() {
533	if(initialiseDashboardMenu()) {
534		window.addEventListener("beforeunload", function() {saveScrollPosition("logbook_flying");}, false);
535		loadDashboardLogbookFlying(0);
536		document.getElementById("filter_date_from").addEventListener("click", preventDefaults, false);
537		document.getElementById("filter_date_to").addEventListener("click", preventDefaults, false);
538		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
539		if(document.getElementById("filter_icon").className == "log_filter_icon filter_icon_active") {
540			showFilterBlockOnLargeScreen();
541		}
542	}
543}
544
545function initialiseLogbookSim() {
546	if(initialiseDashboardMenu()) {
547		window.addEventListener("beforeunload", function() {saveScrollPosition("logbook_sim");}, false);
548		loadDashboardLogbookSim(0);
549		document.getElementById("filter_date_from").addEventListener("click", preventDefaults, false);
550		document.getElementById("filter_date_to").addEventListener("click", preventDefaults, false);
551		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
552		if(document.getElementById("filter_icon").className == "log_filter_icon filter_icon_active") {
553			showFilterBlockOnLargeScreen();
554		}
555	}
556}
557
558function initialiseLogbookDuty() {
559	if(initialiseDashboardMenu()) {
560		window.addEventListener("beforeunload", function() {saveScrollPosition("logbook_duty");}, false);
561		loadDashboardLogbookDuty(0);
562		document.getElementById("filter_date_from").addEventListener("click", preventDefaults, false);
563		document.getElementById("filter_date_to").addEventListener("click", preventDefaults, false);
564		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
565		if(document.getElementById("filter_icon").className == "log_filter_icon filter_icon_active") {
566			showFilterBlockOnLargeScreen();
567		}
568	}
569}
570
571function initialiseAircraft(action) {
572	if(initialiseDashboardMenu()) {
573		window.addEventListener("beforeunload", function() {saveScrollPosition("aircraft");}, false);
574		document.getElementById("edit_aircraft").addEventListener("click", function() {quickHideOverlay("edit_aircraft");}, false);
575		document.getElementById("edit_aircraft_container").addEventListener("click", preventDefaults, false);
576	 	loadDashboardAircraft(0);
577		showFilterBlockOnLargeScreen();
578		if(action == "add") {
579			dashboardEditAircraft(0);
580		}
581	}
582}
583
584function initialiseAirports(action) {
585	if(initialiseDashboardMenu()) {
586		window.addEventListener("beforeunload", function() {saveScrollPosition("airports");}, false);
587		document.getElementById("edit_airport").addEventListener("click", function() {quickHideOverlay("edit_airport");}, false);
588		document.getElementById("edit_airport_container").addEventListener("click", preventDefaults, false);
589	 	loadDashboardAirports(0);
590		showFilterBlockOnLargeScreen();
591		if(action == "add") {
592			dashboardEditAirport(0);
593		}
594	}
595}
596
597function initialiseIncomplete() {
598	if(initialiseDashboardMenu()) {
599		loadDashboardIncomplete(0);
600		document.getElementById("mod_from_date").addEventListener("click", preventDefaults, false);
601		document.getElementById("mod_to_date").addEventListener("click", preventDefaults, false);
602		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
603	}
604}
605
606function initialiseProvisional() {
607	if(initialiseDashboardMenu()) {
608		loadDashboardProvisional(0);
609		document.getElementById("mod_from_date").addEventListener("click", preventDefaults, false);
610		document.getElementById("mod_to_date").addEventListener("click", preventDefaults, false);
611		document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
612	}
613}
614
615function initialiseDGCA() {
616	if(initialiseDashboardMenu()) {
617		if(document.getElementById("start_date")) {
618			document.getElementById("start_date").addEventListener("click", preventDefaults, false);
619			document.getElementById("end_date").addEventListener("click", preventDefaults, false);
620			document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);
621		}
622	}
623}
624
625function initialiseBGA() {
626	if(initialiseDashboardMenu()) {
627		//nothing more to do
628	}
629}
629
630
631function initialiseUsers() {
632	if(initialiseDashboardMenu()) {
633		window.addEventListener("beforeunload", function() {saveScrollPosition("users");}, false);
634		loadDashboardUsers(0);
635		showFilterBlockOnLargeScreen();
636	}
637}
638
639function initialiseMap() {
640	document.getElementById("from_date").addEventListener("click", preventDefaults, false);
641	document.getElementById("to_date").addEventListener("click", preventDefaults, false);
642	document.getElementById("dashboard_calendar_popup").addEventListener("click", preventDefaults, false);	
643}
644
645function initialiseLogin(id, child_id) {
646	document.getElementById("dashboard_login_form").className = "login_form_visible";
647	window.setTimeout(function () {
648		document.getElementById("dashboard_login_form").className = "login_form_scrolling";
649	}, 500);
650	document.getElementById("login_username").focus();
651	document.getElementById("login_username").addEventListener('keyup', loginKeyPress);
652	document.getElementById("login_password").addEventListener('keyup', loginKeyPress);
653}
654
655function dashboardFreeTrial() {
656	window.location.assign("/trial.php");
657}
658
659function initialiseFreeTrial() {
660}
661
662function saveScrollPosition(log) {
663	scroll = document.getElementById("dashboard_logbook_container").scrollTop;
664	var xmlHttp = createXMLHttpRequest();
665	if(xmlHttp) {
666		//xmlHttp.onreadystatechange = function(){return true;};	//no need to handle response, assume success
667		xmlHttp.open("post", "/log/ajax/saveScroll.php", true);
668		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
669		var data = "scroll=" + encodeURIComponent(scroll);
670		data += "&log=" + encodeURIComponent(log);
671		xmlHttp.send(data);
672	}
673}
674
675function showDownloadBackup() {
676	window.location.assign("backupInstructions.php");
677}
678
679function downloadBackup() {
680	if(document.getElementById("download_button").innerHTML == "Download") {
681		document.getElementById("download_button").innerHTML = "Please Wait...";
682		window.open("backup.php", "_self");
683	} else {
684		dashboard_confirm("File downloading", "Please wait\n\nThis may take a few seconds", "OK", false, false, false);
685	}
686}
687
688function downloadICS() {
689	if(document.getElementById("download_button").innerHTML == "Download ICS") {
690		document.getElementById("download_button").innerHTML = "Please Wait...";
691		document.getElementById("ics_data_form").submit();
692	} else {
693		dashboard_confirm("File downloading", "Please wait\n\nThis may take a few seconds", "OK", false, false, false);
694	}
695}
696
697function showDownloadCalendar() {
698	window.location.assign("exportCalendar.php");
699}
700
701function exportDGCA() {
702	window.location.assign("dgcaReport.php");
703}
704
705function bgaReport() {
706	window.location.assign("bgaReport.php");
707}
708
709function BGAPeriodChanged() {
710	document.getElementById("content").className = "hidden";
711	document.location.replace("bgaReport.php?reportPeriod="+document.getElementById("reportPeriod").value);
712}
713
714function emailBGAReport(period) {
715	document.location.replace("bgaReport.php?reportPeriod="+period+"&email=y");
716}
717
718function addSignature() {
719	dashboard_confirm("Warning", "Flight records must be signed after entering all information.\n\nThe flight details will then be locked from further changes.", "OK", "Cancel", function(){saveThenAddSignature("n");}, false);
720}
721
722function saveThenAddSignature(override_warnings) {
723	var validate_only = "test";
724	var check_warnings = "flight";
725	var callback = function(xml){saveFlightThenAddSignatureResult(xml);};
726	var url = "saveFlight";
727	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getFlightFields(), callback);
728}
729
730function saveFlightThenAddSignatureResult(xml) {
731	dashboard_clear_modal_message();
732	warning = getXmlField(xml[0], "warning");
733	if(warning == "OK") {
734		provisional = getXmlField(xml[0], "provisional");
735		if(provisional == "n") {
736			actuallyAddSignature();
737		} else {
738			future = getXmlField(xml[0], "future");
739			if(future == "y") {
740				dashboardAlertMessage("Error", "Only completed flights can be signed.\nThis flight has an arrival time in the future.")
741			} else {
742				dashboardAlertMessage("Error", "Only completed flights can be signed.\nThis flight is marked as provisional data.\nYou must select 'provisional data: no' before signing.")
743			}
744		}
745	} else {
746		if(confirm(warning)) {
747			saveThenAddSignature("y");
748		}
749	}
750}
751
752function actuallyAddSignature() {
753	editing_locked = true;
754	signature_locked = false;
755	var fields = getFlightFields();
756	for(f=0; f<fields.length; f++) {
757		if(fields[f] != "flight_pic_licence" && fields[f] != "flight_comment") {
758			document.getElementById(fields[f]).disabled = "disabled";
759		}
760	}
761
762	document.getElementById("signature_add").className = "hidden";
763	document.getElementById("signature_edit").className = "";
764	//document.getElementById("flight_signature_canvas").style.width = "360px";
765
766	document.getElementById("flight_signature_canvas").className = "signature_canvas_unlocked";
767	document.getElementById("flight_signature_clear").className = "dashboard_text_button";
768	document.getElementById("flight_signature_clear").innerHTML = "clear";
769	formatSignatureCanvas(signature_canvas, signature_context);
770}
771
772function removeSignature() {		// clear signature and unlock fields to edit if 'cancel' clicked when adding signature
773	document.getElementById("signature_edit").className = "hidden";
774	actuallyEraseSignature();
775}
776
777function showSignature() {
778	if(document.getElementById("flight_signature").value != no_signature) {
779		var dimensions = formatSignatureCanvas(signature_display_canvas, signature_display_context);
780		var image = new Image();
781		image.onload = function() {
782			signature_display_context.drawImage(image, 0, 0, dimensions.width, dimensions.height);
783		};
784		image.src = document.getElementById("flight_signature").value;
785		editing_locked = true;
786		signature_locked = true;
787		var fields = getFlightFields();
788		for(f=0; f<fields.length; f++) {
789			document.getElementById(fields[f]).disabled = "disabled";
790		}
791		document.getElementById("page_title_text").innerHTML = "View Flight <span class='dashboard_page_title_suffix'>Erase signature to edit</span>";
792	}
793}
794
795function formatSignatureCanvas(canvas, context) {
796	var width = canvas.clientWidth;
797	var height = canvas.clientHeight;
798	var pixel_ratio = 4.0;
799	var canvas_width = width;
800	var canvas_height = height;
801	canvas.height = canvas_height * pixel_ratio;
802	canvas.width = canvas_width * pixel_ratio;
803	context.setTransform(pixel_ratio, 0, 0, pixel_ratio, 0, 0);
804	return {width:canvas_width, height:canvas_height};
805}
806
807function eraseSignature() {
808	dashboard_confirm("Confirm", "Permanently erase signature?\n\nNo other details will be changed.", "Yes", "No", function(){actuallyEraseSignature();}, false);
809}
810
811function actuallyEraseSignature() {
812	signature_context.clearRect(0, 0, signature_canvas.width, signature_canvas.height);
813	document.getElementById("flight_signature").value = no_signature;
814	document.getElementById("signature_add").className = "";
815	document.getElementById("signature_display").className = "hidden";
816	editing_locked = false;
817	signature_locked = true;
818	var fields = getFlightFields();
819	for(f=0; f<fields.length; f++) {
820		document.getElementById(fields[f]).disabled = "";
821		document.getElementById(fields[f]).enabled = "enabled";
822	}
823	document.getElementById("page_title_text").innerHTML = "Edit Flight";
824	checkFlightChanges();
825}
826
827function clearSignature() {
828	signature_context.clearRect(0, 0, signature_canvas.width, signature_canvas.height);
829	document.getElementById("flight_signature").value = no_signature;
830	checkFlightChanges();
831}
832
833function addSimSignature() {
834	dashboard_confirm("Warning", "Simulator records must be signed after entering all information.\n\nThe details will then be locked from further changes.", "OK", "Cancel", function(){saveThenAddSimSignature("n");}, false);
835}
836
837function saveThenAddSimSignature(override_warnings) {
838	var validate_only = "test";
839	var check_warnings = "sim";
840	var callback = function(xml){saveSimThenAddSignatureResult(xml);};
841	var url = "saveSim";
842	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getSimFields(), callback);
843}
844
845function saveSimThenAddSignatureResult(xml) {
846	dashboard_clear_modal_message();
847	warning = getXmlField(xml[0], "warning");
848	if(warning == "OK") {
849		provisional = getXmlField(xml[0], "provisional");
850		if(provisional == "n") {
851			actuallyAddSimSignature();
852		} else {
853			future = getXmlField(xml[0], "future");
854			if(future == "y") {
855				dashboardAlertMessage("Error", "Only completed entries can be signed.\nThis simulator detail has an end time in the future.")
856			} else {
857				dashboardAlertMessage("Error", "Only completed entries can be signed.\nThis simulator detail is marked as provisional data.\nYou must select 'provisional data: no' before signing.")
858			}
859		}
860	} else {
861		if(confirm(warning)) {
862			saveThenAddSimSignature("y");
863		}
864	}
865}
866
867function actuallyAddSimSignature() {
868	editing_locked = true;
869	signature_locked = false;
870	var fields = getSimFields();
871	for(f=0; f<fields.length; f++) {
872		if(fields[f] != "sim_instructor_licence" && fields[f] != "sim_comment") {
873			document.getElementById(fields[f]).disabled = "disabled";
874		}
875	}
876
877	document.getElementById("signature_add").className = "hidden";
878	document.getElementById("signature_edit").className = "";
879	//document.getElementById("flight_signature_canvas").style.width = "360px";
880
881	document.getElementById("sim_signature_canvas").className = "signature_canvas_unlocked";
882	document.getElementById("sim_signature_clear").className = "dashboard_text_button";
883	document.getElementById("sim_signature_clear").innerHTML = "clear";
884	formatSignatureCanvas(signature_canvas, signature_context);
885}
886
887function removeSimSignature() {		// clear signature and unlock fields to edit if 'cancel' clicked when adding signature
888	document.getElementById("signature_edit").className = "hidden";
889	actuallyEraseSimSignature();
890}
891
892function showSimSignature() {
893	if(document.getElementById("sim_signature").value != no_signature) {
894		var dimensions = formatSignatureCanvas(signature_display_canvas, signature_display_context);
895		var image = new Image();
896		image.onload = function() {
897			signature_display_context.drawImage(image, 0, 0, dimensions.width, dimensions.height);
898		};
899		image.src = document.getElementById("sim_signature").value;
900		editing_locked = true;
901		signature_locked = true;
902		var fields = getSimFields();
903		for(f=0; f<fields.length; f++) {
904			document.getElementById(fields[f]).disabled = "disabled";
905		}
906		document.getElementById("page_title_text").innerHTML = "View Sim <span class='dashboard_page_title_suffix'>Erase signature to edit</span>";
907	}
908}
909
910function eraseSimSignature() {
911	dashboard_confirm("Confirm", "Permanently erase signature?\n\nNo other details will be changed.", "Yes", "No", function(){actuallyEraseSimSignature();}, false);
912}
913
914function actuallyEraseSimSignature() {
915	signature_context.clearRect(0, 0, signature_canvas.width, signature_canvas.height);
916	document.getElementById("sim_signature").value = no_signature;
917	document.getElementById("signature_add").className = "";
918	document.getElementById("signature_display").className = "hidden";
919	editing_locked = false;
920	signature_locked = true;
921	var fields = getSimFields();
922	for(f=0; f<fields.length; f++) {
923		document.getElementById(fields[f]).disabled = "";
924		document.getElementById(fields[f]).enabled = "enabled";
925	}
926	document.getElementById("page_title_text").innerHTML = "Edit Sim";
927	checkSimChanges();
928}
929
930function clearSimSignature() {
931	signature_context.clearRect(0, 0, signature_canvas.width, signature_canvas.height);
932	document.getElementById("sim_signature").value = no_signature;
933	checkSimChanges();
934}
935
936function drawSignatureDot(x, y) {
937	signature_context.beginPath();
938	signature_context.arc(x, y, signature_line_width/2, 0, Math.PI*2, true); 
939	signature_context.closePath();
940	signature_context.fill();
941} 
942
943function drawSignatureLine(x, y) {
944	if (signature_last_x == -1) {
945		drawSignatureDot(x, y);
946		signature_last_x = x;
947		signature_last_y = y;
948	}
949	signature_context.strokeStyle = "black";
950	signature_context.lineCap = "round";
951	signature_context.lineWidth = signature_line_width;
952	signature_context.beginPath();
953	signature_context.moveTo(signature_last_x, signature_last_y);
954	signature_context.lineTo(x,y);
955	signature_context.stroke();
956	signature_context.closePath();
957	// Update the last position to reference the current position
958	signature_last_x = x;
959	signature_last_y = y;
960	document.getElementById(signature_field_ref).value = signature_canvas.toDataURL();
961	if(signature_field_ref == "flight_signature") {
962		checkFlightChanges();
963	} else if(signature_field_ref == "sim_signature") {
964		checkSimChanges();
965	}
966} 
967
968function signature_mouseDown() {
969	if(!signature_locked) {
970		signature_mouse_down = 1;
971		drawSignatureLine(signature_mouse_x, signature_mouse_y);
972	}
973}
974
975function signature_mouseUp() {
976	signature_mouse_down = 0;
977	signature_last_x = -1;
978	signature_last_y = -1;
979}
980
981function signature_mouseMove(e) { 
982	if(!signature_locked) {
983		getMousePos(e);
984		if (signature_mouse_down == 1) {
985			drawSignatureLine(signature_mouse_x, signature_mouse_y);
986		}
987	}
988}
989
990function getMousePos(e) {
991	if (!e) {
992		var e = event;
993	}
994	if (e.offsetX) {
995		signature_mouse_x = e.offsetX;
996		signature_mouse_y = e.offsetY;
997	} else if (e.layerX) {
998		signature_mouse_x = e.layerX;
999		signature_mouse_y = e.layerY;
1000	}
1001}
1002
1003function signature_touchStart() {
1004	if(!signature_locked) {
1005		getTouchPos();
1006		drawSignatureLine(signature_touch_x, signature_touch_y);
1007		// Prevents an additional mousedown event being triggered
1008		event.preventDefault();
1009	}
1010}
1011
1012function signature_touchMove(e) { 
1013	if(!signature_locked) {
1014		getTouchPos(e);
1015		drawSignatureLine(signature_touch_x, signature_touch_y);
1016		// Prevent a scrolling action as a result of this touchmove triggering.
1017		event.preventDefault();
1018	}
1019}
1020
1021function signature_touchEnd() {
1022	signature_last_x = -1;
1023	signature_last_y = -1;
1024}
1025
1026// Get the touch position relative to the top-left of the canvas
1027// When we get the raw values of pageX and pageY below, they take into account the scrolling on the page
1028// but not the position relative to our target div. We'll adjust them using "target.offsetLeft" and
1029// "target.offsetTop" to get the correct values in relation to the top left of the canvas.
1030function getTouchPos(e) {
1031	if (!e) {
1032		var e = event;
1033	}
1034	if(e.touches) {
1035		if (e.touches.length == 1) {		// Only deal with one finger
1036			var touch = e.touches[0];		// Get the information for finger #1
1037			var offsets = touch.target.getBoundingClientRect();
1038			signature_touch_x = touch.pageX - offsets.left;
1039			signature_touch_y = touch.pageY - offsets.top;
1040		}
1041	}
1042}
1043
1044function loginKeyPress(e) {
1045	if(e.keyCode == 13) {
1046		if(e.target.id == "login_username") {
1047			password_field = document.getElementById("login_password");
1048			if(password_field.value == "") {						// if no password entered, focus password field
1049				document.getElementById("login_password").focus();
1050			} else {												// if password entered (e.g. password manager) login
1051				dashboardLogin();
1052			}
1053		} else if(e.target.id == "login_password") {
1054			dashboardLogin();
1055		}
1056	}
1057}
1058
1059function toggleTotalsSection(section) {
1060	var header_obj = document.getElementById(section);
1061	var section_obj = document.getElementById(section + "_child");
1062	if(section_obj.style.height == "0px") {			//show section
1063		header_obj.classList.remove("total_row_collapsed");
1064		header_obj.classList.add("total_row_expanded");
1065		expandSection(section_obj);
1066	} else {		//show section
1067		header_obj.classList.remove("total_row_expanded");
1068		header_obj.classList.add("total_row_collapsed");
1069		collapseSection(section_obj);
1070	}
1071}
1072
1073function toggleSettingsSection(section) {
1074	var header_obj = document.getElementById("settings_section_" + section + "_header");
1075	var section_obj = document.getElementById("settings_section_" + section);
1076	if(section_obj.style.height == "0px") {			//show section
1077		header_obj.className = "settings_section_header settings_section_header_active";
1078		expandSection(section_obj);
1079	} else {		//show section
1080		header_obj.className = "settings_section_header settings_section_header_inactive";
1081		collapseSection(section_obj);
1082	}
1083}
1084
1085function showSettingsSection(section, scroll) {
1086	var section_obj = document.getElementById("settings_section_" + section);
1087	if(section_obj.style.height == "0px") {			//show section
1088		expandSection(section_obj);
1089	}
1090	if(scroll) {
1091		var section_header = document.getElementById("settings_section_" + section+ "_header");
1092		//wait until after section is open (0.5s CSS height transition) before scrolling to view
1093		window.setTimeout(function() {section_header.scrollIntoView({behavior:"smooth", block:"start", inline:"center"});}, 500);
1094	}
1095}
1096
1097function toggleFilterSection(section) {
1098	var header_obj = document.getElementById("filter_section_" + section + "_header");
1099	var section_obj = document.getElementById("filter_section_" + section);
1100	if(section_obj.style.height == "0px") {			//show section
1101		header_obj.className = "filter_section_header filter_section_header_active";
1102		expandSection(section_obj);
1103	} else {		//show section
1104		header_obj.className = "filter_section_header filter_section_header_inactive";
1105		collapseSection(section_obj);
1106	}
1107}
1108
1109function collapseSection(element) {
1110	// get the height of the element's inner content, regardless of its actual size
1111	var sectionHeight = element.scrollHeight;
1112	// temporarily disable all css transitions
1113	var elementTransition = element.style.transition;
1114	element.style.transition = '';
1115	// on the next frame (as soon as the previous style change has taken effect),
1116	// explicitly set the element's height to its current pixel height, so we 
1117	// aren't transitioning out of 'auto'
1118	requestAnimationFrame(function() {
1119		element.style.height = sectionHeight + 'px';
1120		element.style.transition = elementTransition;
1121		// on the next frame (as soon as the previous style change has taken effect),
1122		// have the element transition to height: 0
1123		requestAnimationFrame(function() {
1124			element.style.height = '0px';
1125		});
1126	});
1127}
1128
1129function expandSection(element) {
1130	// get the height of the element's inner content, regardless of its actual size
1131	var sectionHeight = element.scrollHeight;
1132	// have the element transition to the height of its inner content
1133	element.style.height = sectionHeight + 'px';
1134	// when the next css transition finishes (which should be the one we just triggered)
1135	element.addEventListener('transitionend', function(e) {
1136		// remove this event listener so it only gets triggered once
1137		element.removeEventListener('transitionend', arguments.callee);
1138		// remove "height" from the element's inline styles, so it can return to its initial value
1139		element.style.height = null;
1140	});
1141}
1142
1143function toggleFieldLock(id) {
1144	var element = document.getElementById(id);
1145	var button = document.getElementById(id+"_lock");
1146	if(element && button) {
1147		if(element.disabled) {
1148			element.disabled = false;
1149			button.innerHTML = "Lock";
1150		} else {
1151			element.disabled = true;
1152			button.innerHTML = "Unlock";
1153		}
1154	}
1155}
1156
1157function checkSettingsChanges() {
1158	dashboardCheckForChanges(getSettingsFields());
1159	dashboardSaveSettings("y");
1160}
1161
1162function checkFlightChanges() {
1163	dashboardCheckForChanges(getFlightFields());		//quick result here, called again after validation in case of auto hours updates
1164	dashboardSaveFlight('y');
1165}
1166
1167function checkSimChanges() {
1168	dashboardCheckForChanges(getSimFields());
1169	dashboardSaveSim('y');
1170}
1171
1172function checkDutyChanges() {
1173	dashboardCheckForChanges(getDutyFields());
1174	dashboardSaveDuty('y');
1175}
1176
1177function checkExpiryChanges() {
1178	dashboardCheckForChanges(getExpiryFields());
1179	if(dashboardCalendarVisible) {
1180		updateCalendarDate("exp_date");
1181	}
1182	dashboardSaveExpiry('y');
1183}
1184
1185function checkRecencyChanges() {
1186	dashboardCheckForChanges(getRecencyFields());
1187	dashboardSaveRecency('y');
1188}
1189
1190function checkPreviousChanges() {
1191	dashboardCheckForChanges(getPrevFields());
1192	dashboardSavePrevious('y');
1193}
1194
1195function previousTypeChanged() {
1196	if(document.getElementById("prev_type").value == "Type") {
1197		document.getElementById("prev_aircraft_selection").className = "dashboard_input";
1198		document.getElementById("prev_sim_selection").className = "hidden";
1199		document.getElementById("column_selection").className = "";
1200		document.getElementById("flight_style").innerHTML = prev_flight_styles_options[0];
1201	} else {
1202		document.getElementById("prev_aircraft_selection").className = "hidden";
1203		document.getElementById("prev_sim_selection").className = "dashboard_input";
1204		document.getElementById("column_selection").className = "hidden";
1205		document.getElementById("flight_style").innerHTML = prev_flight_styles_options[1];		// hide flight-only fields
1206		showPrevColumn(0);													// show hours column
1207	}
1208	checkPreviousChanges();
1209}
1210
1211function previousAircraftChanged() {
1212	if(document.getElementById("prev_type_initial").value == "Generic") {		// check if we need to switch from generic to type-specific or vice versa
1213		if(document.getElementById("prev_aircraft").value == document.getElementById("prev_aircraft_initial").value) {
1214			document.getElementById("prev_type").value = "Generic";		// original type selected; this is the generic type
1215		} else {
1216			document.getElementById("prev_type").value = "Type";			// new type selected; this is type-specific
1217		}
1218	}
1219	//debug(document.getElementById("prev_type").value);
1220	checkPreviousChanges();
1221}
1222
1223function checkMilestoneChanges() {
1224	dashboardCheckForChanges(getMilestoneFields());
1225	dashboardSaveMilestone('y');
1226}
1227
1228function checkAircraftChanges() {
1229	var extra_class = "hidden";					//show or hide extra fields for Single-engine piston aeroplanes
1230	if(document.getElementById("ac_engines").value == "1") {					//single-engine
1231		if(document.getElementById("ac_power").value == "P") {					//piston
1232			var airframe = document.getElementById("ac_airframe").value;
1233			if(airframe == "L" || airframe == "A" || airframe == "W") {			//landplane, amphibian or floatplane (not helicopters, powered gliders, etc.)
1234				extra_class = "";
1235			}
1236		}
1237	}
1238	document.getElementById("aircraft_extras_block").className = extra_class;
1239	var glider_class = "hidden";					//show or hide extra fields for Single-engine piston aeroplanes
1240	var airframe = document.getElementById("ac_airframe").value;
1241	if(airframe == "T" || airframe == "S" || airframe == "E" || airframe == "P" || airframe == "G") {			// TMG, SLMG, SLS, Powered Glider, Glider
1242		glider_class = "";
1243	}
1244	document.getElementById("glider_extras_block").className = glider_class;
1245	dashboardCheckForChanges(getAircraftFields(), "aircraft");
1246	dashboardSaveAircraft('y');
1247}
1248
1249function checkAirportChanges() {
1250	dashboardCheckForChanges(getAirportFields(), "airport");
1251	dashboardSaveAirport('y');
1252}
1253
1254function getFlightFields() {
1255	if(!flight_fields) {
1256		flight_fields = ["flight_id", "flight_date", "flight_reg", "flight_number", "flight_from", "flight_to", "flight_depart", "flight_arrive", "flight_plan_date", "flight_ptd", "flight_pta", "flight_capacity", "flight_percent", "flight_landing", "flight_pic", "flight_pic_licence", "flight_signature", "flight_p2", "flight_heavy_1", "flight_heavy_2", "flight_sccm", "flight_launch", "flight_approach", "flight_autoland", "flight_instrument", "flight_cross_country", "flight_exclude", "flight_provisional", "flight_comment", "flight_manual_breakdown", "flight_hours_instrument", "flight_day_takeoffs", "flight_night_takeoffs", "flight_day_landings", "flight_night_landings", "flight_day_distance", "flight_night_distance", "flight_hours_day_cross_country", "flight_hours_night_cross_country"];
1257		var num_capacities = flight_capacities.length;
1258		for(c=0; c<num_capacities; c++) {
1259			flight_fields.push("flight_hours_day_"+flight_capacities[c]);
1260			flight_fields.push("flight_hours_night_"+flight_capacities[c]);
1261		}
1262		for(c=1; c<=num_flight_custom_fields; c++) {
1263			flight_fields.push("flight_custom_text_"+c);
1264			flight_fields.push("flight_custom_time_"+c);
1265			flight_fields.push("flight_custom_numeric_"+c);
1266			flight_fields.push("flight_custom_boolean_"+c);
1267		}
1268	}
1269	var extra_crew_index = 0;
1270	while(document.getElementById("flight_extra_crew_" + extra_crew_index)) {
1271		flight_fields.push("flight_extra_crew_" + extra_crew_index);
1272		extra_crew_index++;
1273	}
1274	return flight_fields;
1275}
1276
1277function getSimFields() {
1278	if(!sim_fields) {
1279		sim_fields = ["sim_id", "sim_date", "sim_detail_title", "sim_detail_type", "sim_name", "sim_type", "sim_aircraft_id", "sim_start", "sim_end", "sim_timezone", "sim_duration", "sim_capacity", "sim_instructor", "sim_instructor_licence", "sim_signature", "sim_pic", "sim_p2", "sim_takeoffs", "sim_landings", "sim_exclude", "sim_provisional", "sim_comment", "duration_only"];
1280		for(c=1; c<=num_sim_custom_fields; c++) {
1281			sim_fields.push("sim_custom_text_"+c);
1282			sim_fields.push("sim_custom_time_"+c);
1283			sim_fields.push("sim_custom_numeric_"+c);
1284			sim_fields.push("sim_custom_boolean_"+c);
1285		}
1286	}
1287	var extra_crew_index = 0;
1288	while(document.getElementById("sim_extra_crew_" + extra_crew_index)) {
1289		sim_fields.push("sim_extra_crew_" + extra_crew_index);
1290		extra_crew_index++;
1291	}
1292	return sim_fields;
1293}
1294
1295function getDutyFields() {
1296	if(!duty_fields) {
1297		duty_fields = ["duty_id", "duty_title", "duty_manual_figures", "duty_type", "duty_num_sectors", "duty_crew", "duty_acclimatised", "duty_acclimatised_tz", "duty_provisional", "duty_date", "duty_start", "duty_start_tz", "duty_start_fdp", "duty_start_rotation", "duty_end_of_flying", "duty_end", "duty_end_tz", "duty_end_rotation", "duty_extension_rest", "duty_rest_facility", "duty_extension_split", "duty_discretion_extend_duty", "duty_discretion_reduce_rest", "duty_manual_limits", "duty_extended", "duty_maximum", "duty_rest_earned", "duty_comment"];
1298		for(c=1; c<=num_duty_custom_fields; c++) {
1299			duty_fields.push("duty_custom_text_"+c);
1300			duty_fields.push("duty_custom_time_"+c);
1301			duty_fields.push("duty_custom_numeric_"+c);
1302			duty_fields.push("duty_custom_boolean_"+c);
1303		}
1304	}
1305	return duty_fields;
1306}
1307
1308function getPrevFields() {
1309	if(!prev_fields) {
1310		prev_fields = ["prev_id", "prev_type", "prev_aircraft", "prev_sim", "prev_instrument"];
1311		var num_capacities = flight_capacities.length;
1312		for(c=0; c<num_capacities; c++) {
1313			prev_fields.push("prev_hours_day_"+flight_capacities[c]);
1314			prev_fields.push("prev_hours_night_"+flight_capacities[c]);
1315			prev_fields.push("prev_sectors_day_"+flight_capacities[c]);
1316			prev_fields.push("prev_sectors_night_"+flight_capacities[c]);
1317			prev_fields.push("prev_takeoffs_day_"+flight_capacities[c]);
1318			prev_fields.push("prev_takeoffs_night_"+flight_capacities[c]);
1319			prev_fields.push("prev_landings_day_"+flight_capacities[c]);
1320			prev_fields.push("prev_landings_night_"+flight_capacities[c]);
1321		}
1322	}
1323	return prev_fields;
1324}
1325
1326function getSettingsFields() {
1327	if(!settings_fields) {
1328		settings_fields = ["user_title", "user_first_name", "user_middle_name", "user_surname", "user_licence_date", "user_licence_number", "user_licence_type", "user_licence_details", "user_address_1", "user_address_2", "user_address_3", "user_address_town", "user_address_county", "user_address_postcode", "user_country_id", "user_state_id", "user_phone", "user_mobile", "user_email", "settings_airline_id", "settings_employer", "employer_address_1", "employer_address_2", "employer_address_3", "employer_address_town", "employer_address_county", "employer_address_postcode", "employer_country_id", "employer_state_id", "settings_base_airfields", "settings_default_timezone_id", "settings_duty_ruleset", "settings_auto_duty_log", "settings_default_rest", "settings_default_flight_report", "settings_default_flight_clear", "settings_default_sim_report", "settings_default_sim_clear", "num_report_exceptions", "settings_display_order", "settings_date_format", "settings_number_format", "settings_hours_format", "settings_distance_unit", "settings_weight_unit", "settings_airport_display", "settings_aircraft_display", "settings_round_night", "settings_statistical_year_start", "settings_statistical_week_start", "settings_limitations_warning", "settings_display_audit_logs", "settings_reg_prefix", "settings_show_flight_number", "settings_show_plan", "settings_show_percent", "settings_show_licence", "settings_show_p2", "settings_show_heavy_1", "settings_show_heavy_2", "settings_show_scc", "settings_show_launch", "settings_show_approach", "settings_show_autoland", "settings_show_xc", "settings_show_exclude", "settings_ftl_exclude_other", "settings_split_flights", "settings_show_sim_p2", "settings_show_sim_licence", "settings_show_sim_exclude"];
1329		for(c=1; c<=num_flight_custom_fields; c++) {
1330			settings_fields.push("flight_custom_text_"+c);
1331			settings_fields.push("flight_custom_time_"+c);
1332			settings_fields.push("flight_custom_numeric_"+c);
1333			settings_fields.push("flight_custom_boolean_"+c);
1334			settings_fields.push("flight_custom_text_"+c+"_display");
1335			settings_fields.push("flight_custom_time_"+c+"_display");
1336			settings_fields.push("flight_custom_numeric_"+c+"_display");
1337			settings_fields.push("flight_custom_boolean_"+c+"_display");
1338			settings_fields.push("flight_custom_text_"+c+"_delete");
1339			settings_fields.push("flight_custom_time_"+c+"_delete");
1340			settings_fields.push("flight_custom_numeric_"+c+"_delete");
1341			settings_fields.push("flight_custom_boolean_"+c+"_delete");
1342		}
1343		for(c=1; c<=num_sim_custom_fields; c++) {
1344			settings_fields.push("sim_custom_text_"+c);
1345			settings_fields.push("sim_custom_time_"+c);
1346			settings_fields.push("sim_custom_numeric_"+c);
1347			settings_fields.push("sim_custom_boolean_"+c);
1348			settings_fields.push("sim_custom_text_"+c+"_display");
1349			settings_fields.push("sim_custom_time_"+c+"_display");
1350			settings_fields.push("sim_custom_numeric_"+c+"_display");
1351			settings_fields.push("sim_custom_boolean_"+c+"_display");
1352			settings_fields.push("sim_custom_text_"+c+"_delete");
1353			settings_fields.push("sim_custom_time_"+c+"_delete");
1354			settings_fields.push("sim_custom_numeric_"+c+"_delete");
1355			settings_fields.push("sim_custom_boolean_"+c+"_delete");
1356		}
1357		for(c=1; c<=num_duty_custom_fields; c++) {
1358			settings_fields.push("duty_custom_text_"+c);
1359			settings_fields.push("duty_custom_time_"+c);
1360			settings_fields.push("duty_custom_numeric_"+c);
1361			settings_fields.push("duty_custom_boolean_"+c);
1362			settings_fields.push("duty_custom_text_"+c+"_display");
1363			settings_fields.push("duty_custom_time_"+c+"_display");
1364			settings_fields.push("duty_custom_numeric_"+c+"_display");
1365			settings_fields.push("duty_custom_boolean_"+c+"_display");
1366			settings_fields.push("duty_custom_text_"+c+"_delete");
1367			settings_fields.push("duty_custom_time_"+c+"_delete");
1368			settings_fields.push("duty_custom_numeric_"+c+"_delete");
1369			settings_fields.push("duty_custom_boolean_"+c+"_delete");
1370		}
1371		for(l=1; l<=num_flight_limitations; l++) {
1372			settings_fields.push("limitations_flight_"+l+"_hours");
1373			settings_fields.push("limitations_flight_"+l+"_num");
1374			settings_fields.push("limitations_flight_"+l+"_period");
1375		}
1376		for(l=1; l<=num_duty_limitations; l++) {
1377			settings_fields.push("limitations_duty_"+l+"_hours");
1378			settings_fields.push("limitations_duty_"+l+"_num");
1379			settings_fields.push("limitations_duty_"+l+"_period");
1380		}
1381		var num_exceptions = parseInt(document.getElementById("num_report_exceptions").value, 10);
1382		for(f=1; f<=num_exceptions; f++) {
1383			settings_fields.push("report_exception_" + f + "_id");
1384			settings_fields.push("report_exception_" + f + "_airport");
1385			settings_fields.push("report_exception_" + f + "_report");
1386			settings_fields.push("report_exception_" + f + "_clear");
1387			settings_fields.push("report_exception_" + f + "_deleted");
1388		}
1389	}
1390	return settings_fields;
1391}
1392
1393function getModifyProvisionalFields() {
1394	return ["mod_range", "mod_from_date", "mod_to_date", "mod_prov", "mod_generic", "mod_aircraft", "mod_approach", "mod_approach_type", "mod_crew", "mod_crew_capacity", "mod_landing"];
1395}
1396
1397function getUserFields() {
1398	if(!user_fields) {
1399		user_fields = ["send_email", "user_id", "user_name", "user_password", "user_email", "user_brand", "user_promo_code", "user_referrer", "user_referrer_id", "user_trial_expiry", "user_extend_trial", "user_phone", "user_mobile", "user_title", "user_forename", "user_middlename", "user_surname", "user_address_1", "user_address_2", "user_address_3", "user_address_town", "user_address_postcode", "user_address_county", "user_country_id", "user_state_id", "user_airline_id", "user_employer", "user_duty_rules_id", "user_default_timezone_id", "user_date_format", "user_in_referral_scheme", "user_own_promo_code", "user_comment", "user_type", "user_status", "user_payment", "user_payment_frequency", "user_last_payment", "user_next_payment", "user_date_of_joining", "user_subscription_date", "user_stripe_id", "user_stripe_subscription_id", "user_stripe_brand", "user_stripe_card", "user_stripe_expiry", "user_paypal_email", "user_monthly_fee", "user_annual_fee", "user_lite_monthly_fee", "user_lite_annual_fee", "user_administrator", "user_admin_brand", "user_organisation_id", "user_organisation_admin", "user_organisation_read_logs", "user_admin_add_users", "user_admin_edit_users", "user_admin_edit_aircraft", "user_admin_edit_airports", "user_admin_read_logs", "user_admin_write_logs"];
1400	}
1401	return user_fields;
1402}
1403
1404function getChangePasswordFields() {
1405	return ["old_password", "new_password_1", "new_password_2"];
1406}
1407
1408function getAircraftFields() {
1409	return ["ac_id", "ac_reg", "ac_manufacturer", "ac_name", "ac_type", "ac_mtow", "ac_crew", "ac_airframe", "ac_engines", "ac_power", "ac_glider_ss", "ac_vp", "ac_retr", "ac_turbo", "ac_press", "ac_tailwheel", "ac_efis", "ac_slpc", "ac_verified", "ac_comment", "ac_addedby", "ac_valid_from", "ac_valid_to", "ac_clone_at"];
1410}
1411
1412function getAirportFields() {
1413	return ["ap_id", "ap_name", "ap_icao", "ap_iata", "ap_country_id", "ap_state_id", "ap_timezone_id", "ap_lat_ns", "ap_lat_deg", "ap_lat_min", "ap_lat_sec", "ap_lon_ew", "ap_lon_deg", "ap_lon_min", "ap_lon_sec", "ap_verified", "ap_private", "ap_comment", "ap_addedby", "ap_validfrom", "ap_validto", "ap_clone"];
1414}
1415
1416function getExpiryFields() {
1417	return ["exp_id", "exp_description", "exp_date", "exp_num", "exp_period", "exp_email", "exp_actioned"];
1418}
1419
1420function getRecencyFields() {
1421	return ["recency_id", "recency_title", "recency_check_forward", "recency_required", "recency_monitor", "recency_monitor_alt", "recency_num", "recency_period", "recency_aircraft", "recency_airport", "recency_day_night", "recency_capacity"];
1422}
1423
1424function getMilestoneFields() {
1425	return ["milestone_id", "milestone_title", "milestone_display", "milestone_required", "milestone_monitor", "milestone_monitor_alt", "milestone_aircraft", "milestone_airport", "milestone_day_night", "milestone_capacity"];
1426}
1427
1428function checkUserChanges() {
1429	dashboardCheckForChanges(getUserFields());
1430}
1431
1432function checkModifyProvisionalChanges() {
1433	dashboardCheckForChanges(getModifyProvisionalFields(), "modify_provisional");
1434	dashboardSaveModifyIncomplete("y");
1435}
1436
1437function dashboardCheckForChanges(fields, context) {
1438	changes = false;
1439	for(n=0; n<fields.length; n++) {
1440		if(document.getElementById(fields[n]+"_initial")) {
1441			initial_value = document.getElementById(fields[n]+"_initial").value;
1442			current_value = document.getElementById(fields[n]).value;
1443			if(current_value != initial_value) {
1444				changes = true;
1445				//debug(fields[n] + " '" + document.getElementById(fields[n]+"_initial").value + "' - '" + document.getElementById(fields[n]).value + "'");
1446				break;
1447			}
1448		}
1449	}
1450	var back_button = "dashboard_back_link_text";
1451	var save_button = "dashboard_save";
1452	if(context) {
1453		back_button += "_"+context;
1454		save_button += "_"+context;
1455	}
1456	if(changes) {
1457		if(context) {
1458			confirm_discard_changes_overlay = true;
1459		} else {
1460			confirm_discard_changes = true;
1461		}
1462		if(document.getElementById(back_button)) {
1463			document.getElementById(back_button).innerHTML = "Discard Changes";
1464		}
1465		document.getElementById(save_button).className = "";
1466	} else {
1467		if(context) {
1468			confirm_discard_changes_overlay = false;
1469		} else {
1470			confirm_discard_changes = false;
1471		}
1472		if(document.getElementById(back_button)) {
1473			document.getElementById(back_button).innerHTML = "Back";
1474		}
1475		document.getElementById(save_button).className = "hidden";
1476	}
1477}
1478
1479function dashboardBodyClicked() {
1480	var elements = ["dashboard_nav_menu", "dashboard_share_links", "configure_dashboard", "configure_dashboard_totals"];
1481	for(n=0; n<elements.length; n++) {
1482		element = document.getElementById(elements[n]);
1483		if(element) {
1484			elementFadeOut(element);
1485		}
1486	}
1487	hideDashboardCalendar();
1488}
1489
1490function preventDefaults (e) {
1491	e.preventDefault();
1492	e.stopPropagation();
1493}
1494
1495function toggleFilterBlock() {
1496	var element_filter = document.getElementById('filter_block');
1497	var element_list = document.getElementById('dashboard_content');
1498	if(element_filter) {
1499		if(element_filter.className == "filter_block_hidden") {
1500			element_filter.className = "filter_block_visible";
1501			if(element_list) {
1502				element_list.className = "filter_block_padding";
1503			}
1504		} else {
1505			element_filter.className = "filter_block_hidden";
1506			if(element_list) {
1507				element_list.className = "";
1508			}
1509		}
1510	}
1511}
1512
1513function showFilterBlockOnLargeScreen() {
1514	if(window.innerWidth >= 800) {			//800px to match min-width for filter overlay/inline in CSS file
1515		showFilterBlock();
1516	}
1517}
1518
1519function showFilterBlock() {
1520	var element_filter = document.getElementById('filter_block');
1521	var element_list = document.getElementById('dashboard_content');
1522	if(element_filter) {
1523		element_filter.className = "filter_block_visible";
1524		element_list.className = "filter_block_padding";
1525	}
1526}
1527
1528function hideFilterBlockOnSmallScreen() {
1529	if(window.innerWidth < 800) {			//800px to match min-width for filter overlay/inline in CSS file
1530		hideFilterBlock();
1531	}
1532}
1533
1534function hideFilterBlock() {
1535	var element_filter = document.getElementById('filter_block');
1536	var element_list = document.getElementById('dashboard_content');
1537	if(element_filter) {
1538		element_filter.className = "filter_block_hidden";
1539		element_list.className = "";
1540	}
1541}
1542
1543function dashboardNavigation(callback) {
1544	dashboardHideMenu();
1545	if(confirm_discard_changes) {
1546		dashboard_confirm("Discard Changes", "Are you sure that you want to discard your changes?", "Discard", "No", callback, false);
1547	} else {
1548		callback();
1549	}
1550}
1551
1552function dashboardHome() {
1553	window.location.assign(log_home + "index.php");
1554}
1555
1556function dashboardLogbook() {
1557	window.location.assign(log_home + "logbook.php");
1558}
1559
1560function dashboardLogbookIncomplete() {
1561	window.location.assign(log_home + "incomplete.php");
1562}
1563
1564function dashboardShowProvisional() {
1565	window.location.assign(log_home + "provisional.php");
1566}
1567
1568function dashboardShowPrevious() {
1569	window.location.assign(log_home + "previous.php");
1570}
1571
1572function dashboardPrintLog() {
1573	window.location.assign(log_home + "printLog.php");
1574}
1575
1576function dashboardShowSettings(section) {
1577	var url = log_home + "settings.php";
1578	if(section) {
1579		url += "?section="+section;
1580	}
1581	window.location.assign(url);
1582}
1583
1584function dashboardShowLimitations(show_current) {
1585	var url = log_home + "charts.php";
1586	if(show_current == "block") {
1587		url += "?show=block&index=" + current_dashboard_total_tab;				// index starts at 1; zero if career total
1588	} else if(show_current == "duty") {
1589		url += "?show=duty&index=" + (current_dashboard_duty_total_tab + 1);	// index starts at 0; add 1 to match limitations index numbering
1590	}
1591	window.location.assign(url);
1592}
1593
1594function dashboardShowReports() {
1595	window.location.assign(log_home + "reports.php");
1596}
1597
1598function dashboardShowImport() {
1599	window.location.assign(log_home + "import.php");
1600}
1601
1602function dashboardShowExport() {
1603	window.location.assign(log_home + "export.php");
1604}
1605
1606function dashboardShowTopEntries(show) {
1607	var url = log_home + "topEntries.php";
1608	if(show) {
1609		url += "?show=" + show;
1610	}
1611	window.location.assign(url);
1612}
1613
1614function dashboardShowHelp() {
1615	window.location.assign(log_home + "help.php");
1616}
1617
1618function dashboardShowAbout() {
1619	window.location.assign("/terms_and_conditions.php");
1620}
1621
1622function dashboardShowFlyingLog() {
1623	window.location.assign(log_home + "logbook_flying.php");
1624}
1625
1626function dashboardShowSimLog() {
1627	window.location.assign(log_home + "logbook_sim.php");
1628}
1629
1630function dashboardShowDutyLog() {
1631	window.location.assign(log_home + "logbook_duty.php");
1632}
1633
1634function dashboardShowAircraft(suffix) {
1635	var url = log_home + "aircraft.php";
1636	if(suffix) {
1637		url += "?" + suffix;
1638	}
1639	window.location.assign(url);
1640}
1641
1642function dashboardShowAirports(suffix) {
1643	var url = log_home + "airports.php";
1644	if(suffix) {
1645		url += "?" + suffix;
1646	}
1647	window.location.assign(url);
1648}
1649
1650function dashboardShowTotals(show) {
1651	url = log_home + "totals.php";
1652	if(show) {
1653		url += "&show="+show;
1654	}
1655	window.location.assign(url);
1656}
1657
1658function dashboardShowMilestones() {
1659	window.location.assign(log_home + "milestones.php");
1660}
1661
1662function dashboardShowDistance() {
1663	window.location.assign(log_home + "distances.php");
1664}
1665
1666function dashboardEditFlight(id, replace) {
1667	if(replace) {
1668		window.location.replace(log_home + "addFlight.php?id="+id);
1669	} else {
1670		window.location.assign(log_home + "addFlight.php?id="+id);
1671	}
1672}
1673
1674function dashboardEditSim(id, replace) {
1675	if(replace) {
1676		window.location.replace(log_home + "addSim.php?id="+id);
1677	} else {
1678		window.location.assign(log_home + "addSim.php?id="+id);
1679	}
1680}
1681
1682function dashboardEditDuty(id, replace) {
1683	if(replace) {
1684		window.location.replace(log_home + "addDuty.php?id="+id);
1685	} else {
1686		window.location.assign(log_home + "addDuty.php?id="+id);
1687	}
1688}
1689
1690function dashboardEditExpiry(id) {
1691	window.location.assign(log_home + "addExpiry.php?id="+id);
1692}
1693
1694function dashboardEditRecency(id) {
1695	window.location.assign(log_home + "addRecency.php?id="+id);
1696}
1697
1698function dashboardEditUser(id) {
1699	window.location.assign(log_home + "addUser.php?id="+id);
1700}
1701
1702function dashboardEditPrevious(id) {
1703	window.location.assign(log_home + "addPrevious.php?id="+id);
1704}
1705
1706function dashboardEditMilestone(id, edit_child_id) {
1707	if(!confirm_discard_changes) {
1708		window.location.assign(log_home + "addMilestone.php?id="+id+"&edit_child_id="+edit_child_id);
1709	}
1710}
1711
1712function addMissingAircraft() {
1713	reg = document.getElementById("flight_reg").value;
1714	dashboardEditAircraft(0, reg);
1715	checkAircraftChanges();
1716}
1717
1718function dashboardEditAircraft(id, reg, view_only, copy_aircraft) {
1719	if(!reg) {
1720		reg = "";
1721	}
1722	if(!copy_aircraft) {
1723		copy_aircraft = "n";
1724	}
1725	if(window.location.href.includes("aircraft.php")) {		//save position for reload on aircraft page, but not when editing a flight
1726		saveScrollPosition("aircraft");
1727	}
1728	confirm_discard_changes_overlay = false;
1729	document.getElementById("dashboard_back_link_text_aircraft").innerHTML = "Back";
1730	document.getElementById("dashboard_save_aircraft").className = "hidden";
1731	document.getElementById("glider_extras_block").className = "hidden";
1732	document.getElementById("aircraft_extras_block").className = "hidden";
1733	document.getElementById("delete_aircraft_block").className = "hidden";
1734	document.getElementById("ac_id").value = id;
1735	document.getElementById("ac_reg").value = reg;
1736	document.getElementById("ac_manufacturer").value = "";
1737	document.getElementById("ac_name").value = "";
1738	document.getElementById("ac_type").value = "";
1739	document.getElementById("ac_mtow").value = "";
1740	document.getElementById("ac_crew").value = "m";		// multi-crew
1741	document.getElementById("ac_airframe").value = "L";	// landplane
1742	document.getElementById("ac_engines").value = "2";	// 2 engines
1743	document.getElementById("ac_power").value = "J";	// jet
1744	document.getElementById("ac_glider_ss").value = "0";	// two-seat glider
1745	setYesNoButton("ac_vp", "n");
1746	setYesNoButton("ac_retr", "n");
1747	setYesNoButton("ac_turbo", "n");
1748	setYesNoButton("ac_press", "n");
1749	setYesNoButton("ac_tailwheel", "n");
1750	setYesNoButton("ac_efis", "n");
1751	setYesNoButton("ac_slpc", "n");
1752	if(document.getElementById("ac_verified")) {
1753		setYesNoButton("ac_verified", "n");
1754		document.getElementById("ac_comment").value = "";
1755		document.getElementById("ac_addedby").value = "";
1756		document.getElementById("ac_valid_from").value = "";
1757		document.getElementById("ac_valid_to").value = "";
1758		document.getElementById("ac_clone_at").value = "";
1759	}
1760	document.getElementById("ac_reg_initial").value = reg;
1761	document.getElementById("ac_manufacturer_initial").value = "";
1762	document.getElementById("ac_name_initial").value = "";
1763	document.getElementById("ac_type_initial").value = "";
1764	document.getElementById("ac_mtow_initial").value = "";
1765	document.getElementById("ac_crew_initial").value = "m";		// multi-crew
1766	document.getElementById("ac_airframe_initial").value = "L";	// landplane
1767	document.getElementById("ac_engines_initial").value = "2";	// 2 engines
1768	document.getElementById("ac_power_initial").value = "J";	// jet
1769	document.getElementById("ac_glider_ss_initial").value = "0";	// two-seat glider
1770	document.getElementById("ac_vp_initial").value = "n";
1771	document.getElementById("ac_retr_initial").value = "n";
1772	document.getElementById("ac_turbo_initial").value = "n";
1773	document.getElementById("ac_press_initial").value = "n";
1774	document.getElementById("ac_tailwheel_initial").value = "n";
1775	document.getElementById("ac_efis_initial").value = "n";
1776	document.getElementById("ac_slpc_initial").value = "n";
1777	if(document.getElementById("ac_verified")) {
1778		document.getElementById("ac_verified_initial").value = "n";
1779		document.getElementById("ac_comment_initial").value = "";
1780		document.getElementById("ac_addedby_initial").value = "";
1781		document.getElementById("ac_valid_from_initial").value = "";
1782		document.getElementById("ac_valid_to_initial").value = "";
1783		document.getElementById("ac_clone_at_initial").value = "";
1784	}
1785	if(id == 0 ) {				//add new aircraft
1786		document.getElementById("edit_aircraft_title").innerHTML = "Add Aircraft";
1787		setAircraftLock(false, true);		//not locked, hide delete button
1788		document.getElementById("aircraft_details_block").className = "";
1789		if(document.getElementById("aircraft_admin_block")) {
1790			document.getElementById("aircraft_admin_block").className = "";
1791		}
1792	} else {					//load aircraft details to edit
1793		document.getElementById("edit_aircraft_title").innerHTML = "Loading...";
1794		document.getElementById("aircraft_details_block").className = "hidden";
1795		if(document.getElementById("aircraft_admin_block")) {
1796			document.getElementById("aircraft_admin_block").className = "hidden";
1797		}
1798		loadAircraftToEdit(id, view_only, copy_aircraft);
1799	}
1800	document.getElementById("ac_reg").classList.remove("dashboard_invali
1800d");
1801	document.getElementById("ac_reg").classList.add("dashboard_valid");
1802	document.getElementById("ac_mtow").classList.remove("dashboard_invalid");
1803	document.getElementById("ac_mtow").classList.add("dashboard_valid");
1804	document.getElementById("edit_aircraft").className = "";
1805	if(id == 0) {
1806		document.getElementById("ac_reg").focus();
1807	}
1808}
1809
1810function loadAircraftToEdit(id, view_only, copy_aircraft) {
1811	var xmlHttp = createXMLHttpRequest();
1812	if(xmlHttp) {
1813		xmlHttp.onreadystatechange = function(){aircraftDetailsLoaded(xmlHttp, view_only);};
1814		xmlHttp.open("post", "/log/ajax/getAircraft.php", true);
1815		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
1816		var data = "ac_id=" + encodeURIComponent(id);
1817		data += "&copy_aircraft=" + encodeURIComponent(copy_aircraft);
1818		xmlHttp.send(data);
1819	}
1820}
1821
1822function aircraftDetailsLoaded(xmlHttp, view_only) {
1823	xml = getXmlContent(xmlHttp);
1824	if(xml[3]) {			//received with no errors
1825		document.getElementById("ac_id").value = getXmlField(xml[0], "ac_id");
1826		document.getElementById("ac_reg").value = getXmlField(xml[0], "ac_reg");
1827		document.getElementById("ac_manufacturer").value = getXmlField(xml[0], "ac_manufacturer");
1828		document.getElementById("ac_name").value = getXmlField(xml[0], "ac_name");
1829		document.getElementById("ac_type").value = getXmlField(xml[0], "ac_type");
1830		document.getElementById("ac_mtow").value = getXmlField(xml[0], "ac_mtow");
1831		document.getElementById("ac_crew").value = getXmlField(xml[0], "ac_crew");
1832		document.getElementById("ac_airframe").value = getXmlField(xml[0], "ac_airframe");
1833		document.getElementById("ac_engines").value = getXmlField(xml[0], "ac_engines");
1834		document.getElementById("ac_power").value = getXmlField(xml[0], "ac_power");
1835		document.getElementById("ac_glider_ss").value = getXmlField(xml[0], "ac_glider_ss");
1836		if(getXmlField(xml[0], "show_glider") == "y") {
1837			document.getElementById("glider_extras_block").className = "";
1838		} else {
1839			document.getElementById("glider_extras_block").className = "hidden";
1840		}
1841		setYesNoButton("ac_vp", getXmlField(xml[0], "ac_vp"));
1842		setYesNoButton("ac_retr", getXmlField(xml[0], "ac_retr"));
1843		setYesNoButton("ac_turbo", getXmlField(xml[0], "ac_turbo"));
1844		setYesNoButton("ac_press", getXmlField(xml[0], "ac_press"));
1845		setYesNoButton("ac_tailwheel", getXmlField(xml[0], "ac_tailwheel"));
1846		setYesNoButton("ac_efis", getXmlField(xml[0], "ac_efis"));
1847		setYesNoButton("ac_slpc", getXmlField(xml[0], "ac_slpc"));
1848		if(getXmlField(xml[0], "show_extras") == "y") {
1849			document.getElementById("aircraft_extras_block").className = "";
1850		} else {
1851			document.getElementById("aircraft_extras_block").className = "hidden";
1852		}
1853		if(document.getElementById("ac_verified")) {
1854			setYesNoButton("ac_verified", getXmlField(xml[0], "ac_verified"));
1855			document.getElementById("ac_comment").value = getXmlField(xml[0], "ac_comment");
1856			document.getElementById("ac_addedby").value = getXmlField(xml[0], "ac_addedby");
1857			document.getElementById("ac_valid_from").value = getXmlField(xml[0], "ac_valid_from");
1858			document.getElementById("ac_valid_to").value = getXmlField(xml[0], "ac_valid_to");
1859			document.getElementById("ac_clone_at").value = "";
1860		}
1861		document.getElementById("ac_reg_initial").value = getXmlField(xml[0], "ac_reg");
1862		document.getElementById("ac_manufacturer_initial").value = getXmlField(xml[0], "ac_manufacturer");
1863		document.getElementById("ac_name_initial").value = getXmlField(xml[0], "ac_name");
1864		document.getElementById("ac_type_initial").value = getXmlField(xml[0], "ac_type");
1865		document.getElementById("ac_mtow_initial").value = getXmlField(xml[0], "ac_mtow");
1866		document.getElementById("ac_crew_initial").value = getXmlField(xml[0], "ac_crew");
1867		document.getElementById("ac_airframe_initial").value = getXmlField(xml[0], "ac_airframe");
1868		document.getElementById("ac_engines_initial").value = getXmlField(xml[0], "ac_engines");
1869		document.getElementById("ac_power_initial").value = getXmlField(xml[0], "ac_power");
1870		document.getElementById("ac_glider_ss_initial").value = getXmlField(xml[0], "ac_glider_ss");
1871		document.getElementById("ac_vp_initial").value = getXmlField(xml[0], "ac_vp");
1872		document.getElementById("ac_retr_initial").value = getXmlField(xml[0], "ac_retr");
1873		document.getElementById("ac_turbo_initial").value = getXmlField(xml[0], "ac_turbo");
1874		document.getElementById("ac_press_initial").value = getXmlField(xml[0], "ac_press");
1875		document.getElementById("ac_tailwheel_initial").value = getXmlField(xml[0], "ac_tailwheel");
1876		document.getElementById("ac_efis_initial").value = getXmlField(xml[0], "ac_efis");
1877		document.getElementById("ac_slpc_initial").value = getXmlField(xml[0], "ac_slpc");
1878		if(document.getElementById("ac_verified")) {
1879			document.getElementById("ac_verified_initial").value = getXmlField(xml[0], "ac_verified");
1880			document.getElementById("ac_comment_initial").value = getXmlField(xml[0], "ac_comment");
1881			document.getElementById("ac_addedby_initial").value = getXmlField(xml[0], "ac_addedby");
1882			document.getElementById("ac_valid_from_initial").value = getXmlField(xml[0], "ac_valid_from");
1883			document.getElementById("ac_valid_to_initial").value = getXmlField(xml[0], "ac_valid_to");
1884			document.getElementById("ac_clone_at_initial").value = "";
1885		}
1886		if(getXmlField(xml[0], "ac_locked") == "y" || view_only) {
1887			document.getElementById("edit_aircraft_title").innerHTML = "Aircraft Details";
1888			setAircraftLock(true);
1889		} else {
1890			if(getXmlField(xml[0], "ac_id") == "0") {
1891				document.getElementById("edit_aircraft_title").innerHTML = "Copy Aircraft";
1892			} else {
1893				document.getElementById("edit_aircraft_title").innerHTML = "Edit Aircraft";
1894			}
1895			setAircraftLock(false);
1896		}
1897		document.getElementById("aircraft_details_block").className = "";
1898		if(document.getElementById("aircraft_admin_block") && !view_only) {
1899			document.getElementById("aircraft_admin_block").className = "";
1900		}
1901		document.getElementById("ac_reg").focus();
1902	} else if(xml[4] == 500) {			//server error
1903		dashboard_clear_modal_message();
1904		dashboard_confirm("Error", "Server error (HTTP 500)<br /><br />If this error persists, please contact support", "OK", "", function(){dashboardBackOverlay("edit_aircraft");}, false);
1905	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
1906	} else if(xml[0])	{		//received with error
1907		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
1908			dashboardForceReload();
1909		} else {
1910			dashboard_clear_modal_message();
1911			dashboard_confirm("Error", xml[0], "OK", "", function(){dashboardBackOverlay("edit_aircraft");}, false);
1912		}
1913	}
1914}
1915
1916function setAircraftLock(lock, hide_delete) {
1917	if(lock) {
1918		disabled = "disabled";
1919		delete_button = "hidden";
1920	} else {
1921		disabled = "";
1922		delete_button = "";
1923	}
1924	if(hide_delete) {
1925		delete_button = "hidden";
1926	}
1927	document.getElementById("ac_reg").disabled = disabled;
1928	document.getElementById("ac_manufacturer").disabled = disabled;
1929	document.getElementById("ac_name").disabled = disabled;
1930	document.getElementById("ac_type").disabled = disabled;
1931	document.getElementById("ac_mtow").disabled = disabled;
1932	document.getElementById("ac_crew").disabled = disabled;
1933	document.getElementById("ac_airframe").disabled = disabled;
1934	document.getElementById("ac_engines").disabled = disabled;
1935	document.getElementById("ac_power").disabled = disabled;
1936	document.getElementById("ac_glider_ss").disabled = disabled;
1937	dashboardYesNoButtonDisabled("ac_vp", disabled);
1938	dashboardYesNoButtonDisabled("ac_retr", disabled);
1939	dashboardYesNoButtonDisabled("ac_turbo", disabled);
1940	dashboardYesNoButtonDisabled("ac_press", disabled);
1941	dashboardYesNoButtonDisabled("ac_tailwheel", disabled);
1942	dashboardYesNoButtonDisabled("ac_efis", disabled);
1943	dashboardYesNoButtonDisabled("ac_slpc", disabled);
1944	if(document.getElementById("ac_verified")) {
1945		dashboardYesNoButtonDisabled("ac_verified", disabled);
1946		document.getElementById("ac_comment").disabled = disabled;
1947		document.getElementById("ac_addedby").disabled = disabled;
1948		document.getElementById("ac_valid_from").disabled = disabled;
1949		document.getElementById("ac_valid_to").disabled = disabled;
1950		document.getElementById("ac_clone_at").disabled = disabled;
1951	}
1952	document.getElementById("delete_aircraft_block").className = delete_button;
1953}
1954
1955function addMissingAirport(id) {
1956	text = document.getElementById(id).value;
1957	dashboardEditAirport(0, text);
1958	checkAirportChanges();
1959}
1960
1961// used for roster import unrecognised airport
1962function addNewAirport(code) {
1963	dashboardEditAirport(0, code, false);
1964}
1965
1966function dashboardEditAirport(id, text, view_only) {
1967	if(!text) {
1968		text = "";
1969	}
1970	add_name = "";
1971	add_icao = "";
1972	add_iata = "";
1973	if(text != "") {
1974		if(text.length == 4) {
1975			add_icao = text;
1976		} else if(text.length == 3) {
1977			add_iata = text;
1978		} else {
1979			add_name = text;
1980		}
1981	}
1982	if(window.location.href.includes("airports.php")) {		//save position for reload on airports page, but not when editing a flight
1983		saveScrollPosition("airports");
1984	}
1985	confirm_discard_changes_overlay = false;
1986	document.getElementById("dashboard_back_link_text_airport").innerHTML = "Back";
1987	document.getElementById("dashboard_save_airport").className = "hidden";
1988	document.getElementById("airport_weather_block").className = "hidden";
1989	document.getElementById("delete_airport_block").className = "hidden";
1990	document.getElementById("ap_id").value = id;
1991	document.getElementById("ap_name").value = add_name;
1992	document.getElementById("ap_icao").value = add_icao;
1993	document.getElementById("ap_iata").value = add_iata;
1994	document.getElementById("ap_lat_ns").value = "";
1995	document.getElementById("ap_lat_deg").value = "";
1996	document.getElementById("ap_lat_min").value = "";
1997	document.getElementById("ap_lat_sec").value = "";
1998	document.getElementById("ap_lon_ew").value = "";
1999	document.getElementById("ap_lon_deg").value = "";
2000	document.getElementById("ap_lon_min").value = "";
2001	document.getElementById("ap_lon_sec").value = "";
2002	document.getElementById("ap_country_id").value = "0";
2003	document.getElementById("ap_state_id").value = "0";
2004	document.getElementById("ap_timezone_id").value = "0";
2005	emptySelect("ap_state_id");
2006	emptySelect("ap_timezone_id");
2007	document.getElementById("airport_weather_text").innerHTML = "";
2008	if(document.getElementById("ap_verified")) {
2009		setYesNoButton("ap_verified", "n");
2010		document.getElementById("ap_comment").value = "";
2011		document.getElementById("ap_addedby").value = "";
2012		document.getElementById("ap_validfrom").value = "";
2013		document.getElementById("ap_validto").value = "";
2014		document.getElementById("ap_clone").value = "";
2015	}
2016	document.getElementById("ap_name_initial").value = add_name;
2017	document.getElementById("ap_icao_initial").value = add_icao;
2018	document.getElementById("ap_iata_initial").value = add_iata;
2019	document.getElementById("ap_lat_ns_initial").value = "";
2020	document.getElementById("ap_lat_deg_initial").value = "";
2021	document.getElementById("ap_lat_min_initial").value = "";
2022	document.getElementById("ap_lat_sec_initial").value = "";
2023	document.getElementById("ap_lon_ew_initial").value = "";
2024	document.getElementById("ap_lon_deg_initial").value = "";
2025	document.getElementById("ap_lon_min_initial").value = "";
2026	document.getElementById("ap_lon_sec_initial").value = "";
2027	document.getElementById("ap_country_id_initial").value = "0";
2028	document.getElementById("ap_state_id_initial").value = "0";
2029	document.getElementById("ap_timezone_id_initial").value = "0";
2030	if(document.getElementById("ap_verified")) {
2031		document.getElementById("ap_verified_initial").value = "n";
2032		document.getElementById("ap_comment_initial").value = "";
2033		document.getElementById("ap_addedby_initial").value = "";
2034		document.getElementById("ap_validfrom_initial").value = "";
2035		document.getElementById("ap_validto_initial").value = "";
2036		document.getElementById("ap_clone_initial").value = "";
2037	}
2038	if(id == 0 ) {				//add new airport
2039		document.getElementById("edit_airport_title").innerHTML = "Add Airport";
2040		setAirportLock(false, true);		//not locked, hide delete button
2041		document.getElementById("airport_details_block").className = "";
2042		if(document.getElementById("airport_admin_block")) {
2043			document.getElementById("airport_admin_block").className = "";
2044		}
2045		document.getElementById("edit_airport_state_field").className = "hidden";
2046		getTimezoneListForCountry("ap_country_id", "ap_state_id", "ap_timezone_id");
2047	} else {					//load airport details to edit
2048		document.getElementById("edit_airport_title").innerHTML = "Loading...";
2049		document.getElementById("airport_details_block").className = "hidden";
2050		if(document.getElementById("airport_admin_block")) {
2051			document.getElementById("airport_admin_block").className = "hidden";
2052		}
2053		loadAirportToEdit(id, view_only);
2054	}
2055	document.getElementById("ap_name").classList.remove("dashboard_invalid");
2056	document.getElementById("ap_name").classList.add("dashboard_valid");
2057	document.getElementById("ap_icao").classList.remove("dashboard_invalid");
2058	document.getElementById("ap_icao").classList.add("dashboard_valid");
2059	document.getElementById("ap_iata").classList.remove("dashboard_invalid");
2060	document.getElementById("ap_iata").classList.add("dashboard_valid");
2061	document.getElementById("ap_lat_ns").classList.remove("dashboard_invali
2061d");
2062	document.getElementById("ap_lat_ns").classList.add("dashboard_valid");
2063	document.getElementById("ap_lat_deg").classList.remove("dashboard_invalid");
2064	document.getElementById("ap_lat_deg").classList.add("dashboard_valid");
2065	document.getElementById("ap_lat_min").classList.remove("dashboard_invalid");
2066	document.getElementById("ap_lat_min").classList.add("dashboard_valid");
2067	document.getElementById("ap_lat_sec").classList.remove("dashboard_invalid");
2068	document.getElementById("ap_lat_sec").classList.add("dashboard_valid");
2069	document.getElementById("ap_lon_ew").classList.remove("dashboard_invalid");
2070	document.getElementById("ap_lon_ew").classList.add("dashboard_valid");
2071	document.getElementById("ap_lon_deg").classList.remove("dashboard_invalid");
2072	document.getElementById("ap_lon_deg").classList.add("dashboard_valid");
2073	document.getElementById("ap_lon_min").classList.remove("dashboard_invalid");
2074	document.getElementById("ap_lon_min").classList.add("dashboard_valid");
2075	document.getElementById("ap_lon_sec").classList.remove("dashboard_invalid");
2076	document.getElementById("ap_lon_sec").classList.add("dashboard_valid");
2077	document.getElementById("edit_airport").className = "";
2078}
2079
2080function loadAirportToEdit(id, view_only) {
2081	var xmlHttp = createXMLHttpRequest();
2082	if(xmlHttp) {
2083		xmlHttp.onreadystatechange = function(){airportDetailsLoaded(xmlHttp, view_only);};
2084		xmlHttp.open("post", "/log/ajax/getAirport.php", true);
2085		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2086		var data = "ap_id=" + encodeURIComponent(id);
2087		xmlHttp.send(data);
2088	}
2089	var xmlHttp_weather = createXMLHttpRequest();
2090	if(xmlHttp_weather) {
2091		xmlHttp_weather.onreadystatechange = function(){airportWeatherLoaded(xmlHttp_weather);};
2092		xmlHttp_weather.open("post", "/log/ajax/getAirportWeather.php", true);
2093		xmlHttp_weather.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2094		var data = "ap_id=" + encodeURIComponent(id);
2095		xmlHttp_weather.send(data);
2096	}
2097}
2098
2099function airportDetailsLoaded(xmlHttp, view_only) {
2100	xml = getXmlContent(xmlHttp);
2101	if(xml[3]) {			//received with no errors
2102		document.getElementById("ap_id").value = getXmlField(xml[0], "ap_id");
2103		document.getElementById("ap_name").value = getXmlField(xml[0], "ap_name");
2104		document.getElementById("ap_icao").value = getXmlField(xml[0], "ap_icao");
2105		document.getElementById("ap_iata").value = getXmlField(xml[0], "ap_iata");
2106		document.getElementById("ap_lat_ns").value = getXmlField(xml[0], "ap_lat_ns");
2107		document.getElementById("ap_lat_deg").value = getXmlField(xml[0], "ap_lat_deg");
2108		document.getElementById("ap_lat_min").value = getXmlField(xml[0], "ap_lat_min");
2109		document.getElementById("ap_lat_sec").value = getXmlField(xml[0], "ap_lat_sec");
2110		document.getElementById("ap_lon_ew").value = getXmlField(xml[0], "ap_lon_ew");
2111		document.getElementById("ap_lon_deg").value = getXmlField(xml[0], "ap_lon_deg");
2112		document.getElementById("ap_lon_min").value = getXmlField(xml[0], "ap_lon_min");
2113		document.getElementById("ap_lon_sec").value = getXmlField(xml[0], "ap_lon_sec");
2114		document.getElementById("ap_country_id").value = getXmlField(xml[0], "ap_country_id");
2115		document.getElementById("ap_state_id").value = getXmlField(xml[0], "ap_state_id");
2116		document.getElementById("ap_timezone_id").value = getXmlField(xml[0], "ap_timezone_id");
2117		if(document.getElementById("ap_verified")) {
2118			setYesNoButton("ap_verified", getXmlField(xml[0], "ap_verified"));
2119			setYesNoButton("ap_private", getXmlField(xml[0], "ap_private"));
2120			document.getElementById("ap_comment").value = getXmlField(xml[0], "ap_comment");
2121			document.getElementById("ap_addedby").value = getXmlField(xml[0], "ap_addedby");
2122			document.getElementById("ap_validfrom").value = getXmlField(xml[0], "ap_validfrom");
2123			document.getElementById("ap_validto").value = getXmlField(xml[0], "ap_validto");
2124			document.getElementById("ap_clone").value = "";
2125		}
2126		document.getElementById("ap_name_initial").value = getXmlField(xml[0], "ap_name");
2127		document.getElementById("ap_icao_initial").value = getXmlField(xml[0], "ap_icao");
2128		document.getElementById("ap_iata_initial").value = getXmlField(xml[0], "ap_iata");
2129		document.getElementById("ap_lat_ns_initial").value = getXmlField(xml[0], "ap_lat_ns");
2130		document.getElementById("ap_lat_deg_initial").value = getXmlField(xml[0], "ap_lat_deg");
2131		document.getElementById("ap_lat_min_initial").value = getXmlField(xml[0], "ap_lat_min");
2132		document.getElementById("ap_lat_sec_initial").value = getXmlField(xml[0], "ap_lat_sec");
2133		document.getElementById("ap_lon_ew_initial").value = getXmlField(xml[0], "ap_lon_ew");
2134		document.getElementById("ap_lon_deg_initial").value = getXmlField(xml[0], "ap_lon_deg");
2135		document.getElementById("ap_lon_min_initial").value = getXmlField(xml[0], "ap_lon_min");
2136		document.getElementById("ap_lon_sec_initial").value = getXmlField(xml[0], "ap_lon_sec");
2137		document.getElementById("ap_country_id_initial").value = getXmlField(xml[0], "ap_country_id");
2138		document.getElementById("ap_state_id_initial").value = getXmlField(xml[0], "ap_state_id");
2139		document.getElementById("ap_timezone_id_initial").value = getXmlField(xml[0], "ap_timezone_id");
2140		if(document.getElementById("ap_verified")) {
2141			document.getElementById("ap_verified_initial").value = getXmlField(xml[0], "ap_verified");
2142			document.getElementById("ap_private_initial").value = getXmlField(xml[0], "ap_private");
2143			document.getElementById("ap_comment_initial").value = getXmlField(xml[0], "ap_comment");
2144			document.getElementById("ap_addedby_initial").value = getXmlField(xml[0], "ap_addedby");
2145			document.getElementById("ap_validfrom_initial").value = getXmlField(xml[0], "ap_validfrom");
2146			document.getElementById("ap_validto_initial").value = getXmlField(xml[0], "ap_validto");
2147			document.getElementById("ap_clone_initial").value = "";
2148		}
2149		if(getXmlField(xml[0], "ap_locked") == "y" || view_only) {
2150			document.getElementById("edit_airport_title").innerHTML = "Airport Details";
2151			setAirportLock(true);
2152		} else {
2153			document.getElementById("edit_airport_title").innerHTML = "Edit Airport";
2154			setAirportLock(false);
2155		}
2156		document.getElementById("airport_details_block").className = "";
2157		if(document.getElementById("airport_admin_block") && !view_only) {
2158			document.getElementById("airport_admin_block").className = "";
2159		}
2160		updateAirportStateSelectOptions(xml);
2161		updateAirportTimezoneSelectOptions(xml);
2162	} else if(xml[4] == 500) {			//server error
2163		dashboard_clear_modal_message();
2164		dashboard_confirm("Error", "Server error (HTTP 500)<br /><br />If this error persists, please contact support", "OK", "", function(){dashboardBackOverlay("edit_airport");}, false);
2165	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
2166	} else if(xml[0])	{		//received with error
2167		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
2168			dashboardForceReload();
2169		} else {
2170			dashboard_clear_modal_message();
2171			dashboard_confirm("Error", xml[0], "OK", "", function(){dashboardBackOverlay("edit_airport");}, false);
2172		}
2173	}
2174}
2175
2176function airportWeatherLoaded(xmlHttp) {
2177	xml = getXmlContent(xmlHttp);
2178	if(xml[3]) {			//received with no errors. Ignore errors in this call as this is a non-essential service
2179		if(document.getElementById("ap_icao").value == getXmlField(xml[0], "ap_icao")) {			//check that this result is not for the currently displayed airport
2180			document.getElementById("airport_weather_text").innerHTML = getXmlField(xml[0], "weather_html");
2181			document.getElementById("airport_weather_block").className = "";
2182		}
2183	}
2184}
2185
2186function updateAirportStateSelectOptions(xml) {
2187	emptySelect("ap_state_id");
2188	addOption("ap_state_id", "", 0);
2189	if(getXmlField(xml[0], "states_empty") == "y") {
2190		document.getElementById("edit_airport_state_field").className = "hidden";
2191	} else {
2192		document.getElementById("edit_airport_state_field").className = "";
2193		list = xml[0].getElementsByTagName('state_option');
2194		for(n=0; n<list.length; n++) {
2195			value = getXmlField(list[n], "id")
2196			name = getXmlField(list[n], "name")
2197			addOption("ap_state_id", name, value);
2198		}
2199	}
2200	document.getElementById("ap_state_id").value = getXmlField(xml[0], "ap_state_id");
2201}
2202
2203function updateAirportTimezoneSelectOptions(xml) {
2204	emptySelect("ap_timezone_id");
2205	addOption("ap_timezone_id", "", 0);
2206	list = xml[0].getElementsByTagName('timezone_option');
2207	for(n=0; n<list.length; n++) {
2208		value = getXmlField(list[n], "id")
2209		name = getXmlField(list[n], "name")
2210		addOption("ap_timezone_id", name, value);
2211	}
2212	document.getElementById("ap_timezone_id").value = getXmlField(xml[0], "ap_timezone_id");
2213}
2214
2215function airportCountryChange() {
2216	getStateListForCountry("ap_country_id", "ap_state_id", "edit_airport_state_field");
2217	getTimezoneListForCountry("ap_country_id", false, "ap_timezone_id");
2218	checkAirportChanges();
2219}
2220
2221function airportStateChange() {
2222	getTimezoneListForCountry("ap_country_id", "ap_state_id", "ap_timezone_id");
2223	checkAirportChanges();
2224}
2225
2226function setAirportLock(lock, hide_delete) {
2227	if(lock) {
2228		disabled = "disabled";
2229		delete_button = "hidden";
2230	} else {
2231		disabled = "";
2232		delete_button = "";
2233	}
2234	if(hide_delete) {
2235		delete_button = "hidden";
2236	}
2237	document.getElementById("ap_name").disabled = disabled;
2238	document.getElementById("ap_icao").disabled = disabled;
2239	document.getElementById("ap_iata").disabled = disabled;
2240	document.getElementById("ap_lat_ns").disabled = disabled;
2241	document.getElementById("ap_lat_deg").disabled = disabled;
2242	document.getElementById("ap_lat_min").disabled = disabled;
2243	document.getElementById("ap_lat_sec").disabled = disabled;
2244	document.getElementById("ap_lon_ew").disabled = disabled;
2245	document.getElementById("ap_lon_deg").disabled = disabled;
2246	document.getElementById("ap_lon_min").disabled = disabled;
2247	document.getElementById("ap_lon_sec").disabled = disabled;
2248	document.getElementById("ap_country_id").disabled = disabled;
2249	document.getElementById("ap_state_id").disabled = disabled;
2250	document.getElementById("ap_timezone_id").disabled = disabled;
2251	if(document.getElementById("ap_verified")) {
2252		dashboardYesNoButtonDisabled("ap_verified", disabled);
2253		dashboardYesNoButtonDisabled("ap_private", disabled);
2254		document.getElementById("ap_comment").disabled = disabled;
2255		document.getElementById("ap_addedby").disabled = disabled;
2256		document.getElementById("ap_validfrom").disabled = disabled;
2257		document.getElementById("ap_validto").disabled = disabled;
2258		document.getElementById("ap_clone").disabled = disabled;
2259	}
2260	document.getElementById("delete_airport_block").className = delete_button;
2261}
2262
2263function dashboardUploadRoster() {
2264	window.location.assign(log_home + "importRoster.php");
2265}
2266
2267function dashboardUploadFlightlogger() {
2268	window.location.assign(log_home + "importFlightlogger.php");
2269}
2270
2271function dashboardUploadAirbly() {
2272	window.location.assign(log_home + "importAirbly.php");
2273}
2274
2275function dashboardShowExpiries() {
2276	window.location.assign(log_home + "expiries.php");
2277}
2278
2279function dashboardShowRecency() {
2280	window.location.assign(log_home + "recency.php");
2281}
2282
2283function dashboardShowUsers() {
2284	window.location.assign(log_home + "users.php");
2285}
2286
2287function dashboardToggleMenu() {
2288	var menu = document.getElementById('dashboard_nav_menu');
2289	if(menu.className == "hidden_animated" || menu.className == "hidden") {
2290		dashboardBodyClicked();
2291		elementFadeIn(menu);
2292		document.getElementById("dashboard_nav_menu").scrollTop = "0px";
2293	} else {
2294		elementFadeOut(menu);
2295	}
2296}
2297
2298function dashboardHideMenu() {
2299	var menu = document.getElementById('dashboard_nav_menu');
2300	if(menu) {
2301		if(!menu.className == "hidden_animated" && !menu.className == "hidden") {
2302			elementFadeOut(menu);
2303		}
2304	}
2305}
2306
2307function elementFadeIn(element) {
2308	delay = 5;
2309	if(element.className == "hidden_animated") {		//if already fading out, delay fade-in to avoid getting hidden again
2310		delay = fade_delay;
2311	}
2312	element.className = "hidden_animated";
2313	window.setTimeout(function () {
2314		element.className = "visible_animated";
2315	}, delay);
2316}
2317
2318function elementFadeOut(element) {
2319	if(element.className != "hidden") {
2320		element.className = "hidden_animated";
2321		window.setTimeout(function () {
2322			element.className = "hidden";
2323		}, fade_delay);
2324	}
2325}
2326
2327function modifyProvisional() {
2328	dashboardYesNoButtonClicked("mod_prov", "n");
2329	dashboardYesNoButtonClicked("mod_generic", "n");
2330	dashboardYesNoButtonClicked("mod_approach", "n");
2331	dashboardYesNoButtonClicked("mod_crew", "n");
2332	dashboardYesNoButtonClicked("mod_landing", "n");
2333	document.getElementById("block_generic_aircraft").className = "hidden";
2334	document.getElementById("block_modify_approach").className = "hidden";
2335	document.getElementById("block_modify_crew").className = "hidden";
2336	document.getElementById("modify_provisional").className = "";
2337	checkModifyProvisionalChanges();
2338}
2339
2340function toggleGenericAircraft() {
2341	var val = document.getElementById("mod_generic").value;
2342	if(val == "y") {
2343		document.getElementById("block_generic_aircraft").className = "dashboard_input";
2344	} else {
2345		document.getElementById("block_generic_aircraft").className = "hidden";
2346	}
2347}
2348
2349function toggleModifyApproach() {
2350	var val = document.getElementById("mod_approach").value;
2351	if(val == "y") {
2352		document.getElementById("block_modify_approach").className = "dashboard_input";
2353	} else {
2354		document.getElementById("block_modify_approach").className = "hidden";
2355	}
2356}
2357
2358function toggleModifyCrew() {
2359	var val = document.getElementById("mod_crew").value;
2360	if(val == "y") {
2361		document.getElementById("block_modify_crew").className = "dashboard_input";
2362	} else {
2363		document.getElementById("block_modify_crew").className = "hidden";
2364	}
2365}
2366
2367function toggleModifyDates() {
2368	var val = document.getElementById("mod_range").value;
2369	if(val == "range") {
2370		document.getElementById("mod_from_date_block").className = "dashboard_input";
2371		document.getElementById("mod_to_date_block").className = "dashboard_input";
2372	} else {
2373		document.getElementById("mod_from_date_block").className = "hidden";
2374		document.getElementById("mod_to_date_block").className = "hidden";
2375	}
2376}
2377
2378function dashboardModifyIncompleteClicked() {
2379	dashboard_confirm("Modify Incomplete Entries", "There is no undo option\n\nAre you sure?", "Yes", "No", function() {applyModifyIncomplete();});
2380}
2381
2382function applyModifyIncomplete() {
2383	dashboard_modal_message("Please wait...");
2384	dashboardSaveModifyIncomplete("n");
2385}
2386
2387function dashboardModifyProvisionalClicked() {
2388	dashboard_confirm("Modify Provisional Entries", "There is no undo option\n\nAre you sure?", "Yes", "No", function() {applyModifyProvisional();});
2389}
2390
2391function applyModifyProvisional() {
2392	dashboard_modal_message("Please wait...");
2393	dashboardSaveModifyProvisional("n");
2394}
2395
2396function dashboardShowSharing(element_id) {
2397	dashboardBodyClicked();
2398	if(element_id == "dashboard_bottom_link_summary") {
2399		if(dashboard_total_titles.length > 0) {
2400			activeTab = 0;
2401			for(n=0; n<dashboard_total_titles.length; n++) {
2402				id = "dashboard_totals_button_" + n;
2403				if(document.getElementById(id).className.indexOf("active") > 0) {
2404					activeTab = n;
2405					break;
2406				}
2407			}
2408			if(activeTab == 0) {
2409				period = "";
2410			} else {
2411				period = " in " + dashboard_total_button_titles[activeTab].toLowerCase();
2412			}
2413			share_quote = "I have logged " + dashboard_totals[activeTab] + " hours" + period + " using " + brand_name + "!";
2414		}
2415	} else if(element_id == "dashboard_bottom_link_milestones") {
2416		if(document.getElementById("dashboard_milestone_quote_0")) {
2417			share_quote = document.getElementById("dashboard_milestone_quote_0").value;
2418		} else {
2419			share_quote = "";
2420		}
2421	} else if(element_id == "dashboard_bottom_link_distance") {
2422		if(document.getElementById("dashboard_distance_quote")) {
2423			share_quote = document.getElementById("dashboard_distance_quote").value;
2424		} else {
2425			share_quote = "";
2426		}
2427	} else if(element_id == "dashboard_bottom_link_totals") {
2428		if(document.getElementById("dashboard_totals_quote")) {
2429			share_quote = document.getElementById("dashboard_totals_quote").value;
2430		} else {
2431			share_quote = "";
2432		}
2433	} else if(element_id == "dashboard_bottom_link_aircraft") {
2434		if(document.getElementById("dashboard_aircraft_quote")) {
2435			share_quote = document.getElementById("dashboard_aircraft_quote").value;
2436		} else {
2437			share_quote = "";
2438		}
2439	} else if(element_id == "dashboard_bottom_link_airports") {
2440		if(document.getElementById("dashboard_airports_quote")) {
2441			share_quote = document.getElementById("dashboard_airports_quote").value;
2442		} else {
2443			share_quote = "";
2444		}
2445	} else {
2446		share_quote = "";
2447	}
2448	var share_link = document.getElementById(element_id);
2449	var share = document.getElementById("dashboard_share_links");
2450	share_link.appendChild(share);
2451	elementFadeIn(share);
2452}
2453
2454function facebook_share() {
2455	dashboardBodyClicked();
2456	app_id = 233071171298997;
2457	href = "https://www.facebook.com/dialog/share?app_id=" + app_id + "&href=https://www." + domain + "&quote=" + encodeURIComponent(share_quote) + "&display=popup";
2458	openEditWindow(href, 'facebook');
2459}
2460
2461function linkedin_share() {
2462	dashboardBodyClicked();
2463	href = "https://www.linkedin.com/shareArticle?mini=true&url=https://www." + domain;
2464	openEditWindow(href, 'linkedin');
2465}
2466
2467function twitter_share() {
2468	dashboardBodyClicked();
2469	href = "https://twitter.com/intent/tweet?url=https://www." + domain + "&text=" + encodeURIComponent(share_quote);
2470	openEditWindow(href, 'twitter');
2471}
2472
2473function whatsapp_share() {
2474	dashboardBodyClicked();
2475	href = "whatsapp://send?text=" + encodeURIComponent(share_quote);
2476	window.location.replace(href);
2477}
2478
2479function contactSupport(subject) {
2480	var url = "mailto:" + email_support;
2481	if(subject) {
2482		url += "?subject=" + encodeURIComponent(subject);
2483	}
2484	window.location.href = url;
2485}
2486
2487function openEditWindow(url,name,wd,ht,statusbar) {
2488	x=0;
2489	y=0;
2490	if(!wd) {wd=600;}
2491	if(!ht) {ht=500;}
2492	if(window.outerWidth) {
2493		xAvail=window.outerWidth;
2494		if(wd>xAvail){wd=xAvail;}
2495		yAvail=window.outerHeight;
2496		if(ht>yAvail){ht=yAvail;}
2497		x=((xAvail-wd)/2);  
2498		y=((yAvail-ht)/2);
2499	} else if(document.documentElement.clientWidth) {
2500		xAvail=document.documentElement.clientWidth;
2501		if(wd>xAvail){wd=xAvail;}
2502		yAvail=document.documentElement.clientHeight;
2503		if(ht>yAvail){ht=yAvail;}
2504		xp=window.screenLeft;
2505		yp=window.screenTop;
2506		x=((xAvail-wd)/2)+xp;  
2507		y=((yAvail-ht)/2)+yp;
2508	}
2509	if(window.screenX) {
2510		x+=window.screenX;
2511		y+=window.screenY;
2512	}
2513	if(y<0){y=0;}
2514	winProp= 'width=' + wd + ',';
2515	winProp+='height=' + ht + ',';
2516	winProp+='left=' + x + ',';
2517	winProp+='top=' + y + ',';
2518	winProp+='status=no,';
2519	winProp+='resizable=yes,scrollbars=yes';
2520	editWin=window.open(url,name,winProp);
2521	editWin.focus();
2522}
2523
2524
2525
2526function dashboardDrawCircleChart(canvas_id, percent, provisional_percent, colour_index, include_text) {
2527	var colour_theme = "";
2528	if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
2529		colour_theme = "_dark";
2530	}
2531	var canvas = document.getElementById(canvas_id);
2532	var size = canvas.clientWidth;
2533	if(size == 0) {
2534		//return;
2535	}
2536	var pixel_ratio = 4.0;
2537	if(!colour_index) {
2538		colour_index = 1;
2539	}
2540	var circle_colour = eval("colour_theme_" + colour_index);
2541	var circle_highlight_colour = eval("colour_theme_highlight_" + colour_index);
2542	//if(canvas_id=="dashboard_total_duty_graphic"){dashboardErrorMessage(size);}
2543	var canvas_width = size;
2544	var canvas_height = size;
2545	canvas.height = canvas_height * pixel_ratio;
2546	canvas.width = canvas_width * pixel_ratio;
2547	var ctx = canvas.getContext("2d");
2548	ctx.setTransform(pixel_ratio, 0, 0, pixel_ratio, 0, 0);
2549	//solid background circle
2550	var radius = size / 2.0;
2551	var x = radius;
2552	var y = radius;
2553	var lineWidth = size / 10.0;
2554	ctx.beginPath();
2555	ctx.fillStyle = eval("colour" + colour_theme + "_dashboard_background");
2556	ctx.arc(x, y, radius, 0, 2 * Math.PI);
2557	ctx.fill();
2558	//blank circle
2559	radius = radius * 0.7;
2560	ctx.beginPath();
2561	ctx.strokeStyle = colour_dashboard_block;
2562	ctx.lineWidth = lineWidth;
2563	ctx.arc(x, y, radius, 0, 2 * Math.PI);
2564	ctx.stroke();
2565	var radians = 0;
2566	var startAngle = 0;
2567	var endAngle = 0;
2568	var dotX = 0;
2569	var dotY = 0;
2570	if(provisional_percent != percent) {
2571		//grey arc
2572		startAngle = 1.5 * Math.PI;				//top of circle
2573		radians = provisional_percent * 2 * Math.PI / 100;
2574		endAngle = radians + 1.5 * Math.PI;
2575		ctx.beginPath();
2576		ctx.strokeStyle = colour_muted_text;
2577		ctx.lineWidth = lineWidth;
2578		ctx.arc(x, y, radius, startAngle, endAngle);
2579		ctx.stroke();
2580		//end circle dot
2581		dotX = x + (radius * Math.sin(radians));
2582		dotY = y - (radius * Math.cos(radians));
2583		ctx.beginPath();
2584		ctx.fillStyle = colour_dashboard_block;
2585		ctx.arc(dotX, dotY, lineWidth, 0, 2 * Math.PI);
2586		ctx.fill();
2587		ctx.beginPath();
2588		ctx.fillStyle = colour_muted_text;
2589		ctx.arc(dotX, dotY, lineWidth * 0.65, 0, 2 * Math.PI);
2590		ctx.fill();
2591	}
2592	//colured arc
2593	startAngle = 1.5 * Math.PI;				//top of circle
2594	radians = percent * 2 * Math.PI / 100;
2595	endAngle = radians + 1.5 * Math.PI;
2596	var grd = ctx.createLinearGradient(size/3, 0, 2*size/3, size);
2597	grd.addColorStop(0, circle_highlight_colour);			//top
2598	grd.addColorStop(1, circle_colour);		//bottom
2599	ctx.beginPath();
2600	ctx.strokeStyle = grd;
2601	ctx.lineWidth = lineWidth;
2602	ctx.arc(x, y, radius, startAngle, endAngle);
2603	ctx.stroke();
2604	if(include_text) {
2605		//start circle dot
2606		dotX = x;
2607		dotY = y - radius;
2608		ctx.beginPath();
2609		ctx.fillStyle = colour_dashboard_block;
2610		ctx.arc(dotX, dotY, lineWidth, 0, 2 * Math.PI);
2611		ctx.fill();
2612		ctx.beginPath();
2613		ctx.fillStyle = circle_colour;
2614		ctx.arc(dotX, dotY, lineWidth * 0.65, 0, 2 * Math.PI);
2615		ctx.fill();
2616		//end circle dot
2617		dotX = x + (radius * Math.sin(radians));
2618		dotY = y - (radius * Math.cos(radians));
2619		ctx.beginPath();
2620		ctx.fillStyle = colour_dashboard_block;
2621		ctx.arc(dotX, dotY, lineWidth, 0, 2 * Math.PI);
2622		ctx.fill();
2623		ctx.beginPath();
2624		ctx.fillStyle = circle_colour;
2625		ctx.arc(dotX, dotY, lineWidth * 0.65, 0, 2 * Math.PI);
2626		ctx.fill();
2627	}
2628
2629	p = Math.round(percent);
2630	var text = p + "%";
2631	//text percentage
2632	if(!include_text) {
2633		text = "Total";
2634	}
2635	font_size = 14 + ((size - 70) / 8);
2636	var font = "NarrowBold";
2637	if(size < 80) {
2638		font = "NarrowRegular";
2639	}
2640	ctx.fillStyle = circle_colour;
2641	ctx.textAlign = 'center';
2642	ctx.textBaseline = "middle";
2643	ctx.font = font_size + "px " + font;
2644	ctx.fillText(text, x, y);
2645}
2646
2647function showDashboardTotal(tab) {
2648	current_dashboard_total_tab = tab;
2649	current_dashboard_duty_total_tab = 0;
2650	var include_percent = true;
2651	if(tab == 0) {
2652		include_percent = false;
2653		dashboard_total_percentages[0] = 100;
2654		dashboard_total_provisional_percentages[0] = 100;
2655	}
2656	if(dashboard_totals.length == 0) {
2657		loadDashboardTotals();
2658		//dashboardDrawCircleChart("dashboard_total_hours_graphic", 100, 100, block_total_theme_colour, false);
2659	} else {
2660		if(include_percent) {
2661			dashboardDrawCircleChart("dashboard_total_hours_graphic", dashboard_total_percentages[tab], dashboard_total_provisional_percentages[tab], block_total_theme_colour, include_percent);
2662		} else {
2663			dashboardDrawCircleChart("dashboard_total_hours_graphic", dashboard_total_percentages[tab], dashboard_total_provisional_percentages[tab], block_total_theme_colour, include_percent);
2664			//var canvas = document.getElementById("dashboard_total_hours_graphic");
2665			//const context = canvas.getContext('2d');
2666			//context.clearRect(0, 0, canvas.width, canvas.height);
2667		}
2668		document.getElementById("dashboard_total_hours_label").innerHTML = dashboard_total_titles[tab];
2669		if(dashboard_totals[tab] == dashboard_provisional_totals[tab]) {
2670			hours_text = dashboard_totals[tab];
2671		} else {
2672			hours_text = dashboard_totals[tab] + "<div class='dashboard_medium_total_text'>("+dashboard_provisional_totals[tab]+")</div>";
2673		}
2674		document.getElementById("dashboard_total_hours_text").innerHTML = hours_text;
2675		for(n=0; n<dashboard_total_titles.length; n++) {
2676			id = "dashboard_totals_button_" + n;
2677			className = "dashboard_text_button dashboard_text_button_compact";
2678			if(n == tab) {
2679				className += " dashboard_text_button_active";
2680			}
2681			element = document.getElementById(id);
2682			if(element) {
2683				element.className = className;
2684				element.innerHTML = dashboard_total_button_titles[n];
2685			}
2686		}
2687	}
2688}
2689
2690function showDashboardDutyTotal(tab, attempt_load) {
2691	current_dashboard_duty_total_tab = tab;
2692	current_dashboard_total_tab = 0;
2693	if(dashboard_duty_totals.length == 0) {
2694		if(attempt_load) {
2695			loadDashboardDutyTotals();
2696		}
2697		dashboardDrawCircleChart("dashboard_total_duty_graphic", 100, 100, duty_total_theme_colour, false);
2698	} else {
2699		dashboardDrawCircleChart("dashboard_total_duty_graphic", dashboard_total_duty_percentages[tab], dashboard_total_provisional_duty_percentages[tab], duty_total_theme_colour, true);
2700		document.getElementById("dashboard_total_duty_label").innerHTML = dashboard_total_duty_titles[tab];
2701		if(dashboard_duty_totals[tab] == dashboard_provisional_duty_totals[tab]) {
2702			hours_text = dashboard_duty_totals[tab];
2703		} else {
2704			hours_text = dashboard_duty_totals[tab] + "<div class='dashboard_medium_total_text'>("+dashboard_provisional_duty_totals[tab]+")</div>";
2705		}
2706		document.getElementById("dashboard_total_duty_text").innerHTML = hours_text;
2707		for(n=0; n<dashboard_total_duty_titles.length; n++) {
2708			id = "dashboard_totals_duty_button_" + n;
2709			className = "dashboard_text_button dashboard_duty_text_button dashboard_text_button_compact";
2710			if(n == tab) {
2711				className += " dashboard_duty_text_button_active";
2712			}
2713			element = document.getElementById(id);
2714			if(element) {
2715				element.className = className;
2716				element.innerHTML = dashboard_total_duty_button_titles[n];
2717			}
2718		}
2719	}
2720}
2721
2722function dashboardToggleTotals(idToShow, idToHide) {
2723	document.getElementById(idToHide).className = "hidden";
2724	document.getElementById(idToShow).className = "";
2725	if(idToShow == "dashboard_summary_duty_hours") {
2726		showDashboardDutyTotal(current_dashboard_duty_total_tab, true);
2727	} else {
2728		showDashboardTotal(current_dashboard_total_tab);
2729	}
2730}
2731
2732function drawDashboardMilestoneCharts() {
2733	var index = 0;
2734	var colour_index = 1;
2735	var percent = document.getElementById("dashboard_milestone_percent_"+index);
2736	while(percent) {
2737		pc = Math.floor(percent.value);		//round down for milestones to avoid premature 100% at 99.5% achieved
2738		dashboardDrawCircleChart("dashboard_milestone_graphic_"+index, pc, pc, colour_index, true);
2739		index++;
2740		colour_index++;
2741		if(colour_index > num_theme_colours) {
2742			colour_index = 1;
2743		}
2744		percent = document.getElementById("dashboard_milestone_percent_"+index);
2745	}
2746}
2747
2748function reloadDetailedTotals() {
2749	loadDashboardDetailedTotals(current_totals_type, current_totals_prov);
2750}
2751
2752function loadDashboardDetailedTotals(show, provisional) {		//load first (visible) panel of totals
2753	var xmlHttp = createXMLHttpRequest();
2754	if(xmlHttp) {
2755		document.getElementById("dashboard_content_flying_achieved").innerHTML = loading_list;
2756		if(!show) {
2757			show = "flying";
2758		}
2759		if(!provisional) {
2760			provisional = "achieved";
2761		}
2762		current_totals_type = show;
2763		current_totals_prov = provisional;
2764		var element = "dashboard_content_" + show + "_" + provisional;
2765		var callback = function() {loadRemainingTotals(show, provisional);};
2766		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, element, callback);};
2767		xmlHttp.open("post", "/log/ajax/dashboardDetailedTotals.php", true);
2768		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2769		var data = "show=" + show;
2770		data += "&provisional="+provisional;
2771		xmlHttp.send(data);
2772	}
2773}
2774
2775function loadRemainingTotals(already_loaded, loaded_provisional) {		//background load remaining totals tabs
2776	var totals_to_load = [["flying", "achieved"], ["flying", "provisional"], ["sim", "achieved"], ["sim", "provisional"], ["duty", "achieved"], ["duty", "provisional"]];
2777	for(n=0; n<totals_to_load.length; n++) {
2778		if(totals_to_load[n][0] == already_loaded && totals_to_load[n][1] == loaded_provisional) {
2779			totals_to_load.splice(n,1);
2780		}
2781	}
2782	loadNextTotals(totals_to_load, 0);
2783}
2784
2785function loadNextTotals(totals_to_load, index) {
2786	var xmlHttp = createXMLHttpRequest();
2787	if(xmlHttp) {
2788		var show = totals_to_load[index][0];
2789		var provisional = totals_to_load[index][1];
2790		var element = "dashboard_content_" + show + "_" + provisional;
2791		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, element);};
2792		xmlHttp.open("post", "/log/ajax/dashboardDetailedTotals.php", true);
2793		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2794		var data  = "show=" +			encodeURIComponent(show);
2795		data += "&provisional=" +		encodeURIComponent(provisional);
2796		xmlHttp.send(data);
2797	}
2798	index++;
2799	if(index < totals_to_load.length) {
2800		loadNextTotals(totals_to_load, index);
2801	}
2802}
2803
2804function loadDashboardTopEntries(show) {		//load first (visible) panel of top entries
2805	var xmlHttp = createXMLHttpRequest();
2806	if(xmlHttp) {
2807		if(show) {
2808			current_top_entries_tab = show;
2809		} else {
2810			show = current_top_entries_tab;
2811		}
2812		var element = "dashboard_content_" + show;
2813		var callback = function() {loadRemainingTopEntries(show);};
2814		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, element, callback);};
2815		xmlHttp.open("post", "/log/ajax/dashboardTopEntries.php", true);
2816		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2817		var data = "show=" + show;
2818		xmlHttp.send(data);
2819	}
2820}
2821
2822function loadRemainingTopEntries(already_loaded) {		//background load remaining totals tabs
2823	var totals_to_load = [...totals_names];				//shallow copy array to modify
2824	for(n=0; n<totals_to_load.length; n++) {
2825		if(totals_to_load[n] == already_loaded) {
2826			totals_to_load.splice(n,1);
2827		}
2828	}
2829	loadNextTopEntries(totals_to_load, 0);
2830}
2831
2832function loadNextTopEntries(totals_to_load, index) {
2833	var xmlHttp = createXMLHttpRequest();
2834	if(xmlHttp) {
2835		var element = "dashboard_content_" + totals_to_load[index];
2836		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, element);};
2837		xmlHttp.open("post", "/log/ajax/dashboardTopEntries.php", true);
2838		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2839		var data  = "show=" + encodeURIComponent(totals_to_load[index]);
2840		xmlHttp.send(data);
2841	}
2842	index++;
2843	if(index < totals_to_load.length) {
2844		loadNextTopEntries(totals_to_load, index);
2845	}
2846}
2847
2848
2849function loadDashboardTotals(num_distances) {
2850	var xmlHttp = createXMLHttpRequest();
2851	if(xmlHttp) {
2852		xmlHttp.onreadystatechange = function(){updateDashboardTotals(xmlHttp);};
2853		xmlHttp.open("post", "/log/ajax/dashboardTotals.php", true);
2854		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2855		var data = "";
2856		if(typeof(num_distances) !== "undefined") {
2857			var data = "num_distances=" + num_distances;
2858		}
2859		xmlHttp.send(data);
2860	}
2861}
2862
2863function updateDashboardTotals(xmlHttp) {
2864	var xml = getXmlContent(xmlHttp);
2865	if(xml[3]) {
2866		if(document.getElementById("hours_pic")) {
2867			num_totals = parseInt(getXmlField(xml[0], "num_limits"), 10);
2868			for(n=0; n<=num_totals; n++) {
2869				dashboard_total_titles[n] =						getXmlField(xml[0], "title_"+n);
2870				dashboard_total_button_titles[n] =				getXmlField(xml[0], "button_title_"+n);
2871				dashboard_totals[n] =							getXmlField(xml[0], "total_"+n);
2872				dashboard_provisional_totals[n] =				getXmlField(xml[0], "prov_total_"+n);
2873				dashboard_total_percentages[n] =				parseInt(getXmlField(xml[0], "percent_"+n), 10);
2874				dashboard_total_provisional_percentages[n] =	parseInt(getXmlField(xml[0], "prov_percent_"+n), 10);
2875			}
2876			showDashboardTotal(0);
2877			var elements = ["hours_pic", "hours_total_pic", "hours_night", "hours_picus", "hours_dual", "hours_p2", "hours_instrument", "hours_instructor", "hours_examiner"];
2878			for(n=1; n<=num_flight_custom_fields; n++) {
2879				elements.push("hours_custom_"+n);
2880				elements.push("hours_custom_numeric_"+n);
2881				elements.push("hours_custom_boolean_"+n);
2882			}
2883			for(i=0; i<elements.length; i++) {
2884				element = document.getElementById(elements[i]);
2885				if(element) {
2886					element.innerHTML = getXmlField(xml[0], elements[i]);
2887				}
2888			}
2889		}
2890		document.getElementById("dashboard_content_distances").innerHTML = getXmlField(xml[0], "distance_content");
2891	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
2892	} else if(xml[0]) {
2893		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
2894			window.location.reload(true);			//will display login screen
2895		} else if(xml[0].toUpperCase() == "SUSPENDED") {
2896			showSubscriptionPopup(true);
2897		} else {
2898			dashboardErrorMessage(xml[0]);
2899		}
2900	}
2901}
2902
2903function loadDashboardDutyTotals() {
2904	var xmlHttp = createXMLHttpRequest();
2905	if(xmlHttp) {
2906		xmlHttp.onreadystatechange = function(){updateDashboardDutyTotals(xmlHttp);};
2907		xmlHttp.open("post", "/log/ajax/dashboardDutyTotals.php", true);
2908		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2909		xmlHttp.send();
2910	}
2911}
2912
2913function updateDashboardDutyTotals(xmlHttp) {
2914	var xml = getXmlContent(xmlHttp);
2915	if(xml[3]) {
2916		num_totals = parseInt(getXmlField(xml[0], "num_limits"), 10);
2917		for(n=0; n<num_totals; n++) {
2918			dashboard_total_duty_titles[n] =					getXmlField(xml[0], "title_"+n);
2919			dashboard_total_duty_button_titles[n] =				getXmlField(xml[0], "button_title_"+n);
2920			dashboard_duty_totals[n] =							getXmlField(xml[0], "total_"+n);
2921			dashboard_provisional_duty_totals[n] =				getXmlField(xml[0], "prov_total_"+n);
2922			dashboard_total_duty_percentages[n] =				parseInt(getXmlField(xml[0], "percent_"+n), 10);
2923			dashboard_total_provisional_duty_percentages[n] =	parseInt(getXmlField(xml[0], "prov_percent_"+n), 10);
2924		}
2925		showDashboardDutyTotal(0, false);		// prevent infinite loop in case no duty limits configured
2926	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
2927	} else if(xml[0]) {
2928		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
2929			window.location.reload(true);			//will display login screen
2930		} else if(xml[0].toUpperCase() == "SUSPENDED") {
2931			showSubscriptionPopup(true);
2932		} else {
2933			dashboardErrorMessage(xml[0]);
2934		}
2935	}
2936}
2937
2938function loadDashboardTopTen() {
2939	var xmlHttp = createXMLHttpRequest();
2940	if(xmlHttp) {
2941		xmlHttp.onreadystatechange = function(){updateDashboardTopTen(xmlHttp);};
2942		xmlHttp.open("post", "/log/ajax/dashboardTopTen.php", true);
2943		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2944		xmlHttp.send();
2945	}
2946}
2947
2948function updateDashboardTopTen(xmlHttp) {
2949	var xml = getXmlContent(xmlHttp);
2950	if(xml[3]) {
2951		aircraft_content = getXmlField(xml[0], "aircraft_content");
2952		document.getElementById("dashboard_content_top_aircraft").innerHTML = aircraft_content;
2953		airports_content = getXmlField(xml[0], "airports_content");
2954		document.getElementById("dashboard_content_top_airports").innerHTML = airports_content;
2955	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
2956	} else if(xml[0]) {
2957		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
2958			window.location.reload(true);			//will display login screen
2959		} else if(xml[0].toUpperCase() == "SUSPENDED") {
2960			showSubscriptionPopup(true);
2961		} else {
2962			dashboardErrorMessage(xml[0]);
2963		}
2964	}
2965}
2966
2967function loadDashboardUsers(offset) {			//for users database screen
2968	if(!loading_logbook) {
2969		var xmlHttp = createXMLHttpRequest();
2970		if(xmlHttp) {
2971			if(offset == 0) {
2972				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", loadDashboardUsersCallback);};
2973			} else {
2974				loading_logbook = true;
2975				document.getElementById("load_more").innerHTML = "loading...";
2976				var override_order = true;
2977				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp, override_order);};
2978			}
2979			xmlHttp.open("post", "/log/ajax/dashboardUsers.php", true);
2980			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
2981			var data = "offset="+offset;
2982			xmlHttp.send(data);
2983		}
2984	}
2985}
2986
2987function loadDashboardUsersCallback(content, xmlHttp) {
2988	var xml = getXmlContent(xmlHttp);
2989	num_found = getXmlField(xml[0], "num_found");
2990	document.getElementById("num_users_title").innerHTML = "("+num_found+")";
2991	scrollLogbook();
2992}
2993
2994function loadDashboardNewUsers() {		//for 'pending trials' on dashboard screen
2995	var xmlHttp = createXMLHttpRequest();
2996	if(xmlHttp) {
2997		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_admin_users", loadDashboardNewUsersCallback);};
2998		xmlHttp.open("post", "/log/ajax/dashboardUsers.php", true);
2999		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3000		var data = "new=y";
3001		xmlHttp.send(data);
3002	}
3003}
3004
3005function loadDashboardNewUsersCallback(content, xmlHttp) {
3006	var section_class = "";
3007	if(content == "none") {
3008		section_class = "hidden";
3009	}
3010	document.getElementById("dashboard_container_col2_admin_users").className = section_class;
3011}
3012
3013function loadDashboardNewAircraft() {		//for 'unverified aircraft' on dashboard screen
3014	var xmlHttp = createXMLHttpRequest();
3015	if(xmlHttp) {
3016		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_admin_aircraft", loadDashboardNewAircraftCallback);};
3017		xmlHttp.open("post", "/log/ajax/dashboardAircraft.php", true);
3018		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3019		var data = "unverified=y";
3020		xmlHttp.send(data);
3021	}
3022}
3023
3024function loadDashboardNewAircraftCallback(content, xmlHttp) {
3025	var section_class = "";
3026	if(content == "none") {
3027		section_class = "hidden";
3028	}
3029	document.getElementById("dashboard_container_col2_admin_aircraft").className = section_class;
3030}
3031
3032function loadDashboardNewAirports() {		//for 'unverified airports' on dashboard screen
3033	var xmlHttp = createXMLHttpRequest();
3034	if(xmlHttp) {
3035		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_admin_airports", loadDashboardNewAirportsCallback);};
3036		xmlHttp.open("post", "/log/ajax/dashboardAirports.php", true);
3037		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3038		var data = "unverified=y";
3039		xmlHttp.send(data);
3040	}
3041}
3042
3043function loadDashboardNewAirportsCallback(content, xmlHttp) {
3044	var section_class = "";
3045	if(content == "none") {
3046		section_class = "hidden";
3047	}
3048	document.getElementById("dashboard_container_col2_admin_airports").className = section_class;
3049}
3050
3051function loadDashboardLogbook(offset) {
3052	if(!loading_logbook) {
3053		var xmlHttp = createXMLHttpRequest();
3054		if(xmlHttp) {
3055			if(offset == 0) {
3056				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3057			} else {
3058				loading_logbook = true;
3059				document.getElementById("load_more").innerHTML = "loading...";
3060				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp);};
3061			}
3062			xmlHttp.open("post", "/log/ajax/dashboardLogbook.php", true);
3063			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3064			var data = "offset="+offset;
3065			xmlHttp.send(data);
3066		}
3067	}
3068}
3069
3070function loadDashboardLogbookFlying(offset) {
3071	if(!loading_logbook) {
3072		var xmlHttp = createXMLHttpRequest();
3073		if(xmlHttp) {
3074			if(offset == 0) {
3075				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3076			} else {
3077				loading_logbook = true;
3078				document.getElementById("load_more").innerHTML = "loading...";
3079				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp);};
3080			}
3081			xmlHttp.open("post", "/log/ajax/dashboardLogbookFlights.php", true);
3082			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3083			var data = "offset="+offset;
3084			xmlHttp.send(data);
3085		}
3086	}
3087}
3088
3089function loadDashboardLogbookSim(offset) {
3090	if(!loading_logbook) {
3091		var xmlHttp = createXMLHttpRequest();
3092		if(xmlHttp) {
3093			if(offset == 0) {
3094				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3095			} else {
3096				loading_logbook = true;
3097				document.getElementById("load_more").innerHTML = "loading...";
3098				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp);};
3099			}
3100			xmlHttp.open("post", "/log/ajax/dashboardLogbookSims.php", true);
3101			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3102			var data = "offset="+offset;
3103			xmlHttp.send(data);
3104		}
3105	}
3106}
3107
3108function loadDashboardLogbookDuty(offset) {
3109	if(!loading_logbook) {
3110		var xmlHttp = createXMLHttpRequest();
3111		if(xmlHttp) {
3112			if(offset == 0) {
3113				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3114			} else {
3115				loading_logbook = true;
3116				document.getElementById("load_more").innerHTML = "loading...";
3117				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp);};
3118			}
3119			xmlHttp.open("post", "/log/ajax/dashboardLogbookDuties.php", true);
3120			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3121			var data = "offset="+offset;
3122			xmlHttp.send(data);
3123		}
3124	}
3125}
3126
3127function loadDashboardIncomplete(offset) {
3128	if(!loading_logbook) {
3129		var xmlHttp = createXMLHttpRequest();
3130		if(xmlHttp) {
3131			if(offset == 0) {
3132				document.getElementById("dashboard_content").innerHTML = loading_list;
3133				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3134			} else {
3135				loading_logbook = true;
3136				document.getElementById("load_more").innerHTML = "loading...";
3137				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp);};
3138			}
3139			xmlHttp.open("post", "/log/ajax/dashboardIncomplete.php", true);
3140			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3141			var data = "offset="+offset;
3142			xmlHttp.send(data);
3143		}
3144	}
3145}
3146
3147function loadDashboardProvisional(offset) {
3148	if(!loading_logbook) {
3149		var xmlHttp = createXMLHttpRequest();
3150		if(xmlHttp) {
3151			if(offset == 0) {
3152				document.getElementById("dashboard_content").innerHTML = loading_list;
3153				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3154			} else {
3155				loading_logbook = true;
3156				document.getElementById("load_more").innerHTML = "loading...";
3157				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp);};
3158			}
3159			xmlHttp.open("post", "/log/ajax/dashboardProvisional.php", true);
3160			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3161			var data = "offset="+offset;
3162			xmlHttp.send(data);
3163		}
3164	}
3165}
3166
3167function scrollLogbook(content, xmlHttp) {
3168	if(!scrollAndHighlightCell()) {
3169		var previous_scroll = document.getElementById("scroll_to");
3170		var scroll_offset = -1;
3171		if(previous_scroll) {
3172			scroll_offset = previous_scroll.value;
3173		}
3174		if(scroll_offset >= 0) {				//scroll to previously viewed position
3175			document.getElementById("dashboard_logbook_container").scrollTop = scroll_offset;
3176		} else {								//scroll to target element in list
3177			var element = document.getElementById("date_cell_target");
3178			if(element) {
3179				element.scrollIntoView({behavior:"auto", block:"center", inline:"center"});
3180			} else if(data_display_order == "ASC") {		//scroll to bottom only if in ascending order, otherwise most recent data is at top
3181				element = document.getElementById("bottom_of_logbook_page");
3182				if(element) {
3183					element.scrollIntoView({behavior:"auto", block:"center", inline:"center"});
3184				}
3185			}
3186		}
3187	}
3188}
3189
3190
3191function scrollUpcoming(content, xmlHttp) {
3192	if(scrollAndHighlightCell()) {
3193		//scroll
3194	} else if(data_display_order == "DESC") {		//scroll to bottom only if in descending order, otherwise next flight is at top
3195		element = document.getElementById("dashboard_content_upcoming");
3196		if(element) {
3197			element.scrollTop = element.scrollHeight;
3198		}
3199	}
3200}
3201
3202function scrollAndHighlightCell() {										// reference_id is id of HTML <input> tag with value of cell id to highlight
3203	var found = false;													// return whether we found a cell and scrolled or not
3204	var highlight_cell = document.getElementById("highlight_cell");
3205	if(highlight_cell) {												// scroll and highlight saved entry
3206		hl = highlight_cell.value;
3207		if(hl != "" && hl != last_log_highlight) {
3208			cell_to_highlight = document.getElementById(hl);
3209			if(cell_to_highlight) {
3210				found = true;
3211				last_log_highlight = hl;									// save id to avoid duplicate triggers
3212				window.setTimeout(function() {last_log_hightlight = "";}, 2000);	//reset after a couple of seconds for future refreshes
3213				setElementToHighlight("");									//clear highlight from server so that event only occurs once
3214				cell_to_highlight.scrollIntoView({behavior:"auto", block:"center", inline:"center"});
3215				cell_to_highlight.classList.add("dashboard_data_cell_highlight");
3216				var restore_background = function() {
3217					cell_to_highlight.classList.remove("dashboard_data_cell_highlight");
3218				};
3219				if(cell_to_highlight.classList.contains("dashboard_cell_background")) {		//remove then replace this explicit background class
3220					cell_to_highlight.classList.remove("dashboard_cell_background");
3221					restore_background = function() {
3222						cell_to_highlight.classList.add("dashboard_cell_background");
3223						cell_to_highlight.classList.remove("dashboard_data_cell_highlight");
3224					};
3225				} else if(cell_to_highlight.classList.contains("dashboard_data_cell_clear")) {		//remove then replace this explicit background class
3226					cell_to_highlight.classList.remove("dashboard_data_cell_clear");
3227					restore_background = function() {
3228						cell_to_highlight.classList.add("dashboard_data_cell_clear");
3229						cell_to_highlight.classList.remove("dashboard_data_cell_highlight");
3230					};
3231				}
3232				window.setTimeout(restore_background, 2000);
3233			}
3234		}
3235	}
3236	return found;
3237}
3238
3239function setElementToHighlight(element_id) {
3240	var xmlHttp = createXMLHttpRequest();
3241	if(xmlHttp) {
3242		//xmlHttp.onreadystatechange = function(){return true;};	//no need to handle response, assume success
3243		xmlHttp.open("post", "/log/ajax/saveHighlight.php", true);
3244		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3245		var data = "element_id=" + encodeURIComponent(element_id);
3246		xmlHttp.send(data);
3247	}
3248}
3249
3250function loadDashboardUpcoming() {
3251	var xmlHttp = createXMLHttpRequest();
3252	if(xmlHttp) {
3253		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_upcoming", scrollUpcoming);};
3254		xmlHttp.open("post", "/log/ajax/dashboardUpcoming.php", true);
3255		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3256		xmlHttp.send();
3257	}
3258}
3259
3260function loadDashboardUncompleted() {
3261	var xmlHttp = createXMLHttpRequest();
3262	if(xmlHttp) {
3263		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_uncompleted", showOrHideUncompleted);};
3264		xmlHttp.open("post", "/log/ajax/dashboardUncompleted.php", true);
3265		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3266		xmlHttp.send();
3267	}
3268}
3269
3270function showOrHideUncompleted(content, xmlHttp) {
3271	if(content == "") {
3272		className = "hidden";
3273	} else {
3274		var className = "";
3275	}
3276	document.getElementById("dashboard_container_col1_*").className = className;
3277	if(className == "") {
3278		if(!scrollAndHighlightCell()) {
3279			element = document.getElementById("dashboard_content_uncompleted");
3280			if(element && data_display_order == "ASC") {			//only scroll to bottom if in ascending order (most recent at bottom)
3281				element.scrollTop = element.scrollHeight;
3282			}
3283		}
3284	}
3285}
3286
3287function loadDashboardAircraft(offset) {
3288	if(!loading_logbook) {
3289		var xmlHttp = createXMLHttpRequest();
3290		if(xmlHttp) {
3291			if(offset == 0) {
3292				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3293			} else {
3294				loading_logbook = true;
3295				document.getElementById("load_more").innerHTML = "loading...";
3296				var override_order = true;
3297				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp, override_order);};
3298			}
3299			xmlHttp.open("post", "/log/ajax/dashboardAircraft.php", true);
3300			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3301			var data = "offset="+offset;
3302			xmlHttp.send(data);
3303		}
3304	}
3305}
3306
3307function loadDashboardAirports(offset) {
3308	if(!loading_logbook) {
3309		var xmlHttp = createXMLHttpRequest();
3310		if(xmlHttp) {
3311			if(offset == 0) {
3312				xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content", scrollLogbook);};
3313			} else {
3314				loading_logbook = true;
3315				document.getElementById("load_more").innerHTML = "loading...";
3316				var override_order = true;
3317				xmlHttp.onreadystatechange = function(){updateLogbookContent(xmlHttp, override_order);};
3318			}
3319			xmlHttp.open("post", "/log/ajax/dashboardAirports.php", true);
3320			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3321			var data = "offset="+offset;
3322			xmlHttp.send(data);
3323		}
3324	}
3325}
3326
3327function loadDashboardExpiries(expanded) {
3328	var xmlHttp = createXMLHttpRequest();
3329	if(xmlHttp) {
3330		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_expiries", scrollAndHighlightCell);};
3331		xmlHttp.open("post", "/log/ajax/dashboardExpiries.php", true);
3332		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3333		if(expanded) {
3334			var data = "expanded=y";
3335		} else {
3336			var data = "expanded=n"
3337		}
3338		xmlHttp.send(data);
3339	}
3340}
3341
3342function loadDashboardRecency(expanded) {
3343	var xmlHttp = createXMLHttpRequest();
3344	if(xmlHttp) {
3345		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_recency", scrollAndHighlightCell);};
3346		xmlHttp.open("post", "/log/ajax/dashboardRecency.php", true);
3347		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3348		if(expanded) {
3349			var data = "expanded=y";
3350		} else {
3351			var data = "expanded=n"
3352		}
3353		xmlHttp.send(data);
3354	}
3355}
3356
3357function loadDashboardMilestones(expanded) {
3358	var xmlHttp = createXMLHttpRequest();
3359	if(xmlHttp) {
3360		var callback = function() {
3361			scrollAndHighlightCell();
3362			drawDashboardMilestoneCharts();
3363		};
3364		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_content_milestones", callback);};
3365		xmlHttp.open("post", "/log/ajax/dashboardMilestones.php", true);
3366		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3367		if(expanded) {
3368			var data = "expanded=y";
3369		} else {
3370			var data = "expanded=n"
3371		}
3372		xmlHttp.send(data);
3373	}
3374}
3375
3376function loadDashboardMilestone(id, edit_child_id) {
3377	var xmlHttp = createXMLHttpRequest();
3378	if(xmlHttp) {
3379		var callback = function() {
3380			scrollAndHighlightCell();
3381			drawDashboardMilestoneCharts();
3382		};
3383		xmlHttp.onreadystatechange = function(){updateDashboardContent(xmlHttp, "dashboard_editing_page_container", callback);};
3384		xmlHttp.open("post", "/log/ajax/dashboardMilestone.php", true);
3385		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3386		var data  = "id="+id;
3387		data += "&edit_child_id=" + edit_child_id;
3388		xmlHttp.send(data);
3389	}
3390}
3391
3392function heartbeat() {
3393	var xmlHttp = createXMLHttpRequest();
3394	if(xmlHttp) {
3395		xmlHttp.onreadystatechange = function(){heartbeatResult(xmlHttp);};
3396		xmlHttp.open("post", "/log/ajax/heartbeat.php", true);
3397		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3398		xmlHttp.timeout = 3000;		//3 seconds
3399		xmlHttp.ontimeout = function() {window.setTimeout(heartbeat, 60000);};			//try again in 1 minute
3400		xmlHttp.onerror = function() {window.setTimeout(heartbeat, 60000);};			//try again in 1 minute
3401		xmlHttp.send();
3402	}
3403}
3404
3405function heartbeatResult(xmlHttp) {
3406	var xml = getXmlContent(xmlHttp);
3407	if(xml[3]) {
3408		window.setTimeout(heartbeat, 60000);		//check again in one minute
3409	} else if(xml[4] == 0) {						//HTTP error 0; request cancelled; ignore
3410	} else if(xml[0]) {
3411		//debug(xml[0].toUpperCase());
3412		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
3413			window.location.reload(true);			//will display login screen
3414		} else if(xml[0].toUpperCase() == "SUSPENDED") {
3415			showSubscriptionPopup(true);
3416		} else {
3417			dashboardErrorMessage(xml[0]);
3418		}
3419	}
3420}
3421
3422function updateDashboardContent(xmlHttp, element, callback) {
3423	var xml = getXmlContent(xmlHttp);
3424	if(xml[3]) {
3425		content = getXmlField(xml[0], "content");
3426		document.getElementById(element).innerHTML = content;
3427		if(callback) {
3428			callback(content, xmlHttp);
3429		}
3430	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
3431	} else if(xml[0]) {
3432		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
3433			window.location.reload(true);			//will display login screen
3434		} else if(xml[0].toUpperCase() == "SUSPENDED") {
3435			showSubscriptionPopup(true);
3436		} else {
3437			dashboardErrorMessage(xml[0]);
3438		}
3439	}
3440}
3441
3442function updateLogbookContent(xmlHttp, override_order) {
3443	var xml = getXmlContent(xmlHttp);
3444	if(xml[3]) {
3445		loading_logbook = false;
3446		element = document.getElementById("dashboard_content");
3447		var initial_height = element.clientHeight;
3448		//var new_top = window.scrollY;
3449		document.getElementById("load_more").remove();
3450		content = getXmlField(xml[0], "content");
3451		if(data_display_order == "ASC" && !override_order) {
3452			element.innerHTML = content + element.innerHTML;
3453			removeDuplicateDates();
3454			var new_height = element.clientHeight;
3455			var new_top = new_height - initial_height;
3456			document.getElementById("dashboard_logbook_container").scrollTop = new_top;
3457		} else {
3458			element.innerHTML = element.innerHTML + content;
3459			removeDuplicateDates();
3460		}
3461	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
3462	} else if(xml[0]) {
3463		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
3464			window.location.reload(true);			//will display login screen
3465		} else if(xml[0].toUpperCase() == "SUSPENDED") {
3466			showSubscriptionPopup(true);
3467		} else {
3468			loading_logbook = false;
3469			document.getElementById("load_more").innerHTML = "load more...";
3470			dashboardErrorMessage(xml[0]);
3471		}
3472	}
3473}
3474
3475function removeDuplicateDates() {
3476	var date_elements = Array.from(document.querySelectorAll('[id^="date_cell_"]'));
3477	var num_elements = date_elements.length;
3478	for(n=0; n<(num_elements-1); n++) {
3479		if(date_elements[n].innerHTML == date_elements[n+1].innerHTML) {
3480			date_elements[n+1].remove();
3481			break;
3482		}
3483	}
3484}
3485
3486function dashboardShowConfigure() {
3487	dashboard_config_section_order = document.getElementById('dashboard_config_order').value;
3488	dashboardBodyClicked();
3489	window.setTimeout(function() {elementFadeIn(document.getElementById("configure_dashboard"));}, 5);
3490}
3491
3492function configureDashboardShowSection(section, index) {
3493	document.getElementById('configure_dashboard_show_button_'+section.toUpperCase()).className = "dashboard_show_hide_button dashboard_show_hide_button_active";
3494	document.getElementById('configure_dashboard_hide_button_'+section.toUpperCase()).className = "dashboard_show_hide_button";
3495	pos = dashboard_config_section_order.toUpperCase().indexOf(section.toUpperCase());
3496	col = dashboard_config_section_order.indexOf("^");
3497	s0 = dashboard_config_section_order.substring(0, pos);
3498	s1 = dashboard_config_section_order.charAt(pos).toUpperCase();
3499	s2 = dashboard_config_section_order.substring(pos+1);
3500	dashboard_config_section_order = s0 + s1 + s2;
3501	document.getElementById('dashboard_config_order').value = dashboard_config_section_order;
3502	if(pos < col) {
3503		id = "dashboard_container_col1_"+pos;
3504	} else {
3505		id = "dashboard_container_col2_"+(pos-(col+1));
3506	}
3507	document.getElementById(id).className = "";
3508	saveDashboardConfig();
3509	if(section == "J") {
3510		loadDashboardMapData();
3511	}
3512}
3513
3514
3515function configureDashboardHideSection(section, index) {
3516	document.getElementById('configure_dashboard_show_button_'+section.toUpperCase()).className = "dashboard_show_hide_button";
3517	document.getElementById('configure_dashboard_hide_button_'+section.toUpperCase()).className = "dashboard_show_hide_button dashboard_show_hide_button_active";
3518	pos = dashboard_config_section_order.toUpperCase().indexOf(section.toUpperCase());
3519	col = dashboard_config_section_order.indexOf("^");
3520	s0 = dashboard_config_section_order.substring(0, pos);
3521	s1 = dashboard_config_section_order.charAt(pos).toLowerCase();
3522	s2 = dashboard_config_section_order.substring(pos+1);
3523	dashboard_config_section_order = s0 + s1 + s2;
3524	document.getElementById('dashboard_config_order').value = dashboard_config_section_order;
3525	if(pos < col) {
3526		id = "dashboard_container_col1_"+pos;
3527	} else {
3528		id = "dashboard_container_col2_"+(pos-(col+1));
3529	}
3530	document.getElementById(id).className = "hidden";
3531	saveDashboardConfig();
3532}
3533
3534function setDashboardVisibility() {
3535	index = 0;
3536	col = 1;
3537	for(pos=0; pos<dashboard_config_section_order.length; pos++) {
3538		ch = dashboard_config_section_order.charAt(pos);
3539		if(ch == "^") {
3540			index = 0;
3541			col = 2;
3542		} else if(ch == "*") {
3543			index++;
3544			continue;				//no user control over Uncompleted Flights
3545		} else {
3546			if(ch == ch.toUpperCase()) {
3547				document.getElementById("dashboard_container_col"+col+"_"+index).className = "";
3548			} else {
3549				document.getElementById("dashboard_container_col"+col+"_"+index).className = "hidden";
3550			}
3551			index++;
3552		}
3553	}
3554}
3555
3556function setDashboardTotalsVisibility() {
3557	var index = 0;
3558	var totals = dashboard_config_totals_order.split("^");
3559	for(pos=0; pos<totals.length; pos++) {
3560		if(totals[pos] == totals[pos].toUpperCase()) {
3561			document.getElementById("dashboard_totals_container_"+index).className = "";
3562		} else {
3563			document.getElementById("dashboard_totals_container_"+index).className = "hidden";
3564		}
3565		index++;
3566	}
3567}
3568
3569function configureDashboardMoveUp(index) {
3570	if(index > 0) {
3571		col = dashboard_config_section_order.indexOf("^");
3572		if(col == index) {				//moving column divider up; bottom of col1 goes to top of col2
3573			//move all col2 sections down one place
3574			numSections = dashboard_config_section_order.length - 1;
3575			numCol2Sections = numSections - col;
3576			for(s=numCol2Sections-1; s>=0; s--) {
3577				from_id = "dashboard_container_col2_" + s;
3578				to_id = "dashboard_container_col2_" + (s + 1);
3579				swapElements(from_id, to_id);
3580			}
3581			//move element at bottom of col1, to top of col2
3582			from_id = "dashboard_container_col1_" + (col - 1);
3583			to_id = "dashboard_container_col2_0";
3584			swapElements(from_id, to_id);
3585		} else if(col == index - 1) {		//moving section above column divider, move to bottom of col1
3586			//move element at top of col2, to bottom of col1
3587			from_id = "dashboard_container_col2_0";
3588			to_id = "dashboard_container_col1_" + col;
3589			swapElements(from_id, to_id);
3590			//move all col2 sections up one place
3591			numSections = dashboard_config_section_order.length - 1;
3592			numCol2Sections = numSections - col;
3593			for(s=1; s<numCol2Sections; s++) {
3594				from_id = "dashboard_container_col2_" + s;
3595				to_id = "dashboard_container_col2_" + (s - 1);
3596				swapElements(from_id, to_id);
3597			}
3598		} else {					//moving within column
3599			if(index < col) {
3600				from_id = "dashboard_container_col1_" + index;
3601				to_id = "dashboard_container_col1_" + (index - 1);
3602			} else {
3603				from_id = "dashboard_container_col2_" + (index - (col + 1));
3604				to_id = "dashboard_container_col2_" + ((index - (col + 1)) - 1);
3605			}
3606			swapElements(from_id, to_id);
3607		}
3608		//move elements in configuration list
3609		temp = document.getElementById("configure_dashboard_"+(index-1)).innerHTML;
3610		document.getElementById("configure_dashboard_"+(index-1)).innerHTML = document.getElementById("configure_dashboard_"+index).innerHTML;
3611		document.getElementById("configure_dashboard_"+index).innerHTML = temp;
3612		//adjust configuration code string
3613		s0 = dashboard_config_section_order.substring(0, index-1);
3614		s1 = dashboard_config_section_order.charAt(index-1);
3615		s2 = dashboard_config_section_order.charAt(index);
3616		s3 = dashboard_config_section_order.substring(index+1);
3617		dashboard_config_section_order = s0 + s2 + s1 + s3;
3618		document.getElementById('dashboard_config_order').value = dashboard_config_section_order;
3619		showDashboardTotal(current_dashboard_total_tab);			//redraw circles
3620		drawDashboardMilestoneCharts();
3621		setDashboardVisibility();
3622		saveDashboardConfig();
3623	}
3624}
3625
3626function configureDashboardMoveDown(index) {
3627	if(index < dashboard_config_section_order.length - 1) {
3628		col = dashboard_config_section_order.indexOf("^");
3629		if(col == index) {			//moving column divider down; top of col2 goes to bottom of col1
3630			//move element at top of col2, to bottom of col1
3631			from_id = "dashboard_container_col2_0";
3632			to_id = "dashboard_container_col1_" + col;
3633			swapElements(from_id, to_id);
3634			//move all col2 sections up one place
3635			numSections = dashboard_config_section_order.length - 1;
3636			numCol2Sections = numSections - col;
3637			for(s=1; s<numCol2Sections; s++) {
3638				from_id = "dashboard_container_col2_" + s;
3639				to_id = "dashboard_container_col2_" + (s - 1);
3640				swapElements(from_id, to_id);
3641			}
3642		} else if(col == index + 1) {	//moving section below column divider, move bottom of col1 to top of col2
3643			//move all col2 sections down one place
3644			numSections = dashboard_config_section_order.length - 1;
3645			numCol2Sections = numSections - col;
3646			for(s=numCol2Sections-1; s>=0; s--) {
3647				from_id = "dashboard_container_col2_" + s;
3648				to_id = "dashboard_container_col2_" + (s + 1);
3649				swapElements(from_id, to_id);
3650			}
3651			//move element at bottom of col1, to top of col2
3652			from_id = "dashboard_container_col1_" + (col - 1);
3653			to_id = "dashboard_container_col2_0";
3654			swapElements(from_id, to_id);
3655		} else {					//moving within column
3656			if(index < col) {
3657				from_id = "dashboard_container_col1_" + index;
3658				to_id = "dashboard_container_col1_" + (index + 1);
3659			} else {
3660				from_id = "dashboard_container_col2_" + (index - (col + 1));
3661				to_id = "dashboard_container_col2_" + ((index - (col + 1)) + 1);
3662			}
3663			swapElements(from_id, to_id);
3664		}
3665		//move elements in configuration list
3666		from_id = "configure_dashboard_" + (index + 1);
3667		to_id = "configure_dashboard_" + index;
3668		swapElements(from_id, to_id);
3669		//adjust configuration code string
3670		s0 = dashboard_config_section_order.substring(0, index);
3671		s1 = dashboard_config_section_order.charAt(index);
3672		s2 = dashboard_config_section_order.charAt(index+1);
3673		s3 = dashboard_config_section_order.substring(index+2);
3674		dashboard_config_section_order = s0 + s2 + s1 + s3;
3675		document.getElementById('dashboard_config_order').value = dashboard_config_section_order;
3676		showDashboardTotal(current_dashboard_total_tab);			//redraw circles
3677		drawDashboardMilestoneCharts();
3678		setDashboardVisibility();
3679		saveDashboardConfig();
3680	}
3681}
3682
3683function configureDashboardTotalsMoveUp(index) {
3684	if(index > 0) {
3685		from_id = "dashboard_totals_container_" + index;
3686		to_id = "dashboard_totals_container_" + (index - 1);
3687		swapElements(from_id, to_id);
3688		//move elements in configuration list
3689		from_id = "configure_dashboard_totals_" + (index - 1);
3690		to_id = "configure_dashboard_totals_" + index;
3691		swapElements(from_id, to_id);
3692		//adjust configuration code string
3693		var totals = dashboard_config_totals_order.split("^");
3694		var temp = totals[index];
3695		totals[index] = totals[index - 1];
3696		totals[index - 1] = temp;
3697		dashboard_config_totals_order = totals.join("^");
3698		//s0 = dashboard_config_totals_order.substring(0, index-1);
3699		//s1 = dashboard_config_totals_order.charAt(index-1);
3700		//s2 = dashboard_config_totals_order.charAt(index);
3701		//s3 = dashboard_config_totals_order.substring(index+1);
3702		//dashboard_config_totals_order = s0 + s2 + s1 + s3;
3703		document.getElementById('dashboard_config_totals_order').value = dashboard_config_totals_order;
3704		setDashboardTotalsVisibility();
3705		saveDashboardConfig();
3706	}
3707}
3708
3709function configureDashboardTotalsMoveDown(index) {
3710	debug(dashboard_config_totals_order);
3711	var totals = dashboard_config_totals_order.split("^");
3712	//if(index < dashboard_config_totals_order.length - 1) {
3713	if(index < totals.length - 1) {
3714		from_id = "dashboard_totals_container_" + index;
3715		to_id = "dashboard_totals_container_" + (index + 1);
3716		swapElements(from_id, to_id);
3717		//move elements in configuration list
3718		from_id = "configure_dashboard_totals_" + (index + 1);
3719		to_id = "configure_dashboard_totals_" + index;
3720		swapElements(from_id, to_id);
3721		//adjust configuration code string
3722		var temp = totals[index];
3723		totals[index] = totals[index + 1];
3724		totals[index + 1] = temp;
3725		dashboard_config_totals_order = totals.join("^");
3726		//s0 = dashboard_config_totals_order.substring(0, index);
3727		//s1 = dashboard_config_totals_order.charAt(index);
3728		//s2 = dashboard_config_totals_order.charAt(index+1);
3729		//s3 = dashboard_config_totals_order.substring(index+2);
3730		//dashboard_config_totals_order = s0 + s2 + s1 + s3;
3731		document.getElementById('dashboard_config_totals_order').value = dashboard_config_totals_order;
3732		setDashboardTotalsVisibility();
3733		saveDashboardConfig();
3734	}
3735}
3736
3737function swapElements(id1, id2) {
3738	temp = document.getElementById(id1).innerHTML;
3739	document.getElementById(id1).innerHTML = document.getElementById(id2).innerHTML;
3740	document.getElementById(id2).innerHTML = temp;
3741}
3742
3743function saveDashboardConfig() {
3744	var xmlHttp = createXMLHttpRequest();
3745	if(xmlHttp) {
3746		xmlHttp.onreadystatechange = function(){saveDashboardConfigResult(xmlHttp);};
3747		xmlHttp.open("post", "/log/ajax/saveDashboardConfig.php", true);
3748		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
3749		var data = "layout=" + encodeURIComponent(document.getElementById('dashboard_config_order').value);
3750		data += "&totals="+encodeURIComponent(document.getElementById('dashboard_config_totals_order').value);
3751		xmlHttp.send(data);
3752	}
3753}
3754
3755function saveDashboardConfigResult(xmlHttp, callback) {
3756	var xml = getXmlContent(xmlHttp);
3757	if(xml[3]) {				//received with no errors
3758		if(callback) {
3759			callback();
3760		}
3761	} else if(xml[4] == 0) {	//HTTP error 0; request cancelled; ignore
3762	} else if(xml[0]) {			//received with error
3763		dashboardErrorMessage(xml[0]);
3764	}
3765}
3766
3767function dashboardToggleCustomiseTotals() {
3768	var menu = document.getElementById('configure_dashboard_totals');
3769	if(menu.className == "hidden_animated" || menu.className == "hidden") {
3770		dashboardShowCustomiseTotals();
3771	} else {
3772		elementFadeOut(menu);
3773	}
3774}
3775
3776function dashboardShowCustomiseTotals() {
3777	dashboard_config_totals_order = document.getElementById('dashboard_config_totals_order').value;
3778	dashboardBodyClicked();
3779	//document.getElementById("configure_dashboard_totals").className = "";
3780	elementFadeIn(document.getElementById("configure_dashboard_totals"));
3781}
3782
3783function configureDashboardShowTotalsSection(section, index) {
3784	document.getElementById('configure_dashboard_totals_show_button_'+section.toUpperCase()).className = "dashboard_show_hide_button dashboard_show_hide_button_active";
3785	document.getElementById('configure_dashboard_totals_hide_button_'+section.toUpperCase()).className = "dashboard_show_hide_button";
3786	var totals = dashboard_config_totals_order.split("^");
3787	var pos = -1;
3788	for(n=0; n<totals.length; n++) {
3789		if(totals[n].toUpperCase() == section.toUpperCase()) {
3790			totals[n] = section.toUpperCase();
3791			pos = n;
3792			break;
3793		}
3794	}
3795	dashboard_config_totals_order = totals.join("^");
3796	//pos = dashboard_config_totals_order.toUpperCase().indexOf(section.toUpperCase());
3797	//s0 = dashboard_config_totals_order.substring(0, pos);
3798	//s1 = dashboard_config_totals_order.charAt(pos).toUpperCase();
3799	//s2 = dashboard_config_totals_order.substring(pos+1);
3800	//dashboard_config_totals_order = s0 + s1 + s2;
3801	document.getElementById('dashboard_config_totals_order').value = dashboard_config_totals_order;
3802	document.getElementById("dashboard_totals_container_"+pos).className = "";
3803	saveDashboardConfig();
3804}
3805
3806
3807function configureDashboardHideTotalsSection(section, index) {
3808	document.getElementById('configure_dashboard_totals_show_button_'+section.toUpperCase()).className = "dashboard_show_hide_button";
3809	document.getElementById('configure_dashboard_totals_hide_button_'+section.toUpperCase()).className = "dashboard_show_hide_button dashboard_show_hide_button_active";
3810	var totals = dashboard_config_totals_order.split("^");
3811	var pos = -1;
3812	for(n=0; n<totals.length; n++) {
3813		if(totals[n].toUpperCase() == section.toUpperCase()) {
3814			totals[n] = section.toLowerCase();
3815			pos = n;
3816			break;
3817		}
3818	}
3819	dashboard_config_totals_order = totals.join("^");
3820	//pos = dashboard_config_totals_order.toUpperCase().indexOf(section.toUpperCase());
3821	//s0 = dashboard_config_totals_order.substring(0, pos);
3822	//s1 = dashboard_config_totals_order.charAt(pos).toLowerCase();
3823	//s2 = dashboard_config_totals_order.substring(pos+1);
3824	//dashboard_config_totals_order = s0 + s1 + s2;
3825	document.getElementById('dashboard_config_totals_order').value = dashboard_config_totals_order;
3826	document.getElementById("dashboard_totals_container_"+pos).className = "hidden";
3827	saveDashboardConfig();
3828}
3829
3830function dashboardShowNotifications() {
3831	dashboard_confirm("Notifications", notification_message, "OK", false, false);
3832
3833}
3834
3835function dashboardTouchStart(e) {
3836	e.preventDefault();
3837	var touchLocation = e.targetTouches[0];
3838	drag_start_x = touchLocation.clientX;
3839	drag_start_y = touchLocation.clientY;
3840	dashboardUniversalMoveStart(e);
3841}
3842
3843function dashboardMouseStart(e) {
3844	e.preventDefault();
3845	drag_start_x = e.screenX;
3846	drag_start_y = e.screenY;
3847	dashboardUniversalMoveStart(e);
3848}
3849
3850function dashboardTouchMove(e) {
3851	if(dragging_element_index >= 0) {
3852		e.preventDefault();
3853		var touchLocation = e.targetTouches[0];
3854		var x = touchLocation.clientX;
3855		var y = touchLocation.clientY;
3856		dashboardUniversalMove(x, y);
3857	}
3858}
3859
3860function dashboardMouseMove(e) {
3861	if(dragging_element_index >= 0) {
3862		e.preventDefault();
3863		var x = e.screenX;
3864		var y = e.screenY;
3865		dashboardUniversalMove(x, y);
3866	}
3867}
3868
3869function dashboardUniversalMoveStart(e) {
3870	if(e.target.id.indexOf("total") > 0) {
3871		drag_context = "totals";
3872	} else if(e.target.id.indexOf("alert") > 0) {
3873		drag_context = "alert";
3874	} else {
3875		drag_context = "config";
3876	}
3877	drag_last_x = drag_start_x;
3878	drag_last_y = drag_start_y;
3879	if(drag_context == "totals") {
3880		drag_position_x = e.target.parentElement.offsetLeft;
3881		drag_position_y = e.target.parentElement.offsetTop;
3882		dragging_element_index = parseInt(e.target.id.substring(e.target.id.lastIndexOf("_")+1), 10);
3883		dragging_element_height = document.getElementById('configure_dashboard_totals_container_1').offsetTop - document.getElementById('configure_dashboard_totals_container_0').offsetTop;
3884		copy = new String(document.getElementById("configure_dashboard_totals_"+dragging_element_index).innerHTML);
3885		document.getElementById("dashboard_configure_totals_drag_box").innerHTML = document.getElementById("configure_dashboard_totals_"+dragging_element_index).innerHTML;
3886		document.getElementById("dashboard_configure_totals_drag_box").className = "dashboard_configure_item dashboard_configure_item_drag";
3887		document.getElementById("dashboard_configure_totals_drag_box").style.top = drag_position_y+"px";
3888	} else if(drag_context == "config") {
3889		drag_position_x = e.target.parentElement.offsetLeft;
3890		drag_position_y = e.target.parentElement.offsetTop;
3891		dragging_element_index = parseInt(e.target.id.substring(e.target.id.lastIndexOf("_")+1), 10);
3892		dragging_element_height = document.getElementById('configure_dashboard_container_1').offsetTop - document.getElementById('configure_dashboard_container_0').offsetTop;
3893		copy = new String(document.getElementById("configure_dashboard_"+dragging_element_index).innerHTML);
3894		document.getElementById("dashboard_configure_drag_box").innerHTML = document.getElementById("configure_dashboard_"+dragging_element_index).innerHTML;
3895		document.getElementById("dashboard_configure_drag_box").className = "dashboard_configure_item dashboard_configure_item_drag";
3896		document.getElementById("dashboard_configure_drag_box").style.top = drag_position_y+"px";
3897	} else if(drag_context == "alert") {
3898		dragging_element_index = 1;
3899		drag_position_x = document.getElementById("dashboard_alert_body").offsetLeft;
3900		drag_position_y = document.getElementById("dashboard_alert_body").offsetTop;
3901		document.getElementById("dashboard_alert_body").style.left = drag_position_x+"px";
3902		document.getElementById("dashboard_alert_body").style.top = drag_position_y+"px";
3903	}
3904}
3905
3906function dashboardUniversalMove(x, y) {
3907	var adjust_x = x - drag_last_x;
3908	var adjust_y = y - drag_last_y;
3909	drag_last_x = x;
3910	drag_last_y = y;
3911	drag_position_x += adjust_x;
3912	drag_position_y += adjust_y;
3913	if(drag_context == "totals") {
3914		document.getElementById("dashboard_configure_totals_drag_box").style.top = drag_position_y+"px";
3915	} else if(drag_context == "config") {
3916		document.getElementById("dashboard_configure_drag_box").style.top = drag_position_y+"px";
3917	} else if(drag_context == "alert") {
3918		document.getElementById("dashboard_alert_body").style.left = drag_position_x+"px";
3919		document.getElementById("dashboard_alert_body").style.top = drag_position_y+"px";
3920	}
3921	if(drag_context == "totals" || drag_context == "config") {
3922		var moved = y - drag_start_y;
3923		if(moved >= dragging_element_height / 2) {
3924			if(drag_context == "totals") {
3925				configureDashboardTotalsMoveDown(dragging_element_index);
3926			} else if(drag_context == "config") {
3927				configureDashboardMoveDown(dragging_element_index);
3928			}
3929			drag_start_y += dragging_element_height;
3930			dragging_element_index++;
3931		}
3932		if(moved <= -dragging_element_height / 2) {
3933			inhibit = false;
3934			if(drag_context == "totals") {
3935				if(dragging_element_index == 0) {
3936					inhibit = true;
3937				} else {
3938					configureDashboardTotalsMoveUp(dragging_element_index);
3939				}
3940			} else if(drag_context == "config") {
3941				if(dragging_element_index == 0) {
3942					inhibit = true;
3943				} else {
3944					configureDashboardMoveUp(dragging_element_index);
3945				}
3946			}
3947			if(!inhibit) {
3948				drag_start_y -= dragging_element_height;
3949				dragging_element_index--;
3950			}
3951		}
3952	}
3953}
3954
3955function dashboardUniversalMoveEnd(e) {
3956	if(drag_context == "config") {
3957		document.getElementById("dashboard_configure_drag_box").innerHTML = "";
3958		document.getElementById("dashboard_configure_drag_box").className = "hidden";
3959	} else if(drag_context == "totals") {
3960		document.getElementById("dashboard_configure_totals_drag_box").innerHTML = "";
3961		document.getElementById("dashboard_configure_totals_drag_box").className = "hidden";
3962	} else if(drag_context == "alert") {
3963	} else {
3964	}
3965	drag_context = "";
3966	dragging_element_index = -1;
3967}
3968
3969function dashboardAlertMessage(title, message) {
3970	dashboard_confirm(title, message, "OK", false, false, false)
3971}
3972
3973function dashboardErrorMessage(message) {
3974	dashboard_confirm("Error", message, "OK", false, false, false)
3975}
3976
3977function dashboard_confirm(title, message, ok, cancel, ok_callback, cancel_callback) {
3978	alert_ok_callback = ok_callback;
3979	alert_cancel_callback = cancel_callback;
3980	message = (message + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1<br />$2');
3981	document.getElementById("dashboard_alert_title").innerHTML = title;
3982	document.getElementById("dashboard_alert_message").innerHTML = message;
3983	document.getElementById("dashboard_alert_button_ok").innerHTML = ok;
3984	document.getElementById("dashboard_alert_button_cancel").innerHTML = cancel;
3985	if(cancel == "") {
3986		document.getElementById("dashboard_alert_button_cancel").className = "hidden";
3987	} else {
3988		document.getElementById("dashboard_alert_button_cancel").className = "";
3989	}
3990	document.getElementById("dashboard_alert").className = "dashboard_alert_visible";
3991}
3992
3993function dashboard_modal_message(message, allow_hide) {
3994	allow_hide_message = allow_hide;
3995	document.getElementById("dashboard_message_body").style.top = null;		//reset to auto-size
3996	document.getElementById("dashboard_message_body").style.bottom = null;
3997	document.getElementById("dashboard_message_message").innerHTML = message;
3998	document.getElementById("dashboard_message").className = "dashboard_alert_visible";
3999}
4000
4001function dashboard_hide_modal_message() {
4002	if(allow_hide_message) {
4003		dashboard_clear_modal_message();
4004	}
4005}
4006
4007function dashboard_clear_modal_message() {
4008	document.getElementById("dashboard_message_message").innerHTML = "";
4009	document.getElementById("dashboard_message").className = "hidden";
4010}
4011
4012function dashboard_alert_cancel() {
4013	alert_ok_callback = false;
4014	if(alert_cancel_callback) {
4015		alert_cancel_callback();
4016		alert_cancel_callback = false;
4017	}
4018	document.getElementById("dashboard_alert").className = "hidden";
4019}
4020
4021function dashboard_alert_ok() {
4022	alert_cancel_callback = false;
4023	if(alert_ok_callback) {
4024		alert_ok_callback();
4025		alert_ok_callback = false;
4026	}
4027	document.getElementById("dashboard_alert").className = "hidden";
4028}
4029
4030function quickHideOverlay(id) {
4031	if(!confirm_discard_changes_overlay) {
4032		document.getElementById(id).className = "hidden";
4033	}
4034}
4035
4036function dashboardBack(no_confirm) {
4037	if(no_confirm) {
4038		confirm_discard_changes = false;
4039	}
4040	if(confirm_discard_changes) {
4041		alert_context = "discard";
4042		dashboard_confirm("Discard Changes", "Are you sure that you want to discard your changes?", "Discard", "No", function() {dashboardBack(true);}, false);
4043	} else {
4044		window.history.back();
4045	}
4046}
4047
4048function dashboardBackOverlay(id, no_confirm) {
4049	if(no_confirm) {
4050		confirm_discard_changes_overlay = false;
4051	}
4052	if(confirm_discard_changes_overlay) {
4053		alert_context = "discard";
4054		dashboard_confirm("Discard Changes", "Are you sure that you want to discard your changes?", "Discard", "No", function() {dashboardBackOverlay(id, true);}, false);
4055	} else {
4056		document.getElementById(id).className = 'hidden';
4057	}
4058}
4059
4060function dashboardForceReload() {
4061	confirm_discard_changes = false;
4062	confirm_discard_changes_overlay = false;
4063	window.location.reload(true);
4064}
4065
4066function dashboardYesNoButtonClicked(id, value, check_function, class_suffix) {
4067	if(!editing_locked && document.getElementById(id+"_disabled").value == "n") {
4068		setYesNoButton(id, value, class_suffix);
4069		if(check_function) {
4070			check_function();
4071		}
4072	}
4073}
4074
4075function setYesNoButton(id, value, class_suffix) {
4076	// no check for disabled or locked. Call this function directly to force an automatic setting change e.g. after validation
4077	if(!class_suffix) {
4078		class_suffix = "";
4079	}
4080	document.getElementById(id).value = value;
4081	values = document.getElementById(id+"_values").value.split("_");
4082	for(n=0; n<values.length; n++) {
4083		document.getElementById(id+"_"+values[n]).className = "dashboard_input_button" + class_suffix;
4084	}
4085	document.getElementById(id+"_"+value).className = "dashboard_input_button" + class_suffix + " dashboard_input_button_selected";
4086	if(document.getElementById(id+"_disabled").value == "y") {		//re-apply disabled styling if required
4087		dashboardYesNoButtonDisabled(id, "y", class_suffix);
4088	}
4089}
4090
4091function dashboardYesNoButtonDisabled(id, disabled, class_suffix) {		//disabled = true, false, "disabled" or ""
4092	if(!class_suffix) {
4093		class_suffix = "";
4094	}
4095	if(disabled === true || disabled === "disabled" || disabled === "y") {
4096		disabled = "y";
4097		class_disabled = " dashboard_input_button_disabled";
4098		class_selected_disabled = " dashboard_input_button_selected_disabled";
4099		document.getElementById(id+"_container").classList.add("dashboard_input_buttons_disabled");
4100	} else {
4101		disabled = "n";
4102		class_disabled = "";
4103		class_selected_disabled = "";
4104		document.getElementById(id+"_container").classList.remove("dashboard_input_buttons_disabled");
4105	}
4106	document.getElementById(id+"_disabled").value = disabled;
4107	current_value = document.getElementById(id).value;
4108	values = document.getElementById(id+"_values").value.split("_");
4109	for(n=0; n<values.length; n++) {
4110		document.getElementById(id+"_"+values[n]).className = "dashboard_input_button" + class_suffix + class_disabled;
4111	}
4112	document.getElementById(id+"_"+current_value).className = "dashboard_input_button" + class_suffix + class_disabled + " dashboard_input_button_selected" + class_selected_disabled;
4113}
4114
4115function dashboardSaveFlight(validate_only, override_warnings) {
4116	if(!override_warnings) {
4117		override_warnings = "n";
4118	}
4119	var check_warnings = "flight";
4120	var callback = false;
4121	var cleanup_callback = false;
4122	if(validate_only == "y") {
4123		cleanup_callback = function() {dashboardCheckForChanges(getFlightFields());};		//check again after updating hours fields
4124	}
4125	var url = "saveFlight";
4126	last_log_highlight = "";		//enable highlight for next load, even if using same cell id
4127	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getFlightFields(), callback, cleanup_callback);
4128}
4129
4130function dashboardSaveSim(validate_only, override_warnings) {
4131	if(!override_warnings) {
4132		override_warnings = "n";
4133	}
4134	var check_warnings = false;
4135	var callback = false;
4136	var cleanup_callback = false;
4137	var url = "saveSim";
4138	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getSimFields(), callback, cleanup_callback);
4139}
4140
4141function dashboardSaveDuty(validate_only, override_warnings) {
4142	if(!override_warnings) {
4143		override_warnings = "n";
4144	}
4145	var check_warnings = "duty";
4146	var callback = false;
4147	var cleanup_callback = false;
4148	var url = "saveDuty";
4149	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getDutyFields(), callback, cleanup_callback);
4150}
4151
4152function dashboardSaveAircraft(validate_only, cleanup_callback) {
4153	var override_warnings = "n";
4154	var check_warnings = "aircraft";
4155	var callback = false;
4156	var url = "saveAircraft";
4157	//aircraft are edited on the parent page, so refresh alert bell after saving to update unverified number
4158	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getAircraftFields(), callback, cleanup_callback, true);
4159}
4160
4161function dashboardSaveAirport(validate_only, cleanup_callback) {
4162	var override_warnings = "n";
4163	var check_warnings = "airport";
4164	var callback = false;
4165	var url = "saveAirport";
4166	//airports are edited on the parent page, so refresh alert bell after saving to update unverified number
4167	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getAirportFields(), callback, cleanup_callback, true);
4168}
4169
4170function dashboardSaveExpiry(validate_only) {
4171	var check_warnings = false;
4172	var override_warnings = "n";
4173	var callback = false;
4174	var url = "saveExpiry";
4175	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getExpiryFields(), callback);
4176}
4177
4178function dashboardSaveRecency(validate_only, standalone) {
4179	var check_warnings;
4180	var override_warnings = "n";
4181	var callback = false;
4182	var cleanup_callback = false;
4183	if(standalone) {
4184		check_warnings = "settings_standalone";
4185		cleanup_callback = function() {window.location.replace("recency.php");};
4186	} else {
4187		check_warnings = false;
4188		cleanup_callback = false;
4189	}
4190	var url = "saveRecencyRequirement";
4191	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getRecencyFields(), callback, cleanup_callback);
4192}
4193
4194function dashboardSaveUser(validate_only) {
4195	var check_warnings = false;
4196	var override_warnings = "n";
4197	var callback = false;
4198	var url = "saveUser";
4199	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getUserFields(), callback);
4200}
4201
4202function dashboardSaveSettings(validate_only, standalone) {
4203	var check_warnings;
4204	var override_warnings = "n";
4205	var callback = false;
4206	var cleanup_callback;
4207	if(standalone) {
4208		check_warnings = "settings_standalone";
4209		cleanup_callback = function() {window.location.replace("index.php");};
4210	} else {
4211		check_warnings = false;
4212		cleanup_callback = false;
4213	}
4214	var url = "saveSettings";
4215	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getSettingsFields(), callback, cleanup_callback);
4216}
4217
4218function dashboardSavePrevious(validate_only) {
4219	var check_warnings = false;
4220	var callback = false;
4221	var override_warnings = "n";
4222	var url = "savePreviousHours";
4223	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getPrevFields(), callback);
4224}
4225
4226function dashboardSaveModifyIncomplete(validate_only) {
4227	var check_warnings = "modify_incomplete";
4228	var override_warnings = "n";
4229	var callback = false;
4230	var cleanup_callback = false;
4231	var refresh_alerts = false;
4232	if(validate_only == "n") {			// reload list if actually saving result
4233		cleanup_callback = function() {loadDashboardIncomplete(0);};
4234		refresh_alerts = "y";
4235	}
4236	var url = "dashboardModifyProvisional";
4237	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getModifyProvisionalFields(), callback, cleanup_callback, refresh_alerts);
4238}
4239
4240function dashboardSaveModifyProvisional(validate_only) {
4241	var check_warnings = "modify_provisional";
4242	var override_warnings = "n";
4243	var callback = false;
4244	var cleanup_callback = false;
4245	var refresh_alerts = false;
4246	if(validate_only == "n") {			// reload list if actually saving result
4247		cleanup_callback = function() {loadDashboardProvisional(0);};
4248		refresh_alerts = "y";
4249	}
4250	var url = "dashboardModifyProvisional";
4251	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getModifyProvisionalFields(), callback, cleanup_callback, refresh_alerts);
4252}
4253
4254function dashboardSaveMilestone(validate_only, add_another, callback) {
4255	//customised save code to account for parent and/or child options, and adding an extra child
4256	var xmlHttp = createXMLHttpRequest();
4257	if(xmlHttp) {
4258		validation_reference++;			//increment counter to match response to request in case of network delays and overlappping requests
4259		if(validate_only == "n") {
4260			dashboard_modal_message("Saving...", false);
4261		}
4262		if(!add_another) {
4263			add_another = "n";
4264		}
4265		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp, callback);};
4266		xmlHttp.open("post", "/log/ajax/saveMilestone.php", true);
4267		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4268		var data  = "milestone_id=" +				encodeURIComponent(document.getElementById("milestone_id").value);
4269		data += "&milestone_title=" +			encodeURIComponent(document.getElementById("milestone_title").value);
4270		data += "&milestone_display=" +			encodeURIComponent(document.getElementById("milestone_display").value);
4271		if(document.getElementById("milestone_child_id")) {
4272			data += "&milestone_child_id=" +		encodeURIComponent(document.getElementById("milestone_child_id").value);
4273			data += "&milestone_required=" +		encodeURIComponent(document.getElementById("milestone_required").value);
4274			data += "&milestone_monitor=" +			encodeURIComponent(document.getElementById("milestone_monitor").value);
4275			data += "&milestone_monitor_alt=" +		encodeURIComponent(document.getElementById("milestone_monitor_alt").value);
4276			data += "&milestone_aircraft=" +		encodeURIComponent(document.getElementById("milestone_aircraft").value);
4277			data += "&milestone_airport=" +			encodeURIComponent(document.getElementById("milestone_airport").value);
4278			data += "&milestone_day_night=" +		encodeURIComponent(document.getElementById("milestone_day_night").value);
4279			data += "&milestone_capacity=" +		encodeURIComponent(document.getElementById("milestone_capacity").value);
4280		}
4281		data += "&validate_only=" +				encodeURIComponent(validate_only);
4282		data += "&validation_reference=" +		encodeURIComponent(validation_reference);
4283		data += "&add_another=" +				encodeURIComponent(add_another);
4284		xmlHttp.send(data);
4285	}
4286}
4287
4288function dashboardAddMilestoneRequirement() {
4289	if(!confirm_discard_changes) {
4290		dashboardSaveMilestone("n", "y", function(){dashboardAddMilestoneRequirementSuccess();})
4291	}
4292}
4293
4294function dashboardAddMilestoneRequirementBasic() {
4295	if(confirm_discard_changes) {		//just save title and display
4296		//dashboardSaveMilestone("n", "y", function(){dashboardAddMilestoneRequirementSuccess();})
4297	} else {
4298		dashboardAddMilestoneRequirementSuccess();
4299	}
4300}
4301
4302function dashboardAddMilestoneRequirementSuccess() {
4303	window.location.replace("addMilestone.php?id="+document.getElementById("milestone_id").value+"&edit_child_id=0");		//exclude from 'back' history
4304}
4305
4306function dashboardToggleMilestoneDisplay(id) {
4307	var xmlHttp = createXMLHttpRequest();
4308	if(xmlHttp) {
4309		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp);};
4310		xmlHttp.open("post", "/log/ajax/saveMilestoneDisplay.php", true);
4311		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4312		var data  = "milestone_id=" +				encodeURIComponent(id);
4313		data += "&milestone_display=" +			encodeURIComponent(document.getElementById("milestone_display_"+id).value);
4314		xmlHttp.send(data);
4315	}
4316}
4317
4318function dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, fields, callback, cleanup_callback, refresh_alerts) {
4319	if(!validate_only) {
4320		validate_only = "n";
4321	}
4322	var xmlHttp = createXMLHttpRequest();
4323	if(xmlHttp) {
4324		validation_reference++;			//increment counter to match response to request in case of network delays and overlappping requests
4325		if(validate_only == "n") {
4326			last_log_highlight = "";		//enable highlight for next load, even if editing same cell id repeatedly
4327			dashboard_modal_message("Saving...", false);
4328		} else if(validate_only == "test") {
4329			dashboard_modal_message("Validating...", false);
4330		}
4331		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp, callback, check_warnings, cleanup_callback, refresh_alerts);};
4332		xmlHttp.open("post", "/log/ajax/" + url + ".php", true);
4333		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4334		var data = "validate_only=" + encodeURIComponent(validate_only);
4335		data += "&override_warnings=" + encodeURIComponent(override_warnings);
4336		data += "&validation_reference=" + encodeURIComponent(validation_reference);
4337		if(check_warnings) {
4338			data += "&check_warnings=" + encodeURIComponent(check_warnings);
4339		}
4340		for(n=0; n<fields.length; n++) {
4341			if(document.getElementById(fields[n])) {
4342				data += "&" + fields[n] + "=" + encodeURIComponent(document.getElementById(fields[n]).value);
4343			}
4344		}
4345		xmlHttp.send(data);
4346	}
4347}
4348
4349function dashboardSaveResult(xmlhttp, callback, check_warnings, cleanup_callback, refresh_alerts) {
4350	xml = getXmlContent(xmlhttp);
4351	if(xml[3]) {			//received with no errors
4352		if(callback) {		//replace this generic function with a specific one
4353			callback(xml);
4354			return;
4355		}
4356		validate_only = getXmlField(xml[0], "validate_only");
4357		if(validate_only == "y") {
4358			if(parseInt(getXmlField(xml[0], "validation_reference"), 10) == validation_reference) {		//only process most recent request. Ignore old responses if they are received out of order
4359				valid_fields = getXmlField(xml[0], "valid_fields");
4360				var fields = valid_fields.split("|");
4361				for(n=0; n<fields.length; n++) {
4362					if(fields[n] != "") {
4363						document.getElementById(fields[n]).classList.remove("dashboard_invali
4363d");
4364						document.getElementById(fields[n]).classList.add("dashboard_valid");
4365					}
4366				}
4367				invalid_fields = getXmlField(xml[0], "invalid_fields");
4368				fields = invalid_fields.split("|");
4369				for(n=0; n<fields.length; n++) {
4370					if(fields[n] != "") {
4371						document.getElementById(fields[n]).classList.remove("dashboard_valid");
4372						document.getElementById(fields[n]).classList.add("dashboard_invalid");
4373					}
4374				}
4375				if(check_warnings == "flight") {
4376					dashboardFlightValidation(xml[0]);
4377				} else if(check_warnings == "duty") {
4378					dashboardDutyValidation(xml[0]);
4379				}
4380			}
4381		} else if(validate_only == "no_action") {
4382			//only respond in case of error (below)
4383		} else if(check_warnings == "aircraft") {
4384			dashboardBackOverlay("edit_aircraft", true);
4385			dashboard_clear_modal_message();
4386		} else if(check_warnings == "airport") {
4387			dashboardBackOverlay("edit_airport", true);
4388			dashboard_clear_modal_message();
4389		} else if(check_warnings == "modify_incomplete" || check_warnings == "modify_provisional") {
4390			dashboardBackOverlay("modify_provisional", true);
4391			dashboard_clear_modal_message();
4392		} else if(check_warnings == "password") {
4393			dashboardBackOverlay("change_password", true);
4394			dashboard_clear_modal_message();
4395		} else if(check_warnings == "settings_standalone") {
4396			// do not go back; cleanup_callback redirects to index.php
4397		} else if(check_warnings) {						//save flight, sim, check for invalid aircraft, duty log errors, etc.
4398			warning = getXmlField(xml[0], "warning");
4399			if(warning == "OK") {
4400				dashboardBack(true);
4401			} else {
4402				dashboard_clear_modal_message();
4403				if(check_warnings == "flight") {
4404					dashboard_confirm("Warning", warning, "Save", "Back", function() {dashboardSaveFlight("n", "y");}, false);		//do not validate, yes override warnings
4405				} else if(check_warnings == "sim") {
4406					dashboard_confirm("Warning", warning, "Save", "Back", function() {dashboardSaveSim("n", "y");}, false);
4407				} else if(check_warnings == "duty") {
4408					dashboard_confirm("Warning", warning, "Save", "Back", function() {dashboardSaveDuty("n", "y");}, false);
4409				}
4410			}
4411		} else {
4412			dashboardBack(true);
4413		}
4414		if(cleanup_callback) {		//ui updates, etc. after validating
4415			cleanup_callback();
4416		}
4417		if(refresh_alerts) {
4418			checkAlerts();		//update alert bell and number after saving data
4419		}
4420	} else if(xml[4] == 500) {			//server error
4421		dashboard_clear_modal_message();
4422		dashboard_confirm("Error", "Server error (HTTP 500)<br /><br />If this error persists, please contact support", "OK", "", false, false);
4423	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
4424	} else if(xml[0])	{		//received with error
4425		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
4426			dashboardForceReload();
4427		} else if(xml[0].toUpperCase() == "SUSPENDED") {
4428			showSubscriptionPopup(true);
4429		} else if(xml[0].search(/^Saved /) != -1) {
4430			dashboard_clear_modal_message();
4431			dashboard_confirm("Error", xml[0], "OK", "Edit", function() {dashboardBack(true);}, false);
4432		} else if(check_warnings == "aircraft" && xml[0].toUpperCase() == "INUSEME") {
4433			dashboard_clear_modal_message();
4434			dashboard_confirm("Warning", "This aircraft is in use in your log.\n\nAre you sure you wish to delete it?", "Delete", "Cancel", function() {deleteAircraft(cleanup_callback, "y");}, false);
4435		} else if(check_warnings == "aircraft" && xml[0].substring(0, 9).toUpperCase() == "INUSEPREV" ) {
4436			dashboard_clear_modal_message();
4437			dashboard_confirm("Warning", "This aircraft is in use in previous experience.\n\nAre you sure you wish to delete it?\n\n" + xml[0].substring(10), "Delete", "Cancel", function() {deleteAircraft(cleanup_callback, "y");}, false);
4438		} else if(check_warnings == "aircraft" && xml[0].substring(0, 11).toUpperCase() == "INUSEOTHERS") {
4439			dashboard_clear_modal_message();
4440			dashboard_confirm("Warning", "This aircraft is in use in other users' logs.\n\nAre you sure you wish to delete it?\n\n" + xml[0].substring(12), "Delete", "Cancel", function() {deleteAircraft(cleanup_callback, "y");}, false);
4441		} else if(check_warnings == "airport" && xml[0].toUpperCase() == "INUSEME") {
4442			dashboard_clear_modal_message();
4443			dashboard_confirm("Warning", "This airport is in use in your log.\n\nAre you sure you wish to delete it?", "Delete", "Cancel", function() {deleteAirport(cleanup_callback, "y");}, false);
4444		} else if(check_warnings == "airport" && xml[0].substring(0, 11).toUpperCase() == "INUSEOTHERS") {
4445			dashboard_clear_modal_message();
4446			dashboard_confirm("Warning", "This airport is in use in other users' logs.\n\nAre you sure you wish to delete it?\n\n" + xml[0].substring(12), "Delete", "Cancel", function() {deleteAirport(cleanup_callback, "y");}, false);
4447		} else {
4448			dashboard_clear_modal_message();
4449			dashboard_confirm("Error", xml[0], "OK", "", false, false);
4450		}
4451	}
4452}
4453
4454function dashboardFlightValidation(xml) {
4455	document.getElementById("flight_aircraft_description").innerHTML = getXmlField(xml, "aircraft_description");
4456	document.getElementById("flight_from_description").innerHTML = getXmlField(xml, "from_description");
4457	document.getElementById("flight_to_description").innerHTML = getXmlField(xml, "to_description");
4458	var num_capacities = flight_capacities.length;
4459	for(c=0; c<num_capacities; c++) {
4460		document.getElementById("flight_hours_total_"+flight_capacities[
4460c]).innerHTML = getXmlField(xml, "flight_hours_total_"+flight_capacities[c]);
4461	}
4462	if(getXmlField(xml, "manual_breakdown") == "n") {
4463		for(c=0; c<num_capacities; c++) {
4464			document.getElementById("flight_hours_day_"+flight_capacities[c]+"_view_label").innerHTML = getXmlField(xml, "flight_hours_day_"+flight_capacities[c]);
4465			document.getElementById("flight_hours_night_"+flight_capacities[c]+"_view_label").innerHTML = getXmlField(xml, "flight_hours_night_"+flight_capacities[c]);
4466			document.getElementById("flight_hours_day_"+flight_capacities[c]).value = getXmlField(xml, "flight_hours_day_"+flight_capacities[c]+"_zero");
4467			document.getElementById("flight_hours_night_"+flight_capacities[c]).value = getXmlField(xml, "flight_hours_night_"+flight_capacities[c]+"_zero");
4468		}
4469		document.getElementById("flight_day_takeoffs_view_label").innerHTML = getXmlField(xml, "flight_day_takeoffs");
4470		document.getElementById("flight_day_takeoffs").value = getXmlField(xml, "flight_day_takeoffs_zero");
4471		document.getElementById("flight_night_takeoffs_view_label").innerHTML = getXmlField(xml, "flight_night_takeoffs");
4472		document.getElementById("flight_night_takeoffs").value = getXmlField(xml, "flight_night_takeoffs_zero");
4473		document.getElementById("flight_day_landings_view_label").innerHTML = getXmlField(xml, "flight_day_landings");
4474		document.getElementById("flight_day_landings").value = getXmlField(xml, "flight_day_landings_zero");
4475		document.getElementById("flight_night_landings_view_label").innerHTML = getXmlField(xml, "flight_night_landings");
4476		document.getElementById("flight_night_landings").value = getXmlField(xml, "flight_night_landings_zero");
4477		document.getElementById("flight_day_distance_view_label").innerHTML = getXmlField(xml, "flight_day_distance");
4478		document.getElementById("flight_day_distance").value = getXmlField(xml, "flight_day_distance_zero");
4479		document.getElementById("flight_night_distance_view_label").innerHTML = getXmlField(xml, "flight_night_distance");
4480		document.getElementById("flight_night_distance").value = getXmlField(xml, "flight_night_distance_zero");
4481		document.getElementById("flight_hours_day_cross_country_view_label").innerHTML = getXmlField(xml, "flight_day_cross_country");
4482		document.getElementById("flight_hours_day_cross_country").value = getXmlField(xml, "flight_day_cross_country_zero");
4483		document.getElementById("flight_hours_night_cross_country_view_label").innerHTML = getXmlField(xml, "flight_night_cross_country");
4484		document.getElementById("flight_hours_night_cross_country").value = getXmlField(xml, "flight_night_cross_country_zero");
4485		document.getElementById("flight_hours_instrument_view_label").innerHTML = getXmlField(xml, "flight_instrument");
4486		document.getElementById("flight_hours_instrument").value = getXmlField(xml, "flight_instrument_zero");
4487	}
4488	var total_calc = getXmlField(xml, "hours_total_calc");
4489	var total_entered = getXmlField(xml, "hours_total");
4490	document.getElementById("flight_hours_total_total").innerHTML = total_calc;
4491	document.getElementById("flight_hours_total_entered").innerHTML = total_entered;
4492	document.getElementById("flight_hours_day_total").innerHTML = getXmlField(xml, "hours_total_day_calc");
4493	document.getElementById("flight_hours_day_entered").innerHTML = getXmlField(xml, "hours_total_day");
4494	document.getElementById("flight_hours_night_total").innerHTML = getXmlField(xml, "hours_total_night_calc");
4495	document.getElementById("flight_hours_night_entered").innerHTML = getXmlField(xml, "hours_total_night");
4496	if(total_calc == total_entered) {
4497		document.getElementById("flight_hours_total_total").className = "dashboard_label";
4498		document.getElementById("flight_hours_total_entered").className = "dashboard_label";
4499	} else {
4500		document.getElementById("flight_hours_total_total").className = "dashboard_label dashboard_label_error";
4501		document.getElementById("flight_hours_total_entered").className = "dashboard_label dashboard_label_error";
4502	}
4503	document.getElementById("flight_total_takeoffs").innerHTML = getXmlField(xml, "flight_total_takeoffs");
4504	document.getElementById("flight_total_landings").innerHTML = getXmlField(xml, "flight_total_landings");
4505	document.getElementById("flight_total_distance").innerHTML = getXmlField(xml, "flight_total_distance");
4506	document.getElementById("flight_hours_total_cross_country").innerHTML = getXmlField(xml, "flight_total_cross_country");
4507}
4508
4509function dashboardDutyValidation(xml) {
4510	var acclimatised_tz_copy_button = document.getElementById("button_copy_duty_acclimatised_tz");
4511	if(document.getElementById("duty_manual_figures").value == "y") {	//manual details entry; set form as required for type of duty
4512		document.getElementById("duty_type").disabled = false;
4513		document.getElementById("duty_acclimatised_tz").disabled = false;
4514		document.getElementById("duty_date").disabled = false;
4515		document.getElementById("duty_start").disabled = false;
4516		document.getElementById("duty_start_tz").disabled = false;
4517		document.getElementById("duty_end").disabled = false;
4518		document.getElementById("duty_end_tz").disabled = false;
4519		dashboardYesNoButtonDisabled("duty_acclimatised", "");
4520		dashboardYesNoButtonDisabled("duty_start_rotation", "");
4521		dashboardYesNoButtonDisabled("duty_end_rotation", "");
4522		dashboardYesNoButtonDisabled("duty_provisional", "");
4523		document.getElementById("button_copy_duty_type").classList.remove("dashboard_copy_button_disabled");
4524		if(acclimatised_tz_copy_button) {
4525			document.getElementById("button_copy_duty_acclimatised_tz").classList.remove("dashboard_copy_button_disabled");
4526		}
4527		document.getElementById("button_copy_duty_start_tz").classList.remove("dashboard_copy_button_disabled");
4528		document.getElementById("button_copy_duty_end_tz").classList.remove("dashboard_copy_button_disabled");
4529		if(getXmlField(xml, "flying") == "y") {		// flying duties require all fields
4530			document.getElementById("duty_num_sectors").disabled = false;
4531			document.getElementById("duty_crew").disabled = false;
4532			document.getElementById("duty_start_fdp").disabled = false;
4533			document.getElementById("duty_end_of_flying").disabled = false;
4534			if(document.getElementById("duty_extension_rest_type").value == "time") {
4535				document.getElementById("duty_extension_rest").disabled = false;
4536			} else {
4537				dashboardYesNoButtonDisabled("duty_extension_rest", "");
4538			}
4539			document.getElementById("duty_rest_facility").disabled = false;
4540			document.getElementById("duty_extension_split").disabled = false;
4541			document.getElementById("button_copy_duty_crew").classList.remove("dashboard_copy_button_disabled");
4542			document.getElementById("button_copy_duty_rest_facility").classList.remove("dashboard_copy_button_disabled");
4543		} else {									// non-flying duties require less information
4544			//clear unused fields or set defaults (e.g. no bunk rest facility, 0 crew)
4545			document.getElementById("duty_num_sectors").value = "";
4546			document.getElementById("duty_crew").value = 0;
4547			document.getElementById("duty_start_fdp").value = "";
4548			document.getElementById("duty_end_of_flying").value = "";
4549			document.getElementById("duty_rest_facility").value = "n";
4550			document.getElementById("duty_extension_split").value = "";
4551			document.getElementById("duty_discretion_extend_duty").value = "";
4552			document.getElementById("duty_discretion_reduce_rest").value = "";
4553			//mark empty, unused fields as valid in case previously invalid
4554			document.getElementById("duty_start_fdp").classList.remove("dashboard_invalid");
4555			document.getElementById("duty_start_fdp").classList.add("dashboard_valid");
4556			document.getElementById("duty_end_of_flying").classList.remove("dashboard_invalid");
4557			document.getElementById("duty_end_of_flying").classList.add("dashboard_valid");
4558			document.getElementById("duty_extension_split").classList.remove("dashboard_invalid");
4559			document.getElementById("duty_extension_split").classList.add("dashboard_valid");
4560			//disable unused fields
4561			document.getElementById("duty_num_sectors").disabled = true;
4562			document.getElementById("duty_crew").disabled = true;
4563			document.getElementById("duty_start_fdp").disabled = true;
4564			document.getElementById("duty_end_of_flying").disabled = true;
4565			document.getElementById("button_copy_duty_crew").classList.add("dashboard_copy_button_disabled");
4566			document.getElementById("button_copy_duty_rest_facility").classList.add("dashboard_copy_button_disabled");
4567			if(document.getElementById("duty_extension_rest_type").value == "time") {
4568				document.getElementById("duty_extension_rest").disabled = true;
4569				document.getElementById("duty_extension_rest").classList.remove("dashboard_invalid");
4570				document.getElementById("duty_extension_rest").classList.add("dashboard_valid");
4571			} else {
4572				setYesNoButton("duty_extension_rest", "n");
4573				dashboardYesNoButtonDisabled("duty_extension_rest", "disabled");
4574			}
4575			document.getElementById("duty_rest_facility").disabled = true;
4576			document.getElementById("duty_extension_split").disabled = true;
4577		}
4578	} else {			
4579		//disable data entry for automatic duty
4580		document.getElementById("duty_type").disabled = true;
4581		document.getElementById("duty_acclimatised_tz").disabled = true;
4582		document.getElementById("duty_date").disabled = true;
4583		document.getElementById("duty_start").disabled = true;
4584		document.getElementById("duty_start_tz").disabled = true;
4585		document.getElementById("duty_end").disabled = true;
4586		document.getElementById("duty_end_tz").disabled = true;
4587		dashboardYesNoButtonDisabled("duty_acclimatised", "disabled");
4588		dashboardYesNoButtonDisabled("duty_start_rotation", "disabled");
4589		dashboardYesNoButtonDisabled("duty_end_rotation", "disabled");
4590		dashboardYesNoButtonDisabled("duty_provisional", "disabled");
4591		document.getElementById("button_copy_duty_type").classList.add("dashboard_copy_button_disabled");
4592		if(acclimatised_tz_copy_button) {
4593			document.getElementById("button_copy_duty_acclimatised_tz").classList.add("dashboard_copy_button_disabled");
4594		}
4595		document.getElementById("button_copy_duty_start_tz").classList.add("dashboard_copy_button_disabled");
4596		document.getElementById("button_copy_duty_end_tz").classList.add("dashboard_copy_button_disabled");
4597		document.getElementById("button_copy_duty_crew").classList.add("dashboard_copy_button_disabled");
4598		document.getElementById("button_copy_duty_rest_facility").classList.add("dashboard_copy_button_disabled");
4599		document.getElementById("duty_num_sectors").disabled = true;
4600		document.getElementById("duty_crew").disabled = true;
4601		document.getElementById("duty_start_fdp").disabled = true;
4602		document.getElementById("duty_end_of_flying").disabled = true;
4603		if(document.getElementById("duty_extension_rest_type").value == "time") {
4604			document.getElementById("duty_extension_rest").disabled = true;
4605			document.getElementById("duty_extension_rest").classList.remove("dashboard_invali
4605d");
4606			document.getElementById("duty_extension_rest").classList.add("dashboard_valid");
4607			document.getElementById("duty_extension_rest").value = getXmlField(xml, "duty_extension_rest");
4608		} else {
4609			setYesNoButton("duty_extension_rest", getXmlField(xml, "duty_extension_rest"));
4610			dashboardYesNoButtonDisabled("duty_extension_rest", "disabled");
4611		}
4612		if(getXmlField(xml, "flying") == "y") {		// rest facility may be required for flying duties (not automatic)
4613			document.getElementById("duty_rest_facility").disabled = false;
4614		} else {
4615			document.getElementById("duty_rest_facility").disabled = true;
4616		}
4617		document.getElementById("duty_extension_split").disabled = true;
4618		// display automatically calculated values
4619		document.getElementById("duty_type").value = getXmlField(xml, "duty_type");
4620		document.getElementById("duty_num_sectors").value = getXmlField(xml, "duty_num_sectors");
4621		document.getElementById("duty_crew").value = getXmlField(xml, "duty_crew");
4622		setYesNoButton("duty_acclimatised", getXmlField(xml, "duty_acclimatised"));
4623		document.getElementById("duty_acclimatised_tz").value = getXmlField(xml, "duty_acclimatised_tz");
4624		setYesNoButton("duty_provisional", getXmlField(xml, "duty_provisional"));
4625		document.getElementById("duty_date").value = getXmlField(xml, "duty_date");
4626		document.getElementById("duty_start").value = getXmlField(xml, "duty_start");
4627		document.getElementById("duty_start_tz").value = getXmlField(xml, "duty_start_tz");
4628		document.getElementById("duty_start_fdp").value = getXmlField(xml, "duty_start_fdp");
4629		setYesNoButton("duty_start_rotation", getXmlField(xml, "duty_start_rotation"));
4630		document.getElementById("duty_end_of_flying").value = getXmlField(xml, "duty_end_of_flying");
4631		document.getElementById("duty_end").value = getXmlField(xml, "duty_end");
4632		document.getElementById("duty_end_tz").value = getXmlField(xml, "duty_end_tz");
4633		setYesNoButton("duty_end_rotation", getXmlField(xml, "duty_end_rotation"));
4634
4635	}
4636	if(document.getElementById("duty_manual_limits").value == "y") {	//manual limitations entry; set form as required for type of duty
4637		document.getElementById("duty_rest_earned").disabled = false;
4638		if(getXmlField(xml, "flying") == "y") {		// flying duties have an FDP limit
4639			dashboardYesNoButtonDisabled("duty_extended", "");
4640			document.getElementById("duty_maximum").disabled = false;
4641		} else {									// non-flying duties have no FDP
4642			//clear unused fields or set defaults (e.g. no bunk rest facility, 0 crew)
4643			setYesNoButton("duty_extended", "n");
4644			document.getElementById("duty_maximum").value = "";
4645			//mark empty, unused fields as valid in case previously invalid
4646			document.getElementById("duty_maximum").classList.remove("dashboard_invalid");
4647			//disable unused fields
4648			dashboardYesNoButtonDisabled("duty_extended", "disabled");
4649			document.getElementById("duty_maximum").disabled = true;
4650		}
4651	} else {			//disable data entry for automatic duty
4652		dashboardYesNoButtonDisabled("duty_extended", "disabled");
4653		document.getElementById("duty_rest_earned").disabled = true;
4654		document.getElementById("duty_maximum").disabled = true;
4655		document.getElementById("duty_maximum").classList.remove("dashboard_invalid");
4656		document.getElementById("duty_rest_earned").classList.remove("dashboard_invalid");
4657	}
4658	//display calculated values
4659	document.getElementById("duty_start_local").value = getXmlField(xml, "duty_start_local");
4660	document.getElementById("duty_end_local").value = getXmlField(xml, "duty_end_local");
4661	document.getElementById("duty_duration").value = getXmlField(xml, "duty_duration");
4662	document.getElementById("fdp_duration").value = getXmlField(xml, "fdp_duration");
4663	document.getElementById("fdp_spare").value = getXmlField(xml, "fdp_spare");
4664	if(document.getElementById("duty_manual_limits").value == "n") {		//show automatic duty limits
4665		setYesNoButton("duty_extended", getXmlField(xml, "duty_extended"));
4666		document.getElementById("duty_maximum").value = getXmlField(xml, "duty_maximum");
4667		document.getElementById("duty_rest_earned").value = getXmlField(xml, "duty_rest_earned");
4668	}
4669	document.getElementById("duty_content_text").innerHTML = getXmlField(xml, "duty_content");
4670	if(getXmlField(xml, "duty_content") == "") {
4671		dashboardYesNoButtonDisabled("duty_manual_figures", "disabled");
4672	} else {
4673		dashboardYesNoButtonDisabled("duty_manual_figures", "");
4674	}
4675	var class_normal = "hidden";
4676	var class_early = "hidden";
4677	var class_late = "hidden";
4678	var class_night = "hidden";
4679	if(getXmlField(xml, "duty_early") == "y") {
4680		class_early = "dashboard_input";
4681	} else if(getXmlField(xml, "duty_late") == "y") {
4682		class_late = "dashboard_input";
4683	} else if(getXmlField(xml, "duty_night") == "y") {
4684		class_night = "dashboard_input";
4685	} else {
4686		class_normal = "dashboard_input";
4687	}
4688	document.getElementById("duty_normal").className = class_normal;
4689	document.getElementById("duty_early").className = class_early;
4690	document.getElementById("duty_late").className = class_late;
4691	document.getElementById("duty_night").className = class_night;
4692}
4693
4694function dashboardDeleteFlight() {
4695	dashboard_confirm("Delete Flight", "Are you sure that you wish to delete this flight?", "Delete", "No", function() {dashboardDeleteEntity("deleteFlight", document.getElementById("flight_id").value);}, false);
4696}
4697
4698function dashboardDeleteSim() {
4699	dashboard_confirm("Delete Sim", "Are you sure that you wish to delete this simulator detail?", "Delete", "No", function() {dashboardDeleteEntity("deleteSim", document.getElementById("sim_id").value);}, false);
4700}
4701
4702function dashboardDeleteDuty() {
4703	dashboard_confirm("Delete Duty", "Are you sure that you wish to delete this duty?", "Delete", "No", function() {dashboardDeleteEntity("deleteDuty", document.getElementById("duty_id").value);}, false);
4704}
4705
4706function dashboardDeleteExpiry() {
4707	dashboard_confirm("Delete Expiry", "Are you sure that you wish to delete this expiry?", "Delete", "No", function() {dashboardDeleteExpiryAction();}, false);
4708}
4709
4710function dashboardDeleteRecency() {
4711	dashboard_confirm("Delete Recency Requirement", "Are you sure that you wish to delete this requirement?", "Delete", "No", function() {dashboardDeleteRecencyAction();}, false);
4712}
4713
4714function dashboardDeletePrevious() {
4715	dashboard_confirm("Delete Previous Experience", "Are you sure that you wish to delete this entry?", "Delete", "No", function() {dashboardDeletePreviousAction();}, false);
4716}
4717
4718function dashboardDeleteMilestone() {
4719	dashboard_confirm("Delete Milestone", "Are you sure that you wish to delete this milestone?", "Delete", "No", function() {dashboardDeleteMilestoneAction();}, false);
4720}
4721
4722function dashboardDeleteMilestoneRequirement() {
4723	if(confirm_discard_changes || document.getElementById("milestone_child_id").value != "0") {
4724		dashboard_confirm("Remove Requirement", "Are you sure that you wish to remove this requirement from your milestone?", "Remove", "No", function() {dashboardDeleteMilestoneRequirementAction();}, false);
4725	} else {
4726		dashboardDeleteMilestoneRequirementAction();
4727	}
4728}
4729
4730function deleteProvisional(future_only) {
4731	var message = "This will delete <strong>all</strong> provisional entries in your log\n\nThere is no undo option\n\nAre you sure?";
4732	if(future_only) {
4733		message = "This will delete all future entries in your log\n\nThere is no undo option\n\nAre you sure?";
4734	}
4735	dashboard_confirm("Delete Provisional Entries", message, "Delete", "No", function() {dashboardDeleteProvisionalAction(future_only);}, false);
4736}
4737
4738function dashboardDeleteUser() {
4739	dashboard_confirm("Delete User", "Are you sure that you wish to delete this user?", "Delete", "No", function() {dashboardDeleteEntity("deleteUser", document.getElementById("user_id").value);}, false);
4740}
4741
4742function dashboardDeleteEntity(url, id) {
4743	var xmlHttp = createXMLHttpRequest();
4744	if(xmlHttp) {
4745		dashboard_modal_message("Deleting...", false);
4746		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp);};
4747		xmlHttp.open("post", "/log/ajax/" + url + ".php", true);
4748		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4749		var data  = "id=" + id;
4750		xmlHttp.send(data);
4751	} else {
4752		dashboardErrorMessage("AJAX communication failure");
4753	}
4754}
4755
4756function deleteAircraft(cleanup_callback, override_warnings) {
4757	if(!override_warnings) {
4758		override_warnings = "n";
4759	}
4760	deleteAircraftOrAirport("Aircraft", document.getElementById("ac_id").value, override_warnings, cleanup_callback);
4761}
4762
4763function deleteAirport(cleanup_callback, override_warnings) {
4764	if(!override_warnings) {
4765		override_warnings = "n";
4766	}
4767	deleteAircraftOrAirport("Airport", document.getElementById("ap_id").value, override_warnings, cleanup_callback);
4768}
4769
4770function deleteAircraftOrAirport(aircraft_or_airport, id, override_warnings, cleanup_callback) {
4771	var xmlHttp = createXMLHttpRequest();
4772	if(xmlHttp) {
4773		var callback = false;
4774		var check_warnings = aircraft_or_airport.toLowerCase();
4775		dashboard_modal_message("Deleting...", false);
4776		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp, callback, check_warnings, cleanup_callback);};
4777		xmlHttp.open("post", "/log/ajax/delete" + aircraft_or_airport + ".php", true);
4778		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4779		var data  = "id=" + id;
4780		data += "&override=" + override_warnings;
4781		xmlHttp.send(data);
4782	} else {
4783		dashboardErrorMessage("AJAX communication failure");
4784	}
4785}
4786
4787function dashboardDeleteExpiryAction() {
4788	var xmlHttp = createXMLHttpRequest();
4789	if(xmlHttp) {
4790		dashboard_modal_message("Deleting...", false);
4791		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp);};
4792		xmlHttp.open("post", "/log/ajax/deleteExpiry.php", true);
4793		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4794		var data  = "expiry_id=" + encodeURIComponent(document.getElementById("exp_id").value);
4795		xmlHttp.send(data);
4796	} else {
4797		dashboardErrorMessage("AJAX communication failure");
4798	}
4799}
4800
4801function dashboardDeleteRecencyAction() {
4802	var xmlHttp = createXMLHttpRequest();
4803	if(xmlHttp) {
4804		dashboard_modal_message("Deleting...", false);
4805		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp);};
4806		xmlHttp.open("post", "/log/ajax/deleteRecency.php", true);
4807		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4808		var data  = "recency_id=" + encodeURIComponent(document.getElementById("recency_id").value);
4809		xmlHttp.send(data);
4810	} else {
4811		dashboardErrorMessage("AJAX communication failure");
4812	}
4813}
4814
4815function dashboardDeletePreviousAction() {
4816	var xmlHttp = createXMLHttpRequest();
4817	if(xmlHttp) {
4818		dashboard_modal_message("Deleting...", false);
4819		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp);};
4820		xmlHttp.open("post", "/log/ajax/deletePrevious.php", true);
4821		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4822		var data  = "prev_id=" + encodeURIComponent(document.getElementById("prev_id").value);
4823		xmlHttp.send(data);
4824	} else {
4825		dashboardErrorMessage("AJAX communication failure");
4826	}
4827}
4828
4829function dashboardDeleteProvisionalAction(future_only) {
4830	var xmlHttp = createXMLHttpRequest();
4831	if(xmlHttp) {
4832		dashboard_modal_message("Deleting...", false);
4833		var callback = function() {provisionalDeletedSuccess(future_only);};
4834		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp, callback);};
4835		xmlHttp.open("post", "/log/ajax/deleteProvisional.php", true);
4836		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4837		var future = "n";
4838		if(future_only) {
4839			future = "y";
4840		}
4841		var data  = "future=" + encodeURIComponent(future);
4842		xmlHttp.send(data);
4843	} else {
4844		dashboardErrorMessage("AJAX communication failure");
4845	}
4846}
4847
4848function provisionalDeletedSuccess(future_only) {
4849	dashboard_clear_modal_message();
4850	if(future_only) {
4851		loadDashboardProvisional(0);
4852	} else {
4853		window.location.assign("index.php");
4854	}
4855}
4856
4857function dashboardDeleteMilestoneAction() {
4858	var xmlHttp = createXMLHttpRequest();
4859	if(xmlHttp) {
4860		dashboard_modal_message("Deleting...", false);
4861		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp);};
4862		xmlHttp.open("post", "/log/ajax/deleteMilestone.php", true);
4863		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4864		var data  = "milestone_id=" + encodeURIComponent(document.getElementById("milestone_id").value);
4865		xmlHttp.send(data);
4866	} else {
4867		dashboardErrorMessage("AJAX communication failure");
4868	}
4869}
4870
4871function dashboardDeleteMilestoneRequirementAction() {
4872	var xmlHttp = createXMLHttpRequest();
4873	if(xmlHttp) {
4874		dashboard_modal_message("Deleting...", false);
4875		xmlHttp.onreadystatechange = function(){dashboardSaveResult(xmlHttp);};
4876		xmlHttp.open("post", "/log/ajax/deleteMilestone.php", true);
4877		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4878		var data  = "milestone_id=" + encodeURIComponent(document.getElementById("milestone_child_id").value);
4879		data += "&milestone_parent_id=" + encodeURIComponent(document.getElementById("milestone_id").value);
4880		xmlHttp.send(data);
4881	} else {
4882		dashboardErrorMessage("AJAX communication failure");
4883	}
4884}
4885
4886// Login code
4887
4888function dashboardLogin() {
4889	var xmlHttp = createXMLHttpRequest();
4890	if(xmlHttp) {
4891		xmlHttp.onreadystatechange = function(){handleLoginResponseDashboard(xmlHttp, "login");};
4892		xmlHttp.open("post", "/log/ajax/login.php", true);
4893		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4894		var data  = "username=" +			encodeURIComponent(document.getElementById('login_username').value);
4895		data += "&password=" +			encodeURIComponent(document.getElementById("login_password").value);
4896		xmlHttp.send(data);
4897	} else {
4898		dashboardErrorMessage("AJAX communication failure");
4899	}
4900}
4901
4902function dashboardProxyLogin(user_id) {
4903	var xmlHttp = createXMLHttpRequest();
4904	if(xmlHttp) {
4905		xmlHttp.onreadystatechange = function(){handleLoginResponseDashboard(xmlHttp, "proxy_login");};
4906		xmlHttp.open("post", "/log/ajax/loginAsUser.php", true);
4907		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4908		var data  = "id=" +	user_id;
4909		xmlHttp.send(data);
4910	} else {
4911		dashboardErrorMessage("AJAX communication failure");
4912	}
4913}
4914
4915function dashboardLogout() {
4916	var xmlHttp = createXMLHttpRequest();
4917	if(xmlHttp) {
4918		xmlHttp.onreadystatechange = function(){handleLoginResponseDashboard(xmlHttp, "logout");};
4919		xmlHttp.open("post", "/log/ajax/logout.php", true);
4920		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4921		xmlHttp.send();
4922	} else {
4923		dashboardErrorMessage("AJAX communication failure");
4924	}
4925}
4926
4927function dashboardPasswordReset() {
4928	var xmlHttp = createXMLHttpRequest();
4929	if(xmlHttp) {
4930		xmlHttp.onreadystatechange = function(){handleLoginResponseDashboard(xmlHttp, "reset");};
4931		xmlHttp.open("post", "/log/ajax/passwordReset.php", true);
4932		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
4933		var data  = "username=" +		encodeURIComponent(document.getElementById('login_reset').value);
4934		xmlHttp.send(data);
4935	} else {
4936		dashboardErrorMessage("AJAX communication failure");
4937	}
4938}
4939
4940function dashboardForgotPassword() {
4941	document.getElementById("dashboard_login_form").className = "popup_form_hidden";
4942	window.setTimeout(function () {
4943		document.getElementById("dashboard_reminder_form").className = "reminder_form_visible";
4944		window.setTimeout(function () {
4945			document.getElementById("dashboard_reminder_form").className = "reminder_form_scrolling";
4946		}, 500);
4947	}, 500);
4948}
4949
4950function dashboardShowLogin() {
4951	document.getElementById("dashboard_reminder_form").className = "popup_form_hidden";
4952	window.setTimeout(function () {
4953		document.getElementById("dashboard_login_form").className = "login_form_visible";
4954		window.setTimeout(function () {
4955			document.getElementById("dashboard_login_form").className = "login_form_scrolling";
4956		}, 500);
4957	}, 500);
4958}
4959
4960function handleLoginResponseDashboard(xmlHttp, mode) {
4961	var xml = getXmlContent(xmlHttp);
4962	if(xml[1]) {
4963		if(xml[2]) {
4964			if(xml[3]) {
4965				if(mode == "login") {									//successful login, reload current page
4966					window.location.reload(true);
4967				} else if(mode == "proxy_login") {						//proxy login, go to dashboard of user
4968					window.location.replace("/dashboard/index.php");
4969				} else if(mode == "logout") {
4970					proxy = getXmlField(xml[0], "proxy_logout");
4971					if(proxy == "y") {									//proxy logout, go back to users dataabse
4972						window.location.replace("/dashboard/users.php");
4973					} else {											//normal logout, show home page
4974						window.location.replace("/index.php");
4975					}
4976				} else if(mode == "reset") {							//password reset request, show message and display login prompt
4977					dashboardErrorMessage("Password reset request sent. Please check your email.");
4978					dashboardShowLogin();
4979				}
4980			} else {
4981				dashboardErrorMessage(xml[0]);
4982			}
4983		} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
4984		} else {
4985			dashboardErrorMessage("AJAX HTTP error code "+xml[4]+" at SAL002");
4986		}
4987	}
4988}
4989
4990// End Login code
4991
4992function dashboardClearSearch(database, callback) {
4993	hideFilterBlockOnSmallScreen();
4994	document.getElementById("log_search_text").value = "";
4995	if(database == "logbook" || database == "logbook_flying" || database == "logbook_sim" || database == "logbook_duty" || database == "totals") {
4996		document.getElementById("filter_date_from").value = "";
4997		document.getElementById("filter_date_to").value = "";
4998		if(database == "logbook" || database == "logbook_flying" || database == "logbook_sim" || database == "totals") {
4999			filterAllCapacities("s");
5000			filterAllLaunches("s");
5001			filterAllApproaches("s");
5002			filterAllAircraftAirframes("s");
5003			filterAllAircraftPowers("s");
5004			filterAllAircraftExtras("s");
5005			document.getElementById("filter_aircraft").value = "";
5006			document.getElementById("filter_crew").value = "";
5007			document.getElementById("filter_autoland").value = "i";
5008			if(database == "logbook" || database == "logbook_flying" || database == "totals") {
5009				document.getElementById("filter_airport").value = "";
5010			}
5011		}
5012		for(var n=1; n<num_flight_custom_fields; n++) {
5013			document.getElementById("filter_flight_custom_"+n).value = "i";
5014		}
5015		for(var n=1; n<num_sim_custom_fields; n++) {
5016			document.getElementById("filter_sim_custom_"+n).value = "i";
5017		}
5018		for(var n=1; n<num_duty_custom_fields; n++) {
5019			document.getElementById("filter_duty_custom_"+n).value = "i";
5020		}
5021		applyFilters(database, callback, false, 0);
5022	} else {
5023		applyFilters(database, callback, "#all#", 0);
5024	}
5025	document.getElementById("filter_icon").className = "log_filter_icon filter_icon_inactive";
5026}
5027
5028function filterTextKeyUp(event, database, callback) {
5029	if(event.keyCode == 13) {
5030		event.target.blur();
5031		applyFilters(database, callback);
5032	}
5033}
5034
5035function filterAllCapacities(value) {
5036	for(var n=0; n<flight_capacities.length; n++) {
5037		dashboardYesNoButtonClicked("filter_capacity_"+flight_capacities[n], value, false, false);
5038	}
5039}
5040
5041function filterAllLaunches(value) {
5042	for(var n=0; n<launch_types.length; n++) {
5043		dashboardYesNoButtonClicked("filter_launch_"+launch_types[n], value, false, false);
5044	}
5045}
5046
5047function filterAllApproaches(value) {
5048	for(var n=0; n<approach_types.length; n++) {
5049		dashboardYesNoButtonClicked("filter_approach_"+approach_types[n], value, false, false);
5050	}
5051}
5052
5053function filterAllAircraftAirframes(value) {
5054	for(var n=0; n<aircraft_airframes.length; n++) {
5055		dashboardYesNoButtonClicked("filter_aircraft_airframe_"+aircraft_airframes[n], value, false, false);
5056	}
5057}
5058
5059function filterAllAircraftPowers(value) {
5060	document.getElementById("filter_num_engines").value = "A";
5061	for(var n=0; n<aircraft_powers.length; n++) {
5062		dashboardYesNoButtonClicked("filter_aircraft_power_"+aircraft_powers[n], value, false, false);
5063	}
5064}
5065
5066function filterAllAircraftExtras(value) {
5067	for(var n=0; n<aircraft_extras.length; n++) {
5068		dashboardYesNoButtonClicked("filter_aircraft_extras_"+aircraft_extras[n], value, false, false);
5069	}
5070}
5071
5072function applyFilters(database, callback, shortcut, button_id) {
5073	if(shortcut == "#all#") {
5074		document.getElementById("log_search_text").value = "";
5075		if(database == "logbook" || database == "logbook_flying" || database == "logbook_sim" || database == "logbook_duty" || database == "totals") {
5076			document.getElementById("filter_date_from").value = "";
5077			document.getElementById("filter_date_to").value = "";
5078			if(database == "logbook" || database == "logbook_flying" || database == "logbook_sim" || database == "totals") {
5079				document.getElementById("filter_aircraft").value = "";
5080				document.getElementById("filter_crew").value = "";
5081				if(database == "logbook" || database == "logbook_flying" || database == "totals") {
5082					document.getElementById("filter_airport").value = "";
5083				}
5084			}
5085		}
5086	}
5087	hideFilterBlockOnSmallScreen();
5088	if(document.getElementById("applied_filter")) {
5089		if(shortcut) {
5090			document.getElementById("applied_filter").value = shortcut;			//save shortcut for future text searches
5091		} else {
5092			shortcut = document.getElementById("applied_filter").value;			//recall previous filter to apply alongside text
5093		}
5094	}
5095	if(typeof button_id !== 'undefined') {
5096		n=0;
5097		current_button = document.getElementById("filter_button_" + n);
5098		while(current_button) {
5099			if(n == button_id) {
5100				current_button.classList.add("filter_button_active");
5101			} else {
5102				current_button.classList.remove("filter_button_active");
5103			}
5104			n++;
5105			current_button = document.getElementById("filter_button_" + n);
5106		}
5107	}
5108	var data = "database=";
5109	if(database == "totals") {
5110		data += encodeURIComponent("logbook");
5111	} else {
5112		data += encodeURIComponent(database);
5113	}
5114	data += "&text=" + encodeURIComponent(document.getElementById("log_search_text").value);
5115	var url = "/log/ajax/quickSearch.php";
5116	if(database == "logbook" || database == "logbook_flying"|| database == "logbook_sim" || database == "logbook_duty" || database == "totals") {
5117		url = "/log/ajax/setFiltersLogbook.php";
5118		data += "&date_from=" + encodeURIComponent(document.getElementById("filter_date_from").value);
5119		data += "&date_to=" + encodeURIComponent(document.getElementById("filter_date_to").value);
5120		data += "&aircraft=" + encodeURIComponent(document.getElementById("filter_aircraft").value);
5121		data += "&airport=" + encodeURIComponent(document.getElementById("filter_airport").value);
5122		data += "&crew=" + encodeURIComponent(document.getElementById("filter_crew").value);
5123		if(document.getElementById("filter_autoland").value != "i") {
5124			data += "&autoland=" + encodeURIComponent(document.getElementById("filter_autoland").value);
5125		}
5126		var show_capacities = "";
5127		var showing_all = true;
5128		for(var n=0; n<flight_capacities.length; n++) {
5129			if(document.getElementById("filter_capacity_"+flight_capacities[n]).value == "s") {
5130				if(show_capacities != "") {
5131					show_capacities += "|";
5132				}
5133				show_capacities += flight_capacities[n];
5134			} else {
5135				showing_all = false;
5136			}
5137		}
5138		if(showing_all) {
5139			show_capacities = "";		// no filter applied, show all
5140		}
5141		data += "&capacity=" + encodeURIComponent(show_capacities);
5142		var show_options = "";
5143		var showing_all = true;
5144		for(var n=0; n<launch_types.length; n++) {
5145			if(document.getElementById("filter_launch_"+launch_types[n]).value == "s") {
5146				if(show_options != "") {
5147					show_options += "|";
5148				}
5149				show_options += launch_types[n];
5150			} else {
5151				showing_all = false;
5152			}
5153		}
5154		if(showing_all) {
5155			show_options = "";		// no filter applied, show all
5156		}
5157		data += "&launch_types=" + encodeURIComponent(show_options);
5158		var show_options = "";
5159		var showing_all = true;
5160		for(var n=0; n<approach_types.length; n++) {
5161			if(document.getElementById("filter_approach_"+approach_types[n]).value == "s") {
5162				if(show_options != "") {
5163					show_options += "|";
5164				}
5165				show_options += approach_types[n];
5166			} else {
5167				showing_all = false;
5168			}
5169		}
5170		if(showing_all) {
5171			show_options = "";		// no filter applied, show all
5172		}
5173		data += "&approach_types=" + encodeURIComponent(show_options);
5174		var show_options = "";
5175		var showing_all = true;
5176		for(var n=0; n<aircraft_airframes.length; n++) {
5177			if(document.getElementById("filter_aircraft_airframe_"+aircraft_airframes[n]).value == "s") {
5178				if(show_options != "") {
5179					show_options += "|";
5180				}
5181				show_options += aircraft_airframes[n];
5182			} else {
5183				showing_all = false;
5184			}
5185		}
5186		if(showing_all) {
5187			show_options = "";		// no filter applied, show all
5188		}
5189		data += "&aircraft_airframe=" + encodeURIComponent(show_options);
5190		show_options = document.getElementById("filter_num_engines").value;
5191		showing_all = true;
5192		if(document.getElementById("filter_num_engines").value != "A") {
5193			showing_all = false;
5194		}
5195		for(var n=0; n<aircraft_powers.length; n++) {
5196			if(document.getElementById("filter_aircraft_power_"+aircraft_powers[n]).value == "s") {
5197				if(show_options != "") {
5198					show_options += "|";
5199				}
5200				show_options += aircraft_powers[n];
5201			} else {
5202				showing_all = false;
5203			}
5204		}
5205		if(showing_all) {
5206			show_options = "";		// no filter applied, show all
5207		}
5208		data += "&aircraft_power=" + encodeURIComponent(show_options);
5209		var show_options = "";
5210		var showing_all = true;
5211		for(var n=0; n<aircraft_extras.length; n++) {
5212			if(document.getElementById("filter_aircraft_extras_"+aircraft_extras[n]).value == "s") {
5213				if(show_options != "") {
5214					show_options += "|";
5215				}
5216				show_options += aircraft_extras[n];
5217			} else {
5218				showing_all = false;
5219			}
5220		}
5221		if(showing_all) {
5222			show_options = "";		// no filter applied, show all
5223		}
5224		data += "&aircraft_extras=" + encodeURIComponent(show_options);
5225		var filter = "";
5226		for(n=1; n<=num_flight_custom_fields; n++) {
5227			if(document.getElementById("filter_flight_custom_"+n).value != "i") {
5228				if(filter != "") {
5229					filter += "|";
5230				}
5231				filter += n+"^"+document.getElementById("filter_flight_custom_"+n).value;
5232			}
5233		}
5234		data += "&flight_custom_boolean=" + encodeURIComponent(filter);
5235		filter = "";
5236		for(n=1; n<=num_sim_custom_fields; n++) {
5237			if(document.getElementById("filter_sim_custom_"+n).value != "i") {
5238				if(filter != "") {
5239					filter += "|";
5240				}
5241				filter += n+"^"+document.getElementById("filter_sim_custom_"+n).value;
5242			}
5243		}
5244		data += "&sim_custom_boolean=" + encodeURIComponent(filter);
5245		filter = "";
5246		for(n=1; n<=num_duty_custom_fields; n++) {
5247			if(document.getElementById("filter_duty_custom_"+n).value != "i") {
5248				if(filter != "") {
5249					filter += "|";
5250				}
5251				filter += n+"^"+document.getElementById("filter_duty_custom_"+n).value;
5252			}
5253		}
5254		data += "&duty_custom_boolean=" + encodeURIComponent(filter);
5255	} else if(database == "aircraft") {
5256		url = "/log/ajax/setFiltersAircraft.php";
5257		if(shortcut) {
5258			data += "&filter=" + encodeURIComponent(shortcut);
5259		}
5260	} else if(database == "airport") {
5261		url = "/log/ajax/setFiltersAirport.php";
5262		if(shortcut) {
5263			data += "&filter=" + encodeURIComponent(shortcut);
5264		}
5265	} else if(database == "users") {
5266		url = "/log/ajax/setFiltersUsers.php";
5267		if(shortcut) {
5268			data += "&filter=" + encodeURIComponent(shortcut);
5269		}
5270	}
5271	var xmlHttp = createXMLHttpRequest();
5272	if(xmlHttp) {
5273		if(database != "totals") {
5274			document.getElementById("dashboard_content").innerHTML = loading_list;
5275		}
5276		xmlHttp.onreadystatechange = function(){searchResult(xmlHttp, callback);};
5277		xmlHttp.open("post", url, true);
5278		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
5279		xmlHttp.send(data);
5280	}
5281}
5282
5283function searchResult(xmlHttp, callback) {
5284	var xml = getXmlContent(xmlHttp);
5285	if(xml[3]) {
5286		error = getXmlField(xml[0], "error");
5287		if(error == "OK") {
5288			if(getXmlField(xml[0], "filter_applied") == "y") {
5289				document.getElementById("filter_icon").className = "log_filter_icon filter_icon_active";
5290			} else {
5291				document.getElementById("filter_icon").className = "log_filter_icon filter_icon_inactive";
5292			}
5293			callback();
5294		} else {
5295			dashboardErrorMessage(error);
5296		}
5297	} else if(xml[4] == 500) {			//server error
5298		dashboard_clear_modal_message();
5299		dashboard_confirm("Error", "Server error (HTTP 500)<br /><br />If this error persists, please contact support", "OK", "", false, false);
5300	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
5301	} else if(xml[0])	{		//received with error
5302		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
5303			dashboardForceReload();
5304		} else if(xml[0].toUpperCase() == "SUSPENDED") {
5305			showSubscriptionPopup(true);
5306		} else {
5307			dashboard_clear_modal_message();
5308			dashboardErrorMessage(xml[0]);
5309		}
5310	}
5311}
5312
5313function todayDate(id) {
5314	document.getElementById(id).value = textFromDate(new Date());
5315}
5316
5317function addToDate(id, interval, units) {
5318	oldDate = getDateFromTextField(id, date_format_setting);
5319	newDate = new Date(oldDate);
5320	var checkRollover = function() { if(newDate.getDate() != oldDate.getDate()) newDate.setDate(0);};
5321	switch(String(units).toLowerCase().substring(0, 3)) {		//truncate to 3 characters so that 'day' and 'days' are both recognised
5322		case 'yea' :  newDate.setFullYear(newDate.getFullYear() + interval); checkRollover();  break;
5323		case 'qua' :  newDate.setMonth(newDate.getMonth() + 3*interval); checkRollover();  break;
5324		case 'mon' :  newDate.setMonth(newDate.getMonth() + interval); checkRollover();  break;
5325		case 'wee' :  newDate.setDate(newDate.getDate() + 7*interval);  break;
5326		case 'day' :  newDate.setDate(newDate.getDate() + interval);  break;
5327		case 'hou' :  newDate.setTime(newDate.getTime() + interval*3600000);  break;
5328		case 'min' :  newDate.setTime(newDate.getTime() + interval*60000);  break;
5329		case 'sec' :  newDate.setTime(newDate.getTime() + interval*1000);  break;
5330		default       :  newDate = undefined;  break;
5331	}
5332	document.getElementById(id).value = textFromDate(newDate);
5333}
5334
5335function textFromDate(date_object) {
5336	var text = "";
5337	yr = date_object.getFullYear();
5338	mt = date_object.getMonth()+1;
5339	dy = date_object.getDate();
5340	if(dy < 10) {
5341		dy_zero = "0";
5342	} else {
5343		dy_zero = "";
5344	}
5345	if(mt < 10) {
5346		mt_zero = "0";
5347	} else {
5348		mt_zero = "";
5349	}
5350	if(date_format_setting == "dmy") {
5351		text = dy_zero+dy+"/"+mt_zero+mt+"/"+yr;
5352	} else if(date_format_setting == "mdy") {
5353		text = mt_zero+mt+"/"+dy_zero+dy+"/"+yr;
5354	} else {
5355		text = yr+"-"+mt_zero+mt+"-"+dy_zero+dy;
5356	}
5357	return text;
5358}
5359
5360function dashboardCopy(id, callback) {
5361	if(!editing_locked) {
5362		var element = document.getElementById(id);
5363		var previous = document.getElementById(id + "_previous");
5364		if(element && previous) {
5365			if(!element.disabled) {
5366				//var temp = element.value;
5367				element.value = previous.value;
5368				//previous.value = temp;
5369				if(callback) {
5370					callback();
5371				}
5372			}
5373		}
5374	}
5375}
5376
5377function dashboardSwapCrew(id, callback) {
5378	if(!editing_locked) {
5379		var element = document.getElementById(id);
5380		var swap_with;
5381		if(id == "flight_p2") {
5382			swap_with = document.getElementById("flight_pic");
5383		} else if(id == "flight_heavy_1") {
5384			swap_with = document.getElementById("flight_p2");
5385			if(swap_with.offsetParent === null) {
5386				swap_with = document.getElementById("flight_pic");
5387			}
5388		} else if(id == "flight_heavy_2") {
5389			swap_with = document.getElementById("flight_heavy_1");
5390			if(swap_with.offsetParent === null) {
5391				swap_with = document.getElementById("flight_p2");
5392			}
5393			if(swap_with.offsetParent === null) {
5394				swap_with = document.getElementById("flight_pic");
5395			}
5396		} else if(id == "sim_pic") {
5397			swap_with = document.getElementById("sim_instructor");
5398		} else if(id == "sim_p2") {
5399			swap_with = document.getElementById("sim_pic");
5400		}
5401		if(element && swap_with) {
5402			if(!element.disabled) {
5403				var temp = element.value;
5404				element.value = swap_with.value;
5405				swap_with.value = temp;
5406				if(callback) {
5407					callback();
5408				}
5409			}
5410		}
5411	}
5412}
5413
5414function dashboardCopyPlan() {
5415	if(!editing_locked) {
5416		document.getElementById("flight_plan_date").value = document.getElementById("flight_date").value;
5417		document.getElementById("flight_ptd").value = document.getElementById("flight_depart").value;
5418		document.getElementById("flight_pta").value = document.getElementById("flight_arrive").value;
5419	}
5420}
5421
5422function incrementFlightNumber(number_to_add) {
5423	var flightNumber = document.getElementById("flight_number").value;
5424	if(flightNumber.length > 0) {
5425		const reNumber = /(\d+)/g;
5426		var result = flightNumber.match(reNumber);
5427		if(result != null) {
5428			var lastMatch = result[result.length - 1];
5429			var n = parseInt(lastMatch, 10);
5430			n += number_to_add;
5431			var pos = flightNumber.lastIndexOf(lastMatch);
5432			var newFlightNumber = flightNumber.substring(0, pos);
5433			newFlightNumber += n.toString();
5434			pos += lastMatch.length;
5435			newFlightNumber += flightNumber.substring(pos);
5436			document.getElementById("flight_number").value = newFlightNumber;
5437		}
5438	}
5439}
5440
5441// Add User code
5442
5443function setTrialExpiry(months) {
5444	document.getElementById("user_status").value = "Trial";
5445	document.getElementById("user_payment").value = "Free";
5446	document.getElementById("user_payment_frequency").value = "None";
5447	document.getElementById("user_type").value = "Pro";
5448	setYesNoButton("user_extend_trial", "n");
5449	dt = new Date();
5450	yr = dt.getFullYear();
5451	mt = dt.getMonth() + 1;
5452	mt += months;
5453	while(mt > 12) {
5454		mt = mt - 12;
5455		yr++;
5456	}
5457	dy = daysInMonth(mt, yr);
5458	if(mt < 10) {
5459		mt = "0" + mt;
5460	}
5461	if(dy < 10) {
5462		dy = "0" + dy;
5463	}
5464	if(date_format_setting == "dmy") {
5465		document.getElementById("user_trial_expiry").value = dy+"/"+mt+"/"+yr;
5466	} else if(date_format_setting == "mdy") {
5467		document.getElementById("user_trial_expiry").value = mt+"/"+dy+"/"+yr;
5468	} else {
5469		document.getElementById("user_trial_expiry").value = yr+"-"+mt+"-"+dy;
5470	}
5471	checkUserChanges();
5472}
5473
5474function addUserNameChange() {
5475	if(!document.getElementById("user_name").disabled) {
5476		var forename = document.getElementById("user_forename").value;
5477		var surname = document.getElementById("user_surname").value;
5478		var username = forename + surname;
5479		username = username.replace(/[^a-zA-Z]/, "");
5480		document.getElementById("user_name").value = username;
5481	}
5482	checkUserChanges();
5483}
5484
5485function capitaliseNameAndAddress() {
5486	document.getElementById("user_title").value = capitalise(document.getElementById("user_title").value);
5487	document.getElementById("user_forename").value = capitalise(document.getElementById("user_forename").value);
5488	document.getElementById("user_middlename").value = capitalise(document.getElementById("user_middlename").value);
5489	document.getElementById("user_surname").value = capitalise(document.getElementById("user_surname").value);
5490	document.getElementById("user_address_1").value = capitalise(document.getElementById("user_address_1").value);
5491	document.getElementById("user_address_2").value = capitalise(document.getElementById("user_address_2").value);
5492	document.getElementById("user_address_3").value = capitalise(document.getElementById("user_address_3").value);
5493	document.getElementById("user_address_town").value = capitalise(document.getElementById("user_address_town").value);
5494	document.getElementById("user_address_county").value = capitalise(document.getElementById("user_address_county").value);
5495	document.getElementById("user_address_postcode").value = document.getElementById("user_address_postcode").value.toUpperCase();
5496	addUserNameChange();
5497	checkUserChanges();
5498}
5499
5500function capitalise(s) {
5501	if (typeof s !== 'string') return '';
5502	// start with all uppercase
5503	s = s.toUpperCase();
5504	// separate Mc , O' and hyphenated names
5505	s = s.replace("MC", "MC ");
5506	s = s.replace("'", "' ");
5507	s = s.replace("-", "- ");
5508	// get individual words
5509	words = s.split(" ");
5510	for(w=0; w<words.length; w++) {
5511		words[w] = words[w].charAt(0).toUpperCase() + words[w].slice(1).toLowerCase();
5512	}
5513	// rebuild string from capitalised words
5514	s = "";
5515	for(w=0; w<words.length; w++) {
5516		if(w > 0) {
5517			s = s + " ";
5518		}
5519		s = s + words[w];
5520	}
5521	// re-concatenate parts split above
5522	s = s.replace("Mc ", "Mc");
5523	s = s.replace("' ", "'");
5524	s = s.replace("- ", "-");
5525	// un-capitalise joining words
5526	s = s.replace("De ", "de ");
5527	s = s.replace("Du ", "du ");
5528	s = s.replace("Dos ", "dos ");
5529	s = s.replace("Den ", "den ");
5530	s = s.replace("Der ", "der ");
5531	s = s.replace("Le ", "le ");
5532	s = s.replace("El ", "el ");
5533	s = s.replace("Van ", "van ");
5534	return s;
5535}
5536
5537function addressCountryChange() {
5538	document.getElementById("user_state_id").value = 0;
5539	getStateListForCountry("user_country_id", "user_state_id", "addressStateRow");
5540	airline = document.getElementById("user_airline_id").value;
5541	if(airline == 1) {
5542		getTimezoneListForCountry("user_country_id", "user_state_id", "user_default_timezone_id");
5543	}
5544	checkUserChanges();
5545}
5546
5547function addressStateChange() {
5548	checkUserChanges();
5549	airline = document.getElementById("user_airline_id").value;
5550	if(airline == 1) {
5551		getTimezoneListForCountry("user_country_id", "user_state_id", "user_default_timezone_id");
5552	}
5553}
5554
5555function settingsAddressCountryChange() {
5556	document.getElementById("user_state_id").value = 0;
5557	getStateListForCountry("user_country_id", "user_state_id", "addressStateRow");
5558	checkSettingsChanges();
5559}
5560
5561function settingsAirlineAddressCountryChange() {
5562	document.getElementById("employer_state_id").value = 0;
5563	getStateListForCountry("employer_country_id", "employer_state_id", "employerAddressStateRow");
5564	getTimezoneListForCountry("employer_country_id", "employer_state_id", "settings_default_timezone_id");
5565	checkSettingsChanges();
5566}
5567
5568function settingsAirlineAddressStateChange() {
5569	airline = document.getElementById("settings_airline_id").value;
5570	getTimezoneListForCountry("employer_country_id", "employer_state_id", "settings_default_timezone_id");
5571	checkSettingsChanges();
5572}
5573
5574function settingsAirlineChange() {
5575	//checkSettingsChanges();
5576	var airline_id = document.getElementById("settings_airline_id").value;
5577	getAirlineDefaultsForSettings(airline_id, false);		//update address and basic details
5578	dashboard_confirm("Change Airline Settings", "Do you wish to automatically update your limitations settings, or retain the existing values and modify them manually?", "Update", "Retain", function() {getAirlineDefaultsForSettings(airline_id, true);}, false);
5579}
5580
5581function getAirlineDefaultsForSettings(airline_id, include_limitations) {
5582	var xmlHttp = createXMLHttpRequest();
5583	if(xmlHttp) {
5584		xmlHttp.onreadystatechange = function(){airlineDefaultsResult(xmlHttp, include_limitations);};
5585		xmlHttp.open("post", "/log/ajax/getDefaultsForAirline.php", true);
5586		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
5587		var data  = "id=" +	encodeURIComponent(airline_id);
5588		xmlHttp.send(data);
5589	}
5590}
5591
5592function airlineDefaultsResult(xmlHttp, include_limitations) {
5593	var xml = getXmlContent(xmlHttp);
5594	if(xml[3]) {				//received with no errors
5595		error = getXmlField(xml[0], "error");
5596		if(error == "OK") {
5597			response = xml[0];
5598			airline_name = getXmlField(response, "airline_name");
5599			if(airline_name == "[Other]") {
5600				document.getElementById("settings_employer").value = "";
5601				document.getElementById("settings_employer").disabled = false;
5602				document.getElementById("settings_employer").focus();
5603			} else {
5604				document.getElementById("settings_employer").value = airline_name;
5605				document.getElementById("settings_employer").disabled = true;
5606				getTimezoneListForAirline("settings_airline_id", "settings_default_timezone_id");
5607			}
5608			document.getElementById("employer_address_1").value = getXmlField(response, "address_1");
5609			document.getElementById("employer_address_2").value = getXmlField(response, "address_2");
5610			document.getElementById("employer_address_3").value = getXmlField(response, "address_3");
5611			document.getElementById("employer_address_town").value = getXmlField(response, "town");
5612			document.getElementById("employer_address_county").value = getXmlField(response, "county");
5613			document.getElementById("employer_address_postcode").value = getXmlField(response, "postcode");
5614			document.getElementById("employer_country_id").value = getXmlField(response, "country_id");
5615			document.getElementById("settings_base_airfields").value = getXmlField(response, "base_airfields");
5616			if(include_limitations) {
5617				auto_update_limitations = true;			//override warning to user as we have already asked
5618				document.getElementById("settings_duty_ruleset").value = getXmlField(response, "duty_rules");
5619				settingsRulesChange();
5620				document.getElementById("settings_default_flight_report").value = getXmlField(response, "default_report");
5621				document.getElementById("settings_default_flight_clear").value = getXmlField(response, "default_clear");
5622				document.getElementById("settings_default_sim_report").value = getXmlField(response, "default_sim_report");
5623				document.getElementById("settings_default_sim_clear").value = getXmlField(response, "default_sim_clear");
5624				deleteAllReportExceptions();
5625				var report_exceptions = response.getElementsByTagName("exception");
5626				for(n=0; n<report_exceptions.length; n++) {
5627					var airport = getXmlField(report_exceptions[n], "airport");
5628					var report = getXmlField(report_exceptions[n], "report");
5629					var clear = getXmlField(report_exceptions[n], "clear");
5630					addReportException(airport, report, clear);
5631				}
5632				showSettingsSection("limitations");		//open tab if not already visible so user can see changes
5633				document.getElementById("settings_statistical_week_start").value = getXmlField(response, "week_starts");
5634				document.getElementById("settings_statistical_year_start").value = getXmlField(response, "year_starts");
5635				document.getElementById("settings_split_flights").value = getXmlField(response, "midnight_split");
5636				document.getElementById("settings_ftl_exclude_other").value = getXmlField(response, "exclude_other");
5637			} else {
5638				checkSettingsChanges();
5639			}
5640		} else {
5641			dashboardErrorMessage(error);
5642		}
5643	} else if(xml[4] == 500) {			//server error
5644		dashboardErrorMessage("Server error (HTTP 500)<br /><br />If this error persists, please contact support");
5645	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
5646	} else if(xml[0])	{				//received with error
5647		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
5648			dashboardForceReload();
5649		} else if(xml[0].toUpperCase() == "SUSPENDED") {
5650			showSubscriptionPopup(true);
5651		} else {
5652			dashboardErrorMessage(xml[0]);
5653		}
5654	}
5655}
5656
5657function settingsRulesChange() {
5658	//checkSettingsChanges();
5659	var rules_id = document.getElementById("settings_duty_ruleset").value;
5660	if(auto_update_limitations) {				//triggered by airline change; do not ask again
5661		auto_update_limitations = false;		//reset for future calls
5662		getLimitationsForSettings(rules_id);
5663	} else {									//manual rules change; check whether to update
5664		dashboard_confirm("Change Limitations Settings", "Do you wish to automatically update your limitations settings, or retain the existing values and modify them manually?", "Update", "Retain", function() {getLimitationsForSettings(rules_id);}, function() {checkSettingsChanges();});
5665	}
5666}
5667
5668function getLimitationsForSettings(rules_id) {
5669	var xmlHttp = createXMLHttpRequest();
5670	if(xmlHttp) {
5671		xmlHttp.onreadystatechange = function(){limitationsResult(xmlHttp);};
5672		xmlHttp.open("post", "/log/ajax/getLimitsForDutyRules.php", true);
5673		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
5674		var data  = "id=" +	encodeURIComponent(rules_id);
5675		xmlHttp.send(data);
5676	}
5677}
5678
5679function limitationsResult(xmlHttp) {
5680	var xml = getXmlContent(xmlHttp);
5681	if(xml[3]) {				//received with no errors
5682		error = getXmlField(xml[0], "error");
5683		if(error == "OK") {
5684			showSettingsSection("limitations");		//open tab if not already visible so user can see changes
5685			response = xml[0];
5686			var flight_limits = response.getElementsByTagName("flight_limit");
5687			var duty_limits = response.getElementsByTagName("duty_limit");
5688			for(l=1; l<=num_flight_limitations; l++) {
5689				var field = "limitations_flight_"+l;
5690				var hours = getXmlField(flight_limits[l-1], "hours");
5691				var num = getXmlField(flight_limits[l-1], "num");
5692				var period = getXmlField(flight_limits[l-1], "period");
5693				var container = document.getElementById("flight_limitations_container");
5694				var element = document.getElementById(field+"_view");
5695				if(hours == "") {
5696					document.getElementById(field+"_hours").value = "";
5697					document.getElementById(field+"_num").value = "";
5698					document.getElementById(field+"_period").value = "DAY";
5699					element.className = "hidden";
5700				} else {
5701					container.append(element);			//move element to bottom of list
5702					document.getElementById(field+"_hours").value = hours;
5703					document.getElementById(field+"_num").value = num;
5704					document.getElementById(field+"_period").value = period;
5705					element.className = "dashboard_input";
5706				}
5707			}
5708			for(l=1; l<=num_duty_limitations; l++) {
5709				var field = "limitations_duty_"+l;
5710				var hours = getXmlField(duty_limits[l-1], "hours");
5711				var num = getXmlField(duty_limits[l-1], "num");
5712				var period = getXmlField(duty_limits[l-1], "period");
5713				var container = document.getElementById("duty_limitations_container");
5714				var element = document.getElementById(field+"_view");
5715				if(hours == "") {
5716					document.getElementById(field+"_hours").value = "";
5717					document.getElementById(field+"_num").value = "";
5718					document.getElementById(field+"_period").value = "DAY";
5719					element.className = "hidden";
5720				} else {
5721					container.append(element);			//move element to bottom of list
5722					document.getElementById(field+"_hours").value = hours;
5723					document.getElementById(field+"_num").value = num;
5724					document.getElementById(field+"_period").value = period;
5725					element.className = "dashboard_input";
5726				}
5727			}
5728			checkSettingsChanges();
5729		} else {
5730			dashboardErrorMessage(error);
5731		}
5732	} else if(xml[4] == 500) {			//server error
5733		dashboardErrorMessage("Server error (HTTP 500)<br /><br />If this error persists, please contact support");
5734	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
5735	} else if(xml[0])	{				//received with error
5736		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
5737			dashboardForceReload();
5738		} else if(xml[0].toUpperCase() == "SUSPENDED") {
5739			showSubscriptionPopup(true);
5740		} else {
5741			dashboardErrorMessage(xml[0]);
5742		}
5743	}
5744}
5745
5746var add_user_last_promo_code = "#";
5747var add_user_last_referrer_text = "#";
5748function referrerChange() {
5749	checkUserChanges();
5750	ref_id = document.getElementById("user_referrer_id").value;
5751	ref_text = document.getElementById("user_referrer").value;
5752	promo_code = document.getElementById("user_promo_code").value;
5753	if(ref_text != add_user_last_referrer_text || promo_code != add_user_last_promo_code) {		//prevent multiple calls
5754		getReferrerList(ref_id, ref_text, "y", promo_code);
5755	}
5756	add_user_last_promo_code = promo_code;
5757	add_user_last_referrer_text = ref_text;
5758}
5759
5760function getReferrerList(select_id, match, with_promo, promo_code) {
5761	var xmlHttp = createXMLHttpRequest();
5762	if(xmlHttp) {
5763		xmlHttp.onreadystatechange = function(){referrerResult(xmlHttp);};
5764		xmlHttp.open("post", "/log/ajax/usersList.php", true);
5765		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
5766		var data  = "select_id=" +		encodeURIComponent(select_id);
5767		data  += "&match=" +		encodeURIComponent(match);
5768		data  += "&with_promo=" +	encodeURIComponent(with_promo);
5769		data  += "&match_promo=" +	encodeURIComponent(promo_code);
5770		xmlHttp.send(data);
5771	}
5772}
5773
5774function referrerResult(xmlHttp) {
5775	var xml = getXmlContent(xmlHttp);
5776	if(xml[3]) {
5777		error = getXmlField(xml[0], "error");
5778		if(error == "OK") {
5779			response = xml[0];
5780			selObj = document.getElementById("user_referrer_id");
5781			selObj = clearSelect(selObj);
5782			entries = response.getElementsByTagName('option');
5783			for(n=0; n<entries.length; n++) {
5784				id = getXmlField(entries[n], "id");
5785				text = getXmlField(entries[n], "text");
5786				sel = getXmlField(entries[n], "selected");
5787				addToSelect(selObj, text, id);
5788				if(sel == "y") {
5789					selObj.selectedIndex = n;
5790				}
5791			}
5792		} else {
5793			dashboardErrorMessage(error);
5794		}
5795	} else if(xml[4] == 500) {			//server error
5796		dashboardErrorMessage("Server error (HTTP 500)<br /><br />If this error persists, please contact support");
5797	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
5798	} else if(xml[0])	{				//received with error
5799		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
5800			dashboardForceReload();
5801		} else if(xml[0].toUpperCase() == "SUSPENDED") {
5802			showSubscriptionPopup(true);
5803		} else {
5804			dashboardErrorMessage(xml[0]);
5805		}
5806	}
5807}
5808
5809function clearSelect(object){
5810	var selectParentNode = object.parentNode;
5811	var newSelectObj = object.cloneNode(false);				// Make a shallow copy
5812	selectParentNode.replaceChild(newSelectObj, object);
5813	return newSelectObj;
5814}
5815
5816function addToSelect(object, text, value){
5817	var optionObject = document.createElement('option');
5818	optionObject.text = text;
5819	optionObject.value = value;
5820	try {
5821		object.add(optionObject, null);
5822	} catch(ex) {
5823		object.add(optionObject);
5824	}
5825}
5826
5827function airlineChange() {
5828	checkUserChanges();
5829	airline_id = document.getElementById("user_airline_id").value;
5830	if(airline_id == 1) {		// [Other]
5831		document.getElementById("user_employer").value = "";
5832		getTimezoneListForCountry("user_country_id", "user_state_id", "user_default_timezone_id");
5833	} else {
5834		getAirlineSettings(airline_id);
5835	}
5836}
5837
5838function getAirlineSettings(airline_id) {
5839	var xmlHttp = createXMLHttpRequest();
5840	if(xmlHttp) {
5841		xmlHttp.onreadystatechange = function(){airlineSettingsResult(xmlHttp);};
5842		xmlHttp.open("post", "/log/ajax/getDefaultsForAirline.php", true);
5843		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
5844		var data  = "id=" +	encodeURIComponent(airline_id);
5845		xmlHttp.send(data);
5846	}
5847}
5848
5849function airlineSettingsResult(xmlHttp) {
5850	var xml = getXmlContent(xmlHttp);
5851	if(xml[3]) {				//received with no errors
5852		error = getXmlField(xml[0], "error");
5853		if(error == "OK") {
5854			response = xml[0];
5855			getTimezoneListForAirline("user_airline_id", "user_default_timezone_id");
5856			document.getElementById("user_duty_rules_id").value = getXmlField(response, "duty_rules");
5857			airline_name = getXmlField(response, "airline_name");
5858			if(airline_name == "[Other]") {
5859				document.getElementById("user_employer").value = "";
5860			} else {
5861				document.getElementById("user_employer").value = airline_name;
5862			}
5863		} else {
5864			dashboardErrorMessage(error);
5865		}
5866	} else if(xml[4] == 500) {			//server error
5867		dashboardErrorMessage("Server error (HTTP 500)<br /><br />If this error persists, please contact support");
5868	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
5869	} else if(xml[0])	{				//received with error
5870		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
5871			dashboardForceReload();
5872		} else if(xml[0].toUpperCase() == "SUSPENDED") {
5873			showSubscriptionPopup(true);
5874		} else {
5875			dashboardErrorMessage(xml[0]);
5876		}
5877	}
5878}
5879
5880
5881// end add user code
5882
5883// add flight code
5884
5885function manualHoursBreakdown() {
5886	checkFlightChanges();
5887	var view = "";
5888	var edit = "hidden";
5889	var total_title = "Total";
5890	if(document.getElementById('flight_manual_breakdown').value == "y") {
5891		view = "hidden";
5892		edit = "";
5893		total_title = "Calculated";
5894	}
5895	document.getElementById("flight_hours_entered").className = edit;
5896	document.getElementById("flight_hours_instrument_view").className = view;
5897	document.getElementById("flight_hours_instrument_edit").className = edit;
5898	var num_capacities = flight_capacities.length;
5899	for(c=0; c<num_capacities; c++) {
5900		document.getElementById("flight_hours_day_"+flight_capacities[
5900c]+"_view").className = view;
5901		document.getElementById("flight_hours_day_"+flight_capacities[c]+"_edit").className = edit;
5902		document.getElementById("flight_hours_night_"+flight_capacities[c]+"_view").className = view;
5903		document.getElementById("flight_hours_night_"+flight_capacities[c]+"_edit").className = edit;
5904	}
5905	document.getElementById("flight_day_takeoffs_view").className = view;
5906	document.getElementById("flight_day_takeoffs_edit").className = edit;
5907	document.getElementById("flight_night_takeoffs_view").className = view;
5908	document.getElementById("flight_night_takeoffs_edit").className = edit;
5909	document.getElementById("flight_day_landings_view").className = view;
5910	document.getElementById("flight_day_landings_edit").className = edit;
5911	document.getElementById("flight_night_landings_view").className = view;
5912	document.getElementById("flight_night_landings_edit").className = edit;
5913	document.getElementById("flight_day_distance_view").className = view;
5914	document.getElementById("flight_day_distance_edit").className = edit;
5915	document.getElementById("flight_night_distance_view").className = view;
5916	document.getElementById("flight_night_distance_edit").className = edit;
5917	document.getElementById("flight_hours_day_cross_country_view").className = view;
5918	document.getElementById("flight_hours_day_cross_country_edit").className = edit;
5919	document.getElementById("flight_hours_night_cross_country_view").className = view;
5920	document.getElementById("flight_hours_night_cross_country_edit").className = edit;
5921
5922	document.getElementById("hours_total_title").innerHTML = total_title;
5923}
5924
5925function getClosestAirport(id, callback) {
5926	if(!editing_locked) {
5927		if(navigator.geolocation) {
5928			document.getElementById(id).value = "";
5929			document.getElementById(id + "_description").innerHTML = "Please wait...";
5930			var options = {
5931				enableHighAccuracy: true,
5932				timeout: 30000,
5933				maximumAge: 600000
5934			};
5935			navigator.geolocation.getCurrentPosition(callback, positionError);
5936		} else {
5937			dashboardErrorMessage("Position information unavailable");
5938		}
5939	}
5940}
5941
5942function setClosestAirportFrom(position) {
5943	setClosestAirport(position, "flight_from");
5944}
5945
5946function setClosestAirportTo(position) {
5947	setClosestAirport(position, "flight_to");
5948}
5949
5950function positionError(error) {
5951switch(error.code) {
5952	case error.PERMISSION_DENIED:
5953		dashboardErrorMessage("User denied the request for Geolocation.");
5954		break;
5955	case error.POSITION_UNAVAILABLE:
5956		dashboardErrorMessage("Location information is unavailable.");
5957		break;
5958	case error.TIMEOUT:
5959		dashboardErrorMessage("The request to get user location timed out.");
5960		break;
5961	case error.UNKNOWN_ERROR:
5962		dashboardErrorMessage("An unknown error occurred.");
5963		break;
5964	}
5965}
5966
5967function setClosestAirport(position, id) {
5968	var xmlHttp = createXMLHttpRequest();
5969	if(xmlHttp) {
5970		xmlHttp.onreadystatechange = function(){setClosestAirportResult(xmlHttp, id);};
5971		xmlHttp.open("post", "/log/ajax/closestAirport.php", true);
5972		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
5973		var data  = "lat=" +	encodeURIComponent(position.coords.latitude);
5974		data += "&lon=" +	encodeURIComponent(position.coords.longitude);
5975		xmlHttp.send(data);
5976	}
5977}
5978
5979function setClosestAirportResult(xmlHttp, id) {
5980	var xml = getXmlContent(xmlHttp);
5981	if(xml[3]) {				//received with no errors
5982		error = getXmlField(xml[0], "error");
5983		if(error == "OK") {
5984			response = xml[0];
5985			document.getElementById(id).value = getXmlField(response, "airport");
5986			checkFlightChanges();
5987		} else {
5988			dashboardErrorMessage(error);
5989		}
5990	} else if(xml[4] == 500) {			//server error
5991		dashboardErrorMessage("Server error (HTTP 500)<br /><br />If this error persists, please contact support");
5992	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
5993	} else if(xml[0])	{				//received with error
5994		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
5995			dashboardForceReload();
5996		} else if(xml[0].toUpperCase() == "SUSPENDED") {
5997			showSubscriptionPopup(true);
5998		} else {
5999			dashboardErrorMessage(xml[0]);
6000		}
6001	}
6002}
6003
6004function showFlightPlannedTimes() {
6005	document.getElementById("field_plan_button").className = "hidden";
6006	document.getElementById("field_plan_date").className = "dashboard_input";
6007	document.getElementById("field_plan_times").className = "dashboard_input";
6008}
6009
6010function showMoreFlightCrew() {
6011	document.getElementById("field_crew_button").className = "hidden";
6012	document.getElementById("field_name_p2").className = "dashboard_input";
6013	if(user_is_pro == "y") {
6014		document.getElementById("field_name_heavy_1").className = "dashboard_input";
6015		document.getElementById("field_name_heavy_2").className = "dashboard_input";
6016		document.getElementById("field_name_scc").className = "dashboard_input";
6017		document.getElementById("field_add_crew_button").className = "dashboard_input";
6018	}
6019}
6020
6021function addExtraFlightCrew() {
6022	if(!editing_locked) {
6023		var new_index = 0;
6024		while(document.getElementById("flight_extra_crew_" + new_index)) {
6025			new_index++;
6026		}
6027		var node = document.getElementById("extra_crew_clone");
6028		var new_node = node.cloneNode(true);
6029		new_node.setAttribute("id", "flight_extra_crew_row_" + new_index);
6030		new_node.className = "dashboard_input";
6031		children = new_node.childNodes;
6032		for(n=0; n < children.length; n++) {
6033			if(children[n].id == "flight_extra_crew_n_initial") {
6034				children[n].id = "flight_extra_crew_" + new_index + "_initial";
6035			} else if(children[n].id == "flight_extra_crew_n") {
6036				children[n].id = "flight_extra_crew_" + new_index;
6037				children[n].setAttribute("onkeyup", 'getCrewNames("flight_extra_crew_' + new_index + '")');
6038				children[n].setAttribute("onblur", 'hideAutocomplete("flight_extra_crew_' + new_index + '")');
6039			} else if(children[n].id == "flight_extra_crew_copy_n") {
6040				children[n].id = "flight_extra_crew_copy_" + new_index;
6041				children[n].onclick = function() {
6042					dashboardCopy("flight_extra_crew_" + new_index, function(){checkFlightChanges();});
6043				};
6044			}
6045
6046		}
6047		document.getElementById("extra_crew_container").appendChild(new_node);
6048	}
6049}
6050
6051
6052// end add flight code
6053
6054// add sim code
6055
6056function toggleSimDuration() {
6057	var times = document.getElementById("field_sim_times");
6058	var duration = document.getElementById("field_sim_duration");
6059	var duration_only = document.getElementById("duration_only");
6060	if(times.className == "hidden") {
6061		times.className = "";
6062		duration.className = "hidden";
6063		duration_only.value = "n";
6064	} else {
6065		times.className = "hidden";
6066		duration.className = "";
6067		duration_only.value = "y";
6068	}
6069	checkSimChanges();
6070}
6071
6072function showMoreSimCrew() {
6073	document.getElementById("field_crew_button").className = "hidden";
6074	document.getElementById("field_name_p2").className = "dashboard_input";
6075	document.getElementById("field_add_crew_button").className = "dashboard_input";
6076}
6077
6078function addExtraSimCrew() {
6079	if(!editing_locked) {
6080		var new_index = 0;
6081		while(document.getElementById("sim_extra_crew_" + new_index)) {
6082			new_index++;
6083		}
6084		var node = document.getElementById("extra_crew_clone");
6085		var new_node = node.cloneNode(true);
6086		new_node.setAttribute("id", "sim_extra_crew_row_" + new_index);
6087		new_node.className = "dashboard_input";
6088		children = new_node.childNodes;
6089		for(n=0; n < children.length; n++) {
6090			if(children[n].id == "sim_extra_crew_n_initial") {
6091				children[n].id = "sim_extra_crew_" + new_index + "_initial";
6092			} else if(children[n].id == "sim_extra_crew_n") {
6093				children[n].id = "sim_extra_crew_" + new_index;
6094				children[n].setAttribute("onkeyup", 'getCrewNames("sim_extra_crew_' + new_index + '")');
6095				children[n].setAttribute("onblur", 'hideAutocomplete("sim_extra_crew_' + new_index + '")');
6096			} else if(children[n].id == "sim_extra_crew_copy_n") {
6097				children[n].id = "sim_extra_crew_copy_" + new_index;
6098				children[n].onclick = function() {
6099					dashboardCopy("sim_extra_crew_" + new_index, function(){checkSimChanges();});
6100				};
6101			}
6102
6103		}
6104		document.getElementById("extra_crew_container").appendChild(new_node);
6105	}
6106}
6107
6108//end add sim code
6109
6110//add duty code
6111
6112
6113
6114//end add duty code
6115
6116//settings code
6117
6118function handleDropProfilePhoto(e) {
6119	dt = e.dataTransfer;
6120	files = dt.files;
6121	handlePhotoFile(files);
6122}
6123
6124function handlePhotoFile(files) {
6125	if(files) {
6126		if(files.length > 0) {
6127			document.getElementById("profile_photo").src = "/log/profile_photos/blank.jpg";
6128			uploadFile(files[0]);
6129		}
6130	}
6131}
6132
6133function uploadFile(file) {
6134	var url = '/log/ajax/uploadProfilePhoto.php';
6135	xmlHttp = new XMLHttpRequest();
6136	var formData = new FormData();
6137	xmlHttp.open('POST', url, true);
6138	xmlHttp.addEventListener('readystatechange', function(){modifyProfilePhotoResult(xmlHttp);});
6139	formData.append('file', file);
6140	xmlHttp.send(formData);
6141}
6142
6143function removePhoto() {
6144	dashboard_confirm("Remove Photo", "Do you wish to permanently delete your profile photo?", "Yes", "No", actuallyRemovePhoto, false);
6145}
6146
6147function actuallyRemovePhoto() {
6148	var url = '/log/ajax/removeProfilePhoto.php';
6149	xmlHttp = new XMLHttpRequest();
6150	xmlHttp.open('POST', url, true);
6151	xmlHttp.addEventListener('readystatechange', function(){modifyProfilePhotoResult(xmlHttp);});
6152	var formData = new FormData();
6153	xmlHttp.send(formData);
6154}
6155
6156function modifyProfilePhotoResult(xmlHttp) {
6157	var xml = getXmlContent(xmlHttp);
6158	if(xml[3]) {				//received with no errors
6159		error = getXmlField(xml[0], "error");
6160		if(error == "OK") {
6161			document.getElementById("profile_photo").src = "profilePhoto.php?refresh=" + new Date().getTime();
6162		} else {
6163			dashboardErrorMessage(error);
6164		}
6165	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
6166	} else if(xml[0]) {					//received with error
6167		dashboardErrorMessage(xml[0]);
6168	}
6169}
6170
6171//end settings code
6172
6173
6174
6175
6176// calendar code
6177
6178var calDates=new Array();
6179var displayingDate = new Date();
6180var	selDate = new Date();
6181var calField = false;
6182var callback = function() {return true;};
6183var allowHideCalendar = true;
6184var dashboardCalendarVisible = false;
6185
6186var calendarAction = false;
6187
6188function fillCalendar() {         // uses global variables yr and mt for year and month to display
6189	yr=displayingDate.getUTCFullYear();
6190	mt=displayingDate.getUTCMonth();
6191
6192	monthnames=new Array("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec")
6193	monthlength=new Array(31,1,31,30,31,30,31,31,30,31,30,31)    //feb left to be set depending on leap years
6194	monthlength[1]=daysInFeb(yr)    //set days in feb as appropriate
6195
6196	ddd=new Date(yr, mt, 1)
6197	startday=ddd.getDay()
6198	if(startday==0) {
6199		startday=7
6200	}
6201	strmonth=mt+1;
6202	if(strmonth<10){strmonth='0'+strmonth;}
6203	enddate=monthlength[mt];
6204	ttext=monthnames[mt] + " (" + (mt+1) + ") " + yr;
6205	document.getElementById('dashboard_calendar_title_text').innerHTML=ttext;
6206	nextday=1
6207	for(rows=1; rows<7; rows++) {
6208		for(cols=1; cols<8; cols++) {
6209			ref=(rows*10)+cols;
6210			calDates[ref]=false;
6211			if(nextday>1 && nextday<=enddate || cols>=startday && nextday<=enddate) {
6212				document.getElementById('calpopcell' + ref).style.cursor="pointer";
6213				cellcontent=nextday;
6214				strday=nextday;
6215				if(strday<10){strday='0'+strday;}
6216				calDates[ref]=yr+"-"+strmonth+"-"+strday;
6217				nowd=selDate.getUTCDate();
6218				nowm=selDate.getUTCMonth();
6219				nowy=selDate.getUTCFullYear();
6220				if(nowd==nextday && nowm==mt && nowy==yr) {
6221					cellcontent="<div class='calendar_today'>" + nextday + "</div>";
6222				}
6223				document.getElementById('calpopcell' + ref).innerHTML=cellcontent;
6224				++nextday;
6225			} else {
6226				document.getElementById('calpopcell' + ref).style.cursor="default";
6227				document.getElementById('calpopcell' + ref).innerHTML="&nbsp;";
6228			}
6229		}
6230	}
6231}
6232
6233function showDashboardCalendar(field, fn) {	
6234	dashboardBodyClicked();
6235	calendar_callback = fn;
6236	dtObj = getDateFromTextField(field, date_format_setting);
6237	if(dtObj) {
6238		displayingDate = dtObj;
6239		selDate = dtObj;
6240	}
6241	calField = field;
6242	fillCalendar();
6243	document.getElementById('dashboard_calendar_popup').className = 'calendar_visible';
6244	dashboardCalendarVisible = true;
6245	positionCalendarNextToField(field);
6246	allowHideCalendar = false;
6247	window.setTimeout(function () { allowHideCalendar = true; }, 200);
6248}
6249
6250function updateCalendarDate(field) {
6251	dtObj = getDateFromTextField(field, date_format_setting);
6252	if(dtObj) {
6253		displayingDate = dtObj;
6254		selDate = dtObj;
6255		fillCalendar();
6256	}
6257}
6258
6259function getDateFromTextField(field, format) {
6260	var dt = document.getElementById(field).value;
6261	var dtObj = new Date();
6262	var valid = true;
6263	if(dt != "") {
6264		dd = 0;
6265		bits = dt.split("/");
6266		if(bits.length == 1) {
6267			bits = dt.split(".");
6268		}
6269		if(bits.length == 1) {
6270			bits = dt.split("-");
6271		}
6272		if(bits.length == 3) {
6273			if(format == "dmy") {
6274				dd = bits[0];
6275				mm = bits[1];
6276				yy = bits[2];
6277			} else if(format == "mdy") {
6278				dd = bits[1];
6279				mm = bits[0];
6280				yy = bits[2];
6281			} else if(format == "ymd") {
6282				dd = bits[2];
6283				mm = bits[1];
6284				yy = bits[0];
6285			}
6286			if(!isNumber(dd) || !isNumber(mm) || !isNumber(yy)) {
6287				valid = false;
6288			}
6289			dd = parseInt(dd, 10);
6290			mm = parseInt(mm, 10);
6291			yy = parseInt(yy, 10);
6292			if(dd == 0 || mm == 0 || yy == 0) {
6293				valid = false;
6294			}
6295		} else {
6296			valid = false;
6297		}
6298
6299		if(valid) {
6300			if(yy < 1900 && yy >= 100) {
6301				valid = false;
6302			}
6303		}
6304		if(valid) {
6305			if(yy < 100) {
6306				now = new Date();
6307				currentYear = now.getFullYear().toString();
6308				century = currentYear.substring(0, 2);
6309				if(yy < 10) {
6310					yearZero = "0";
6311				} else {
6312					yearZero = "";
6313				}
6314				yy = century + yearZero + yy;
6315				currentYear = parseInt(currentYear, 10) + 50;
6316				if(yy > currentYear) {
6317					yy -= 100;		//dates more than 'rollCentury' years in the future are assumed to be in the past
6318				}
6319			}
6320		}
6321		if(valid) {
6322			if(isNumber(dd) && isNumber(mm) && isNumber(yy)) {
6323				mm = mm - 1;
6324				if(mm < 0){mm = 11;}
6325				dtObj.setFullYear(yy, mm, dd);
6326			} else {
6327				valid = false;
6328			}
6329		}
6330		if(!valid) {
6331			dtObj = false;
6332		}
6333	}
6334	return dtObj;
6335}
6336
6337function isNumber(n) {
6338	return !isNaN(parseFloat(n)) && isFinite(n);
6339}
6340
6341function daysInMonth(month_text, year_text) {
6342	var month = parseInt(month_text, 10);
6343	var year = parseInt(year_text, 10);
6344	var monthLength = new Array('0','31','0','31','30','31','30','31','31','30','31','30','31');		//first month is index 0 in array
6345	monthLength[2] = daysInFeb(year);
6346	return monthLength[month];
6347}
6348
6349function daysInFeb(year) {
6350	var days = 28;
6351	if((year/4) == Math.floor(year/4)) {
6352		days = 29;
6353	}
6354	if((year/100) == Math.floor(year/100)) {
6355		days = 28;
6356	}
6357	if((year/400) == Math.floor(year/400)) {
6358		days = 29;
6359	}
6360	return days; 
6361}
6362
6363
6364function positionAutocompleteNextToField(field) {
6365	document.getElementById('autocomplete').style.width = (field_object.offsetWidth - 60) + "px";
6366	x += 30;
6367	y += field_object.offsetHeight;
6368	document.getElementById('autocomplete').style.left = x+"px";
6369	document.getElementById('autocomplete').style.top = y+"px";
6370}
6371
6372
6373function positionCalendarNextToField(field) {
6374	field_object = document.getElementById(field);
6375	var x = field_object.offsetLeft;
6376	var y = field_object.offsetTop;
6377	var parent = field_object.parentElement;
6378	var parent_width = parent.offsetWidth;
6379	while(parent) {
6380		x += parent.offsetLeft;
6381		y += parent.offsetTop;
6382		parent = parent.parentElement;
6383		if(parent.id == "dashboard_editing_page_container" || parent.id == "filter_block" || parent.id == "map_options" || parent.id == "mod_provisional_options") {
6384			break;
6385		}
6386	}
6387	winW = document.body.offsetWidth;
6388	winH = document.body.offsetHeight;
6389	calWidth = document.getElementById('dashboard_calendar_popup').offsetWidth;
6390	fieldWidth = field_object.offsetWidth;
6391	x -= (calWidth - fieldWidth) / 2;
6392	if(x + calWidth > winW) {
6393		x = winW - calWidth;
6394	}
6395	if(x + calWidth > parent_width) {
6396		x = parent_width - calWidth;
6397	}
6398	if(x < 0) {
6399		x = 0;
6400	}
6401	y += document.getElementById(field).offsetHeight;
6402	document.getElementById('dashboard_calendar_popup').style.left = x+"px";
6403	document.getElementById('dashboard_calendar_popup').style.top = y+"px";
6404}
6405
6406function hideDashboardCalendar() {
6407	if(allowHideCalendar) {
6408		if(document.getElementById('dashboard_calendar_popup')) {
6409			document.getElementById('dashboard_calendar_popup').className='hidden';
6410			calField = false;
6411			dashboardCalendarVisible = false;
6412		}
6413	}
6414}
6415
6416function jumpToday() {
6417	displayingDate = new Date();
6418	selDate = displayingDate;
6419	fillCalendar();
6420	today = displayingDate.toISOString().substring(0, 10);
6421	for(ref=0; ref<calDates.length; ref++) {
6422		if(calDates[ref] == today) {
6423			calClick(ref);
6424			break;
6425		}
6426	}
6427}
6428
6429function previousMonth() {
6430	mt = displayingDate.getUTCMonth();
6431	yr = displayingDate.getUTCFullYear();
6432	mt--;
6433	if(mt<0) {
6434		mt=11;
6435		yr--;
6436	}
6437	displayingDate = new Date(yr, mt, 1, 12, 0, 0, 0);
6438	fillCalendar();
6439}
6440
6441function nextMonth() {
6442	mt = displayingDate.getUTCMonth();
6443	yr = displayingDate.getUTCFullYear();
6444	mt++;
6445	if(mt>11) {
6446		mt=0;
6447		yr++;
6448	}
6449	displayingDate = new Date(yr, mt, 1, 12, 0, 0, 0);
6450	fillCalendar();
6451}
6452
6453function previousYear() {
6454	mt = displayingDate.getUTCMonth();
6455	yr = displayingDate.getUTCFullYear();
6456	yr--;
6457	displayingDate = new Date(yr, mt, 1, 12, 0, 0, 0);
6458	fillCalendar();
6459}
6460
6461function nextYear() {
6462	mt = displayingDate.getUTCMonth();
6463	yr = displayingDate.getUTCFullYear();
6464	yr++;
6465	displayingDate = new Date(yr, mt, 1, 12, 0, 0, 0);
6466	fillCalendar();
6467}
6468
6469function calClick(ref) {
6470	if(calDates[ref] && calField) {
6471		dt = calDates[ref];
6472		year = dt.substring(0, 4);
6473		month = dt.substring(5, 7);
6474		day = dt.substring(8, 10);
6475		if(date_format_setting == "dmy") {
6476			dt = day+"/"+month+"/"+year;
6477		} else if(date_format_setting == "mdy") {
6478			dt = month+"/"+day+"/"+year;
6479		} else if(date_format_setting == "ymd") {
6480			dt = year+"-"+month+"-"+day;
6481		}
6482		document.getElementById(calField).value = dt;
6483		hideDashboardCalendar();
6484		if(calendar_callback) {
6485			calendar_callback();
6486			calendar_callback = null;
6487		}
6488	}
6489}
6490
6491function daysInFeb(y) {
6492	leapyear=0;
6493	a=y/4;
6494	b=Math.round(y/4);
6495	if(a==b) {
6496		leapyear=1;
6497	}
6498	c=y/100;
6499	d=Math.round(y/100);
6500	if(c==d) {
6501		leapyear=0;
6502	}
6503	c=y/400;
6504	d=Math.round(y/400);
6505	if(c==d) {
6506		leapyear=1;
6507	}
6508	feb=28+leapyear;
6509	return feb;
6510}
6511
6512//end calendar code
6513
6514function download(filename, text) {
6515  var element = document.createElement('a');
6516  element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text));
6517  element.setAttribute('download', filename);
6518
6519  element.style.display = 'none';
6520  document.body.appendChild(element);
6521
6522  element.click();
6523
6524  document.body.removeChild(element);
6525}
6526
6527const copyToClipboard = str => {
6528	const el = document.createElement('textarea');  // Create a <textarea> element
6529	el.value = str;                                 // Set its value to the string that you want copied
6530	el.setAttribute('readonly', '');                // Make it readonly to be tamper-proof
6531	el.style.position = 'absolute';                 
6532	el.style.left = '-9999px';                      // Move outside the screen to make it invisible
6533	document.body.appendChild(el);                  // Append the <textarea> element to the HTML document
6534	const selected =            
6535		document.getSelection().rangeCount > 0        // Check if there is any content selected previously
6536			? document.getSelection().getRangeAt(0)     // Store selection if found
6537			: false;                                    // Mark as false to know no selection existed before
6538	el.select();                                    // Select the <textarea> content
6539	document.execCommand('copy');                   // Copy - only works as a result of a user action (e.g. click events)
6540	document.body.removeChild(el);                  // Remove the <textarea> element
6541	if (selected) {                                 // If a selection existed before copying
6542		document.getSelection().removeAllRanges();    // Unselect everything on the HTML document
6543		document.getSelection().addRange(selected);   // Restore the original selection
6544	}
6545};
6546
6547function createXMLHttpRequest() {
6548	var xmlHttp = false;
6549	try {
6550		xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
6551	} catch (e) {
6552		try {
6553			xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
6554		} catch (E) {
6555			xmlHttp = false;
6556		}
6557	}
6558	if (!xmlHttp && typeof XMLHttpRequest!='undefined') {
6559		xmlHttp = new XMLHttpRequest();
6560	}
6561	return xmlHttp;
6562}
6563
6564function getXmlContent(xmlHttpObject) {
6565	/*
6566	Use the result flags to determine the level of error handling in the calling function.
6567	Check result[3] if you just want to see if the server response was OK and ignore errors
6568	Check result[2] if you want to see if a response was received then handle any errors generated by the server script
6569	Check result[1] if you want to handle errors in HTTP transmission (authentication, page not found, etc) - HTTP response code in result[4]
6570	*/
6571	result = Array();
6572	result[0] = false;		//xml content
6573	result[1] = false;		//flag for request completed
6574	result[2] = false;		//flag for HTML request OK
6575	result[3] = false;		//flag for OK or error
6576	result[4] = false;		//HTTP response code
6577	result[5] = xmlHttpObject.readyState;
6578	if(xmlHttpObject.readyState == 4) {					//request completed (0=uninitialised, 1=loading, 2=loaded, 3=interactive, 4=completed)
6579		result[1] = true;								//request completed
6580		result[4] = xmlHttpObject.status;
6581		if(result[4] == 200) {							//http 'OK' code
6582			//alert(xmlHttpObject.responseText);
6583			result[2] = true;							//HTML OK
6584			if(xmlHttpObject.responseXML) {
6585				xml = xmlHttpObject.responseXML.documentElement;
6586				if(xml.getElementsByTagName('error')[0]) {
6587					error = xml.getElementsByTagName('error')[0].firstChild.nodeValue;		//returns 'OK' or server error description e.g. 'Database Connect Failure'
6588				} else {
6589					error = "Invalid XML response\n\n"+xmlHttpObject.responseText;
6590				}
6591			} else {
6592				error = "Invalid XML response\n\n"+xmlHttpObject.responseText;
6593			}
6594			if(error == "OK") {
6595				result[3] = true;						//received OK without errors
6596				result[0] = xml;
6597			} else {
6598				result[0] = error;						//return error description
6599			}
6600		} else {
6601			result[0] = "HTTP Error " + result[4];		//return error description
6602		}
6603	}
6604	return result;
6605}
6606
6607function getXmlField(xml, field) {
6608	if(xml.getElementsByTagName(field)[0]) {
6609		if(xml.getElementsByTagName(field)[0].firstChild == null) {
6610			result = "Null XML field '"+field+"'";
6611		} else {
6612			if(xml.getElementsByTagName(field)[0].firstChild.textContent && xml.getElementsByTagName(field)[0].normalize) {
6613				xml.getElementsByTagName(field)[0].normalize(xml.getElementsByTagName(field)[0].firstChild);
6614				result = xml.getElementsByTagName(field)[0].firstChild.textContent;
6615			} else if(xml.getElementsByTagName(field)[0].firstChild.nodeValue) {
6616				result = xml.getElementsByTagName(field)[0].firstChild.nodeValue;
6617			} else {
6618				result = "";
6619			}
6620		}
6621	} else {
6622		result = "Missing XML field '"+field+"'";
6623	}
6624	if(result == "~") {
6625		result = "";
6626	}
6627 	return result;
6628}
6629
6630function getStateListForCountry(country, state, container_element) {
6631	var xmlHttp = createXMLHttpRequest();
6632	if(xmlHttp) {
6633		xmlHttp.onreadystatechange = function(){stateListResult(xmlHttp, state, container_element);};
6634		xmlHttp.open("post", "/log/ajax/stateList.php", true);
6635		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
6636		var data  = "country_id=" +	encodeURIComponent(document.getElementById(country).value);
6637		xmlHttp.send(data);
6638	}
6639}
6640
6641function stateListResult(xmlHttp, state, container_element) {
6642	xml = getXmlContent(xmlHttp);
6643	if(xml[3]) {
6644		response = xml[0];
6645		preSelect = 0;
6646		emptySelect(state);
6647		addOption(state, "", 0);
6648		empty = getXmlField(response, "empty");
6649		//debug(empty);
6650		if(empty == "y") {
6651			document.getElementById(container_element).className = "hidden";
6652		} else {
6653			list = response.getElementsByTagName('option');
6654			for(n=0; n<list.length; n++) {
6655				value = getXmlField(list[n], "id")
6656				name = getXmlField(list[n], "name")
6657				addOption(state, name, value);
6658			}
6659			document.getElementById(container_element).className = "";
6660		}
6661		if(document.getElementById(state+"_preset")) {
6662			preSelect = document.getElementById(state+"_preset").value;
6663		}
6664		document.getElementById(state).value = preSelect;
6665	} else if(xml[0]) {
6666		dashboardErrorMessage(xml[0]);
6667	}
6668}
6669
6670function getTimezoneListForCountry(country, state, timezone) {
6671	var xmlHttp = createXMLHttpRequest();
6672	if(xmlHttp) {
6673		xmlHttp.onreadystatechange = function(){timezoneListResult(xmlHttp, timezone);};
6674		xmlHttp.open("post", "/log/ajax/timezoneList.php", true);
6675		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
6676		var data  = "country_id=" +	encodeURIComponent(document.getElementById(country).value);
6677		if(state) {
6678			data += "&state_id=" +	encodeURIComponent(document.getElementById(state).value);
6679		}
6680		xmlHttp.send(data);
6681	}
6682}
6683
6684function getTimezoneListForAirline(airline, timezone) {
6685	var xmlHttp = createXMLHttpRequest();
6686	if(xmlHttp) {
6687		xmlHttp.onreadystatechange = function(){timezoneListResult(xmlHttp, timezone);};
6688		xmlHttp.open("post", "/log/ajax/timezoneList.php", true);
6689		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
6690		var data  = "airline_id=" +	encodeURIComponent(document.getElementById(airline).value);
6691		xmlHttp.send(data);
6692	}
6693}
6694
6695function timezoneListResult(xmlHttp, timezone) {
6696	var xml = getXmlContent(xmlHttp);
6697	if(xml[3]) {
6698		response = xml[0];
6699		emptySelect(timezone);
6700		list = response.getElementsByTagName('option');
6701		if(list.length != 1) {
6702			addOption(timezone, "", 0);
6703		}
6704		for(n=0; n<list.length; n++) {
6705			value = getXmlField(list[n], "id")
6706			name = getXmlField(list[n], "name")
6707			addOption(timezone, name, value);
6708		}
6709		if(list.length == 1) {
6710			document.getElementById(timezone).value = value;
6711		} else {
6712			document.getElementById(timezone).value = 0;
6713		}
6714	} else if(xml[0]) {
6715		dashboardErrorMessage(xml[0]);
6716	}
6717}
6718
6719function emptySelect(element) {
6720	document.getElementById(element).options.length = 0;
6721}
6722
6723function addOption(element, text, value) {
6724	document.getElementById(element).options[document.getElementById(element).options.length] = new Option(text, value);
6725}
6726
6727function getSimulatorNames() {
6728	if(document.getElementById("autocomplete_attached_field").value != "sim_name") {			//hide previous autocomplete if target field changed
6729		document.getElementById("autocomplete").className = "hidden";
6730	}
6731	document.getElementById("autocomplete_attached_field").value = "sim_name";
6732	positionAutocompleteNextToField("sim_name");
6733	text = document.getElementById("sim_name").value;
6734	if(document.getElementById("sim_name") === document.activeElement) {
6735		var xmlHttp = createXMLHttpRequest();
6736		if(xmlHttp) {
6737			xmlHttp.onreadystatechange = function(){autocompleteSimulatorResult(xmlHttp);};
6738			xmlHttp.open("post", "/log/ajax/simulatorList.php", true);
6739			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
6740			var data  = "text=" + encodeURIComponent(text);
6741			xmlHttp.send(data);
6742		}
6743	}
6744}
6745
6746function autocompleteSimulatorResult(xmlHttp) {
6747	if(document.getElementById("sim_name") === document.activeElement) {					//only do this if the field still has focus
6748		xml = getXmlContent(xmlHttp);
6749		if(xml[3]) {
6750			var list_content = document.getElementById("autocomplete_content");
6751			var html = "";
6752			response = xml[0];
6753			options = response.getElementsByTagName("option");
6754			if(options.length > 0) {
6755				for(n=0; n<options.length; n++) {
6756					name = options[n].getElementsByTagName("sim_name")[0].childNodes[0].nodeValue;
6757					type = options[n].getElementsByTagName("sim_type")[0].childNodes[0].nodeValue;
6758					aircraft = options[n].getElementsByTagName("sim_aircraft_id")[0].childNodes[0].nodeValue;
6759					//name = names[n].firstChild.nodeValue;
6760					html += "<div class='autocomplete_entry' onclick='autocompleteSimulator(\"" + name.replace(/\'/g, "&#039;") + "\", \"" + type + "\", \"" + aircraft + "\");'>" + name.replace(/\s/g, "&nbsp;") + "</div>";
6761				}
6762				list_content.innerHTML = html;
6763				showAutocomplete("sim_name");
6764			} else {
6765				hideAutocomplete("sim_name");
6766			}
6767		} else if(xml[0]) {
6768			dashboardErrorMessage(xml[0]);
6769		}
6770	}
6771}
6772
6773function autocompleteSimulator(text, type, aircraft_id) {
6774	document.getElementById("sim_name").value = text;
6775	document.getElementById("sim_type").value = type;
6776	document.getElementById("sim_aircraft_id").value = aircraft_id;
6777	hideAutocompleteNow("sim_name");
6778	document.getElementById("sim_name").focus();
6779}
6780
6781function getCrewNames(field) {
6782	if(document.getElementById("autocomplete_attached_field").value != field) {			//hide previous autocomplete if target field changed
6783		document.getElementById("autocomplete").className = "hidden";
6784	}
6785	document.getElementById("autocomplete_attached_field").value = field;
6786	positionAutocompleteNextToField(field);
6787	text = document.getElementById(field).value;
6788	if(document.getElementById(field) === document.activeElement) {
6789		var xmlHttp = createXMLHttpRequest();
6790		if(xmlHttp) {
6791			xmlHttp.onreadystatechange = function(){autocompleteResult(xmlHttp, field);};
6792			xmlHttp.open("post", "/log/ajax/crewList.php", true);
6793			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
6794			var data  = "text=" +	encodeURIComponent(text);
6795			data += "&field=" +	encodeURIComponent(field);
6796			xmlHttp.send(data);
6797		}
6798	}
6799}
6800
6801function getAirportMatches(field) {
6802	text = document.getElementById(field).value;
6803	if(text.length > 4) {				//only search for airport names if more that 4 characters entered. 3-4 characters treated as airport code
6804		if(document.getElementById("autocomplete_attached_field").value != field) {			//hide previous autocomplete if target field changed
6805			document.getElementById("autocomplete").className = "hidden";
6806		}
6807		document.getElementById("autocomplete_attached_field").value = field;
6808		positionAutocompleteNextToField(field);
6809		if(document.getElementById(field) === document.activeElement) {
6810			var xmlHttp = createXMLHttpRequest();
6811			if(xmlHttp) {
6812				xmlHttp.onreadystatechange = function(){autocompleteResult(xmlHttp, field, "checkFlightChanges();");};
6813				xmlHttp.open("post", "/log/ajax/airportList.php", true);
6814				xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
6815				var data  = "text=" +	encodeURIComponent(text);
6816				data += "&date=" +	encodeURIComponent(document.getElementById("flight_date").value);
6817				if(field == "flight_from") {
6818					data += "&time=" +	encodeURIComponent(document.getElementById("flight_depart").value);
6819				} else {
6820					data += "&time=" +	encodeURIComponent(document.getElementById("flight_arrive").value);
6821				}
6822				xmlHttp.send(data);
6823			}
6824		}
6825	} else {
6826		document.getElementById("autocomplete").className = "hidden";
6827	}
6828}
6829
6830function autocompleteResult(xmlHttp, field, extra) {
6831	if(!extra) {
6832		extra = "";
6833	}
6834	if(document.getElementById(field) === document.activeElement) {					//only do this if the field still has focus
6835		xml = getXmlContent(xmlHttp);
6836		if(xml[3]) {
6837			var list_content = document.getElementById("autocomplete_content");
6838			var html = "";
6839			response = xml[0];
6840			names = response.getElementsByTagName("name");
6841			if(names.length > 0) {
6842				for(n=0; n<names.length; n++) {
6843					name = names[n].firstChild.nodeValue;
6844					html += "<div class='autocomplete_entry' onclick='autocompleteText(\"" + field + "\", \"" + name.replace(/\'/g, "&#039;") + "\");" + extra + "'>" + name.replace(/\s/g, "&nbsp;") + "</div>";
6845				}
6846				list_content.innerHTML = html;
6847				showAutocomplete(field);
6848			} else {
6849				hideAutocomplete(field);
6850			}
6851		} else if(xml[0]) {
6852			dashboardErrorMessage(xml[0]);
6853		}
6854	}
6855}
6856
6857function showAutocomplete(field) {
6858	document.getElementById("autocomplete").className = "";
6859	document.getElementById("autocomplete").scrollTop = 0;
6860}
6861
6862function hideAutocomplete(field) {
6863	setTimeout(function(){hideAutocompleteNow(field);}, 100);						//slight timeout so that blur event does not hide autcomplete before onclick selection
6864}
6865
6866function hideAutocompleteNow(field) {
6867	if(document.getElementById("autocomplete_attached_field").value == field) {			//only hide field if it is attached to the calling element; it may have moved
6868		document.getElementById("autocomplete").className = "hidden";
6869	}
6870}
6871
6872function autocompleteText(field, text) {
6873	document.getElementById(field).value = text;
6874	hideAutocompleteNow(field);
6875	document.getElementById(field).focus();
6876}
6877
6878function positionAutocompleteNextToField(field) {
6879	field_object = document.getElementById(field);
6880	var x = field_object.offsetLeft;
6881	var y = field_object.offsetTop;
6882	var parent = field_object.parentElement;
6883	while(parent) {
6884		x += parent.offsetLeft;
6885		y += parent.offsetTop;
6886		parent = parent.parentElement;
6887		if(parent.id == "dashboard_editing_page_container") {
6888			break;
6889		}
6890	}
6891	var fieldWidth = field_object.offsetWidth;
6892	var autoCompleteOffset = 30;
6893	var autocompleteWidth = Math.max(fieldWidth - autoCompleteOffset, 150) - 4;
6894	document.getElementById('autocomplete').style.width = autocompleteWidth + "px";
6895	x += autoCompleteOffset;		//offset div to avoid completely hiding following fields
6896	y += field_object.offsetHeight - 2;
6897	document.getElementById('autocomplete').style.left = x+"px";
6898	document.getElementById('autocomplete').style.top = y+"px";
6899}
6900
6901function searchAircraftOnline() {
6902	regMark = document.getElementById("ac_reg").value.toUpperCase();
6903
6904	reGReg=/^G-[A-Z]{4}$/					//regular expression checks for G-XXXX
6905	reGShortReg=/^G[A-Z]{4}$/				//regular expression checks for GXXXX
6906	reNReg=/^N[A-Z0-9]{1,5}$/				//regular expression checks for Nxxxxx
6907	rePHReg=/^PH-[A-Z0-9]{3}$/				//regular expression checks for PH-XXX
6908	reBrazilReg=/^P[PRSTU]-[A-Z]{3}$/		//regular expression checks for PP-XXX PR-XXX PU-XXX PT-XXX
6909	reAustraliaReg=/^VH-[A-Z0-9]{3}$/		//regular expression checks for VH-XXX
6910
6911	url = "https://www.google.com/search?q=aircraft+"+encodeURIComponent(regMark);
6912	caa_url = false;
6913	if (regMark.search(reGReg)==0) {						//reg starting G-
6914		searchReg=regMark.substring(2);								//chop 'G-' off start of string for searching
6915		copyToClipboard(searchReg);
6916		caa_url = "https://www.caa.co.uk/aircraft-register/g-info/search-g-info";				//no automation of g-info since upgrade Feb 2018
6917	} else if (regMark.search(reGShortReg)==0) {						//reg starting G
6918		searchReg=regMark.substring(1);								//chop 'G' off start of string for searching
6919		copyToClipboard(searchReg);
6920		caa_url = "https://www.caa.co.uk/aircraft-register/g-info/search-g-info";
6921	} else if (regMark.search(reNReg)==0) {				//reg starting N
6922		searchReg=regMark.substring(1);								//chop 'N' off start of string for searching
6923		caa_url = "https://registry.faa.gov/AircraftInquiry/Search/NNumberResult?nNumberTxt="+searchReg;
6924	} else if (regMark.search(reBrazilReg)==0) {
6925		caa_url = "https://sistemas.anac.gov.br/aeronaves/cons_rab_resposta.asp?textMarca="+regMark;
6926	} else if (regMark.search(reAustraliaReg)==0) {
6927		searchReg=regMark.substring(3);								//chop 'VH-' off start of string for searching
6928		caa_url = "https://www.casa.gov.au/search-centre/aircraft-register?reg="+searchReg;
6929	}
6930	if(aircraft_search_window == null || aircraft_search_window.closed) {
6931		aircraft_search_window = window.open(url,'aircraft_search_window');
6932	} else {
6933		aircraft_search_window.location.replace(url);
6934	}
6935	if(caa_url) {
6936		if(aircraft_caa_window == null || aircraft_caa_window.closed) {
6937			aircraft_caa_window = window.open(caa_url,'aircraft_caa_window');
6938		} else {
6939			aircraft_caa_window.location.replace(caa_url);
6940		}
6941	}
6942}
6943
6944function searchAirportDetails() {
6945	name = document.getElementById("ap_name").value;
6946	icao = document.getElementById("ap_icao").value.toUpperCase();
6947	iata = document.getElementById("ap_iata").value.toUpperCase();
6948	if(iata != "") {
6949		search_text = iata;
6950	} else if(icao != "") {
6951		search_text = icao;
6952	} else {
6953		search_text = name;
6954	}
6955	if(search_text != "") {
6956		url = "https://www.google.com/search?q=airport+"+encodeURIComponent(search_text);
6957		if(airport_search_window == null || airport_search_window.closed) {
6958			airport_search_window = window.open(url,'airport_search_window');
6959		} else {
6960			airport_search_window.location.replace(url);
6961		}
6962	}
6963}
6964
6965function showAirportOnMap() {
6966	latNS = document.getElementById('ap_lat_ns').value;
6967	latDeg = parseFloat(document.getElementById('ap_lat_deg').value, 10);
6968	latMin = parseFloat(document.getElementById('ap_lat_min').value, 10);
6969	latSec = parseFloat(document.getElementById('ap_lat_sec').value, 10);
6970	lonEW = document.getElementById('ap_lon_ew').value;
6971	lonDeg = parseFloat(document.getElementById('ap_lon_deg').value, 10);
6972	lonMin = parseFloat(document.getElementById('ap_lon_min').value, 10);
6973	lonSec = parseFloat(document.getElementById('ap_lon_sec').value, 10);
6974	if(latNS == "" || lonEW == "") {
6975		searchAirportDetails();
6976	} else {
6977		if(isNaN(latDeg)) {
6978			latDeg = 0;
6979		}
6980		if(isNaN(latMin)) {
6981			latMin = 0;
6982		}
6983		if(isNaN(latSec)) {
6984			latSec = 0;
6985		}
6986		if(isNaN(lonDeg)) {
6987			lonDeg = 0;
6988		}
6989		if(isNaN(lonMin)) {
6990			lonMin = 0;
6991		}
6992		if(isNaN(lonSec)) {
6993			lonSec = 0;
6994		}
6995		ewSign = 1.0;
6996		nsSign = 1.0;
6997		if(latNS=="S" || latNS=="s") {
6998			nsSign = -1.0;
6999		}
7000		if(lonEW=="W" || lonEW=="w") {
7001			ewSign = -1.0;
7002		}
7003		lat = (latDeg + (latMin / 60) + (latSec / 3600)) * nsSign;
7004		lon = (lonDeg + (lonMin / 60) + (lonSec / 3600)) * ewSign;
7005		if(Math.abs(lat) < 0.0001 && Math.abs(lon) < 0.0001) {
7006			searchAirportDetails();
7007		} else {
7008			url = "https://maps.google.co.uk/maps?q="+lat+"%2C"+lon;
7009			if(airport_map_window == null || airport_map_window.closed) {
7010				airport_map_window = window.open(url,'airport_map_window');
7011			} else {
7012				airport_map_window.location.replace(url);
7013			}
7014		}	
7015	}
7016}
7017
7018function showChangePassword() {
7019	document.getElementById("change_password").className = "";
7020	checkPasswordChanges();
7021}
7022
7023function checkPasswordChanges() {
7024	var valid = true;
7025	var old_password = document.getElementById("old_password");
7026	var new_password_1 = document.getElementById("new_password_1");
7027	var new_password_2 = document.getElementById("new_password_2");
7028	if(new_password_1.value == "") {
7029		valid = false;
7030		new_password_1.classList.remove("dashboard_valid");
7031		new_password_1.classList.add("dashboard_invalid");
7032	} else {
7033		data_entered = true;
7034		new_password_1.classList.remove("dashboard_invalid");
7035		new_password_1.classList.add("dashboard_valid");
7036	}
7037	if(new_password_2.value == "") {
7038		valid = false;
7039		new_password_2.classList.remove("dashboard_valid");
7040		new_password_2.classList.add("dashboard_invalid");
7041	} else {
7042		data_entered = true;
7043		new_password_2.classList.remove("dashboard_invalid");
7044		new_password_2.classList.add("dashboard_valid");
7045	}
7046	if(valid) {			// if passwords have been entered, check that they match
7047		if(new_password_1.value != new_password_2.value) {
7048			valid = false;
7049			new_password_1.classList.remove("dashboard_valid");
7050			new_password_1.classList.add("dashboard_invalid");
7051			new_password_2.classList.remove("dashboard_valid");
7052			new_password_2.classList.add("dashboard_invalid");
7053		} else {
7054			new_password_1.classList.remove("dashboard_invalid");
7055			new_password_1.classList.add("dashboard_valid");
7056			new_password_2.classList.remove("dashboard_invalid");
7057			new_password_2.classList.add("dashboard_valid");
7058		}
7059	}
7060	if(old_password.value == "") {
7061		valid = false;
7062		old_password.classList.remove("dashboard_valid");
7063		old_password.classList.add("dashboard_invalid");
7064	} else {
7065		old_password.classList.remove("dashboard_invalid");
7066		old_password.classList.add("dashboard_valid");
7067	}
7068	dashboardCheckForChanges(getChangePasswordFields(), "change_password");
7069}
7070
7071function dashboardSavePassword() {
7072	var validate_only = "n";
7073	var override_warnings = "n";
7074	var check_warnings = "password";
7075	var callback = false;
7076	var cleanup_callback = false;
7077	var url = "changePassword";
7078	dashboardSaveEntity(validate_only, override_warnings, check_warnings, url, getChangePasswordFields(), callback, cleanup_callback, true);
7079}
7080
7081function addLimitation(limitation_type) {
7082	var found = false;
7083	var num_limits = num_flight_limitations;
7084	if(limitation_type == "duty") {
7085		num_limits = num_duty_limitations;
7086	}
7087	for(l=1; l<=num_limits; l++) {
7088		var field = "limitations_"+limitation_type+"_"+l;
7089		if(document.getElementById(field+"_hours").value == "") {
7090			var container = document.getElementById(limitation_type+"_limitations_container");
7091			var element = document.getElementById(field+"_view");
7092			container.append(element);			//move empty element to bottom of list
7093			document.getElementById(field+"_period").value = "DAY";
7094			element.className = "dashboard_input";
7095			document.getElementById(field+"_hours").focus();
7096			found = true;
7097			break;
7098		}
7099	}
7100	if(!found) {
7101		dashboardErrorMessage("You can add a maximum of " + num_flight_limitations + " " + limitation_type + " limitations.");
7102	}
7103	checkSettingsChanges();
7104}
7105
7106function deleteLimitation(field) {
7107	document.getElementById(field+"_view").className = "hidden";
7108	document.getElementById(field+"_hours").value = "";
7109	document.getElementById(field+"_num").value = "";
7110	document.getElementById(field+"_period").value = "DAY";
7111	checkSettingsChanges();
7112}
7113
7114function addCustomField(log, prefix) {
7115	var field_base = log + prefix;
7116	var num_fields = num_flight_custom_fields;
7117	var found = false;
7118	if(log == "sim") {
7119		num_fields = num_sim_custom_fields;
7120	} else if(log == "duty") {
7121		num_fields = num_duty_custom_fields;
7122	}
7123	for(n=1; n<=num_fields; n++) {
7124		var field = field_base + n;
7125		var view = field + "_view";
7126		if(document.getElementById(field).value == "") {	//find first unused field
7127			document.getElementById(view).className = "dashboard_input";
7128			document.getElementById(field).focus();
7129			found = true;
7130			break;
7131		}
7132	}
7133	if(!found) {
7134		dashboardErrorMessage("You can add a maximum of " + num_fields + " " + log + " custom fields of each type.");
7135	}
7136}
7137
7138function deleteCustomField(field) {
7139	if(document.getElementById(field + "_initial").value == "") {	//field added but never saved. Just remove it
7140		//hide field
7141		document.getElementById(field+"_view").className = "hidden";
7142		//reset values in case reused later to add another new field
7143		document.getElementById(field).value = "";
7144		setYesNoButton(field+"_display", "n");
7145	} else if(document.getElementById(field + "_delete").value == "y") {		//original field already deleted. This is a newly added, unsaved field
7146		//hide field
7147		document.getElementById(field+"_view").className = "hidden";
7148		//reset values in case reused later to add another new field
7149		document.getElementById(field).value = "";
7150		setYesNoButton(field+"_display", "n");
7151	} else {							//this is an existing field, possibly with data, to delete. Check first!
7152		dashboard_confirm("Delete Custom Field", "This will permanently delete any data stored in this field in your log.\n\nAre you sure that you want to delete it?", "Delete", "No", function() {deleteExistingCustomField(field);});
7153	}
7154	checkSettingsChanges();
7155}
7156
7157function deleteExistingCustomField(field) {
7158	//hide field
7159	document.getElementById(field+"_view").className = "hidden";
7160	//reset values in case reused later to add another new field
7161	document.getElementById(field).value = "";
7162	setYesNoButton(field+"_display", "n");
7163	// set delete flag to remove field from server when saved
7164	document.getElementById(field + "_delete").value = "y";
7165	checkSettingsChanges();
7166}
7167
7168function addReportException(airport, report, clear) {
7169	var num_exceptions = parseInt(document.getElementById("num_report_exceptions").value, 10);
7170	var new_id = "report_exception_" + (num_exceptions + 1);
7171	var new_element = document.getElementById("report_exception_0").cloneNode(true);
7172	new_element.innerHTML = new_element.innerHTML.replace(/report_exception_0/g, new_id);
7173	new_element.id = new_id;
7174	document.getElementById("report_exceptions_table").append(new_element);
7175	document.getElementById("num_report_exceptions").value = num_exceptions + 1;
7176	getSettingsFields();		//force load if not already set
7177	settings_fields.push(new_id + "_id");
7178	settings_fields.push(new_id + "_airport");
7179	settings_fields.push(new_id + "_report");
7180	settings_fields.push(new_id + "_clear");
7181	settings_fields.push(new_id + "_deleted");
7182	document.getElementById("report_exceptions_header_1").className = "dashboard_input"
7183	document.getElementById("report_exceptions_header_2").className = "dashboard_input"
7184	if(typeof(airport) !== "undefined") {
7185		document.getElementById(new_id + "_airport").value = airport;
7186	} else {
7187		document.getElementById(new_id + "_airport").focus();				//only focus if added manually		
7188		checkSettingsChanges();												//called elsewhere if automatic
7189	}
7190	if(typeof(report) !== "undefined") {
7191		document.getElementById(new_id + "_report").value = report;
7192	}
7193	if(typeof(clear) !== "undefined") {
7194		document.getElementById(new_id + "_clear").value = clear;
7195	}
7196}
7197
7198function deleteAllReportExceptions() {		//used before adding new options automatically on airline change
7199	var num_exceptions = parseInt(document.getElementById("num_report_exceptions").value, 10);
7200	for(n=1; n<=num_exceptions; n++) {
7201		deleteReportException("report_exception_" + n, true);
7202	}
7203}
7204
7205function deleteReportException(field, skip_check) {
7206	//do not actually delete the element. Hide it and mark as deleted to ensure deletion from server and ensure continuity of object indices
7207	document.getElementById(field).className = "hidden";
7208	document.getElementById(field + "_deleted").value = "y";
7209	if(document.getElementById(field + "_id").value == "0") {		//added but not saved. Set values to indcate 'no change'
7210		document.getElementById(field + "_deleted_initial").value = "y";
7211		document.getElementById(field + "_airport_initial").value = "";
7212		document.getElementById(field + "_airport").value = "";
7213		document.getElementById(field + "_report_initial").value = "";
7214		document.getElementById(field + "_report").value = "";
7215		document.getElementById(field + "_clear_initial").value = "";
7216		document.getElementById(field + "_clear").value = "";
7217	}
7218	var num_exceptions = parseInt(document.getElementById("num_report_exceptions").value, 10);
7219	var any_visible = false;
7220	for(f=1; f<=num_exceptions; f++) {
7221		if(document.getElementById("report_exception_" + f + "_deleted").value == "n") {
7222			any_visible = true;
7223			break;
7224		}
7225	}
7226	if(!any_visible) {
7227		document.getElementById("report_exceptions_header_1").className = "hidden"
7228		document.getElementById("report_exceptions_header_2").className = "hidden"
7229	}
7230	if(!skip_check) {				//do not call check changes when using this finction automatically
7231		checkSettingsChanges();
7232	}
7233}
7234
7235// ---------------------------
7236// subscription code
7237// ---------------------------
7238
7239function showSubscriptionPopup(disable_close) {
7240	if(document.getElementById("subscription_popup_container").className == "hidden") {		//avoid repeated calls
7241		if(disable_close) {																	//for suspended accounts
7242			document.getElementById("subscription_close_button").className = "hidden";
7243		}
7244		var xmlHttp = createXMLHttpRequest();
7245		if(xmlHttp) {
7246			xmlHttp.onreadystatechange = function(){subscriptionPopupLoaded(xmlHttp);};
7247			xmlHttp.open("post", "/log/ajax/dashboardSubscription.php", true);
7248			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7249			xmlHttp.send();
7250			document.getElementById("subscription_popup_container").className = "";
7251		}
7252	}
7253}
7254
7255function closeSubscriptionPopup() {
7256	if(!inhibit_dismiss) {
7257		document.getElementById("subscription_popup_container").className = "hidden";
7258		document.getElementById("subscription_popup_content").innerHTML = "Loading. Pease wait...";
7259	}
7260}
7261
7262function subscriptionPopupLoaded(xmlHttp) {
7263	var xml = getXmlContent(xmlHttp);
7264	if(xml[3]) {
7265		notification_message = getXmlField(xml[0], "message");
7266		var number = getXmlField(xml[0], "number");
7267		document.getElementById("subscription_popup_content").innerHTML = getXmlField(xml[0], "content");
7268		subscription_mode = document.getElementById("subscription_mode").value;
7269		// Create a Stripe client.
7270		stripe = Stripe(document.getElementById("stripe_public_key").value);
7271		// Create an instance of Elements.
7272		var elements = stripe.elements();
7273		// Custom styling can be passed to options when creating an Element.
7274		// (Note that this demo uses a wider set of styles than the guide below.)
7275		var style = {
7276		  base: {
7277			color: '#32325d',
7278		    fontFamily: '"Helvetica Neue", Helvetica, sans-serif',
7279		    fontSmoothing: 'antialiased',
7280		    fontSize: '16px',
7281		    '::placeholder': {
7282		      color: '#aab7c4',
7283		    }
7284		  },
7285		  invalid: {
7286		    color: '#fa755a',
7287		    iconColor: '#fa755a'
7288		  }
7289		};
7290		var options = {
7291			style: style
7292		};
7293		// Create an instance of the card Element.
7294		stripeCardElement = elements.create('card', options);
7295		// Add an instance of the card Element into the `card-element` <div>.
7296		if(subscription_mode == "create") {
7297			stripeCardElement.mount('#card-element');
7298		} else if(subscription_mode == "manage") {
7299			stripeCardElement.mount('#card-element-update');		
7300		}
7301		// Handle real-time validation errors from the card Element.
7302		stripeCardElement.addEventListener('change', function(event) {
7303			var displayError;
7304			var buttons;
7305			if(subscription_mode == "create") {
7306				displayError = document.getElementById('card-errors');
7307			} else if(subscription_mode == "manage") {
7308				displayError = document.getElementById('card-errors-update');
7309			}
7310			if (event.error) {
7311				displayError.textContent = event.error.message;
7312				enableSubscriptionCloseButton();
7313				cardValidationError = true;
7314			} else {
7315				displayError.textContent = '';
7316				cardValidationError = false;
7317			}
7318		});
7319	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
7320	} else if(xml[0]) {
7321		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
7322			window.location.reload(true);			//will display login screen
7323		} else {
7324			closeSubscriptionPopup();
7325			dashboardErrorMessage(xml[0]);
7326		}
7327	}
7328}
7329
7330function disableSubscriptionCloseButton() {
7331	inhibit_dismiss = true;
7332	var button = document.getElementById("subscription_close_button");
7333	if(button) {
7334		button.innerHTML = "Please wait...";
7335	}
7336	document.getElementById("subscription_terms").className = "hidden";
7337}
7338
7339function enableSubscriptionCloseButton(retry) {
7340	inhibit_dismiss = false;
7341	var button = document.getElementById("subscription_close_button");
7342	if(button) {
7343		button.innerHTML = "Close";
7344	}
7345	if(retry) {		// display terms and submit button
7346		document.getElementById("subscription_terms").className = "subscription_text";
7347	}
7348}
7349
7350function chooseProLite(pl, alias) {
7351	subscription_pro_lite = pl;
7352	if(alias) {
7353		subscription_alias = alias;
7354	} else {
7355		subscription_alias = subscription_pro_lite;
7356	}
7357	chooseAnnual = false;
7358	if(subscription_pro_lite == "Pro") {
7359		introPeriod = document.getElementById("time_to_payment_pro").value;
7360		introUnits = document.getElementById("units_to_payment_pro").value;
7361		document.getElementById("monthly-sub-amount").innerHTML = document.getElementById("monthly_pro_fee").value;
7362		document.getElementById("annual-sub-amount").innerHTML = document.getElementById("annual_pro_fee").value;
7363	} else if(subscription_pro_lite == "Dormant") {
7364		introPeriod = document.getElementById("time_to_payment_dormant").value;
7365		introUnits = document.getElementById("units_to_payment_dormant").value;
7366		document.getElementById("monthly-sub-amount").innerHTML = document.getElementById("monthly_pro_fee").value;
7367		document.getElementById("annual-sub-amount").innerHTML = document.getElementById("monthly_pro_fee").value;
7368		chooseAnnual = true;
7369	} else {
7370		introPeriod = document.getElementById("time_to_payment_lite").value;
7371		introUnits = document.getElementById("units_to_payment_lite").value;
7372		document.getElementById("monthly-sub-amount").innerHTML = document.getElementById("monthly_lite_fee").value;
7373		document.getElementById("annual-sub-amount").innerHTML = document.getElementById("annual_lite_fee").value;
7374	}
7375	if(introPeriod > 0) {
7376		document.getElementById("paypal_intro_period").value = introPeriod;
7377		document.getElementById("paypal_intro_unit").value = introUnits;
7378	}
7379	document.getElementById("choose-frequency-note").innerHTML = "Setup " + subscription_alias + " subscription<br />Please choose monthly or annual payments";
7380	document.getElementById("subscription_introdution").className = "hidden";
7381	document.getElementById("choose_pro_lite").className = "hidden";
7382	document.getElementById("choose_payment_frequency").className = "";
7383	if(document.getElementById("next_payment_date")) {
7384		document.getElementById("next_payment_date").innerHTML = document.getElementById("next_payment_date_" + subscription_pro_lite.toLowerCase()).value
7385	}
7386	if(chooseAnnual) {
7387		choosePaymentFrequency("Annual");
7388	}
7389}
7390
7391function choosePaymentFrequency(fr) {
7392	subscription_payment_frequency = fr;
7393	if(subscription_pro_lite == "Pro") {
7394		if(subscription_payment_frequency == "Monthly") {
7395			amount = document.getElementById("monthly_pro_fee").value;
7396			document.getElementById("paypal-item-name").value = "PilotLog Monthly Subscription";
7397		} else {
7398			amount = document.getElementById("annual_pro_fee").value;
7399			document.getElementById("paypal-item-name").value = "PilotLog Annual Subscription";
7400		}
7401	} else if(subscription_pro_lite == "Dormant") {
7402		amount = document.getElementById("monthly_pro_fee").value;
7403		document.getElementById("paypal-item-name").value = "PilotLog Annual Dormant Subscription";
7404	} else {
7405		if(subscription_payment_frequency == "Monthly") {
7406			amount = document.getElementById("monthly_lite_fee").value;
7407			document.getElementById("paypal-item-name").value = "PilotLog Monthly Lite Subscription";
7408		} else {
7409			amount = document.getElementById("annual_lite_fee").value;
7410			document.getElementById("paypal-item-name").value = "PilotLog Annual Lite Subscription";
7411		}
7412	}
7413	document.getElementById("choose-payment-note").innerHTML = "Setup " + subscription_alias + " " + subscription_payment_frequency + " subscription (GBP " + amount + ")<br />Please choose payment type";
7414	document.getElementById("paypal-cost").value = amount;
7415	if(subscription_payment_frequency == "Monthly") {
7416		if(document.getElementById("bank_payment_button")) {
7417			document.getElementById("bank_payment_button").className = "hidden";
7418		}
7419		paypal_unit = "M";
7420	} else {
7421		if(document.getElementById("bank_payment_button")) {
7422			document.getElementById("bank_payment_button").className = "padded-left";
7423		}
7424		paypal_unit = "Y";
7425	}
7426	document.getElementById("paypal-period").value = paypal_unit;
7427	var bank = document.getElementById("bank-payment-button");
7428	if(bank) {
7429		if(subscription_payment_frequency == "Monthly") {
7430			bank.className = "hidden";
7431		} else {
7432			bank.className = "subscription_option";
7433		}
7434	}
7435	document.getElementById("subscription_introdution").className = "hidden";
7436	document.getElementById("choose_payment_frequency").className = "hidden";
7437	document.getElementById("choose_payment_type").className = "";
7438}
7439
7440function choosePaymentType(id) {
7441	message = "Setup " + subscription_alias + " " + subscription_payment_frequency + " subscription (GBP " + amount + ")";
7442	document.getElementById("card-payment-note").innerHTML = message;
7443	//document.getElementById("paypal-payment-note").innerHTML = message;
7444	if(document.getElementById("bank-payment-note")) {
7445		document.getElementById("bank-payment-note").innerHTML = message;
7446		document.getElementById("bank-amount").innerHTML = amount;
7447	}
7448	switchDivs('choose_payment_type', id);
7449	if(id == "stripe_card_details") {
7450		stripeCardElement.focus();
7451	}
7452}
7453
7454function changeStripeCard() {
7455	if(!inhibit_dismiss) {
7456		document.getElementById("subscription_introdution").className = "hidden";
7457		document.getElementById("stripe_manage_options").className = "hidden";
7458		document.getElementById("stripe_card_update_details").className = "";
7459		stripeCardElement.focus();
7460	}
7461}
7462
7463function backFromStripeUpdate() {
7464	if(!inhibit_dismiss) {
7465		document.getElementById("subscription_introdution").className = "";
7466		document.getElementById("stripe_manage_options").className = "";
7467		document.getElementById("stripe_card_update_details").className = "hidden";
7468	}
7469}
7470
7471function showStripeSwitchOptions() {
7472	if(!inhibit_dismiss) {
7473		document.getElementById("subscription_introdution").className = "hidden";
7474		document.getElementById("stripe_manage_options").className = "hidden";
7475		document.getElementById("stripe_switch_plans").className = "";
7476	}
7477}
7478
7479function backFromStripeSwitchOptions() {
7480	if(!inhibit_dismiss) {
7481		document.getElementById("subscription_introdution").className = "";
7482		document.getElementById("stripe_manage_options").className = "";
7483		document.getElementById("stripe_switch_plans").className = "hidden";
7484	}
7485}
7486
7487function backFromStripeSwitchFrequency() {
7488	if(!inhibit_dismiss) {
7489		document.getElementById("stripe_switch_plans").className = "";
7490		document.getElementById("switch_payment_frequency").className = "hidden";
7491	}
7492}
7493
7494function backFromStripeSwitchConfirm() {
7495	if(!inhibit_dismiss) {
7496		document.getElementById(back_page).className = "";
7497		document.getElementById(current_page).className = "hidden";
7498	}
7499}
7500
7501function cancelStripe() {
7502	if(!inhibit_dismiss) {
7503		document.getElementById("subscription_introdution").className = "hidden";
7504		document.getElementById("stripe_manage_options").className = "hidden";
7505		document.getElementById("cancel_confirm").className = "";
7506	}
7507}
7508
7509function backFromStripeCancel() {
7510	if(!inhibit_dismiss) {
7511		document.getElementById("subscription_introdution").className = "";
7512		document.getElementById("stripe_manage_options").className = "";
7513		document.getElementById("cancel_confirm").className = "hidden";
7514	}
7515}
7516
7517function switchStripePlans(pl) {
7518	subscription_pro_lite = pl;
7519	var chooseAnnual = false;
7520	var chooseMonthly = false;
7521	var proNote = document.getElementById("proSwitchNote").value;
7522	var liteNote = document.getElementById("liteSwitchNote").value;
7523	if(subscription_pro_lite == "Pro") {
7524		if(proNote == "Annual") {
7525			chooseAnnual = true;
7526		} else if(proNote == "Monthly") {
7527			chooseMonthly = true;
7528		} else {
7529			document.getElementById("switch_frequency_note").innerHTML = proNote;
7530		}
7531		document.getElementById("monthly-sub-amount").innerHTML = document.getElementById("monthly_pro_fee").value;
7532		document.getElementById("annual-sub-amount").innerHTML = document.getElementById("annual_pro_fee").value;
7533	} else if(subscription_pro_lite == "Dormant") {
7534		document.getElementById("monthly-sub-amount").innerHTML = document.getElementById("monthly_pro_fee").value;
7535		document.getElementById("annual-sub-amount").innerHTML = document.getElementById("monthly_pro_fee").value;
7536		chooseAnnual = true;
7537	} else {
7538		if(liteNote == "Annual") {
7539			chooseAnnual = true;
7540		} else if(liteNote == "Monthly") {
7541			chooseMonthly = true;
7542		} else {
7543			document.getElementById("switch_frequency_note").innerHTML = liteNote;
7544		}
7545		document.getElementById("monthly-sub-amount").innerHTML = document.getElementById("monthly_lite_fee").value;
7546		document.getElementById("annual-sub-amount").innerHTML = document.getElementById("annual_lite_fee").value;
7547	}
7548	document.getElementById("stripe_switch_plans").className = "hidden";
7549	document.getElementById("switch_payment_frequency").className = "";
7550	back_page = "stripe_switch_plans";
7551	current_page = "switch_payment_frequency";
7552	if(chooseAnnual) {
7553		switchPaymentFrequency("Annual", true);
7554	} else if(chooseMonthly) {
7555		switchPaymentFrequency("Monthly", true);
7556	}
7557}
7558
7559function stripeCancelConfirm() {
7560	if(!inhibit_dismiss) {
7561		disableSubscriptionCloseButton();
7562		document.getElementById("subscription_status").innerHTML = "&nbsp;";
7563		document.getElementById("cancel_confirm_note").innerHTML = "Contacting server. Please wait...";
7564		var xmlHttp = createXMLHttpRequest();
7565		if(xmlHttp) {
7566			xmlHttp.onreadystatechange = function() {stripeCancelResult(xmlHttp);};
7567			xmlHttp.open("post", "/log/ajax/stripe_changePlan.php", true);
7568			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7569			var data  = "proration_time=" +		encodeURIComponent(document.getElementById("current_time").value);
7570			data += "&proLite=cancel";
7571			data += "&frequency=cancel";
7572			xmlHttp.send(data);
7573		}
7574	}
7575}
7576
7577function stripeCancelResult(xmlHttp) {
7578	var resultOK = false;
7579	var xml = getXmlContent(xmlHttp);
7580	if(xml[3]) {			//received with no errors
7581		var error = getXmlField(xml[0], "error");
7582		if(error == "OK") {
7583			resultOK = true;
7584		} else {
7585			dashboardErrorMessage(error);
7586		}
7587	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
7588	} else if(xml[0]) {			//received with error
7589		document.getElementById("cancel_confirm_note").innerHTML = xml[0];
7590		enableSubscriptionCloseButton();
7591	}
7592	if(resultOK) {
7593		document.getElementById("cancel_confirm_note").innerHTML = "Subscription cancelled successfully.";
7594		enableSubscriptionCloseButton();
7595	}
7596	updateAccountStatus();
7597}
7598
7599function switchPaymentFrequency(fr, ooverride_back) {
7600	subscription_payment_frequency = fr;
7601	if(subscription_pro_lite == "Pro") {
7602		if(subscription_payment_frequency == "Monthly") {
7603			amount = document.getElementById("monthly_pro_fee").value;
7604		} else {
7605			amount = document.getElementById("annual_pro_fee").value;
7606		}
7607	} else if(subscription_pro_lite == "Dormant") {
7608		amount = document.getElementById("monthly_pro_fee").value;
7609	} else {
7610		if(subscription_payment_frequency == "Monthly") {
7611			amount = document.getElementById("monthly_lite_fee").value;
7612		} else {
7613			amount = document.getElementById("annual_lite_fee").value;
7614		}
7615	}
7616	if(subscription_pro_lite == "Dormant") {
7617		$noteField = "DormantSwitchNote";
7618	} else {
7619		noteField = subscription_pro_lite+subscription_payment_frequency+"SwitchNote";
7620	}
7621	document.getElementById("subscription_title").innerHTML = "Switch Subscriptions";
7622	document.getElementById("subscription_status").innerHTML = "&nbsp;";
7623	document.getElementById("switch_confirm_note").innerHTML = "Contacting server. Please wait...";
7624	document.getElementById("switch_payment_frequency").className = "hidden";
7625	document.getElementById("switch_confirm").className = "";
7626	if(!ooverride_back) {
7627		back_page = "switch_payment_frequency";
7628	}
7629	current_page = "switch_confirm";
7630	disableSubscriptionCloseButton();
7631	loadInvoicePreview();
7632}
7633
7634function loadInvoicePreview() {
7635	var xmlHttp = createXMLHttpRequest();
7636	if(xmlHttp) {
7637		xmlHttp.onreadystatechange = function() {invoicePreviewLoaded(xmlHttp);};
7638		xmlHttp.open("post", "/log/ajax/stripe_invoice_preview.php", true);
7639		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7640		var data  = "proration_time=" +		encodeURIComponent(document.getElementById("current_time").value);
7641		data += "&proLite=" +			encodeURIComponent(subscription_pro_lite);
7642		data += "&frequency=" +			encodeURIComponent(subscription_payment_frequency);
7643		xmlHttp.send(data);
7644	}
7645}
7646
7647function invoicePreviewLoaded(xmlHttp) {
7648	var xml = getXmlContent(xmlHttp);
7649	if(xml[3]) {			//received with no errors
7650		var error = getXmlField(xml[0], "error");
7651		if(error == "OK") {
7652			document.getElementById("switch_confirm_note").innerHTML = getXmlField(xml[0], "content");
7653			enableSubscriptionCloseButton();
7654		} else {
7655			dashboardErrorMessage(error);
7656			enableSubscriptionCloseButton();
7657		}
7658	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
7659	} else if(xml[0]) {			//received with error
7660		dashboardErrorMessage(xml[0]);
7661		enableSubscriptionCloseButton();
7662	}
7663}
7664
7665function stripeSwitchConfirm() {
7666	if(!inhibit_dismiss) {
7667		disableSubscriptionCloseButton();
7668		document.getElementById("switch_confirm_note").innerHTML = "Please wait...";
7669		var xmlHttp = createXMLHttpRequest();
7670		if(xmlHttp) {
7671			xmlHttp.onreadystatechange = function() {stripeSwitchResult(xmlHttp);};
7672			xmlHttp.open("post", "/log/ajax/stripe_changePlan.php", true);
7673			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7674			var data  = "proration_time=" +		encodeURIComponent(document.getElementById("current_time").value);
7675			data += "&proLite=" +			encodeURIComponent(subscription_pro_lite);
7676			data += "&frequency=" +			encodeURIComponent(subscription_payment_frequency);
7677			xmlHttp.send(data);
7678		}
7679	}
7680}
7681
7682function stripeSwitchResult(xmlHttp) {
7683	var resultOK = false;
7684	var xml = getXmlContent(xmlHttp);
7685	if(xml[3]) {			//received with no errors
7686		var error = getXmlField(xml[0], "error");
7687		if(error == "OK") {
7688			resultOK = true;
7689		} else {
7690			alert(error);
7691		}
7692	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
7693	} else if(xml[0]) {			//received with error
7694		document.getElementById("switch_confirm_note").innerHTML = xml[0];
7695		enableSubscriptionCloseButton();
7696	}
7697	if(resultOK) {
7698		document.getElementById("switch_confirm_note").innerHTML = "Subscription updated successfully. Thank you.";
7699		enableSubscriptionCloseButton();
7700	}
7701}
7702
7703function switchPlansBack() {
7704	switchDivs('switch_confirm', 'stripe_switch_plans', '');
7705}
7706
7707function backToFrequency() {
7708	if(subscription_pro_lite == "Dormant") {
7709		switchDivs('choose_payment_type', 'choose_pro_lite');
7710	} else {
7711		switchDivs('choose_payment_type', 'choose_payment_frequency');
7712		if(!document.getElementById("choose_pro_lite")) {
7713			document.getElementById("subscription_introdution").className = "";
7714		}
7715	}
7716}
7717
7718function backFromFrequency() {
7719	switchDivs('choose_payment_frequency', 'choose_pro_lite');
7720	document.getElementById("subscription_introdution").className = "";
7721}
7722
7723function submitCard() {
7724	if(!inhibit_dismiss && !cardValidationError) {
7725		disableSubscriptionCloseButton();
7726		document.getElementById("payment-error").innerHTML = "Please wait...";
7727		stripe.createToken(stripeCardElement).then(function(result) {
7728			if (result.error) {
7729				// Inform the user if there was an error.
7730				var errorElement = document.getElementById('card-errors');
7731				errorElement.textContent = result.error.message;
7732			} else {
7733				// Send the token to your server.
7734				stripeTokenHandler(result.token.id);
7735			}
7736		});
7737	}
7738}
7739
7740function stripeTokenHandler(token) {
7741	document.getElementById("payment-error").innerHTML = "Card validated. Please wait...";
7742	var xmlHttp = createXMLHttpRequest();
7743	if(xmlHttp) {
7744		xmlHttp.onreadystatechange = function() {setupSubscriptionResult(xmlHttp);};
7745		xmlHttp.open("post", "/log/ajax/stripe_setupSubscription.php", true);
7746		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7747		var data  = "token=" +				encodeURIComponent(token);
7748		data += "&proLite=" +			encodeURIComponent(subscription_pro_lite);
7749		data += "&frequency=" +			encodeURIComponent(subscription_payment_frequency);
7750		data += "&free_days=" +			encodeURIComponent(document.getElementById("days_to_payment_"+subscription_pro_lite.toLowerCase()).value);
7751		xmlHttp.send(data);
7752	}
7753}
7754
7755function setupSubscriptionResult(xmlHttp) {
7756	var resultOK = false;
7757	var waiting = false;
7758	var okMessage = "Subscription created successfully. Thank you.";
7759	var xml = getXmlContent(xmlHttp);
7760	if(xml[3]) {			//received with no errors
7761		var error = getXmlField(xml[0], "error");
7762		if(error == "OK") {
7763			resultOK = true;
7764			var status = getXmlField(xml[0], "status");
7765			if(status == "requires_action") {			//3D Secure request
7766				waiting = true;
7767				var client_secret = getXmlField(xml[0], "secret");
7768				var type = getXmlField(xml[0], "type");
7769				if(type == "setup_intent") {
7770					stripe.handleCardSetup(client_secret).then(function(stripe_result) {			//for SetupIntent, future payment
7771					 	// Handle result.error or result.setupIntent
7772						if(stripe_result.setupIntent) {
7773							if(stripe_result.setupIntent.status == "succeeded") {
7774								document.getElementById("payment-error").innerHTML = okMessage;
7775								enableSubscriptionCloseButton();
7776								updateUserFollowingValidation();
7777							} else {
7778								document.getElementById("payment-error").innerHTML = "Payment setup failed - status is "+stripe_result.setupIntent.status;
7779								enableSubscriptionCloseButton();
7780							}
7781						} else {
7782							resultOK = false;
7783							document.getElementById("payment-error").innerHTML = stripe_result.error.message;
7784							enableSubscriptionCloseButton();
7785						}
7786					});
7787				} else {
7788					stripe.handleCardPayment(client_secret).then(function(stripe_result) {			//for PaymentIntent, actual payment
7789					 	// Handle result.error or result.paymentIntent
7790						if(stripe_result.paymentIntent) {
7791							if(stripe_result.paymentIntent.status == "succeeded") {
7792								document.getElementById("payment-error").innerHTML = okMessage;
7793								enableSubscriptionCloseButton();
7794								updateUserFollowingValidation();
7795							} else {
7796								document.getElementById("payment-error").innerHTML = "Payment setup failed - status is "+stripe_result.paymentIntent.status;
7797								enableSubscriptionCloseButton();
7798							}
7799						} else {
7800							resultOK = false;
7801							document.getElementById("payment-error").innerHTML = stripe_result.error.message;
7802							enableSubscriptionCloseButton();
7803						}
7804					});
7805				}
7806			}
7807		} else {
7808			resultOK = false;
7809			document.getElementById("payment-error").innerHTML = error;
7810			enableSubscriptionCloseButton();
7811		}
7812	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
7813	} else if(xml[0]) {			//received with error
7814		document.getElementById("payment-error").innerHTML = xml[0];
7815		enableSubscriptionCloseButton();
7816	}
7817	if(!waiting) {
7818		if(resultOK) {
7819			document.getElementById("payment-error").innerHTML = okMessage;
7820			enableSubscriptionCloseButton();
7821		}
7822		updateAccountStatus();
7823	}
7824}
7825
7826function updateUserFollowingValidation() {
7827	var xmlHttp = createXMLHttpRequest();
7828	if(xmlHttp) {
7829		xmlHttp.onreadystatechange = function() {updateCustomerResult();};
7830		xmlHttp.open("post", "/log/ajax/stripe_updateCustomer.php", true);
7831		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7832		xmlHttp.send("");
7833	}
7834}
7835
7836function updateCustomerResult() {		//fail silently, as this just updates status in real-time. Webhooks should perform the same job within a few seconds anyway
7837	updateAccountStatus();
7838}
7839
7840function submitNewCard() {
7841	if(!inhibit_dismiss && !cardValidationError) {
7842		disableSubscriptionCloseButton();
7843		document.getElementById("payment-error-update").innerHTML = "Please wait...";
7844		stripe.createToken(stripeCardElement).then(function(result) {
7845			if (result.error) {
7846				// Inform the user if there was an error.
7847				var errorElement = document.getElementById('card-errors-update');
7848				errorElement.textContent = result.error.message;
7849			} else {
7850				// Send the token to your server.
7851				stripeTokenUpdateHandler(result.token.id);
7852			}
7853		});
7854	}
7855}
7856
7857function stripeTokenUpdateHandler(token) {
7858	document.getElementById("payment-error-update").innerHTML = "Card validated. Please wait...";
7859	var xmlHttp = createXMLHttpRequest();
7860	if(xmlHttp) {
7861		xmlHttp.onreadystatechange = function() {updateCardResult(xmlHttp);};
7862		xmlHttp.open("post", "/log/ajax/stripe_updateCard.php", true);
7863		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7864		var data = "token=" + encodeURIComponent(token);
7865		xmlHttp.send(data);
7866	}
7867}
7868
7869function updateCardResult(xmlHttp) {
7870	var resultOK = false;
7871	var waiting = false;
7872	var okMessage = "Card updated successfully. Thank you.";
7873	var xml = getXmlContent(xmlHttp);
7874	if(xml[3]) {			//received with no errors
7875		var error = getXmlField(xml[0], "error");
7876		if(error == "OK") {
7877			resultOK = true;
7878			var status = getXmlField(xml[0], "status");
7879			if(status == "requires_action") {			//3D Secure request
7880				waiting = true;
7881				var client_secret = getXmlField(xml[0], "secret");
7882				stripe.handleCardSetup(client_secret).then(function(stripe_result) {			//for SetupIntent, future payment
7883				 	// Handle result.error or result.setupIntent
7884					if(stripe_result.setupIntent) {
7885						if(stripe_result.setupIntent.status == "succeeded") {
7886							document.getElementById("payment-error-update").innerHTML = okMessage;
7887							disableBackButton("stripe_card_update_details_back");
7888							enableSubscriptionCloseButton(false);		//no retry; succeeded
7889							updateUserFollowingValidation();
7890						} else {
7891							document.getElementById("payment-error-update").innerHTML = "Payment setup failed - status is "+stripe_result.setupIntent.status;
7892							enableSubscriptionCloseButton(true);		//allow retry
7893						}
7894					} else {
7895						resultOK = false;
7896						document.getElementById("payment-error-update").innerHTML = stripe_result.error.message;
7897						enableSubscriptionCloseButton(true);		//allow retry
7898					}
7899				});
7900			}
7901		} else {
7902			resultOK = false;
7903			document.getElementById("payment-error-update").innerHTML = error;
7904			enableSubscriptionCloseButton(true);		//allow retry
7905		}
7906	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
7907	} else if(xml[0]) {			//received with error
7908		document.getElementById("payment-error-update").innerHTML = xml[0];
7909		enableSubscriptionCloseButton(true);		//allow retry
7910	}
7911	if(!waiting) {
7912		if(resultOK) {
7913			document.getElementById("payment-error-update").innerHTML = okMessage;
7914			disableBackButton("stripe_card_update_details_back");
7915			enableSubscriptionCloseButton(false);		//no retry; succeeded
7916		}
7917		updateAccountStatus();
7918	}
7919}
7920
7921function switchDivs(hide, show, visibleClass) {
7922	if(!inhibit_dismiss) {
7923		if(!visibleClass) {
7924			visibleClass = "";
7925		}
7926		document.getElementById(hide).className = "hidden";
7927		document.getElementById(show).className = visibleClass;
7928	}
7929}
7930
7931function disableBackButton(id) {
7932	document.getElementById(id).innerHTML = "&nbsp;";
7933	document.getElementById(id).onclick = null;
7934}
7935
7936// update account details on settings page
7937function updateAccountStatus() {
7938	if(document.getElementById("settings_account_title")) {		//only do this if settings page visible; not on dashboard or in app
7939		var xmlHttp = createXMLHttpRequest();
7940		if(xmlHttp) {
7941			xmlHttp.onreadystatechange = function() {updateAccountStatusResult(xmlHttp);};
7942			xmlHttp.open("post", "/log/ajax/dashboardSubscriptionDetails.php", true);
7943			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
7944			xmlHttp.send("");
7945		}
7946	}
7947}
7948
7949function updateAccountStatusResult(xmlHttp) {
7950	var xml = getXmlContent(xmlHttp);
7951	if(xml[3]) {			//received with no errors
7952		var error = getXmlField(xml[0], "error");
7953		if(error == "OK") {
7954			document.getElementById("settings_account_title").innerHTML = getXmlField(xml[0], "status_html");
7955			document.getElementById("settings_account_status_note").innerHTML = getXmlField(xml[0], "detail_html");
7956			var mode = getXmlField(xml[0], "mode");
7957			if(mode == "create") {
7958				document.getElementById("settings_manage_subscription").className = "dashboard_input";
7959				document.getElementById("manage_subscription_button").innerHTML = "Create Subscription";
7960			} else if(mode == "manage") {
7961				document.getElementById("settings_manage_subscription").className = "dashboard_input";
7962				document.getElementById("manage_subscription_button").innerHTML = "Manage Subscription";
7963			} else {
7964				document.getElementById("settings_manage_subscription").className = "hidden";
7965				document.getElementById("manage_subscription_button").innerHTML = "Manage Subscription";
7966			}
7967		} else {
7968			dashboardErrorMessage(error);
7969		}
7970	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
7971	} else if(xml[0]) {			//received with error
7972		dashboardErrorMessage(xml[0]);
7973	}
7974}
7975
7976// ---------------------------
7977// end subscription code
7978// ---------------------------
7979
7980function showChart(chart_type, chart_index) {
7981	clearChartPoint(current_chart_type, current_chart_index);
7982	current_chart_type = chart_type;
7983	current_chart_index = chart_index;
7984	for(i=1; i<block_charts.length; i++) {
7985		document.getElementById("block_"+block_charts[i]).className = "hidden";
7986		document.getElementById("button_block_"+block_charts[i]).classList.remove("dashboard_chart_block_text_button_active");
7987	}
7988	for(i=1; i<duty_charts.length; i++) {
7989		document.getElementById("duty_"+duty_charts[i]).className = "hidden";
7990		document.getElementById("button_duty_"+duty_charts[i]).classList.remove("dashboard_chart_duty_text_button_active");
7991	}
7992	document.getElementById(chart_type+"_"+chart_index).className = "";
7993	document.getElementById("button_"+chart_type+"_"+chart_index).classList.add("dashboard_chart_"+chart_type+"_text_button_active");
7994	if(document.getElementById("chart_"+chart_type+"_"+chart_index)) {
7995		document.getElementById("chart_"+chart_type+"_"+chart_index).scrollLeft = 999999999;
7996	}
7997}
7998
7999function setChartRange(years) {
8000	current_chart_range = years;
8001	if(!document.getElementById("button_range_"+years).classList.contains("dashboard_chart_block_text_button_active")) {
8002		document.getElementById("button_range_"+years).classList.add("dashboard_chart_block_text_button_active");
8003		loadFirstChart();
8004	}
8005	var ranges = [0, 1, 2, 5, 10];
8006	for(i=0; i<ranges.length; i++) {
8007		if(ranges[i] != years) {
8008			document.getElementById("button_range_"+ranges[i]).classList.remove("dashboard_chart_block_text_button_active");
8009		}
8010	}
8011}
8012
8013//load one chart first for quick display of visible tab
8014function loadFirstChart() {
8015	for(i=1; i<block_charts.length; i++) {
8016		document.getElementById("block_content_"+block_charts[i]).innerHTML = loading_list;
8017	}
8018	for(i=1; i<duty_charts.length; i++) {
8019		document.getElementById("duty_content_"+duty_charts[i]).innerHTML = loading_list;
8020	}
8021	var xmlHttp = createXMLHttpRequest();
8022	if(xmlHttp) {
8023		var chart_type = current_chart_type;		//create local variables in case globals change during load
8024		var chart_index = current_chart_index;
8025		xmlHttp.onreadystatechange = function() {updateChart(xmlHttp, chart_type, chart_index, function() {loadRemainingCharts(chart_type, chart_index);});};
8026		xmlHttp.open("post", "/log/ajax/dashboardChart.php", true);
8027		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
8028		var container_width = window.innerWidth - 30;
8029		var container_height = window.innerHeight - 270;	//allow for header and footers
8030		container_height -= document.getElementById("charts_buttons_container").clientHeight;
8031		var data  = "chart_type=" +		encodeURIComponent(current_chart_type);
8032		data += "&chart_index=" +		encodeURIComponent(current_chart_index);
8033		data += "&chart_range=" +		encodeURIComponent(current_chart_range);
8034		data += "&container_width=" +	encodeURIComponent(container_width);
8035		data += "&container_height=" +	encodeURIComponent(container_height);
8036		xmlHttp.send(data);
8037	}
8038}
8039
8040//then load remaining charts in the background ready to display if required
8041//chart type and chart index are the one already loaded, to exclude from loading
8042function loadRemainingCharts(chart_type, chart_index) {
8043	var charts_to_load = [];
8044	for(i=1; i<block_charts.length; i++) {
8045		if(chart_type == "duty" || chart_index != block_charts[i]) {
8046			charts_to_load.push(["block", block_charts[i]]);
8047		}
8048	}
8049	for(i=1; i<duty_charts.length; i++) {
8050		if(chart_type == "block" || chart_index != duty_charts[i]) {
8051			charts_to_load.push(["duty", duty_charts[i]]);
8052		}
8053	}
8054	loadNextChart(charts_to_load, 0);
8055}
8056
8057function loadNextChart(charts_to_load, index) {
8058	var xmlHttp = createXMLHttpRequest();
8059	if(xmlHttp) {
8060		var chart_type = charts_to_load[index][0];
8061		var chart_index = charts_to_load[index][1];
8062		xmlHttp.onreadystatechange = function() {updateChart(xmlHttp, chart_type, chart_index);};
8063		xmlHttp.open("post", "/log/ajax/dashboardChart.php", true);
8064		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
8065		var container_width = window.innerWidth - 30;
8066		var container_height = window.innerHeight - 270;	//allow for header and footers
8067		container_height -= document.getElementById("charts_buttons_container").clientHeight;
8068		var data  = "chart_type=" +		encodeURIComponent(chart_type);
8069		data += "&chart_index=" +		encodeURIComponent(chart_index);
8070		data += "&chart_range=" +		encodeURIComponent(current_chart_range);
8071		data += "&container_width=" +	encodeURIComponent(container_width);
8072		data += "&container_height=" +	encodeURIComponent(container_height);
8073		xmlHttp.send(data);
8074	}
8075	index++;
8076	if(index < charts_to_load.length) {
8077		loadNextChart(charts_to_load, index);
8078	}
8079}
8080
8081function updateChart(xmlHttp, chart_type, chart_index, callback) {
8082	var xml = getXmlContent(xmlHttp);
8083	if(xml[3]) {			//received with no errors
8084		var error = getXmlField(xml[0], "error");
8085		if(error == "OK") {
8086			document.getElementById(chart_type+"_content_"+chart_index).innerHTML = getXmlField(xml[0], "content");
8087			if(document.getElementById("chart_"+chart_type+"_"+chart_index)) {
8088				document.getElementById("chart_"+chart_type+"_"+chart_index).scrollLeft = 999999999;
8089			}
8090		} else {
8091			document.getElementById(chart_type+"_content_"+chart_index).innerHTML = "<div class='dashboard_large_text centre'><br />"+error+"</div>";
8092		}
8093		if(callback) {
8094			callback();
8095		}
8096	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
8097	} else if(xml[0]) {			//received with error
8098		if(xml[0].toUpperCase() == "NOT LOGGED IN") {
8099			dashboardForceReload();
8100		} else if(xml[0].toUpperCase() == "SUSPENDED") {
8101			showSubscriptionPopup(true);
8102		} else {
8103			dashboardErrorMessage(xml[0]);
8104		}
8105	}
8106}
8107
8108function showChartPoint(info, index, chart_type, chart_index) {
8109	if(current_chart_point_highlight == -1) {
8110		document.getElementById(chart_type+"_"+chart_index+"_chart_text").innerHTML = info;
8111	}
8112}
8113
8114function clickChartPoint(info, index, chart_type, chart_index) {
8115	if(current_chart_point_highlight == -1) {
8116		document.getElementById(chart_type+"_"+chart_index+"_chart_text").innerHTML = info;
8117		document.getElementById(chart_type+"_"+chart_index+"_point_"+index).classList.add("overlay_chart_bar_clicked");
8118		current_chart_point_highlight = index;
8119	} else {
8120		document.getElementById(chart_type+"_"+chart_index+"_chart_text").innerHTML = "";
8121		document.getElementById(chart_type+"_"+chart_index+"_point_"+current_chart_point_highlight).classList.remove("overlay_chart_bar_clicked");
8122		current_chart_point_highlight = -1;
8123	}
8124}
8125
8126// called when switching charts to clear fixed highlight
8127function clearChartPoint(chart_type, chart_index) {
8128	if(document.getElementById(chart_type+"_"+chart_index+"_chart_text")) {
8129		document.getElementById(chart_type+"_"+chart_index+"_chart_text").innerHTML = "";
8130	}
8131	if(current_chart_point_highlight != -1) {
8132		document.getElementById(chart_type+"_"+chart_index+"_point_"+current_chart_point_highlight).classList.remove("overlay_chart_bar_clicked");
8133		current_chart_point_highlight = -1;
8134	}
8135}
8136
8137//reload charts when window resized (or device orientation changed) after delay to allow for dragging browser window without continuous reload requests
8138function chartsResize() {
8139	var d = new Date();
8140	var chart_resize_delay = 500;
8141	chart_resize_timer = d.getTime();			// milliseconds
8142	window.setTimeout(function() {reloadCharts(chart_resize_delay);}, chart_resize_delay)
8143}
8144
8145function reloadCharts(chart_resize_delay) {
8146	var d = new Date();
8147	if(d.getTime() - chart_resize_timer >= chart_resize_delay) {
8148		loadFirstChart();
8149	}
8150}
8151
8152function showTotals(show) {
8153	document.getElementById("dashboard_content_"+current_totals_type+"_"+current_totals_prov).className = "hidden";
8154	if(show == "achieved" || show == "provisional") {
8155		current_totals_prov = show;							// achieved or provisional
8156		document.getElementById("button_totals_achieved").classList.remove("dashboard_chart_block_text_button_active");
8157		document.getElementById("button_totals_provisional").classList.remove("dashboard_chart_block_text_button_active");
8158		document.getElementById("button_totals_"+current_totals_prov).classList.add("dashboard_chart_block_text_button_active");
8159	} else {
8160		current_totals_type = show;							// flying, sim or duty
8161		document.getElementById("button_totals_flying").classList.remove("dashboard_chart_block_text_button_active");
8162		document.getElementById("button_totals_sim").classList.remove("dashboard_chart_block_text_button_active");
8163		document.getElementById("button_totals_duty").classList.remove("dashboard_chart_block_text_button_active");
8164		document.getElementById("button_totals_"+current_totals_type).classList.add("dashboard_chart_block_text_button_active");
8165		if(show == "flying") {
8166			document.getElementById("totals_flying_bar").className = "";
8167			document.getElementById("totals_sim_bar").className = "hidden";
8168		} else if(show == "sim") {
8169			document.getElementById("totals_flying_bar").className = "hidden";
8170			document.getElementById("totals_sim_bar").className = "";
8171		} else {
8172			document.getElementById("totals_flying_bar").className = "hidden";
8173			document.getElementById("totals_sim_bar").className = "hidden";
8174		}
8175	}
8176	document.getElementById("dashboard_content_"+current_totals_type+"_"+current_totals_prov).className = "";
8177}
8178
8179function showFlightTotals(style_index) {
8180	totals_styles.innerHTML = totals_styles_options[style_index];
8181	for(n=0; n<5; n++) {
8182		element = document.getElementById("button_totals_"+n);
8183		if(element) {
8184			element.classList.remove("dashboard_chart_block_text_button_active");
8185		}
8186	}
8187	document.getElementById("button_totals_"+style_index).classList.add("dashboard_chart_block_text_button_active");
8188}
8189
8190function showTopEntries(index) {
8191	for(n=0; n<totals_names.length; n++) {
8192		if(index == n){
8193			document.getElementById("button_totals_"+n).classList.add("dashboard_chart_block_text_button_active");
8194			document.getElementById("dashboard_content_"+totals_names[n]).classList.remove("hidden");
8195		} else {
8196			document.getElementById("button_totals_"+n).classList.remove("dashboard_chart_block_text_button_active");
8197			document.getElementById("dashboard_content_"+totals_names[n]).classList.add("hidden");
8198		}
8199	}
8200}
8201
8202// roster import code
8203function importRosterSubmit() {
8204	document.getElementById("button_import").disabled = "disabled";
8205	document.getElementById("button_import").value = "Please Wait...";
8206	document.getElementById("rosterImport").submit();
8207}
8208
8209// roster import code
8210function importFlightloggerSubmit() {
8211	document.getElementById("button_import").disabled = "disabled";
8212	document.getElementById("button_import").value = "Please Wait...";
8213	document.getElementById("rosterImport").submit();
8214}
8215
8216function downloadRosterCalendar() {
8217	document.getElementById("calendar").submit();
8218}
8219
8220function openWindow(url) {
8221	roster_window = window.open(url,'Roster','width=700,height=600,status=no,resize=yes,scrollbars=yes');
8222}
8223
8224function futureChanged(yn) {
8225	if(yn == 'y') {
8226		document.getElementById("importFromDate").value = document.getElementById("importDateToday").value;
8227		document.getElementById("importToDate").value = document.getElementById("importDateLater").value;
8228		document.getElementById("import_range").className = "hidden";
8229	} else if(yn == 'n') {
8230		document.getElementById("importFromDate").value = document.getElementById("importDateAll").value;
8231		document.getElementById("importToDate").value = document.getElementById("importDateLater").value;
8232		document.getElementById("import_range").className = "hidden";
8233	} else {
8234		document.getElementById("importFromDate").value = '';
8235		document.getElementById("importToDate").value = '';
8236		document.getElementById("import_range").className = "";
8237	}
8238}
8239// end roster import code
8240
8241// trial setup
8242
8243function submitFreeTrial() {
8244	dashboard_modal_message("Contacting server<br /><br />Please wait...", false);
8245	var xmlHttp = createXMLHttpRequest();
8246	if(xmlHttp) {
8247		xmlHttp.onreadystatechange = function() {signupResult(xmlHttp);};
8248		xmlHttp.open("post", "/signupAjax.php", true);
8249		xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
8250		var data  = "title=" +			encodeURIComponent(document.getElementById("title").value);
8251		data += "&forename=" +		encodeURIComponent(document.getElementById("forename").value);
8252		data += "&middlename=" +	encodeURIComponent(document.getElementById("middlename").value);
8253		data += "&surname=" +		encodeURIComponent(document.getElementById("surname").value);
8254		data += "&email=" +			encodeURIComponent(document.getElementById("email").value);
8255		data += "&airline_id=" +	encodeURIComponent(document.getElementById("airline_id").value);
8256		data += "&employer=" +		encodeURIComponent(document.getElementById("employer").value);
8257		data += "&tncAgree=" +		encodeURIComponent(document.getElementById("tncAgree").value);
8258		data += "&address1=" +		encodeURIComponent(document.getElementById("address1").value);
8259		data += "&address2=" +		encodeURIComponent(document.getElementById("address2").value);
8260		data += "&address3=" +		encodeURIComponent(document.getElementById("address3").value);
8261		data += "&town=" +			encodeURIComponent(document.getElementById("town").value);
8262		data += "&county=" +		encodeURIComponent(document.getElementById("county").value);
8263		data += "&postcode=" +		encodeURIComponent(document.getElementById("postcode").value);
8264		data += "&country_id=" +	encodeURIComponent(document.getElementById("country_id").value);
8265		data += "&state_id=" +		encodeURIComponent(document.getElementById("state_id").value);
8266		data += "&tel=" +			encodeURIComponent(document.getElementById("tel").value);
8267		data += "&mobile=" +		encodeURIComponent(document.getElementById("mobile").value);
8268		data += "&referrer=" +		encodeURIComponent(document.getElementById("referrer").value);
8269		data += "&promocode=" +		encodeURIComponent(document.getElementById("promocode").value);
8270		xmlHttp.send(data);
8271	}
8272}
8273
8274function signupResult(xmlHttp) {
8275	var xml = getXmlContent(xmlHttp);
8276	if(xml[3]) {				//received with no errors
8277		dashboard_clear_modal_message();
8278		problems = getXmlField(xml[0], "problems");
8279		if(problems == "") {
8280			document.getElementById("free_trial_form").className = "hidden";
8281			document.getElementById("signupOK").className = "";
8282		} else {
8283			if(getXmlField(xml[0], "classTitle") == "invalidField") {
8284				document.getElementById("title").classList.remove("dashboard_valid");
8285				document.getElementById("title").classList.add("dashboard_invalid");
8286			}
8287			if(getXmlField(xml[0], "classForename") == "invalidField") {
8288				document.getElementById("forename").classList.remove("dashboard_valid");
8289				document.getElementById("forename").classList.add("dashboard_invalid");
8290			}
8291			if(getXmlField(xml[0], "classSurname") == "invalidField") {
8292				document.getElementById("surname").classList.remove("dashboard_valid");
8293				document.getElementById("surname").classList.add("dashboard_invalid");
8294			}
8295			if(getXmlField(xml[0], "classEmail") == "invalidField") {
8296				document.getElementById("email").classList.remove("dashboard_valid");
8297				document.getElementById("email").classList.add("dashboard_invalid");
8298			}
8299			if(getXmlField(xml[0], "classCountry") == "invalidField") {
8300				document.getElementById("country_id").classList.remove("dashboard_valid");
8301				document.getElementById("country_id").classList.add("dashboard_invalid");
8302			}
8303			dashboardErrorMessage(problems);
8304		}
8305	} else if(xml[0]) {		//received with error
8306		dashboard_clear_modal_message();
8307		dashboardErrorMessage(xml[0]);
8308	}
8309}
8310
8311function signupCountryChange()
8312{
8313	ajaxGetStateListForCountry("country_id", "state_id", "stateRow");
8314}
8315
8316function airlineChange()
8317{
8318	if(document.getElementById("airline_id").value == 1)
8319	{
8320		document.getElementById("airline_other").className = "";
8321	}
8322	else
8323	{
8324		document.getElementById("airline_other").className = "hidden";
8325		document.getElementById("employer").value = "";
8326	}
8327}
8328
8329// end trial setup
8330
8331function poster(size) {
8332	url = "/log/poster.php?size="+size+"&type=Poster";
8333	window.open(url, 'Poster', 'toolbar=1,scrollbars=1,location=1,statusbar=1,menubar=1,resizable=1,width=800,height=800');
8334}
8335
8336function flyers(size) {
8337	url = "/log/poster.php?size="+size+"&type=Flyers";
8338	window.open(url, 'Flyers', 'toolbar=1,scrollbars=1,location=1,statusbar=1,menubar=1,resizable=1,width=800,height=800');
8339}
8340
8341function printFormatChanged() {
8342	var format = document.getElementById("format").value;
8343	if(format == "aileron") {
8344		document.getElementById("split").value = "y";
8345		document.getElementById("split_pages").value = "100";
8346		printSplitChanged();
8347		document.getElementById("print_aileron_options").className = "";
8348		document.getElementById("page_breaks").disabled = "";
8349	} else if(format == "india") {
8350		document.getElementById("print_aileron_options").className = "hidden";
8351		document.getElementById("page_breaks").value = "m";
8352		printPageBreakChanged();
8353		document.getElementById("page_breaks").disabled = "disabled";
8354	} else {
8355		document.getElementById("print_aileron_options").className = "hidden";
8356		document.getElementById("page_breaks").disabled = "";
8357	}
8358}
8359
8360function printSplitChanged() {
8361	var split = document.getElementById("split").value;
8362	if(split == "n") {
8363		document.getElementById("print_book_length_options").className = "hidden";
8364		document.getElementById("print_date_option").className = "hidden";
8365		document.getElementById("print_date_range_entry").className = "hidden";
8366	} else if(split == "y") {
8367		document.getElementById("print_book_length_options").className = "";
8368		document.getElementById("print_date_option").className = "hidden";
8369	} else {
8370		document.getElementById("print_book_length_options").className = "hidden";
8371		document.getElementById("print_date_option").className = "";
8372	}
8373	printDateRangeChanged();
8374}
8375
8376function printDateRangeChanged() {
8377	var split = document.getElementById("split").value;
8378	var split_range = document.getElementById("split_range").value;
8379	if(split_range == "m" && split == "r") {			// manual selection
8380		document.getElementById("print_date_range_entry").className = "";
8381	} else {
8382		document.getElementById("print_date_range_entry").className = "hidden";
8383	}
8384}
8385
8386function printPageBreakChanged() {
8387	var page_breaks = document.getElementById("page_breaks").value;
8388	if(page_breaks == "y") {			// year breaks - show year start month option
8389		document.getElementById("print_year_start").className = "";
8390	} else {
8391		document.getElementById("print_year_start").className = "hidden";
8392	}
8393}
8394
8395function downloadPrintPDF() {
8396	var printForm = document.createElement("form");
8397	printForm.target = "_self";
8398	printForm.method = "POST"; // or "post" if appropriate
8399	printForm.enctype = "multipart/form-data";
8400	printForm.action = "printLog.php";
8401
8402    var format = document.createElement("input");
8403    format.type = "text";
8404    format.name = "format";
8405    format.value = document.getElementById("format").value;
8406    printForm.appendChild(format);
8407
8408    var include_provisional = document.createElement("input");
8409    include_provisional.type = "text";
8410    include_provisional.name = "include_provisional";
8411    include_provisional.value = document.getElementById("include_provisional").value;
8412    printForm.appendChild(include_provisional);
8413
8414    var search = document.createElement("input");
8415    search.type = "text";
8416    search.name = "search";
8417    search.value = document.getElementById("search").value;
8418    printForm.appendChild(search);
8419
8420    var split = document.createElement("input");
8421    split.type = "text";
8422    split.name = "split";
8423    split.value = document.getElementById("split").value;
8424    printForm.appendChild(split);
8425
8426    var split_pages = document.createElement("input");
8427    split_pages.type = "text";
8428    split_pages.name = "split_pages";
8429    split_pages.value = document.getElementById("split_pages").value;
8430    printForm.appendChild(split_pages);
8431
8432    var split_book = document.createElement("input");
8433    split_book.type = "text";
8434    split_book.name = "split_book";
8435    split_book.value = document.getElementById("split_book").value;
8436    printForm.appendChild(split_book);
8437
8438    var split_range = document.createElement("input");
8439    split_range.type = "text";
8440    split_range.name = "split_range";
8441    split_range.value = document.getElementById("split_range").value;
8442    printForm.appendChild(split_range);
8443
8444    var split_start = document.createElement("input");
8445    split_start.type = "text";
8446    split_start.name = "split_start";
8447    split_start.value = document.getElementById("split_start").value;
8448    printForm.appendChild(split_start);
8449
8450    var split_end = document.createElement("input");
8451    split_end.type = "text";
8452    split_end.name = "split_end";
8453    split_end.value = document.getElementById("split_end").value;
8454    printForm.appendChild(split_end);
8455
8456    var page_breaks = document.createElement("input");
8457    page_breaks.type = "text";
8458    page_breaks.name = "page_breaks";
8459    page_breaks.value = document.getElementById("page_breaks").value;
8460    printForm.appendChild(page_breaks);
8461
8462    var log_year_start = document.createElement("input");
8463    log_year_start.type = "text";
8464    log_year_start.name = "log_year_start";
8465    log_year_start.value = document.getElementById("log_year_start").value;
8466    printForm.appendChild(log_year_start);
8467
8468    var aileron_airport = document.createElement("input");
8469    aileron_airport.type = "text";
8470    aileron_airport.name = "aileron_airport";
8471    aileron_airport.value = document.getElementById("aileron_airport").value;
8472    printForm.appendChild(aileron_airport);
8473
8474    var aileron_headers = document.createElement("input");
8475    aileron_headers.type = "text";
8476    aileron_headers.name = "aileron_headers";
8477    aileron_headers.value = document.getElementById("aileron_headers").value;
8478    printForm.appendChild(aileron_headers);
8479
8480    var print_p2_remarks = document.createElement("input");
8481    print_p2_remarks.type = "text";
8482    print_p2_remarks.name = "print_p2_remarks";
8483    print_p2_remarks.value = document.getElementById("print_p2_remarks").value;
8484    printForm.appendChild(print_p2_remarks);
8485
8486    var print_remarks = document.createElement("input");
8487    print_remarks.type = "text";
8488    print_remarks.name = "print_remarks";
8489    print_remarks.value = document.getElementById("print_remarks").value;
8490    printForm.appendChild(print_remarks);
8491
8492    var aileron_col_1 = document.createElement("input");
8493    aileron_col_1.type = "text";
8494    aileron_col_1.name = "aileron_col_1";
8495    aileron_col_1.value = document.getElementById("aileron_col_1").value;
8496    printForm.appendChild(aileron_col_1);
8497
8498    var aileron_col_2 = document.createElement("input");
8499    aileron_col_2.type = "text";
8500    aileron_col_2.name = "aileron_col_2";
8501    aileron_col_2.value = document.getElementById("aileron_col_2").value;
8502    printForm.appendChild(aileron_col_2);
8503
8504    var aileron_col_3 = document.createElement("input");
8505    aileron_col_3.type = "text";
8506    aileron_col_3.name = "aileron_col_3";
8507    aileron_col_3.value = document.getElementById("aileron_col_3").value;
8508    printForm.appendChild(aileron_col_3);
8509
8510    var aileron_col_4 = document.createElement("input");
8511    aileron_col_4.type = "text";
8512    aileron_col_4.name = "aileron_col_4";
8513    aileron_col_4.value = document.getElementById("aileron_col_4").value;
8514    printForm.appendChild(aileron_col_4);
8515
8516    var print_signatures = document.createElement("input");
8517    print_signatures.type = "text";
8518    print_signatures.name = "print_signatures";
8519    print_signatures.value = document.getElementById("print_signatures").value;
8520    printForm.appendChild(print_signatures);
8521
8522    var print_user_signature = document.createElement("input");
8523    print_user_signature.type = "text";
8524    print_user_signature.name = "print_user_signature";
8525    print_user_signature.value = document.getElementById("print_user_signature").value;
8526    printForm.appendChild(print_user_signature);
8527
8528    printForm.style.visibility = "hidden";
8529    document.body.appendChild(printForm);
8530
8531	dashboard_confirm("Downloading", "Please wait\n\nThis may take a few seconds", "OK", false);
8532	printForm.submit();
8533}
8534
8535function handleDropSignature(e) {
8536	dt = e.dataTransfer;
8537	files = dt.files;
8538	handleSignatureFile(files);
8539}
8540
8541function handleSignatureFile(files) {
8542	if(files) {
8543		if(files.length > 0) {
8544			document.getElementById("pilot_signature").src = "/dashboard/signature_blank.png";
8545			uploadSignatureFile(files[0]);
8546		}
8547	}
8548}
8549
8550function uploadSignatureFile(file) {
8551	var url = '/log/ajax/uploadSignature.php';
8552	xmlHttp = new XMLHttpRequest();
8553	var formData = new FormData();
8554	xmlHttp.open('POST', url, true);
8555	xmlHttp.addEventListener('readystatechange', function(){modifySignatureResult(xmlHttp);});
8556	formData.append('file', file);
8557	xmlHttp.send(formData);
8558}
8559
8560function removeSignature() {
8561	dashboard_confirm("Remove Signature", "Do you wish to permanently delete your signature?", "Yes", "No", actuallyRemoveSignature, false);
8562}
8563
8564function actuallyRemoveSignature() {
8565	var url = '/log/ajax/removeSignature.php';
8566	xmlHttp = new XMLHttpRequest();
8567	xmlHttp.open('POST', url, true);
8568	xmlHttp.addEventListener('readystatechange', function(){modifySignatureResult(xmlHttp);});
8569	var formData = new FormData();
8570	xmlHttp.send(formData);
8571}
8572
8573function modifySignatureResult(xmlHttp) {
8574	var xml = getXmlContent(xmlHttp);
8575	if(xml[3]) {				//received with no errors
8576		error = getXmlField(xml[0], "error");
8577		if(error == "OK") {
8578			document.getElementById("pilot_signature").src = "pilotSignature.php?refresh=" + new Date().getTime();
8579		} else {
8580			dashboardErrorMessage(error);
8581		}
8582	} else if(xml[4] == 0) {			//HTTP error 0; request cancelled; ignore
8583	} else if(xml[0]) {					//received with error
8584		dashboardErrorMessage(xml[0]);
8585	}
8586}
8587
8588
8589
8590// map code
8591
8592function showMap() {
8593	window.open("map.php");
8594}
8595
8596function toggleMapOptions() {
8597	if(document.getElementById("map_options_view").className == "map_options_open") {
8598		document.getElementById("map_options_view").className = "map_options_closed";
8599		document.getElementById("map_options_control").className = "map_options_control_closed";
8600	} else {
8601		document.getElementById("map_options_view").className = "map_options_open";
8602		document.getElementById("map_options_control").className = "map_options_control_open";
8603	}
8604}
8605
8606function loadDashboardMapData() {
8607	// only run this code if the map is visible (J rather than j in the display options) - save API hits if hidden
8608	var display_options = document.getElementById("dashboard_config_order").value;
8609	if(display_options.indexOf("J") >= 0) {
8610		var xmlHttp = createXMLHttpRequest();
8611		if(xmlHttp) {
8612			xmlHttp.onreadystatechange = function(){drawDashboardMap(xmlHttp);};
8613			xmlHttp.open("post", "/log/ajax/dashboardMapData.php", true);
8614			xmlHttp.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
8615			xmlHttp.send();
8616		}
8617	}
8618}
8619
8620var dashboard_map;
8621var map_polyOptions;
8622var map_line_weight = 3.0;
8623function drawDashboardMap(xmlHttp) {
8624	xml = getXmlContent(xmlHttp);
8625	if(xml[3]) {			//received with no errors
8626		var centre_lat = parseFloat(getXmlField(xml[0], "centre_lat"));
8627		var centre_lon = parseFloat(getXmlField(xml[0], "centre_lon"));
8628		var min_lat = parseFloat(getXmlField(xml[0], "min_lat"));
8629		var min_lon = parseFloat(getXmlField(xml[0], "min_lon"));
8630		var max_lat = parseFloat(getXmlField(xml[0], "max_lat"));
8631		var max_lon = parseFloat(getXmlField(xml[0], "max_lon"));
8632		var mapOptions = {
8633			center: new google.maps.LatLng(centre_lat, centre_lon),
8634			zoom: 2,
8635			streetViewControl: false,
8636			mapTypeControl: false,
8637			fullscreenControl: false,
8638			zoomControl: false,
8639			mapTypeId: google.maps.MapTypeId.HYBRID
8640		};
8641		dashboard_map = new google.maps.Map(document.getElementById("dashboard_content_map"), mapOptions);
8642		dashboard_map.fitBounds({east:max_lon, north:max_lat, south:min_lat, west:min_lon});
8643		const infoWindow = new google.maps.InfoWindow();
8644		const map_pin_icon = {
8645			path: "M11.75,1.75a10,10,0,0,0-10,10h0c0,7.5,10,18.57,10,18.57s10-11.07,10-18.57a10,10,0,0,0-10-10Zm0,13.57a3.57,3.57,0,1,1,3.57-3.57A3.57,3.57,0,0,1,11.75,15.32Z",
8646			fillColor: colour_theme_3,
8647			fillOpacity: 0,
8648			strokeColor: colour_theme_3,
8649			strokeWeight: 3,
8650			rotation: 0,
8651			scale: 1,
8652			anchor: new google.maps.Point(11.75, 32),
8653		}
8654		const map_icon_shadow = {
8655			path: "M11.75,1.75a10,10,0,0,0-10,10h0c0,7.5,10,18.57,10,18.57s10-11.07,10-18.57a10,10,0,0,0-10-10Zm0,13.57a3.57,3.57,0,1,1,3.57-3.57A3.57,3.57,0,0,1,11.75,15.32Z",
8656			fillColor: "#000000",
8657			fillOpacity: 0,
8658			strokeColor: "#000000",
8659			strokeWeight: 5,
8660			rotation: 0,
8661			scale: 1,
8662			anchor: new google.maps.Point(11.75, 32),
8663		}
8664		map_polyOptions = {
8665			strokeColor: colour_theme_1,
8666			strokeOpacity: 1.0,
8667			strokeWeight: map_line_weight,
8668			geodesic: true
8669		};
8670		var lines = xml[0].getElementsByTagName("line");
8671		var from_lat;
8672		var from_lon;
8673		var to_lat;
8674		var to_lon;
8675		for(n=0; n<lines.length; n++) {
8676			from_lat = lines[n].getElementsByTagName("from_lat")[0].childNodes[0].nodeValue;
8677			from_lon = lines[n].getElementsByTagName("from_lon")[0].childNodes[0].nodeValue;
8678			to_lat = lines[n].getElementsByTagName("to_lat")[0].childNodes[0].nodeValue;
8679			to_lon = lines[n].getElementsByTagName("to_lon")[0].childNodes[0].nodeValue;
8680			addLineToDashboardMap(from_lat, from_lon, to_lat, to_lon);
8681		}
8682		var pins = xml[0].getElementsByTagName("pin");
8683		var lat;
8684		var lon;
8685		var title;
8686		for(n=0; n<pins.length; n++) {
8687			lat = pins[n].getElementsByTagName("lat")[0].childNodes[0].nodeValue;
8688			lon = pins[n].getElementsByTagName("lon")[0].childNodes[0].nodeValue;
8689			title = pins[n].getElementsByTagName("title")[0].childNodes[0].nodeValue;
8690			addPinToDashboardMap(lat, lon, "", map_icon_shadow, infoWindow);
8691			addPinToDashboardMap(lat, lon, title, map_pin_icon, infoWindow);
8692		}
8693	}
8694}
8695
8696function addLineToDashboardMap(fromLat, fromLon, toLat, toLon) {
8697	var poly = new google.maps.Polyline(map_polyOptions);
8698	poly.setMap(dashboard_map);
8699	var path = poly.getPath();
8700	var pointFrom = new google.maps.LatLng(fromLat, fromLon);
8701	path.push(pointFrom);
8702	var pointTo = new google.maps.LatLng(toLat, toLon);
8703	path.push(pointTo);
8704}
8705
8706function addPinToDashboardMap(lat, lon, title, icon, infoWindow) {
8707	var point = new google.maps.LatLng(lat,lon);
8708	var marker = new google.maps.Marker({
8709		position: point,
8710		title: title,
8711		map: dashboard_map,
8712		icon: icon
8713	});
8714    marker.addListener("click", () => {
8715      infoWindow.close();
8716      infoWindow.setContent(marker.getTitle());
8717      infoWindow.open(marker.getMap(), marker);
8718    });
8719}
8720
8721
8722// end map code
8723
8724function debug(text, persist) {
8725	if(document.getElementById("debug_text")) {
8726		document.getElementById("debug_text").innerHTML = text;
8727		if(!persist) {
8728			window.setTimeout(function () {
8729				document.getElementById("debug_text").innerHTML = "";
8730			}, 2000);
8731		}
8732	}
8733	console.log(text);
8734}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.