Merge pull request #1449 from emanuelschuetze/angularjs

User templates with angularjs
This commit is contained in:
Oskar Hahn 2015-03-02 18:55:34 +01:00
commit 962dd209f5
22 changed files with 1259 additions and 680 deletions

View File

@ -7,15 +7,11 @@
"jquery.cookie": "~1.4.1", "jquery.cookie": "~1.4.1",
"bootstrap": "~3.3.1", "bootstrap": "~3.3.1",
"datatables-bootstrap3-plugin": "~0.2.0", "datatables-bootstrap3-plugin": "~0.2.0",
"angular": "~1.3.11", "angular": "~1.3.13",
"angular-ui-router": "~0.2.13", "angular-ui-router": "~0.2.13",
"angular-gettext": "~2.0.2",
"js-data-angular": "~2.1.0", "js-data-angular": "~2.1.0",
"sockjs": "~0.3.4", "sockjs": "~0.3.4",
"jed": "~1.1.0" "font-awesome-bower": "4.3.0"
},
"overrides": {
"jed": {
"main": "jed.js"
}
} }
} }

View File

@ -16,6 +16,7 @@ var argv = require('yargs').argv,
gulp = require('gulp'), gulp = require('gulp'),
concat = require('gulp-concat'), concat = require('gulp-concat'),
gulpif = require('gulp-if'), gulpif = require('gulp-if'),
gettext = require('gulp-angular-gettext'),
mainBowerFiles = require('main-bower-files'), mainBowerFiles = require('main-bower-files'),
minifyCSS = require('gulp-minify-css'), minifyCSS = require('gulp-minify-css'),
path = require('path'), path = require('path'),
@ -54,5 +55,24 @@ gulp.task('fonts', function() {
.pipe(gulp.dest(path.join(output_directory, 'fonts'))); .pipe(gulp.dest(path.join(output_directory, 'fonts')));
}); });
// Extracts translatable strings using angular-gettext and saves them in file
// openslides/locale/angular-gettext/template-en.pot.
gulp.task('pot', function () {
return gulp.src(['openslides/*/static/templates/*/*.html',
'openslides/*/static/js/*/*.js'])
.pipe(gettext.extract('template-en.pot', {}))
.pipe(gulp.dest('openslides/locale/angular-gettext/'));
});
// Compiles translation files (*.po) to *.json and saves them in the directory
// openslides/static/i18n/.
gulp.task('translations', function () {
return gulp.src('openslides/locale/angular-gettext/*.po')
.pipe(gettext.compile({
format: 'json'
}))
.pipe(gulp.dest(path.join(output_directory, 'i18n')));
});
// Gulp default task. Runs all other tasks before. // Gulp default task. Runs all other tasks before.
gulp.task('default', ['js', 'css', 'fonts'], function() {}); gulp.task('default', ['js', 'css', 'fonts'], function() {});

View File

