Cut, Copy, Paste Events

While copy & pasting one or more events is useful, sometimes being able to move events between two separate calendars can improve productivity. How the calendars are laid out depends on the application, but the basic idea is that you will need to be able to tell where the events from the clipboard will be pasted.

In this example this is implemented by tracking the active instance, which is determined by the active tab of the segmented control. With this out of the way, CTRL/CMD+C/X/Z/V handle the copy, cut, undo and paste actions.

Looking for multiple event selection & bulk operations?  Take a look at the previous example →
Download and try example

Demo

Loading the live demo

Preview in full screen

Transfer events between two event calendars with cut, copy, paste, and undo — using keyboard shortcuts or a right-click menu.

Code

mobiscroll.setOptions({
  locale:  ,
  theme: ' ',
  themeVariant: ' '
});

var containerElm = document.getElementById('demo-copy-cut-paste-cont');
var firstContainer = document.getElementById('demo-copy-cut-paste-first-cont');
var secondContainer = document.getElementById('demo-copy-cut-paste-second-cont');
var dummyElm = document.getElementById('my-focus');
var selectedEvents = [];
var deletedEvents = [];
var cutEvents = [];
var pastedEvents = [];
var today = new Date();
var toDate;
var originDate;
var firstToDate = today;
var secondToDate = today;
var activeInst;
var originInst;
var cutInst;
var menuOpen;
var action;
var menuData = [
  { text: 'Copy', value: 'c' },
  { text: 'Cut', value: 'x' },
  { text: 'Paste', value: 'v' },
  { text: 'Delete', value: 'delete' },
];
var disabledMenu = [
  { text: 'Copy', value: 'c', disabled: true },
  { text: 'Cut', value: 'x', disabled: true },
  { text: 'Paste', value: 'v' },
  { text: 'Delete', value: 'delete', disabled: true },
];
var calendarSettings = {
  clickToCreate: true,
  dragToCreate: true,
  dragToMove: true,
  dragToResize: true,
  selectMultipleEvents: true,
  view: {
    calendar: {
      labels: 'all',
    },
  },
  onSelectedEventsChange: function (args, inst) {
    if (inst === secondInst) {
      secondInst.setSelectedEvents(args.events);
    } else {
      firstInst.setSelectedEvents(args.events);
    }
  },
  onPageLoading: function (args, inst) {
    if (inst === secondInst) {
      secondToDate = args.month;
    } else {
      firstToDate = args.month;
    }
    toDate = args.month;
  },
  onCellRightClick: function (args, inst) {
    if (!menuOpen) {
      args.domEvent.preventDefault();
      menu.setOptions({
        data: disabledMenu,
        anchor: args.domEvent.target,
      });
      setTimeout(function () {
        menu.open();
      });
      activeInst = inst;
    }
  },
  onEventRightClick: function (args, inst) {
    if (inst.getSelectedEvents().length <= 1) {
      inst.setSelectedEvents([args.event]);
    }
    args.domEvent.preventDefault();
    menu.setOptions({
      data: menuData,
      anchor: args.domEvent.target,
    });
    setTimeout(function () {
      menu.open();
    });
    activeInst = inst;
    menuOpen = true;
  },
  onEventDeleted: function (args, inst) {
    deletedEvents = args.events;
    originInst = inst;
    action = 'delete';
    mobiscroll.snackbar({
      button: {
        action: function () {
          inst.addEvent(deletedEvents);
          deletedEvents = [];
        },
        text: 'Undo',
      },
      duration: 3000,
      message: 'Event' + (deletedEvents.length === 1 ? '' : 's') + ' deleted',
    });
    dummyElm.focus();
  },
};
var firstInst = mobiscroll.eventcalendar(
  '#demo-copy-cut-paste-first',
  Object.assign(
    {
      data: [
        {
          start: '2026-10-02T09:00',
          end: '2026-10-06T18:00',
          title: 'Business of Software Conference',
          color: '#ff6d42',
        },
        {
          start: '2026-10-10T07:00',
          end: '2026-10-10T08:00',
          title: 'Green box to post office',
          color: '#6e7f29',
        },
        {
          start: '2026-10-15T09:30',
          end: '2026-10-15T10:30',
          title: 'Product team mtg.',
          color: '#f67944',
        },
        {
          start: '2026-10-23T11:00',
          end: '2026-10-23T11:45',
          title: 'Stakeholder mtg.',
          color: '#a144f6',
        },
        {
          start: '2026-10-28T13:00',
          end: '2026-10-28T13:45',
          title: "Lunch @ Butcher's",
          color: '#00aabb',
        },
      ],
    },
    calendarSettings,
  ),
);
var secondInst = mobiscroll.eventcalendar(
  '#demo-copy-cut-paste-second',
  Object.assign(
    {
      data: [
        {
          start: '2026-10-04T08:45',
          end: '2026-10-04T10:00',
          title: 'Quick mtg. with Martin',
          color: '#de3d83',
        },
        {
          start: '2026-10-08T15:00',
          end: '2026-10-08T16:00',
          title: 'General orientation',
          color: '#a71111',
        },
        {
          start: '2026-10-10T13:00',
          end: '2026-10-14T21:00',
          title: 'Friends binge marathon',
          color: '#7bde83',
        },
        {
          start: '2026-10-23T08:00',
          end: '2026-10-27T09:00',
          title: 'Product team mtg.',
          color: '#913aa7',
        },
      ],
    },
    calendarSettings,
  ),
);
var menu = mobiscroll.select('#copy-cut-paste-menu', {
  touchUi: false,
  display: 'anchored',
  buttons: [],
  data: menuData,
  inputElement: document.getElementById('copy-cut-paste-menu-input'),
  onChange: function (args) {
    detectAction(args.value);
  },
  onClose: function () {
    menuOpen = false;
    // Clear selection
    menu.setVal();
  },
});

