Merge pull request #2918 from FinnStutzenstein/Issue2842

Show config save status (closes #2842)
This commit is contained in:
Norman Jäckel 2017-02-01 11:44:40 +01:00 committed by GitHub
commit 7d2a037567
4 changed files with 75 additions and 21 deletions

View File

@ -43,6 +43,7 @@ Core:
- Added smooth projector scroll. - Added smooth projector scroll.
- Added watching permissions in client and change the view immediately on changes. - Added watching permissions in client and change the view immediately on changes.
- Validate HTML strings from CKEditor against XSS attacks. - Validate HTML strings from CKEditor against XSS attacks.
- Added success/error symbol to config to show if saving was successful.
Motions: Motions:
- Added adjustable line numbering mode (outside, inside, none) for each - Added adjustable line numbering mode (outside, inside, none) for each

View File

@ -1052,6 +1052,9 @@ img {
.input-comments > div { .input-comments > div {
margin-bottom: 5px margin-bottom: 5px
} }
.config-checkbox {
padding: 6px 12px;
}
/** Pojector sidebar **/ /** Pojector sidebar **/
.col2 .projectorSelector { .col2 .projectorSelector {

View File

@ -661,7 +661,7 @@ angular.module('OpenSlidesApp.core.site', [
} else { } else {
$scope.value = gettextCatalog.getString($scope.default_value); $scope.value = gettextCatalog.getString($scope.default_value);
} }
$scope.save(field.key, $scope.value); $scope.save(field, $scope.value);
}; };
} }
}; };
@ -843,26 +843,61 @@ angular.module('OpenSlidesApp.core.site', [
// Config Controller // Config Controller
.controller('ConfigCtrl', [ .controller('ConfigCtrl', [
'$scope', '$scope',
'$timeout',
'MajorityMethodChoices', 'MajorityMethodChoices',
'Config', 'Config',
'configOptions', 'configOptions',
'gettextCatalog', 'gettextCatalog',
'DateTimePickerTranslation', 'DateTimePickerTranslation',
'Editor', 'Editor',
function($scope, MajorityMethodChoices, Config, configOptions, gettextCatalog, DateTimePickerTranslation, Editor) { function($scope, $timeout, MajorityMethodChoices, Config, configOptions,
gettextCatalog, DateTimePickerTranslation, Editor) {
Config.bindAll({}, $scope, 'configs'); Config.bindAll({}, $scope, 'configs');
$scope.configGroups = configOptions.data.config_groups; $scope.configGroups = configOptions.data.config_groups;
$scope.dateTimePickerTranslatedButtons = DateTimePickerTranslation.getButtons(); $scope.dateTimePickerTranslatedButtons = DateTimePickerTranslation.getButtons();
$scope.ckeditorOptions = Editor.getOptions(); $scope.ckeditorOptions = Editor.getOptions();
$scope.ckeditorOptions.on.change = function (event) { $scope.ckeditorOptions.on.change = function (event) {
$scope.save(event.editor.element.$.id, this.getData()); // we could just retrieve the key, but we need the configOption object.
var configOption_key = event.editor.element.$.id;
// find configOption object
var subgroups = _.flatMap($scope.configGroups, function (group) {
return group.subgroups;
});
var items = _.flatMap(subgroups, function (subgroup) {
return subgroup.items;
});
var configOption = _.find(items, function (_item) {
return _item.key === configOption_key;
});
var editor = this;
// The $timeout executes the given function in an angular context. Because
// this is a standard JS event, all changes may not happen in the digist-cylce.
// By using $timeout angular calls $apply for us that we do not have to care
// about starting the digist-cycle.
$timeout(function () {
$scope.save(configOption, editor.getData());
}, 1);
}; };
// save changed config value // save changed config value
$scope.save = function(key, value) { $scope.save = function(configOption, value) {
Config.get(key).value = value; Config.get(configOption.key).value = value;
Config.save(key); Config.save(configOption.key).then(function (success) {
configOption.success = true;
// fade out the success symbol after 2 seconds.
$timeout(function () {
var element = $('#success-field-' + configOption.key);
element.fadeOut(800, function () {
configOption.success = void 0;
});
}, 2000);
}, function (error) {
configOption.success = false;
configOption.errorMessage = error.data.detail;
});
}; };
// For comments input // For comments input

View File

@ -2,27 +2,34 @@
<label>{{ label | translate }}</label> <label>{{ label | translate }}</label>
<div class="input-group"> <div class="input-group">
<!-- text/number input, checkbox --> <!-- text/number input -->
<input ng-if="type == 'text' || type == 'number' || type == 'checkbox'" <input ng-if="type === 'text' || type === 'number'"
ng-model="$parent.value" ng-model="$parent.value"
ng-model-options="{debounce: 1000}" ng-model-options="{debounce: 1000}"
ng-change="save(configOption.key, $parent.value)" ng-change="save(configOption, $parent.value)"
ng-class="{ 'form-control': type != 'checkbox' }" ng-class="{ 'form-control': type != 'checkbox' }"
id="{{ key }}" id="{{ key }}"
type="{{ type }}"> type="{{ type }}">
<!-- checkbox -->
<div ng-if="type === 'checkbox'" class="config-checkbox">
<i class="fa" id="{{ key }}"
ng-click="$parent.value = !$parent.value; save(configOption, $parent.value)"
ng-class="$parent.value ? 'fa-check-square-o' : 'fa-square-o'"></i>
</div>
<!-- comments --> <!-- comments -->
<div class="input-comments" ng-if="type == 'comments'"> <div class="input-comments" ng-if="type === 'comments'">
<div ng-repeat="entry in $parent.value" class="input-group"> <div ng-repeat="entry in $parent.value" class="input-group">
<input ng-model="entry.name" <input ng-model="entry.name"
ng-model-options="{debounce: 1000}" ng-model-options="{debounce: 1000}"
ng-change="save(configOption.key, $parent.value)" ng-change="save(configOption, $parent.value)"
class="form-control" class="form-control"
id="{{ key }}" id="{{ key }}"
type="text"> type="text">
<span class="input-group-btn"> <span class="input-group-btn">
<button type=button" class="btn btn-default" <button type=button" class="btn btn-default"
ng-click="entry.public = !entry.public; save(configOption.key, $parent.value);"> ng-click="entry.public = !entry.public; save(configOption, $parent.value);">
<i class="fa" ng-class="entry.public ? 'fa-unlock' : 'fa-lock'"></i> <i class="fa" ng-class="entry.public ? 'fa-unlock' : 'fa-lock'"></i>
{{ (entry.public ? 'Public' : 'Private') | translate }} {{ (entry.public ? 'Public' : 'Private') | translate }}
</button> </button>
@ -43,20 +50,20 @@
</div> </div>
<!-- colorpicker --> <!-- colorpicker -->
<input ng-if="type == 'colorpicker'" <input ng-if="type === 'colorpicker'"
colorpicker colorpicker
class="form-control" class="form-control"
ng-model="$parent.value" ng-model="$parent.value"
ng-model-options="{debounce: 1000}" ng-model-options="{debounce: 1000}"
ng-change="save(configOption.key, $parent.value)" ng-change="save(configOption, $parent.value)"
type="text"> type="text">
<!-- datetimepicker --> <!-- datetimepicker -->
<input ng-if="type == 'datetimepicker'" <input ng-if="type === 'datetimepicker'"
class="form-control" class="form-control"
datetime-picker="dd.MM.yyyy HH:mm" datetime-picker="dd.MM.yyyy HH:mm"
ng-model="$parent.value" ng-model="$parent.value"
ng-change="save(configOption.key, $parent.value)" ng-change="save(configOption, $parent.value)"
is-open="datetimeOpen[key]" is-open="datetimeOpen[key]"
ng-focus="datetimeOpen[key]=true;" ng-focus="datetimeOpen[key]=true;"
save-as="'number'" save-as="'number'"
@ -64,15 +71,15 @@
default-time="10:00:00"> default-time="10:00:00">
<!-- textarea --> <!-- textarea -->
<textarea ng-if="type == 'textarea'" <textarea ng-if="type === 'textarea'"
ng-model="$parent.value" ng-model="$parent.value"
ng-model-options="{debounce: 1000}" ng-model-options="{debounce: 1000}"
ng-change="save(configOption.key, $parent.value)" ng-change="save(configOption, $parent.value)"
id="{{ key }}" class="form-control"> id="{{ key }}" class="form-control">
</textarea> </textarea>
<!-- editor --> <!-- editor -->
<textarea ng-if="type == 'editor'" <textarea ng-if="type === 'editor'"
id="{{ configOption.key }}" id="{{ configOption.key }}"
ckeditor="ckeditorOptions" ckeditor="ckeditorOptions"
ng-model="$parent.value" class="form-control" ng-model="$parent.value" class="form-control"
@ -80,14 +87,22 @@
</textarea> </textarea>
<!-- select --> <!-- select -->
<select ng-if="type == 'choice'" <select ng-if="type === 'choice'"
ng-model="$parent.value" ng-model="$parent.value"
ng-model-options="{debounce: 500}" ng-model-options="{debounce: 500}"
ng-change="save(configOption.key, $parent.value)" ng-change="save(configOption, $parent.value)"
id="{{ key }}" class="form-control" id="{{ key }}" class="form-control"
ng-options="option.value as option.display_name | translate for option in choices"> ng-options="option.value as option.display_name | translate for option in choices">
</select> </select>
<span id="success-{{ key }}" class="input-group-addon" ng-if="configOption.success !== undefined">
<i class="fa fa-lg fa-check-circle text-success"
ng-if="configOption.success === true"></i>
<i class="fa fa-lg fa-exclamation-triangle text-danger"
ng-if="configOption.success === false"
uib-tooltip="{{ configOption.errorMessage | translate }}"></i>
</span>
<span class="input-group-btn"> <span class="input-group-btn">
<button ng-click="reset()" class="btn btn-default" title="{{ default_value | translate }}"> <button ng-click="reset()" class="btn btn-default" title="{{ default_value | translate }}">
<i class="fa fa-undo"></i> <i class="fa fa-undo"></i>