如何通过ctrl复制事件,在FullCalendar v5中拖放 - 仅限纯javascript

Rad*_*dek 6 javascript fullcalendar fullcalendar-5

我想仅CTRL + Drag & Drop使用PURE JavaScript在 FullCalendar v5 中实现。

我对主题进行了研究,发现这是在 FC github 上作为新功能 UI 请求进行讨论的。很少有建议如何做到这一点,即使是可行的建议。

arshaw 发表于 2015 年 8 月 19 日

You can use eventDrop to create this feature. jsEvent has a ctrlKey
on which you can test. Copy the event, received as a parameter, in a new variable.
revertFunc to make go back, and then apply renderEvent with the new variable created.
Run Code Online (Sandbox Code Playgroud)

chris-verclytte 发布于 2016 年 4 月 11 日对我没有任何帮助

If it can help, here is a little trick I use waiting for this new feature to be integrated.
In eventDrop callback

    // If no alt key pressed we move the event, else we duplicate it
    if (!jsEvent.altKey) {
        // Handle drag'n'drop copy
    } else {
        // Handle drag'n'drop duplication
        // Here I add the event to event source
        _addEventToSelectedSource(event.start, event.end);
        // "Disable" the default behavior using revertFunc to avoid event moving
         revertFunc();
    }
The only problem with this is that the copied event disappears during drag'n'drop due to https://github.com/fullcalendar/fullcalendar/blob/master/src/common/Grid.events.js#L273
Run Code Online (Sandbox Code Playgroud)

我喜欢AllyMurray 于 2018 年 7 月 13 日发布的最佳解决方案

For anyone that comes across this issue, I have created a solution that should give you a starting point to work from. It uses the same approach as external events and leaves the original event in place.

/sf/answers/3592939171/
https://codepen.io/ally-murray/full/JBdaBV/
Run Code Online (Sandbox Code Playgroud)

但我不知道如何在纯 javascript 中实现这个解决方案。

有人可以帮忙吗?我更喜欢复制按 CTRL 键意味着复制的方式工作,因此原始事件保持在原始位置。

js小提琴

Twi*_*her 8

我有一个可行的最小解决方案。它包括在Ctrl持有密钥的情况下在其原始日期克隆移动的事件。

要测试此代码片段,只需在测试之前单击页面顶部的输入,否则结果iframe不会获得焦点,也不会触发keydown事件keyup

// Beginning of the workaround for this: https://github.com/fullcalendar/fullcalendar/blob/3e89de5d8206c32b6be326133b6787d54c6fd66c/packages/interaction/src/dnd/PointerDragging.ts#L306
const ctrlKeyDescriptor = Object.getOwnPropertyDescriptor(
  MouseEvent.prototype,
  'ctrlKey'
);

// Always return false for event.ctrlKey when event is of type MouseEvent
ctrlKeyDescriptor.get = function() {
  return false;
};

Object.defineProperty(MouseEvent.prototype, 'ctrlKey', ctrlKeyDescriptor);
// End of the workaround

let calendarEl = document.getElementById('calendar-container');

// Hold the ctrlKey state, emit events to the subscribers when it changes
const ctrlKeyChanged = (function() {
  let ctrlHeld = false;
  let subscriptions = [];
  ['keydown', 'keyup'].forEach(x =>
    document.addEventListener(x, e => {
      // emit only when the key state has changed
      if (ctrlHeld !== e.ctrlKey) subscriptions.forEach(fun => fun(e.ctrlKey));

      ctrlHeld = e.ctrlKey;
    })
  );

  function subscribe(callback) {
    subscriptions.push(callback);
    callback(ctrlHeld); // Emit the current state (case when Ctrl is already being held)
  }

  function unsubscribe(callback) {
    const index = subscriptions.indexOf(callback);
    subscriptions.splice(index, 1);
  }

  return { subscribe, unsubscribe };
})();

const extractEventProperties = ({ title, start, end, allDay }) => ({
  title,
  start,
  end,
  allDay
});

const callbackKey = Symbol();

let calendar = new FullCalendar.Calendar(calendarEl, {
  editable: true,
  droppable: true,
  eventDragStart: e => {
    let event;
    const callback = ctrlKey => {
      if (ctrlKey) {
        event = calendar.addEvent(extractEventProperties(e.event));
      } else {
        event && event.remove();
      }
    };
    ctrlKeyChanged.subscribe(callback);
    // store the callback for further unsubscribe
    e.event.setExtendedProp(callbackKey, callback); 
  },
  // stop listening when the event has been dropped
  eventDragStop: e => ctrlKeyChanged.unsubscribe(e.event.extendedProps[callbackKey]),
  events: [
    {
      title: 'event1',
      start: new Date,
      allDay: true // will make the time show
    },
    {
      title: 'event2',
      start: new Date().setDate(new Date().getDate() + 1),
      end: new Date().setDate(new Date().getDate() + 1)
    },
    {
      title: 'event3',
      start: new Date().setDate(new Date().getDate() - 1),
      allDay: true
    }
  ]
});

calendar.render();
Run Code Online (Sandbox Code Playgroud)
<link href="https://cdn.jsdelivr.net/npm/fullcalendar@5.6.0/main.min.css" rel="stylesheet"/>
<script src="https://cdn.jsdelivr.net/npm/fullcalendar@5.6.0/main.min.js"></script>

<input placeholder="Click here to give the focus to the result iframe">
<div id="calendar-container"></div>
Run Code Online (Sandbox Code Playgroud)

Ctrl主要的困难是 Fullcalendar 在按住按键时禁用拖动行为:

// Returns a boolean whether this was a left mouse click and no ctrl key (which means right click on Mac)
function isPrimaryMouseButton(ev: MouseEvent) {
  return ev.button === 0 && !ev.ctrlKey
}
Run Code Online (Sandbox Code Playgroud)

您可以在此处的官方存储库中看到此代码,该代码在此处被调用

解决方法包括进行变异,MouseEvent.prototype以便false在访问 时始终返回ctrlKey

如果您有兴趣,我已经提供了解决方案: