mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 14:13:34 +01:00
Drop support for Internet Explorer
This commit is contained in:
parent
c5cf7ab144
commit
b82bf5c726
7 changed files with 149 additions and 619 deletions
|
@ -5,6 +5,8 @@
|
|||
Existing group pads that were previously password protected will no longer be
|
||||
password protected. If you need fine-grained access control, you can restrict
|
||||
API session creation in your frontend service, or you can use plugins.
|
||||
* All workarounds for Microsoft Internet Explorer have been removed. IE might
|
||||
still work, but it is untested.
|
||||
* Plugin hook functions are now subject to new sanity checks. Buggy hook
|
||||
functions will cause an error message to be logged
|
||||
* Authorization failures now return 403 by default instead of 401
|
||||
|
|
|
@ -24,15 +24,6 @@ const padutils = require('./pad_utils').padutils;
|
|||
|
||||
let _, $, jQuery, plugins, Ace2Common;
|
||||
const browser = require('./browser');
|
||||
if (browser.msie) {
|
||||
// Honestly fuck IE royally.
|
||||
// Basically every hack we have since V11 causes a problem
|
||||
if (parseInt(browser.version) >= 11) {
|
||||
delete browser.msie;
|
||||
browser.chrome = true;
|
||||
browser.modernIE = true;
|
||||
}
|
||||
}
|
||||
|
||||
Ace2Common = require('./ace2_common');
|
||||
|
||||
|
@ -1180,12 +1171,6 @@ function Ace2Inner() {
|
|||
const dirtyNodes = [];
|
||||
for (let n = firstDirtyNode; n && !(n.previousSibling && n.previousSibling == lastDirtyNode);
|
||||
n = n.nextSibling) {
|
||||
if (browser.msie) {
|
||||
// try to undo IE's pesky and overzealous linkification
|
||||
try {
|
||||
n.createTextRange().execCommand('unlink', false, null);
|
||||
} catch (e) {}
|
||||
}
|
||||
cc.collectContent(n);
|
||||
dirtyNodes.push(n);
|
||||
}
|
||||
|
@ -1213,13 +1198,12 @@ function Ace2Inner() {
|
|||
var scrollToTheLeftNeeded = false;
|
||||
|
||||
if (linesWrapped > 0) {
|
||||
if (!browser.msie) {
|
||||
// chrome decides in it's infinite wisdom that its okay to put the browsers visisble window in the middle of the span
|
||||
// an outcome of this is that the first chars of the string are no longer visible to the user.. Yay chrome..
|
||||
// Move the browsers visible area to the left hand side of the span
|
||||
// Firefox isn't quite so bad, but it's still pretty quirky.
|
||||
var scrollToTheLeftNeeded = true;
|
||||
}
|
||||
// Chrome decides in its infinite wisdom that it's okay to put the browser's visisble
|
||||
// window in the middle of the span. An outcome of this is that the first chars of the
|
||||
// string are no longer visible to the user.. Yay chrome.. Move the browser's visible area
|
||||
// to the left hand side of the span. Firefox isn't quite so bad, but it's still pretty
|
||||
// quirky.
|
||||
var scrollToTheLeftNeeded = true;
|
||||
}
|
||||
|
||||
if (ss[0] >= 0) selStart = [ss[0] + a + netNumLinesChangeSoFar, ss[1]];
|
||||
|
@ -1472,15 +1456,6 @@ function Ace2Inner() {
|
|||
let after = false;
|
||||
if (charsLeft === 0) {
|
||||
let index = 0;
|
||||
|
||||
if (browser.msie && parseInt(browser.version) >= 11) {
|
||||
browser.msie = false; // Temp fix to resolve enter and backspace issues..
|
||||
// Note that this makes MSIE behave like modern browsers..
|
||||
}
|
||||
if (browser.msie && line == (rep.lines.length() - 1) && lineNode.childNodes.length === 0) {
|
||||
// best to stay at end of last empty div in IE
|
||||
index = 1;
|
||||
}
|
||||
return {
|
||||
node: lineNode,
|
||||
index,
|
||||
|
@ -1514,11 +1489,7 @@ function Ace2Inner() {
|
|||
}
|
||||
|
||||
function nodeText(n) {
|
||||
if (browser.msie) {
|
||||
return n.innerText;
|
||||
} else {
|
||||
return n.textContent || n.nodeValue || '';
|
||||
}
|
||||
return n.textContent || n.nodeValue || '';
|
||||
}
|
||||
|
||||
function getLineAndCharForPoint(point) {
|
||||
|
@ -2281,59 +2252,7 @@ function Ace2Inner() {
|
|||
}
|
||||
|
||||
function doCreateDomLine(nonEmpty) {
|
||||
if (browser.msie && (!nonEmpty)) {
|
||||
const result = {
|
||||
node: null,
|
||||
appendSpan: noop,
|
||||
prepareForAdd: noop,
|
||||
notifyAdded: noop,
|
||||
clearSpans: noop,
|
||||
finishUpdate: noop,
|
||||
lineMarker: 0,
|
||||
};
|
||||
|
||||
const lineElem = doc.createElement('div');
|
||||
result.node = lineElem;
|
||||
|
||||
result.notifyAdded = function () {
|
||||
// magic -- settng an empty div's innerHTML to the empty string
|
||||
// keeps it from collapsing. Apparently innerHTML must be set *after*
|
||||
// adding the node to the DOM.
|
||||
// Such a div is what IE 6 creates naturally when you make a blank line
|
||||
// in a document of divs. However, when copy-and-pasted the div will
|
||||
// contain a space, so we note its emptiness with a property.
|
||||
lineElem.innerHTML = ' '; // Frist we set a value that isnt blank
|
||||
// a primitive-valued property survives copy-and-paste
|
||||
setAssoc(lineElem, 'shouldBeEmpty', true);
|
||||
// an object property doesn't
|
||||
setAssoc(lineElem, 'unpasted', {});
|
||||
lineElem.innerHTML = ''; // Then we make it blank.. New line and no space = Awesome :)
|
||||
};
|
||||
let lineClass = 'ace-line';
|
||||
result.appendSpan = function (txt, cls) {
|
||||
if ((!txt) && cls) {
|
||||
// gain a whole-line style (currently to show insertion point in CSS)
|
||||
lineClass = domline.addToLineClass(lineClass, cls);
|
||||
}
|
||||
// otherwise, ignore appendSpan, this is an empty line
|
||||
};
|
||||
result.clearSpans = function () {
|
||||
lineClass = ''; // non-null to cause update
|
||||
};
|
||||
|
||||
const writeClass = function () {
|
||||
if (lineClass !== null) lineElem.className = lineClass;
|
||||
};
|
||||
|
||||
result.prepareForAdd = writeClass;
|
||||
result.finishUpdate = writeClass;
|
||||
result.getInnerHTML = function () {
|
||||
return '';
|
||||
};
|
||||
return result;
|
||||
} else {
|
||||
return domline.createDomLine(nonEmpty, doesWrap, browser, doc);
|
||||
}
|
||||
return domline.createDomLine(nonEmpty, doesWrap, browser, doc);
|
||||
}
|
||||
|
||||
function textify(str) {
|
||||
|
@ -2558,12 +2477,6 @@ function Ace2Inner() {
|
|||
const dirtiness = {};
|
||||
dirtiness.nodeId = uniqueId(n);
|
||||
dirtiness.knownHTML = n.innerHTML;
|
||||
if (browser.msie) {
|
||||
// adding a space to an "empty" div in IE designMode doesn't
|
||||
// change the innerHTML of the div's parent; also, other
|
||||
// browsers don't support innerText
|
||||
dirtiness.knownText = n.innerText;
|
||||
}
|
||||
setAssoc(n, 'dirtiness', dirtiness);
|
||||
}
|
||||
|
||||
|
@ -2573,9 +2486,6 @@ function Ace2Inner() {
|
|||
const data = getAssoc(n, 'dirtiness');
|
||||
if (!data) return true;
|
||||
if (n.id !== data.nodeId) return true;
|
||||
if (browser.msie) {
|
||||
if (n.innerText !== data.knownText) return true;
|
||||
}
|
||||
if (n.innerHTML !== data.knownHTML) return true;
|
||||
p.end();
|
||||
return false;
|
||||
|
@ -2839,20 +2749,11 @@ function Ace2Inner() {
|
|||
// On Mac and Linux, move right moves to end of word and move left moves to start;
|
||||
// on Windows, always move to start of word.
|
||||
// On Windows, Firefox and IE disagree on whether to stop for punctuation (FF says no).
|
||||
if (browser.msie && forwardNotBack) {
|
||||
while ((!isDone()) && isWordChar(nextChar())) {
|
||||
advance();
|
||||
}
|
||||
while ((!isDone()) && !isWordChar(nextChar())) {
|
||||
advance();
|
||||
}
|
||||
} else {
|
||||
while ((!isDone()) && !isWordChar(nextChar())) {
|
||||
advance();
|
||||
}
|
||||
while ((!isDone()) && isWordChar(nextChar())) {
|
||||
advance();
|
||||
}
|
||||
while ((!isDone()) && !isWordChar(nextChar())) {
|
||||
advance();
|
||||
}
|
||||
while ((!isDone()) && isWordChar(nextChar())) {
|
||||
advance();
|
||||
}
|
||||
|
||||
return i;
|
||||
|
@ -2891,8 +2792,8 @@ function Ace2Inner() {
|
|||
return; // This stops double enters in Opera but double Tabs still show on single tab keypress, adding keyCode == 9 to this doesn't help as the event is fired twice
|
||||
}
|
||||
let specialHandled = false;
|
||||
const isTypeForSpecialKey = ((browser.msie || browser.safari || browser.chrome || browser.firefox) ? (type == 'keydown') : (type == 'keypress'));
|
||||
const isTypeForCmdKey = ((browser.msie || browser.safari || browser.chrome || browser.firefox) ? (type == 'keydown') : (type == 'keypress'));
|
||||
const isTypeForSpecialKey = ((browser.safari || browser.chrome || browser.firefox) ? (type == 'keydown') : (type == 'keypress'));
|
||||
const isTypeForCmdKey = ((browser.safari || browser.chrome || browser.firefox) ? (type == 'keydown') : (type == 'keypress'));
|
||||
let stopped = false;
|
||||
|
||||
inCallStackIfNecessary('handleKeyEvent', function () {
|
||||
|
@ -3319,259 +3220,80 @@ function Ace2Inner() {
|
|||
else return 1;
|
||||
}
|
||||
|
||||
function hasIESelection() {
|
||||
let browserSelection;
|
||||
try {
|
||||
browserSelection = doc.selection;
|
||||
} catch (e) {}
|
||||
if (!browserSelection) return false;
|
||||
let origSelectionRange;
|
||||
try {
|
||||
origSelectionRange = browserSelection.createRange();
|
||||
} catch (e) {}
|
||||
if (!origSelectionRange) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
function getSelection() {
|
||||
// returns null, or a structure containing startPoint and endPoint,
|
||||
// each of which has node (a magicdom node), index, and maxIndex. If the node
|
||||
// is a text node, maxIndex is the length of the text; else maxIndex is 1.
|
||||
// index is between 0 and maxIndex, inclusive.
|
||||
if (browser.msie) {
|
||||
var browserSelection;
|
||||
try {
|
||||
browserSelection = doc.selection;
|
||||
} catch (e) {}
|
||||
if (!browserSelection) return null;
|
||||
let origSelectionRange;
|
||||
try {
|
||||
origSelectionRange = browserSelection.createRange();
|
||||
} catch (e) {}
|
||||
if (!origSelectionRange) return null;
|
||||
const selectionParent = origSelectionRange.parentElement();
|
||||
if (selectionParent.ownerDocument != doc) return null;
|
||||
var browserSelection = window.getSelection();
|
||||
if (!browserSelection || browserSelection.type === 'None' ||
|
||||
browserSelection.rangeCount === 0) {
|
||||
return null;
|
||||
}
|
||||
const range = browserSelection.getRangeAt(0);
|
||||
|
||||
const newRange = function () {
|
||||
return doc.body.createTextRange();
|
||||
};
|
||||
function isInBody(n) {
|
||||
while (n && !(n.tagName && n.tagName.toLowerCase() == 'body')) {
|
||||
n = n.parentNode;
|
||||
}
|
||||
return !!n;
|
||||
}
|
||||
|
||||
const rangeForElementNode = function (nd) {
|
||||
const rng = newRange();
|
||||
// doesn't work on text nodes
|
||||
rng.moveToElementText(nd);
|
||||
return rng;
|
||||
};
|
||||
|
||||
const pointFromCollapsedRange = function (rng) {
|
||||
const parNode = rng.parentElement();
|
||||
let elemBelow = -1;
|
||||
let elemAbove = parNode.childNodes.length;
|
||||
const rangeWithin = rangeForElementNode(parNode);
|
||||
|
||||
if (rng.compareEndPoints('StartToStart', rangeWithin) === 0) {
|
||||
return {
|
||||
node: parNode,
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
} else if (rng.compareEndPoints('EndToEnd', rangeWithin) === 0) {
|
||||
if (isBlockElement(parNode) && parNode.nextSibling) {
|
||||
// caret after block is not consistent across browsers
|
||||
// (same line vs next) so put caret before next node
|
||||
return {
|
||||
node: parNode.nextSibling,
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
}
|
||||
return {
|
||||
node: parNode,
|
||||
index: 1,
|
||||
maxIndex: 1,
|
||||
};
|
||||
} else if (parNode.childNodes.length === 0) {
|
||||
return {
|
||||
node: parNode,
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
}
|
||||
|
||||
for (let i = 0; i < parNode.childNodes.length; i++) {
|
||||
const n = parNode.childNodes.item(i);
|
||||
if (!isNodeText(n)) {
|
||||
const nodeRange = rangeForElementNode(n);
|
||||
const startComp = rng.compareEndPoints('StartToStart', nodeRange);
|
||||
const endComp = rng.compareEndPoints('EndToEnd', nodeRange);
|
||||
if (startComp >= 0 && endComp <= 0) {
|
||||
let index = 0;
|
||||
if (startComp > 0) {
|
||||
index = 1;
|
||||
}
|
||||
return {
|
||||
node: n,
|
||||
index,
|
||||
maxIndex: 1,
|
||||
};
|
||||
} else if (endComp > 0) {
|
||||
if (i > elemBelow) {
|
||||
elemBelow = i;
|
||||
rangeWithin.setEndPoint('StartToEnd', nodeRange);
|
||||
}
|
||||
} else if (startComp < 0) {
|
||||
if (i < elemAbove) {
|
||||
elemAbove = i;
|
||||
rangeWithin.setEndPoint('EndToStart', nodeRange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((elemAbove - elemBelow) == 1) {
|
||||
if (elemBelow >= 0) {
|
||||
return {
|
||||
node: parNode.childNodes.item(elemBelow),
|
||||
index: 1,
|
||||
maxIndex: 1,
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
node: parNode.childNodes.item(elemAbove),
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
let idx = 0;
|
||||
const r = rng.duplicate();
|
||||
// infinite stateful binary search! call function for values 0 to inf,
|
||||
// expecting the answer to be about 40. return index of smallest
|
||||
// true value.
|
||||
const indexIntoRange = binarySearchInfinite(40, (i) => {
|
||||
// the search algorithm whips the caret back and forth,
|
||||
// though it has to be moved relatively and may hit
|
||||
// the end of the buffer
|
||||
const delta = i - idx;
|
||||
const moved = Math.abs(r.move('character', -delta));
|
||||
// next line is work-around for fact that when moving left, the beginning
|
||||
// of a text node is considered to be after the start of the parent element:
|
||||
if (r.move('character', -1)) r.move('character', 1);
|
||||
if (delta < 0) idx -= moved;
|
||||
else idx += moved;
|
||||
return (r.compareEndPoints('StartToStart', rangeWithin) <= 0);
|
||||
});
|
||||
// iterate over consecutive text nodes, point is in one of them
|
||||
let textNode = elemBelow + 1;
|
||||
let indexLeft = indexIntoRange;
|
||||
while (textNode < elemAbove) {
|
||||
var tn = parNode.childNodes.item(textNode);
|
||||
if (indexLeft <= tn.nodeValue.length) {
|
||||
return {
|
||||
node: tn,
|
||||
index: indexLeft,
|
||||
maxIndex: tn.nodeValue.length,
|
||||
};
|
||||
}
|
||||
indexLeft -= tn.nodeValue.length;
|
||||
textNode++;
|
||||
}
|
||||
var tn = parNode.childNodes.item(textNode - 1);
|
||||
function pointFromRangeBound(container, offset) {
|
||||
if (!isInBody(container)) {
|
||||
// command-click in Firefox selects whole document, HEAD and BODY!
|
||||
return {
|
||||
node: tn,
|
||||
index: tn.nodeValue.length,
|
||||
maxIndex: tn.nodeValue.length,
|
||||
node: root,
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
};
|
||||
|
||||
var selection = {};
|
||||
if (origSelectionRange.compareEndPoints('StartToEnd', origSelectionRange) === 0) {
|
||||
// collapsed
|
||||
const pnt = pointFromCollapsedRange(origSelectionRange);
|
||||
selection.startPoint = pnt;
|
||||
selection.endPoint = {
|
||||
node: pnt.node,
|
||||
index: pnt.index,
|
||||
maxIndex: pnt.maxIndex,
|
||||
}
|
||||
const n = container;
|
||||
const childCount = n.childNodes.length;
|
||||
if (isNodeText(n)) {
|
||||
return {
|
||||
node: n,
|
||||
index: offset,
|
||||
maxIndex: n.nodeValue.length,
|
||||
};
|
||||
} else if (childCount === 0) {
|
||||
return {
|
||||
node: n,
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
}
|
||||
// treat point between two nodes as BEFORE the second (rather than after the first)
|
||||
// if possible; this way point at end of a line block-element is treated as
|
||||
// at beginning of next line
|
||||
else if (offset == childCount) {
|
||||
var nd = n.childNodes.item(childCount - 1);
|
||||
var max = nodeMaxIndex(nd);
|
||||
return {
|
||||
node: nd,
|
||||
index: max,
|
||||
maxIndex: max,
|
||||
};
|
||||
} else {
|
||||
const start = origSelectionRange.duplicate();
|
||||
start.collapse(true);
|
||||
const end = origSelectionRange.duplicate();
|
||||
end.collapse(false);
|
||||
selection.startPoint = pointFromCollapsedRange(start);
|
||||
selection.endPoint = pointFromCollapsedRange(end);
|
||||
var nd = n.childNodes.item(offset);
|
||||
var max = nodeMaxIndex(nd);
|
||||
return {
|
||||
node: nd,
|
||||
index: 0,
|
||||
maxIndex: max,
|
||||
};
|
||||
}
|
||||
return selection;
|
||||
} else {
|
||||
// non-IE browser
|
||||
var browserSelection = window.getSelection();
|
||||
if (browserSelection && browserSelection.type != 'None' && browserSelection.rangeCount !== 0) {
|
||||
const range = browserSelection.getRangeAt(0);
|
||||
|
||||
function isInBody(n) {
|
||||
while (n && !(n.tagName && n.tagName.toLowerCase() == 'body')) {
|
||||
n = n.parentNode;
|
||||
}
|
||||
return !!n;
|
||||
}
|
||||
|
||||
function pointFromRangeBound(container, offset) {
|
||||
if (!isInBody(container)) {
|
||||
// command-click in Firefox selects whole document, HEAD and BODY!
|
||||
return {
|
||||
node: root,
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
}
|
||||
const n = container;
|
||||
const childCount = n.childNodes.length;
|
||||
if (isNodeText(n)) {
|
||||
return {
|
||||
node: n,
|
||||
index: offset,
|
||||
maxIndex: n.nodeValue.length,
|
||||
};
|
||||
} else if (childCount === 0) {
|
||||
return {
|
||||
node: n,
|
||||
index: 0,
|
||||
maxIndex: 1,
|
||||
};
|
||||
}
|
||||
// treat point between two nodes as BEFORE the second (rather than after the first)
|
||||
// if possible; this way point at end of a line block-element is treated as
|
||||
// at beginning of next line
|
||||
else if (offset == childCount) {
|
||||
var nd = n.childNodes.item(childCount - 1);
|
||||
var max = nodeMaxIndex(nd);
|
||||
return {
|
||||
node: nd,
|
||||
index: max,
|
||||
maxIndex: max,
|
||||
};
|
||||
} else {
|
||||
var nd = n.childNodes.item(offset);
|
||||
var max = nodeMaxIndex(nd);
|
||||
return {
|
||||
node: nd,
|
||||
index: 0,
|
||||
maxIndex: max,
|
||||
};
|
||||
}
|
||||
}
|
||||
var selection = {};
|
||||
selection.startPoint = pointFromRangeBound(range.startContainer, range.startOffset);
|
||||
selection.endPoint = pointFromRangeBound(range.endContainer, range.endOffset);
|
||||
selection.focusAtStart = (((range.startContainer != range.endContainer) || (range.startOffset != range.endOffset)) && browserSelection.anchorNode && (browserSelection.anchorNode == range.endContainer) && (browserSelection.anchorOffset == range.endOffset));
|
||||
|
||||
if (selection.startPoint.node.ownerDocument !== window.document) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return selection;
|
||||
} else { return null; }
|
||||
}
|
||||
var selection = {};
|
||||
selection.startPoint = pointFromRangeBound(range.startContainer, range.startOffset);
|
||||
selection.endPoint = pointFromRangeBound(range.endContainer, range.endOffset);
|
||||
selection.focusAtStart = (((range.startContainer != range.endContainer) || (range.startOffset != range.endOffset)) && browserSelection.anchorNode && (browserSelection.anchorNode == range.endContainer) && (browserSelection.anchorOffset == range.endOffset));
|
||||
|
||||
if (selection.startPoint.node.ownerDocument !== window.document) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
function setSelection(selection) {
|
||||
|
@ -3582,191 +3304,80 @@ function Ace2Inner() {
|
|||
maxIndex: pt.maxIndex,
|
||||
};
|
||||
}
|
||||
if (browser.msie) {
|
||||
// Oddly enough, accessing scrollHeight fixes return key handling on IE 8,
|
||||
// presumably by forcing some kind of internal DOM update.
|
||||
doc.body.scrollHeight;
|
||||
let isCollapsed;
|
||||
|
||||
function moveToElementText(s, n) {
|
||||
while (n.firstChild && !isNodeText(n.firstChild)) {
|
||||
n = n.firstChild;
|
||||
}
|
||||
s.moveToElementText(n);
|
||||
}
|
||||
|
||||
function newRange() {
|
||||
return doc.body.createTextRange();
|
||||
}
|
||||
|
||||
function setCollapsedBefore(s, n) {
|
||||
// s is an IE TextRange, n is a dom node
|
||||
if (isNodeText(n)) {
|
||||
// previous node should not also be text, but prevent inf recurs
|
||||
if (n.previousSibling && !isNodeText(n.previousSibling)) {
|
||||
setCollapsedAfter(s, n.previousSibling);
|
||||
} else {
|
||||
setCollapsedBefore(s, n.parentNode);
|
||||
}
|
||||
} else {
|
||||
moveToElementText(s, n);
|
||||
// work around for issue that caret at beginning of line
|
||||
// somehow ends up at end of previous line
|
||||
if (s.move('character', 1)) {
|
||||
s.move('character', -1);
|
||||
}
|
||||
s.collapse(true); // to start
|
||||
}
|
||||
}
|
||||
|
||||
function setCollapsedAfter(s, n) {
|
||||
// s is an IE TextRange, n is a magicdom node
|
||||
if (isNodeText(n)) {
|
||||
// can't use end of container when no nextSibling (could be on next line),
|
||||
// so use previousSibling or start of container and move forward.
|
||||
setCollapsedBefore(s, n);
|
||||
s.move('character', n.nodeValue.length);
|
||||
} else {
|
||||
moveToElementText(s, n);
|
||||
s.collapse(false); // to end
|
||||
}
|
||||
}
|
||||
|
||||
function getPointRange(point) {
|
||||
const s = newRange();
|
||||
const n = point.node;
|
||||
if (isNodeText(n)) {
|
||||
setCollapsedBefore(s, n);
|
||||
s.move('character', point.index);
|
||||
} else if (point.index === 0) {
|
||||
setCollapsedBefore(s, n);
|
||||
} else {
|
||||
setCollapsedAfter(s, n);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
if (selection) {
|
||||
if (!hasIESelection()) {
|
||||
return; // don't steal focus
|
||||
}
|
||||
|
||||
const startPoint = copyPoint(selection.startPoint);
|
||||
const endPoint = copyPoint(selection.endPoint);
|
||||
|
||||
// fix issue where selection can't be extended past end of line
|
||||
// with shift-rightarrow or shift-downarrow
|
||||
if (endPoint.index == endPoint.maxIndex && endPoint.node.nextSibling) {
|
||||
endPoint.node = endPoint.node.nextSibling;
|
||||
endPoint.index = 0;
|
||||
endPoint.maxIndex = nodeMaxIndex(endPoint.node);
|
||||
}
|
||||
var range = getPointRange(startPoint);
|
||||
range.setEndPoint('EndToEnd', getPointRange(endPoint));
|
||||
|
||||
// setting the selection in IE causes everything to scroll
|
||||
// so that the selection is visible. if setting the selection
|
||||
// definitely accomplishes nothing, don't do it.
|
||||
|
||||
|
||||
function isEqualToDocumentSelection(rng) {
|
||||
let browserSelection;
|
||||
try {
|
||||
browserSelection = doc.selection;
|
||||
} catch (e) {}
|
||||
if (!browserSelection) return false;
|
||||
const rng2 = browserSelection.createRange();
|
||||
if (rng2.parentElement().ownerDocument != doc) return false;
|
||||
if (rng.compareEndPoints('StartToStart', rng2) !== 0) return false;
|
||||
if (rng.compareEndPoints('EndToEnd', rng2) !== 0) return false;
|
||||
return true;
|
||||
}
|
||||
if (!isEqualToDocumentSelection(range)) {
|
||||
// dmesg(toSource(selection));
|
||||
// dmesg(escapeHTML(doc.body.innerHTML));
|
||||
range.select();
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
doc.selection.empty();
|
||||
} catch (e) {}
|
||||
}
|
||||
} else {
|
||||
// non-IE browser
|
||||
let isCollapsed;
|
||||
|
||||
function pointToRangeBound(pt) {
|
||||
const p = copyPoint(pt);
|
||||
// Make sure Firefox cursor is deep enough; fixes cursor jumping when at top level,
|
||||
// and also problem where cut/copy of a whole line selected with fake arrow-keys
|
||||
// copies the next line too.
|
||||
if (isCollapsed) {
|
||||
function diveDeep() {
|
||||
while (p.node.childNodes.length > 0) {
|
||||
// && (p.node == root || p.node.parentNode == root)) {
|
||||
if (p.index === 0) {
|
||||
p.node = p.node.firstChild;
|
||||
p.maxIndex = nodeMaxIndex(p.node);
|
||||
} else if (p.index == p.maxIndex) {
|
||||
p.node = p.node.lastChild;
|
||||
p.maxIndex = nodeMaxIndex(p.node);
|
||||
p.index = p.maxIndex;
|
||||
} else { break; }
|
||||
}
|
||||
}
|
||||
// now fix problem where cursor at end of text node at end of span-like element
|
||||
// with background doesn't seem to show up...
|
||||
if (isNodeText(p.node) && p.index == p.maxIndex) {
|
||||
let n = p.node;
|
||||
while ((!n.nextSibling) && (n != root) && (n.parentNode != root)) {
|
||||
n = n.parentNode;
|
||||
}
|
||||
if (n.nextSibling && (!((typeof n.nextSibling.tagName) === 'string' && n.nextSibling.tagName.toLowerCase() == 'br')) && (n != p.node) && (n != root) && (n.parentNode != root)) {
|
||||
// found a parent, go to next node and dive in
|
||||
p.node = n.nextSibling;
|
||||
function pointToRangeBound(pt) {
|
||||
const p = copyPoint(pt);
|
||||
// Make sure Firefox cursor is deep enough; fixes cursor jumping when at top level,
|
||||
// and also problem where cut/copy of a whole line selected with fake arrow-keys
|
||||
// copies the next line too.
|
||||
if (isCollapsed) {
|
||||
function diveDeep() {
|
||||
while (p.node.childNodes.length > 0) {
|
||||
// && (p.node == root || p.node.parentNode == root)) {
|
||||
if (p.index === 0) {
|
||||
p.node = p.node.firstChild;
|
||||
p.maxIndex = nodeMaxIndex(p.node);
|
||||
p.index = 0;
|
||||
diveDeep();
|
||||
}
|
||||
} else if (p.index == p.maxIndex) {
|
||||
p.node = p.node.lastChild;
|
||||
p.maxIndex = nodeMaxIndex(p.node);
|
||||
p.index = p.maxIndex;
|
||||
} else { break; }
|
||||
}
|
||||
// try to make sure insertion point is styled;
|
||||
// also fixes other FF problems
|
||||
if (!isNodeText(p.node)) {
|
||||
}
|
||||
// now fix problem where cursor at end of text node at end of span-like element
|
||||
// with background doesn't seem to show up...
|
||||
if (isNodeText(p.node) && p.index == p.maxIndex) {
|
||||
let n = p.node;
|
||||
while ((!n.nextSibling) && (n != root) && (n.parentNode != root)) {
|
||||
n = n.parentNode;
|
||||
}
|
||||
if (n.nextSibling && (!((typeof n.nextSibling.tagName) === 'string' && n.nextSibling.tagName.toLowerCase() == 'br')) && (n != p.node) && (n != root) && (n.parentNode != root)) {
|
||||
// found a parent, go to next node and dive in
|
||||
p.node = n.nextSibling;
|
||||
p.maxIndex = nodeMaxIndex(p.node);
|
||||
p.index = 0;
|
||||
diveDeep();
|
||||
}
|
||||
}
|
||||
if (isNodeText(p.node)) {
|
||||
return {
|
||||
container: p.node,
|
||||
offset: p.index,
|
||||
};
|
||||
} else {
|
||||
// p.index in {0,1}
|
||||
return {
|
||||
container: p.node.parentNode,
|
||||
offset: childIndex(p.node) + p.index,
|
||||
};
|
||||
// try to make sure insertion point is styled;
|
||||
// also fixes other FF problems
|
||||
if (!isNodeText(p.node)) {
|
||||
diveDeep();
|
||||
}
|
||||
}
|
||||
const browserSelection = window.getSelection();
|
||||
if (browserSelection) {
|
||||
browserSelection.removeAllRanges();
|
||||
if (selection) {
|
||||
isCollapsed = (selection.startPoint.node === selection.endPoint.node && selection.startPoint.index === selection.endPoint.index);
|
||||
const start = pointToRangeBound(selection.startPoint);
|
||||
const end = pointToRangeBound(selection.endPoint);
|
||||
if (isNodeText(p.node)) {
|
||||
return {
|
||||
container: p.node,
|
||||
offset: p.index,
|
||||
};
|
||||
} else {
|
||||
// p.index in {0,1}
|
||||
return {
|
||||
container: p.node.parentNode,
|
||||
offset: childIndex(p.node) + p.index,
|
||||
};
|
||||
}
|
||||
}
|
||||
const browserSelection = window.getSelection();
|
||||
if (browserSelection) {
|
||||
browserSelection.removeAllRanges();
|
||||
if (selection) {
|
||||
isCollapsed = (selection.startPoint.node === selection.endPoint.node && selection.startPoint.index === selection.endPoint.index);
|
||||
const start = pointToRangeBound(selection.startPoint);
|
||||
const end = pointToRangeBound(selection.endPoint);
|
||||
|
||||
if ((!isCollapsed) && selection.focusAtStart && browserSelection.collapse && browserSelection.extend) {
|
||||
// can handle "backwards"-oriented selection, shift-arrow-keys move start
|
||||
// of selection
|
||||
browserSelection.collapse(end.container, end.offset);
|
||||
browserSelection.extend(start.container, start.offset);
|
||||
} else {
|
||||
var range = doc.createRange();
|
||||
range.setStart(start.container, start.offset);
|
||||
range.setEnd(end.container, end.offset);
|
||||
browserSelection.removeAllRanges();
|
||||
browserSelection.addRange(range);
|
||||
}
|
||||
if ((!isCollapsed) && selection.focusAtStart && browserSelection.collapse && browserSelection.extend) {
|
||||
// can handle "backwards"-oriented selection, shift-arrow-keys move start
|
||||
// of selection
|
||||
browserSelection.collapse(end.container, end.offset);
|
||||
browserSelection.extend(start.container, start.offset);
|
||||
} else {
|
||||
var range = doc.createRange();
|
||||
range.setStart(start.container, start.offset);
|
||||
range.setEnd(end.container, end.offset);
|
||||
browserSelection.removeAllRanges();
|
||||
browserSelection.addRange(range);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3802,30 +3413,6 @@ function Ace2Inner() {
|
|||
});
|
||||
}
|
||||
|
||||
const iePastedLines = null;
|
||||
|
||||
function handleIEPaste(evt) {
|
||||
// Pasting in IE loses blank lines in a way that loses information;
|
||||
// "one\n\ntwo\nthree" becomes "<p>one</p><p>two</p><p>three</p>",
|
||||
// which becomes "one\ntwo\nthree". We can get the correct text
|
||||
// from the clipboard directly, but we still have to let the paste
|
||||
// happen to get the style information.
|
||||
const clipText = window.clipboardData && window.clipboardData.getData('Text');
|
||||
if (clipText && doc.selection) {
|
||||
// this "paste" event seems to mess with the selection whether we try to
|
||||
// stop it or not, so can't really do document-level manipulation now
|
||||
// or in an idle call-stack. instead, use IE native manipulation
|
||||
// function escapeLine(txt) {
|
||||
// return processSpaces(escapeHTML(textify(txt)));
|
||||
// }
|
||||
// var newHTML = map(clipText.replace(/\r/g,'').split('\n'), escapeLine).join('<br>');
|
||||
// doc.selection.createRange().pasteHTML(newHTML);
|
||||
// evt.preventDefault();
|
||||
// iePastedLines = map(clipText.replace(/\r/g,'').split('\n'), textify);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var inInternationalComposition = false;
|
||||
function handleCompositionEvent(evt) {
|
||||
// international input events, fired in FF3, at least; allow e.g. Japanese input
|
||||
|
@ -3852,10 +3439,6 @@ function Ace2Inner() {
|
|||
// $(document).on("cut", handleCut);
|
||||
|
||||
$(root).on('blur', handleBlur);
|
||||
if (browser.msie) {
|
||||
$(document).on('click', handleIEOuterClick);
|
||||
}
|
||||
if (browser.msie) $(root).on('paste', handleIEPaste);
|
||||
|
||||
// If non-nullish, pasting on a link should be suppressed.
|
||||
let suppressPasteOnLink = null;
|
||||
|
@ -3932,11 +3515,8 @@ function Ace2Inner() {
|
|||
});
|
||||
});
|
||||
|
||||
// CompositionEvent is not implemented below IE version 8
|
||||
if (!(browser.msie && parseInt(browser.version <= 9)) && document.documentElement) {
|
||||
$(document.documentElement).on('compositionstart', handleCompositionEvent);
|
||||
$(document.documentElement).on('compositionend', handleCompositionEvent);
|
||||
}
|
||||
$(document.documentElement).on('compositionstart', handleCompositionEvent);
|
||||
$(document.documentElement).on('compositionend', handleCompositionEvent);
|
||||
}
|
||||
|
||||
function topLevel(n) {
|
||||
|
@ -3947,26 +3527,6 @@ function Ace2Inner() {
|
|||
return n;
|
||||
}
|
||||
|
||||
function handleIEOuterClick(evt) {
|
||||
if ((evt.target.tagName || '').toLowerCase() != 'html') {
|
||||
return;
|
||||
}
|
||||
if (!(evt.pageY > root.clientHeight)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// click below the body
|
||||
inCallStackIfNecessary('handleOuterClick', () => {
|
||||
// put caret at bottom of doc
|
||||
fastIncorp(11);
|
||||
if (isCaret()) { // don't interfere with drag
|
||||
const lastLine = rep.lines.length() - 1;
|
||||
const lastCol = rep.lines.atIndex(lastLine).text.length;
|
||||
performSelectionChange([lastLine, lastCol], [lastLine, lastCol]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function getClassArray(elem, optFilter) {
|
||||
const bodyClasses = [];
|
||||
(elem.className || '').replace(/\S+/g, (c) => {
|
||||
|
@ -3985,14 +3545,7 @@ function Ace2Inner() {
|
|||
window.focus();
|
||||
}
|
||||
|
||||
function handleBlur(evt) {
|
||||
if (browser.msie) {
|
||||
// a fix: in IE, clicking on a control like a button outside the
|
||||
// iframe can "blur" the editor, causing it to stop getting
|
||||
// events, though typing still affects it(!).
|
||||
setSelection(null);
|
||||
}
|
||||
}
|
||||
function handleBlur(evt) {}
|
||||
|
||||
function getSelectionPointX(point) {
|
||||
// doesn't work in wrap-mode
|
||||
|
@ -4335,7 +3888,6 @@ function Ace2Inner() {
|
|||
root = body; // defined as a var in scope outside
|
||||
if (browser.firefox) $(root).addClass('mozilla');
|
||||
if (browser.safari) $(root).addClass('safari');
|
||||
if (browser.msie) $(root).addClass('msie');
|
||||
root.classList.toggle('authorColors', true);
|
||||
root.classList.toggle('doesWrap', doesWrap);
|
||||
|
||||
|
|
|
@ -606,9 +606,7 @@ function makeContentCollector(collectStyles, abrowser, apool, domInterface, clas
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!abrowser.msie) {
|
||||
_reachBlockPoint(node, 1, state);
|
||||
}
|
||||
_reachBlockPoint(node, 1, state);
|
||||
if (isBlock) {
|
||||
if (lines.length() - 1 == startLine) {
|
||||
// added additional check to resolve https://github.com/JohnMcLear/ep_copy_paste_images/issues/20
|
||||
|
@ -624,10 +622,6 @@ function makeContentCollector(collectStyles, abrowser, apool, domInterface, clas
|
|||
_ensureColumnZero(state);
|
||||
}
|
||||
}
|
||||
if (abrowser.msie) {
|
||||
// in IE, a point immediately after a DIV appears on the next line
|
||||
_reachBlockPoint(node, 1, state);
|
||||
}
|
||||
state.localAttribs = localAttribs;
|
||||
};
|
||||
// can pass a falsy value for end of doc
|
||||
|
|
|
@ -201,7 +201,7 @@ domline.createDomLine = function (nonEmpty, doesWrap, optBrowser, optDocument) {
|
|||
if (!newHTML) {
|
||||
if ((!document) || (!optBrowser)) {
|
||||
newHTML += ' ';
|
||||
} else if (!optBrowser.msie) {
|
||||
} else {
|
||||
newHTML += '<br/>';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -275,13 +275,6 @@ linestylefilter.getFilterStack = function (lineText, textAndClassFunc, abrowser)
|
|||
func = hookFilter(lineText, func);
|
||||
});
|
||||
|
||||
if (abrowser !== undefined && abrowser.msie) {
|
||||
// IE7+ will take an e-mail address like <foo@bar.com> and linkify it to foo@bar.com.
|
||||
// We then normalize it back to text with no angle brackets. It's weird. So always
|
||||
// break spans at an "at" sign.
|
||||
func = linestylefilter.getAtSignSplitterFilter(
|
||||
lineText, func);
|
||||
}
|
||||
return func;
|
||||
};
|
||||
|
||||
|
|
|
@ -406,13 +406,6 @@ var pad = {
|
|||
pad.initTime = +(new Date());
|
||||
pad.padOptions = clientVars.initialOptions;
|
||||
|
||||
// for IE
|
||||
if (browser.msie) {
|
||||
try {
|
||||
document.execCommand('BackgroundImageCache', false, true);
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
// order of inits is important here:
|
||||
pad.myUserInfo = {
|
||||
userId: clientVars.userId,
|
||||
|
|
|
@ -543,11 +543,7 @@ const paduserlist = (function () {
|
|||
|
||||
$('#myswatch').css({'background-color': myUserInfo.colorId});
|
||||
|
||||
if (browser.msie && parseInt(browser.version) <= 8) {
|
||||
$('li[data-key=showusers] > a').css({'box-shadow': `inset 0 0 30px ${myUserInfo.colorId}`, 'background-color': myUserInfo.colorId});
|
||||
} else {
|
||||
$('li[data-key=showusers] > a').css({'box-shadow': `inset 0 0 30px ${myUserInfo.colorId}`});
|
||||
}
|
||||
$('li[data-key=showusers] > a').css({'box-shadow': `inset 0 0 30px ${myUserInfo.colorId}`});
|
||||
},
|
||||
};
|
||||
return self;
|
||||
|
|
Loading…
Reference in a new issue