Merge branch 'develop' of github.com:Pita/etherpad-lite into feature/frontend-tests

This commit is contained in:
Peter 'Pita' Martischka 2012-10-27 16:32:37 +01:00
commit f59b643aa6
25 changed files with 378 additions and 83 deletions

View file

@ -141,22 +141,6 @@ exports.getAuthor = function (author, callback)
db.get("globalAuthor:" + author, callback);
}
/**
* Returns the Author Name of the author
* @param {String} author The id of the author
* @param {Function} callback callback(err, name)
*/
exports.getAuthorName = function (authorID, callback)
{
db.getSub("globalAuthor:" + author, ["name"], callback);
console.log(authorID);
db.getSub("globalAuthor:" + authorID, ["name"], function(err, authorName){
if(ERR(err, callback)) return;
callback(null, {authorName: authorName});
});
}
/**

View file

@ -16,6 +16,7 @@ var padMessageHandler = require("../handler/PadMessageHandler");
var readOnlyManager = require("./ReadOnlyManager");
var crypto = require("crypto");
var randomString = require("../utils/randomstring");
var hooks = require('ep_etherpad-lite/static/js/pluginfw/hooks');
//serialization/deserialization attributes
var attributeBlackList = ["id"];
@ -86,6 +87,12 @@ Pad.prototype.appendRevision = function appendRevision(aChangeset, author) {
// set the author to pad
if(author)
authorManager.addPad(author, this.id);
if (this.head == 0) {
hooks.callAll("padCreate", {'pad':this});
} else {
hooks.callAll("padUpdate", {'pad':this});
}
};
//save all attributes to the database
@ -368,6 +375,7 @@ Pad.prototype.init = function init(text, callback) {
_this.appendRevision(firstChangeset, '');
}
hooks.callAll("padLoad", {'pad':_this});
callback(null);
});
};
@ -467,6 +475,7 @@ Pad.prototype.remove = function remove(callback) {
{
db.remove("pad:"+padID);
padManager.unloadPad(padID);
hooks.callAll("padRemove", {'padID':padID});
callback();
}
], function(err)

View file

@ -176,9 +176,11 @@ exports.handleMessage = function(client, message)
// Call handleMessage hook. If a plugin returns null, the message will be dropped. Note that for all messages
// handleMessage will be called, even if the client is not authorized
hooks.aCallAll("handleMessage", { client: client, message: message }, function ( messages ) {
hooks.aCallAll("handleMessage", { client: client, message: message }, function ( err, messages ) {
if(ERR(err, callback)) return;
_.each(messages, function(newMessage){
if ( newmessage === null ) {
if ( newMessage === null ) {
dropMessage = true;
}
});
@ -415,22 +417,34 @@ function handleUserInfoUpdate(client, message)
authorManager.setAuthorName(author, message.data.userInfo.name);
var padId = sessioninfos[client.id].padId;
var infoMsg = {
type: "COLLABROOM",
data: {
// The Client doesn't know about USERINFO_UPDATE, use USER_NEWINFO
type: "USER_NEWINFO",
userInfo: {
userId: author,
name: message.data.userInfo.name,
colorId: message.data.userInfo.colorId,
userAgent: "Anonymous",
ip: "127.0.0.1",
}
}
};
//set a null name, when there is no name set. cause the client wants it null
if(message.data.userInfo.name == null)
if(infoMsg.data.userInfo.name == null)
{
message.data.userInfo.name = null;
infoMsg.data.userInfo.name = null;
}
//The Client don't know about a USERINFO_UPDATE, it can handle only new user_newinfo, so change the message type
message.data.type = "USER_NEWINFO";
//Send the other clients on the pad the update message
for(var i in pad2sessions[padId])
{
if(pad2sessions[padId][i] != client.id)
{
socketio.sockets.sockets[pad2sessions[padId][i]].json.send(message);
socketio.sockets.sockets[pad2sessions[padId][i]].json.send(infoMsg);
}
}
}

View file

@ -37,7 +37,7 @@ exports.ip = "0.0.0.0";
/**
* The Port ep-lite should listen to
*/
exports.port = 9001;
exports.port = process.env.PORT || 9001;
/*
* The Type of the database
*/

