PageSourceSearch

https://sleepful.org.uk/custom/sleepful/js/sleepful.js?v=1785925736

js sleepful.org.uk collected 2026-10-05 22:39:29 UTC 9,579 bytes, 276 lines download raw bytes

1function confirmation(options, success_callback) {
2	var disable_scroll = function (e) {
3		e.preventDefault();
4		e.stopPropagation();
5		return false;
6	};
7	var popup = $('<div class="popup-wrapper"><div class="popup"><div class="popup-header"><span>' + (options.header || "Confirmation") + '</span></div>' +
8		'<div class="popup-body"><div class="popup-message">' + (options.message || "Are you sure you want to do this?") + '</div>' +
9		'<div class="popup-buttons"><button class="popup-btn-cancel">Cancel</button><button class="popup-btn-confirm">Ok</button></div>' +
10		'</div>' +
11		'</div></div>');
12	var hide = function () {
13		popup.add(background).fadeOut(170, function () {
14			$(this).remove();
15		});
16		$('body').off('scroll mousewheel touchmove', disable_scroll)
17	};
18	var background = $('<div class="popup-background" />');
19
20	background.add(popup.find('.popup-btn-cancel')).click(hide);
21	if (success_callback)
22		popup.find('.popup-btn-confirm').click(function () {
23			success_callback();
24			hide();
25		});
26	background.appendTo('body');
27	popup.appendTo('body');
28
29	background.add(popup).fadeIn(170);
30	$('body').on('scroll mousewheel touchmove', disable_scroll);
31}
32
33$(function () {
34	$.fn.input_error = function (message) {
35		$(this).each(function () {
36			var parent = $(this).parent();
37			if ($(this).is('.all'))
38				parent = $(this);
39			if (parent.find('.input-error').length)
40				return;
41			var popup = $('<div class="input-error"><span>' + message + '</span></div>');
42			if ($(this).is('input')) {
43				popup.addClass($(this).attr('name'));
44				if ($(this).is('#sleep_rating-hidden')) {
45					parent = $(this).closest('.fm-options');
46				}
47			}
48			parent.append(popup);
49			console.log(parent);
50			parent.css('position', 'relative');
51			popup.css({
52				top: -($(popup).outerHeight() - $(this).position().top || 0) - 3,
53				left: (($(this).outerWidth() || parent.outerWidth()) - $(popup).outerWidth() * .5),
54			});
55			var target;
56			var instance = $(this);
57			instance.addClass('error');
58			if ($(this).is('.all')) {
59				target = $(this).closest('form').find('input');
60			} else if ($(this).is("[type=hidden]")) {
61				target = $(this).closest(".fm-options");
62			} else {
63				target = $(this);
64			}
65			console.log(target);
66			target.add(popup).on('change click focus', function () {
67				popup.fadeOut(170, function () {
68					$(this).remove();
69				});
70				instance.removeClass('error');
71			});
72		});
73	};
74
75
76	// $('a').each(function() {
77	// 	console.log($(this).attr('href'));
78	//
79	// 	if($(this).attr('href') === '/social/facebook') {
80	// 		$(this).attr('href', '/api/social-login/facebook');
81	// 	}
82	//
83	// 	if($(this).attr('href') === '/social/google') {
84	// 		$(this).attr('href', '/api/social-login/google');
85	// 	}
86	//
87	// 	if($(this).attr('href') === '/social/twitter') {
88	// 		$(this).attr('href', '/api/social-login/twitter');
89	// 	}
90	// });
91
92	$('.timepicker-day').click(function (e) {
93		e.preventDefault();
94		$(this).parent().find('input[type=text]').trigger('focus');
95	});
96	$('.sleep-calculator #field-date').each(function () {
97		var value = $(this).find('input[type="hidden"]').val();
98		// The date field always has a value (the framework defaults new
99		// records' date column), so it can't tell a validation-error
100		// redisplay apart from a first visit. The ".errors" summary block
101		// is only rendered when a submission actually failed validation.
102		var is_validation_redisplay = $(this).closest('.sleep-calculator').find('.errors').length > 0;
103		if (is_validation_redisplay && value) {
104			$(this).find('.sleepful-day-picker[data-value="' + value + '"]').addClass('selected');
105			return;
106		}
107		$(this).nextAll().hide();
108		$(this).closest('form.fm-form').find('.fm-footer').hide();
109	});
110	$('.sleepful-day-picker').on('click', function (e) {
111		if ($(this).is('.complete')) return true;
112
113		e.preventDefault();
114		$(this).addClass('selected').siblings().removeClass('selected');
115		$(this).closest('.fm-field').nextAll().show();
116		$(this).closest('form.fm-form').find('.fm-footer').show();
117		$(this).parent().find('input[type="hidden"]').val($(this).data('value'));
118
119	});
120	$(".menu-toggle").click(function (e) {
121		e.stopImmediatePropagation();
122		$(".mobile-menu").toggleClass("show");
123	});
124	$(".month-result h5").click(function (e) {
125		e.stopImmediatePropagation();
126		$(this).closest('.month-result').toggleClass("expanded").toggleClass("collapsed");
127	});
128	$(".login-toggle").each(function () {
129		// Disclosure-widget pattern: the toggle button announces whether the
130		// box it controls is open, and points assistive tech at that box.
131		var toggle = $(this);
132		var box = toggle.next(".login-box");
133		if (!box.attr("id"))
134			box.attr("id", "login-box-" + Math.floor(Math.random() * 100000));
135		toggle.attr({
136			"aria-expanded": box.is(".show"),
137			"aria-controls": box.attr("id")
138		});
139	});
140	$(".login-toggle").click(function (e) {
141		e.stopImmediatePropagation();
142		var instance = $(this);
143		var box = instance.next(".login-box");
144		var close = function () {
145			instance.removeClass("show").attr("aria-expanded", false);
146			box.removeClass("show");
147			$(document).off('click', document_handler).off('keydown', keydown_handler);
148			instance.add(box).off('focusout', focusout_handler);
149		};
150		var document_handler = function (e) {
151			if (!$(e.target).closest('.login-box, .login-toggle').length)
152				close();
153		};
154		var keydown_handler = function (e) {
155			if (e.key === "Escape") {
156				close();
157				instance.trigger('focus');
158			}
159		};
160		var focusout_handler = function (e) {
161			// relatedTarget is the element about to receive focus; null
162			// means focus left for somewhere non-focusable (or the window
163			// lost focus entirely), so treat that as "outside" too.
164			var next = e.relatedTarget;
165			if (!next || (!instance.is(next) && !box.is(next) && !box.has(next).length))
166				close();
167		};
168
169		if (box.is(".show")) {
170			close();
171			return;
172		}
173
174		instance.addClass("show").attr("aria-expanded", true);
175		box.addClass("show");
176		box.find('input, a, button').first().trigger('focus');
177		$(document).on('click', document_handler).on('keydown', keydown_handler);
178		instance.add(box).on('focusout', focusout_handler);
179	});
180	$("#login input[type=password]").each(function () {
181		var input = $(this);
182		var wrapper = input.wrap('<span class="password-wrapper"></span>').parent();
183		var toggle = $('<button type="button" class="password-toggle">Show</button>');
184
185		wrapper.css({position: "relative", display: "block"});
186		input.css({"padding-right": "50px", "box-sizing": "border-box", width: "100%"});
187		toggle.css({
188			position: "absolute",
189			top: "50%",
190			right: "8px",
191			transform: "translateY(-50%)",
192			background: "none",
193			border: "none",
194			padding: "0 4px",
195			"font-size": ".8em",
196			cursor: "pointer",
197			color: "inherit"
198		});
199		toggle.attr({"aria-label": "Show password", "aria-pressed": "false"});
200
201		toggle.on("click", function (e) {
202			e.preventDefault();
203			var showing = input.attr("type") === "text";
204			input.attr("type", showing ? "password" : "text");
205			toggle.text(showing ? "Show" : "Hide");
206			toggle.attr({
207				"aria-label": showing ? "Show password" : "Hide password",
208				"aria-pressed": (!showing).toString()
209			});
210		});
211
212		wrapper.append(toggle);
213	});
214	$("#template:not(.editting) .panel.expanded .panel-header,#template:not(.editting) .panel.collapsed .panel-header").click(function (e) {
215		$(this).closest('.panel').toggleClass("expanded").toggleClass("collapsed");
216	});
217
218
219	$('.sleep-calculator #editform, .results #editform')
220		.data('confirmed', false)
221		.on('submit', function (e) {
222			var instance = $(this);
223
224			// Check input exists
225			var error = false;
226			["time_went_bed", "woke_up", "out_of_bed", "sleep_rating-hidden", "time_taken_to_sleep", "awake_in_night"].forEach(function (value) {
227				var input = instance.find("#" + value);
228				console.log(input);
229				if (input.length)
230					if (!input.val() || input.val() == "00:00:01") {
231						input.input_error("This is a required field.");
232						error = true;
233					}
234			});
235
236			if (error) {
237				e.preventDefault();
238				return false;
239			}
240
241			// Valid times
242
243			["time_went_bed", "woke_up", "out_of_bed", "time_taken_to_sleep", "awake_in_night"].forEach(function (value) {
244				var input = instance.find("#" + value);
245				console.log(input);
246				if (input.length)
247					if (!moment("2012-12-12 " + input.val()).isValid()) {
248						input.input_error("Must be a valid time.");
249						error = true;
250					}
251			});
252
253			if (error) {
254				e.preventDefault();
255				return false;
256			}
257			var time_went_bed_field = $("#field-time-went-bed");
258			var out_of_bed_field = $("#field-out-of-bed");
259			var time_went_bed = moment(time_went_bed_field.find('.timepicker-day').data("date").format("YYYY-MM-DD") + " " + time_went_bed_field.find('input').val());
260			var out_of_bed = moment(out_of_bed_field.find('.timepicker-day').data("date").format("YYYY-MM-DD") + " " + out_of_bed_field.find('input').val());
261
262			if (time_went_bed.diff(out_of_bed, "day") != 0) {
263				if (!instance.data('confirmed')) {
264
265					confirmation({
266						message: "The data you've entered seems to span over 24 hours. Are sure this is correct?"
267					}, function () {
268						instance.data("confirmed", true);
269						instance.find("input[type=submit][name=submit]").click().trigger('click');
270					});
271					e.preventDefault();
272					return false;
273				}
274			}
275		});
276});

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.