mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-02-01 03:12:42 +01:00
Merge branch 'develop' of github.com:ether/etherpad-lite into image-example
This commit is contained in:
commit
5bedfa0ba1
6 changed files with 198 additions and 211 deletions
|
@ -1,3 +1,4 @@
|
|||
'use strict';
|
||||
/**
|
||||
* This code represents the Attribute Pool Object of the original Etherpad.
|
||||
* 90% of the code is still like in the original Etherpad
|
||||
|
@ -69,7 +70,7 @@ AttributePool.prototype.getAttribValue = function (num) {
|
|||
};
|
||||
|
||||
AttributePool.prototype.eachAttrib = function (func) {
|
||||
for (const n in this.numToAttrib) {
|
||||
for (const n of Object.keys(this.numToAttrib)) {
|
||||
const pair = this.numToAttrib[n];
|
||||
func(pair[0], pair[1]);
|
||||
}
|
||||
|
@ -86,7 +87,7 @@ AttributePool.prototype.fromJsonable = function (obj) {
|
|||
this.numToAttrib = obj.numToAttrib;
|
||||
this.nextNum = obj.nextNum;
|
||||
this.attribToNum = {};
|
||||
for (const n in this.numToAttrib) {
|
||||
for (const n of Object.keys(this.numToAttrib)) {
|
||||
this.attribToNum[String(this.numToAttrib[n])] = Number(n);
|
||||
}
|
||||
return this;
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
'use strict';
|
||||
|
||||
// One rep.line(div) can be broken in more than one line in the browser.
|
||||
// This function is useful to get the caret position of the line as
|
||||
// is represented by the browser
|
||||
exports.getPosition = function () {
|
||||
exports.getPosition = () => {
|
||||
let rect, line;
|
||||
const editor = $('#innerdocbody')[0];
|
||||
const range = getSelectionRange();
|
||||
const isSelectionInsideTheEditor = range && $(range.endContainer).closest('body')[0].id === 'innerdocbody';
|
||||
const isSelectionInsideTheEditor = range &&
|
||||
$(range.endContainer).closest('body')[0].id === 'innerdocbody';
|
||||
|
||||
if (isSelectionInsideTheEditor) {
|
||||
// when we have the caret in an empty line, e.g. a line with only a <br>,
|
||||
// getBoundingClientRect() returns all dimensions value as 0
|
||||
const selectionIsInTheBeginningOfLine = range.endOffset > 0;
|
||||
if (selectionIsInTheBeginningOfLine) {
|
||||
var clonedRange = createSelectionRange(range);
|
||||
const clonedRange = createSelectionRange(range);
|
||||
line = getPositionOfElementOrSelection(clonedRange);
|
||||
clonedRange.detach();
|
||||
}
|
||||
|
@ -20,7 +22,7 @@ exports.getPosition = function () {
|
|||
// when there's a <br> or any element that has no height, we can't get
|
||||
// the dimension of the element where the caret is
|
||||
if (!rect || rect.height === 0) {
|
||||
var clonedRange = createSelectionRange(range);
|
||||
const clonedRange = createSelectionRange(range);
|
||||
|
||||
// as we can't get the element height, we create a text node to get the dimensions
|
||||
// on the position
|
||||
|
@ -36,8 +38,8 @@ exports.getPosition = function () {
|
|||
return line;
|
||||
};
|
||||
|
||||
var createSelectionRange = function (range) {
|
||||
clonedRange = range.cloneRange();
|
||||
const createSelectionRange = (range) => {
|
||||
const clonedRange = range.cloneRange();
|
||||
|
||||
// we set the selection start and end to avoid error when user selects a text bigger than
|
||||
// the viewport height and uses the arrow keys to expand the selection. In this particular
|
||||
|
@ -48,7 +50,7 @@ var createSelectionRange = function (range) {
|
|||
return clonedRange;
|
||||
};
|
||||
|
||||
const getPositionOfRepLineAtOffset = function (node, offset) {
|
||||
const getPositionOfRepLineAtOffset = (node, offset) => {
|
||||
// it is not a text node, so we cannot make a selection
|
||||
if (node.tagName === 'BR' || node.tagName === 'EMPTY') {
|
||||
return getPositionOfElementOrSelection(node);
|
||||
|
@ -66,7 +68,7 @@ const getPositionOfRepLineAtOffset = function (node, offset) {
|
|||
return linePosition;
|
||||
};
|
||||
|
||||
function getPositionOfElementOrSelection(element) {
|
||||
const getPositionOfElementOrSelection = (element) => {
|
||||
const rect = element.getBoundingClientRect();
|
||||
const linePosition = {
|
||||
bottom: rect.bottom,
|
||||
|
@ -74,15 +76,15 @@ function getPositionOfElementOrSelection(element) {
|
|||
top: rect.top,
|
||||
};
|
||||
return linePosition;
|
||||
}
|
||||
};
|
||||
|
||||
// here we have two possibilities:
|
||||
// [1] the line before the caret line has the same type, so both of them has the same margin, padding
|
||||
// height, etc. So, we can use the caret line to make calculation necessary to know where is the top
|
||||
// of the previous line
|
||||
// [1] the line before the caret line has the same type, so both of them has the same margin,
|
||||
// padding height, etc. So, we can use the caret line to make calculation necessary to know
|
||||
// where is the top of the previous line
|
||||
// [2] the line before is part of another rep line. It's possible this line has different margins
|
||||
// height. So we have to get the exactly position of the line
|
||||
exports.getPositionTopOfPreviousBrowserLine = function (caretLinePosition, rep) {
|
||||
exports.getPositionTopOfPreviousBrowserLine = (caretLinePosition, rep) => {
|
||||
let previousLineTop = caretLinePosition.top - caretLinePosition.height; // [1]
|
||||
const isCaretLineFirstBrowserLine = caretLineIsFirstBrowserLine(caretLinePosition.top, rep);
|
||||
|
||||
|
@ -91,13 +93,14 @@ exports.getPositionTopOfPreviousBrowserLine = function (caretLinePosition, rep)
|
|||
if (isCaretLineFirstBrowserLine) { // [2]
|
||||
const lineBeforeCaretLine = rep.selStart[0] - 1;
|
||||
const firstLineVisibleBeforeCaretLine = getPreviousVisibleLine(lineBeforeCaretLine, rep);
|
||||
const linePosition = getDimensionOfLastBrowserLineOfRepLine(firstLineVisibleBeforeCaretLine, rep);
|
||||
const linePosition =
|
||||
getDimensionOfLastBrowserLineOfRepLine(firstLineVisibleBeforeCaretLine, rep);
|
||||
previousLineTop = linePosition.top;
|
||||
}
|
||||
return previousLineTop;
|
||||
};
|
||||
|
||||
function caretLineIsFirstBrowserLine(caretLineTop, rep) {
|
||||
const caretLineIsFirstBrowserLine = (caretLineTop, rep) => {
|
||||
const caretRepLine = rep.selStart[0];
|
||||
const lineNode = rep.lines.atIndex(caretRepLine).lineNode;
|
||||
const firstRootNode = getFirstRootChildNode(lineNode);
|
||||
|
@ -105,37 +108,28 @@ function caretLineIsFirstBrowserLine(caretLineTop, rep) {
|
|||
// to get the position of the node we get the position of the first char
|
||||
const positionOfFirstRootNode = getPositionOfRepLineAtOffset(firstRootNode, 1);
|
||||
return positionOfFirstRootNode.top === caretLineTop;
|
||||
}
|
||||
};
|
||||
|
||||
// find the first root node, usually it is a text node
|
||||
function getFirstRootChildNode(node) {
|
||||
const getFirstRootChildNode = (node) => {
|
||||
if (!node.firstChild) {
|
||||
return node;
|
||||
} else {
|
||||
return getFirstRootChildNode(node.firstChild);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
function getPreviousVisibleLine(line, rep) {
|
||||
if (line < 0) {
|
||||
return 0;
|
||||
} else if (isLineVisible(line, rep)) {
|
||||
return line;
|
||||
} else {
|
||||
return getPreviousVisibleLine(line - 1, rep);
|
||||
}
|
||||
}
|
||||
|
||||
function getDimensionOfLastBrowserLineOfRepLine(line, rep) {
|
||||
const getDimensionOfLastBrowserLineOfRepLine = (line, rep) => {
|
||||
const lineNode = rep.lines.atIndex(line).lineNode;
|
||||
const lastRootChildNode = getLastRootChildNode(lineNode);
|
||||
|
||||
// we get the position of the line in the last char of it
|
||||
const lastRootChildNodePosition = getPositionOfRepLineAtOffset(lastRootChildNode.node, lastRootChildNode.length);
|
||||
const lastRootChildNodePosition =
|
||||
getPositionOfRepLineAtOffset(lastRootChildNode.node, lastRootChildNode.length);
|
||||
return lastRootChildNodePosition;
|
||||
}
|
||||
};
|
||||
|
||||
function getLastRootChildNode(node) {
|
||||
const getLastRootChildNode = (node) => {
|
||||
if (!node.lastChild) {
|
||||
return {
|
||||
node,
|
||||
|
@ -144,39 +138,42 @@ function getLastRootChildNode(node) {
|
|||
} else {
|
||||
return getLastRootChildNode(node.lastChild);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// here we have two possibilities:
|
||||
// [1] The next line is part of the same rep line of the caret line, so we have the same dimensions.
|
||||
// So, we can use the caret line to calculate the bottom of the line.
|
||||
// [2] the next line is part of another rep line. It's possible this line has different dimensions, so we
|
||||
// have to get the exactly dimension of it
|
||||
exports.getBottomOfNextBrowserLine = function (caretLinePosition, rep) {
|
||||
// [2] the next line is part of another rep line.
|
||||
// It's possible this line has different dimensions, so we have to get the exactly dimension of it
|
||||
exports.getBottomOfNextBrowserLine = (caretLinePosition, rep) => {
|
||||
let nextLineBottom = caretLinePosition.bottom + caretLinePosition.height; // [1]
|
||||
const isCaretLineLastBrowserLine = caretLineIsLastBrowserLineOfRepLine(caretLinePosition.top, rep);
|
||||
const isCaretLineLastBrowserLine =
|
||||
caretLineIsLastBrowserLineOfRepLine(caretLinePosition.top, rep);
|
||||
|
||||
// the caret is at the end of a rep line, so we can get the next browser line dimension
|
||||
// using the position of the first char of the next rep line
|
||||
if (isCaretLineLastBrowserLine) { // [2]
|
||||
const nextLineAfterCaretLine = rep.selStart[0] + 1;
|
||||
const firstNextLineVisibleAfterCaretLine = getNextVisibleLine(nextLineAfterCaretLine, rep);
|
||||
const linePosition = getDimensionOfFirstBrowserLineOfRepLine(firstNextLineVisibleAfterCaretLine, rep);
|
||||
const linePosition =
|
||||
getDimensionOfFirstBrowserLineOfRepLine(firstNextLineVisibleAfterCaretLine, rep);
|
||||
nextLineBottom = linePosition.bottom;
|
||||
}
|
||||
return nextLineBottom;
|
||||
};
|
||||
|
||||
function caretLineIsLastBrowserLineOfRepLine(caretLineTop, rep) {
|
||||
const caretLineIsLastBrowserLineOfRepLine = (caretLineTop, rep) => {
|
||||
const caretRepLine = rep.selStart[0];
|
||||
const lineNode = rep.lines.atIndex(caretRepLine).lineNode;
|
||||
const lastRootChildNode = getLastRootChildNode(lineNode);
|
||||
|
||||
// we take a rep line and get the position of the last char of it
|
||||
const lastRootChildNodePosition = getPositionOfRepLineAtOffset(lastRootChildNode.node, lastRootChildNode.length);
|
||||
const lastRootChildNodePosition =
|
||||
getPositionOfRepLineAtOffset(lastRootChildNode.node, lastRootChildNode.length);
|
||||
return lastRootChildNodePosition.top === caretLineTop;
|
||||
}
|
||||
};
|
||||
|
||||
function getPreviousVisibleLine(line, rep) {
|
||||
const getPreviousVisibleLine = (line, rep) => {
|
||||
const firstLineOfPad = 0;
|
||||
if (line <= firstLineOfPad) {
|
||||
return firstLineOfPad;
|
||||
|
@ -185,10 +182,12 @@ function getPreviousVisibleLine(line, rep) {
|
|||
} else {
|
||||
return getPreviousVisibleLine(line - 1, rep);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
exports.getPreviousVisibleLine = getPreviousVisibleLine;
|
||||
|
||||
function getNextVisibleLine(line, rep) {
|
||||
const getNextVisibleLine = (line, rep) => {
|
||||
const lastLineOfThePad = rep.lines.length() - 1;
|
||||
if (line >= lastLineOfThePad) {
|
||||
return lastLineOfThePad;
|
||||
|
@ -197,31 +196,28 @@ function getNextVisibleLine(line, rep) {
|
|||
} else {
|
||||
return getNextVisibleLine(line + 1, rep);
|
||||
}
|
||||
}
|
||||
};
|
||||
exports.getNextVisibleLine = getNextVisibleLine;
|
||||
|
||||
function isLineVisible(line, rep) {
|
||||
return rep.lines.atIndex(line).lineNode.offsetHeight > 0;
|
||||
}
|
||||
const isLineVisible = (line, rep) => rep.lines.atIndex(line).lineNode.offsetHeight > 0;
|
||||
|
||||
function getDimensionOfFirstBrowserLineOfRepLine(line, rep) {
|
||||
const getDimensionOfFirstBrowserLineOfRepLine = (line, rep) => {
|
||||
const lineNode = rep.lines.atIndex(line).lineNode;
|
||||
const firstRootChildNode = getFirstRootChildNode(lineNode);
|
||||
|
||||
// we can get the position of the line, getting the position of the first char of the rep line
|
||||
const firstRootChildNodePosition = getPositionOfRepLineAtOffset(firstRootChildNode, 1);
|
||||
return firstRootChildNodePosition;
|
||||
}
|
||||
};
|
||||
|
||||
function getSelectionRange() {
|
||||
let selection;
|
||||
const getSelectionRange = () => {
|
||||
if (!window.getSelection) {
|
||||
return;
|
||||
}
|
||||
selection = window.getSelection();
|
||||
const selection = window.getSelection();
|
||||
if (selection.rangeCount > 0) {
|
||||
return selection.getRangeAt(0);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* This code is mostly from the old Etherpad. Please help us to comment this code.
|
||||
* This helps other people to understand this code better and helps them to improve it.
|
||||
|
@ -26,24 +28,24 @@ const colorutils = {};
|
|||
|
||||
// Check that a given value is a css hex color value, e.g.
|
||||
// "#ffffff" or "#fff"
|
||||
colorutils.isCssHex = function (cssColor) {
|
||||
return /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(cssColor);
|
||||
};
|
||||
colorutils.isCssHex = (cssColor) => /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(cssColor);
|
||||
|
||||
// "#ffffff" or "#fff" or "ffffff" or "fff" to [1.0, 1.0, 1.0]
|
||||
colorutils.css2triple = function (cssColor) {
|
||||
colorutils.css2triple = (cssColor) => {
|
||||
const sixHex = colorutils.css2sixhex(cssColor);
|
||||
|
||||
function hexToFloat(hh) {
|
||||
return Number(`0x${hh}`) / 255;
|
||||
}
|
||||
return [hexToFloat(sixHex.substr(0, 2)), hexToFloat(sixHex.substr(2, 2)), hexToFloat(sixHex.substr(4, 2))];
|
||||
const hexToFloat = (hh) => Number(`0x${hh}`) / 255;
|
||||
return [
|
||||
hexToFloat(sixHex.substr(0, 2)),
|
||||
hexToFloat(sixHex.substr(2, 2)),
|
||||
hexToFloat(sixHex.substr(4, 2)),
|
||||
];
|
||||
};
|
||||
|
||||
// "#ffffff" or "#fff" or "ffffff" or "fff" to "ffffff"
|
||||
colorutils.css2sixhex = function (cssColor) {
|
||||
colorutils.css2sixhex = (cssColor) => {
|
||||
let h = /[0-9a-fA-F]+/.exec(cssColor)[0];
|
||||
if (h.length != 6) {
|
||||
if (h.length !== 6) {
|
||||
const a = h.charAt(0);
|
||||
const b = h.charAt(1);
|
||||
const c = h.charAt(2);
|
||||
|
@ -53,66 +55,54 @@ colorutils.css2sixhex = function (cssColor) {
|
|||
};
|
||||
|
||||
// [1.0, 1.0, 1.0] -> "#ffffff"
|
||||
colorutils.triple2css = function (triple) {
|
||||
function floatToHex(n) {
|
||||
colorutils.triple2css = (triple) => {
|
||||
const floatToHex = (n) => {
|
||||
const n2 = colorutils.clamp(Math.round(n * 255), 0, 255);
|
||||
return (`0${n2.toString(16)}`).slice(-2);
|
||||
}
|
||||
};
|
||||
return `#${floatToHex(triple[0])}${floatToHex(triple[1])}${floatToHex(triple[2])}`;
|
||||
};
|
||||
|
||||
|
||||
colorutils.clamp = function (v, bot, top) {
|
||||
return v < bot ? bot : (v > top ? top : v);
|
||||
};
|
||||
colorutils.min3 = function (a, b, c) {
|
||||
return (a < b) ? (a < c ? a : c) : (b < c ? b : c);
|
||||
};
|
||||
colorutils.max3 = function (a, b, c) {
|
||||
return (a > b) ? (a > c ? a : c) : (b > c ? b : c);
|
||||
};
|
||||
colorutils.colorMin = function (c) {
|
||||
return colorutils.min3(c[0], c[1], c[2]);
|
||||
};
|
||||
colorutils.colorMax = function (c) {
|
||||
return colorutils.max3(c[0], c[1], c[2]);
|
||||
};
|
||||
colorutils.scale = function (v, bot, top) {
|
||||
return colorutils.clamp(bot + v * (top - bot), 0, 1);
|
||||
};
|
||||
colorutils.unscale = function (v, bot, top) {
|
||||
return colorutils.clamp((v - bot) / (top - bot), 0, 1);
|
||||
};
|
||||
colorutils.clamp = (v, bot, top) => v < bot ? bot : (v > top ? top : v);
|
||||
colorutils.min3 = (a, b, c) => (a < b) ? (a < c ? a : c) : (b < c ? b : c);
|
||||
colorutils.max3 = (a, b, c) => (a > b) ? (a > c ? a : c) : (b > c ? b : c);
|
||||
colorutils.colorMin = (c) => colorutils.min3(c[0], c[1], c[2]);
|
||||
colorutils.colorMax = (c) => colorutils.max3(c[0], c[1], c[2]);
|
||||
colorutils.scale = (v, bot, top) => colorutils.clamp(bot + v * (top - bot), 0, 1);
|
||||
colorutils.unscale = (v, bot, top) => colorutils.clamp((v - bot) / (top - bot), 0, 1);
|
||||
|
||||
colorutils.scaleColor = function (c, bot, top) {
|
||||
return [colorutils.scale(c[0], bot, top), colorutils.scale(c[1], bot, top), colorutils.scale(c[2], bot, top)];
|
||||
};
|
||||
colorutils.scaleColor = (c, bot, top) => [
|
||||
colorutils.scale(c[0], bot, top),
|
||||
colorutils.scale(c[1], bot, top),
|
||||
colorutils.scale(c[2], bot, top),
|
||||
];
|
||||
|
||||
colorutils.unscaleColor = function (c, bot, top) {
|
||||
return [colorutils.unscale(c[0], bot, top), colorutils.unscale(c[1], bot, top), colorutils.unscale(c[2], bot, top)];
|
||||
};
|
||||
colorutils.unscaleColor = (c, bot, top) => [
|
||||
colorutils.unscale(c[0], bot, top),
|
||||
colorutils.unscale(c[1], bot, top),
|
||||
colorutils.unscale(c[2], bot, top),
|
||||
];
|
||||
|
||||
colorutils.luminosity = function (c) {
|
||||
// rule of thumb for RGB brightness; 1.0 is white
|
||||
return c[0] * 0.30 + c[1] * 0.59 + c[2] * 0.11;
|
||||
};
|
||||
colorutils.luminosity = (c) => c[0] * 0.30 + c[1] * 0.59 + c[2] * 0.11;
|
||||
|
||||
colorutils.saturate = function (c) {
|
||||
colorutils.saturate = (c) => {
|
||||
const min = colorutils.colorMin(c);
|
||||
const max = colorutils.colorMax(c);
|
||||
if (max - min <= 0) return [1.0, 1.0, 1.0];
|
||||
return colorutils.unscaleColor(c, min, max);
|
||||
};
|
||||
|
||||
colorutils.blend = function (c1, c2, t) {
|
||||
return [colorutils.scale(t, c1[0], c2[0]), colorutils.scale(t, c1[1], c2[1]), colorutils.scale(t, c1[2], c2[2])];
|
||||
};
|
||||
colorutils.blend = (c1, c2, t) => [
|
||||
colorutils.scale(t, c1[0], c2[0]),
|
||||
colorutils.scale(t, c1[1], c2[1]),
|
||||
colorutils.scale(t, c1[2], c2[2]),
|
||||
];
|
||||
|
||||
colorutils.invert = function (c) {
|
||||
return [1 - c[0], 1 - c[1], 1 - c[2]];
|
||||
};
|
||||
colorutils.invert = (c) => [1 - c[0], 1 - c[1], 1 - c[2]];
|
||||
|
||||
colorutils.complementary = function (c) {
|
||||
colorutils.complementary = (c) => {
|
||||
const inv = colorutils.invert(c);
|
||||
return [
|
||||
(inv[0] >= c[0]) ? Math.min(inv[0] * 1.30, 1) : (c[0] * 0.30),
|
||||
|
@ -121,9 +111,9 @@ colorutils.complementary = function (c) {
|
|||
];
|
||||
};
|
||||
|
||||
colorutils.textColorFromBackgroundColor = function (bgcolor, skinName) {
|
||||
const white = skinName == 'colibris' ? 'var(--super-light-color)' : '#fff';
|
||||
const black = skinName == 'colibris' ? 'var(--super-dark-color)' : '#222';
|
||||
colorutils.textColorFromBackgroundColor = (bgcolor, skinName) => {
|
||||
const white = skinName === 'colibris' ? 'var(--super-light-color)' : '#fff';
|
||||
const black = skinName === 'colibris' ? 'var(--super-dark-color)' : '#222';
|
||||
|
||||
return colorutils.luminosity(colorutils.css2triple(bgcolor)) < 0.5 ? white : black;
|
||||
};
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* This code is mostly from the old Etherpad. Please help us to comment this code.
|
||||
* This helps other people to understand this code better and helps them to improve it.
|
||||
|
@ -20,14 +22,15 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
function makeCSSManager(emptyStylesheetTitle, doc) {
|
||||
const makeCSSManager = (emptyStylesheetTitle, doc) => {
|
||||
if (doc === true) {
|
||||
doc = 'parent';
|
||||
} else if (!doc) {
|
||||
doc = 'inner';
|
||||
}
|
||||
|
||||
function getSheetByTitle(title) {
|
||||
const getSheetByTitle = (title) => {
|
||||
let win;
|
||||
if (doc === 'parent') {
|
||||
win = window.parent.parent;
|
||||
} else if (doc === 'inner') {
|
||||
|
@ -35,46 +38,44 @@ function makeCSSManager(emptyStylesheetTitle, doc) {
|
|||
} else if (doc === 'outer') {
|
||||
win = window.parent;
|
||||
} else {
|
||||
throw 'Unknown dynamic style container';
|
||||
throw new Error('Unknown dynamic style container');
|
||||
}
|
||||
const allSheets = win.document.styleSheets;
|
||||
|
||||
for (let i = 0; i < allSheets.length; i++) {
|
||||
const s = allSheets[i];
|
||||
if (s.title == title) {
|
||||
if (s.title === title) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
const browserSheet = getSheetByTitle(emptyStylesheetTitle);
|
||||
|
||||
function browserRules() {
|
||||
return (browserSheet.cssRules || browserSheet.rules);
|
||||
}
|
||||
const browserRules = () => (browserSheet.cssRules || browserSheet.rules);
|
||||
|
||||
function browserDeleteRule(i) {
|
||||
const browserDeleteRule = (i) => {
|
||||
if (browserSheet.deleteRule) browserSheet.deleteRule(i);
|
||||
else browserSheet.removeRule(i);
|
||||
}
|
||||
};
|
||||
|
||||
function browserInsertRule(i, selector) {
|
||||
const browserInsertRule = (i, selector) => {
|
||||
if (browserSheet.insertRule) browserSheet.insertRule(`${selector} {}`, i);
|
||||
else browserSheet.addRule(selector, null, i);
|
||||
}
|
||||
};
|
||||
const selectorList = [];
|
||||
|
||||
function indexOfSelector(selector) {
|
||||
const indexOfSelector = (selector) => {
|
||||
for (let i = 0; i < selectorList.length; i++) {
|
||||
if (selectorList[i] == selector) {
|
||||
if (selectorList[i] === selector) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
function selectorStyle(selector) {
|
||||
const selectorStyle = (selector) => {
|
||||
let i = indexOfSelector(selector);
|
||||
if (i < 0) {
|
||||
// add selector
|
||||
|
@ -83,23 +84,21 @@ function makeCSSManager(emptyStylesheetTitle, doc) {
|
|||
i = 0;
|
||||
}
|
||||
return browserRules().item(i).style;
|
||||
}
|
||||
};
|
||||
|
||||
function removeSelectorStyle(selector) {
|
||||
const removeSelectorStyle = (selector) => {
|
||||
const i = indexOfSelector(selector);
|
||||
if (i >= 0) {
|
||||
browserDeleteRule(i);
|
||||
selectorList.splice(i, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
selectorStyle,
|
||||
removeSelectorStyle,
|
||||
info() {
|
||||
return `${selectorList.length}:${browserRules().length}`;
|
||||
},
|
||||
info: () => `${selectorList.length}:${browserRules().length}`,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
exports.makeCSSManager = makeCSSManager;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* This code is mostly from the old Etherpad. Please help us to comment this code.
|
||||
* This helps other people to understand this code better and helps them to improve it.
|
||||
|
@ -31,7 +33,6 @@
|
|||
const Changeset = require('./Changeset');
|
||||
const hooks = require('./pluginfw/hooks');
|
||||
const linestylefilter = {};
|
||||
const _ = require('./underscore');
|
||||
const AttributeManager = require('./AttributeManager');
|
||||
const padutils = require('./pad_utils').padutils;
|
||||
|
||||
|
@ -45,32 +46,30 @@ linestylefilter.ATTRIB_CLASSES = {
|
|||
const lineAttributeMarker = 'lineAttribMarker';
|
||||
exports.lineAttributeMarker = lineAttributeMarker;
|
||||
|
||||
linestylefilter.getAuthorClassName = function (author) {
|
||||
return `author-${author.replace(/[^a-y0-9]/g, (c) => {
|
||||
if (c == '.') return '-';
|
||||
linestylefilter.getAuthorClassName = (author) => `author-${author.replace(/[^a-y0-9]/g, (c) => {
|
||||
if (c === '.') return '-';
|
||||
return `z${c.charCodeAt(0)}z`;
|
||||
})}`;
|
||||
};
|
||||
|
||||
// lineLength is without newline; aline includes newline,
|
||||
// but may be falsy if lineLength == 0
|
||||
linestylefilter.getLineStyleFilter = function (lineLength, aline, textAndClassFunc, apool) {
|
||||
linestylefilter.getLineStyleFilter = (lineLength, aline, textAndClassFunc, apool) => {
|
||||
// Plugin Hook to add more Attrib Classes
|
||||
for (const attribClasses of hooks.callAll('aceAttribClasses', linestylefilter.ATTRIB_CLASSES)) {
|
||||
Object.assign(linestylefilter.ATTRIB_CLASSES, attribClasses);
|
||||
}
|
||||
|
||||
if (lineLength == 0) return textAndClassFunc;
|
||||
if (lineLength === 0) return textAndClassFunc;
|
||||
|
||||
const nextAfterAuthorColors = textAndClassFunc;
|
||||
|
||||
const authorColorFunc = (function () {
|
||||
const authorColorFunc = (() => {
|
||||
const lineEnd = lineLength;
|
||||
let curIndex = 0;
|
||||
let extraClasses;
|
||||
let leftInAuthor;
|
||||
|
||||
function attribsToClasses(attribs) {
|
||||
const attribsToClasses = (attribs) => {
|
||||
let classes = '';
|
||||
let isLineAttribMarker = false;
|
||||
top.console.log("attribs", attribs)
|
||||
|
@ -81,14 +80,14 @@ top.console.log("attribs", attribs)
|
|||
if (key) {
|
||||
const value = apool.getAttribValue(n);
|
||||
if (value) {
|
||||
if (!isLineAttribMarker && _.indexOf(AttributeManager.lineAttributes, key) >= 0) {
|
||||
if (!isLineAttribMarker && AttributeManager.lineAttributes.indexOf(key) >= 0) {
|
||||
isLineAttribMarker = true;
|
||||
}
|
||||
if (key == 'author') {
|
||||
if (key === 'author') {
|
||||
classes += ` ${linestylefilter.getAuthorClassName(value)}`;
|
||||
} else if (key == 'list') {
|
||||
} else if (key === 'list') {
|
||||
classes += ` list:${value}`;
|
||||
} else if (key == 'start') {
|
||||
} else if (key === 'start') {
|
||||
// Needed to introduce the correct Ordered list item start number on import
|
||||
classes += ` start:${value}`;
|
||||
} else if (linestylefilter.ATTRIB_CLASSES[key]) {
|
||||
|
@ -106,37 +105,38 @@ top.console.log("attribs", attribs)
|
|||
|
||||
if (isLineAttribMarker) classes += ` ${lineAttributeMarker}`;
|
||||
return classes.substring(1);
|
||||
}
|
||||
};
|
||||
|
||||
const attributionIter = Changeset.opIterator(aline);
|
||||
let nextOp, nextOpClasses;
|
||||
|
||||
function goNextOp() {
|
||||
const goNextOp = () => {
|
||||
nextOp = attributionIter.next();
|
||||
nextOpClasses = (nextOp.opcode && attribsToClasses(nextOp.attribs));
|
||||
}
|
||||
};
|
||||
goNextOp();
|
||||
|
||||
function nextClasses() {
|
||||
const nextClasses = () => {
|
||||
if (curIndex < lineEnd) {
|
||||
extraClasses = nextOpClasses;
|
||||
leftInAuthor = nextOp.chars;
|
||||
goNextOp();
|
||||
while (nextOp.opcode && nextOpClasses == extraClasses) {
|
||||
while (nextOp.opcode && nextOpClasses === extraClasses) {
|
||||
leftInAuthor += nextOp.chars;
|
||||
goNextOp();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
nextClasses();
|
||||
|
||||
return function (txt, cls) {
|
||||
return (txt, cls) => {
|
||||
const disableAuthColorForThisLine = hooks.callAll('disableAuthorColorsForThisLine', {
|
||||
linestylefilter,
|
||||
text: txt,
|
||||
class: cls,
|
||||
}, ' ', ' ', '');
|
||||
const disableAuthors = (disableAuthColorForThisLine == null || disableAuthColorForThisLine.length == 0) ? false : disableAuthColorForThisLine[0];
|
||||
const disableAuthors = (disableAuthColorForThisLine == null ||
|
||||
disableAuthColorForThisLine.length === 0) ? false : disableAuthColorForThisLine[0];
|
||||
while (txt.length > 0) {
|
||||
if (leftInAuthor <= 0 || disableAuthors) {
|
||||
// prevent infinite loop if something funny's going on
|
||||
|
@ -151,7 +151,7 @@ top.console.log("attribs", attribs)
|
|||
nextAfterAuthorColors(curTxt, (cls && `${cls} `) + extraClasses);
|
||||
curIndex += spanSize;
|
||||
leftInAuthor -= spanSize;
|
||||
if (leftInAuthor == 0) {
|
||||
if (leftInAuthor === 0) {
|
||||
nextClasses();
|
||||
}
|
||||
}
|
||||
|
@ -160,7 +160,7 @@ top.console.log("attribs", attribs)
|
|||
return authorColorFunc;
|
||||
};
|
||||
|
||||
linestylefilter.getAtSignSplitterFilter = function (lineText, textAndClassFunc) {
|
||||
linestylefilter.getAtSignSplitterFilter = (lineText, textAndClassFunc) => {
|
||||
const at = /@/g;
|
||||
at.lastIndex = 0;
|
||||
let splitPoints = null;
|
||||
|
@ -177,8 +177,7 @@ linestylefilter.getAtSignSplitterFilter = function (lineText, textAndClassFunc)
|
|||
return linestylefilter.textAndClassFuncSplitter(textAndClassFunc, splitPoints);
|
||||
};
|
||||
|
||||
linestylefilter.getRegexpFilter = function (regExp, tag) {
|
||||
return function (lineText, textAndClassFunc) {
|
||||
linestylefilter.getRegexpFilter = (regExp, tag) => (lineText, textAndClassFunc) => {
|
||||
regExp.lastIndex = 0;
|
||||
let regExpMatchs = null;
|
||||
let splitPoints = null;
|
||||
|
@ -196,7 +195,7 @@ linestylefilter.getRegexpFilter = function (regExp, tag) {
|
|||
|
||||
if (!regExpMatchs) return textAndClassFunc;
|
||||
|
||||
function regExpMatchForIndex(idx) {
|
||||
const regExpMatchForIndex = (idx) => {
|
||||
for (let k = 0; k < regExpMatchs.length; k++) {
|
||||
const u = regExpMatchs[k];
|
||||
if (idx >= u[0] && idx < u[0] + u[1].length) {
|
||||
|
@ -204,11 +203,11 @@ linestylefilter.getRegexpFilter = function (regExp, tag) {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
const handleRegExpMatchsAfterSplit = (function () {
|
||||
const handleRegExpMatchsAfterSplit = (() => {
|
||||
let curIndex = 0;
|
||||
return function (txt, cls) {
|
||||
return (txt, cls) => {
|
||||
const txtlen = txt.length;
|
||||
let newCls = cls;
|
||||
const regExpMatch = regExpMatchForIndex(curIndex);
|
||||
|
@ -222,21 +221,22 @@ linestylefilter.getRegexpFilter = function (regExp, tag) {
|
|||
|
||||
return linestylefilter.textAndClassFuncSplitter(handleRegExpMatchsAfterSplit, splitPoints);
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
linestylefilter.getURLFilter = linestylefilter.getRegexpFilter(padutils.urlRegex, 'url');
|
||||
|
||||
linestylefilter.textAndClassFuncSplitter = function (func, splitPointsOpt) {
|
||||
linestylefilter.textAndClassFuncSplitter = (func, splitPointsOpt) => {
|
||||
let nextPointIndex = 0;
|
||||
let idx = 0;
|
||||
|
||||
// don't split at 0
|
||||
while (splitPointsOpt && nextPointIndex < splitPointsOpt.length && splitPointsOpt[nextPointIndex] == 0) {
|
||||
while (splitPointsOpt &&
|
||||
nextPointIndex < splitPointsOpt.length &&
|
||||
splitPointsOpt[nextPointIndex] === 0) {
|
||||
nextPointIndex++;
|
||||
}
|
||||
|
||||
function spanHandler(txt, cls) {
|
||||
const spanHandler = (txt, cls) => {
|
||||
if ((!splitPointsOpt) || nextPointIndex >= splitPointsOpt.length) {
|
||||
func(txt, cls);
|
||||
idx += txt.length;
|
||||
|
@ -247,7 +247,7 @@ linestylefilter.textAndClassFuncSplitter = function (func, splitPointsOpt) {
|
|||
if (pointLocInSpan >= txtlen) {
|
||||
func(txt, cls);
|
||||
idx += txt.length;
|
||||
if (pointLocInSpan == txtlen) {
|
||||
if (pointLocInSpan === txtlen) {
|
||||
nextPointIndex++;
|
||||
}
|
||||
} else {
|
||||
|
@ -260,18 +260,18 @@ linestylefilter.textAndClassFuncSplitter = function (func, splitPointsOpt) {
|
|||
spanHandler(txt.substring(pointLocInSpan), cls);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
return spanHandler;
|
||||
};
|
||||
|
||||
linestylefilter.getFilterStack = function (lineText, textAndClassFunc, abrowser) {
|
||||
linestylefilter.getFilterStack = (lineText, textAndClassFunc, abrowser) => {
|
||||
let func = linestylefilter.getURLFilter(lineText, textAndClassFunc);
|
||||
|
||||
const hookFilters = hooks.callAll('aceGetFilterStack', {
|
||||
linestylefilter,
|
||||
browser: abrowser,
|
||||
});
|
||||
_.map(hookFilters, (hookFilter) => {
|
||||
hookFilters.map((hookFilter) => {
|
||||
func = hookFilter(lineText, func);
|
||||
});
|
||||
|
||||
|
@ -279,16 +279,16 @@ linestylefilter.getFilterStack = function (lineText, textAndClassFunc, abrowser)
|
|||
};
|
||||
|
||||
// domLineObj is like that returned by domline.createDomLine
|
||||
linestylefilter.populateDomLine = function (textLine, aline, apool, domLineObj) {
|
||||
linestylefilter.populateDomLine = (textLine, aline, apool, domLineObj) => {
|
||||
// remove final newline from text if any
|
||||
let text = textLine;
|
||||
if (text.slice(-1) == '\n') {
|
||||
if (text.slice(-1) === '\n') {
|
||||
text = text.substring(0, text.length - 1);
|
||||
}
|
||||
|
||||
function textAndClassFunc(tokenText, tokenClass) {
|
||||
const textAndClassFunc = (tokenText, tokenClass) => {
|
||||
domLineObj.appendSpan(tokenText, tokenClass);
|
||||
}
|
||||
};
|
||||
|
||||
let func = linestylefilter.getFilterStack(text, textAndClassFunc);
|
||||
func = linestylefilter.getLineStyleFilter(text.length, aline, func, apool);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
// Proviedes a require'able version of jQuery without leaking $ and jQuery;
|
||||
'use strict';
|
||||
// Provides a require'able version of jQuery without leaking $ and jQuery;
|
||||
window.$ = require('./jquery');
|
||||
const jq = window.$.noConflict(true);
|
||||
exports.jQuery = exports.$ = jq;
|
||||
|
|
Loading…
Reference in a new issue