如何通过 ctrl 复制事件,在 FullCalendar v5 中拖放 - 仅限纯 javascript
How to copy events via ctrl, drag & drop in FullCalendar v5 - pure javascript only
我想在 FullCalendar v5 中实现 CTRL + Drag & Drop
仅使用 PURE JavaScript。
我对 主题 进行了研究,发现它在 FC github 上作为 new feature UI request 进行了讨论。几乎没有关于如何做到这一点的建议,甚至是可行的建议。
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.
chris-verclytte posted on Apr 11, 2016 对我没有任何作用
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
我喜欢 AllyMurray posted on Jul 13, 2018
的最佳解决方案
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.
https://codepen.io/ally-murray/full/JBdaBV/
但我不知道如何在纯 javascript 中实现此解决方案。
有人能帮忙吗?我更喜欢复制的工作方式,即按 CTRL 键表示复制,这样原始事件就保持在原来的位置。
我有一个可行的最小解决方案。如果按住 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();
<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>
主要的困难是 Fullcalendar 在按住 Ctrl 键时禁用拖动行为:
// 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
}
你可以在官方仓库中看到这段代码here which is being called here
解决方法包括改变 MouseEvent.prototype
以便在访问 ctrlKey
.
时总是 return false
如果您有兴趣,我已经提供了解决方案:
- 作为 Stackblitz demo 和 TypeScript
- 作为带有 TypeScript 和 Webpack 的完整独立项目:https://github.com/Guerric-P/fullcalendar-drag-and-drop-copy
我想在 FullCalendar v5 中实现 CTRL + Drag & Drop
仅使用 PURE JavaScript。
我对 主题 进行了研究,发现它在 FC github 上作为 new feature UI request 进行了讨论。几乎没有关于如何做到这一点的建议,甚至是可行的建议。
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.
chris-verclytte posted on Apr 11, 2016 对我没有任何作用
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
我喜欢 AllyMurray posted on Jul 13, 2018
的最佳解决方案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.
https://codepen.io/ally-murray/full/JBdaBV/
但我不知道如何在纯 javascript 中实现此解决方案。
有人能帮忙吗?我更喜欢复制的工作方式,即按 CTRL 键表示复制,这样原始事件就保持在原来的位置。
我有一个可行的最小解决方案。如果按住 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();
<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>
主要的困难是 Fullcalendar 在按住 Ctrl 键时禁用拖动行为:
// 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
}
你可以在官方仓库中看到这段代码here which is being called here
解决方法包括改变 MouseEvent.prototype
以便在访问 ctrlKey
.
false
如果您有兴趣,我已经提供了解决方案:
- 作为 Stackblitz demo 和 TypeScript
- 作为带有 TypeScript 和 Webpack 的完整独立项目:https://github.com/Guerric-P/fullcalendar-drag-and-drop-copy