summaryrefslogtreecommitdiffstats
path: root/modules-available/locations
diff options
context:
space:
mode:
authorChristian Hofmaier2020-09-08 20:56:19 +0200
committerChristian Hofmaier2020-09-08 20:56:19 +0200
commitc535ce5e2f78f5223662c97543f718334abf2a35 (patch)
tree728fe2fcfe16e33757daeb086ba905c2f834118e /modules-available/locations
parent[locationinfo] Fix overriding "show hostnames" not being saved (diff)
downloadslx-admin-c535ce5e2f78f5223662c97543f718334abf2a35.tar.gz
slx-admin-c535ce5e2f78f5223662c97543f718334abf2a35.tar.xz
slx-admin-c535ce5e2f78f5223662c97543f718334abf2a35.zip
[locations] Migrate openingtimes from infoscreen to locations module
- move openingtimes from infoscreen db to locations db - read-only openingtimes in infoscreen
Diffstat (limited to 'modules-available/locations')
-rw-r--r--modules-available/locations/clientscript.js153
-rw-r--r--modules-available/locations/config.json8
-rw-r--r--modules-available/locations/install.inc.php22
-rw-r--r--modules-available/locations/lang/de/template-tags.json14
-rw-r--r--modules-available/locations/lang/en/template-tags.json14
-rw-r--r--modules-available/locations/pages/details.inc.php177
-rw-r--r--modules-available/locations/templates/ajax-opening-location.html173
-rw-r--r--modules-available/locations/templates/location-subnets.html44
-rw-r--r--modules-available/locations/templates/locations.html5
9 files changed, 605 insertions, 5 deletions
diff --git a/modules-available/locations/clientscript.js b/modules-available/locations/clientscript.js
new file mode 100644
index 00000000..25c255fb
--- /dev/null
+++ b/modules-available/locations/clientscript.js
@@ -0,0 +1,153 @@
+/*
+ * Generic helpers.
+ */
+
+/**
+ * Initialize timepicker on given element.
+ */
+function setTimepicker($e) {
+ $e.timepicker({
+ minuteStep: 15,
+ appendWidgetTo: 'body',
+ showSeconds: false,
+ showMeridian: false,
+ defaultTime: false
+ });
+}
+
+function getTime(str) {
+ if (!str) return false;
+ str = str.split(':');
+ if (str.length !== 2) return false;
+ var h = parseInt(str[0].replace(/^0/, ''));
+ var m = parseInt(str[1].replace(/^0/, ''));
+ if (h < 0 || h > 23) return false;
+ if (m < 0 || m > 59) return false;
+ return h * 60 + m;
+}
+
+const allDays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
+
+/*
+ * Opening times related...
+ */
+
+var slxIdCounter = 0;
+
+/**
+ * Adds a new opening time to the table in expert mode.
+ */
+function newOpeningTime(vals) {
+ var $row = $('#expert-template').find('div.row').clone();
+ if (vals['days'] && Array.isArray(vals['days'])) {
+ for (var i = 0; i < allDays.length; ++i) {
+ $row.find('.i-' + allDays[i]).prop('checked', vals['days'].indexOf(allDays[i]) !== -1);
+ }
+ }
+ $row.find('input').each(function() {
+ var $inp = $(this);
+ if ($inp.length === 0) return;
+ slxIdCounter++;
+ $inp.prop('id', 'id-inp-' + slxIdCounter);
+ $inp.siblings('label').prop('for', 'id-inp-' + slxIdCounter);
+ });
+ $row.find('.i-openingtime').val(vals['openingtime']);
+ $row.find('.i-closingtime').val(vals['closingtime']);
+ $('#expert-table').append($row);
+ return $row;
+}
+
+/**
+ * Convert fields from simple mode view to entries in expert mode.
+ * @returns {Array}
+ */
+function simpleToExpert() {
+ var retval = [];
+ if ($('#week-open').val() || $('#week-close').val()) {
+ retval.push({
+ 'days': ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'],
+ 'openingtime': $('#week-open').val(),
+ 'closingtime': $('#week-close').val(),
+ 'tag': '#week'
+ });
+ }
+ if ($('#saturday-open').val() || $('#saturday-close').val()) {
+ retval.push({
+ 'days': ['Saturday'],
+ 'openingtime': $('#saturday-open').val(),
+ 'closingtime': $('#saturday-close').val(),
+ 'tag': '#saturday'
+ });
+ }
+ if ($('#sunday-open').val() || $('#sunday-close').val()) {
+ retval.push({
+ 'days': ['Sunday'],
+ 'openingtime': $('#sunday-open').val(),
+ 'closingtime': $('#sunday-close').val(),
+ 'tag': '#sunday'
+ });
+ }
+ return retval;
+}
+
+/**
+ * Triggered when the form is submitted
+ */
+function submitLocationSettings(event) {
+ var schedule, s, e;
+ var badFormat = false;
+ $('#settings-outer').find('.red-bg').removeClass('red-bg');
+ if ($('#week-open').length > 0) {
+ schedule = simpleToExpert();
+ for (var i = 0; i < schedule.length; ++i) {
+ s = getTime(schedule[i].openingtime);
+ e = getTime(schedule[i].closingtime);
+ if (s === false) {
+ $(schedule[i].tag + '-open').addClass('red-bg');
+ badFormat = true;
+ }
+ if (e === false || e <= s) {
+ $(schedule[i].tag + '-close').addClass('red-bg');
+ badFormat = true;
+ }
+ }
+ } else {
+ // Serialize
+ schedule = [];
+ $('#expert-table').find('.expert-row').each(function () {
+ var $t = $(this);
+ if ($t.find('.i-delete').is(':checked')) return; // Skip marked as delete
+ var entry = {
+ 'days': [],
+ 'openingtime': $t.find('.i-openingtime').val(),
+ 'closingtime': $t.find('.i-closingtime').val()
+ };
+ for (var i = 0; i < allDays.length; ++i) {
+ if ($t.find('.i-' + allDays[i]).is(':checked')) {
+ entry['days'].push(allDays[i]);
+ }
+ }
+ if (entry.openingtime.length === 0 && entry.closingtime.length === 0 && entry.days.length === 0) return; // Also ignore empty lines
+ s = getTime(entry.openingtime);
+ e = getTime(entry.closingtime);
+ if (s === false) {
+ $t.find('.i-openingtime').addClass('red-bg');
+ badFormat = true;
+ }
+ if (e === false || e <= s) {
+ $t.find('.i-closingtime').addClass('red-bg');
+ badFormat = true;
+ }
+ if (entry.days.length === 0) {
+ $t.find('.days-box').addClass('red-bg');
+ badFormat = true;
+ }
+ if (badFormat) return;
+ schedule.push(entry);
+ });
+ }
+ if (badFormat) {
+ event.preventDefault();
+ }
+ $('#json-openingtimes').val(JSON.stringify(schedule));
+} \ No newline at end of file
diff --git a/modules-available/locations/config.json b/modules-available/locations/config.json
index 110f8b67..ee2600f2 100644
--- a/modules-available/locations/config.json
+++ b/modules-available/locations/config.json
@@ -1,3 +1,9 @@
{
- "category": "main.content"
+ "category": "main.content",
+ "dependencies": [
+ "bootstrap_timepicker"
+ ],
+ "scripts": [
+ "clientscript.js"
+ ]
} \ No newline at end of file
diff --git a/modules-available/locations/install.inc.php b/modules-available/locations/install.inc.php
index d4e1b67b..31d53560 100644
--- a/modules-available/locations/install.inc.php
+++ b/modules-available/locations/install.inc.php
@@ -35,5 +35,27 @@ $res[] = tableAddConstraint('subnet', 'locationid', 'location', 'locationid',
$res[] = tableAddConstraint('setting_location', 'locationid', 'location', 'locationid',
'ON UPDATE CASCADE ON DELETE CASCADE');
+// Update
+
+// 2020-07-14 Add openingtime column to location table, then migrate data and delete the column from locationinfo
+
+if (!tableHasColumn('location', 'openingtime')) {
+ if (Database::exec("ALTER TABLE location ADD openingtime BLOB") === false) {
+ finalResponse(UPDATE_FAILED, 'Could not create openingtime column');
+ } else {
+ if (Module::get('locationinfo') !== false) {
+ if (Database::exec(
+ "UPDATE location, locationinfo_locationconfig
+ SET location.openingtime = locationinfo_locationconfig.openingtime
+ WHERE location.locationid = locationinfo_locationconfig.locationid") === false) {
+ finalResponse(UPDATE_FAILED, 'Could not migrate openingtime data from table to table');
+ }
+ if (Database::exec("ALTER TABLE locationinfo_locationconfig DROP COLUMN openingtime") === false) {
+ finalResponse(UPDATE_FAILED, 'Could not delete openingtime column');
+ }
+ }
+ }
+}
+
// Create response for browser
responseFromArray($res);
diff --git a/modules-available/locations/lang/de/template-tags.json b/modules-available/locations/lang/de/template-tags.json
index 2a03aa85..18176278 100644
--- a/modules-available/locations/lang/de/template-tags.json
+++ b/modules-available/locations/lang/de/template-tags.json
@@ -4,6 +4,8 @@
"lang_assignSubnetExplanation": "Rechner, die in einen der hier aufgef\u00fchrten Adressbereiche fallen, werden diesem Ort zugeschrieben und erhalten damit z.B. f\u00fcr diesen Raum angepasste Veranstaltungslisten.",
"lang_assignedSubnets": "Zugeordnete Subnetze bzw. IP-Bereiche",
"lang_bootMenu": "Bootmen\u00fc",
+ "lang_closingTime": "Schlie\u00dfungszeit",
+ "lang_day": "Tag",
"lang_deleteChildLocations": "Untergeordnete Orte ebenfalls l\u00f6schen",
"lang_deleteLocation": "Ort l\u00f6schen",
"lang_deleteSubnet": "Bereich l\u00f6schen",
@@ -11,6 +13,7 @@
"lang_editConfigVariables": "Konfig.-Variablen",
"lang_editRoomplan": "Raumplan bearbeiten",
"lang_endAddress": "Endadresse",
+ "lang_expertMode": "Experten Modus",
"lang_fixMachineAssign": "Zuweisungen anzeigen\/aufheben",
"lang_ip": "IP-Adresse",
"lang_listOfSubnets": "Liste der Subnetze",
@@ -29,17 +32,28 @@
"lang_matchingMachines": "Enthaltene Rechner",
"lang_mismatchHeading": "Rechner mit widerspr\u00fcchlicher Raumzuweisung",
"lang_mismatchIntroText": "Die hier aufgelisteten Rechner wurden mittels des Raumplaners im oben genannten Raum platziert. Ihrer IP-Adresse nach fallen diese jedoch in einen anderen Raum (durch die f\u00fcr diesen definierten IP-Ranges). Wenn Sie die entsprechenden Rechner hier markieren und auf \"Zur\u00fccksetzen\" klicken, werden die Rechner aus dem oben genannten Raumplan entfernt. Wenn Sie stattdessen auf \"Verschieben\" klicken, werden die Rechner mit ihrer aktuellen Position aus dem jetzigen Raum in den eigentlichen Raum (siehe letzte Spalte der Tabelle) verschoben.",
+ "lang_monTilFr": "Montag - Freitag",
"lang_moveMachines": "In durch Subnet zugeordneten Raum verschieben",
"lang_moveable": "Verschiebbar",
"lang_name": "Name",
"lang_numMachinesWithOverrides": "Anzahl Rechner, bei denen mindestens eine Konfigurationsvariable \u00fcberschrieben wird",
+ "lang_openingTime": "\u00d6ffnungszeit",
"lang_overridenVarsForLocation": "Anzahl Variablen, die an diesem Ort \u00fcberschrieben werden",
"lang_parentLocation": "\u00dcbergeordneter Ort",
"lang_referencingLectures": "Veranstaltungen",
"lang_resetMachines": "Raumzuweisung zur\u00fccksetzen",
+ "lang_saturday": "Samstag",
+ "lang_shortFriday": "Fr",
+ "lang_shortMonday": "Mo",
+ "lang_shortSaturday": "Sa",
+ "lang_shortSunday": "Su",
+ "lang_shortThursday": "Do",
+ "lang_shortTuesday": "Di",
+ "lang_shortWednesday": "Mi",
"lang_showRoomplan": "Raumplan anzeigen",
"lang_startAddress": "Startadresse",
"lang_subnet": "IP-Bereich",
+ "lang_sunday": "Sonntag",
"lang_sysConfig": "Lokalisierung",
"lang_thisListByLocation": "Orte",
"lang_thisListBySubnet": "Subnetze",
diff --git a/modules-available/locations/lang/en/template-tags.json b/modules-available/locations/lang/en/template-tags.json
index 3a79494c..c4fabdb0 100644
--- a/modules-available/locations/lang/en/template-tags.json
+++ b/modules-available/locations/lang/en/template-tags.json
@@ -4,6 +4,8 @@
"lang_assignSubnetExplanation": "Client machines which fall into an IP range listed below will be assigned to this location and will see an according lecture list (e.g. they will see lectures that are exclusively assigned to this location).",
"lang_assignedSubnets": "Assigned subnets \/ IP ranges",
"lang_bootMenu": "Boot menu",
+ "lang_closingTime": "Closing time",
+ "lang_day": "Day",
"lang_deleteChildLocations": "Delete child locations as well",
"lang_deleteLocation": "Delete location",
"lang_deleteSubnet": "Delete range",
@@ -11,6 +13,7 @@
"lang_editConfigVariables": "Config vars",
"lang_editRoomplan": "Edit roomplan",
"lang_endAddress": "End address",
+ "lang_expertMode": "Expert mode",
"lang_fixMachineAssign": "Fix or remove assignment",
"lang_ip": "IP address",
"lang_listOfSubnets": "List of subnets",
@@ -29,17 +32,28 @@
"lang_matchingMachines": "Matching clients",
"lang_mismatchHeading": "Machines with mismatching room plan assignment",
"lang_mismatchIntroText": "Machines listed here are assigned to the room above, but judging from their IP address, should actually be in another room (because of the IP range(s) assigned to that room). By selecting machines below and clicking \"reset\", they will be removed from their current room plan. If you choose \"move\", they will be transferred to the plan of the room they should actually belong to (see last column of table).",
+ "lang_monTilFr": "Monday - Friday",
"lang_moveMachines": "Move to room designated by IP address",
"lang_moveable": "Moveable",
"lang_name": "Name",
"lang_numMachinesWithOverrides": "Number of clients where at least one variable is overridden",
+ "lang_openingTime": "Opening Time",
"lang_overridenVarsForLocation": "Number of variables that get overridden for this location",
"lang_parentLocation": "Parent location",
"lang_referencingLectures": "Assigned Lectures",
"lang_resetMachines": "Reset room assignment",
+ "lang_saturday": "Saturday",
+ "lang_shortFriday": "Fri",
+ "lang_shortMonday": "Mon",
+ "lang_shortSaturday": "Sat",
+ "lang_shortSunday": "Sun",
+ "lang_shortThursday": "Thu",
+ "lang_shortTuesday": "Tue",
+ "lang_shortWednesday": "Wed",
"lang_showRoomplan": "Show room plan",
"lang_startAddress": "Start address",
"lang_subnet": "IP range",
+ "lang_sunday": "Sunday",
"lang_sysConfig": "Localization\/Integration",
"lang_thisListByLocation": "Locations",
"lang_thisListBySubnet": "Subnets",
diff --git a/modules-available/locations/pages/details.inc.php b/modules-available/locations/pages/details.inc.php
index 81b58456..a55460cf 100644
--- a/modules-available/locations/pages/details.inc.php
+++ b/modules-available/locations/pages/details.inc.php
@@ -8,6 +8,9 @@ class SubPage
if ($action === 'updatelocation') {
self::updateLocation();
return true;
+ } else if ($action === 'updateOpeningtimes') {
+ self::updateOpeningTimes();
+ return true;
}
return false;
}
@@ -22,10 +25,75 @@ class SubPage
if ($action === 'showlocation') {
self::ajaxShowLocation();
return true;
+ } elseif ($action === 'getOpeningtimes') {
+ $id = Request::any('locid', 0, 'int');
+ self::ajaxOpeningTimes($id);
+ return true;
}
return false;
}
+ private static function updateOpeningTimes() {
+ $openingTimes = Request::post('openingtimes', '', 'string');
+ $locationid = Request::post('locationid', false, 'int');
+
+ User::assertPermission('location.edit', $locationid);
+
+ // Construct opening-times for database
+ if ($openingTimes !== '') {
+ $openingTimes = json_decode($openingTimes, true);
+ if (!is_array($openingTimes)) {
+ $openingTimes = '';
+ } else {
+ $mangled = array();
+ foreach (array_keys($openingTimes) as $key) {
+ $entry = $openingTimes[$key];
+ if (!isset($entry['days']) || !is_array($entry['days']) || empty($entry['days'])) {
+ Message::addError('ignored-line-no-days');
+ continue;
+ }
+ $start = self::getTime($entry['openingtime']);
+ $end = self::getTime($entry['closingtime']);
+ if ($start === false) {
+ Message::addError('ignored-invalid-start', $entry['openingtime']);
+ continue;
+ }
+ if ($end === false) {
+ Message::addError('ignored-invalid-end', $entry['closingtime']);
+ continue;
+ }
+ if ($end <= $start) {
+ Message::addError('ignored-invalid-range', $entry['openingtime'], $entry['closingtime']);
+ continue;
+ }
+ unset($entry['tag']);
+ $mangled[] = $entry;
+ }
+ if (empty($mangled)) {
+ $openingTimes = null;
+ } else {
+ $openingTimes = json_encode($mangled);
+ }
+ }
+ }
+ // Check if opening-times changed
+ // $res = Database::queryFirst('SELECT openingtime FROM location WHERE locationid = :locationid', compact('locationid'));
+ // $otChanged = $res === false || $res['openingtime'] !== $openingTimes;
+
+ Database::exec('UPDATE location SET openingtime = :openingtime WHERE locationid = :locationid',
+ array('locationid' => $locationid, 'openingtime' => $openingTimes));
+
+ return true;
+ }
+
+ private static function getTime($str)
+ {
+ $str = explode(':', $str);
+ if (count($str) !== 2) return false;
+ if ($str[0] < 0 || $str[0] > 23 || $str[1] < 0 || $str[1] > 59) return false;
+ return $str[0] * 60 + $str[1];
+ }
+
private static function updateLocation()
{
$locationId = Request::post('locationid', false, 'integer');
@@ -313,4 +381,113 @@ class SubPage
echo Render::parse('location-subnets', $data);
}
+ private static function ajaxOpeningTimes($id) {
+ User::assertPermission('location.edit', $id);
+ $openTimes = Database::queryFirst("SELECT openingtime FROM `location` WHERE locationid = :id", array('id' => $id));
+ if ($openTimes !== false) {
+ $openingTimes = json_decode($openTimes['openingtime'], true);
+ }
+ if (!isset($openingTimes) || !is_array($openingTimes)) {
+ $openingTimes = array();
+ }
+ $data = array('id' => $id);
+ $data['expertMode'] = !self::isSimpleMode($openingTimes);
+ $data['schedule_data'] = json_encode($openingTimes);
+
+ echo Render::parse('ajax-opening-location', $data);
+ }
+
+ private static function isSimpleMode(&$array) {
+ if (empty($array))
+ return true;
+ // Decompose by day
+ $new = array();
+ foreach ($array as $row) {
+ $s = self::getTime($row['openingtime']);
+ $e = self::getTime($row['closingtime']);
+ if ($s === false || $e === false || $e <= $s)
+ continue;
+ foreach ($row['days'] as $day) {
+ self::addDay($new, $day, $s, $e);
+ }
+ }
+ // Merge by timespan, but always keep saturday and sunday separate
+ $merged = array();
+ foreach ($new as $day => $ranges) {
+ foreach ($ranges as $range) {
+ if ($day === 'Saturday' || $day === 'Sunday') {
+ $add = $day;
+ } else {
+ $add = '';
+ }
+ $key = '#' . $range[0] . '#' . $range[1] . '#' . $add;
+ if (!isset($merged[$key])) {
+ $merged[$key] = array();
+ }
+ $merged[$key][$day] = true;
+ }
+ }
+ // Check if it passes as simple mode
+ if (count($merged) > 3)
+ return false;
+ foreach ($merged as $days) {
+ if (count($days) === 5) {
+ $res = array_keys($days);
+ $res = array_intersect($res, array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"));
+ if (count($res) !== 5)
+ return false;
+ } elseif (count($days) === 1) {
+ if (!isset($days['Saturday']) && !isset($days['Sunday'])) {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ }
+ // Valid simple mode, finally transform back to what we know
+ $new = array();
+ foreach ($merged as $span => $days) {
+ preg_match('/^#(\d+)#(\d+)#/', $span, $out);
+ $new[] = array(
+ 'days' => array_keys($days),
+ 'openingtime' => floor($out[1] / 60) . ':' . ($out[1] % 60),
+ 'closingtime' => floor($out[2] / 60) . ':' . ($out[2] % 60),
+ );
+ }
+ $array = $new;
+ return true;
+ }
+
+ private static function addDay(&$array, $day, $s, $e)
+ {
+ if (!isset($array[$day])) {
+ $array[$day] = array(array($s, $e));
+ return;
+ }
+ foreach (array_keys($array[$day]) as $key) {
+ $current = $array[$day][$key];
+ if ($s <= $current[0] && $e >= $current[1]) {
+ // Fully dominated
+ unset($array[$day][$key]);
+ continue; // Might partially overlap with additional ranges, keep going
+ }
+ if ($current[0] <= $s && $current[1] >= $s) {
+ // $start lies within existing range
+ if ($current[0] <= $e && $current[1] >= $e)
+ return; // Fully in existing range, do nothing
+ // $end seems to extend range we're checking against but $start lies within this range, update and keep going
+ $s = $current[0];
+ unset($array[$day][$key]);
+ continue;
+ }
+ // Last possibility: $start is before range, $end within range
+ if ($current[0] <= $e && $current[1] >= $e) {
+ // $start must lie before range start, otherwise we'd have hit the case above
+ $e = $current[1];
+ unset($array[$day][$key]);
+ continue;
+ }
+ }
+ $array[$day][] = array($s, $e);
+ }
} \ No newline at end of file
diff --git a/modules-available/locations/templates/ajax-opening-location.html b/modules-available/locations/templates/ajax-opening-location.html
new file mode 100644
index 00000000..09fe7869
--- /dev/null
+++ b/modules-available/locations/templates/ajax-opening-location.html
@@ -0,0 +1,173 @@
+<input type="hidden" name="locationid" value="{{id}}">
+<div id="settings-outer">
+ <h3>{{lang_openingTime}}</h3>
+ {{^expertMode}}
+ <div id="simple-mode">
+
+ <div align="right" style="margin-bottom: 10px;">
+ <a href="#" class="btn btn-default btn-sm" id="btn-show-expert">{{lang_expertMode}}</a>
+ </div>
+ <div class="clearfix"></div>
+ <table class="table table-condensed" style="margin-bottom:0">
+ <tr>
+ <th>{{lang_day}}</th>
+ <th>{{lang_openingTime}}</th>
+ <th>{{lang_closingTime}}</th>
+ </tr>
+
+ <tr class="tablerow">
+ <td>{{lang_monTilFr}}</td>
+ <td>
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input type="text" class="form-control timepicker2" id="week-open" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </td>
+ <td>
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input type="text" class="form-control timepicker2" id="week-close" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </td>
+ </tr>
+ <tr class="tablerow">
+ <td>{{lang_saturday}}</td>
+ <td>
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input type="text" class="form-control timepicker2" id="saturday-open" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </td>
+ <td>
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input type="text" class="form-control timepicker2" id="saturday-close" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </td>
+ </tr>
+ <tr class="tablerow">
+ <td>{{lang_sunday}}</td>
+ <td>
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input type="text" class="form-control timepicker2" id="sunday-open" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </td>
+ <td>
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon">
+ <span class="glyphicon glyphicon-time"></span>
+ </span>
+ <input type="text" class="form-control timepicker2" id="sunday-close" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </td>
+ </tr>
+ </table>
+ </div>
+ {{/expertMode}}
+
+ <div id="expert-mode" style="{{^expertMode}}display:none{{/expertMode}}">
+ <div class="clearfix"></div>
+ <div id="expert-table">
+ <div class="row">
+ <div class="col-sm-6">{{lang_openingTime}}</div>
+ <div class="col-sm-4">{{lang_closingTime}}</div>
+ <div class="col-sm-2 text-right">{{lang_delete}}</div>
+ </div>
+ </div>
+ <hr>
+ <div style="text-align: center;">
+ <a class="btn btn-success btn-sm" id="new-openingtime">
+ <span class="glyphicon glyphicon-plus-sign"></span>
+ {{lang_openingTime}}
+ </a>
+ </div>
+ <br>
+ </div>
+</div>
+
+<div class="hidden" id="expert-template">
+ <div class="row expert-row">
+ <hr>
+ <div class="col-xs-12 days-box">
+ <div class="pull-right checkbox checkbox-inline"><input type="checkbox" class="i-delete"><label><span class="glyphicon glyphicon-trash"></span></label></div>
+ <div class="checkbox checkbox-inline"><input type="checkbox" class="i-Monday"><label>{{lang_shortMonday}}</label></div>
+ <div class="checkbox checkbox-inline"><input type="checkbox" class="i-Tuesday"><label>{{lang_shortTuesday}}</label></div>
+ <div class="checkbox checkbox-inline"><input type="checkbox" class="i-Wednesday"><label>{{lang_shortWednesday}}</label></div>
+ <div class="checkbox checkbox-inline"><input type="checkbox" class="i-Thursday"><label>{{lang_shortThursday}}</label></div>
+ <div class="checkbox checkbox-inline"><input type="checkbox" class="i-Friday"><label>{{lang_shortFriday}}</label></div>
+ <div class="checkbox checkbox-inline"><input type="checkbox" class="i-Saturday"><label>{{lang_shortSaturday}}</label></div>
+ <div class="checkbox checkbox-inline"><input type="checkbox" class="i-Sunday"><label>{{lang_shortSunday}}</label></div>
+ </div>
+ <div class="col-sm-6">
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
+ <input type="text" class="form-control timepicker2 i-openingtime" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </div>
+ <div class="col-sm-6">
+ <div class="input-group bootstrap-timepicker">
+ <span class="input-group-addon"><span class="glyphicon glyphicon-time"></span></span>
+ <input type="text" class="form-control timepicker2 i-closingtime" pattern="[0-9]{1,2}:[0-9]{2}">
+ </div>
+ </div>
+ </div>
+</div>
+
+<script type="application/javascript"><!--
+ (function() {
+
+ var scheduleData = {{{schedule_data}}};
+
+ {{#expertMode}}
+ for (var i = 0; i < scheduleData.length; ++i) {
+ newOpeningTime(scheduleData[i]);
+ }
+ {{/expertMode}}
+ {{^expertMode}}
+ for (var i = 0; i < scheduleData.length; ++i) {
+ if (scheduleData[i].days.length === 5) {
+ $('#week-open').val(scheduleData[i]['openingtime']);
+ $('#week-close').val(scheduleData[i]['closingtime']);
+ } else if (scheduleData[i].days.length === 1 && scheduleData[i].days[0] === 'Saturday') {
+ $('#saturday-open').val(scheduleData[i]['openingtime']);
+ $('#saturday-close').val(scheduleData[i]['closingtime']);
+ } else if (scheduleData[i].days.length === 1 && scheduleData[i].days[0] === 'Sunday') {
+ $('#sunday-open').val(scheduleData[i]['openingtime']);
+ $('#sunday-close').val(scheduleData[i]['closingtime']);
+ }
+ }
+ {{/expertMode}}
+
+ setTimepicker($('#settings-outer').find('.timepicker2'));
+
+ $('p.helptext').tooltip();
+
+ $('#new-openingtime').click(function (e) {
+ e.preventDefault();
+ setTimepicker(newOpeningTime({}).find('.timepicker2'));
+ });
+
+ $('#btn-show-expert').click(function (e) {
+ e.preventDefault();
+ scheduleData = simpleToExpert();
+ for (var i = 0; i < scheduleData.length; ++i) {
+ setTimepicker(newOpeningTime(scheduleData[i]).find('.timepicker2'));
+ }
+ $('#simple-mode').remove();
+ $('#expert-mode').show();
+ });
+
+ })();
+
+//--></script>
diff --git a/modules-available/locations/templates/location-subnets.html b/modules-available/locations/templates/location-subnets.html
index 6062b559..b85ddbec 100644
--- a/modules-available/locations/templates/location-subnets.html
+++ b/modules-available/locations/templates/location-subnets.html
@@ -62,7 +62,7 @@
<div class="slx-bold">{{lang_locationInfo}}</div>
<div class="row">
- <div class="col-md-4">
+ <div class="col-md-3">
{{#haveDozmod}}
<div>
<span class="slx-ga2">{{lang_referencingLectures}}:</span> {{lectures}}
@@ -81,7 +81,13 @@
</div>
{{/haveStatistics}}
</div>
- <div class="col-md-4 text-center">
+ <div class="col-md-3 text-center">
+ <button type="button" class="btn btn-default" data-toggle="modal" data-target="#openingTimesModal{{locationid}}" onclick="loadOpeningTimes('{{locationid}}')">
+ <span class="glyphicon glyphicon-time"></span>
+ {{lang_openingTime}}
+ </button>
+ </div>
+ <div class="col-md-3 text-center">
{{#roomplanner}}
<a class="btn btn-default" href="?do=roomplanner&amp;locationid={{locationid}}" target="_blank"
onclick="window.open(this.href, '_blank', 'toolbar=0,scrollbars,resizable');return false">
@@ -91,7 +97,7 @@
</a>
{{/roomplanner}}
</div>
- <div class="col-md-4 text-right">
+ <div class="col-md-3 text-right">
<button {{perms.location.delete.disabled}} type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteLocationModal{{locationid}}"><span class="glyphicon glyphicon-trash"></span> {{lang_deleteLocation}}</button>
<button onclick="deleteSubnetWarning('{{locationid}}')" {{perms.save_button.disabled}} type="button" class="btn btn-primary"><span class="glyphicon glyphicon-floppy-disk"></span> {{lang_save}}</button>
</div>
@@ -130,4 +136,34 @@
</div>
</form>
-</div> \ No newline at end of file
+</div>
+
+<div class="modal fade" id="openingTimesModal{{locationid}}" tabindex="-1" role="dialog">
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+ <form method="post" action="?do=Locations" id="settings-form">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="updateOpeningtimes">
+ <input type="hidden" name="page" value="details">
+ <input type="hidden" name="openingtimes" id="json-openingtimes" value="">
+
+ <div class="modal-header">{{locationname}}</div>
+ <div class="modal-body"></div>
+ <div class="modal-footer">
+ <button type="button" class="btn btn-default" data-dismiss="modal">{{lang_close}}</button>
+ <button type="submit" class="btn btn-primary">
+ <span class="glyphicon glyphicon-floppy-disk"></span>
+ {{lang_save}}
+ </button>
+ </div>
+
+ </form>
+ </div>
+
+ </div>
+</div>
+
+<script type="text/javascript">
+ $('#settings-form').submit(submitLocationSettings);
+</script> \ No newline at end of file
diff --git a/modules-available/locations/templates/locations.html b/modules-available/locations/templates/locations.html
index 7adfe2fc..12d401c1 100644
--- a/modules-available/locations/templates/locations.html
+++ b/modules-available/locations/templates/locations.html
@@ -250,5 +250,10 @@ function deleteSubnetWarning(locid) {
form.submit();
}
}
+
+function loadOpeningTimes(locid) {
+ $("#openingTimesModal" + locid).find('.modal-body').load("?do=Locations&page=details&action=getOpeningtimes&locid=" + locid)
+}
+
// -->
</script>