Changes for the voting plugin
- new-style template hooks. See changes in the template hook documentation - reordered user list view to get more space for extra things - added template hooks.
This commit is contained in:
parent
209ea70d75
commit
2256031184
@ -123,11 +123,14 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 translate>Election result</h3>
|
<h3 translate>Election result</h3>
|
||||||
|
<template-hook hook-name="assignmentPollNewBallotButton">
|
||||||
<button os-perms="assignments.can_manage" ng-show="assignment.phase !== 2" ng-click="createBallot()"
|
<button os-perms="assignments.can_manage" ng-show="assignment.phase !== 2" ng-click="createBallot()"
|
||||||
class="btn btn-default btn-sm">
|
class="btn btn-default btn-sm">
|
||||||
<i class="fa fa-bar-chart fa-lg"></i>
|
<i class="fa fa-bar-chart fa-lg"></i>
|
||||||
<translate>New ballot</translate>
|
<translate>New ballot</translate>
|
||||||
</button>
|
</button>
|
||||||
|
</template-hook>
|
||||||
|
|
||||||
<uib-tabset ng-if="assignment.polls.length > 0" class="spacer ballot-tabs" active="$parent.activeTab">
|
<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'"
|
<uib-tab ng-repeat="poll in assignment.polls | orderBy:'id'"
|
||||||
index="$index" heading="{{ 'Ballot' | translate }} {{ $index + 1 }}">
|
index="$index" heading="{{ 'Ballot' | translate }} {{ $index + 1 }}">
|
||||||
@ -274,7 +277,7 @@
|
|||||||
</uib-tabset>
|
</uib-tabset>
|
||||||
|
|
||||||
<!-- Workaround to prevent page scrolling up after autoupdate. -->
|
<!-- Workaround to prevent page scrolling up after autoupdate. -->
|
||||||
<div style="height: 700px"><div>
|
<div style="height: 700px"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template-hook hook-name="assignmentDetailViewDetailContainer"></template-hook>
|
<template-hook hook-name="assignmentDetailViewDetailContainer"></template-hook>
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<i class="fa fa-tags fa-lg"></i>
|
<i class="fa fa-tags fa-lg"></i>
|
||||||
<translate>Tags</translate>
|
<translate>Tags</translate>
|
||||||
</a>
|
</a>
|
||||||
|
<template-hook hook-name="assignmentListMenuButton"></template-hook>
|
||||||
</div>
|
</div>
|
||||||
<h1 translate>Elections</h1>
|
<h1 translate>Elections</h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -553,27 +553,57 @@ angular.module('OpenSlidesApp.core', [
|
|||||||
])
|
])
|
||||||
|
|
||||||
// Template hooks
|
// Template hooks
|
||||||
// 2 possible uses:
|
// Possible uses:
|
||||||
// - { Id: 'myHookId', template: '<button>click me</button>' }
|
// 1. { id: 'myHookId', template: '<button>click me</button>' }
|
||||||
// - { Id: 'myHookId', templateUrl: '/static/templates/plugin_name/my-hook.html' }
|
// 2. { 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.
|
// 3. { id: 'myHookId' }
|
||||||
// This overrides functions/values of the parent scope, but there may are conflicts
|
//
|
||||||
// with other plugins defining the same function/value. E.g.:
|
// 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>',
|
// { Id: 'hookId', template: '<button ng-click="customFn()">click me</button>',
|
||||||
// scope: {
|
// 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', [
|
.factory('templateHooks', [
|
||||||
function () {
|
function () {
|
||||||
var hooks = {};
|
var hooks = {};
|
||||||
return {
|
return {
|
||||||
hooks: hooks,
|
hooks: hooks,
|
||||||
registerHook: function (hook) {
|
registerHook: function (hook) {
|
||||||
if (hooks[hook.Id] === undefined) {
|
// Deprecated: Set the new style 'id', if 'Id' is given.
|
||||||
hooks[hook.Id] = [];
|
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',
|
'$http',
|
||||||
'$q',
|
'$q',
|
||||||
'$templateCache',
|
'$templateCache',
|
||||||
|
'$timeout',
|
||||||
'templateHooks',
|
'templateHooks',
|
||||||
function ($compile, $http, $q, $templateCache, templateHooks) {
|
function ($compile, $http, $q, $templateCache, $timeout, templateHooks) {
|
||||||
return {
|
return {
|
||||||
restrict: 'E',
|
restrict: 'E',
|
||||||
template: '',
|
template: '',
|
||||||
link: function (scope, iElement, iAttr) {
|
link: function (scope, iElement, iAttr) {
|
||||||
var hooks = templateHooks.hooks[iAttr.hookName];
|
var hooks = templateHooks.hooks[iAttr.hookName];
|
||||||
if (hooks) {
|
if (hooks) {
|
||||||
var templates = _.map(hooks, function (hook) {
|
// Populate scopes
|
||||||
// Populate scope
|
_.forEach(hooks, function (hook) {
|
||||||
_.forEach(hook.scope, function (value, key) {
|
var _scope = hook.scope;
|
||||||
if (!scope.hasOwnProperty(key)) {
|
// If it is a function, get the scope from the function and provide
|
||||||
scope[key] = value;
|
// 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
|
// Either a template (html given as string) or a templateUrl has
|
||||||
// to be given. If a scope is provided, the schope of this templateHook
|
// to be given. If a scope is provided, the schope of this templateHook
|
||||||
// is populated with the given functions/values.
|
// is populated with the given functions/values.
|
||||||
@ -608,8 +658,17 @@ angular.module('OpenSlidesApp.core', [
|
|||||||
return $templateCache.get(hook.templateUrl);
|
return $templateCache.get(hook.templateUrl);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var html = templates.join('');
|
|
||||||
|
// 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));
|
iElement.append($compile(html)(scope));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -468,10 +468,12 @@
|
|||||||
</table>
|
</table>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
|
<template-hook hook-name="motionPollNewVoteButton">
|
||||||
<button ng-if="motion.isAllowed('create_poll')" ng-click="create_poll()" class="btn btn-default btn-sm">
|
<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>
|
<i class="fa fa-bar-chart fa-lg"></i>
|
||||||
<translate>New vote</translate>
|
<translate>New vote</translate>
|
||||||
</button>
|
</button>
|
||||||
|
</template-hook>
|
||||||
|
|
||||||
<div class="spacer-top pull-right nobr">
|
<div class="spacer-top pull-right nobr">
|
||||||
<a href ng-click="gotoPersonalNote()" translate>Personal note</a>
|
<a href ng-click="gotoPersonalNote()" translate>Personal note</a>
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
<i class="fa fa-download fa-lg"></i>
|
<i class="fa fa-download fa-lg"></i>
|
||||||
<translate>Import</translate>
|
<translate>Import</translate>
|
||||||
</a>
|
</a>
|
||||||
|
<template-hook hook-name="motionListMenuButton"></template-hook>
|
||||||
</div>
|
</div>
|
||||||
<h1 translate>Motions</h1>
|
<h1 translate>Motions</h1>
|
||||||
</div>
|
</div>
|
||||||
|
@ -447,13 +447,15 @@ class MotionViewSet(ModelViewSet):
|
|||||||
raise ValidationError({'detail': 'You can not create a poll in this motion state.'})
|
raise ValidationError({'detail': 'You can not create a poll in this motion state.'})
|
||||||
try:
|
try:
|
||||||
with transaction.atomic():
|
with transaction.atomic():
|
||||||
motion.create_poll(skip_autoupdate=True)
|
poll = motion.create_poll(skip_autoupdate=True)
|
||||||
except WorkflowError as e:
|
except WorkflowError as e:
|
||||||
raise ValidationError({'detail': e})
|
raise ValidationError({'detail': e})
|
||||||
motion.write_log([ugettext_noop('Vote created')], request.user, skip_autoupdate=True)
|
motion.write_log([ugettext_noop('Vote created')], request.user, skip_autoupdate=True)
|
||||||
|
|
||||||
inform_changed_data(motion)
|
inform_changed_data(motion)
|
||||||
return Response({'detail': _('Vote created successfully.')})
|
return Response({
|
||||||
|
'detail': _('Vote created successfully.'),
|
||||||
|
'createdPollId': poll.pk})
|
||||||
|
|
||||||
|
|
||||||
class MotionPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
class MotionPollViewSet(UpdateModelMixin, DestroyModelMixin, GenericViewSet):
|
||||||
|
@ -565,6 +565,9 @@ angular.module('OpenSlidesApp.users.site', [
|
|||||||
_.forEach($scope.users, function (user) {
|
_.forEach($scope.users, function (user) {
|
||||||
user.has_last_email_send = !!user.last_email_send;
|
user.has_last_email_send = !!user.last_email_send;
|
||||||
});
|
});
|
||||||
|
if ($scope.updateUsers) {
|
||||||
|
$scope.updateUsers();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups');
|
Group.bindAll({where: {id: {'>': 1}}}, $scope, 'groups');
|
||||||
$scope.$watch(function () {
|
$scope.$watch(function () {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
<i class="fa fa-download fa-lg"></i>
|
<i class="fa fa-download fa-lg"></i>
|
||||||
<translate>Import</translate>
|
<translate>Import</translate>
|
||||||
</a>
|
</a>
|
||||||
|
<template-hook hook-name="userListMenuButtons"></template-hook>
|
||||||
</div>
|
</div>
|
||||||
<h1 translate>Participants</h1>
|
<h1 translate>Participants</h1>
|
||||||
</div>
|
</div>
|
||||||
@ -69,6 +70,8 @@
|
|||||||
</a>
|
</a>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<template-hook hook-name="userListSubmenuRight"></template-hook>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div uib-collapse="!isSelectMode" class="row spacer">
|
<div uib-collapse="!isSelectMode" class="row spacer">
|
||||||
@ -146,6 +149,7 @@
|
|||||||
{{ usersFiltered.length }} /
|
{{ usersFiltered.length }} /
|
||||||
{{ users.length }} {{ "participants" | translate }}<span ng-if="(users|filter:{selected:true}).length > 0">,
|
{{ users.length }} {{ "participants" | translate }}<span ng-if="(users|filter:{selected:true}).length > 0">,
|
||||||
{{(users|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
|
{{(users|filter:{selected:true}).length}} {{ "selected" | translate }}</span>
|
||||||
|
<template-hook hook-name="userListTableStats"></template-hook>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6" ng-show="usersFiltered.length > pagination.itemsPerPage">
|
<div class="col-md-6" ng-show="usersFiltered.length > pagination.itemsPerPage">
|
||||||
<span class="pull-right">
|
<span class="pull-right">
|
||||||
@ -340,7 +344,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<div os-perms="users.can_manage" ng-class="{'hiddenDiv': !user.hover}">
|
<div os-perms="users.can_manage" ng-class="{'hiddenDiv': !user.hover}">
|
||||||
<small>
|
<small>
|
||||||
|
<template-hook hook-name="userListEditButton">
|
||||||
<a href="" ng-click="openDialog(user)" translate>Edit</a> ·
|
<a href="" ng-click="openDialog(user)" translate>Edit</a> ·
|
||||||
|
</template-hook>
|
||||||
<a ui-sref="users.user.change-password({id: user.id})" translate>Change password</a> ·
|
<a ui-sref="users.user.change-password({id: user.id})" translate>Change password</a> ·
|
||||||
<a href="" class="text-danger"
|
<a href="" class="text-danger"
|
||||||
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
ng-bootbox-confirm="{{ 'Are you sure you want to delete this entry?' | translate }}<br>
|
||||||
@ -434,17 +440,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</small>
|
</small>
|
||||||
</div>
|
</div>
|
||||||
<div style="width: 40%;" class="pull-right" os-perms="users.can_see_extra_data">
|
<div style="width: 40%;" class="pull-right">
|
||||||
<div os-perms="users.can_manage" ng-show="user.hover || user.is_present">
|
<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);">
|
<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>
|
<i class="fa" ng-class="user.is_present ? 'fa-check-square-o' : 'fa-square-o'"></i>
|
||||||
<span class="spacer-left" translate>Present</span>
|
<span class="spacer-left" translate>Present</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</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>
|
<i class="fa fa-check-square-o"></i>
|
||||||
<span class="spacer-left" translate>Present</span>
|
<span class="spacer-left" translate>Present</span>
|
||||||
</div>
|
</div>
|
||||||
|
<template-hook hook-name="userListExtraContent"></template-hook>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user