diff options
author | Simon Rettberg | 2017-07-25 19:02:01 +0200 |
---|---|---|
committer | Simon Rettberg | 2017-07-25 19:02:01 +0200 |
commit | bb53f6136e2950f3d656728be469d318a0d9f606 (patch) | |
tree | 4e8648ff6fde4b8496eba6e19afdfd7bf542c241 /modules-available/locationinfo/frontend | |
parent | [locationinfo] Better error handling in hisinone backend (diff) | |
download | slx-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')
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> |