Merge pull request #3682 from FinnStutzenstein/voting-plugin

Changes for the voting plugin
This commit is contained in:
Emanuel Schütze 2018-04-13 15:11:48 +02:00 committed by GitHub
commit b6ebc78e85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 115 additions and 35 deletions

View File

@ -125,11 +125,14 @@
</div>
<h3 translate>Election result</h3>
<button os-perms="assignments.can_manage" ng-show="assignment.phase !== 2" ng-click="createBallot()"
class="btn btn-default btn-sm">
<i class="fa fa-bar-chart fa-lg"></i>
<translate>New ballot</translate>
</button>
<template-hook hook-name="assignmentPollNewBallotButton">
<button os-perms="assignments.can_manage" ng-show="assignment.phase !== 2" ng-click="createBallot()"
class="btn btn-default btn-sm">
<i class="fa fa-bar-chart fa-lg"></i>
<translate>New ballot</translate>
</button>
</template-hook>
<uib-tabset ng-if="assignment.polls.length > 0" class="spacer ballot-tabs" active="$parent.activeTab">
<uib-tab ng-repeat="poll in assignment.polls | orderBy:'id'"
index="$index" heading="{{ 'Ballot' | translate }} {{ $index + 1 }}">
@ -276,7 +279,7 @@
</uib-tabset>
<!-- Workaround to prevent page scrolling up after autoupdate. -->
<div style="height: 700px"><div>
<div style="height: 700px"></div>
</div>
<template-hook hook-name="assignmentDetailViewDetailContainer"></template-hook>

View File

@ -9,6 +9,7 @@
<i class="fa fa-tags fa-lg"></i>
<translate>Tags</translate>
</a>
<template-hook hook-name="assignmentListMenuButton"></template-hook>
</div>
<h1 translate>Elections</h1>
</div>

View File

@ -553,27 +553,57 @@ angular.module('OpenSlidesApp.core', [
])
// Template hooks
// 2 possible uses:
// - { Id: 'myHookId', template: '<button>click me</button>' }
// - { Id: 'myHookId', templateUrl: '/static/templates/plugin_name/my-hook.html' }
// It is possible to provide a scope, that is merged into the scope of the templateHook.
// This overrides functions/values of the parent scope, but there may are conflicts
// with other plugins defining the same function/value. E.g.:
// Possible uses:
// 1. { id: 'myHookId', template: '<button>click me</button>' }
// 2. { id: 'myHookId', templateUrl: '/static/templates/plugin_name/my-hook.html' }
// 3. { id: 'myHookId' }
//
// Deprecated: Give the id with 'Id'. Please use 'id'.
//
// Option 3 is for just changing the scope (see below), but not the original content. This
// is usefull to alter a JS behavior, e.g. on a ng-click. In this case, override is false
// for this template hook.
//
// It is possible to provide a scope, that is merged into the surrounding scope.
// You can override functions or values of the surrounding scope by providing them:
// { Id: 'hookId', template: '<button ng-click="customFn()">click me</button>',
// scope: {
// customFn: function () { /*Do something */ },
// customOrOverwritten: function () { /*Do something */ },
// },
// }
// Or you provide a function that returns an object of functions/values to overwrite to
// get access to the scope merged in:
// { Id: 'hookId', template: '<button ng-click="customFn()">click me</button>',
// scope: function (scope) {
// return {
// customOrOverwritten: function () {
// scope.value = /* change it */;
// },
// };
// },
// }
//
// As a default, template hooks in flavour of option 1 and 2 override the content that was
// originally there. Provide 'override: false', to prevent overriding the original content.
.factory('templateHooks', [
function () {
var hooks = {};
return {
hooks: hooks,
registerHook: function (hook) {
if (hooks[hook.Id] === undefined) {
hooks[hook.Id] = [];
// Deprecated: Set the new style 'id', if 'Id' is given.
if (hook.id === undefined) {
hook.id = hook.Id;
}
hooks[hook.Id].push(hook);
if (hooks[hook.id] === undefined) {
hooks[hook.id] = [];
}
// set override default
if (hook.override === undefined) {
hook.override = !!(hook.template || hook.templateUrl);
}
hooks[hook.id].push(hook);
}
};
}
@ -584,21 +614,41 @@ angular.module('OpenSlidesApp.core', [
'$http',
'$q',
'$templateCache',
'$timeout',
'templateHooks',
function ($compile, $http, $q, $templateCache, templateHooks) {
function ($compile, $http, $q, $templateCache, $timeout, templateHooks) {
return {
restrict: 'E',
template: '',
link: function (scope, iElement, iAttr) {
var hooks = templateHooks.hooks[iAttr.hookName];
if (hooks) {
var templates = _.map(hooks, function (hook) {
// Populate scope
_.forEach(hook.scope, function (value, key) {
if (!scope.hasOwnProperty(key)) {
scope[key] = value;
}
// Populate scopes
_.forEach(hooks, function (hook) {
var _scope = hook.scope;
// If it is a function, get the scope from the function and provide
// the original scope.
if (typeof hook.scope === 'function') {
_scope = hook.scope(scope);
}
_.forEach(_scope, function (value, key) {
scope[key] = value;
});
});
// Check, if at least one hook overrides the original content.
var override = _.some(hooks, function (hook) {
return hook.override;
});
// filter hooks, that does actually have a template
hooks = _.filter(hooks, function (hook) {
return hook.template || hook.templateUrl;
});
// Get all templates
var templates = _.map(hooks, function (hook) {
// Either a template (html given as string) or a templateUrl has
// to be given. If a scope is provided, the schope of this templateHook
// is populated with the given functions/values.
@ -608,8 +658,17 @@ angular.module('OpenSlidesApp.core', [
return $templateCache.get(hook.templateUrl);
}
});
var html = templates.join('');
iElement.append($compile(html)(scope));
// Wait for the dom to build up, so we can retrieve the inner html of iElement.
$timeout(function () {
var html = override ? '' : iElement.html();
if (templates.length) {
html += templates.join('');
}
iElement.empty();
iElement.append($compile(html)(scope));
});
}
}
};

View File

@ -469,10 +469,12 @@
</table>
</ol>
<button ng-if="motion.isAllowed('create_poll')" ng-click="create_poll()" class="btn btn-default btn-sm">
<i class="fa fa-bar-chart fa-lg"></i>
<translate>New vote</translate>
</button>
<template-hook hook-name="motionPollNewVoteButton">
<button ng-if="motion.isAllowed('create_poll')" ng-click="create_poll()" class="btn btn-default btn-sm">
<i class="fa fa-bar-chart fa-lg"></i>
<translate>New vote</translate>
</button>
</template-hook>
<div class="spacer-top pull-right nobr">
<a href ng-click="gotoPersonalNote()" translate>Personal note</a>

View File

@ -21,6 +21,7 @@
<i class="fa fa-download fa-lg"></i>
<translate>Import</translate>
</a>
<template-hook hook-name="motionListMenuButton"></template-hook>
</div>
<h1 translate>Motions</h1>
</div>

View File

@ -447,13 +447,15 @@ class MotionViewSet(ModelViewSet):
raise ValidationError({'detail': 'You can not create a poll in this motion state.'})
try:
with transaction.atomic():
motion.create_poll(skip_autoupdate=True)
poll = motion.create_poll(skip_autoupdate=True)
except WorkflowError as e:
raise ValidationError({'detail': e})
motion.write_log([ugettext_noop('Vote created')], request.user, skip_autoupdate=True)
inform_changed_data(motion)
return Response({'detail': _('Vote created successfully.')})
return Response({
'detail': _('Vote created successfully.'),
'createdPollId': poll.pk})
class MotionPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet):

View File

@ -563,6 +563,9 @@ angular.module('OpenSlidesApp.users.site', [
_.forEach($scope.users, function (user) {
user.has_last_email_send = !!user.last_email_send;
});
if ($scope.updateUsers) {
$scope.updateUsers();
}
});
Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups');
$scope.$watch(function () {

View File

@ -19,6 +19,7 @@
<i class="fa fa-download fa-lg"></i>
<translate>Import</translate>
</a>
<template-hook hook-name="userListMenuButtons"></template-hook>
</div>
<h1 translate>Participants</h1>
</div>
@ -69,6 +70,8 @@
</a>
</ul>
</div>
<template-hook hook-name="userListSubmenuRight"></template-hook>
</div>
</div>
<div uib-collapse="!isSelectMode" class="row spacer">
@ -146,6 +149,7 @@
{{ usersFiltered.length }} /
{{ users.length }} {{ "participants" | translate }}<span ng-if="(users|filter:{selected:true}).length > 0">,
{{(users|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
<template-hook hook-name="userListTableStats"></template-hook>
</div>
<div class="col-md-6" ng-show="usersFiltered.length > pagination.itemsPerPage">
<span class="pull-right">
@ -348,7 +352,9 @@
</div>
<div os-perms="users.can_manage" ng-class="{'hiddenDiv': !user.hover}">
<small>
<a href="" ng-click="openDialog(user)" translate>Edit</a> &middot;
<template-hook hook-name="userListEditButton">
<a href="" ng-click="openDialog(user)" translate>Edit</a> &middot;
</template-hook>
<a ui-sref="users.user.change-password({id: user.id})" translate>Change password</a> &middot;
<a href="" class="text-danger"
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
@ -442,17 +448,20 @@
</div>
</small>
</div>
<div style="width: 40%;" class="pull-right" os-perms="users.can_see_extra_data">
<div os-perms="users.can_manage" ng-show="user.hover || user.is_present">
<div style="width: 40%;" class="pull-right">
<div os-perms="users.can_see_extra_data users.can_manage"
ng-style="{'visibility': (user.hover || user.is_present) ? 'visible' : 'hidden'}">
<span class="pointer nobr" ng-click="user.is_present = !user.is_present; save(user);">
<i class="fa" ng-class="user.is_present ? 'fa-check-square-o' : 'fa-square-o'"></i>
<span class="spacer-left" translate>Present</span>
</span>
</div>
<div os-perms="!users.can_manage" class="nobr" ng-show="user.is_present">
<div os-perms="!users.can_manage" class="nobr"
ng-style="{'visibility': user.is_present ? 'visible' : 'hidden'}">
<i class="fa fa-check-square-o"></i>
<span class="spacer-left" translate>Present</span>
</div>
<template-hook hook-name="userListExtraContent"></template-hook>
</div>
</div>