diff --git a/src/app/services/createComponentService.spec.ts b/src/app/services/createComponentService.spec.ts new file mode 100644 index 00000000000..25f3052bd7c --- /dev/null +++ b/src/app/services/createComponentService.spec.ts @@ -0,0 +1,61 @@ +import { TestBed } from '@angular/core/testing'; +import { CreateComponentService } from '../../assets/wise5/services/createComponentService'; +import { TeacherProjectService } from '../../assets/wise5/services/teacherProjectService'; +import { StudentTeacherCommonServicesModule } from '../student-teacher-common-services.module'; +import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import { ComponentServiceLookupService } from '../../assets/wise5/services/componentServiceLookupService'; +import { Node } from '../../assets/wise5/common/Node'; + +let componentServiceLookupService: ComponentServiceLookupService; +let projectService: TeacherProjectService; +let service: CreateComponentService; +let node; +describe('CreateComponentService', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [StudentTeacherCommonServicesModule], + providers: [ + CreateComponentService, + TeacherProjectService, + provideHttpClient(withInterceptorsFromDi()) + ] + }); + node = new Node(); + componentServiceLookupService = TestBed.inject(ComponentServiceLookupService); + projectService = TestBed.inject(TeacherProjectService); + service = TestBed.inject(CreateComponentService); + spyOn(projectService, 'getNode').and.returnValue(node); + }); + create_NullInsertAfterComponentId(); + create_NonNullInsertAfterComponentId(); +}); + +function create_NullInsertAfterComponentId() { + describe('create() without insertAfterComponentId', () => { + it('should add the new component at the beginning', () => { + const component1 = service.create('node1', 'HTML'); + expect(component1.type).toEqual('HTML'); + expectNodeComponentTypes(['HTML']); + const component2 = service.create('node1', 'OpenResponse'); + expect(component2.type).toEqual('OpenResponse'); + expectNodeComponentTypes(['OpenResponse', 'HTML']); + }); + }); +} + +function create_NonNullInsertAfterComponentId() { + describe('create() with insertAfterComponentId', () => { + it('should add the new component after the insertAfterComponentId', () => { + const component1 = service.create('node1', 'HTML'); + expect(component1.type).toEqual('HTML'); + expectNodeComponentTypes(['HTML']); + const component2 = service.create('node1', 'OpenResponse', component1.id); + expect(component2.type).toEqual('OpenResponse'); + expectNodeComponentTypes(['HTML', 'OpenResponse']); + }); + }); +} + +function expectNodeComponentTypes(types: string[]) { + expect(node.components.map((c) => c.type)).toEqual(types); +} diff --git a/src/app/teacher/teacher-authoring.module.ts b/src/app/teacher/teacher-authoring.module.ts index 3e2f3692ff1..cfa8558608e 100644 --- a/src/app/teacher/teacher-authoring.module.ts +++ b/src/app/teacher/teacher-authoring.module.ts @@ -35,6 +35,7 @@ import { ComponentInfoService } from '../../assets/wise5/services/componentInfoS import { TeacherProjectTranslationService } from '../../assets/wise5/services/teacherProjectTranslationService'; import { DeleteTranslationsService } from '../../assets/wise5/services/deleteTranslationsService'; import { CopyTranslationsService } from '../../assets/wise5/services/copyTranslationsService'; +import { CreateComponentService } from '../../assets/wise5/services/createComponentService'; import { NotifyAuthorService } from '../../assets/wise5/services/notifyAuthorService'; import { RemoveNodeIdFromTransitionsService } from '../../assets/wise5/services/removeNodeIdFromTransitionsService'; @@ -46,6 +47,7 @@ import { RemoveNodeIdFromTransitionsService } from '../../assets/wise5/services/ CopyNodesService, CopyProjectService, CopyTranslationsService, + CreateComponentService, DataExportService, { provide: DataService, useExisting: TeacherDataService }, TeacherProjectTranslationService, diff --git a/src/assets/wise5/authoringTool/addNode/add-your-own-node/add-your-own-node.component.ts b/src/assets/wise5/authoringTool/addNode/add-your-own-node/add-your-own-node.component.ts index fb2139ceee9..277af642145 100644 --- a/src/assets/wise5/authoringTool/addNode/add-your-own-node/add-your-own-node.component.ts +++ b/src/assets/wise5/authoringTool/addNode/add-your-own-node/add-your-own-node.component.ts @@ -9,6 +9,7 @@ import { ReactiveFormsModule } from '@angular/forms'; import { ComponentTypeService } from '../../../services/componentTypeService'; +import { CreateComponentService } from '../../../services/createComponentService'; import { ActivatedRoute, Router, RouterModule } from '@angular/router'; import { TeacherProjectService } from '../../../services/teacherProjectService'; import { CommonModule } from '@angular/common'; @@ -52,6 +53,7 @@ export class AddYourOwnNodeComponent { constructor( private componentTypeService: ComponentTypeService, + private createComponentService: CreateComponentService, private fb: FormBuilder, private projectService: TeacherProjectService, private route: ActivatedRoute, @@ -97,7 +99,7 @@ export class AddYourOwnNodeComponent { private addInitialComponents(nodeId: string, components: any[]): void { components .reverse() - .forEach((component) => this.projectService.createComponent(nodeId, component.type)); + .forEach((component) => this.createComponentService.create(nodeId, component.type)); } private save(): any { diff --git a/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.spec.ts b/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.spec.ts index 12bdb7b5c9a..7545cab1030 100644 --- a/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.spec.ts +++ b/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.spec.ts @@ -1,6 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { AddComponentButtonComponent } from './add-component-button.component'; import { MatDialog } from '@angular/material/dialog'; +import { CreateComponentService } from '../../../services/createComponentService'; import { TeacherProjectService } from '../../../services/teacherProjectService'; import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed'; import { HarnessLoader } from '@angular/cdk/testing'; @@ -11,9 +12,11 @@ import { Node } from '../../../common/Node'; import { provideRouter } from '@angular/router'; class MockTeacherProjectService { - createComponent() {} saveProject() {} } +class MockCreateComponentService { + create() {} +} let loader: HarnessLoader; describe('AddComponentButtonComponent', () => { let component: AddComponentButtonComponent; @@ -23,6 +26,7 @@ describe('AddComponentButtonComponent', () => { await TestBed.configureTestingModule({ imports: [AddComponentButtonComponent], providers: [ + { provide: CreateComponentService, useClass: MockCreateComponentService }, { provide: TeacherProjectService, useClass: MockTeacherProjectService }, provideRouter([]) ] @@ -40,7 +44,7 @@ describe('AddComponentButtonComponent', () => { afterClosed: () => of({ action: 'create', componentType: 'OpenResponse' }) } as any); const projectService = TestBed.inject(TeacherProjectService); - const createComponentSpy = spyOn(projectService, 'createComponent'); + const createComponentSpy = spyOn(TestBed.inject(CreateComponentService), 'create'); const saveProjectSpy = spyOn(projectService, 'saveProject'); await (await loader.getHarness(MatButtonHarness)).click(); expect(dialogSpy).toHaveBeenCalledWith(ChooseNewComponent, { diff --git a/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.ts b/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.ts index a52c9b7c023..2f00c1ff18f 100644 --- a/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.ts +++ b/src/assets/wise5/authoringTool/node/add-component-button/add-component-button.component.ts @@ -1,4 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { CreateComponentService } from '../../../services/createComponentService'; import { TeacherProjectService } from '../../../services/teacherProjectService'; import { MatDialog } from '@angular/material/dialog'; import { ChooseNewComponent } from '../../../../../app/authoring-tool/add-component/choose-new-component/choose-new-component.component'; @@ -21,6 +22,7 @@ export class AddComponentButtonComponent { @Output() newComponentsEvent: EventEmitter = new EventEmitter(); constructor( + private createComponentService: CreateComponentService, private dialog: MatDialog, private projectService: TeacherProjectService, private route: ActivatedRoute, @@ -44,7 +46,7 @@ export class AddComponentButtonComponent { } }); } else { - const component = this.projectService.createComponent( + const component = this.createComponentService.create( this.node.id, componentType, this.insertAfterComponentId diff --git a/src/assets/wise5/authoringTool/node/node-authoring/node-authoring.component.spec.ts b/src/assets/wise5/authoringTool/node/node-authoring/node-authoring.component.spec.ts index 9ee41e4706f..5ccbf0c7edc 100644 --- a/src/assets/wise5/authoringTool/node/node-authoring/node-authoring.component.spec.ts +++ b/src/assets/wise5/authoringTool/node/node-authoring/node-authoring.component.spec.ts @@ -32,6 +32,7 @@ import { TranslatableInputComponent } from '../../components/translatable-input/ import { CopyTranslationsService } from '../../../services/copyTranslationsService'; import { provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; import { RouterTestingModule } from '@angular/router/testing'; +import { CreateComponentService } from '../../../services/createComponentService'; let component: NodeAuthoringComponent; let component1: any; @@ -68,6 +69,7 @@ describe('NodeAuthoringComponent', () => { ], providers: [ ClassroomStatusService, + CreateComponentService, CopyTranslationsService, DeleteTranslationsService, TeacherProjectTranslationService, diff --git a/src/assets/wise5/services/createComponentService.ts b/src/assets/wise5/services/createComponentService.ts new file mode 100644 index 00000000000..bd53503ba41 --- /dev/null +++ b/src/assets/wise5/services/createComponentService.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@angular/core'; +import { TeacherProjectService } from './teacherProjectService'; +import { ComponentServiceLookupService } from './componentServiceLookupService'; +import { Node } from '../common/Node'; + +@Injectable() +export class CreateComponentService { + constructor( + private componentServiceLookupService: ComponentServiceLookupService, + private projectService: TeacherProjectService + ) {} + + /** + * Create a new component + * @param nodeId the node id to create the component in + * @param componentType the component type + * @param insertAfterComponentId Insert the new component after the given + * component id. If this argument is null, we will place the new component + * in the first position. + */ + create(nodeId: string, componentType: string, insertAfterComponentId: string = null): any { + const node = this.projectService.getNode(nodeId); + const service = this.componentServiceLookupService.getService(componentType); + const component = service.createComponent(); + if (service.componentHasWork(component)) { + if (node.showSaveButton == false) { + if (this.projectService.doesAnyComponentInNodeShowSubmitButton(node.id)) { + component.showSaveButton = true; + } else { + node.showSaveButton = true; + } + } + } + this.addComponentToNode(node, component, insertAfterComponentId); + return component; + } + + private addComponentToNode(node: Node, component: any, insertAfterComponentId: string): void { + const insertPosition = + insertAfterComponentId == null + ? 0 + : node.components.findIndex((c) => c.id === insertAfterComponentId) + 1; + node.components.splice(insertPosition, 0, component); + } +} diff --git a/src/assets/wise5/services/teacherProjectService.ts b/src/assets/wise5/services/teacherProjectService.ts index 98e9423af38..f37643bb75d 100644 --- a/src/assets/wise5/services/teacherProjectService.ts +++ b/src/assets/wise5/services/teacherProjectService.ts @@ -1164,50 +1164,6 @@ export class TeacherProjectService extends ProjectService { } } - /** - * Remove the node from the inactive nodes array - * @param nodeId the node to remove from the inactive nodes array - */ - removeNodeIdFromInactiveNodes(nodeId) { - const inactiveNodes = this.project.inactiveNodes; - if (inactiveNodes != null) { - for (let i = 0; i < inactiveNodes.length; i++) { - const inactiveNode = inactiveNodes[i]; - if (inactiveNode != null) { - const inactiveNodeId = inactiveNode.id; - if (inactiveNodeId === nodeId) { - inactiveNodes.splice(i, 1); - } - } - } - } - } - - /** - * Create a new component - * @param nodeId the node id to create the component in - * @param componentType the component type - * @param insertAfterComponentId Insert the new compnent after the given - * component id. If this argument is null, we will place the new component - * in the first position. - */ - createComponent(nodeId, componentType, insertAfterComponentId = null) { - const node = this.getNodeById(nodeId); - const service = this.componentServiceLookupService.getService(componentType); - const component = service.createComponent(); - if (service.componentHasWork(component)) { - if (node.showSaveButton == false) { - if (this.doesAnyComponentInNodeShowSubmitButton(node.id)) { - component.showSaveButton = true; - } else { - node.showSaveButton = true; - } - } - } - this.addComponentToNode(node, component, insertAfterComponentId); - return component; - } - /** * Check if any of the components in the node are showing their submit button. * @param nodeId {string} The node id to check. @@ -1247,52 +1203,6 @@ export class TeacherProjectService extends ProjectService { return -1; } - /** - * Add the component to the node - * @param node the node - * @param component the component - * @param insertAfterComponentId Insert the component after this given - * component id. If this argument is null, we will place the new component - * in the first position. - */ - addComponentToNode(node, component, insertAfterComponentId) { - if (insertAfterComponentId == null) { - node.components.splice(0, 0, component); - } else { - // place the new component after the insertAfterComponentId - - // boolean flag for whether we have added the component yet - let added = false; - - const components = node.components; - for (let c = 0; c < components.length; c++) { - const tempComponent = components[c]; - if ( - tempComponent != null && - tempComponent.id != null && - tempComponent.id == insertAfterComponentId - ) { - /* - * we have found the component we want to add the new - * one after - */ - - components.splice(c + 1, 0, component); - added = true; - break; - } - } - - if (!added) { - /* - * the component has not been added yet so we will just add - * it at the end - */ - node.components.push(component); - } - } - } - /** * Update the transitions so that the fromGroup points to the newToGroup * diff --git a/src/messages.xlf b/src/messages.xlf index 1f7c7e827d9..539dbe91252 100644 --- a/src/messages.xlf +++ b/src/messages.xlf @@ -9644,7 +9644,7 @@ Click "Cancel" to keep the invalid JSON open so you can fix it.New Step src/assets/wise5/authoringTool/addNode/add-your-own-node/add-your-own-node.component.ts - 46 + 47