table-schedule
v0.4.0
Published
Vanilla JS table schedule with DnD support.
Downloads
20
Maintainers
Readme
TableSchedule.js
Vanilla JS table schedule with DnD support.
In this document, event or event item stands for event item in the schedule, while Event stands for JavaScript Event
object.
Contents
- TableSchedule.js
Features
What TableSchedule.js provides:
- Drag-and-Drop to trigger aed (i.e. add / edit / delete) Events.
- Quantization or snap-to-grid by default when DnD, switchable by holding SHIFT key.
- APIs to aed event items programmatically.
- Manages events data and makes them accessible through custom Events as well as an instance property.
What it doesn't provide:
- UI components for filling forms / confirmation / changing dates or whatever. It only provides an interface for displaying and manipulating event items. Say if you're using Bootstrap, you might need to initialize a form modal when add / edit Events fire.
Getting Started
Installing
npm
npm install table-schedule
then
import TableSchedule from 'table-schedule'
or
var TableSchedule = require('table-schedule')
or
<script src="/path/to/table-schedule.js"></script>
and don't forget css
<link rel="stylesheet" href="/path/to/table-schedule.css">
Usage
Prepare a <TABLE>
element, wrapped in an overflow:auto
element.
<div style="overflow:auto">
<table class="table-schedule">
</table>
</div>
Initiate the instance.
var ts = new TableSchedule('.table-schedule')
The constructor takes two params:
- element
- Type:
CSS selector
orHTMLElement
- The container for the widget, must be a
<TABLE>
element or equivalent selector
- Type:
- options (optional)
- Type:
Object
- See Options below.
- Type:
Then add Event handlers:
var $ts = document.querySelector('.table-schedule')
$ts.addEventListener('create', function(e) {
const { item } = e.detail
// Assume you have a very convenient prompt dialog like this
fantasyDialog({
fields: [
// you can put date time values from e.detail into the form
{label: 'Date', type: 'date', initValue: item.date},
{label: 'Start Time', type: 'time', initValue: item.start},
{label: 'End Time', type: 'time', initValue: item.end},
// you might need other data
{label: 'Title', type: 'text'},
{label: 'Content', type: 'textarea'},
],
onConfirm: function(load) { // load contains all field values
ts.addEvent({
date: load[0],
start: load[1],
end: load[2],
title: load[3],
content: load[4]
})
}
})
})
$ts.addEventListener('modify', function(e) {
const { item, coords, mod } = e.detail
// if you don't need a form to modify other information
var modified = Object.assign({}, item, mod)
ts.updateEvent(coords, modified)
// else you still need to provide a form for input
})
$ts.addEventListener('remove', function(e) {
const { coords } = e.detail
ts.deleteEvent(coords)
})
All events' data are stored in the instance's events
property, which is a 2-dimensional array.
instance.events[i][j]
is the j-th (starts from 0) added event on i-th (starts from 0) date among the current period.
These two indices together bind the event item's UI element and its data, and I'll call them a pair of coordinates for the event item in the rest of the document.
Options
num
- Type:
Number
- Default: 7
Length of the period.
startDate
- Type:
Date
- Default:
new Date()
Initial start date of the period.
dayStart
- Type:
Number
- Default:
6
Start hour of the day.
dayEnd
- Type:
Number
- Default:
22
End hour of the day.
gap
- Type:
Number
- Default:
10
Equivalent minutes of cell height.
quantizing
- Type:
Boolean
- Default:
true
Use quantization without(true) or with(false) holding SHIFT key.
createThreshold
- Type:
Number
- Default:
10
In minutes.
When a new event is drawn, create
Event only fires if the event item's duration equals or is longer than this.
When change event item's duration (by dragging the handle), delete
Event will fire when duration is shorter than this.
stretchThreshold
- Type:
Number
- Default:
5
In minutes. When dragging an event item's handle, the item's duration (height) won't start to change until mouse / finger moved equivalent pixels (default is half of cell height) in Y axis.
moveYThreshold
- Type:
Number
- Default:
5
In minutes. When dragging an event item, the item won't start to move until mouse / finger moved equivalent pixels (default is half of cell height) in Y axis.
dateFormat
- Type:
function
- Default:
date => {format(date, 'MM/dd')}
,
The date texts displayed in the table header take what this function returns.
Params:
date
- Date object
directChange
- Type:
Boolean|Array
- Default:
false
Whether to automatically apply aed changes to the event items when corresponding Event fires.
When it is true
, all changes will be applied.
Or it can be an array of any of:
create
: apply add changesmodify
: apply all edit changesstart
/end
/date
/datetime
: apply specific edit changes. See modifyremove
: apply delete changes
extraDataset
- Type:
Object
- Default:
null
Add extra dataset entries to event elements. For example, {id: 'ID'}
will add a data-id
to the element with the value from event item's ID
property.
labelGroups
- Type:
Boolean
- Default:
false
Whether to show group headers below the top table header.
groupHeaderText
- Type:
Object|String|function
- Default:
null
What text to show in group headers.
null
- eventItem.groupString
- a property value from eventItemfunction
- a function which takes eventItem.group, e.g. group => ('Group - ' + group)
Custom Events
These 3 CustomEvent
s are fired on mouseup
or touchend
, which is after a drag-and-drop action on the schedule. All of them come with a detail
property which contains useful information.
create
Fired when a new event item is drawn. Event.detail:
- item
Object
: new event item- date
String
: date string formatted inyyyy/MM/dd
- start
String
: start time, formatted inHH:mm
- end
String
: end time, formatted inHH:mm
- date
modify
Fired when change either date / start / end of an event item. Event.detail:
- item
Object
: reference to the original event item, which is untouched since added throughinstance.addEvent
- coords
Array
: the coordinates for the event item - mod
Object
: the modification made to the event item- type
String
: type of the modification, can be either of:'start'
- when DnD an event item within its date and the start time is changed'end'
- when DnD the handle bar at the event item's bottom and the end time is changed'date'
- when DnD an event item to another date with start time not changed'datetime'
- when drag-n-drap an event item to another date and start time
- date
String
: the event item's date after modifying - start
String
: the event item's start time after modifying - end
String
: the event item's end time after modifying
- type
remove
Fired when drag an event item's handle and change the event item's duration to a value smaller than options.createThreshold
.
Event.detail:
- item
Object
: reference to the original event item - coords
Array
: the coordinates for the event item
APIs
addEvent(eventItem)
- eventItem
- Type:
Object
- Type:
- (return value)
- Type:
this
- Type:
Add new event item to the schedule.
eventItem
MUST include these properties:
- date
Sting|Object
: a date string that can be parsed byDate.parse
or aDate
object - start
String
: start time, inHH:mm
format - end
String
: end time, inHH:mm
format
may include these properties:
- title
String
: event item's title - content
String
: event item's content, which will be rendered usinginnerHTML
- style
Object
: additional styles you want to apply to the event item. - className
String
: additional classnames you want to apply to the event item. - group
String|Number
: event items with a same group key will be grouped together, while event items with different group keys will never be in a same column.
Besides all above which will take effect on display, you can put any properties you want in it, like an ID for the event or whatever. eventItem
is stored in the instance untouched and is available in Event.detail.
updateEvent(coords, modified)
- coords
- Type:
Array
- coordinates
- Type:
- modified
- Type:
Object
- modified eventItem
- Type:
- (return value)
- Type:
this
- Type:
Update the event item instance.events[coords[0]][coords[1]]
to modified
.
deleteEvent(coords)
- coords
- Type:
Array
- Type:
- (return value)
- Type:
this
- Type:
Delete event item instance.events[coords[0]][coords[1]]
clear(which)
- which
- Type: any
- clear event items on which date(s)
- (return value)
- Type:
this
- Type:
which
can be:
Number
: Date index, value constrained in [0, options.num]String
: Date stringDate
: Date objectArray
: array of values of any types aboveundefined
: to clear all
changeStartDate(date)
- date
- Type:
Object
- Target start date
- Type:
- (return value)
- Type:
this
- Type:
Change the start date to target date, will also alter instance.events
accordingly.
rerender()
- (return value)
- Type:
this
- Type:
Rerender all event items in the schedule.
updateRect()
- (return value)
- Type:
this
- Type:
Update the container's size and position. You'll need to call this after any changes that affect the container's size and position, e.g. the container is switched from hidden to shown, a toolbar appears above the widget, etc.
destroy()
Destroy the instance.
getEvent(elem)
- elem
- Type:
Object
- the event item element
- Type:
- (return value)
- Type:
Object
- a reference to the corresponding event item stored in
instance.events
ornull
.
- Type:
getElem(eventItem)
- eventItem
- Type:
Object
- the event item
- Type:
- (return value)
- Type:
Object
- a reference to the corresponding event item element in the schedule or
null
- Type:
events
- Type:
Array
All event items.
Browser Support
Not tested yet but supposed to and should work in all latest modern browsers.
Contribute
If you find this widget useful and are willing to help, any issue or PR is welcomed.
License
MIT.