Skip to content

Commit 22d05d7

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

File tree

7 files changed

+399
-2
lines changed

7 files changed

+399
-2
lines changed
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: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
$(() => {
2+
let selectionData = null;
3+
let $overlays = [];
4+
let $anchor = null;
5+
6+
function showSelectionOverlay($cells) {
7+
removeOverlay();
8+
if (!$cells.length) return;
9+
10+
const columns = {};
11+
$cells.each(function () {
12+
const r = this.getBoundingClientRect();
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+
$overlays.push($('<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+
});
36+
37+
const lastCol = cols[cols.length - 1];
38+
$anchor = $('<div>').css({
39+
position: 'fixed',
40+
left: `${lastCol.x + lastCol.width}px`,
41+
top: `${(lastCol.minY + lastCol.maxY) / 2}px`,
42+
width: '1px',
43+
height: '1px',
44+
pointerEvents: 'none',
45+
}).appendTo('body');
46+
}
47+
48+
function removeOverlay() {
49+
$overlays.forEach(($el) => $el.remove());
50+
$overlays = [];
51+
if ($anchor) {
52+
$anchor.remove();
53+
$anchor = null;
54+
}
55+
}
56+
57+
const popover = $('#creation-popover').dxPopover({
58+
width: 260,
59+
height: 'auto',
60+
showTitle: true,
61+
title: 'New Appointment',
62+
showCloseButton: false,
63+
shading: false,
64+
position: 'right',
65+
hideOnOutsideClick: true,
66+
hideOnParentScroll: false,
67+
contentTemplate() {
68+
const $content = $('<div>').addClass('popover-content');
69+
70+
$('<div id="appointment-subject">').appendTo($content);
71+
72+
const $buttons = $('<div>').addClass('popover-buttons');
73+
$('<div id="create-btn">').appendTo($buttons);
74+
$('<div id="cancel-btn">').appendTo($buttons);
75+
$buttons.appendTo($content);
76+
77+
return $content;
78+
},
79+
onShown() {
80+
$('#appointment-subject').dxTextBox({
81+
placeholder: 'Enter appointment name',
82+
stylingMode: 'outlined',
83+
}).dxTextBox('instance').focus();
84+
85+
$('#create-btn').dxButton({
86+
text: 'Create',
87+
type: 'default',
88+
onClick() {
89+
if (!selectionData) return;
90+
91+
const subject = $('#appointment-subject').dxTextBox('instance').option('value');
92+
if (!subject) return;
93+
94+
scheduler.addAppointment({
95+
text: subject,
96+
startDate: selectionData.startDate,
97+
endDate: selectionData.endDate,
98+
...selectionData.groups,
99+
});
100+
101+
popover.hide();
102+
},
103+
});
104+
105+
$('#cancel-btn').dxButton({
106+
text: 'Cancel',
107+
onClick() {
108+
popover.hide();
109+
},
110+
});
111+
},
112+
onHidden() {
113+
removeOverlay();
114+
const subjectBox = $('#appointment-subject').data('dxTextBox');
115+
if (subjectBox) {
116+
subjectBox.option('value', '');
117+
}
118+
},
119+
}).dxPopover('instance');
120+
121+
const scheduler = $('#scheduler').dxScheduler({
122+
timeZone: 'America/Los_Angeles',
123+
dataSource: data,
124+
views: [{
125+
type: 'workWeek',
126+
groupOrientation: 'horizontal',
127+
cellDuration: 30,
128+
}],
129+
currentView: 'workWeek',
130+
currentDate: new Date(2021, 3, 21),
131+
startDayHour: 9,
132+
endDayHour: 16,
133+
groups: ['priorityId'],
134+
resources: [{
135+
fieldExpr: 'priorityId',
136+
allowMultiple: false,
137+
dataSource: priorityData,
138+
label: 'Priority',
139+
}],
140+
showCurrentTimeIndicator: false,
141+
allDayPanelMode: 'allDay',
142+
onAppointmentFormOpening() {
143+
popover.hide();
144+
},
145+
onAppointmentTooltipShowing() {
146+
popover.hide();
147+
},
148+
onAppointmentClick() {
149+
popover.hide();
150+
},
151+
onCellClick() {
152+
popover.hide();
153+
},
154+
onSelectionEnd(e) {
155+
const cells = e.selectedCellData;
156+
if (cells.length <= 1) {
157+
return;
158+
}
159+
160+
const startDate = cells[0].startDateUTC || cells[0].startDate;
161+
const endDate = cells[cells.length - 1].endDateUTC || cells[cells.length - 1].endDate;
162+
163+
selectionData = {
164+
startDate,
165+
endDate,
166+
groups: cells[0].groups || {},
167+
};
168+
169+
const $focused = e.component.$element().find('.dx-scheduler-date-table-cell.dx-state-focused');
170+
showSelectionOverlay($focused);
171+
172+
setTimeout(() => {
173+
if ($anchor) {
174+
popover.option('target', $anchor);
175+
popover.show();
176+
}
177+
}, 50);
178+
},
179+
}).dxScheduler('instance');
180+
});

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
},

packages/devextreme/js/__internal/scheduler/workspaces/m_work_space.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1244,7 +1244,7 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
12441244
(eventsEngine.off as any)(element, SCHEDULER_CELL_DXPOINTERDOWN_EVENT_NAME);
12451245

12461246
eventsEngine.on(element, SCHEDULER_CELL_DXPOINTERDOWN_EVENT_NAME, DRAG_AND_DROP_SELECTOR, (e) => {
1247-
if (isMouseEvent(e) && e.which === 1) {
1247+
if ((isMouseEvent(e) || e.pointerType === 'mouse') && e.which === 1) {
12481248
isPointerDown = true;
12491249
(this.$element() as any).addClass(WORKSPACE_WITH_MOUSE_SELECTION_CLASS);
12501250
(eventsEngine.off as any)(domAdapter.getDocument(), SCHEDULER_CELL_DXPOINTERUP_EVENT_NAME);
@@ -1256,7 +1256,7 @@ class SchedulerWorkSpace extends Widget<WorkspaceOptionsInternal> {
12561256
});
12571257

12581258
eventsEngine.on(element, SCHEDULER_CELL_DXPOINTERMOVE_EVENT_NAME, DRAG_AND_DROP_SELECTOR, (e) => {
1259-
if (isPointerDown && this._dateTableScrollable && !this._dateTableScrollable.option('scrollByContent')) {
1259+
if (isPointerDown && this._dateTableScrollable) {
12601260
e.preventDefault();
12611261
e.stopPropagation();
12621262
this.moveToCell($(e.target), true);

0 commit comments

Comments
 (0)