etherpad-lite/src/static/js/pad_editbar.js

476 lines
14 KiB
JavaScript
Raw Normal View History

/**
2013-03-09 23:57:42 +01:00
* 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.
* TL;DR COMMENTS ON THIS FILE ARE HIGHLY APPRECIATED
*/
2011-03-26 14:10:41 +01:00
/**
* Copyright 2009 Google Inc.
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* http://www.apache.org/licenses/LICENSE-2.0
2011-07-07 19:59:34 +02:00
*
2011-03-26 14:10:41 +01:00
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var hooks = require('./pluginfw/hooks');
2012-03-07 02:27:03 +01:00
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');
var ToolbarItem = function (element) {
this.$el = element;
};
ToolbarItem.prototype.getCommand = function () {
return this.$el.attr("data-key");
};
ToolbarItem.prototype.getValue = function () {
if (this.isSelect()) {
return this.$el.find("select").val();
}
};
ToolbarItem.prototype.setValue = function (val) {
if (this.isSelect()) {
return this.$el.find("select").val(val);
}
};
ToolbarItem.prototype.getType = function () {
return this.$el.attr("data-type");
};
ToolbarItem.prototype.isSelect = function () {
return this.getType() == "select";
};
ToolbarItem.prototype.isButton = function () {
return this.getType() == "button";
};
ToolbarItem.prototype.bind = function (callback) {
var self = this;
if (self.isButton()) {
self.$el.click(function (event) {
2015-03-25 16:49:41 +01:00
$(':focus').blur();
callback(self.getCommand(), self);
event.preventDefault();
});
}
else if (self.isSelect()) {
self.$el.find("select").change(function () {
callback(self.getCommand(), self);
});
}
};
2011-07-07 19:59:34 +02:00
var padeditbar = (function()
{
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
var syncAnimation = (function()
{
2011-03-26 14:10:41 +01:00
var SYNCING = -100;
var DONE = 100;
var state = DONE;
var fps = 25;
2011-07-07 19:59:34 +02:00
var step = 1 / fps;
2011-03-26 14:10:41 +01:00
var T_START = -0.5;
var T_FADE = 1.0;
var T_GONE = 1.5;
2011-07-07 19:59:34 +02:00
var animator = padutils.makeAnimationScheduler(function()
{
if (state == SYNCING || state == DONE)
{
2011-03-26 14:10:41 +01:00
return false;
}
2011-07-07 19:59:34 +02:00
else if (state >= T_GONE)
{
2011-03-26 14:10:41 +01:00
state = DONE;
$("#syncstatussyncing").css('display', 'none');
$("#syncstatusdone").css('display', 'none');
return false;
}
2011-07-07 19:59:34 +02:00
else if (state < 0)
{
2011-03-26 14:10:41 +01:00
state += step;
2011-07-07 19:59:34 +02:00
if (state >= 0)
{
2011-03-26 14:10:41 +01:00
$("#syncstatussyncing").css('display', 'none');
$("#syncstatusdone").css('display', 'block').css('opacity', 1);
}
return true;
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
state += step;
2011-07-07 19:59:34 +02:00
if (state >= T_FADE)
{
2011-03-26 14:10:41 +01:00
$("#syncstatusdone").css('opacity', (T_GONE - state) / (T_GONE - T_FADE));
}
return true;
}
2011-07-07 19:59:34 +02:00
}, step * 1000);
2011-03-26 14:10:41 +01:00
return {
2011-07-07 19:59:34 +02:00
syncing: function()
{
2011-03-26 14:10:41 +01:00
state = SYNCING;
$("#syncstatussyncing").css('display', 'block');
$("#syncstatusdone").css('display', 'none');
},
2011-07-07 19:59:34 +02:00
done: function()
{
2011-03-26 14:10:41 +01:00
state = T_START;
animator.scheduleAnimation();
}
};
}());
var self = {
init: function() {
var self = this;
self.dropdowns = [];
2014-11-06 16:43:21 +01:00
2011-03-26 14:10:41 +01:00
$("#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) {
self.triggerCommand(command, item);
});
});
$('body:not(#editorcontainerbox)').on("keydown", function(evt){
bodyKeyEvent(evt);
});
$('.show-more-icon-btn').click(function() {
$('.toolbar').toggleClass('full-icons');
});
self.checkAllIconsAreDisplayedInToolbar();
$(window).resize(_.debounce( self.checkAllIconsAreDisplayedInToolbar, 100 ) );
registerDefaultCommands(self);
hooks.callAll("postToolbarInit", {
toolbar: self,
ace: padeditor.ace
});
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
isEnabled: function()
{
return true;
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
disable: function()
{
2011-03-26 14:10:41 +01:00
$("#editbar").addClass('disabledtoolbar').removeClass("enabledtoolbar");
},
commands: {},
registerCommand: function (cmd, callback) {
this.commands[cmd] = callback;
return this;
},
registerDropdownCommand: function (cmd, dropdown) {
dropdown = dropdown || cmd;
self.dropdowns.push(dropdown)
this.registerCommand(cmd, function () {
self.toggleDropDown(dropdown);
});
},
registerAceCommand: function (cmd, callback) {
this.registerCommand(cmd, function (cmd, ace, item) {
ace.callWithAce(function (ace) {
callback(cmd, ace, item);
}, cmd, true);
});
},
triggerCommand: function (cmd, item) {
if (self.isEnabled() && this.commands[cmd]) {
this.commands[cmd](cmd, padeditor.ace, item);
2011-03-26 14:10:41 +01:00
}
if(padeditor.ace) padeditor.ace.focus();
2011-03-26 14:10:41 +01:00
},
2012-07-13 08:24:02 +02:00
toggleDropDown: function(moduleName, cb)
2011-07-08 16:19:38 +02:00
{
// do nothing if users are sticked
if (moduleName === "users" && $('#users').hasClass('stickyUsers')) {
return;
}
// hide all modules and remove highlighting of all buttons
2011-07-08 16:19:38 +02:00
if(moduleName == "none")
{
var returned = false;
for(var i=0;i<self.dropdowns.length;i++)
2011-07-08 16:19:38 +02:00
{
var thisModuleName = self.dropdowns[i];
2011-08-21 20:07:35 +02:00
//skip the userlist
if(thisModuleName == "users")
2011-08-21 20:07:35 +02:00
continue;
2013-03-09 23:57:42 +01:00
var module = $("#" + thisModuleName);
//skip any "force reconnect" message
var isAForceReconnectMessage = module.find('button#forcereconnect:visible').length > 0;
if(isAForceReconnectMessage)
continue;
2013-03-09 23:57:42 +01:00
2011-07-08 16:19:38 +02:00
if(module.css('display') != "none")
{
$("li[data-key=" + thisModuleName + "] > a").removeClass("selected");
2020-04-06 11:11:08 +02:00
module.removeClass("popup-show");
2011-07-08 16:19:38 +02:00
}
}
if(!returned && cb) return cb();
2011-07-08 16:19:38 +02:00
}
2013-03-09 23:57:42 +01:00
else
2011-07-08 16:19:38 +02:00
{
// hide all modules that are not selected and remove highlighting
// respectively add highlighting to the corresponding button
for(var i=0;i<self.dropdowns.length;i++)
2011-07-08 16:19:38 +02:00
{
var thisModuleName = self.dropdowns[i];
var module = $("#" + thisModuleName);
2013-03-09 23:57:42 +01:00
2020-04-06 11:11:08 +02:00
if(module.hasClass('popup-show'))
2011-07-08 16:19:38 +02:00
{
$("li[data-key=" + thisModuleName + "] > a").removeClass("selected");
2020-04-06 11:11:08 +02:00
module.removeClass("popup-show");
2011-07-08 16:19:38 +02:00
}
else if(thisModuleName==moduleName)
2011-07-08 16:19:38 +02:00
{
$("li[data-key=" + thisModuleName + "] > a").addClass("selected");
module.addClass("popup-show");
if (cb) {
cb();
}
2011-07-08 16:19:38 +02:00
}
}
}
},
2011-07-07 19:59:34 +02:00
setSyncStatus: function(status)
{
if (status == "syncing")
{
2011-03-26 14:10:41 +01:00
syncAnimation.syncing();
}
2011-07-07 19:59:34 +02:00
else if (status == "done")
{
2011-03-26 14:10:41 +01:00
syncAnimation.done();
}
2011-11-24 16:34:28 +01:00
},
setEmbedLinks: function()
{
if ($('#readonlyinput').is(':checked'))
{
var basePath = document.location.href.substring(0, document.location.href.indexOf("/p/"));
2012-04-23 16:20:55 +02:00
var readonlyLink = basePath + "/p/" + clientVars.readOnlyId;
$('#embedinput').val('<iframe name="embed_readonly" src="' + readonlyLink + '?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false" width=600 height=400></iframe>');
2011-11-24 16:34:28 +01:00
$('#linkinput').val(readonlyLink);
}
else
{
var padurl = window.location.href.split("?")[0];
$('#embedinput').val('<iframe name="embed_readwrite" src="' + padurl + '?showControls=true&showChat=true&showLineNumbers=true&useMonospaceFont=false" width=600 height=400></iframe>');
2011-11-24 16:34:28 +01:00
$('#linkinput').val(padurl);
}
},
checkAllIconsAreDisplayedInToolbar: function()
{
// reset style
$('.toolbar').removeClass('cropped')
var menu_left = $('.toolbar .menu_left')[0];
if (menu_left && menu_left.scrollWidth > $('.toolbar').width()) {
$('.toolbar').addClass('cropped');
}
2011-03-26 14:10:41 +01:00
}
};
2015-03-25 16:19:52 +01:00
var editbarPosition = 0;
function bodyKeyEvent(evt){
2015-03-31 15:47:00 +02:00
2015-03-26 15:26:21 +01:00
// 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 we're in the editbar already..
// Close any dropdowns we have open..
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'){
// 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{
// 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{
// Focus on the editbar :)
var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first();
$(this).blur();
firstEditbarElement.focus();
evt.preventDefault();
}
}
// Are we in the toolbar??
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;
// Get all the focusable items in the editbar
var focusItems = $('#editbar').find('button, select');
// On left arrow move to next button in editbar
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;
editbarPosition--;
// Allow focus to shift back to end of row and start of row
if(editbarPosition === -1) editbarPosition = focusItems.length -1;
$(focusItems[editbarPosition]).focus()
}
// On right arrow move to next button in editbar
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;
editbarPosition++;
// Allow focus to shift back to end of row and start of row
if(editbarPosition >= focusItems.length) editbarPosition = 0;
$(focusItems[editbarPosition]).focus();
}
}
2015-03-25 16:19:52 +01:00
}
function aceAttributeCommand(cmd, ace) {
ace.ace_toggleAttributeOnSelection(cmd);
}
function registerDefaultCommands(toolbar) {
toolbar.registerDropdownCommand("showusers", "users");
toolbar.registerDropdownCommand("settings");
toolbar.registerDropdownCommand("connectivity");
2014-10-03 17:35:48 +02:00
toolbar.registerDropdownCommand("import_export");
toolbar.registerDropdownCommand("embed");
2015-03-26 00:30:17 +01:00
toolbar.registerCommand("settings", function () {
toolbar.toggleDropDown("settings", function(){
2015-03-26 00:30:17 +01:00
$('#options-stickychat').focus();
});
2015-03-26 00:30:17 +01:00
});
toolbar.registerCommand("import_export", function () {
toolbar.toggleDropDown("import_export", function(){
// If Import file input exists then focus on it..
if($('#importfileinput').length !== 0){
setTimeout(function(){
$('#importfileinput').focus();
}, 100);
}else{
$('.exportlink').first().focus();
}
});
});
toolbar.registerCommand("showusers", function () {
toolbar.toggleDropDown("users", function(){
$('#myusernameedit').focus();
});
});
toolbar.registerCommand("embed", function () {
toolbar.setEmbedLinks();
toolbar.toggleDropDown("embed", function(){
2015-03-26 00:30:17 +01:00
$('#linkinput').focus().select();
});
});
toolbar.registerCommand("savedRevision", function () {
padsavedrevs.saveNow();
});
toolbar.registerCommand("showTimeSlider", function () {
document.location = document.location.pathname+ '/timeslider';
});
toolbar.registerAceCommand("bold", aceAttributeCommand);
toolbar.registerAceCommand("italic", aceAttributeCommand);
toolbar.registerAceCommand("underline", aceAttributeCommand);
toolbar.registerAceCommand("strikethrough", aceAttributeCommand);
toolbar.registerAceCommand("undo", function (cmd, ace) {
ace.ace_doUndoRedo(cmd);
});
2014-03-30 13:05:51 +02:00
toolbar.registerAceCommand("redo", function (cmd, ace) {
ace.ace_doUndoRedo(cmd);
});
toolbar.registerAceCommand("insertunorderedlist", function (cmd, ace) {
ace.ace_doInsertUnorderedList();
});
toolbar.registerAceCommand("insertorderedlist", function (cmd, ace) {
ace.ace_doInsertOrderedList();
});
toolbar.registerAceCommand("indent", function (cmd, ace) {
if (!ace.ace_doIndentOutdent(false)) {
ace.ace_doInsertUnorderedList();
}
});
toolbar.registerAceCommand("outdent", function (cmd, ace) {
ace.ace_doIndentOutdent(true);
});
toolbar.registerAceCommand("clearauthorship", function (cmd, ace) {
if ((!(ace.ace_getRep().selStart && ace.ace_getRep().selEnd)) || ace.ace_isCaret()) {
if (window.confirm(html10n.get("pad.editbar.clearcolors"))) {
ace.ace_performDocumentApplyAttributesToCharRange(0, ace.ace_getRep().alltext.length, [
['author', '']
]);
}
}
else {
ace.ace_setAttributeOnSelection('author', '');
}
});
toolbar.registerCommand('timeslider_returnToPad', function(cmd) {
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("/"));
}
});
}
2011-03-26 14:10:41 +01:00
return self;
2011-03-26 15:50:13 +01:00
}());
exports.padeditbar = padeditbar;