@ -22,7 +22,14 @@ body {
padding: 7px 20px 0; padding: 7px 20px 0;
position: relative; position: relative;
} }
#header .logo img { .navbar-brand {
padding: 2px;
height: 40px;
}
.navbar-text {
margin-top: 9px;
}
#logo {
height: 30px; height: 30px;
padding-left: 3px; padding-left: 3px;
} }
@ -46,6 +53,13 @@ h1 {
margin: 0px 0 30px; margin: 0px 0 30px;
padding-bottom: 9px; padding-bottom: 9px;
} }
#submenu {
float: right;
font-size: 85%;
position: absolute;
top: 0;
right: 15px;
}
a:hover { a:hover {
text-decoration: none; text-decoration: none;
} }
@ -118,6 +132,7 @@ tr.total td {
.user_details label { .user_details label {
font-weight: bold; font-weight: bold;
margin: 10px 0 0 0; margin: 10px 0 0 0;
display: block;
} }
.user_details label:after { .user_details label:after {
content: ":"; content: ":";
@ -129,29 +144,11 @@ tr.total td {
} }
/** Forms **/ /** Forms **/
input, textarea {
width: 320px; /* Fix the top position by using fa-icons
} * in bootstrap's form elements with form-control-feedback */
.small-form input { .has-feedback i.form-control-feedback {
width: 55px; top: 35px;
}
.normal-form input {
width: 320px;
}
textarea {
height: 100px;
}
.help-inline {
font-size: 11px;
}
.errorlist{
margin: 0;
}
.errorlist li {
list-style: none outside none;
}
form .required label:after {
content: " *";
} }
legend + .control-group { legend + .control-group {
margin-top: 0px !important; margin-top: 0px !important;

View File

@ -1,6 +1,7 @@
angular.module('OpenSlidesApp', [ angular.module('OpenSlidesApp', [
'ui.router', 'ui.router',
'js-data', 'js-data',
'gettext',
'OpenSlidesApp.core', 'OpenSlidesApp.core',
'OpenSlidesApp.agenda', 'OpenSlidesApp.agenda',
'OpenSlidesApp.assignments', 'OpenSlidesApp.assignments',

View File

@ -115,16 +115,6 @@ angular.module('OpenSlidesApp.core', [])
}); });
}) })
.run(function($rootScope, i18n) {
// Puts the gettext methods into each scope.
// Uses the methods that are known by xgettext by default.
methods = ['gettext', 'dgettext', 'dcgettext', 'ngettext', 'dngettext',
'pgettext', 'dpgettext'];
_.forEach(methods, function(method) {
$rootScope[method] = _.bind(i18n[method], i18n);
});
})
.run(function($rootScope, Config) { .run(function($rootScope, Config) {
// Puts the config object into each scope. // Puts the config object into each scope.
// TODO: maybe rootscope.config has to set before findAll() is finished // TODO: maybe rootscope.config has to set before findAll() is finished
@ -164,25 +154,39 @@ angular.module('OpenSlidesApp.core', [])
return Autoupdate; return Autoupdate;
}) })
.factory('i18n', function($http) {
// TODO: there is a bug(?) in jed. I had to call val_idx++; in line 285
// TODO: make the language variable and changeable at runtime
var i18n = new Jed({
'domain': 'de',
'locale_data': {'de': {"": {}}},
}); // TODO: use promise here
$http.get('/static/i18n/de.json')
.success(function(data) {
// TODO: check data.
i18n.options.locale_data['de'] = data;
});
return i18n;
})
.factory('Config', function(DS) { .factory('Config', function(DS) {
return DS.defineResource({ return DS.defineResource({
name: 'config/config', name: 'config/config',
idAttribute: 'key', idAttribute: 'key',
endpoint: '/rest/config/config/' endpoint: '/rest/config/config/'
}); });
})
.controller("LanguageCtrl", function ($scope, gettextCatalog) {
// controller to switch app language
// TODO: detect browser language for default language
gettextCatalog.setCurrentLanguage('en');
//TODO: for debug only! (helps to find untranslated strings by adding "[MISSING]:")
gettextCatalog.debug = true;
$scope.switchLanguage = function (lang) {
gettextCatalog.setCurrentLanguage(lang);
if (lang != 'en') {
gettextCatalog.loadRemote("static/i18n/" + lang + ".json");
}
}
})
.directive('osFocusMe', function ($timeout) {
return {
link: function (scope, element, attrs, model) {
$timeout(function () {
element[0].focus();
});
}
};
});
// some general JavaScript functions used in all OpenSlides apps
$(function () {
$('[data-toggle="tooltip"]').tooltip({'placement': 'bottom'})
}); });

View File

@ -1,4 +1,6 @@
<h1>Dashboard</h1> <h1>Dashboard</h1>
<a ui-sref="assignments.assignment.list">Assignments</a> <ul>
<a ui-sref="agenda.item.list">Agenda</a> <li><a ui-sref="agenda.item.list">Agenda</a>
<a ui-sref="users.user.list">User</a> <li><a ui-sref="assignments.assignment.list">Assignments</a>
<li><a ui-sref="users.user.list">Participants</a>
</ul>

View File

@ -3,7 +3,6 @@
<!--[if IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]--> <!--[if IE 7]> <html lang="en" ng-app="myApp" class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]--> <!--[if IE 8]> <html lang="en" ng-app="myApp" class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html lang="en" ng-app="OpenSlidesApp" class="no-js"> <!--<![endif]--> <!--[if gt IE 8]><!--> <html lang="en" ng-app="OpenSlidesApp" class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<base href="/"> <base href="/">
@ -13,68 +12,123 @@
<link rel="stylesheet" href="static/css/openslides-libs.css"> <link rel="stylesheet" href="static/css/openslides-libs.css">
<link rel="stylesheet" href="static/css/app.css"> <link rel="stylesheet" href="static/css/app.css">
<script src="static/js/openslides-libs.js"></script> <script src="static/js/openslides-libs.js"></script>
</head>
<body>
<!-- Navbar --> <!-- Navbar -->
<nav id="header" class="navbar"> <nav id="header" class="navbar navbar-inverse">
<div class="container-fluid"> <div class="container-fluid">
<div class="navbar-header"> <div class="navbar-header">
<a href="/" class="logo"><img src="/static/img/logo.png" alt="OpenSlides" /></a> <a ui-sref="dashboard" class="navbar-brand">
<span class="title optional">{{ config('event_name') }}</span> <img id="logo" src="/static/img/logo.png" alt="OpenSlides" />
</a>
<span class="navbar-text optional">{{ config('event_name') }}</span>
</div> </div>
<div class="navbar-right" ng-controller="userMenu"> <div class="navbar-right" ng-controller="userMenu">
<!-- login/logout button --> <!-- login/logout button -->
<div class="btn-group"> <div class="btn-group">
<div ng-if="operator.isAuthenticated()"> <div ng-if="operator.isAuthenticated()">
<a href="#" data-toggle="dropdown" class="btn btn-default dropdown-toggle"> <button data-toggle="dropdown" class="btn btn-default dropdown-toggle">
<span class="glyphicon glyphicon-user" aria-hidden="true"></span> <span class="glyphicon glyphicon-user" aria-hidden="true"></span>
<span class="optional-small">{{ operator.user.get_short_name() }}</span> <span class="optional-small">{{ operator.user.get_short_name() }}</span>
<span class="caret"></span> <span class="caret"></span>
</a> </button>
<ul class="dropdown-menu pull-right"> <ul class="dropdown-menu pull-right">
<li><a href="{% url 'user_settings' %}"> <li><a href="{% url 'user_settings' %}">
<span class="glyphicon glyphicon-cog" aria-hidden="true"></span> <i class="fa fa-cog"></i>
{{ gettext("Edit profile") }}</a></li> <translate>Edit profile</translate>
<li><a href="{% url 'password_change' %}"> </a>
<span class="glyphicon glyphicon-lock" aria-hidden="true"></span> <li><a href="{% url 'password_change' %}">
{% trans "Change password" %}</a></li> <i class="fa fa-key"></i>
<li class="divider"></li> <translate>Change password</translate>
<li> </a>
<a ng-click="logout()"> <li class="divider">
<span class="glyphicon glyphicon-log-out" aria-hidden="true"></span> <li><a ng-click="logout()" href="">
Logout <i class="fa fa-sign-out"></i>
<translate>Logout</translate>
</a> </a>
</li>
</ul> </ul>
</div> </div>
<div ng-if="!operator.isAuthenticated()"> <div ng-if="!operator.isAuthenticated()">
<a href="#" ng-click="showLoginForm = true" class="btn btn-default"> <button class="btn btn-default" data-toggle="modal" data-target="#loginFormModal">
<span class="glyphicon glyphicon-log-in" aria-hidden="true"></span> <i class="fa fa-sign-in"></i>
{{ gettext("Login") }} <translate>Login</translate>
</a> </button>
<div ng-if="showLoginForm"> <div class="modal" id="loginFormModal" tabindex="-1" role="dialog"
aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="myModalLabel" translate>Please sign in!</h4>
</div>
<div class="modal-body">
<p ng-if='loginFailed' class="text-danger">
<strong translate>Username or password is not correct.</strong>
<form> <form>
username: <input type="text" ng-model="username"><br> <div class="input-group form-group">
password: <input type="password" ng-model="password"><br> <div class="input-group-addon"><i class="fa fa-user"></i></div>
<input type="submit" ng-click="login(username, password)" value="Save" /> <input type="text" ng-model="username" class="form-control input-lg"
placeholder="{{'Username'|translate}}">
</div>
<div class="input-group form-group">
<div class="input-group-addon"><i class="fa fa-key"></i></div>
<input type="password" ng-model="password" class="form-control input-lg"
placeholder="{{'Password'|translate}}">
</div>
<div class="form-group">
<button type="submit" ng-click="login(username, password)"
class="btn btn-primary btn-lg btn-block" translate>
Login
</button>
</div>
<div class="form-group">
<!-- TODO: if anonymous user is activate -->
<button type="submit" class="btn btn-default" translate>
Continue as guest
</button>
</div>
</form> </form>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
</div>
<!-- language switcher -->
<div class="btn-group" ng-controller="LanguageCtrl">
<button class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-expanded="false">
<i class="fa fa-flag"></i>
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right" role="menu">
<li><a href="" ng-click="switchLanguage('en')">
<i class="fa fa-flag"></i>
<translate>English</translate> (EN)
</a>
<li><a href="" ng-click="switchLanguage('de')">
<i class="fa fa-flag"></i>
<translate>German</translate> (DE)
</a>
<li><a href="" ng-click="switchLanguage('fr')">
<i class="fa fa-flag"></i>
<translate>French</translate> (FR)
</a>
</ul>
</div>
</div>
</div>
</nav> </nav>
<!-- Container --> <!-- Container -->
<div class="container-fluid" id="container"> <div class="container-fluid" id="container">
<div class="row"> <div class="row">
<!-- TODO: Sidebar navigation (main menu)
<!-- Sidebar navigation (main menu) -->
<div class="col-md-2 leftmenu lefticon"> <div class="col-md-2 leftmenu lefticon">
<ul> <ul>
{% for entry in main_menu_entries %} {% for entry in main_menu_entries %}
<li{% if entry.is_active %} class="active"{% endif %}> <li{% if entry.is_active %} class="active"{% endif %}>
<a href="{{ entry.get_url }}" class="tooltip-right"> <a href="{{ entry.get_url }}" class="tooltip-right">
<!--TODO-->
<span class="glyphicon {{ entry.get_icon_css_class }}" aria-hidden="true"></span> <span class="glyphicon {{ entry.get_icon_css_class }}" aria-hidden="true"></span>
<span class="text">{{ entry }}</span> <span class="text">{{ entry }}</span>
</a> </a>
@ -82,6 +136,7 @@
{% endfor %} {% endfor %}
</ul> </ul>
</div> </div>
-->
<!-- Content --> <!-- Content -->
<div id="content" class="col-md-10"> <div id="content" class="col-md-10">
@ -93,19 +148,17 @@
<hr /> <hr />
<footer> <footer>
<small> <small>
&copy; Copyright 20112015 | Powered by <a href="http://openslides.org" target="_blank">OpenSlides</a> | <a href="{% url 'core_version' %}">Version</a> &copy; Copyright 2011-2015 |
Powered by <a href="http://openslides.org" target="_blank">OpenSlides</a> |
<a href="{% url 'core_version' %}">Version</a>
</small> </small>
</footer> </footer>
</div><!--/#content--> </div><!--/#content-->
</div><!--/.row--> </div><!--/.row-->
</div><!--/#container--> </div><!--/#container-->
<script src="static/js/app.js"></script> <script src="static/js/app.js"></script>
<script src="static/js/core.js"></script> <script src="static/js/core.js"></script>
<script src="static/js/agenda/agenda.js"></script> <script src="static/js/agenda/agenda.js"></script>
<script src="static/js/assignments/assignments.js"></script> <script src="static/js/assignments/assignments.js"></script>
<script src="static/js/users/users.js"></script> <script src="static/js/users/users.js"></script>
</body>
</html>

