mirror of
https://github.com/DSpace/dspace-angular.git
synced 2025-10-07 01:54:15 +00:00
Merge pull request #703 from atmire/CC-License-Submission-Step
Cc license submission step
This commit is contained in:
@@ -462,7 +462,7 @@ describe('CommunityListService', () => {
|
|||||||
});
|
});
|
||||||
let flatNodeList;
|
let flatNodeList;
|
||||||
describe('should return list containing only flatnode corresponding to that community', () => {
|
describe('should return list containing only flatnode corresponding to that community', () => {
|
||||||
beforeAll((done) => {
|
beforeEach((done) => {
|
||||||
service.transformCommunity(communityWithSubcoms, 0, null, null)
|
service.transformCommunity(communityWithSubcoms, 0, null, null)
|
||||||
.pipe(take(1))
|
.pipe(take(1))
|
||||||
.subscribe((value) => {
|
.subscribe((value) => {
|
||||||
|
@@ -148,6 +148,10 @@ import { Registration } from './shared/registration.model';
|
|||||||
import { MetadataSchemaDataService } from './data/metadata-schema-data.service';
|
import { MetadataSchemaDataService } from './data/metadata-schema-data.service';
|
||||||
import { MetadataFieldDataService } from './data/metadata-field-data.service';
|
import { MetadataFieldDataService } from './data/metadata-field-data.service';
|
||||||
import { TokenResponseParsingService } from './auth/token-response-parsing.service';
|
import { TokenResponseParsingService } from './auth/token-response-parsing.service';
|
||||||
|
import { SubmissionCcLicenseDataService } from './submission/submission-cc-license-data.service';
|
||||||
|
import { SubmissionCcLicence } from './submission/models/submission-cc-license.model';
|
||||||
|
import { SubmissionCcLicenceUrl } from './submission/models/submission-cc-license-url.model';
|
||||||
|
import { SubmissionCcLicenseUrlDataService } from './submission/submission-cc-license-url-data.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When not in production, endpoint responses can be mocked for testing purposes
|
* When not in production, endpoint responses can be mocked for testing purposes
|
||||||
@@ -214,6 +218,8 @@ const PROVIDERS = [
|
|||||||
BrowseItemsResponseParsingService,
|
BrowseItemsResponseParsingService,
|
||||||
BrowseService,
|
BrowseService,
|
||||||
ConfigResponseParsingService,
|
ConfigResponseParsingService,
|
||||||
|
SubmissionCcLicenseDataService,
|
||||||
|
SubmissionCcLicenseUrlDataService,
|
||||||
SubmissionDefinitionsConfigService,
|
SubmissionDefinitionsConfigService,
|
||||||
SubmissionFormsConfigService,
|
SubmissionFormsConfigService,
|
||||||
SubmissionRestService,
|
SubmissionRestService,
|
||||||
@@ -300,6 +306,8 @@ export const models =
|
|||||||
License,
|
License,
|
||||||
WorkflowItem,
|
WorkflowItem,
|
||||||
WorkspaceItem,
|
WorkspaceItem,
|
||||||
|
SubmissionCcLicence,
|
||||||
|
SubmissionCcLicenceUrl,
|
||||||
SubmissionDefinitionsModel,
|
SubmissionDefinitionsModel,
|
||||||
SubmissionFormsModel,
|
SubmissionFormsModel,
|
||||||
SubmissionSectionModel,
|
SubmissionSectionModel,
|
||||||
|
@@ -1,4 +1,5 @@
|
|||||||
import { HALLink } from './hal-link.model';
|
import { HALLink } from './hal-link.model';
|
||||||
|
import { deserialize } from 'cerialize';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents HAL resources.
|
* Represents HAL resources.
|
||||||
@@ -6,10 +7,13 @@ import { HALLink } from './hal-link.model';
|
|||||||
* A HAL resource has a _links section with at least a self link.
|
* A HAL resource has a _links section with at least a self link.
|
||||||
*/
|
*/
|
||||||
export class HALResource {
|
export class HALResource {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HALLink}s for this {@link HALResource}
|
* The {@link HALLink}s for this {@link HALResource}
|
||||||
*/
|
*/
|
||||||
|
@deserialize
|
||||||
_links: {
|
_links: {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The {@link HALLink} that refers to this {@link HALResource}
|
* The {@link HALLink} that refers to this {@link HALResource}
|
||||||
*/
|
*/
|
||||||
|
@@ -0,0 +1,9 @@
|
|||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource type for License
|
||||||
|
*
|
||||||
|
* Needs to be in a separate file to prevent circular
|
||||||
|
* dependencies in webpack.
|
||||||
|
*/
|
||||||
|
export const SUBMISSION_CC_LICENSE_URL = new ResourceType('submissioncclicenseUrl');
|
@@ -0,0 +1,9 @@
|
|||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The resource type for License
|
||||||
|
*
|
||||||
|
* Needs to be in a separate file to prevent circular
|
||||||
|
* dependencies in webpack.
|
||||||
|
*/
|
||||||
|
export const SUBMISSION_CC_LICENSE = new ResourceType('submissioncclicense');
|
@@ -0,0 +1,23 @@
|
|||||||
|
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||||
|
import { typedObject } from '../../cache/builders/build-decorators';
|
||||||
|
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
import { HALResource } from '../../shared/hal-resource.model';
|
||||||
|
import { SUBMISSION_CC_LICENSE_URL } from './submission-cc-licence-link.resource-type';
|
||||||
|
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(HALResource)
|
||||||
|
export class SubmissionCcLicenceUrl extends HALResource {
|
||||||
|
|
||||||
|
static type = SUBMISSION_CC_LICENSE_URL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object type
|
||||||
|
*/
|
||||||
|
@excludeFromEquals
|
||||||
|
@autoserialize
|
||||||
|
type: ResourceType;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
url: string;
|
||||||
|
}
|
@@ -0,0 +1,42 @@
|
|||||||
|
import { autoserialize, inheritSerialization } from 'cerialize';
|
||||||
|
import { typedObject } from '../../cache/builders/build-decorators';
|
||||||
|
import { excludeFromEquals } from '../../utilities/equals.decorators';
|
||||||
|
import { ResourceType } from '../../shared/resource-type';
|
||||||
|
import { HALResource } from '../../shared/hal-resource.model';
|
||||||
|
import { SUBMISSION_CC_LICENSE } from './submission-cc-licence.resource-type';
|
||||||
|
|
||||||
|
@typedObject
|
||||||
|
@inheritSerialization(HALResource)
|
||||||
|
export class SubmissionCcLicence extends HALResource {
|
||||||
|
|
||||||
|
static type = SUBMISSION_CC_LICENSE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The object type
|
||||||
|
*/
|
||||||
|
@excludeFromEquals
|
||||||
|
@autoserialize
|
||||||
|
type: ResourceType;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@autoserialize
|
||||||
|
fields: Field[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Field {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
enums: Option[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface Option {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
}
|
@@ -0,0 +1,15 @@
|
|||||||
|
import { Option } from './submission-cc-license.model';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface to represent the submission's creative commons license section data.
|
||||||
|
*/
|
||||||
|
export interface WorkspaceitemSectionCcLicenseObject {
|
||||||
|
ccLicense?: {
|
||||||
|
id: string;
|
||||||
|
fields: {
|
||||||
|
[fieldId: string]: Option;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
uri?: string;
|
||||||
|
accepted?: boolean;
|
||||||
|
}
|
@@ -1,6 +1,7 @@
|
|||||||
import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model';
|
import { WorkspaceitemSectionFormObject } from './workspaceitem-section-form.model';
|
||||||
import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model';
|
import { WorkspaceitemSectionLicenseObject } from './workspaceitem-section-license.model';
|
||||||
import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model';
|
import { WorkspaceitemSectionUploadObject } from './workspaceitem-section-upload.model';
|
||||||
|
import { WorkspaceitemSectionCcLicenseObject } from './workspaceitem-section-cc-license.model';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An interface to represent submission's section object.
|
* An interface to represent submission's section object.
|
||||||
@@ -17,4 +18,5 @@ export type WorkspaceitemSectionDataType
|
|||||||
= WorkspaceitemSectionUploadObject
|
= WorkspaceitemSectionUploadObject
|
||||||
| WorkspaceitemSectionFormObject
|
| WorkspaceitemSectionFormObject
|
||||||
| WorkspaceitemSectionLicenseObject
|
| WorkspaceitemSectionLicenseObject
|
||||||
|
| WorkspaceitemSectionCcLicenseObject
|
||||||
| string;
|
| string;
|
||||||
|
@@ -0,0 +1,34 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { dataService } from '../cache/builders/build-decorators';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { DataService } from '../data/data.service';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { SUBMISSION_CC_LICENSE } from './models/submission-cc-licence.resource-type';
|
||||||
|
import { SubmissionCcLicence } from './models/submission-cc-license.model';
|
||||||
|
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@dataService(SUBMISSION_CC_LICENSE)
|
||||||
|
export class SubmissionCcLicenseDataService extends DataService<SubmissionCcLicence> {
|
||||||
|
|
||||||
|
protected linkPath = 'submissioncclicenses';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected comparator: DefaultChangeAnalyzer<SubmissionCcLicence>,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,76 @@
|
|||||||
|
import { HttpClient } from '@angular/common/http';
|
||||||
|
import { Injectable } from '@angular/core';
|
||||||
|
import { Store } from '@ngrx/store';
|
||||||
|
import { NotificationsService } from '../../shared/notifications/notifications.service';
|
||||||
|
import { dataService } from '../cache/builders/build-decorators';
|
||||||
|
import { RemoteDataBuildService } from '../cache/builders/remote-data-build.service';
|
||||||
|
import { ObjectCacheService } from '../cache/object-cache.service';
|
||||||
|
import { CoreState } from '../core.reducers';
|
||||||
|
import { HALEndpointService } from '../shared/hal-endpoint.service';
|
||||||
|
import { DataService } from '../data/data.service';
|
||||||
|
import { RequestService } from '../data/request.service';
|
||||||
|
import { DefaultChangeAnalyzer } from '../data/default-change-analyzer.service';
|
||||||
|
import { SubmissionCcLicenceUrl } from './models/submission-cc-license-url.model';
|
||||||
|
import { SUBMISSION_CC_LICENSE_URL } from './models/submission-cc-licence-link.resource-type';
|
||||||
|
import { Field, Option, SubmissionCcLicence } from './models/submission-cc-license.model';
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
import { filter, map, switchMap } from 'rxjs/operators';
|
||||||
|
import { getRemoteDataPayload, getSucceededRemoteData } from '../shared/operators';
|
||||||
|
import { isNotEmpty } from '../../shared/empty.util';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
@dataService(SUBMISSION_CC_LICENSE_URL)
|
||||||
|
export class SubmissionCcLicenseUrlDataService extends DataService<SubmissionCcLicenceUrl> {
|
||||||
|
|
||||||
|
protected linkPath = 'submissioncclicenseUrl-search';
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected comparator: DefaultChangeAnalyzer<SubmissionCcLicenceUrl>,
|
||||||
|
protected halService: HALEndpointService,
|
||||||
|
protected http: HttpClient,
|
||||||
|
protected notificationsService: NotificationsService,
|
||||||
|
protected objectCache: ObjectCacheService,
|
||||||
|
protected rdbService: RemoteDataBuildService,
|
||||||
|
protected requestService: RequestService,
|
||||||
|
protected store: Store<CoreState>,
|
||||||
|
) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the link to the Creative Commons license corresponding to the given type and options.
|
||||||
|
* @param ccLicense the Creative Commons license type
|
||||||
|
* @param options the selected options of the license fields
|
||||||
|
*/
|
||||||
|
getCcLicenseLink(ccLicense: SubmissionCcLicence, options: Map<Field, Option>): Observable<string> {
|
||||||
|
|
||||||
|
return this.getSearchByHref(
|
||||||
|
'rightsByQuestions',{
|
||||||
|
searchParams: [
|
||||||
|
{
|
||||||
|
fieldName: 'license',
|
||||||
|
fieldValue: ccLicense.id
|
||||||
|
},
|
||||||
|
...ccLicense.fields.map(
|
||||||
|
(field) => {
|
||||||
|
return {
|
||||||
|
fieldName: `answer_${field.id}`,
|
||||||
|
fieldValue: options.get(field).id,
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
).pipe(
|
||||||
|
switchMap((href) => this.findByHref(href)),
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
map((response) => response.url),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getSearchEndpoint(searchMethod: string): Observable<string> {
|
||||||
|
return this.halService.getEndpoint(`${this.linkPath}`).pipe(
|
||||||
|
filter((href: string) => isNotEmpty(href)),
|
||||||
|
map((href: string) => `${href}/${searchMethod}`));
|
||||||
|
}
|
||||||
|
}
|
31
src/app/shared/ds-select/ds-select.component.html
Normal file
31
src/app/shared/ds-select/ds-select.component.html
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<div>
|
||||||
|
|
||||||
|
<div ngbDropdown class="btn-group" (openChange)="toggled.emit($event)">
|
||||||
|
|
||||||
|
<div class="input-group-prepend" *ngIf="label">
|
||||||
|
<span id="dsSelectMenuLabel" class="input-group-text">
|
||||||
|
{{ label | translate }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button aria-describedby="dsSelectMenuLabel"
|
||||||
|
id="dsSelectMenuButton"
|
||||||
|
class="btn btn-outline-primary selection"
|
||||||
|
(blur)="close.emit($event)"
|
||||||
|
(click)="close.emit($event)"
|
||||||
|
[disabled]="disabled"
|
||||||
|
ngbDropdownToggle>
|
||||||
|
<ng-content select=".selection"></ng-content>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<div ngbDropdownMenu
|
||||||
|
class="dropdown-menu"
|
||||||
|
id="dsSelectDropdownMenu"
|
||||||
|
aria-labelledby="dsSelectMenuButton">
|
||||||
|
<div aria-labelledby="dropdownMenuButton">
|
||||||
|
<ng-content select=".menu"></ng-content>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
0
src/app/shared/ds-select/ds-select.component.scss
Normal file
0
src/app/shared/ds-select/ds-select.component.scss
Normal file
30
src/app/shared/ds-select/ds-select.component.spec.ts
Normal file
30
src/app/shared/ds-select/ds-select.component.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { DsSelectComponent } from './ds-select.component';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
|
||||||
|
describe('DsSelectComponent', () => {
|
||||||
|
let component: DsSelectComponent;
|
||||||
|
let fixture: ComponentFixture<DsSelectComponent>;
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
DsSelectComponent,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(DsSelectComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create', () => {
|
||||||
|
expect(component).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
36
src/app/shared/ds-select/ds-select.component.ts
Normal file
36
src/app/shared/ds-select/ds-select.component.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component which represent a DSpace dropdown selector.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-select',
|
||||||
|
templateUrl: './ds-select.component.html',
|
||||||
|
styleUrls: ['./ds-select.component.scss']
|
||||||
|
})
|
||||||
|
export class DsSelectComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional label for the dropdown selector.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the dropdown selector is disabled.
|
||||||
|
*/
|
||||||
|
@Input()
|
||||||
|
disabled: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an event when the dropdown selector is opened or closed.
|
||||||
|
*/
|
||||||
|
@Output()
|
||||||
|
toggled = new EventEmitter();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits an event when the dropdown selector or closed.
|
||||||
|
*/
|
||||||
|
@Output()
|
||||||
|
close = new EventEmitter();
|
||||||
|
}
|
@@ -206,6 +206,7 @@ import { EpersonSearchBoxComponent } from './resource-policies/form/eperson-grou
|
|||||||
import { GroupSearchBoxComponent } from './resource-policies/form/eperson-group-list/group-search-box/group-search-box.component';
|
import { GroupSearchBoxComponent } from './resource-policies/form/eperson-group-list/group-search-box/group-search-box.component';
|
||||||
import { FileDownloadLinkComponent } from './file-download-link/file-download-link.component';
|
import { FileDownloadLinkComponent } from './file-download-link/file-download-link.component';
|
||||||
import { CollectionDropdownComponent } from './collection-dropdown/collection-dropdown.component';
|
import { CollectionDropdownComponent } from './collection-dropdown/collection-dropdown.component';
|
||||||
|
import { DsSelectComponent } from './ds-select/ds-select.component';
|
||||||
|
|
||||||
const MODULES = [
|
const MODULES = [
|
||||||
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
// Do NOT include UniversalModule, HttpModule, or JsonpModule here
|
||||||
@@ -282,6 +283,7 @@ const COMPONENTS = [
|
|||||||
DsDynamicFormGroupComponent,
|
DsDynamicFormGroupComponent,
|
||||||
DsDynamicFormArrayComponent,
|
DsDynamicFormArrayComponent,
|
||||||
DsDatePickerInlineComponent,
|
DsDatePickerInlineComponent,
|
||||||
|
DsSelectComponent,
|
||||||
ErrorComponent,
|
ErrorComponent,
|
||||||
FormComponent,
|
FormComponent,
|
||||||
LangSwitchComponent,
|
LangSwitchComponent,
|
||||||
|
@@ -0,0 +1,144 @@
|
|||||||
|
<div class="mb-4 ccLicense-select">
|
||||||
|
<ds-select
|
||||||
|
[disabled]="!submissionCcLicenses">
|
||||||
|
|
||||||
|
<ng-container class="selection">
|
||||||
|
<span *ngIf="!submissionCcLicenses">
|
||||||
|
<ds-loading></ds-loading>
|
||||||
|
</span>
|
||||||
|
<span *ngIf="getSelectedCcLicense()">
|
||||||
|
{{ getSelectedCcLicense().name }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="submissionCcLicenses && !getSelectedCcLicense()">
|
||||||
|
<ng-container *ngIf="storedCcLicenseLink">
|
||||||
|
{{ 'submission.sections.ccLicense.change' | translate }}
|
||||||
|
</ng-container>
|
||||||
|
<ng-container *ngIf="!storedCcLicenseLink">
|
||||||
|
{{ 'submission.sections.ccLicense.select' | translate }}
|
||||||
|
</ng-container>
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container class="menu">
|
||||||
|
<button *ngIf="submissionCcLicenses?.length == 0"
|
||||||
|
class="dropdown-item disabled">
|
||||||
|
{{ 'submission.sections.ccLicense.none' | translate }}
|
||||||
|
</button>
|
||||||
|
<button *ngFor="let license of submissionCcLicenses"
|
||||||
|
class="dropdown-item"
|
||||||
|
(click)="selectCcLicense(license)">
|
||||||
|
{{ license.name }}
|
||||||
|
</button>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</ds-select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="getSelectedCcLicense()">
|
||||||
|
|
||||||
|
<div *ngFor="let field of getSelectedCcLicense().fields"
|
||||||
|
class="mb-4">
|
||||||
|
|
||||||
|
<div class="d-flex flex-row">
|
||||||
|
<div class="font-weight-bold {{ field.id }}">
|
||||||
|
{{ field.label }}
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
class="btn btn-outline-info btn-sm ml-2"
|
||||||
|
(click)="openInfoModal(infoModal)">
|
||||||
|
<i class="fas fa-question"></i>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-template #infoModal>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<div class="modal-header mb-4 ">
|
||||||
|
<div>
|
||||||
|
<h4>
|
||||||
|
{{ field.label }}
|
||||||
|
</h4>
|
||||||
|
<div [innerHTML]="field.description"></div>
|
||||||
|
</div>
|
||||||
|
<button type="button" class="close"
|
||||||
|
(click)="closeInfoModal()" aria-label="Close">
|
||||||
|
<span aria-hidden="true">×</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="modal-body">
|
||||||
|
<div *ngFor="let value of field.enums"
|
||||||
|
class="mb-4">
|
||||||
|
<h5>
|
||||||
|
{{ value.label }}
|
||||||
|
</h5>
|
||||||
|
<div [innerHTML]="value.description" class="font-weight-light"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-template>
|
||||||
|
|
||||||
|
<ds-select *ngIf="field.enums?.length > 5">
|
||||||
|
<ng-container class="selection" *ngVar="getSelectedOption(getSelectedCcLicense(), field) as option">
|
||||||
|
<span *ngIf="option">
|
||||||
|
{{ option.label }}
|
||||||
|
</span>
|
||||||
|
<span *ngIf="!option">
|
||||||
|
{{ 'submission.sections.ccLicense.option.select' | translate }}
|
||||||
|
</span>
|
||||||
|
</ng-container>
|
||||||
|
<ng-container class="menu">
|
||||||
|
<div class="options-select-menu overflow-auto">
|
||||||
|
<button *ngFor="let option of field.enums"
|
||||||
|
class="dropdown-item"
|
||||||
|
(click)="selectOption(getSelectedCcLicense(), field, option)">
|
||||||
|
{{ option.label }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ds-select>
|
||||||
|
|
||||||
|
<ng-container *ngIf="field.enums?.length <= 5">
|
||||||
|
<div *ngFor="let option of field.enums"
|
||||||
|
class="d-flex flex-row m-1">
|
||||||
|
<div (click)="selectOption(getSelectedCcLicense(), field, option)">
|
||||||
|
<input type="radio"
|
||||||
|
title="{{ option.label }}"
|
||||||
|
class="mr-1"
|
||||||
|
[checked]="isSelectedOption(getSelectedCcLicense(), field, option)">
|
||||||
|
<span>{{ option.label }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container *ngIf="getCcLicenseLink$()">
|
||||||
|
<ng-container *ngVar="getCcLicenseLink$() | async as licenseLink">
|
||||||
|
<div *ngIf="!licenseLink">
|
||||||
|
<ds-loading></ds-loading>
|
||||||
|
</div>
|
||||||
|
<div *ngIf="licenseLink"
|
||||||
|
class="mt-2 p-4 bg-light text-dark">
|
||||||
|
<div>
|
||||||
|
{{ 'submission.sections.ccLicense.link' | translate }}
|
||||||
|
</div>
|
||||||
|
<a class="license-link" href="{{ licenseLink }}" target="_blank" rel="noopener noreferrer">
|
||||||
|
{{ licenseLink }}
|
||||||
|
</a>
|
||||||
|
<div class="m-2">
|
||||||
|
<div (click)="setAccepted(!accepted)">
|
||||||
|
<input type="checkbox"
|
||||||
|
title="accepted"
|
||||||
|
[checked]="accepted">
|
||||||
|
<span>{{ 'submission.sections.ccLicense.confirmation' | translate }}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
</ng-container>
|
@@ -0,0 +1,3 @@
|
|||||||
|
.options-select-menu {
|
||||||
|
max-height: 25vh;
|
||||||
|
}
|
@@ -0,0 +1,280 @@
|
|||||||
|
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
import { SubmissionSectionCcLicensesComponent } from './submission-section-cc-licenses.component';
|
||||||
|
import { SUBMISSION_CC_LICENSE } from '../../../core/submission/models/submission-cc-licence.resource-type';
|
||||||
|
import { of as observableOf } from 'rxjs';
|
||||||
|
import { SubmissionCcLicenseDataService } from '../../../core/submission/submission-cc-license-data.service';
|
||||||
|
import { DebugElement } from '@angular/core';
|
||||||
|
import { By } from '@angular/platform-browser';
|
||||||
|
import { SharedModule } from '../../../shared/shared.module';
|
||||||
|
import { SectionsService } from '../sections.service';
|
||||||
|
import { SectionDataObject } from '../models/section-data.model';
|
||||||
|
import { SectionsType } from '../sections-type';
|
||||||
|
import { RemoteData } from '../../../core/data/remote-data';
|
||||||
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { PageInfo } from '../../../core/shared/page-info.model';
|
||||||
|
import { PaginatedList } from '../../../core/data/paginated-list';
|
||||||
|
import { SubmissionCcLicence } from '../../../core/submission/models/submission-cc-license.model';
|
||||||
|
import { cold } from 'jasmine-marbles';
|
||||||
|
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
|
||||||
|
import { SubmissionCcLicenseUrlDataService } from '../../../core/submission/submission-cc-license-url-data.service';
|
||||||
|
|
||||||
|
describe('SubmissionSectionCcLicensesComponent', () => {
|
||||||
|
|
||||||
|
let component: SubmissionSectionCcLicensesComponent;
|
||||||
|
let fixture: ComponentFixture<SubmissionSectionCcLicensesComponent>;
|
||||||
|
let de: DebugElement;
|
||||||
|
|
||||||
|
const sectionObject: SectionDataObject = {
|
||||||
|
config: 'test config',
|
||||||
|
mandatory: true,
|
||||||
|
data: {},
|
||||||
|
errors: [],
|
||||||
|
header: 'test header',
|
||||||
|
id: 'test section id',
|
||||||
|
sectionType: SectionsType.SubmissionForm
|
||||||
|
};
|
||||||
|
|
||||||
|
const submissionCcLicenses: SubmissionCcLicence[] = [
|
||||||
|
{
|
||||||
|
id: 'test license id 1',
|
||||||
|
type: SUBMISSION_CC_LICENSE,
|
||||||
|
name: 'test license name 1',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'test-field-id-1a',
|
||||||
|
label: 'test field label 1a',
|
||||||
|
description: 'test field description 1a',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 1a I',
|
||||||
|
label: 'test enum label 1a I',
|
||||||
|
description: 'test enum description 1a I',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 1a II',
|
||||||
|
label: 'test enum label 1a II',
|
||||||
|
description: 'test enum description 1a II',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test-field-id-1b',
|
||||||
|
label: 'test field label 1b',
|
||||||
|
description: 'test field description 1b',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 1b I',
|
||||||
|
label: 'test enum label 1b I',
|
||||||
|
description: 'test enum description 1b I',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 1b II',
|
||||||
|
label: 'test enum label 1b II',
|
||||||
|
description: 'test enum description 1b II',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'test link',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test license id 2',
|
||||||
|
type: SUBMISSION_CC_LICENSE,
|
||||||
|
name: 'test license name 2',
|
||||||
|
fields: [
|
||||||
|
{
|
||||||
|
id: 'test-field-id-2a',
|
||||||
|
label: 'test field label 2a',
|
||||||
|
description: 'test field description 2a',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 2a I',
|
||||||
|
label: 'test enum label 2a I',
|
||||||
|
description: 'test enum description 2a I'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 2a II',
|
||||||
|
label: 'test enum label 2a II',
|
||||||
|
description: 'test enum description 2a II'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test-field-id-2b',
|
||||||
|
label: 'test field label 2b',
|
||||||
|
description: 'test field description 2b',
|
||||||
|
enums: [
|
||||||
|
{
|
||||||
|
id: 'test enum id 2b I',
|
||||||
|
label: 'test enum label 2b I',
|
||||||
|
description: 'test enum description 2b I'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'test enum id 2b II',
|
||||||
|
label: 'test enum label 2b II',
|
||||||
|
description: 'test enum description 2b II'
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
_links: {
|
||||||
|
self: {
|
||||||
|
href: 'test link',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const submissionCcLicensesDataService = jasmine.createSpyObj('submissionCcLicensesDataService', {
|
||||||
|
findAll: observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
new PaginatedList(new PageInfo(), submissionCcLicenses),
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
|
||||||
|
const submissionCcLicenseUrlDataService = jasmine.createSpyObj('submissionCcLicenseUrlDataService', {
|
||||||
|
getCcLicenseLink: observableOf(new RemoteData(
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
{
|
||||||
|
url: 'test cc license link',
|
||||||
|
}
|
||||||
|
)),
|
||||||
|
});
|
||||||
|
|
||||||
|
const sectionService = {
|
||||||
|
getSectionState: () => {
|
||||||
|
return observableOf({});
|
||||||
|
},
|
||||||
|
setSectionStatus: () => undefined,
|
||||||
|
updateSectionData: (submissionId, sectionId, updatedData) => {
|
||||||
|
component.sectionData.data = updatedData;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const operationsBuilder = jasmine.createSpyObj('operationsBuilder', {
|
||||||
|
add: undefined,
|
||||||
|
remove: undefined,
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(async(() => {
|
||||||
|
TestBed.configureTestingModule({
|
||||||
|
imports: [
|
||||||
|
SharedModule,
|
||||||
|
TranslateModule.forRoot(),
|
||||||
|
],
|
||||||
|
declarations: [
|
||||||
|
SubmissionSectionCcLicensesComponent,
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
{ provide: SubmissionCcLicenseDataService, useValue: submissionCcLicensesDataService },
|
||||||
|
{ provide: SubmissionCcLicenseUrlDataService, useValue: submissionCcLicenseUrlDataService },
|
||||||
|
{ provide: SectionsService, useValue: sectionService },
|
||||||
|
{ provide: JsonPatchOperationsBuilder, useValue: operationsBuilder },
|
||||||
|
{ provide: 'collectionIdProvider', useValue: 'test collection id' },
|
||||||
|
{ provide: 'sectionDataProvider', useValue: sectionObject },
|
||||||
|
{ provide: 'submissionIdProvider', useValue: 'test submission id' },
|
||||||
|
],
|
||||||
|
})
|
||||||
|
.compileComponents();
|
||||||
|
}));
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
fixture = TestBed.createComponent(SubmissionSectionCcLicensesComponent);
|
||||||
|
component = fixture.componentInstance;
|
||||||
|
de = fixture.debugElement;
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a dropdown with the different cc licenses', () => {
|
||||||
|
expect(
|
||||||
|
de.query(By.css('.ccLicense-select ds-select .dropdown-menu button:nth-child(1)')).nativeElement.innerText
|
||||||
|
).toContain('test license name 1');
|
||||||
|
expect(
|
||||||
|
de.query(By.css('.ccLicense-select ds-select .dropdown-menu button:nth-child(2)')).nativeElement.innerText
|
||||||
|
).toContain('test license name 2');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when a license is selected', () => {
|
||||||
|
|
||||||
|
const ccLicence = submissionCcLicenses[1];
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.selectCcLicense(ccLicence);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display the selected cc license', () => {
|
||||||
|
expect(
|
||||||
|
de.query(By.css('.ccLicense-select ds-select button.selection')).nativeElement.innerText
|
||||||
|
).toContain('test license name 2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display all field labels of the selected cc license only', () => {
|
||||||
|
expect(de.query(By.css('div.test-field-id-1a'))).toBeNull();
|
||||||
|
expect(de.query(By.css('div.test-field-id-1b'))).toBeNull();
|
||||||
|
expect(de.query(By.css('div.test-field-id-2a'))).toBeTruthy();
|
||||||
|
expect(de.query(By.css('div.test-field-id-2b'))).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not display a cc license link', () => {
|
||||||
|
expect(de.query(By.css('.license-link'))).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have section status incomplete', () => {
|
||||||
|
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false }));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when all options have a value selected', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.selectOption(ccLicence, ccLicence.fields[0], ccLicence.fields[0].enums[1]);
|
||||||
|
component.selectOption(ccLicence, ccLicence.fields[1], ccLicence.fields[1].enums[0]);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should call the submission cc licenses data service getCcLicenseLink method', () => {
|
||||||
|
expect(submissionCcLicenseUrlDataService.getCcLicenseLink).toHaveBeenCalledWith(
|
||||||
|
ccLicence,
|
||||||
|
new Map([
|
||||||
|
[ccLicence.fields[0], ccLicence.fields[0].enums[1]],
|
||||||
|
[ccLicence.fields[1], ccLicence.fields[1].enums[0]],
|
||||||
|
])
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should display a cc license link', () => {
|
||||||
|
expect(de.query(By.css('.license-link'))).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not be accepted', () => {
|
||||||
|
expect(component.accepted).toBeFalse();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have section status incomplete', () => {
|
||||||
|
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: false }));
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when the cc license is accepted', () => {
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.setAccepted(true);
|
||||||
|
fixture.detectChanges();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have section status complete', () => {
|
||||||
|
expect(component.getSectionStatus()).toBeObservable(cold('(a|)', { a: true }));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
@@ -0,0 +1,279 @@
|
|||||||
|
import { Component, Inject } from '@angular/core';
|
||||||
|
import { Observable, of as observableOf, Subscription } from 'rxjs';
|
||||||
|
import { Field, Option, SubmissionCcLicence } from '../../../core/submission/models/submission-cc-license.model';
|
||||||
|
import { getRemoteDataPayload, getSucceededRemoteData } from '../../../core/shared/operators';
|
||||||
|
import { distinctUntilChanged, filter, map, take } from 'rxjs/operators';
|
||||||
|
import { SubmissionCcLicenseDataService } from '../../../core/submission/submission-cc-license-data.service';
|
||||||
|
import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
|
||||||
|
import { renderSectionFor } from '../sections-decorator';
|
||||||
|
import { SectionsType } from '../sections-type';
|
||||||
|
import { SectionModelComponent } from '../models/section.model';
|
||||||
|
import { SectionDataObject } from '../models/section-data.model';
|
||||||
|
import { SectionsService } from '../sections.service';
|
||||||
|
import { WorkspaceitemSectionCcLicenseObject } from '../../../core/submission/models/workspaceitem-section-cc-license.model';
|
||||||
|
import { JsonPatchOperationPathCombiner } from '../../../core/json-patch/builder/json-patch-operation-path-combiner';
|
||||||
|
import { isNotEmpty } from '../../../shared/empty.util';
|
||||||
|
import { JsonPatchOperationsBuilder } from '../../../core/json-patch/builder/json-patch-operations-builder';
|
||||||
|
import { SubmissionCcLicenseUrlDataService } from '../../../core/submission/submission-cc-license-url-data.service';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component represents the submission section to select the Creative Commons license.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'ds-submission-section-cc-licenses',
|
||||||
|
templateUrl: './submission-section-cc-licenses.component.html',
|
||||||
|
styleUrls: ['./submission-section-cc-licenses.component.scss']
|
||||||
|
})
|
||||||
|
@renderSectionFor(SectionsType.CcLicense)
|
||||||
|
export class SubmissionSectionCcLicensesComponent extends SectionModelComponent {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The form id
|
||||||
|
* @type {string}
|
||||||
|
*/
|
||||||
|
public formId: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A boolean representing if this section is loading
|
||||||
|
* @type {boolean}
|
||||||
|
*/
|
||||||
|
public isLoading = true;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The [JsonPatchOperationPathCombiner] object
|
||||||
|
* @type {JsonPatchOperationPathCombiner}
|
||||||
|
*/
|
||||||
|
protected pathCombiner: JsonPatchOperationPathCombiner;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of Subscriptions this component subscribes to.
|
||||||
|
*/
|
||||||
|
private subscriptions: Subscription[] = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache of the available Creative Commons licenses.
|
||||||
|
*/
|
||||||
|
submissionCcLicenses: SubmissionCcLicence[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reference to NgbModal
|
||||||
|
*/
|
||||||
|
protected modalRef: NgbModalRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Creative Commons link saved in the workspace item.
|
||||||
|
*/
|
||||||
|
get storedCcLicenseLink(): string {
|
||||||
|
return this.data.uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The accepted state for the selected Creative Commons license.
|
||||||
|
*/
|
||||||
|
get accepted(): boolean {
|
||||||
|
if (this.data.accepted === undefined) {
|
||||||
|
return !!this.data.uri;
|
||||||
|
}
|
||||||
|
return this.data.accepted;
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
protected modalService: NgbModal,
|
||||||
|
protected sectionService: SectionsService,
|
||||||
|
protected submissionCcLicensesDataService: SubmissionCcLicenseDataService,
|
||||||
|
protected submissionCcLicenseUrlDataService: SubmissionCcLicenseUrlDataService,
|
||||||
|
protected operationsBuilder: JsonPatchOperationsBuilder,
|
||||||
|
@Inject('collectionIdProvider') public injectedCollectionId: string,
|
||||||
|
@Inject('sectionDataProvider') public injectedSectionData: SectionDataObject,
|
||||||
|
@Inject('submissionIdProvider') public injectedSubmissionId: string
|
||||||
|
) {
|
||||||
|
super(
|
||||||
|
injectedCollectionId,
|
||||||
|
injectedSectionData,
|
||||||
|
injectedSubmissionId,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data of this section.
|
||||||
|
*/
|
||||||
|
get data(): WorkspaceitemSectionCcLicenseObject {
|
||||||
|
return this.sectionData.data as WorkspaceitemSectionCcLicenseObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select a given Creative Commons license.
|
||||||
|
* @param ccLicense the Creative Commons license to select.
|
||||||
|
*/
|
||||||
|
selectCcLicense(ccLicense: SubmissionCcLicence) {
|
||||||
|
if (!!this.getSelectedCcLicense() && this.getSelectedCcLicense().id === ccLicense.id) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.setAccepted(false);
|
||||||
|
this.updateSectionData({
|
||||||
|
ccLicense: {
|
||||||
|
id: ccLicense.id,
|
||||||
|
fields: {},
|
||||||
|
},
|
||||||
|
uri: undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the selected Creative Commons license.
|
||||||
|
*/
|
||||||
|
getSelectedCcLicense(): SubmissionCcLicence {
|
||||||
|
if (!this.submissionCcLicenses || !this.data.ccLicense) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this.submissionCcLicenses.filter((ccLicense) => ccLicense.id === this.data.ccLicense.id)[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select an option for a given license field.
|
||||||
|
* @param ccLicense the related Creative Commons license.
|
||||||
|
* @param field the field for which to select an option.
|
||||||
|
* @param option the option to select.
|
||||||
|
*/
|
||||||
|
selectOption(ccLicense: SubmissionCcLicence, field: Field, option: Option) {
|
||||||
|
if (this.isSelectedOption(ccLicense, field, option)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.updateSectionData({
|
||||||
|
ccLicense: {
|
||||||
|
id: ccLicense.id,
|
||||||
|
fields: Object.assign({}, this.data.ccLicense.fields, {
|
||||||
|
[field.id]: option
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
accepted: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the selected option for a given license field.
|
||||||
|
* @param ccLicense the related Creative Commons license.
|
||||||
|
* @param field the field for which to get the selected option value.
|
||||||
|
*/
|
||||||
|
getSelectedOption(ccLicense: SubmissionCcLicence, field: Field): Option {
|
||||||
|
return this.data.ccLicense.fields[field.id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether a given option is selected for a given Creative Commons license field.
|
||||||
|
* @param ccLicense the related Creative Commons license.
|
||||||
|
* @param field the field for which to check whether the option is selected.
|
||||||
|
* @param option the option for which to check whether it is selected.
|
||||||
|
*/
|
||||||
|
isSelectedOption(ccLicense: SubmissionCcLicence, field: Field, option: Option): boolean {
|
||||||
|
return this.getSelectedOption(ccLicense, field) && this.getSelectedOption(ccLicense, field).id === option.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the link to the Creative Commons license corresponding with the selected options.
|
||||||
|
*/
|
||||||
|
getCcLicenseLink$(): Observable<string> {
|
||||||
|
|
||||||
|
if (!!this.storedCcLicenseLink) {
|
||||||
|
return observableOf(this.storedCcLicenseLink);
|
||||||
|
}
|
||||||
|
if (!this.getSelectedCcLicense() || this.getSelectedCcLicense().fields.some(
|
||||||
|
(field) => !this.getSelectedOption(this.getSelectedCcLicense(), field))) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
const selectedCcLicense = this.getSelectedCcLicense();
|
||||||
|
return this.submissionCcLicenseUrlDataService.getCcLicenseLink(
|
||||||
|
selectedCcLicense,
|
||||||
|
new Map(selectedCcLicense.fields.map(
|
||||||
|
(field) => [field, this.getSelectedOption(selectedCcLicense, field)]
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a given info modal.
|
||||||
|
* @param content the modal content.
|
||||||
|
*/
|
||||||
|
openInfoModal(content) {
|
||||||
|
this.modalRef = this.modalService.open(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the info modal.
|
||||||
|
*/
|
||||||
|
closeInfoModal() {
|
||||||
|
this.modalRef.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get section status
|
||||||
|
*
|
||||||
|
* @return Observable<boolean>
|
||||||
|
* the section status
|
||||||
|
*/
|
||||||
|
getSectionStatus(): Observable<boolean> {
|
||||||
|
return observableOf(this.accepted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unsubscribe from all subscriptions
|
||||||
|
*/
|
||||||
|
onSectionDestroy(): void {
|
||||||
|
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize the section.
|
||||||
|
*/
|
||||||
|
onSectionInit(): void {
|
||||||
|
this.pathCombiner = new JsonPatchOperationPathCombiner('sections', this.sectionData.id);
|
||||||
|
this.subscriptions.push(
|
||||||
|
this.sectionService.getSectionState(this.submissionId, this.sectionData.id).pipe(
|
||||||
|
filter((sectionState) => {
|
||||||
|
return isNotEmpty(sectionState) && (isNotEmpty(sectionState.data) || isNotEmpty(sectionState.errors))
|
||||||
|
}),
|
||||||
|
distinctUntilChanged(),
|
||||||
|
map((sectionState) => sectionState.data as WorkspaceitemSectionCcLicenseObject),
|
||||||
|
).subscribe((data) => {
|
||||||
|
if (this.data.accepted !== data.accepted) {
|
||||||
|
const path = this.pathCombiner.getPath('uri');
|
||||||
|
if (data.accepted) {
|
||||||
|
this.getCcLicenseLink$().pipe(
|
||||||
|
take(1),
|
||||||
|
).subscribe((link) => {
|
||||||
|
this.operationsBuilder.add(path, link.toString(), false, true);
|
||||||
|
});
|
||||||
|
} else if (!!this.data.uri) {
|
||||||
|
this.operationsBuilder.remove(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.sectionData.data = data;
|
||||||
|
}),
|
||||||
|
this.submissionCcLicensesDataService.findAll({elementsPerPage: Number.MAX_SAFE_INTEGER}).pipe(
|
||||||
|
getSucceededRemoteData(),
|
||||||
|
getRemoteDataPayload(),
|
||||||
|
map((list) => list.page),
|
||||||
|
).subscribe(
|
||||||
|
(licenses) => this.submissionCcLicenses = licenses
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the accepted state for the Creative Commons license.
|
||||||
|
* @param accepted the accepted state for the cc license.
|
||||||
|
*/
|
||||||
|
setAccepted(accepted: boolean) {
|
||||||
|
this.updateSectionData({
|
||||||
|
accepted
|
||||||
|
});
|
||||||
|
this.updateSectionStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update the section data for this section.
|
||||||
|
*/
|
||||||
|
updateSectionData(data: WorkspaceitemSectionCcLicenseObject) {
|
||||||
|
this.sectionService.updateSectionData(this.submissionId, this.sectionData.id, Object.assign({}, this.data, data));
|
||||||
|
}
|
||||||
|
}
|
@@ -28,7 +28,7 @@ import { SubmissionSectionUploadFileViewComponent } from './sections/upload/file
|
|||||||
import { SubmissionSectionUploadAccessConditionsComponent } from './sections/upload/accessConditions/submission-section-upload-access-conditions.component';
|
import { SubmissionSectionUploadAccessConditionsComponent } from './sections/upload/accessConditions/submission-section-upload-access-conditions.component';
|
||||||
import { SubmissionSubmitComponent } from './submit/submission-submit.component';
|
import { SubmissionSubmitComponent } from './submit/submission-submit.component';
|
||||||
import { storeModuleConfig } from '../app.reducer';
|
import { storeModuleConfig } from '../app.reducer';
|
||||||
import { CoreState } from '../core/core.reducers';
|
import { SubmissionSectionCcLicensesComponent } from './sections/cc-license/submission-section-cc-licenses.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
@@ -44,8 +44,8 @@ import { CoreState } from '../core/core.reducers';
|
|||||||
SubmissionSectionUploadComponent,
|
SubmissionSectionUploadComponent,
|
||||||
SubmissionSectionformComponent,
|
SubmissionSectionformComponent,
|
||||||
SubmissionSectionLicenseComponent,
|
SubmissionSectionLicenseComponent,
|
||||||
|
SubmissionSectionCcLicensesComponent,
|
||||||
SectionsDirective,
|
SectionsDirective,
|
||||||
SubmissionSectionContainerComponent,
|
|
||||||
SubmissionEditComponent,
|
SubmissionEditComponent,
|
||||||
SubmissionFormSectionAddComponent,
|
SubmissionFormSectionAddComponent,
|
||||||
SubmissionFormCollectionComponent,
|
SubmissionFormCollectionComponent,
|
||||||
@@ -53,6 +53,7 @@ import { CoreState } from '../core/core.reducers';
|
|||||||
SubmissionFormFooterComponent,
|
SubmissionFormFooterComponent,
|
||||||
SubmissionSubmitComponent,
|
SubmissionSubmitComponent,
|
||||||
SubmissionUploadFilesComponent,
|
SubmissionUploadFilesComponent,
|
||||||
|
SubmissionSectionContainerComponent,
|
||||||
SubmissionSectionUploadFileComponent,
|
SubmissionSectionUploadFileComponent,
|
||||||
SubmissionSectionUploadFileEditComponent,
|
SubmissionSectionUploadFileEditComponent,
|
||||||
SubmissionSectionUploadFileViewComponent
|
SubmissionSectionUploadFileViewComponent
|
||||||
@@ -61,7 +62,9 @@ import { CoreState } from '../core/core.reducers';
|
|||||||
SubmissionSectionUploadComponent,
|
SubmissionSectionUploadComponent,
|
||||||
SubmissionSectionformComponent,
|
SubmissionSectionformComponent,
|
||||||
SubmissionSectionLicenseComponent,
|
SubmissionSectionLicenseComponent,
|
||||||
SubmissionSectionContainerComponent],
|
SubmissionSectionContainerComponent,
|
||||||
|
SubmissionSectionCcLicensesComponent,
|
||||||
|
],
|
||||||
exports: [
|
exports: [
|
||||||
SubmissionEditComponent,
|
SubmissionEditComponent,
|
||||||
SubmissionFormComponent,
|
SubmissionFormComponent,
|
||||||
|
@@ -2768,6 +2768,20 @@
|
|||||||
|
|
||||||
"submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Use only for this submission",
|
"submission.sections.describe.relationship-lookup.name-variant.notification.decline": "Use only for this submission",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.type": "License Type",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.select": "Select a license type…",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.change": "Change your license type…",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.none": "No licenses available",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.option.select": "Select an option…",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.link": "You’ve selected the following license:",
|
||||||
|
|
||||||
|
"submission.sections.ccLicense.confirmation": "I grant the license above",
|
||||||
|
|
||||||
"submission.sections.general.add-more": "Add more",
|
"submission.sections.general.add-more": "Add more",
|
||||||
|
|
||||||
"submission.sections.general.collection": "Collection",
|
"submission.sections.general.collection": "Collection",
|
||||||
@@ -2798,7 +2812,7 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
"submission.sections.submit.progressbar.cclicense": "Creative commons license",
|
"submission.sections.submit.progressbar.CClicense": "Creative commons license",
|
||||||
|
|
||||||
"submission.sections.submit.progressbar.describe.recycle": "Recycle",
|
"submission.sections.submit.progressbar.describe.recycle": "Recycle",
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user