import 'bootstrap.css';
import '@mescius/wijmo.styles/wijmo.css';
import './styles.css';
//
import { CollectionView, Globalize } from '@mescius/wijmo';
import * as wjcScheduler from '@mescius/wijmo.scheduler';
import { getDisplayDate, getEvents, getRooms } from './data';
//
document.readyState === 'loading' ? document.addEventListener('DOMContentLoaded', init) : init();
function init() {
const eventView = new CollectionView(getEvents());
const createButton = document.querySelector('#createButton');
const updateButton = document.querySelector('#updateButton');
const removeButton = document.querySelector('#removeButton');
const selectionStatus = document.querySelector('#selectionStatus');
const operationStatus = document.querySelector('#operationStatus');
const notificationStatus = document.querySelector('#notificationStatus');
let selectedItem = null;
let selectedCell = null;
let selectedElement = null;
let nextId = 107;
let changingCount = 0;
let changedCount = 0;
const scheduler = new wjcScheduler.FlexScheduler('#theScheduler', {
itemsSource: eventView,
eventFields: { subject: 'subject', start: 'start', end: 'end' },
resources: [
{
fieldExpr: 'roomId',
label: 'Room',
dataSource: getRooms(),
valueExpr: 'id',
displayExpr: 'name',
backgroundColorExpr: 'color',
foreColorExpr: 'textColor',
},
],
definition: getWeekDefinition(),
displayDate: getDisplayDate(),
workHours: [{ start: '08:00', end: '17:00' }],
toolbarViewItems: [{ name: 'Week', key: wjcScheduler.SchedulerBuiltInViewItem.Week }],
});
scheduler.hostElement.addEventListener('click', (event) => {
const hit = scheduler.hitTest(event);
clearVisualSelection();
if (hit.hitTestType === wjcScheduler.SchedulerHitTestType.Item) {
const presentation = hit.getHitInfo();
selectedItem = presentation.item;
selectedCell = null;
selectedElement = hit.element;
selectedElement.classList.add('demo-selected-target');
selectionStatus.replaceChildren(createIcon('bi-calendar-event'), document.createTextNode(selectedItem.subject));
}
else if (hit.hitTestType === wjcScheduler.SchedulerHitTestType.Cell) {
selectedItem = null;
selectedCell = hit.getHitInfo();
selectedElement = hit.element;
selectedElement.classList.add('demo-selected-target');
selectionStatus.replaceChildren(createIcon('bi-clock'), document.createTextNode(`Empty slot | ${formatSlot(selectedCell)}`));
}
else {
selectedItem = null;
selectedCell = null;
selectionStatus.replaceChildren(createIcon('bi-cursor'), document.createTextNode('Select an event or empty time slot'));
}
updateActionState();
});
scheduler.itemChanging.addHandler((_sender, args) => {
changingCount++;
operationStatus.textContent = `${getActionName(args.request.action)} changing`;
updateNotificationStatus();
});
scheduler.itemChanged.addHandler((_sender, args) => {
changedCount++;
operationStatus.textContent = `${getActionName(args.request.action)} changed | ${getSourceItems().length} events`;
updateNotificationStatus();
clearSelection();
});
createButton.addEventListener('click', () => {
if (!selectedCell)
return;
scheduler.create({
id: nextId++,
subject: 'New schedule event',
start: selectedCell.start,
end: selectedCell.end,
roomId: selectedCell.resources.roomId || 'blue',
});
});
updateButton.addEventListener('click', () => {
if (!selectedItem)
return;
scheduler.update(selectedItem, {
subject: selectedItem.subject.startsWith('Updated: ')
? selectedItem.subject
: `Updated: ${selectedItem.subject}`,
end: new Date(selectedItem.end.getTime() + 30 * 60000),
});
});
removeButton.addEventListener('click', () => {
if (selectedItem)
scheduler.remove(selectedItem);
});
function getSourceItems() {
return eventView.sourceCollection;
}
function updateActionState() {
createButton.disabled = !selectedCell;
updateButton.disabled = !selectedItem;
removeButton.disabled = !selectedItem;
}
function clearVisualSelection() {
selectedElement === null || selectedElement === void 0 ? void 0 : selectedElement.classList.remove('demo-selected-target');
selectedElement = null;
}
function clearSelection() {
clearVisualSelection();
selectedItem = null;
selectedCell = null;
selectionStatus.replaceChildren(createIcon('bi-cursor'), document.createTextNode('Select an event or empty time slot'));
updateActionState();
}
function updateNotificationStatus() {
notificationStatus.textContent = `Notifications: ${changingCount} changing / ${changedCount} changed`;
}
updateActionState();
}
function createIcon(name) {
const icon = document.createElement('i');
icon.className = `bi ${name}`;
icon.setAttribute('aria-hidden', 'true');
return icon;
}
function formatSlot(cell) {
return `${Globalize.format(cell.start, 'ddd MMM d, h:mm tt')} - ${Globalize.format(cell.end, 'h:mm tt')}`;
}
function getActionName(action) {
switch (action) {
case wjcScheduler.SchedulerItemChangeAction.Create:
return 'Create';
case wjcScheduler.SchedulerItemChangeAction.Update:
return 'Update';
case wjcScheduler.SchedulerItemChangeAction.Remove:
return 'Remove';
}
}
function getWeekDefinition() {
const definition = wjcScheduler.createSchedulerDefinitionPreset(wjcScheduler.SchedulerBuiltInViewItem.Week);
return Object.assign(Object.assign({}, definition), { rows: {
bindings: [
{
type: wjcScheduler.SchedulerAxisBindingType.Time,
unit: wjcScheduler.SchedulerTimeUnit.Hour,
visible: (args) => args.hour >= 8 && args.hour < 17,
},
],
} });
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>MESCIUS Wijmo Scheduler Programmatic CRUD</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap-icons/font/bootstrap-icons.css" rel="stylesheet">
<!-- SystemJS -->
<script src="https://cdn.jsdelivr.net/npm/systemjs@0.21.5/dist/system.src.js" integrity="sha512-skZbMyvYdNoZfLmiGn5ii6KmklM82rYX2uWctBhzaXPxJgiv4XBwJnFGr5k8s+6tE1pcR1nuTKghozJHyzMcoA==" crossorigin="anonymous"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('./src/app');
</script>
</head>
<body>
<main class="container-fluid">
<div class="crud-toolbar" role="toolbar" aria-label="Event actions">
<div class="selection-summary">
<strong id="selectionStatus"><i class="bi bi-cursor" aria-hidden="true"></i> Select an event or empty time slot</strong>
<span>Available actions follow the selected Scheduler target.</span>
</div>
<div class="crud-actions">
<button id="createButton" class="btn btn-primary btn-sm" type="button" disabled><i class="bi bi-plus-lg" aria-hidden="true"></i> Create</button>
<button id="updateButton" class="btn btn-outline-primary btn-sm" type="button" disabled><i class="bi bi-pencil" aria-hidden="true"></i> Update</button>
<button id="removeButton" class="btn btn-outline-danger btn-sm" type="button" disabled><i class="bi bi-trash3" aria-hidden="true"></i> Remove</button>
</div>
<div class="crud-status">
<span id="operationStatus" aria-live="polite">Ready | 6 events</span>
<span id="notificationStatus">Notifications: 0 changing / 0 changed</span>
</div>
</div>
<div id="theScheduler"></div>
</main>
</body>
</html>
function createDate(day, hour, minute = 0) {
return new Date(2026, 4, day, hour, minute);
}
export function getDisplayDate() {
return createDate(13, 9);
}
export function getRooms() {
return [
{ id: 'blue', name: 'Blue Room', color: '#1d4ed8', textColor: '#ffffff' },
{ id: 'green', name: 'Green Room', color: '#087f5b', textColor: '#ffffff' },
{ id: 'violet', name: 'Studio', color: '#7e22ce', textColor: '#ffffff' },
{ id: 'amber', name: 'Forum', color: '#a1420b', textColor: '#ffffff' },
];
}
export function getEvents() {
return [
{ id: 101, subject: 'Weekly Planning', start: createDate(11, 9), end: createDate(11, 10), roomId: 'blue' },
{ id: 102, subject: 'Design Review', start: createDate(11, 13), end: createDate(11, 14, 30), roomId: 'violet' },
{
id: 103,
subject: 'Customer Workshop',
start: createDate(12, 10),
end: createDate(12, 11, 30),
roomId: 'amber',
},
{
id: 104,
subject: 'Release Checkpoint',
start: createDate(13, 9, 30),
end: createDate(13, 10, 30),
roomId: 'green',
},
{
id: 105,
subject: 'Partner Briefing',
start: createDate(14, 14),
end: createDate(14, 15, 30),
roomId: 'blue',
},
{ id: 106, subject: 'Weekly Wrap-up', start: createDate(15, 11), end: createDate(15, 12), roomId: 'green' },
];
}
body {
color: #1f2937;
font-size: 15px;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
user-select: none;
margin: 0;
}
.container-fluid {
box-sizing: border-box;
margin: 0;
padding: 5px;
}
.crud-toolbar {
display: flex;
align-items: flex-end;
gap: 10px 14px;
min-height: 54px;
margin-bottom: 6px;
padding: 6px 9px;
border: 1px solid #dbe2ea;
background: #f8fafc;
}
.selection-summary {
display: flex;
flex-direction: column;
min-width: 0;
}
.selection-summary strong {
display: flex;
align-items: center;
gap: 6px;
color: #0f172a;
font-size: 13px;
}
.selection-summary span {
color: #64748b;
font-size: 12px;
}
.crud-actions {
display: flex;
gap: 6px;
}
.crud-status {
display: flex;
flex-direction: column;
min-width: 240px;
color: #475569;
font-size: 13px;
line-height: 1.35;
}
.crud-actions {
margin-left: auto;
}
.demo-selected-target {
outline: 3px solid #0f6cbd !important;
outline-offset: -3px;
box-shadow: inset 0 0 0 1px #ffffff;
}
#operationStatus {
color: #1f2937;
font-weight: 600;
}
.form-select:focus,
.btn:focus-visible {
border-color: #0f6cbd;
box-shadow: 0 0 0 2px rgb(15 108 189 / 22%);
}
#theScheduler {
height: calc(100vh - 64px);
min-height: 600px;
}
@media (max-width: 700px) {
.crud-toolbar {
align-items: stretch;
flex-wrap: wrap;
}
.selection-summary {
flex: 1 1 100%;
}
.crud-actions {
margin-left: 0;
flex: 0 0 auto;
}
.crud-status {
flex: 1 1 180px;
min-width: 0;
}
#theScheduler {
height: 680px;
min-height: 680px;
}
}
input,
textarea,
[contenteditable="true"] {
user-select: text;
}
(function (global) {
System.config({
transpiler: 'plugin-babel',
babelOptions: {
es2015: true,
},
meta: {
'*.css': { loader: 'css' },
},
paths: {
// paths serve as alias
'npm:': 'node_modules/',
'cdn:': 'https://cdn.mescius.io/demoapps/packages/wijmojs/5.20262.60-rc/',
'pcdn:': 'https://cdn.jsdelivr.net/npm/',
},
// map tells the System loader where to look for things
map: {
'@mescius/wijmo': 'cdn:@mescius/wijmo/index.js',
'@mescius/wijmo.input': 'cdn:@mescius/wijmo.input/index.js',
'@mescius/wijmo.scheduler': 'cdn:@mescius/wijmo.scheduler/index.js',
'@mescius/wijmo.styles': 'cdn:@mescius/wijmo.styles',
'@mescius/wijmo.cultures': 'cdn:@mescius/wijmo.cultures',
jszip: 'pcdn:jszip@3.8.0/dist/jszip.js',
'bootstrap.css': 'pcdn:bootstrap@5.3.8/dist/css/bootstrap.min.css',
css: 'pcdn:systemjs-plugin-css@0.1.37/css.js',
'plugin-babel': 'pcdn:systemjs-plugin-babel@0.0.25/plugin-babel.js',
'systemjs-babel-build': 'pcdn:systemjs-plugin-babel@0.0.25/systemjs-babel-browser.js',
},
packages: {
src: {
defaultExtension: 'js',
},
node_modules: {
defaultExtension: 'js',
},
},
});
})(this);