View file

@ -48,7 +48,7 @@ CachingMiddleware.prototype = new function () {
var old_res = {};
var supportsGzip =
req.header('Accept-Encoding', '').indexOf('gzip') != -1;
(req.get('Accept-Encoding') || '').indexOf('gzip') != -1;
var path = require('url').parse(req.url).path;
var cacheKey = (new Buffer(path)).toString('base64').replace(/[\/\+=]/g, '');

View file

@ -5,9 +5,10 @@
"keywords" : ["etherpad", "realtime", "collaborative", "editor"],
"author" : "Peter 'Pita' Martischka <petermartischka@googlemail.com> - Primary Technology Ltd",
"contributors" : [
{ "name": "John McLear",
"name": "Hans Pinckaers",
"name": "Robin Buse" }
{ "name": "John McLear" },
{ "name": "Hans Pinckaers" },
{ "name": "Robin Buse" },
{ "name": "Marcel Klehr" }
],
"dependencies" : {
"yajsml" : "1.1.6",
@ -15,7 +16,7 @@
"require-kernel" : "1.0.5",
"resolve" : "0.2.x",
"socket.io" : "0.9.x",
"ueberDB" : "0.1.7",
"ueberDB" : "0.1.8",
"async" : "0.1.22",
"express" : "3.x",
"connect" : "2.4.x",
@ -25,7 +26,7 @@
"log4js" : "0.5.x",
"jsdom-nocontextifiy" : "0.2.10",
"async-stacktrace" : "0.0.2",
"npm" : "1.1.24",
"npm" : "1.1.x",
"ejs" : "0.6.1",
"graceful-fs" : "1.1.5",
"slide" : "1.1.3",
@ -42,5 +43,5 @@
"engines" : { "node" : ">=0.6.0",
"npm" : ">=1.0"
},
"version" : "1.1.2"
"version" : "1.1.4"
}

View file

@ -122,6 +122,11 @@ function Ace2Editor()
return info.ace_getDebugProperty(prop);
};
editor.getInInternationalComposition = function()
{
return info.ace_getInInternationalComposition();
};
// prepareUserChangeset:
// Returns null if no new changes or ACE not ready. Otherwise, bundles up all user changes
// to the latest base text into a Changeset, which is returned (as a string if encodeAsString).

View file

