summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2017-06-10 16:15:22 +0200
committerSimon Rettberg2017-06-10 16:15:22 +0200
commita0b42aa257d0a6c56cd4a099aa0a2cea4a8dc2c9 (patch)
tree3e1655c828e0cb6f069b8c17ddf260237e0f4ce2
parent[inc/Util] Add randomUuid() function (diff)
downloadslx-admin-a0b42aa257d0a6c56cd4a099aa0a2cea4a8dc2c9.tar.gz
slx-admin-a0b42aa257d0a6c56cd4a099aa0a2cea4a8dc2c9.tar.xz
slx-admin-a0b42aa257d0a6c56cd4a099aa0a2cea4a8dc2c9.zip
[locationinfo] Started rewrite for panel-based approach
-rw-r--r--modules-available/locationinfo/clientscript.js143
-rw-r--r--modules-available/locationinfo/lang/de/template-tags.json5
-rw-r--r--modules-available/locationinfo/lang/en/template-tags.json5
-rw-r--r--modules-available/locationinfo/page.inc.php605
-rw-r--r--modules-available/locationinfo/templates/ajax-config-location.html178
-rw-r--r--modules-available/locationinfo/templates/ajax-config-server.html (renamed from modules-available/locationinfo/templates/server-settings.html)0
-rw-r--r--modules-available/locationinfo/templates/location-info.html219
-rw-r--r--modules-available/locationinfo/templates/page-config-panel.html (renamed from modules-available/locationinfo/templates/config.html)46
-rw-r--r--modules-available/locationinfo/templates/page-locations.html98
-rw-r--r--modules-available/locationinfo/templates/page-servers.html113
-rw-r--r--modules-available/locationinfo/templates/timetable.html216
-rw-r--r--modules-available/locations/inc/location.inc.php5
-rw-r--r--style/default.css4
13 files changed, 851 insertions, 786 deletions
diff --git a/modules-available/locationinfo/clientscript.js b/modules-available/locationinfo/clientscript.js
new file mode 100644
index 00000000..b18cc5bd
--- /dev/null
+++ b/modules-available/locationinfo/clientscript.js
@@ -0,0 +1,143 @@
+/*
+ * 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...
+ */
+
+/**
+ * Adds a new opening time to the table in expert mode.
+ */
+function newOpeningTime(vals) {
+ var $row = $('#expert-template div.row').clone();
+ if (vals['days'] && Array.isArray(vals['days'])) {
+ for (var i = 0; i < allDays.length; ++i) {
+ $row.find('.i-' + allDays[i]).attr('checked', vals['days'].indexOf(allDays[i]) !== -1);
+ }
+ }
+ $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()
+ };
+ 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 (badFormat) return;
+ for (var i = 0; i < allDays.length; ++i) {
+ if ($t.find('.i-' + allDays[i]).is(':checked')) {
+ entry['days'].push(allDays[i]);
+ }
+ }
+ if (entry.days.length === 0) {
+ $t.find('.days-box').addClass('red-bg');
+ badFormat = true;
+ }
+ schedule.push(entry);
+ });
+ }
+ if (badFormat) {
+ event.preventDefault();
+ }
+ $('#json-openingtimes').val(JSON.stringify(schedule));
+} \ No newline at end of file
diff --git a/modules-available/locationinfo/lang/de/template-tags.json b/modules-available/locationinfo/lang/de/template-tags.json
index 253ae674..379730e5 100644
--- a/modules-available/locationinfo/lang/de/template-tags.json
+++ b/modules-available/locationinfo/lang/de/template-tags.json
@@ -24,8 +24,6 @@
"lang_general": "Allgemein",
"lang_language": "Sprache",
"lang_languageTooltip": "Legt die Sprache der angezeigten Oberfl\u00e4che fest",
- "lang_locationIsHidden": "Versteckt",
- "lang_locationIsHidden_title": "Wenn aktiv, dann liefert die API keine Informationen \u00fcber diesen Raum",
"lang_locationName": "Name",
"lang_locationSettings": "Einstellungen",
"lang_mainHeader": "Infoscreen",
@@ -38,8 +36,9 @@
"lang_monTilFr": "Montag - Freitag",
"lang_nameTooltip": "Legt den Namen des Servers fest",
"lang_noServer": "<Kein Server>",
- "lang_openingTime": "\u00d6ffnungszeiten",
+ "lang_openingTime": "\u00d6ffnungszeit",
"lang_pleaseSelect": "Bitte w\u00e4hlen...",
+ "lang_remoteSchedule": "Abruf Belegungsplan",
"lang_room": "Raum",
"lang_roomId": "Raum ID",
"lang_roomIdTooltip": "Die Raum ID, die der Server ben\u00f6tigt, um Kalenderdaten abzurufen",
diff --git a/modules-available/locationinfo/lang/en/template-tags.json b/modules-available/locationinfo/lang/en/template-tags.json
index 60e5c9b5..6df405c9 100644
--- a/modules-available/locationinfo/lang/en/template-tags.json
+++ b/modules-available/locationinfo/lang/en/template-tags.json
@@ -24,8 +24,6 @@
"lang_general": "General",
"lang_language": "Language",
"lang_languageTooltip": "The language the frontend uses",
- "lang_locationIsHidden": "Hidden",
- "lang_locationIsHidden_title": "If checked the API doesn't return information about the room",
"lang_locationName": "Name",
"lang_locationSettings": "Settings",
"lang_mainHeader": "Infoscreen",
@@ -38,8 +36,9 @@
"lang_monTilFr": "Monday - Friday",
"lang_nameTooltip": "Defines the name of the server",
"lang_noServer": "<no server>",
- "lang_openingTime": "Opening times",
+ "lang_openingTime": "Opening time",
"lang_pleaseSelect": "Please select...",
+ "lang_remoteSchedule": "Time table retrieval",
"lang_room": "Room",
"lang_roomId": "Room ID",
"lang_roomIdTooltip": "The ID of the room the server needs, for querying the calendar data",
diff --git a/modules-available/locationinfo/page.inc.php b/modules-available/locationinfo/page.inc.php
index 52964b10..fe53bc99 100644
--- a/modules-available/locationinfo/page.inc.php
+++ b/modules-available/locationinfo/page.inc.php
@@ -16,13 +16,13 @@ class Page_LocationInfo extends Page
Util::redirect('?do=Main'); // does not return
}
+ $show = Request::any('show', '', 'string');
$this->action = Request::post('action');
- if ($this->action === 'updateOpeningTimeExpert') {
- $this->updateOpeningTimeExpert();
- } elseif ($this->action === 'updateOpeningTimeEasy') {
- $this->updateOpeningTimeEasy();
- } elseif ($this->action === 'updateConfig') {
- $this->updateLocationConfig();
+ if ($this->action === 'writePanelConfig') {
+ $this->writePanelConfig();
+ } elseif ($this->action === 'writeLocationConfig') {
+ $this->writeLocationConfig();
+ $show = 'locations';
} elseif ($this->action === 'deleteServer') {
$this->deleteServer();
} elseif ($this->action === 'checkConnection') {
@@ -33,7 +33,10 @@ class Page_LocationInfo extends Page
Messages::addWarning('main.invalid-action', $this->action);
}
if (Request::isPost()) {
- Util::redirect('?do=locationinfo');
+ if (!empty($show)) {
+ $show = '&show=' . $show;
+ }
+ Util::redirect('?do=locationinfo' . $show);
}
}
@@ -42,7 +45,20 @@ class Page_LocationInfo extends Page
*/
protected function doRender()
{
- $this->getInfoScreenTable();
+ $show = Request::get('show', '', 'string');
+ switch ($show) {
+ case 'locations':
+ $this->showLocationsTable();
+ break;
+ case 'edit-panel':
+ $this->showConfigPanel();
+ break;
+ case '':
+ $this->showInfoScreenTable();
+ break;
+ default:
+ Message::addError('main.value-invalid', 'show', $show);
+ }
}
/**
@@ -58,51 +74,147 @@ class Page_LocationInfo extends Page
Database::exec("DELETE FROM `locationinfo_coursebackend` WHERE serverid=:id", array('id' => $id));
}
- /**
- * Updated the config in the db.
- */
- private function updateLocationConfig()
+ private function getTime($str)
{
- $result = array();
+ $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];
+ }
- $locationid = Request::post('id', 0, 'int');
- if ($locationid <= 0) {
+ private function writeLocationConfig()
+ {
+ // Check locations
+ $locationid = Request::post('locationid', false, 'int');
+ if ($locationid === false) {
+ Message::addError('main.paramter-missing', 'locationid');
+ return false;
+ }
+ if (Location::get($locationid) === false) {
Message::addError('location.invalid-location-id', $locationid);
- Util::redirect('?do=locationinfo');
+ return false;
}
$serverid = Request::post('serverid', 0, 'int');
if ($serverid === 0) {
$serverid = null;
}
- $result['language'] = Request::post('language', 'en', 'string');
- $result['mode'] = Request::post('mode', 1, 'int');
- $result['vertical'] = Request::post('vertical', false, 'bool');
- $result['eco'] = Request::post('eco', false, 'bool');
- $result['scaledaysauto'] = Request::post('scaledaysauto', false, 'bool');
- $result['daystoshow'] = Request::post('daystoshow', 7, 'int');
- $result['rotation'] = Request::post('rotation', 0, 'int');
- $result['scale'] = Request::post('scale', 50, 'int');
- $result['switchtime'] = Request::post('switchtime', 20, 'int');
- $result['calupdate'] = Request::post('calupdate', 120, 'int');
- $result['roomupdate'] = Request::post('roomupdate', 30, 'int');
- $result['configupdate'] = Request::post('configupdate', 180, 'int');
- if ($result['roomupdate'] < 30) {
- $result['roomupdate'] = 30;
- }
- if ($result['calupdate'] < 120) {
- $result['calupdate'] = 120;
- }
$serverlocationid = Request::post('serverlocationid', '', 'string');
- Database::exec("INSERT INTO `locationinfo_locationconfig` (locationid, serverid, serverlocationid, config, lastcalendarupdate)
- VALUES (:id, :serverid, :serverlocationid, :config, 0)
- ON DUPLICATE KEY UPDATE config = VALUES(config), serverid = VALUES(serverid),
- serverlocationid = VALUES(serverlocationid), lastcalendarupdate = 0", array(
+ // Opening times
+ $openingtimes = Request::post('openingtimes', '', 'string');
+ 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;
+ }
+ $s = $this->getTime($entry['openingtime']);
+ $e = $this->getTime($entry['closingtime']);
+ if ($s === false) {
+ Message::addError('ignored-invalid-start', $entry['openingtime']);
+ continue;
+ }
+ if ($e === false) {
+ Message::addError('ignored-invalid-end', $entry['closingtime']);
+ continue;
+ }
+ if ($e <= $s) {
+ Message::addError('ignored-invalid-range', $entry['openingtime'], $entry['closingtime']);
+ continue;
+ }
+ unset($entry['tag']);
+ $mangled[] = $entry;
+ }
+ if (empty($mangled)) {
+ $openingtimes = '';
+ } else {
+ $openingtimes = json_encode($mangled);
+ }
+ }
+ }
+
+ Database::exec("INSERT INTO `locationinfo_locationconfig` (locationid, serverid, serverlocationid, openingtime, lastcalendarupdate)
+ VALUES (:id, :serverid, :serverlocationid, :openingtimes, 0)
+ ON DUPLICATE KEY UPDATE serverid = VALUES(serverid), serverlocationid = VALUES(serverlocationid),
+ openingtime = VALUES(openingtime), lastcalendarupdate = 0", array(
'id' => $locationid,
- 'config' => json_encode($result),
'serverid' => $serverid,
+ 'openingtimes' => $openingtimes,
'serverlocationid' => $serverlocationid,
));
+ return true;
+ }
+
+ /**
+ * Updated the config in the db.
+ */
+ private function writePanelConfig()
+ {
+ // UUID - existing or new
+ $paneluuid = Request::post('paneluuid', false, 'string');
+ if (($paneluuid === false || strlen($paneluuid) !== 36) && $paneluuid !== 'new') {
+ Message::addError('invalid-panel-id', $paneluuid);
+ Util::redirect('?do=locationinfo');
+ }
+ // Check locations
+ $locationids = Request::post('locationids', false, 'array');
+ if ($locationids === false) {
+ Message::addError('main.paramter-missing', 'locationids');
+ Util::redirect('?do=locationinfo');
+ }
+ $all = array_map(function ($item) { return $item['locationid']; }, Location::queryLocations());
+ $locationids = array_filter($locationids, function ($item) use ($all) { return in_array($item, $all); });
+ if (empty($locationids)) {
+ Message::addError('main.paramter-empty', 'locationids');
+ Util::redirect('?do=locationinfo');
+ }
+ if (count($locationids) > 4) {
+ $locationids = array_slice($locationids, 0, 4);
+ }
+ // Build json struct
+ $conf = array(
+ 'ts' => time(),
+ 'language' => Request::post('language', 'en', 'string'),
+ 'mode' => Request::post('mode', 1, 'int'),
+ 'vertical' => Request::post('vertical', false, 'bool'),
+ 'eco' => Request::post('eco', false, 'bool'),
+ 'scaledaysauto' => Request::post('scaledaysauto', false, 'bool'),
+ 'daystoshow' => Request::post('daystoshow', 7, 'int'),
+ 'rotation' => Request::post('rotation', 0, 'int'),
+ 'scale' => Request::post('scale', 50, 'int'),
+ 'switchtime' => Request::post('switchtime', 20, 'int'),
+ 'calupdate' => Request::post('calupdate', 120, 'int'),
+ 'roomupdate' => Request::post('roomupdate', 30, 'int'),
+ 'configupdate' => Request::post('configupdate', 180, 'int'),
+ );
+ if ($conf['roomupdate'] < 30) {
+ $conf['roomupdate'] = 30;
+ }
+ if ($conf['calupdate'] < 120) {
+ $conf['calupdate'] = 120;
+ }
+
+ if ($paneluuid === 'new') {
+ $paneluuid = Util::randomUuid();
+ $query = "INSERT INTO `locationinfo_panel` (paneluuid, locationids, paneltype, panelconfig)
+ VALUES (:id, :locationids, :type, :config)";
+ } else {
+ $query = "UPDATE `locationinfo_panel`
+ SET locationids = :locationids, paneltype = :type, panelconfig = :config
+ WHERE paneluuid = :id";
+ }
+ Database::exec($query, array(
+ 'id' => $paneluuid,
+ 'locationids' => implode(',', $locationids),
+ 'type' => 'DEFAULT', // TODO
+ 'config' => json_encode($conf),
+ ));
Message::addSuccess('config-saved');
Util::redirect('?do=locationinfo');
@@ -148,133 +260,6 @@ class Page_LocationInfo extends Page
}
/**
- * Updates the opening time in the db from the expert mode.
- */
- private function updateOpeningTimeExpert()
- {
- $days = Request::post('days', array(), 'array');
- $locationid = Request::post('id', 0, 'int');
- $openingtime = Request::post('openingtime', array(), 'array');
- $closingtime = Request::post('closingtime', array(), 'array');
- $easyMode = Request::post('easyMode', false, 'bool');
- $delete = Request::post('delete', array(), 'array');
- $dontadd = Request::post('dontadd', array(), 'array');
- $count = 0;
- $result = array();
- $resulttmp = array();
- $deleteCounter = 0;
-
- if (!$easyMode) {
- $resulttmp = Database::queryFirst("SELECT openingtime FROM `locationinfo_locationconfig` WHERE locationid = :id", array('id' => $locationid));
- if ($resulttmp !== false) {
- $resulttmp = json_decode($resulttmp['openingtime'], true);
- }
- if (!is_array($resulttmp)) {
- $resulttmp = array();
- }
-
- $index = 0;
-
- foreach ($resulttmp as $day) {
- $skip = false;
-
- foreach ($delete as $del) {
- if ($del == $index) {
- $skip = true;
- break;
- }
- }
- if ($skip) {
- $index++;
- $deleteCounter++;
- continue;
- }
-
- $result[] = $day;
- $index++;
- }
- }
-
- if (!empty($days) && !is_array($days)) {
- Message::addError('no-days-selected');
- Util::redirect('?do=locationinfo');
- } else {
-
- $dayz = array();
- $da = array();
-
- foreach ($days as $d) {
- if ($d != '-') {
- $da[] = $d;
- } else {
- $dayz[$count] = $da;
- $da = array();
- $count++;
- }
- }
-
- $optime = array();
- for ($x = 0; $x < $count; $x++) {
- if ($dontadd[$x] == 'dontadd') {
- continue;
- }
- $optime['days'] = $dayz[$x];
- $optime['openingtime'] = $openingtime[$x];
- $optime['closingtime'] = $closingtime[$x];
- $result[] = $optime;
- }
- }
-
- Database::exec("INSERT INTO `locationinfo_locationconfig` (locationid, openingtime)
- VALUES (:id, :openingtime)
- ON DUPLICATE KEY UPDATE openingtime = VALUES(openingtime)",
- array('id' => $locationid, 'openingtime' => json_encode($result)));
-
- if ($deleteCounter > 0) {
- Message::addSuccess('deleted-x-entries', $deleteCounter);
- }
- if ($count > 0) {
- Message::addSuccess('added-x-entries', $count);
- }
-
- Util::redirect('?do=locationinfo');
- }
-
- /**
- * Updates the opening time in the db from the easy mode.
- */
- private function updateOpeningTimeEasy()
- {
- $locationid = Request::post('id', 0, 'int');
- $openingtime = Request::post('openingtime', array(), 'array');
- $closingtime = Request::post('closingtime', array(), 'array');
- $result = array();
-
- $blocks = array(
- 0 => array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday"),
- 1 => array("Saturday"),
- 2 => array("Sunday"),
- );
- foreach ($blocks as $idx => $days) {
- //if (!empty($openingtime[$idx]) && !empty($closingtime[$idx])) {
- $result[] = array(
- 'days' => $days,
- 'openingtime' => $openingtime[$idx],
- 'closingtime' => $closingtime[$idx],
- );
- //}
- }
-
- Database::exec("INSERT INTO `locationinfo_locationconfig` (locationid, openingtime)
- VALUES (:id, :openingtime)
- ON DUPLICATE KEY UPDATE openingtime = VALUES(openingtime)",
- array('id' => $locationid, 'openingtime' => json_encode($result)));
-
- Message::addSuccess('openingtime-updated');
- Util::redirect('?do=locationinfo');
- }
-
- /**
* Checks if the server connection to a backend is valid.
*
* @param int $id Server id which connection should be checked.
@@ -303,65 +288,11 @@ class Page_LocationInfo extends Page
LocationInfo::setServerError($serverid, $serverInstance->getError());
}
-
- /**
- * Sets the new hidden value and checks childs and parents.
- *
- * @param int $id The location id which was toggled
- * @param bool $hidden The hidden value true / false
- */
- protected function toggleHidden($id, $hidden)
- {
- $locs = Location::getLocationsAssoc();
- if (!isset($locs[$id]))
- die('Invalid location id');
- $loc = $locs[$id];
-
- // The JSON to return, telling the client which locationids to update in the view
- $return = array();
- $return[] = array('locationid' => $id, 'hidden' => $hidden);
-
- // Update the location, plus all child locations
- $qs = '(?,?)' . str_repeat(',(?,?)', count($loc['children']));
- $params = array($id, $hidden);
- foreach ($loc['children'] as $child) {
- $params[] = $child;
- $params[] = $hidden;
- $return[] = array('locationid' => $child, 'hidden' => $hidden);
- }
- Database::exec("INSERT INTO locationinfo_locationconfig (locationid, hidden)
- VALUES $qs ON DUPLICATE KEY UPDATE hidden = VALUES(hidden)", $params);
-
- // Handle parents - uncheck if not all children are checked
- while ($loc['parentlocationid'] != 0) {
- $stats = Database::queryFirst('SELECT Count(*) AS total, Sum(li.hidden > 0) AS hidecount FROM location l
- LEFT JOIN locationinfo_locationconfig li USING (locationid)
- WHERE l.parentlocationid = :parent', array('parent' => $loc['parentlocationid']));
- $hidden = ($stats['total'] == $stats['hidecount']) ? 1 : 0;
- $params = array('locationid' => $loc['parentlocationid'], 'hidden' => $hidden);
- Database::exec('INSERT INTO locationinfo_locationconfig (locationid, hidden)
- VALUES (:locationid, :hidden) ON DUPLICATE KEY UPDATE hidden = VALUES(hidden)', $params);
- $return[] = $params;
- $loc = $locs[$loc['parentlocationid']];
- }
- return $return;
- }
-
/**
* Loads the Infoscreen page in the admin-panel and passes all needed information.
*/
- protected function getInfoScreenTable()
+ private function showInfoScreenTable()
{
- $locations = Location::getLocations(0, 0, false, true);
-
- // Get hidden state of all locations
- $dbquery = Database::simpleQuery("SELECT li.locationid, li.hidden FROM `locationinfo_locationconfig` AS li");
-
- while ($row = $dbquery->fetch(PDO::FETCH_ASSOC)) {
- $locid = (int)$row['locationid'];
- $locations[$locid]['hidden_checked'] = $row['hidden'] != 0 ? 'checked' : '';
- }
-
// Get a list of all the backend types.
$servertypes = array();
$s_list = CourseBackend::getList();
@@ -395,12 +326,35 @@ class Page_LocationInfo extends Page
}
// Pass the data to the html and render it.
- Render::addTemplate('location-info', array(
- 'list' => array_values($locations),
+ Render::addTemplate('page-servers', array(
'serverlist' => $serverlist,
));
}
+ private function showLocationsTable()
+ {
+ $locations = Location::getLocations(0, 0, false, true);
+
+ // Get hidden state of all locations
+ $dbquery = Database::simpleQuery("SELECT li.locationid, li.serverid, li.serverlocationid, li.openingtime, li.lastcalendarupdate
+ FROM `locationinfo_locationconfig` AS li");
+
+ while ($row = $dbquery->fetch(PDO::FETCH_ASSOC)) {
+ $locid = (int)$row['locationid'];
+ $hasTable = is_array(json_decode($row['openingtime'], true));
+ $hasBackend = !empty($row['serverid']) && !empty($row['serverlocationid']);
+ $locations[$locid] += array(
+ 'hasTable' => $hasTable,
+ 'hasBackend' => $hasBackend,
+ 'lastCalendarUpdate' => $row['lastcalendarupdate'], // TODO
+ );
+ }
+
+ Render::addTemplate('page-locations', array(
+ 'list' => array_values($locations),
+ ));
+ }
+
/**
* AJAX
*/
@@ -412,32 +366,14 @@ class Page_LocationInfo extends Page
}
$action = Request::any('action');
$id = Request::any('id', 0, 'int');
- if ($action === 'timetable') {
- $this->ajaxTimeTable($id);
- } elseif ($action === 'config') {
- $this->ajaxLoadLocationConfig($id);
+ if ($action === 'config-location') {
+ $this->ajaxConfigLocation($id);
} elseif ($action === 'serverSettings') {
$this->ajaxServerSettings($id);
- } elseif ($action === 'hide') {
- $this->ajaxHideLocation();
}
}
/**
- * Request to deny displaying the door sign for the
- * given location. Sends a list of all affected
- * locations, so the client can update its view.
- */
- private function ajaxHideLocation()
- {
- $locationId = Request::post('locationid', 0, 'int');
- $hidden = Request::post('hidden', 0, 'int');
- Header('Content-Type: application/json; charset=utf-8');
- $ret = $this->toggleHidden($locationId, $hidden);
- echo json_encode(array('changed' => $ret));
- }
-
- /**
* Ajax the server settings.
*
* @param int $id Serverid
@@ -477,7 +413,7 @@ class Page_LocationInfo extends Page
}
$serverBackends[] = $backend;
}
- echo Render::parse('server-settings', array('id' => $id,
+ echo Render::parse('ajax-config-server', array('id' => $id,
'name' => $oldConfig['servername'],
'currentbackend' => $oldConfig['servertype'],
'backendList' => $serverBackends,
@@ -489,57 +425,140 @@ class Page_LocationInfo extends Page
*
* @param $id id of the location
*/
- private function ajaxTimeTable($id)
+ private function ajaxConfigLocation($id)
{
- $row = Database::queryFirst("SELECT openingtime FROM `locationinfo_locationconfig` WHERE locationid = :id", array('id' => $id));
- if ($row !== false) {
- $openingtimes = json_decode($row['openingtime'], true);
+ $locConfig = Database::queryFirst("SELECT serverid, serverlocationid, openingtime FROM `locationinfo_locationconfig` WHERE locationid = :id", array('id' => $id));
+ if ($locConfig !== false) {
+ $openingtimes = json_decode($locConfig['openingtime'], true);
}
if (!isset($openingtimes) || !is_array($openingtimes)) {
$openingtimes = array();
}
- if ($this->isEasyMode($openingtimes)) {
- $data = array('id' => $id,
- 'easyMode' => true,
- 'expertMode' => false
- );
- foreach ($openingtimes as $idx => $ot) {
- foreach ($ot as $k => $v) {
- $data[$k . $idx] = $v;
- }
- }
- echo Render::parse('timetable', $data);
- } else {
- $index = 0;
- foreach ($openingtimes as &$entry) {
- $entry['days'] = implode(', ', $entry['days']);
- $entry['index'] = $index++;
+ // get Server / ID list
+ $res = Database::simpleQuery("SELECT serverid, servername FROM locationinfo_coursebackend ORDER BY servername ASC");
+ $serverList = array();
+ while ($row = $res->fetch(PDO::FETCH_ASSOC)) {
+ if ($row['serverid'] == $locConfig['serverid']) {
+ $row['selected'] = 'selected';
}
- echo Render::parse('timetable', array('id' => $id,
- 'openingtimes' => array_values($openingtimes),
- 'easyMode' => false,
- 'expertMode' => true));
+ $serverList[] = $row;
}
+
+ $data = array(
+ 'id' => $id,
+ 'serverlist' => $serverList,
+ 'serverlocationid' => $locConfig['serverlocationid'],
+ );
+ $data['expertMode'] = !$this->isSimpleMode($openingtimes);
+ // !! isSimpleMode might have changed $openingtimes, so order is important here...
+ $data['schedule_data'] = json_encode($openingtimes);
+
+ echo Render::parse('ajax-config-location', $data);
}
/**
- * Checks if easymode or expert mode is active.
+ * Checks if simple mode or expert mode is active.
+ * Tries to merge/compact the opening times schedule, and
+ * will actually modify the passed array iff it can be
+ * transformed into easy opening times.
*
- * @param $array Array of the saved openingtimes.
- * @return bool True if easy mode, false if expert mode
+ * @param array $array of the saved openingtimes.
+ * @return bool True if simple mode, false if expert mode
*/
- private function isEasyMode($array)
+ private function isSimpleMode(&$array)
{
if (empty($array))
return true;
- if (count($array) === 3
- && $array[0]['days'] == array("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
- && $array[1]['days'][0] == "Saturday" && $array[2]['days'][0] == "Sunday"
- ) {
- return true;
+ // Decompose by day
+ $new = array();
+ foreach ($array as $row) {
+ $s = $this->getTime($row['openingtime']);
+ $e = $this->getTime($row['closingtime']);
+ if ($s === false || $e === false || $e <= $s)
+ continue;
+ foreach ($row['days'] as $day) {
+ $this->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;
+ }
}
- return false;
+ // 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 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);
}
/**
@@ -547,28 +566,19 @@ class Page_LocationInfo extends Page
*
* @param $id Location ID
*/
- private function ajaxLoadLocationConfig($id)
+ private function showConfigPanel()
{
+ $id = Request::get('paneluuid', false, 'string');
// Get Config data from db
- $location = Database::queryFirst("SELECT lc.config, lc.serverid, lc.serverlocationid
- FROM location l
- LEFT JOIN `locationinfo_locationconfig` lc USING (locationid)
- WHERE l.locationid = :id", array('id' => $id));
- if ($location === false) {
- die("Invalid location id: $id");
+ $panel = Database::queryFirst("SELECT locationids, paneltype, panelconfig
+ FROM locationinfo_panel
+ WHERE paneluuid = :id", array('id' => $id));
+ if ($panel === false) {
+ die("Invalid panel id: $id");
}
- $config = json_decode($location['config'], true); // TODO: Validate we got an array, fill with defaults otherwise
+ $config = json_decode($panel['panelconfig'], true); // TODO: Validate we got an array, fill with defaults otherwise
- // get Server / ID list
- $dbq = Database::simpleQuery("SELECT serverid, servername FROM locationinfo_coursebackend ORDER BY servername ASC");
- $serverList = array();
- while ($row = $dbq->fetch(PDO::FETCH_ASSOC)) {
- if ($row['serverid'] == $location['serverid']) {
- $row['selected'] = 'selected';
- }
- $serverList[] = $row;
- }
$langs = Dictionary::getLanguages(true);
foreach ($langs as &$lang) {
if ($lang['cc'] === $config['language']) {
@@ -576,7 +586,7 @@ class Page_LocationInfo extends Page
}
}
- echo Render::parse('config', array(
+ Render::addTemplate('page-config-panel', array(
'id' => $id,
'languages' => $langs,
'mode' => $config['mode'],
@@ -590,9 +600,6 @@ class Page_LocationInfo extends Page
'calupdate' => $config['calupdate'],
'roomupdate' => $config['roomupdate'],
'configupdate' => $config['configupdate'],
- 'serverlist' => $serverList,
- 'serverid' => $location['serverid'],
- 'serverlocationid' => $location['serverlocationid']
));
}
diff --git a/modules-available/locationinfo/templates/ajax-config-location.html b/modules-available/locationinfo/templates/ajax-config-location.html
new file mode 100644
index 00000000..2cbad89d
--- /dev/null
+++ b/modules-available/locationinfo/templates/ajax-config-location.html
@@ -0,0 +1,178 @@
+<input type="hidden" name="locationid" value="{{id}}">
+<div id="settings-outer">
+ <h3>{{lang_openingTime}}</h3>
+ {{^expertMode}}
+ <div id="simple-mode">
+
+ <div align="right">
+ <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="pull-right">
+ <a class="btn btn-success btn-sm" id="new-openingtime">
+ <span class="glyphicon glyphicon-plus-sign"></span>
+ {{lang_openingTime}}
+ </a>
+ </div>
+ <div class="clearfix"></div>
+ <div id="expert-table">
+ <div class="row">
+ <div class="col-xs-9">{{lang_day}}</div>
+ <div class="col-xs-3 text-right">{{lang_delete}}</div>
+ <div class="col-sm-6">{{lang_openingTime}}</div>
+ <div class="col-sm-6">{{lang_closingTime}}</div>
+ </div>
+ </div>
+ </div>
+</div>
+
+<h3>{{lang_remoteSchedule}}</h3>
+<div class="row">
+ <div class="col-sm-3">
+ {{lang_server}}
+ </div>
+ <div class="col-sm-7">
+ <select class="form-control" name="serverid">
+ <option value="0">{{lang_noServer}}</option>
+ {{#serverlist}}
+ <option value="{{serverid}}" {{selected}}>{{servername}}</option>
+ {{/serverlist}}
+ </select>
+ </div>
+ <div class="col-sm-2">
+ <a class="btn btn-default helptext" title="{{lang_serverTooltip}}">
+ <span class="glyphicon glyphicon-question-sign"></span>
+ </a>
+ </div>
+</div>
+<div class="row">
+ <div class="col-sm-3">
+ {{lang_roomId}}
+ </div>
+ <div class="col-sm-7">
+ <input class="form-control" name="serverlocationid" id="serverlocationid" value="{{serverlocationid}}">
+ </div>
+ <div class="col-sm-2">
+ <a class="btn btn-default helptext" title="{{lang_roomIdTooltip}}">
+ <span class="glyphicon glyphicon-question-sign"></span>
+ </a>
+ </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'));
+
+ $('a.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/locationinfo/templates/server-settings.html b/modules-available/locationinfo/templates/ajax-config-server.html
index 940bc55a..940bc55a 100644
--- a/modules-available/locationinfo/templates/server-settings.html
+++ b/modules-available/locationinfo/templates/ajax-config-server.html
diff --git a/modules-available/locationinfo/templates/location-info.html b/modules-available/locationinfo/templates/location-info.html
deleted file mode 100644
index e2ee2960..00000000
--- a/modules-available/locationinfo/templates/location-info.html
+++ /dev/null
@@ -1,219 +0,0 @@
-<div>
- <h1>{{lang_mainHeader}}</h1>
-
- <h4>{{lang_serverTable}}</h4>
-
- <table class="table table-hover">
- <tr>
- <th width="1">{{lang_serverType}}</th>
- <th>{{lang_locationName}}</th>
- <th width="1"></th>
- <th width="1"></th>
- </tr>
- {{#serverlist}}
- <form method="post" action="?do=locationinfo">
- <input type="hidden" name="token" value="{{token}}">
- <input type="hidden" name="serverid" value="{{serverid}}">
- <tr>
- <td nowrap>{{typename}}</td>
- <td nowrap>{{servername}}</td>
-
- <td align="center" nowrap>
- <button class="btn btn-sm {{^autherror}}btn-success{{/autherror}}{{#autherror}}btn-danger{{/autherror}}"
- data-server-edit="{{serverid}}" {{disabled}} type="button">
- <span style="margin-right: 5px;" class="glyphicon glyphicon-cog"></span>
- {{lang_locationSettings}}
- </button>
- <button class="btn btn-sm btn-primary server-check" {{disabled}} name="action" value="checkConnection"
- type="submit">
- <span style="margin-right: 5px;" class="glyphicon glyphicon-refresh"></span>
- {{lang_checkConnection}}
- </button>
- </td>
- <td align="center" nowrap>
- <button class="btn btn-sm btn-danger server-delete" type="submit" name="action" value="deleteServer">
- <span style="margin-right: 5px;" class="glyphicon glyphicon-remove"></span>
- {{lang_delete}}
- </button>
- </td>
- </tr>
- </form>
- {{/serverlist}}
- </table>
-
- <div>
- <button class="btn btn-sm btn-success" id="addServerButton" onclick="addServer()">
- <span style="margin-right: 5px;" class="glyphicon glyphicon-plus"></span>
- {{lang_addServer}}
- </button>
- </div>
-
- <h4>{{lang_buildingTable}}</h4>
- <table class="table table-condensed table-hover" style="margin-bottom:0">
-
- <tr>
- <th>{{lang_locationName}}</th>
- <th width="50" title="{{lang_locationIsHidden_title}}">{{lang_locationIsHidden}}</th>
- <th width="50">{{lang_openingTime}}</th>
- <th width="50">{{lang_locationSettings}}</th>
- </tr>
-
- {{#list}}
- <tr id="row{{locationid}}">
- <td>
- <div style="display:inline-block;width:{{depth}}em"></div>
- <a href="modules/locationinfo/frontend/doorsign.html?id={{locationid}}" target="_blank">{{locationname}}</a>
- </td>
- <td align="center">
- <div class="checkbox" style="margin:0">
- <input class="hidden-toggle" type="checkbox" data-locationid="{{locationid}}" {{hidden_checked}}>
- <label></label>
- </div>
- </td>
- <td>
- <a class="btn btn-sm btn-default" role="button" style="width: 100%"
- onclick="loadTimeModal({{locationid}}, '{{locationname}}');">
- <span style="margin-right: 5px;" class="glyphicon glyphicon-time"></span>
- </a>
- </td>
- <td>
- <a class="btn btn-sm btn-default" role="button" style="width: 100%;"
- onclick="loadLocationConfigModal({{locationid}}, '{{locationname}}');">
- <span style="margin-right: 5px;" class="glyphicon glyphicon-cog"></span>
- </a>
- </td>
- </tr>
-
- {{/list}}
- </table>
-
- <div class="modal fade" id="myModal" tabindex="-1" role="dialog">
- <div class="modal-dialog">
-
- <div class="modal-content">
- <div class="modal-header" id="myModalHeader"></div>
- <div class="modal-body" id="myModalBody"></div>
- <div class="modal-footer">
- <button type="submit" id="myModalSubmitButton" class="btn btn-primary" form="">{{lang_save}}</button>
-
- <a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a>
- </div>
- </div>
-
- </div>
- </div>
-</div>
-<script type="text/javascript"><!--
-
- document.addEventListener("DOMContentLoaded", function () {
-
- /**
- * React to click on a "hidden" checkbox.
- */
- $('.hidden-toggle').change(function() {
- $input = $(this);
- $.ajax({
- type: 'POST',
- url: '?do=locationinfo&action=hide',
- data: {locationid: $input.data('locationid'), hidden: $input[0].checked ? 1 : 0, token: TOKEN },
- dataType: 'json'
- }).done(function(data) {
- if (data && $.isArray(data.changed)) {
- markBoxes(data.changed);
- } else {
- $input.replaceWith('ERROR');
- }
- }).fail(function () {
- $input.replaceWith('ERROR');
- });
- }).parent().click(function() {
- $this = $(this);
- $box = $this.find('input');
- if (!$this.is($box)) {
- $box.click();
- }
- });
-
- /**
- * Confirm deleting a server.
- */
- $('.server-delete').click(function(ev) {
- var del = confirm("{{lang_deleteConfirmation}}");
- if (!del) ev.preventDefault();
- });
-
- /**
- * Animate refresh icon while page is loading
- */
- $('.server-check').click(function() {
- $(this).find('.glyphicon').addClass('slx-rotation');
- });
-
- $('button[data-server-edit]').click(function() {
- var id = $(this).data('server-edit');
- loadServerSettingsModal(id);
- });
-
- });
-
- /**
- * Gets a status array delivered by backend's ajaxHideLocation()
- * and sets the checkbox states accordingly.
- */
- function markBoxes(boxArray) {
- for (var i = 0; i < boxArray.length; ++i) {
- if (boxArray[i].locationid) {
- var lid = parseInt(boxArray[i].locationid);
- $('input.hidden-toggle[data-locationid="' + lid + '"]').prop('checked', !!boxArray[i].hidden);
- }
- }
- }
-
- /**
- * Loads the settings modal of a server.
- *
- * @param serverid The id of the server.
- */
- function loadServerSettingsModal(serverid) {
- $('#myModalHeader').text("{{lang_locationSettings}}").css("font-weight", "Bold");
- $('#myModal .modal-dialog').css('width', '');
- $('#myModal').modal('show');
- $('#myModalBody').load("?do=locationinfo&action=serverSettings&id=" + serverid);
- }
-
- /**
- * Load a opening time modal of a location.
- *
- * @param locationId The id of the location.
- * @param locationName The name of the location.
- */
- function loadTimeModal(locationId, locationName) {
- $('#myModalHeader').text("[" + locationId + "] " + locationName).css("font-weight", "Bold");
- $('#myModal .modal-dialog').css('width', '');
- $('#myModal').modal('show');
- $('#myModalBody').load("?do=locationinfo&action=timetable&id=" + locationId);
- }
-
- /**
- * Loads the config modal of a location.
- *
- * @param locationId The id of the location
- * @param locationName the name of the location
- */
- function loadLocationConfigModal(locationId, locationName) {
- $('#myModalHeader').text("[" + locationId + "] " + locationName).css("font-weight", "Bold");
- $('#myModalSubmitButton').attr("form", "configForm");
- $('#myModal .modal-dialog').css('width', '90%');
- $('#myModal').modal('show');
- $('#myModalBody').load("?do=locationinfo&action=config&id=" + locationId);
- }
-
- // ########### Server Table ###########
-
- /**
- * Loads a new / empty server settings modal.
- */
- function addServer() {
- loadServerSettingsModal(0);
- }
-//--></script>
diff --git a/modules-available/locationinfo/templates/config.html b/modules-available/locationinfo/templates/page-config-panel.html
index cce63de1..244b80c9 100644
--- a/modules-available/locationinfo/templates/config.html
+++ b/modules-available/locationinfo/templates/page-config-panel.html
@@ -5,52 +5,6 @@
<div class="row">
<div class="col-md-6">
- <div class="panel panel-default">
- <div class="panel-heading">{{lang_server}}</div>
- <div class="panel-body">
- <div class="list-group">
- <div class="list-group-item">
- <div class="row">
- <div class="col-sm-3">
- <label>{{lang_server}}</label>
- </div>
- <div class="col-sm-7">
- <select class="form-control" name="serverid">
- <option value="0">{{lang_noServer}}</option>
- {{#serverlist}}
- <option value="{{serverid}}" {{selected}}>{{servername}}</option>
- {{/serverlist}}
- </select>
- </div>
- <div class="col-sm-2">
- <a class="btn btn-default helptext" title="{{lang_serverTooltip}}">
- <span class="glyphicon glyphicon-question-sign"></span>
- </a>
- </div>
- </div>
- </div>
-
- <div class="list-group-item">
- <div class="row">
- <div class="col-sm-3">
- <label>{{lang_roomId}}</label>
- </div>
- <div class="col-sm-7">
- <input class="form-control" name="serverlocationid" id="serverlocationid" value="{{serverlocationid}}">
- </div>
- <div class="col-sm-2">
- <a class="btn btn-default helptext" title="{{lang_roomIdTooltip}}">
- <span class="glyphicon glyphicon-question-sign"></span>
- </a>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
- </div>
-
- <div class="col-md-6">
<div class="modify-inputs panel panel-default">
<div class="panel-heading">{{lang_display}}</div>
<div class="panel-body">
diff --git a/modules-available/locationinfo/templates/page-locations.html b/modules-available/locationinfo/templates/page-locations.html
new file mode 100644
index 00000000..436aa8d5
--- /dev/null
+++ b/modules-available/locationinfo/templates/page-locations.html
@@ -0,0 +1,98 @@
+<h4>{{lang_buildingTable}}</h4>
+<table class="table table-condensed table-hover" style="margin-bottom:0">
+
+ <tr>
+ <th>{{lang_locationName}}</th>
+ <th width="50">{{lang_openingTime}}</th>
+ <th width="50">{{lang_locationSettings}}</th>
+ </tr>
+
+ {{#list}}
+ <tr>
+ <td>
+ <div style="display:inline-block;width:{{depth}}em"></div>
+ <a href="#" class="loc-name" data-locationid="{{locationid}}">{{locationname}}</a>
+ </td>
+ <td>
+ <a class="btn btn-sm btn-default" role="button" style="width: 100%"
+ onclick="loadTimeModal({{locationid}}, '{{locationname}}');">
+ <span style="margin-right: 5px;" class="glyphicon glyphicon-time"></span>
+ </a>
+ </td>
+ <td>
+ <a class="btn btn-sm btn-default" role="button" style="width: 100%;"
+ onclick="loadLocationConfigModal({{locationid}}, '{{locationname}}');">
+ <span style="margin-right: 5px;" class="glyphicon glyphicon-cog"></span>
+ </a>
+ </td>
+ </tr>
+
+ {{/list}}
+</table>
+
+<div class="modal fade" id="location-modal" tabindex="-1" role="dialog">
+ <div class="modal-dialog"> <!--style="min-width:600px;width:70%"-->
+
+ <div class="modal-content">
+ <form method="post" action="?do=locationinfo" id="settings-form">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="action" value="writeLocationConfig">
+ <input type="hidden" name="openingtimes" id="json-openingtimes" value="">
+ <div class="modal-header"><h2 id="location-modal-header"></h2></div>
+ <div class="modal-body"></div>
+ <div class="modal-footer">
+ <button type="submit" class="btn btn-primary">{{lang_save}}</button>
+ <a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a>
+ </div>
+ </form>
+ </div>
+
+ </div>
+</div>
+
+<div class="hidden" id="expert-template">
+ <div class="row expert-row" style="margin-top:1em;border-top:1px solid #ddd">
+ <div class="col-xs-9 days-box">
+ <label><input type="checkbox" class="i-Monday">{{lang_shortMonday}}</label> |
+ <label><input type="checkbox" class="i-Tuesday">{{lang_shortTuesday}}</label> |
+ <label><input type="checkbox" class="i-Wednesday">{{lang_shortWednesday}}</label> |
+ <label><input type="checkbox" class="i-Thursday">{{lang_shortThursday}}</label> |
+ <label><input type="checkbox" class="i-Friday">{{lang_shortFriday}}</label> |
+ <label><input type="checkbox" class="i-Saturday">{{lang_shortSaturday}}</label> |
+ <label><input type="checkbox" class="i-Sunday">{{lang_shortSunday}}</label>
+ </div>
+ <div class="col-xs-3 text-right">
+ <label><input type="checkbox" class="i-delete"><span class="glyphicon glyphicon-trash"></span></label>
+ </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="text/javascript"><!--
+
+document.addEventListener("DOMContentLoaded", function () {
+ /**
+ * Load a opening time modal of a location.
+ */
+ $('.loc-name').click(function (e) {
+ e.preventDefault();
+ var locationId = $(this).data('locationid');
+ var locationName = $(this).text();
+ $('#location-modal-header').text("[" + locationId + "] " + locationName);
+ $('#location-modal').modal('show').find('.modal-body').load("?do=locationinfo&action=config-location&id=" + locationId);
+ });
+ $('#settings-form').submit(submitLocationSettings);
+});
+
+//--></script> \ No newline at end of file
diff --git a/modules-available/locationinfo/templates/page-servers.html b/modules-available/locationinfo/templates/page-servers.html
new file mode 100644
index 00000000..2dfe63e1
--- /dev/null
+++ b/modules-available/locationinfo/templates/page-servers.html
@@ -0,0 +1,113 @@
+<div>
+ <h1>{{lang_mainHeader}}</h1>
+
+ <h4>{{lang_serverTable}}</h4>
+
+ <table class="table table-hover">
+ <tr>
+ <th width="1">{{lang_serverType}}</th>
+ <th>{{lang_locationName}}</th>
+ <th width="1"></th>
+ <th width="1"></th>
+ </tr>
+ {{#serverlist}}
+ <form method="post" action="?do=locationinfo">
+ <input type="hidden" name="token" value="{{token}}">
+ <input type="hidden" name="serverid" value="{{serverid}}">
+ <tr>
+ <td nowrap>{{typename}}</td>
+ <td nowrap>{{servername}}</td>
+
+ <td align="center" nowrap>
+ <button class="btn btn-sm {{^autherror}}btn-success{{/autherror}}{{#autherror}}btn-danger{{/autherror}}"
+ data-server-edit="{{serverid}}" {{disabled}} type="button">
+ <span style="margin-right: 5px;" class="glyphicon glyphicon-cog"></span>
+ {{lang_locationSettings}}
+ </button>
+ <button class="btn btn-sm btn-primary server-check" {{disabled}} name="action" value="checkConnection"
+ type="submit">
+ <span style="margin-right: 5px;" class="glyphicon glyphicon-refresh"></span>
+ {{lang_checkConnection}}
+ </button>
+ </td>
+ <td align="center" nowrap>
+ <button class="btn btn-sm btn-danger server-delete" type="submit" name="action" value="deleteServer">
+ <span style="margin-right: 5px;" class="glyphicon glyphicon-remove"></span>
+ {{lang_delete}}
+ </button>
+ </td>
+ </tr>
+ </form>
+ {{/serverlist}}
+ </table>
+
+ <div>
+ <button class="btn btn-sm btn-success" id="addServerButton" onclick="addServer()">
+ <span style="margin-right: 5px;" class="glyphicon glyphicon-plus"></span>
+ {{lang_addServer}}
+ </button>
+ </div>
+
+ <div class="modal fade" id="myModal" tabindex="-1" role="dialog">
+ <div class="modal-dialog">
+
+ <div class="modal-content">
+ <div class="modal-header" id="myModalHeader"></div>
+ <div class="modal-body" id="myModalBody"></div>
+ <div class="modal-footer">
+ <button type="submit" id="myModalSubmitButton" class="btn btn-primary" form="">{{lang_save}}</button>
+
+ <a class="btn btn-primary" data-dismiss="modal">{{lang_close}}</a>
+ </div>
+ </div>
+
+ </div>
+ </div>
+</div>
+<script type="text/javascript"><!--
+
+ document.addEventListener("DOMContentLoaded", function () {
+
+ /**
+ * Confirm deleting a server.
+ */
+ $('.server-delete').click(function(ev) {
+ var del = confirm("{{lang_deleteConfirmation}}");
+ if (!del) ev.preventDefault();
+ });
+
+ /**
+ * Animate refresh icon while page is loading
+ */
+ $('.server-check').click(function() {
+ $(this).find('.glyphicon').addClass('slx-rotation');
+ });
+
+ $('button[data-server-edit]').click(function() {
+ var id = $(this).data('server-edit');
+ loadServerSettingsModal(id);
+ });
+
+ });
+
+ /**
+ * Loads the settings modal of a server.
+ *
+ * @param serverid The id of the server.
+ */
+ function loadServerSettingsModal(serverid) {
+ $('#myModalHeader').text("{{lang_locationSettings}}").css("font-weight", "Bold");
+ $('#myModal .modal-dialog').css('width', '');
+ $('#myModal').modal('show');
+ $('#myModalBody').load("?do=locationinfo&action=serverSettings&id=" + serverid);
+ }
+
+ // ########### Server Table ###########
+
+ /**
+ * Loads a new / empty server settings modal.
+ */
+ function addServer() {
+ loadServerSettingsModal(0);
+ }
+//--></script>
diff --git a/modules-available/locationinfo/templates/timetable.html b/modules-available/locationinfo/templates/timetable.html
deleted file mode 100644
index 91a80877..00000000
--- a/modules-available/locationinfo/templates/timetable.html
+++ /dev/null
@@ -1,216 +0,0 @@
-<div>
- <div align="right">
- <label for="CB_1">{{lang_expertMode}}</label>
- <input class="bs-switch" name="1" id="CB_1" type="checkbox" {{#expertMode}}checked{{/expertMode}}>
- </div>
- <br>
-
- <div id="easyMode" style="{{#expertMode}}display: none;{{/expertMode}}">
- <form method="post" action="?do=locationinfo" id="timeFormEasy">
- <input type="hidden" name="token" value="{{token}}">
- <input type="hidden" name="action" value="updateOpeningTimeEasy">
- <input type="hidden" name="id" value="{{id}}">
- <input type="hidden" name="easyMode" value="{{easyMode}}">
-
- <table class="table table-condensed locations" 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" name="openingtime[]" id="openingtimepicker"
- pattern="[0-9]{1,2}:[0-9]{2}" value="{{openingtime0}}">
- </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" name="closingtime[]" id="openingtimepicker"
- pattern="[0-9]{1,2}:[0-9]{2}" value="{{closingtime0}}">
- </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" name="openingtime[]" id="openingtimepicker"
- pattern="[0-9]{1,2}:[0-9]{2}" value="{{openingtime1}}">
- </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" name="closingtime[]" id="openingtimepicker"
- pattern="[0-9]{1,2}:[0-9]{2}" value="{{closingtime1}}">
- </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" name="openingtime[]" id="openingtimepicker"
- pattern="[0-9]{1,2}:[0-9]{2}" value="{{openingtime2}}">
- </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" name="closingtime[]" id="openingtimepicker"
- pattern="[0-9]{1,2}:[0-9]{2}" value="{{closingtime2}}">
- </div>
- </td>
- </tr>
- </table>
- </form>
- </div>
-
- <div id="expertMode" style="{{#easyMode}}display: none;{{/easyMode}}">
- <form method="post" action="?do=locationinfo" id="timeFormExpert">
- <input type="hidden" name="token" value="{{token}}">
- <input type="hidden" name="action" value="updateOpeningTimeExpert">
- <input type="hidden" name="id" value="{{id}}">
- <input type="hidden" name="easyMode" value="{{easyMode}}">
-
-
- <table class="table table-condensed locations" style="margin-bottom:0">
- <tr>
- <th>{{lang_day}}</th>
- <th>{{lang_openingTime}}</th>
- <th>{{lang_closingTime}}</th>
- <th>{{lang_delete}}</th>
- </tr>
-
- {{#openingtimes}}
- <tr class=tablerow>
- <td>{{days}}</td>
- <td>{{openingtime}}</td>
- <td>{{closingtime}}</td>
- <td align="center"><input type="checkbox" name="delete[]" value="{{index}}"></td>
- </tr>
- {{/openingtimes}}
-
- <tr id="lastOpenTimesTableElement"></tr>
- </table>
-
- <br>
- <a class="btn btn-success btn-sm" onclick=newOpeningTime()>
- <span class="glyphicon glyphicon-plus-sign"></span>
- {{lang_openingTime}}
- </a>
- </form>
- </div>
-</div>
-
-<script>
- setTimepicker();
- $('#CB_1').bootstrapSwitch();
- $('#CB_1').on('switchChange.bootstrapSwitch', function (e, data) {
-
- if (data == false) {
- $('#expertMode').hide();
- $('#easyMode').show();
- $('#myModalSubmitButton').attr("Form", "timeFormEasy");
- } else {
- $('#easyMode').hide();
- $('#expertMode').show();
- $('#myModalSubmitButton').attr("Form", "timeFormExpert");
- }
- });
-
- if ('{{easyMode}}' == true) {
- $('#myModalSubmitButton').attr("Form", "timeFormEasy");
- } else if ('{{expertMode}}' == true) {
- $('#myModalSubmitButton').attr("Form", "timeFormExpert");
- }
-
- /**
- * Sets the timepicker element.
- */
- function setTimepicker() {
- $('.timepicker2').timepicker({
- minuteStep: 1,
- template: 'modal',
- appendWidgetTo: 'body',
- showSeconds: false,
- showMeridian: false,
- defaultTime: false
- });
- }
-
- /**
- * Adds a new opening time to the table in expert mode.
- */
- function newOpeningTime() {
- $('#lastOpenTimesTableElement').before('<tr>\
- <td>\
- <div class="form-group options">\
- <label><input required type="checkbox" name="days[]" value="Monday">{{lang_shortMonday}}</label>\
- <label><input required type="checkbox" name="days[]" value="Tuesday">{{lang_shortTuesday}}</label>\
- <label><input required type="checkbox" name="days[]" value="Wednesday">{{lang_shortWednesday}}</label>\
- <label><input required type="checkbox" name="days[]" value="Thursday">{{lang_shortThursday}}</label>\
- <label><input required type="checkbox" name="days[]" value="Friday">{{lang_shortFriday}}</label>\
- <label><input required type="checkbox" name="days[]" value="Saturday">{{lang_shortSaturday}}</label>\
- <label><input required type="checkbox" name="days[]" value="Sunday">{{lang_shortSunday}}</label>\
- </div>\
- <input type="hidden" name="days[]" value="-">\
- </td>\
- <td>\
- <div class="input-group bootstrap-timepicker">\
- <span class="input-group-addon">\
- <span class="glyphicon glyphicon-time"></span>\
- </span>\
- <input required type="text" class="form-control timepicker2" name="openingtime[]" id="openingtimepicker" pattern="[0-9]{1,2}:[0-9]{2}" value="8:00">\
- </div>\
- \
- </td>\
- <td>\
- \
- <div class="input-group bootstrap-timepicker">\
- <span class="input-group-addon">\
- <span class="glyphicon glyphicon-time"></span>\
- </span>\
- <input required type="text" class="form-control timepicker2" name="closingtime[]" id="closingtimepicker" pattern="[0-9]{1,2}:[0-9]{2}" value="18:00">\
- </div>\
- \
- </td>\
- <td align="center">\
- <input type="checkbox" name="dontadd[]" value="dontadd"\
- </td>\
- </tr>');
- setTimepicker();
-
- $(function () {
- var requiredCheckboxes = $('.options :checkbox[required]');
- requiredCheckboxes.change(function () {
- if (requiredCheckboxes.is(':checked')) {
- requiredCheckboxes.removeAttr('required');
- } else {
- requiredCheckboxes.attr('required', 'required');
- }
- });
- });
- }
-
-</script>
diff --git a/modules-available/locations/inc/location.inc.php b/modules-available/locations/inc/location.inc.php
index b2b6da4a..aff2dec5 100644
--- a/modules-available/locations/inc/location.inc.php
+++ b/modules-available/locations/inc/location.inc.php
@@ -27,6 +27,11 @@ class Location
return $rows;
}
+ /**
+ * Return row from location table for $locationId.
+ * @param $locationId
+ * @return array|bool row from DB, false if not found
+ */
public static function get($locationId)
{
return Database::queryFirst("SELECT * FROM location WHERE locationid = :locationId", compact('locationId'));
diff --git a/style/default.css b/style/default.css
index 894aa752..35b61277 100644
--- a/style/default.css
+++ b/style/default.css
@@ -467,6 +467,10 @@ nav.navbar.sidebar {
color: #fff;
}
+.red-bg, input[type="checkbox"]:checked {
+ background:#f77;
+}
+
/* this is based on https://github.com/flatlogic/awesome-bootstrap-checkbox
and "fixes" the style of radio buttons and check boxes.
it only applies if they're in a container that has the checkbox class */