mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-26 12:21:36 +03:00
Range handling improvements. (#656)
closes https://github.com/TryGhost/Ghost/issues/8323 closes https://github.com/TryGhost/Ghost/issues/8191 Fixes some of the range issues that we're seeing across browsers also simplifies the positioning code for UI elements. 1. For the title the cursor is now placed in the correct place on key up and down. 2. For the body Safari now displays the `/` menu correctly.
This commit is contained in:
parent
35bef04a7f
commit
53cbfcf9ca
@ -52,30 +52,10 @@ export default Component.extend({
|
||||
}
|
||||
}
|
||||
if (event.keyCode === 13) {
|
||||
// enter
|
||||
// on enter we want to split the title, create a new paragraph in the mobile doc and insert it into the content.
|
||||
let title = this.$('.gh-editor-title');
|
||||
// enter
|
||||
// on enter create a new paragraph at the top of the editor, this is because the first item may be a card.
|
||||
editor.run((postEditor) => {
|
||||
let {anchorOffset, focusOffset} = window.getSelection();
|
||||
let text = title.text();
|
||||
let startText = ''; // the text before the split
|
||||
let endText = ''; // the text after the split
|
||||
// if the selection is not collapsed then we have to delete the text that is selected.
|
||||
if (anchorOffset !== focusOffset) {
|
||||
// if the start of the selection is after the end then reverse the selection
|
||||
if (anchorOffset > focusOffset) {
|
||||
[anchorOffset, focusOffset] = [focusOffset, anchorOffset];
|
||||
}
|
||||
startText = text.substring(0, anchorOffset);
|
||||
endText = text.substring(focusOffset);
|
||||
} else {
|
||||
startText = text.substring(0, anchorOffset);
|
||||
endText = text.substring(anchorOffset);
|
||||
}
|
||||
|
||||
title.html(startText);
|
||||
|
||||
let marker = editor.builder.createMarker(endText);
|
||||
let marker = editor.builder.createMarker('');
|
||||
let newSection = editor.builder.createMarkupSection('p', [marker]);
|
||||
postEditor.insertSectionBefore(editor.post.sections, newSection, editor.post.sections.head);
|
||||
|
||||
@ -95,6 +75,12 @@ export default Component.extend({
|
||||
}
|
||||
let range = window.getSelection().getRangeAt(0); // get the actual range within the DOM.
|
||||
let cursorPositionOnScreen = range.getBoundingClientRect();
|
||||
|
||||
// in safari getBoundingClientRect on a range does not work if the range is collapsed.
|
||||
if (cursorPositionOnScreen.bottom === 0) {
|
||||
cursorPositionOnScreen = range.getClientRects()[0];
|
||||
}
|
||||
|
||||
let offset = title.offset();
|
||||
let bottomOfHeading = offset.top + title.height();
|
||||
if (cursorPositionOnScreen.bottom > bottomOfHeading - 13) {
|
||||
@ -107,12 +93,9 @@ export default Component.extend({
|
||||
window.getSelection().removeAllRanges();
|
||||
$(editor.post.sections.head.renderNode.element).children('div').click();
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
let cursorPositionInEditor = editor.positionAtPoint(cursorPositionOnScreen.left, loc.top);
|
||||
|
||||
if (!cursorPositionInEditor || cursorPositionInEditor.isBlank) {
|
||||
editor.element.focus();
|
||||
} else {
|
||||
@ -163,7 +146,6 @@ export default Component.extend({
|
||||
if (this.get('editorMenuIsOpen')) {
|
||||
return;
|
||||
}
|
||||
|
||||
let editor = this.get('editor');
|
||||
if (event.keyCode === 38) { // up arrow
|
||||
let selection = window.getSelection();
|
||||
@ -172,11 +154,19 @@ export default Component.extend({
|
||||
}
|
||||
let range = selection.getRangeAt(0); // get the actual range within the DOM.
|
||||
let cursorPositionOnScreen = range.getBoundingClientRect();
|
||||
if (cursorPositionOnScreen.bottom === 0) {
|
||||
cursorPositionOnScreen = range.getClientRects()[0];
|
||||
}
|
||||
let topOfEditor = editor.element.getBoundingClientRect().top;
|
||||
|
||||
// if the current paragraph is empty then the position is 0
|
||||
if (cursorPositionOnScreen.top === 0) {
|
||||
cursorPositionOnScreen = editor.activeSection.renderNode.element.getBoundingClientRect();
|
||||
if (!cursorPositionOnScreen || cursorPositionOnScreen.top === 0) {
|
||||
if (editor.activeSection.renderNode) {
|
||||
cursorPositionOnScreen = editor.activeSection.renderNode.element.getBoundingClientRect();
|
||||
} else {
|
||||
this.setCursorAtOffset(0);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (cursorPositionOnScreen.top < topOfEditor + 33) {
|
||||
@ -197,7 +187,6 @@ export default Component.extend({
|
||||
let range = document.createRange();
|
||||
|
||||
for (let i = len - 1; i > -1; i--) {
|
||||
// console.log(title);
|
||||
range.setStart(title, i);
|
||||
range.setEnd(title, i + 1);
|
||||
let rect = range.getBoundingClientRect();
|
||||
@ -212,20 +201,24 @@ export default Component.extend({
|
||||
|
||||
return len;
|
||||
},
|
||||
setCursorAtOffset() {
|
||||
|
||||
// position the users cursor in the title based on the offset.
|
||||
// unfortunately creating a range and adding it to the selection doesn't work.
|
||||
// In Chrome it ignores the new range and places the cursor at the start of the element.
|
||||
// in Firefox it places the cursor at the correct place but refuses to accept keyboard input.
|
||||
setCursorAtOffset(offset) {
|
||||
let [title] = this.$('.gh-editor-title');
|
||||
title.focus();
|
||||
// the following code sets the start point based on the offest provided.
|
||||
// it works in isolation of ghost-admin but in ghost-admin it doesn't work in Chrome
|
||||
// and works in Firefox, but in firefox you can no longer edit the title once this has happened.
|
||||
// It's either an issue with ghost-admin or mobiledoc and more investigation needs to be done.
|
||||
// Probably after the beta release though.
|
||||
let selection = window.getSelection();
|
||||
|
||||
// let range = document.createRange();
|
||||
// let selection = window.getSelection();
|
||||
// range.setStart(title.childNodes[0], offset);
|
||||
// range.collapse(true);
|
||||
// selection.removeAllRanges();
|
||||
// selection.addRange(range);
|
||||
window.requestAnimationFrame(() => {
|
||||
run.join(() => {
|
||||
if (selection.modify) {
|
||||
for (let i = 0; i < offset; i++) {
|
||||
selection.modify('move', 'forward', 'character');
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
@ -7,7 +7,7 @@ import {MOBILEDOC_VERSION} from 'mobiledoc-kit/renderers/mobiledoc';
|
||||
import createCardFactory from '../lib/card-factory';
|
||||
import defaultCommands from '../options/default-commands';
|
||||
import editorCards from '../cards/index';
|
||||
import {getCardFromDoc, checkIfClickEventShouldCloseCard} from '../lib/utils';
|
||||
import {getCardFromDoc, checkIfClickEventShouldCloseCard, getPositionFromRange} from '../lib/utils';
|
||||
import $ from 'jquery';
|
||||
// import { VALID_MARKUP_SECTION_TAGNAMES } from 'mobiledoc-kit/models/markup-section'; //the block elements supported by mobile-doc
|
||||
|
||||
@ -154,27 +154,19 @@ export default Component.extend({
|
||||
},
|
||||
|
||||
// makes sure the cursor is on screen except when selection is happening in which case the browser mostly ensures it.
|
||||
// there is an issue with keyboard selection on some browsers though so the next step will be to record mouse and touch events.
|
||||
// there is an issue with keyboard selection on some browsers though so the next step may be to record mouse and touch events.
|
||||
cursorMoved() {
|
||||
let editor = this.get('editor');
|
||||
|
||||
if (editor.range.isCollapsed) {
|
||||
let scrollBuffer = 33; // the extra buffer to scroll.
|
||||
let selection = window.getSelection();
|
||||
if (!selection.rangeCount) {
|
||||
|
||||
let position = getPositionFromRange(editor, $(this.get('containerSelector')));
|
||||
|
||||
if (!position) {
|
||||
return;
|
||||
}
|
||||
let range = selection.getRangeAt(0); // get the actual range within the DOM.
|
||||
let position = range.getBoundingClientRect();
|
||||
if (position.left === 0 && position.top === 0) {
|
||||
// in safari if the range is collapsed you can't get it's location.
|
||||
// this is a bug as it's against the spec.
|
||||
if (editor.range.section) {
|
||||
position = editor.range.head.section.renderNode.element.getBoundingClientRect();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let windowHeight = window.innerHeight;
|
||||
|
||||
if (position.bottom > windowHeight) {
|
||||
|
@ -4,6 +4,7 @@ import run from 'ember-runloop';
|
||||
import $ from 'jquery';
|
||||
import Tools from '../options/default-tools';
|
||||
import layout from '../templates/components/koenig-slash-menu';
|
||||
import {getPositionFromRange} from '../lib/utils';
|
||||
|
||||
const ROW_LENGTH = 4;
|
||||
|
||||
@ -104,7 +105,7 @@ export default Component.extend({
|
||||
},
|
||||
actions: {
|
||||
openMenu: function () { // eslint-disable-line
|
||||
let $editor = $(this.get('containerSelector'));
|
||||
let holder = $(this.get('containerSelector'));
|
||||
let editor = this.get('editor');
|
||||
let self = this;
|
||||
|
||||
@ -198,28 +199,20 @@ export default Component.extend({
|
||||
}
|
||||
});
|
||||
|
||||
let range = window.getSelection().getRangeAt(0); // get the actual range within the DOM.
|
||||
|
||||
let position = range.getBoundingClientRect();
|
||||
let edOffset = $editor.offset();
|
||||
if (position.left === 0 && position.top === 0) {
|
||||
// in safari if the range is collapsed you can't get it's location.
|
||||
// this is a bug as it's against the spec.
|
||||
position = editor.range.head.section.renderNode.element.getBoundingClientRect();
|
||||
}
|
||||
let position = getPositionFromRange(editor, holder);
|
||||
run.schedule('afterRender', this,
|
||||
() => {
|
||||
let menu = this.$('.gh-cardmenu');
|
||||
let top = position.top + $editor.scrollTop() - edOffset.top + 20;
|
||||
let left = position.left + (position.width / 2) + $editor.scrollLeft() - edOffset.left;
|
||||
let top = position.top + 20;
|
||||
let left = position.left + (position.width / 2);
|
||||
// calculate if parts of the menu that are hidden by the overflow.
|
||||
let hiddenByOverflowY = ($editor.innerHeight() + $editor.scrollTop()) - (menu.height() + top);
|
||||
let hiddenByOverflowY = (holder.innerHeight() + holder.scrollTop()) - (menu.height() + top);
|
||||
// if the menu is off the bottom of the screen then place it above the cursor
|
||||
|
||||
if (hiddenByOverflowY < 0) {
|
||||
menu.css('margin-top', -(menu.outerHeight() + 20));
|
||||
}
|
||||
let hiddenByOverflowX = ($editor.innerWidth() + $editor.scrollLeft()) - (menu.width() + left);
|
||||
let hiddenByOverflowX = (holder.innerWidth() + holder.scrollLeft()) - (menu.width() + left);
|
||||
// if the menu is off the bottom of the screen then place it above the cursor
|
||||
if (hiddenByOverflowX < 0) {
|
||||
menu.css('margin-left', -(menu.outerWidth() + 20));
|
||||
|
@ -5,6 +5,7 @@ import $ from 'jquery';
|
||||
import layout from '../templates/components/koenig-toolbar';
|
||||
import cajaSanitizers from '../lib/caja-sanitizers';
|
||||
import Tools from '../options/default-tools';
|
||||
import {getPositionFromRange} from '../lib/utils';
|
||||
|
||||
export default Component.extend({
|
||||
layout,
|
||||
@ -25,9 +26,6 @@ export default Component.extend({
|
||||
}),
|
||||
|
||||
toolbar: computed('tools.@each.selected', function () {
|
||||
// TODO if a block section other than a primary section is selected then
|
||||
// the returned list removes one of the primary sections to compensate,
|
||||
// so that there are only ever four primary sections.
|
||||
let visibleTools = [];
|
||||
|
||||
this.tools.forEach((tool) => {
|
||||
@ -39,9 +37,6 @@ export default Component.extend({
|
||||
}),
|
||||
|
||||
toolbarBlocks: computed('tools.@each.selected', function () {
|
||||
// TODO if a block section other than a primary section is selected then
|
||||
// the returned list removes one of the primary sections to compensate,
|
||||
// so that there are only ever four primary sections.
|
||||
let visibleTools = [];
|
||||
|
||||
this.tools.forEach((tool) => {
|
||||
@ -64,15 +59,15 @@ export default Component.extend({
|
||||
}
|
||||
let toolbar = this.$();
|
||||
let {editor} = this;
|
||||
let $editor = $(this.get('containerSelector')); // TODO - this element is part of ghost-admin, we need to separate them more.
|
||||
let holder = $(this.get('containerSelector'));
|
||||
let isMousedown = false;
|
||||
|
||||
$editor.mousedown(() => isMousedown = true);
|
||||
$editor.mouseup(() => {
|
||||
holder.mousedown(() => isMousedown = true);
|
||||
holder.mouseup(() => {
|
||||
isMousedown = false;
|
||||
updateToolbarToRange(this, toolbar, $editor, isMousedown);
|
||||
this.updateToolbarToRange(toolbar, holder, isMousedown);
|
||||
});
|
||||
editor.cursorDidChange(() => updateToolbarToRange(this, toolbar, $editor, isMousedown));
|
||||
editor.cursorDidChange(() => this.updateToolbarToRange(toolbar, holder, isMousedown));
|
||||
this.set('hasRendered', true);
|
||||
},
|
||||
|
||||
@ -80,6 +75,95 @@ export default Component.extend({
|
||||
this.editor.destroy();
|
||||
},
|
||||
|
||||
// update the location of the toolbar and display it if the range is visible.
|
||||
updateToolbarToRange(toolbar, holder, isMouseDown) {
|
||||
// if there is no cursor:
|
||||
let editor = this.get('editor');
|
||||
if (!editor.range || editor.range.head.isBlank || isMouseDown) {
|
||||
if (!this.get('isLink')) {
|
||||
this.set('isVisible', false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// set the active markups and sections
|
||||
let sectionTagName = editor.activeSection.tagName === 'li' ? editor.activeSection.parent.tagName : editor.activeSection.tagName;
|
||||
this.set('activeTags', editor.activeMarkups.concat([{tagName: sectionTagName}]));
|
||||
|
||||
// if we have a selection, then the toolbar appears just above said selection:
|
||||
// unless it's a selection around a single card (firefox bug)
|
||||
if (!editor.range.isCollapsed
|
||||
&& !(editor.range.head.section.isCardSection && editor.range.head.section === editor.range.tail.section)) {
|
||||
let position = getPositionFromRange(editor, holder);
|
||||
|
||||
this.set('isVisible', true);
|
||||
run.schedule('afterRender', this,
|
||||
() => {
|
||||
// if we're in touch mode we just use CSS to display the toolbar.
|
||||
if (this.get('isTouch')) {
|
||||
return;
|
||||
}
|
||||
let width = toolbar.width();
|
||||
let height = toolbar.height();
|
||||
let top = position.top - toolbar.height() - 20;
|
||||
let left = position.left + (position.width / 2) - (width / 2);
|
||||
let right = left + width;
|
||||
let edWidth = holder[0].scrollWidth;
|
||||
|
||||
if (left < 0) {
|
||||
if (Math.round(left / (width / 4)) === -1) {
|
||||
this.setTickPosition('tickFullLeft');
|
||||
} else {
|
||||
this.setTickPosition('tickHalfLeft');
|
||||
}
|
||||
left = 0;
|
||||
} else if (right > edWidth) {
|
||||
if (Math.round((edWidth - right) / (width / 4)) === -1) {
|
||||
this.setTickPosition('tickFullRight');
|
||||
} else {
|
||||
this.setTickPosition('tickHalfRight');
|
||||
}
|
||||
left = left + (edWidth - right);
|
||||
} else {
|
||||
this.setTickPosition(null);
|
||||
}
|
||||
|
||||
if (!this.get('isTouch') && top - holder.scrollTop() < 0) {
|
||||
top = top + height + 60;
|
||||
this.set('tickAbove', true);
|
||||
} else {
|
||||
this.set('tickAbove', false);
|
||||
}
|
||||
|
||||
toolbar.css('top', top);
|
||||
toolbar.css('left', left);
|
||||
}
|
||||
);
|
||||
|
||||
this.send('closeLink');
|
||||
|
||||
this.tools.forEach((tool) => {
|
||||
if (tool.hasOwnProperty('checkElements')) {
|
||||
// if its a list we want to know what type
|
||||
let sectionTagName = editor.activeSection._tagName === 'li' ? editor.activeSection.parent._tagName : editor.activeSection._tagName;
|
||||
tool.checkElements(editor.activeMarkups.concat([{tagName: sectionTagName}]));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (this.isVisible) {
|
||||
this.set('isVisible', false);
|
||||
this.send('closeLink');
|
||||
}
|
||||
}
|
||||
},
|
||||
// set the location of the 'tick' arrow that appears at the bottom of the toolbar and points out the selection.
|
||||
setTickPosition(tickPosition) {
|
||||
let positions = ['tickFullLeft', 'tickHalfLeft', 'tickFullRight', 'tickHalfRight'];
|
||||
positions.forEach((position) => {
|
||||
this.set(position, position === tickPosition);
|
||||
});
|
||||
},
|
||||
|
||||
actions: {
|
||||
linkKeyDown(event) {
|
||||
// if escape close link
|
||||
@ -132,106 +216,3 @@ export default Component.extend({
|
||||
}
|
||||
});
|
||||
|
||||
// update the location of the toolbar and display it if the range is visible.
|
||||
function updateToolbarToRange(self, $holder, $editor, isMouseDown) {
|
||||
// if there is no cursor:
|
||||
let {editor} = self;
|
||||
if (!editor.range || editor.range.head.isBlank || isMouseDown) {
|
||||
if (!self.get('isLink')) {
|
||||
self.set('isVisible', false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// set the active markups and sections
|
||||
let sectionTagName = editor.activeSection.tagName === 'li' ? editor.activeSection.parent.tagName : editor.activeSection.tagName;
|
||||
self.set('activeTags', editor.activeMarkups.concat([{tagName: sectionTagName}]));
|
||||
|
||||
self.propertyWillChange('toolbar');
|
||||
self.propertyWillChange('toolbarBlocks');
|
||||
|
||||
// if we have a selection, then the toolbar appears just above said selection:
|
||||
// unless it's a selection around a single card (firefox bug)
|
||||
if (!editor.range.isCollapsed
|
||||
&& !(editor.range.head.section.isCardSection && editor.range.head.section === editor.range.tail.section)) {
|
||||
|
||||
let range = window.getSelection().getRangeAt(0); // get the actual range within the DOM.
|
||||
let position = range.getBoundingClientRect();
|
||||
let edOffset = $editor.offset();
|
||||
|
||||
self.set('isVisible', true);
|
||||
run.schedule('afterRender', this,
|
||||
() => {
|
||||
// if we're in touch mode we just use CSS to display the toolbar.
|
||||
if (self.get('isTouch')) {
|
||||
return;
|
||||
}
|
||||
let width = $holder.width();
|
||||
let height = $holder.height();
|
||||
let top = position.top + $editor.scrollTop() - $holder.height() - 20;
|
||||
let left = position.left + (position.width / 2) + $editor.scrollLeft() - edOffset.left - (width / 2);
|
||||
let right = left + width;
|
||||
let edWidth = $editor[0].scrollWidth;
|
||||
if (left < 0) {
|
||||
if (Math.round(left / (width / 4)) === -1) {
|
||||
self.set('tickFullLeft', true);
|
||||
self.set('tickHalfLeft', false);
|
||||
self.set('tickFullRight', false);
|
||||
self.set('tickHalfRight', false);
|
||||
} else {
|
||||
self.set('tickFullLeft', false);
|
||||
self.set('tickHalfLeft', true);
|
||||
self.set('tickFullRight', false);
|
||||
self.set('tickHalfRight', false);
|
||||
}
|
||||
left = 0;
|
||||
} else if (right > edWidth) {
|
||||
if (Math.round((edWidth - right) / (width / 4)) === -1) {
|
||||
self.set('tickFullLeft', false);
|
||||
self.set('tickHalfLeft', false);
|
||||
self.set('tickFullRight', true);
|
||||
self.set('tickHalfRight', false);
|
||||
} else {
|
||||
self.set('tickFullLeft', false);
|
||||
self.set('tickHalfLeft', false);
|
||||
self.set('tickFullRight', false);
|
||||
self.set('tickHalfRight', true);
|
||||
}
|
||||
left = left + (edWidth - right);
|
||||
} else {
|
||||
self.set('tickFullLeft', false);
|
||||
self.set('tickHalfLeft', false);
|
||||
self.set('tickFullRight', false);
|
||||
self.set('tickHalfRight', false);
|
||||
}
|
||||
|
||||
if (!self.get('isTouch') && top - $editor.scrollTop() < 0) {
|
||||
top = top + height + 60;
|
||||
self.set('tickAbove', true);
|
||||
} else {
|
||||
self.set('tickAbove', false);
|
||||
}
|
||||
$holder.css('top', top);
|
||||
$holder.css('left', left);
|
||||
}
|
||||
);
|
||||
|
||||
self.send('closeLink');
|
||||
|
||||
self.tools.forEach((tool) => {
|
||||
if (tool.hasOwnProperty('checkElements')) {
|
||||
// if its a list we want to know what type
|
||||
let sectionTagName = editor.activeSection._tagName === 'li' ? editor.activeSection.parent._tagName : editor.activeSection._tagName;
|
||||
tool.checkElements(editor.activeMarkups.concat([{tagName: sectionTagName}]));
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (self.isVisible) {
|
||||
self.set('isVisible', false);
|
||||
self.send('closeLink');
|
||||
}
|
||||
}
|
||||
|
||||
self.propertyDidChange('toolbar');
|
||||
self.propertyDidChange('toolbarBlocks');
|
||||
}
|
||||
|
@ -38,22 +38,59 @@ export function checkIfClickEventShouldCloseCard(target, cardHolder) {
|
||||
// in Chrome, Firefox, and Edge range.getBoundingClientRect() works
|
||||
// in Safari if the range is collapsed you get nothing so we expand the range by 1
|
||||
// if that doesn't work then we fallback got the paragraph.
|
||||
// export function getPositionFromRange(editor, range = window.getSelection().getRangeAt(0)) {
|
||||
// let {top, left} = editor.element.getBoundingClientRect();
|
||||
// let position = range.getBoundingClientRect();
|
||||
export function getPositionFromRange(editor, holder, range) {
|
||||
if (!editor.range || !editor.range.head || !editor.range.head.section) {
|
||||
return;
|
||||
}
|
||||
let position;
|
||||
let offset = holder.offset();
|
||||
let selection = window.getSelection();
|
||||
|
||||
// if (position.left === 0 && position.top === 0) {
|
||||
// // in safari if the range is collapsed you can't get it's location.
|
||||
// // this is a bug as it's against the spec.
|
||||
// position = getCursorPositionSafari(range);
|
||||
// // position = editor.range.head.section.renderNode.element.getBoundingClientRect();
|
||||
// }
|
||||
// }
|
||||
if (!range && selection.rangeCount) {
|
||||
range = selection.getRangeAt(0);
|
||||
}
|
||||
|
||||
// function getCursorPositionSafari(range) {
|
||||
// if(offset < container.length) {
|
||||
if (range) {
|
||||
if (range.getBoundingClientRect) {
|
||||
let rect = range.getBoundingClientRect();
|
||||
position = {left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom};
|
||||
}
|
||||
|
||||
// } else {
|
||||
// if getBoundingClientRect doesn't work then create it from the client rects
|
||||
if ((!position || (position.left === 0 && position.top === 0)) && range.getClientRects) {
|
||||
|
||||
// }
|
||||
// }
|
||||
let rects = range.getClientRects();
|
||||
|
||||
for (let i = 0; i < rects.length; i++) {
|
||||
let rect = rects[i];
|
||||
if (position.left === 0 || position.left > rect.left) {
|
||||
position.left = rect.left;
|
||||
}
|
||||
if (position.top === 0 || position.top > rect.top) {
|
||||
position.top = rect.top;
|
||||
}
|
||||
if (position.right < rect.right) {
|
||||
position.right = rect.right;
|
||||
}
|
||||
if (position.bottom < rect.bottom) {
|
||||
position.bototm = rect.bottom;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if we can't get the position from either getBoundingClientRect or getClientRects then get it based on the paragraph.
|
||||
if (!position || (position && position.left === 0 && position.top === 0)) {
|
||||
let rect = editor.range.head.section.renderNode.element.getBoundingClientRect();
|
||||
position = {left: rect.left, right: rect.right, top: rect.top, bottom: rect.bottom};
|
||||
}
|
||||
|
||||
return {
|
||||
left: position.left + holder.scrollLeft() - offset.left,
|
||||
right: position.right + holder.scrollLeft() - offset.left,
|
||||
top: position.top + holder.scrollTop() - offset.top,
|
||||
bottom: position.bottom + holder.scrollTop() - offset.top,
|
||||
width: position.right - position.left,
|
||||
height: position.bottom - position.top
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user