@ -1173,7 +1173,7 @@ function Ace2Inner(){
//if (! top.BEFORE) top.BEFORE = [];
//top.BEFORE.push(magicdom.root.dom.innerHTML);
//if (! isEditable) return; // and don't reschedule
if (window.parent.parent.inInternationalComposition)
if (inInternationalComposition)
{
// don't do idle input incorporation during international input composition
idleWorkTimer.atLeast(500);
@ -3729,7 +3729,7 @@ function Ace2Inner(){
thisKeyDoesntTriggerNormalize = true;
}
if ((!specialHandled) && (!thisKeyDoesntTriggerNormalize) && (!window.parent.parent.inInternationalComposition))
if ((!specialHandled) && (!thisKeyDoesntTriggerNormalize) && (!inInternationalComposition))
{
if (type != "keyup" || !incorpIfQuick())
{
@ -4589,9 +4589,24 @@ function Ace2Inner(){
}
}
var inInternationalComposition = false;
function handleCompositionEvent(evt)
{
window.parent.parent.handleCompositionEvent(evt);
// international input events, fired in FF3, at least; allow e.g. Japanese input
if (evt.type == "compositionstart")
{
inInternationalComposition = true;
}
else if (evt.type == "compositionend")
{
inInternationalComposition = false;
}
}
editorInfo.ace_getInInternationalComposition = function ()
{
return inInternationalComposition;
}
function bindTheEventHandlers()

View file

@ -111,7 +111,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
function handleUserChanges()
{
if (window.parent.parent.inInternationalComposition) return;
if (editor.getInInternationalComposition()) return;
if ((!getSocket()) || channelState == "CONNECTING")
{
if (channelState == "CONNECTING" && (((+new Date()) - initialStartConnectTime) > 20000))
@ -288,7 +288,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
var apool = msg.apool;
// When inInternationalComposition, msg pushed msgQueue.
if (msgQueue.length > 0 || window.parent.parent.inInternationalComposition) {
if (msgQueue.length > 0 || editor.getInInternationalComposition()) {
if (msgQueue.length > 0) oldRev = msgQueue[msgQueue.length - 1].newRev;
else oldRev = rev;
@ -358,6 +358,14 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
{
var userInfo = msg.userInfo;
var id = userInfo.userId;
// Avoid a race condition when setting colors. If our color was set by a
// query param, ignore our own "new user" message's color value.
if (id === initialUserInfo.userId && initialUserInfo.globalUserColor)
{
msg.userInfo.colorId = initialUserInfo.globalUserColor;
}
if (userSet[id])
{

View file

@ -24,6 +24,13 @@
var colorutils = {};
// Check that a given value is a css hex color value, e.g.
// "#ffffff" or "#fff"
colorutils.isCssHex = function(cssColor)
{
return /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.test(cssColor);
}
// "#ffffff" or "#fff" or "ffffff" or "fff" to [1.0, 1.0, 1.0]
colorutils.css2triple = function(cssColor)
{

View file

@ -311,7 +311,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
['insertorder', 'first']
].concat(
_.map(state.lineAttributes,function(value,key){
if (window.console) console.log([key, value])
if (typeof(window)!= 'undefined' && window.console) console.log([key, value])
return [key, value];
})
);

View file

@ -43,6 +43,7 @@ var padmodals = require('./pad_modals').padmodals;
var padsavedrevs = require('./pad_savedrevs');
var paduserlist = require('./pad_userlist').paduserlist;
var padutils = require('./pad_utils').padutils;
var colorutils = require('./colorutils').colorutils;
var createCookie = require('./pad_utils').createCookie;
var readCookie = require('./pad_utils').readCookie;
@ -50,22 +51,6 @@ var randomString = require('./pad_utils').randomString;
var hooks = require('./pluginfw/hooks');
window.inInternationalComposition = false;
var inInternationalComposition = window.inInternationalComposition;
window.handleCompositionEvent = function handleCompositionEvent(evt)
{
// international input events, fired in FF3, at least; allow e.g. Japanese input
if (evt.type == "compositionstart")
{
this.inInternationalComposition = true;
}
else if (evt.type == "compositionend")
{
this.inInternationalComposition = false;
}
}
function createCookie(name, value, days, path)
{
if (days)
@ -114,6 +99,7 @@ function getParams()
var showControls = params["showControls"];
var showChat = params["showChat"];
var userName = params["userName"];
var userColor = params["userColor"];
var showLineNumbers = params["showLineNumbers"];
var useMonospaceFont = params["useMonospaceFont"];
var IsnoColors = params["noColors"];
@ -162,6 +148,11 @@ function getParams()
// If the username is set as a parameter we should set a global value that we can call once we have initiated the pad.
settings.globalUserName = decodeURIComponent(userName);
}
if(userColor)
// If the userColor is set as a parameter, set a global value to use once we have initiated the pad.
{
settings.globalUserColor = decodeURIComponent(userColor);
}
if(rtl)
{
if(rtl == "true")
@ -363,6 +354,14 @@ function handshake()
pad.myUserInfo.name = settings.globalUserName;
$('#myusernameedit').attr({"value":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);
}
}
//This handles every Message after the clientVars
else
@ -1029,6 +1028,7 @@ var settings = {
, noColors: false
, useMonospaceFontGlobal: false
, globalUserName: false
, globalUserColor: false
, rtlIsTrue: false
};

View file

@ -144,13 +144,12 @@ function handleClientVars(message)
require('./pad_impexp').padimpexp.init();
//change export urls when the slider moves
var export_rev_regex = /(\/\d+)?\/export/
BroadcastSlider.onSlider(function(revno)
{
// export_links is a jQuery Array, so .each is allowed.
export_links.each(function()
{
this.setAttribute('href', this.href.replace(export_rev_regex, '/' + revno + '/export'));
this.setAttribute('href', this.href.replace( /(.+?)\/\w+\/(\d+\/)?export/ , '$1/' + padId + '/' + revno + '/export'));
});
});

View file

@ -2,6 +2,29 @@
<html>
<title>Etherpad Lite</title>
<script>
/*
|@licstart The following is the entire license notice for the
JavaScript code in this page.|
Copyright 2011 Peter Martischka, Primary Technology.
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
http://www.apache.org/licenses/LICENSE-2.0
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.
|@licend The above is the entire license notice
for the JavaScript code in this page.|
*/
</script>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">
@ -9,9 +32,11 @@
<link rel="shortcut icon" href="favicon.ico">
<style>
html, body {
height: 100%;
}
body {
margin: 0;
height: 100%;
color: #333;
font: 14px helvetica, sans-serif;
background: #ddd;

View file

@ -3,8 +3,30 @@
%>
<!doctype html>
<html>
<title>Etherpad Lite</title>
<script>
/*
|@licstart The following is the entire license notice for the
JavaScript code in this page.|
Copyright 2011 Peter Martischka, Primary Technology.
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
http://www.apache.org/licenses/LICENSE-2.0
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.
|@licend The above is the entire license notice
for the JavaScript code in this page.|
*/
</script>
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
@ -233,7 +255,7 @@
</div>
<div class="reconnecting">
<h1>Reestablishing connection...</h1>
<p><img alt="" border="0" src="/static/img/connectingbar.gif" /></p>
<p><img alt="" border="0" src="../static/img/connectingbar.gif" /></p>
</div>
<div class="userdup">
<h1>Opened in another window.</h1>

View file

@ -1,11 +1,32 @@
<!doctype html>
<html lang="en">
<title>Etherpad Lite Timeslider</title>
<script>
/*
|@licstart The following is the entire license notice for the
JavaScript code in this page.|
Copyright 2011 Peter Martischka, Primary Technology.
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
http://www.apache.org/licenses/LICENSE-2.0
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.
|@licend The above is the entire license notice
for the JavaScript code in this page.|
*/
</script>
<head>
<meta charset="utf-8">
<meta name="robots" content="noindex, nofollow">
<title>Etherpad Lite Timeslider</title>
<link rel="shortcut icon" href="../../favicon.ico">
<link rel="stylesheet" href="../../static/css/pad.css">
<link rel="stylesheet" href="../../static/css/timeslider.css">
@ -83,7 +104,7 @@
</div>
<div class="reconnecting">
<h1>Reestablishing connection...</h1>
<p><img alt="" border="0" src="/static/img/connectingbar.gif" /></p>
<p><img alt="" border="0" src="../../static/img/connectingbar.gif" /></p>
</div>
<div class="userdup">
<h1>Opened in another window.</h1>

32
src/web.config Normal file
View file

@ -0,0 +1,32 @@
<configuration>
<system.webServer>
<handlers>
<add name="iisnode" path="node_modules/ep_etherpad-lite/node/server.js" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<!-- uncomment this section to enable debugging
<rule name="LogFile" patternSyntax="ECMAScript" stopProcessing="true">
<match url="iisnode"/>
<action type="Rewrite" url="node_modules/ep_etherpad-lite/node/iisnode" />
</rule>
<rule name="NodeInspector" patternSyntax="ECMAScript" stopProcessing="true">
<match url="^server.js\/debug[\/]?" />
</rule>
-->
<rule name="StaticContent">
<action type="Rewrite" url="public{{REQUEST_URI}}"/>
</rule>
<rule name="DynamicContent">
<conditions>
<add input="{{REQUEST_FILENAME}}" matchType="IsFile" negate="True"/>
</conditions>
<action type="Rewrite" url="node_modules/ep_etherpad-lite/node/server.js" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>