PageSourceSearch

https://mdpls.org/js/am-room-info.js?v=1480

js mdpls.org collected 2026-09-24 08:49:44 UTC 21,061 bytes, 504 lines download raw bytes

1;(function ( $, window, document, undefined ) {
2
3	"use strict";
4		var pluginName = "amRoomInfo",
5			defaults = {
6				timeZone:'America/New_York',
7				allowOtherDates:true,
8				pinlessAuth:false,
9				loginRequired:false
10			};
11		var self=false;
12
13		// The actual plugin constructor'email'
14		function Plugin ( element, options ) {
15			self=this;
16			this.element = element;
17			this.$element = $(element);
18			this.settings = $.extend(true, {}, defaults, options );
19			this._defaults = defaults;
20			this._name = pluginName;
21			this.currentTime=moment(self.settings.startTime).tz(self.settings.timeZone);
22			this.currentNavigationDate=self.currentTime.clone().startOf('day');
23			this.init();
24		}
25
26		$.extend(Plugin.prototype, {
27				init: function () {
28					self._buildInterface();
29					self._bindEvents();
30					self._updateRoomList();
31					self._update();
32				},
33				_buildInterface:function(){
34					self.$element.css({
35						backgroundColor: '#171717',
36						color:'##949494',
37						width: '100%',
38						height: '100%',
39						position: 'absolute',
40						top: '0',
41						left: '0'
42
43					});
44
45					self.holder = $('<div class="amri-holder"></div>').appendTo(self.element);
46
47					self.leftCol = $('<div class="amri-left-col"></div>').appendTo(self.holder);
48					self.rightCol = $('<div class="amri-right-col"></div>').appendTo(self.holder);
49
50					self.bookingFormHolder = $('<div class="amri-booking-form-holder"></div>').appendTo(self.leftCol).hide();
51					self.bookingForm = $('<div class="amri-booking-form"></div>').appendTo(self.bookingFormHolder);
52
53					self.statusBox = $('<div class="amri-status-box"></div>').appendTo(self.leftCol);
54					self.statusBoxContent = $('<div class="amri-status-box-content"></div>').appendTo(self.statusBox);
55					self.roomName = $('<div class="amri-room-name"></div>').appendTo(self.statusBoxContent);
56					self.roomStatus = $('<div class="amri-room-status"></div>').appendTo(self.statusBoxContent);
57					self.roomStatusUntil = $('<div class="amri-room-status-until"></div>').appendTo(self.statusBoxContent);
58					self.roomStatusTitle = $('<div class="amri-room-status-title"></div>').appendTo(self.statusBoxContent);
59					self.roomStatusRemaining = $('<div class="amri-room-status-remaining"></div>').appendTo(self.statusBoxContent);
60
61					self.upnextBox = $('<div class="amri-next-box"></div>').appendTo(self.leftCol);
62
63					self.topBox = $('<div class="amri-top-box"></div>').appendTo(self.rightCol);
64					self.timeBox = $('<div class="amri-time-box"><div class="amri-date"></div><div class="amri-time"></div></div>').appendTo(self.topBox);
65					$('<div class="amri-choose-label">Choose a room</div>').appendTo(self.topBox);
66
67					self.availabilityList = $('<div class="amri-availability-box"></div>').appendTo(self.rightCol);
68
69					self.roomList=$('<select class="form-control"></select>').appendTo(self.topBox);
70					if(self.settings.allowOtherDates){
71						self.todayButton=$('<button class="amri-today-btn">Today</button>').appendTo(self.topBox);
72					}
73					self.navigation=$('<div class="amri-navigation"></div>').appendTo(self.topBox);
74
75					if(self.settings.allowOtherDates){
76						$('<div class="amri-prev amri-nav" data-amount="-1"><i class="fa fa-angle-left"></i></div><div class="amri-navigation-date"></div><div class="amri-next amri-nav" data-amount="1"><i class="fa fa-angle-right"></i></div>').appendTo(self.navigation);
77						self.topBox.addClass('amri-has-navigation');
78						self.availabilityList.addClass('amri-has-navigation');
79					}else{
80						$('<div class="amri-bookings-title">Today\'s schedule</div>').appendTo(self.topBox);
81					}
82
83					self.todaysHours=$('<div class="amri-opening-hours"></div>').appendTo(self.topBox);
84					self.bookingsListHolder=$('<div class="amri-bookings-list-holder"></div>').appendTo(self.availabilityList);
85					self.bookingsList=$('<ul class="amri-bookings-list"></ul>').appendTo(self.bookingsListHolder);
86
87					self.bookBox = $('<div class="amri-book-box"></div>').appendTo(self.rightCol);
88					self.bookButton=$('<button class="amri-book-btn">Book a room</button>').appendTo(self.bookBox);
89
90				},
91				_bindEvents:function(){
92					$(window).on('resize.amc', function(event) {//TODO: debounce this
93						event.preventDefault();
94						self.updateFonts();
95					});
96					self.roomList.on('change', function(event) {
97						event.preventDefault();
98						self._updateNavigation();
99					});
100					if(self.settings.allowOtherDates){
101						self.todayButton.on('click', function(event) {
102							event.preventDefault();
103							self.currentNavigationDate=self.currentTime.clone().startOf('day');
104							self._updateNavigation();
105						});
106					}
107					self.navigation.on('click', '.amri-nav', function(event) {
108						event.preventDefault();
109						var amount = parseInt($(this).attr('data-amount'), 10);
110						self.currentNavigationDate.add(amount, 'days');
111						self._updateNavigation();
112					});
113					self.bookButton.on('click', function(event) {
114						event.preventDefault();
115
116						self.statusBox.hide();
117						self.upnextBox.hide();
118						self.bookButton.hide();
119						self.bookingFormHolder.show();
120					});
121					self.bookingForm.on('click', '.amri-cancel-btn', function(event) {
122						event.preventDefault();
123						self.statusBox.show();
124						self.upnextBox.show();
125						self.bookButton.show();
126						self.bookingFormHolder.hide();
127					}).on('change', '.agreed', function(event) {
128						event.preventDefault();
129						if($(this).is(':checked')){
130							$('.amri-submit-book-btn').removeProp('disabled');
131						}else{
132							$('.amri-submit-book-btn').prop('disabled', 'true');
133						}
134					}).on('click', '.amri-submit-book-btn', function(event) {
135						event.preventDefault();
136
137						var clean=true;
138						var requiredFields = $('.required-field', self.bookingForm);
139						for (var i = requiredFields.length - 1; i >= 0; i--) {
140							var input = $(requiredFields[i]).closest('label').parent().find('input');
141							if(input.length>0&&input.val().length===0){
142								var input=$(requiredFields[i]).closest('label').parent().find('input').addClass('amrp-missing-field');
143								clean=false;
144							}
145						}
146						if(!clean){
147							$('.events2-error-message', self.bookingForm).text('Please enter information for all required fields').fadeIn().delay(3000).fadeOut();
148							return;
149						}
150
151						var start = moment(self.currentNavigationDate.format('YYYY-MM-DD')+' '+$('#start_hours').val()+':'+$('#start_mins').val()+$('#start_ampm').val(), 'YYYY-MM-DD h:mma');
152						var end = start.clone().add($('#duration', self.bookingForm).val(), 'minute');
153
154						var open=moment(self.openingHours.raw_open_time);
155						var close=moment(self.openingHours.raw_close_time);
156
157						if(start<open||end>close){
158							$('.events2-error-message', self.bookingForm).text('Sorry, the room is unavailable at this time.').fadeIn().delay(3000).fadeOut();
159							return;
160						}
161
162						for (var i = self.currentRoom.bookings.length - 1; i >= 0; i--) {
163							var booking = self.currentRoom.bookings[i];
164							var lStart=moment(booking.start_time);
165							var lEnd=moment(booking.end_time);
166
167							if(lStart<end && lEnd>start){
168								$('.events2-error-message', self.bookingForm).text('Sorry, the room is unavailable at this time.').fadeIn().delay(3000).fadeOut();
169								return;
170							}
171						}
172						var booking={
173							assets:[],
174							contact:{
175								first_name:$('#first_name', self.bookingForm).val(),
176								last_name:$('#last_name', self.bookingForm).val(),
177								email:$('#email', self.bookingForm).val(),
178								booking_title:$('#booking_title', self.bookingForm).val(),
179								group_name: $('#first_name', self.bookingForm).val()+' '+$('#last_name', self.bookingForm).val(),
180								librarycard:$('#librarycard', self.bookingForm).val(),
181								phone:$('#tel', self.bookingForm).val()
182							},
183							customQuestions:false,
184							start_time: start.format('YYYY-MM-DD HH:mm:ss'),
185							end_time: end.format('YYYY-MM-DD HH:mm:ss'),
186							room_id: self.roomList.val(),
187						}
188						$.getJSON('/reserve?action=submit', booking, function(json, textStatus) {
189							self.statusBox.show();
190							self.upnextBox.show();
191							self.bookButton.show();
192							self.bookingFormHolder.hide();
193							self._update();
194							self._updateNavigation();
195						});
196
197					}).on('focus', '.amrp-missing-field', function(event) {
198						$(this).removeClass('amrp-missing-field');
199					});
200					self.bookingForm.on('click', '.amri-login-btn', function(event) {
201						event.preventDefault();
202						var b=$(this).button('loading');
203
204						// CH#1942 - Trim the card/pin fields to prevent blanks.
205						var card= $.trim($('#login_card', self.holder).val());
206						var pin= $.trim($('#login_pin', self.holder).val());
207
208						$.getJSON(self.settings.apiServer+'/v1/'+self.settings.client+'/patron', {u:card, p:pin, 'type':'reserve'}, function(json, textStatus) {
209							if(json.result=='ok'){
210								if(json.data.names.length>0){
211									$('#first_name', self.bookingForm).val(json.data.names[0].first_name);
212									$('#last_name', self.bookingForm).val(json.data.names[0].last_name);
213
214									$('#booking_title', self.bookingForm).val(json.data.names[0].first_name+' '+json.data.names[0].last_name);
215								}
216								if(json.data.phones.length>0){
217									$('#tel', self.bookingForm).val(json.data.phones[0]);
218								}
219								if(json.data.emails.length>0){
220									$('#email', self.bookingForm).val(json.data.emails[0]);
221								}
222								if(json.data.barcodes.length>0){
223									$('#librarycard', self.bookingForm).val(json.data.barcodes[0]);
224								}
225							}else{
226								$('.events2-error-message', self.holder).text(json.message||'Sorry, pin or card number not found').fadeIn().delay(3000).fadeOut();
227							}
228							b.button('reset');
229						}).error(function() {
230							$('.events2-error-message', self.holder).text('Sorry, there was a problem making the request').fadeIn().delay(3000).fadeOut();
231							b.button('reset');
232						});
233
234					});
235					setInterval(function(){
236						self.currentTime.add(1, 'minute');
237						self._update();
238					}, 60000)
239				},
240				_reset:function(){
241
242				},
243				_createField:function(id, type, label, required, append, desc, min){
244					if(!type)type='text';
245					if(!label)label='';
246					if(!desc)desc='';
247					var field = $('<div class="row"></div>');
248					var input = '';
249
250					switch(type){
251						case 'number':
252						var minV = 0;
253						if(typeof(min) !== "undefined"){
254							minV = min;
255							input='<input type="'+type+'" class="form-control" id="'+id+'" min="'+minV+'">';
256						}else{
257							input='<input type="'+type+'" class="form-control" id="'+id+'">';
258						}
259
260						break;
261						case 'select':
262						input='<select class="form-control" id="'+id+'"></select>';
263						break;
264						default:
265						input='<input type="'+type+'" class="form-control" id="'+id+'">';
266						break;
267					}
268
269					if(append){
270						$('<div class="">'+
271						'<div class="col-sm-5">'+
272						'<div class="input-group">'+
273						input+
274						'</div>'+
275						'</div>'+
276						'</div>').appendTo(field);
277						$('.input-group', field).append(append);
278
279					}else{
280						$('<div class="">'+
281						'<div class="col-sm-5">'+
282						input+
283						'</div>'+
284						'</div>').appendTo(field);
285					}
286
287					var labelEl = $('<label for="'+id+'" class="col-sm-3 control-label">'+label+' </label>').prependTo(field);
288					if(required)labelEl.append('<span class="required-field"></span>');
289					$('<div class="col-sm-4 amrp-field-desc">'+desc+'</div>').appendTo(field);
290					return field;
291				},
292				_updateBookingForm:function(room){
293					self.bookingForm.empty();
294					$('<div class="amri-book-room-title">'+room.title+'</div>').appendTo(self.bookingForm);
295					$('<div class="amri-book-room-date">'+this.currentNavigationDate.format('dddd DD MMMM YYYY')+'</div>').appendTo(self.bookingForm);
296
297
298					self._createField('login_card', 'text', 'Library card number', true).appendTo(self.bookingForm);
299					var pin=self._createField('login_pin', 'password', 'PIN / Password', false, '<span data-loading-text="<i class=\'fa fa-circle-o-notch fa-spin\'></i>" class="btn btn-edit amri-login-btn input-group-addon">Look up details</span>', 'Enter your Library card number and PIN and we\'ll look up your details to fill in the next felds.').appendTo(self.bookingForm);
300
301					var start_hours = self._createField('start_hours', 'select', 'Booking from:', false, false).addClass('amri-booking-start').appendTo(self.bookingForm);
302					var start_select = $('#start_hours', start_hours);
303
304					for (var i = 1; i <= 12; i++) {
305						$('<option>'+i+'</option>').appendTo(start_select);
306					}
307
308					var h=this.currentTime.format('h');
309					var r=Math.round(this.currentTime.format('mm') /15) * 15;
310					if(r==60){
311						r='00';
312						h++;
313						if(h>12)h=1;
314					}else if(r==0){
315						r='00';
316					}
317
318					start_select.val(h);
319
320
321					var startMin=$('<select id="start_mins" class="form-control">'+
322						'<option>00</option>'+
323						'<option>15</option>'+
324						'<option>30</option>'+
325						'<option>45</option>'+
326						'</select>').insertAfter(start_select).val(r);
327
328					var startAMPM=$('<select id="start_ampm" class="form-control">'+
329						'<option>am</option>'+
330						'<option>pm</option>'+
331						'</select>').insertAfter(startMin).val(this.currentTime.format('a'));
332
333
334					var duration = self._createField('duration', 'select', 'Duration:', false, false).appendTo(self.bookingForm);
335
336					for (var i = 15; i <= parseInt(room.restrictions.maximum_booking_time, 10); i+=15) {
337						$('<option value="'+i+'">'+self._formatMinsAsString(i)+'</option>').appendTo($('#duration', duration));
338					}
339
340					self._createField('first_name', 'text', 'First name:', true, false).appendTo(self.bookingForm);
341					self._createField('last_name', 'text', 'Last name:', true, false).appendTo(self.bookingForm);
342
343					self._createField('email', 'text', 'Email', self.settings.emailRequired, false, 'We\'ll use the email address to confirm the booking.').appendTo(self.bookingForm);
344					$('<input type="hidden" id="tel" value="">').appendTo(self.bookingForm);
345					$('<input type="hidden" id="librarycard" value="">').appendTo(self.bookingForm);
346
347					self._createField('booking_title', 'text', 'Display name:', true, false, '(This <b>will be displayed</b> to the public)').appendTo(self.bookingForm);
348
349					if(room.app_tc_link&&room.app_tc_link.length>0){
350						$('<label><input class="agreed" type="checkbox"> I have read and agree to the room booking <a target="_blank" href="'+room.app_tc_link+'">terms and conditions</a></label>').appendTo(self.bookingForm);
351					}else{
352						$('<label><input class="agreed" type="checkbox"> I have read and agree to the room booking terms and conditions</label>').appendTo(self.bookingForm);
353					}
354
355					// $('<div class="amrp-spacer"></div>').appendTo(self.bookingForm);
356					$('<div class="amri-booking-buttons"><div class="events2-error-message"></div><button class="btn btn-edit amri-cancel-btn">Cancel</button><button class="btn btn-success amri-submit-book-btn" disabled="disabled">Book</button></div>').appendTo(self.bookingForm);
357
358				},
359				_updateNavigation:function(){
360						var dateString = self.currentNavigationDate.format('YYYY-MM-DD');
361						var selected=parseInt(self.roomList.val(), 10);
362
363						$.getJSON(self.settings.apiServer+'/v2/'+self.settings.client+'/rooms/'+self.settings.location_id, {date:dateString, classtype:1}, function(json, textStatus) {
364							self.bookingsList.empty();
365							$('.amri-navigation-date', self.navigation).text(self.currentNavigationDate.format('MMMM DD, YYYY'));
366							$.each(json, function (index, room) {
367								if(parseInt(room.id, 10)===selected){
368									self.currentRoom=room;
369									self._updateBookingForm(room);
370									if(room.bookings.length>0){
371										$.each(room.bookings, function(index, val) {
372											var start=moment.tz(val.start_time, self.settings.timeZone);
373											var end=moment.tz(val.end_time, self.settings.timeZone);
374											$('<li><div>' + start.format('h:mma') + ' - ' + end.format('h:mma') + '</div>' + val.display_name + '</li>').appendTo(self.bookingsList);
375										});
376									}else{
377										$('<li class="amri-no-bookings">Free all day</li>').appendTo(self.bookingsList);
378									}
379								}
380							});
381						});
382				},
383				_updateRoomList:function(){
384					self.roomList.empty();
385					$.getJSON(self.settings.apiServer+'/v2/'+self.settings.client+'/rooms/'+self.settings.location_id, {classtype:1, unmediated_only:1}, function(json, textStatus) {
386						$.each(json, function (index, val) {
387							if(self.settings.room_id==val.id){
388								$('<option value="'+val.id+'">'+val.title+' (This room)</option>').appendTo(self.roomList);
389							}else if(val.patron_viewable==="0"){
390								return;
391							}else{
392								$('<option value="'+val.id+'">'+val.title+'</option>').appendTo(self.roomList);
393							}
394						});
395						self.roomList.val(self.settings.room_id);
396						self._updateNavigation();
397					});
398				},
399				_update:function(){
400						self.updateFonts();
401						self._updateTime();
402
403						var dateString = self.currentTime.clone().startOf('day').format('YYYY-MM-DD');
404
405
406						$.getJSON(self.settings.apiServer+'/v2/'+self.settings.client+'/rooms/'+self.settings.location_id, {date:dateString, classtype:1, unmediated_only:1}, function(json, textStatus) {
407							self.rooms=json;
408							$.each(self.rooms, function(index, val) {
409								if(parseInt(val.id, 10)===parseInt(self.settings.room_id, 10)){
410									self.currentRoom=val;
411									self._renderStatus();
412								}
413							});
414
415							$.getJSON(self.settings.apiServer+'/v1/'+self.settings.client+'/opening-hours/'+dateString+'/1', function(openingTimes, textStatus) {
416								self.openingHours=openingTimes[self.settings.location_id][dateString];
417								var d = moment(dateString).startOf('day');
418								self.openingHours.raw_open_time=d.clone().add(moment(self.openingHours.open, 'h:mma').diff(moment().startOf('day'), 'seconds'), 'seconds').format('YYYY-MM-DD HH:mm:ss');
419								self.openingHours.raw_close_time=d.clone().add(moment(self.openingHours.close, 'h:mma').diff(moment().startOf('day'), 'seconds'), 'seconds').format('YYYY-MM-DD HH:mm:ss');
420
421								self.todaysHours.text('Opening hours: '+self.openingHours.open.toLowerCase() + ' - '+self.openingHours.close.toLowerCase());
422							});
423						});
424
425
426				},
427				_renderStatus:function(){
428					self.roomName.text(self.currentRoom.title);
429					var inuse=false;
430					var nextBooking=false;
431					for (var i = self.currentRoom.bookings.length - 1; i >= 0; i--) {
432						var booking = self.currentRoom.bookings[i];
433						if(self.currentTime>moment.tz(booking.start_time, self.settings.timeZone)&&self.currentTime<moment.tz(booking.end_time, self.settings.timeZone)){
434							inuse=booking;
435						}
436						if(!nextBooking&&moment.tz(booking.start_time, self.settings.timeZone)>
436self.currentTime){
437							nextBooking=booking;
438						}
439					}
440					if(inuse){
441						var end=moment.tz(inuse.end_time, self.settings.timeZone);
442						var left=Math.ceil(moment.duration(end.diff(self.currentTime)).asMinutes());
443						self.statusBox.css({backgroundColor: '#C6001F'});
444						self.roomStatus.text('In use');
445						self.roomStatusUntil.text('Until '+end.format('h:mma'));
446						self.roomStatusTitle.text(inuse.display_name);
447						self.roomStatusRemaining.text(self._formatMinsAsString(left)+' remaining');
448					}else{
449						self.statusBox.css({backgroundColor: '#17B603'});
450						self.roomStatus.text('Available');
451					}
452					self.upnextBox.empty();
453					if(nextBooking){
454						var nextStart=moment.tz(nextBooking.start_time, self.settings.timeZone);
455						var nextend=moment.tz(nextBooking.end_time, self.settings.timeZone);
456						$('<div><span>Next:</span> ' + nextStart.format('h:mma') + ' - ' + nextend.format('h:mma') + ' ' + nextBooking.display_name + '</div>').appendTo(self.upnextBox);
457					}
458				},
459				updateFonts:function(){
460					var self=this;
461					$('>div', self.element).each(function(index, el) {
462						$(el).css('font-size', self._getFontSize() + 'px');
463					});
464				},
465				_getFontSize: function(){
466					var self=this;
467					return (self.$element.innerWidth() / 350)*5;
468				},
469				_updateTime:function(){
470					$('.amri-date', self.timeBox).text(self.currentTime.format('dddd DD MMMM YYYY'));
471					$('.amri-time', self.timeBox).text(self.currentTime.format('h:mma'));
472				},
473				_formatMinsAsString:function(mins){
474					var min=parseInt(mins, 10);
475    				if(min<60){
476    					return mins+" minutes";
477    				}
478					var hours = Math.floor( min / 60);
479					var minutes = min % 60;
480					if(minutes>0){
481						if(hours>1){
482							return hours+' hours '+minutes+' minutes';
483						}else{
484							return hours+' hour '+minutes+' minutes';
485						}
486					}else{
487						if(hours>1){
488							return hours+' hours';
489						}else{
490							return hours+' hour';
491						}
492					}
493				}
494		});
495
496		$.fn[ pluginName ] = function ( options ) {
497				return this.each(function() {
498						if ( !$.data( this, "plugin_" + pluginName ) ) {
499								$.data( this, "plugin_" + pluginName, new Plugin( this, options ) );
500						}
501				});
502		};
503
504})( jQuery, window, document );

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.