JavaScript Scheduler

Copy Events using Ctrl+Drag (or Meta+Drag)

javascript scheduler event copying ctrl meta

The status of Ctrl and Shift keys is saved in args.ctrl and args.shift properties in onEventMove and onEventMoved events.

We need to use onEventMove instead of onEventMoved - this way we can cancel the default action by calling args.preventDefault(). This will prevent moving the source event to the new location. Instead, we will create a copy.

<div id="dp"></div>
<script type="text/javascript">
  const dp = new DayPilot.Scheduler("dp", {
    onEventMove: (args) => {
      if (args.ctrl) {
        const newEvent = {
          start: args.newStart,
          end: args.newEnd,
          text: "Copy of " + args.e.text(),
          resource: args.newResource,
          id: DayPilot.guid()  // generate random id
        };
        dp.events.add(newEvent);

        // send the action to the server using an HTTP call here

        args.preventDefault(); // prevent the default action - moving event to the new location
      }
    },

    // ...

  });
  dp.init();
</script>

Copy and Paste Events using Context Menu

1. Create a copied global variable that will hold the the copied event (DayPilot.Event object).

<script type="text/javascript">
let copied = null;
</script> 

2. Add a "Copy" command to the event context menu (contextMenu).

javascript scheduler event copy context menu

<div id="dp"></div>
<script type="text/javascript">
  const dp = new DayPilot.Scheduler("dp", {
    contextMenu: new DayPilot.Menu({
      items: [
        {text:"Copy", onClick: args => copied = args.source }
      ],
    }),
    // ...
  });
  dp.init();
</script>

The onClick handler of menu item stores the selected event in the copied variable.

3. Add a "Paste" command to the cell context menu (contextMenuSelection):

javascript scheduler event paste context menu

<div id="dp"></div>
<script type="text/javascript">
  const  dp = new DayPilot.Scheduler("dp", {
    contextMenuSelection: new DayPilot.Menu({
      items: [
        {
          text: "Paste", onClick: args => {
            if (!copied) {
              alert('You need to copy an event first.'); 
              return; 
            } 
            const selection = args.source;
            const duration = copied.end().getTime() - copied.start().getTime(); // milliseconds
            const newEvent = {
              start: selection.start,
              end: selection.start.addMilliseconds(duration),
              text: "Copy of " + copied.text(),
              resource: selection.resource,
              id: DayPilot.guid()  // generate random id
            };
            dp.events.add(newEvent);
            dp.clearSelection();

            // send the action to the server using an HTTP call here

          }
        }
      ]
    }),
    
    // ...
  
  });
  dp.init();
</script>

You can also clear the copied variable:

copied = null;

Tutorial

Angular Scheduler

Tutorial

angular scheduler event copy cut and paste

Angular Scheduler: Event Cut, Copy & Paste

Angular scheduling project that allows moving events using "cut and paste" and creating events from existing ones using "copy and paste" actions (with support for selecting multiple events).

ASP.NET WebForms

Ctrl during Drag and Drop

Ctrl and Shift key status is saved in "ctrl" and "shift" variables available to the JavaScript EventMove handler (EventMoveJavaScript).

.aspx

EventMoveHandling="JavaScript"
EventMoveJavaScript="dps1.eventMoveCallBack(e, newStart, newEnd, newResource, {ctrl: ctrl, shift: shift} )"

.aspx.cs

protected void DayPilotScheduler1_EventMove(object sender, DayPilot.Web.Ui.Events.EventMoveEventArgs e)
{
  bool shift = (bool) e.Data["shift"];
  bool ctrl = (bool) e.Data["ctrl"];

  if (ctrl) {
    // copy the event in the DB (INSERT)
  }
  else if (shift) {
    // move the event in the DB (UPDATE)
  }

  setDataSourceAndBind(); // custom method that loads the data from a DB, assigns DataSource and calls DataBind()
  DayPilotScheduler1.Update("Event moved");
}

Copy and Paste (Context Menu)

This sample shows how to implement a copy & paste functionality using context menu in the Scheduler control.

1. Add a global variable that will hold the id of the copied event.

<script type="text/javascript">
var copied = null;
</script> 

2. Add a "Copy" command to the event context menu (ContextMenuID).

calendar menu copy

<daypilot:daypilotmenu id="DayPilotMenu1" runat="server" CssClassPrefix="menu_default" ShowMenuTitle="true">
        <DayPilot:MenuItem Text="Copy" Action="JavaScript" JavaScript="copied = e.value();" ></DayPilot:MenuItem>
