summaryrefslogtreecommitdiffstats
path: root/modules-available/locationinfo/frontend
diff options
context:
space:
mode:
authorSimon Rettberg2017-07-25 19:02:01 +0200
committerSimon Rettberg2017-07-25 19:02:01 +0200
commitbb53f6136e2950f3d656728be469d318a0d9f606 (patch)
tree4e8648ff6fde4b8496eba6e19afdfd7bf542c241 /modules-available/locationinfo/frontend
parent[locationinfo] Better error handling in hisinone backend (diff)
downloadslx-admin-bb53f6136e2950f3d656728be469d318a0d9f606.tar.gz
slx-admin-bb53f6136e2950f3d656728be469d318a0d9f606.tar.xz
slx-admin-bb53f6136e2950f3d656728be469d318a0d9f606.zip
[locationinfo] Make panel accessible via slxadmin, add URL type panel
Diffstat (limited to 'modules-available/locationinfo/frontend')
-rwxr-xr-xmodules-available/locationinfo/frontend/doorsign.html1802
-rwxr-xr-xmodules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.css284
-rwxr-xr-xmodules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.iml10
-rwxr-xr-xmodules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.js2968
-rw-r--r--modules-available/locationinfo/frontend/panel.html700
5 files changed, 0 insertions, 5764 deletions
diff --git a/modules-available/locationinfo/frontend/doorsign.html b/modules-available/locationinfo/frontend/doorsign.html
deleted file mode 100755
index 5e6306a0..00000000
--- a/modules-available/locationinfo/frontend/doorsign.html
+++ /dev/null
@@ -1,1802 +0,0 @@
-<!DOCTYPE html>
-<!--
-
-parameter
-
-required:
- uuid: [integer] panel 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
- scaledaysauto: [true] if true it finds automatically the daystoshow parameter depending on display size
-
--->
-<html lang="de">
-<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8">
-<head>
- <title>DoorSign</title>
- <link rel='stylesheet' type='text/css' href='../../js_jqueryui/style.css'/>
- <link rel='stylesheet' type='text/css' href='jquery-week-calendar/jquery.weekcalendar.css'/>
-
- <style type='text/css'>
-
- body {
- margin: 0;
- padding: 0;
- width: 100%;
- height: 100%;
- background-color: #cacaca;
- overflow: hidden;
- position: absolute;
- display: table;
- }
-
- body, .wc-container {
- font-family: "Lucida Grande", Helvetica, Arial, Verdana, sans-serif;
- }
-
- .row {
- background-color: #444;
- box-shadow: 0 0.1875rem 0.375rem rgba(0, 0, 0, 0.25);
- margin-bottom: 4px;
- width: 100%;
- display: flex;
- flex-wrap: nowrap;
- align-items: center;
- justify-content: space-between;
- }
-
- .pull-left {
- float: left;
- }
-
- .clearfix {
- clear: both;
- }
-
- .col {
- padding: 0 4px;
- color: white;
- overflow: hidden;
- flex: 1 1 auto;
- text-overflow: ellipsis;
- position: relative;
- display: flex;
- flex-direction: column;
- justify-content: center;
- }
-
- .col-square {
- order: 1000;
- float: right;
- width: 70pt;
- width: 6vw;
- height: 70pt;
- height: 6vw;
- font-size: 56pt;
- font-size: 4.25vw;
- flex: 0 0 auto;
- text-align: center;
- padding: 0;
- overflow: visible;
- }
-
- .count-1 .col-square {
- width: 93pt;
- width: 8vw;
- height: 93pt;
- height: 8vw;
- font-size: 85pt;
- font-size: 6vw;
- }
-
- .count-3 .col-square {
- width: 46pt;
- width: 4vw;
- height: 46pt;
- height: 4vw;
- font-size: 35pt;
- font-size: 2.5vw;
- }
-
- .progressbar {
- width: 0;
- height: 2px;
- position: absolute;
- background-color: red;
- bottom: 0;
- z-index: 100;
- }
-
- .header-font {
- font-size: 25pt;
- font-size: 1.8vw;
- font-weight: bold;
- padding: 10px;
- }
-
- .nowrap {
- white-space: nowrap;
- overflow: hidden;
- }
-
- .timer {
- color: #ddd;
- }
-
- .count-3 .header-font {
- font-size: 16pt;
- font-size: 1.2vw;
- }
-
- .count-1 .header-font {
- font-size: 30pt;
- font-size: 2.25vw;
- }
-
- .seats-counter {
- color: white;
- margin: auto;
- font-weight: bold;
- padding: 0;
- text-shadow: #000 2px 2px;
- }
-
- .center {
- text-align: center;
- }
-
- .room-layout {
- position: relative;
- float: left;
- }
-
- .location-container {
- position: absolute;
- width: 100%;
- height: 100%;
- overflow: hidden;
- border: 1px solid darkgrey;
- background: linear-gradient(#ddd, white);
- box-sizing: border-box;
- }
-
- .calendar {
- float: left;
- padding: 0;
- box-sizing: border-box;
- }
-
- .free-busy-busy {
- background: rgba(0, 0, 0, .25);
- }
-
- .ui-widget-content {
- color: white;
- }
-
- .wc-header {
- background-color: #444;
- font-weight: bold;
- }
-
- .ui-state-default {
- text-shadow: none;
- }
-
- .BROKEN {
- opacity: 0.4;
- }
-
- .pc-container {
- position: absolute;
- left: 0;
- bottom: 0;
- display: inline-block;
- padding: 0;
- margin: 0;
- overflow: hidden;
- }
-
- .pc-container div {
- box-sizing: border-box;
- }
-
- .screen-frame {
- position: relative;
- background: black;
- border-radius: 11%;
- width: 100%;
- height: 83%;
- padding: 6%;
- }
-
- .screen-inner {
- width: 100%;
- height: 100%;
- transition: background 2s;
- border-radius: 5%;
- padding-top: 4px;
- overflow: hidden;
- text-align: center;
- color: #fff;
- }
-
- .BROKEN .screen-inner {
- background: #000;
- }
-
- .OFF .screen-inner {
- background: #332;
- }
-
- /*
- .OFF .screen-inner:after {
- content: "\01F4A4";
- }
- */
-
- .IDLE .screen-inner {
- background: #250;
- }
-
- .OCCUPIED .screen-inner {
- background: #d23;
- }
-
- .OCCUPIED .screen-inner:after {
- content: '\01F464';
- font-weight: bold;
- }
-
- .screen-foot1 {
- margin: 0 auto;
- width: 10%;
- height: 7%;
- background: black;
- }
-
- .screen-foot2 {
- margin: 0 auto;
- width: 80%;
- height: 7%;
- background: black;
- border-radius: 30% 30% 0 0;
- }
-
- .pc-overlay-container {
- position: absolute;
- left: 0;
- bottom: 0;
- width: 100%;
- height: 100%;
- display: table;
- }
-
- .pc-img {
- position: absolute;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
-
- }
-
- .overlay {
- display: inline-block;
- 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;
- }
-
- .ui-widget-content .ui-state-active {
- font-weight: bold;
- color: black;
- }
-
- .wc-today {
- background-color: rgba(255, 255, 255, .66);
- }
-
- .wc-time-header-cell {
- background-color: #eeeeee;
- border: none;
- }
-
- .ui-corner-all {
- border-radius: 0;
- }
-
- .wc-scrollable-grid {
- transition: height 500ms;
- background: rgba(0, 0, 0, 0);
- }
-
- .wc-grid-timeslot-header,
- .wc-header .wc-time-column-header {
- width: 50px;
- }
-
- </style>
-
- <script type='text/javascript' src='../../../script/jquery.js'></script>
- <script type='text/javascript' src='../../js_jqueryui/clientscript.js'></script>
- <script type='text/javascript' src="jquery-week-calendar/jquery.weekcalendar.js"></script>
-
-</head>
-<body>
-</body>
-
-<script type="text/javascript">
- var rooms = {};
- var lastRoomUpdate = 0;
- var lastCalendarUpdate = 0;
- var lastSwitchTime = 0;
- var hasMode4 = false;
- var globalConfig = {};
- var roomIds = [];
- var panelUuid = false;
- const IMG_FORMAT_LIST = (function() {
- if (typeof(SVGRect) !== "undefined") {
- return [".svg", ".png", ".jpg", ".gif"];
- }
- return [".png", ".jpg", ".gif"];
- })();
-
- // TODO: Get languages from slx-admin
- 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 () {
- var uuid;
- uuid = window.location.pathname.match( /[a-z0-9\-]{36}/gi );
- if (uuid === null) {
- uuid = getUrlParameter("uuid");
- } else {
- uuid = uuid[0];
- }
- if (!uuid) {
- console.log('No panel uuid given');
- $("body").empty().append($('<h1>').text('No panel UUID given.'));
- return;
- }
- getConfig(uuid);
- });
-
- /**
- * Display given error message and try reloading page once a minute
- */
- function fatalError(message) {
- $('body').empty().append($('<h1>').text(message));
- window.setInterval(function () {
- $.ajax('/').done(function () {
- window.location.reload(true);
- }).fail(function () {
- $('body').append('...');
- });
- }, 60000);
- }
-
-
- /**
- * Downloads the config of a room, also reloads the page if the config hase changed over time
- * @param uuid ID of the room
- */
-
- function getConfig(uuid) {
- $.ajax({
- url: "../../../api.php?do=locationinfo&get=config&uuid=" + uuid,
- dataType: 'json',
- cache: false,
- timeout: 30000,
- success: function (result) {
-
- if (!result.locations || result.locations.constructor !== Array) {
- fatalError("Requested panel doesn't contain locations / not array");
- return;
- }
-
- var fetchedRooms = result.locations.filter(function (x) {
- // filter out if no numeric id, or id already present, or already got 4 locations
- if (typeof(x.id) !== 'number' || x.id <= 0 || roomIds.indexOf(x.id) !== -1 || roomIds.length >= 4)
- return false;
- roomIds.push(x.id);
- return true;
- });
-
- if (roomIds.length === 0) {
- fatalError("List of location ids is empty");
- return;
- }
-
- var time = false;
- var p = result.time.split('-');
- if (p.length === 6) {
- time = new Date(p[0], p[1], p[2], p[3], p[4], p[5]);
- console.log(time);
- }
- if (time === false || isNaN(time.getTime()) || time.getYear() < 2010) {
- time = new Date(result.time);
- }
- if (isNaN(time.getTime()) || time.getYear() < 2010) {
- time = new Date();
- }
- SetUpDate(time);
- delete result.time;
- delete result.locations;
-
- globalConfig = result;
- sanitizeGlobalConfig();
- lastRoomUpdate = MyDate().getTime();
-
- for (var i = 0; i < fetchedRooms.length; ++i) {
- addRoom(fetchedRooms[i]);
- }
-
- panelUuid = uuid;
- initRooms();
- // TODO: Check for changed config using get=timestamp and reload whole page on change
-
- }, error: function () {
- fatalError('Could not fetch panel config');
- }
- })
- }
-
- const PARAM_STRING = 1;
- const PARAM_INT = 2;
- const PARAM_BOOL = 3;
-
- /**
- * Read given parameter from URL, replacing it in the config object if present.
- * @param config object config object
- * @param property string name of property in object, URL param of same name is being checked
- * @param paramType int one of PARAM_STRING, PARAM_INT, PARAM_BOOL
- * @param intScaleFactor int optional scale factor that will be applied if paramType == PARAM_INT
- */
- function setRoomConfigFromUrl(config, property, paramType, intScaleFactor) {
- var val = getUrlParameter(property);
- if (val === true || val === false)
- return;
- if (paramType === PARAM_STRING) {
- config[property] = val;
- } else if (paramType === PARAM_INT) {
- config[property] = parseInt(val);
- if (intScaleFactor) {
- config[property] *= intScaleFactor;
- }
- } else if (paramType === PARAM_BOOL) {
- val = val.toLowerCase();
- config[property] = val.length > 0 && val !== 'false' && val !== 'off' && val !== '0';
- } else {
- console.log('Invalid paramType: ' + paramType);
- }
- }
-
- /**
- * Put given numeric config property in range min..max (both inclusive),
- * if not in range, set to default.
- * @param config - object config object
- * @param property - string config property
- * @param min int - min allowed value (inclusive)
- * @param max int - max allowed value (inclusive)
- * @param defaultval - default value to use if out of range
- * @param scaleFactor int - optional scale factor to apply
- */
- function putInRange(config, property, min, max, defaultval, scaleFactor) {
- var v = config[property];
- if (!scaleFactor) {
- scaleFactor = 1;
- }
- if (!v || !isFinite(v) || isNaN(v) || v < min * scaleFactor || v > max * scaleFactor) {
- config[property] = defaultval * scaleFactor;
- }
- }
-
- /**
- * gets Additional Parameters from the URL, and from the
- * downloaded json.
- * also makes sure parameters are in a given range
- */
- function sanitizeGlobalConfig() {
- sanitizeConfig(globalConfig);
- $('html').attr('lang', globalConfig.language);
- }
-
- function sanitizeConfig(config) {
- if (config) {
- config.switchtime = config.switchtime * 1000;
- config.calupdate = config.calupdate * 60 * 1000;
- config.roomupdate = config.roomupdate * 1000;
- }
-
- setRoomConfigFromUrl(config, 'calupdate', PARAM_INT, 60 * 1000);
- setRoomConfigFromUrl(config, 'roomupdate', PARAM_INT, 1000);
- setRoomConfigFromUrl(config, 'daystoshow', PARAM_INT);
- setRoomConfigFromUrl(config, 'scaledaysauto', PARAM_BOOL);
- setRoomConfigFromUrl(config, 'vertical', PARAM_BOOL);
- setRoomConfigFromUrl(config, 'eco', PARAM_BOOL);
-
- setRoomConfigFromUrl(config, 'scale', PARAM_INT);
- setRoomConfigFromUrl(config, 'rotation', PARAM_INT);
- setRoomConfigFromUrl(config, 'switchtime', PARAM_INT, 1000);
-
- // parameter validation
- putInRange(config, 'switchtime', 5, 120, 6, 1000);
- putInRange(config, 'scale', 10, 90, 50);
- putInRange(config, 'daystoshow', 1, 7, 7);
- putInRange(config, 'roomupdate', 15, 5 * 60, 60, 1000);
- putInRange(config, 'calupdate', 1, 60, 30, 60 * 1000);
- putInRange(config, 'mode', 1, 4, 1);
- putInRange(config, 'rotation', 0, 3, 0);
- }
-
- /**
- * generates the Room divs and calls the needed functions depending on the rooms mode
- */
- function initRooms() {
-
- var width = "100%";
- var height = "100%";
- var columns = 1;
- var top, left;
- hasMode4 = false;
- if (roomIds.length === 2 || roomIds.length === 4) {
- width = "50%";
- columns = 2;
- }
- if (roomIds.length === 3) {
- width = "33%";
- columns = 3;
- }
- if (roomIds.length === 4) {
- height = "50%";
- }
- for (var t = 0; t < roomIds.length; t++) {
- var rid = roomIds[t];
- var room = rooms[rid];
- if (roomIds.length === 3) {
- top = 0;
- left = (t * 33) + '%';
- } else {
- top = (Math.floor(t / 2) * 50) + '%';
- left = ((t % 2) * 50) + '%';
- }
-
- var $loc = $("<div>").addClass('location-container');
- $loc.css({top: top, left: left, width: width, height: height});
- $("body").append($loc);
-
- room.$.container = $loc;
- room.$.locationName = $('<div>').addClass('col').addClass('header-font').addClass('pull-left');
- room.$.currentEvent = $("<span>").addClass('nowrap');
- room.$.currentRemain = $("<span>").addClass('nowrap').addClass('timer');
- room.$.seatsCounter = $('<span>').addClass('seats-counter');
- room.$.seatsBackground = $('<div>').addClass('col col-square').append(room.$.seatsCounter);
-
- var $header = $('<div>').addClass('row').addClass('count-' + columns);
- $header.append(room.$.locationName);
- $header.append(room.$.seatsBackground);
- $header.append($('<div>').addClass('col header-font center').append(room.$.currentEvent).append(' ').append(room.$.currentRemain));
- room.$.header = $header;
- $loc.append($header);
- $header.append('<div class="clearfix">');
-
- if (room.name !== null) {
- room.$.locationName.text(room.name);
- }
-
- if (room.config.mode !== 3) {
- setUpCalendar(room);
- }
- if (room.config.mode !== 2) {
- initRoomLayout(room);
- }
- if (room.config.mode === 4) {
- hasMode4 = true;
- }
- SetOpeningTimes(room);
- UpdateRoomHeader(room);
-
- (function (room) {
- setTimeout(function () {
- resizeIfRequired(room);
- }, 800);
- })(room);
- }
-
- if (hasMode4) {
- generateProgressBar();
- }
-
- mainUpdateLoop();
- setInterval(mainUpdateLoop, 10000);
- setInterval(updateHeaders, globalConfig.eco ? 10000 : 1000);
- }
-
- var lastDate = false;
- /**
- * Main Update loop, this loop runs every 10 seconds
- */
- function mainUpdateLoop() {
- var date = MyDate();
- var now = date.getTime();
-
- if (lastCalendarUpdate + globalConfig.calupdate < now) {
- lastCalendarUpdate = now;
- queryCalendars();
- } else if (lastRoomUpdate + globalConfig.roomupdate < now) {
- lastRoomUpdate = now;
- queryRooms();
- } else {
- queryPanelChange();
- }
-
- $('.calendar').weekCalendar("scrollToHour");
-
- // reload site at midnight
- var today = date.getDate();
- if (lastDate !== false) {
- if (lastDate !== today) {
- location.reload(true);
- }
- } else {
- lastDate = today;
- }
- }
-
- /**
- * Update all location headers.
- * Runs ever second (normal) or every 10 seconds (eco)
- */
- function updateHeaders() {
- for (var property in rooms) {
- if (rooms[property].state.end) {
- // Updating All room Headers
- UpdateRoomHeader(rooms[property]);
- }
- }
-
- }
-
- /**
- * Generates a room Object and adds it to the rooms array
- * @param roomData Config Json of the room
- */
- function addRoom(roomData) {
- var mergedConfig = {};
- if (roomData.config && typeof(roomData.config) === 'object') {
- mergedConfig = roomData.config;
- sanitizeConfig(mergedConfig);
- }
- for (var k in globalConfig) {
- if (typeof mergedConfig[k] === 'undefined') {
- mergedConfig[k] = globalConfig[k];
- }
- }
- var now = MyDate().getTime();
- var room = {
- id: roomData.id,
- name: roomData.name,
- config: mergedConfig,
- timetable: null,
- currentEvent: null,
- nextEventEnd: null,
- timeTilFree: null,
- state: null,
- rawOpeningTimes: roomData.openingtime || null,
- openingTimes: null,
- openTimes: 24,
- currentfreePcs: 0,
- layout: roomData.machines || null,
- freePcs: 0,
- resizeRoom: true,
- resizeCalendar: true,
- lastCalendarUpdate: now,
- lastRoomUpdate: now,
- $: {},
- getState: function () {
- if (this.state === null) {
- ComputeCurrentState(this);
- return this.state;
- }
- if (this.state.end) {
- if (this.state.end < MyDate()) {
- ComputeCurrentState(this);
- }
- }
- return this.state;
- }
-
-
- };
- rooms[roomData.id] = room;
- return room;
- }
-
- /**
- * inilizes the Calendar for an room
- * @param room Room Object
- */
- function setUpCalendar(room) {
- var daysToShow = room.config.daystoshow;
- generateCalendarDiv(room);
- room.$.calendar.weekCalendar({
- timeslotsPerHour: 1,
- timeslotHeight: 30,
- daysToShow: daysToShow,
- height: function () {
- if (room.config.mode === 1 && room.config.vertical && (!room.timetable || !room.timetable.length)) return 20;
- var height = $(window).height();
- if (roomIds.length === 4) {
- height /= 2;
- }
-
- height -= room.$.header.height() - 5;
- if (room.config.mode === 1 && room.config.vertical) {
- height *= (room.config.scale / 100);
- }
- return height;
- },
- eventRender: function (calEvent, $event) {
- if (calEvent.end.getTime() < MyDate().getTime()) {
- $event.css("backgroundColor", "#aaa");
- $event.find(".time").css({"backgroundColor": "#999", "border": "1px solid #888"});
- } else if (calEvent.end.getTime() > MyDate().getTime() && calEvent.start.getTime() < 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}
- });
- }
-
- /**
- * Generates the Calendar Div, depending on it's width
- * @param width width of the Calendar Div
- * @param room Room Object
- */
-
- function generateCalendarDiv(room) {
- var width = 100;
- if (room.config.mode === 1 && !room.config.vertical) {
- width = room.config.scale;
- }
- var $cal = $('<div>').addClass('calendar');
- if (room.config.mode === 1 && room.config.vertical) {
- $cal.css('float', "none");
- }
- $cal.width(width + '%');
- room.$.container.append($cal);
- room.$.calendar = $cal;
- }
-
- const OT_DAYS = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
- const OT_KEYS = ['HourOpen', 'HourClose', 'MinutesOpen', 'MinutesClose'];
-
- /**
- * sets the opening Time in the calendar plugin and saves it in the room object
- * @param room Room Object
- */
-
- function SetOpeningTimes(room) {
- var opening = 24;
- var close = 0;
- var i;
- if (room.rawOpeningTimes && typeof(room.rawOpeningTimes) === 'object') {
- // TODO: wtf! we have three(!) formats for storing the opening times (DB, API, now this one) - WHY!?
- var parsedOpenings = room.rawOpeningTimes;
- room.state = null;
- room.openingTimesCalendar = [];
- room.openingTimes = [];
- for (i = 0; i < OT_DAYS.length; ++i) {
- room.openingTimes.push(filterOpeningTimesDay(parsedOpenings[OT_DAYS[i]]));
- }
- delete room.rawOpeningTimes;
- }
- if (!room.openingTimes) {
- scaleCalendar(room);
- return;
- }
- if (room.config.mode === 3) {
- // Calendar is not displayed, don't need to do additional work
- return;
- }
- var now = MyDate();
- for (i = 0; i < 7; i++) {
- var tmp = room.openingTimes[i];
- for (var d = 0; d < tmp.length; d++) {
- var day = getNextDayOfWeek(now, i);
- if (room.openingTimesCalendar) {
- 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 (tmp[d]['HourOpen'] < opening) {
- opening = tmp[d]['HourOpen'];
- }
- if (tmp[d]['HourClose'] >= close) {
- close = tmp[d]['HourClose'];
- if (tmp[d]['MinutesClose'] !== 0) {
- close++;
- }
- }
- }
- }
- if (opening === 24 && close === 0) {
- opening = 0;
- close = 24;
- }
- room.openTimes = close - opening;
- scaleCalendar(room);
- room.$.calendar.weekCalendar("option", "businessHours", {
- start: opening,
- end: close,
- limitDisplay: true
- });
- }
-
- /**
- * Filter out invalid opening time entries from given array,
- * also make sure all the values are of type number (int)
- *
- * @param {Array} arr
- * @return {Array} list of valid opening times
- */
- function filterOpeningTimesDay(arr) {
- if (!arr || arr.constructor !== Array) return [];
- return arr.map(function (el) {
- if (!el || typeof el !== 'object') return null;
- for (var i = 0; i < OT_KEYS.length; ++i) {
- el[OT_KEYS[i]] = toInt(el[OT_KEYS[i]]);
- if (isNaN(el[OT_KEYS[i]])) return null;
- }
- return el;
- }).filter(function (el) {
- if (!el) return false;
- if (el.HourOpen < 0 || el.HourOpen > 23) return false;
- if (el.HourClose < 0 || el.HourClose > 23) return false;
- if (el.HourClose < el.HourOpen) return false;
- if (el.MinutesOpen < 0 || el.MinutesOpen > 59) return false;
- if (el.MinutesClose < 0 || el.MinutesClose > 59) return false;
- if (el.HourOpen === el.HourClose && el.MinutesClose < el.MinutesOpen) return false;
- return true;
- });
- }
-
- /**
- * querys the Calendar data
- */
- function queryCalendars() {
- if (!panelUuid) return;
- var url = "../../../api.php?do=locationinfo&get=calendar&uuid=" + panelUuid;
- $.ajax({
- url: url,
- dataType: 'json',
- cache: false,
- timeout: 30000,
- success: function (result) {
- if (result && result.constructor === Array) {
- var l = result.length;
- for (var i = 0; i < l; i++) {
- updateCalendar(result[i].calendar, rooms[result[i].id]);
- }
- }
- }, error: function () {
- // Retry in 5 minutes (300 seconds)
- lastCalendarUpdate = MyDate().getTime() + globalConfig.calupdate + 300000;
- }
- });
- }
-
- const SEVEN_DAYS = 7 * 86400 * 1000;
-
- /**
- * applays new calendar data to the calendar plugin and also saves it to the room object
- * @param {Array} json Calendar data
- * @param room Room Object
- */
- function updateCalendar(json, room) {
- if (!room) {
- console.log("Error: No room for calendar data");
- return;
- }
- if (!json || json.constructor !== Array) {
- console.log("Error: Calendar data was empty or malformed.");
- return;
- }
- if (json.length === 0) {
- console.log("Notice: Calendar already empty from server");
- }
- var now = MyDate().getTime();
- json = json.filter(function (el) {
- if (!el.title || !el.start || !el.end) return false;
- var s = new Date(el.start).getTime();
- var e = new Date(el.end).getTime();
- return !(isNaN(s) || isNaN(e) || Math.abs(s - now) > SEVEN_DAYS || Math.abs(e - now) > SEVEN_DAYS);
- });
- if (json.length === 0) {
- console.log('Notice: Calendar has no current events for ' + room.name);
- }
- try {
- room.timetable = json;
- if (room.config.mode !== 3) {
- // TODO: Check if they're the same
- var cal = room.$.calendar;
- cal.weekCalendar('option', 'data', {events: json});
- cal.weekCalendar("refresh");
- cal.weekCalendar("option", "defaultFreeBusy", {free: !room.openingTimesCalendar});
- cal.weekCalendar("updateFreeBusy", room.openingTimesCalendar);
- cal.weekCalendar("resizeCalendar");
- setTimeout(function() {
- scaleRoom(room);
- }, 550);
- }
- room.state = null;
- UpdateRoomHeader(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;
- }
- var $cal = room.$.calendar;
- if (!$cal.is(':visible')) return;
- room.resizeCalendar = false;
- var columnWidth = $cal.find(".wc-day-1").width();
-
- 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 !== $cal.weekCalendar("option", "daysToShow")) {
- $cal.weekCalendar("option", "daysToShow", 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 (roomIds.length === 4) {
- clientHeight = clientHeight / 2;
- }
-
- clientHeight = clientHeight - room.$.header.height()
- - room.$.calendar.find(".wc-time-column-header").height() - 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.timetable) {
- $cal.weekCalendar("option", "data", {events: room.timetable});
- $cal.weekCalendar('refresh');
- }
- $cal.weekCalendar("option", "defaultFreeBusy", {free: !room.openingTimesCalendar});
- if (room.openingTimesCalendar) {
- $cal.weekCalendar("updateFreeBusy", room.openingTimesCalendar);
- }
- $cal.weekCalendar("resizeCalendar");
- $cal.weekCalendar("option", "hourLine", true);
- }
-
- /**
- * used for countdown
- * computes the time difference between 2 Date objects
- * @param {Date} a
- * @param {Date} b
- * @param room Room Object
- * @returns {string} printable time
- */
- function GetTimeDiferenceAsString(a, b, room) {
- if (!a || !b) {
- 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) {
- // don't show?
- return "";
- }
- if (globalConfig.eco) {
- 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) {
- if (!room.openingTimes || room.openingTimes.length === 0) return null;
- var now = MyDate();
- var day = now.getDay();
- var bestdate = null;
- for (var a = 0; a < 7; a++) {
- var tmp = room.openingTimes[(day + a) % 7];
- if (!tmp) continue;
- for (var i = 0; i < tmp.length; i++) {
- var closeDate = getNextDayOfWeek(now, (day + a) % 7);
- closeDate.setHours(tmp[i].HourClose);
- closeDate.setMinutes(tmp[i].MinutesClose);
- closeDate.setSeconds(0);
- if (closeDate > now) {
- if (!IsOpen(new Date(closeDate.getTime() + 1800000), room)) {
- if (!bestdate || bestdate > closeDate) {
- bestdate = closeDate;
- }
- }
- }
- }
- if (bestdate) return bestdate;
- }
- return null;
- }
-
-
- /**
- * checks if a room is on a given date/time open
- * @param date Date Object
- * @param room Room object
- * @returns {Boolean} for open or not
- */
- function IsOpen(date, room) {
- if (!room.openingTimes || room.openingTimes.length === 0) return true;
- var tmp = room.openingTimes[date.getDay()];
- if (!tmp) return false;
- var openDate = new Date(date.getTime());
- var closeDate = new Date(date.getTime());
- for (var i = 0; i < tmp.length; i++) {
- openDate.setHours(tmp[i].HourOpen);
- openDate.setMinutes(tmp[i].MinutesOpen);
- closeDate.setHours(tmp[i].HourClose);
- closeDate.setMinutes(tmp[i].MinutesClose);
- if (openDate < date && closeDate > date) {
- return true;
- }
- }
- return false;
- }
-
-
- /**
- * Returns next Opening
- * @param room Room Object
- * @returns {Date} Object of next opening
- */
- function GetNextOpening(room) {
- if (!room.openingTimes) return null;
- var now = MyDate();
- var day = now.getDay();
- var bestdate = null;
- for (var dow = 0; dow < 7; dow++) {
- var tmp = room.openingTimes[(day + dow) % 7];
- if (!tmp) continue;
- for (var i = 0; i < tmp.length; i++) {
- var openDate = getNextDayOfWeek(now, (day + dow) % 7);
- openDate.setHours(tmp[i].HourOpen);
- openDate.setMinutes(tmp[i].MinutesOpen);
- if (openDate > now) {
- if (!IsOpen(new Date(openDate.getTime() - 1800000), room)) {
- if (!bestdate || bestdate > openDate) {
- bestdate = openDate;
- }
- }
- }
- }
- if (bestdate) return bestdate;
- }
- return null;
- }
-
-
- /**
- * Sets the free PCs number in the right corner and updates the square color accordingly
- * @param room Room
- * @param seats Number of free PC's in the room
- */
- function SetFreeSeats(room) {
- room.$.seatsCounter.text(room.freePcs >= 0 ? room.freePcs : '');
- if (room.freePcs > 0 && room.state && room.state.free) {
- room.$.seatsBackground.css('background-color', '#250');
- } else if (room.freePcs === -1) {
- room.$.seatsBackground.css('background-color', 'red');
- } else {
- room.$.seatsBackground.css('background-color', 'red');
- }
- }
-
- /**
- * Updates the Header of an Room
- * @param room Room Object
- */
- function UpdateRoomHeader(room) {
- var tmp = room.getState();
- var same = (tmp === room.lastHeaderState);
- if (!same) {
- room.lastHeaderState = tmp;
- }
- var newText = false, newTime = false;
- var seats = room.freePcs;
- if (tmp.state === 'closed' || tmp.state === 'CalendarEvent' || tmp.state === 'Free') {
- newTime = GetTimeDiferenceAsString(tmp.end, MyDate(), room);
- } else if (!same) {
- newTime = '';
- }
- if (tmp.state === "closed") {
- if (!same) newText = t("closed", globalConfig.language);
- } else if (tmp.state === "CalendarEvent") {
- if (!same) newText = tmp.title;
- seats = -1;
- } else if (tmp.state === "Free") {
- if (!same) newText = t("free", room.config.language);
- } else if (tmp.state === "FreeNoEnd") {
- if (!same) newText = t("free", room.config.language);
- }
- if (newText !== false) {
- room.$.currentEvent.text(newText);
- }
- if (newTime !== false) {
- room.$.currentRemain.text(newTime);
- }
- if (room.lastFreeSeats !== seats) {
- SetFreeSeats(room);
- room.lastFreeSeats = seats;
- }
- }
-
- /**
- * computes state of a room, states are:
- * closed, FreeNoEnd, Free, CalendarEvent.
- * @param room Object
- */
- function ComputeCurrentState(room) {
- if (!IsOpen(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 && !event) {
- room.state = {state: "FreeNoEnd", end: "", title: "", next: "", free: true};
- return;
- }
-
- // no event so closing is next
- if (!event) {
- room.state = {state: "Free", end: closing, title: "", next: "closing", free: true};
- return;
- }
-
- // event is at the moment
- if ((!closing || event.start.getTime() < closing.getTime()) && event.start.getTime() < MyDate()) {
- room.state = {
- state: "CalendarEvent",
- end: event.end,
- title: event.title,
- next: ""
- };
- return;
- }
-
- // no closing so event is next
- if (!closing) {
- 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 {
- room.state = {state: "Free", end: closing, title: "", next: "closing"};
- }
-
- }
-
-
- /**
- * returns next event from a given json of events
- * @param calEvents Json which contains the calendar data.
- * @returns event next Calendar Event
- */
- function getNextEvent(calEvents) {
- if (!calEvents) return null;
- if (calEvents.constructor !== Array) {
- console.log('getNextEvent called with something not array: ' + typeof(calEvents));
- return null;
- }
- var event;
- var now = MyDate();
- for (var i = 0; i < calEvents.length; i++) {
- //event is now active
- if (calEvents[i].start.getTime() < now.getTime() && calEvents[i].end.getTime() > now.getTime()) {
- return calEvents[i];
- }
- //first element to consider
- if (!event) {
- if (calEvents[i].start.getTime() > now.getTime()) {
- event = calEvents[i];
- }
- } else if (calEvents[i].start.getTime() > now.getTime() && event.start.getTime() > calEvents[i].start.getTime()) {
- event = calEvents[i];
- }
- }
- return event;
- }
-
- /**
- * Skip to next upcoming day matching the given day of week.
- * @return {Date}
- */
- function getNextDayOfWeek(date, dayOfWeek) {
- var resultDate = new Date(date.getTime());
- resultDate.setDate(date.getDate() + (7 + dayOfWeek - date.getDay()) % 7);
- return resultDate;
- }
- /*
- /========================================== Room Layout =============================================
- */
-
-
- const picSizeX = 3.8;
- const picSizeY = 3;
-
- /**
- * Generates the RoomLayout Div
- * @param width The width the RoomLayout should have (in percent).
- * @param room Room Object
- */
- function generateRoomLayoutDiv(width, room) {
- if ((room.config.vertical && room.config.mode === 1) || (room.config.mode === 3) || (room.config.mode === 4)) {
- width = 100 + "%";
- }
- var $div = $('<div>').prop('id', 'roomLayout_' + room.id).addClass("room-layout").css('width', width);
-
- if (room.config.mode === 4) {
- $div.hide();
- }
- room.$.container.append($div);
- room.$.layout = $div;
- }
-
- /**
- * Main function for generating the Room Layout
- * @param room Room Object
- */
- function initRoomLayout(room) {
- var maxX = false, maxY = false;
- var minX = false, minY = false;
- var xDifference, yDifference;
- var x, y;
-
- generateRoomLayoutDiv((100 - room.config.scale) + "%", room);
- var layout = room.layout;
- if (layout === null || !layout.length) {
- return;
- }
-
- rotateRoom(room.config.rotation, layout);
-
- for (var i = 0; i < layout.length; i++) {
- x = layout[i].x = parseInt(layout[i].x);
- y = layout[i].y = parseInt(layout[i].y);
- if (isNaN(x) || isNaN(y)) continue;
- if (minX === false || x < minX) {
- minX = x;
- }
- if (minY === false || y < minY) {
- minY = y;
- }
- if (maxX === false || x > maxX) {
- maxX = x;
- }
- if (maxY === false || y > maxY) {
- maxY = 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;
-
- 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;
-
- if (room.config.vertical && room.config.mode === 1) {
- clientHeight = room.$.container.height() - (room.$.calendar.position().top + room.$.calendar.height());
- } else {
- clientHeight = room.$.container.height() - (room.$.header.height() + 5);
- }
-
- var clientWidth = room.$.layout.width();
-
- 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;
- }
-
- room.scale = Math.min(scaleYs, scaleY, scaleXs, scaleX, (clientHeight * 0.9) / picSizeY, (clientWidth * 0.9) / picSizeX);
- 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 (!isNaN(layout[i].y) && !isNaN(layout[i].x)) {
- //var $img = $('<img>').prop('id', "pc-img_" + room.id + "_" + layout[i].id).addClass('pc-img');
- var $overlays = $('<div>').addClass('pc-overlay-container');
- layout[i].$div = $('<div>').prop('id', "pc_" + room.id + "_" + layout[i].id).addClass('pc-container');
- layout[i].$div.append($('<div>').addClass('screen-frame').append($('<div>').addClass('screen-inner')));
- layout[i].$div.append($('<div>').addClass('screen-foot1'));
- layout[i].$div.append($('<div>').addClass('screen-foot2'));
- //layout[i].$div.append($overlays).append($img);
- room.$.layout.append(layout[i].$div);
-
- if (layout[i].overlay && layout[i].overlay.constructor === Array) {
- for (var a = 0; a < layout[i].overlay.length; a++) {
- addOverlay($overlays, layout[i].overlay[a]);
- }
- }
- }
- }
- }
-
- /**
- * Generate overlay with given image name.
- * @param $container container to put overlay into
- * @param overlayName name of the overlay (image name without ending)
- */
- function addOverlay($container, overlayName) {
- var imgname;
- for (var i = 0; i < IMG_FORMAT_LIST.length; ++i) {
- if (imageExists("img/overlay/" + overlayName + IMG_FORMAT_LIST[i])) {
- imgname = "img/overlay/" + overlayName + IMG_FORMAT_LIST[i];
- break;
- }
-
- }
- var $overlay;
- if (!imgname) {
- $overlay = $('<div>');
- } else {
- $overlay = $("<img>").attr('src', imgname);
- }
- $overlay.addClass('overlay').addClass("overlay-" + overlayName);
- $container.append($overlay);
- }
-
-
- var imgExists = {};
-
- /**
- * checks if images exists on the web server.
- * result will be cached after fist call.
- *
- * @param {String} image_url URL of image to check
- * @return {Boolean} true iff image exists
- */
- 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 === 200;
- }
- return imgExists[image_url];
-
- }
-
- /**
- * Checks whether the panel has been edited and reloads
- * the entire page if so.
- */
- function queryPanelChange() {
- $.ajax({
- url: "../../../api.php?do=locationinfo&get=timestamp&uuid=" + panelUuid,
- dataType: 'json',
- cache: false,
- timeout: 5000,
- success: function (result) {
- if (!result || !result.ts) {
- console.log('Warning: get=timestamp didnt return json with ts field');
- return;
- }
- if (globalConfig.ts && globalConfig.ts !== result.ts) {
- // Change
- window.location.reload(true);
- }
- globalConfig.ts = result.ts;
- }
- })
- }
-
- /**
- * Queries Pc states
- */
- function queryRooms() {
- $.ajax({
- url: "../../../api.php?do=locationinfo&get=machines&uuid=" + panelUuid,
- dataType: 'json',
- cache: false,
- timeout: 30000,
- success: function (result) {
- if (!result || result.constructor !== Array) {
- console.log('Warning: get=machines didnt return array');
- return;
- }
- for (var i = 0; i < result.length; i++) {
- UpdatePc(result[i].machines, rooms[result[i].id]);
- }
- }
- })
- }
-
- /**
- * 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 (!room) {
- console.log('Got room update for unknown room, ignored.');
- return;
- }
- if (!update || update.constructor !== Array) {
- console.log('Update data is not array for room ' + room.name);
- console.log(update);
- return;
- }
- var freePcs = 0;
- for (var i = 0; i < update.length; i++) {
- var $div = $("#pc_" + room.id + "_" + update[i].id);
- // Pc free
- if (update[i].pcState === "IDLE" || update[i].pcState === "OFF") {
- freePcs++;
- }
-
- $div.removeClass('BROKEN OFF IDLE OCCUPIED'.replace(update[i].pcState, '')).addClass(update[i].pcState);
- }
- room.freePcs = freePcs;
- UpdateRoomHeader(room);
- }
-
- /**
- * 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 according to their position and div size
- * @param room Room object
- */
- function scaleRoom(room) {
- if (!room.$.layout.is(':visible')) return;
- room.resizeRoom = false;
- generateOffsetAndScale(room);
- room.$.layout.css('font-size', Math.floor(room.scale) + 'pt');
- for (var i = 0; i < room.layout.length; i++) {
- var pcWidth = (picSizeX * room.scale) + "px";
- var pcHeight = (picSizeY * room.scale) + "px";
- if (room.layout[i].$div && !isNaN(room.layout[i].y) && !isNaN(room.layout[i].x)) {
- room.layout[i].$div.css({
- width: pcWidth,
- height: pcHeight,
- top: ((room.layout[i].y + room.yOffset) * room.scale) + "px",
- left: ((room.layout[i].x + room.xOffset) * room.scale) + "px"
- });
- }
- }
- }
-
- /*
- /========================================== Misc =============================================
- */
- var resizeTimeout = false;
-
- // called when browser window changes size
- // scales calendar and room layout accordingly
-
- $(window).resize(function () {
- if (resizeTimeout !== false) clearTimeout(resizeTimeout);
- resizeTimeout = setTimeout(function () {
- resizeTimeout = false;
- for (var property in rooms) {
- rooms[property].resizeCalendar = true;
- rooms[property].resizeRoom = true;
- scaleCalendar(rooms[property]);
- scaleRoom(rooms[property]);
- }
- SetProgressBarSpeed();
- }, 200);
- });
-
-
- /**
- * returns parameter value from the url
- * @param sParam
- * @returns boolean|string for given parameter
- */
- 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('=', 2);
-
- if (sParameterName[0] === sParam) {
- if (sParameterName.length === 1) return true;
- return sParameterName[1];
- }
- }
- return false;
- }
-
- /**
- * 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 || !translation[lang] || !translation[lang][toTranslate]) {
- r = translation['en'][toTranslate] || 'missing';
- } else {
- r = translation[lang][toTranslate];
- }
- return r;
- }
-
- function resizeIfRequired(room) {
- if (room.resizeCalendar) {
- scaleCalendar(room);
- }
- if (room.resizeRoom) {
- scaleRoom(room);
- }
- }
-
-
- /**
- * Used in Mode 4, switches given room from Timetable to room layout and vice versa
- */
- function switchLayouts() {
- for (var roomKey in rooms) {
- var room = rooms[roomKey];
- if (room.config.mode !== 4) continue;
- if (room.$.layout.is(':visible')) {
- room.$.layout.hide();
- room.$.calendar.show();
- } else {
- room.$.layout.show();
- room.$.calendar.hide();
- }
- resizeIfRequired(room);
- }
- lastSwitchTime = MyDate().getTime();
- }
-
- var $pbar = false;
- var pbarTimer = false;
- const PX_PER_SEC_TARGET = 10;
-
- /**
- * adds a progressbar (id) used in mode 4
- */
- function generateProgressBar() {
- if ($pbar) return;
- $pbar = $('<div class="progressbar">');
- $('body').append($pbar);
- SetProgressBarSpeed();
- }
-
- function SetProgressBarSpeed() {
- if (!$pbar || !globalConfig.switchtime) return;
- if (pbarTimer) clearInterval(pbarTimer);
- var interval = 1000;
- if (!globalConfig.eco) {
- var pxPerMSec = $('body').width() / globalConfig.switchtime;
- interval = Math.max(1 / (pxPerMSec / PX_PER_SEC_TARGET), 100);
- }
- pbarTimer = setInterval(function () {
- var width = ((MyDate().getTime() - lastSwitchTime) / globalConfig.switchtime) * 100;
- if (width < 0) width = 0;
- if (width >= 100) {
- width = 100;
- switchLayouts();
- }
- $pbar.width(width + '%');
- }, interval);
- }
-
- /**
- * Convert passed argument to integer if possible, return NaN otherwise.
- * The difference to parseInt() is that leading zeros are ignored and not
- * interpreted as octal representation.
- *
- * @param str string or already a number
- * @return {number} str converted to number, or NaN
- */
- function toInt(str) {
- var t = typeof str;
- if (t === 'number') return str | 0;
- if (t === 'string') return parseInt(str.replace(/^0+([^0])/, '$1'));
- return NaN;
- }
-
-</script>
-</html>
diff --git a/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.css b/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.css
deleted file mode 100755
index aae8f956..00000000
--- a/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.css
+++ /dev/null
@@ -1,284 +0,0 @@
-.wc-container {
- font-size: 14px;
- font-family: arial, helvetica;
-}
-
-.wc-toolbar {
- padding: 1em;
- font-size:0.8em;
-}
-
-.wc-toolbar .wc-nav {
- float:left;
-}
-
-.wc-toolbar .wc-display {
- float: right;
-}
-
-.wc-toolbar button {
- margin-top: 0;
- margin-bottom: 0;
-}
-
-.wc-toolbar .wc-title {
- text-align: center;
- padding:0;
- margin:0;
-}
-
-.wc-container table {
- border-collapse: collapse;
- border-spacing: 0;
-}
-.wc-container table td {
- margin: 0;
- padding: 0;
-}
-
-.wc-header {
- background: #eee;
- border-width:1px 0;
- border-style:solid;
-}
-.wc-header table{
- width: 100%;
- table-layout:fixed;
-}
-
-.wc-grid-timeslot-header,
-.wc-header .wc-time-column-header {
- width: 45px;
-}
-
-.wc-header .wc-scrollbar-shim {
- width: 16px;
-}
-
-.wc-header .wc-day-column-header {
- text-align: center;
- padding: 0.4em;
-}
-
-.wc-header .wc-user-header{
- text-align: center;
- padding: 0.4em 0;
- overflow:hidden;
-}
-.wc-grid-timeslot-header {
- background: #eee;
-}
-
-.wc-scrollable-grid {
- overflow: auto;
- overflow-x: hidden !important;
- overflow-y: auto !important;
- position: relative;
- background-color: #fff;
- width: 100%;
-}
-
-
-table.wc-time-slots {
- width: 100%;
- table-layout: fixed;
- cursor: default;
- overflow:hidden;
-}
-
-.wc-day-column {
- width: 13.5%;
- overflow: visible;
- vertical-align: top;
-}
-.wc-day-column-header{border-width: 0 0 1px 3px; border-style: solid;border-color:transparent;}
-.wc-scrollable-grid .wc-day-column-last,
-.wc-scrollable-grid .wc-day-column-middle{border-width: 0 0 0 1px; border-style: dashed;}
-.wc-scrollable-grid .wc-day-column-first{border-width: 0 0 0 3px; border-style: double;}
-
-.wc-day-column-inner {
- width: 100%;
- position:relative;
-}
-
-.wc-no-height-wrapper{
- position:relative;
- overflow: visible;
- height: 0px;
-}
-
-.wc-time-slot-wrapper {
-/* top: 3px;*/
-}
-.wc-oddeven-wrapper .wc-full-height-column{
-/* top: 2px; */
- /* Modern Browsers */ opacity: 0.4;
- /* IE 8 */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
- /* IE 5-7 */ filter: alpha(opacity=40);
- /* Netscape */ -moz-opacity: 0.4;
- /* Safari 1 */ -khtml-opacity: 0.4;
-}
-.wc-freebusy-wrapper .wc-freebusy{
-/* top: 1px;*/
- /* Modern Browsers */ opacity: 0.4;
- /* IE 8 */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";
- /* IE 5-7 */ filter: alpha(opacity=40);
- /* Netscape */ -moz-opacity: 0.4;
- /* Safari 1 */ -khtml-opacity: 0.4;
-}
-
-.wc-time-slots {
- position: absolute;
- width: 100%;
-}
-
-.wc-column-odd,
-.wc-column-even.ui-state-hover{background-image:none;border:none;}
-
-.wc-header .wc-today.ui-state-active{background-image:none;}
-.wc-header .wc-today.wc-day-column-header{border-width:0 3px; border-style: solid;}
-.wc-header .wc-user-header{border-width:0;}
-
-.wc-time-slots .wc-day-column.ui-state-default{background:transparent;}
-.wc-time-slots .wc-today.ui-state-active{background-image:none;}
-.wc-header .wc-today.ui-state-active.wc-day-column-middle{border-width:0;}
-.wc-header .wc-today.ui-state-active.wc-day-column-first{border-left-width:3px;}
-.wc-header .wc-today.ui-state-active.wc-day-column-last{border-right-width:3px;}
-
-.wc-full-height-column{
- display:block;
-/* width:100%;*/
-}
-
-
-.wc-time-header-cell {
- padding: 5px;
- height: 80px; /* reference height */
-}
-
-
-.wc-time-slot {
- border-bottom: 1px dotted #ddd;
-}
-
-.wc-hour-header {
- text-align: right;
-}
-.wc-hour-header.ui-state-active,
-.wc-hour-header.ui-state-default{
- border-width:0 0 1px 0;
-}
-
-.wc-hour-end, .wc-hour-header {
- border-bottom: 1px solid #ccc;
- color: #555;
-}
-
-.wc-business-hours {
- background-color: #E6EEF1;
- border-bottom: 1px solid #ccc;
- color: #333;
- font-size: 1em;
- font-weight: bold;
-}
-
-.wc-business-hours .wc-am-pm {
- font-size: 0.6em;
-}
-
-.wc-day-header-cell {
- text-align: center;
- vertical-align: middle;
- padding: 5px;
-}
-
-
-
-.wc-time-slot-header .wc-header-cell {
- text-align: right;
- padding-right: 10px;
-}
-
-.wc-cal-event {
- background-color: #68a1e5;
- /* Modern Browsers */ opacity: 0.8;
- /* IE 8 */ -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=80)";
- /* IE 5-7 */ filter: alpha(opacity=80);
- /* Netscape */ -moz-opacity: 0.8;
- /* Safari 1 */ -khtml-opacity: 0.8;
- position: absolute;
- text-align: center;
- overflow: hidden;
- cursor: pointer;
- color: #fff;
- width: 100%;
- display: none;
-}
-
-
-.wc-cal-event-delete {
- float: right;
- cursor: pointer;
- width: 16px;
- height: 16px;
-}
-
-.wc-cal-event.ui-resizable-resizing {
- cursor: s-resize;
-}
-
-.wc-cal-event .wc-time {
- background-color: #2b72d0;
- border: 1px solid #1b62c0;
- color: #fff;
- padding: 0;
- font-weight: bold;
-}
-
-.wc-container .ui-draggable .wc-time {
- cursor: move;
-}
-
-.wc-cal-event .wc-title {
- position: relative;
-}
-
-.wc-container .ui-resizable-s {
- height: 10px;
- line-height: 10px;
- bottom: -2px;
- font-size: .75em;
-}
-
-
-.wc-container .ui-draggable-dragging {
- z-index: 1000;
-}
-
-.free-busy-free{}
-.free-busy-busy{
- background:url("./libs/css/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png") repeat scroll 50% 50% #666666;
-}
-
-/** hourLine */
-
-.wc-hourline {
- height: 0pt;
- border-top: 2px solid #FF7F6E;
- overflow: hidden;
- position: absolute;
- width: inherit;
-}
-
-/* IE6 hacks */
-* html .wc-no-height-wrapper{position:absolute;}
-* html .wc-time-slot-wrapper{top:3px;}
-* html .wc-grid-row-oddeven{top:2px;}
-* html .wc-grid-row-freebusy{top:1px;}
-
-/* IE7 hacks */
-*:first-child+html .wc-no-height-wrapper{position:relative;}
-*:first-child+html .wc-time-slot-wrapper{top:3px;}
-*:first-child+html .wc-grid-row-oddeven{top:2px;}
-*:first-child+html .wc-grid-row-freebusy{top:1px;}
-*:first-child+html .wc-time-slots .wc-today{/* due to rendering issues, no background */background:none;}
diff --git a/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.iml b/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.iml
deleted file mode 100755
index 0f7b5ef4..00000000
--- a/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.iml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<module relativePaths="true" type="JAVA_MODULE" version="4">
- <component name="NewModuleRootManager" inherit-compiler-output="true">
- <exclude-output />
- <content url="file://$MODULE_DIR$" />
- <orderEntry type="inheritedJdk" />
- <orderEntry type="sourceFolder" forTests="false" />
- </component>
-</module>
-
diff --git a/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.js b/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.js
deleted file mode 100755
index 28b9e3cf..00000000
--- a/modules-available/locationinfo/frontend/jquery-week-calendar/jquery.weekcalendar.js
+++ /dev/null
@@ -1,2968 +0,0 @@
-/*
- * jQuery.weekCalendar v2.0-dev
- *
- * for support join us at the google group:
- * - http://groups.google.com/group/jquery-week-calendar
- * have a look to the wiki for documentation:
- * - http://wiki.github.com/themouette/jquery-week-calendar/
- * something went bad ? report an issue:
- * - http://github.com/themouette/jquery-week-calendar/issues
- * get the last version on github:
- * - http://github.com/themouette/jquery-week-calendar
- *
- * Copyright (c) 2009 Rob Monie
- * Copyright (c) 2010 Julien MUETTON
- * Dual licensed under the MIT and GPL licenses:
- * http://www.opensource.org/licenses/mit-license.php
- * http://www.gnu.org/licenses/gpl.html
- *
- * If you're after a monthly calendar plugin, check out this one :
- * http://arshaw.com/fullcalendar/
- */
-var startdate = 0;
-
-function SetUpDate(d) {
- startdate = d.getTime() - new Date().getTime();
-}
-
-/**
- *
- * @return {Date}
- */
-function MyDate() {
- return new Date(startdate + new Date().getTime());
-}
-
-(function($) {
-
- // check the jquery version
- var _v = $.fn.jquery.split('.'),
- _jQuery14OrLower = (10 * _v[0] + _v[1]) < 15;
- $.widget('ui.weekCalendar', (function() {
- var _currentAjaxCall, _hourLineTimeout;
-
- return {
- options: {
- date: MyDate(),
- timeFormat: null,
- dateFormat: 'M d, Y',
- alwaysDisplayTimeMinutes: true,
- use24Hour: false,
- daysToShow: 7,
- minBodyHeight: 100,
- firstDayOfWeek: function(calendar) {
- if ($(calendar).weekCalendar('option', 'daysToShow') != 5) {
- return 0;
- } else {
- //workweek
- return 1;
- }
- }, // 0 = Sunday, 1 = Monday, 2 = Tuesday, ... , 6 = Saturday
- useShortDayNames: false,
- timeSeparator: ' to ',
- startParam: 'start',
- endParam: 'end',
- businessHours: {start: 8, end: 18, limitDisplay: false},
- newEventText: 'New Event',
- timeslotHeight: 20,
- defaultEventLength: 2,
- timeslotsPerHour: 4,
- minDate: null,
- maxDate: null,
- showHeader: true,
- buttons: true,
- buttonText: {
- today: 'today',
- lastWeek: 'previous',
- nextWeek: 'next'
- },
- switchDisplay: {},
- scrollToHourMillis: 500,
- allowEventDelete: false,
- allowCalEventOverlap: false,
- overlapEventsSeparate: false,
- totalEventsWidthPercentInOneColumn: 100,
- readonly: false,
- allowEventCreation: true,
- hourLine: false,
- deletable: function(calEvent, element) {
- return true;
- },
- draggable: function(calEvent, element) {
- return true;
- },
- resizable: function(calEvent, element) {
- return true;
- },
- eventClick: function(calEvent, element, dayFreeBusyManager,
- calendar, clickEvent) {
- },
- eventRender: function(calEvent, element) {
- return element;
- },
- eventAfterRender: function(calEvent, element) {
- return element;
- },
- eventRefresh: function(calEvent, element) {
- return element;
- },
- eventDrag: function(calEvent, element) {
- },
- eventDrop: function(calEvent, element) {
- },
- eventResize: function(calEvent, element) {
- },
- eventNew: function(calEvent, element, dayFreeBusyManager,
- calendar, mouseupEvent) {
- },
- eventMouseover: function(calEvent, $event) {
- },
- eventMouseout: function(calEvent, $event) {
- },
- eventDelete: function(calEvent, element, dayFreeBusyManager,
- calendar, clickEvent) {
- calendar.weekCalendar('removeEvent',calEvent.id);
- },
- calendarBeforeLoad: function(calendar) {
- },
- calendarAfterLoad: function(calendar) {
- },
- noEvents: function() {
- },
- eventHeader: function(calEvent, calendar) {
- var options = calendar.weekCalendar('option');
- var one_hour = 3600000;
- var displayTitleWithTime = calEvent.end.getTime() - calEvent.start.getTime() <= (one_hour / options.timeslotsPerHour);
- if (displayTitleWithTime) {
- return calendar.weekCalendar(
- 'formatTime', calEvent.start) +
- ': ' + calEvent.title;
- } else {
- return calendar.weekCalendar(
- 'formatTime', calEvent.start) +
- options.timeSeparator +
- calendar.weekCalendar(
- 'formatTime', calEvent.end);
- }
- },
- eventBody: function(calEvent, calendar) {
- return calEvent.title;
- },
- shortMonths: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
- longMonths: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
- shortDays: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'],
- longDays: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],
- /* multi-users options */
- /**
- * the available users for calendar.
- * if you want to display users separately, enable the
- * showAsSeparateUsers option.
- * if you provide a list of user and do not enable showAsSeparateUsers
- * option, then only the events that belongs to one or several of
- * given users will be displayed
- * @type {array}
- */
- users: [],
- /**
- * should the calendar be displayed with separate column for each
- * users.
- * note that this option does nothing if you do not provide at least
- * one user.
- * @type {boolean}
- */
- showAsSeparateUsers: true,
- /**
- * callback used to read user id from a user object.
- * @param {Object} user the user to retrieve the id from.
- * @param {number} index the user index from user list.
- * @param {jQuery} calendar the calendar object.
- * @return {int|String} the user id.
- */
- getUserId: function(user, index, calendar) {
- return index;
- },
- /**
- * callback used to read user name from a user object.
- * @param {Object} user the user to retrieve the name from.
- * @param {number} index the user index from user list.
- * @param {jQuery} calendar the calendar object.
- * @return {String} the user name.
- */
- getUserName: function(user, index, calendar) {
- return user;
- },
- /**
- * reads the id(s) of user(s) for who the event should be displayed.
- * @param {Object} calEvent the calEvent to read informations from.
- * @param {jQuery} calendar the calendar object.
- * @return {number|String|Array} the user id(s) to appened events for.
- */
- getEventUserId: function(calEvent, calendar) {
- return calEvent.userId;
- },
- /**
- * sets user id(s) to the calEvent
- * @param {Object} calEvent the calEvent to set informations to.
- * @param {jQuery} calendar the calendar object.
- * @return {Object} the calEvent with modified user id.
- */
- setEventUserId: function(userId, calEvent, calendar) {
- calEvent.userId = userId;
- return calEvent;
- },
- /* freeBusy options */
- /**
- * should the calendar display freebusys ?
- * @type {boolean}
- */
- displayFreeBusys: false,
- /**
- * read the id(s) for who the freebusy is available
- * @param {Object} calEvent the calEvent to read informations from.
- * @param {jQuery} calendar the calendar object.
- * @return {number|String|Array} the user id(s) to appened events for.
- */
- getFreeBusyUserId: function(calFreeBusy, calendar) {
- return calFreeBusy.userId;
- },
- /**
- * the default freeBusy object, used to manage default state
- * @type {Object}
- */
- defaultFreeBusy: {free: false},
- /**
- * function used to display the freeBusy element
- * @type {Function}
- * @param {Object} freeBusy the freeBusy timeslot to render.
- * @param {jQuery} $freeBusy the freeBusy HTML element.
- * @param {jQuery} calendar the calendar element.
- */
- freeBusyRender: function(freeBusy, $freeBusy, calendar) {
- if (!freeBusy.free) {
- $freeBusy.addClass('free-busy-busy');
- }
- else {
- $freeBusy.addClass('free-busy-free');
- }
- return $freeBusy;
- },
- /* other options */
- /**
- * true means start on first day of week, false means starts on
- * startDate.
- * @param {jQuery} calendar the calendar object.
- * @type {Function|bool}
- */
- startOnFirstDayOfWeek: function(calendar) {
- return $(calendar).weekCalendar('option', 'daysToShow') >= 5;
- },
- /**
- * should the columns be rendered alternatively using odd/even
- * class
- * @type {boolean}
- */
- displayOddEven: false,
- textSize: 13,
- /**
- * the title attribute for the calendar. possible placeholders are:
- * <ul>
- * <li>%start%</li>
- * <li>%end%</li>
- * <li>%date%</li>
- * </ul>
- * @type {Function|string}
- * @param {number} option daysToShow.
- * @return {String} the title attribute for the calendar.
- */
- title: '%start% - %end%',
- /**
- * default options to pass to callback
- * you can pass a function returning an object or a litteral object
- * @type {object|function(#calendar)}
- */
- jsonOptions: {},
- headerSeparator: '<br />',
- /**
- * returns formatted header for day display
- * @type {function(date,calendar)}
- */
- getHeaderDate: null,
- preventDragOnEventCreation: false,
- /**
- * the event on which to bind calendar resize
- * @type {string}
- */
- resizeEvent: 'resize.weekcalendar'
- },
-
- /***********************
- * Initialise calendar *
- ***********************/
- _create: function() {
- var self = this;
- self._computeOptions();
- self._setupEventDelegation();
- self._renderCalendar();
- self._loadCalEvents();
- self._resizeCalendar();
- self._scrollToHour(self.options.date.getHours(), true);
-
- if (this.options.resizeEvent) {
- $(window).unbind(this.options.resizeEvent);
- $(window).bind(this.options.resizeEvent, function() {
- self._resizeCalendar();
- });
- }
-
- },
-
- /********************
- * public functions *
- ********************/
- /*
- * Refresh the events for the currently displayed week.
- */
- refresh: function() {
- //reload with existing week
- this._loadCalEvents(this.element.data('startDate'));
- },
-
- resizeCalendar:function(){
- this._resizeCalendar();
- },
- scrollToHour:function(){
- this._scrollToHour(MyDate().getHours(), false);
- },
- /*
- * Clear all events currently loaded into the calendar
- */
- clear: function() {
- this._clearCalendar();
- },
-
- /*
- * Go to this week
- */
- today: function() {
- this._clearCalendar();
- this._loadCalEvents(MyDate());
- },
-
- /*
- * Go to the previous week relative to the currently displayed week
- */
- prevWeek: function() {
- //minus more than 1 day to be sure we're in previous week - account for daylight savings or other anomolies
- var newDate = new Date(this.element.data('startDate').getTime() - (MILLIS_IN_WEEK / 6));
- this._clearCalendar();
- this._loadCalEvents(newDate);
- },
-
- /*
- * Go to the next week relative to the currently displayed week
- */
- nextWeek: function() {
- //add 8 days to be sure of being in prev week - allows for daylight savings or other anomolies
- var newDate = new Date(this.element.data('startDate').getTime() + MILLIS_IN_WEEK + MILLIS_IN_DAY);
- this._clearCalendar();
- this._loadCalEvents(newDate);
- },
-
- /*
- * Reload the calendar to whatever week the date passed in falls on.
- */
- gotoWeek: function(date) {
- this._clearCalendar();
- this._loadCalEvents(date);
- },
-
- /*
- * Reload the calendar to whatever week the date passed in falls on.
- */
- gotoDate: function(date) {
- this._clearCalendar();
- this._loadCalEvents(date);
- },
-
- /**
- * change the number of days to show
- */
- setDaysToShow: function(daysToShow) {
- var self = this;
- var hour = self._getCurrentScrollHour();
- self.options.daysToShow = daysToShow;
- $(self.element).html('');
- self._renderCalendar();
- self._loadCalEvents();
- self._resizeCalendar();
- self._scrollToHour(hour, false);
-
- if (this.options.resizeEvent) {
- $(window).unbind(this.options.resizeEvent);
- $(window).bind(this.options.resizeEvent, function() {
- self._resizeCalendar();
- });
- }
- },
-
- /*
- * Remove an event based on it's id
- */
- removeEvent: function(eventId) {
-
- var self = this;
-
- self.element.find('.wc-cal-event').each(function() {
- if ($(this).data('calEvent').id === eventId) {
- $(this).remove();
- return false;
- }
- });
-
- //this could be more efficient rather than running on all days regardless...
- self.element.find('.wc-day-column-inner').each(function() {
- self._adjustOverlappingEvents($(this));
- });
- },
-
- /*
- * Removes any events that have been added but not yet saved (have no id).
- * This is useful to call after adding a freshly saved new event.
- */
- removeUnsavedEvents: function() {
-
- var self = this;
-
- self.element.find('.wc-new-cal-event').each(function() {
- $(this).remove();
- });
-
- //this could be more efficient rather than running on all days regardless...
- self.element.find('.wc-day-column-inner').each(function() {
- self._adjustOverlappingEvents($(this));
- });
- },
-
- /*
- * update an event in the calendar. If the event exists it refreshes
- * it's rendering. If it's a new event that does not exist in the calendar
- * it will be added.
- */
- updateEvent: function(calEvent) {
- this._updateEventInCalendar(calEvent);
- },
-
- /*
- * Returns an array of timeslot start and end times based on
- * the configured grid of the calendar. Returns in both date and
- * formatted time based on the 'timeFormat' config option.
- */
- getTimeslotTimes: function(date) {
- var options = this.options;
- var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
- var startDate = new Date(date.getFullYear(), date.getMonth(), date.getDate(), firstHourDisplayed);
-
- var times = [],
- startMillis = startDate.getTime();
- for (var i = 0; i < options.timeslotsPerDay; i++) {
- var endMillis = startMillis + options.millisPerTimeslot;
- times[i] = {
- start: new Date(startMillis),
- startFormatted: this.formatTime(new Date(startMillis), options.timeFormat),
- end: new Date(endMillis),
- endFormatted: this.formatTime(new Date(endMillis), options.timeFormat)
- };
- startMillis = endMillis;
- }
- return times;
- },
-
- formatDate: function(date, format) {
- if (format) {
- return this._formatDate(date, format);
- } else {
- return this._formatDate(date, this.options.dateFormat);
- }
- },
-
- formatTime: function(date, format) {
- if (format) {
- return this._formatDate(date, format);
- } else if (this.options.timeFormat) {
- return this._formatDate(date, this.options.timeFormat);
- } else if (this.options.use24Hour) {
- return this._formatDate(date, 'H:i');
- } else {
- return this._formatDate(date, 'h:i a');
- }
- },
-
- serializeEvents: function() {
- var self = this;
- var calEvents = [];
-
- self.element.find('.wc-cal-event').each(function() {
- calEvents.push($(this).data('calEvent'));
- });
- return calEvents;
- },
-
- next: function() {
- if (this._startOnFirstDayOfWeek()) {
- return this.nextWeek();
- }
- var newDate = new Date(this.element.data('startDate').getTime());
- newDate.setDate(newDate.getDate() + this.options.daysToShow);
-
- this._clearCalendar();
- this._loadCalEvents(newDate);
- },
-
- prev: function() {
- if (this._startOnFirstDayOfWeek()) {
- return this.prevWeek();
- }
- var newDate = new Date(this.element.data('startDate').getTime());
- newDate.setDate(newDate.getDate() - this.options.daysToShow);
-
- this._clearCalendar();
- this._loadCalEvents(newDate);
- },
- getCurrentFirstDay: function() {
- return this._dateFirstDayOfWeek(this.options.date || MyDate());
- },
- getCurrentLastDay: function() {
- return this._addDays(this.getCurrentFirstDay(), this.options.daysToShow - 1);
- },
-
- /*********************
- * private functions *
- *********************/
- _setOption: function(key, value) {
- var self = this;
- if (self.options[key] != value) {
- // event callback change, no need to re-render the events
- if (key == 'beforeEventNew') {
- self.options[key] = value;
- return;
- }
-
- // this could be made more efficient at some stage by caching the
- // events array locally in a store but this should be done in conjunction
- // with a proper binding model.
-
- var currentEvents = self.element.find('.wc-cal-event').map(function() {
- return $(this).data('calEvent');
- });
-
- var newOptions = {};
- newOptions[key] = value;
- self._renderEvents({events: currentEvents, options: newOptions}, self.element.find('.wc-day-column-inner'));
- }
- },
-
- // compute dynamic options based on other config values
- _computeOptions: function() {
- var options = this.options;
- if (options.businessHours.limitDisplay) {
- options.timeslotsPerDay = options.timeslotsPerHour * (options.businessHours.end - options.businessHours.start);
- options.millisToDisplay = (options.businessHours.end - options.businessHours.start) * 3600000; // 60 * 60 * 1000
- options.millisPerTimeslot = options.millisToDisplay / options.timeslotsPerDay;
- } else {
- options.timeslotsPerDay = options.timeslotsPerHour * 24;
- options.millisToDisplay = MILLIS_IN_DAY;
- options.millisPerTimeslot = MILLIS_IN_DAY / options.timeslotsPerDay;
- }
- },
-
- /*
- * Resize the calendar scrollable height based on the provided function in options.
- */
- _resizeCalendar: function() {
- var options = this.options;
- if (options && $.isFunction(options.height)) {
- var calendarHeight = options.height(this.element);
- var headerHeight = this.element.find('.wc-header').outerHeight(true);
- var navHeight = this.element.find('.wc-toolbar').outerHeight(true);
- var scrollContainerHeight = Math.max(calendarHeight - navHeight - headerHeight, options.minBodyHeight);
- var timeslotHeight = this.element.find('.wc-time-slots').outerHeight(true);
- this.element.find('.wc-scrollable-grid').height(scrollContainerHeight);
- if (timeslotHeight <= scrollContainerHeight) {
- this.element.find('.wc-scrollbar-shim').width(0);
- }
- else {
- this.element.find('.wc-scrollbar-shim').width(this._findScrollBarWidth());
- }
- this._trigger('resize', this.element);
- }
- },
-
- _findScrollBarWidth: function() {
- var parent = $('<div style="width:50px;height:50px;overflow:auto"><div/></div>').appendTo('body');
- var child = parent.children();
- var width = child.innerWidth() - child.height(99).innerWidth();
- parent.remove();
- return width || /* default to 16 that is the average */ 16;
- },
-
- /*
- * configure calendar interaction events that are able to use event
- * delegation for greater efficiency
- */
- _setupEventDelegation: function() {
- var self = this;
- var options = this.options;
-
- this.element.click(function(event) {
- var $target = $(event.target),
- freeBusyManager;
-
- // click is disabled
- if ($target.data('preventClick')) {
- return;
- }
-
- var $calEvent = $target.hasClass('wc-cal-event') ?
- $target :
- $target.parents('.wc-cal-event');
- if (!$calEvent.length || !$calEvent.data('calEvent')) {
- return;
- }
-
- freeBusyManager = self.getFreeBusyManagerForEvent($calEvent.data('calEvent'));
-
- if (options.allowEventDelete && $target.hasClass('wc-cal-event-delete')) {
- options.eventDelete($calEvent.data('calEvent'), $calEvent, freeBusyManager, self.element, event);
- } else {
- options.eventClick($calEvent.data('calEvent'), $calEvent, freeBusyManager, self.element, event);
- }
- }).mouseover(function(event) {
- var $target = $(event.target);
- var $calEvent = $target.hasClass('wc-cal-event') ?
- $target :
- $target.parents('.wc-cal-event');
-
- if (!$calEvent.length || !$calEvent.data('calEvent')) {
- return;
- }
-
- if (self._isDraggingOrResizing($calEvent)) {
- return;
- }
-
- options.eventMouseover($calEvent.data('calEvent'), $calEvent, event);
- }).mouseout(function(event) {
- var $target = $(event.target);
- var $calEvent = $target.hasClass('wc-cal-event') ?
- $target :
- $target.parents('.wc-cal-event');
-
- if (!$calEvent.length || !$calEvent.data('calEvent')) {
- return;
- }
-
- if (self._isDraggingOrResizing($calEvent)) {
- return;
- }
-
- options.eventMouseout($calEvent.data('calEvent'), $calEvent, event);
- });
- },
-
- /**
- * check if a ui draggable or resizable is currently being dragged or
- * resized.
- */
- _isDraggingOrResizing: function($target) {
- return $target.hasClass('ui-draggable-dragging') ||
- $target.hasClass('ui-resizable-resizing');
- },
-
- /*
- * Render the main calendar layout
- */
- _renderCalendar: function() {
- var $calendarContainer, $weekDayColumns;
- var self = this;
- var options = this.options;
-
- $calendarContainer = $('<div class=\"ui-widget wc-container\">').appendTo(self.element);
-
- //render the different parts
- // nav links
- self._renderCalendarButtons($calendarContainer);
- // header
- self._renderCalendarHeader($calendarContainer);
- // body
- self._renderCalendarBody($calendarContainer);
-
- $weekDayColumns = $calendarContainer.find('.wc-day-column-inner');
- $weekDayColumns.each(function(i, val) {
- if (!options.readonly) {
- self._addDroppableToWeekDay($(this));
- if (options.allowEventCreation) {
- self._setupEventCreationForWeekDay($(this));
- }
- }
- });
- },
-
- /**
- * render the nav buttons on top of the calendar
- */
- _renderCalendarButtons: function($calendarContainer) {
- var self = this, options = this.options;
- if ( !options.showHeader ) return;
- if (options.buttons) {
- var calendarNavHtml = '';
-
- calendarNavHtml += '<div class=\"ui-widget-header wc-toolbar\">';
- calendarNavHtml += '<div class=\"wc-display\"></div>';
- calendarNavHtml += '<div class=\"wc-nav\">';
- calendarNavHtml += '<button class=\"wc-prev\">' + options.buttonText.lastWeek + '</button>';
- calendarNavHtml += '<button class=\"wc-today\">' + options.buttonText.today + '</button>';
- calendarNavHtml += '<button class=\"wc-next\">' + options.buttonText.nextWeek + '</button>';
- calendarNavHtml += '</div>';
- calendarNavHtml += '<h1 class=\"wc-title\"></h1>';
- calendarNavHtml += '</div>';
-
- $(calendarNavHtml).appendTo($calendarContainer);
-
- $calendarContainer.find('.wc-nav .wc-today')
- .button({
- icons: {primary: 'ui-icon-home'}})
- .click(function() {
- self.today();
- return false;
- });
-
- $calendarContainer.find('.wc-nav .wc-prev')
- .button({
- text: false,
- icons: {primary: 'ui-icon-seek-prev'}})
- .click(function() {
- self.element.weekCalendar('prev');
- return false;
- });
-
- $calendarContainer.find('.wc-nav .wc-next')
- .button({
- text: false,
- icons: {primary: 'ui-icon-seek-next'}})
- .click(function() {
- self.element.weekCalendar('next');
- return false;
- });
-
- // now add buttons to switch display
- if (this.options.switchDisplay && $.isPlainObject(this.options.switchDisplay)) {
- var $container = $calendarContainer.find('.wc-display');
- $.each(this.options.switchDisplay, function(label, option) {
- var _id = 'wc-switch-display-' + option;
- var _input = $('<input type="radio" id="' + _id + '" name="wc-switch-display" class="wc-switch-display"/>');
- var _label = $('<label for="' + _id + '"></label>');
- _label.html(label);
- _input.val(option);
- if (parseInt(self.options.daysToShow, 10) === parseInt(option, 10)) {
- _input.attr('checked', 'checked');
- }
- $container
- .append(_input)
- .append(_label);
- });
- $container.find('input').change(function() {
- self.setDaysToShow(parseInt($(this).val(), 10));
- });
- }
- $calendarContainer.find('.wc-nav, .wc-display').buttonset();
- var _height = $calendarContainer.find('.wc-nav').outerHeight();
- $calendarContainer.find('.wc-title')
- .height(_height)
- .css('line-height', _height + 'px');
- }else{
- var calendarNavHtml = '';
- calendarNavHtml += '<div class=\"ui-widget-header wc-toolbar\">';
- calendarNavHtml += '<h1 class=\"wc-title\"></h1>';
- calendarNavHtml += '</div>';
- $(calendarNavHtml).appendTo($calendarContainer);
-
- }
- },
-
- /**
- * render the calendar header, including date and user header
- */
- _renderCalendarHeader: function($calendarContainer) {
- var self = this, options = this.options,
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- rowspan = '', colspan = '', calendarHeaderHtml;
-
- if (showAsSeparatedUser) {
- rowspan = ' rowspan=\"2\"';
- colspan = ' colspan=\"' + options.users.length + '\" ';
- }
-
- //first row
- calendarHeaderHtml = '<div class=\"ui-widget-content wc-header\">';
- calendarHeaderHtml += '<table><tbody><tr><td class=\"wc-time-column-header\"></td>';
- for (var i = 1; i <= options.daysToShow; i++) {
- calendarHeaderHtml += '<td class=\"wc-day-column-header wc-day-' + i + '\"' + colspan + '></td>';
- }
- calendarHeaderHtml += '<td class=\"wc-scrollbar-shim\"' + rowspan + '></td></tr>';
-
- //users row
- if (showAsSeparatedUser) {
- calendarHeaderHtml += '<tr><td class=\"wc-time-column-header\"></td>';
- var uLength = options.users.length,
- _headerClass = '';
-
- for (var i = 1; i <= options.daysToShow; i++) {
- for (var j = 0; j < uLength; j++) {
- _headerClass = [];
- if (j == 0) {
- _headerClass.push('wc-day-column-first');
- }
- if (j == uLength - 1) {
- _headerClass.push('wc-day-column-last');
- }
- if (!_headerClass.length) {
- _headerClass = 'wc-day-column-middle';
- }
- else {
- _headerClass = _headerClass.join(' ');
- }
- calendarHeaderHtml += '<td class=\"' + _headerClass + ' wc-user-header wc-day-' + i + ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
-// calendarHeaderHtml+= "<div class=\"wc-user-header wc-day-" + i + " wc-user-" + self._getUserIdFromIndex(j) +"\" >";
- calendarHeaderHtml += self._getUserName(j);
-// calendarHeaderHtml+= "</div>";
- calendarHeaderHtml += '</td>';
- }
- }
- calendarHeaderHtml += '</tr>';
- }
- //close the header
- calendarHeaderHtml += '</tbody></table></div>';
-
- $(calendarHeaderHtml).appendTo($calendarContainer);
- },
-
- /**
- * render the calendar body.
- * Calendar body is composed of several distinct parts.
- * Each part is displayed in a separated row to ease rendering.
- * for further explanations, see each part rendering function.
- */
- _renderCalendarBody: function($calendarContainer) {
- var self = this, options = this.options,
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- $calendarBody, $calendarTableTbody;
- // create the structure
- $calendarBody = '<div class=\"wc-scrollable-grid\">';
- $calendarBody += '<table class=\"wc-time-slots\">';
- $calendarBody += '<tbody>';
- $calendarBody += '</tbody>';
- $calendarBody += '</table>';
- $calendarBody += '</div>';
- $calendarBody = $($calendarBody);
- $calendarTableTbody = $calendarBody.find('tbody');
-
- self._renderCalendarBodyTimeSlots($calendarTableTbody);
- self._renderCalendarBodyOddEven($calendarTableTbody);
- self._renderCalendarBodyFreeBusy($calendarTableTbody);
- self._renderCalendarBodyEvents($calendarTableTbody);
-
- $calendarBody.appendTo($calendarContainer);
-
- //set the column height
- $calendarContainer.find('.wc-full-height-column').height(options.timeslotHeight * options.timeslotsPerDay);
- //set the timeslot height
- $calendarContainer.find('.wc-time-slot').height(options.timeslotHeight - 1); //account for border
- //init the time row header height
- /**
- TODO if total height for an hour is less than 11px, there is a display problem.
- Find a way to handle it
- */
- $calendarContainer.find('.wc-time-header-cell').css({
- height: (options.timeslotHeight * options.timeslotsPerHour) - 11,
- padding: 5
- });
- //add the user data to every impacted column
- if (showAsSeparatedUser) {
- for (var i = 0, uLength = options.users.length; i < uLength; i++) {
- $calendarContainer.find('.wc-user-' + self._getUserIdFromIndex(i))
- .data('wcUser', options.users[i])
- .data('wcUserIndex', i)
- .data('wcUserId', self._getUserIdFromIndex(i));
- }
- }
- },
-
- /**
- * render the timeslots separation
- */
- _renderCalendarBodyTimeSlots: function($calendarTableTbody) {
- var options = this.options,
- renderRow, i, j,
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
- end = (options.businessHours.limitDisplay ? options.businessHours.end : 24),
- rowspan = 1;
-
- //calculate the rowspan
- if (options.displayOddEven) { rowspan += 1; }
- if (options.displayFreeBusys) { rowspan += 1; }
- if (rowspan > 1) {
- rowspan = ' rowspan=\"' + rowspan + '\"';
- }
- else {
- rowspan = '';
- }
-
- renderRow = '<tr class=\"wc-grid-row-timeslot\">';
- renderRow += '<td class=\"wc-grid-timeslot-header\"' + rowspan + '></td>';
- renderRow += '<td colspan=\"' + options.daysToShow * (showAsSeparatedUser ? options.users.length : 1) + '\">';
- renderRow += '<div class=\"wc-no-height-wrapper wc-time-slot-wrapper\">';
- renderRow += '<div class=\"wc-time-slots\">';
-
- for (i = start; i < end; i++) {
- for (j = 0; j < options.timeslotsPerHour - 1; j++) {
- renderRow += '<div class=\"wc-time-slot\"></div>';
- }
- renderRow += '<div class=\"wc-time-slot wc-hour-end\"></div>';
- }
-
- renderRow += '</div>';
- renderRow += '</div>';
- renderRow += '</td>';
- renderRow += '</tr>';
-
- $(renderRow).appendTo($calendarTableTbody);
- },
-
- /**
- * render the odd even columns
- */
- _renderCalendarBodyOddEven: function($calendarTableTbody) {
- if (this.options.displayOddEven) {
- var options = this.options,
- renderRow = '<tr class=\"wc-grid-row-oddeven\">',
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- oddEven,
- // let's take advantage of the jquery ui framework
- oddEvenClasses = {'odd': 'wc-column-odd', 'even': 'ui-state-hover wc-column-even'};
-
- //now let's display oddEven placeholders
- for (var i = 1; i <= options.daysToShow; i++) {
- if (!showAsSeparatedUser) {
- oddEven = (oddEven == 'odd' ? 'even' : 'odd');
- renderRow += '<td class=\"wc-day-column day-' + i + '\">';
- renderRow += '<div class=\"wc-no-height-wrapper wc-oddeven-wrapper\">';
- renderRow += '<div class=\"wc-full-height-column ' + oddEvenClasses[oddEven] + '\"></div>';
- renderRow += '</div>';
- renderRow += '</td>';
- }
- else {
- var uLength = options.users.length;
- for (var j = 0; j < uLength; j++) {
- oddEven = (oddEven == 'odd' ? 'even' : 'odd');
- renderRow += '<td class=\"wc-day-column day-' + i + '\">';
- renderRow += '<div class=\"wc-no-height-wrapper wc-oddeven-wrapper\">';
- renderRow += '<div class=\"wc-full-height-column ' + oddEvenClasses[oddEven] + '\" ></div>';
- renderRow += '</div>';
- renderRow += '</td>';
- }
- }
- }
- renderRow += '</tr>';
-
- $(renderRow).appendTo($calendarTableTbody);
- }
- },
-
- /**
- * render the freebusy placeholders
- */
- _renderCalendarBodyFreeBusy: function($calendarTableTbody) {
- if (this.options.displayFreeBusys) {
- var self = this, options = this.options,
- renderRow = '<tr class=\"wc-grid-row-freebusy\">',
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
- renderRow += '</td>';
-
- //now let's display freebusy placeholders
- for (var i = 1; i <= options.daysToShow; i++) {
- if (options.displayFreeBusys) {
- if (!showAsSeparatedUser) {
- renderRow += '<td class=\"wc-day-column day-' + i + '\">';
- renderRow += '<div class=\"wc-no-height-wrapper wc-freebusy-wrapper\">';
- renderRow += '<div class=\"wc-full-height-column wc-column-freebusy wc-day-' + i + '\"></div>';
- renderRow += '</div>';
- renderRow += '</td>';
- }
- else {
- var uLength = options.users.length;
- for (var j = 0; j < uLength; j++) {
- renderRow += '<td class=\"wc-day-column day-' + i + '\">';
- renderRow += '<div class=\"wc-no-height-wrapper wc-freebusy-wrapper\">';
- renderRow += '<div class=\"wc-full-height-column wc-column-freebusy wc-day-' + i;
- renderRow += ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
- renderRow += '</div>';
- renderRow += '</div>';
- renderRow += '</td>';
- }
- }
- }
- }
-
- renderRow += '</tr>';
-
- $(renderRow).appendTo($calendarTableTbody);
- }
- },
-
- /**
- * render the calendar body for event placeholders
- */
- _renderCalendarBodyEvents: function($calendarTableTbody) {
- var self = this, options = this.options,
- renderRow,
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
- end = (options.businessHours.limitDisplay ? options.businessHours.end : 24);
- renderRow = '<tr class=\"wc-grid-row-events\">';
- renderRow += '<td class=\"wc-grid-timeslot-header\">';
- for (var i = start; i < end; i++) {
- var bhClass = (options.businessHours.start <= i && options.businessHours.end > i) ? 'ui-state-active wc-business-hours' : 'ui-state-default';
- renderRow += '<div class=\"wc-hour-header ' + bhClass + '\">';
- if (options.use24Hour) {
- renderRow += '<div class=\"wc-time-header-cell\">' + self._24HourForIndex(i) + '</div>';
- }
- else {
- renderRow += '<div class=\"wc-time-header-cell\">' + self._hourForIndex(i) + '<span class=\"wc-am-pm\">' + self._amOrPm(i) + '</span></div>';
- }
- renderRow += '</div>';
- }
- renderRow += '</td>';
-
- //now let's display events placeholders
- var _columnBaseClass = 'ui-state-default wc-day-column';
- for (var i = 1; i <= options.daysToShow; i++) {
- if (!showAsSeparatedUser) {
- renderRow += '<td class=\"' + _columnBaseClass + ' wc-day-column-first wc-day-column-last day-' + i + '\">';
- renderRow += '<div class=\"wc-full-height-column wc-day-column-inner day-' + i + '\"></div>';
- renderRow += '</td>';
- }
- else {
- var uLength = options.users.length;
- var columnclass;
- for (var j = 0; j < uLength; j++) {
- columnclass = [];
- if (j == 0) {
- columnclass.push('wc-day-column-first');
- }
- if (j == uLength - 1) {
- columnclass.push('wc-day-column-last');
- }
- if (!columnclass.length) {
- columnclass = 'wc-day-column-middle';
- }
- else {
- columnclass = columnclass.join(' ');
- }
- renderRow += '<td class=\"' + _columnBaseClass + ' ' + columnclass + ' day-' + i + '\">';
- renderRow += '<div class=\"wc-full-height-column wc-day-column-inner day-' + i;
- renderRow += ' wc-user-' + self._getUserIdFromIndex(j) + '\">';
- renderRow += '</div>';
- renderRow += '</td>';
- }
- }
- }
-
- renderRow += '</tr>';
-
- $(renderRow).appendTo($calendarTableTbody);
- },
-
- /*
- * setup mouse events for capturing new events
- */
- _setupEventCreationForWeekDay: function($weekDay) {
- var self = this;
- var options = this.options;
- $weekDay.mousedown(function(event) {
- var $target = $(event.target);
- if ($target.hasClass('wc-day-column-inner')) {
-
- var $newEvent = $('<div class=\"wc-cal-event wc-new-cal-event wc-new-cal-event-creating\"></div>');
-
- $newEvent.css({lineHeight: (options.timeslotHeight - 2) + 'px', fontSize: (options.timeslotHeight / 2) + 'px'});
- $target.append($newEvent);
-
- var columnOffset = $target.offset().top;
- var clickY = event.pageY - columnOffset;
- var clickYRounded = (clickY - (clickY % options.timeslotHeight)) / options.timeslotHeight;
- var topPosition = clickYRounded * options.timeslotHeight;
- $newEvent.css({top: topPosition});
-
- if (!options.preventDragOnEventCreation) {
- $target.bind('mousemove.newevent', function(event) {
- $newEvent.show();
- $newEvent.addClass('ui-resizable-resizing');
- var height = Math.round(event.pageY - columnOffset - topPosition);
- var remainder = height % options.timeslotHeight;
- //snap to closest timeslot
- if (remainder < 0) {
- var useHeight = height - remainder;
- $newEvent.css('height', useHeight < options.timeslotHeight ? options.timeslotHeight : useHeight);
- } else {
- $newEvent.css('height', height + (options.timeslotHeight - remainder));
- }
- }).mouseup(function() {
- $target.unbind('mousemove.newevent');
- $newEvent.addClass('ui-corner-all');
- });
- }
- }
-
- }).mouseup(function(event) {
- var $target = $(event.target);
-
- var $weekDay = $target.closest('.wc-day-column-inner');
- var $newEvent = $weekDay.find('.wc-new-cal-event-creating');
-
- if ($newEvent.length) {
- var createdFromSingleClick = !$newEvent.hasClass('ui-resizable-resizing');
-
- //if even created from a single click only, default height
- if (createdFromSingleClick) {
- $newEvent.css({height: options.timeslotHeight * options.defaultEventLength}).show();
- }
- var top = parseInt($newEvent.css('top'));
- var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $newEvent, top);
-
- $newEvent.remove();
- var newCalEvent = {start: eventDuration.start, end: eventDuration.end, title: options.newEventText};
- var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
-
- if (showAsSeparatedUser) {
- newCalEvent = self._setEventUserId(newCalEvent, $weekDay.data('wcUserId'));
- }
- else if (!options.showAsSeparateUsers && options.users && options.users.length == 1) {
- newCalEvent = self._setEventUserId(newCalEvent, self._getUserIdFromIndex(0));
- }
-
- var freeBusyManager = self.getFreeBusyManagerForEvent(newCalEvent);
-
- var $renderedCalEvent = self._renderEvent(newCalEvent, $weekDay);
-
- if (!options.allowCalEventOverlap) {
- self._adjustForEventCollisions($weekDay, $renderedCalEvent, newCalEvent, newCalEvent);
- self._positionEvent($weekDay, $renderedCalEvent);
- } else {
- self._adjustOverlappingEvents($weekDay);
- }
-
- var proceed = self._trigger('beforeEventNew', event, {
- 'calEvent': newCalEvent,
- 'createdFromSingleClick': createdFromSingleClick,
- 'calendar': self.element
- });
- if (proceed) {
- options.eventNew(newCalEvent, $renderedCalEvent, freeBusyManager, self.element, event);
- }
- else {
- $($renderedCalEvent).remove();
- }
- }
- });
- },
-
- /*
- * load calendar events for the week based on the date provided
- */
- _loadCalEvents: function(dateWithinWeek) {
-
- var date, weekStartDate, weekEndDate, $weekDayColumns;
- var self = this;
- var options = this.options;
- date = this._fixMinMaxDate(dateWithinWeek || options.date);
- // if date is not provided
- // or was not set
- // or is different than old one
- if ((!date || !date.getTime) ||
- (!options.date || !options.date.getTime) ||
- date.getTime() != options.date.getTime()
- ) {
- // trigger the changedate event
- this._trigger('changedate', this.element, date);
- }
- this.options.date = date;
- weekStartDate = self._dateFirstDayOfWeek(date);
- weekEndDate = self._dateLastMilliOfWeek(date);
-
- options.calendarBeforeLoad(self.element);
-
- self.element.data('startDate', weekStartDate);
- self.element.data('endDate', weekEndDate);
-
- $weekDayColumns = self.element.find('.wc-day-column-inner');
-
- self._updateDayColumnHeader($weekDayColumns);
-
- //load events by chosen means
- if (typeof options.data == 'string') {
- if (options.loading) {
- options.loading(true);
- }
- if (_currentAjaxCall) {
- // first abort current request.
- if (!_jQuery14OrLower) {
- _currentAjaxCall.abort();
- } else {
- // due to the fact that jquery 1.4 does not detect a request was
- // aborted, we need to replace the onreadystatechange and
- // execute the "complete" callback.
- _currentAjaxCall.onreadystatechange = null;
- _currentAjaxCall.abort();
- _currentAjaxCall = null;
- if (options.loading) {
- options.loading(false);
- }
- }
- }
- var jsonOptions = self._getJsonOptions();
- jsonOptions[options.startParam || 'start'] = Math.round(weekStartDate.getTime() / 1000);
- jsonOptions[options.endParam || 'end'] = Math.round(weekEndDate.getTime() / 1000);
- _currentAjaxCall = $.ajax({
- url: options.data,
- data: jsonOptions,
- dataType: 'json',
- error: function(XMLHttpRequest, textStatus, errorThrown) {
- // only prevent error with jQuery 1.5
- // see issue #34. thanks to dapplebeforedawn
- // (https://github.com/themouette/jquery-week-calendar/issues#issue/34)
- // for 1.5+, aborted request mean errorThrown == 'abort'
- // for prior version it means !errorThrown && !XMLHttpRequest.status
- // fixes #55
- if (errorThrown != 'abort' && XMLHttpRequest.status != 0) {
- alert('unable to get data, error:' + textStatus);
- }
- },
- success: function(data) {
- self._renderEvents(data, $weekDayColumns);
- },
- complete: function() {
- _currentAjaxCall = null;
- if (options.loading) {
- options.loading(false);
- }
- }
- });
- }
- else if ($.isFunction(options.data)) {
- options.data(weekStartDate, weekEndDate,
- function(data) {
- self._renderEvents(data, $weekDayColumns);
- });
- }
- else if (options.data) {
- self._renderEvents(options.data, $weekDayColumns);
- }
-
- self._disableTextSelect($weekDayColumns);
- },
-
- /**
- * Draws a thin line which indicates the current time.
- */
- _drawCurrentHourLine: function() {
- var self = this;
- var d = MyDate(),
- options = this.options,
- businessHours = options.businessHours;
-
- self._scrollToHour(d.getHours() ,false);
- // first, we remove the old hourline if it exists
- $('.wc-hourline', this.element).remove();
-
- // the line does not need to be displayed
- if (businessHours.limitDisplay && d.getHours() > businessHours.end) {
- return;
- }
-
- // then we recreate it
- var paddingStart = businessHours.limitDisplay ? businessHours.start : 0;
- var nbHours = d.getHours() - paddingStart + d.getMinutes() / 60;
- var positionTop = nbHours * options.timeslotHeight * options.timeslotsPerHour;
- var lineWidth = $('.wc-scrollable-grid .wc-today', this.element).width() + 3;
- $('.wc-scrollable-grid .wc-today', this.element).append(
- $('<div>', {
- 'class': 'wc-hourline',
- style: 'top: ' + positionTop + 'px; width: ' + lineWidth + 'px'
- })
- );
- },
-
- /*
- * update the display of each day column header based on the calendar week
- */
- _updateDayColumnHeader: function($weekDayColumns) {
- var self = this;
- var options = this.options;
- var currentDay = self._cloneDate(self.element.data('startDate'));
- var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
- var todayClass = 'ui-state-active wc-today';
-
- self.element.find('.wc-header td.wc-day-column-header').each(function(i, val) {
- $(this).html(self._getHeaderDate(currentDay));
- if (self._isToday(currentDay)) {
- $(this).addClass(todayClass);
- } else {
- $(this).removeClass(todayClass);
- }
- currentDay = self._addDays(currentDay, 1);
-
- });
-
- currentDay = self._cloneDate(self.element.data('startDate'));
- if (showAsSeparatedUser)
- {
- self.element.find('.wc-header td.wc-user-header').each(function(i, val) {
- if (self._isToday(currentDay)) {
- $(this).addClass(todayClass);
- } else {
- $(this).removeClass(todayClass);
- }
- currentDay = ((i + 1) % options.users.length) ? currentDay : self._addDays(currentDay, 1);
- });
- }
-
- currentDay = self._cloneDate(self.element.data('startDate'));
-
- $weekDayColumns.each(function(i, val) {
-
- $(this).data('startDate', self._cloneDate(currentDay));
- $(this).data('endDate', new Date(currentDay.getTime() + (MILLIS_IN_DAY)));
- if (self._isToday(currentDay)) {
- $(this).parent()
- .addClass(todayClass)
- .removeClass('ui-state-default');
- } else {
- $(this).parent()
- .removeClass(todayClass)
- .addClass('ui-state-default');
- }
-
- if (!showAsSeparatedUser || !((i + 1) % options.users.length)) {
- currentDay = self._addDays(currentDay, 1);
- }
- });
-
- //now update the freeBusy placeholders
- if (options.displayFreeBusys) {
- currentDay = self._cloneDate(self.element.data('startDate'));
- self.element.find('.wc-grid-row-freebusy .wc-column-freebusy').each(function(i, val) {
- $(this).data('startDate', self._cloneDate(currentDay));
- $(this).data('endDate', new Date(currentDay.getTime() + (MILLIS_IN_DAY)));
- if (!showAsSeparatedUser || !((i + 1) % options.users.length)) {
- currentDay = self._addDays(currentDay, 1);
- }
- });
- }
-
- // now update the calendar title
- if (this.options.title) {
- var date = this.options.date,
- start = self._cloneDate(self.element.data('startDate')),
- end = self._dateLastDayOfWeek(new Date(this._cloneDate(self.element.data('endDate')).getTime() - (MILLIS_IN_DAY))),
- title = this._getCalendarTitle(),
- date_format = options.dateFormat;
-
- // replace the placeholders contained in the title
- title = title.replace('%start%', self._formatDate(start, date_format));
- title = title.replace('%end%', self._formatDate(end, date_format));
- title = title.replace('%date%', self._formatDate(date, date_format));
-
- $('.wc-toolbar .wc-title', self.element).html(title);
- }
- //self._clearFreeBusys();
- },
-
- /**
- * Gets the calendar raw title.
- */
- _getCalendarTitle: function() {
- if ($.isFunction(this.options.title)) {
- return this.options.title(this.options.daysToShow);
- }
-
- return this.options.title || '';
- },
-
- /**
- * Render the events into the calendar
- */
- _renderEvents: function(data, $weekDayColumns) {
- var self = this;
- var options = this.options;
- var eventsToRender, nbRenderedEvents = 0;
-
- if (data.options) {
- var updateLayout = false;
- // update options
- $.each(data.options, function(key, value) {
- if (value !== options[key]) {
- options[key] = value;
- updateLayout = updateLayout || $.ui.weekCalendar.updateLayoutOptions[key];
- }
- });
-
- self._computeOptions();
-
- if (updateLayout) {
- var hour = self._getCurrentScrollHour();
- self.element.empty();
- self._renderCalendar();
- $weekDayColumns = self.element.find('.wc-time-slots .wc-day-column-inner');
- self._updateDayColumnHeader($weekDayColumns);
- self._resizeCalendar();
- self._scrollToHour(hour, false);
- }
- }
- this._clearCalendar();
-
- if ($.isArray(data)) {
- eventsToRender = self._cleanEvents(data);
- } else if (data.events) {
- eventsToRender = self._cleanEvents(data.events);
- self._renderFreeBusys(data);
- }
-
- $.each(eventsToRender, function(i, calEvent) {
- // render a multi day event as various event :
- // thanks to http://github.com/fbeauchamp/jquery-week-calendar
- if (!calEvent || !calEvent.start || !calEvent.end) return;
- var initialStart = new Date(calEvent.start);
- var initialEnd = new Date(calEvent.end);
- var maxHour = self.options.businessHours.limitDisplay ? self.options.businessHours.end : 24;
- var minHour = self.options.businessHours.limitDisplay ? self.options.businessHours.start : 0;
- var start = new Date(initialStart);
- var startDate = self._formatDate(start, 'Ymd');
- var endDate = self._formatDate(initialEnd, 'Ymd');
- var $weekDay;
- var isMultiday = false;
-
- while (startDate < endDate) {
- calEvent.start = start;
-
- // end of this virual calEvent is set to the end of the day
- calEvent.end.setFullYear(start.getFullYear());
- calEvent.end.setDate(start.getDate());
- calEvent.end.setMonth(start.getMonth());
- calEvent.end.setHours(maxHour, 0, 0);
-
- if (($weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns))) {
- self._renderEvent(calEvent, $weekDay);
- nbRenderedEvents += 1;
- }
-
- // start is set to the begin of the new day
- start.setDate(start.getDate() + 1);
- start.setHours(minHour, 0, 0);
-
- startDate = self._formatDate(start, 'Ymd');
- isMultiday = true;
- }
-
- if (start <= initialEnd) {
- calEvent.start = start;
- calEvent.end = initialEnd;
-
- if (((isMultiday && calEvent.start.getTime() != calEvent.end.getTime()) || !isMultiday) && ($weekDay = self._findWeekDayForEvent(calEvent, $weekDayColumns))) {
- self._renderEvent(calEvent, $weekDay);
- nbRenderedEvents += 1;
- }
- }
-
- // put back the initial start date
- calEvent.start = initialStart;
- });
-
- $weekDayColumns.each(function() {
- self._adjustOverlappingEvents($(this));
- });
-
- options.calendarAfterLoad(self.element);
-
- if (self._hourLineTimeout) {
- clearInterval(self._hourLineTimeout);
- self._hourLineTimeout = false;
- }
-
- if (options.hourLine) {
- self._drawCurrentHourLine();
-
- self._hourLineTimeout = setInterval(function() {
- self._drawCurrentHourLine();
- }, 60 * 1000); // redraw the line each minute
- }
-
- !nbRenderedEvents && options.noEvents();
- },
-
- /*
- * Render a specific event into the day provided. Assumes correct
- * day for calEvent date
- */
- _renderEvent: function(calEvent, $weekDay) {
- var self = this;
- var options = this.options;
- if (calEvent.start.getTime() > calEvent.end.getTime()) {
- return; // can't render a negative height
- }
-
- var eventClass, eventHtml, $calEventList, $modifiedEvent;
-
- eventClass = calEvent.id ? 'wc-cal-event' : 'wc-cal-event wc-new-cal-event';
- eventHtml = '<div class=\"' + eventClass + ' ui-corner-all\">';
- eventHtml += '<div class=\"wc-time ui-corner-top\"></div>';
- eventHtml += '<div class=\"wc-title\"></div></div>';
-
- $weekDay.each(function() {
- var $calEvent = $(eventHtml);
- $modifiedEvent = options.eventRender(calEvent, $calEvent);
- $calEvent = $modifiedEvent ? $modifiedEvent.appendTo($(this)) : $calEvent.appendTo($(this));
- $calEvent.css({lineHeight: (options.textSize + 2) + 'px', fontSize: options.textSize + 'px'});
-
- self._refreshEventDetails(calEvent, $calEvent);
- self._positionEvent($(this), $calEvent);
-
- //add to event list
- if ($calEventList) {
- $calEventList = $calEventList.add($calEvent);
- }
- else {
- $calEventList = $calEvent;
- }
- });
- $calEventList.show();
-
- if (!options.readonly && options.resizable(calEvent, $calEventList)) {
- self._addResizableToCalEvent(calEvent, $calEventList, $weekDay);
- }
- if (!options.readonly && options.draggable(calEvent, $calEventList)) {
- self._addDraggableToCalEvent(calEvent, $calEventList);
- }
- options.eventAfterRender(calEvent, $calEventList);
-
- return $calEventList;
-
- },
- addEvent: function() {
- return this._renderEvent.apply(this, arguments);
- },
-
- _adjustOverlappingEvents: function($weekDay) {
- var self = this;
- if (self.options.allowCalEventOverlap) {
- var groupsList = self._groupOverlappingEventElements($weekDay);
- $.each(groupsList, function() {
- var curGroups = this;
- $.each(curGroups, function(groupIndex) {
- var curGroup = this;
-
- // do we want events to be displayed as overlapping
- if (self.options.overlapEventsSeparate) {
- var newWidth = self.options.totalEventsWidthPercentInOneColumn / curGroups.length;
- var newLeft = groupIndex * newWidth;
- } else {
- // TODO what happens when the group has more than 10 elements
- var newWidth = self.options.totalEventsWidthPercentInOneColumn - ((curGroups.length - 1) * 10);
- var newLeft = groupIndex * 10;
- }
- $.each(curGroup, function() {
- // bring mouseovered event to the front
- if (!self.options.overlapEventsSeparate) {
- $(this).bind('mouseover.z-index', function() {
- var $elem = $(this);
- $.each(curGroup, function() {
- $(this).css({'z-index': '1'});
- });
- $elem.css({'z-index': '3'});
- });
- }
- $(this).css({width: newWidth + '%', left: newLeft + '%', right: 0});
- });
- });
- });
- }
- },
-
-
- /*
- * Find groups of overlapping events
- */
- _groupOverlappingEventElements: function($weekDay) {
- var $events = $weekDay.find('.wc-cal-event:visible');
- var sortedEvents = $events.sort(function(a, b) {
- return $(a).data('calEvent').start.getTime() - $(b).data('calEvent').start.getTime();
- });
-
- var lastEndTime = new Date(0, 0, 0);
- var groups = [];
- var curGroups = [];
- var $curEvent;
- $.each(sortedEvents, function() {
- $curEvent = $(this);
- //checks, if the current group list is not empty, if the overlapping is finished
- if (curGroups.length > 0) {
- if (lastEndTime.getTime() <= $curEvent.data('calEvent').start.getTime()) {
- //finishes the current group list by adding it to the resulting list of groups and cleans it
-
- groups.push(curGroups);
- curGroups = [];
- }
- }
-
- //finds the first group to fill with the event
- for (var groupIndex = 0; groupIndex < curGroups.length; groupIndex++) {
- if (curGroups[groupIndex].length > 0) {
- //checks if the event starts after the end of the last event of the group
- if (curGroups[groupIndex][curGroups[groupIndex].length - 1].data('calEvent').end.getTime() <= $curEvent.data('calEvent').start.getTime()) {
- curGroups[groupIndex].push($curEvent);
- if (lastEndTime.getTime() < $curEvent.data('calEvent').end.getTime()) {
- lastEndTime = $curEvent.data('calEvent').end;
- }
- return;
- }
- }
- }
- //if not found, creates a new group
- curGroups.push([$curEvent]);
- if (lastEndTime.getTime() < $curEvent.data('calEvent').end.getTime()) {
- lastEndTime = $curEvent.data('calEvent').end;
- }
- });
- //adds the last groups in result
- if (curGroups.length > 0) {
- groups.push(curGroups);
- }
- return groups;
- },
-
-
- /*
- * find the weekday in the current calendar that the calEvent falls within
- */
- _findWeekDayForEvent: function(calEvent, $weekDayColumns) {
-
- var $weekDay,
- options = this.options,
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- user_ids = this._getEventUserId(calEvent);
-
- if (!$.isArray(user_ids)) {
- user_ids = [user_ids];
- }
-
- $weekDayColumns.each(function(index, curDay) {
- if ($(this).data('startDate').getTime() <= calEvent.start.getTime() &&
- $(this).data('endDate').getTime() >= calEvent.end.getTime() &&
- (!showAsSeparatedUser || $.inArray($(this).data('wcUserId'), user_ids) !== -1)
- ) {
- if ($weekDay) {
- $weekDay = $weekDay.add($(curDay));
- }
- else {
- $weekDay = $(curDay);
- }
- }
- });
-
- return $weekDay;
- },
-
- /*
- * update the events rendering in the calendar. Add if does not yet exist.
- */
- _updateEventInCalendar: function(calEvent) {
- var self = this;
- self._cleanEvent(calEvent);
-
- if (calEvent.id) {
- self.element.find('.wc-cal-event').each(function() {
- if ($(this).data('calEvent').id === calEvent.id || $(this).hasClass('wc-new-cal-event')) {
- $(this).remove();
- // return false;
- }
- });
- }
-
- var $weekDays = self._findWeekDayForEvent(calEvent, self.element.find('.wc-grid-row-events .wc-day-column-inner'));
- if ($weekDays) {
- $weekDays.each(function(index, weekDay) {
- var $weekDay = $(weekDay);
- var $calEvent = self._renderEvent(calEvent, $weekDay);
- self._adjustForEventCollisions($weekDay, $calEvent, calEvent, calEvent);
- self._refreshEventDetails(calEvent, $calEvent);
- self._positionEvent($weekDay, $calEvent);
- self._adjustOverlappingEvents($weekDay);
- });
- }
- },
-
- /*
- * Position the event element within the weekday based on it's start / end dates.
- */
- _positionEvent: function($weekDay, $calEvent) {
- var options = this.options;
- var calEvent = $calEvent.data('calEvent');
- var pxPerMillis = $weekDay.height() / options.millisToDisplay;
- var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
- var startMillis = this._getDSTdayShift(calEvent.start).getTime() - this._getDSTdayShift(new Date(calEvent.start.getFullYear(), calEvent.start.getMonth(), calEvent.start.getDate(), firstHourDisplayed)).getTime();
- var eventMillis = this._getDSTdayShift(calEvent.end).getTime() - this._getDSTdayShift(calEvent.start).getTime();
- var pxTop = pxPerMillis * startMillis;
- var pxHeight = pxPerMillis * eventMillis;
- //var pxHeightFallback = pxPerMillis * (60 / options.timeslotsPerHour) * 60 * 1000;
- $calEvent.css({top: pxTop, height: pxHeight || (pxPerMillis * 3600000 / options.timeslotsPerHour)});
- },
-
- /*
- * Determine the actual start and end times of a calevent based on it's
- * relative position within the weekday column and the starting hour of the
- * displayed calendar.
- */
- _getEventDurationFromPositionedEventElement: function($weekDay, $calEvent, top) {
- var options = this.options;
- var startOffsetMillis = options.businessHours.limitDisplay ? options.businessHours.start * 3600000 : 0;
- var start = new Date($weekDay.data('startDate').getTime() + startOffsetMillis + Math.round(top / options.timeslotHeight) * options.millisPerTimeslot);
- var end = new Date(start.getTime() + ($calEvent.height() / options.timeslotHeight) * options.millisPerTimeslot);
- return {start: this._getDSTdayShift(start, -1), end: this._getDSTdayShift(end, -1)};
- },
-
- /*
- * If the calendar does not allow event overlap, adjust the start or end date if necessary to
- * avoid overlapping of events. Typically, shortens the resized / dropped event to it's max possible
- * duration based on the overlap. If no satisfactory adjustment can be made, the event is reverted to
- * it's original location.
- */
- _adjustForEventCollisions: function($weekDay, $calEvent, newCalEvent, oldCalEvent, maintainEventDuration) {
- var options = this.options;
-
- if (options.allowCalEventOverlap) {
- return;
- }
- var adjustedStart, adjustedEnd;
- var self = this;
-
- $weekDay.find('.wc-cal-event').not($calEvent).each(function() {
- var currentCalEvent = $(this).data('calEvent');
-
- //has been dropped onto existing event overlapping the end time
- if (newCalEvent.start.getTime() < currentCalEvent.end.getTime() &&
- newCalEvent.end.getTime() >= currentCalEvent.end.getTime()) {
-
- adjustedStart = currentCalEvent.end;
- }
-
-
- //has been dropped onto existing event overlapping the start time
- if (newCalEvent.end.getTime() > currentCalEvent.start.getTime() &&
- newCalEvent.start.getTime() <= currentCalEvent.start.getTime()) {
-
- adjustedEnd = currentCalEvent.start;
- }
- //has been dropped inside existing event with same or larger duration
- if (oldCalEvent.resizable == false ||
- (newCalEvent.end.getTime() <= currentCalEvent.end.getTime() &&
- newCalEvent.start.getTime() >= currentCalEvent.start.getTime())) {
-
- adjustedStart = oldCalEvent.start;
- adjustedEnd = oldCalEvent.end;
- return false;
- }
-
- });
-
-
- newCalEvent.start = adjustedStart || newCalEvent.start;
-
- if (adjustedStart && maintainEventDuration) {
- newCalEvent.end = new Date(adjustedStart.getTime() + (oldCalEvent.end.getTime() - oldCalEvent.start.getTime()));
- self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, oldCalEvent);
- } else {
- newCalEvent.end = adjustedEnd || newCalEvent.end;
- }
-
-
- //reset if new cal event has been forced to zero size
- if (newCalEvent.start.getTime() >= newCalEvent.end.getTime()) {
- newCalEvent.start = oldCalEvent.start;
- newCalEvent.end = oldCalEvent.end;
- }
-
- $calEvent.data('calEvent', newCalEvent);
- },
-
- /**
- * Add draggable capabilities to an event
- */
- _addDraggableToCalEvent: function(calEvent, $calEvent) {
- var options = this.options;
-
- $calEvent.draggable({
- handle: '.wc-time',
- containment: 'div.wc-time-slots',
- snap: '.wc-day-column-inner',
- snapMode: 'inner',
- snapTolerance: options.timeslotHeight - 1,
- revert: 'invalid',
- opacity: 0.5,
- grid: [$calEvent.outerWidth() + 1, options.timeslotHeight],
- start: function(event, ui) {
- var $calEvent = ui.draggable || ui.helper;
- options.eventDrag(calEvent, $calEvent);
- }
- });
- },
-
- /*
- * Add droppable capabilites to weekdays to allow dropping of calEvents only
- */
- _addDroppableToWeekDay: function($weekDay) {
- var self = this;
- var options = this.options;
- $weekDay.droppable({
- accept: '.wc-cal-event',
- drop: function(event, ui) {
- var $calEvent = ui.draggable;
- var top = Math.round(parseInt(ui.position.top));
- var eventDuration = self._getEventDurationFromPositionedEventElement($weekDay, $calEvent, top);
- var calEvent = $calEvent.data('calEvent');
- var newCalEvent = $.extend(true, {}, calEvent, {start: eventDuration.start, end: eventDuration.end});
- var showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length;
- if (showAsSeparatedUser) {
- // we may have dragged the event on column with a new user.
- // nice way to handle that is:
- // - get the newly dragged on user
- // - check if user is part of the event
- // - if yes, nothing changes, if not, find the old owner to remove it and add new one
- var newUserId = $weekDay.data('wcUserId');
- var userIdList = self._getEventUserId(calEvent);
- var oldUserId = $(ui.draggable.parents('.wc-day-column-inner').get(0)).data('wcUserId');
- if (!$.isArray(userIdList)) {
- userIdList = [userIdList];
- }
- if ($.inArray(newUserId, userIdList) == -1) {
- // remove old user
- var _index = $.inArray(oldUserId, userIdList);
- userIdList.splice(_index, 1);
- // add new user ?
- if ($.inArray(newUserId, userIdList) == -1) {
- userIdList.push(newUserId);
- }
- }
- newCalEvent = self._setEventUserId(newCalEvent, ((userIdList.length == 1) ? userIdList[0] : userIdList));
- }
- self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent, true);
- var $weekDayColumns = self.element.find('.wc-day-column-inner');
-
- //trigger drop callback
- options.eventDrop(newCalEvent, calEvent, $calEvent);
-
- var $newEvent = self._renderEvent(newCalEvent, self._findWeekDayForEvent(newCalEvent, $weekDayColumns));
- $calEvent.hide();
-
- $calEvent.data('preventClick', true);
-
- var $weekDayOld = self._findWeekDayForEvent($calEvent.data('calEvent'), self.element.find('.wc-time-slots .wc-day-column-inner'));
-
- if ($weekDayOld.data('startDate') != $weekDay.data('startDate')) {
- self._adjustOverlappingEvents($weekDayOld);
- }
- self._adjustOverlappingEvents($weekDay);
-
- setTimeout(function() {
- $calEvent.remove();
- }, 1000);
-
- }
- });
- },
-
- /*
- * Add resizable capabilities to a calEvent
- */
- _addResizableToCalEvent: function(calEvent, $calEvent, $weekDay) {
- var self = this;
- var options = this.options;
- $calEvent.resizable({
- grid: options.timeslotHeight,
- containment: $weekDay,
- handles: 's',
- minHeight: options.timeslotHeight,
- stop: function(event, ui) {
- var $calEvent = ui.element;
- var newEnd = new Date($calEvent.data('calEvent').start.getTime() + Math.max(1, Math.round(ui.size.height / options.timeslotHeight)) * options.millisPerTimeslot);
- if (self._needDSTdayShift($calEvent.data('calEvent').start, newEnd))
- newEnd = self._getDSTdayShift(newEnd, -1);
- var newCalEvent = $.extend(true, {}, calEvent, {start: calEvent.start, end: newEnd});
- self._adjustForEventCollisions($weekDay, $calEvent, newCalEvent, calEvent);
-
- //trigger resize callback
- options.eventResize(newCalEvent, calEvent, $calEvent);
- self._refreshEventDetails(newCalEvent, $calEvent);
- self._positionEvent($weekDay, $calEvent);
- self._adjustOverlappingEvents($weekDay);
- $calEvent.data('preventClick', true);
- setTimeout(function() {
- $calEvent.removeData('preventClick');
- }, 500);
- }
- });
- $('.ui-resizable-handle', $calEvent).text('=');
- },
-
- /*
- * Refresh the displayed details of a calEvent in the calendar
- */
- _refreshEventDetails: function(calEvent, $calEvent) {
- var suffix = '';
- if (!this.options.readonly &&
- this.options.allowEventDelete &&
- this.options.deletable(calEvent,$calEvent)) {
- suffix = '<div class="wc-cal-event-delete ui-icon ui-icon-close"></div>';
- }
- $calEvent.find('.wc-time').html(this.options.eventHeader(calEvent, this.element) + suffix);
- $calEvent.find('.wc-title').html(this.options.eventBody(calEvent, this.element));
- $calEvent.data('calEvent', calEvent);
- this.options.eventRefresh(calEvent, $calEvent);
- },
-
- /*
- * Clear all cal events from the calendar
- */
- _clearCalendar: function() {
- this.element.find('.wc-day-column-inner div').remove();
- this._clearFreeBusys();
- },
-
- /*
- * Scroll the calendar to a specific hour
- */
- _scrollToHour: function(hour, animate) {
- var self = this;
- var options = this.options;
- var $scrollable = this.element.find('.wc-scrollable-grid');
- var slot = hour;
- if (self.options.businessHours.limitDisplay) {
- if (hour <= self.options.businessHours.start) {
- slot = 0;
- } else if (hour >= self.options.businessHours.end) {
- slot = self.options.businessHours.end - self.options.businessHours.start - 1;
- } else {
- slot = hour - self.options.businessHours.start;
- }
- }
-
- //scroll to the hour plus some padding so that hour is in middle of viewport
- var hourHeaderHeight = this.element.find(".wc-grid-timeslot-header .wc-hour-header").outerHeight();
- var calHeight = this.element.find(".wc-scrollable-grid").outerHeight();
- var scroll = (hourHeaderHeight * slot) - calHeight/3;
- if (animate) {
- $scrollable.animate({scrollTop: scroll}, options.scrollToHourMillis);
- }
- else {
- $scrollable.animate({scrollTop: scroll}, 0);
- }
- },
-
- /*
- * find the hour (12 hour day) for a given hour index
- */
- _hourForIndex: function(index) {
- if (index === 0) { //midnight
- return 12;
- } else if (index < 13) { //am
- return index;
- } else { //pm
- return index - 12;
- }
- },
-
- _24HourForIndex: function(index) {
- if (index === 0) { //midnight
- return '00:00';
- } else if (index < 10) {
- return '0' + index + ':00';
- } else {
- return index + ':00';
- }
- },
-
- _amOrPm: function(hourOfDay) {
- return hourOfDay < 12 ? 'AM' : 'PM';
- },
-
- _isToday: function(date) {
- var clonedDate = this._cloneDate(date);
- this._clearTime(clonedDate);
- var today = MyDate();
- this._clearTime(today);
- return today.getTime() === clonedDate.getTime();
- },
-
- /*
- * Clean events to ensure correct format
- */
- _cleanEvents: function(events) {
- var self = this;
- $.each(events, function(i, event) {
- self._cleanEvent(event);
- });
- return events;
- },
-
- /*
- * Clean specific event
- */
- _cleanEvent: function(event) {
- event.start = this._cleanDate(event.start);
- event.end = this._cleanDate(event.end);
- if (!event.end) {
- event.end = this._addDays(this._cloneDate(event.start), 1);
- }
- },
-
- /*
- * Disable text selection of the elements in different browsers
- */
- _disableTextSelect: function($elements) {
- $elements.each(function() {
- $(this).attr('unselectable', 'on')
- .css({
- '-moz-user-select': '-moz-none',
- '-moz-user-select': 'none',
- '-o-user-select': 'none',
- '-khtml-user-select': 'none', /* you could also put this in a class */
- '-webkit-user-select': 'none',/* and add the CSS class here instead */
- '-ms-user-select': 'none',
- 'user-select': 'none'
- }).bind('selectstart', function () { return false; });
-
- });
- },
-
- /*
- * returns the date on the first millisecond of the week
- */
- _dateFirstDayOfWeek: function(date) {
- var self = this;
- var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
- var adjustedDate = new Date(midnightCurrentDate);
- adjustedDate.setDate(adjustedDate.getDate() - self._getAdjustedDayIndex(midnightCurrentDate));
-
- return adjustedDate;
- },
-
- /*
- * returns the date on the first millisecond of the last day of the week
- */
- _dateLastDayOfWeek: function(date) {
- var self = this;
- var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
- var adjustedDate = new Date(midnightCurrentDate);
- var daysToAdd = (self.options.daysToShow - 1 - self._getAdjustedDayIndex(midnightCurrentDate));
- adjustedDate.setDate(adjustedDate.getDate() + daysToAdd);
-
- return adjustedDate;
- },
-
- /**
- * fix the date if it is not within given options
- * minDate and maxDate
- */
- _fixMinMaxDate: function(date) {
- var minDate, maxDate;
- date = this._cleanDate(date);
-
- // not less than minDate
- if (this.options.minDate) {
- minDate = this._cleanDate(this.options.minDate);
- // midnight on minDate
- minDate = new Date(minDate.getFullYear(), minDate.getMonth(), minDate.getDate());
- if (date.getTime() < minDate.getTime()) {
- this._trigger('reachedmindate', this.element, date);
- }
- date = this._cleanDate(Math.max(date.getTime(), minDate.getTime()));
- }
-
- // not more than maxDate
- if (this.options.maxDate) {
- maxDate = this._cleanDate(this.options.maxDate);
- // apply correction for max date if not startOnFirstDayOfWeek
- // to make sure no further date is displayed.
- // otherwise, the complement will still be shown
- if (!this._startOnFirstDayOfWeek()) {
- var day = maxDate.getDate() - this.options.daysToShow + 1;
- maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), day);
- }
- // microsecond before midnight on maxDate
- maxDate = new Date(maxDate.getFullYear(), maxDate.getMonth(), maxDate.getDate(), 23, 59, 59, 999);
- if (date.getTime() > maxDate.getTime()) {
- this._trigger('reachedmaxdate', this.element, date);
- }
- date = this._cleanDate(Math.min(date.getTime(), maxDate.getTime()));
- }
-
- return date;
- },
-
- /*
- * gets the index of the current day adjusted based on options
- */
- _getAdjustedDayIndex: function(date) {
- if (!this._startOnFirstDayOfWeek()) {
- return 0;
- }
-
- var midnightCurrentDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
- var currentDayOfStandardWeek = midnightCurrentDate.getDay();
- var days = [0, 1, 2, 3, 4, 5, 6];
- this._rotate(days, this._firstDayOfWeek());
- return days[currentDayOfStandardWeek];
- },
-
- _firstDayOfWeek: function() {
- if ($.isFunction(this.options.firstDayOfWeek)) {
- return this.options.firstDayOfWeek(this.element);
- }
- return this.options.firstDayOfWeek;
- },
-
- /*
- * returns the date on the last millisecond of the week
- */
- _dateLastMilliOfWeek: function(date) {
- var lastDayOfWeek = this._dateLastDayOfWeek(date);
- lastDayOfWeek = this._cloneDate(lastDayOfWeek);
- lastDayOfWeek.setDate(lastDayOfWeek.getDate() + 1);
- return lastDayOfWeek;
-
- },
-
- /*
- * Clear the time components of a date leaving the date
- * of the first milli of day
- */
- _clearTime: function(d) {
- d.setHours(0);
- d.setMinutes(0);
- d.setSeconds(0);
- d.setMilliseconds(0);
- return d;
- },
-
- /*
- * add specific number of days to date
- */
- _addDays: function(d, n, keepTime) {
- d.setDate(d.getDate() + n);
- if (keepTime) {
- return d;
- }
- return this._clearTime(d);
- },
-
- /*
- * Rotate an array by specified number of places.
- */
- _rotate: function(a /*array*/, p /* integer, positive integer rotate to the right, negative to the left... */) {
- for (var l = a.length, p = (Math.abs(p) >= l && (p %= l), p < 0 && (p += l), p), i, x; p; p = (Math.ceil(l / p) - 1) * p - l + (l = p)) {
- for (i = l; i > p; x = a[--i], a[i] = a[i - p], a[i - p] = x) {}
- }
- return a;
- },
-
- _cloneDate: function(d) {
- return new Date(d.getTime());
- },
-
- /**
- * Return a Date instance for different representations.
- * Valid representations are:
- * * timestamps
- * * Date objects
- * * textual representations (only these accepted by the Date
- * constructor)
- *
- * @return {Date} The clean date object.
- */
- _cleanDate: function(d) {
- if (typeof d === 'string') {
- // if is numeric
- if (!isNaN(Number(d))) {
- return this._cleanDate(parseInt(d, 10));
- }
-
- // this is a human readable date
- if (d[d.length - 1] !== 'Z') d += 'Z';
- var o = new Date(d);
- o.setTime(o.getTime() + (o.getTimezoneOffset() * 60 * 1000));
- return o;
- }
-
- if (typeof d === 'number') {
- return new Date(d);
- }
-
- return d;
- },
-
- /*
- * date formatting is adapted from
- * http://jacwright.com/projects/javascript/date_format
- */
- _formatDate: function(date, format) {
- var returnStr = '';
- for (var i = 0; i < format.length; i++) {
- var curChar = format.charAt(i);
- if (i !== 0 && format.charAt(i - 1) === '\\') {
- returnStr += curChar;
- }
- else if (this._replaceChars[curChar]) {
- returnStr += this._replaceChars[curChar](date, this);
- } else if (curChar !== '\\') {
- returnStr += curChar;
- }
- }
- return returnStr;
- },
-
- _replaceChars: {
- // Day
- d: function(date) { return (date.getDate() < 10 ? '0' : '') + date.getDate(); },
- D: function(date, calendar) { return calendar.options.shortDays[date.getDay()]; },
- j: function(date) { return date.getDate(); },
- l: function(date, calendar) { return calendar.options.longDays[date.getDay()]; },
- N: function(date) { var _d = date.getDay(); return _d ? _d : 7; },
- S: function(date) { return (date.getDate() % 10 == 1 && date.getDate() != 11 ? 'st' : (date.getDate() % 10 == 2 && date.getDate() != 12 ? 'nd' : (date.getDate() % 10 == 3 && date.getDate() != 13 ? 'rd' : 'th'))); },
- w: function(date) { return date.getDay(); },
- z: function(date) { var d = new Date(date.getFullYear(), 0, 1); return Math.ceil((date - d) / 86400000); }, // Fixed now
- // Week
- W: function(date) { var d = new Date(date.getFullYear(), 0, 1); return Math.ceil((((date - d) / 86400000) + d.getDay() + 1) / 7); }, // Fixed now
- // Month
- F: function(date, calendar) { return calendar.options.longMonths[date.getMonth()]; },
- m: function(date) { return (date.getMonth() < 9 ? '0' : '') + (date.getMonth() + 1); },
- M: function(date, calendar) { return calendar.options.shortMonths[date.getMonth()]; },
- n: function(date) { return date.getMonth() + 1; },
- t: function(date) { var d = date; return new Date(d.getFullYear(), d.getMonth() + 1, 0).getDate() }, // Fixed now, gets #days of date
- // Year
- L: function(date) { var year = date.getFullYear(); return (year % 400 == 0 || (year % 100 != 0 && year % 4 == 0)); }, // Fixed now
- o: function(date) { var d = new Date(date.valueOf()); d.setDate(d.getDate() - ((date.getDay() + 6) % 7) + 3); return d.getFullYear();}, //Fixed now
- Y: function(date) { return date.getFullYear(); },
- y: function(date) { return ('' + date.getFullYear()).substr(2); },
- // Time
- a: function(date) { return date.getHours() < 12 ? 'am' : 'pm'; },
- A: function(date) { return date.getHours() < 12 ? 'AM' : 'PM'; },
- B: function(date) { return Math.floor((((date.getUTCHours() + 1) % 24) + date.getUTCMinutes() / 60 + date.getUTCSeconds() / 3600) * 1000 / 24); }, // Fixed now
- g: function(date) { return date.getHours() % 12 || 12; },
- G: function(date) { return date.getHours(); },
- h: function(date) { return ((date.getHours() % 12 || 12) < 10 ? '0' : '') + (date.getHours() % 12 || 12); },
- H: function(date) { return (date.getHours() < 10 ? '0' : '') + date.getHours(); },
- i: function(date) { return (date.getMinutes() < 10 ? '0' : '') + date.getMinutes(); },
- s: function(date) { return (date.getSeconds() < 10 ? '0' : '') + date.getSeconds(); },
- u: function(date) { var m = date.getMilliseconds(); return (m < 10 ? '00' : (m < 100 ? '0' : '')) + m; },
- // Timezone
- e: function(date) { return 'Not Yet Supported'; },
- I: function(date) { return 'Not Yet Supported'; },
- O: function(date) { return (-date.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(date.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(date.getTimezoneOffset() / 60)) + '00'; },
- P: function(date) { return (-date.getTimezoneOffset() < 0 ? '-' : '+') + (Math.abs(date.getTimezoneOffset() / 60) < 10 ? '0' : '') + (Math.abs(date.getTimezoneOffset() / 60)) + ':00'; }, // Fixed now
- T: function(date) { var m = date.getMonth(); date.setMonth(0); var result = date.toTimeString().replace(/^.+ \(?([^\)]+)\)?$/, '$1'); date.setMonth(m); return result;},
- Z: function(date) { return -date.getTimezoneOffset() * 60; },
- // Full Date/Time
- c: function(date, calendar) { return calendar._formatDate(date, 'Y-m-d\\TH:i:sP'); }, // Fixed now
- r: function(date, calendar) { return calendar._formatDate(date, 'D, d M Y H:i:s O'); },
- U: function(date) { return date.getTime() / 1000; }
- },
-
- /* USER MANAGEMENT FUNCTIONS */
-
- getUserForId: function(id) {
- return $.extend({}, this.options.users[this._getUserIndexFromId(id)]);
- },
-
- /**
- * return the user name for header
- */
- _getUserName: function(index) {
- var self = this;
- var options = this.options;
- var user = options.users[index];
- if ($.isFunction(options.getUserName)) {
- return options.getUserName(user, index, self.element);
- }
- else {
- return user;
- }
- },
- /**
- * return the user id for given index
- */
- _getUserIdFromIndex: function(index) {
- var self = this;
- var options = this.options;
- if ($.isFunction(options.getUserId)) {
- return options.getUserId(options.users[index], index, self.element);
- }
- return index;
- },
- /**
- * returns the associated user index for given ID
- */
- _getUserIndexFromId: function(id) {
- var self = this;
- var options = this.options;
- for (var i = 0; i < options.users.length; i++) {
- if (self._getUserIdFromIndex(i) == id) {
- return i;
- }
- }
- return 0;
- },
- /**
- * return the user ids for given calEvent.
- * default is calEvent.userId field.
- */
- _getEventUserId: function(calEvent) {
- var self = this;
- var options = this.options;
- if (options.showAsSeparateUsers && options.users && options.users.length) {
- if ($.isFunction(options.getEventUserId)) {
- return options.getEventUserId(calEvent, self.element);
- }
- return calEvent.userId;
- }
- return [];
- },
- /**
- * sets the event user id on given calEvent
- * default is calEvent.userId field.
- */
- _setEventUserId: function(calEvent, userId) {
- var self = this;
- var options = this.options;
- if ($.isFunction(options.setEventUserId)) {
- return options.setEventUserId(userId, calEvent, self.element);
- }
- calEvent.userId = userId;
- return calEvent;
- },
- /**
- * return the user ids for given freeBusy.
- * default is freeBusy.userId field.
- */
- _getFreeBusyUserId: function(freeBusy) {
- var self = this;
- var options = this.options;
- if ($.isFunction(options.getFreeBusyUserId)) {
- return options.getFreeBusyUserId(freeBusy.getOption(), self.element);
- }
- return freeBusy.getOption('userId');
- },
-
- /* FREEBUSY MANAGEMENT */
-
- /**
- * ckean the free busy managers and remove all the freeBusy
- */
- _clearFreeBusys: function() {
- if (this.options.displayFreeBusys) {
- var self = this,
- options = this.options,
- $freeBusyPlaceholders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy');
- $freeBusyPlaceholders.each(function() {
- $(this).data('wcFreeBusyManager', new FreeBusyManager({
- start: self._cloneDate($(this).data('startDate')),
- end: self._cloneDate($(this).data('endDate')),
- defaultFreeBusy: options.defaultFreeBusy || {}
- }));
- });
- self.element.find('.wc-grid-row-freebusy .wc-freebusy').remove();
- }
- },
- /**
- * retrieve placeholders for given freebusy
- */
- _findWeekDaysForFreeBusy: function(freeBusy, $weekDays) {
- var $returnWeekDays,
- options = this.options,
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- self = this,
- userList = self._getFreeBusyUserId(freeBusy);
- if (!$.isArray(userList)) {
- userList = userList != 'undefined' ? [userList] : [];
- }
- if (!$weekDays) {
- $weekDays = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy');
- }
- $weekDays.each(function() {
- var manager = $(this).data('wcFreeBusyManager'),
- has_overlap = manager.isWithin(freeBusy.getStart()) ||
- manager.isWithin(freeBusy.getEnd()) ||
- freeBusy.isWithin(manager.getStart()) ||
- freeBusy.isWithin(manager.getEnd()),
- userId = $(this).data('wcUserId');
- if (has_overlap && (!showAsSeparatedUser || ($.inArray(userId, userList) != -1))) {
- $returnWeekDays = $returnWeekDays ? $returnWeekDays.add($(this)) : $(this);
- }
- });
- return $returnWeekDays;
- },
-
- /**
- * used to render all freeBusys
- */
- _renderFreeBusys: function(freeBusys) {
- if (this.options.displayFreeBusys) {
- var self = this,
- $freeBusyPlaceholders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
- freebusysToRender;
- //insert freebusys to dedicated placeholders freebusy managers
- if ($.isArray(freeBusys)) {
- freebusysToRender = self._cleanFreeBusys(freeBusys);
- } else if (freeBusys.freebusys) {
- freebusysToRender = self._cleanFreeBusys(freeBusys.freebusys);
- }
- else {
- freebusysToRender = [];
- }
-
- $.each(freebusysToRender, function(index, freebusy) {
- var $placeholders = self._findWeekDaysForFreeBusy(freebusy, $freeBusyPlaceholders);
- if ($placeholders) {
- $placeholders.each(function() {
- var manager = $(this).data('wcFreeBusyManager');
- manager.insertFreeBusy(new FreeBusy(freebusy.getOption()));
- $(this).data('wcFreeBusyManager', manager);
- });
- }
- });
-
- //now display freebusys on place holders
- self._refreshFreeBusys($freeBusyPlaceholders);
- }
- },
- /**
- * refresh freebusys for given placeholders
- */
- _refreshFreeBusys: function($freeBusyPlaceholders) {
- if (this.options.displayFreeBusys && $freeBusyPlaceholders) {
- var self = this,
- options = this.options,
- start = (options.businessHours.limitDisplay ? options.businessHours.start : 0),
- end = (options.businessHours.limitDisplay ? options.businessHours.end : 24);
-
- $freeBusyPlaceholders.each(function() {
- var $placehoder = $(this);
- var s = self._cloneDate($placehoder.data('startDate')),
- e = self._cloneDate(s);
- s.setHours(start);
- e.setHours(end);
- $placehoder.find('.wc-freebusy').remove();
- $.each($placehoder.data('wcFreeBusyManager').getFreeBusys(s, e), function() {
- self._renderFreeBusy(this, $placehoder);
- });
- });
- }
- },
- /**
- * render a freebusy item on dedicated placeholders
- */
- _renderFreeBusy: function(freeBusy, $freeBusyPlaceholder) {
- if (this.options.displayFreeBusys) {
- var self = this,
- options = this.options,
- freeBusyHtml = '<div class="wc-freebusy"></div>';
-
- var $fb = $(freeBusyHtml);
- $fb.data('wcFreeBusy', new FreeBusy(freeBusy.getOption()));
- this._positionFreeBusy($freeBusyPlaceholder, $fb);
- $fb = options.freeBusyRender(freeBusy.getOption(), $fb, self.element);
- if ($fb) {
- $fb.appendTo($freeBusyPlaceholder);
- }
- }
- },
- /*
- * Position the freebusy element within the weekday based on it's start / end dates.
- */
- _positionFreeBusy: function($placeholder, $freeBusy) {
- var options = this.options;
- var freeBusy = $freeBusy.data('wcFreeBusy');
- var pxPerMillis = $placeholder.height() / options.millisToDisplay;
- var firstHourDisplayed = options.businessHours.limitDisplay ? options.businessHours.start : 0;
- var startMillis = freeBusy.getStart().getTime() - new Date(freeBusy.getStart().getFullYear(), freeBusy.getStart().getMonth(), freeBusy.getStart().getDate(), firstHourDisplayed).getTime();
- var eventMillis = freeBusy.getEnd().getTime() - freeBusy.getStart().getTime();
- var pxTop = pxPerMillis * startMillis;
- var pxHeight = pxPerMillis * eventMillis;
- $freeBusy.css({top: pxTop, height: pxHeight});
- },
- /*
- * Clean freebusys to ensure correct format
- */
- _cleanFreeBusys: function(freebusys) {
- var self = this,
- freeBusyToReturn = [];
- if (!$.isArray(freebusys)) {
- var freebusys = [freebusys];
- }
- $.each(freebusys, function(i, freebusy) {
- if (!freebusy) return;
- freeBusyToReturn.push(new FreeBusy(self._cleanFreeBusy(freebusy)));
- });
- return freeBusyToReturn;
- },
-
- /*
- * Clean specific freebusy
- */
- _cleanFreeBusy: function(freebusy) {
- if (freebusy.date) {
- freebusy.start = freebusy.date;
- }
- freebusy.start = this._cleanDate(freebusy.start);
- freebusy.end = this._cleanDate(freebusy.end);
- return freebusy;
- },
-
- /**
- * retrives the first freebusy manager matching demand.
- */
- getFreeBusyManagersFor: function(date, users) {
- var calEvent = {
- start: date,
- end: date
- };
- this._setEventUserId(calEvent, users);
- return this.getFreeBusyManagerForEvent(calEvent);
- },
- /**
- * retrives the first freebusy manager for given event.
- */
- getFreeBusyManagerForEvent: function(newCalEvent) {
- var self = this,
- options = this.options,
- freeBusyManager;
- if (options.displayFreeBusys) {
- var $freeBusyPlaceHoders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
- freeBusy = new FreeBusy({start: newCalEvent.start, end: newCalEvent.end}),
- showAsSeparatedUser = options.showAsSeparateUsers && options.users && options.users.length,
- userId = showAsSeparatedUser ? self._getEventUserId(newCalEvent) : null;
- if (!$.isArray(userId)) {
- userId = [userId];
- }
- $freeBusyPlaceHoders.each(function() {
- var manager = $(this).data('wcFreeBusyManager'),
- has_overlap = manager.isWithin(freeBusy.getEnd()) ||
- manager.isWithin(freeBusy.getEnd()) ||
- freeBusy.isWithin(manager.getStart()) ||
- freeBusy.isWithin(manager.getEnd());
- if (has_overlap && (!showAsSeparatedUser || $.inArray($(this).data('wcUserId'), userId) != -1)) {
- freeBusyManager = $(this).data('wcFreeBusyManager');
- return false;
- }
- });
- }
- return freeBusyManager;
- },
- /**
- * appends the freebusys to replace the old ones.
- * @param {array|object} freeBusys freebusy(s) to apply.
- */
- updateFreeBusy: function(freeBusys) {
- var self = this,
- options = this.options;
- if (options.displayFreeBusys) {
- var $toRender,
- $freeBusyPlaceHoders = self.element.find('.wc-grid-row-freebusy .wc-column-freebusy'),
- _freeBusys = self._cleanFreeBusys(freeBusys);
-
- $.each(_freeBusys, function(index, _freeBusy) {
-
- var $weekdays = self._findWeekDaysForFreeBusy(_freeBusy, $freeBusyPlaceHoders);
- //if freebusy has a placeholder
- if ($weekdays && $weekdays.length) {
- $weekdays.each(function(index, day) {
- var manager = $(day).data('wcFreeBusyManager');
- manager.insertFreeBusy(_freeBusy);
- $(day).data('wcFreeBusyManager', manager);
- });
- $toRender = $toRender ? $toRender.add($weekdays) : $weekdays;
- }
- });
- self._refreshFreeBusys($toRender);
- }
- },
-
- /* NEW OPTIONS MANAGEMENT */
-
- /**
- * checks wether or not the calendar should be displayed starting on first day of week
- */
- _startOnFirstDayOfWeek: function() {
- return jQuery.isFunction(this.options.startOnFirstDayOfWeek) ? this.options.startOnFirstDayOfWeek(this.element) : this.options.startOnFirstDayOfWeek;
- },
-
- /**
- * finds out the current scroll to apply it when changing the view
- */
- _getCurrentScrollHour: function() {
- var self = this;
- var options = this.options;
- var $scrollable = this.element.find('.wc-scrollable-grid');
- var scroll = $scrollable.scrollTop();
- if (self.options.businessHours.limitDisplay) {
- scroll = scroll + options.businessHours.start * options.timeslotHeight * options.timeslotsPerHour;
- }
- return Math.round(scroll / (options.timeslotHeight * options.timeslotsPerHour)) + 1;
- },
- _getJsonOptions: function() {
- if ($.isFunction(this.options.jsonOptions)) {
- return $.extend({}, this.options.jsonOptions(this.element));
- }
- if ($.isPlainObject(this.options.jsonOptions)) {
- return $.extend({}, this.options.jsonOptions);
- }
- return {};
- },
- _getHeaderDate: function(date) {
- var options = this.options;
- if (options.getHeaderDate && $.isFunction(options.getHeaderDate))
- {
- return options.getHeaderDate(date, this.element);
- }
- var dayName = options.useShortDayNames ? options.shortDays[date.getDay()] : options.longDays[date.getDay()];
- return dayName + (options.headerSeparator) + this._formatDate(date, options.dateFormat);
- },
-
-
-
- /**
- * returns corrected date related to DST problem
- */
- _getDSTdayShift: function(date, shift) {
- var start = new Date(date.getFullYear(), date.getMonth(), date.getDate(), 0);
- var offset1 = start.getTimezoneOffset();
- var offset2 = date.getTimezoneOffset();
- if (offset1 == offset2)
- return date;
- shift = shift ? shift : 1;
- return new Date(date.getTime() - shift * (offset1 > offset2 ? -1 : 1) * (Math.max(offset1, offset2) - Math.min(offset1, offset2)) * 60000);
- },
- _needDSTdayShift: function(date1, date2) {
- return date1.getTimezoneOffset() != date2.getTimezoneOffset();
- }
-
-
-
- }; // end of widget function return
- })() //end of widget function closure execution
- ); // end of $.widget("ui.weekCalendar"...
-
- $.extend($.ui.weekCalendar, {
- version: '2.0-dev',
- updateLayoutOptions: {
- startOnFirstDayOfWeek: true,
- firstDayOfWeek: true,
- daysToShow: true,
- displayOddEven: true,
- timeFormat: true,
- dateFormat: true,
- use24Hour: true,
- useShortDayNames: true,
- businessHours: true,
- timeslotHeight: true,
- timeslotsPerHour: true,
- buttonText: true,
- height: true,
- shortMonths: true,
- longMonths: true,
- shortDays: true,
- longDays: true,
- textSize: true,
- users: true,
- showAsSeparateUsers: true,
- displayFreeBusys: true
- }
- });
-
- var MILLIS_IN_DAY = 86400000;
- var MILLIS_IN_WEEK = MILLIS_IN_DAY * 7;
-
- /* FREE BUSY MANAGERS */
- var FreeBusyProto = {
- getStart: function() {return this.getOption('start')},
- getEnd: function() {return this.getOption('end')},
- getOption: function() {
- if (!arguments.length) { return this.options }
- if (typeof(this.options[arguments[0]]) !== 'undefined') {
- return this.options[arguments[0]];
- }
- else if (typeof(arguments[1]) !== 'undefined') {
- return arguments[1];
- }
- return null;
- },
- setOption: function(key, value) {
- if (arguments.length == 1) {
- $.extend(this.options, arguments[0]);
- return this;
- }
- this.options[key] = value;
- return this;
- },
- isWithin: function(dateTime) {return Math.floor(dateTime.getTime() / 1000) >= Math.floor(this.getStart().getTime() / 1000) && Math.floor(dateTime.getTime() / 1000) < Math.floor(this.getEnd().getTime() / 1000)},
- isValid: function() {return this.getStart().getTime() < this.getEnd().getTime()}
- };
-
- /**
- * @constructor
- * single user freebusy manager.
- */
- var FreeBusy = function(options) {
- this.options = $.extend({}, options || {});
- };
- $.extend(FreeBusy.prototype, FreeBusyProto);
-
- var FreeBusyManager = function(options) {
- this.options = $.extend({
- defaultFreeBusy: {}
- }, options || {});
- this.freeBusys = [];
- this.freeBusys.push(new FreeBusy($.extend({
- start: this.getStart(),
- end: this.getEnd()
- }, this.options.defaultFreeBusy)));
- };
- $.extend(FreeBusyManager.prototype, FreeBusyProto, {
- /**
- * return matching freeBusys.
- * if you do not pass any argument, returns all freebusys.
- * if you only pass a start date, only matchinf freebusy will be returned.
- * if you pass 2 arguments, then all freebusys available within the time period will be returned
- * @param {Date} start [optionnal] if you do not pass end date, will return the freeBusy within which this date falls.
- * @param {Date} end [optionnal] the date where to stop the search.
- * @return {Array} an array of FreeBusy matching arguments.
- */
- getFreeBusys: function() {
- switch (arguments.length) {
- case 0:
- return this.freeBusys;
- case 1:
- var freeBusy = [];
- var start = arguments[0];
- if (!this.isWithin(start)) {
- return freeBusy;
- }
- $.each(this.freeBusys, function() {
- if (this.isWithin(start)) {
- freeBusy.push(this);
- }
- if (Math.floor(this.getEnd().getTime() / 1000) > Math.floor(start.getTime() / 1000)) {
- return false;
- }
- });
- return freeBusy;
- default:
- //we assume only 2 first args are revealants
- var freeBusy = [];
- var start = arguments[0], end = arguments[1];
- var tmpFreeBusy = new FreeBusy({start: start, end: end});
- if (end.getTime() < start.getTime() || this.getStart().getTime() > end.getTime() || this.getEnd().getTime() < start.getTime()) {
- return freeBusy;
- }
- $.each(this.freeBusys, function() {
- if (this.getStart().getTime() >= end.getTime()) {
- return false;
- }
- if (tmpFreeBusy.isWithin(this.getStart()) && tmpFreeBusy.isWithin(this.getEnd())) {
- freeBusy.push(this);
- }
- else if (this.isWithin(tmpFreeBusy.getStart()) && this.isWithin(tmpFreeBusy.getEnd())) {
- var _f = new FreeBusy(this.getOption());
- _f.setOption('end', tmpFreeBusy.getEnd());
- _f.setOption('start', tmpFreeBusy.getStart());
- freeBusy.push(_f);
- }
- else if (this.isWithin(tmpFreeBusy.getStart()) && this.getStart().getTime() < start.getTime()) {
- var _f = new FreeBusy(this.getOption());
- _f.setOption('start', tmpFreeBusy.getStart());
- freeBusy.push(_f);
- }
- else if (this.isWithin(tmpFreeBusy.getEnd()) && this.getEnd().getTime() > end.getTime()) {
- var _f = new FreeBusy(this.getOption());
- _f.setOption('end', tmpFreeBusy.getEnd());
- freeBusy.push(_f);
- }
- });
- return freeBusy;
- }
- },
- insertFreeBusy: function(freeBusy) {
- var freeBusy = new FreeBusy(freeBusy.getOption());
- //first, if inserted freebusy is bigger than manager
- if (freeBusy.getStart().getTime() < this.getStart().getTime()) {
- freeBusy.setOption('start', this.getStart());
- }
- if (freeBusy.getEnd().getTime() > this.getEnd().getTime()) {
- freeBusy.setOption('end', this.getEnd());
- }
- var start = freeBusy.getStart(), end = freeBusy.getEnd(),
- startIndex = 0, endIndex = this.freeBusys.length - 1,
- newFreeBusys = [];
- var pushNewFreeBusy = function(_f) {if (_f.isValid()) newFreeBusys.push(_f);};
-
- $.each(this.freeBusys, function(index) {
- //within the loop, we have following vars:
- // curFreeBusyItem: the current iteration freeBusy, part of manager freeBusys list
- // start: the insterted freeBusy start
- // end: the inserted freebusy end
- var curFreeBusyItem = this;
- if (curFreeBusyItem.isWithin(start) && curFreeBusyItem.isWithin(end)) {
- /*
- we are in case where inserted freebusy fits in curFreeBusyItem:
- curFreeBusyItem: *-----------------------------*
- freeBusy: *-------------*
- obviously, start and end indexes are this item.
- */
- startIndex = index;
- endIndex = index;
- if (start.getTime() == curFreeBusyItem.getStart().getTime() && end.getTime() == curFreeBusyItem.getEnd().getTime()) {
- /*
- in this case, inserted freebusy is exactly curFreeBusyItem:
- curFreeBusyItem: *-----------------------------*
- freeBusy: *-----------------------------*
-
- just replace curFreeBusyItem with freeBusy.
- */
- var _f1 = new FreeBusy(freeBusy.getOption());
- pushNewFreeBusy(_f1);
- }
- else if (start.getTime() == curFreeBusyItem.getStart().getTime()) {
- /*
- in this case inserted freebusy starts with curFreeBusyItem:
- curFreeBusyItem: *-----------------------------*
- freeBusy: *--------------*
-
- just replace curFreeBusyItem with freeBusy AND the rest.
- */
- var _f1 = new FreeBusy(freeBusy.getOption());
- var _f2 = new FreeBusy(curFreeBusyItem.getOption());
- _f2.setOption('start', end);
- pushNewFreeBusy(_f1);
- pushNewFreeBusy(_f2);
- }
- else if (end.getTime() == curFreeBusyItem.getEnd().getTime()) {
- /*
- in this case inserted freebusy ends with curFreeBusyItem:
- curFreeBusyItem: *-----------------------------*
- freeBusy: *--------------*
-
- just replace curFreeBusyItem with before part AND freeBusy.
- */
- var _f1 = new FreeBusy(curFreeBusyItem.getOption());
- _f1.setOption('end', start);
- var _f2 = new FreeBusy(freeBusy.getOption());
- pushNewFreeBusy(_f1);
- pushNewFreeBusy(_f2);
- }
- else {
- /*
- in this case inserted freebusy is within curFreeBusyItem:
- curFreeBusyItem: *-----------------------------*
- freeBusy: *--------------*
-
- just replace curFreeBusyItem with before part AND freeBusy AND the rest.
- */
- var _f1 = new FreeBusy(curFreeBusyItem.getOption());
- var _f2 = new FreeBusy(freeBusy.getOption());
- var _f3 = new FreeBusy(curFreeBusyItem.getOption());
- _f1.setOption('end', start);
- _f3.setOption('start', end);
- pushNewFreeBusy(_f1);
- pushNewFreeBusy(_f2);
- pushNewFreeBusy(_f3);
- }
- /*
- as work is done, no need to go further.
- return false
- */
- return false;
- }
- else if (curFreeBusyItem.isWithin(start) && curFreeBusyItem.getEnd().getTime() != start.getTime()) {
- /*
- in this case, inserted freebusy starts within curFreeBusyItem:
- curFreeBusyItem: *----------*
- freeBusy: *-------------------*
-
- set start index AND insert before part, we'll insert freebusy later
- */
- if (curFreeBusyItem.getStart().getTime() != start.getTime()) {
- var _f1 = new FreeBusy(curFreeBusyItem.getOption());
- _f1.setOption('end', start);
- pushNewFreeBusy(_f1);
- }
- startIndex = index;
- }
- else if (curFreeBusyItem.isWithin(end) && curFreeBusyItem.getStart().getTime() != end.getTime()) {
- /*
- in this case, inserted freebusy starts within curFreeBusyItem:
- curFreeBusyItem: *----------*
- freeBusy: *-------------------*
-
- set end index AND insert freebusy AND insert after part if needed
- */
- pushNewFreeBusy(new FreeBusy(freeBusy.getOption()));
- if (end.getTime() < curFreeBusyItem.getEnd().getTime()) {
- var _f1 = new FreeBusy(curFreeBusyItem.getOption());
- _f1.setOption('start', end);
- pushNewFreeBusy(_f1);
- }
- endIndex = index;
- return false;
- }
- });
- //now compute arguments
- var tmpFB = this.freeBusys;
- this.freeBusys = [];
-
- if (startIndex) {
- this.freeBusys = this.freeBusys.concat(tmpFB.slice(0, startIndex));
- }
- this.freeBusys = this.freeBusys.concat(newFreeBusys);
- if (endIndex < tmpFB.length) {
- this.freeBusys = this.freeBusys.concat(tmpFB.slice(endIndex + 1));
- }
-/* if(start.getDate() == 1){
- console.info('insert from '+freeBusy.getStart() +' to '+freeBusy.getEnd());
- console.log('index from '+ startIndex + ' to ' + endIndex);
- var str = [];
- $.each(tmpFB, function(i){str.push(i + ": " + this.getStart().getHours() + ' > ' + this.getEnd().getHours() + ' ' + (this.getOption('free') ? 'free' : 'busy'))});
- console.log(str.join('\n'));
-
- console.log('insert');
- var str = [];
- $.each(newFreeBusys, function(i){str.push(this.getStart().getHours() + ' > ' + this.getEnd().getHours())});
- console.log(str.join(', '));
-
- console.log('results');
- var str = [];
- $.each(this.freeBusys, function(i){str.push(i + ": " + this.getStart().getHours() + ' > ' + this.getEnd().getHours() + ' ' + (this.getOption('free') ? 'free' :'busy'))});
- console.log(str.join('\n'));
- }*/
- return this;
- }
- });
-})(jQuery);
-
diff --git a/modules-available/locationinfo/frontend/panel.html b/modules-available/locationinfo/frontend/panel.html
deleted file mode 100644
index dd5fc25d..00000000
--- a/modules-available/locationinfo/frontend/panel.html
+++ /dev/null
@@ -1,700 +0,0 @@
-<!DOCTYPE html>
-<html lang="de">
-<meta name="viewport" content="width=device-width, initial-scale=1.0" charset="utf-8">
-<head>
- <script type='text/javascript' src='../../../script/jquery.js'></script>
-
- <style type='text/css'>
- body {
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- background-color: lightgrey;
- color: black;
- }
-
- #main {
- display: flex;
- flex-wrap: wrap;
- }
-
- .outermost {
- font-size: 16pt;
- }
-
- .parent, .child {
- padding: 5px;
- float: left;
- background-color: white;
- font-size: 90%;
- min-height: 7em;
- flex-grow: 1;
- align-items: stretch;
- }
-
- .parent .parent, .parent .child {
- min-height: 5em;
- }
-
- .border {
- flex-grow: 1;
- display: inline-flex;
- align-items: stretch;
- padding: 5px;
- }
-
- .courseFont {
- padding: 2px;
- font-size: 90%;
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-weight: bold;
- overflow: hidden;
- }
-
- .headerFont {
- font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-weight: bold;
- border: 0px;
- border-bottom: 1px;
- margin-bottom: 1px;
- border-color: grey;
- border-style: solid;
- }
-
- .pc-idle, .pc-occupied, .pc-off, .pc-broken {
- padding: 2px 1px;
- text-align: center;
- font-size: 90%;
- font-weight: 800;
- overflow: hidden;
- transition: width 2s;
- width: 25%;
- }
-
- .pc-idle {
- background-color: green;
- }
-
- .pc-occupied {
- background-color: red;
- border-radius: 3px 0px 0px 3px;
- }
-
- .pc-off {
- background-color: darkgrey;
- }
-
- .pc-broken {
- background-color: black;
- color: white;
- border-radius: 0px 3px 3px 0px;
- }
-
- .pc-state-wrapper {
- display: flex;
- }
-
- .paperEffect {
- margin: 0 auto;
- background-color: #fff;
- box-shadow: 0 0 0.2vmin rgba(0, 0, 0, 0.4), inset 0 0 1vmin rgba(0, 0, 0, 0.1);
- border-radius: 1px;
- }
-
-
- </style>
- <script type='text/javascript'>
-
- var rooms = {};
- var startdate;
- var roomidsString = "";
-
-
- $(document).ready(function () {
- //temp
- SetUpDate(new Date());
- init();
- });
-
- function init() {
- var ids = getUrlParameter("id");
- $.getJSON("../../../api.php?do=locationinfo&action=locationtree&id=" + ids, function (result) {
- generateLayout(result);
-
- setTimeout(update, 1000);
- });
-
- }
-
- function SetUpDate(d) {
- startdate = d.getTime() - new Date().getTime();
- }
-
- function MyDate() {
- return new Date(startdate + new Date().getTime());
- }
-
- function generateLayout(json) {
- for (var i = 0; i < json.length; i++) {
- console.log('Outermost for ' + json[i].locationid);
- var el = generateObject(json[i], ($("#main")), true);
- }
- }
-
- /**
- * generates the divs, decidecs if parent or child
- * @param json Room tree json
- * @param myParent parent div
- * @param outermost if the object is a root node
- * @returns generated div
- */
- function generateObject(json, myParent, outermost) {
- var obj;
- if (!json.children || json.children.length == 0) {
- obj = generateChild(myParent, json.locationid, json.locationname, outermost);
- } else {
- obj = generateParent(myParent, json.locationid, json.locationname, outermost);
- for (var i = 0; i < json.children.length; i++) {
- generateObject(json.children[i], $("#parent_" + json.locationid), false);
- }
- }
- return obj;
-
- }
-
- /**
- * 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;
- }
-
-
- const ROOMUPDATE_MS = 2*60*1000;
- const CALUPDATE_MS = 20*60*1000;
-
- function update() {
- var calendarUpdateIds = "";
- var rommUpdateIds = "";
- var count = 0;
- var nextUpdate = 15000;
- for (var property in rooms) {
- if (rooms[property].lastCalendarUpdate === null || rooms[property].lastCalendarUpdate + CALUPDATE_MS < MyDate().getTime()) {
- calendarUpdateIds = addIdToUpdateList(calendarUpdateIds, rooms[property].id);
- count++;
- rooms[property].lastCalendarUpdate = MyDate().getTime();
- }
- if (rooms[property].lastRoomUpdate === null || rooms[property].lastRoomUpdate + ROOMUPDATE_MS < MyDate().getTime()) {
- rommUpdateIds = addIdToUpdateList(rommUpdateIds, rooms[property].id);
- count++;
- rooms[property].lastRoomUpdate = MyDate().getTime();
- }
- if (count > 7) break;
- }
- if (calendarUpdateIds !== "") {
- queryCalendars(calendarUpdateIds);
- nextUpdate = 1000;
- }
- if (rommUpdateIds !== "") {
- queryRooms(rommUpdateIds);
- nextUpdate = 1000;
- }
- for (var property in rooms) {
- upDateRoomState(rooms[property]);
- }
- setTimeout(update, nextUpdate);
- }
-
-
- function UpdateTimeTables(json) {
- var l = json.length;
- for (var i = 0; i < l; i++) {
- rooms[json[i].id].timetable = json[i].calendar;
- for (var property in rooms[json[i].id].timetable) {
- rooms[json[i].id].timetable[property].start = new Date(rooms[json[i].id].timetable[property].start);
- rooms[json[i].id].timetable[property].end = new Date(rooms[json[i].id].timetable[property].end);
- }
- ComputeCurrentState(rooms[json[i].id]);
- }
- }
-
- /**
- * 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=pcstates&id=" + ids,
- dataType: 'json',
- cache: false,
- timeout: 30000,
- success: function (result) {
- var l = result.length;
- if (result[0] == null) {
- console.log("Error: Backend reported null back for RoomUpdate, this might happend if the room isn't" +
- "configurated.");
- return;
- }
- updatePcStates(result);
- }, error: function () {
-
- }
- })
- }
-
- /**
- * Updates a room visualy
- * @param room A room to update
- */
- function upDateRoomState(room) {
- if (room === undefined || room.lastRoomUpdate === null) {
- return;
- }
-
- var state = room.getState();
-
- if (state.state == "CalendarEvent") {
- updateCourseText(room.id, state.titel);
- updateCoursTimer(room.id, GetTimeDiferenceAsString(state.end, MyDate()));
- } else if (state.state == "Free") {
- updateCourseText(room.id, "Frei");
- updateCoursTimer(room.id, GetTimeDiferenceAsString(state.end, MyDate()));
- } else if (state.state == "FreeNoEnd") {
- updateCourseText(room.id, "Frei");
- updateCoursTimer(room.id, "");
- }
- else if (state.state == "closed") {
- updateCourseText(room.id, "Geschlossen");
- updateCoursTimer(room.id, "");
- }
-
- }
-
- /**
- * Updates for all rooms the PC's states
- * @param json Json with information about the PC's states
- */
- function updatePcStates(json) {
- var l = json.length;
- for (var i = 0; i < l; i++) {
- updateRoomUsage(json[i].id, json[i].idle, json[i].occupied, json[i].off, json[i].broken)
- }
-
- }
- /**
- * 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) {
- var room = {
- id: id,
- name: name,
- timetable: null,
- currentEvent: null,
- nextEventEnd: null,
- timeTilFree: null,
- state: null,
- openingTimes: null,
- lastCalendarUpdate: null,
- lastRoomUpdate: null,
- getState: function () {
- if (!this.state) {
- ComputeCurrentState(this);
- return this.state;
- }
- if (this.state.end != "") {
- if (this.state.end < new MyDate()) {
- ComputeCurrentState(this);
- }
- }
- return this.state;
- }
-
-
- };
-
- rooms[id] = room;
-
- if (roomidsString == "") {
- roomidsString = id;
- } else {
- roomidsString = roomidsString + "," + id;
- }
- }
-
-
- /**
- * computes state of a room, states are:
- * closed, FreeNoEnd, Free, ClaendarEvent.
- * @param Room Object
- */
- function ComputeCurrentState(room) {
- if (room.lastRoomUpdate === null) {
- room.state = {state: 'unknown'};
- return;
- }
- if (!IsOpenNow(room)) {
- room.state = {state: "closed", end: GetNextOpening(room), titel: "", 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: "", titel: "", next: ""};
- return;
- }
-
- // no event so closing is next
- if (event == null) {
- room.state = {state: "Free", end: closing, titel: "", next: "closing"};
- return;
- }
-
- // event is at the moment
- if ((closing == null || event.start.getTime() < closing.getTime()) && event.start.getTime() < new MyDate()) {
- room.state = {state: "CalendarEvent", end: event.end, titel: event.title, next: ""};
- return;
- }
-
- // no closing so event is next
- if (closing == null) {
- room.state = {state: "Free", end: event.start, titel: "", next: "event"};
- return;
- }
-
- // event sooner then closing
- if (event.start.getTime() < closing) {
- room.state = {state: "Free", end: event.start, titel: "", next: "event"};
- } else if (event.start.getTime() > closing) {
- room.state = {state: "Free", end: closing, titel: "", next: "closing"};
- }
- }
- /**
- * checks if a room is open
- * @param room Room object
- * @returns bool for open or not
- */
- function IsOpenNow(room) {
- var now = new MyDate();
- if (room.openingTimes == null) {
-
- // changes from falls needs testing
- return true;
- }
- var tmp = room.openingTimes[now.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 < now && closeDate > now) {
- return true;
- }
- }
- return false;
- }
-
- /**
- * 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) {
- if (json == null) {
- return;
- }
- var event;
- var now = new MyDate();
- 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;
- }
-
- /**
- * 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))) {
- if (bestdate == null || bestdate > openDate) {
- bestdate = openDate;
- }
- }
- }
- }
- }
- offset++;
- day++;
- if (day > 6) {
- day = 0;
- }
- }
- return bestdate;
- }
-
- /**
- * 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++) {
- //Test
- if (room.openingTimes === null) {
- return null;
- }
- 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);
- if (closeDate > now) {
- if (!IsOpen(new Date(closeDate.getTime() + 60000))) {
- if (bestdate == null || bestdate > closeDate) {
- bestdate = closeDate;
- }
- }
- }
- }
- }
- offset++;
- day++;
- if (day > 6) {
- day = 0;
- }
- }
- return bestdate;
- }
-
- /**
- * Updates the Course Text of a child
- * @param id of the child
- * @param idle PC's on
- * @param occupied PC's used
- * @param off PC's that are off
- * @param broken PC's that are broken
- */
- function updateRoomUsage(id, idle, occupied, off, broken) {
- if (idle == 0 && occupied == 0 && off == 0) {
- $('#parent_' + id).parent().hide();
- return;
- }
- $('#parent_' + id).parent().show();
- var total = parseInt(idle) + parseInt(occupied) + parseInt(off) + parseInt(broken);
- $("#pc_Idle_" + id).text(idle).width((idle / total) * 100 + '%');
- $("#pc_Occupied_" + id).text(occupied).width((occupied / total) * 100 + '%');
- $("#pc_Off_" + id).text(off).width((off / total) * 100 + '%');
- $("#pc_Broken_" + id).text(broken).width((broken / total) * 100 + '%');
- }
-
- /**
- * Updates the Course Text of a child
- * @param id of the child
- * @param text Text
- */
- function updateCourseText(id, text) {
- $("#div_course" + id).text(text);
- }
-
- /**
- * Updates the Course time of a child
- * @param id of the child
- * @param time Time value
- */
- function updateCoursTimer(id, time) {
- $("#div_Time_" + id).text(time);
- }
-
- /**
- * generates a Div, used for a child node
- * @param target Div it should be inserted
- * @param id ID of the Object it represents
- * @param name Name of the Object it represents
- * @param outermost if the object is a root node
- * @returns generated div
- */
- function generateChild(target, id, name, outermost) {
-
- var c = "";
- if (outermost) {
- c = "outermost";
- }
-
- var text = "<div class='border " + c + "'>" +
- "<div class='child paperEffect' id='parent_" + id + "'>" +
- "<div class='headerFont'>" + name + "</div>" +
- "<div class='pc-state-wrapper'>" +
- "<div id = 'pc_Occupied_" + id + "' class='pc-occupied'>?</div>" +
- "<div id = 'pc_Idle_" + id + "' class='pc-idle'>?</div>" +
- "<div id = 'pc_Off_" + id + "' class='pc-off'>?</div>" +
- "<div id = 'pc_Broken_" + id + "' class='pc-broken'>?</div>" +
- "</div>" +
- "<div class='aroundCourse'>" +
- "<div id = 'div_course" + id + "'class='courseFont'>?</div>" +
- "<div id = 'div_Time_" + id + "'class='courseFont'></div></div></div></div>";
- var obj = $(target).append(text);
- addRoom(id, name);
- return obj
-
- }
-
- /**
- * generates a Div, used for a parent node
- * @param target Div it should be inserted
- * @param id ID of the Object it represents
- * @param name Name of the Object it represents
- * @param outermost if the object is a root node
- * @returns generated div
- */
- function generateParent(target, id, name, outermost) {
- var c = "";
- if (outermost) {
- c = "outermost";
- }
-
- var text = "<div class='border " + c + "'>" +
- "<div class='parent paperEffect'>" +
- "<div class='headerFont'>" + name + "</div>" +
- "<div id='parent_" + id + "'></div>" +
- "</div></div>";
- return $(target).append(text);
- }
-
- /**
- * 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];
- }
- }
- };
-
-
- /**
- * 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) {
- UpdateTimeTables(result);
-
-
- }, error: function () {
-
- }
- });
- }
-
-
- /**
- * used for countdown
- * computes the time difference between 2 Date objects
- * @param a Date Object
- * @param b Date Object
- * @returns time string
- */
- function GetTimeDiferenceAsString(a, b) {
- 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 "";
- }
- return hours + ":" + minutes + ":" + seconds;
- }
- </script>
-</head>
-<body>
-<div id="main"></div>
-</body>
-</html>