function monthDiff(d1, d2) {
  return d2.getMonth() - d1.getMonth() + 12 * (d2.getFullYear() - d1.getFullYear());
}

function pasteEvents() {
  var evLength = selectedEvents.length;
  if (evLength > 0) {
    for (var i = 0; i < evLength; ++i) {
      var event = Object.assign({}, selectedEvents[i]);
      var startDate = new Date(event.start);
      var endDate = new Date(event.end);
      var diff = Math.abs(endDate - startDate);

      event.start = startDate.setMonth(startDate.getMonth() - monthDiff(toDate, originDate));
      event.end = new Date(startDate.getTime() + diff);

      delete event.id;
      activeInst.addEvent(event);
      pastedEvents.push(event);
    }
    if (action === 'cut') {
      cutEvents = selectedEvents;
      cutInst = activeInst;
      originInst.removeEvent(selectedEvents);
      mobiscroll.snackbar({
        button: {
          action: function () {
            originInst.addEvent(cutEvents);
            cutInst.removeEvent(pastedEvents);
            mobiscroll.toast({
              message: 'Event' + (cutEvents.length === 1 ? '' : 's') + ' reverted',
            });
          },
          text: 'Undo',
        },
        duration: 3000,
        message: 'Event' + (selectedEvents.length === 1 ? '' : 's') + ' pasted',
      });
    } else {
      mobiscroll.toast({
        message: 'Event' + (evLength === 1 ? '' : 's') + ' pasted',
      });
    }
    dummyElm.focus();
    if (action !== 'copy') {
      selectedEvents = [];
    }
  }
}

function detectAction(key) {
  switch (key) {
    case 'delete': // Delete
      action = 'delete';
      originInst = activeInst;
      var selEvs = activeInst.getSelectedEvents();
      if (selEvs.length > 0) {
        activeInst.removeEvent(selEvs);
        deletedEvents = selEvs;
        mobiscroll.snackbar({
          button: {
            action: function () {
              activeInst.addEvent(selEvs);
              deletedEvents = [];
            },
            text: 'Undo',
          },
          duration: 3000,
          message: 'Event' + (selEvs.length === 1 ? '' : 's') + ' deleted',
        });
        dummyElm.focus();
      }
      break;
    case 'c': // Copy
      if (activeInst.getSelectedEvents().length > 0) {
        action = 'copy';
        selectedEvents = activeInst.getSelectedEvents();
        if (selectedEvents.length > 0) {
          originInst = activeInst;
          originDate = toDate;
          mobiscroll.toast({
            message: 'Event' + (selectedEvents.length === 1 ? '' : 's') + ' copied',
          });
        }
      }
      break;
    case 'x': // Cut
      if (activeInst.getSelectedEvents().length > 0) {
        action = 'cut';
        selectedEvents = activeInst.getSelectedEvents();
        if (selectedEvents.length > 0) {
          originInst = activeInst;
          deletedEvents = [];
          originDate = toDate;
          mobiscroll.toast({
            message: 'Event' + (selectedEvents.length === 1 ? '' : 's') + ' cut',
          });
        }
      }
      break;
    case 'z': // Undo
      if (action === 'delete') {
        originInst.addEvent(deletedEvents);
        deletedEvents = [];
      } else if (action === 'cut') {
        originInst.addEvent(cutEvents);
        cutInst.removeEvent(pastedEvents);
        cutEvents = [];
        pastedEvents = [];
      }
      break;
    case 'v': // Paste
      pasteEvents();
      break;
  }
}

document.querySelectorAll('.md-header-toggle').forEach(function (elm) {
  elm.addEventListener('change', function (ev) {
    if (ev.target.value === 'first') {
      firstContainer.classList.remove('md-hide-calendar');
      secondContainer.classList.add('md-hide-calendar');
      activeInst = firstInst;
      toDate = firstToDate;
      secondInst.setSelectedEvents([]);
    } else {
      secondContainer.classList.remove('md-hide-calendar');
      firstContainer.classList.add('md-hide-calendar');
      activeInst = secondInst;
      toDate = secondToDate;
      firstInst.setSelectedEvents([]);
    }
  });
});

containerElm.addEventListener('keydown', function (ev) {
  if (ev.ctrlKey || ev.metaKey) {
    detectAction(ev.key);
  }
  if (ev.key === 'Delete') {
    detectAction('delete');
  }
});

secondContainer.classList.add('md-hide-calendar');
activeInst = firstInst;
  

Duplicate Session

You have signed in on a different machine. To keep everything in sync, you have been signed out of this session.

If you need to invite team members, manage seats and accounts you can do it from the licenses page.

Duplicate Session

We noticed you are logged in on a different machine and have closed your old session.

If you need to invite team members, manage seats and accounts you can do it from the licenses page.