Merge pull request #4944 from opf/fix/23896/enter-in-edit-mode

[23896] Submit and close edit mode on enter for most edit fields
pull/4963/merge
ulferts 8 years ago committed by GitHub
commit 2387901eff
  1. 4
      frontend/app/components/routing/main/work-packages.new.html
  2. 7
      frontend/app/components/routing/wp-list/wp.list.new.html
  3. 2
      frontend/app/components/work-packages/work-package-comment/work-package-comment.directive.html
  4. 2
      frontend/app/components/work-packages/work-package-comment/work-package-comment.directive.ts
  5. 15
      frontend/app/components/wp-create/wp-create.controller.ts
  6. 2
      frontend/app/components/wp-edit/field-types/wp-edit-boolean-field.directive.html
  7. 5
      frontend/app/components/wp-edit/field-types/wp-edit-date-field.directive.html
  8. 1
      frontend/app/components/wp-edit/field-types/wp-edit-duration-field.directive.html
  9. 1
      frontend/app/components/wp-edit/field-types/wp-edit-float-field.directive.html
  10. 1
      frontend/app/components/wp-edit/field-types/wp-edit-integer-field.directive.html
  11. 2
      frontend/app/components/wp-edit/field-types/wp-edit-select-field.directive.html
  12. 1
      frontend/app/components/wp-edit/field-types/wp-edit-text-field.directive.html
  13. 2
      frontend/app/components/wp-edit/field-types/wp-edit-wiki-textarea-field.directive.html
  14. 3
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field.directive.html
  15. 29
      frontend/app/components/wp-edit/wp-edit-field/wp-edit-field.directive.ts
  16. 12
      frontend/app/components/wp-edit/wp-edit-form.directive.ts
  17. 9
      frontend/app/components/wp-edit/wp-edit-mode-state.service.ts
  18. 12
      spec/features/work_packages/edit_work_package_spec.rb
  19. 14
      spec/features/work_packages/new_work_package_spec.rb

@ -3,12 +3,12 @@
ng-if="$ctrl.newWorkPackage" ng-if="$ctrl.newWorkPackage"
has-edit-mode="true" has-edit-mode="true"
wp-edit-form="$ctrl.newWorkPackage" wp-edit-form="$ctrl.newWorkPackage"
> wp-edit-form-on-save="$ctrl.refreshAfterSave(workPackage, 'work-packages.show')">
<h2>{{ $ctrl.header }}</h2> <h2>{{ $ctrl.header }}</h2>
<wp-subject work-package="$ctrl.newWorkPackage"></wp-subject> <wp-subject work-package="$ctrl.newWorkPackage"></wp-subject>
<wp-single-view work-package="$ctrl.newWorkPackage"></wp-single-view> <wp-single-view work-package="$ctrl.newWorkPackage"></wp-single-view>
<edit-actions-bar <edit-actions-bar
on-save="$ctrl.saveWorkPackage('work-packages.show')" on-save="$ctrl.saveWorkPackage()"
on-cancel="$ctrl.cancelAndBackToList()" on-cancel="$ctrl.cancelAndBackToList()"
></edit-actions-bar> ></edit-actions-bar>
</div> </div>

@ -4,10 +4,9 @@
> >
<div class="work-packages--details-content -create-mode"> <div class="work-packages--details-content -create-mode">
<span class="hidden-for-sighted" tabindex="-1" focus ng-bind="focusAnchorLabel"></span> <span class="hidden-for-sighted" tabindex="-1" focus ng-bind="focusAnchorLabel"></span>
<div <div has-edit-mode="true"
has-edit-mode="true"
wp-edit-form="$ctrl.newWorkPackage" wp-edit-form="$ctrl.newWorkPackage"
> wp-edit-form-on-save="$ctrl.refreshAfterSave(workPackage, 'work-packages.list.details.overview')">
<h2>{{ $ctrl.header }}</h2> <h2>{{ $ctrl.header }}</h2>
<wp-subject work-package="$ctrl.newWorkPackage"></wp-subject> <wp-subject work-package="$ctrl.newWorkPackage"></wp-subject>
<wp-single-view work-package="$ctrl.newWorkPackage"></wp-single-view> <wp-single-view work-package="$ctrl.newWorkPackage"></wp-single-view>
@ -16,7 +15,7 @@
<div class="bottom-toolbar"> <div class="bottom-toolbar">
<edit-actions-bar <edit-actions-bar
on-save="$ctrl.saveWorkPackage('work-packages.list.details.overview')" on-save="$ctrl.saveWorkPackage()"
on-cancel="$ctrl.cancelAndBackToList()" on-cancel="$ctrl.cancelAndBackToList()"
></edit-actions-bar> ></edit-actions-bar>
</div> </div>

