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

963 lines
28 KiB
JavaScript
Raw Normal View History

/**
* 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 Peter 'Pita' Martischka (Primary Technology Ltd)
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.
*/
/* global $, window */
var socket;
// These jQuery things should create local references, but for now `require()`
// assigns to the global `$` and augments it with plugins.
2012-03-07 02:27:03 +01:00
require('./jquery');
require('./farbtastic');
require('./excanvas');
JSON = require('./json2');
2012-03-07 02:27:03 +01:00
var chat = require('./chat').chat;
var getCollabClient = require('./collab_client').getCollabClient;
var padconnectionstatus = require('./pad_connectionstatus').padconnectionstatus;
var padcookie = require('./pad_cookie').padcookie;
var padeditbar = require('./pad_editbar').padeditbar;
var padeditor = require('./pad_editor').padeditor;
var padimpexp = require('./pad_impexp').padimpexp;
var padmodals = require('./pad_modals').padmodals;
var padsavedrevs = require('./pad_savedrevs');
2012-03-07 02:27:03 +01:00
var paduserlist = require('./pad_userlist').paduserlist;
var padutils = require('./pad_utils').padutils;
var colorutils = require('./colorutils').colorutils;
2012-03-07 02:27:03 +01:00
var createCookie = require('./pad_utils').createCookie;
var readCookie = require('./pad_utils').readCookie;
var randomString = require('./pad_utils').randomString;
var gritter = require('./gritter').gritter;
2011-03-26 14:10:41 +01:00
2012-03-27 22:23:55 +02:00
var hooks = require('./pluginfw/hooks');
var receivedClientVars = false;
function createCookie(name, value, days, path){ /* Warning Internet Explorer doesn't use this it uses the one from pad_utils.js */
2011-07-07 19:59:34 +02:00
if (days)
{
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
var expires = "; expires=" + date.toGMTString();
}
else{
var expires = "";
}
if(!path){ // If the path isn't set then just whack the cookie on the root path
path = "/";
}
//Check if the browser is IE and if so make sure the full path is set in the cookie
2014-11-01 21:21:48 +01:00
if((navigator.appName == 'Microsoft Internet Explorer') || ((navigator.appName == 'Netscape') && (new RegExp("Trident/.*rv:([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null))){
document.cookie = name + "=" + value + expires + "; path="+document.location;
}
else{
document.cookie = name + "=" + value + expires + "; path=" + path;
}
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function readCookie(name)
{
var nameEQ = name + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++)
{
var c = ca[i];
while (c.charAt(0) == ' ') c = c.substring(1, c.length);
if (c.indexOf(nameEQ) == 0) return c.substring(nameEQ.length, c.length);
}
return null;
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
function randomString()
{
2011-07-31 12:48:06 +02:00
var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
2011-07-07 19:59:34 +02:00
var string_length = 20;
var randomstring = '';
for (var i = 0; i < string_length; i++)
{
var rnum = Math.floor(Math.random() * chars.length);
randomstring += chars.substring(rnum, rnum + 1);
}
return "t." + randomstring;
2011-03-26 14:10:41 +01:00
}
// This array represents all GET-parameters which can be used to change a setting.
// name: the parameter-name, eg `?noColors=true` => `noColors`
// checkVal: the callback is only executed when
// * the parameter was supplied and matches checkVal
// * the parameter was supplied and checkVal is null
// callback: the function to call when all above succeeds, `val` is the value supplied by the user
var getParameters = [
{ name: "noColors", checkVal: "true", callback: function(val) { settings.noColors = true; $('#clearAuthorship').hide(); } },
{ name: "showControls", checkVal: "false", callback: function(val) { $('#editbar').hide(); $('#editorcontainer').css({"top":"0px"}); } },
{ name: "showChat", checkVal: "false", callback: function(val) { $('#chaticon').hide(); } },
{ name: "showLineNumbers", checkVal: "false", callback: function(val) { settings.LineNumbersDisabled = true; } },
{ name: "useMonospaceFont", checkVal: "true", callback: function(val) { settings.useMonospaceFontGlobal = true; } },
// If the username is set as a parameter we should set a global value that we can call once we have initiated the pad.
{ name: "userName", checkVal: null, callback: function(val) { settings.globalUserName = decodeURIComponent(val); } },
// If the userColor is set as a parameter, set a global value to use once we have initiated the pad.
{ name: "userColor", checkVal: null, callback: function(val) { settings.globalUserColor = decodeURIComponent(val); } },
{ name: "rtl", checkVal: "true", callback: function(val) { settings.rtlIsTrue = true } },
{ name: "alwaysShowChat", checkVal: "true", callback: function(val) { chat.stickToScreen(); } },
2015-01-19 02:45:49 +01:00
{ name: "chatAndUsers", checkVal: "true", callback: function(val) { chat.chatAndUsers(); } },
{ name: "lang", checkVal: null, callback: function(val) { window.html10n.localize([val, 'en']); } }
];
function getParams()
{
var params = getUrlVars()
for(var i = 0; i < getParameters.length; i++)
{
var setting = getParameters[i];
var value = params[setting.name];
if(value && (value == setting.checkVal || setting.checkVal == null))
{
setting.callback(value);
}
}
}
function getUrlVars()
{
var vars = [], hash;
var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
for(var i = 0; i < hashes.length; i++)
{
hash = hashes[i].split('=');
vars.push(hash[0]);
vars[hash[0]] = hash[1];
}
return vars;
}
function savePassword()
{
//set the password cookie
createCookie("password",$("#passwordinput").val(),null,document.location.pathname);
//reload
document.location=document.location;
2012-12-03 14:10:32 +01:00
return false;
}
function sendClientReady(isReconnect, messageType)
{
messageType = typeof messageType !== 'undefined' ? messageType : 'CLIENT_READY';
var padId = document.location.pathname.substring(document.location.pathname.lastIndexOf("/") + 1);
padId = decodeURIComponent(padId); // unescape neccesary due to Safari and Opera interpretation of spaces
if(!isReconnect)
{
var titleArray = document.title.split('|');
var title = titleArray[titleArray.length - 1];
document.title = padId.replace(/_+/g, ' ') + " | " + title;
}
var token = readCookie("token");
if (token == null)
{
token = "t." + randomString();
createCookie("token", token, 60);
}
var sessionID = decodeURIComponent(readCookie("sessionID"));
var password = readCookie("password");
var msg = {
"component": "pad",
"type": messageType,
"padId": padId,
"sessionID": sessionID,
"password": password,
"token": token,
"protocolVersion": 2
};
//this is a reconnect, lets tell the server our revisionnumber
if(isReconnect == true)
{
msg.client_rev=pad.collabClient.getCurrentRevisionNumber();
msg.reconnect=true;
}
socket.json.send(msg);
}
2011-03-26 14:10:41 +01:00
function handshake()
{
2011-07-05 20:16:45 +02:00
var loc = document.location;
//get the correct port
var port = loc.port == "" ? (loc.protocol == "https:" ? 443 : 80) : loc.port;
//create the url
var url = loc.protocol + "//" + loc.hostname + ":" + port + "/";
//find out in which subfolder we are
2012-04-29 19:54:38 +02:00
var resource = exports.baseURL.substring(1) + "socket.io";
2011-07-05 20:16:45 +02:00
//connect
socket = pad.socket = io.connect(url, {
2014-11-25 19:42:40 +01:00
// Allow deployers to host Etherpad on a non-root path
'path': exports.baseURL + "socket.io",
'resource': resource,
'max reconnection attempts': 3,
'sync disconnect on unload' : false
2011-07-07 19:59:34 +02:00
});
var disconnectTimeout;
socket.once('connect', function () {
sendClientReady(false);
});
socket.on('reconnect', function () {
//reconnect is before the timeout, lets stop the timeout
if(disconnectTimeout)
{
clearTimeout(disconnectTimeout);
}
pad.collabClient.setChannelState("CONNECTED");
pad.sendClientReady(true);
});
socket.on('disconnect', function (reason) {
if(reason == "booted"){
pad.collabClient.setChannelState("DISCONNECTED");
} else {
function disconnectEvent()
{
pad.collabClient.setChannelState("DISCONNECTED", "reconnect_timeout");
}
pad.collabClient.setChannelState("RECONNECTING");
2013-04-02 21:20:38 +02:00
disconnectTimeout = setTimeout(disconnectEvent, 20000);
}
2011-07-07 19:59:34 +02:00
});
var initalized = false;
socket.on('message', function(obj)
{
//the access was not granted, give the user a message
if(obj.accessStatus)
{
2014-03-17 20:20:32 +01:00
if(!receivedClientVars){
$('.passForm').submit(require(module.id).savePassword);
2014-03-17 20:20:32 +01:00
}
if(obj.accessStatus == "deny")
{
$('#loading').hide();
2012-12-03 12:41:51 +01:00
$("#permissionDenied").show();
if(receivedClientVars)
{
// got kicked
$("#editorcontainer").hide();
$("#editorloadingbox").show();
}
}
else if(obj.accessStatus == "needPassword")
{
$('#loading').hide();
$('#passwordRequired').show();
$("#passwordinput").focus();
}
else if(obj.accessStatus == "wrongPassword")
{
$('#loading').hide();
$('#wrongPassword').show();
$('#passwordRequired').show();
$("#passwordinput").focus();
}
}
2011-07-07 19:59:34 +02:00
//if we haven't recieved the clientVars yet, then this message should it be
else if (!receivedClientVars && obj.type == "CLIENT_VARS")
2011-07-07 19:59:34 +02:00
{
//log the message
2011-07-07 19:59:34 +02:00
if (window.console) console.log(obj);
receivedClientVars = true;
//set some client vars
clientVars = obj.data;
clientVars.userAgent = "Anonymous";
clientVars.collab_client_vars.clientAgent = "Anonymous";
2012-04-23 16:41:41 +02:00
//initalize the pad
pad._afterHandshake();
2011-07-07 19:59:34 +02:00
initalized = true;
$("body").addClass(clientVars.readonly ? "readonly" : "readwrite")
2012-04-23 16:41:41 +02:00
padeditor.ace.callWithAce(function (ace) {
ace.ace_setEditable(!clientVars.readonly);
});
// If the LineNumbersDisabled value is set to true then we need to hide the Line Numbers
if (settings.LineNumbersDisabled == true)
{
pad.changeViewOption('showLineNumbers', false);
}
// If the noColors value is set to true then we need to hide the background colors on the ace spans
if (settings.noColors == true)
{
pad.changeViewOption('noColors', true);
}
2011-12-04 19:55:35 +01:00
if (settings.rtlIsTrue == true)
2011-12-04 19:55:35 +01:00
{
pad.changeViewOption('rtlIsTrue', true);
2011-12-04 19:55:35 +01:00
}
// If the Monospacefont value is set to true then change it to monospace.
if (settings.useMonospaceFontGlobal == true)
{
pad.changeViewOption('useMonospaceFont', true);
}
// if the globalUserName value is set we need to tell the server and the client about the new authorname
if (settings.globalUserName !== false)
{
pad.notifyChangeName(settings.globalUserName); // Notifies the server
pad.myUserInfo.name = settings.globalUserName;
$('#myusernameedit').val(settings.globalUserName); // Updates the current users UI
}
if (settings.globalUserColor !== false && colorutils.isCssHex(settings.globalUserColor))
{
// Add a 'globalUserColor' property to myUserInfo, so collabClient knows we have a query parameter.
pad.myUserInfo.globalUserColor = settings.globalUserColor;
pad.notifyChangeColor(settings.globalUserColor); // Updates pad.myUserInfo.colorId
paduserlist.setMyUserInfo(pad.myUserInfo);
}
2011-07-07 19:59:34 +02:00
}
//This handles every Message after the clientVars
else
{
2011-08-16 21:02:30 +02:00
//this message advices the client to disconnect
2011-07-07 19:59:34 +02:00
if (obj.disconnect)
2011-03-26 14:10:41 +01:00
{
2012-04-23 13:29:27 +02:00
console.warn("FORCED TO DISCONNECT");
console.warn(obj);
2011-08-16 21:02:30 +02:00
padconnectionstatus.disconnected(obj.disconnect);
2011-07-07 19:59:34 +02:00
socket.disconnect();
return;
2011-03-26 14:10:41 +01:00
}
else
{
2011-07-07 19:59:34 +02:00
pad.collabClient.handleMessageFromServer(obj);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
}
});
2011-08-20 19:22:10 +02:00
// Bind the colorpicker
var fb = $('#colorpicker').farbtastic({ callback: '#mycolorpickerpreview', width: 220});
// Bind the read only button
$('#readonlyinput').on('click',function(){
padeditbar.setEmbedLinks();
});
2011-03-26 14:10:41 +01:00
}
2013-01-29 02:55:36 +01:00
$.extend($.gritter.options, {
2013-01-29 03:08:37 +01:00
position: 'bottom-right', // defaults to 'top-right' but can be 'bottom-left', 'bottom-right', 'top-left', 'top-right' (added in 1.7.1)
fade: false, // dont fade, too jerky on mobile
2013-01-29 03:08:37 +01:00
time: 6000 // hang on the screen for...
2013-01-29 02:55:36 +01:00
});
2011-03-26 14:10:41 +01:00
var pad = {
// don't access these directly from outside this file, except
// for debugging
collabClient: null,
myUserInfo: null,
diagnosticInfo: {},
initTime: 0,
2011-07-14 17:15:38 +02:00
clientTimeOffset: null,
2011-03-26 14:10:41 +01:00
padOptions: {},
// these don't require init; clientVars should all go through here
2011-07-07 19:59:34 +02:00
getPadId: function()
{
return clientVars.padId;
},
getClientIp: function()
{
return clientVars.clientIp;
},
getColorPalette: function()
{
return clientVars.colorPalette;
},
getDisplayUserAgent: function()
{
2011-03-26 14:10:41 +01:00
return padutils.uaDisplay(clientVars.userAgent);
},
2011-07-07 19:59:34 +02:00
getIsDebugEnabled: function()
{
return clientVars.debugEnabled;
},
getPrivilege: function(name)
{
return clientVars.accountPrivs[name];
},
getUserIsGuest: function()
{
return clientVars.userIsGuest;
},
getUserId: function()
{
return pad.myUserInfo.userId;
},
getUserName: function()
{
return pad.myUserInfo.name;
},
sendClientReady: function(isReconnect, messageType)
{
messageType = typeof messageType !== 'undefined' ? messageType : 'CLIENT_READY';
sendClientReady(isReconnect, messageType);
},
switchToPad: function(padId)
{
var options = document.location.href.split('?')[1];
var newHref = "/p/" + padId;
if (options != null)
newHref = newHref + '?' + options;
if(window.history && window.history.pushState)
{
$('#chattext p').remove(); //clear the chat messages
window.history.pushState("", "", newHref);
receivedClientVars = false;
sendClientReady(false, 'SWITCH_TO_PAD');
}
else // fallback
{
window.location.href = newHref;
}
},
2011-07-07 19:59:34 +02:00
sendClientMessage: function(msg)
{
2011-03-26 14:10:41 +01:00
pad.collabClient.sendClientMessage(msg);
},
2012-11-12 16:49:15 +01:00
createCookie: createCookie,
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
init: function()
{
padutils.setupGlobalExceptionHandler();
$(document).ready(function()
{
// start the custom js
if (typeof customStart == "function") customStart();
getParams();
handshake();
// To use etherpad you have to allow cookies.
// This will check if the creation of a test-cookie has success.
// Otherwise it shows up a message to the user.
createCookie("test", "test");
if (!readCookie("test"))
{
$('#loading').hide();
2014-12-28 22:20:09 +01:00
$('#noCookie').show();
}
});
},
_afterHandshake: function()
2011-07-07 19:59:34 +02:00
{
2011-07-14 17:15:38 +02:00
pad.clientTimeOffset = new Date().getTime() - clientVars.serverTimestamp;
//initialize the chat
2012-01-16 06:05:19 +01:00
chat.init(this);
2013-03-23 03:59:12 +01:00
padcookie.init(); // initialize the cookies
2011-03-26 14:10:41 +01:00
pad.initTime = +(new Date());
pad.padOptions = clientVars.initialOptions;
2015-01-21 14:24:21 +01:00
if ((!browser.msie) && (!(browser.firefox && browser.version.indexOf("1.8.") == 0)))
2011-07-07 19:59:34 +02:00
{
2011-03-26 14:10:41 +01:00
document.domain = document.domain; // for comet
}
// for IE
if (browser.msie)
2011-07-07 19:59:34 +02:00
{
try
{
2013-04-17 16:51:54 +02:00
document.execCommand("BackgroundImageCache", false, true);
2011-07-07 19:59:34 +02:00
}
catch (e)
{}
2011-03-26 14:10:41 +01:00
}
// order of inits is important here:
pad.myUserInfo = {
userId: clientVars.userId,
name: clientVars.userName,
ip: pad.getClientIp(),
colorId: clientVars.userColor,
userAgent: pad.getDisplayUserAgent()
};
2011-08-20 19:22:10 +02:00
padimpexp.init(this);
2012-02-29 20:40:14 +01:00
padsavedrevs.init(this);
2011-03-26 14:10:41 +01:00
padeditor.init(postAceInit, pad.padOptions.view || {}, this);
2011-03-26 14:10:41 +01:00
paduserlist.init(pad.myUserInfo, this);
2011-03-26 14:10:41 +01:00
padconnectionstatus.init();
padmodals.init(this);
2011-03-26 14:10:41 +01:00
2011-07-07 19:59:34 +02:00
pad.collabClient = getCollabClient(padeditor.ace, clientVars.collab_client_vars, pad.myUserInfo, {
colorPalette: pad.getColorPalette()
}, pad);
2011-03-26 14:10:41 +01:00
pad.collabClient.setOnUserJoin(pad.handleUserJoin);
pad.collabClient.setOnUpdateUserInfo(pad.handleUserUpdate);
pad.collabClient.setOnUserLeave(pad.handleUserLeave);
pad.collabClient.setOnClientMessage(pad.handleClientMessage);
pad.collabClient.setOnServerMessage(pad.handleServerMessage);
pad.collabClient.setOnChannelStateChange(pad.handleChannelStateChange);
pad.collabClient.setOnInternalAction(pad.handleCollabAction);
// load initial chat-messages
if(clientVars.chatHead != -1)
{
var chatHead = clientVars.chatHead;
var start = Math.max(chatHead - 100, 0);
pad.collabClient.sendMessage({"type": "GET_CHAT_MESSAGES", "start": start, "end": chatHead});
}
else // there are no messages
{
$("#chatloadmessagesbutton").css("display", "none");
}
2011-07-07 19:59:34 +02:00
function postAceInit()
{
2011-03-26 14:10:41 +01:00
padeditbar.init();
2011-07-07 19:59:34 +02:00
setTimeout(function()
{
padeditor.ace.focus();
}, 0);
if(padcookie.getPref("chatAlwaysVisible")){ // if we have a cookie for always showing chat then show it
chat.stickToScreen(true); // stick it to the screen
$('#options-stickychat').prop("checked", true); // set the checkbox to on
}
2015-01-19 02:45:49 +01:00
if(padcookie.getPref("chatAndUsers")){ // if we have a cookie for always showing chat then show it
chat.chatAndUsers(true); // stick it to the screen
$('#options-chatandusers').prop("checked", true); // set the checkbox to on
}
if(padcookie.getPref("showAuthorshipColors") == false){
2013-02-07 11:15:16 +01:00
pad.changeViewOption('showAuthorColors', false);
}
2014-12-27 15:08:54 +01:00
if(padcookie.getPref("showLineNumbers") == false){
pad.changeViewOption('showLineNumbers', false);
}
if(padcookie.getPref("rtlIsTrue") == true){
pad.changeViewOption('rtlIsTrue', true);
}
if(padcookie.getPref("useMonospaceFont") == true){
pad.changeViewOption('useMonospaceFont', true);
}
hooks.aCallAll("postAceInit", {ace: padeditor.ace, pad: pad});
2011-03-26 14:10:41 +01:00
}
},
2011-07-07 19:59:34 +02:00
dispose: function()
{
2011-03-26 14:10:41 +01:00
padeditor.dispose();
},
2011-07-07 19:59:34 +02:00
notifyChangeName: function(newName)
{
2011-03-26 14:10:41 +01:00
pad.myUserInfo.name = newName;
pad.collabClient.updateUserInfo(pad.myUserInfo);
},
2011-07-07 19:59:34 +02:00
notifyChangeColor: function(newColorId)
{
2011-03-26 14:10:41 +01:00
pad.myUserInfo.colorId = newColorId;
pad.collabClient.updateUserInfo(pad.myUserInfo);
},
2011-07-07 19:59:34 +02:00
changePadOption: function(key, value)
{
2011-03-26 14:10:41 +01:00
var options = {};
options[key] = value;
pad.handleOptionsChange(options);
2011-07-07 19:59:34 +02:00
pad.collabClient.sendClientMessage(
{
2011-03-26 14:10:41 +01:00
type: 'padoptions',
options: options,
changedBy: pad.myUserInfo.name || "unnamed"
});
},
2011-07-07 19:59:34 +02:00
changeViewOption: function(key, value)
{
var options = {
view: {}
};
2011-03-26 14:10:41 +01:00
options.view[key] = value;
pad.handleOptionsChange(options);
},
2011-07-07 19:59:34 +02:00
handleOptionsChange: function(opts)
{
2011-03-26 14:10:41 +01:00
// opts object is a full set of options or just
// some options to change
2011-07-07 19:59:34 +02:00
if (opts.view)
{
if (!pad.padOptions.view)
{
2011-03-26 14:10:41 +01:00
pad.padOptions.view = {};
}
2011-07-07 19:59:34 +02:00
for (var k in opts.view)
{
2011-03-26 14:10:41 +01:00
pad.padOptions.view[k] = opts.view[k];
2014-12-27 15:08:54 +01:00
padcookie.setPref(k, opts.view[k]);
2011-03-26 14:10:41 +01:00
}
padeditor.setViewOptions(pad.padOptions.view);
}
2011-07-07 19:59:34 +02:00
if (opts.guestPolicy)
{
2011-03-26 14:10:41 +01:00
// order important here
pad.padOptions.guestPolicy = opts.guestPolicy;
}
},
2011-07-07 19:59:34 +02:00
getPadOptions: function()
{
2011-03-26 14:10:41 +01:00
// caller shouldn't mutate the object
return pad.padOptions;
},
2011-07-07 19:59:34 +02:00
isPadPublic: function()
{
return pad.getPadOptions().guestPolicy == 'allow';
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
suggestUserName: function(userId, name)
{
pad.collabClient.sendClientMessage(
{
2011-03-26 14:10:41 +01:00
type: 'suggestUserName',
unnamedId: userId,
newName: name
});
},
2011-07-07 19:59:34 +02:00
handleUserJoin: function(userInfo)
{
2011-03-26 14:10:41 +01:00
paduserlist.userJoinOrUpdate(userInfo);
},
2011-07-07 19:59:34 +02:00
handleUserUpdate: function(userInfo)
{
2011-03-26 14:10:41 +01:00
paduserlist.userJoinOrUpdate(userInfo);
},
2011-07-07 19:59:34 +02:00
handleUserLeave: function(userInfo)
{
2011-03-26 14:10:41 +01:00
paduserlist.userLeave(userInfo);
},
2011-07-07 19:59:34 +02:00
handleClientMessage: function(msg)
{
if (msg.type == 'suggestUserName')
{
if (msg.unnamedId == pad.myUserInfo.userId && msg.newName && !pad.myUserInfo.name)
{
2011-03-26 14:10:41 +01:00
pad.notifyChangeName(msg.newName);
paduserlist.setMyUserInfo(pad.myUserInfo);
}
}
2011-07-07 19:59:34 +02:00
else if (msg.type == 'newRevisionList')
{
2011-03-26 14:10:41 +01:00
padsavedrevs.newRevisionList(msg.revisionList);
}
2011-07-07 19:59:34 +02:00
else if (msg.type == 'revisionLabel')
{
2011-03-26 14:10:41 +01:00
padsavedrevs.newRevisionList(msg.revisionList);
}
2011-07-07 19:59:34 +02:00
else if (msg.type == 'padoptions')
{
2011-03-26 14:10:41 +01:00
var opts = msg.options;
pad.handleOptionsChange(opts);
}
2011-07-07 19:59:34 +02:00
else if (msg.type == 'guestanswer')
{
2011-03-26 14:10:41 +01:00
// someone answered a prompt, remove it
paduserlist.removeGuestPrompt(msg.guestId);
}
},
2011-07-07 19:59:34 +02:00
dmesg: function(m)
{
if (pad.getIsDebugEnabled())
{
2011-03-26 14:10:41 +01:00
var djs = $('#djs').get(0);
2011-07-07 19:59:34 +02:00
var wasAtBottom = (djs.scrollTop - (djs.scrollHeight - $(djs).height()) >= -20);
$('#djs').append('<p>' + m + '</p>');
if (wasAtBottom)
{
2011-03-26 14:10:41 +01:00
djs.scrollTop = djs.scrollHeight;
}
}
},
2011-07-07 19:59:34 +02:00
handleServerMessage: function(m)
{
if (m.type == 'NOTICE')
{
if (m.text)
{
alertBar.displayMessage(function(abar)
{
2013-03-14 22:28:35 +01:00
abar.find("#servermsgdate").text(" (" + padutils.simpleDateTime(new Date) + ")");
abar.find("#servermsgtext").text(m.text);
2011-03-26 14:10:41 +01:00
});
}
2011-07-07 19:59:34 +02:00
if (m.js)
{
window['ev' + 'al'](m.js);
2011-03-26 14:10:41 +01:00
}
}
2011-07-07 19:59:34 +02:00
else if (m.type == 'GUEST_PROMPT')
{
2011-03-26 14:10:41 +01:00
paduserlist.showGuestPrompt(m.userId, m.displayName);
}
},
2011-07-07 19:59:34 +02:00
handleChannelStateChange: function(newState, message)
{
2011-03-26 14:10:41 +01:00
var oldFullyConnected = !! padconnectionstatus.isFullyConnected();
var wasConnecting = (padconnectionstatus.getStatus().what == 'connecting');
2011-07-07 19:59:34 +02:00
if (newState == "CONNECTED")
{
2011-03-26 14:10:41 +01:00
padconnectionstatus.connected();
}
2011-07-07 19:59:34 +02:00
else if (newState == "RECONNECTING")
{
2011-03-26 14:10:41 +01:00
padconnectionstatus.reconnecting();
}
2011-07-07 19:59:34 +02:00
else if (newState == "DISCONNECTED")
{
2011-03-26 14:10:41 +01:00
pad.diagnosticInfo.disconnectedMessage = message;
pad.diagnosticInfo.padId = pad.getPadId();
pad.diagnosticInfo.socket = {};
//we filter non objects from the socket object and put them in the diagnosticInfo
//this ensures we have no cyclic data - this allows us to stringify the data
for(var i in socket.socket)
{
var value = socket.socket[i];
var type = typeof value;
if(type == "string" || type == "number")
{
pad.diagnosticInfo.socket[i] = value;
}
}
2011-03-26 14:10:41 +01:00
pad.asyncSendDiagnosticInfo();
2011-07-07 19:59:34 +02:00
if (typeof window.ajlog == "string")
{
window.ajlog += ("Disconnected: " + message + '\n');
}
2011-03-26 14:10:41 +01:00
padeditor.disable();
padeditbar.disable();
padimpexp.disable();
padconnectionstatus.disconnected(message);
}
var newFullyConnected = !! padconnectionstatus.isFullyConnected();
2011-07-07 19:59:34 +02:00
if (newFullyConnected != oldFullyConnected)
{
2011-03-26 14:10:41 +01:00
pad.handleIsFullyConnected(newFullyConnected, wasConnecting);
}
},
2011-07-07 19:59:34 +02:00
handleIsFullyConnected: function(isConnected, isInitialConnect)
{
pad.determineChatVisibility(isConnected && !isInitialConnect);
2015-01-21 17:08:54 +01:00
pad.determineChatAndUsersVisibility(isConnected && !isInitialConnect);
pad.determineAuthorshipColorsVisibility();
2011-07-07 19:59:34 +02:00
},
determineChatVisibility: function(asNowConnectedFeedback){
var chatVisCookie = padcookie.getPref('chatAlwaysVisible');
if(chatVisCookie){ // if the cookie is set for chat always visible
chat.stickToScreen(true); // stick it to the screen
$('#options-stickychat').prop("checked", true); // set the checkbox to on
}
else{
$('#options-stickychat').prop("checked", false); // set the checkbox for off
}
},
2015-01-21 17:08:54 +01:00
determineChatAndUsersVisibility: function(asNowConnectedFeedback){
2015-01-19 02:45:49 +01:00
var chatAUVisCookie = padcookie.getPref('chatAndUsersVisible');
if(chatAUVisCookie){ // if the cookie is set for chat always visible
chat.chatAndUsers(true); // stick it to the screen
$('#options-chatandusers').prop("checked", true); // set the checkbox to on
}
else{
$('#options-chatandusers').prop("checked", false); // set the checkbox for off
}
},
determineAuthorshipColorsVisibility: function(){
var authColCookie = padcookie.getPref('showAuthorshipColors');
if (authColCookie){
pad.changeViewOption('showAuthorColors', true);
$('#options-colorscheck').prop("checked", true);
}
else {
$('#options-colorscheck').prop("checked", false);
}
},
2011-07-07 19:59:34 +02:00
handleCollabAction: function(action)
{
if (action == "commitPerformed")
{
2011-03-26 14:10:41 +01:00
padeditbar.setSyncStatus("syncing");
}
2011-07-07 19:59:34 +02:00
else if (action == "newlyIdle")
{
2011-03-26 14:10:41 +01:00
padeditbar.setSyncStatus("done");
}
},
2011-07-07 19:59:34 +02:00
hideServerMessage: function()
{
2011-03-26 14:10:41 +01:00
alertBar.hideMessage();
},
2011-07-07 19:59:34 +02:00
asyncSendDiagnosticInfo: function()
{
window.setTimeout(function()
{
$.ajax(
{
2011-03-26 14:10:41 +01:00
type: 'post',
url: '/ep/pad/connection-diagnostic-info',
2011-07-07 19:59:34 +02:00
data: {
diagnosticInfo: JSON.stringify(pad.diagnosticInfo)
},
success: function()
{},
error: function()
{}
2011-03-26 14:10:41 +01:00
});
}, 0);
},
2011-07-07 19:59:34 +02:00
forceReconnect: function()
{
2011-03-26 14:10:41 +01:00
$('form#reconnectform input.padId').val(pad.getPadId());
pad.diagnosticInfo.collabDiagnosticInfo = pad.collabClient.getDiagnosticInfo();
$('form#reconnectform input.diagnosticInfo').val(JSON.stringify(pad.diagnosticInfo));
$('form#reconnectform input.missedChanges').val(JSON.stringify(pad.collabClient.getMissedChanges()));
$('form#reconnectform').submit();
},
// this is called from code put into a frame from the server:
2011-07-07 19:59:34 +02:00
handleImportExportFrameCall: function(callName, varargs)
{
padimpexp.handleFrameCall.call(padimpexp, callName, Array.prototype.slice.call(arguments, 1));
2011-03-26 14:10:41 +01:00
},
2011-07-07 19:59:34 +02:00
callWhenNotCommitting: function(f)
{
2011-03-26 14:10:41 +01:00
pad.collabClient.callWhenNotCommitting(f);
},
2011-07-07 19:59:34 +02:00
getCollabRevisionNumber: function()
{
2011-03-26 14:10:41 +01:00
return pad.collabClient.getCurrentRevisionNumber();
},
2011-07-07 19:59:34 +02:00
isFullyConnected: function()
{
2011-03-26 14:10:41 +01:00
return padconnectionstatus.isFullyConnected();
},
2011-07-07 19:59:34 +02:00
addHistoricalAuthors: function(data)
{
if (!pad.collabClient)
{
window.setTimeout(function()
{
pad.addHistoricalAuthors(data);
}, 1000);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
else
{
2011-03-26 14:10:41 +01:00
pad.collabClient.addHistoricalAuthors(data);
}
}
};
2011-07-07 19:59:34 +02:00
var alertBar = (function()
{
2011-03-26 14:10:41 +01:00
var animator = padutils.makeShowHideAnimator(arriveAtAnimationState, false, 25, 400);
2011-07-07 19:59:34 +02:00
function arriveAtAnimationState(state)
{
if (state == -1)
{
2011-03-26 14:10:41 +01:00
$("#alertbar").css('opacity', 0).css('display', 'block');
}
2011-07-07 19:59:34 +02:00
else if (state == 0)
{
2011-03-26 14:10:41 +01:00
$("#alertbar").css('opacity', 1);
}
2011-07-07 19:59:34 +02:00
else if (state == 1)
{
2011-03-26 14:10:41 +01:00
$("#alertbar").css('opacity', 0).css('display', 'none');
}
2011-07-07 19:59:34 +02:00
else if (state < 0)
{
$("#alertbar").css('opacity', state + 1);
2011-03-26 14:10:41 +01:00
}
2011-07-07 19:59:34 +02:00
else if (state > 0)
{
2011-03-26 14:10:41 +01:00
$("#alertbar").css('opacity', 1 - state);
}
}
var self = {
2011-07-07 19:59:34 +02:00
displayMessage: function(setupFunc)
{
2011-03-26 14:10:41 +01:00
animator.show();
setupFunc($("#alertbar"));
},
2011-07-07 19:59:34 +02:00
hideMessage: function()
{
2011-03-26 14:10:41 +01:00
animator.hide();
}
};
return self;
}());
function init() {
return pad.init();
}
2012-01-27 06:40:13 +01:00
var settings = {
LineNumbersDisabled: false
, noColors: false
, useMonospaceFontGlobal: false
, globalUserName: false
, globalUserColor: false
2012-01-27 06:40:13 +01:00
, rtlIsTrue: false
};
pad.settings = settings;
exports.baseURL = '';
exports.settings = settings;
exports.createCookie = createCookie;
exports.readCookie = readCookie;
exports.randomString = randomString;
exports.getParams = getParams;
exports.getUrlVars = getUrlVars;
exports.savePassword = savePassword;
exports.handshake = handshake;
exports.pad = pad;
exports.init = init;
exports.alertBar = alertBar;