Merge pull request #2994 from FinnStutzenstein/Improvements

Usability improvements
This commit is contained in:
Emanuel Schütze 2017-02-22 19:03:42 +01:00 committed by GitHub
commit 60ebac9f8b
10 changed files with 181 additions and 55 deletions

View File

@ -78,7 +78,7 @@
<translate>Sort ...</translate>
</a>
<!-- auto numbering button -->
<button os-perms="core.can_manage_projector" class="btn btn-default btn-sm"
<button os-perms="agenda.can_manage" class="btn btn-default btn-sm"
ng-click="autoNumbering()">
<i class="fa fa-sort-numeric-asc"></i>
<translate>Numbering</translate>
@ -325,6 +325,15 @@
</span>
</div>
</div>
<div ng-style="{'visibility': ((item.type == 1) && item.hover) ? 'visible' : 'hidden'}" os-perms="agenda.can_manage">
<div class="popover-wrapper" os-perms="agenda.can_manage">
<i class="fa fa-info-circle"></i>
<span editable-text="item.item_number" onaftersave="save(item)">
<span ng-if="!item.item_number" translate>Set item number ...</span>
<span ng-if="item.item_number"><em translate>Change item number ...</em></span>
</span>
</div>
</div>
</small>
</div>
<div style="width: 40%;" class="pull-right">

View File

