Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ep_cursortrace

Package Overview
Dependencies
Maintainers
6
Versions
39
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ep_cursortrace - npm Package Compare versions

Comparing version 3.0.10 to 3.1.0

50

handleMessage.js

@@ -1,2 +0,2 @@

/***
/** *
*

@@ -7,7 +7,7 @@ * Responsible for negotiating messages between two clients

var authorManager = require("ep_etherpad-lite/node/db/AuthorManager"),
padMessageHandler = require("ep_etherpad-lite/node/handler/PadMessageHandler"),
async = require('ep_etherpad-lite/node_modules/async');
const authorManager = require('ep_etherpad-lite/node/db/AuthorManager');
const padMessageHandler = require('ep_etherpad-lite/node/handler/PadMessageHandler');
const async = require('ep_etherpad-lite/node_modules/async');
var buffer = {};
const buffer = {};

@@ -17,3 +17,3 @@ /*

*/
exports.handleMessage = async function(hookName, context) {
exports.handleMessage = async function (hookName, context) {
// Firstly ignore any request that aren't about cursor

@@ -24,3 +24,3 @@ const {message: {type, data = {}} = {}} = context || {};

const message = data;
/***
/** *
What's available in a message?

@@ -33,18 +33,18 @@ * action -- The action IE cursorPosition

***/
if(message.action === 'cursorPosition'){
var authorName = await authorManager.getAuthorName(message.myAuthorId);
if (message.action === 'cursorPosition') {
const authorName = await authorManager.getAuthorName(message.myAuthorId);
var msg = {
type: "COLLABROOM",
const msg = {
type: 'COLLABROOM',
data: {
type: "CUSTOM",
type: 'CUSTOM',
payload: {
action: "cursorPosition",
action: 'cursorPosition',
authorId: message.myAuthorId,
authorName: authorName,
authorName,
padId: message.padId,
locationX: message.locationX,
locationY: message.locationY
}
}
locationY: message.locationY,
},
},
};

@@ -54,13 +54,13 @@ sendToRoom(message, msg);

return null; // null prevents Etherpad from attempting to process the message any further.
}
return null; // null prevents Etherpad from attempting to process the message any further.
};
function sendToRoom(message, msg){
var bufferAllows = true; // Todo write some buffer handling for protection and to stop DDoS -- myAuthorId exists in message.
if(bufferAllows){
setTimeout(function(){ // This is bad.. We have to do it because ACE hasn't redrawn by the time the cursor has arrived
padMessageHandler.handleCustomObjectMessage(msg, false, function(){
function sendToRoom(message, msg) {
const bufferAllows = true; // Todo write some buffer handling for protection and to stop DDoS -- myAuthorId exists in message.
if (bufferAllows) {
setTimeout(() => { // This is bad.. We have to do it because ACE hasn't redrawn by the time the cursor has arrived
padMessageHandler.handleCustomObjectMessage(msg, false, () => {
// TODO: Error handling.
})
});
}

@@ -67,0 +67,0 @@ , 500);

{
"name": "ep_cursortrace",
"description": "Show cursor/caret movements of other users in real time",
"version": "3.0.10",
"version": "3.1.0",
"author": "RedHog (Egil Moeller) <egil.moller@freecode.no>",

@@ -21,3 +21,19 @@ "repository": "git@github.com:redhog/ep_cursortrace.git",

"url": "http://etherpad.org/"
},
"devDependencies": {
"eslint": "^7.14.0",
"eslint-config-etherpad": "^1.0.8",
"eslint-plugin-mocha": "^8.0.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-prefer-arrow": "^1.2.2",
"eslint-plugin-promise": "^4.2.1"
},
"eslintConfig": {
"root": true,
"extends": "etherpad/plugin"
},
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint --fix ."
}
}

@@ -7,3 +7,2 @@ /*

*/
exports.aceEditorCSS = function(hook_name, cb){return ["/ep_cursortrace/static/css/cursortrace.css"];} // inner pad CSS
exports.aceEditorCSS = function (hook_name, cb) { return ['/ep_cursortrace/static/css/cursortrace.css']; }; // inner pad CSS

@@ -1,11 +0,15 @@

var initiated = false;
var last = undefined;
var globalKey = 0;
'use strict';
exports.aceInitInnerdocbodyHead = function(hook_name, args, cb) {
args.iframeHTML.push('<link rel="stylesheet" type="text/css" href="../static/plugins/ep_cursortrace/static/css/ace_inner.css"/>');
let initiated = false;
let last = undefined;
let globalKey = 0;
exports.aceInitInnerdocbodyHead = (hook_name, args, cb) => {
const path = '../static/plugins/ep_cursortrace/static/css/ace_inner.css';
args.iframeHTML.push(
`<link rel="stylesheet" type="text/css" href="${path}"/>`);
return cb();
};
exports.postAceInit = function(hook_name, args, cb) {
exports.postAceInit = function (hook_name, args, cb) {
initiated = true;

@@ -15,25 +19,17 @@ return cb();

exports.getAuthorClassName = function(author)
{
if(!author) return;
return "ep_cursortrace-" + author.replace(/[^a-y0-9]/g, function(c)
{
if (c == ".") return "-";
return 'z' + c.charCodeAt(0) + 'z';
exports.getAuthorClassName = (author) => {
if (!author) return false;
const authorId = author.replace(/[^a-y0-9]/g, (c) => {
if (c === '.') return '-';
return `z${c.charCodeAt(0)}z`;
});
}
return `ep_real_time_chat-${authorId}`;
};
exports.className2Author = function(className)
{
if (className.substring(0, 15) == "ep_cursortrace-")
{
return className.substring(15).replace(/[a-y0-9]+|-|z.+?z/g, function(cc)
{
if (cc == '-') return '.';
else if (cc.charAt(0) == 'z')
{
exports.className2Author = function (className) {
if (className.substring(0, 15) == 'ep_cursortrace-') {
return className.substring(15).replace(/[a-y0-9]+|-|z.+?z/g, (cc) => {
if (cc == '-') { return '.'; } else if (cc.charAt(0) == 'z') {
return String.fromCharCode(Number(cc.slice(1, -1)));
}
else
{
} else {
return cc;

@@ -44,25 +40,25 @@ }

return null;
}
};
exports.aceEditEvent = function(hook_name, args, cb) {
exports.aceEditEvent = function (hook_name, args, cb) {
// Note: last is a tri-state: undefined (when the pad is first loaded), null (no last cursor) and [line, col]
// The AceEditEvent because it usually applies to selected items and isn't really so mucha bout current position.
var caretMoving = ((args.callstack.editEvent.eventType == "handleClick") || (args.callstack.type === "handleKeyEvent") || (args.callstack.type === "idleWorkTimer") );
if (caretMoving && initiated){ // Note that we have to use idle timer to get the mouse position
var Y = args.rep.selStart[0];
var X = args.rep.selStart[1];
const caretMoving = ((args.callstack.editEvent.eventType == 'handleClick') || (args.callstack.type === 'handleKeyEvent') || (args.callstack.type === 'idleWorkTimer'));
if (caretMoving && initiated) { // Note that we have to use idle timer to get the mouse position
const Y = args.rep.selStart[0];
const X = args.rep.selStart[1];
if (!last || Y != last[0] || X != last[1]) { // If the position has changed
var cls = exports.getAuthorClassName(args.editorInfo.ace_getAuthor());
var myAuthorId = pad.getUserId();
var padId = pad.getPadId();
var location = {y: Y, x: X};
const cls = exports.getAuthorClassName(args.editorInfo.ace_getAuthor());
const myAuthorId = pad.getUserId();
const padId = pad.getPadId();
const location = {y: Y, x: X};
// Create a cursor position message to send to the server
var message = {
type : 'cursor',
action : 'cursorPosition',
const message = {
type: 'cursor',
action: 'cursorPosition',
locationY: Y,
locationX: X,
padId : padId,
myAuthorId : myAuthorId
}
padId,
myAuthorId,
};
last = [];

@@ -73,42 +69,41 @@ last[0] = Y;

// console.log("Sent message", message);
pad.collabClient.sendMessage(message); // Send the cursor position message to the server
pad.collabClient.sendMessage(message); // Send the cursor position message to the server
}
}
return cb();
}
};
exports.handleClientMessage_CUSTOM = function(hook, context, cb){
exports.handleClientMessage_CUSTOM = function (hook, context, cb) {
/* I NEED A REFACTOR, please */
// A huge problem with this is that it runs BEFORE the dom has been updated so edit events are always late..
var action = context.payload.action;
var padId = context.payload.padId;
var authorId = context.payload.authorId;
if(pad.getUserId() === authorId) return false; // Dont process our own caret position (yes we do get it..) -- This is not a bug
var authorClass = exports.getAuthorClassName(authorId);
const action = context.payload.action;
const padId = context.payload.padId;
const authorId = context.payload.authorId;
if (pad.getUserId() === authorId) return false; // Dont process our own caret position (yes we do get it..) -- This is not a bug
const authorClass = exports.getAuthorClassName(authorId);
if(action === 'cursorPosition'){ // an author has sent this client a cursor position, we need to show it in the dom
if (action === 'cursorPosition') { // an author has sent this client a cursor position, we need to show it in the dom
var authorName = context.payload.authorName;
if(authorName == "null"){
var authorName = "😊" // If the users username isn't set then display a smiley face
if (authorName == 'null') {
var authorName = '😊'; // If the users username isn't set then display a smiley face
}
var y = context.payload.locationY + 1; // +1 as Etherpad line numbers start at 1
var x = context.payload.locationX;
var inner = $('iframe[name="ace_outer"]').contents().find('iframe');
var innerWidth = inner.contents().find('#innerdocbody').width();
if(inner.length !== 0){
const y = context.payload.locationY + 1; // +1 as Etherpad line numbers start at 1
let x = context.payload.locationX;
const inner = $('iframe[name="ace_outer"]').contents().find('iframe');
const innerWidth = inner.contents().find('#innerdocbody').width();
if (inner.length !== 0) {
var leftOffset = parseInt($(inner).offset().left);
leftOffset = leftOffset + parseInt($(inner).css('padding-left'));
leftOffset += parseInt($(inner).css('padding-left'));
}
var stickUp = false;
let stickUp = false;
// Get the target Line
var div = $('iframe[name="ace_outer"]').contents().find('iframe').contents().find('#innerdocbody').find("div:nth-child("+y+")");
const div = $('iframe[name="ace_outer"]').contents().find('iframe').contents().find('#innerdocbody').find(`div:nth-child(${y})`);
var divWidth = div.width();
const divWidth = div.width();
// Is the line visible yet?
if ( div.length !== 0 ) {
var top = $(div).offset().top; // A standard generic offset
if (div.length !== 0) {
let top = $(div).offset().top; // A standard generic offset
// The problem we have here is we don't know the px X offset of the caret from the user

@@ -124,18 +119,18 @@ // Because that's a blocker for now lets just put a nice little div on the left hand side..

// We need the offset of the innerdocbody on top too.
top = top + parseInt($('iframe[name="ace_outer"]').contents().find('iframe').css('paddingTop'));
top += parseInt($('iframe[name="ace_outer"]').contents().find('iframe').css('paddingTop'));
// Get the HTML
var html = $(div).html();
const html = $(div).html();
// build an ugly ID, makes sense to use authorId as authorId's cursor can only exist once
var authorWorker = "hiddenUgly" + exports.getAuthorClassName(authorId);
const authorWorker = `hiddenUgly${exports.getAuthorClassName(authorId)}`;
// if Div contains block attribute IE h1 or H2 then increment by the number
if ( $(div).children("span").length < 1 ){ x = x - 1; }// This is horrible but a limitation because I'm parsing HTML
if ($(div).children('span').length < 1) { x -= 1; }// This is horrible but a limitation because I'm parsing HTML
// Get the new string but maintain mark up
var newText = html_substr(html, (x));
const newText = html_substr(html, (x));
// A load of ugly HTML that can prolly be moved to CSS
var newLine = "<span style='width:"+divWidth+"px' id='" + authorWorker + "' class='ghettoCursorXPos'>"+newText+"</span>";
const newLine = `<span style='width:${divWidth}px' id='${authorWorker}' class='ghettoCursorXPos'>${newText}</span>`;

@@ -149,3 +144,3 @@ // Set the globalKey to 0, we use this when we wrap the objects in a datakey

// Get the worker element
var worker = $('iframe[name="ace_outer"]').contents().find('#outerdocbody').find("#" + authorWorker);
const worker = $('iframe[name="ace_outer"]').contents().find('#outerdocbody').find(`#${authorWorker}`);

@@ -157,8 +152,8 @@ // Wrap the HTML in spans so we can find a char

// Get the Left offset of the x span
var span = $(worker).find("[data-key="+(x-1)+"]");
const span = $(worker).find(`[data-key=${x - 1}]`);
// Get the width of the element (This is how far out X is in px);
if(span.length !== 0){
if (span.length !== 0) {
var left = span.position().left;
}else{
} else {
// empty span.

@@ -169,63 +164,63 @@ var left = 0;

// Get the height of the element minus the inner line height
var height = worker.height(); // the height of the worker
const height = worker.height(); // the height of the worker
top = top + height - (span.height() || 12); // plus the top offset minus the actual height of our focus span
if(top <= 0){ // If the tooltip wont be visible to the user because it's too high up
if (top <= 0) { // If the tooltip wont be visible to the user because it's too high up
stickUp = true;
top = top + (span.height()*2);
if(top < 0){ top = 0; } // handle case where caret is in 0,0
top += (span.height() * 2);
if (top < 0) { top = 0; } // handle case where caret is in 0,0
}
// Add the innerdocbody offset
left = left + leftOffset;
left += leftOffset;
// Add support for page view margins
var divMargin = $(div).css("margin-left");
var innerdocbodyMargin = $(div).parent().css("padding-left");
if(innerdocbodyMargin){
let divMargin = $(div).css('margin-left');
let innerdocbodyMargin = $(div).parent().css('padding-left');
if (innerdocbodyMargin) {
innerdocbodyMargin = parseInt(innerdocbodyMargin);
}else{
} else {
innerdocbodyMargin = 0;
}
if(divMargin){
divMargin = divMargin.replace("px", "");
if (divMargin) {
divMargin = divMargin.replace('px', '');
// console.log("Margin is ", divMargin);
divMargin = parseInt(divMargin);
if((divMargin + innerdocbodyMargin) > 0){
if ((divMargin + innerdocbodyMargin) > 0) {
// console.log("divMargin", divMargin);
left = left + divMargin;
left += divMargin;
}
}
left = left+18;
left += 18;
// Remove the element
$('iframe[name="ace_outer"]').contents().find('#outerdocbody').contents().remove("#" + authorWorker);
$('iframe[name="ace_outer"]').contents().find('#outerdocbody').contents().remove(`#${authorWorker}`);
// Author color
var users = pad.collabClient.getConnectedUsers();
$.each(users, function(user, value){
if(value.userId == authorId){
var colors = pad.getColorPalette(); // support non set colors
if(colors[value.colorId]){
const users = pad.collabClient.getConnectedUsers();
$.each(users, (user, value) => {
if (value.userId == authorId) {
const colors = pad.getColorPalette(); // support non set colors
if (colors[value.colorId]) {
var color = colors[value.colorId];
}else{
} else {
var color = value.colorId; // Test for XSS
}
var outBody = $('iframe[name="ace_outer"]').contents().find("#outerdocbody");
var span = $(div).contents().find("span:first");
const outBody = $('iframe[name="ace_outer"]').contents().find('#outerdocbody');
const span = $(div).contents().find('span:first');
// Remove all divs that already exist for this author
$('iframe[name="ace_outer"]').contents().find(".caret-"+authorClass).remove();
$('iframe[name="ace_outer"]').contents().find(`.caret-${authorClass}`).remove();
// Location of stick direction IE up or down
if(stickUp){var location = 'stickUp';}else{var location = 'stickDown';}
if (stickUp) { var location = 'stickUp'; } else { var location = 'stickDown'; }
// Create a new Div for this author
var $indicator = $("<div class='caretindicator "+ location+ " caret-"+authorClass+"' style='height:16px;left:"+left+"px;top:"+top +"px;background-color:"+color+"'><p class='stickp "+location+"'></p></div>");
$indicator.attr("title", authorName);
$indicator.find("p").text(authorName);
const $indicator = $(`<div class='caretindicator ${location} caret-${authorClass}' style='height:16px;left:${left}px;top:${top}px;background-color:${color}'><p class='stickp ${location}'></p></div>`);
$indicator.attr('title', authorName);
$indicator.find('p').text(authorName);
$(outBody).append($indicator);
// After a while, fade it out :)
setTimeout(function(){
$indicator.fadeOut(500, function(){
setTimeout(() => {
$indicator.fadeOut(500, () => {
$indicator.remove();

@@ -239,20 +234,20 @@ });

return cb();
}
};
function html_substr( str, count ) {
if( browser.msie ) return ""; // IE can't handle processing any of the X position stuff so just return a blank string
function html_substr(str, count) {
if (browser.msie) return ''; // IE can't handle processing any of the X position stuff so just return a blank string
// Basically the recursion makes IE run out of memory and slows a pad right down, I guess a way to fix this would be to
// only wrap the target / last span or something or stop it destroying and recreating on each change..
// Also IE can often inherit the wrong font face IE bold but not apply that to the whole document ergo getting teh width wrong
var div = document.createElement('div');
const div = document.createElement('div');
div.innerHTML = str;
walk( div, track );
walk(div, track);
function track( el ) {
if( count > 0 ) {
var len = el.data.length;
function track(el) {
if (count > 0) {
const len = el.data.length;
count -= len;
if( count <= 0 ) {
el.data = el.substringData( 0, el.data.length + count );
if (count <= 0) {
el.data = el.substringData(0, el.data.length + count);
}

@@ -264,13 +259,13 @@ } else {

function walk( el, fn ) {
var node = el.firstChild;
if(!node) return;
function walk(el, fn) {
let node = el.firstChild;
if (!node) return;
do {
if( node.nodeType === 3 ) {
if (node.nodeType === 3) {
fn(node);
// Added this >>------------------------------------<<
} else if( node.nodeType === 1 && node.childNodes && node.childNodes[0] ) {
walk( node, fn );
} else if (node.nodeType === 1 && node.childNodes && node.childNodes[0]) {
walk(node, fn);
}
} while( node = node.nextSibling );
} while (node = node.nextSibling);
}

@@ -281,22 +276,19 @@ return div.innerHTML;

function wrap(target) {
var newtarget = $("<div></div>");
const newtarget = $('<div></div>');
nodes = target.contents().clone(); // the clone is critical!
nodes.each(function() {
nodes.each(function () {
if (this.nodeType == 3) { // text
var newhtml = "";
var text = this.wholeText; // maybe "textContent" is better?
for (var i=0; i < text.length; i++) {
if (text[i] == ' '){
newhtml += "<span data-key="+globalKey+"> </span>";
let newhtml = '';
const text = this.wholeText; // maybe "textContent" is better?
for (let i = 0; i < text.length; i++) {
if (text[i] == ' ') {
newhtml += `<span data-key=${globalKey}> </span>`;
} else {
newhtml += `<span data-key=${globalKey}>${text[i]}</span>`;
}
else
{
newhtml += "<span data-key="+globalKey+">" + text[i] + "</span>";
}
globalKey++;
}
newtarget.append($(newhtml));
}
else { // recursion FTW!
} else { // recursion FTW!
// console.log("recursion"); // IE handles recursion badly

@@ -303,0 +295,0 @@ $(this).html(wrap($(this))); // This really hurts doing any sort of count..

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc