/** * DragDropOverrides.js * * Released under LGPL License. * Copyright (c) 1999-2015 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /** * This module contains logic overriding the drag/drop logic of the editor. * * @private * @class tinymce.DragDropOverrides */ define("tinymce/DragDropOverrides", [ "tinymce/dom/NodeType", "tinymce/util/Arr", "tinymce/util/Fun" ], function( NodeType, Arr, Fun ) { var isContentEditableFalse = NodeType.isContentEditableFalse, isContentEditableTrue = NodeType.isContentEditableTrue; function init(editor) { var $ = editor.$, rootDocument = document, editableDoc = editor.getDoc(), dom = editor.dom, state = {}; function isDraggable(elm) { return isContentEditableFalse(elm); } function setBodyCursor(cursor) { $(editor.getBody()).css('cursor', cursor); } function isValidDropTarget(elm) { if (elm == state.element || editor.dom.isChildOf(elm, state.element)) { return false; } if (isContentEditableFalse(elm)) { return false; } return true; } function move(e) { var deltaX, deltaY, pos, viewPort, overflowX = 0, overflowY = 0, movement, clientX, clientY, rootClientRect; if (e.button !== 0) { return; } deltaX = e.screenX - state.screenX; deltaY = e.screenY - state.screenY; movement = Math.max(Math.abs(deltaX), Math.abs(deltaY)); if (!state.dragging && movement > 10) { state.dragging = true; setBodyCursor('default'); state.clone = state.element.cloneNode(true); pos = dom.getPos(state.element); state.relX = state.clientX - pos.x; state.relY = state.clientY - pos.y; state.width = state.element.offsetWidth; state.height = state.element.offsetHeight; $(state.clone).css({ width: state.width, height: state.height }).removeAttr('data-mce-selected'); state.ghost = $('
').css({ position: 'absolute', opacity: 0.5, overflow: 'hidden', width: state.width, height: state.height }).attr({ 'data-mce-bogus': 'all', unselectable: 'on', contenteditable: 'false' }).addClass('mce-drag-container mce-reset'). append(state.clone). appendTo(editor.getBody())[0]; viewPort = editor.dom.getViewPort(editor.getWin()); state.maxX = viewPort.w; state.maxY = viewPort.h; } if (state.dragging) { editor.selection.placeCaretAt(e.clientX, e.clientY); clientX = state.clientX + deltaX - state.relX; clientY = state.clientY + deltaY + 5; if (clientX + state.width > state.maxX) { overflowX = (clientX + state.width) - state.maxX; } if (clientY + state.height > state.maxY) { overflowY = (clientY + state.height) - state.maxY; } if (editor.getBody().nodeName != 'BODY') { rootClientRect = editor.getBody().getBoundingClientRect(); } else { rootClientRect = {left: 0, top: 0}; } $(state.ghost).css({ left: clientX - rootClientRect.left, top: clientY - rootClientRect.top, width: state.width - overflowX, height: state.height - overflowY }); } } function drop() { var evt; if (state.dragging) { // Hack for IE since it doesn't sync W3C Range with IE Specific range editor.selection.setRng(editor.selection.getSel().getRangeAt(0)); if (isValidDropTarget(editor.selection.getNode())) { var targetClone = state.element; evt = editor.fire('drop', {targetClone: targetClone}); if (evt.isDefaultPrevented()) { return; } targetClone = evt.targetClone; editor.undoManager.transact(function() { editor.insertContent(dom.getOuterHTML(targetClone)); $(state.element).remove(); }); } } stop(); } function start(e) { var ceElm, evt; stop(); if (e.button !== 0) { return; } ceElm = Arr.find(editor.dom.getParents(e.target), Fun.or(isContentEditableFalse, isContentEditableTrue)); if (isDraggable(ceElm)) { evt = editor.fire('dragstart', {target: ceElm}); if (evt.isDefaultPrevented()) { return; } editor.on('mousemove', move); editor.on('mouseup', drop); if (rootDocument != editableDoc) { dom.bind(rootDocument, 'mousemove', move); dom.bind(rootDocument, 'mouseup', drop); } state = { screenX: e.screenX, screenY: e.screenY, clientX: e.clientX, clientY: e.clientY, element: ceElm }; } } function stop() { $(state.ghost).remove(); setBodyCursor(null); editor.off('mousemove', move); editor.off('mouseup', stop); if (rootDocument != editableDoc) { dom.unbind(rootDocument, 'mousemove', move); dom.unbind(rootDocument, 'mouseup', stop); } state = {}; } editor.on('mousedown', start); // Blocks drop inside cE=false on IE editor.on('drop', function(e) { var realTarget = editor.getDoc().elementFromPoint(e.clientX, e.clientY); if (isContentEditableFalse(realTarget) || isContentEditableFalse(editor.dom.getContentEditableParent(realTarget))) { e.preventDefault(); } }); } return { init: init }; });