return None
- def get_pref(self, key, default=None):
- return prefs.get(self.current_user or 'anonymous', key, default)
+ def get_pref(self, key):
+ return prefs.get(self.current_user or 'anonymous', key)
def set_pref(self, key, value):
return prefs.set(self.current_user or 'anonymous', key, value)
class PrefsHandler(BaseHandler):
- def get(self, key):
+ def get(self, key=None):
self.finish_json(self.get_pref(key))
- def post(self, key):
+ def post(self, key=None):
try:
value = json.loads(self.request.body)
_PREFS_FILE_NAME = 'prefs.json'
+_DEFAULT_PREFS = {
+ 'layout_columns': 3
+}
_prefs = None
file.close()
else:
- logging.debug('preferences file "%s" does not exist, using default preferences')
+ logging.debug('preferences file "%s" does not exist, using default preferences' % file_path)
def _save():
file.close()
-def get(username, key, default=None):
+def get(username, key=None):
if _prefs is None:
_load()
- return _prefs.get(username, {}).get(key, default)
+ if key:
+ return _prefs.get(username, {}).get(key, _DEFAULT_PREFS.get(key))
+
+ else:
+ return _prefs.get(username, _DEFAULT_PREFS)
def set(username, key, value):
if _prefs is None:
_load()
- _prefs.setdefault(username, {})[key] = value
- _save()
+ if key:
+ _prefs.setdefault(username, {})[key] = value
+
+ else:
+ _prefs[username] = value
+ _save()
(r'^/movie/(?P<camera_id>\d+)/(?P<op>download|preview|delete)/(?P<filename>.+?)/?$', handlers.MovieHandler),
(r'^/movie/(?P<camera_id>\d+)/(?P<op>delete_all)/(?P<group>.*?)/?$', handlers.MovieHandler),
(r'^/action/(?P<camera_id>\d+)/(?P<action>\w+)/?$', handlers.ActionHandler),
- (r'^/prefs/(?P<key>\w+)/?$', handlers.PrefsHandler),
+ (r'^/prefs/(?P<key>\w+)?/?$', handlers.PrefsHandler),
(r'^/_relay_event/?$', handlers.RelayEventHandler),
(r'^/log/(?P<name>\w+)/?$', handlers.LogHandler),
(r'^/update/?$', handlers.UpdateHandler),
height: 48px;
}
-body.admin div.logout-button {
- display: none;
-}
-
-body.admin div.settings-top-bar.closed div.logout-button {
- display: inline-block;
-}
-
-body:not(.admin) div.settings-top-bar div.logout-button {
- display: none;
-}
-
div.button.rem-camera-button {
display: none;
border: 1px solid transparent;
min-width: 360px;
}
-body:not(.admin) div.settings {
- display: none !important;
-}
-
div.settings-container {
position: relative;
padding-top: 10px;
min-width: 360px;
}
-body:not(.admin) div.settings-top-bar {
- display: none !important;
-}
-
div.settings-top-bar.closed div.apply-button {
display: none !important;
}
text-align: right;
background-color: rgba(100, 100, 100, 0.3);
padding: 5px 0.5em 5px 5px;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ user-select: none;
}
a.settings-section-title {
div.camera-frame {
width: 100% !important;
}
+
+ #layoutColumnsRow {
+ /* layout columns are ignored on small screens,
+ * so hide the prefs row as well */
+ display: none !important;
+ }
}
@media all and (max-height: 320px) {
});
});
- /* various change handlers */
+ /* prefs change handlers */
+ $('#layoutColumnsSlider').change(function () {
+ var columns = parseInt(this.value);
+ setLayoutColumns(columns);
+ savePrefs();
+ });
+ /* various change handlers */
$('#storageDeviceSelect').change(function () {
$('#rootDirectoryEntry').val('/');
});
}
});
+ if (!isAdmin()) {
+ $('#generalSectionDiv').each(markHideLogic);
+ $('#generalSectionDiv').next().each(markHideLogic);
+ }
+
if ($('#cameraSelect').find('option').length < 2) { /* no camera configured */
$('#videoDeviceEnabledSwitch').parent().each(markHideLogic);
$('#videoDeviceEnabledSwitch').parent().nextAll('div.settings-section-title, table.settings').each(markHideLogic);
return valid;
}
+function prefsUi2Dict() {
+ var dict = {
+ 'layout_columns': $('#layoutColumnsSlider').val()
+ };
+
+ return dict;
+}
+
+function dict2PrefsUi(dict) {
+ $('#layoutColumnsSlider').val(dict['layout_columns']);
+
+ updateConfigUI();
+}
+
+function applyPrefs(dict) {
+ setLayoutColumns(dict['layout_columns']);
+}
+
+function savePrefs() {
+ var prefs = prefsUi2Dict();
+ ajax('POST', basePath + 'prefs/', prefs);
+}
+
function mainUi2Dict() {
var dict = {
'show_advanced': $('#showAdvancedSwitch')[0].checked,
/* normal user with no cameras doesn't make too much sense - force login */
doLogout();
}
+
+ $('#cameraSelect').hide();
+ $('#remCameraButton').hide();
if (onFetch) {
onFetch(data);
/* add a progress indicator */
getPageContainer().append('<img class="main-loading-progress" src="' + staticPath + 'img/main-loading-progress.gif">');
- if (isAdmin()) {
- /* fetch the main configuration */
- ajax('GET', basePath + 'config/main/get/', null, function (data) {
- if (data == null || data.error) {
- showErrorMessage(data && data.error);
- return;
- }
-
- dict2MainUi(data);
+ /* fetch the prefs */
+ ajax('GET', basePath + 'prefs/', null, function (data) {
+ if (data == null || data.error) {
+ showErrorMessage(data && data.error);
+ return;
+ }
+
+ dict2PrefsUi(data);
+ applyPrefs(data);
+
+ if (isAdmin()) {
+ /* fetch the main configuration */
+ ajax('GET', basePath + 'config/main/get/', null, function (data) {
+ if (data == null || data.error) {
+ showErrorMessage(data && data.error);
+ return;
+ }
+
+ dict2MainUi(data);
+ fetchCameraList();
+ });
+ }
+ else {
fetchCameraList();
- });
- }
- else {
- fetchCameraList();
- }
+ }
+ });
}
function fetchCurrentCameraConfig(onFetch) {
var cameraImg = cameraFrameDiv.find('img.camera');
var progressImg = cameraFrameDiv.find('img.camera-progress');
- /* no camera buttons if not admin */
+ /* no configure button unless admin */
if (!isAdmin()) {
configureButton.hide();
}
<div class="button apply-button" id="applyButton">Apply</div>
{% if hostname %}<div class="hostname">{{hostname}}</div>{% endif %}
</div>
- <div class="button logout-button mouse-effect" title="switch user"></div>
<div class="logo">
<a href="/">
<span class="logo">motionEye</span>
<div class="page">
<div class="settings closed">
<div class="settings-container">
+ <!-- Preferences -->
+ <div class="settings-section-title" id="preferencesDiv">
+ <span class="help-mark" title="user preferences">?</span>
+ <a class="settings-section-title">Preferences</a>
+ <span class="minimize open"></span>
+ </div>
+ <table class="settings">
+ <tr class="settings-item" min="1" max="4" snap="1" ticksnum="4" decimals="0" id="layoutColumnsRow">
+ <td class="settings-item-label"><span class="settings-item-label">Layout Columns</span></td>
+ <td class="settings-item-value"><input type="text" class="range styled prefs" id="layoutColumnsSlider"></td>
+ <td><span class="help-mark" title="configures the number of columns to use when laying out the camera frames">?</span></td>
+ </tr>
+ </table>
<!-- General Settings -->
- <div class="settings-section-title">
+ <div class="settings-section-title" id="generalSectionDiv">
<span class="help-mark" title="general settings, not related to any camera">?</span>
<a class="settings-section-title">General Settings</a>
<span class="minimize open"></span>
</tr>
<!-- Video Device -->
- <div class="settings-section-title">
+ <div class="settings-section-title" id="deviceSectionDiv">
<input type="checkbox" class="styled section device camera-config" id="videoDeviceEnabledSwitch">
<span class="help-mark" title="enable this if you want to use this camera device">?</span>
<a class="settings-section-title">Video Device</a>
</table>
<!-- File Storage -->
- <div class="settings-section-title advanced-setting">
+ <div class="settings-section-title advanced-setting" id="storageSectionDiv">
<span class="help-mark" title="choose where and how your media files are saved">?</span>
<a class="settings-section-title">File Storage</a>
<span class="minimize"></span>
</table>
<!-- Text Overlay -->
- <div class="settings-section-title advanced-setting">
+ <div class="settings-section-title advanced-setting" id="textOverlaySectionDiv">
<input type="checkbox" class="styled section text-overlay camera-config" id="textOverlayEnabledSwitch">
<span class="help-mark" title="choose what information is displayed on the captured frames">?</span>
<a class="settings-section-title">Text Overlay</a>
</table>
<!-- Video Streaming -->
- <div class="settings-section-title" minimize-switch-independent="true">
+ <div class="settings-section-title" minimize-switch-independent="true" id="streamingSectionDiv">
<input type="checkbox" class="styled section streaming camera-config" id="videoStreamingEnabledSwitch">
<span class="help-mark" title="enable this if you want video streaming for this camera">?</span>
<a class="settings-section-title">Video Streaming</a>
</table>
<!-- Still Images -->
- <div class="settings-section-title">
+ <div class="settings-section-title" id="stillImagesSectionDiv">
<input type="checkbox" class="styled section still-images camera-config" id="stillImagesEnabledSwitch">
<span class="help-mark" title="enable this if you want to capture still images (pictures)">?</span>
<a class="settings-section-title">Still Images</a>
</table>
<!-- Movies -->
- <div class="settings-section-title">
+ <div class="settings-section-title" id="moviesSectionDiv">
<input type="checkbox" class="styled section movies camera-config" id="moviesEnabledSwitch">
<span class="help-mark" title="enable this if you want to record movies">?</span>
<a class="settings-section-title">Movies</a>
</table>
<!-- Motion Detection -->
- <div class="settings-section-title advanced-setting">
+ <div class="settings-section-title advanced-setting" id="motionDetectionSectionDiv">
<input type="checkbox" class="styled section motion-detection camera-config" id="motionDetectionEnabledSwitch">
<span class="help-mark" title="enable this to use and configure the motion detection mechanism">?</span>
<a class="settings-section-title">Motion Detection</a>
</table>
<!-- Motion Notifications -->
- <div class="settings-section-title advanced-setting">
+ <div class="settings-section-title advanced-setting" id="notificationsSectionDiv">
<span class="help-mark" title="enable this if you want to be notified when motion is detected">?</span>
<a class="settings-section-title">Motion Notifications</a>
<span class="minimize"></span>
</table>
<!-- Working Schedule -->
- <div class="settings-section-title" depends="motionDetectionEnabled">
+ <div class="settings-section-title" depends="motionDetectionEnabled" id="workingScheduleSectionDiv">
<input type="checkbox" class="styled section working-schedule camera-config" id="workingScheduleEnabledSwitch">
<span class="help-mark" title="enable this if you want to define a weekly working schedule for motion detection">?</span>
<a class="settings-section-title">Working Schedule</a>