

JavaScript Scheduler: Copy Multiple Events | DayPilot Code
source link: https://code.daypilot.org/72047/javascript-scheduler-copy-multiple-events
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Overview
The JavaScript Scheduler component allows operations on multiple events.
Copy events from multiple Scheduler rows using Ctrl+drag
In addition to the drag and drop method, you can use “Copy” and “Paste” context menu items.
Includes a trial version of DayPilot Pro for JavaScript (see License below)
License
Licensed for testing and evaluation purposes. Please see the license agreement included in the sample project. You can use the source code of the tutorial if you are a licensed user of DayPilot Pro for JavaScript. Buy a license.
Allow Selection of Multiple Events
First, it is necessary to set the allowMultiSelect property to true
to enable selection of multiple events.
allowMultiSelect: true,
Now we will set the event click action to "Select"
(eventClickHandling property). This will allow event selection on click. Multiple events can be selected using Ctrl+click.
eventClickHandling: "Select",
Copy Multiple Events using Drag and Drop
Enable moving of multiple selected events using allowMultiMove property of the JavaScript Scheduler component.
Set the multiMoveVerticalMode to "All"
. That will ensure that all selected events will be moved vertically.
In the onEventMove event handler (which is fired before the event position is updated after drop) we need to detect the Ctrl
/Meta
key state. If the modifier key is pressed, we will copy the events:
We cancel the default action (update of the selected events positions) using
args.preventDefault()
.We create new events using events.add() at the target position. Selected properties of the source events can be copied here, we use the modified text.
Please note that the new events need to have different IDs (duplicate event IDs are not allowed). In this example, we simply generate a random ID on the client side. Normally you would call the API and use the IDs generated by the database.
In this case it’s not possible to use onEventMoved event handler - this event is fired after the events are already updated.
allowMultiMove: true, multiMoveVerticalMode: "All", onEventMove: args => { const copy = args.ctrl || args.meta; if (copy) { args.preventDefault(); args.multimove.forEach(item => { dp.events.add({ start: item.start, end: item.end, id: DayPilot.guid(), text: "Copy of " + item.event.text(), resource: item.resource }); }); } },
Copy Events using Context Menu (Copy & Paste)
The event context menu (defined using contextMenu property) needs to include the “Copy” item.
It stores the selected events in the global clipboard
variable.
let clipboard = []; const dp = new DayPilot.Scheduler("dp", { // ... contextMenu: new DayPilot.Menu({ items: [ { text: "Copy", onClick: args => { clipboard = dp.multiselect.events(); } } ] }), }); dp.init();
Now we need to add the “Paste” item to the time range selection context menu (contextMenuSelection):
contextMenuSelection: new DayPilot.Menu({ onShow: args => { const pasteEnabled = clipboard.length > 0; dp.contextMenuSelection.items[0].disabled = !pasteEnabled; dp.contextMenuSelection.items[1].disabled = !pasteEnabled; }, items: [ { text: "Paste", onClick: args => { const ref = clipboard[0]; const refRowIndex = dp.rows.find(ref.data.resource).index; const selection = args.source; const targetRowIndex = dp.rows.find(selection.resource).index; const events = clipboard.map(e => { const srcRowIndex = dp.rows.find(e.data.resource).index; const rowOffset = srcRowIndex - refRowIndex; const rowIndex = targetRowIndex + rowOffset; const cell = dp.cells.findXy(0, rowIndex)[0]; if (!cell) { return null; } const resource = dp.cells.findXy(0, rowIndex)[0].resource; const duration = e.duration(); // milliseconds const offset = e.start().getTime() - ref.start().getTime(); const start = selection.start.addTime(offset); const end = start.addTime(duration); return new DayPilot.Event({ start, end, text: "Copy of " + e.text(), resource, id: DayPilot.guid() }); }); events.forEach(e => { dp.events.add(e); }); dp.clearSelection(); } }, { text: "Paste into the same row", onClick: args => { const ref = clipboard[0]; const selection = args.source; clipboard.forEach(e=> { const duration = e.duration(); // milliseconds const offset = e.start().getTime() - ref.start().getTime(); const start = selection.start.addTime(offset); const end = start.addTime(duration); var newEvent = new DayPilot.Event({ start, end, text: "Copy of " + e.text(), resource: selection.resource, id: DayPilot.guid() // generate random id }); dp.events.add(newEvent); }); dp.clearSelection(); } } ] })
The onClick
handler of the “Paste” item calculates the relative position for each of the events in the clipboard and creates a corresponding new event in the JavaScript Scheduler.
For reference, the context menu also includes “Paste into the same row” which places all copied events in the same target row.
Full Source Code
And here is the complete source code of our example that configures the JavaScript Scheduler to allow copying emultiple vents using context menu and drag and drop.
<!DOCTYPE html> <html> <head> <meta charset="utf-8"/> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>JavaScript Scheduler: Copy Multiple Events</title> <style type="text/css"> /* ... */ </style> <!-- DayPilot library --> <script src="js/daypilot/daypilot-all.min.js"></script> </head> <body> <div class="header"> <h1><a href='https://code.daypilot.org/72047/javascript-scheduler-copy-multiple-events'>JavaScript Scheduler: Copy Multiple Events</a></h1> <div><a href="https://javascript.daypilot.org/">DayPilot for JavaScript</a> - HTML5 Calendar/Scheduling Components for JavaScript/Angular/React/Vue</div> </div> <div class="main"> <div class="space"> Select multiple events using Ctrl+click (or <a href="javascript: dp.events.all().forEach(e => dp.multiselect.add(e))">select all</a>) and right click to copy and paste. You can also copy events using Ctrl+drag. </div> <div id="dp"></div> <div class="generated">Generated using <a href="https://builder.daypilot.org/">DayPilot UI Builder</a>.</div> </div> <script> let clipboard = []; const dp = new DayPilot.Scheduler("dp", { timeHeaders: [{"groupBy":"Month"},{"groupBy":"Day","format":"d"}], scale: "Day", days: 30, startDate: "2021-04-01", timeRangeSelectedHandling: "Enabled", allowMultiSelect: true, onTimeRangeSelected: async args => { const modal = await DayPilot.Modal.prompt("Create a new event:", "Event 1"); dp.clearSelection(); if (modal.canceled) { return; } dp.events.add({ start: args.start, end: args.end, id: DayPilot.guid(), resource: args.resource, text: modal.result }); }, eventClickHandling: "Select", allowMultiMove: true, multiMoveVerticalMode: "All", treeEnabled: true, onEventMove: args => { const copy = args.ctrl || args.meta; if (copy) { args.preventDefault(); args.multimove.forEach(item => { dp.events.add({ start: item.start, end: item.end, id: DayPilot.guid(), text: "Copy of " + item.event.text(), resource: item.resource }); }); } }, contextMenu: new DayPilot.Menu({ items: [ { text: "Copy", onClick: args => { clipboard = dp.multiselect.events(); } } ] }), contextMenuSelection: new DayPilot.Menu({ onShow: args => { const pasteEnabled = clipboard.length > 0; dp.contextMenuSelection.items[0].disabled = !pasteEnabled; dp.contextMenuSelection.items[1].disabled = !pasteEnabled; }, items: [ { text: "Paste", onClick: args => { const ref = clipboard[0]; const refRowIndex = dp.rows.find(ref.data.resource).index; const selection = args.source; const targetRowIndex = dp.rows.find(selection.resource).index; const events = clipboard.map(e => { const srcRowIndex = dp.rows.find(e.data.resource).index; const rowOffset = srcRowIndex - refRowIndex; const rowIndex = targetRowIndex + rowOffset; const cell = dp.cells.findXy(0, rowIndex)[0]; if (!cell) { return null; } const resource = dp.cells.findXy(0, rowIndex)[0].resource; const duration = e.duration(); // milliseconds const offset = e.start().getTime() - ref.start().getTime(); const start = selection.start.addTime(offset); const end = start.addTime(duration); return new DayPilot.Event({ start, end, text: "Copy of " + e.text(), resource, id: DayPilot.guid() }); }); events.forEach(e => { dp.events.add(e); }); dp.clearSelection(); } }, { text: "Paste into the same row", onClick: args => { const ref = clipboard[0]; const selection = args.source; clipboard.forEach(e=> { const duration = e.duration(); // milliseconds const offset = e.start().getTime() - ref.start().getTime(); const start = selection.start.addTime(offset); const end = start.addTime(duration); var newEvent = new DayPilot.Event({ start, end, text: "Copy of " + e.text(), resource: selection.resource, id: DayPilot.guid() // generate random id }); dp.events.add(newEvent); }); dp.clearSelection(); } } ] }) }); dp.resources = [ {name: "Resource 1", id: "R1"}, {name: "Resource 2", id: "R2"}, {name: "Resource 3", id: "R3"}, {name: "Resource 4", id: "R4"}, {name: "Resource 5", id: "R5"}, {name: "Resource 6", id: "R6"}, {name: "Resource 7", id: "R7"}, {name: "Resource 8", id: "R8"}, {name: "Resource 9", id: "R9"}, ]; dp.events.list = [{"start":"2021-04-05T00:00:00","end":"2021-04-10T00:00:00","id":"d0d4fe15-edde-728e-d75b-d31b36a9e1eb","resource":"R3","text":"Event 1"},{"start":"2021-04-08T00:00:00","end":"2021-04-13T00:00:00","id":"60e400c6-0dc9-cf4e-25b3-1d955670fe0d","resource":"R4","text":"Event 1"},{"start":"2021-04-10T00:00:00","end":"2021-04-12T00:00:00","id":"6d96bfcb-51ce-4406-45e7-e82ff824a3b7","resource":"R5","text":"Event 1"}]; dp.init(); </script> </body> </html>
Recommend
-
8
FeaturesJavaScript Scheduler with client-side undo/redo functionalityThe universal UndoService stores history of all changes and provides undo() and redo() functions
-
72
How to define your own Scheduler event types and customize the appearance. You can change the event type using a context menu or a modal dialog.
-
8
FeaturesZoom using HTML5 slider controlZoom using buttons: [+] and [-]Custom zoom levels with defined properties (scale, visible days, time headers...)Includes a trial version o...
-
18
How to configure Scheduler event boxes to accept items from an external list (drag and drop). Implemented using standard HTML5 drag and drop API.
-
16
FeaturesJavaScript Scheduler component that displays timeline on the horizontal axis and resources on the vertical axisYou can use customization event h...
-
10
How to group related events into a single event in the JavaScript Scheduler component and add expand [+] and collapse [-] icons that allow changing the event visibility.
-
16
FeaturesGlobal read-only mode (all drag and drop operations disabled)Per-event read-only mode (drag and drop disabled for individual events)JavaScript/HTML5 project generated using
-
13
FeaturesImplementing custom snap-to-grid rules using onTimeRangeSelecting, onEventMoving and onEventResizing event handlersThe snap-to-grid matrix doesn't have to corresp...
-
32
How to link the JavaScript Scheduler component to a date picker that can change the visible date.
-
9
OverviewSince version 2021.3.5070, DayPilot Pro makes the pure JavaScript version available as a NPM package (daypilot-pro-javascrip...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK