1- import { ChangeDetectorRef , Component , NgZone , OnDestroy } from '@angular/core' ;
1+ import { ChangeDetectorRef , Component , NgZone , OnDestroy , HostListener } from '@angular/core' ;
22import { AbstractItemUpdateComponent } from '../abstract-item-update/abstract-item-update.component' ;
33import { map , switchMap , take } from 'rxjs/operators' ;
44import { Observable , Subscription , zip as observableZip } from 'rxjs' ;
@@ -8,13 +8,11 @@ import { ActivatedRoute, Router } from '@angular/router';
88import { NotificationsService } from '../../../shared/notifications/notifications.service' ;
99import { TranslateService } from '@ngx-translate/core' ;
1010import { BitstreamDataService } from '../../../core/data/bitstream-data.service' ;
11- import { hasValue } from '../../../shared/empty.util' ;
1211import { ObjectCacheService } from '../../../core/cache/object-cache.service' ;
1312import { RequestService } from '../../../core/data/request.service' ;
1413import {
1514 getFirstSucceededRemoteData ,
1615 getRemoteDataPayload ,
17- getFirstCompletedRemoteData
1816} from '../../../core/shared/operators' ;
1917import { RemoteData } from '../../../core/data/remote-data' ;
2018import { PaginatedList } from '../../../core/data/paginated-list.model' ;
@@ -23,7 +21,6 @@ import { BundleDataService } from '../../../core/data/bundle-data.service';
2321import { PaginatedSearchOptions } from '../../../shared/search/models/paginated-search-options.model' ;
2422import { ResponsiveTableSizes } from '../../../shared/responsive-table-sizes/responsive-table-sizes' ;
2523import { NoContent } from '../../../core/shared/NoContent.model' ;
26- import { Operation } from 'fast-json-patch' ;
2724import { ItemBitstreamsService } from './item-bitstreams.service' ;
2825import { AlertType } from '../../../shared/alert/aletr-type' ;
2926
@@ -88,13 +85,63 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
8885 postItemInit ( ) : void {
8986 const bundlesOptions = this . itemBitstreamsService . getInitialBundlesPaginationOptions ( ) ;
9087
91- this . bundles$ = this . itemService . getBundles ( this . item . id , new PaginatedSearchOptions ( { pagination : bundlesOptions } ) ) . pipe (
88+ this . bundles$ = this . itemService . getBundles ( this . item . id , new PaginatedSearchOptions ( { pagination : bundlesOptions } ) ) . pipe (
9289 getFirstSucceededRemoteData ( ) ,
9390 getRemoteDataPayload ( ) ,
9491 map ( ( bundlePage : PaginatedList < Bundle > ) => bundlePage . page )
9592 ) ;
9693 }
9794
95+ /**
96+ * Handles keyboard events that should move the currently selected bitstream up
97+ */
98+ @HostListener ( 'document:keydown.arrowUp' , [ '$event' ] )
99+ moveUp ( event : KeyboardEvent ) {
100+ if ( this . itemBitstreamsService . hasSelectedBitstream ( ) ) {
101+ event . preventDefault ( ) ;
102+ this . itemBitstreamsService . moveSelectedBitstreamUp ( ) ;
103+ }
104+ }
105+
106+ /**
107+ * Handles keyboard events that should move the currently selected bitstream down
108+ */
109+ @HostListener ( 'document:keydown.arrowDown' , [ '$event' ] )
110+ moveDown ( event : KeyboardEvent ) {
111+ if ( this . itemBitstreamsService . hasSelectedBitstream ( ) ) {
112+ event . preventDefault ( ) ;
113+ this . itemBitstreamsService . moveSelectedBitstreamDown ( ) ;
114+ }
115+ }
116+
117+ /**
118+ * Handles keyboard events that should cancel the currently selected bitstream.
119+ * A cancel means that the selected bitstream is returned to its original position and is no longer selected.
120+ * @param event
121+ */
122+ @HostListener ( 'document:keyup.escape' , [ '$event' ] )
123+ cancelSelection ( event : KeyboardEvent ) {
124+ if ( this . itemBitstreamsService . hasSelectedBitstream ( ) ) {
125+ event . preventDefault ( ) ;
126+ this . itemBitstreamsService . cancelSelection ( ) ;
127+ }
128+ }
129+
130+ /**
131+ * Handles keyboard events that should clear the currently selected bitstream.
132+ * A clear means that the selected bitstream remains in its current position but is no longer selected.
133+ */
134+ @HostListener ( 'document:keydown.enter' , [ '$event' ] )
135+ @HostListener ( 'document:keydown.space' , [ '$event' ] )
136+ clearSelection ( event : KeyboardEvent ) {
137+ // Only when no specific element is in focus do we want to clear the currently selected bitstream
138+ // Otherwise we might clear the selection when a different action was intended, e.g. clicking a button or selecting
139+ // a different bitstream.
140+ if ( event . target instanceof Element && event . target . tagName === 'BODY' ) {
141+ this . itemBitstreamsService . clearSelection ( ) ;
142+ }
143+ }
144+
98145 /**
99146 * Initialize the notification messages prefix
100147 */
@@ -120,36 +167,6 @@ export class ItemBitstreamsComponent extends AbstractItemUpdateComponent impleme
120167 } ) ;
121168 }
122169
123- /**
124- * A bitstream was dropped in a new location. Send out a Move Patch request to the REST API, display notifications,
125- * refresh the bundle's cache (so the lists can properly reload) and call the event's callback function (which will
126- * navigate the user to the correct page)
127- * @param bundle The bundle to send patch requests to
128- * @param event The event containing the index the bitstream came from and was dropped to
129- */
130- dropBitstream ( bundle : Bundle , event : any ) {
131- this . zone . runOutsideAngular ( ( ) => {
132- if ( hasValue ( event ) && hasValue ( event . fromIndex ) && hasValue ( event . toIndex ) && hasValue ( event . finish ) ) {
133- const moveOperation = {
134- op : 'move' ,
135- from : `/_links/bitstreams/${ event . fromIndex } /href` ,
136- path : `/_links/bitstreams/${ event . toIndex } /href`
137- } as Operation ;
138- this . bundleService . patch ( bundle , [ moveOperation ] ) . pipe (
139- getFirstCompletedRemoteData ( ) ,
140- ) . subscribe ( ( response : RemoteData < Bundle > ) => {
141- this . zone . run ( ( ) => {
142- this . itemBitstreamsService . displayNotifications ( 'item.edit.bitstreams.notifications.move' , [ response ] ) ;
143- // Remove all cached requests from this bundle and call the event's callback when the requests are cleared
144- this . requestService . setStaleByHrefSubstring ( bundle . self ) . pipe (
145- take ( 1 )
146- ) . subscribe ( ( ) => event . finish ( ) ) ;
147- } ) ;
148- } ) ;
149- }
150- } ) ;
151- }
152-
153170 /**
154171 * Request the object updates service to discard all current changes to this item
155172 * Shows a notification to remind the user that they can undo this
0 commit comments