View File

@ -0,0 +1,50 @@
# Language file of OpenSlides used by transifex:
# https://www.transifex.com/projects/p/openslides/
# Copyright (C) 20112013 by OpenSlides team, see AUTHORS.
# This file is distributed under the same license as the OpenSlides package.
# Translators:
# emanuel <emanuel@intevation.de>, 2013
# Emanuel Schütze <emanuel.schuetze@intevation.de>, 2013
# Emanuel Schütze <emanuel.schuetze@intevation.de>, 2013
# emanuel <emanuel@intevation.de>, 2013
# Emanuel Schütze <emanuel.schuetze@intevation.de>, 2013
# Emanuel Schütze <emanuel.schuetze@intevation.de>, 2013-2015
# Oskar Hahn <mail@oshahn.de>, 2012
# Norman Jäckel <transifex16062013@normanjaeckel.de>, 2013-2014
# Norman Jäckel <transifex16062013@normanjaeckel.de>, 2013
# Oskar Hahn <mail@oshahn.de>, 2012-2013
# Oskar Hahn <mail@oshahn.de>, 2012
msgid ""
msgstr ""
"Project-Id-Version: OpenSlides\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-01-16 14:24+0100\n"
"PO-Revision-Date: 2015-01-20 08:09+0000\n"
"Last-Translator: Emanuel Schütze <emanuel.schuetze@intevation.de>\n"
"Language-Team: German (http://www.transifex.com/projects/p/openslides/language/de/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: de\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: index.html:74
msgid "English"
msgstr "Englisch"
#: index.html:86
msgid "French"
msgstr "Französisch"
#: index.html:80
msgid "German"
msgstr "Deutsch"
#: user-list.html:26
msgid "Groups"
msgstr "Gruppen"
#: user-list.html:1
msgid "Participants"
msgstr "Teilnehmer"

View File

@ -0,0 +1,26 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: \n"
"Language: fr\n"
#: index.html:74
msgid "English"
msgstr "Anglais"
#: index.html:86
msgid "French"
msgstr "Français"
#: index.html:80
msgid "German"
msgstr "Allemand"
#: user-list.html:26
msgid "Groups"
msgstr "Groupe"
#: user-list.html:1
msgid "Participants"
msgstr "Participants"

View File

