working sample in IE

This commit is contained in:
petkir 2020-06-19 21:30:44 +02:00
parent dbfa9603a3
commit 28cee20809
8 changed files with 105 additions and 65 deletions

View File

@ -2,7 +2,7 @@ import { IKanbanBucket } from "./IKanbanBucket";
export interface IKanbanBoardTaskActions { export interface IKanbanBoardTaskActions {
toggleCompleted?: (taskId: number | string) => void; toggleCompleted?: (taskId: string) => void;
allowMove?: (taskId: number | string, prevBucket: IKanbanBucket, targetBucket: IKanbanBucket) => boolean; allowMove?: (taskId: string, prevBucket: IKanbanBucket, targetBucket: IKanbanBucket) => boolean;
moved?: (taskId: number | string, targetBucket: IKanbanBucket) => void; moved?: (taskId: string, targetBucket: IKanbanBucket) => void;
} }

View File

@ -1,5 +1,5 @@
export interface IKanbanTask { export interface IKanbanTask {
taskId: number | string; taskId: string;
title: string; title: string;
isCompleted?: boolean; isCompleted?: boolean;
bucket: string; bucket: string;

View File

@ -15,19 +15,19 @@ export interface IKanbanBucketProps extends IKanbanBucket {
tasksettings: IKanbanBoardTaskSettings; tasksettings: IKanbanBoardTaskSettings;
taskactions: IKanbanBoardTaskActions; taskactions: IKanbanBoardTaskActions;
onDragStart: (event, taskId: string | number, bucket: string) => void; onDragStart: (event, taskId: string, bucket: string) => void;
onDragOver: (event, targetbucket: string) => void; onDragOver: (event, targetbucket: string) => void;
onDragLeave: (event, targetbucket: string) => void; onDragLeave: (event, targetbucket: string) => void;
onDrop: (event, targetbucket: string) => void; onDrop: (event, targetbucket: string) => void;
onDragEnd: (event, taskId: string, bucket: string) => void;
leavingTaskId?: number | string; leavingTaskId?: string;
leavingBucket?: string; leavingBucket?: string;
overBucket?: string; overBucket?: string;
openDetails?: (taskId: number | string) => void; openDetails?: (taskId: string) => void;
} }
export interface IKanbanBucketState { } export interface IKanbanBucketState { }
@ -49,18 +49,21 @@ export default class KanbanBucket extends React.Component<IKanbanBucketProps, IK
hope this will be translated hope this will be translated
*/ */
public render(): React.ReactElement<IKanbanBucketProps> { public render(): React.ReactElement<IKanbanBucketProps> {
const { bucket, bucketheadline, color, buckettasks, const { bucket, bucketheadline, color, buckettasks,
tasksettings, taskactions, percentageComplete, tasksettings, taskactions, percentageComplete,
allowAddTask, overBucket,leavingTaskId,leavingBucket } = this.props; allowAddTask, overBucket, leavingTaskId, leavingBucket } = this.props;
return ( return (
<div className={classNames({[styles.bucket]: true, [styles.dragover]: (overBucket && overBucket === bucket)})} <div
key={bucket} className={classNames({ [styles.bucket]: true, [styles.dragover]: !!(overBucket && overBucket === bucket) })}
key={bucket}
onDragOver={(event) => this.props.onDragOver(event, bucket)} onDragOver={(event) => this.props.onDragOver(event, bucket)}
onDragLeave={(event) => this.props.onDragLeave(event, bucket)} onDragLeave={(event) => this.props.onDragLeave(event, bucket)}
onDrop={(event) => this.props.onDrop(event, bucket)} onDrop={(event) => this.props.onDrop(event, bucket)}
> >
<div className={styles.headline}> <div className={styles.headline}
>
<span>{bucketheadline}</span> <span>{bucketheadline}</span>
{color && <div style={{ backgroundColor: color }} className={styles.colorindicator}></div>} {color && <div style={{ backgroundColor: color }} className={styles.colorindicator}></div>}
<ProgressIndicator percentComplete={percentageComplete / 100} /> <ProgressIndicator percentComplete={percentageComplete / 100} />
@ -75,16 +78,16 @@ key={bucket}
{ {
buckettasks.map((t) => { buckettasks.map((t) => {
const merge = { ...t, ...tasksettings, ...taskactions }; const merge = { ...t, ...tasksettings, ...taskactions };
const isMoving= (t.taskId === leavingTaskId && t.bucket === leavingBucket); const isMoving = (t.taskId === leavingTaskId && t.bucket === leavingBucket);
return (<div className={isMoving&&styles.placeholder} > return (<div className={isMoving ? styles.placeholder : undefined} key={'' + t.taskId} >
<KanbanTask <KanbanTask
key={t.taskId} key={'task' + t.taskId}
{...merge} {...merge}
isMoving={isMoving} isMoving={isMoving}
openDetails={this.props.openDetails} openDetails={this.props.openDetails}
onDragStart={(event) => this.props.onDragStart(event, t.taskId, t.bucket)} onDragStart={(event) => this.props.onDragStart(event, t.taskId, t.bucket)}
onDragEnd={(event) => this.props.onDragEnd(event, t.taskId, t.bucket)}
/></div> /></div>
); );
}) })

View File

@ -14,6 +14,7 @@ import { IStackStyles, Stack } from 'office-ui-fabric-react/lib/Stack';
import { CommandBar } from 'office-ui-fabric-react/lib/CommandBar'; import { CommandBar } from 'office-ui-fabric-react/lib/CommandBar';
export interface IKanbanComponentProps { export interface IKanbanComponentProps {
@ -30,11 +31,11 @@ export interface IKanbanComponentProps {
} }
export interface IKanbanComponentState { export interface IKanbanComponentState {
leavingTaskId?: number | string; leavingTaskId?: string;
leavingBucket?: string; leavingBucket?: string;
overBucket?: string; overBucket?: string;
openDialog: boolean; openDialog: boolean;
openTaskId?: number | string; openTaskId?: string;
} }
export default class KanbanComponent extends React.Component<IKanbanComponentProps, IKanbanComponentState> { export default class KanbanComponent extends React.Component<IKanbanComponentProps, IKanbanComponentState> {
@ -48,6 +49,7 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
leavingBucket: null, leavingBucket: null,
overBucket: null overBucket: null
}; };
} }
public render(): React.ReactElement<IKanbanComponentProps> { public render(): React.ReactElement<IKanbanComponentProps> {
@ -78,7 +80,7 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
onDragLeave={this.onDragLeave.bind(this)} onDragLeave={this.onDragLeave.bind(this)}
onDragOver={this.onDragOver.bind(this)} onDragOver={this.onDragOver.bind(this)}
onDragStart={this.onDragStart.bind(this)} onDragStart={this.onDragStart.bind(this)}
onDragEnd={this.onDragEnd.bind(this)}
/>); />);
} }
@ -91,7 +93,6 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
} }
private renderDetails(): JSX.Element { private renderDetails(): JSX.Element {
debugger;
const renderer = this.props.renderers && this.props.renderers.taskDetail ? this.props.renderers.taskDetail : this.internalTaskDetailRenderer; const renderer = this.props.renderers && this.props.renderers.taskDetail ? this.props.renderers.taskDetail : this.internalTaskDetailRenderer;
const tasks = this.props.tasks.filter(t => t.taskId == this.state.openTaskId); const tasks = this.props.tasks.filter(t => t.taskId == this.state.openTaskId);
@ -151,7 +152,7 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
openTaskId: undefined openTaskId: undefined
}); });
} }
private openDialog(taskid: number | string) { private openDialog(taskid: string) {
this.setState({ this.setState({
openDialog: true, openDialog: true,
openTaskId: taskid openTaskId: taskid
@ -167,13 +168,21 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
} }
private onDragStart(event, taskId: string | number, bucket: string): void { private onDragEnd(event): void {
console.log('onDragStart'); console.log('onDragEnd');
const taskitem = this.props.tasks.filter(p => p.taskId == taskId); this.dragelement=undefined;
}
private onDragStart(event, taskId: string, bucket: string): void {
console.log('onDragStart');
const taskitem = this.props.tasks.filter(p => p.taskId === taskId);
console.log('onDragStart taskitem');
if (taskitem.length === 1) { if (taskitem.length === 1) {
event.dataTransfer.setData("taskId", taskId); console.log('onDragStart taskitem check done');
event.dataTransfer.setData("sourcebucket", bucket); console.log(event);
event.dataTransfer.setData("text", taskId);
//event.dataTransfer.setData("sourcebucket", bucket);
//set element because event.dataTransfer is empty by DragOver //set element because event.dataTransfer is empty by DragOver
console.log('set dragelement'); console.log('set dragelement');
this.dragelement = taskitem[0]; this.dragelement = taskitem[0];
@ -181,8 +190,12 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
leavingTaskId: taskId, leavingTaskId: taskId,
leavingBucket: bucket, leavingBucket: bucket,
}); });
console.log('dragelement set and refresh state');
} else { } else {
// Error not consitent // Error not consitent
console.log('onDragStart prop data wrong!!');
throw "TaskItem not found on DragStart";
} }
@ -190,8 +203,9 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
private onDragOver(event, targetbucket: string): void { private onDragOver(event, targetbucket: string): void {
event.preventDefault(); event.preventDefault();
console.log('onDragOver'); console.log('onDragOver this.dragelement');
console.log(event.dataTransfer.getData("sourcebucket")); console.log(this.dragelement);
if (this.dragelement.bucket !== targetbucket) { if (this.dragelement.bucket !== targetbucket) {
/* if (!this.bucketRef.current.classList.contains(styles.dragover)) { /* if (!this.bucketRef.current.classList.contains(styles.dragover)) {
this.bucketRef.current.classList.add(styles.dragover) this.bucketRef.current.classList.add(styles.dragover)
@ -203,15 +217,16 @@ export default class KanbanComponent extends React.Component<IKanbanComponentPro
} }
private onDrop(event, targetbucket: string): void { private onDrop(event, targetbucket: string): void {
console.log(`onDrop sourcebucket ${event.dataTransfer.getData("sourcebucket")} taskid: ${event.dataTransfer.getData("taskId")}`); console.log('onDrop');
/* if (this.bucketRef.current.classList.contains(styles.dragover)) { /* if (this.bucketRef.current.classList.contains(styles.dragover)) {
this.bucketRef.current.classList.remove(styles.dragover) this.bucketRef.current.classList.remove(styles.dragover)
}*/ }*/
if (event.dataTransfer.getData("sourcebucket") !== targetbucket) { if (this.dragelement.bucket !== targetbucket) {
const sourcebucket = event.dataTransfer.getData("sourcebucket"); //event.dataTransfer.getData("text");
const source = this.props.buckets.filter(s => s.bucket == sourcebucket)[0]; const taskId = this.dragelement.taskId;
const source = this.props.buckets.filter(s => s.bucket == this.dragelement.bucket)[0];
const target = this.props.buckets.filter(s => s.bucket == targetbucket)[0]; const target = this.props.buckets.filter(s => s.bucket == targetbucket)[0];
const taskId = event.dataTransfer.getData("taskId");
if (this.props.taskactions) { if (this.props.taskactions) {
let allowMove = true; let allowMove = true;
if (this.props.taskactions.allowMove) { if (this.props.taskactions.allowMove) {

View File

@ -2,18 +2,19 @@ import * as React from 'react';
import styles from './KanbanTask.module.scss'; import styles from './KanbanTask.module.scss';
import * as strings from 'KanbanBoardStrings'; import * as strings from 'KanbanBoardStrings';
import { IconButton } from 'office-ui-fabric-react/lib/Button'; import { IconButton } from 'office-ui-fabric-react/lib/Button';
import {IKanbanTask} from './IKanbanTask'; import { IKanbanTask } from './IKanbanTask';
import {IKanbanBoardTaskSettings} from './IKanbanBoardTaskSettings'; import { IKanbanBoardTaskSettings } from './IKanbanBoardTaskSettings';
import {IKanbanBoardTaskActions} from './IKanbanBoardTaskActions'; import { IKanbanBoardTaskActions } from './IKanbanBoardTaskActions';
import classNames from 'classnames'; import classNames from 'classnames';
import { IconNames } from 'office-ui-fabric-react'; import { IconNames } from 'office-ui-fabric-react';
export interface IKanbanTaskProps extends IKanbanTask,IKanbanBoardTaskSettings,IKanbanBoardTaskActions { export interface IKanbanTaskProps extends IKanbanTask, IKanbanBoardTaskSettings, IKanbanBoardTaskActions {
openDetails: (taskId: number | string) => void; openDetails: (taskId: string) => void;
onDragStart:(event) => void; onDragStart: (event) => void;
isMoving:boolean; onDragEnd: (event) => void;
isMoving: boolean;
} }
export interface IKanbanTaskState { } export interface IKanbanTaskState { }
@ -25,13 +26,14 @@ export default class KanbanTask extends React.Component<IKanbanTaskProps, IKanba
} }
public render(): React.ReactElement<IKanbanTaskProps> { public render(): React.ReactElement<IKanbanTaskProps> {
const { title, showLabels, showPriority, showAssignedTo, isCompleted,isMoving,showTaskDetailsButton } = this.props; const { title, showLabels, showPriority, showAssignedTo, isCompleted, isMoving, showTaskDetailsButton } = this.props;
const showCompleted = !!this.props.toggleCompleted; const showCompleted = !!this.props.toggleCompleted;
const iconCompleted = { iconName: isCompleted ? 'RadioBtnOn' : 'RadioBtnOff' }; const iconCompleted = { iconName: isCompleted ? 'RadioBtnOn' : 'RadioBtnOff' };
return ( return (
<div className={classNames({[styles.taskcard]: true, [styles.moving]: isMoving}) } <div className={classNames({ [styles.taskcard]: true, [styles.moving]: isMoving })}
onDragStart = {this.props.onDragStart} onDragStart={this.props.onDragStart}
draggable onDragEnd={this.props.onDragEnd}
draggable
> >
<div className={styles.titlerow}> <div className={styles.titlerow}>
{showCompleted && ( {showCompleted && (
@ -43,15 +45,15 @@ export default class KanbanTask extends React.Component<IKanbanTaskProps, IKanba
/>) />)
} }
<div className={styles.title}>{title}</div> <div className={styles.title}>{title}</div>
{ showTaskDetailsButton && ( {showTaskDetailsButton && (
<IconButton <IconButton
iconProps={{iconName:'More'}} iconProps={{ iconName: 'More' }}
title={strings.OpenDetails} title={strings.OpenDetails}
ariaLabel={strings.OpenDetails} ariaLabel={strings.OpenDetails}
onClick={this._openDetails.bind(this)} onClick={this._openDetails.bind(this)}
/>) />)
} }
</div> </div>
<div className={styles.membersAndLabels}> <div className={styles.membersAndLabels}>
{showAssignedTo && (<div className={styles.assignedto}></div>)} {showAssignedTo && (<div className={styles.assignedto}></div>)}
@ -68,13 +70,13 @@ export default class KanbanTask extends React.Component<IKanbanTaskProps, IKanba
} }
} }
private _openDetails():void { private _openDetails(): void {
debugger; debugger;
if(this.props.openDetails) { if (this.props.openDetails) {
this.props.openDetails(this.props.taskId); this.props.openDetails(this.props.taskId);
} }
} }
} }

View File

@ -26,7 +26,7 @@ export class MockKanban extends React.Component<IMockKanbanProps, IMockKanbanSta
], ],
tasks: [ tasks: [
{ {
taskId: 1, title: 'test1', bucket: 'Not Started', taskId: '1', title: 'test1', bucket: 'Not Started',
mamagedProperties: [ mamagedProperties: [
{ {
name: 'Prop1', name: 'Prop1',
@ -52,8 +52,8 @@ export class MockKanban extends React.Component<IMockKanbanProps, IMockKanbanSta
} }
] ]
}, },
{ taskId: 2, title: 'test2', bucket: 'Not Started' }, { taskId: '2', title: 'test2', bucket: 'Not Started' },
{ taskId: 3, title: 'test3', bucket: 'Not Started' }, { taskId: '3', title: 'test3', bucket: 'Not Started' },
{ taskId: '4', title: 'test 4', bucket: 'Test4' }, { taskId: '4', title: 'test 4', bucket: 'Test4' },
{ taskId: '5', title: 'test 5', bucket: 'Test3' }, { taskId: '5', title: 'test 5', bucket: 'Test3' },
@ -88,17 +88,17 @@ export class MockKanban extends React.Component<IMockKanbanProps, IMockKanbanSta
private _toggleCompleted(taskId: number | string): void { private _toggleCompleted(taskId: string): void {
//TODO //TODO
} }
private _allowMove(taskId: number | string, prevBucket: IKanbanBucket, targetBucket: IKanbanBucket): boolean { private _allowMove(taskId: string, prevBucket: IKanbanBucket, targetBucket: IKanbanBucket): boolean {
if (prevBucket.bucket === 'Test2' && targetBucket.bucket === 'Test3') { if (prevBucket.bucket === 'Test2' && targetBucket.bucket === 'Test3') {
return false; return false;
} }
return true; return true;
} }
private _moved(taskId: number | string, targetBucket: IKanbanBucket): void { private _moved(taskId: string, targetBucket: IKanbanBucket): void {
debugger; debugger;
const elementsIndex = findIndex(this.state.tasks, element => element.taskId == taskId); const elementsIndex = findIndex(this.state.tasks, element => element.taskId == taskId);
let newArray = [...this.state.tasks]; let newArray = [...this.state.tasks];

View File

@ -36,4 +36,22 @@ Something like this sould come out, but styling is currently bad
![prototype](./img1.PNG "prototype") ![prototype](./img1.PNG "prototype")
Something like this sould come out, but styling is currently bad Something like this sould come out, but styling is currently bad
![prototype](./sample.gif "prototype on 2nd day") ![prototype](./sample.gif "prototype on 2nd day")
IMPORTANT
```
IKanbanTask {
taskId: string;
}
```
has to be a string because, i use event ```event.dataTransfer.setData``` and this accespts only strings in IE
```
event.dataTransfer.setData('text',1)
Invalid argument.
```
The second big thing is IE allows only to set the value 'text' event.dataTransfer.setData('text','1')
```
event.dataTransfer.setData('xyz','1')
Unexpected call to method or property access.
```

View File

@ -47,6 +47,7 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
} }
); );
*/ */
const element: React.ReactElement<IMockKanbanProps > = React.createElement( const element: React.ReactElement<IMockKanbanProps > = React.createElement(
MockKanban, MockKanban,
{ {
@ -55,6 +56,7 @@ export default class KanbanBoardWebPart extends BaseClientSideWebPart<IKanbanBoa
); );
ReactDom.render(element, this.domElement); ReactDom.render(element, this.domElement);
} }
protected onDispose(): void { protected onDispose(): void {