@ -632,18 +632,19 @@ angular.module('OpenSlidesApp.assignments.site', [
.controller('AssignmentCreateCtrl', [
'$scope',
'$state',
'Assignment',
'AssignmentForm',
'Agenda',
'AgendaUpdate',
function($scope, Assignment, AssignmentForm, Agenda, AgendaUpdate) {
function($scope, $state, Assignment, AssignmentForm, Agenda, AgendaUpdate) {
$scope.model = {};
// set default value for open posts form field
$scope.model.open_posts = 1;
// get all form fields
$scope.formFields = AssignmentForm.getFormFields(true);
// save assignment
$scope.save = function(assignment) {
$scope.save = function(assignment, gotoDetailView) {
Assignment.create(assignment).then(
function(success) {
// type: Value 1 means a non hidden agenda item, value 2 means a hidden agenda item,
@ -651,6 +652,9 @@ angular.module('OpenSlidesApp.assignments.site', [
var changes = [{key: 'type', value: (assignment.showAsAgendaItem ? 1 : 2)},
{key: 'parent_id', value: assignment.agenda_parent_item_id}];
AgendaUpdate.saveChanges(success.agenda_item_id,changes);
if (gotoDetailView) {
$state.go('assignments.assignment.detail', {id: success.id});
}
$scope.closeThisDialog();
}
);
@ -660,12 +664,13 @@ angular.module('OpenSlidesApp.assignments.site', [
.controller('AssignmentUpdateCtrl', [
'$scope',
'$state',
'Assignment',
'AssignmentForm',
'Agenda',
'AgendaUpdate',
'assignmentId',
function($scope, Assignment, AssignmentForm, Agenda, AgendaUpdate, assignmentId) {
function($scope, $state, Assignment, AssignmentForm, Agenda, AgendaUpdate, assignmentId) {
var assignment = Assignment.get(assignmentId);
$scope.alert = {};
// set initial values for form model by create deep copy of assignment object
@ -684,7 +689,7 @@ angular.module('OpenSlidesApp.assignments.site', [
}
// save assignment
$scope.save = function (assignment) {
$scope.save = function (assignment, gotoDetailView) {
// inject the changed assignment (copy) object back into DS store
Assignment.inject(assignment);
// save change assignment object on server
@ -693,6 +698,9 @@ angular.module('OpenSlidesApp.assignments.site', [
var changes = [{key: 'type', value: (assignment.showAsAgendaItem ? 1 : 2)},
{key: 'parent_id', value: assignment.agenda_parent_item_id}];
AgendaUpdate.saveChanges(success.agenda_item_id,changes);
if (gotoDetailView) {
$state.go('assignments.assignment.detail', {id: success.id});
}
$scope.closeThisDialog();
},
function (error) {

View File

@ -5,8 +5,13 @@
{{ alert.msg }}
</div>
<form name="assignmentForm" ng-submit="save(model)">
<form name="assignmentForm" ng-submit="save(model, gotoDetailView)">
<formly-form model="model" fields="formFields">
<hr class="smallhr">
<div class="checkbox pointer" ng-click="$parent.$parent.gotoDetailView = !$parent.$parent.gotoDetailView">
<i class="fa" ng-class="$parent.$parent.gotoDetailView ? 'fa-check-square-o' : 'fa-square-o'"></i>
<translate>Open election detail view after save.</translate>
</div>
<button type="submit" ng-disabled="assignmentForm.$invalid" class="btn btn-primary" translate>
Save
</button>

View File

@ -384,9 +384,6 @@ img {
opacity: 1;
background-color: #eee;
}
.col1 .details .motion-toolbar .toolbar-left .goto-line-number {
max-width: 220px;
}
.col1 .details .inline-editing-activator {
margin-right: 13px;
@ -1642,6 +1639,10 @@ tr.selected td {
background-color: #ff9999;
}
/** Angular formly **/
.checkbox label {
padding-left: 0;
}
/** Colors **/

View File

@ -634,6 +634,11 @@ angular.module('OpenSlidesApp.core.site', [
extends: 'input',
templateUrl: 'static/templates/core/password.html',
});
formlyConfig.setType({
name: 'checkbox',
templateUrl: 'static/templates/core/checkbox.html',
overwriteOk: true,
});
formlyConfig.setType({
name: 'select-single',
extends: 'select',

View File

@ -0,0 +1,7 @@
<div class="checkbox">
<label ng-click="model[options.key] = !model[options.key]">
<i class="fa" ng-class="model[options.key] ? 'fa-check-square-o' : 'fa-square-o'"></i>
{{to.label}}
{{to.required ? '*' : ''}}
</label>
</div>

View File

@ -995,6 +995,7 @@ angular.module('OpenSlidesApp.motions.site', [
.controller('MotionDetailCtrl', [
'$scope',
'$http',
'$timeout',
'operator',
'ngDialog',
'MotionForm',
@ -1015,16 +1016,18 @@ angular.module('OpenSlidesApp.motions.site', [
'MotionCommentsInlineEditing',
'Projector',
'ProjectionDefault',
function($scope, $http, operator, ngDialog, MotionForm,
'MotionBlock',
function($scope, $http, $timeout, operator, ngDialog, MotionForm,
ChangeRecommmendationCreate, ChangeRecommmendationView, MotionChangeRecommendation, MotionPDFExport,
Motion, MotionComment, Category, Mediafile, Tag, User, Workflow, Config, motionId, MotionInlineEditing,
MotionCommentsInlineEditing, Projector, ProjectionDefault) {
MotionCommentsInlineEditing, Projector, ProjectionDefault, MotionBlock) {
var motion = Motion.get(motionId);
Category.bindAll({}, $scope, 'categories');
Mediafile.bindAll({}, $scope, 'mediafiles');
Tag.bindAll({}, $scope, 'tags');
User.bindAll({}, $scope, 'users');
Workflow.bindAll({}, $scope, 'workflows');
MotionBlock.bindAll({}, $scope, 'motionBlocks');
$scope.$watch(function () {
return MotionChangeRecommendation.lastModified();
}, function () {
@ -1132,6 +1135,10 @@ angular.module('OpenSlidesApp.motions.site', [
$('html, body').animate({
'scrollTop': scrollTop - 50
}, 1000);
// remove the line highlight after 2 seconds.
$timeout(function () {
$scope.highlight = 0;
}, 2000);
}
// set highlight and scroll on Projector
setHighlightOnProjector($scope.linesForProjector ? line : 0);
@ -1148,6 +1155,12 @@ angular.module('OpenSlidesApp.motions.site', [
}
ngDialog.open(MotionForm.getDialog(motion));
};
$scope.save = function (motion) {
motion.title = motion.getTitle(-1);
motion.text = motion.getText(-1);
motion.reason = motion.getReason(-1);
Motion.save(motion);
};
// support
$scope.support = function () {
$http.post('/rest/motions/motion/' + motion.id + '/support/');
@ -1173,24 +1186,49 @@ angular.module('OpenSlidesApp.motions.site', [
$scope.reset_state = function () {
$http.put('/rest/motions/motion/' + motion.id + '/set_state/', {});
};
// toggle functions for meta information
$scope.toggleCategory = function (category) {
if ($scope.motion.category_id == category.id) {
$scope.motion.category_id = null;
} else {
$scope.motion.category_id = category.id;
}
$scope.save($scope.motion);
};
$scope.toggleMotionBlock = function (block) {
if ($scope.motion.motion_block_id == block.id) {
$scope.motion.motion_block_id = null;
} else {
$scope.motion.motion_block_id = block.id;
}
$scope.save($scope.motion);
};
$scope.toggleTag = function (tag) {
if (_.indexOf($scope.motion.tags_id, tag.id) > -1) {
// remove
$scope.motion.tags_id = _.filter($scope.motion.tags_id,
function (tag_id){
return tag_id != tag.id;
}
);
} else {
$scope.motion.tags_id.push(tag.id);
}
$scope.save($scope.motion);
};
// save additional state field
$scope.saveAdditionalStateField = function (stateExtension) {
if (stateExtension) {
motion["comment " + $scope.commentFieldForState] = stateExtension;
motion.title = motion.getTitle(-1);
motion.text = motion.getText(-1);
motion.reason = motion.getReason(-1);
Motion.save(motion);
$scope.save(motion);
}
};
// save additional recommendation field
$scope.saveAdditionalRecommendationField = function (recommendationExtension) {
if (recommendationExtension) {
motion["comment " + $scope.commentFieldForRecommendation] = recommendationExtension;
motion.title = motion.getTitle(-1);
motion.text = motion.getText(-1);
motion.reason = motion.getReason(-1);
Motion.save(motion);
$scope.save(motion);
}
};
// update recommendation
@ -1414,7 +1452,7 @@ angular.module('OpenSlidesApp.motions.site', [
$scope.formFields = MotionForm.getFormFields(true);
// save motion
$scope.save = function (motion) {
$scope.save = function (motion, gotoDetailView) {
Motion.create(motion).then(
function(success) {
// type: Value 1 means a non hidden agenda item, value 2 means a hidden agenda item,
@ -1422,7 +1460,7 @@ angular.module('OpenSlidesApp.motions.site', [
var changes = [{key: 'type', value: (motion.showAsAgendaItem ? 1 : 2)},
{key: 'parent_id', value: motion.agenda_parent_item_id}];
AgendaUpdate.saveChanges(success.agenda_item_id, changes);
if (isAmendment) {
if (isAmendment || gotoDetailView) {
$state.go('motions.motion.detail', {id: success.id});
}
$scope.closeThisDialog();
@ -1434,6 +1472,7 @@ angular.module('OpenSlidesApp.motions.site', [
.controller('MotionUpdateCtrl', [
'$scope',
'$state',
'Motion',
'Category',
'Config',
@ -1445,7 +1484,8 @@ angular.module('OpenSlidesApp.motions.site', [
'Agenda',
'AgendaUpdate',
'motionId',
function($scope, Motion, Category, Config, Mediafile, MotionForm, Tag, User, Workflow, Agenda, AgendaUpdate, motionId) {
function($scope, $state, Motion, Category, Config, Mediafile, MotionForm, Tag,
User, Workflow, Agenda, AgendaUpdate, motionId) {
Category.bindAll({}, $scope, 'categories');
Mediafile.bindAll({}, $scope, 'mediafiles');
Tag.bindAll({}, $scope, 'tags');
@ -1501,7 +1541,7 @@ angular.module('OpenSlidesApp.motions.site', [
}
// save motion
$scope.save = function (motion) {
$scope.save = function (motion, gotoDetailView) {
// inject the changed motion (copy) object back into DS store
Motion.inject(motion);
// save change motion object on server
@ -1512,6 +1552,9 @@ angular.module('OpenSlidesApp.motions.site', [
var changes = [{key: 'type', value: (motion.showAsAgendaItem ? 1 : 2)},
{key: 'parent_id', value: motion.agenda_parent_item_id}];
AgendaUpdate.saveChanges(success.agenda_item_id,changes);
if (gotoDetailView) {
$state.go('motions.motion.detail', {id: success.id});
}
$scope.closeThisDialog();
},
function (error) {

View File

@ -132,10 +132,10 @@
<h3 ng-if="!motion.isAllowed('change_state')" class="heading" translate>State</h3>
<div ng-if="motion.isAllowed('change_state')" class="heading">
<span uib-dropdown>
<a href id="state-dropdown" class="drop-down-name" uib-dropdown-toggle>
<span id="state-dropdown" class="drop-down-name pointer" uib-dropdown-toggle>
<translate>State</translate>
<i class="fa fa-cog"></i>
</a>
</span>
<ul uib-dropdown-menu class="dropdown-menu" aria-labelledby="state-dropdown">
<li ng-repeat="state in motion.state.getNextStates()">
<a href ng-click="updateState(state.id)">{{ state.action_word | translate }}</a>
@ -171,10 +171,10 @@
</h3>
<div ng-if="motion.isAllowed('change_recommendation')" class="heading">
<span uib-dropdown>
<a href id="recommendation-dropdown" class="drop-down-name" uib-dropdown-toggle>
<span id="recommendation-dropdown" class="drop-down-name pointer" uib-dropdown-toggle>
{{ config('motions_recommendations_by') }}
<i class="fa fa-cog"></i>
</a>
</span>
<ul uib-dropdown-menu class="dropdown-menu" aria-labelledby="recommendation-dropdown">
<li ng-repeat="recommendation in motion.state.getRecommendations()">
<a href ng-click="updateRecommendation(recommendation.id)">
@ -189,11 +189,11 @@
</ul>
</span>
</div>
<div class="label" ng-class="'label-'+motion.recommendation.css_class">
<div class="label" ng-if="motion.recommendation" ng-class="'label-'+motion.recommendation.css_class">
{{ motion.getRecommendationName() }}
</div>
<div class="input-group spacer"
ng-show="motion.recommendation.show_recommendation_extension_field">
ng-if="motion.recommendation.show_recommendation_extension_field">
<label class="sr-only" for="recommendationExtensionField">{{ commentFieldForRecommendation }}</label>
<input type="text" ng-model="recommendationExtension"
id="recommendationExtensionField" class="form-control input-sm"
@ -216,17 +216,65 @@
</div>
<!-- Category -->
<h3 ng-if="motion.category" translate>Category</h3>
<h3 class="heading" os-perms="!motions.can_manage" ng-show="motion.category" translate>Category</h3>
<div class="heading" os-perms="motions.can_manage" ng-show="categories.length > 0">
<span uib-dropdown>
<span id="category-dropdown" class="drop-down-name pointer" uib-dropdown-toggle>
<translate>Category</translate>
<i class="fa fa-cog"></i>
</span>
<ul class="dropdown-menu" aria-labelledby="category-dropdown">
<li ng-repeat="category in categories">
<a href ng-click="toggleCategory(category)">
<i class="fa fa-check" ng-if="category.id == motion.category.id"></i>
{{ category.name }}
</a>
</li>
</ul>
</span>
</div>
{{ motion.category.name }}
<!-- Motion block -->
<h3 ng-if="motion.motionBlock" translate>Motion block</h3>
<h3 class="heading" os-perms="!motions.can_manage" ng-show="motion.motionBlock" translate>Motion block</h3>
<div class="heading" os-perms="motions.can_manage" ng-show="motionBlocks.length > 0">
<span uib-dropdown>
<span id="motionBlock-dropdown" class="drop-down-name pointer" uib-dropdown-toggle>
<translate>Motion block</translate>
<i class="fa fa-cog"></i>
</span>
<ul class="dropdown-menu" aria-labelledby="motionBlock-dropdown">
<li ng-repeat="motionBlock in motionBlocks">
<a href ng-click="toggleMotionBlock(motionBlock)">
<i class="fa fa-check" ng-if="motionBlock.id == motion.motionBlock.id"></i>
{{ motionBlock.title }}
</a>
</li>
</ul>
</span>
</div>
<a ui-sref="motions.motionBlock.detail({id: motion.motionBlock.id})"
os-perms="motions.can_manage">{{ motion.motionBlock.title }}</a>
<span os-perms="!motions.can_manage">{{ motion.motionBlock.title }}</span>
<!-- Tags -->
<h3 ng-if="motion.tags.length > 0" translate>Tags</h3>
<h3 class="heading" os-perms="!motions.can_manage" ng-show="motion.tags.length" translate>Tags</h3>
<div class="heading" os-perms="motions.can_manage" ng-show="tags.length > 0">
<span uib-dropdown>
<span id="tag-dropdown" class="drop-down-name pointer" uib-dropdown-toggle>
<translate>Tags</translate>
<i class="fa fa-cog"></i>
</span>
<ul class="dropdown-menu" aria-labelledby="tag-dropdown">
<li ng-repeat="tag in tags">
<a href ng-click="toggleTag(tag)">
<i class="fa fa-check" ng-if="inArray(motion.tags_id, tag.id)"></i>
{{ tag.name }}
</a>
</li>
</ul>
</span>
</div>
<span ng-repeat="tag in motion.tags">
{{ tag.name }}{{$last ? '' : ', '}}
</span>

View File

@ -48,28 +48,23 @@
</div>
<!-- go to line number -->
<div class="goto-line-number">
<form class="input-group" ng-if="lineNumberMode != 'none'" ng-submit="scrollToAndHighlight(gotoLinenumber)">
<input type="number" class="form-control input-sm" ng-model="gotoLinenumber"
placeholder="{{ 'Line' | translate }}"/>
<div class="input-group-btn">
<button type="button" class="btn btn-sm btn-default btn-slim" ng-show="gotoLinenumber"
ng-click="gotoLinenumber = ''; scrollToAndHighlight(0);">
<i class="fa fa-times text-danger"></i>
</button>
<button type="submit" class="btn btn-sm btn-default">
<i class="fa fa-share"></i>
<translate>go</translate>
</button>
<button type="button" class="btn btn-sm btn-default" os-perms="core.can_manage_projector"
ng-show="lineNumberMode != 'none' && motion.isProjected().length"
ng-click="toggleLinesForProjector()"
uib-tooltip="{{ 'Show highlighted line also on projector.' | translate }}">
<i class="fa" ng-class="linesForProjector ? 'fa-check-square-o' : 'fa-square-o'"></i>&nbsp;
<i class="fa fa-video-camera"></i>
</button>
</div>
</form>
<div class="popover-wrapper">
<span editable-text="gotoLinenumber" e-form="lineNumberForm"
onaftersave="scrollToAndHighlight(gotoLinenumber)">
</span>
<div class="btn-group" ng-if="lineNumberMode != 'none'">
<button type="button" class="btn btn-sm btn-default" ng-click="lineNumberForm.$show()">
<i class="fa fa-share"></i>
<translate>go</translate>
</button>
<button type="button" class="btn btn-sm btn-default" os-perms="core.can_manage_projector"
ng-if="lineNumberMode != 'none' && motion.isProjected().length"
ng-click="toggleLinesForProjector()"
uib-tooltip="{{ 'Show highlighted line also on projector.' | translate }}">
<i class="fa" ng-class="linesForProjector ? 'fa-check-square-o' : 'fa-square-o'"></i>&nbsp;
<i class="fa fa-video-camera"></i>
</button>
</div>
</div>
</div>
</div>

View File

@ -6,8 +6,13 @@
{{ alert.msg }}
</div>
<form name="motionForm" ng-submit="save(model)" novalidate>
<form name="motionForm" ng-submit="save(model, gotoDetailView)" novalidate>
<formly-form model="model" fields="formFields">
<hr class="smallhr">
<div class="checkbox pointer" ng-click="$parent.$parent.gotoDetailView = !$parent.$parent.gotoDetailView">
<i class="fa" ng-class="$parent.$parent.gotoDetailView ? 'fa-check-square-o' : 'fa-square-o'"></i>
<translate>Open motion detail view after save.</translate>
</div>
<button type="submit" ng-disabled="motionForm.$invalid" class="btn btn-primary" translate>
Save
</button>