@ -0,0 +1,446 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Project-Id-Version: \n"
#: users/static/templates/users/user-csv-import.html:15
msgid ""
"'title, first name, last name, gender, email, group id, structure level,\n"
" committee, about me, comment, is active'"
msgstr ""
#: users/static/templates/users/user-detail.html:18
#: users/static/templates/users/user-form.html:60
msgid "About me"
msgstr ""
#: users/static/templates/users/group-list.html:32
#: users/static/templates/users/user-list.html:94
msgid "Actions"
msgstr ""
#: users/static/templates/users/user-detail.html:23
msgid "Administrative data"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:13
msgid "Apr"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:7
msgid "April"
msgstr ""
#: users/static/templates/users/user-csv-import.html:20
msgid ""
"At least first name or last name have to be filled in. All\n"
" other fields are optional and may be empty."
msgstr ""
#: core/static/js/jquery/datepicker-config.js:14
msgid "Aug"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:8
msgid "August"
msgstr ""
#: users/static/templates/users/group-detail.html:6
#: users/static/templates/users/group-form.html:7
#: users/static/templates/users/group-list.html:10
#: users/static/templates/users/user-csv-import.html:6
#: users/static/templates/users/user-detail.html:6
#: users/static/templates/users/user-form.html:7
msgid "Back to overview"
msgstr ""
#: users/static/templates/users/user-csv-import.html:32
msgid "CSV file:"
msgstr ""
#: users/static/templates/users/group-form.html:26
#: users/static/templates/users/user-csv-import.html:41
#: users/static/templates/users/user-form.html:79
msgid "Cancel"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:42
msgid "Close"
msgstr ""
#: users/static/templates/users/user-detail.html:26
#: users/static/templates/users/user-form.html:56
#: users/static/templates/users/user-list.html:87
msgid "Comment"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:41
msgid "Current time"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:15
msgid "Dec"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:9
msgid "December"
msgstr ""
#: users/static/templates/users/user-csv-import.html:17
msgid "Default groups"
msgstr ""
#: users/static/templates/users/user-form.html:51
msgid "Default password"
msgstr ""
#: users/static/templates/users/user-csv-import.html:18
msgid "Delegate"
msgstr ""
#: users/static/templates/users/group-list.html:51
#: users/static/templates/users/user-list.html:118
msgid "Delete"
msgstr ""
#: users/static/templates/users/group-list.html:46
#: users/static/templates/users/user-list.html:113
msgid "Edit"
msgstr ""
#: users/static/templates/users/user-form.html:1
msgid "Edit participant"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:12
msgid "Feb"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:6
msgid "February"
msgstr ""
#: users/static/templates/users/group-list.html:17
#: users/static/templates/users/user-list.html:63
msgid "Filter"
msgstr ""
#: users/static/templates/users/user-form.html:29
msgid "First name"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:23
#: core/static/js/jquery/datepicker-config.js:27
msgid "Fr"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:19
msgid "Friday"
msgstr ""
#: users/static/templates/users/user-list.html:83
msgid "Group"
msgstr ""
#: users/static/templates/users/user-form.html:46
msgid "Group is required."
msgstr ""
#: users/static/templates/users/group-list.html:1
#: users/static/templates/users/user-detail.html:15
#: users/static/templates/users/user-form.html:42
#: users/static/templates/users/user-list.html:25
msgid "Groups"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:39
msgid "Hour"
msgstr ""
#: users/static/templates/users/group-list.html:25
msgid "ID"
msgstr ""
#: users/static/templates/users/user-csv-import.html:38
#: users/static/templates/users/user-list.html:29
msgid "Import"
msgstr ""
#: users/static/templates/users/user-csv-import.html:1
msgid "Import participants"
msgstr ""
#: users/static/templates/users/user-form.html:72
msgid "Is active"
msgstr ""
#: users/static/templates/users/user-form.html:66
#: users/static/templates/users/user-list.html:59
msgid "Is present"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:12
msgid "Jan"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:6
msgid "January"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:14
msgid "Jul"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:8
msgid "July"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:13
msgid "Jun"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:7
msgid "June"
msgstr ""
#: users/static/templates/users/user-list.html:91
msgid "Last Login"
msgstr ""
#: users/static/templates/users/user-detail.html:28
msgid "Last login"
msgstr ""
#: users/static/templates/users/user-form.html:33
msgid "Last name"
msgstr ""
#: users/static/templates/users/user-list.html:50
msgid "List of access data"
msgstr ""
#: users/static/templates/users/user-list.html:45
msgid "List of participants"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:12
msgid "Mar"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:6
msgid "March"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:13
#: core/static/js/jquery/datepicker-config.js:7
msgid "May"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:40
msgid "Minute"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:22
#: core/static/js/jquery/datepicker-config.js:26
msgid "Mo"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:18
msgid "Monday"
msgstr ""
#: users/static/templates/users/user-list.html:19
msgid "Multiple participants"
msgstr ""
#: users/static/templates/users/group-form.html:13
#: users/static/templates/users/group-list.html:29
#: users/static/templates/users/user-list.html:75
msgid "Name"
msgstr ""
#: users/static/templates/users/group-list.html:6
#: users/static/templates/users/user-list.html:7
msgid "New"
msgstr ""
#: users/static/templates/users/user-form.html:2
msgid "New participant"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:15
msgid "Nov"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:9
msgid "November"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:15
msgid "Oct"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:9
msgid "October"
msgstr ""
#: users/static/templates/users/user-list.html:35
msgid "PDF"
msgstr ""
#: users/static/templates/users/user-list.html:1
msgid "Participants"
msgstr ""
#: users/static/templates/users/group-form.html:17
msgid "Permissions"
msgstr ""
#: users/static/templates/users/group-detail.html:11
msgid "Permissions:"
msgstr ""
#: users/static/templates/users/user-detail.html:12
msgid "Personal data"
msgstr ""
#: users/static/templates/users/user-csv-import.html:12
msgid "Please note:"
msgstr ""
#: users/static/templates/users/user-list.html:71
msgid "Present"
msgstr ""
#: users/static/templates/users/user-csv-import.html:23
msgid "Required CSV file encoding is UTF-8."
msgstr ""
#: users/static/templates/users/user-csv-import.html:14
msgid "Required comma separated values"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:23
#: core/static/js/jquery/datepicker-config.js:27
msgid "Sa"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:19
msgid "Saturday"
msgstr ""
#: users/static/templates/users/group-form.html:23
#: users/static/templates/users/user-form.html:76
msgid "Save"
msgstr ""
#: users/static/templates/users/user-csv-import.html:10
msgid "Select a CSV file to import users!"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:14
msgid "Sep"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:8
msgid "September"
msgstr ""
#: users/static/templates/users/group-list.html:40
#: users/static/templates/users/user-list.html:107
msgid "Show"
msgstr ""
#: users/static/templates/users/user-list.html:15
msgid "Single participant"
msgstr ""
#: users/static/templates/users/user-csv-import.html:19
msgid "Staff"
msgstr ""
#: users/static/templates/users/user-detail.html:13
#: users/static/templates/users/user-form.html:38
#: users/static/templates/users/user-list.html:79
msgid "Structure level"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:22
#: core/static/js/jquery/datepicker-config.js:26
msgid "Su"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:18
msgid "Sunday"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:23
#: core/static/js/jquery/datepicker-config.js:27
msgid "Th"
msgstr ""
#: users/static/templates/users/user-csv-import.html:34
msgid "The file has to be encoded in UTF-8."
msgstr ""
#: users/static/templates/users/user-csv-import.html:22
msgid "The first line (header) is ignored."
msgstr ""
#: core/static/js/jquery/datepicker-config.js:19
msgid "Thursday"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:38
msgid "Time"
msgstr ""
#. academic degree
#: users/static/templates/users/user-form.html:25
msgid "Title"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:22
#: core/static/js/jquery/datepicker-config.js:26
msgid "Tu"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:18
msgid "Tuesday"
msgstr ""
#: users/static/templates/users/user-csv-import.html:24
msgid "Use the CSV example file from OpenSlides Wiki."
msgstr ""
#: users/static/templates/users/user-detail.html:24
#: users/static/templates/users/user-form.html:14
msgid "Username"
msgstr ""
#: users/static/templates/users/user-form.html:19
msgid "Username is required."
msgstr ""
#: core/static/js/jquery/datepicker-config.js:22
#: core/static/js/jquery/datepicker-config.js:26
msgid "We"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:18
msgid "Wednesday"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:2
#: core/static/js/jquery/datepicker-config.js:32
msgid "en"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:4
msgid "next month"
msgstr ""
#: core/static/js/jquery/datepicker-config.js:3
msgid "previous month"
msgstr ""

