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?: string;
leavingTaskId?: number | string;
leavingBucket?: string; leavingBucket?: string;
overBucket?: string; overBucket?: string;
openDetails?: (taskId: number | string) => void; openDetails?: (taskId: string) => void;
} }
export interface IKanbanBucketState { } export interface IKanbanBucketState { }
@ -51,16 +51,19 @@ export default class KanbanBucket extends React.Component<IKanbanBucketProps, IK
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,9 +45,9 @@ 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)}
@ -68,9 +70,9 @@ 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

@ -37,3 +37,21 @@ Something like this sould come out, but styling is currently bad
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 {