-
Notifications
You must be signed in to change notification settings - Fork 76
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hc-drag-list): drag/drop component for making assignments
Drag/drop component for making assignments. Targets are on the left, options are on the right. re #2010
- Loading branch information
1 parent
60d5a51
commit 95cd2bd
Showing
9 changed files
with
631 additions
and
32 deletions.
There are no files selected for viewing
27 changes: 26 additions & 1 deletion
27
...ts/cashmere-examples/src/lib/drag-list-overview/drag-list-overview-example.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,26 @@ | ||
<hc-drag-list></hc-drag-list> | ||
<hc-drag-list | ||
[assignments]="assignments" | ||
[options]="options" | ||
targetDisplayNameField="name" | ||
targetHelperText="Targets" | ||
targetTooltip="Assign options to targets below. | ||
Example: | ||
Target 1 = Option 3 | ||
Target 2 = Option 1 | ||
Target 3 = Option 3 (locked)" | ||
optionsHelperText="Drag options to targets on the left" | ||
optionDisplayNameField="name" | ||
[requireAllAssignments]="false" | ||
></hc-drag-list> | ||
<div class="buttons"> | ||
<button hc-button buttonStyle="secondary" size="lg" (click)="dragList.resetChanges()">Reset Changes</button> | ||
<button | ||
hc-button | ||
buttonStyle="primary" | ||
size="lg" | ||
(click)="saveSelections(dragList.selections)" | ||
[disabled]="!(dragList || {}).submissionAllowed || false" | ||
> | ||
Save Selections | ||
</button> | ||
</div> |
9 changes: 9 additions & 0 deletions
9
...ts/cashmere-examples/src/lib/drag-list-overview/drag-list-overview-example.component.scss
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
.buttons { | ||
margin-top: 20px; | ||
display: flex; | ||
justify-content: flex-end; | ||
|
||
button:first-of-type { | ||
margin-right: 10px; | ||
} | ||
} |
37 changes: 35 additions & 2 deletions
37
...ects/cashmere-examples/src/lib/drag-list-overview/drag-list-overview-example.component.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,44 @@ | ||
import { Component } from '@angular/core'; | ||
import {Component, ViewChild} from '@angular/core'; | ||
import {DragDropAssignment, DragListComponent} from 'projects/cashmere/src/lib/drag-list/drag-list.component'; | ||
|
||
/** | ||
* @title Overview of Drag List functionality | ||
*/ | ||
@Component({ | ||
selector: 'hc-drag-list-overview-example', | ||
templateUrl: 'drag-list-overview-example.component.html' | ||
templateUrl: 'drag-list-overview-example.component.html', | ||
styleUrls: ['./drag-list-overview-example.component.scss'] | ||
}) | ||
export class DragListOverviewExampleComponent { | ||
@ViewChild(DragListComponent) dragList: DragListComponent; | ||
|
||
options: {id: number; name: string; title: string}[] = [ | ||
{id: 1, name: 'option 1', title: 'this is option 1'}, | ||
{id: 2, name: 'option 2', title: 'this is option 2'}, | ||
{id: 3, name: 'option 3', title: 'this is option 3'}, | ||
{id: 4, name: 'option 4', title: 'this is option 4'}, | ||
{id: 5, name: 'option 5', title: 'this is option 5'} | ||
]; | ||
assignments: DragDropAssignment[] = [ | ||
{ | ||
target: {id: 1, name: 'target 1', title: 'this is target 1'}, | ||
assignment: null, | ||
locked: false | ||
}, | ||
{ | ||
target: {id: 2, name: 'target 2', title: 'this is target 2'}, | ||
assignment: null, | ||
locked: false | ||
}, | ||
{ | ||
target: {id: 3, name: 'target 3', title: 'this is target 3'}, | ||
assignment: this.options[4], | ||
locked: true | ||
} | ||
]; | ||
|
||
saveSelections(selections: DragDropAssignment[]) { | ||
console.log('SELECTIONS', selections); | ||
window.alert('check console for received selections'); | ||
} | ||
} |
101 changes: 100 additions & 1 deletion
101
projects/cashmere/src/lib/drag-list/drag-list.component.html
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,102 @@ | ||
<div class="hc-drag-list-container"> | ||
<h1>Hello World!</h1> | ||
<div class="targets"> | ||
<div class="targets-info"> | ||
<span>{{ targetHelperText }}</span> | ||
<hc-icon | ||
*ngIf="!!targetTooltip" | ||
fontSet="fa" | ||
fontIcon="fa-info-circle" | ||
[hcPop]="productStandardLevelNamesPop" | ||
trigger="hover" | ||
></hc-icon> | ||
<hc-pop #productStandardLevelNamesPop> | ||
<div class="preserve-whitespace" style="white-space: pre">{{ targetTooltip }}</div> | ||
</hc-pop> | ||
</div> | ||
<div *ngFor="let assignment of modifiedAssignments" class="assignments"> | ||
<div class="target-name" [title]="assignment.target[targetHoverTextField] ?? ''"> | ||
<hc-icon | ||
fontSet="fa" | ||
fontIcon="fa-check" | ||
*ngIf="!assignment.locked" | ||
[style.visibility]="!!assignment.assignment ? 'visible' : 'hidden'" | ||
></hc-icon> | ||
<hc-icon fontSet="fa" fontIcon="fa-lock" [hcPop]="lockedText" trigger="hover" *ngIf="!!assignment.locked"></hc-icon> | ||
<hc-pop #lockedText>{{ optionLockedText }}</hc-pop> | ||
{{ assignment.target[targetDisplayNameField] }} | ||
</div> | ||
|
||
<div | ||
class="assignment placeholder" | ||
(dragenter)="dragenter($event)" | ||
(dragleave)="dragleave($event)" | ||
*ngIf="!assignment.assignment && !assignment.locked" | ||
[attr.data-target-id]="assignment.target[targetIdField]" | ||
(drop)="makeAssignment($event)" | ||
(dragover)="dragover($event)" | ||
> | ||
{{ targetPlaceholder }} | ||
</div> | ||
<div | ||
class="assignment" | ||
(dragenter)="dragenter($event)" | ||
(dragleave)="dragleave($event)" | ||
*ngIf="!!assignment.assignment && !assignment.locked" | ||
[attr.data-target-id]="assignment.target[targetIdField]" | ||
[attr.data-option-id]="assignment.assignment[optionIdField]" | ||
(drop)="makeAssignment($event)" | ||
(dragover)="dragover($event)" | ||
> | ||
<div | ||
class="option" | ||
[attr.data-target-id]="assignment.target[targetIdField]" | ||
[attr.data-option-id]="assignment.assignment[optionIdField]" | ||
[title]="tooltipsByOptionId[assignment.assignment[optionIdField]]" | ||
draggable="true" | ||
(dragstart)="dragstart($event)" | ||
> | ||
<div class="option-name"> | ||
{{ assignment.assignment[optionDisplayNameField] }} | ||
</div> | ||
<div class="option-close" (click)="unassign(assignment)"> | ||
<svg width="10" height="10" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg"> | ||
<path | ||
d="M1 7.03906L4 4.03906L7 7.03906M7 1.03906L3.99943 4.03906L1 1.03906" | ||
stroke="#C0C5CC" | ||
stroke-width="1.5" | ||
stroke-linecap="round" | ||
stroke-linejoin="round" | ||
/> | ||
</svg> | ||
</div> | ||
</div> | ||
</div> | ||
|
||
<div class="assignment" *ngIf="!!assignment.assignment && !!assignment.locked"> | ||
<div class="option option-locked" [title]="tooltipsByOptionId[assignment.assignment[optionIdField]]"> | ||
<div class="option-name"> | ||
{{ assignment.assignment[optionDisplayNameField] }} | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
<div class="options"> | ||
<div class="options-info">{{ optionsHelperText }}</div> | ||
<div class="options-container" (drop)="returnToOptionsList($event)" (dragover)="dragover($event)"> | ||
<div | ||
*ngFor="let option of unassignedOptions" | ||
class="option" | ||
[attr.data-option-id]="option[optionIdField]" | ||
[title]="tooltipsByOptionId[option[optionIdField]]" | ||
draggable="true" | ||
(dragstart)="dragstart($event)" | ||
> | ||
<div class="option-name"> | ||
{{ option[optionDisplayNameField] }} | ||
</div> | ||
<hc-icon fontSet="hc-icons" fontIcon="hci-grip"></hc-icon> | ||
</div> | ||
</div> | ||
</div> | ||
</div> |
79 changes: 58 additions & 21 deletions
79
projects/cashmere/src/lib/drag-list/drag-list.component.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,27 +1,64 @@ | ||
import { waitForAsync, ComponentFixture, TestBed } from '@angular/core/testing'; | ||
import { DragListModule } from './drag-list.module'; | ||
import { Component } from '@angular/core'; | ||
|
||
@Component({ | ||
template: ` | ||
<hc-drag-list></hc-drag-list> | ||
` | ||
}) | ||
export class DragListTestComponent { | ||
} | ||
import {ComponentFixture, TestBed} from '@angular/core/testing'; | ||
import {DragDropAssignment, DragListComponent} from './drag-list.component'; | ||
import {ElementRef} from '@angular/core'; | ||
|
||
describe('DragListTestComponent', () => { | ||
let formComponent: DragListTestComponent; | ||
let formFixture: ComponentFixture<DragListTestComponent>; | ||
let component: DragListComponent; | ||
let fixture: ComponentFixture<DragListComponent>; | ||
const el: ElementRef = new ElementRef({focus() { | ||
// do nothing. | ||
}}); | ||
let options: {id: number; name: string; title: string}[] = [ | ||
{id: 1, name: 'option 1', title: 'this is option 1'}, | ||
{id: 2, name: 'option 2', title: 'this is option 2'}, | ||
{id: 3, name: 'option 3', title: 'this is option 3'}, | ||
{id: 4, name: 'option 4', title: 'this is option 4'}, | ||
{id: 5, name: 'option 5', title: 'this is option 5'} | ||
]; | ||
let assignments: DragDropAssignment[] = [ | ||
{ | ||
target: {id: 1, name: 'target 1', title: 'this is target 1'}, | ||
assignment: null, | ||
locked: false | ||
}, | ||
{ | ||
target: {id: 2, name: 'target 2', title: 'this is target 2'}, | ||
assignment: null, | ||
locked: false | ||
}, | ||
{ | ||
target: {id: 3, name: 'target 3', title: 'this is target 3'}, | ||
assignment: options[4], | ||
locked: true | ||
} | ||
]; | ||
|
||
beforeEach(waitForAsync(() => { | ||
TestBed.configureTestingModule({ | ||
declarations: [DragListTestComponent], | ||
imports: [DragListModule] | ||
beforeEach(async done => { | ||
await TestBed.configureTestingModule({ | ||
declarations: [DragListComponent], | ||
providers: [{provide: ElementRef, useValue: el}] | ||
}).compileComponents(); | ||
fixture = TestBed.createComponent(DragListComponent); | ||
component = fixture.componentInstance; | ||
fixture.detectChanges(); | ||
await fixture.whenStable(); | ||
done(); | ||
}); | ||
it('should create the component without error', () => { | ||
expect(component).toBeTruthy(); | ||
}); | ||
it('submissionAllowed should be invalid if requireAllAssignments is true and there are unassigned targets', () => { | ||
component.assignments = assignments; | ||
component.options = options; | ||
component.requireAllAssignments = true; | ||
|
||
expect(component.submissionAllowed).toBeFalse(); | ||
}); | ||
it('submissionAllowed should be valid if requireAllAssignments is false and there are unassigned targets', () => { | ||
component.assignments = assignments; | ||
component.options = options; | ||
component.requireAllAssignments = false; | ||
|
||
formFixture = TestBed.createComponent(DragListTestComponent); | ||
formComponent = formFixture.componentInstance; | ||
formFixture.detectChanges(); | ||
})); | ||
expect(component.submissionAllowed).toBeTrue(); | ||
}); | ||
}); |
Oops, something went wrong.