diff options
Diffstat (limited to 'modules-available/locationinfo/frontend/doorsign.html')
-rwxr-xr-x | modules-available/locationinfo/frontend/doorsign.html | 1804 |
1 files changed, 1804 insertions, 0 deletions
diff --git a/modules-available/locationinfo/frontend/doorsign.html b/modules-available/locationinfo/frontend/doorsign.html new file mode 100755 index 00000000..6c943e03 --- /dev/null +++ b/modules-available/locationinfo/frontend/doorsign.html @@ -0,0 +1,1804 @@ +<!-- + +parameter + +required: + id: [integer] room id, see in admin panel +optional: + + lang:[en,de] set the language + mode:[1,2,3,4] sets the displaying + 1: Calendar & Room + 2: only Calendar + 3: only Room + 4: Calendar & Room alternately + daystoshow:[1,2,3,4,5,6,7] sets how many days the calendar shows + scale:[10-90] scales the calendar and Roomplan in mode 1 + switchtime:[1-120] sets the time between switchen in mode 4 (in seconds) + calupdate: Time the calender querys for updates,in minutes. + roomupdate: Time the PCs in the room gets updated,in seconds. + rotation:[0-3] rotation of the roomplan + vertical:[true] only mode 1, sets the calendar above the roomplan + configupdate: Time interval the config gets updated (in minutes) + scaledaysauto: [true] if true it finds automaticly the daystoshow parameter depending on display size + +--> +<!DOCTYPE html> +<html lang="de"> +<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8"> +<head> + <title>DoorSign</title> + <script type='text/javascript' src='../../../script/jquery.js'></script> + <script type='text/javascript' src='../../js_jqueryui/clientscript.js'></script> + <link rel='stylesheet' type='text/css' href='../../js_jqueryui/style.css'/> + <link rel='stylesheet' type='text/css' href='jquery-week-calendar/jquery.weekcalendar.css'/> + + <script type='text/javascript' src="jquery-week-calendar/jquery.weekcalendar.js"></script> + <style type='text/css'> + + body { + font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif; + margin: 0; + width: 100%; + height: 100%; + float: left; + box-sizing: border-box; + + background-color: #cacaca; + overflow: hidden; + position: absolute; + display: table; + + } + + .row { + background-color: #404040; + box-shadow: 0 0.1875rem 0.375rem rgba(0, 0, 0, 0.25); + margin-bottom: 4px; + + width: 100%; + + } + + .header { + display: table; + color: white; + padding: 0; + height: 8vw; + + } + + .progressbar { + width: 0px; + height: 2px; + position: absolute; + background-color: red; + bottom: 2px; + z-index: 1; + } + + .font { + display: table-cell; + vertical-align: middle; + font-size: 3vw; + font-weight: bold + } + + .courseText { + text-align: center; + } + + .row::after { + content: ""; + clear: both; + display: block; + } + + [class*="col-"] { + float: left;; + padding: 0; + box-sizing: border-box; + } + + .col-1 { + width: 33%; + } + + .col-2 { + width: 33%; + } + + .roomLayoutDesign { + position: relative; + float: left; + boxSizing: border-box; + } + + .roompadding { + float: left; + position: relative; + } + + .room { + position: relative; + background-color: white; + width: 100%; + height: 100%; + overflow: hidden; + border-width: 1px; + border-color: darkgrey; + border-style: solid; + + } + + .calendar { + float: left; + padding: 0; + dboxSizing: border-box; + background: linear-gradient(#cccccc, white); + + } + + .free-busy-busy { + background: grey; + } + + .ui-widget-content { + color: white; + } + + .wc-header { + background-color: #404040; + font-weight: bold; + } + + .ui-state-default { + text-shadow: none; + } + + .square { + display: table; + float: right; + padding: 0; + width: 8vw; + height: 8vw; + } + + .FreeSeatsFont { + display: table-cell; + vertical-align: middle; + font-size: 6vw; + color: white; + top: 0; + margin: 0 auto; + position: relative; + text-align: center; + font-weight: bold; + overflow: visible; + } + + .PCImgDiv { + position: absolute; + left: 0; + bottom: 0; + display: inline-block; + + } + + .OverlayDiv { + position: absolute; + left: 0; + bottom: 0; + width: 100%; + height: 100%; + display: table; + } + + .pcImg { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + + } + + .overlay { + position: relative; + width: 50%; + height: 50%; + opacity: 0.5; + float: left; + z-index: 5; + } + + .overlay-rollstuhl { + width: 25%; + height: 50%; + background-color: white; + opacity: 0.5; + float: left; + } + + .wc-scrollable-grid { + + } + + .ui-widget-content .ui-state-active { + font-weight: bold; + color: black; + } + + .wc-container { + font-weight: bold; + } + + .wc-today { + background-color: white; + } + + .wc-time-header-cell { + background-color: #eeeeee; + border: none; + } + + .ui-corner-all { + moz-border-radius-bottomright: 0; + webkit-border-bottom-right-radius: 0; + -khtml-border-bottom-right-radius: 0; + border-bottom-right-radius: 0; + + moz-border-radius-topright: 0; + webkit-border-top-right-radius: 0; + -khtml-border-top-right-radius: 0; + border-top-right-radius: 0; + + moz-border-radius-bottomleft: 0; + webkit-border-bottom-left-radius: 0; + -khtml-border-bottom-left-radius: 0; + border-bottom-left-radius: 0; + + moz-border-radius-topleft: 0; + webkit-border-left-right-radius: 0; + -khtml-border-left-right-radius: 0; + border-top-left-radius: 0; + } + + .wc-scrollable-grid .wc-day-column-first { + border-style: solid; + + } + + [class*="wc-day-"] { + border-color: grey; + } + + + </style> + <script type='text/javascript'> + + var rooms = {}; + var lastSwitchTime; + var roomsToshow = 0; + var roomIds; + //Todo change these + var date; + var supportSvg = typeof SVGRect != "undefined"; + var calendarQueryUrl; + var translation = { + "en": { + "room": "Room", + "closed": "Closed", + "free": "Free", + "shortDays": ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], + "longDays": ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], + "to": "to" + + }, + "de": { + "room": "Raum", + "closed": "Geschlossen", + "free": "Frei", + "shortDays": ["Son", "Mon", "Die", "Mit", "Don", "Frei", "Sam"], + "longDays": ["Sonntag", "Montag", "Dienstag", "Mittwoch", "Donnerstag", "Freitag", "Samstag"], + "to": "bis" + }, + "pt": { + "room": "Quarto", + "closed": "Fechado", + "free": "Livre", + "shortDays": ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Se', 'Sáb'], + "longDays": ['Domingo', 'Segunda-feira', 'Terça-feira', 'Quarta-feira', 'Quinta-feira', + 'Sexta-feira', 'Sábado'], + "to": "para" + + } + }; + + + $(document).ready(function () { + if (!getId()) { + + } + }); + + + /** + * Downloads the config of a room, also reloads the page if the config hase changed over time + * @param id ID of the room + * @param room Room Object, only needed if it already exists + */ + + function getConfig(id, room) { + $.ajax({ + url: "../../../api.php?do=locationinfo&action=config&id=" + id, + dataType: 'json', + cache: false, + timeout: 30000, + success: function (result) { + + if (room == null) { + + if (result.room == null) { + + for (var i = roomIds.length - 1; i >= 0; i--) { + if (roomIds[i] === id) { + roomIds.splice(i, 1); + } + } + if (roomsToshow == roomIds.length) { + + initRooms(); + + } + return; + } + + var time = new Date(result.time); + if (isNaN(time.getTime())) { + time = new Date(); + } + SetUpDate(time); + delete result.time; + + room = addRoom(id, result.room, result); + roomsToshow++; + if (roomsToshow == roomIds.length) { + + initRooms(); + + } + + + } else { + + delete result.time; + if (JSON.stringify(rooms[id].config) != JSON.stringify(result)) { + // reload Page if someone changed config + location.reload(true); + } + } + // check for config changes from time to time + setTimeout(function () { + getConfig(id, room); + }, room.config.configupdate); + + + }, error: function () { + //Todo Error handling: + } + }) + } + + + /** + * gets the Parameter IDs from the Urls + */ + function getId() { + roomIds = getUrlParameter("id"); + if (roomIds == null) { + + var text = "<h1>Error: No Room Id's given in parameter </h1>"; + $("body").append(text); + + return false; + } + + roomIds = roomIds.split(','); + if (roomIds.length > 4) { + roomIds.length = 4; + } + + for (var i = 0; i < roomIds.length; i++) { + getConfig(roomIds[i], null); + + } + + } + + + /** + * gets Additional Parameters from the URL, and from the + * downloaded json. + * also makes sure parameters are in a given range + * @param room Room Object + */ + + function getParamerter(room) { + + + if (room.config != null) { + room.config.switchtime = room.config.switchtime * 1000; + room.config.calupdate = room.config.calupdate * 60 * 1000; + room.config.roomupdate = room.config.roomupdate * 1000; + room.config.configupdate = room.config.configupdate * 60 * 1000; + } + + if (getUrlParameter("mode") != null) { + room.config.mode = parseInt(getUrlParameter("mode")); + } + if (getUrlParameter("calupdate") != null) { + room.config.calupdate = (parseInt(getUrlParameter("calupdate")) * 60 * 1000); + } + if (getUrlParameter("roomupdate") != null) { + room.config.roomupdate = (parseInt(getUrlParameter("roomupdate")) * 1000); + } + if (getUrlParameter("daystoshow") != null) { + room.config.daystoshow = parseInt(getUrlParameter("daystoshow")); + } + if (getUrlParameter("scaledaysauto") == "true") { + room.config.scaledaysauto = true; + } else if (getUrlParameter("scaledaysauto") == "false") { + room.config.scaledaysauto = false; + } + if (getUrlParameter("vertical") == "true") { + room.config.vertical = true; + } else if (getUrlParameter("vertical") == "false") { + room.config.vertical = false; + } + if (getUrlParameter("einkmode") == "true") { + room.config.einkmode = true; + } else if (getUrlParameter("einkmode") == "false") { + room.config.einkmode = false; + } + + if (getUrlParameter("scale") != null) { + room.config.scale = parseInt(getUrlParameter("scale")); + } + if (getUrlParameter("rotation") != null) { + room.config.rotation = parseInt(getUrlParameter("rotation")); + } + if (getUrlParameter("switchtime") != null) { + room.config.switchtime = (parseInt(getUrlParameter("switchtime")) * 1000); + } + if (getUrlParameter("configupdate") != null) { + room.config.configupdate = (parseInt(getUrlParameter("configupdate")) * 60 * 1000); + } + + // parameter validation + if (room.config.switchtime == null || isNaN(room.config.switchtime) || room.config.switchtime > 120 * 1000 + || room.config.switchtime < 1 * 1000) { + room.config.switchtime = 5 * 1000; + } + if (room.config.scale == null || isNaN(room.config.scale) || room.config.scale > 90 || room.config.scale < 10) { + room.config.scale = 50; + } + if (room.config.vertical == null) { + room.config.vertical = false; + } + if (room.config.daystoshow == null || isNaN(room.config.daystoshow) || room.config.daystoshow > 7 + || room.config.daystoshow < 1) { + room.config.daystoshow = 7; + } + + if (room.config.roomupdate == null || isNaN(room.config.roomupdate) || room.config.roomupdate < 1000) { + room.config.roomupdate = 20 * 1000; + } + if (room.config.configupdate == null || isNaN(room.config.configupdate) || (room.config.configupdate < 1)) { + room.config.configupdate = 30 * 60 * 1000; + } + + if (room.config.calupdate == null || isNaN(room.config.calupdate) || room.config.calupdate < 60 * 1000) { + room.config.calupdate = 30 * 60 * 1000; + } + if (room.config.mode == null || isNaN(room.config.mode) || room.config.mode > 4 || room.config.mode < 1) { + room.config.mode = 1; + } + if (room.config.rotation == null || isNaN(room.config.rotation) || room.config.rotation < 0 + || room.config.rotation > 4) { + room.config.rotation = 0; + } + + if (getUrlParameter("lang") != null && getUrlParameter("lang") in translation) { + room.config.language = getUrlParameter("lang"); + } + $('html').attr('lang', room.config.language); + } + + /** + * generates the Room divs and calls the needed functions depending on the rooms mode + */ + function initRooms() { + + var width = "100%"; + var height = "100%"; + if (roomsToshow == 2 || roomsToshow == 4) { + width = "50%"; + } + if (roomsToshow == 3) { + width = "33%"; + } + if (roomsToshow == 4) { + height = "50%"; + } + var i = 0; + for (var t = 0; t < roomIds.length; t++) { + var property = roomIds[t]; + var text = "<div class='roompadding' id ='roompadding_" + rooms[property].id + "'></div>"; + $("body").append(text); + + + var obj = document.getElementById("roompadding_" + rooms[property].id); + obj.style.height = height; + obj.style.width = width; + text = "<div class='room' id ='room_" + rooms[property].id + "'></div>"; + + $("#roompadding_" + rooms[property].id).append(text); + + + text = "<div id='header_" + rooms[property].id + "' class='row'>" + + "<div class='header col-2'>" + + "<div class='font' id='roomHeader_" + rooms[property].id + "'></div>" + + "</div>" + + "<div class='col-1 courseText header'>" + + "<div class='font' id='courseHeading_" + rooms[property].id + "'></div>" + + "</div>" + + "<div class='square .col-2' id='square_" + rooms[property].id + "'>" + + "<div class='FreeSeatsFont' id='freeSeatsHeader_" + rooms[property].id + "'></div>" + + "</div>" + + "</div>"; + $("#room_" + rooms[property].id).append(text); + + if (rooms[property].name != null) { + $("#roomHeader_" + rooms[property].id).text(rooms[property].name); + } + + if (roomsToshow == 2) { + document.getElementById("square_" + rooms[property].id).style.width = "6vw"; + document.getElementById("square_" + rooms[property].id).style.height = "6vw"; + document.getElementById("roomHeader_" + rooms[property].id).style.fontSize = "1.8vw"; + document.getElementById("freeSeatsHeader_" + rooms[property].id).style.fontSize = "4.5vw"; + document.getElementById("courseHeading_" + rooms[property].id).style.fontSize = "1.8vw"; + var headers = document.getElementsByClassName('header'); + for (var j = 0; j < headers.length; j++) { + headers[j].style.height = "6vw"; + } + } + if (roomsToshow == 3) { + document.getElementById("square_" + rooms[property].id).style.width = "4vw"; + document.getElementById("square_" + rooms[property].id).style.height = "4vw"; + document.getElementById("roomHeader_" + rooms[property].id).style.fontSize = "1.2vw"; + document.getElementById("freeSeatsHeader_" + rooms[property].id).style.fontSize = "2.5vw"; + document.getElementById("courseHeading_" + rooms[property].id).style.fontSize = "1.2vw"; + var headers = document.getElementsByClassName('header'); + for (var j = 0; j < headers.length; j++) { + headers[j].style.height = "4vw"; + } + + } + if (roomsToshow == 4) { + document.getElementById("square_" + rooms[property].id).style.width = "4vw"; + document.getElementById("square_" + rooms[property].id).style.height = "4vw"; + document.getElementById("roomHeader_" + rooms[property].id).style.fontSize = "1.5vw"; + document.getElementById("freeSeatsHeader_" + rooms[property].id).style.fontSize = "2.5vw"; + document.getElementById("courseHeading_" + rooms[property].id).style.fontSize = "1.5vw"; + + var headers = document.getElementsByClassName('header'); + for (var j = 0; j < headers.length; j++) { + headers[j].style.height = "4vw"; + } + } + + + if (rooms[property].config.mode == 1) { + setUpCalendar(rooms[property].config.scale + "%", rooms[property].config.daystoshow, rooms[property]); + preInitRoom(rooms[property]); + + } else if (rooms[property].config.mode == 2) { + setUpCalendar("100%", rooms[property].config.daystoshow, rooms[property]); + + } else if (rooms[property].config.mode == 3) { + preInitRoom(rooms[property]); + getOpeningTimes(rooms[property]); + } else if (rooms[property].config.mode == 4) { + + setUpCalendar("100%", rooms[property].config.daystoshow, rooms[property]); + preInitRoom(rooms[property]); + generateProgressBar(rooms[property].id); + } + + i++; + } + + setInterval(mainUpdateLoop, 1000); + } + + /** + * Helper function to generate id string used in query functions + * @param list A string, wicht contains ids or not(for now) + * @param id An ID which should be added to the list + */ + function addIdToUpdateList(list, id) { + if (list == "") { + list += id; + } else { + list += ("," + id); + } + return list; + } + + + var timeSteps = 10; + /** + * Main Update loop, this loop runs every 1 seconds and calls all + * function which should be called periodically + */ + function mainUpdateLoop() { + + // check ervery 10 sec if rooms need new calendar data or room data + // groups request + + if (timeSteps > 9) { + timeSteps = 0; + + var calendarUpdateIds = ""; + var rommUpdateIds = ""; + for (var property in rooms) { + if (rooms[property].config.lastCalendarUpdate == null || rooms[property].config.lastCalendarUpdate + rooms[property].config.calupdate < MyDate().getTime()) { + + calendarUpdateIds = addIdToUpdateList(calendarUpdateIds, rooms[property].id); + rooms[property].config.lastCalendarUpdate = MyDate().getTime(); + } + if (rooms[property].config.lastRoomUpdate == null || rooms[property].config.lastRoomUpdate + rooms[property].config.roomupdate < MyDate().getTime()) { + rommUpdateIds = addIdToUpdateList(rommUpdateIds, rooms[property].id); + rooms[property].config.lastRoomUpdate = MyDate().getTime(); + } + } + + + if (calendarUpdateIds != "") { + queryCalendars(calendarUpdateIds); + } + if (rommUpdateIds != "") { + queryRooms(rommUpdateIds); + } + } + + + // switches calendar and roomlayout in mode 4 + + for (var property in rooms) { + if (rooms[property].config.mode == 4) { + if (rooms[property].lastSwitchTime == null + || rooms[property].lastSwitchTime + rooms[property].config.switchtime < MyDate().getTime()) { + + + switchLayout(rooms[property]); + MoveProgressBar(rooms[property].id, rooms[property].config.switchtime); + + if (rooms[property].lastSwitchTime == null) { + rooms[property].lastSwitchTime = MyDate().getTime(); + } else { + rooms[property].lastSwitchTime = rooms[property].lastSwitchTime + rooms[property].config.switchtime; + } + } + + // + } + // Updateing All room Headers + + UpdateRoomHeader(rooms[property]); + } + + + // reload site at midnight + var now = new MyDate(); + if (date != null) { + if (date.getDate() != now.getDate()) { + location.reload(true); + } + } + date = now; + timeSteps++; + + } + + /** + * Generates a room Object and adds it to the rooms array + * @param id ID of the room + * @param name Name of the room + * @param config Config Json of the room + */ + function addRoom(id, name, config) { + var room = { + id: id, + name: name, + timetable: null, + currentEvent: null, + nextEventEnd: null, + timeTilFree: null, + state: null, + openingTimes: null, + config: config, + currentfreePcs: 0, + layout: null, + freePcs: 0, + resized: true, + lastCalendarUpdate: null, + lastRoomUpdate: null, + getState: function () { + if (this.state == null) { + ComputeCurrentState(this); + return this.state; + } + if (this.state.end != "") { + if (this.state.end < new MyDate()) { + ComputeCurrentState(this); + } + } + return this.state; + } + + + }; + getParamerter(room); + rooms[id] = room; + return room; + + } + + /** + * inilizes the Calendar for an room + * @param percent Percentages of how mucht width the Calendar div should get (only used in mode 1) + * @param daysToShow How many days the calendar should show + * @param room Room Object + */ + function setUpCalendar(percent, daysToShow, room) { + generateCalendarDiv(percent, room); + var $calendar = $("#calendar_" + room.id).weekCalendar({ + timeslotsPerHour: 1, + timeslotHeight: 30, + daysToShow: daysToShow, + height: function ($calendar) { + var height = $(window).height(); + if (roomsToshow == 4) { + height = height / 2; + } + + height = height - document.getElementById('header_' + room.id).clientHeight - 5; + if (room.config.mode == 1 && room.config.vertical) { + height = height * (room.config.scale / 100) + } + return height; + }, + eventRender: function (calEvent, $event) { + if (calEvent.end.getTime() < new MyDate().getTime()) { + $event.css("backgroundColor", "#aaa"); + $event.find(".time").css({"backgroundColor": "#999", "border": "1px solid #888"}); + } else if (calEvent.end.getTime() > new MyDate().getTime() && calEvent.start.getTime() < new MyDate().getTime()) { + $event.css("backgroundColor", "#25B002"); + $event.find(".time").css({"backgroundColor": "#25B002", "border": "1px solid #888"}); + } + }, + date: MyDate(), + dateFormat: "j.n", + timeFormat: "G:i", + scrollToHourMillis: 500, + use24Hour: true, + readonly: true, + showHeader: false, + hourLine: true, + shortDays: t("shortDays", room.config.language), + longDays: t("longDays", room.config.language), + buttons: false, + timeSeparator: " " + t("to", room.config.language) + " ", + startOnFirstDayOfWeek: false, + displayFreeBusys: true, + defaultFreeBusy: {free: false} + }); + getOpeningTimes(room); + + + } + + /** + * downloads openingTimes for an room + * @param room Room Object + */ + function getOpeningTimes(room) { + $.getJSON("../../../api.php?do=locationinfo&action=openingtime&id=" + room.id, function (result) { + if (Object.prototype.toString.call(result) === '[object Array]') { + if (result.length > 0) { + SetOpeningTimes(result[0].openingtime, room); + } + } + scaleCalendar(room); + + }) + .error(function () { + scaleCalendar(room); + + }) + } + + + /** + * Generates the Calendar Div, depending on it's width + * @param width width of the Calendar Div + * @param room Room Object + */ + + function generateCalendarDiv(width, room) { + var div = document.createElement("div"); + div.id = "calendar_" + room.id; + div.className = "calendar"; + if (room.config.vertical && room.config.mode == 1) { + width = 100 + "%"; + div.float = "Top"; + } + div.style.width = width; + //document.body.appendChild(div); + $("#room_" + room.id).append(div); + + } + + /** + * sets the opening Time in the calendar plugin and saves it in the room object + * @param parsedOpenings Dictonary of Opening times. + * @param room Room Object + */ + + function SetOpeningTimes(parsedOpenings, room) { + var opening = 24; + var close = 0; + room.openingTimesCalendar = []; + room.openingTimes = [parsedOpenings['Sunday'], parsedOpenings['Monday'], parsedOpenings['Tuesday'], + parsedOpenings['Wednesday'], parsedOpenings['Thursday'], + parsedOpenings['Friday'], parsedOpenings['Saturday']]; + if (room.config.mode == 3) { + return; + } + for (var i = 0; i < 7; i++) { + var tmp = room.openingTimes[i]; + if (tmp != null) { + for (var d = 0; d < tmp.length; d++) { + var day = getNextDayOfWeek(new MyDate(), i); + room.openingTimesCalendar.push({ + "start": new Date(day.getFullYear(), day.getMonth(), day.getDate(), + tmp[d]['HourOpen'], tmp[d]['MinutesOpen']), + "end": new Date(day.getFullYear(), day.getMonth(), + day.getDate(), tmp[d]['HourClose'], tmp[d]['MinutesClose']), + "free": true + }); + if (parseInt(tmp[d]['HourOpen']) < opening) { + opening = tmp[d]['HourOpen']; + } + if (parseInt(tmp[d]['HourClose']) > close) { + close = tmp[d]['HourClose']; + if (parseInt(tmp[d]['MinutesClose']) != 0) { + close++; + } + } + } + } + } + if (parsedOpenings.length == 0) { + opening = 0; + close = 24; + } + room.openTimes = close - opening; + $('#calendar_' + room.id).weekCalendar("option", "businessHours", { + start: parseInt(opening), + end: parseInt(close), + limitDisplay: true + }); + } + + /** + * querys the Calendar data + * @param ids ID'S of rooms to query as string, for e.g.: "5,17,8" or "5" + */ + function queryCalendars(ids) { + var url = "../../../api.php?do=locationinfo&action=calendar&id=" + ids; + + // Todo reimplement Frontend methode if needed + /* + if(!(room.config.calendarqueryurl === undefined)) { + url = room.config.calendarqueryurl; + } + */ + $.ajax({ + url: url, + dataType: 'json', + cache: false, + timeout: 30000, + success: function (result) { + var l = result.length; + for (var i = 0; i < l; i++) { + updateCalendar(result[i].calendar, rooms[result[i].id]); + } + + + }, error: function () { + + } + }); + } + + /** + * applays new calendar data to the calendar plugin and also saves it to the room object + * @param json Calendar data JSON + * @param room Room Object + */ + function updateCalendar(json, room) { + + if (!json) { + console.log("Error: Calendar data was an empty string."); + return; + } + try { + room.timetable = json; + if (room.config.mode != 3) { + var cal = $('#calendar_' + room.id); + cal.weekCalendar("option", "data", json); + cal.weekCalendar("refresh"); + cal.weekCalendar("option", "defaultFreeBusy", {free: false}); + cal.weekCalendar("updateFreeBusy", room.openingTimesCalendar); + } + ComputeCurrentState(room); + } catch (e) { + console.log("Error: Couldnt add calendar data"); + console.log(e); + } + } + + /** + * scales calendar, called once on create and on window resize + * @param room Room Object + */ + function scaleCalendar(room) { + if (room.config.mode == 3) { + return; + } + if (room.openTimes == null) { + room.openTimes = 24; + } + var cal = $('#calendar_' + room.id); + var columnWidth = document.getElementById("calendar_" + room.id).getElementsByClassName("wc-day-1")[0].clientWidth; + + if (room.config.scaledaysauto) { + var result = (cal.weekCalendar("option", "daysToShow") * columnWidth) / 100; + result = parseInt(Math.min(Math.max(Math.abs(result), 1), 7)); + if (result != parseInt(cal.weekCalendar("option", "daysToShow"))) { + + cal.weekCalendar("option", "daysToShow", Math.abs(result)); + } + } + if (((!room.config.scaledaysauto) || cal.weekCalendar("option", "daysToShow") == 1) && columnWidth < 85) { + cal.weekCalendar("option", "useShortDayNames", true); + } else { + cal.weekCalendar("option", "useShortDayNames", false); + } + var clientHeight = $(window).height(); + if (roomsToshow == 4) { + clientHeight = clientHeight / 2; + } + + clientHeight = clientHeight - document.getElementById('header_' + room.id).clientHeight + - document.getElementsByClassName("wc-time-column-header")[0].clientHeight - 2; + + if (room.config.mode == 1 && room.config.vertical) { + + clientHeight = clientHeight * (room.config.scale / 100); + clientHeight -= 22; + } + clientHeight -= 6; + var height = clientHeight / (room.openTimes * cal.weekCalendar("option", "timeslotsPerHour")); + + + if (height < 30) { + height = 30; + } + // Scale calendar font + if (height > 120) { + cal.weekCalendar("option", "textSize", 28); + } + else if (height > 100) { + cal.weekCalendar("option", "textSize", 24); + } else if (height > 80) { + cal.weekCalendar("option", "textSize", 22); + } else if (height > 70) { + cal.weekCalendar("option", "textSize", 20); + } else if (height > 60) { + cal.weekCalendar("option", "textSize", 14); + } else { + cal.weekCalendar("option", "textSize", 13); + } + cal.weekCalendar("option", "timeslotHeight", height); + if (room.openingTimesCalendar != null) { + cal.weekCalendar("updateFreeBusy", room.openingTimesCalendar); + } + cal.weekCalendar("resizeCalendar"); + cal.weekCalendar("scrollToHour"); + + } + + /** + * used for countdown + * computes the time difference between 2 Date objects + * @param a Date Object + * @param b Date Object + * @param room Room Object + * @returns time string + */ + function GetTimeDiferenceAsString(a, b, room) { + if (a == null || b == null) { + return ""; + } + var milliseconds = a.getTime() - b.getTime(); + var seconds = Math.floor((milliseconds / 1000) % 60); + milliseconds -= seconds * 1000; + var minutes = Math.floor((milliseconds / (1000 * 60)) % 60); + milliseconds -= minutes * 1000 * 60; + var hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24); + + var days = Math.floor((milliseconds / (1000 * 60 * 60 * 24)) % 31); + if (seconds < 10) { + seconds = "0" + seconds; + } + if (minutes < 10) { + minutes = "0" + minutes; + } + if (days != 0) { + // dont show? + return ""; + } + if (room.config.einkmode) { + return hours + ":" + minutes; + } + return hours + ":" + minutes + ":" + seconds; + } + + /** + * returns next closing time of a given room + * @param room + * @returns Date Object of next closing + */ + function GetNextClosing(room) { + var now = new MyDate(); + var day = now.getDay(); + var offset = 0; + var bestdate; + for (var a = 0; a < 7; a++) { + var tmp = room.openingTimes[day]; + if (tmp != null) { + for (var i = 0; i < tmp.length; i++) { + var closeDate = new MyDate(); + closeDate.setDate(now.getDate() + offset); + closeDate.setHours(tmp[i].HourClose); + closeDate.setMinutes(tmp[i].MinutesClose); + closeDate.setSeconds(0); + if (closeDate > now) { + if (!IsOpen(new Date(closeDate.getTime() + 60000), room)) { + if (bestdate == null || bestdate > closeDate) { + bestdate = closeDate; + } + } + } + } + } + offset++; + day++; + if (day > 6) { + day = 0; + } + } + return bestdate; + } + + + /** + * checks if a room is on a given date/time open + * @param date Date Object + * @param room Room object + * @returns bool for open or not + */ + function IsOpen(date, room) { + if (room.openingTimes == null) { + return false; + } + var tmp = room.openingTimes[date.getDay()]; + if (tmp == null) { + return false; + } + for (var i = 0; i < tmp.length; i++) { + var openDate = new MyDate(); + openDate.setHours(tmp[i].HourOpen); + openDate.setMinutes(tmp[i].MinutesOpen); + var closeDate = new MyDate(); + closeDate.setHours(tmp[i].HourClose); + closeDate.setMinutes(tmp[i].MinutesClose); + if (openDate < date && closeDate > date) { + return true; + } + } + return false; + } + + + /** + * Retruns next Opening + * @param room Room Object + * @returns bestdate Date Object of next opening + */ + function GetNextOpening(room) { + var now = new MyDate(); + var day = now.getDay(); + var offset = 0; + var bestdate; + for (var a = 0; a < 7; a++) { + if (room.openingTimes == null) { + return null; + } + var tmp = room.openingTimes[day]; + if (tmp != null) { + for (var i = 0; i < tmp.length; i++) { + var openDate = new MyDate(); + openDate.setDate(now.getDate() + offset); + openDate.setHours(tmp[i].HourOpen); + openDate.setMinutes(tmp[i].MinutesOpen); + if (openDate > now) { + if (!IsOpen(new Date(openDate.getTime() - 60000), room)) { + if (bestdate == null || bestdate > openDate) { + bestdate = openDate; + } + } + } + } + } + offset++; + day++; + if (day > 6) { + day = 0; + } + } + return bestdate; + } + + + /** + * Sets the free PCs number in the right corner and updates the sqare color acordingly + * @param id Room id + * @param seats Number of free PC's in the room + */ + function SetFreeSeats(id, seats) { + if (seats > 0) { + $("#freeSeatsHeader_" + id).text(seats); + $("#square_" + id).css('background-color', '#00dd10'); + } else if (seats == -1) { + $("#freeSeatsHeader_" + id).text(""); + $("#square_" + id).css('background-color', 'red'); + } else { + $("#freeSeatsHeader_" + id).text("0"); + $("#square_" + id).css('background-color', 'red'); + } + } + + /** + * Updates the Header of an Room + * @param room Room Object + */ + function UpdateRoomHeader(room) { + var tmp = room.getState(); + if (tmp.state == "closed") { + $("#courseHeading_" + room.id).text(t("closed", room.config.language) + " " + GetTimeDiferenceAsString(tmp.end, new MyDate(), room)); + SetFreeSeats(room.id, room.freePcs); + } else if (tmp.state == "ClaendarEvent") { + $("#courseHeading_" + room.id).text(tmp.title); + SetFreeSeats(room.id, -1); + } else if (tmp.state == "Free") { + $("#courseHeading_" + room.id).text(t("free", room.config.language) + " " + GetTimeDiferenceAsString(tmp.end, new MyDate(), room)); + SetFreeSeats(room.id, room.freePcs); + } else if (tmp.state == "FreeNoEnd") { + $("#courseHeading_" + room.id).text(t("free", room.config.language)); + SetFreeSeats(room.id, room.freePcs); + } + } + + /** + * computes state of a room, states are: + * closed, FreeNoEnd, Free, ClaendarEvent. + * @param Room Object + */ + function ComputeCurrentState(room) { + if (!IsOpen(new MyDate(), room)) { + room.state = {state: "closed", end: GetNextOpening(room), title: "", next: ""}; + + return; + } + var closing = GetNextClosing(room); + + var event = getNextEvent(room.timetable); + + // no event and no closing + if (closing == null && event == null) { + room.state = {state: "FreeNoEnd", end: "", title: "", next: ""}; + return; + } + + // no event so closing is next + if (event == null) { + room.state = {state: "Free", end: closing, title: "", next: "closing"}; + return; + } + + // event is at the moment + if ((closing == null || event.start.getTime() < closing.getTime()) && event.start.getTime() < new MyDate()) { + room.state = {state: "ClaendarEvent", end: event.end, title: event.title, next: ""}; + return; + } + + // no closing so event is next + if (closing == null) { + room.state = {state: "Free", end: event.start, title: "", next: "event"}; + return; + } + + // event sooner then closing + if (event.start.getTime() < closing) { + room.state = {state: "Free", end: event.start, title: "", next: "event"}; + } else if (event.start.getTime() > closing) { + room.state = {state: "Free", end: closing, title: "", next: "closing"}; + } + + } + + + /** + * returns next event from a given json of events + * @param json Json which contains the calendar data. + * @returns event next Carlendar Event + */ + function getNextEvent(json) { + var event; + var now = new MyDate(); + if (json == null) { + return; + } + for (var i = 0; i < json.length; i++) { + //event is now active + if (json[i].start.getTime() < now.getTime() && json[i].end.getTime() > now.getTime()) { + return json[i]; + } + //first element to consider + if (event == null) { + if (json[i].start.getTime() > now.getTime()) { + event = json[i]; + } + } + if (json[i].start.getTime() > now.getTime() && event.start.getTime() > json[i].start.getTime()) { + event = json[i]; + } + } + return event; + } + + function getNextDayOfWeek(date, dayOfWeek) { + // Code to check that date and dayOfWeek are valid left as an exercise ;) + + var resultDate = new Date(date.getTime()); + + resultDate.setDate(date.getDate() + (7 + dayOfWeek - date.getDay()) % 7); + + return resultDate; + } + /* + /========================================== Room Layout ============================================= + */ + + + var picSizeX = 3.8; + var picSizeY = 3; + + /** + * Generates the RoomLayout Div + * @param width The width the RoomLayout should have (in percent). + * @param room Room Object + */ + function generateRoomLayoutDiv(width, room) { + var div = document.createElement("div"); + div.id = "roomLayout_" + room.id; + div.className = "roomLayoutDesign"; + if ((room.config.vertical && room.config.mode == 1) || (room.config.mode == 3) || (room.config.mode == 4)) { + width = 100 + "%"; + div.float = "Top"; + } + + div.style.width = width; + if (room.config.mode == 4) { + div.style.display = "none"; + } + //document.body.appendChild(div); + $("#room_" + room.id).append(div); + + + } + /** + * Donwloads Room Layout Json (which contains the pc information for a given room) + * @param room Room Object + */ + function preInitRoom(room) { + + $.getJSON("../../../api.php?do=locationinfo&action=locationinfo&id=" + room.id + "&coords=1", function (result) { + + generateRoomLayoutDiv((100 - room.config.scale) + "%", room); + if (result && result[0] && result[0].computer) { + initRoom(result[0].computer, room); + } else { + initRoom([], room); + } + + }).error(function () { + + generateRoomLayoutDiv((100 - room.config.scale) + "%", room); + + }) + } + + + /** + * Main funciton for generating the Room Layout + * @param layout Layout Json + * @param room Room Object + */ + function initRoom(layout, room) { + var maxX; + var maxY; + var minY; + var minX; + var xDifference; + var yDifference; + room.layout = layout; + if (layout == null || layout.length == 0) { + return; + } + if (room.config.rotation != 0) { + rotateRoom(room.config.rotation, layout); + } + + + for (var i = 0; i < layout.length; i++) { + if (!isNaN(parseInt(layout[i].x)) && !isNaN(parseInt(layout[i].y)) && layout[i].y != null && layout[i].y != null) { + if (minX === undefined) { + minX = parseInt(layout[i].x); + } + if (minY === undefined) { + minY = parseInt(layout[i].y); + } + if (maxX === undefined) { + maxX = parseInt(layout[i].x); + } + if (maxY === undefined) { + maxY = parseInt(layout[i].y); + } + if (parseInt(layout[i].x) < parseInt(minX)) { + minX = parseInt(layout[i].x); + } + if (parseInt(layout[i].y) < parseInt(minY)) { + minY = parseInt(layout[i].y); + } + if (parseInt(layout[i].x) > parseInt(maxX)) { + maxX = parseInt(layout[i].x); + } + if (parseInt(layout[i].y) > parseInt(maxY)) { + maxY = parseInt(layout[i].y); + } + } + } + + xDifference = maxX - minX; + yDifference = maxY - minY; + + room.xDifference = xDifference; + room.yDifference = yDifference; + room.minX = minX; + room.minY = minY; + room.maxX = maxX; + room.maxY = maxY; + + generateOffsetAndScale(room); + setUpRoom(room, layout); + scaleRoom(room); + UpdatePc(layout, room); + + } + + /** + * Computes offsets and scaling's for the RoomLayout + * @param room Room Object + */ + function generateOffsetAndScale(room) { + + var clientHeight = $(window).height(); + if (roomsToshow == 4) { + clientHeight = clientHeight / 2; + } + + clientHeight = clientHeight - document.getElementById('header_' + room.id).clientHeight - 5; + + if (roomsToshow > 1) { + clientHeight -= 5; + } + if (room.config.vertical && room.config.mode == 1) { + clientHeight = clientHeight * (1 - (room.config.scale / 100)); + } + var roomLayout = document.getElementById('roomLayout_' + room.id); + + var clientWidth = roomLayout.clientWidth; + //roomLayout.style.height = clientHeight + "px"; + + var scaleX; + if (room.xDifference != 0) { + scaleX = clientWidth / room.xDifference; + } else { + scaleX = clientWidth; + } + var scaleY; + if (room.yDifference != 0) { + scaleY = clientHeight / room.yDifference; + } else { + scaleY = clientHeight; + } + var scaleYs = (clientHeight - (picSizeY * scaleY)) / room.yDifference; + var scaleXs = (clientWidth - (picSizeX * scaleX)) / room.xDifference; + if (scaleYs <= 0) { + scaleYs = 9999; + } + if (scaleXs <= 0) { + scaleXs = 9999; + } + + + var tmp = [scaleYs, scaleY, scaleXs, scaleX, (clientHeight * 0.9) / picSizeY, (clientWidth * 0.9) / picSizeX]; + room.scale = Math.min.apply(Math, tmp); + room.xOffset = 0 - room.minX; + room.yOffset = 0 - room.minY; + room.xOffset += ((1 / 2 * (clientWidth - (((room.maxX + room.xOffset) * room.scale) + picSizeX * room.scale))) / room.scale); + room.yOffset += ((1 / 2 * (clientHeight - (((room.maxY + room.yOffset) * room.scale) + picSizeY * room.scale))) / room.scale); + } + + + /** + * adds images for each pc to Room Layout + * @param room Room Object + * @param layout Layout json + */ + function setUpRoom(room, layout) { + for (var i = 0; i < layout.length; i++) { + + if (layout[i].y != null && layout[i].x != null && !isNaN(layout[i].y) && !isNaN(layout[i].x)) { + var text = "<div class= 'PCImgDiv' id ='layout_PC_div_" + room.id + "_" + layout[i].id + "'>" + + + "<div class= 'OverlayDiv' id ='layout_PC_overlay_" + room.id + "_" + layout[i].id + "'>" + + "</div>" + + "<img class= 'pcImg' id ='layout_PC_" + room.id + "_" + layout[i].id + "'> </img>" + + "</div>"; + + $('#roomLayout_' + room.id).append(text); + if (layout[i].hasOwnProperty('overlay')) { + for (var a = 0; a < layout[i].overlay.length; a++) { + addOverlay($('#layout_PC_overlay_' + room.id + "_" + layout[i].id), layout[i].overlay[a]); + } + } + } + } + } + + /** + * Adds an overlay to an div(here the PC's shown in the RoomLayout). + * @param object Object where the overlay should be added + * @param overlayName name of the overlay (image name without ending) + */ + function addOverlay(object, overlayName) { + var a = [".svg", ".png", "jpg"]; + var imgname; + for (var i = 0; i < a.length; a++) { + if (imageExists("img/overlay/" + overlayName + a[i])) { + imgname = "img/overlay/" + overlayName + a[i]; + break; + } + + } + if (imgname == null) { + return; + } + var text = $("<img class='overlay' src='" + imgname + "'></img>"); + text.addClass("overlay-" + overlayName); + + object.append(text); + + + } + + + var imgExists = {}; + + /** + * checks if images exists on the webserver(chaches it also) + * @param image_url Path to the image + */ + function imageExists(image_url) { + if (!imgExists.hasOwnProperty(image_url)) { + var http = new XMLHttpRequest(); + http.open('HEAD', image_url, false); + http.send(); + imgExists[image_url] = http.status != 404; + } + return imgExists[image_url]; + + } + + /** + * Querys Pc states + * @param ids Room ID's which should be queried. Format for e.g.: "20,5,6" + */ + function queryRooms(ids) { + $.ajax({ + url: "../../../api.php?do=locationinfo&action=locationinfo&id=" + ids + "&coords=0", + dataType: 'json', + cache: false, + timeout: 30000, + success: function (result) { + for (var i = 0; i < result.length; i++) { + UpdatePc(result[i].computer, rooms[result[i].id]); + } + } + }) + } + + + /** + * Adjust pc coordinate depending on room rotation + * @param r Rotation, from 0 - 3 (int) + * @param layout Layout json + */ + function rotateRoom(r, layout) { + for (var z = 0; z < r; z++) { + for (var i = 0; i < layout.length; i++) { + var x = parseInt(layout[i].x); + var y = parseInt(layout[i].y); + layout[i].x = y; + layout[i].y = -x; + } + } + } + + /** + * Positions the computer images in the roomLayout div accoring to ther potion and div size + * @param room Room object + */ + function scaleRoom(room) { + if (room.layout == null) { + return; + } + for (var i = 0; i < room.layout.length; i++) { + if (room.layout[i].y != null && room.layout[i].x != null && !isNaN(room.layout[i].y) && !isNaN(room.layout[i].x)) { + var tmp = document.getElementById("layout_PC_div_" + room.id + "_" + room.layout[i].id); + var img = document.getElementById("layout_PC_" + room.id + "_" + room.layout[i].id); + if (tmp != null) { + tmp.style.width = (picSizeX * room.scale); + tmp.setAttribute("style", "width:" + (picSizeX * room.scale) + "px"); + tmp.style.height = (picSizeY * room.scale) + "px"; + tmp.style.left = ((parseInt(room.layout[i].x) + room.xOffset) * room.scale) + "px"; + tmp.style.top = ((parseInt(room.layout[i].y) + room.yOffset) * room.scale ) + "px"; + } + } + } + } + + + /** + * Updates the PC's (images) in the room layout. Also Updates how many pc's are free. + * @param update Update Json from query for one(!) room + * @param room Room object + */ + function UpdatePc(update, room) { + if (update === undefined || update == null) { + return; + } + var freePcs = 0; + for (var i = 0; i < update.length; i++) { + var imgobj = document.getElementById("layout_PC_" + room.id + "_" + update[i].id); + + + var img; + // Pc free + if (update[i].pcState == "IDLE") { + if (supportSvg) { + img = "img/pc_free"; + } else { + imgobj.style.backgroundColor = "green"; + } + freePcs++; + // Pc in use + } else if (update[i].pcState == "OCCUPIED") { + if (supportSvg) { + img = "img/pc_used"; + } else { + imgobj.style.backgroundColor = "red"; + } + // PC off + } else if (update[i].pcState == "OFF") { + if (supportSvg) { + img = "img/pc_off"; + } else { + imgobj.style.backgroundColor = "black"; + } + freePcs++; + } else { + if (supportSvg) { + img = "img/pc_defect"; + } else { + imgobj.style.backgroundColor = "black"; + } + } + + if (imgobj != null && supportSvg) { + if (room.config.einkmode) { + img = img + "_eink"; + } + imgobj.src = img + ".svg"; + } + + } + + room.freePcs = freePcs; + + + } + + /* + /========================================== Misc ============================================= + */ + var resizeTimeout; + + // called when browser window changes size + // scales calendar and room layout acordingly + + $(window).resize(function () { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(function () { + + for (var property in rooms) { + + rooms[property].resized = true; + if (rooms[property].config.mode != null) { + if (rooms[property].config.mode != 3) { + scaleCalendar(rooms[property]); + + } + if (rooms[property].config.mode != 2) { + generateOffsetAndScale(rooms[property]); + scaleRoom(rooms[property]); + } + } + } + }, 50); + }); + + + /** + * returns parameter value from the url + * @param sParam + * @returns value for given parameter + */ + var getUrlParameter = function getUrlParameter(sParam) { + var sPageURL = decodeURIComponent(window.location.search.substring(1)), + sURLVariables = sPageURL.split('&'), + sParameterName, + i; + + for (i = 0; i < sURLVariables.length; i++) { + sParameterName = sURLVariables[i].split('='); + + if (sParameterName[0] === sParam) { + return sParameterName[1] === undefined ? true : sParameterName[1]; + } + } + }; + + /** + * Function for translation + * @param toTranslate key which we wan't to translate + * @param lang languages in which should be translated + * @returns r translated string + */ + function t(toTranslate, lang) { + + var r; + if (lang === undefined) { + r = translation['en'][toTranslate]; + } else { + r = translation[lang][toTranslate]; + } + return r; + } + + + /** + * Used in Mode 4, switches given room from Timetable to Roomlayout and vice versa + * @param room + */ + function switchLayout(room) { + var car = document.getElementById("calendar_" + room.id); + var roomLayout = document.getElementById("roomLayout_" + room.id); + + if (car.style.display == "none") { + roomLayout.style.display = "none"; + car.style.display = "block"; + if (room.resized) { + scaleCalendar(room); + room.resized = false; + } + } else { + car.style.display = "none"; + roomLayout.style.display = "block"; + if (room.resized) { + generateOffsetAndScale(room); + scaleRoom(room); + room.resized = false; + } + } + } + + + /** + * adds a progressbar to a given room (id) used in mode 4 + * @param id room id + */ + function generateProgressBar(id) { + + var div = document.createElement("div"); + div.id = "progressBar_" + id; + div.classList.add("progressbar"); + //document.body.appendChild(div); + $("#room_" + id).append(div); + + } + /** + * Animates the progressbar used in mode 4 + * @param roomId + * @param time + * @constructor + */ + function MoveProgressBar(roomId, time) { + var elem = document.getElementById("progressBar_" + roomId); + var width = 1; + var id = setInterval(frame, time / 100); + + function frame() { + if (width >= 100) { + clearInterval(id); + } else { + width++; + elem.style.width = width + '%'; + } + } + } + + + </script> +</head> +<body> +</body> +</html> |