Index: lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/static/css/stats.css =================================================================== diff -u -r3cd4201e8c6d28d1539c24fe5d2efba5f680251e -r9090c3eb16ff0576f977660b27735d185f2d48d5 --- lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/static/css/stats.css (.../stats.css) (revision 3cd4201e8c6d28d1539c24fe5d2efba5f680251e) +++ lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/static/css/stats.css (.../stats.css) (revision 9090c3eb16ff0576f977660b27735d185f2d48d5) @@ -1,46 +1,36 @@ -#stats { - display: none; - z-index: 99999; - position: fixed; - bottom: 0; - right: 30px; - width: 300px; - background-color: #fff; - color: #000; - padding: 20px; - overflow: auto; +#stats{ + display:none; + z-index: 20; + position:fixed; + bottom:0; + right: 30px; + width:300px; + height: 500px; + background-color: var(--bg-color); + color:#000; + padding:20px; + overflow:auto; } - -#stats .stats { - font-size: 14px; - display: inline; +.stats{ + font-size:14px; + display:inline; } -#stats h1 { +#stats h3 { font-size: 16px; } -#stats h2 { - font-size: 14px; +#stats > div > div{ + line-height:20px; + padding:5px; } - -#stats>div>div { - line-height: 20px; - padding: 5px; +#stats > div > div > h4{ + font-size: 14px; + display:inline; } +#stats > div > div:nth-child(even) {background: var(--bg-soft-color)} +#stats > div > div:nth-child(odd) {background: var(--bg-color)} -#stats>div>div>h2 { - display: inline; +.statsAuthorColor{ + width:4px; } - -#stats>div>div:nth-child(even) { - background: #CCC -} - -#stats>div>div:nth-child(odd) { - background: #FFF -} - -.statsAuthorColor { - width: 4px; -} \ No newline at end of file Index: lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/static/js/stats.js =================================================================== diff -u -r62e82c7396362b49c0a47738201018b36792299f -r9090c3eb16ff0576f977660b27735d185f2d48d5 --- lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/static/js/stats.js (.../stats.js) (revision 62e82c7396362b49c0a47738201018b36792299f) +++ lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/static/js/stats.js (.../stats.js) (revision 9090c3eb16ff0576f977660b27735d185f2d48d5) @@ -1,71 +1,84 @@ -if(typeof exports == 'undefined'){ - var exports = this['mymodule'] = {}; -} +'use strict'; -exports.stats = { - init: function(){ +const stats = { + init: () => { stats.update(); }, - show: function(){ + show: () => { $('#stats').show(); - $('#stats').css("top", $('#settings').offset().top + $('#settings').height() + 10 + 'px'); -// $('#options-stickychat').attr("checked","checked"); - exports.stats.update(); + // LAMS modified this line so stats are lower than settings + $('#stats').css('top', `${$('#editorcontainer').offset().top + $('#settings').height() + 15}px`); + // $('#options-stickychat').attr("checked","checked"); + stats.update(); }, - hide: function(){ + hide: () => { $('#stats').hide(); }, - update: function(){ - var html = $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").html(); - var text = $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").text(); - $('#length > .stats').html( text.replace(/\s/g,"").length ); - $('#lengthWhitespace > .stats').html( text.length ); - $('#wordCount > .stats').html( exports.wordCount()); - $('#revCount > .stats').html( pad.getCollabRevisionNumber() ); - $('#savedRevCount > .stats').html( clientVars.savedRevisions.length ); // TODO cake doesnt update in real time - $('#authorCount > .stats').html( Object.keys(clientVars.collab_client_vars.historicalAuthorData).length ); - $('#wordsContributed > .stats').html( tb(exports.stats.authors.numberOfWords()) ); - $('#linesContributed > .stats').html( tb(exports.stats.authors.numberOfLines()) ); - $('#linesAsOnlyContributor > .stats').html( tb(exports.stats.authors.numberOfLinesExclusive()) ); - $('#numberOfCharsIncWS > .stats').html( tb(exports.stats.authors.numberOfChars()) ); - $('#numberOfCharsExcWS > .stats').html( tb(exports.stats.authors.numberOfCharsExcWS()) ); - } -} + update: () => { + const text = $('iframe[name="ace_outer"]').contents().find('iframe') + .contents().find('#innerdocbody').text(); + $('#length > .stats').html(text.replace(/\s/g, '').length); + $('#lengthWhitespace > .stats').html(text.length); + $('#wordCount > .stats').html(wordCount()); + $('#revCount > .stats').html(pad.getCollabRevisionNumber()); + // TODO cake doesnt update in real time + $('#savedRevCount > .stats').html(clientVars.savedRevisions.length); + $('#authorCount > .stats').html( + Object.keys(clientVars.collab_client_vars.historicalAuthorData).length); + $('#wordsContributed > .stats').html(tb(stats.authors.numberOfWords())); + $('#linesContributed > .stats').html(tb(stats.authors.numberOfLines())); + $('#linesAsOnlyContributor > .stats').html(tb(stats.authors.numberOfLinesExclusive())); + $('#numberOfCharsIncWS > .stats').html(tb(stats.authors.numberOfChars())); + $('#numberOfCharsExcWS > .stats').html(tb(stats.authors.numberOfCharsExcWS())); + }, +}; -exports.wordCount = function(){ - var totalCount = 0; - $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").contents().each(function(){ - var lineCount = 0; - $(this).contents().each(function(){ - var numberOf = $(this).text().split(" "); - numberOf = arrayDelete(numberOf, ""); // dont include spaces or line breaks or other nastyness - lineCount += numberOf.length; +const wordCount = () => { + const arrayDelete = (arr, deleteValue) => { + for (let i = 0; i < arr.length; i++) { + if (arr[i] === deleteValue) { + arr.splice(i, 1); + } + } + return arr; + }; + + let totalCount = 0; + const $padInner = $('iframe[name="ace_outer"]').contents().find('iframe').contents(); + $padInner.find('#innerdocbody').contents().each(function () { + let lineCount = 0; + $(this).contents().each(function () { + let numberOf = $(this).text().split(' '); + // dont include spaces or line breaks or other nastyness + numberOf = arrayDelete(numberOf, ''); + if (numberOf.length) lineCount += numberOf.length; }); totalCount += lineCount; }); return totalCount; -} +}; -exports.stats.authors = { - numberOfWords: function(){ - var results = {}; +stats.authors = { + numberOfWords: () => { + const results = {}; // go through each word, does it have the class of this author? // output format. John -- 6, Dave -- 9 - $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").contents().each(function(){ - $(this).contents().each(function(){ - var line = this; - var classes = $(this).attr("class"); - if(classes){ - classes = classes.split(" "); - $.each(classes, function(k, spanClass){ - if( spanClass.indexOf("author") !== -1){ // if an author class exists on this span + const $padInner = $('iframe[name="ace_outer"]').contents().find('iframe').contents(); + $padInner.find('#innerdocbody').contents().each(function () { + $(this).contents().each(function () { + const line = this; + let classes = $(this).attr('class'); + if (classes) { + classes = classes.split(' '); + $.each(classes, (k, spanClass) => { + if (spanClass.indexOf('author') !== -1) { // if an author class exists on this span // how many words are in this string? - var number = $(line).text().split(" ").length; - if( !results[ spanClass ] ){ - results[ spanClass ] = number; - }else{ - results[ spanClass ] = results[ spanClass ] + number; + const number = $(line).text().split(' ').length; + if (!results[spanClass]) { + results[spanClass] = number; + } else { + results[spanClass] += number; } } }); @@ -74,230 +87,215 @@ }); return results; }, - numberOfLines: function(){ - var results = {}; + numberOfLines: () => { + const results = {}; // output format. John -- 2, Dave -- 3 - $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").contents().each(function(){ // each line - $(this).contents().each(function(){ - var line = this; - var classes = $(this).attr("class"); - if(classes){ - classes = classes.split(" "); - $.each(classes, function(k, spanClass){ - if( spanClass.indexOf("author") !== -1){ // if an author class exists on this span + const $padInner = $('iframe[name="ace_outer"]').contents().find('iframe').contents(); + $padInner.find('#innerdocbody').contents().each(function () { + // each line + $(this).contents().each(function () { + // const line = this; // TODO: Why was this not used? + let classes = $(this).attr('class'); + if (classes) { + classes = classes.split(' '); + $.each(classes, (k, spanClass) => { + // if an author class exists on this span + if (spanClass.indexOf('author') !== -1) { // how many words are in this string? - var number = $(line).text().split(" ").length; - if( !results[ spanClass ] ){ - results[ spanClass ] = 1; - }else{ - results[ spanClass ] = results[ spanClass ] + 1; + // const number = $(line).text().split(' ').length; + // TODO: Why was this not used? + if (!results[spanClass]) { + results[spanClass] = 1; + } else { + results[spanClass] += 1; } } }); } }); - }); return results; - }, - numberOfLinesExclusive: function(){ - var results = {}; - var lineCount = 1; + numberOfLinesExclusive: () => { + const results = {}; + let lineCount = 1; // output format. John -- 1, Dave -- 1 - $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").contents().each(function(){ // For Each LINE - var line = {}; - $(this).contents().each(function(){ // For SPAN! - var classes = $(this).attr("class"); - if(classes){ - classes = classes.split(" "); - $.each(classes, function(k, spanClass){ - if( spanClass.indexOf("author") !== -1){ // if an author class exists on this span - if( !line[ lineCount ] ){ - line[ lineCount ] = {}; - line[ lineCount ].author = spanClass; // first author! - }else{ - delete line[ lineCount ];// already has an author so nuke! + const $padInner = $('iframe[name="ace_outer"]').contents().find('iframe').contents(); + $padInner.find('#innerdocbody').contents().each(function () { + const line = {}; + $(this).contents().each(function () { // For SPAN! + let classes = $(this).attr('class'); + if (classes) { + classes = classes.split(' '); + $.each(classes, (k, spanClass) => { + if (spanClass.indexOf('author') !== -1) { // if an author class exists on this span + if (!line[lineCount]) { + line[lineCount] = {}; + line[lineCount].author = spanClass; // first author! + } else { + delete line[lineCount];// already has an author so nuke! } } }); - - } // End Span }); - var lineHasOneAuthor = (line[lineCount]) - if(lineHasOneAuthor){ + const lineHasOneAuthor = (line[lineCount]); + if (lineHasOneAuthor) { // add author to results obj - var author = line[lineCount].author; - results[author] = (results[author] +1) || 1 + const author = line[lineCount].author; + results[author] = (results[author] + 1) || 1; } lineCount++; // End Line }); return results; }, - numberOfChars: function(){ - var results = {}; + numberOfChars: () => { + const results = {}; // output format. John -- 6, Dave -- 9 - $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").contents().each(function(){ - $(this).contents().each(function(){ - var classes = $(this).attr("class"); - if(classes){ - classes = classes.split(" "); - var number = $(this).text().length; - $.each(classes, function(k, spanClass){ - if( spanClass.indexOf("author") !== -1){ // if an author class exists on this span - results[ spanClass ] = number; - }else{ - results[ spanClass ] = results [ spanClass] + 1; + const $padInner = $('iframe[name="ace_outer"]').contents().find('iframe').contents(); + $padInner.find('#innerdocbody').contents().each(function () { + $(this).contents().each(function () { + let classes = $(this).attr('class'); + if (classes) { + classes = classes.split(' '); + const number = $(this).text().length; + $.each(classes, (k, spanClass) => { + if (spanClass.indexOf('author') !== -1) { // if an author class exists on this span + results[spanClass] = number; + } else { + results[spanClass] += 1; } }); - }; + } }); }); return results; }, - numberOfCharsExcWS: function(){ - var results = {}; + numberOfCharsExcWS: () => { + const results = {}; // output format. John -- 6, Dave -- 9 - $('iframe[name="ace_outer"]').contents().find('iframe').contents().find("#innerdocbody").contents().each(function(){ - $(this).contents().each(function(){ - var classes = $(this).attr("class"); - if(classes){ - - classes = classes.split(" "); - var number = $(this).text().replace(/\s/g,"").length; // get length without whitespace - $.each(classes, function(k, spanClass){ - if(spanClass.indexOf("author") !== -1){ // if an author class exists on this span - results[ spanClass ] = number; - }else{ - results[ spanClass ] = results[ spanClass] + number; + const $padInner = $('iframe[name="ace_outer"]').contents().find('iframe').contents(); + $padInner.find('#innerdocbody').contents().each(function () { + $(this).contents().each(function () { + let classes = $(this).attr('class'); + if (classes) { + classes = classes.split(' '); + const number = $(this).text().replace(/\s/g, '').length; // get length without whitespace + $.each(classes, (k, spanClass) => { + if (classes.indexOf('author') !== -1) { // if an author class exists on this span + results[spanClass] = number; + } else { + results[spanClass] += number; } }); } }); }); return results; - } -} + }, +}; -exports.postAceInit = function(hook, context){ - stats = exports.stats; - +exports.postAceInit = (hook, context) => { + // LAMS modified this line so stats are hidden by default + stats.hide(); /* on click */ - $('#options-stats').on('click', function() { - if($('#options-stats').is(':checked')) { + $('#options-stats').on('click', () => { + if ($('#options-stats').is(':checked')) { stats.show(); } else { stats.hide(); } }); -} +}; -exports.aceEditEvent = function(hook_name, event, cb){ - if($('#options-stats').is(':checked')) { // if stats are enabled - if(event.callstack.docTextChanged && event.callstack.domClean){ - exports.stats.update(); +exports.aceEditEvent = (hookName, event) => { + if ($('#options-stats').is(':checked')) { // if stats are enabled + if (event.callstack.docTextChanged && event.callstack.domClean) { + stats.update(); } } -} +}; -exports.className2Author = function(className) -{ - return className.substring(7).replace(/[a-y0-9]+|-|z.+?z/g, function(cc) - { - if (cc == '-') return '.'; - else if (cc.charAt(0) == 'z') - { - return String.fromCharCode(Number(cc.slice(1, -1))); - } - else - { - return cc; - } - }); -} +exports.className2Author = + (className) => className.substring(7).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 { + return cc; + } + }); -exports.getAuthorClassName = function(author) -{ - return "ep_cursortrace-" + author.replace(/[^a-y0-9]/g, function(c) - { - if (c == ".") return "-"; - return 'z' + c.charCodeAt(0) + 'z'; - }); -} +exports.getAuthorClassName = + (author) => `ep_cursortrace-${author.replace(/[^a-y0-9]/g, (c) => { + if (c === '.') return '-'; + return `z${c.charCodeAt(0)}z`; + })}`; -function tb(data){ // turns data object into a table - var table = ""; - for (var value in data){ - table += ""; - }; - table += "
"+authorNameFromClass(value)+":"+data[value]+"
"; +const tb = (data) => { // turns data object into a table + let table = ''; + for (const value of Object.keys(data)) { + table += + ` + + `; + } + table += '
+ ${authorNameFromClass(value)}:${data[value]}
'; return table; -} +}; -function authorNameFromClass(authorClass){ // turn authorClass into authorID then authorname.. +// turn authorClass into authorID then authorname.. +const authorNameFromClass = (authorClass) => { // get the authorID from the class.. - var authorId = exports.className2Author(authorClass); + const authorId = exports.className2Author(authorClass); // It could always be me.. - var myAuthorId = pad.myUserInfo.userId; - if(myAuthorId == authorId){ - return "Me"; + const myAuthorId = pad.myUserInfo.userId; + if (myAuthorId === authorId) { + return 'Me'; } // Not me, let's look up in the DOM - var name = null; - $('#otheruserstable > tbody > tr').each(function(){ - if (authorId == $(this).data("authorid")){ - $(this).find('.usertdname').each( function() { + let name = null; + $('#otheruserstable > tbody > tr').each(function () { + if (authorId === $(this).data('authorid')) { + $(this).find('.usertdname').each(function () { name = $(this).text(); }); } }); - if (name) - return name; + if (name) return name; // Else go historical - var historical = clientVars.collab_client_vars.historicalAuthorData[authorId]; - return (historical && historical.name) || "Unknown Author"; -} + const historical = clientVars.collab_client_vars.historicalAuthorData[authorId]; + return (historical && historical.name) || 'Unknown Author'; +}; -function authorColorFromClass(authorClass){ // turn authorClass into authorID then authorname.. +// turn authorClass into authorID then authorname.. +const authorColorFromClass = (authorClass) => { // get the authorID from the class.. - var authorId = exports.className2Author(authorClass); + const authorId = exports.className2Author(authorClass); // It could always be me.. - var myAuthorId = pad.myUserInfo.userId; - if(myAuthorId == authorId){ - return "#fff"; + const myAuthorId = pad.myUserInfo.userId; + if (myAuthorId === authorId) { + return '#fff'; } // Not me, let's look up in the DOM - var color = null; - $('#otheruserstable > tbody > tr').each(function(){ - if (authorId == $(this).data("authorid")){ - $(this).find('.usertdswatch > div').each( function() { - color = $(this).css("background-color"); + let color = null; + $('#otheruserstable > tbody > tr').each(function () { + if (authorId === $(this).data('authorid')) { + $(this).find('.usertdswatch > div').each(function () { + color = $(this).css('background-color'); }); } }); - if (color) - return color; + if (color) return color; // Else go historical - var historical = clientVars.collab_client_vars.historicalAuthorData[authorId]; - return (historical && historical.color) || "#fff"; -} - - -function arrayDelete(array, deleteValue) { - for (var i = 0; i < this.length; i++) { - if (this[i] == deleteValue) { - this.splice(i, 1); - i--; - } - } - return this; -} + const historical = clientVars.collab_client_vars.historicalAuthorData[authorId]; + return (historical && historical.color) || '#fff'; +}; Index: lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/templates/stats_entry.ejs =================================================================== diff -u --- lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/templates/stats_entry.ejs (revision 0) +++ lams_build/conf/etherpad/etherpad-lite/node_modules/ep_stats/templates/stats_entry.ejs (revision 9090c3eb16ff0576f977660b27735d185f2d48d5) @@ -0,0 +1,4 @@ +

+ + +