Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(NodeAuthoring): Toggle Edit/Preview component #1994

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
de4675d
Toggle Edit/Preview component working.
hirokiterashima Nov 18, 2024
5bd282a
feat(OutsideClickDirective): add directive to handle outside click ev…
hirokiterashima Nov 18, 2024
93e7c5e
feat(component-authoring): add hover effect and cursor style to previ…
hirokiterashima Nov 18, 2024
8c2753f
feat(node-authoring): enhance drag-and-drop functionality with placeh…
hirokiterashima Nov 18, 2024
627f5f4
feat(node-authoring): expand all components when a step is opened for…
hirokiterashima Nov 19, 2024
7446dd3
feat(authoring-tool): remove preview component button and related files
hirokiterashima Nov 19, 2024
acde96d
feat(node-authoring): conditionally render edit component button base…
hirokiterashima Nov 19, 2024
31f3f91
feat(component-authoring): disable preview components
hirokiterashima Nov 19, 2024
aa7d3b0
Merge branch 'develop' into node-authoring-ui-changes-toggle-edit-pre…
hirokiterashima Nov 19, 2024
4f080aa
Merge branch 'develop' into node-authoring-ui-changes-toggle-edit-pre…
hirokiterashima Nov 20, 2024
28cea81
feat(node-authoring): enhance drag-and-drop functionality
hirokiterashima Nov 21, 2024
e880fe4
Merge branch 'develop' into node-authoring-ui-changes-toggle-edit-pre…
hirokiterashima Nov 23, 2024
c279cd6
feat(DrawingTool): show canvasOnly view when in preview and showStude…
hirokiterashima Nov 25, 2024
e0feb74
render assets in preview component by injecting asset paths.
hirokiterashima Nov 25, 2024
90db6a8
Don't emit outsideClick event if a dialog is opened. This fixes issue…
hirokiterashima Nov 25, 2024
f8f363d
feat(AddComponentButton): Add option to add component before/after fo…
hirokiterashima Nov 25, 2024
6ab754a
feat(AddComponentButton): Update tooltip text if there is no componen…
hirokiterashima Nov 25, 2024
7ae8810
Merge branch 'develop' into node-authoring-ui-changes-toggle-edit-pre…
hirokiterashima Nov 26, 2024
f9d9827
Merge branch 'develop' into node-authoring-ui-changes-toggle-edit-pre…
hirokiterashima Dec 3, 2024
5d6a849
fix(node-authoring): Support scrolling while draggingcomponents
breity Dec 10, 2024
c897fc6
feat(component-authoring): Update styles, layout, and drag/drop
breity Dec 11, 2024
dc24a18
feat(component-authoring): focus on component editing component when …
breity Dec 11, 2024
2ac1737
Remove test that is no longer applicable
breity Dec 11, 2024
97946bf
feat(node-authoring): Remove checkboxes and bulk actions, expand/coll…
breity Dec 12, 2024
7da2fd5
feat(node-authoring): Add move up and move down buttons for each comp…
breity Dec 12, 2024
106b49a
refactor(temporarilyHighlightElement): Remove jQuery usage and utiliz…
breity Dec 12, 2024
2029ea2
Remove use of mat-expansion-panel for components
breity Dec 14, 2024
7795a41
fix(node-authoring): Re-enable TinyMCE menu clicks for HTML component…
breity Dec 14, 2024
338281e
Fix tests
breity Dec 14, 2024
a4d6988
Merge branch 'develop' into node-authoring-ui-changes-toggle-edit-pre…
hirokiterashima Dec 16, 2024
ec8e9af
test(edit-component): add focus test for host element after timeout
hirokiterashima Dec 16, 2024
c06a79e
refactor(node-authoring): simplify component deletion confirmation
hirokiterashima Dec 16, 2024
83df929
refactor(Node Authoring): Clean up tests
hirokiterashima Dec 16, 2024
05bba50
fix(Node Authoring): reset editingComponentId to null on initialization
hirokiterashima Dec 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/app/student-teacher-common.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { MathModule } from './math/math.module';
import { MatMenuModule } from '@angular/material/menu';
import { MainMenuComponent } from '../assets/wise5/common/main-menu/main-menu.component';
import { SideMenuComponent } from '../assets/wise5/common/side-menu/side-menu.component';
import { ScrollingModule } from '@angular/cdk/scrolling';

@NgModule({
declarations: [
Expand Down Expand Up @@ -82,6 +83,7 @@ import { SideMenuComponent } from '../assets/wise5/common/side-menu/side-menu.co
NodeStatusIconComponent,
NotebookModule,
ReactiveFormsModule,
ScrollingModule,
StudentTeacherCommonServicesModule
],
exports: [
Expand Down
5 changes: 0 additions & 5 deletions src/app/teacher/authoring-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import { ProjectAuthoringComponent } from '../../assets/wise5/authoringTool/proj
import { NodeAuthoringComponent } from '../../assets/wise5/authoringTool/node/node-authoring/node-authoring.component';
import { NodeAdvancedAuthoringComponent } from '../../assets/wise5/authoringTool/node/advanced/node-advanced-authoring/node-advanced-authoring.component';
import { NodeAdvancedConstraintAuthoringComponent } from '../../assets/wise5/authoringTool/node/advanced/constraint/node-advanced-constraint-authoring.component';
import { ChooseComponentLocationComponent } from '../../assets/wise5/authoringTool/node/chooseComponentLocation/choose-component-location.component';
import { AddLessonConfigureComponent } from '../../assets/wise5/authoringTool/addLesson/add-lesson-configure/add-lesson-configure.component';
import { ChooseNewNodeTemplateComponent } from '../../assets/wise5/authoringTool/addNode/choose-new-node-template/choose-new-node-template.component';
import { AddYourOwnNodeComponent } from '../../assets/wise5/authoringTool/addNode/add-your-own-node/add-your-own-node.component';
Expand Down Expand Up @@ -153,10 +152,6 @@ const routes: Routes = [
{ path: 'rubric', component: EditNodeRubricComponent }
]
},
{
path: 'choose-component-location',
component: ChooseComponentLocationComponent
},
{
path: 'import-component',
children: [{ path: 'choose-component', component: ChooseImportComponentComponent }]
Expand Down
4 changes: 0 additions & 4 deletions src/app/teacher/authoring-tool.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { WiseTinymceEditorModule } from '../../assets/wise5/directives/wise-tiny
import { NotebookAuthoringComponent } from '../../assets/wise5/authoringTool/notebook-authoring/notebook-authoring.component';
import { StructureAuthoringModule } from '../../assets/wise5/authoringTool/structure/structure-authoring.module';
import { MilestonesAuthoringComponent } from '../../assets/wise5/authoringTool/milestones-authoring/milestones-authoring.component';
import { ChooseComponentLocationComponent } from '../../assets/wise5/authoringTool/node/chooseComponentLocation/choose-component-location.component';
import { TopBarComponent } from '../../assets/wise5/authoringTool/components/top-bar/top-bar.component';
import { ProjectAssetAuthoringModule } from '../../assets/wise5/authoringTool/project-asset-authoring/project-asset-authoring.module';
import { ChooseSimulationComponent } from '../../assets/wise5/authoringTool/addNode/choose-simulation/choose-simulation.component';
Expand Down Expand Up @@ -57,7 +56,6 @@ import { TranslatableTextareaComponent } from '../../assets/wise5/authoringTool/
import { TranslatableRichTextEditorComponent } from '../../assets/wise5/authoringTool/components/translatable-rich-text-editor/translatable-rich-text-editor.component';
import { AddStepButtonComponent } from '../../assets/wise5/authoringTool/add-step-button/add-step-button.component';
import { CreateBranchComponent } from '../../assets/wise5/authoringTool/create-branch/create-branch.component';
import { PreviewComponentButtonComponent } from '../../assets/wise5/authoringTool/components/preview-component-button/preview-component-button.component';
import { EditBranchComponent } from '../../assets/wise5/authoringTool/edit-branch/edit-branch.component';
import { ComponentTypeButtonComponent } from '../../assets/wise5/authoringTool/components/component-type-button/component-type-button.component';
import { MatExpansionModule } from '@angular/material/expansion';
Expand Down Expand Up @@ -92,7 +90,6 @@ import { MatExpansionModule } from '@angular/material/expansion';
AddYourOwnNodeComponent,
AuthoringToolBarComponent,
ChooseAutomatedAssessmentComponent,
ChooseComponentLocationComponent,
ChooseCopyNodeLocationComponent,
ChooseImportStepComponent,
ChooseImportUnitComponent,
Expand All @@ -116,7 +113,6 @@ import { MatExpansionModule } from '@angular/material/expansion';
NodeAdvancedAuthoringModule,
NodeIconAndTitleComponent,
NodeWithMoveAfterButtonComponent,
PreviewComponentButtonComponent,
ProjectAssetAuthoringModule,
ProjectListComponent,
RouterModule,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
class="l-main"
[ngClass]="{ 'l-main--with-toolbar': showToolbar }"
role="main"
cdkScrollable
>
<router-outlet></router-outlet>
</content>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,45 +1,65 @@
import {
ApplicationRef,
Component,
ComponentRef,
ElementRef,
EnvironmentInjector,
Input,
ViewChild,
createComponent
} from '@angular/core';
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { ComponentContent } from '../../common/ComponentContent';
import { components } from '../../components/Components';
import { PreviewComponentComponent } from './preview-component/preview-component.component';
import { EditComponentComponent } from './edit-component/edit-component.component';
import { ComponentFactory } from '../../common/ComponentFactory';
import { Component as WISEComponent } from '../../common/Component';
import { TeacherProjectService } from '../../services/teacherProjectService';
import { MatTooltipModule } from '@angular/material/tooltip';

@Component({
imports: [PreviewComponentComponent, EditComponentComponent, MatTooltipModule],
selector: 'component-authoring',
standalone: true,
template: '<div #component></div>'
styles: [
`
preview-component {
display: block;
position: relative;
cursor: pointer;
}
preview-component:hover {
outline: 3px dashed #aaaaaa;
outline-offset: 8px;
}
preview-component:after {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
`
],
template: `@if (editing) {
<edit-component [componentContent]="componentContent" [nodeId]="nodeId" />
} @else {
<preview-component
role="button"
tabindex="0"
(click)="editComponentEvent.emit()"
(keyup.enter)="editComponentEvent.emit()"
[component]="component"
[disabled]="true"
matTooltip="Edit content"
i18n-matTooltip
/>
}`
})
export class ComponentAuthoringComponent {
@Input() private componentContent: ComponentContent;
@ViewChild('component') private componentElementRef: ElementRef;
private componentRef: ComponentRef<any>;
@Input() private nodeId: string;
protected component: WISEComponent;
@Input() componentContent: ComponentContent;
@Input() editing: boolean;
@Output() editComponentEvent: EventEmitter<void> = new EventEmitter<void>();
@Input() nodeId: string;

constructor(
private applicationRef: ApplicationRef,
private injector: EnvironmentInjector
) {}
constructor(private projectService: TeacherProjectService) {}

ngAfterViewInit(): void {
this.componentRef = createComponent(components[this.componentContent.type].authoring, {
hostElement: this.componentElementRef.nativeElement,
environmentInjector: this.injector
});
Object.assign(this.componentRef.instance, {
componentContent: this.componentContent,
nodeId: this.nodeId
});
this.applicationRef.attachView(this.componentRef.hostView);
}

ngOnDestroy(): void {
this.componentRef.destroy();
ngOnChanges(): void {
this.component = new ComponentFactory().getComponent(
this.projectService.injectAssetPaths(this.componentContent),
this.nodeId
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { EditComponentComponent } from './edit-component.component';
import { Component } from '@angular/core';
import { components } from '../../../components/Components';
import { ComponentContent } from '../../../common/ComponentContent';

@Component({
selector: 'mock-authoring',
template: '<div>Mock Authoring Component</div>'
})
class MockAuthoringComponent {
componentContent: any;
nodeId: string;
}

describe('EditComponentComponent', () => {
let component: EditComponentComponent;
let fixture: ComponentFixture<EditComponentComponent>;
const mockComponentContent = {
type: 'mockComponent'
};
const mockNodeId = 'node1';

beforeEach(async () => {
components['mockComponent'] = {
authoring: MockAuthoringComponent
};

await TestBed.configureTestingModule({
imports: [EditComponentComponent]
}).compileComponents();

fixture = TestBed.createComponent(EditComponentComponent);
component = fixture.componentInstance;
component.componentContent = mockComponentContent as ComponentContent;
component.nodeId = mockNodeId;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});

it('should create the dynamic component after view init', () => {
component.ngAfterViewInit();
fixture.detectChanges();
const componentElement = fixture.nativeElement.querySelector('div');
expect(componentElement.textContent).toContain('Mock Authoring Component');
});

it('should pass inputs to the dynamic component', () => {
component.ngAfterViewInit();
fixture.detectChanges();
const componentInstance = (component as any).componentRef.instance;
expect(componentInstance.componentContent).toBe(mockComponentContent);
expect(componentInstance.nodeId).toBe(mockNodeId);
});

it('should destroy the component reference on destroy', () => {
component.ngAfterViewInit();
const destroySpy = spyOn((component as any).componentRef, 'destroy');
component.ngOnDestroy();
expect(destroySpy).toHaveBeenCalled();
});

it('should focus the host element after timeout', (done) => {
component.ngAfterViewInit();
fixture.detectChanges();
setTimeout(() => {
const hostElement = fixture.nativeElement.querySelector('div');
expect(document.activeElement).toBe(hostElement);
done();
}, 0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {
ApplicationRef,
Component,
ComponentRef,
ElementRef,
EnvironmentInjector,
Input,
ViewChild,
createComponent
} from '@angular/core';
import { ComponentContent } from '../../../common/ComponentContent';
import { components } from '../../../components/Components';

@Component({
selector: 'edit-component',
standalone: true,
template: '<div #component tabindex="-1"></div>'
})
export class EditComponentComponent {
@Input() componentContent: ComponentContent;
@ViewChild('component') private componentElementRef: ElementRef;
private componentRef: ComponentRef<any>;
@Input() nodeId: string;

constructor(
private applicationRef: ApplicationRef,
private injector: EnvironmentInjector
) {}

ngAfterViewInit(): void {
const hostElement = this.componentElementRef.nativeElement;
this.componentRef = createComponent(components[this.componentContent.type].authoring, {
hostElement: hostElement,
environmentInjector: this.injector
});
Object.assign(this.componentRef.instance, {
componentContent: this.componentContent,
nodeId: this.nodeId
});
this.applicationRef.attachView(this.componentRef.hostView);
setTimeout(() => hostElement.focus());
}

ngOnDestroy(): void {
this.componentRef.destroy();
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,20 @@ import { components } from '../../../components/Components';
@Component({
selector: 'preview-component',
standalone: true,
template: '<div class="component__wrapper"><div #component></div></div>'
template: '<div #component></div>'
})
export class PreviewComponentComponent {
@Input() protected component: WISEComponent;
@Input() component: WISEComponent;
@ViewChild('component') private componentElementRef: ElementRef;
private componentRef: ComponentRef<WISEComponent>;
@Input() protected periodId: number;
@Output() private starterStateChangedEvent: EventEmitter<any> = new EventEmitter<any>();
@Input() disabled: boolean;
@Input() periodId: number;
@Output() starterStateChangedEvent: EventEmitter<any> = new EventEmitter<any>();

constructor(private applicationRef: ApplicationRef, private injector: EnvironmentInjector) {}
constructor(
private applicationRef: ApplicationRef,
private injector: EnvironmentInjector
) {}

ngAfterViewInit(): void {
this.renderComponent();
Expand All @@ -50,6 +54,7 @@ export class PreviewComponentComponent {
component: this.component,
mode: 'preview',
periodId: this.periodId,
isDisabled: this.disabled,
starterStateChangedEvent: this.starterStateChangedEvent
});
this.applicationRef.attachView(this.componentRef.hostView);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
<div class="warn">
<b>{{ message }}</b>
</div>
@if (message) {
<div class="concurrent-authors">
<b class="warn">{{ message }}</b>
</div>
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,6 @@ describe('ConcurrentAuthorsMessageComponent', () => {

function ngOnInit() {
describe('ngOnInit()', () => {
it('set empty message when there are no other authors', () => {
expectMessage('["aa"]', '');
});
it('set message to author when there is one other author', () => {
expectMessage(
'["aa","bb"]',
Expand Down
Loading
Loading