View File

@ -1,220 +0,0 @@
# Language file of OpenSlides used by transifex:
# https://www.transifex.com/projects/p/openslides/
msgid ""
msgstr ""
"Project-Id-Version: 2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-01 11:55+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"plural_forms: nplurals=2; plural=(n != 1);"
#: openslides/agenda/static/js/agenda/agenda.js:51
msgid "test"
msgid_plural "tests"
msgstr[0] "test-de"
msgstr[1] "tests-de"
#: openslides/agenda/static/js/agenda.js:14
#, javascript-format
msgid ", of which %s are hidden."
msgstr ""
#: openslides/agenda/static/templates/agenda/item-list.html:7
msgid "New"
msgstr "Neu"
#: openslides/core/static/js/jquery/datepicker-config.js:2
#: openslides/core/static/js/jquery/datepicker-config.js:32
msgid "en"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:3
msgid "previous month"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:4
msgid "next month"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:6
msgid "January"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:6
msgid "February"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:6
msgid "March"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:7
msgid "April"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:7
#: openslides/core/static/js/jquery/datepicker-config.js:13
msgid "May"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:7
msgid "June"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:8
msgid "July"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:8
msgid "August"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:8
msgid "September"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:9
msgid "October"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:9
msgid "November"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:9
msgid "December"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:12
msgid "Jan"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:12
msgid "Feb"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:12
msgid "Mar"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:13
msgid "Apr"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:13
msgid "Jun"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:14
msgid "Jul"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:14
msgid "Aug"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:14
msgid "Sep"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:15
msgid "Oct"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:15
msgid "Nov"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:15
msgid "Dec"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Sunday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Monday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Tuesday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Wednesday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:19
msgid "Thursday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:19
msgid "Friday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:19
msgid "Saturday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "Su"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "Mo"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "Tu"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "We"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:23
#: openslides/core/static/js/jquery/datepicker-config.js:27
msgid "Th"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:23
#: openslides/core/static/js/jquery/datepicker-config.js:27
msgid "Fr"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:23
#: openslides/core/static/js/jquery/datepicker-config.js:27
msgid "Sa"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:38
msgid "Time"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:39
msgid "Hour"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:40
msgid "Minute"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:41
msgid "Current time"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:42
msgid "Close"
msgstr ""

View File

@ -1,220 +0,0 @@
# Language file of OpenSlides used by transifex:
# https://www.transifex.com/projects/p/openslides/
msgid ""
msgstr ""
"Project-Id-Version: 2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2015-02-01 11:55+0100\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=CHARSET\n"
"Content-Transfer-Encoding: 8bit\n"
"plural_forms: nplurals=2; plural=(n != 1);"
#: openslides/agenda/static/js/agenda/agenda.js:51
msgid "test"
msgid_plural "tests"
msgstr[0] ""
msgstr[1] ""
#: openslides/agenda/static/js/agenda.js:14
#, javascript-format
msgid ", of which %s are hidden."
msgstr ""
#: openslides/agenda/static/templates/agenda/item-list.html:7
msgid "New"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:2
#: openslides/core/static/js/jquery/datepicker-config.js:32
msgid "en"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:3
msgid "previous month"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:4
msgid "next month"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:6
msgid "January"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:6
msgid "February"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:6
msgid "March"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:7
msgid "April"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:7
#: openslides/core/static/js/jquery/datepicker-config.js:13
msgid "May"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:7
msgid "June"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:8
msgid "July"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:8
msgid "August"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:8
msgid "September"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:9
msgid "October"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:9
msgid "November"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:9
msgid "December"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:12
msgid "Jan"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:12
msgid "Feb"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:12
msgid "Mar"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:13
msgid "Apr"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:13
msgid "Jun"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:14
msgid "Jul"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:14
msgid "Aug"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:14
msgid "Sep"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:15
msgid "Oct"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:15
msgid "Nov"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:15
msgid "Dec"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Sunday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Monday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Tuesday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:18
msgid "Wednesday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:19
msgid "Thursday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:19
msgid "Friday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:19
msgid "Saturday"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "Su"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "Mo"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "Tu"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:22
#: openslides/core/static/js/jquery/datepicker-config.js:26
msgid "We"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:23
#: openslides/core/static/js/jquery/datepicker-config.js:27
msgid "Th"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:23
#: openslides/core/static/js/jquery/datepicker-config.js:27
msgid "Fr"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:23
#: openslides/core/static/js/jquery/datepicker-config.js:27
msgid "Sa"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:38
msgid "Time"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:39
msgid "Hour"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:40
msgid "Minute"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:41
msgid "Current time"
msgstr ""
#: openslides/core/static/js/jquery/datepicker-config.js:42
msgid "Close"
msgstr ""

View File