@ -9,7 +9,7 @@
<form ng-switch-when="true" <form ng-switch-when="true"
name="wp-edit-form-coment" name="wp-edit-form-coment"
ng-submit="vm.submit()" ng-submit="vm.handleUserSubmit()"
role="form" role="form"
tabindex="-1"> tabindex="-1">

@ -98,7 +98,7 @@ export class CommentFieldDirectiveController {
return this.editing = true; return this.editing = true;
} }
public submit() { public handleUserSubmit() {
if (this.field.isEmpty()) { if (this.field.isEmpty()) {
return; return;
} }

@ -92,19 +92,12 @@ export class WorkPackageCreateController {
this.$state.go('work-packages.list', this.$state.params); this.$state.go('work-packages.list', this.$state.params);
} }
public saveWorkPackage(successState:string):ng.IPromise<WorkPackageResource> { public saveWorkPackage():ng.IPromise<WorkPackageResource> {
if (this.wpEditModeState.active) { return this.wpEditModeState.save();
return this.wpEditModeState.save().then(wp => {
this.newWorkPackage = null;
this.refreshAfterSave(wp, successState);
return wp;
});
}
return this.$q.reject();
} }
private refreshAfterSave(wp, successState) { public refreshAfterSave(wp, successState) {
this.wpEditModeState.onSaved();
this.loadingIndicator.mainPage = this.$state.go(successState, {workPackageId: wp.id}) this.loadingIndicator.mainPage = this.$state.go(successState, {workPackageId: wp.id})
.then(() => { .then(() => {
this.$rootScope.$emit('workPackagesRefreshInBackground'); this.$rootScope.$emit('workPackagesRefreshInBackground');

@ -3,7 +3,7 @@
wp-edit-field-requirements="vm.field.schema" wp-edit-field-requirements="vm.field.schema"
ng-model="vm.workPackage[vm.fieldName]" ng-model="vm.workPackage[vm.fieldName]"
ng-false-value="false" ng-false-value="false"
ng-change="vm.submit()" ng-change="vm.handleUserSubmit()"
ng-focus="vm.handleUserFocus()" ng-focus="vm.handleUserFocus()"
ng-blur="vm.handleUserBlur()" ng-blur="vm.handleUserBlur()"
ng-disabled="vm.workPackage.inFlight" ng-disabled="vm.workPackage.inFlight"

@ -1,7 +1,7 @@
<op-date-picker <op-date-picker
tabindex="-1" tabindex="-1"
on-change="vm.submit()" on-change="vm.handleUserSubmit()"
on-close="vm.submit()" on-change="vm.handleUserSubmit()"
ng-model="vm.workPackage[vm.fieldName]"> ng-model="vm.workPackage[vm.fieldName]">
<input ng-model="vm.workPackage[vm.fieldName]" <input ng-model="vm.workPackage[vm.fieldName]"
@ -9,6 +9,7 @@
class="wp-inline-edit--field" class="wp-inline-edit--field"
transform-date-value transform-date-value
ng-blur="vm.onlyInAccessibilityMode(vm.handleUserBlur)" ng-blur="vm.onlyInAccessibilityMode(vm.handleUserBlur)"
ng-keydown="vm.handleUserSubmitOnEnter($event)"
ng-required="vm.field.required" ng-required="vm.field.required"
ng-disabled="vm.workPackage.inFlight" ng-disabled="vm.workPackage.inFlight"
focus="vm.shouldFocus()" focus="vm.shouldFocus()"

@ -6,6 +6,7 @@
ng-required="vm.field.required" ng-required="vm.field.required"
ng-focus="vm.handleUserFocus()" ng-focus="vm.handleUserFocus()"
ng-blur="vm.handleUserBlur()" ng-blur="vm.handleUserBlur()"
ng-keydown="vm.handleUserSubmitOnEnter($event)"
ng-disabled="vm.workPackage.inFlight" ng-disabled="vm.workPackage.inFlight"
focus="vm.shouldFocus()" focus="vm.shouldFocus()"
focus-priority="vm.shouldFocus()" focus-priority="vm.shouldFocus()"

@ -5,6 +5,7 @@
ng-required="vm.field.required" ng-required="vm.field.required"
ng-focus="vm.handleUserFocus()" ng-focus="vm.handleUserFocus()"
ng-blur="vm.handleUserBlur()" ng-blur="vm.handleUserBlur()"
ng-keydown="vm.handleUserSubmitOnEnter($event)"
transform-float-value transform-float-value
ng-disabled="vm.workPackage.inFlight" ng-disabled="vm.workPackage.inFlight"
focus="vm.shouldFocus()" focus="vm.shouldFocus()"

@ -5,6 +5,7 @@
ng-required="vm.field.required" ng-required="vm.field.required"
ng-focus="vm.handleUserFocus()" ng-focus="vm.handleUserFocus()"
ng-blur="vm.handleUserBlur()" ng-blur="vm.handleUserBlur()"
ng-keydown="vm.handleUserSubmitOnEnter($event)"
ng-disabled="vm.workPackage.inFlight" ng-disabled="vm.workPackage.inFlight"
focus="vm.shouldFocus()" focus="vm.shouldFocus()"
focus-priority="vm.shouldFocus()" focus-priority="vm.shouldFocus()"

@ -2,7 +2,7 @@
class="wp-inline-edit--field form--select" class="wp-inline-edit--field form--select"
wp-edit-field-requirements="vm.field.schema" wp-edit-field-requirements="vm.field.schema"
ng-options="value as (value.name || value.value) for value in vm.field.options track by value.href" ng-options="value as (value.name || value.value) for value in vm.field.options track by value.href"
ng-change="vm.submit()" ng-change="vm.handleUserSubmit()"
ng-required="vm.field.required" ng-required="vm.field.required"
ng-focus="vm.handleUserFocus()" ng-focus="vm.handleUserFocus()"
ng-blur="vm.handleUserBlur()" ng-blur="vm.handleUserBlur()"

@ -6,6 +6,7 @@
ng-focus="vm.handleUserFocus()" ng-focus="vm.handleUserFocus()"
ng-blur="vm.handleUserBlur()" ng-blur="vm.handleUserBlur()"
ng-disabled="vm.workPackage.inFlight" ng-disabled="vm.workPackage.inFlight"
ng-keydown="vm.handleUserSubmitOnEnter($event)"
focus="vm.shouldFocus()" focus="vm.shouldFocus()"
focus-priority="vm.shouldFocus()" focus-priority="vm.shouldFocus()"
ng-attr-id="{{vm.htmlId}}" /> ng-attr-id="{{vm.htmlId}}" />

@ -19,7 +19,7 @@
</div> </div>
<wp-edit-field-controls ng-show="!vm.inEditMode" <wp-edit-field-controls ng-show="!vm.inEditMode"
field-controller="vm" field-controller="vm"
on-save="vm.submit()" on-save="vm.handleUserSubmit()"
on-cancel="vm.handleUserCancel()" on-cancel="vm.handleUserCancel()"
save-title="{{ vm.field.text.saveTitle }}" save-title="{{ vm.field.text.saveTitle }}"
cancel-title="{{ vm.field.text.cancelTitle }}"> cancel-title="{{ vm.field.text.cancelTitle }}">

@ -13,7 +13,8 @@
ng-click="vm.haltUserFormClick($event)" ng-click="vm.haltUserFormClick($event)"
ng-dblclick="vm.haltUserFormClick($event)" ng-dblclick="vm.haltUserFormClick($event)"
name="vm.fieldForm" name="vm.fieldForm"
ng-submit="vm.submit()" ng-submit="vm.handleUserSubmit()"
ng-keydown="vm.handleUserKey($event)"
role="form" role="form"
tabindex="-1"> tabindex="-1">

@ -65,6 +65,7 @@ export class WorkPackageEditFieldController {
protected NotificationsService, protected NotificationsService,
protected ConfigurationService, protected ConfigurationService,
protected wpCacheService: WorkPackageCacheService, protected wpCacheService: WorkPackageCacheService,
protected ENTER_KEY,
protected I18n) { protected I18n) {
} }
@ -81,11 +82,7 @@ export class WorkPackageEditFieldController {
} }
public submit() { public submit() {
if (this.inEditMode) { this.formCtrl.onFieldSubmit()
return this.formCtrl.updateForm();
}
this.formCtrl.updateWorkPackage()
.finally(() => { .finally(() => {
this.deactivate(); this.deactivate();
this._forceFocus = true; this._forceFocus = true;
@ -235,6 +232,26 @@ export class WorkPackageEditFieldController {
}); });
} }
public handleUserSubmit() {
if (this.inEditMode) {
return this.formCtrl.updateForm();
}
return this.submit();
}
/**
* Handle users pressing enter inside an edit mode.
* Outside an edit mode, the regular save event is captured by handleUserSubmit (submit event).
* In an edit mode, we can't derive from a submit event wheteher the user pressed enter
* (and on what field he did that).
*/
public handleUserSubmitOnEnter(event) {
if (this.inEditMode && event.which === this.ENTER_KEY) {
return this.submit();
}
}
public handleUserFocus() { public handleUserFocus() {
this._hasFocus = true; this._hasFocus = true;
} }
@ -253,7 +270,7 @@ export class WorkPackageEditFieldController {
} }
this.deactivate(); this.deactivate();
this.submit(); this.handleUserSubmit();
} }
public handleUserCancel() { public handleUserCancel() {

@ -120,6 +120,18 @@ export class WorkPackageEditFormController {
}); });
} }
/**
* Handle submission event of a single work package field that may or
* may not be involved inside an active edit mode.
*/
public onFieldSubmit() {
if (this.wpEditModeState.active) {
return this.wpEditModeState.save();
}
return this.updateWorkPackage();
}
public updateWorkPackage() { public updateWorkPackage() {
if (!(this.workPackage.dirty || this.workPackage.isNew)) { if (!(this.workPackage.dirty || this.workPackage.isNew)) {
return this.$q.when(this.workPackage); return this.$q.when(this.workPackage);

@ -80,13 +80,16 @@ export class WorkPackageEditModeStateService {
return this._active = false; return this._active = false;
} }
public save() { public onSaved() {
if (this.active) {
return this.form.updateWorkPackage().then(wp => {
// Doesn't use cancel() since that resets all values // Doesn't use cancel() since that resets all values
this.form.closeAllFields(); this.form.closeAllFields();
this._active = false; this._active = false;
}
public save() {
if (this.active) {
return this.form.updateWorkPackage().then(wp => {
this.onSaved();
return wp; return wp;
}); });
} }

@ -227,4 +227,16 @@ describe 'edit work package', js: true do
wp_page.expect_notification message: 'Subject is too long (maximum is 255 characters)', wp_page.expect_notification message: 'Subject is too long (maximum is 255 characters)',
type: 'error' type: 'error'
end end
it 'submits the edit mode when pressing enter' do
page.click_button(I18n.t('js.button_edit'))
subject_field = wp_page.edit_field(:subject)
subject_field.set_value 'My new subject!'
subject_field.input_element.send_keys(:return)
wp_page.expect_notification(message: 'Successful update')
subject_field.expect_inactive!
subject_field.expect_state_text 'My new subject!'
end
end end

@ -96,6 +96,20 @@ describe 'new work package', js: true do
selected: 'Bug') selected: 'Bug')
end end
it 'saves the work package with enter' do
subject_field = wp_page.subject_field
subject_field.set(subject)
subject_field.send_keys(:return)
# safegurards
wp_page.dismiss_notification!
wp_page.expect_no_notification(
message: 'Successful creation. Click here to open this work package in fullscreen view.'
)
wp_page.expect_subject
end
context 'with missing values' do context 'with missing values' do
it 'shows an error when subject is missing' do it 'shows an error when subject is missing' do
wp_page.description_field.set(description) wp_page.description_field.set(description)

Loading…
Cancel
Save