mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 10:04:11 +00:00
Merge branch 'main' into DURACOM-195
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<div class="container">
|
||||
<h1>{{ 'admin.access-control.bulk-access.title' | translate }}</h1>
|
||||
<ds-bulk-access-browse [listId]="listId"></ds-bulk-access-browse>
|
||||
<div class="clearfix mb-3"></div>
|
||||
<ds-bulk-access-settings #dsBulkSettings ></ds-bulk-access-settings>
|
||||
|
@@ -201,7 +201,7 @@ export class EPeopleRegistryComponent implements OnInit, OnDestroy {
|
||||
deleteEPerson(ePerson: EPerson) {
|
||||
if (hasValue(ePerson.id)) {
|
||||
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||
modalRef.componentInstance.dso = ePerson;
|
||||
modalRef.componentInstance.name = this.dsoNameService.getName(ePerson);
|
||||
modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-eperson.header';
|
||||
modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-eperson.info';
|
||||
modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-eperson.cancel';
|
||||
|
@@ -478,7 +478,7 @@ export class EPersonFormComponent implements OnInit, OnDestroy {
|
||||
take(1),
|
||||
switchMap((eperson: EPerson) => {
|
||||
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||
modalRef.componentInstance.dso = eperson;
|
||||
modalRef.componentInstance.name = this.dsoNameService.getName(eperson);
|
||||
modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-eperson.header';
|
||||
modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-eperson.info';
|
||||
modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-eperson.cancel';
|
||||
|
@@ -420,7 +420,7 @@ export class GroupFormComponent implements OnInit, OnDestroy {
|
||||
delete() {
|
||||
this.groupDataService.getActiveGroup().pipe(take(1)).subscribe((group: Group) => {
|
||||
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||
modalRef.componentInstance.dso = group;
|
||||
modalRef.componentInstance.name = this.dsoNameService.getName(group);
|
||||
modalRef.componentInstance.headerLabel = this.messagePrefix + '.delete-group.modal.header';
|
||||
modalRef.componentInstance.infoLabel = this.messagePrefix + '.delete-group.modal.info';
|
||||
modalRef.componentInstance.cancelLabel = this.messagePrefix + '.delete-group.modal.cancel';
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<div class="container">
|
||||
<h2 id="header">{{'admin.batch-import.page.header' | translate}}</h2>
|
||||
<h1 id="header">{{'admin.batch-import.page.header' | translate}}</h1>
|
||||
<p>{{'admin.batch-import.page.help' | translate}}</p>
|
||||
<p *ngIf="dso">
|
||||
selected collection: <b>{{getDspaceObjectName()}}</b>
|
||||
|
@@ -19,7 +19,7 @@
|
||||
<table id="formats" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" [attr.aria-label]="'admin.registries.bitstream-formats.select' | translate"></th>
|
||||
<th scope="col"><span class="sr-only">{{'admin.registries.bitstream-formats.table.selected' | translate}}</span></th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.id' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.name' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.bitstream-formats.table.mimetype' | translate}}</th>
|
||||
@@ -35,6 +35,7 @@
|
||||
[checked]="isSelected(bitstreamFormat) | async"
|
||||
(change)="selectBitStreamFormat(bitstreamFormat, $event)"
|
||||
>
|
||||
<span class="sr-only">{{'admin.registries.bitstream-formats.select' | translate}}}</span>
|
||||
</label>
|
||||
</td>
|
||||
<td><a [routerLink]="['/admin/registries/bitstream-formats', bitstreamFormat.id, 'edit']">{{bitstreamFormat.id}}</a></td>
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<div class="metadata-registry row">
|
||||
<div class="col-12">
|
||||
|
||||
<h2 id="header" class="border-bottom pb-2">{{'admin.registries.metadata.head' | translate}}</h2>
|
||||
<h1 id="header" class="border-bottom pb-2">{{'admin.registries.metadata.head' | translate}}</h1>
|
||||
|
||||
<p id="description" class="pb-2">{{'admin.registries.metadata.description' | translate}}</p>
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
<table id="metadata-schemas" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col"></th>
|
||||
<th scope="col"><span class="sr-only">{{'admin.registries.metadata.schemas.table.selected' | translate}}</span></th>
|
||||
<th scope="col">{{'admin.registries.metadata.schemas.table.id' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.metadata.schemas.table.namespace' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.metadata.schemas.table.name' | translate}}</th>
|
||||
@@ -34,6 +34,7 @@
|
||||
[checked]="isSelected(schema) | async"
|
||||
(change)="selectMetadataSchema(schema, $event)"
|
||||
>
|
||||
<span class="sr-only">{{((isSelected(schema) | async) ? 'admin.registries.metadata.schemas.deselect' : 'admin.registries.metadata.schemas.select') | translate}}</span>
|
||||
</label>
|
||||
</td>
|
||||
<td class="selectable-row" (click)="editSchema(schema)"><a [routerLink]="[schema.prefix]">{{schema.id}}</a></td>
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<div *ngIf="registryService.getActiveMetadataSchema() | async; then editheader; else createHeader"></div>
|
||||
|
||||
<ng-template #createHeader>
|
||||
<h4>{{messagePrefix + '.create' | translate}}</h4>
|
||||
<h2>{{messagePrefix + '.create' | translate}}</h2>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #editheader>
|
||||
<h4>{{messagePrefix + '.edit' | translate}}</h4>
|
||||
<h2>{{messagePrefix + '.edit' | translate}}</h2>
|
||||
</ng-template>
|
||||
|
||||
<ds-form [formId]="formId"
|
||||
|
@@ -1,11 +1,11 @@
|
||||
<div *ngIf="registryService.getActiveMetadataField() | async; then editheader; else createHeader"></div>
|
||||
|
||||
<ng-template #createHeader>
|
||||
<h4>{{messagePrefix + '.create' | translate}}</h4>
|
||||
<h2>{{messagePrefix + '.create' | translate}}</h2>
|
||||
</ng-template>
|
||||
|
||||
<ng-template #editheader>
|
||||
<h4>{{messagePrefix + '.edit' | translate}}</h4>
|
||||
<h2>{{messagePrefix + '.edit' | translate}}</h2>
|
||||
</ng-template>
|
||||
|
||||
<ds-form [formId]="formId"
|
||||
|
@@ -2,7 +2,7 @@
|
||||
<div class="metadata-schema row">
|
||||
<div class="col-12" *ngVar="(metadataSchema$ | async) as schema">
|
||||
|
||||
<h2 id="header" class="border-bottom pb-2">{{'admin.registries.schema.head' | translate}}: "{{schema?.prefix}}"</h2>
|
||||
<h1 id="header" class="border-bottom pb-2">{{'admin.registries.schema.head' | translate}}: "{{schema?.prefix}}"</h1>
|
||||
|
||||
<p id="description" class="pb-2">{{'admin.registries.schema.description' | translate:{ namespace: schema?.namespace } }}</p>
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
[metadataSchema]="schema"
|
||||
(submitForm)="forceUpdateFields()"></ds-metadata-field-form>
|
||||
|
||||
<h3>{{'admin.registries.schema.fields.head' | translate}}</h3>
|
||||
<h2>{{'admin.registries.schema.fields.head' | translate}}</h2>
|
||||
|
||||
<ng-container *ngVar="(metadataFields$ | async)?.payload as fields">
|
||||
<ds-pagination
|
||||
@@ -24,7 +24,7 @@
|
||||
<table id="metadata-fields" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th></th>
|
||||
<th><span class="sr-only">{{'admin.registries.schema.fields.table.selected' | translate}}</span></th>
|
||||
<th scope="col">{{'admin.registries.schema.fields.table.id' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.schema.fields.table.field' | translate}}</th>
|
||||
<th scope="col">{{'admin.registries.schema.fields.table.scopenote' | translate}}</th>
|
||||
@@ -33,12 +33,11 @@
|
||||
<tbody>
|
||||
<tr *ngFor="let field of fields?.page"
|
||||
[ngClass]="{'table-primary' : isActive(field) | async}">
|
||||
<td>
|
||||
<label class="mb-0">
|
||||
<td *ngVar="(isSelected(field) | async) as selected">
|
||||
<input type="checkbox"
|
||||
[checked]="isSelected(field) | async"
|
||||
[attr.aria-label]="(selected ? 'admin.registries.schema.fields.deselect' : 'admin.registries.schema.fields.select') | translate"
|
||||
[checked]="selected"
|
||||
(change)="selectMetadataField(field, $event)">
|
||||
</label>
|
||||
</td>
|
||||
<td class="selectable-row" (click)="editField(field)">{{field.id}}</td>
|
||||
<td class="selectable-row" (click)="editField(field)">{{schema?.prefix}}.{{field.element}}{{field.qualifier ? '.' + field.qualifier : ''}}</td>
|
||||
|
@@ -124,7 +124,7 @@ export class WorkspaceItemAdminWorkflowActionsComponent implements OnInit {
|
||||
*/
|
||||
deleteSupervisionOrder(supervisionOrderEntry: SupervisionOrderListEntry) {
|
||||
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||
modalRef.componentInstance.dso = supervisionOrderEntry.group;
|
||||
modalRef.componentInstance.name = this.dsoNameService.getName(supervisionOrderEntry.group);
|
||||
modalRef.componentInstance.headerLabel = this.messagePrefix + '.delete-supervision.modal.header';
|
||||
modalRef.componentInstance.infoLabel = this.messagePrefix + '.delete-supervision.modal.info';
|
||||
modalRef.componentInstance.cancelLabel = this.messagePrefix + '.delete-supervision.modal.cancel';
|
||||
|
@@ -13,7 +13,7 @@
|
||||
<!-- Collection logo -->
|
||||
<ds-comcol-page-logo *ngIf="logoRD$"
|
||||
[logo]="(logoRD$ | async)?.payload"
|
||||
[alternateText]="'Collection Logo'">
|
||||
[alternateText]="'collection.logo' | translate">
|
||||
</ds-comcol-page-logo>
|
||||
|
||||
<!-- Handle -->
|
||||
|
@@ -1,17 +1,17 @@
|
||||
<div class="container-fluid mb-2" *ngVar="(itemTemplateRD$ | async) as itemTemplateRD">
|
||||
<label>{{ 'collection.edit.template.label' | translate}}</label>
|
||||
<span class="d-inline-block mb-2">{{ 'collection.edit.template.label' | translate}}</span>
|
||||
<div class="button-row space-children-mr">
|
||||
<button *ngIf="!itemTemplateRD?.payload" class="btn btn-success" (click)="addItemTemplate()">
|
||||
<i class="fas fa-plus"></i>
|
||||
<i class="fas fa-plus" aria-hidden="true"></i>
|
||||
<span class="d-none d-sm-inline"> {{"collection.edit.template.add-button" | translate}}</span>
|
||||
</button>
|
||||
<button *ngIf="itemTemplateRD?.payload" class="btn btn-danger" (click)="deleteItemTemplate()">
|
||||
<i class="fas fa-trash-alt"></i>
|
||||
<i class="fas fa-trash-alt" aria-hidden="true"></i>
|
||||
<span class="d-none d-sm-inline"> {{"collection.edit.template.delete-button" | translate}}</span>
|
||||
</button>
|
||||
<button *ngIf="itemTemplateRD?.payload" class="btn btn-primary"
|
||||
[routerLink]="'/collections/' + (dsoRD$ | async)?.payload.uuid + '/itemtemplate'">
|
||||
<i class="fas fa-edit"></i>
|
||||
<i class="fas fa-edit" aria-hidden="true"></i>
|
||||
<span class="d-none d-sm-inline"> {{"collection.edit.template.edit-button" | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@@ -4,9 +4,9 @@
|
||||
<cdk-tree-node *cdkTreeNodeDef="let node; when: isShowMore" cdkTreeNodePadding
|
||||
class="example-tree-node show-more-node">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default" cdkTreeNodeToggle>
|
||||
<span class="fa fa-chevron-right invisible" aria-hidden="true"></span>
|
||||
</button>
|
||||
<span aria-hidden="true" class="btn btn-default invisible" cdkTreeNodeToggle>
|
||||
<span class="fa fa-chevron-right"></span>
|
||||
</span>
|
||||
<div class="align-middle pt-2">
|
||||
<button *ngIf="!(dataSource.loading$ | async)" (click)="getNextPage(node)"
|
||||
class="btn btn-outline-primary btn-sm" role="button">
|
||||
@@ -24,15 +24,18 @@
|
||||
<cdk-tree-node *cdkTreeNodeDef="let node; when: hasChild" cdkTreeNodePadding
|
||||
class="example-tree-node expandable-node">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default" cdkTreeNodeToggle
|
||||
[title]="'toggle ' + dsoNameService.getName(node.payload)"
|
||||
[attr.aria-label]="'toggle ' + dsoNameService.getName(node.payload)"
|
||||
<button *ngIf="hasChild(null, node) | async" type="button" class="btn btn-default" cdkTreeNodeToggle
|
||||
[attr.aria-label]="(node.isExpanded ? 'communityList.collapse' : 'communityList.expand') | translate:{ name: dsoNameService.getName(node.payload) }"
|
||||
(click)="toggleExpanded(node)"
|
||||
[ngClass]="(hasChild(null, node)| async) ? 'visible' : 'invisible'"
|
||||
[attr.data-test]="(hasChild(null, node)| async) ? 'expand-button' : ''">
|
||||
data-test="expand-button">
|
||||
<span class="{{node.isExpanded ? 'fa fa-chevron-down' : 'fa fa-chevron-right'}}"
|
||||
aria-hidden="true"></span>
|
||||
<span class="sr-only">{{ (node.isExpanded ? 'communityList.collapse' : 'communityList.expand') | translate:{ name: dsoNameService.getName(node.payload) } }}</span>
|
||||
</button>
|
||||
<!--Don't render the button when non-expandable otherwise it's still accessible, instead render this placeholder-->
|
||||
<span *ngIf="!(hasChild(null, node) | async)" aria-hidden="true" class="btn btn-default invisible">
|
||||
<span class="fa fa-chevron-right"></span>
|
||||
</span>
|
||||
<div class="d-flex flex-row">
|
||||
<span class="align-middle pt-2 lead">
|
||||
<a [routerLink]="node.route" class="lead">{{ dsoNameService.getName(node.payload) }}</a>
|
||||
@@ -44,10 +47,9 @@
|
||||
<ds-truncatable [id]="node.id">
|
||||
<div class="text-muted" cdkTreeNodePadding>
|
||||
<div class="d-flex" *ngIf="node.payload.shortDescription">
|
||||
<button type="button" class="btn btn-default invisible">
|
||||
<span class="{{node.isExpanded ? 'fa fa-chevron-down' : 'fa fa-chevron-right'}}"
|
||||
aria-hidden="true"></span>
|
||||
</button>
|
||||
<span aria-hidden="true" class="btn btn-default invisible">
|
||||
<span class="fa fa-chevron-right"></span>
|
||||
</span>
|
||||
<ds-truncatable-part [id]="node.id" [minLines]="3">
|
||||
<span>{{node.payload.shortDescription}}</span>
|
||||
</ds-truncatable-part>
|
||||
@@ -56,10 +58,9 @@
|
||||
</ds-truncatable>
|
||||
<div class="d-flex" *ngIf="node===loadingNode && dataSource.loading$ | async"
|
||||
cdkTreeNodePadding>
|
||||
<button type="button" class="btn btn-default invisible">
|
||||
<span class="{{node.isExpanded ? 'fa fa-chevron-down' : 'fa fa-chevron-right'}}"
|
||||
aria-hidden="true"></span>
|
||||
</button>
|
||||
<span aria-hidden="true" class="btn btn-default invisible">
|
||||
<span class="fa fa-chevron-right"></span>
|
||||
</span>
|
||||
<ds-themed-loading class="ds-themed-loading"></ds-themed-loading>
|
||||
</div>
|
||||
</cdk-tree-node>
|
||||
@@ -67,9 +68,9 @@
|
||||
<cdk-tree-node *cdkTreeNodeDef="let node; when: !(hasChild && isShowMore)" cdkTreeNodePadding
|
||||
class="example-tree-node childless-node">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-default" cdkTreeNodeToggle>
|
||||
<span class="fa fa-chevron-right invisible" aria-hidden="true"></span>
|
||||
</button>
|
||||
<span aria-hidden="true" class="btn btn-default invisible" cdkTreeNodeToggle>
|
||||
<span class="fa fa-chevron-right"></span>
|
||||
</span>
|
||||
<h6 class="align-middle pt-2">
|
||||
<a [routerLink]="node.route" class="lead">{{ dsoNameService.getName(node.payload) }}</a>
|
||||
</h6>
|
||||
@@ -77,10 +78,9 @@
|
||||
<ds-truncatable [id]="node.id">
|
||||
<div class="text-muted" cdkTreeNodePadding>
|
||||
<div class="d-flex" *ngIf="node.payload.shortDescription">
|
||||
<button type="button" class="btn btn-default invisible">
|
||||
<span class="{{node.isExpanded ? 'fa fa-chevron-down' : 'fa fa-chevron-right'}}"
|
||||
aria-hidden="true"></span>
|
||||
</button>
|
||||
<span aria-hidden="true" class="btn btn-default invisible">
|
||||
<span class="fa fa-chevron-right"></span>
|
||||
</span>
|
||||
<ds-truncatable-part [id]="node.id" [minLines]="3">
|
||||
<span>{{node.payload.shortDescription}}</span>
|
||||
</ds-truncatable-part>
|
||||
|
@@ -0,0 +1,4 @@
|
||||
::ng-deep .fa-chevron-right::before {
|
||||
display: block;
|
||||
width: 16px;
|
||||
}
|
@@ -5,7 +5,7 @@ import { CommunityListService, showMoreFlatNode, toFlatNode } from '../community
|
||||
import { CdkTreeModule } from '@angular/cdk/tree';
|
||||
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
|
||||
import { TranslateLoaderMock } from '../../shared/mocks/translate-loader.mock';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
||||
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '@angular/core';
|
||||
import { RouterTestingModule } from '@angular/router/testing';
|
||||
import { Community } from '../../core/shared/community.model';
|
||||
import { createSuccessfulRemoteDataObject$ } from '../../shared/remote-data.utils';
|
||||
@@ -300,12 +300,14 @@ describe('CommunityListComponent', () => {
|
||||
|
||||
describe('second top community node is expanded and has more children (collections) than page size of collection', () => {
|
||||
describe('children of second top com are added (page-limited pageSize 2)', () => {
|
||||
let allNodes;
|
||||
let allNodes: DebugElement[];
|
||||
beforeEach(fakeAsync(() => {
|
||||
const chevronExpand = fixture.debugElement.queryAll(By.css('.expandable-node button'));
|
||||
const chevronExpandSpan = fixture.debugElement.queryAll(By.css('.expandable-node button span'));
|
||||
if (chevronExpandSpan[1].nativeElement.classList.contains('fa-chevron-right')) {
|
||||
chevronExpand[1].nativeElement.click();
|
||||
const toggleButtons: DebugElement[] = fixture.debugElement.queryAll(By.css('.expandable-node button'));
|
||||
const toggleButtonText: DebugElement = toggleButtons[1].query(By.css('span'));
|
||||
expect(toggleButtonText).not.toBeNull();
|
||||
|
||||
if (toggleButtonText.nativeElement.classList.contains('fa-chevron-right')) {
|
||||
toggleButtons[1].nativeElement.click();
|
||||
tick();
|
||||
fixture.detectChanges();
|
||||
}
|
||||
@@ -315,17 +317,18 @@ describe('CommunityListComponent', () => {
|
||||
allNodes = [...expandableNodesFound, ...childlessNodesFound];
|
||||
}));
|
||||
it('tree contains 2 (page-limited) top com, 2 (page-limited) coll of 2nd top com, a show more for those page-limited coll and show more for page-limited top com', () => {
|
||||
mockTopFlatnodesUnexpanded.slice(0, 2).map((topFlatnode: FlatNode) => {
|
||||
expect(allNodes.find((foundEl) => {
|
||||
return (foundEl.nativeElement.textContent.trim() === topFlatnode.name);
|
||||
})).toBeTruthy();
|
||||
});
|
||||
mockCollectionsPage1.map((coll) => {
|
||||
expect(allNodes.find((foundEl) => {
|
||||
return (foundEl.nativeElement.textContent.trim() === coll.name);
|
||||
})).toBeTruthy();
|
||||
});
|
||||
const allNodeNames: string[] = allNodes.map((node: DebugElement) => node.nativeElement.innerText.trim());
|
||||
expect(allNodes.length).toEqual(4);
|
||||
const flatNodes: string[] = mockTopFlatnodesUnexpanded.slice(0, 2).map((flatNode: FlatNode) => flatNode.name);
|
||||
for (const flatNode of flatNodes) {
|
||||
expect(allNodeNames).toContain(flatNode);
|
||||
}
|
||||
expect(flatNodes.length).toBe(2);
|
||||
const page1CollectionNames: string[] = mockCollectionsPage1.map((collection: Collection) => collection.name);
|
||||
for (const collectionName of page1CollectionNames) {
|
||||
expect(allNodeNames).toContain(collectionName);
|
||||
}
|
||||
expect(page1CollectionNames.length).toBe(2);
|
||||
const showMoreEl = fixture.debugElement.queryAll(By.css('.show-more-node'));
|
||||
expect(showMoreEl.length).toEqual(2);
|
||||
});
|
||||
|
@@ -19,6 +19,7 @@ import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
@Component({
|
||||
selector: 'ds-community-list',
|
||||
templateUrl: './community-list.component.html',
|
||||
styleUrls: ['./community-list.component.scss'],
|
||||
})
|
||||
export class CommunityListComponent implements OnInit, OnDestroy {
|
||||
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<!-- Community name -->
|
||||
<ds-comcol-page-header [name]="dsoNameService.getName(communityPayload)"></ds-comcol-page-header>
|
||||
<!-- Community logo -->
|
||||
<ds-comcol-page-logo *ngIf="logoRD$" [logo]="(logoRD$ | async)?.payload" [alternateText]="'Community Logo'">
|
||||
<ds-comcol-page-logo *ngIf="logoRD$" [logo]="(logoRD$ | async)?.payload" [alternateText]="'community.logo' | translate">
|
||||
</ds-comcol-page-logo>
|
||||
<!-- Handle -->
|
||||
<ds-themed-comcol-page-handle [content]="communityPayload.handle" [title]="'community.page.handle'">
|
||||
|
@@ -7,11 +7,11 @@
|
||||
<div class="form-group row">
|
||||
<div class="col text-right space-children-mr">
|
||||
<button class="btn btn-outline-secondary" (click)="onCancel(dso)" [disabled]="(processing$ | async)">
|
||||
<i class="fas fa-times"></i> {{'community.delete.cancel' | translate}}
|
||||
<i class="fas fa-times" aria-hidden="true"></i> {{'community.delete.cancel' | translate}}
|
||||
</button>
|
||||
<button class="btn btn-danger" (click)="onConfirm(dso)" [disabled]="(processing$ | async)">
|
||||
<span *ngIf="processing$ | async"><i class='fas fa-circle-notch fa-spin'></i> {{'community.delete.processing' | translate}}</span>
|
||||
<span *ngIf="!(processing$ | async)"><i class="fas fa-trash"></i> {{'community.delete.confirm' | translate}}</span>
|
||||
<span *ngIf="processing$ | async"><i class='fas fa-circle-notch fa-spin' aria-hidden="true"></i> {{'community.delete.processing' | translate}}</span>
|
||||
<span *ngIf="!(processing$ | async)"><i class="fas fa-trash" aria-hidden="true"></i> {{'community.delete.confirm' | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -351,7 +351,28 @@ function addOperationToList(body: JsonPatchOperationObject[], actionType, target
|
||||
newBody.push(makeOperationEntry({ op: JsonPatchOperationType.move, from: fromPath, path: targetPath }));
|
||||
break;
|
||||
}
|
||||
return newBody;
|
||||
return dedupeOperationEntries(newBody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dedupe operation entries by op and path. This prevents processing unnecessary patches in a single PATCH request.
|
||||
*
|
||||
* @param body JSON patch operation object entries
|
||||
* @returns deduped JSON patch operation object entries
|
||||
*/
|
||||
function dedupeOperationEntries(body: JsonPatchOperationObject[]): JsonPatchOperationObject[] {
|
||||
const ops = new Map<string, any>();
|
||||
for (let i = body.length - 1; i >= 0; i--) {
|
||||
const patch = body[i].operation;
|
||||
const key = `${patch.op}-${patch.path}`;
|
||||
if (!ops.has(key)) {
|
||||
ops.set(key, patch);
|
||||
} else {
|
||||
body.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
return body;
|
||||
}
|
||||
|
||||
function makeOperationEntry(operation) {
|
||||
|
@@ -2,23 +2,23 @@
|
||||
<div class="button-row top d-flex my-2 space-children-mr ml-gap">
|
||||
<button class="mr-auto btn btn-success" id="dso-add-btn" [disabled]="form.newValue || (saving$ | async)"
|
||||
[title]="dsoType + '.edit.metadata.add-button' | translate"
|
||||
(click)="add()"><i class="fas fa-plus"></i>
|
||||
(click)="add()"><i class="fas fa-plus" aria-hidden="true"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.add-button' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-warning ml-1" id="dso-reinstate-btn" *ngIf="isReinstatable" [disabled]="(saving$ | async)"
|
||||
[title]="dsoType + '.edit.metadata.reinstate-button' | translate"
|
||||
(click)="reinstate()"><i class="fas fa-undo-alt"></i>
|
||||
(click)="reinstate()"><i class="fas fa-undo-alt" aria-hidden="true"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.reinstate-button' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-primary ml-1" id="dso-save-btn" [disabled]="!hasChanges || (saving$ | async)"
|
||||
[title]="dsoType + '.edit.metadata.save-button' | translate"
|
||||
(click)="submit()"><i class="fas fa-save"></i>
|
||||
(click)="submit()"><i class="fas fa-save" aria-hidden="true"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.save-button' | translate }}</span>
|
||||
</button>
|
||||
<button class="btn btn-danger ml-1" id="dso-discard-btn" *ngIf="!isReinstatable"
|
||||
[title]="dsoType + '.edit.metadata.discard-button' | translate"
|
||||
[disabled]="!hasChanges || (saving$ | async)"
|
||||
(click)="discard()"><i class="fas fa-times"></i>
|
||||
(click)="discard()"><i class="fas fa-times" aria-hidden="true"></i>
|
||||
<span class="d-none d-sm-inline"> {{ dsoType + '.edit.metadata.discard-button' | translate }}</span>
|
||||
</button>
|
||||
</div>
|
||||
@@ -74,16 +74,19 @@
|
||||
<div class="mt-2 float-right space-children-mr ml-gap">
|
||||
<button class="btn btn-warning" *ngIf="isReinstatable" [disabled]="(saving$ | async)"
|
||||
[title]="dsoType + '.edit.metadata.reinstate-button' | translate"
|
||||
(click)="reinstate()"><i class="fas fa-undo-alt"></i> {{ dsoType + '.edit.metadata.reinstate-button' | translate }}
|
||||
(click)="reinstate()">
|
||||
<i class="fas fa-undo-alt" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.reinstate-button' | translate }}
|
||||
</button>
|
||||
<button class="btn btn-primary" [disabled]="!hasChanges || (saving$ | async)"
|
||||
[title]="dsoType + '.edit.metadata.save-button' | translate"
|
||||
(click)="submit()"><i class="fas fa-save"></i> {{ dsoType + '.edit.metadata.save-button' | translate }}
|
||||
(click)="submit()">
|
||||
<i class="fas fa-save" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.save-button' | translate }}
|
||||
</button>
|
||||
<button class="btn btn-danger" *ngIf="!isReinstatable"
|
||||
[title]="dsoType + '.edit.metadata.discard-button' | translate"
|
||||
[disabled]="!hasChanges || (saving$ | async)"
|
||||
(click)="discard()"><i class="fas fa-times"></i> {{ dsoType + '.edit.metadata.discard-button' | translate }}
|
||||
(click)="discard()">
|
||||
<i class="fas fa-times" aria-hidden="true"></i> {{ dsoType + '.edit.metadata.discard-button' | translate }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,6 +1,7 @@
|
||||
<div class="w-100 position-relative">
|
||||
<input type="text" #mdFieldInput
|
||||
class="form-control" [ngClass]="{ 'is-invalid': showInvalid }"
|
||||
[attr.aria-label]="(dsoType + '.edit.metadata.metadatafield') | translate"
|
||||
[value]="mdField"
|
||||
[formControl]="input"
|
||||
(focusin)="query$.next(mdField)"
|
||||
@@ -10,9 +11,9 @@
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (mdFieldOptions$ | async)?.length > 0}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let mdFieldOption of (mdFieldOptions$ | async)">
|
||||
<a href="javascript:void(0);" class="d-block dropdown-item" (click)="select(mdFieldOption)">
|
||||
<button class="d-block dropdown-item" (click)="select(mdFieldOption)">
|
||||
<span [innerHTML]="mdFieldOption"></span>
|
||||
</a>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -11,7 +11,9 @@
|
||||
[dsDebounce]="debounceTime" (onDebounce)="find($event)"
|
||||
[placeholder]="placeholder"
|
||||
[ngModelOptions]="{standalone: true}" autocomplete="off"/>
|
||||
<input type="submit" class="d-none"/>
|
||||
<button class="sr-only" type="submit">
|
||||
{{'search.filters.search.submit' | translate}}
|
||||
</button>
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (show | async) && isNotEmpty(suggestions)}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let suggestionOption of suggestions">
|
||||
|
@@ -2,6 +2,7 @@ import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { ChangeDetectionStrategy, NO_ERRORS_SCHEMA } from '@angular/core';
|
||||
import { OrgUnitInputSuggestionsComponent } from './org-unit-input-suggestions.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
|
||||
let component: OrgUnitInputSuggestionsComponent;
|
||||
let fixture: ComponentFixture<OrgUnitInputSuggestionsComponent>;
|
||||
@@ -21,6 +22,7 @@ describe('OrgUnitInputSuggestionsComponent', () => {
|
||||
declarations: [OrgUnitInputSuggestionsComponent],
|
||||
imports: [
|
||||
FormsModule,
|
||||
TranslateModule.forRoot(),
|
||||
],
|
||||
providers: [
|
||||
],
|
||||
|
@@ -12,7 +12,9 @@
|
||||
[dsDebounce]="debounceTime" (onDebounce)="find($event)"
|
||||
[placeholder]="placeholder"
|
||||
[ngModelOptions]="{standalone: true}" autocomplete="off"/>
|
||||
<input type="submit" class="d-none"/>
|
||||
<button class="sr-only" type="submit">
|
||||
{{'search.filters.search.submit' | translate}}
|
||||
</button>
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (show | async) && isNotEmpty(suggestions)}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let suggestionOption of suggestions">
|
||||
|
@@ -1,13 +1,13 @@
|
||||
<div class="container" *ngIf="(registration$ |async)">
|
||||
<h3 class="mb-4">{{'forgot-password.form.head' | translate}}</h3>
|
||||
<h1 class="mb-4">{{'forgot-password.form.head' | translate}}</h1>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">{{'forgot-password.form.identification.header' | translate}}</div>
|
||||
<div class="card-body">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<label class="font-weight-bold"
|
||||
for="email">{{'forgot-password.form.identification.email' | translate}}</label>
|
||||
<span id="email">{{(registration$ |async).email}}</span></div>
|
||||
<span class="font-weight-bold">{{'forgot-password.form.identification.email' | translate}} </span>
|
||||
<span [attr.data-test]="'email' | dsBrowserOnly">{{(registration$ |async).email}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -21,6 +21,7 @@ import {
|
||||
createSuccessfulRemoteDataObject$
|
||||
} from '../../shared/remote-data.utils';
|
||||
import { CoreState } from '../../core/core-state.model';
|
||||
import { BrowserOnlyPipe } from '../../shared/utils/browser-only.pipe';
|
||||
|
||||
describe('ForgotPasswordFormComponent', () => {
|
||||
let comp: ForgotPasswordFormComponent;
|
||||
@@ -54,7 +55,10 @@ describe('ForgotPasswordFormComponent', () => {
|
||||
|
||||
TestBed.configureTestingModule({
|
||||
imports: [CommonModule, RouterTestingModule.withRoutes([]), TranslateModule.forRoot(), ReactiveFormsModule],
|
||||
declarations: [ForgotPasswordFormComponent],
|
||||
declarations: [
|
||||
BrowserOnlyPipe,
|
||||
ForgotPasswordFormComponent,
|
||||
],
|
||||
providers: [
|
||||
{provide: Router, useValue: router},
|
||||
{provide: ActivatedRoute, useValue: route},
|
||||
@@ -75,7 +79,7 @@ describe('ForgotPasswordFormComponent', () => {
|
||||
|
||||
describe('init', () => {
|
||||
it('should initialise mail address', () => {
|
||||
const elem = fixture.debugElement.queryAll(By.css('span#email'))[0].nativeElement;
|
||||
const elem = fixture.debugElement.queryAll(By.css('span[data-test="email"]'))[0].nativeElement;
|
||||
expect(elem.innerHTML).toContain('test@email.org');
|
||||
});
|
||||
});
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<div class="container" *ngIf="(healthResponseInitialised | async) && (healthInfoResponseInitialised | async)">
|
||||
<h2>{{'health-page.heading' | translate}}</h2>
|
||||
<h1>{{'health-page.heading' | translate}}</h1>
|
||||
<div *ngIf="(healthResponse | async) && (healthInfoResponse | async)">
|
||||
<ul ngbNav #nav="ngbNav" [activeId]="'status'" class="nav-tabs">
|
||||
<li [ngbNavItem]="'status'" role="presentation">
|
||||
|
@@ -1,9 +1,8 @@
|
||||
<div class="row row-offcanvas row-offcanvas-right">
|
||||
<div class="col-xs-12 col-sm-12 col-md-9">
|
||||
<form class="primary" [formGroup]="feedbackForm" (ngSubmit)="createFeedback()">
|
||||
<h1>{{ 'info.feedback.head' | translate }}</h1>
|
||||
<p>{{ 'info.feedback.info' | translate }}</p>
|
||||
<fieldset class="col p-0">
|
||||
<form [formGroup]="feedbackForm" (ngSubmit)="createFeedback()" class="col p-0">
|
||||
<div class="row">
|
||||
<div class="control-group col-sm-12">
|
||||
<label class="control-label" for="email">{{ 'info.feedback.email-label' | translate }} </label>
|
||||
@@ -39,7 +38,6 @@
|
||||
<button [disabled]="!feedbackForm.valid" class="btn btn-primary" name="submit" type="submit">{{ 'info.feedback.send' | translate }}</button>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -15,10 +15,10 @@
|
||||
[attr.data-test]="'import-dropdown' | dsBrowserOnly"
|
||||
title="{{'mydspace.new-submission-external' | translate}}">
|
||||
<i class="fa fa-file-import" aria-hidden="true"></i>
|
||||
<span class="caret"></span>
|
||||
<span class="caret" aria-hidden="true"></span>
|
||||
</button>
|
||||
<div ngbDropdownMenu
|
||||
class="dropdown-menu"
|
||||
class="dropdown-menu p-0"
|
||||
id="importControlsDropdownMenu"
|
||||
aria-labelledby="dropdownImport">
|
||||
<ds-entity-dropdown [isSubmission]="false" (selectionChange)="openPage($event)"></ds-entity-dropdown>
|
||||
|
@@ -13,10 +13,10 @@
|
||||
[attr.data-test]="'submission-dropdown' | dsBrowserOnly"
|
||||
title="{{'mydspace.new-submission' | translate}}">
|
||||
<i class="fa fa-plus-circle" aria-hidden="true"></i>
|
||||
<span class="caret"></span>
|
||||
<span class="caret" aria-hidden="true"></span>
|
||||
</button>
|
||||
<div ngbDropdownMenu
|
||||
class="dropdown-menu"
|
||||
class="dropdown-menu p-0"
|
||||
id="entityControlsDropdownMenu"
|
||||
aria-labelledby="dropdownSubmission">
|
||||
<ds-entity-dropdown [isSubmission]="true" (selectionChange)="openDialog($event)"></ds-entity-dropdown>
|
||||
|
@@ -43,7 +43,8 @@ export class ProfilePageMetadataFormComponent implements OnInit {
|
||||
new DynamicInputModel({
|
||||
id: 'email',
|
||||
name: 'email',
|
||||
readOnly: true
|
||||
readOnly: true,
|
||||
disabled: true,
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'firstname',
|
||||
@@ -55,6 +56,7 @@ export class ProfilePageMetadataFormComponent implements OnInit {
|
||||
errorMessages: {
|
||||
required: 'This field is required'
|
||||
},
|
||||
autoComplete: 'given-name',
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'lastname',
|
||||
@@ -66,10 +68,12 @@ export class ProfilePageMetadataFormComponent implements OnInit {
|
||||
errorMessages: {
|
||||
required: 'This field is required'
|
||||
},
|
||||
autoComplete: 'family-name',
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'phone',
|
||||
name: 'eperson.phone'
|
||||
name: 'eperson.phone',
|
||||
autoComplete: 'tel',
|
||||
}),
|
||||
new DynamicSelectModel<string>({
|
||||
id: 'language',
|
||||
|
@@ -39,12 +39,14 @@ export class ProfilePageSecurityFormComponent implements OnInit {
|
||||
new DynamicInputModel({
|
||||
id: 'password',
|
||||
name: 'password',
|
||||
inputType: 'password'
|
||||
inputType: 'password',
|
||||
autoComplete: 'new-password',
|
||||
}),
|
||||
new DynamicInputModel({
|
||||
id: 'passwordrepeat',
|
||||
name: 'passwordrepeat',
|
||||
inputType: 'password'
|
||||
inputType: 'password',
|
||||
autoComplete: 'new-password',
|
||||
})
|
||||
];
|
||||
|
||||
@@ -79,7 +81,8 @@ export class ProfilePageSecurityFormComponent implements OnInit {
|
||||
id: 'current-password',
|
||||
name: 'current-password',
|
||||
inputType: 'password',
|
||||
required: true
|
||||
required: true,
|
||||
autoComplete: 'current-password',
|
||||
}));
|
||||
}
|
||||
if (this.passwordCanBeEmpty) {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
<ng-container *ngVar="(user$ | async) as user">
|
||||
<div class="container" *ngIf="user">
|
||||
<ng-container *ngIf="isResearcherProfileEnabled() | async">
|
||||
<h2 class="mb-4">{{'profile.head' | translate}}</h2>
|
||||
<h1>{{'profile.title' | translate}}</h1>
|
||||
<ng-container>
|
||||
<div class="card mb-4">
|
||||
<div class="card-header">{{'profile.card.researcher' | translate}}</div>
|
||||
<div class="card-body">
|
||||
|
@@ -88,7 +88,7 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label> </label>
|
||||
<span aria-hidden="true" class="mb-2 d-inline-block"> </span>
|
||||
<div class="input-group">
|
||||
|
||||
<button type="button" class="btn btn-outline-danger"
|
||||
|
@@ -23,10 +23,10 @@
|
||||
</ui-switch>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">
|
||||
<fieldset class="row mt-3">
|
||||
<legend class="h4 col-12 col-md-3">
|
||||
{{ 'access-control-mode' | translate }}
|
||||
</div>
|
||||
</legend>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
@@ -47,7 +47,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -78,10 +78,10 @@
|
||||
</div>
|
||||
|
||||
<div *ngIf="showLimitToSpecificBitstreams" class="row mt-3">
|
||||
<div class="col-12">
|
||||
<fieldset class="col-12">
|
||||
<legend class="h4">
|
||||
{{'access-control-limit-to-specific' | translate}}
|
||||
</div>
|
||||
<div class="col-12">
|
||||
</legend>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
name="changesLimit" id="processAll" value="all"
|
||||
@@ -111,14 +111,14 @@
|
||||
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3">
|
||||
<div class="col-12 col-md-3">
|
||||
<fieldset class="row mt-3">
|
||||
<legend class="h4 col-12 col-md-3">
|
||||
{{'access-control-mode' | translate}}
|
||||
</div>
|
||||
</legend>
|
||||
<div class="col-12 col-md-8">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio"
|
||||
@@ -139,7 +139,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<div>
|
||||
<h3 class="h4 mt-3">{{'access-control-access-conditions' | translate}}</h3>
|
||||
|
@@ -1,4 +1,4 @@
|
||||
<div *ngIf="searchField" class="form-group w-100 pr-2 pl-2">
|
||||
<div *ngIf="searchField" class="form-group w-100 pr-2 pl-2 my-2">
|
||||
<input type="search"
|
||||
class="form-control w-100"
|
||||
(click)="$event.stopPropagation();"
|
||||
@@ -6,9 +6,9 @@
|
||||
[formControl]="searchField"
|
||||
#searchFieldEl>
|
||||
</div>
|
||||
<div class="dropdown-divider"></div>
|
||||
<ul class="scrollable-menu p-0"
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
<div class="dropdown-divider m-0"></div>
|
||||
<ul class="scrollable-menu p-0 m-0"
|
||||
role="menu"
|
||||
(scroll)="onScroll($event)"
|
||||
infiniteScroll
|
||||
[infiniteScrollDistance]="1.5"
|
||||
@@ -18,12 +18,13 @@
|
||||
[scrollWindow]="false"
|
||||
(scrolled)="onScrollDown()">
|
||||
|
||||
<li class="dropdown-item disabled" *ngIf="searchListCollection?.length == 0 && !(isLoading | async)">
|
||||
<li class="dropdown-item disabled" role="menuitem" *ngIf="searchListCollection?.length == 0 && !(isLoading | async)">
|
||||
{{'submission.sections.general.no-collection' | translate}}
|
||||
</li>
|
||||
<ng-container *ngIf="searchListCollection?.length > 0">
|
||||
<li *ngFor="let listItem of searchListCollection"
|
||||
class="dropdown-item collection-item"
|
||||
role="menuitem"
|
||||
title="{{ listItem.collection.name }}"
|
||||
(click)="onSelect(listItem)">
|
||||
<div class="list-unstyled mb-0">
|
||||
@@ -34,9 +35,10 @@
|
||||
</div>
|
||||
</li>
|
||||
</ng-container>
|
||||
<button class="dropdown-item disabled" *ngIf="(isLoading | async)">
|
||||
<li *ngIf="(isLoading | async)">
|
||||
<button class="dropdown-item disabled">
|
||||
<ds-themed-loading message="{{'loading.default' | translate}}">
|
||||
</ds-themed-loading>
|
||||
</button>
|
||||
|
||||
</li>
|
||||
</ul>
|
||||
|
@@ -4,7 +4,8 @@
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.collection-item {
|
||||
li:not(:last-of-type), .dropdown-divider {
|
||||
border-top: none;
|
||||
border-bottom: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);
|
||||
}
|
||||
|
||||
|
@@ -1,13 +1,13 @@
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<div class="col-12 d-inline-block">
|
||||
<label>{{type.value + '.edit.logo.label' | translate}}</label>
|
||||
<div class="col-12 d-inline-block mb-1">
|
||||
<span>{{type.value + '.edit.logo.label' | translate}}</span>
|
||||
</div>
|
||||
<ng-container *ngVar="(dso?.logo | async)?.payload as logo">
|
||||
<div class="col-12 d-inline-block alert" [ngClass]="{'alert-danger': markLogoForDeletion}" id="logo-section" *ngIf="logo">
|
||||
<div class="row">
|
||||
<div class="col-8 d-inline-block">
|
||||
<ds-comcol-page-logo [logo]="logo"></ds-comcol-page-logo>
|
||||
<ds-comcol-page-logo [alternateText]="type.value + '.logo.alt'" [logo]="logo"></ds-comcol-page-logo>
|
||||
</div>
|
||||
<div class="col-4 d-inline-block">
|
||||
<div *ngIf="logo" class="btn-group btn-group-sm float-right" role="group">
|
||||
@@ -27,6 +27,7 @@
|
||||
</div>
|
||||
<div *ngIf="!logo" class="col-12 d-inline-block">
|
||||
<ds-uploader *ngIf="initializedUploaderOptions | async"
|
||||
[ariaLabel]="type.value + '.browse.logo'"
|
||||
[dropMsg]="type.value + '.edit.logo.upload'"
|
||||
[dropOverDocumentMsg]="type.value + '.edit.logo.upload'"
|
||||
[enableDragOverDocument]="true"
|
||||
@@ -43,6 +44,6 @@
|
||||
[displayCancel]="false"
|
||||
(submitForm)="onSubmit()">
|
||||
<button before (click)="back.emit()" class="btn btn-outline-secondary" type="button">
|
||||
<i class="fas fa-arrow-left"></i> {{ type.value + '.edit.return' | translate }}
|
||||
<i class="fas fa-arrow-left" aria-hidden="true"></i> {{ type.value + '.edit.return' | translate }}
|
||||
</button>
|
||||
</ds-form>
|
||||
|
@@ -7,7 +7,7 @@
|
||||
<a class="btn btn-danger"
|
||||
[routerLink]="((type === 'community') ? '/communities/' : '/collections/') + (dsoRD$ | async)?.payload.uuid + '/delete'"
|
||||
data-test="delete-button">
|
||||
<i class="fas fa-trash"></i> {{type + '.edit.delete' | translate}}</a>
|
||||
<i class="fas fa-trash" aria-hidden="true"></i> {{type + '.edit.delete' | translate}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-2">
|
||||
@@ -27,7 +27,7 @@
|
||||
</div>
|
||||
<div class="col-12 text-right">
|
||||
<a *ngIf="!hideReturnButton" [routerLink]="getPageUrl((dsoRD$ | async)?.payload)" class="btn btn-outline-secondary">
|
||||
<i class="fas fa-arrow-left"></i> {{ type + '.edit.return' | translate }}
|
||||
<i class="fas fa-arrow-left" aria-hidden="true"></i> {{ type + '.edit.return' | translate }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,3 +1,3 @@
|
||||
<div *ngIf="logo" class="dso-logo mb-3">
|
||||
<img [src]="logo._links.content.href" class="img-fluid" [attr.alt]="alternateText ? alternateText : null" (error)="errorHandler($event)"/>
|
||||
<img [src]="logo._links.content.href" class="w-100 img-fluid" [attr.alt]="alternateText ? alternateText : null" (error)="errorHandler($event)"/>
|
||||
</div>
|
||||
|
@@ -0,0 +1,4 @@
|
||||
img {
|
||||
max-width: var(--ds-comcol-logo-max-width);
|
||||
max-height: var(--ds-comcol-logo-max-height);
|
||||
}
|
||||
|
@@ -1,18 +1,18 @@
|
||||
<div>
|
||||
<div class="modal-header">{{ headerLabel | translate:{ dsoName: dsoNameService.getName(dso) } }}
|
||||
<div class="modal-header">{{ headerLabel | translate:{ dsoName: name } }}
|
||||
<button type="button" class="close" (click)="close()" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>{{ infoLabel | translate:{ dsoName: dsoNameService.getName(dso) } }}</p>
|
||||
<p>{{ infoLabel | translate:{ dsoName: name } }}</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="cancel btn btn-outline-secondary" (click)="cancelPressed()" aria-label="Cancel">
|
||||
<i class="fas fa-times"></i> {{ cancelLabel | translate:{ dsoName: dsoNameService.getName(dso) } }}
|
||||
<i class="fas fa-times"></i> {{ cancelLabel | translate:{ dsoName: name } }}
|
||||
</button>
|
||||
<button type="button" class="confirm btn btn-{{brandColor}}" (click)="confirmPressed()" aria-label="Confirm" ngbAutofocus>
|
||||
<i *ngIf="confirmIcon" class="{{confirmIcon}}"></i> {{ confirmLabel | translate:{ dsoName: dsoNameService.getName(dso) } }}
|
||||
<i *ngIf="confirmIcon" class="{{confirmIcon}}"></i> {{ confirmLabel | translate:{ dsoName: name } }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,7 +1,5 @@
|
||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||
import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { DSpaceObject } from '../../core/shared/dspace-object.model';
|
||||
import { DSONameService } from '../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
@Component({
|
||||
selector: 'ds-confirmation-modal',
|
||||
@@ -18,7 +16,7 @@ export class ConfirmationModalComponent {
|
||||
*/
|
||||
@Input() brandColor = 'primary';
|
||||
|
||||
@Input() dso: DSpaceObject;
|
||||
@Input() name: string;
|
||||
|
||||
/**
|
||||
* An event fired when the cancel or confirm button is clicked, with respectively false or true
|
||||
@@ -28,7 +26,6 @@ export class ConfirmationModalComponent {
|
||||
|
||||
constructor(
|
||||
protected activeModal: NgbActiveModal,
|
||||
public dsoNameService: DSONameService,
|
||||
) {
|
||||
}
|
||||
|
||||
|
@@ -22,7 +22,7 @@
|
||||
class="dropdown-menu"
|
||||
id="dsSelectDropdownMenu"
|
||||
aria-labelledby="dsSelectMenuButton">
|
||||
<div aria-labelledby="dropdownMenuButton">
|
||||
<div>
|
||||
<ng-content select=".menu"></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -1,25 +1,21 @@
|
||||
<div *ngIf="!canActivate" class="dso-button-menu mb-1"
|
||||
[title]="itemModel.text | translate"
|
||||
[ngbTooltip]="itemModel.text | translate">
|
||||
<a *ngIf="!section.model.disabled" class="d-flex flex-row flex-nowrap"
|
||||
[routerLink]="itemModel.link"
|
||||
href="javascript:void(0);">
|
||||
<button [attr.aria-label]="itemModel.text | translate" [title]="itemModel.text | translate" class="btn btn-dark btn-sm" [disabled]="section.model.disabled">
|
||||
<i class="fas fa-{{section.icon}} fa-fw"></i>
|
||||
</button>
|
||||
<a *ngIf="!section.model.disabled" class="btn btn-dark btn-sm"
|
||||
[routerLink]="itemModel.link">
|
||||
<i class="fas fa-{{section.icon}} fa-fw" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{itemModel.text | translate}}</span>
|
||||
</a>
|
||||
<div *ngIf="section.model.disabled" class="d-flex flex-row flex-nowrap">
|
||||
<button [attr.aria-label]="itemModel.text | translate" [title]="itemModel.text | translate" class="btn btn-dark btn-sm" [disabled]="section.model.disabled">
|
||||
<i class="fas fa-{{section.icon}} fa-fw"></i>
|
||||
<button *ngIf="section.model.disabled" class="btn btn-dark btn-sm" [disabled]="true">
|
||||
<i class="fas fa-{{section.icon}} fa-fw" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{itemModel.text | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div *ngIf="canActivate" class="dso-button-menu mb-1"
|
||||
[title]="itemModel.text | translate"
|
||||
[ngbTooltip]="itemModel.text | translate">
|
||||
<button [attr.aria-label]="itemModel.text | translate" [title]="itemModel.text | translate" class="btn btn-dark btn-sm" [disabled]="section.model.disabled"
|
||||
<button class="btn btn-dark btn-sm" [disabled]="section.model.disabled"
|
||||
(click)="activate($event)">
|
||||
<i class="fas fa-{{section.icon}} fa-fw"></i>
|
||||
<i class="fas fa-{{section.icon}} fa-fw" aria-hidden="true"></i>
|
||||
<span class="sr-only">{{itemModel.text | translate}}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@@ -96,7 +96,7 @@ describe('DsoEditMenuSectionComponent', () => {
|
||||
});
|
||||
describe('when the section model in a disabled link or text', () => {
|
||||
it('should show just the button', () => {
|
||||
const textButton = fixture.debugElement.query(By.css('div div button'));
|
||||
const textButton = fixture.debugElement.query(By.css('div a'));
|
||||
expect(textButton.nativeElement.innerHTML).toContain('fa-' + iconString);
|
||||
});
|
||||
});
|
||||
@@ -144,7 +144,7 @@ describe('DsoEditMenuSectionComponent', () => {
|
||||
|
||||
});
|
||||
|
||||
describe('link model', () => {
|
||||
describe('when the section model in a non disabled link', () => {
|
||||
initAsync(dummySectionLink, menuService);
|
||||
beforeEach(() => {
|
||||
spyOn(menuService, 'getSubSectionsByParentID').and.returnValue(observableOf([]));
|
||||
@@ -154,11 +154,8 @@ describe('DsoEditMenuSectionComponent', () => {
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
describe('when the section model in a non disabled link', () => {
|
||||
it('should show a link element with the button in it', () => {
|
||||
const link = fixture.debugElement.query(By.css('a'));
|
||||
expect(link.nativeElement.innerHTML).toContain('button');
|
||||
});
|
||||
it('should show the link element', () => {
|
||||
expect(fixture.debugElement.query(By.css('a'))).not.toBeNull();
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -2,6 +2,7 @@
|
||||
<input type="search"
|
||||
class="form-control"
|
||||
(click)="$event.stopPropagation();"
|
||||
[attr.aria-label]="'dso-selector.placeholder' | translate: { type: typesString }"
|
||||
placeholder="{{'dso-selector.placeholder' | translate: { type: typesString } }}"
|
||||
[formControl]="input" ngbAutofocus (keyup.enter)="selectSingleResult()">
|
||||
</div>
|
||||
|
@@ -75,6 +75,11 @@ export class DSOSelectorComponent implements OnInit, OnDestroy {
|
||||
*/
|
||||
@Input() sort: SortOptions;
|
||||
|
||||
/**
|
||||
* The id that should be given to the input box, this is required for accessibility reasons
|
||||
*/
|
||||
@Input() searchBoxId: string | null = null;
|
||||
|
||||
// list of allowed selectable dsoTypes
|
||||
typesString: string;
|
||||
|
||||
|
@@ -6,14 +6,14 @@
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<button class="btn btn-outline-primary btn-lg btn-block" (click)="selectObject(undefined)">{{'dso-selector.create.community.top-level' | translate}}</button>
|
||||
<h3 class="position-relative py-1 my-3 font-weight-normal">
|
||||
<div class="h3 position-relative py-1 my-3 font-weight-normal">
|
||||
<hr>
|
||||
<div id="create-community-or-separator" class="text-center position-absolute w-100">
|
||||
<span class="px-4 bg-white">{{'dso-selector.create.community.or-divider' | translate}}</span>
|
||||
</div>
|
||||
</h3>
|
||||
</div>
|
||||
|
||||
<h5 class="px-2">{{'dso-selector.create.community.sub-level' | translate}}</h5>
|
||||
<span class="h5 px-2">{{'dso-selector.create.community.sub-level' | translate}}</span>
|
||||
<ds-dso-selector [currentDSOId]="dsoRD?.payload.uuid" [types]="selectorTypes" [sort]="defaultSort" (onSelect)="selectObject($event)"></ds-dso-selector>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -5,7 +5,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h5 *ngIf="header" class="px-2">{{header | translate}}</h5>
|
||||
<span *ngIf="header" class="h5 px-2">{{header | translate}}</span>
|
||||
<ds-authorized-collection-selector [currentDSOId]="dsoRD?.payload.uuid"
|
||||
[entityType]="entityType"
|
||||
[types]="selectorTypes"
|
||||
|
@@ -5,7 +5,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h5 *ngIf="header" class="px-2">{{header | translate}}</h5>
|
||||
<span *ngIf="header" class="h5 px-2">{{header | translate}}</span>
|
||||
<ds-dso-selector [currentDSOId]="dsoRD?.payload.uuid" [types]="selectorTypes" [sort]="defaultSort" (onSelect)="selectObject($event)"></ds-dso-selector>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -5,7 +5,7 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<h5 *ngIf="header" class="px-2">{{header | translate}}</h5>
|
||||
<span *ngIf="header" class="h5 px-2">{{header | translate}}</span>
|
||||
<ds-dso-selector [currentDSOId]="dsoRD?.payload.uuid" [types]="selectorTypes" (onSelect)="selectObject($event)"></ds-dso-selector>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -20,6 +20,7 @@ import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { getProcessDetailRoute } from '../../../../process-page/process-page-routing.paths';
|
||||
import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service';
|
||||
import { FeatureID } from '../../../../core/data/feature-authorization/feature-id';
|
||||
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
/**
|
||||
* Component to wrap a list of existing dso's inside a modal
|
||||
@@ -38,6 +39,7 @@ export class ExportBatchSelectorComponent extends DSOSelectorModalWrapperCompone
|
||||
protected notificationsService: NotificationsService, protected translationService: TranslateService,
|
||||
protected scriptDataService: ScriptDataService,
|
||||
protected authorizationDataService: AuthorizationDataService,
|
||||
protected dsoNameService: DSONameService,
|
||||
private modalService: NgbModal) {
|
||||
super(activeModal, route);
|
||||
}
|
||||
@@ -49,7 +51,7 @@ export class ExportBatchSelectorComponent extends DSOSelectorModalWrapperCompone
|
||||
navigate(dso: DSpaceObject): Observable<boolean> {
|
||||
if (dso instanceof Collection) {
|
||||
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||
modalRef.componentInstance.dso = dso;
|
||||
modalRef.componentInstance.name = this.dsoNameService.getName(dso);
|
||||
modalRef.componentInstance.headerLabel = 'confirmation-modal.export-batch.header';
|
||||
modalRef.componentInstance.infoLabel = 'confirmation-modal.export-batch.info';
|
||||
modalRef.componentInstance.cancelLabel = 'confirmation-modal.export-batch.cancel';
|
||||
|
@@ -21,6 +21,7 @@ import { RemoteData } from '../../../../core/data/remote-data';
|
||||
import { getProcessDetailRoute } from '../../../../process-page/process-page-routing.paths';
|
||||
import { AuthorizationDataService } from '../../../../core/data/feature-authorization/authorization-data.service';
|
||||
import { FeatureID } from '../../../../core/data/feature-authorization/feature-id';
|
||||
import { DSONameService } from '../../../../core/breadcrumbs/dso-name.service';
|
||||
|
||||
/**
|
||||
* Component to wrap a list of existing dso's inside a modal
|
||||
@@ -39,6 +40,7 @@ export class ExportMetadataSelectorComponent extends DSOSelectorModalWrapperComp
|
||||
protected notificationsService: NotificationsService, protected translationService: TranslateService,
|
||||
protected scriptDataService: ScriptDataService,
|
||||
protected authorizationDataService: AuthorizationDataService,
|
||||
protected dsoNameService: DSONameService,
|
||||
private modalService: NgbModal) {
|
||||
super(activeModal, route);
|
||||
}
|
||||
@@ -50,7 +52,7 @@ export class ExportMetadataSelectorComponent extends DSOSelectorModalWrapperComp
|
||||
navigate(dso: DSpaceObject): Observable<boolean> {
|
||||
if (dso instanceof Collection || dso instanceof Community) {
|
||||
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||
modalRef.componentInstance.dso = dso;
|
||||
modalRef.componentInstance.name = this.dsoNameService.getName(dso);
|
||||
modalRef.componentInstance.headerLabel = 'confirmation-modal.export-metadata.header';
|
||||
modalRef.componentInstance.infoLabel = 'confirmation-modal.export-metadata.info';
|
||||
modalRef.componentInstance.cancelLabel = 'confirmation-modal.export-metadata.cancel';
|
||||
|
@@ -1,6 +1,5 @@
|
||||
<div
|
||||
class="scrollable-menu"
|
||||
aria-labelledby="dropdownMenuButton"
|
||||
<ul class="scrollable-menu list-unstyled mb-0"
|
||||
role="menu"
|
||||
(scroll)="onScroll($event)"
|
||||
infiniteScroll
|
||||
[infiniteScrollDistance]="5"
|
||||
@@ -9,20 +8,23 @@
|
||||
[fromRoot]="true"
|
||||
[scrollWindow]="false"
|
||||
(scrolled)="onScrollDown()">
|
||||
<button class="dropdown-item disabled" *ngIf="searchListEntity?.length == 0 && !(isLoadingList | async)">
|
||||
<li *ngIf="searchListEntity?.length == 0 && !(isLoadingList | async)">
|
||||
<button class="dropdown-item disabled" role="menuitem">
|
||||
{{'submission.sections.general.no-entity' | translate}}
|
||||
</button>
|
||||
<button *ngFor="let listItem of searchListEntity"
|
||||
class="dropdown-item entity-item"
|
||||
</li>
|
||||
<li *ngFor="let listItem of searchListEntity" class="entity-item text-primary">
|
||||
<button class="dropdown-item"
|
||||
role="menuitem"
|
||||
title="{{ listItem.label }}"
|
||||
(click)="onSelect(listItem)">
|
||||
<ul class="list-unstyled mb-0">
|
||||
<li class="list-item text-truncate text-primary font-weight-bold">{{ listItem.label.toLowerCase() + '.listelement.badge' | translate }}</li>
|
||||
</ul>
|
||||
<span class="text-truncate font-weight-bold">{{ listItem.label.toLowerCase() + '.listelement.badge' | translate }}</span>
|
||||
</button>
|
||||
<button class="dropdown-item disabled" *ngIf="(isLoadingList | async)" >
|
||||
</li>
|
||||
<li *ngIf="(isLoadingList | async)">
|
||||
<button class="dropdown-item disabled" role="menuitem">
|
||||
<ds-themed-loading message="{{'loading.default' | translate}}">
|
||||
</ds-themed-loading>
|
||||
</button>
|
||||
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
|
@@ -1,6 +1,10 @@
|
||||
.list-item:active {
|
||||
.dropdown-item {
|
||||
padding: 0.35rem 1rem;
|
||||
|
||||
&:active {
|
||||
color: white !important;
|
||||
}
|
||||
}
|
||||
|
||||
.scrollable-menu {
|
||||
height: auto;
|
||||
@@ -8,7 +12,7 @@
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.entity-item {
|
||||
li:not(:last-of-type) .dropdown-item {
|
||||
border-bottom: var(--bs-dropdown-border-width) solid var(--bs-dropdown-border-color);
|
||||
}
|
||||
|
||||
|
@@ -123,7 +123,7 @@ describe('EntityDropdownComponent', () => {
|
||||
scheduler.flush();
|
||||
|
||||
spyOn(component, 'onSelect');
|
||||
const entityItem = fixture.debugElement.query(By.css('.entity-item:nth-child(2)'));
|
||||
const entityItem = fixture.debugElement.query(By.css('.entity-item:nth-child(2) button'));
|
||||
entityItem.triggerEventHandler('click', null);
|
||||
|
||||
scheduler.schedule(() => fixture.detectChanges());
|
||||
|
@@ -88,7 +88,6 @@
|
||||
aria-expanded="false"
|
||||
[attr.aria-labelledby]="'label_' + model.id">
|
||||
<div class="scrollable-menu"
|
||||
aria-labelledby="scrollableDropdownMenuButton"
|
||||
infiniteScroll
|
||||
[infiniteScrollDistance]="2"
|
||||
[infiniteScrollThrottle]="50"
|
||||
|
@@ -27,7 +27,7 @@
|
||||
(keydown)="selectOnKeyDown($event, sdRef)">
|
||||
</div>
|
||||
|
||||
<div ngbDropdownMenu
|
||||
<div #dropdownMenu ngbDropdownMenu
|
||||
class="dropdown-menu scrollable-dropdown-menu w-100"
|
||||
[attr.aria-label]="model.placeholder">
|
||||
<div class="scrollable-menu"
|
||||
@@ -41,7 +41,8 @@
|
||||
[scrollWindow]="false">
|
||||
|
||||
<button class="dropdown-item disabled" *ngIf="optionsList && optionsList.length == 0">{{'form.no-results' | translate}}</button>
|
||||
<button class="dropdown-item collection-item text-truncate" *ngFor="let listEntry of optionsList"
|
||||
<button class="dropdown-item collection-item text-truncate" *ngFor="let listEntry of optionsList; let i = index"
|
||||
[class.active]="i === selectedIndex"
|
||||
(keydown.enter)="onSelect(listEntry); sdRef.close()" (mousedown)="onSelect(listEntry); sdRef.close()"
|
||||
title="{{ listEntry.display }}" role="option"
|
||||
[attr.id]="listEntry.display == (currentValue|async) ? ('combobox_' + id + '_selected') : null">
|
||||
|
@@ -1,8 +1,17 @@
|
||||
import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
|
||||
import {
|
||||
ChangeDetectorRef,
|
||||
Component,
|
||||
EventEmitter,
|
||||
Input,
|
||||
OnInit,
|
||||
Output,
|
||||
ViewChild,
|
||||
ElementRef
|
||||
} from '@angular/core';
|
||||
import { UntypedFormGroup } from '@angular/forms';
|
||||
|
||||
import { Observable, of as observableOf } from 'rxjs';
|
||||
import { catchError, distinctUntilChanged, map, tap } from 'rxjs/operators';
|
||||
import { catchError, map, tap } from 'rxjs/operators';
|
||||
import { NgbDropdown } from '@ng-bootstrap/ng-bootstrap';
|
||||
import { DynamicFormLayoutService, DynamicFormValidationService } from '@ng-dynamic-forms/core';
|
||||
|
||||
@@ -28,6 +37,8 @@ import { FormFieldMetadataValueObject } from '../../../models/form-field-metadat
|
||||
templateUrl: './dynamic-scrollable-dropdown.component.html'
|
||||
})
|
||||
export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyComponent implements OnInit {
|
||||
@ViewChild('dropdownMenu', { read: ElementRef }) dropdownMenu: ElementRef;
|
||||
|
||||
@Input() bindId = true;
|
||||
@Input() group: UntypedFormGroup;
|
||||
@Input() model: DynamicScrollableDropdownModel;
|
||||
@@ -40,6 +51,9 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
|
||||
public loading = false;
|
||||
public pageInfo: PageInfo;
|
||||
public optionsList: any;
|
||||
public inputText: string = null;
|
||||
public selectedIndex = 0;
|
||||
public acceptableKeys = ['Space', 'NumpadMultiply', 'NumpadAdd', 'NumpadSubtract', 'NumpadDecimal', 'Semicolon', 'Equal', 'Comma', 'Minus', 'Period', 'Quote', 'Backquote'];
|
||||
|
||||
constructor(protected vocabularyService: VocabularyService,
|
||||
protected cdr: ChangeDetectorRef,
|
||||
@@ -54,32 +68,26 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
|
||||
*/
|
||||
ngOnInit() {
|
||||
this.updatePageInfo(this.model.maxOptions, 1);
|
||||
this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.pageInfo).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
catchError(() => observableOf(buildPaginatedList(
|
||||
new PageInfo(),
|
||||
[]
|
||||
))
|
||||
))
|
||||
.subscribe((list: PaginatedList<VocabularyEntry>) => {
|
||||
this.optionsList = list.page;
|
||||
if (this.model.value) {
|
||||
this.setCurrentValue(this.model.value, true);
|
||||
this.loadOptions();
|
||||
}
|
||||
|
||||
loadOptions() {
|
||||
this.loading = true;
|
||||
this.vocabularyService.getVocabularyEntriesByValue(this.inputText, false, this.model.vocabularyOptions, this.pageInfo).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
catchError(() => observableOf(buildPaginatedList(new PageInfo(), []))),
|
||||
tap(() => this.loading = false)
|
||||
).subscribe((list: PaginatedList<VocabularyEntry>) => {
|
||||
this.optionsList = list.page;
|
||||
this.updatePageInfo(
|
||||
list.pageInfo.elementsPerPage,
|
||||
list.pageInfo.currentPage,
|
||||
list.pageInfo.totalElements,
|
||||
list.pageInfo.totalPages
|
||||
);
|
||||
this.selectedIndex = 0;
|
||||
this.cdr.detectChanges();
|
||||
});
|
||||
|
||||
this.group.get(this.model.id).valueChanges.pipe(distinctUntilChanged())
|
||||
.subscribe((value) => {
|
||||
this.setCurrentValue(value);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,10 +102,30 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
|
||||
openDropdown(sdRef: NgbDropdown) {
|
||||
if (!this.model.readOnly) {
|
||||
this.group.markAsUntouched();
|
||||
this.inputText = null;
|
||||
this.updatePageInfo(this.model.maxOptions, 1);
|
||||
this.loadOptions();
|
||||
sdRef.open();
|
||||
}
|
||||
}
|
||||
|
||||
navigateDropdown(event: KeyboardEvent) {
|
||||
if (event.key === 'ArrowDown') {
|
||||
this.selectedIndex = Math.min(this.selectedIndex + 1, this.optionsList.length - 1);
|
||||
} else if (event.key === 'ArrowUp') {
|
||||
this.selectedIndex = Math.max(this.selectedIndex - 1, 0);
|
||||
}
|
||||
this.scrollToSelected();
|
||||
}
|
||||
|
||||
scrollToSelected() {
|
||||
const dropdownItems = this.dropdownMenu.nativeElement.querySelectorAll('.dropdown-item');
|
||||
const selectedItem = dropdownItems[this.selectedIndex];
|
||||
if (selectedItem) {
|
||||
selectedItem.scrollIntoView({ block: 'nearest' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* KeyDown handler to allow toggling the dropdown via keyboard
|
||||
* @param event KeyboardEvent
|
||||
@@ -106,13 +134,54 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
|
||||
selectOnKeyDown(event: KeyboardEvent, sdRef: NgbDropdown) {
|
||||
const keyName = event.key;
|
||||
|
||||
if (keyName === ' ' || keyName === 'Enter') {
|
||||
if (keyName === 'Enter') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
sdRef.toggle();
|
||||
} else if (keyName === 'ArrowDown' || keyName === 'ArrowUp') {
|
||||
this.openDropdown(sdRef);
|
||||
if (sdRef.isOpen()) {
|
||||
this.onSelect(this.optionsList[this.selectedIndex]);
|
||||
sdRef.close();
|
||||
} else {
|
||||
sdRef.open();
|
||||
}
|
||||
} else if (keyName === 'ArrowDown' || keyName === 'ArrowUp') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
this.navigateDropdown(event);
|
||||
} else if (keyName === 'Backspace') {
|
||||
this.removeKeyFromInput();
|
||||
} else if (this.isAcceptableKey(keyName)) {
|
||||
this.addKeyToInput(keyName);
|
||||
}
|
||||
}
|
||||
|
||||
addKeyToInput(keyName: string) {
|
||||
if (this.inputText === null) {
|
||||
this.inputText = '';
|
||||
}
|
||||
this.inputText += keyName;
|
||||
// When a new key is added, we need to reset the page info
|
||||
this.updatePageInfo(this.model.maxOptions, 1);
|
||||
this.loadOptions();
|
||||
}
|
||||
|
||||
removeKeyFromInput() {
|
||||
if (this.inputText !== null) {
|
||||
this.inputText = this.inputText.slice(0, -1);
|
||||
if (this.inputText === '') {
|
||||
this.inputText = null;
|
||||
}
|
||||
this.loadOptions();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
isAcceptableKey(keyPress: string): boolean {
|
||||
// allow all letters and numbers
|
||||
if (keyPress.length === 1 && keyPress.match(/^[a-zA-Z0-9]*$/)) {
|
||||
return true;
|
||||
}
|
||||
// Some other characters like space, dash, etc should be allowed as well
|
||||
return this.acceptableKeys.includes(keyPress);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,7 +196,7 @@ export class DsDynamicScrollableDropdownComponent extends DsDynamicVocabularyCom
|
||||
this.pageInfo.totalElements,
|
||||
this.pageInfo.totalPages
|
||||
);
|
||||
this.vocabularyService.getVocabularyEntries(this.model.vocabularyOptions, this.pageInfo).pipe(
|
||||
this.vocabularyService.getVocabularyEntriesByValue(this.inputText, false, this.model.vocabularyOptions, this.pageInfo).pipe(
|
||||
getFirstSucceededRemoteDataPayload(),
|
||||
catchError(() => observableOf(buildPaginatedList(
|
||||
new PageInfo(),
|
||||
|
@@ -58,11 +58,12 @@
|
||||
<div class="col text-right space-children-mr">
|
||||
<ng-content select="[before]"></ng-content>
|
||||
<button *ngIf="displayCancel" type="reset" class="btn btn-outline-secondary" (click)="reset()">
|
||||
<i class="fa fa-times"></i> {{cancelLabel | translate}}
|
||||
<i class="fa fa-times" aria-hidden="true"></i> {{cancelLabel | translate}}
|
||||
</button>
|
||||
<ng-content select="[between]"></ng-content>
|
||||
<button *ngIf="displaySubmit" type="submit" class="btn btn-primary" (click)="onSubmit()"
|
||||
[disabled]="!(isValid() | async)"><i class="fas fa-save"></i> {{submitLabel | translate}}
|
||||
[disabled]="!(isValid() | async)">
|
||||
<i class="fas fa-save" aria-hidden="true"></i> {{submitLabel | translate}}
|
||||
</button>
|
||||
<ng-content select="[after]"></ng-content>
|
||||
</div>
|
||||
|
@@ -9,7 +9,9 @@
|
||||
[dsDebounce]="debounceTime" (onDebounce)="find($event)"
|
||||
[placeholder]="placeholder"
|
||||
[ngModelOptions]="{standalone: true}" autocomplete="off"/>
|
||||
<input type="submit" class="d-none"/>
|
||||
<button class="sr-only" type="submit">
|
||||
{{'search.filters.search.submit' | translate}}
|
||||
</button>
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (show | async) && isNotEmpty(suggestions)}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let suggestionOption of suggestions">
|
||||
|
@@ -20,10 +20,9 @@
|
||||
[ngModelOptions]="{standalone: true}" autocomplete="off"
|
||||
/>
|
||||
</ng-template>
|
||||
<label class="d-none">
|
||||
<input type="submit"/>
|
||||
<span>{{'search.filters.search.submit' | translate}}</span>
|
||||
</label>
|
||||
<button class="sr-only" type="submit">
|
||||
{{'search.filters.search.submit' | translate}}
|
||||
</button>
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (show | async) && isNotEmpty(suggestions)}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let suggestionOption of suggestions">
|
||||
|
@@ -9,7 +9,9 @@
|
||||
[dsDebounce]="debounceTime" (onDebounce)="find($event)"
|
||||
[placeholder]="placeholder"
|
||||
[ngModelOptions]="{standalone: true}" autocomplete="off"/>
|
||||
<input type="submit" class="d-none"/>
|
||||
<button class="sr-only" type="submit">
|
||||
{{'search.filters.search.submit' | translate}}
|
||||
</button>
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (show | async) && isNotEmpty(suggestions)}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let suggestionOption of suggestions">
|
||||
|
@@ -10,7 +10,9 @@
|
||||
[placeholder]="placeholder"
|
||||
ng-model-options="{standalone: true}"
|
||||
autocomplete="off">
|
||||
<input type="submit" class="d-none"/>
|
||||
<button class="sr-only" type="submit">
|
||||
{{'search.filters.search.submit' | translate}}
|
||||
</button>
|
||||
<div class="autocomplete dropdown-menu" [ngClass]="{'show': (show | async) && isNotEmpty(suggestions)}">
|
||||
<div class="dropdown-list">
|
||||
<div *ngFor="let suggestionOption of suggestions">
|
||||
|
@@ -1,9 +1,8 @@
|
||||
<form class="form-login"
|
||||
(ngSubmit)="submit()"
|
||||
[formGroup]="form" novalidate>
|
||||
<label class="sr-only">{{"login.form.email" | translate}}</label>
|
||||
<input [attr.aria-label]="'login.form.email' |translate"
|
||||
autocomplete="off"
|
||||
autocomplete="username"
|
||||
autofocus
|
||||
class="form-control form-control-lg position-relative"
|
||||
formControlName="email"
|
||||
@@ -11,9 +10,8 @@
|
||||
required
|
||||
type="email"
|
||||
[attr.data-test]="'email' | dsBrowserOnly">
|
||||
<label class="sr-only">{{"login.form.password" | translate}}</label>
|
||||
<input [attr.aria-label]="'login.form.password' |translate"
|
||||
autocomplete="off"
|
||||
autocomplete="current-password"
|
||||
class="form-control form-control-lg position-relative mb-3"
|
||||
placeholder="{{'login.form.password' | translate}}"
|
||||
formControlName="password"
|
||||
|
@@ -11,7 +11,7 @@
|
||||
<table id="collection-select" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th aria-hidden="true"></th>
|
||||
<th><span class="sr-only">{{'collection.select.table.selected' | translate}}</span></th>
|
||||
<th scope="col">{{'collection.select.table.title' | translate}}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
@@ -11,7 +11,7 @@
|
||||
<table id="item-select" class="table table-striped table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th aria-hidden="true"></th>
|
||||
<th><span class="sr-only">{{'item.select.table.selected' | translate}}</span></th>
|
||||
<th *ngIf="!hideCollection" scope="col">{{'item.select.table.collection' | translate}}</th>
|
||||
<th scope="col">{{'item.select.table.author' | translate}}</th>
|
||||
<th scope="col">{{'item.select.table.title' | translate}}</th>
|
||||
|
@@ -7,15 +7,29 @@
|
||||
</div>
|
||||
<div class="col">
|
||||
<div *ngIf="!hideGear" ngbDropdown #paginationControls="ngbDropdown" placement="bottom-right" class="d-inline-block float-right">
|
||||
<button class="btn btn-secondary" id="paginationControls" ngbDropdownToggle [title]="'pagination.options.description' | translate" [attr.aria-label]="'pagination.options.description' | translate"><i class="fas fa-cog" aria-hidden="true"></i></button>
|
||||
<div id="paginationControlsDropdownMenu" aria-labelledby="paginationControls" ngbDropdownMenu>
|
||||
<h6 class="dropdown-header">{{ 'pagination.results-per-page' | translate}}</h6>
|
||||
<button class="dropdown-item" *ngFor="let item of pageSizeOptions" (click)="doPageSizeChange(item)"><i [ngClass]="{'invisible': item != (pageSize$|async)}" class="fas fa-check" aria-hidden="true"></i> {{item}} </button>
|
||||
<ng-container *ngIf="!hideSortOptions">
|
||||
<h6 class="dropdown-header">{{ 'pagination.sort-direction' | translate}}</h6>
|
||||
<button class="dropdown-item" *ngFor="let direction of (sortDirections | dsKeys)" (click)="doSortDirectionChange(direction.value)"><i [ngClass]="{'invisible': direction.value !== (sortDirection$ |async)}" class="fas fa-check" aria-hidden="true"></i> {{'sorting.' + direction.key | translate}} </button>
|
||||
</ng-container>
|
||||
</div>
|
||||
<button class="btn btn-secondary" id="paginationControls" ngbDropdownToggle [title]="'pagination.options.description' | translate" [attr.aria-label]="'pagination.options.description' | translate" aria-haspopup="true" aria-expanded="false"><i class="fas fa-cog" aria-hidden="true"></i></button>
|
||||
<ul id="paginationControlsDropdownMenu" aria-labelledby="paginationControls" role="menu" ngbDropdownMenu>
|
||||
<li role="menuitem">
|
||||
<span class="dropdown-header" id="pagination-control_results-per-page" role="heading">{{ 'pagination.results-per-page' | translate}}</span>
|
||||
<ul aria-labelledby="pagination-control_results-per-page" class="list-unstyled" role="listbox">
|
||||
<li *ngFor="let item of pageSizeOptions" role="option" [attr.aria-selected]="item === (pageSize$ | async)">
|
||||
<button (click)="doPageSizeChange(item)" class="dropdown-item">
|
||||
<i [ngClass]="{'invisible': item !== (pageSize$ | async) }" class="fas fa-check" aria-hidden="true"></i> {{item}}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li *ngIf="!hideSortOptions" role="menuitem">
|
||||
<span class="dropdown-header" id="pagination-control_sort-direction" role="heading">{{ 'pagination.sort-direction' | translate}}</span>
|
||||
<ul aria-labelledby="pagination-control_sort-direction" class="list-unstyled" role="listbox">
|
||||
<li *ngFor="let direction of (sortDirections | dsKeys)" [attr.aria-selected]="direction.value === (sortDirection$ | async)" role="option">
|
||||
<button class="dropdown-item" (click)="doSortDirectionChange(direction.value)">
|
||||
<i [ngClass]="{'invisible': direction.value !== (sortDirection$ |async)}" class="fas fa-check" aria-hidden="true"></i> {{'sorting.' + direction.key | translate}}
|
||||
</button>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<ds-rss></ds-rss>
|
||||
</div>
|
||||
|
@@ -167,7 +167,7 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
||||
/**
|
||||
* Number of items per page.
|
||||
*/
|
||||
public pageSize$;
|
||||
public pageSize$: Observable<number>;
|
||||
|
||||
/**
|
||||
* Declare SortDirection enumeration to use it in the template
|
||||
@@ -188,7 +188,7 @@ export class PaginationComponent implements OnDestroy, OnInit {
|
||||
/**
|
||||
* Name of the field that's used to sort by
|
||||
*/
|
||||
public sortField$;
|
||||
public sortField$: Observable<string>;
|
||||
public defaultSortField = 'name';
|
||||
|
||||
/**
|
||||
|
@@ -5,8 +5,8 @@
|
||||
[id]="entry.id"
|
||||
[ngModel]="entry.checked"
|
||||
(ngModelChange)="this.toggleCheckbox.emit($event);">
|
||||
<label class="custom-control-label" [for]="entry.id"
|
||||
[attr.aria-label]="(entry.checked ? 'resource-policies.table.headers.deselect' : 'resource-policies.table.headers.select') | translate">
|
||||
<label class="custom-control-label" [for]="entry.id">
|
||||
<span class="sr-only">{{(entry.checked ? 'resource-policies.table.headers.deselect' : 'resource-policies.table.headers.select') | translate}}</span>
|
||||
</label>
|
||||
</div>
|
||||
</td>
|
||||
@@ -30,12 +30,12 @@
|
||||
<button class="btn btn-outline-primary btn-sm"
|
||||
[title]="'resource-policies.table.headers.edit.policy' | translate"
|
||||
(click)="redirectToResourcePolicyEditPage()">
|
||||
<i class="fas fa-edit fa-fw"></i>
|
||||
<i class="fas fa-edit fa-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
<button *ngIf="(groupName$ | async) !== undefined" class="btn btn-outline-primary btn-sm"
|
||||
[title]="'resource-policies.table.headers.edit.group' | translate"
|
||||
(click)="redirectToGroupEditPage()">
|
||||
<i class="fas fa-users fa-fw"></i>
|
||||
<i class="fas fa-users fa-fw" aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
|
@@ -17,10 +17,10 @@
|
||||
[title]="'resource-policies.delete.btn.title' | translate"
|
||||
(click)="deleteSelectedResourcePolicies()">
|
||||
<span *ngIf="(isProcessingDelete() | async)">
|
||||
<i class='fas fa-circle-notch fa-spin'></i> {{'submission.workflow.tasks.generic.processing' | translate}}
|
||||
<i class='fas fa-circle-notch fa-spin' aria-hidden="true"></i> {{'submission.workflow.tasks.generic.processing' | translate}}
|
||||
</span>
|
||||
<span *ngIf="!(isProcessingDelete() | async)">
|
||||
<i class='fas fa-trash-alt fa-fw'></i>
|
||||
<i class='fas fa-trash-alt fa-fw' aria-hidden="true"></i>
|
||||
{{'resource-policies.delete.btn' | translate}}
|
||||
</span>
|
||||
</button>
|
||||
@@ -28,7 +28,7 @@
|
||||
[disabled]="(isProcessingDelete() | async)"
|
||||
[title]="'resource-policies.add.for.' + resourceType | translate"
|
||||
(click)="redirectToResourcePolicyCreatePage()">
|
||||
<i class='fas fa-plus'></i>
|
||||
<i class='fas fa-plus' aria-hidden="true"></i>
|
||||
{{'resource-policies.add.button' | translate}}
|
||||
</button>
|
||||
</div>
|
||||
@@ -42,8 +42,8 @@
|
||||
class="custom-control-input"
|
||||
[id]="'selectAll_' + resourceUUID"
|
||||
(change)="selectAllCheckbox($event)">
|
||||
<label class="custom-control-label" [for]="'selectAll_' + resourceUUID"
|
||||
[attr.aria-label]="(selectAllBtn.checked ? 'resource-policies.table.headers.deselect-all' : 'resource-policies.table.headers.select-all') | translate">
|
||||
<label class="custom-control-label" [for]="'selectAll_' + resourceUUID">
|
||||
<span class="sr-only">{{(selectAllBtn.checked ? 'resource-policies.table.headers.deselect-all' : 'resource-policies.table.headers.select-all') | translate}}</span>
|
||||
</label>
|
||||
</div>
|
||||
</th>
|
||||
|
@@ -26,10 +26,9 @@
|
||||
/>
|
||||
</label>
|
||||
</div>
|
||||
<label class="d-none">
|
||||
<input type="submit" class="d-none"/>
|
||||
<span>{{'search.filters.search.submit' | translate}}</span>
|
||||
</label>
|
||||
<button class="sr-only" type="submit">
|
||||
{{'search.filters.search.submit' | translate}}
|
||||
</button>
|
||||
</form>
|
||||
|
||||
<ng-container *ngIf="shouldShowSlider()">
|
||||
|
@@ -82,7 +82,7 @@ export class SubscriptionViewComponent {
|
||||
deleteSubscriptionPopup(subscription: Subscription) {
|
||||
if (hasValue(subscription.id)) {
|
||||
const modalRef = this.modalService.open(ConfirmationModalComponent);
|
||||
modalRef.componentInstance.dso = this.dso;
|
||||
modalRef.componentInstance.name = this.dsoNameService.getName(this.dso);
|
||||
modalRef.componentInstance.headerLabel = 'confirmation-modal.delete-subscription.header';
|
||||
modalRef.componentInstance.infoLabel = 'confirmation-modal.delete-subscription.info';
|
||||
modalRef.componentInstance.cancelLabel = 'confirmation-modal.delete-subscription.cancel';
|
||||
|
@@ -23,7 +23,7 @@
|
||||
<i class="fas fa-upload" aria-hidden="true"></i>
|
||||
{{dropMsg | translate}}{{'uploader.or' | translate}}
|
||||
<label for="inputFileUploader-{{uploaderId}}" class="btn btn-link m-0 p-0 ml-1" tabindex="0" (keyup.enter)="$event.stopImmediatePropagation(); fileInput.click()">
|
||||
<span role="button" [attr.aria-label]="'uploader.browse' | translate">{{'uploader.browse' | translate}}</span>
|
||||
<span role="button" [attr.aria-label]="ariaLabel | translate">{{'uploader.browse' | translate}}</span>
|
||||
</label>
|
||||
<input #fileInput id="inputFileUploader-{{uploaderId}}" class="d-none" type="file" ng2FileSelect [uploader]="uploader" multiple tabindex="0" />
|
||||
</span>
|
||||
|
@@ -53,6 +53,11 @@ export class UploaderComponent {
|
||||
*/
|
||||
@Input() uploadProperties: UploaderProperties;
|
||||
|
||||
/**
|
||||
* The aria label to describe what kind of files need to be uploaded
|
||||
*/
|
||||
@Input() ariaLabel: string;
|
||||
|
||||
/**
|
||||
* The function to call when upload is completed
|
||||
*/
|
||||
|
@@ -32,7 +32,7 @@
|
||||
</button>
|
||||
|
||||
<div ngbDropdownMenu
|
||||
class="dropdown-menu"
|
||||
class="dropdown-menu p-0"
|
||||
id="collectionControlsDropdownMenu"
|
||||
aria-labelledby="collectionControlsMenuButton">
|
||||
<ds-themed-collection-dropdown
|
||||
|
@@ -1,25 +1,28 @@
|
||||
<div *ngIf="(isXsOrSm$ | async)" class="input-group mb-2">
|
||||
<input type="text" class="form-control" (keyup.enter)="(searchString === '')?null:search()" [(ngModel)]="searchString" placeholder="{{'submission.import-external.search.placeholder' |translate}}" aria-label="" aria-describedby="">
|
||||
<input type="text" class="form-control" (keyup.enter)="(searchString === '')?null:search()" [(ngModel)]="searchString" placeholder="{{'submission.import-external.search.placeholder' | translate}}" [attr.aria-label]="'submission.import-external.search.placeholder' | translate">
|
||||
</div>
|
||||
<div class="input-group mb-5">
|
||||
<input *ngIf="!(isXsOrSm$ | async)" type="text" class="form-control" (keyup.enter)="(searchString === '')?null:search()" [(ngModel)]="searchString" placeholder="{{'submission.import-external.search.placeholder' |translate}}" aria-label="" aria-describedby="">
|
||||
<div [ngClass]="{'input-group-append': !(isXsOrSm$ | async)}" ngbDropdown role="group" aria-label="">
|
||||
<button class="btn btn-outline-secondary w-fx" title="{{'submission.import-external.search.source.hint' |translate}}" ngbDropdownToggle>{{'submission.import-external.source.' + selectedElement?.name | translate}}</button>
|
||||
<div ngbDropdownMenu class="dropdown-menu scrollable-dropdown-menu w-100"
|
||||
<input *ngIf="!(isXsOrSm$ | async)" type="text" class="form-control" (keyup.enter)="(searchString === '')?null:search()" [(ngModel)]="searchString" placeholder="{{'submission.import-external.search.placeholder' | translate}}" [attr.aria-label]="'submission.import-external.search.placeholder' | translate">
|
||||
<div [ngClass]="{'input-group-append': !(isXsOrSm$ | async)}" ngbDropdown role="group">
|
||||
<button [attr.aria-label]="'submission.import-external.search.source.hint' |translate"
|
||||
class="btn btn-outline-secondary w-fx"
|
||||
title="{{'submission.import-external.search.source.hint' |translate}}"
|
||||
ngbDropdownToggle>
|
||||
{{'submission.import-external.source.' + selectedElement?.name | translate}}
|
||||
</button>
|
||||
<ul ngbDropdownMenu class="dropdown-menu scrollable-dropdown-menu w-100"
|
||||
aria-haspopup="true"
|
||||
aria-expanded="false"
|
||||
aria-labelledby="scrollableDropdownMenuButton">
|
||||
<div class="scrollable-menu"
|
||||
aria-labelledby="scrollableDropdownMenuButton"
|
||||
aria-expanded="false">
|
||||
<li class="scrollable-menu"
|
||||
infiniteScroll
|
||||
[infiniteScrollDistance]="2"
|
||||
[infiniteScrollThrottle]="50"
|
||||
(scrolled)="onScroll()"
|
||||
[scrollWindow]="false">
|
||||
<button ngbDropdownItem class="dropdown-item text-truncate" title="{{'submission.import-external.source.' + source?.name | translate}}" (click)="makeSourceSelection(source)" *ngFor="let source of sourceList">{{'submission.import-external.source.' + source?.name | translate}}</button>
|
||||
<button ngbDropdownItem class="dropdown-item text-truncate" (click)="makeSourceSelection(source)" *ngFor="let source of sourceList">{{'submission.import-external.source.' + source?.name | translate}}</button>
|
||||
<div ngbDropdownItem class="scrollable-dropdown-loading text-center" *ngIf="sourceListLoading"><p>{{'submission.import-external.source.loading' | translate}}</p></div>
|
||||
</div>
|
||||
</div>
|
||||
<button type="button" class="btn btn-primary" [title]="(searchString === '')?('submission.import-external.search.button.hint' | translate):('submission.import-external.search.button' | translate)" [disabled]="searchString === ''" (click)="search()">{{'submission.import-external.search.button' | translate}}</button>
|
||||
</li>
|
||||
</ul>
|
||||
<button type="button" class="btn btn-primary" [title]="(searchString === '')?('submission.import-external.search.button.hint' | translate):''" [disabled]="searchString === ''" (click)="search()">{{'submission.import-external.search.button' | translate}}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -128,6 +128,8 @@
|
||||
|
||||
"admin.registries.bitstream-formats.table.name": "Name",
|
||||
|
||||
"admin.registries.bitstream-formats.table.selected": "Selected bitstream formats",
|
||||
|
||||
"admin.registries.bitstream-formats.table.id": "ID",
|
||||
|
||||
"admin.registries.bitstream-formats.table.return": "Back",
|
||||
@@ -142,7 +144,9 @@
|
||||
|
||||
"admin.registries.bitstream-formats.title": "Bitstream Format Registry",
|
||||
|
||||
"admin.registries.bitstream-formats.select": "Select bitstream format",
|
||||
"admin.registries.bitstream-formats.select": "Select",
|
||||
|
||||
"admin.registries.bitstream-formats.deselect": "Deselect",
|
||||
|
||||
"admin.registries.metadata.breadcrumbs": "Metadata registry",
|
||||
|
||||
@@ -160,8 +164,14 @@
|
||||
|
||||
"admin.registries.metadata.schemas.no-items": "No metadata schemas to show.",
|
||||
|
||||
"admin.registries.metadata.schemas.select": "Select",
|
||||
|
||||
"admin.registries.metadata.schemas.deselect": "Deselect",
|
||||
|
||||
"admin.registries.metadata.schemas.table.delete": "Delete selected",
|
||||
|
||||
"admin.registries.metadata.schemas.table.selected": "Selected schemas",
|
||||
|
||||
"admin.registries.metadata.schemas.table.id": "ID",
|
||||
|
||||
"admin.registries.metadata.schemas.table.name": "Name",
|
||||
@@ -174,6 +184,10 @@
|
||||
|
||||
"admin.registries.schema.description": "This is the metadata schema for \"{{namespace}}\".",
|
||||
|
||||
"admin.registries.schema.fields.select": "Select",
|
||||
|
||||
"admin.registries.schema.fields.deselect": "Deselect",
|
||||
|
||||
"admin.registries.schema.fields.head": "Schema metadata fields",
|
||||
|
||||
"admin.registries.schema.fields.no-items": "No metadata fields to show.",
|
||||
@@ -182,6 +196,8 @@
|
||||
|
||||
"admin.registries.schema.fields.table.field": "Field",
|
||||
|
||||
"admin.registries.schema.fields.table.selected": "Selected metadata fields",
|
||||
|
||||
"admin.registries.schema.fields.table.id": "ID",
|
||||
|
||||
"admin.registries.schema.fields.table.scopenote": "Scope Note",
|
||||
@@ -892,6 +908,8 @@
|
||||
|
||||
"claimed-declined-task-search-result-list-element.title": "Declined, sent back to Review Manager's workflow",
|
||||
|
||||
"collection.browse.logo": "Browse for a collection logo",
|
||||
|
||||
"collection.create.head": "Create a Collection",
|
||||
|
||||
"collection.create.notifications.success": "Successfully created the Collection",
|
||||
@@ -1088,6 +1106,8 @@
|
||||
|
||||
"collection.listelement.badge": "Collection",
|
||||
|
||||
"collection.logo": "Collection logo",
|
||||
|
||||
"collection.page.browse.recent.head": "Recent Submissions",
|
||||
|
||||
"collection.page.browse.recent.empty": "No items to show",
|
||||
@@ -1104,6 +1124,8 @@
|
||||
|
||||
"collection.select.empty": "No collections to show",
|
||||
|
||||
"collection.select.table.selected": "Selected collections",
|
||||
|
||||
"collection.select.table.select": "Select collection",
|
||||
|
||||
"collection.select.table.deselect": "Deselect collection",
|
||||
@@ -1168,6 +1190,12 @@
|
||||
|
||||
"communityList.showMore": "Show More",
|
||||
|
||||
"communityList.expand": "Expand {{ name }}",
|
||||
|
||||
"communityList.collapse": "Collapse {{ name }}",
|
||||
|
||||
"community.browse.logo": "Browse for a community logo",
|
||||
|
||||
"community.create.head": "Create a Community",
|
||||
|
||||
"community.create.notifications.success": "Successfully created the Community",
|
||||
@@ -1244,6 +1272,8 @@
|
||||
|
||||
"community.listelement.badge": "Community",
|
||||
|
||||
"community.logo": "Community logo",
|
||||
|
||||
"comcol-role.edit.no-group": "None",
|
||||
|
||||
"comcol-role.edit.create": "Create",
|
||||
@@ -1690,7 +1720,7 @@
|
||||
|
||||
"forgot-password.form.label.passwordrepeat": "Retype to confirm",
|
||||
|
||||
"forgot-password.form.error.empty-password": "Please enter a password in the box below.",
|
||||
"forgot-password.form.error.empty-password": "Please enter a password in the boxes above.",
|
||||
|
||||
"forgot-password.form.error.matching-passwords": "The passwords do not match.",
|
||||
|
||||
@@ -1914,7 +1944,7 @@
|
||||
|
||||
"info.feedback.page-label": "Page",
|
||||
|
||||
"info.feedback.page_help": "Tha page related to your feedback",
|
||||
"info.feedback.page_help": "The page related to your feedback",
|
||||
|
||||
"item.alerts.private": "This item is non-discoverable",
|
||||
|
||||
@@ -2142,6 +2172,8 @@
|
||||
|
||||
"item.edit.metadata.headers.value": "Value",
|
||||
|
||||
"item.edit.metadata.metadatafield": "Edit field",
|
||||
|
||||
"item.edit.metadata.metadatafield.error": "An error occurred validating the metadata field",
|
||||
|
||||
"item.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field",
|
||||
@@ -2534,6 +2566,8 @@
|
||||
|
||||
"item.select.empty": "No items to show",
|
||||
|
||||
"item.select.table.selected": "Selected items",
|
||||
|
||||
"item.select.table.select": "Select item",
|
||||
|
||||
"item.select.table.deselect": "Deselect item",
|
||||
@@ -2664,6 +2698,8 @@
|
||||
|
||||
"itemtemplate.edit.metadata.headers.value": "Value",
|
||||
|
||||
"itemtemplate.edit.metadata.metadatafield": "Edit field",
|
||||
|
||||
"itemtemplate.edit.metadata.metadatafield.error": "An error occurred validating the metadata field",
|
||||
|
||||
"itemtemplate.edit.metadata.metadatafield.invalid": "Please choose a valid metadata field",
|
||||
@@ -3458,8 +3494,6 @@
|
||||
|
||||
"profile.special.groups.head": "Authorization special groups you belong to",
|
||||
|
||||
"profile.head": "Update Profile",
|
||||
|
||||
"profile.metadata.form.error.firstname.required": "First Name is required",
|
||||
|
||||
"profile.metadata.form.error.lastname.required": "Last Name is required",
|
||||
@@ -4570,6 +4604,8 @@
|
||||
|
||||
"submission.sections.general.no-collection": "No collection found",
|
||||
|
||||
"submission.sections.general.no-entity": "No entity types found",
|
||||
|
||||
"submission.sections.general.no-sections": "No options available",
|
||||
|
||||
"submission.sections.general.save_error_notice": "There was an issue when saving the item, please try again later.",
|
||||
|
@@ -106,4 +106,7 @@
|
||||
--ds-dso-edit-lang-width: 90px;
|
||||
--ds-dso-edit-actions-width: 173px;
|
||||
--ds-dso-edit-virtual-tooltip-min-width: 300px;
|
||||
|
||||
--ds-comcol-logo-max-width: 500px;
|
||||
--ds-comcol-logo-max-height: 500px;
|
||||
}
|
||||
|
Reference in New Issue
Block a user