@ -18,7 +18,13 @@ angular.module('OpenSlidesApp.users', [])
} }
} }
}) })
.state('users.user.create', {}) .state('users.user.create', {
resolve: {
groups: function(Group) {
return Group.findAll();
}
}
})
.state('users.user.detail', { .state('users.user.detail', {
resolve: { resolve: {
user: function(User, $stateParams) { user: function(User, $stateParams) {
@ -29,6 +35,47 @@ angular.module('OpenSlidesApp.users', [])
.state('users.user.detail.update', { .state('users.user.detail.update', {
views: { views: {
'@users.user': {} '@users.user': {}
},
resolve: {
groups: function(Group) {
return Group.findAll();
}
}
})
.state('users.user.csv-import', {
url: '/csv-import',
controller: 'UserCSVImportCtrl',
})
// groups
.state('users.group', {
url: '/groups',
abstract: true,
template: "<ui-view/>",
})
.state('users.group.list', {
resolve: {
groups: function(Group) {
return Group.findAll();
}
}
})
.state('users.group.create', {
resolve: {
groups: function(Group) {
return Group.findAll();
}
}
})
.state('users.group.detail', {
resolve: {
group: function(Group, $stateParams) {
return Group.find($stateParams.id);
}
}
})
.state('users.group.detail.update', {
views: {
'@users.group': {}
} }
}); });
}) })
@ -187,30 +234,99 @@ angular.module('OpenSlidesApp.users', [])
}; };
}]) }])
.controller('UserListCtrl', function($scope, User, i18n) { .controller('UserListCtrl', function($scope, User) {
User.bindAll({}, $scope, 'users'); User.bindAll({}, $scope, 'users');
$scope.sortby = 'first_name';
$scope.reverse = false;
$scope.filterPresent = '';
$scope.togglePresent = function (user) {
//the value was changed by the template (checkbox)
User.save(user);
};
$scope.delete = function (user) {
//TODO: add confirm message
User.destroy(user.id).then(
function(success) {
//TODO: success message
}
);
};
}) })
.controller('UserDetailCtrl', function($scope, User, user) { .controller('UserDetailCtrl', function($scope, User, user) {
User.bindOne(user.id, $scope, 'user'); User.bindOne(user.id, $scope, 'user');
}) })
.controller('UserCreateCtrl', function($scope, User) { .controller('UserCreateCtrl', function($scope, $state, User, Group) {
Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups');
$scope.user = {}; $scope.user = {};
$scope.save = function (user) { $scope.save = function (user) {
User.create(user); User.create(user).then(
// TODO: redirect to list-view function(success) {
$state.go('users.user.list');
}
);
}; };
}) })
.controller('UserUpdateCtrl', function($scope, User, user) { .controller('UserUpdateCtrl', function($scope, $state, User, user, Group) {
$scope.user = user; // do not use Agenda.binOne(...) so autoupdate is not activated Group.bindAll({where: {id: {'>': 2}}}, $scope, 'groups');
$scope.user = user; // autoupdate is not activated
$scope.save = function (user) { $scope.save = function (user) {
User.save(user); User.save(user).then(
// TODO: redirect to list-view function(success) {
$state.go('users.user.list');
}
);
}; };
}) })
.controller('UserCSVImportCtrl', function($scope, User) {
// TODO
})
.controller('GroupListCtrl', function($scope, Group) {
Group.bindAll({}, $scope, 'groups');
$scope.delete = function (group) {
//TODO: add confirm message
Group.destroy(group.id).then(
function(success) {
//TODO: success message
}
);
};
})
.controller('GroupCreateCtrl', function($scope, $state, Group) {
//TODO: permissions Group.bindAll({}, $scope, 'groups');
$scope.group = {};
$scope.save = function (group) {
Group.create(group).then(
function(success) {
$state.go('^');
}
);
};
})
.controller('GroupUpdateCtrl', function($scope, $state, Group, group) {
$scope.group = group; // autoupdate is not activated
$scope.save = function (group) {
Group.save(group).then(
function(success) {
$state.go('users.group.list');
}
);
};
})
.controller('GroupDetailCtrl', function($scope, Group, group) {
Group.bindOne(group.id, $scope, 'group');
})
.controller('userMenu', function($scope, $http, DS, User, operator) { .controller('userMenu', function($scope, $http, DS, User, operator) {
$scope.logout = function() { $scope.logout = function() {
$http.post('/users/logout/').success(function(data) { $http.post('/users/logout/').success(function(data) {
@ -225,8 +341,12 @@ angular.module('OpenSlidesApp.users', [])
'/users/login/', '/users/login/',
{'username': username, 'password': password} {'username': username, 'password': password}
).success(function(data) { ).success(function(data) {
if (data.success) {
operator.setUser(data.user_id); operator.setUser(data.user_id);
$scope.showLoginForm = false; $scope.loginFailed = false;
} else {
$scope.loginFailed = true;
}
}); });
}; };
}); });

View File

@ -0,0 +1,14 @@
<h1>{{ group.name }}</h1>
<div id="submenu">
<a ui-sref="users.group.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
</div>
<b translate>Permissions:</b>
<ul ng-repeat="perm in group.permissions">
<li>{{ perm }}
</ul>

View File

@ -0,0 +1,29 @@
<h1 ng-if="group.id">Edit group</h1>
<h1 ng-if="!group.id">New group</h1>
<div id="submenu">
<a ui-sref="users.group.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
</div>
<form name="userForm">
<div class="form-group">
<label for="inputName" translate>Name</label>
<input type="text" ng-model="group.name" class="form-control" name="inputName" ng-required="true">
</div>
<div class="form-group">
<label for="selectPermissions" translate>Permissions</label>
<select ng-options="group.permissions for group in groups"
ng-model="group.permissions" class="form-control" name="selectGroups">
</select>
</div>
<button type="submit" ng-click="save(group)" class="btn btn-primary" translate>
Save
</button>
<button ui-sref="users.group.list" class="btn btn-default" translate>
Cancel
</button>
</form>

View File

@ -0,0 +1,54 @@
<h1 translate>Groups</h1>
<div id="submenu">
<a ui-sref="users.group.create" os-perms="users.can_manage" class="btn btn-primary btn-sm">
<i class="fa fa-user-plus fa-lg"></i>
<translate>New</translate>
</a>
<a ui-sref="users.user.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
</div>
<div class="row form-group">
<div class="col-sm-4 right">
<input type="text" os-focus-me ng-model="filter.search" class="form-control"
placeholder="{{ 'Filter' | translate }}">
</div>
</div>
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th ng-click="sortby='id';reverse=!reverse">
<translate>ID</translate>
<i class="fa" ng-show="sortby == 'id'"
ng-class="reverse ? 'fa-caret-down' : 'fa-caret-up'"></i>
<th ng-click="sortby='name';reverse=!reverse">
<translate>Name</translate>
<i class="fa" ng-show="sortby == 'name'"
ng-class="reverse ? 'fa-caret-down' : 'fa-caret-up'"></i>
<th os-perms="users.can_manage core.can_manage_projector" class="mini_width" translate>Actions</th>
<tbody>
<tr ng-repeat="group in groups | filter: filter.search | orderBy:sortby:reverse">
<td>{{ group.id }}
<td><a ui-sref="users.group.detail({id: group.id })">{{ group.name }}</a>
<td os-perms="users.can_manage core.can_manage_projector" class="nobr">
<!-- projector, TODO: add link to activate slidea-->
<a href="#TODO" os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
title="{{ 'Show' | translate }}">
<i class="fa fa-video-camera"></i>
</a>
<!-- edit -->
<a ui-sref="users.group.detail.update({id: group.id })" os-perms="users.can_manage"
class="btn btn-default btn-sm"
title="{{ 'Edit' | translate }}">
<i class="fa fa-pencil"></i>
</a>
<!-- delete -->
<a ng-click="delete(group)" os-perms="users.can_manage" class="btn btn-danger btn-sm"
title="{{ 'Delete' | translate }}">
<i class="fa fa-trash-o"></i>
</a>
</table>

View File

@ -0,0 +1,44 @@
<h1 translate>Import participants</h1>
<div id="submenu">
<a ui-sref="users.user.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
</div>
<p translate>Select a CSV file to import users!
<p translate>Please note:</p>
<ul>
<li><translate>Required comma separated values</translate>:<br>
<code translate>'title, first name, last name, gender, email, group id, structure level,
committee, about me, comment, is active'</code>
<li><translate>Default groups</translate>:
<translate>Delegate</translate> <code>3</code>,
<translate>Staff</translate> <code>4</code>
<li translate>At least first name or last name have to be filled in. All
other fields are optional and may be empty.
<li translate>The first line (header) is ignored.
<li translate>Required CSV file encoding is UTF-8.
<li><a href="https://github.com/OpenSlides/OpenSlides/wiki/CSV-Import" translate>
Use the CSV example file from OpenSlides Wiki.
</a>
</ul>
<!-- TODO: add post url to form-->
<form>
<div class="form-group">
<label for="InputFile" translate>CSV file:</label>
<input type="file" id="InputFile">
<p class="help-block" translate>The file has to be encoded in UTF-8.
</div>
<!--TODO-->
<button type="submit" ng-click="" class="btn btn-primary" translate>
Import
</button>
<button ui-sref="users.user.list" class="btn btn-default" translate>
Cancel
</button>
</form>

View File

@ -1,2 +1,31 @@
<h1>Persönliche Daten</h1> <h1>{{ user.get_short_name() }}</h1>
{{ user.get_short_name() }}
<div id="submenu">
<a ui-sref="users.user.list" class="btn btn-sm btn-default">
<i class="fa fa-angle-double-left fa-lg"></i>
<translate>Back to overview</translate>
</a>
</div>
<div class="user_details form-group">
<fieldset>
<legend translate>Personal data</legend>
<label translate>Structure level</label>
{{ user.structure_level }}
<label translate>Groups</label>
{{ user.groups }}
<!-- TODO: print all groups -->
<label translate>About me</label>
{{ user.about_me }}
</fieldset>
<fieldset os-perms="users.can_manage">
<legend translate>Administrative data</legend>
<label translate>Username</label>
{{ user.username }}
<label translate>Comment</label>
{{ user.comment }}
<label translate>Last login</label>
{{ user.last_login }}
</fieldset>
</div>

View File

@ -1,8 +1,82 @@
<h1 ng-if="user.id">{{ user.get_short_name() }}</h1> <h1 ng-if="user.id" translate>Edit participant</h1>
<h1 ng-if="!user.id">{{ gettext("New User") }}</h1> <h1 ng-if="!user.id" translate>New participant</h1>
<form> <div id="submenu">
firstname: <input type="text" ng-model="user.first_name"><br> <a ui-sref="users.user.list" class="btn btn-sm btn-default">
lastname: <input type="text" ng-model="user.last_name"><br> <i class="fa fa-angle-double-left fa-lg"></i>
<input type="submit" ng-click="save(user)" value="Save" /> <translate>Back to overview</translate>
</a>
</div>
<form name="userForm">
<div ng-if="user.id" ng-class="{'has-error has-feedback': userForm.inputUsername.$error.required}"
class="form-group">
<label for="inputUsername" translate>Username</label>
<input type="text" ng-model="user.username" ng-required="true" class="form-control"
name="inputUsername">
<i ng-if="userForm.inputUsername.$error.required"
class="fa fa-times fa-lg form-control-feedback"></i>
<p ng-show="userForm.inputUsername.$error.required"
class="error-message help-block" translate>
Username is required.
</div>
<div class="form-group row">
<div class="col-xs-2">
<label for="inputTitle" translate-comment="academic degree" translate>Title</label>
<input type="text" ng-model="user.title" class="form-control" name="inputTitle">
</div>
<div class="col-xs-5">
<label for="inputFirstName" translate>First name</label>
<input type="text" ng-model="user.first_name" class="form-control" name="inputFirstName">
</div>
<div class="col-xs-5">
<label for="inputLastName" translate>Last name</label>
<input type="text" ng-model="user.last_name" class="form-control" name="inputLastName">
</div>
</div>
<div class="form-group">
<label for="inputStructureLevel" translate>Structure level</label>
<input type="text" ng-model="user.structure_level" class="form-control" name="inputStructureLevel">
</div>
<div class="form-group" ng-class="{'has-error has-feedback': userForm.selectGroups.$error.required}">
<label for="selectGroups" translate>Groups</label>
<select multiple ng-options="group.id as group.name for group in groups"
ng-required="true" ng-model="user.groups" class="form-control" name="selectGroups">
</select>
<p ng-show="userForm.selectGroups.$error.required" class="error-message help-block" translate>
Group is required.
</div>
<div class="form-group row">
<div class="col-xs-6">
<label for="inputDefaultPassword" translate>Default password</label>
<input type="text" ng-model="user.default_password" class="form-control" name="inputDefaultPassword">
</div>
</div>
<div class="form-group">
<label for="textComment" translate>Comment</label>
<textarea ng-model="user.comment" class="form-control" name="textComment" />
</div>
<div class="form-group">
<label for="textAbout" translate>About me</label>
<textarea ng-model="user.about_me" class="form-control" name="textAbout" />
</div>
<div class="form-group">
<label class="checkbox-inline">
<input type="checkbox" ng-model="user.is_present" ng-checked="user.is_present" name="checkboxActive">
<translate>Is present</translate>
</label>
</div>
<div class="form-group">
<label class="checkbox-inline">
<input type="checkbox" ng-model="user.is_active" ng-checked="user.is_active" name="checkboxActive">
<translate>Is active</translate>
</label>
</div>
<button type="submit" ng-click="save(user)" class="btn btn-primary" translate>
Save
</button>
<button ui-sref="users.user.list" class="btn btn-default" translate>
Cancel
</button>
</form> </form>

View File

@ -1,10 +1,121 @@
<ul> <h1 translate>Participants</h1>
<li ng-repeat="user in users">
<a ui-sref="users.user.detail({id: user.id })">{{ user.get_short_name() }}</a>
<a ui-sref="users.user.detail.update({id: user.id })">{{ gettext('Edit') }}</a>
</li>
</ul>
<a os-perms="users.can_manage" ui-sref="users.user.create">{{ gettext('New') }}</a> <div id="submenu">
<span os-perms="!users.can_manage">No Permission to create</span> <div os-perms="users.can_manage" class="btn-group">
<a href="/users/print/" target="_self">PDF</a> <a ui-sref="users.user.create" class="btn btn-primary btn-sm">
<i class="fa fa-user-plus fa-lg"></i>
<translate>New</translate>
</a>
<button class="btn btn-primary btn-sm dropdown-toggle" data-toggle="dropdown">
<span class="fa fa-caret-down"></span>
</button>
<ul class="dropdown-menu">
<li><a ui-sref="users.user.create">
<i class="fa fa-user fa-fw"></i>
<translate>Single participant</translate>
</a>
<li><a href="#TODO">
<i class="fa fa-group fa-fw"></i>
<translate>Multiple participants</translate>
</a>
</ul>
</div>
<a ui-sref="users.group.list" os-perms="users.can_manage" class="btn btn-default btn-sm">
<i class="fa fa-group fa-lg"></i>
<translate>Groups</translate>
</a>
<a ui-sref="users.user.csv-import" os-perms="users.can_manage" class="btn btn-default btn-sm">
<i class="fa fa-download fa-lg"></i>
<translate>Import</translate>
</a>
<div class="btn-group">
<!-- TODO: use ui-sref -->
<a href="/users/print/" class="btn btn-default btn-sm" target="_blank">
<i class="fa fa-file-pdf-o fa-lg"></i>
<translate>PDF</translate>
</a>
<button os-perms="users.can_manage" class="btn btn-default btn-sm dropdown-toggle"
data-toggle="dropdown">
<i class="fa fa-caret-down"></i>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<!-- TODO: use ui-sref -->
<li><a href="/users/print/" target="_blank">
<i class="fa fa-list fa-fw"></i>
<translate>List of participants</translate>
</a>
<li os-perms="users.can_manage">
<a href="/users/passwords/print/" target="_blank">
<i class="fa fa-qrcode fa-fw"></i>
<translate>List of access data</translate>
</a>
</ul>
</div>
</div>
<div class="row form-group">
<div class="col-sm-8">
<input type="checkbox" ng-model="filterPresent" ng-false-value="''">
<translate>Is present</translate>
</div>
<div class="col-sm-4">
<input type="text" os-focus-me ng-model="filter.search" class="form-control"
placeholder="{{ 'Filter' | translate}}">
</div>
</div>
<table class="table table-striped table-bordered table-hover">
<thead>
<tr>
<th ng-click="sortby='is_present';reverse=!reverse">
<translate>Present</translate>
<i class="fa" ng-show="sortby == 'is_present'"
ng-class="reverse ? 'fa-sort-desc' : 'fa-sort-asc'"></i>
<th ng-click="sortby='first_name';reverse=!reverse">
<translate>Name</translate>
<i class="fa" ng-show="sortby == 'first_name'"
ng-class="reverse ? 'fa-caret-down' : 'fa-caret-up'"></i>
<th class="optional" ng-click="sortby='structure_level';reverse=!reverse">
<translate>Structure level</translate>
<i class="fa" ng-show="sortby == 'structure_level'"
ng-class="reverse ? 'fa-caret-down' : 'fa-caret-up'"></i>
<th class="optional" ng-click="sortby='groups';reverse=!reverse">
<translate>Group</translate>
<i class="fa" ng-show="sortby == 'groups'"
ng-class="reverse ? 'fa-caret-down' : 'fa-caret-up'"></i>
<th os-perms="users.can_manage" class="optional" ng-click="sortby='comment';reverse=!reverse">
<translate>Comment</translate>
<i class="fa" ng-show="sortby == 'comment'"
ng-class="reverse ? 'fa-caret-down' : 'fa-caret-up'"></i>
<th os-perms="users.can_manage" class="optional" ng-click="sortby='last_login';reverse=!reverse">
<translate>Last Login</translate>
<i class="fa" ng-show="sortby == 'last_login'"
ng-class="reverse ? 'fa-caret-down' : 'fa-caret-up'"></i>
<th os-perms="users.can_manage core.can_manage_projector" class="mini_width" translate>Actions</th>
<tbody>
<tr ng-repeat="user in users | filter: filter.search | filter: {is_present: filterPresent} |
orderBy: sortby:reverse">
<td><input type="checkbox" ng-model="user.is_present" ng-click="togglePresent(user)">
<td><a ui-sref="users.user.detail({id: user.id})">{{ user.get_short_name() }}</a>
<td class="optional">{{ user.structure_level }}
<td class="optional">{{ user.groups }}
<td os-perms="users.can_manage" class="optional">{{ user.comment }}
<td os-perms="users.can_manage" class="optional">{{ user.last_login | date:'yyyy-MM-dd HH:mm:ss'}}
<td os-perms="users.can_manage core.can_manage_projector" class="nobr">
<!-- projector, TODO: add link to activate slidea-->
<a href="#TODO" os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
title="{{ 'Show' | translate }}">
<i class="fa fa-video-camera"></i>
</a>
<!-- edit -->
<a ui-sref="users.user.detail.update({id: user.id })" os-perms="users.can_manage"
class="btn btn-default btn-sm"
title="{{ 'Edit' | translate}}">
<i class="fa fa-pencil"></i>
</a>
<!-- delete -->
<a ng-click="delete(user)" os-perms="users.can_manage" class="btn btn-danger btn-sm"
title="{{ 'Delete' | translate }}">
<i class="fa fa-trash-o"></i>
</a>
</table>

View File

@ -1,52 +0,0 @@
{% extends "base.html" %}
{% load i18n %}
{% block title %}{% trans "Import users" %} {{ block.super }}{% endblock %}
{% block content %}
<h1>
{% trans 'Import users' %}
<small class="pull-right">
<a href="{% url 'user_list' %}" class="btn btn-mini">
<i class="icon-chevron-left"></i>
{% trans "Back to overview" %}
</a>
</small>
</h1>
<p>{% trans 'Select a CSV file to import users' %}.</p>
<p>{% trans 'Please note' %}:</p>
<ul>
<li>
{% trans 'Required comma separated values' %}:<br>
<code>{% trans 'title, first name, last name, gender, email, group id, structure level, committee, about me, comment, is active' %}</code>
</li>
<li>
{% trans 'Default groups' %}:
{% trans 'Delegate' %} <code>3</code>, {% trans 'Staff' %} <code>4</code>
</li>
<li>
{% trans 'At least first name or last name have to be filled in. All other fields are optional and may be empty.' %}
</li>
<li>{% trans 'The first line (header) is ignored' %}.</li>
<li>
{% trans 'Required CSV file encoding is UTF-8' %}.
</li>
<li><a href="https://github.com/OpenSlides/OpenSlides/wiki/CSV-Import">{% trans 'Use the CSV example file from OpenSlides Wiki.' %}</a></li>
</ul>
<form enctype="multipart/form-data" action="" method="post">{% csrf_token %}
{% include "form.html" %}
<p>
<button class="btn btn-primary" type="submit">
<span class="icon import">{% trans 'Import' %}</span>
</button>
<a href="{% url 'user_list' %}" class="btn">
{% trans 'Cancel' %}
</a>
</p>
<small>* {% trans "required" %}</small>
</form>
{% endblock %}

View File

@ -4,6 +4,7 @@
"devDependencies": { "devDependencies": {
"bower": "~1.3.12", "bower": "~1.3.12",
"gulp": "~3.8.10", "gulp": "~3.8.10",
"gulp-angular-gettext": "~2.1.0",
"gulp-concat": "~2.4.3", "gulp-concat": "~2.4.3",
"gulp-if": "~1.2.5", "gulp-if": "~1.2.5",
"gulp-minify-css": "~0.3.11", "gulp-minify-css": "~0.3.11",