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
|
Existing group pads that were previously password protected will no longer be
|
||||||
password protected. If you need fine-grained access control, you can restrict
|
password protected. If you need fine-grained access control, you can restrict
|
||||||
API session creation in your frontend service, or you can use plugins.
|
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
|
* Plugin hook functions are now subject to new sanity checks. Buggy hook
|
||||||
functions will cause an error message to be logged
|
functions will cause an error message to be logged
|
||||||
* Authorization failures now return 403 by default instead of 401
|
* Authorization failures now return 403 by default instead of 401
|
||||||
|
|
|
@ -24,15 +24,6 @@ const padutils = require('./pad_utils').padutils;
|
||||||
|
|
||||||
let _, $, jQuery, plugins, Ace2Common;
|
let _, $, jQuery, plugins, Ace2Common;
|
||||||
const browser = require('./browser');
|
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');
|
Ace2Common = require('./ace2_common');
|
||||||
|
|
||||||
|
@ -1180,12 +1171,6 @@ function Ace2Inner() {
|
||||||
const dirtyNodes = [];
|
const dirtyNodes = [];
|
||||||
for (let n = firstDirtyNode; n && !(n.previousSibling && n.previousSibling == lastDirtyNode);
|
for (let n = firstDirtyNode; n && !(n.previousSibling && n.previousSibling == lastDirtyNode);
|
||||||
n = n.nextSibling) {
|
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);
|
cc.collectContent(n);
|
||||||
dirtyNodes.push(n);
|
dirtyNodes.push(n);
|
||||||
}
|
}
|
||||||
|
@ -1213,14 +1198,13 @@ function Ace2Inner() {
|
||||||
var scrollToTheLeftNeeded = false;
|
var scrollToTheLeftNeeded = false;
|
||||||
|
|
||||||
if (linesWrapped > 0) {
|
if (linesWrapped > 0) {
|
||||||
if (!browser.msie) {
|
// Chrome decides in its infinite wisdom that it's okay to put the browser's visisble
|
||||||
// chrome decides in it's infinite wisdom that its okay to put the browsers visisble window in the middle of the span
|
// window in the middle of the span. An outcome of this is that the first chars of the
|
||||||
// an outcome of this is that the first chars of the string are no longer visible to the user.. Yay chrome..
|
// string are no longer visible to the user.. Yay chrome.. Move the browser's visible area
|
||||||
// Move the browsers visible area to the left hand side of the span
|
// to the left hand side of the span. Firefox isn't quite so bad, but it's still pretty
|
||||||
// Firefox isn't quite so bad, but it's still pretty quirky.
|
// quirky.
|
||||||
var scrollToTheLeftNeeded = true;
|
var scrollToTheLeftNeeded = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (ss[0] >= 0) selStart = [ss[0] + a + netNumLinesChangeSoFar, ss[1]];
|
if (ss[0] >= 0) selStart = [ss[0] + a + netNumLinesChangeSoFar, ss[1]];
|
||||||
if (se[0] >= 0) selEnd = [se[0] + a + netNumLinesChangeSoFar, se[1]];
|
if (se[0] >= 0) selEnd = [se[0] + a + netNumLinesChangeSoFar, se[1]];
|
||||||
|
@ -1472,15 +1456,6 @@ function Ace2Inner() {
|
||||||
let after = false;
|
let after = false;
|
||||||
if (charsLeft === 0) {
|
if (charsLeft === 0) {
|
||||||
let index = 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 {
|
return {
|
||||||
node: lineNode,
|
node: lineNode,
|
||||||
index,
|
index,
|
||||||
|
@ -1514,12 +1489,8 @@ function Ace2Inner() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function nodeText(n) {
|
function nodeText(n) {
|
||||||
if (browser.msie) {
|
|
||||||
return n.innerText;
|
|
||||||
} else {
|
|
||||||
return n.textContent || n.nodeValue || '';
|
return n.textContent || n.nodeValue || '';
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function getLineAndCharForPoint(point) {
|
function getLineAndCharForPoint(point) {
|
||||||
// Turn DOM node selection into [line,char] selection.
|
// Turn DOM node selection into [line,char] selection.
|
||||||
|
@ -2281,60 +2252,8 @@ function Ace2Inner() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function doCreateDomLine(nonEmpty) {
|
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) {
|
function textify(str) {
|
||||||
return str.replace(/[\n\r ]/g, ' ').replace(/\xa0/g, ' ').replace(/\t/g, ' ');
|
return str.replace(/[\n\r ]/g, ' ').replace(/\xa0/g, ' ').replace(/\t/g, ' ');
|
||||||
|
@ -2558,12 +2477,6 @@ function Ace2Inner() {
|
||||||
const dirtiness = {};
|
const dirtiness = {};
|
||||||
dirtiness.nodeId = uniqueId(n);
|
dirtiness.nodeId = uniqueId(n);
|
||||||
dirtiness.knownHTML = n.innerHTML;
|
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);
|
setAssoc(n, 'dirtiness', dirtiness);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2573,9 +2486,6 @@ function Ace2Inner() {
|
||||||
const data = getAssoc(n, 'dirtiness');
|
const data = getAssoc(n, 'dirtiness');
|
||||||
if (!data) return true;
|
if (!data) return true;
|
||||||
if (n.id !== data.nodeId) 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;
|
if (n.innerHTML !== data.knownHTML) return true;
|
||||||
p.end();
|
p.end();
|
||||||
return false;
|
return false;
|
||||||
|
@ -2839,21 +2749,12 @@ function Ace2Inner() {
|
||||||
// On Mac and Linux, move right moves to end of word and move left moves to start;
|
// 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, always move to start of word.
|
||||||
// On Windows, Firefox and IE disagree on whether to stop for punctuation (FF says no).
|
// 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())) {
|
while ((!isDone()) && !isWordChar(nextChar())) {
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
while ((!isDone()) && isWordChar(nextChar())) {
|
while ((!isDone()) && isWordChar(nextChar())) {
|
||||||
advance();
|
advance();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
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
|
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;
|
let specialHandled = false;
|
||||||
const isTypeForSpecialKey = ((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.msie || 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;
|
let stopped = false;
|
||||||
|
|
||||||
inCallStackIfNecessary('handleKeyEvent', function () {
|
inCallStackIfNecessary('handleKeyEvent', function () {
|
||||||
|
@ -3319,193 +3220,16 @@ function Ace2Inner() {
|
||||||
else return 1;
|
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() {
|
function getSelection() {
|
||||||
// returns null, or a structure containing startPoint and endPoint,
|
// returns null, or a structure containing startPoint and endPoint,
|
||||||
// each of which has node (a magicdom node), index, and maxIndex. If the node
|
// 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.
|
// is a text node, maxIndex is the length of the text; else maxIndex is 1.
|
||||||
// index is between 0 and maxIndex, inclusive.
|
// 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;
|
|
||||||
|
|
||||||
const newRange = function () {
|
|
||||||
return doc.body.createTextRange();
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
return {
|
|
||||||
node: tn,
|
|
||||||
index: tn.nodeValue.length,
|
|
||||||
maxIndex: tn.nodeValue.length,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
const start = origSelectionRange.duplicate();
|
|
||||||
start.collapse(true);
|
|
||||||
const end = origSelectionRange.duplicate();
|
|
||||||
end.collapse(false);
|
|
||||||
selection.startPoint = pointFromCollapsedRange(start);
|
|
||||||
selection.endPoint = pointFromCollapsedRange(end);
|
|
||||||
}
|
|
||||||
return selection;
|
|
||||||
} else {
|
|
||||||
// non-IE browser
|
|
||||||
var browserSelection = window.getSelection();
|
var browserSelection = window.getSelection();
|
||||||
if (browserSelection && browserSelection.type != 'None' && browserSelection.rangeCount !== 0) {
|
if (!browserSelection || browserSelection.type === 'None' ||
|
||||||
|
browserSelection.rangeCount === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const range = browserSelection.getRangeAt(0);
|
const range = browserSelection.getRangeAt(0);
|
||||||
|
|
||||||
function isInBody(n) {
|
function isInBody(n) {
|
||||||
|
@ -3570,8 +3294,6 @@ function Ace2Inner() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return selection;
|
return selection;
|
||||||
} else { return null; }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function setSelection(selection) {
|
function setSelection(selection) {
|
||||||
|
@ -3582,116 +3304,6 @@ function Ace2Inner() {
|
||||||
maxIndex: pt.maxIndex,
|
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;
|
|
||||||
|
|
||||||
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;
|
let isCollapsed;
|
||||||
|
|
||||||
function pointToRangeBound(pt) {
|
function pointToRangeBound(pt) {
|
||||||
|
@ -3770,7 +3382,6 @@ function Ace2Inner() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function childIndex(n) {
|
function childIndex(n) {
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
|
@ -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;
|
var inInternationalComposition = false;
|
||||||
function handleCompositionEvent(evt) {
|
function handleCompositionEvent(evt) {
|
||||||
// international input events, fired in FF3, at least; allow e.g. Japanese input
|
// international input events, fired in FF3, at least; allow e.g. Japanese input
|
||||||
|
@ -3852,10 +3439,6 @@ function Ace2Inner() {
|
||||||
// $(document).on("cut", handleCut);
|
// $(document).on("cut", handleCut);
|
||||||
|
|
||||||
$(root).on('blur', handleBlur);
|
$(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.
|
// If non-nullish, pasting on a link should be suppressed.
|
||||||
let suppressPasteOnLink = null;
|
let suppressPasteOnLink = null;
|
||||||
|
@ -3932,12 +3515,9 @@ 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('compositionstart', handleCompositionEvent);
|
||||||
$(document.documentElement).on('compositionend', handleCompositionEvent);
|
$(document.documentElement).on('compositionend', handleCompositionEvent);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
function topLevel(n) {
|
function topLevel(n) {
|
||||||
if ((!n) || n == root) return null;
|
if ((!n) || n == root) return null;
|
||||||
|
@ -3947,26 +3527,6 @@ function Ace2Inner() {
|
||||||
return n;
|
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) {
|
function getClassArray(elem, optFilter) {
|
||||||
const bodyClasses = [];
|
const bodyClasses = [];
|
||||||
(elem.className || '').replace(/\S+/g, (c) => {
|
(elem.className || '').replace(/\S+/g, (c) => {
|
||||||
|
@ -3985,14 +3545,7 @@ function Ace2Inner() {
|
||||||
window.focus();
|
window.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleBlur(evt) {
|
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 getSelectionPointX(point) {
|
function getSelectionPointX(point) {
|
||||||
// doesn't work in wrap-mode
|
// doesn't work in wrap-mode
|
||||||
|
@ -4335,7 +3888,6 @@ function Ace2Inner() {
|
||||||
root = body; // defined as a var in scope outside
|
root = body; // defined as a var in scope outside
|
||||||
if (browser.firefox) $(root).addClass('mozilla');
|
if (browser.firefox) $(root).addClass('mozilla');
|
||||||
if (browser.safari) $(root).addClass('safari');
|
if (browser.safari) $(root).addClass('safari');
|
||||||
if (browser.msie) $(root).addClass('msie');
|
|
||||||
root.classList.toggle('authorColors', true);
|
root.classList.toggle('authorColors', true);
|
||||||
root.classList.toggle('doesWrap', doesWrap);
|
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 (isBlock) {
|
||||||
if (lines.length() - 1 == startLine) {
|
if (lines.length() - 1 == startLine) {
|
||||||
// added additional check to resolve https://github.com/JohnMcLear/ep_copy_paste_images/issues/20
|
// 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);
|
_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;
|
state.localAttribs = localAttribs;
|
||||||
};
|
};
|
||||||
// can pass a falsy value for end of doc
|
// can pass a falsy value for end of doc
|
||||||
|
|
|
@ -201,7 +201,7 @@ domline.createDomLine = function (nonEmpty, doesWrap, optBrowser, optDocument) {
|
||||||
if (!newHTML) {
|
if (!newHTML) {
|
||||||
if ((!document) || (!optBrowser)) {
|
if ((!document) || (!optBrowser)) {
|
||||||
newHTML += ' ';
|
newHTML += ' ';
|
||||||
} else if (!optBrowser.msie) {
|
} else {
|
||||||
newHTML += '<br/>';
|
newHTML += '<br/>';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -275,13 +275,6 @@ linestylefilter.getFilterStack = function (lineText, textAndClassFunc, abrowser)
|
||||||
func = hookFilter(lineText, func);
|
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;
|
return func;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -406,13 +406,6 @@ var pad = {
|
||||||
pad.initTime = +(new Date());
|
pad.initTime = +(new Date());
|
||||||
pad.padOptions = clientVars.initialOptions;
|
pad.padOptions = clientVars.initialOptions;
|
||||||
|
|
||||||
// for IE
|
|
||||||
if (browser.msie) {
|
|
||||||
try {
|
|
||||||
document.execCommand('BackgroundImageCache', false, true);
|
|
||||||
} catch (e) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
// order of inits is important here:
|
// order of inits is important here:
|
||||||
pad.myUserInfo = {
|
pad.myUserInfo = {
|
||||||
userId: clientVars.userId,
|
userId: clientVars.userId,
|
||||||
|
|
|
@ -543,11 +543,7 @@ const paduserlist = (function () {
|
||||||
|
|
||||||
$('#myswatch').css({'background-color': myUserInfo.colorId});
|
$('#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;
|
return self;
|
||||||
|
|
Loading…
Reference in a new issue