Index: lams_build/conf/etherpad/etherpad-lite/src/static/js/pad_editbar.js =================================================================== diff -u -r180f20eacc0e7da03c85a76e290df8705ddf8f00 -r9e1cd898ae0596ebf686906d5451c4d4bbbc77f2 --- lams_build/conf/etherpad/etherpad-lite/src/static/js/pad_editbar.js (.../pad_editbar.js) (revision 180f20eacc0e7da03c85a76e290df8705ddf8f00) +++ lams_build/conf/etherpad/etherpad-lite/src/static/js/pad_editbar.js (.../pad_editbar.js) (revision 9e1cd898ae0596ebf686906d5451c4d4bbbc77f2) @@ -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,155 +22,140 @@ * limitations under the License. */ -var browser = require('./browser'); -var hooks = require('./pluginfw/hooks'); -var padutils = require('./pad_utils').padutils; -var padeditor = require('./pad_editor').padeditor; -var padsavedrevs = require('./pad_savedrevs'); -var _ = require('ep_etherpad-lite/static/js/underscore'); -require('ep_etherpad-lite/static/js/vendors/nice-select'); +const browser = require('./vendors/browser'); +const hooks = require('./pluginfw/hooks'); +const padutils = require('./pad_utils').padutils; +const padeditor = require('./pad_editor').padeditor; +const padsavedrevs = require('./pad_savedrevs'); +const _ = require('underscore'); +require('./vendors/nice-select'); -var ToolbarItem = function (element) { +const ToolbarItem = function (element) { this.$el = element; }; ToolbarItem.prototype.getCommand = function () { - return this.$el.attr("data-key"); + return this.$el.attr('data-key'); }; ToolbarItem.prototype.getValue = function () { if (this.isSelect()) { - return this.$el.find("select").val(); + return this.$el.find('select').val(); } }; ToolbarItem.prototype.setValue = function (val) { if (this.isSelect()) { - return this.$el.find("select").val(val); + return this.$el.find('select').val(val); } }; ToolbarItem.prototype.getType = function () { - return this.$el.attr("data-type"); + return this.$el.attr('data-type'); }; ToolbarItem.prototype.isSelect = function () { - return this.getType() == "select"; + return this.getType() === 'select'; }; ToolbarItem.prototype.isButton = function () { - return this.getType() == "button"; + return this.getType() === 'button'; }; ToolbarItem.prototype.bind = function (callback) { - var self = this; + const self = this; if (self.isButton()) { - self.$el.click(function (event) { + self.$el.click((event) => { $(':focus').blur(); callback(self.getCommand(), self); event.preventDefault(); }); - } - else if (self.isSelect()) { - self.$el.find("select").change(function () { + } else if (self.isSelect()) { + self.$el.find('select').change(() => { callback(self.getCommand(), self); }); } }; -var padeditbar = (function() -{ - - var syncAnimation = (function() - { - var SYNCING = -100; - var DONE = 100; - var state = DONE; - var fps = 25; - var step = 1 / fps; - var T_START = -0.5; - var T_FADE = 1.0; - var T_GONE = 1.5; - var animator = padutils.makeAnimationScheduler(function() - { - if (state == SYNCING || state == DONE) - { +const padeditbar = (function () { + const syncAnimationFn = () => { + const SYNCING = -100; + const DONE = 100; + let state = DONE; + const fps = 25; + const step = 1 / fps; + const T_START = -0.5; + const T_FADE = 1.0; + const T_GONE = 1.5; + const animator = padutils.makeAnimationScheduler(() => { + if (state === SYNCING || state === DONE) { return false; - } - else if (state >= T_GONE) - { + } else if (state >= T_GONE) { state = DONE; - $("#syncstatussyncing").css('display', 'none'); - $("#syncstatusdone").css('display', 'none'); + $('#syncstatussyncing').css('display', 'none'); + $('#syncstatusdone').css('display', 'none'); return false; - } - else if (state < 0) - { + } else if (state < 0) { state += step; - if (state >= 0) - { - $("#syncstatussyncing").css('display', 'none'); - $("#syncstatusdone").css('display', 'block').css('opacity', 1); + if (state >= 0) { + $('#syncstatussyncing').css('display', 'none'); + $('#syncstatusdone').css('display', 'block').css('opacity', 1); } return true; - } - else - { + } else { state += step; - if (state >= T_FADE) - { - $("#syncstatusdone").css('opacity', (T_GONE - state) / (T_GONE - T_FADE)); + if (state >= T_FADE) { + $('#syncstatusdone').css('opacity', (T_GONE - state) / (T_GONE - T_FADE)); } return true; } }, step * 1000); return { - syncing: function() - { + syncing: () => { state = SYNCING; - $("#syncstatussyncing").css('display', 'block'); - $("#syncstatusdone").css('display', 'none'); + $('#syncstatussyncing').css('display', 'block'); + $('#syncstatusdone').css('display', 'none'); }, - done: function() - { + done: () => { state = T_START; animator.scheduleAnimation(); - } + }, }; - }()); + }; + const syncAnimation = syncAnimationFn(); - var self = { - init: function() { - var self = this; + const self = { + init() { + const self = this; self.dropdowns = []; - $("#editbar .editbarbutton").attr("unselectable", "on"); // for IE - $("#editbar").removeClass("disabledtoolbar").addClass("enabledtoolbar"); - $("#editbar [data-key]").each(function () { - $(this).unbind("click"); - (new ToolbarItem($(this))).bind(function (command, item) { + $('#editbar .editbarbutton').attr('unselectable', 'on'); // for IE + this.enable(); + $('#editbar [data-key]').each(function () { + $(this).unbind('click'); + (new ToolbarItem($(this))).bind((command, item) => { self.triggerCommand(command, item); }); }); - $('body:not(#editorcontainerbox)').on("keydown", function(evt){ + $('body:not(#editorcontainerbox)').on('keydown', (evt) => { bodyKeyEvent(evt); }); - $('.show-more-icon-btn').click(function() { + $('.show-more-icon-btn').click(() => { $('.toolbar').toggleClass('full-icons'); }); self.checkAllIconsAreDisplayedInToolbar(); - $(window).resize(_.debounce( self.checkAllIconsAreDisplayedInToolbar, 100 ) ); + $(window).resize(_.debounce(self.checkAllIconsAreDisplayedInToolbar, 100)); registerDefaultCommands(self); - hooks.callAll("postToolbarInit", { + hooks.callAll('postToolbarInit', { toolbar: self, - ace: padeditor.ace + ace: padeditor.ace, }); /* @@ -178,322 +165,299 @@ * overflow:hidden on parent */ if (!browser.safari) { - $('select').niceSelect(); + $('select').niceSelect(); } // When editor is scrolled, we add a class to style the editbar differently - $('iframe[name="ace_outer"]').contents().scroll(function() { + $('iframe[name="ace_outer"]').contents().scroll(function () { $('#editbar').toggleClass('editor-scrolled', $(this).scrollTop() > 2); - }) + }); }, - isEnabled: function() - { - return true; + isEnabled: () => true, + disable: () => { + $('#editbar').addClass('disabledtoolbar').removeClass('enabledtoolbar'); }, - disable: function() - { - $("#editbar").addClass('disabledtoolbar').removeClass("enabledtoolbar"); + enable: () => { + $('#editbar').addClass('enabledtoolbar').removeClass('disabledtoolbar'); }, commands: {}, - registerCommand: function (cmd, callback) { + registerCommand(cmd, callback) { this.commands[cmd] = callback; return this; }, - registerDropdownCommand: function (cmd, dropdown) { + registerDropdownCommand(cmd, dropdown) { dropdown = dropdown || cmd; - self.dropdowns.push(dropdown) - this.registerCommand(cmd, function () { + self.dropdowns.push(dropdown); + this.registerCommand(cmd, () => { self.toggleDropDown(dropdown); }); }, - registerAceCommand: function (cmd, callback) { - this.registerCommand(cmd, function (cmd, ace, item) { - ace.callWithAce(function (ace) { + registerAceCommand(cmd, callback) { + this.registerCommand(cmd, (cmd, ace, item) => { + ace.callWithAce((ace) => { callback(cmd, ace, item); }, cmd, true); }); }, - triggerCommand: function (cmd, item) { + triggerCommand(cmd, item) { if (self.isEnabled() && this.commands[cmd]) { this.commands[cmd](cmd, padeditor.ace, item); } - if(padeditor.ace) padeditor.ace.focus(); + if (padeditor.ace) padeditor.ace.focus(); }, - toggleDropDown: function(moduleName, cb) - { + toggleDropDown: (moduleName, cb) => { // do nothing if users are sticked - if (moduleName === "users" && $('#users').hasClass('stickyUsers')) { + if (moduleName === 'users' && $('#users').hasClass('stickyUsers')) { return; } $('.nice-select').removeClass('open'); - $('.toolbar-popup').removeClass("popup-show"); + $('.toolbar-popup').removeClass('popup-show'); // hide all modules and remove highlighting of all buttons - if(moduleName == "none") - { - var returned = false; - for(var i=0;i 0; - if(isAForceReconnectMessage) - continue; + // skip any "force reconnect" message + const isAForceReconnectMessage = module.find('button#forcereconnect:visible').length > 0; + if (isAForceReconnectMessage) continue; if (module.hasClass('popup-show')) { - $("li[data-key=" + thisModuleName + "] > a").removeClass("selected"); - module.removeClass("popup-show"); + $(`li[data-key=${thisModuleName}] > a`).removeClass('selected'); + module.removeClass('popup-show'); } } - if(!returned && cb) return cb(); - } - else - { + if (!returned && cb) return cb(); + } else { // hide all modules that are not selected and remove highlighting // respectively add highlighting to the corresponding button - for(var i=0;i a").removeClass("selected"); - module.removeClass("popup-show"); - } - else if(thisModuleName==moduleName) - { - $("li[data-key=" + thisModuleName + "] > a").addClass("selected"); - module.addClass("popup-show"); + if (module.hasClass('popup-show')) { + $(`li[data-key=${thisModuleName}] > a`).removeClass('selected'); + module.removeClass('popup-show'); + } else if (thisModuleName === moduleName) { + $(`li[data-key=${thisModuleName}] > a`).addClass('selected'); + module.addClass('popup-show'); if (cb) { cb(); } } } } }, - setSyncStatus: function(status) - { - if (status == "syncing") - { + setSyncStatus: (status) => { + if (status === 'syncing') { syncAnimation.syncing(); - } - else if (status == "done") - { + } else if (status === 'done') { syncAnimation.done(); } }, - setEmbedLinks: function() - { - var padUrl = window.location.href.split("?")[0]; + setEmbedLinks: () => { + const padUrl = window.location.href.split('?')[0]; + const params = '?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false'; + const props = 'width="100%" height="600" frameborder="0"'; - if ($('#readonlyinput').is(':checked')) - { - var urlParts = padUrl.split("/"); + if ($('#readonlyinput').is(':checked')) { + const urlParts = padUrl.split('/'); urlParts.pop(); - var readonlyLink = urlParts.join("/") + "/" + clientVars.readOnlyId; - $('#embedinput').val(''); + const readonlyLink = `${urlParts.join('/')}/${clientVars.readOnlyId}`; + $('#embedinput') + .val(``); $('#linkinput').val(readonlyLink); - } - else - { - $('#embedinput').val(''); + } else { + $('#embedinput') + .val(``); $('#linkinput').val(padUrl); } }, - checkAllIconsAreDisplayedInToolbar: function() - { + checkAllIconsAreDisplayedInToolbar: () => { // reset style - $('.toolbar').removeClass('cropped') - var menu_left = $('.toolbar .menu_left')[0]; + $('.toolbar').removeClass('cropped'); + $('body').removeClass('mobile-layout'); + const menu_left = $('.toolbar .menu_left')[0]; - // on mobile the menu_right get displayed at the bottom of the screen - var isMobileLayout = $('.toolbar .menu_right').css('position') === 'fixed'; - - if (menu_left && menu_left.scrollWidth > $('.toolbar').width() && isMobileLayout) { + // this is approximate, we cannot measure it because on mobile + // Layout it takes the full width on the bottom of the page + const menuRightWidth = 280; + if (menu_left && menu_left.scrollWidth > $('.toolbar').width() - menuRightWidth || + $('.toolbar').width() < 1000) { + $('body').addClass('mobile-layout'); + } + if (menu_left && menu_left.scrollWidth > $('.toolbar').width()) { $('.toolbar').addClass('cropped'); } - } + }, }; - var editbarPosition = 0; + let editbarPosition = 0; - function bodyKeyEvent(evt){ - + const bodyKeyEvent = (evt) => { // If the event is Alt F9 or Escape & we're already in the editbar menu // Send the users focus back to the pad - if((evt.keyCode === 120 && evt.altKey) || evt.keyCode === 27){ - if($(':focus').parents(".toolbar").length === 1){ + if ((evt.keyCode === 120 && evt.altKey) || evt.keyCode === 27) { + if ($(':focus').parents('.toolbar').length === 1) { // If we're in the editbar already.. // Close any dropdowns we have open.. - padeditbar.toggleDropDown("none"); + padeditbar.toggleDropDown('none'); // Check we're on a pad and not on the timeslider // Or some other window I haven't thought about! - if(typeof pad === 'undefined'){ + if (typeof pad === 'undefined') { // Timeslider probably.. // Shift focus away from any drop downs $(':focus').blur(); // required to do not try to remove! $('#editorcontainerbox').focus(); // Focus back onto the pad - }else{ + } else { // Shift focus away from any drop downs $(':focus').blur(); // required to do not try to remove! padeditor.ace.focus(); // Sends focus back to pad // The above focus doesn't always work in FF, you have to hit enter afterwards evt.preventDefault(); } - }else{ + } else { // Focus on the editbar :) - var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first(); + const firstEditbarElement = parent.parent.$('#editbar button').first(); + $(this).blur(); firstEditbarElement.focus(); evt.preventDefault(); } } // Are we in the toolbar?? - if($(':focus').parents(".toolbar").length === 1){ + if ($(':focus').parents('.toolbar').length === 1) { // On arrow keys go to next/previous button item in editbar - if(evt.keyCode !== 39 && evt.keyCode !== 37) return; + if (evt.keyCode !== 39 && evt.keyCode !== 37) return; // Get all the focusable items in the editbar - var focusItems = $('#editbar').find('button, select'); + const focusItems = $('#editbar').find('button, select'); // On left arrow move to next button in editbar - if(evt.keyCode === 37){ + if (evt.keyCode === 37) { // If a dropdown is visible or we're in an input don't move to the next button - if($('.popup').is(":visible") || evt.target.localName === "input") return; + if ($('.popup').is(':visible') || evt.target.localName === 'input') return; editbarPosition--; // Allow focus to shift back to end of row and start of row - if(editbarPosition === -1) editbarPosition = focusItems.length -1; - $(focusItems[editbarPosition]).focus() + if (editbarPosition === -1) editbarPosition = focusItems.length - 1; + $(focusItems[editbarPosition]).focus(); } // On right arrow move to next button in editbar - if(evt.keyCode === 39){ + if (evt.keyCode === 39) { // If a dropdown is visible or we're in an input don't move to the next button - if($('.popup').is(":visible") || evt.target.localName === "input") return; + if ($('.popup').is(':visible') || evt.target.localName === 'input') return; editbarPosition++; // Allow focus to shift back to end of row and start of row - if(editbarPosition >= focusItems.length) editbarPosition = 0; + if (editbarPosition >= focusItems.length) editbarPosition = 0; $(focusItems[editbarPosition]).focus(); } } + }; - } - - function aceAttributeCommand(cmd, ace) { + const aceAttributeCommand = (cmd, ace) => { ace.ace_toggleAttributeOnSelection(cmd); - } + }; - function registerDefaultCommands(toolbar) { - toolbar.registerDropdownCommand("showusers", "users"); - toolbar.registerDropdownCommand("settings"); - toolbar.registerDropdownCommand("connectivity"); - toolbar.registerDropdownCommand("import_export"); - toolbar.registerDropdownCommand("embed"); + const registerDefaultCommands = (toolbar) => { + toolbar.registerDropdownCommand('showusers', 'users'); + toolbar.registerDropdownCommand('settings'); + toolbar.registerDropdownCommand('connectivity'); + toolbar.registerDropdownCommand('import_export'); + toolbar.registerDropdownCommand('embed'); - toolbar.registerCommand("settings", function () { - toolbar.toggleDropDown("settings", function(){ + toolbar.registerCommand('settings', () => { + toolbar.toggleDropDown('settings', () => { $('#options-stickychat').focus(); }); }); - toolbar.registerCommand("import_export", function () { - toolbar.toggleDropDown("import_export", function(){ - - if (clientVars.thisUserHasEditedThisPad || clientVars.allowAnyoneToImport) { - // the user has edited this pad historically or in this session - $('#importform').show(); - $('#importmessagepermission').hide(); - } else { - // this is the first time this user visits this pad - $('#importform').hide(); - $('#importmessagepermission').show(); - } - + toolbar.registerCommand('import_export', () => { + toolbar.toggleDropDown('import_export', () => { // If Import file input exists then focus on it.. - if($('#importfileinput').length !== 0){ - setTimeout(function(){ + if ($('#importfileinput').length !== 0) { + setTimeout(() => { $('#importfileinput').focus(); }, 100); - }else{ + } else { $('.exportlink').first().focus(); } }); }); - toolbar.registerCommand("showusers", function () { - toolbar.toggleDropDown("users", function(){ + toolbar.registerCommand('showusers', () => { + toolbar.toggleDropDown('users', () => { $('#myusernameedit').focus(); }); }); - toolbar.registerCommand("embed", function () { + toolbar.registerCommand('embed', () => { toolbar.setEmbedLinks(); - toolbar.toggleDropDown("embed", function(){ + toolbar.toggleDropDown('embed', () => { $('#linkinput').focus().select(); }); }); - toolbar.registerCommand("savedRevision", function () { + toolbar.registerCommand('savedRevision', () => { padsavedrevs.saveNow(); }); - toolbar.registerCommand("showTimeSlider", function () { - // LAMS fix for returning to pad with same settings + toolbar.registerCommand('showTimeSlider', () => { + // LAMS fix for returning to pad with same settings localStorage.setItem("etherpadTimesliderReturnUrl", document.location.href); - document.location = document.location.pathname+ '/timeslider'; + document.location = `${document.location.pathname}/timeslider`; }); - toolbar.registerAceCommand("bold", aceAttributeCommand); - toolbar.registerAceCommand("italic", aceAttributeCommand); - toolbar.registerAceCommand("underline", aceAttributeCommand); - toolbar.registerAceCommand("strikethrough", aceAttributeCommand); + toolbar.registerAceCommand('bold', aceAttributeCommand); + toolbar.registerAceCommand('italic', aceAttributeCommand); + toolbar.registerAceCommand('underline', aceAttributeCommand); + toolbar.registerAceCommand('strikethrough', aceAttributeCommand); - toolbar.registerAceCommand("undo", function (cmd, ace) { + toolbar.registerAceCommand('undo', (cmd, ace) => { ace.ace_doUndoRedo(cmd); }); - toolbar.registerAceCommand("redo", function (cmd, ace) { + toolbar.registerAceCommand('redo', (cmd, ace) => { ace.ace_doUndoRedo(cmd); }); - toolbar.registerAceCommand("insertunorderedlist", function (cmd, ace) { + toolbar.registerAceCommand('insertunorderedlist', (cmd, ace) => { ace.ace_doInsertUnorderedList(); }); - toolbar.registerAceCommand("insertorderedlist", function (cmd, ace) { + toolbar.registerAceCommand('insertorderedlist', (cmd, ace) => { ace.ace_doInsertOrderedList(); }); - toolbar.registerAceCommand("indent", function (cmd, ace) { + toolbar.registerAceCommand('indent', (cmd, ace) => { if (!ace.ace_doIndentOutdent(false)) { ace.ace_doInsertUnorderedList(); } }); - toolbar.registerAceCommand("outdent", function (cmd, ace) { + toolbar.registerAceCommand('outdent', (cmd, ace) => { ace.ace_doIndentOutdent(true); }); - toolbar.registerAceCommand("clearauthorship", function (cmd, ace) { + toolbar.registerAceCommand('clearauthorship', (cmd, ace) => { // If we have the whole document selected IE control A has been hit - var rep = ace.ace_getRep(); - var lastChar = rep.lines.atIndex(rep.lines.length()-1).width-1; - var lastLineIndex = rep.lines.length()-1; - if(rep.selStart[0] === 0 && rep.selStart[1] === 0){ + const rep = ace.ace_getRep(); + let doPrompt = false; + const lastChar = rep.lines.atIndex(rep.lines.length() - 1).width - 1; + const lastLineIndex = rep.lines.length() - 1; + if (rep.selStart[0] === 0 && rep.selStart[1] === 0) { // nesting intentionally here to make things readable - if(rep.selEnd[0] === lastLineIndex && rep.selEnd[1] === lastChar){ - var doPrompt = true; + if (rep.selEnd[0] === lastLineIndex && rep.selEnd[1] === lastChar) { + doPrompt = true; } } /* @@ -507,29 +471,31 @@ // if we don't have any text selected, we have a caret or we have already said to prompt if ((!(rep.selStart && rep.selEnd)) || ace.ace_isCaret() || doPrompt) { - if (window.confirm(html10n.get("pad.editbar.clearcolors"))) { + if (window.confirm(html10n.get('pad.editbar.clearcolors'))) { ace.ace_performDocumentApplyAttributesToCharRange(0, ace.ace_getRep().alltext.length, [ - ['author', ''] + ['author', ''], ]); } - } - else { + } else { ace.ace_setAttributeOnSelection('author', ''); } }); - toolbar.registerCommand('timeslider_returnToPad', function(cmd) { - // LAMS fix for returning to pad with same settings + toolbar.registerCommand('timeslider_returnToPad', (cmd) => { + // LAMS fix for returning to pad with same settings let returnUrl = localStorage.getItem("etherpadTimesliderReturnUrl"); if (returnUrl) { document.location.href = returnUrl; - } else if( document.referrer.length > 0 && document.referrer.substring(document.referrer.lastIndexOf("/")-1, document.referrer.lastIndexOf("/")) === "p") { + } else if (document.referrer.length > 0 && + document.referrer.substring(document.referrer.lastIndexOf('/') - 1, + document.referrer.lastIndexOf('/')) === 'p') { document.location = document.referrer; } else { - document.location = document.location.href.substring(0,document.location.href.lastIndexOf("/")); + document.location = document.location.href + .substring(0, document.location.href.lastIndexOf('/')); } }); - } + }; return self; }());