</daypilot:daypilotmenu>

This menu item will store the ID of the selected event in the "copied" variable.

3. Add a "Paste" command to the cell context menu (ContextMenuSelectionID):

calendar menu paste

<DayPilot:DayPilotMenu ID="DayPilotMenuSelection" runat="server" CssClassPrefix="menu_default">
        <DayPilot:MenuItem Action="JavaScript" JavaScript="if (!copied) { alert('You need to copy an event first.'); return; } dps1.commandCallBack('paste', {id:copied, start: e.start});" Text="Paste" />
</DayPilot:DayPilotMenu>

This menu item will execute Command event on the server side, using "paste" as the command, and sending the ID of the copied event under the "id" key and the selected time start under the "start" key.

You can also clear the copied variable:

copied = null;

4. Handle the Command event on the server side. Create a new event from the copied one.

protected void DayPilotScheduler1_Command(object sender, CommandEventArgs e)
{
  switch (e.Command)
  {
    case "paste":
      DateTime pasteHere = (DateTime) e.Data["start"];
      string id = (string) e.Data["id"];

      // find the event using id
      // create a new database record using the original event properties

      DayPilotScheduler1.DataSource = loadEvents(); // your method, load events from database
      DayPilotScheduler1.DataBind();
      DayPilotScheduler1.UpdateWithMessage("Event copied.");
      break;
  }
}

ASP.NET MVC

Ctrl during Drag and Drop

Ctrl and Shift key status is saved in "ctrl" and "shift" variables available to the JavaScript EventMove handler (EventMoveJavaScript).

.aspx

EventMoveHandling = EventMoveHandlingType.JavaScript,
EventMoveJavaScript = "dps1.eventMoveCallBack(e, newStart, newEnd, newResource, {ctrl: ctrl, shift: shift} )"

.aspx.cs

protected override void OnEventMove(EventMoveArgs e)
{
  bool shift = (bool) e.Data["shift"];
  bool ctrl = (bool) e.Data["ctrl"];

  if (ctrl) {
    // copy the event in the DB (INSERT)
  }
  else if (shift) {
    // move the event in the DB (UPDATE)
  }

  UpdateWithMessage("Event moved");
}

Copy and Paste (Context Menu)

1. Add a global variable that will hold the id of the copied event.

<script type="text/javascript">
var copied = null;
</script> 

2. Add a "Copy" command to the event context menu (ContextMenu).

calendar menu copy

@Html.DayPilotMenu("menu_event", new DayPilotMenuConfig {
  CssClassPrefix = "menu_default",
  Items = new DayPilot.Web.Mvc.MenuItemCollection
  {
    new DayPilot.Web.Mvc.MenuItem { Text = "Copy", Action = MenuItemAction.JavaScript, JavaScript = "copied = e.value();"}
  }
})

@Html.DayPilotScheduler("dps", new DayPilotSchedulerConfig {
  BackendUrl = ResolveUrl("~/Scheduler/Backend"),
  ...
  ContextMenu = "menu_event"
})

This menu item will store the ID of the selected event in the "copied" variable.

3. Add a "Paste" command to the cell context menu (ContextMenuSelection):

calendar menu paste

@Html.DayPilotMenu("menu_selection", new DayPilotMenuConfig {
  CssClassPrefix = "menu_default",
  Items = new DayPilot.Web.Mvc.MenuItemCollection
  {
    new DayPilot.Web.Mvc.MenuItem { Text = "Paste", Action = MenuItemAction.JavaScript, JavaScript = "if (!copied) { alert('You need to copy an event first.'); return; } dps1.commandCallBack('paste', {id:copied, start: e.start});"}
  }
})

@Html.DayPilotScheduler("dps", new DayPilotSchedulerConfig {
  BackendUrl = ResolveUrl("~/Scheduler/Backend"),
  ...
  ContextMenuSelection = "menu_selection"
})

This menu item will execute Command event on the server side, using "paste" as the command, and sending the ID of the copied event under the "id" key and the selected time start under the "start" key.

You can also clear the copied variable:

copied = null;

4. Handle the OnCommand event on the server side. Create a new event from the copied one.

protected override void OnCommand(CommandArgs e)
{
  switch (e.Command)
  {
    case "paste":
      DateTime pasteHere = (DateTime) e.Data["start"];
      string id = (string) e.Data["id"];

      // 1. find the event using id
      // 2. create a new database record using the original event properties
      // 3. reload events to Events

      UpdateWithMessage("Event copied.");
      break;
  }
}