PHP Classes

File: public/js/tinymce/src/core/src/main/js/dom/ControlSelection.js

Recommend this page to a friend!
  Classes of Abed Nego Ragil Putra   GoLavaCMS   public/js/tinymce/src/core/src/main/js/dom/ControlSelection.js   Download  
File: public/js/tinymce/src/core/src/main/js/dom/ControlSelection.js
Role: Auxiliary data
Content type: text/plain
Description: Auxiliary data
Class: GoLavaCMS
Publish content on Web pages with SEO support
Author: By
Last change:
Date: 6 years ago
Size: 18,565 bytes
 

Contents

Class file image Download
/** * ControlSelection.js * * Released under LGPL License. * Copyright (c) 1999-2017 Ephox Corp. All rights reserved * * License: http://www.tinymce.com/license * Contributing: http://www.tinymce.com/contributing */ /** * This class handles control selection of elements. Controls are elements * that can be resized and needs to be selected as a whole. It adds custom resize handles * to all browser engines that support properly disabling the built in resize logic. * * @class tinymce.dom.ControlSelection */ define( 'tinymce.core.dom.ControlSelection', [ 'ephox.katamari.api.Fun', 'ephox.sugar.api.node.Element', 'ephox.sugar.api.search.Selectors', 'global!document', 'tinymce.core.dom.NodeType', 'tinymce.core.dom.RangePoint', 'tinymce.core.Env', 'tinymce.core.util.Delay', 'tinymce.core.util.Tools', 'tinymce.core.util.VK' ], function (Fun, Element, Selectors, document, NodeType, RangePoint, Env, Delay, Tools, VK) { var isContentEditableFalse = NodeType.isContentEditableFalse; var isContentEditableTrue = NodeType.isContentEditableTrue; var getContentEditableRoot = function (root, node) { while (node && node != root) { if (isContentEditableTrue(node) || isContentEditableFalse(node)) { return node; } node = node.parentNode; } return null; }; return function (selection, editor) { var dom = editor.dom, each = Tools.each; var selectedElm, selectedElmGhost, resizeHelper, resizeHandles, selectedHandle; var startX, startY, selectedElmX, selectedElmY, startW, startH, ratio, resizeStarted; var width, height, editableDoc = editor.getDoc(), rootDocument = document; var abs = Math.abs, round = Math.round, rootElement = editor.getBody(), startScrollWidth, startScrollHeight; // Details about each resize handle how to scale etc resizeHandles = { // Name: x multiplier, y multiplier, delta size x, delta size y /*n: [0.5, 0, 0, -1], e: [1, 0.5, 1, 0], s: [0.5, 1, 0, 1], w: [0, 0.5, -1, 0],*/ nw: [0, 0, -1, -1], ne: [1, 0, 1, -1], se: [1, 1, 1, 1], sw: [0, 1, -1, 1] }; // Add CSS for resize handles, cloned element and selected var rootClass = '.mce-content-body'; editor.contentStyles.push( rootClass + ' div.mce-resizehandle {' + 'position: absolute;' + 'border: 1px solid black;' + 'box-sizing: content-box;' + 'background: #FFF;' + 'width: 7px;' + 'height: 7px;' + 'z-index: 10000' + '}' + rootClass + ' .mce-resizehandle:hover {' + 'background: #000' + '}' + rootClass + ' img[data-mce-selected],' + rootClass + ' hr[data-mce-selected] {' + 'outline: 1px solid black;' + 'resize: none' + // Have been talks about implementing this in browsers '}' + rootClass + ' .mce-clonedresizable {' + 'position: absolute;' + (Env.gecko ? '' : 'outline: 1px dashed black;') + // Gecko produces trails while resizing 'opacity: .5;' + 'filter: alpha(opacity=50);' + 'z-index: 10000' + '}' + rootClass + ' .mce-resize-helper {' + 'background: #555;' + 'background: rgba(0,0,0,0.75);' + 'border-radius: 3px;' + 'border: 1px;' + 'color: white;' + 'display: none;' + 'font-family: sans-serif;' + 'font-size: 12px;' + 'white-space: nowrap;' + 'line-height: 14px;' + 'margin: 5px 10px;' + 'padding: 5px;' + 'position: absolute;' + 'z-index: 10001' + '}' ); var isImage = function (elm) { return elm && (elm.nodeName === 'IMG' || editor.dom.is(elm, 'figure.image')); }; var isEventOnImageOutsideRange = function (evt, range) { return isImage(evt.target) && !RangePoint.isXYWithinRange(evt.clientX, evt.clientY, range); }; var contextMenuSelectImage = function (evt) { var target = evt.target; if (isEventOnImageOutsideRange(evt, editor.selection.getRng()) && !evt.isDefaultPrevented()) { evt.preventDefault(); editor.selection.select(target); } }; var getResizeTarget = function (elm) { return editor.dom.is(elm, 'figure.image') ? elm.querySelector('img') : elm; }; var isResizable = function (elm) { var selector = editor.settings.object_resizing; if (selector === false || Env.iOS) { return false; } if (typeof selector != 'string') { selector = 'table,img,figure.image,div'; } if (elm.getAttribute('data-mce-resize') === 'false') { return false; } if (elm == editor.getBody()) { return false; } return Selectors.is(Element.fromDom(elm), selector); }; var resizeGhostElement = function (e) { var deltaX, deltaY, proportional; var resizeHelperX, resizeHelperY; // Calc new width/height deltaX = e.screenX - startX; deltaY = e.screenY - startY; // Calc new size width = deltaX * selectedHandle[2] + startW; height = deltaY * selectedHandle[3] + startH; // Never scale down lower than 5 pixels width = width < 5 ? 5 : width; height = height < 5 ? 5 : height; if (isImage(selectedElm) && editor.settings.resize_img_proportional !== false) { proportional = !VK.modifierPressed(e); } else { proportional = VK.modifierPressed(e) || (isImage(selectedElm) && selectedHandle[2] * selectedHandle[3] !== 0); } // Constrain proportions if (proportional) { if (abs(deltaX) > abs(deltaY)) { height = round(width * ratio); width = round(height / ratio); } else { width = round(height / ratio); height = round(width * ratio); } } // Update ghost size dom.setStyles(getResizeTarget(selectedElmGhost), { width: width, height: height }); // Update resize helper position resizeHelperX = selectedHandle.startPos.x + deltaX; resizeHelperY = selectedHandle.startPos.y + deltaY; resizeHelperX = resizeHelperX > 0 ? resizeHelperX : 0; resizeHelperY = resizeHelperY > 0 ? resizeHelperY : 0; dom.setStyles(resizeHelper, { left: resizeHelperX, top: resizeHelperY, display: 'block' }); resizeHelper.innerHTML = width + ' &times; ' + height; // Update ghost X position if needed if (selectedHandle[2] < 0 && selectedElmGhost.clientWidth <= width) { dom.setStyle(selectedElmGhost, 'left', selectedElmX + (startW - width)); } // Update ghost Y position if needed if (selectedHandle[3] < 0 && selectedElmGhost.clientHeight <= height) { dom.setStyle(selectedElmGhost, 'top', selectedElmY + (startH - height)); } // Calculate how must overflow we got deltaX = rootElement.scrollWidth - startScrollWidth; deltaY = rootElement.scrollHeight - startScrollHeight; // Re-position the resize helper based on the overflow if (deltaX + deltaY !== 0) { dom.setStyles(resizeHelper, { left: resizeHelperX - deltaX, top: resizeHelperY - deltaY }); } if (!resizeStarted) { editor.fire('ObjectResizeStart', { target: selectedElm, width: startW, height: startH }); resizeStarted = true; } }; var endGhostResize = function () { resizeStarted = false; var setSizeProp = function (name, value) { if (value) { // Resize by using style or attribute if (selectedElm.style[name] || !editor.schema.isValid(selectedElm.nodeName.toLowerCase(), name)) { dom.setStyle(getResizeTarget(selectedElm), name, value); } else { dom.setAttrib(getResizeTarget(selectedElm), name, value); } } }; // Set width/height properties setSizeProp('width', width); setSizeProp('height', height); dom.unbind(editableDoc, 'mousemove', resizeGhostElement); dom.unbind(editableDoc, 'mouseup', endGhostResize); if (rootDocument != editableDoc) { dom.unbind(rootDocument, 'mousemove', resizeGhostElement); dom.unbind(rootDocument, 'mouseup', endGhostResize); } // Remove ghost/helper and update resize handle positions dom.remove(selectedElmGhost); dom.remove(resizeHelper); showResizeRect(selectedElm); editor.fire('ObjectResized', { target: selectedElm, width: width, height: height }); dom.setAttrib(selectedElm, 'style', dom.getAttrib(selectedElm, 'style')); editor.nodeChanged(); }; var showResizeRect = function (targetElm) { var position, targetWidth, targetHeight, e, rect; hideResizeRect(); unbindResizeHandleEvents(); // Get position and size of target position = dom.getPos(targetElm, rootElement); selectedElmX = position.x; selectedElmY = position.y; rect = targetElm.getBoundingClientRect(); // Fix for Gecko offsetHeight for table with caption targetWidth = rect.width || (rect.right - rect.left); targetHeight = rect.height || (rect.bottom - rect.top); // Reset width/height if user selects a new image/table if (selectedElm != targetElm) { selectedElm = targetElm; width = height = 0; } // Makes it possible to disable resizing e = editor.fire('ObjectSelected', { target: targetElm }); if (isResizable(targetElm) && !e.isDefaultPrevented()) { each(resizeHandles, function (handle, name) { var handleElm; var startDrag = function (e) { startX = e.screenX; startY = e.screenY; startW = getResizeTarget(selectedElm).clientWidth; startH = getResizeTarget(selectedElm).clientHeight; ratio = startH / startW; selectedHandle = handle; handle.startPos = { x: targetWidth * handle[0] + selectedElmX, y: targetHeight * handle[1] + selectedElmY }; startScrollWidth = rootElement.scrollWidth; startScrollHeight = rootElement.scrollHeight; selectedElmGhost = selectedElm.cloneNode(true); dom.addClass(selectedElmGhost, 'mce-clonedresizable'); dom.setAttrib(selectedElmGhost, 'data-mce-bogus', 'all'); selectedElmGhost.contentEditable = false; // Hides IE move layer cursor selectedElmGhost.unSelectabe = true; dom.setStyles(selectedElmGhost, { left: selectedElmX, top: selectedElmY, margin: 0 }); selectedElmGhost.removeAttribute('data-mce-selected'); rootElement.appendChild(selectedElmGhost); dom.bind(editableDoc, 'mousemove', resizeGhostElement); dom.bind(editableDoc, 'mouseup', endGhostResize); if (rootDocument != editableDoc) { dom.bind(rootDocument, 'mousemove', resizeGhostElement); dom.bind(rootDocument, 'mouseup', endGhostResize); } resizeHelper = dom.add(rootElement, 'div', { 'class': 'mce-resize-helper', 'data-mce-bogus': 'all' }, startW + ' &times; ' + startH); }; // Get existing or render resize handle handleElm = dom.get('mceResizeHandle' + name); if (handleElm) { dom.remove(handleElm); } handleElm = dom.add(rootElement, 'div', { id: 'mceResizeHandle' + name, 'data-mce-bogus': 'all', 'class': 'mce-resizehandle', unselectable: true, style: 'cursor:' + name + '-resize; margin:0; padding:0' }); // Hides IE move layer cursor // If we set it on Chrome we get this wounderful bug: #6725 if (Env.ie) { handleElm.contentEditable = false; } dom.bind(handleElm, 'mousedown', function (e) { e.stopImmediatePropagation(); e.preventDefault(); startDrag(e); }); handle.elm = handleElm; // Position element dom.setStyles(handleElm, { left: (targetWidth * handle[0] + selectedElmX) - (handleElm.offsetWidth / 2), top: (targetHeight * handle[1] + selectedElmY) - (handleElm.offsetHeight / 2) }); }); } else { hideResizeRect(); } selectedElm.setAttribute('data-mce-selected', '1'); }; var hideResizeRect = function () { var name, handleElm; unbindResizeHandleEvents(); if (selectedElm) { selectedElm.removeAttribute('data-mce-selected'); } for (name in resizeHandles) { handleElm = dom.get('mceResizeHandle' + name); if (handleElm) { dom.unbind(handleElm); dom.remove(handleElm); } } }; var updateResizeRect = function (e) { var startElm, controlElm; var isChildOrEqual = function (node, parent) { if (node) { do { if (node === parent) { return true; } } while ((node = node.parentNode)); } }; // Ignore all events while resizing or if the editor instance was removed if (resizeStarted || editor.removed) { return; } // Remove data-mce-selected from all elements since they might have been copied using Ctrl+c/v each(dom.select('img[data-mce-selected],hr[data-mce-selected]'), function (img) { img.removeAttribute('data-mce-selected'); }); controlElm = e.type == 'mousedown' ? e.target : selection.getNode(); controlElm = dom.$(controlElm).closest('table,img,figure.image,hr')[0]; if (isChildOrEqual(controlElm, rootElement)) { disableGeckoResize(); startElm = selection.getStart(true); if (isChildOrEqual(startElm, controlElm) && isChildOrEqual(selection.getEnd(true), controlElm)) { showResizeRect(controlElm); return; } } hideResizeRect(); }; var isWithinContentEditableFalse = function (elm) { return isContentEditableFalse(getContentEditableRoot(editor.getBody(), elm)); }; var unbindResizeHandleEvents = function () { for (var name in resizeHandles) { var handle = resizeHandles[name]; if (handle.elm) { dom.unbind(handle.elm); delete handle.elm; } } }; var disableGeckoResize = function () { try { // Disable object resizing on Gecko editor.getDoc().execCommand('enableObjectResizing', false, false); } catch (ex) { // Ignore } }; editor.on('init', function () { disableGeckoResize(); // Sniff sniff, hard to feature detect this stuff if (Env.ie && Env.ie >= 11) { // Needs to be mousedown for drag/drop to work on IE 11 // Needs to be click on Edge to properly select images editor.on('mousedown click', function (e) { var target = e.target, nodeName = target.nodeName; if (!resizeStarted && /^(TABLE|IMG|HR)$/.test(nodeName) && !isWithinContentEditableFalse(target)) { if (e.button !== 2) { editor.selection.select(target, nodeName == 'TABLE'); } // Only fire once since nodeChange is expensive if (e.type == 'mousedown') { editor.nodeChanged(); } } }); editor.dom.bind(rootElement, 'mscontrolselect', function (e) { var delayedSelect = function (node) { Delay.setEditorTimeout(editor, function () { editor.selection.select(node); }); }; if (isWithinContentEditableFalse(e.target)) { e.preventDefault(); delayedSelect(e.target); return; } if (/^(TABLE|IMG|HR)$/.test(e.target.nodeName)) { e.preventDefault(); // This moves the selection from being a control selection to a text like selection like in WebKit #6753 // TODO: Fix this the day IE works like other browsers without this nasty native ugly control selections. if (e.target.tagName == 'IMG') { delayedSelect(e.target); } } }); } var throttledUpdateResizeRect = Delay.throttle(function (e) { if (!editor.composing) { updateResizeRect(e); } }); editor.on('nodechange ResizeEditor ResizeWindow drop', throttledUpdateResizeRect); // Update resize rect while typing in a table editor.on('keyup compositionend', function (e) { // Don't update the resize rect while composing since it blows away the IME see: #2710 if (selectedElm && selectedElm.nodeName == "TABLE") { throttledUpdateResizeRect(e); } }); editor.on('hide blur', hideResizeRect); editor.on('contextmenu', contextMenuSelectImage); // Hide rect on focusout since it would float on top of windows otherwise //editor.on('focusout', hideResizeRect); }); editor.on('remove', unbindResizeHandleEvents); var destroy = function () { selectedElm = selectedElmGhost = null; }; return { isResizable: isResizable, showResizeRect: showResizeRect, hideResizeRect: hideResizeRect, updateResizeRect: updateResizeRect, destroy: destroy }; }; } );