Skip to content

Commit 73d3f3e

Browse files
Scheduler - Add CreateFromSelection demo, touch fix, declarations
1 parent 5ee32cb commit 73d3f3e

8 files changed

Lines changed: 413 additions & 2 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
This demo illustrates how to use the **onSelectionEnd** event to automatically open the appointment creation form when a user selects a time range via click-and-drag. The appointment start/end dates and resource group are pre-filled based on the selected cells.
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
const data = [
2+
{
3+
text: 'Website Re-Design Plan',
4+
priorityId: 2,
5+
startDate: new Date('2021-04-19T16:30:00.000Z'),
6+
endDate: new Date('2021-04-19T18:30:00.000Z'),
7+
}, {
8+
text: 'Book Flights to San Fran for Sales Trip',
9+
priorityId: 1,
10+
startDate: new Date('2021-04-22T17:00:00.000Z'),
11+
endDate: new Date('2021-04-22T19:00:00.000Z'),
12+
}, {
13+
text: 'Install New Router in Dev Room',
14+
priorityId: 1,
15+
startDate: new Date('2021-04-19T20:00:00.000Z'),
16+
endDate: new Date('2021-04-19T22:30:00.000Z'),
17+
}, {
18+
text: 'Approve Personal Computer Upgrade Plan',
19+
priorityId: 2,
20+
startDate: new Date('2021-04-20T17:00:00.000Z'),
21+
endDate: new Date('2021-04-20T18:00:00.000Z'),
22+
}, {
23+
text: 'Final Budget Review',
24+
priorityId: 2,
25+
startDate: new Date('2021-04-20T19:00:00.000Z'),
26+
endDate: new Date('2021-04-20T20:35:00.000Z'),
27+
}, {
28+
text: 'New Brochures',
29+
priorityId: 2,
30+
startDate: new Date('2021-04-19T20:00:00.000Z'),
31+
endDate: new Date('2021-04-19T22:15:00.000Z'),
32+
}, {
33+
text: 'Install New Database',
34+
priorityId: 1,
35+
startDate: new Date('2021-04-20T16:00:00.000Z'),
36+
endDate: new Date('2021-04-20T19:15:00.000Z'),
37+
}, {
38+
text: 'Approve New Online Marketing Strategy',
39+
priorityId: 2,
40+
startDate: new Date('2021-04-21T19:00:00.000Z'),
41+
endDate: new Date('2021-04-21T21:00:00.000Z'),
42+
}, {
43+
text: 'Upgrade Personal Computers',
44+
priorityId: 1,
45+
startDate: new Date('2021-04-19T16:00:00.000Z'),
46+
endDate: new Date('2021-04-19T18:30:00.000Z'),
47+
}, {
48+
text: 'Prepare 2021 Marketing Plan',
49+
priorityId: 2,
50+
startDate: new Date('2021-04-22T18:00:00.000Z'),
51+
endDate: new Date('2021-04-22T20:30:00.000Z'),
52+
}, {
53+
text: 'Brochure Design Review',
54+
priorityId: 1,
55+
startDate: new Date('2021-04-21T18:00:00.000Z'),
56+
endDate: new Date('2021-04-21T20:30:00.000Z'),
57+
}, {
58+
text: 'Create Icons for Website',
59+
priorityId: 2,
60+
startDate: new Date('2021-04-23T17:00:00.000Z'),
61+
endDate: new Date('2021-04-23T18:30:00.000Z'),
62+
}, {
63+
text: 'Upgrade Server Hardware',
64+
priorityId: 1,
65+
startDate: new Date('2021-04-23T16:00:00.000Z'),
66+
endDate: new Date('2021-04-23T22:00:00.000Z'),
67+
}, {
68+
text: 'Submit New Website Design',
69+
priorityId: 2,
70+
startDate: new Date('2021-04-23T23:30:00.000Z'),
71+
endDate: new Date('2021-04-24T01:00:00.000Z'),
72+
}, {
73+
text: 'Launch New Website',
74+
priorityId: 2,
75+
startDate: new Date('2021-04-23T19:20:00.000Z'),
76+
endDate: new Date('2021-04-23T21:00:00.000Z'),
77+
}, {
78+
text: 'Google AdWords Strategy',
79+
priorityId: 1,
80+
startDate: new Date('2021-04-26T16:00:00.000Z'),
81+
endDate: new Date('2021-04-26T19:00:00.000Z'),
82+
}, {
83+
text: 'Rollout of New Website and Marketing Brochures',
84+
priorityId: 1,
85+
startDate: new Date('2021-04-26T20:00:00.000Z'),
86+
endDate: new Date('2021-04-26T22:30:00.000Z'),
87+
}, {
88+
text: 'Non-Compete Agreements',
89+
priorityId: 2,
90+
startDate: new Date('2021-04-27T20:00:00.000Z'),
91+
endDate: new Date('2021-04-27T22:45:00.000Z'),
92+
}, {
93+
text: 'Approve Hiring of John Jeffers',
94+
priorityId: 2,
95+
startDate: new Date('2021-04-27T16:00:00.000Z'),
96+
endDate: new Date('2021-04-27T19:00:00.000Z'),
97+
}, {
98+
text: 'Update NDA Agreement',
99+
priorityId: 1,
100+
startDate: new Date('2021-04-27T18:00:00.000Z'),
101+
endDate: new Date('2021-04-27T21:15:00.000Z'),
102+
}, {
103+
text: 'Update Employee Files with New NDA',
104+
priorityId: 1,
105+
startDate: new Date('2021-04-30T16:00:00.000Z'),
106+
endDate: new Date('2021-04-30T18:45:00.000Z'),
107+
}, {
108+
text: 'Submit Questions Regarding New NDA',
109+
priorityId: 1,
110+
startDate: new Date('2021-04-28T17:00:00.000Z'),
111+
endDate: new Date('2021-04-28T18:30:00.000Z'),
112+
}, {
113+
text: 'Submit Signed NDA',
114+
priorityId: 1,
115+
startDate: new Date('2021-04-28T20:00:00.000Z'),
116+
endDate: new Date('2021-04-28T22:00:00.000Z'),
117+
}, {
118+
text: 'Review Revenue Projections',
119+
priorityId: 2,
120+
startDate: new Date('2021-04-28T18:00:00.000Z'),
121+
endDate: new Date('2021-04-28T21:00:00.000Z'),
122+
}, {
123+
text: 'Comment on Revenue Projections',
124+
priorityId: 2,
125+
startDate: new Date('2021-04-26T17:00:00.000Z'),
126+
endDate: new Date('2021-04-26T20:00:00.000Z'),
127+
}, {
128+
text: 'Provide New Health Insurance Docs',
129+
priorityId: 2,
130+
startDate: new Date('2021-04-30T19:00:00.000Z'),
131+
endDate: new Date('2021-04-30T22:00:00.000Z'),
132+
}, {
133+
text: 'Review Changes to Health Insurance Coverage',
134+
priorityId: 2,
135+
startDate: new Date('2021-04-29T16:00:00.000Z'),
136+
endDate: new Date('2021-04-29T20:00:00.000Z'),
137+
}, {
138+
text: 'Review Training Course for any Omissions',
139+
priorityId: 1,
140+
startDate: new Date('2021-04-29T18:00:00.000Z'),
141+
endDate: new Date('2021-04-29T21:00:00.000Z'),
142+
},
143+
];
144+
145+
const priorityData = [
146+
{
147+
text: 'Low Priority',
148+
id: 1,
149+
color: '#1D90FF',
150+
}, {
151+
text: 'High Priority',
152+
id: 2,
153+
color: '#FF9747',
154+
},
155+
];
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en">
3+
<head>
4+
<title>DevExtreme Demo</title>
5+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
6+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
7+
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=5.0" />
8+
<script src="../../../../node_modules/jquery/dist/jquery.min.js"></script>
9+
<link rel="stylesheet" type="text/css" href="../../../../node_modules/devextreme-dist/css/dx.light.css" />
10+
<script src="../../../../node_modules/devextreme-dist/js/dx.all.js"></script>
11+
<script src="data.js"></script>
12+
<script src="index.js"></script>
13+
<style>
14+
.popover-content { padding: 12px; }
15+
.popover-buttons { display: flex; gap: 8px; justify-content: flex-end; margin-top: 12px; }
16+
</style>
17+
</head>
18+
<body class="dx-viewport">
19+
<div class="demo-container">
20+
<div id="scheduler"></div>
21+
<div id="creation-popover"></div>
22+
</div>
23+
</body>
24+
</html>
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
$(() => {
2+
let selectionData = null;
3+
let lastSelectedCellRects = [];
4+
let $overlays = [];
5+
let $anchor = null;
6+
7+
function createOverlay(schedulerElement, rects) {
8+
removeOverlay();
9+
if (!rects.length) return;
10+
11+
const columns = {};
12+
rects.forEach((r) => {
13+
const key = Math.round(r.x);
14+
if (!columns[key]) {
15+
columns[key] = { x: r.x, width: r.width, minY: r.y, maxY: r.y + r.height };
16+
} else {
17+
columns[key].minY = Math.min(columns[key].minY, r.y);
18+
columns[key].maxY = Math.max(columns[key].maxY, r.y + r.height);
19+
}
20+
});
21+
22+
const cols = Object.values(columns);
23+
cols.forEach((col) => {
24+
const $el = $('<div>').css({
25+
position: 'fixed',
26+
left: `${col.x}px`,
27+
top: `${col.minY}px`,
28+
width: `${col.width}px`,
29+
height: `${col.maxY - col.minY}px`,
30+
backgroundColor: 'rgba(0, 120, 215, 0.2)',
31+
borderRadius: '2px',
32+
pointerEvents: 'none',
33+
zIndex: 100,
34+
}).appendTo('body');
35+
$overlays.push($el);
36+
});
37+
38+
const lastCol = cols[cols.length - 1];
39+
const midY = (lastCol.minY + lastCol.maxY) / 2;
40+
$anchor = $('<div>').css({
41+
position: 'fixed',
42+
left: `${lastCol.x + lastCol.width}px`,
43+
top: `${midY}px`,
44+
width: '1px',
45+
height: '1px',
46+
pointerEvents: 'none',
47+
}).appendTo('body');
48+
}
49+
50+
function removeOverlay() {
51+
$overlays.forEach(($el) => $el.remove());
52+
$overlays = [];
53+
if ($anchor) {
54+
$anchor.remove();
55+
$anchor = null;
56+
}
57+
}
58+
59+
const popover = $('#creation-popover').dxPopover({
60+
width: 260,
61+
height: 'auto',
62+
showTitle: true,
63+
title: 'New Appointment',
64+
showCloseButton: false,
65+
shading: false,
66+
position: 'right',
67+
hideOnOutsideClick: true,
68+
hideOnParentScroll: false,
69+
contentTemplate() {
70+
const $content = $('<div>').addClass('popover-content');
71+
72+
$('<div id="appointment-subject">').appendTo($content);
73+
74+
const $buttons = $('<div>').addClass('popover-buttons');
75+
$('<div id="create-btn">').appendTo($buttons);
76+
$('<div id="cancel-btn">').appendTo($buttons);
77+
$buttons.appendTo($content);
78+
79+
return $content;
80+
},
81+
onShown() {
82+
$('#appointment-subject').dxTextBox({
83+
placeholder: 'Enter appointment name',
84+
stylingMode: 'outlined',
85+
}).dxTextBox('instance').focus();
86+
87+
$('#create-btn').dxButton({
88+
text: 'Create',
89+
type: 'default',
90+
onClick() {
91+
if (!selectionData) return;
92+
93+
const subject = $('#appointment-subject').dxTextBox('instance').option('value');
94+
if (!subject) return;
95+
96+
scheduler.addAppointment({
97+
text: subject,
98+
startDate: selectionData.startDate,
99+
endDate: selectionData.endDate,
100+
...selectionData.groups,
101+
});
102+
103+
popover.hide();
104+
},
105+
});
106+
107+
$('#cancel-btn').dxButton({
108+
text: 'Cancel',
109+
onClick() {
110+
popover.hide();
111+
},
112+
});
113+
},
114+
onHidden() {
115+
removeOverlay();
116+
const subjectBox = $('#appointment-subject').data('dxTextBox');
117+
if (subjectBox) {
118+
subjectBox.option('value', '');
119+
}
120+
},
121+
}).dxPopover('instance');
122+
123+
const scheduler = $('#scheduler').dxScheduler({
124+
timeZone: 'America/Los_Angeles',
125+
dataSource: data,
126+
views: [{
127+
type: 'workWeek',
128+
groupOrientation: 'horizontal',
129+
cellDuration: 30,
130+
}],
131+
currentView: 'workWeek',
132+
currentDate: new Date(2021, 3, 21),
133+
startDayHour: 9,
134+
endDayHour: 16,
135+
groups: ['priorityId'],
136+
resources: [{
137+
fieldExpr: 'priorityId',
138+
allowMultiple: false,
139+
dataSource: priorityData,
140+
label: 'Priority',
141+
}],
142+
showCurrentTimeIndicator: false,
143+
allDayPanelMode: 'allDay',
144+
onAppointmentFormOpening() {
145+
popover.hide();
146+
},
147+
onAppointmentTooltipShowing() {
148+
popover.hide();
149+
},
150+
onAppointmentClick() {
151+
popover.hide();
152+
},
153+
onCellClick() {
154+
popover.hide();
155+
},
156+
onOptionChanged(e) {
157+
if (e.name === 'selectedCellData' && e.value && e.value.length > 0) {
158+
const $el = e.component.$element();
159+
const focused = $el.find('.dx-scheduler-date-table-cell.dx-state-focused, .dx-scheduler-date-table-cell.dx-scheduler-focused-cell');
160+
if (focused.length > 0) {
161+
lastSelectedCellRects = [];
162+
focused.each(function () {
163+
lastSelectedCellRects.push(this.getBoundingClientRect());
164+
});
165+
}
166+
}
167+
},
168+
onSelectionEnd(e) {
169+
const cells = e.selectedCellData;
170+
if (cells.length <= 1) {
171+
return;
172+
}
173+
174+
const startDate = cells[0].startDateUTC || cells[0].startDate;
175+
const endDate = cells[cells.length - 1].endDateUTC || cells[cells.length - 1].endDate;
176+
177+
selectionData = {
178+
startDate,
179+
endDate,
180+
groups: cells[0].groups || {},
181+
};
182+
183+
createOverlay(e.component.$element(), lastSelectedCellRects);
184+
185+
setTimeout(() => {
186+
if ($anchor) {
187+
popover.option('target', $anchor);
188+
popover.show();
189+
}
190+
}, 50);
191+
},
192+
}).dxScheduler('instance');
193+
});

apps/demos/menuMeta.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3649,6 +3649,12 @@
36493649
"/Models/Scheduler/ResolveTimeConflicts.cs"
36503650
],
36513651
"DemoType": "Web"
3652+
},
3653+
{
3654+
"Title": "Create from Selection",
3655+
"Name": "CreateFromSelection",
3656+
"Widget": "Scheduler",
3657+
"DemoType": "Web"
36523658
}
36533659
]
36543660
},

0 commit comments

Comments
 (0)