UNPKG

table-schedule

Version:
400 lines (322 loc) 12 kB
# TableSchedule.js > Vanilla JS table schedule with DnD support. [Demo](https://monkey-d-pixel.github.io/table-schedule/index.html) In this document, *event* or *event item* stands for event item in the schedule, while *Event* stands for JavaScript `Event` object. ## Contents - [TableSchedule.js](#tableschedulejs) - [Contents](#contents) - [Features](#features) - [Getting Started](#getting-started) - [Installing](#installing) - [Usage](#usage) - [Options](#options) - [num](#num) - [startDate](#startdate) - [dayStart](#daystart) - [dayEnd](#dayend) - [gap](#gap) - [quantizing](#quantizing) - [createThreshold](#createthreshold) - [stretchThreshold](#stretchthreshold) - [moveYThreshold](#moveythreshold) - [dateFormat](#dateformat) - [directChange](#directchange) - [extraDataset](#extradataset) - [labelGroups](#labelgroups) - [groupHeaderText](#groupheadertext) - [Custom Events](#custom-events) - [create](#create) - [modify](#modify) - [remove](#remove) - [APIs](#apis) - [addEvent(eventItem)](#addeventeventitem) - [updateEvent(coords, modified)](#updateeventcoords-modified) - [deleteEvent(coords)](#deleteeventcoords) - [clear(which)](#clearwhich) - [changeStartDate(date)](#changestartdatedate) - [rerender()](#rerender) - [updateRect()](#updaterect) - [destroy()](#destroy) - [getEvent(elem)](#geteventelem) - [getElem(eventItem)](#getelemeventitem) - [events](#events) - [Browser Support](#browser-support) - [Contribute](#contribute) - [License](#license) ## 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 ```shell npm install table-schedule ``` then ```js import TableSchedule from 'table-schedule' ``` or ```js var TableSchedule = require('table-schedule') ``` or ```html <script src="/path/to/table-schedule.js"></script> ``` and don't forget css ```html <link rel="stylesheet" href="/path/to/table-schedule.css"> ``` ### Usage Prepare a `<TABLE>` element, wrapped in an `overflow:auto` element. ```html <div style="overflow:auto"> <table class="table-schedule"> </table> </div> ``` Initiate the instance. ```js var ts = new TableSchedule('.table-schedule') ``` The constructor takes two params: - **element** - Type: `CSS selector` or `HTMLElement` - The container for the widget, **must be a `<TABLE>` element or equivalent selector** - **options** (optional) - Type: `Object` - See [Options](#Options) below. Then add Event handlers: ```js 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 changes - `modify`: apply all edit changes - `start`/`end`/`date`/`datetime`: apply specific edit changes. See [modify](#modify) - `remove`: 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.group - `String` - a property value from eventItem - `function` - 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 in `yyyy/MM/dd` - **start** `String`: start time, formatted in `HH:mm` - **end** `String`: end time, formatted in `HH:mm` ### 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 through `instance.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 ### 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` - (return value) - Type: `this` Add new event item to the schedule. `eventItem` MUST include these properties: - **date** `Sting|Object`: a date string that can be parsed by `Date.parse` or a `Date` object - **start** `String`: start time, in `HH:mm` format - **end** `String`: end time, in `HH:mm` format may include these properties: - title `String`: event item's title - content `String`: event item's content, **which will be rendered using `innerHTML`** - 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 - **modified** - Type: `Object` - modified eventItem - (return value) - Type: `this` Update the event item `instance.events[coords[0]][coords[1]]` to `modified`. ### deleteEvent(coords) - **coords** - Type: `Array` - (return value) - Type: `this` 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` `which` can be: - `Number`: Date index, value constrained in [0, options.num] - `String`: Date string - `Date`: Date object - `Array`: array of values of any types above - `undefined`: to clear all ### changeStartDate(date) - **date** - Type: `Object` - Target start date - (return value) - Type: `this` Change the start date to target date, will also alter `instance.events` accordingly. ### rerender() - (return value) - Type: `this` Rerender all event items in the schedule. ### updateRect() - (return value) - Type: `this` 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 - (return value) - Type: `Object` - a reference to the corresponding event item stored in `instance.events` or `null`. ### getElem(eventItem) - **eventItem** - Type: `Object` - the event item - (return value) - Type: `Object` - a reference to the corresponding event item element in the schedule or `null` ### 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](https://opensource.org/licenses/MIT).