|
@@ -11,7 +11,7 @@ import { styleMap } from 'lit-html/directives/style-map';
|
|
|
import syncronizeElementsScrolling from './utils/syncroScroll';
|
|
import syncronizeElementsScrolling from './utils/syncroScroll';
|
|
|
import Selectable from './utils/selectable';
|
|
import Selectable from './utils/selectable';
|
|
|
|
|
|
|
|
-import { TimelineStyle } from './styles/TimelineStyle';
|
|
|
|
|
|
|
+import { TimelineStyle } from './styles/Timeline.style';
|
|
|
|
|
|
|
|
interface TimelineOptions {
|
|
interface TimelineOptions {
|
|
|
ressources?: Array<IRessource>
|
|
ressources?: Array<IRessource>
|
|
@@ -39,7 +39,6 @@ interface legendItem {
|
|
|
// TODO add selectable Slot
|
|
// TODO add selectable Slot
|
|
|
// TODO enable to rearrange between different component.
|
|
// TODO enable to rearrange between different component.
|
|
|
|
|
|
|
|
-
|
|
|
|
|
@customElement('jc-timeline')
|
|
@customElement('jc-timeline')
|
|
|
class Timeline extends LitElement {
|
|
class Timeline extends LitElement {
|
|
|
static styles = [TimelineStyle]
|
|
static styles = [TimelineStyle]
|
|
@@ -139,28 +138,38 @@ class Timeline extends LitElement {
|
|
|
this.legendUnitFormat[unit] = format;
|
|
this.legendUnitFormat[unit] = format;
|
|
|
this.updateLegend()
|
|
this.updateLegend()
|
|
|
}
|
|
}
|
|
|
- addRessources(list:Array<IRessource>):Array<Ressource | undefined>{
|
|
|
|
|
|
|
+ addRessources(list:Array<IRessource>):Array<Ressource>{
|
|
|
return list.map(r=>this.addRessource(r));
|
|
return list.map(r=>this.addRessource(r));
|
|
|
}
|
|
}
|
|
|
// Ressource management
|
|
// Ressource management
|
|
|
- addRessource(ressource: IRessource): Ressource | undefined {
|
|
|
|
|
- if (this.rows.filter(o => o.id == ressource.id).length > 0) {
|
|
|
|
|
- return
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Add the ressource the the timeline or return the existing ressource with the same id
|
|
|
|
|
+ * @param ressource
|
|
|
|
|
+ * @returns
|
|
|
|
|
+ */
|
|
|
|
|
+ addRessource(ressource: IRessource): Ressource {
|
|
|
|
|
+ const existingRessource = this.getRessourceFromId(ressource.id)
|
|
|
|
|
+ if (existingRessource) {
|
|
|
|
|
+ return existingRessource
|
|
|
}
|
|
}
|
|
|
const r = Ressource.toRessource(ressource)
|
|
const r = Ressource.toRessource(ressource)
|
|
|
|
|
|
|
|
if (r.parent !== undefined) {
|
|
if (r.parent !== undefined) {
|
|
|
- const idx = this.rows.indexOf(r.parent)
|
|
|
|
|
|
|
+ r.parent = this.getRessourceFromId(r.parent.id) ?? this.addRessource(r.parent);
|
|
|
|
|
+ const idx = this.rows.indexOf(r.parent as Ressource)
|
|
|
if (idx > -1) {
|
|
if (idx > -1) {
|
|
|
this.rows[idx].children.push(r);
|
|
this.rows[idx].children.push(r);
|
|
|
this.rows.splice(idx + 1, 0, r);
|
|
this.rows.splice(idx + 1, 0, r);
|
|
|
} else {
|
|
} else {
|
|
|
- return
|
|
|
|
|
|
|
+ throw new Error("Not able to create ressource parent.\n" + r.id)
|
|
|
}
|
|
}
|
|
|
} else {
|
|
} else {
|
|
|
this.rows = [...this.rows, r]
|
|
this.rows = [...this.rows, r]
|
|
|
}
|
|
}
|
|
|
- this.updateTimeslotPosition(r)
|
|
|
|
|
|
|
+
|
|
|
|
|
+ this.addRessources(r.children);
|
|
|
|
|
+
|
|
|
|
|
+ this._updateEventPosition(r)
|
|
|
return r;
|
|
return r;
|
|
|
}
|
|
}
|
|
|
removeRessourceById(id: string): TimelineContent {
|
|
removeRessourceById(id: string): TimelineContent {
|
|
@@ -203,41 +212,51 @@ class Timeline extends LitElement {
|
|
|
setRowsTitle(title: string):void {
|
|
setRowsTitle(title: string):void {
|
|
|
this.rowsTitle = title;
|
|
this.rowsTitle = title;
|
|
|
}
|
|
}
|
|
|
- addTimeSlots(list:Array<IEvent>):Array<Event | undefined>{
|
|
|
|
|
- return list.map((e)=>this.addTimeSlot(e));
|
|
|
|
|
|
|
+ getEventById(id:string):Event | undefined{
|
|
|
|
|
+ return this.items.find(o=>o.id==id);
|
|
|
|
|
+ }
|
|
|
|
|
+ addEvents(list:Array<IEvent>):Array<Event | undefined>{
|
|
|
|
|
+ return list.map((e)=>this.addEvent(e));
|
|
|
}
|
|
}
|
|
|
// TimeSlot management
|
|
// TimeSlot management
|
|
|
- addTimeSlot(slot: IEvent): Event | undefined {
|
|
|
|
|
- if (this.items.filter(o => o.id == slot.id).length > 0) {
|
|
|
|
|
- return undefined
|
|
|
|
|
|
|
+ /**
|
|
|
|
|
+ * Add the event the the timeline or return the existing event with the same id
|
|
|
|
|
+ * return undefined if the event ressource is not defined in the timeline
|
|
|
|
|
+ * @param event
|
|
|
|
|
+ * @returns
|
|
|
|
|
+ */
|
|
|
|
|
+ addEvent(event: IEvent): Event | undefined {
|
|
|
|
|
+ const existingEvent = this.getEventById(event.id)
|
|
|
|
|
+ if (existingEvent) {
|
|
|
|
|
+ return existingEvent
|
|
|
}
|
|
}
|
|
|
- const ressource = this.rows.find(r => r.id === slot.ressourceId);
|
|
|
|
|
|
|
+ const ressource = this.rows.find(r => r.id === event.ressourceId);
|
|
|
if (ressource === undefined) {
|
|
if (ressource === undefined) {
|
|
|
return undefined
|
|
return undefined
|
|
|
}
|
|
}
|
|
|
- const timeslot = Event.toTimeSlot(slot);
|
|
|
|
|
|
|
+ const timeslot = Event.toTimeSlot(event);
|
|
|
this.items = [...this.items, timeslot]
|
|
this.items = [...this.items, timeslot]
|
|
|
// Update timeslot status
|
|
// Update timeslot status
|
|
|
timeslot.isDisplayed = timeslot.end > this._start.toDate() || timeslot.start < this._end.toDate();
|
|
timeslot.isDisplayed = timeslot.end > this._start.toDate() || timeslot.start < this._end.toDate();
|
|
|
- this.updateTimeslotPosition(ressource)
|
|
|
|
|
|
|
+ this._updateEventPosition(ressource)
|
|
|
return timeslot;
|
|
return timeslot;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- removeTimeslotById(id: string): Array<Event> {
|
|
|
|
|
|
|
+ removeEventById(id: string): Array<Event> {
|
|
|
const output = this.items.filter(o => o.id === id);
|
|
const output = this.items.filter(o => o.id === id);
|
|
|
this.items = this.items.filter(o => o.id !== id);
|
|
this.items = this.items.filter(o => o.id !== id);
|
|
|
return output
|
|
return output
|
|
|
}
|
|
}
|
|
|
- updateTimeslotById(id: string): Event | null {
|
|
|
|
|
- const output = this.removeTimeslotById(id)
|
|
|
|
|
|
|
+ updateEventById(id: string): Event | null {
|
|
|
|
|
+ const output = this.removeEventById(id)
|
|
|
if (output.length > 0) {
|
|
if (output.length > 0) {
|
|
|
- this.addTimeSlot(output[0])
|
|
|
|
|
|
|
+ this.addEvent(output[0])
|
|
|
return output[0];
|
|
return output[0];
|
|
|
} else {
|
|
} else {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
- private updateTimeslotPosition(ressource: Ressource): void {
|
|
|
|
|
|
|
+ private _updateEventPosition(ressource: Ressource): void {
|
|
|
const timeslots = this.items.filter(i => i.ressourceId === ressource.id);
|
|
const timeslots = this.items.filter(i => i.ressourceId === ressource.id);
|
|
|
if (timeslots.length === 0) {
|
|
if (timeslots.length === 0) {
|
|
|
ressource.height = this.rowHeight + (ressource.collapseChildren ? 5:0);
|
|
ressource.height = this.rowHeight + (ressource.collapseChildren ? 5:0);
|
|
@@ -301,7 +320,7 @@ class Timeline extends LitElement {
|
|
|
|
|
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
- getTimeSlots(): Array<Event> {
|
|
|
|
|
|
|
+ getEvents(): Array<Event> {
|
|
|
return this.items;
|
|
return this.items;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -379,7 +398,7 @@ class Timeline extends LitElement {
|
|
|
const newDate = dayjs(startDate).add(Math.round((e.clientX - startPos) / this.slotWidth) * this.slotDuration, "m").toDate();
|
|
const newDate = dayjs(startDate).add(Math.round((e.clientX - startPos) / this.slotWidth) * this.slotDuration, "m").toDate();
|
|
|
if (direction === "start" ? (newDate < localSlot.end) : (localSlot.start < newDate)) {
|
|
if (direction === "start" ? (newDate < localSlot.end) : (localSlot.start < newDate)) {
|
|
|
localSlot[localDir] = newDate;
|
|
localSlot[localDir] = newDate;
|
|
|
- this.updateTimeslotById(slot.id);
|
|
|
|
|
|
|
+ this.updateEventById(slot.id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -387,7 +406,7 @@ class Timeline extends LitElement {
|
|
|
window.removeEventListener("mousemove", resizeListener)
|
|
window.removeEventListener("mousemove", resizeListener)
|
|
|
window.removeEventListener("mouseup", mouseUpListener)
|
|
window.removeEventListener("mouseup", mouseUpListener)
|
|
|
localSlot.moving = false;
|
|
localSlot.moving = false;
|
|
|
- this.updateTimeslotById(slot.id);
|
|
|
|
|
|
|
+ this.updateEventById(slot.id);
|
|
|
}
|
|
}
|
|
|
localSlot.moving = true
|
|
localSlot.moving = true
|
|
|
window.addEventListener("mousemove", resizeListener)
|
|
window.addEventListener("mousemove", resizeListener)
|
|
@@ -428,7 +447,7 @@ class Timeline extends LitElement {
|
|
|
if (ressourceId !== localSlot.ressourceId) {
|
|
if (ressourceId !== localSlot.ressourceId) {
|
|
|
const oldRessource = this.getRessourceFromId(localSlot.ressourceId) as Ressource;
|
|
const oldRessource = this.getRessourceFromId(localSlot.ressourceId) as Ressource;
|
|
|
localSlot.ressourceId = ressourceId;
|
|
localSlot.ressourceId = ressourceId;
|
|
|
- this.updateTimeslotPosition(oldRessource);
|
|
|
|
|
|
|
+ this._updateEventPosition(oldRessource);
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -440,7 +459,7 @@ class Timeline extends LitElement {
|
|
|
const a = updatePosition(e);
|
|
const a = updatePosition(e);
|
|
|
if (updateRessource(e) || a) {
|
|
if (updateRessource(e) || a) {
|
|
|
hasChanged = true;
|
|
hasChanged = true;
|
|
|
- this.updateTimeslotById(localSlot.id);
|
|
|
|
|
|
|
+ this.updateEventById(localSlot.id);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -448,7 +467,7 @@ class Timeline extends LitElement {
|
|
|
window.removeEventListener("mousemove", moveListener);
|
|
window.removeEventListener("mousemove", moveListener);
|
|
|
window.removeEventListener("mouseup", mouseUpListener);
|
|
window.removeEventListener("mouseup", mouseUpListener);
|
|
|
localSlot.moving = false;
|
|
localSlot.moving = false;
|
|
|
- this.updateTimeslotById(slot.id);
|
|
|
|
|
|
|
+ this.updateEventById(slot.id);
|
|
|
callback(e,hasChanged);
|
|
callback(e,hasChanged);
|
|
|
}
|
|
}
|
|
|
localSlot.moving = true;
|
|
localSlot.moving = true;
|
|
@@ -459,7 +478,7 @@ class Timeline extends LitElement {
|
|
|
private _clearSelectedItems(){
|
|
private _clearSelectedItems(){
|
|
|
this.selectedList.map(selectable => {
|
|
this.selectedList.map(selectable => {
|
|
|
selectable.selected = false;
|
|
selectable.selected = false;
|
|
|
- this.updateTimeslotById(selectable.id)
|
|
|
|
|
|
|
+ this.updateEventById(selectable.id)
|
|
|
});
|
|
});
|
|
|
this.selectedList = []
|
|
this.selectedList = []
|
|
|
}
|
|
}
|
|
@@ -477,7 +496,7 @@ class Timeline extends LitElement {
|
|
|
if (e.ctrlKey) {
|
|
if (e.ctrlKey) {
|
|
|
this.selectedList.splice(idx, 1);
|
|
this.selectedList.splice(idx, 1);
|
|
|
item.selected = false;
|
|
item.selected = false;
|
|
|
- this.updateTimeslotById(item.id)
|
|
|
|
|
|
|
+ this.updateEventById(item.id)
|
|
|
} else {
|
|
} else {
|
|
|
this._clearSelectedItems()
|
|
this._clearSelectedItems()
|
|
|
}
|
|
}
|
|
@@ -488,7 +507,7 @@ class Timeline extends LitElement {
|
|
|
}
|
|
}
|
|
|
item.selected = true;
|
|
item.selected = true;
|
|
|
this.selectedList.push(item)
|
|
this.selectedList.push(item)
|
|
|
- this.updateTimeslotById(item.id)
|
|
|
|
|
|
|
+ this.updateEventById(item.id)
|
|
|
}
|
|
}
|
|
|
const myEvent = new CustomEvent('item-selected', {
|
|
const myEvent = new CustomEvent('item-selected', {
|
|
|
detail: { items: this.selectedList },
|
|
detail: { items: this.selectedList },
|
|
@@ -569,7 +588,7 @@ class Timeline extends LitElement {
|
|
|
_getCollapseRessourceHandler(item:Ressource):(e:MouseEvent)=>void{
|
|
_getCollapseRessourceHandler(item:Ressource):(e:MouseEvent)=>void{
|
|
|
return (_e:MouseEvent) => {
|
|
return (_e:MouseEvent) => {
|
|
|
item.collapseChildren = ! item.collapseChildren;
|
|
item.collapseChildren = ! item.collapseChildren;
|
|
|
- this.updateTimeslotPosition(item);
|
|
|
|
|
|
|
+ this._updateEventPosition(item);
|
|
|
// Force rows refresh TODO improve this rerendering
|
|
// Force rows refresh TODO improve this rerendering
|
|
|
this.rows = [...this.rows];
|
|
this.rows = [...this.rows];
|
|
|
};
|
|
};
|
|
@@ -624,7 +643,7 @@ class Timeline extends LitElement {
|
|
|
}
|
|
}
|
|
|
// Add moved children and associated slots
|
|
// Add moved children and associated slots
|
|
|
this.addRessources(movedContent.ressources);
|
|
this.addRessources(movedContent.ressources);
|
|
|
- this.addTimeSlots(movedContent.items);
|
|
|
|
|
|
|
+ this.addEvents(movedContent.items);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|