kanbanworkflowstimelinescrumrubyroadmapproject-planningproject-managementopenprojectangularissue-trackerifcgantt-chartganttbug-trackerboardsbcf
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
174 lines
5.3 KiB
174 lines
5.3 KiB
import {WorkPackageResourceInterface} from "../../../api/api-v3/hal-resources/work-package-resource.service";
|
|
import {TimelineCellRenderer} from "./timeline-cell-renderer";
|
|
import {
|
|
RenderInfo,
|
|
calculatePositionValueForDayCount,
|
|
timelineElementCssClass,
|
|
calculatePositionValueForDayCountingPx, timelineMarkerSelectionStartClass
|
|
} from "../wp-timeline";
|
|
import * as moment from "moment";
|
|
import Moment = moment.Moment;
|
|
|
|
interface CellMilestoneMovement {
|
|
// Target value to move milestone to
|
|
date?: moment.Moment;
|
|
}
|
|
|
|
export class TimelineMilestoneCellRenderer extends TimelineCellRenderer {
|
|
|
|
public get type(): string {
|
|
return 'milestone';
|
|
}
|
|
|
|
public get fallbackColor(): string {
|
|
return '#C0392B';
|
|
}
|
|
|
|
public isEmpty(wp: WorkPackageResourceInterface) {
|
|
const date = moment(wp.date as any);
|
|
const noDateValue = _.isNaN(date.valueOf());
|
|
return noDateValue;
|
|
}
|
|
|
|
public displayPlaceholderUnderCursor(ev: MouseEvent, renderInfo: RenderInfo): HTMLElement {
|
|
const days = Math.floor(ev.offsetX / renderInfo.viewParams.pixelPerDay);
|
|
|
|
const placeholder = document.createElement("div");
|
|
placeholder.className = "timeline-element milestone";
|
|
placeholder.style.pointerEvents = "none";
|
|
placeholder.style.height = "1em";
|
|
placeholder.style.width = "1em";
|
|
placeholder.style.left = (days * renderInfo.viewParams.pixelPerDay) + "px";
|
|
|
|
const diamond = document.createElement("div");
|
|
diamond.className = "diamond";
|
|
diamond.style.backgroundColor = "#DDDDDD";
|
|
diamond.style.left = "0.5em";
|
|
diamond.style.height = "1em";
|
|
diamond.style.width = "1em";
|
|
placeholder.appendChild(diamond);
|
|
|
|
return placeholder;
|
|
}
|
|
|
|
/**
|
|
* Assign changed dates to the work package.
|
|
* For generic work packages, assigns start and due date.
|
|
*
|
|
*/
|
|
public assignDateValues(wp: WorkPackageResourceInterface, dates: CellMilestoneMovement) {
|
|
this.assignDate(wp, 'date', dates.date!);
|
|
|
|
this.updateMilestoneMovedLabel(dates.date!);
|
|
}
|
|
|
|
/**
|
|
* Restore the original date, if any was set.
|
|
*/
|
|
public onCancel(wp: WorkPackageResourceInterface) {
|
|
wp.restoreFromPristine('date');
|
|
}
|
|
|
|
/**
|
|
* Handle movement by <delta> days of milestone.
|
|
*/
|
|
public onDaysMoved(wp: WorkPackageResourceInterface,
|
|
dayUnderCursor: Moment,
|
|
delta: number,
|
|
direction: "left" | "right" | "both" | "create" | "dragright") {
|
|
|
|
const initialDate = wp.$pristine['date'];
|
|
let dates: CellMilestoneMovement = {};
|
|
|
|
if (initialDate) {
|
|
dates.date = moment(initialDate).add(delta, "days");
|
|
}
|
|
|
|
return dates;
|
|
}
|
|
|
|
public onMouseDown(ev: MouseEvent,
|
|
dateForCreate: string|null,
|
|
renderInfo: RenderInfo,
|
|
elem: HTMLElement): "left" | "right" | "both" | "create" | "dragright" {
|
|
|
|
let direction: "left" | "right" | "both" | "create" | "dragright" = "both";
|
|
renderInfo.workPackage.storePristine('date');
|
|
this.forceCursor('ew-resize');
|
|
|
|
if (dateForCreate) {
|
|
renderInfo.workPackage.date = dateForCreate;
|
|
direction = "create";
|
|
return direction;
|
|
}
|
|
|
|
// create date label
|
|
const dateInfo = document.createElement("div");
|
|
dateInfo.className = "rightDateDisplay";
|
|
this.dateDisplaysOnMouseMove.right = dateInfo;
|
|
elem.appendChild(dateInfo);
|
|
|
|
this.updateMilestoneMovedLabel(moment(renderInfo.workPackage.date));
|
|
|
|
return direction;
|
|
}
|
|
|
|
public update(timelineCell: HTMLElement, element: HTMLDivElement, renderInfo: RenderInfo): boolean {
|
|
const wp = renderInfo.workPackage;
|
|
const viewParams = renderInfo.viewParams;
|
|
const date = moment(wp.date as any);
|
|
|
|
// abort if no start or due date
|
|
if (!wp.date) {
|
|
return false;
|
|
}
|
|
|
|
const diamond = jQuery(".diamond", element)[0];
|
|
|
|
element.style.marginLeft = viewParams.scrollOffsetInPx + "px";
|
|
element.style.width = '1em';
|
|
element.style.height = '1em';
|
|
diamond.style.width = '1em';
|
|
diamond.style.height = '1em';
|
|
diamond.style.backgroundColor = this.typeColor(wp);
|
|
|
|
// offset left
|
|
const offsetStart = date.diff(viewParams.dateDisplayStart, "days");
|
|
element.style.left = 'calc(0.5em + ' + calculatePositionValueForDayCount(viewParams, offsetStart) + ')';
|
|
|
|
this.checkForActiveSelectionMode(renderInfo, diamond);
|
|
|
|
return true;
|
|
}
|
|
|
|
getLeftmostPosition(renderInfo: RenderInfo): number {
|
|
const wp = renderInfo.workPackage;
|
|
let start = moment(wp.date as any);
|
|
const offsetStart = start.diff(renderInfo.viewParams.dateDisplayStart, "days");
|
|
return calculatePositionValueForDayCountingPx(renderInfo.viewParams, offsetStart) + 20;
|
|
}
|
|
|
|
getRightmostPosition(renderInfo: RenderInfo): number {
|
|
return this.getLeftmostPosition(renderInfo);
|
|
}
|
|
|
|
/**
|
|
* Render a milestone element, a single day event with no resize, but
|
|
* move functionality.
|
|
*/
|
|
public render(renderInfo: RenderInfo): HTMLDivElement {
|
|
const element = document.createElement("div");
|
|
element.className = timelineElementCssClass + " " + this.type;
|
|
|
|
const diamond = document.createElement("div");
|
|
diamond.className = "diamond";
|
|
element.appendChild(diamond);
|
|
|
|
return element;
|
|
}
|
|
|
|
private updateMilestoneMovedLabel(date: Moment) {
|
|
this.dateDisplaysOnMouseMove.right!.innerText = date.format("L");
|
|
}
|
|
|
|
}
|
|
|