Merge branch 'develop' of github.com:ether/etherpad-lite into develop

This commit is contained in:
John McLear 2014-11-27 02:24:12 +00:00
commit 65fb25d71f
33 changed files with 346 additions and 237 deletions

View file

@ -99,7 +99,7 @@ fi
echo "Clear minfified cache..." echo "Clear minfified cache..."
rm -f var/minified* rm -f var/minified*
echo "ensure custom css/js files are created..." echo "Ensure custom css/js files are created..."
for f in "index" "pad" "timeslider" for f in "index" "pad" "timeslider"
do do

View file

@ -1,9 +0,0 @@
#!/bin/sh
if [ -d "../bin" ]; then
cd "../"
fi
JSHINT=./node_modules/jshint/bin/hint
$JSHINT ./node/

View file

@ -1,79 +0,0 @@
This is the new load testing file: https://bitbucket.org/rbraakman/etherpad-stresstest
BELOW is the original load testing file.
This load tester is extremely useful for testing how many dormant clients can connect to etherpad.
TODO:
Emulate characters being typed into a pad
HOW TO USE (from @mjd75) proper formatting at: https://github.com/ether/etherpad-lite/issues/360
Server 1:
Installed Node.js (etc), EtherPad and MySQL
Server 2:
Installed Xvfb and PhantomJS
I installed Xvfb following (roughly) this guide: http://blog.martin-lyness.com/archives/installing-xvfb-on-ubuntu-9-10-karmic-koala
#sudo apt-get install xvfb
#sudo apt-get install xfonts-100dpi xfonts-75dpi xfonts-scalable xfonts-cyrillic
Launched two instances of Xvfb directly from the terminal:
#Xvfb :0 -ac
#Xvfb :1 -ac
I installed PhantomJS following this guide: http://code.google.com/p/phantomjs/wiki/Installation
#sudo add-apt-repository ppa:jerome-etienne/neoip
#sudo apt-get update
#sudo apt-get install phantomjs
I created a small JavaScript file for PhatomJS to use to control the browser instances:
### BEGIN JAVASCRIPT ###
var page = new WebPage(),
t, address;
if (phantom.args.length === 0) {
console.log('Usage: loader.js <some URL>');
phantom.exit();
} else {
t = Date.now();
address = phantom.args[0];
var page = new WebPage();
page.onResourceRequested = function (request) {
console.log('Request ' + JSON.stringify(request, undefined, 4));
};
page.onResourceReceived = function (response) {
console.log('Receive ' + JSON.stringify(response, undefined, 4));
};
page.open(address);
}
### END JAVASCRIPT ###
And finally a launcher script that uses screen to run 400 instances of PhantomJS with the above script:
### BEGIN SHELL SCRIPT ###
#!/bin/bash
# connect 200 instances to display :0
for i in {1..200}
do
DISPLAY=:0 screen -d -m phantomjs loader.js http://ec2-50-17-168-xx.compute-1.amazonaws.com:9001/p/pad2 && sleep 2
done
# connect 200 instances to display :1
for i in {1..200}
do
DISPLAY=:1 screen -d -m phantomjs loader.js http://ec2-50-17-168-xx.compute-1.amazonaws.com:9001/p/pad2 && sleep 2
done
### END SHELL SCRIPT ###

View file

@ -1,16 +0,0 @@
#!/bin/bash
# connect 500 instances to display :0
for i in {1..500}
do
echo $i
echo "Displaying Some shit"
DISPLAY=:0 screen -d -m /home/phantomjs/bin/phantomjs loader.js http://10.0.0.55:9001/p/pad2 && sleep 2
done
# connect 500 instances to display :1
for i in {1..500}
do
echo $i
DISPLAY=:1 screen -d -m /home/phantomjs/bin/phantomjs loader.js http://10.0.0.55:9001/p/pad2 && sleep 2
done

View file

@ -1,20 +0,0 @@
var page = new WebPage(),
t, address;
if (phantom.args.length === 0) {
console.log('Usage: loader.js <some URL>');
phantom.exit();
} else {
t = Date.now();
address = phantom.args[0];
var page = new WebPage();
page.onResourceRequested = function (request) {
console.log('Request ' + JSON.stringify(request, undefined, 4));
};
page.onResourceReceived = function (response) {
console.log('Receive ' + JSON.stringify(response, undefined, 4));
};
page.open(address);
}

View file

@ -32,7 +32,7 @@ fi
bin/installDeps.sh $* || exit 1 bin/installDeps.sh $* || exit 1
#Move to the node folder and start #Move to the node folder and start
echo "start..." echo "Started Etherpad..."
SCRIPTPATH=`pwd -P` SCRIPTPATH=`pwd -P`
node $SCRIPTPATH/node_modules/ep_etherpad-lite/node/server.js $* node $SCRIPTPATH/node_modules/ep_etherpad-lite/node/server.js $*

View file

@ -234,7 +234,19 @@ exports.doImport = function(req, res, padId)
ERR(err); ERR(err);
//close the connection //close the connection
res.send("<head><script type='text/javascript' src='../../static/js/jquery.js'></script><script type='text/javascript' src='../../static/js/jquery_browser.js'></script></head><script>$(window).load(function(){if ( (!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf(\"1.8.\") == 0)) ){document.domain = document.domain;}var impexp = window.parent.padimpexp.handleFrameCall('" + status + "');})</script>", 200); res.send(
"<head> \
<script type='text/javascript' src='../../static/js/jquery.js'></script> \
</head> \
<script> \
$(window).load(function(){ \
if(navigator.userAgent.indexOf('MSIE') === -1){ \
document.domain = document.domain; \
} \
var impexp = window.parent.padimpexp.handleFrameCall('" + status + "'); \
}) \
</script>"
, 200);
}); });
} }

View file

@ -94,8 +94,18 @@ exports.handleConnect = function(client)
*/ */
exports.kickSessionsFromPad = function(padID) exports.kickSessionsFromPad = function(padID)
{ {
if(typeof socketio.sockets['clients'] !== 'function')
return;
//skip if there is nobody on this pad //skip if there is nobody on this pad
if(socketio.sockets.clients(padID).length == 0) var roomClients = [], room = socketio.sockets.adapter.rooms[padID];
if (room) {
for (var id in room) {
roomClients.push(socketio.sockets.adapter.nsp.connected[id]);
}
}
if(roomClients.length == 0)
return; return;
//disconnect everyone from this pad //disconnect everyone from this pad
@ -496,14 +506,19 @@ function handleSuggestUserName(client, message)
return; return;
} }
var padId = sessioninfos[client.id].padId, var padId = sessioninfos[client.id].padId;
clients = socketio.sockets.clients(padId); var roomClients = [], room = socketio.sockets.adapter.rooms[padId];
if (room) {
for (var id in room) {
roomClients.push(socketio.sockets.adapter.nsp.connected[id]);
}
}
//search the author and send him this message //search the author and send him this message
for(var i = 0; i < clients.length; i++) { for(var i = 0; i < roomClients.length; i++) {
var session = sessioninfos[clients[i].id]; var session = sessioninfos[roomClients[i].id];
if(session && session.author == message.data.payload.unnamedId) { if(session && session.author == message.data.payload.unnamedId) {
clients[i].json.send(message); roomClients[i].json.send(message);
break; break;
} }
} }
@ -1581,8 +1596,16 @@ function composePadChangesets(padId, startNum, endNum, callback)
* Get the number of users in a pad * Get the number of users in a pad
*/ */
exports.padUsersCount = function (padID, callback) { exports.padUsersCount = function (padID, callback) {
var roomClients = [], room = socketio.sockets.adapter.rooms[padID];
if (room) {
for (var id in room) {
roomClients.push(socketio.sockets.adapter.nsp.connected[id]);
}
}
callback(null, { callback(null, {
padUsersCount: socketio.sockets.clients(padID).length padUsersCount: roomClients.length
}); });
} }
@ -1592,7 +1615,14 @@ exports.padUsersCount = function (padID, callback) {
exports.padUsers = function (padID, callback) { exports.padUsers = function (padID, callback) {
var result = []; var result = [];
async.forEach(socketio.sockets.clients(padID), function(roomClient, callback) { var roomClients = [], room = socketio.sockets.adapter.rooms[padID];
if (room) {
for (var id in room) {
roomClients.push(socketio.sockets.adapter.nsp.connected[id]);
}
}
async.forEach(roomClients, function(roomClient, callback) {
var s = sessioninfos[roomClient.id]; var s = sessioninfos[roomClient.id];
if(s) { if(s) {
authorManager.getAuthor(s.author, function(err, author) { authorManager.getAuthor(s.author, function(err, author) {

View file

@ -14,7 +14,6 @@ exports.expressCreateServer = function (hook_name, args, cb) {
search_results: {}, search_results: {},
errors: [], errors: [],
}; };
res.send( eejs.require("ep_etherpad-lite/templates/admin/plugins.html", render_args) ); res.send( eejs.require("ep_etherpad-lite/templates/admin/plugins.html", render_args) );
}); });
args.app.get('/admin/plugins/info', function(req, res) { args.app.get('/admin/plugins/info', function(req, res) {
@ -25,7 +24,8 @@ exports.expressCreateServer = function (hook_name, args, cb) {
exports.socketio = function (hook_name, args, cb) { exports.socketio = function (hook_name, args, cb) {
var io = args.io.of("/pluginfw/installer"); var io = args.io.of("/pluginfw/installer");
io.on('connection', function (socket) { io.on('connection', function (socket) {
if (!socket.handshake.session.user || !socket.handshake.session.user.is_admin) return;
if (!socket.conn.request.session || !socket.conn.request.session.user || !socket.conn.request.session.user.is_admin) return;
socket.on("getInstalled", function (query) { socket.on("getInstalled", function (query) {
// send currently installed plugins // send currently installed plugins

View file

@ -22,7 +22,8 @@ exports.expressCreateServer = function (hook_name, args, cb) {
exports.socketio = function (hook_name, args, cb) { exports.socketio = function (hook_name, args, cb) {
var io = args.io.of("/settings"); var io = args.io.of("/settings");
io.on('connection', function (socket) { io.on('connection', function (socket) {
if (!socket.handshake.session.user || !socket.handshake.session.user.is_admin) return;
if (!socket.conn.request.session || !socket.conn.request.session.user || !socket.conn.request.session.user.is_admin) return;
socket.on("load", function (query) { socket.on("load", function (query) {
fs.readFile('settings.json', 'utf8', function (err,data) { fs.readFile('settings.json', 'utf8', function (err,data) {

View file

@ -1,24 +1,22 @@
var log4js = require('log4js'); var log4js = require('log4js');
var settings = require('../../utils/Settings'); var settings = require('../../utils/Settings');
var socketio = require('socket.io');
var socketIORouter = require("../../handler/SocketIORouter"); var socketIORouter = require("../../handler/SocketIORouter");
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks"); var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
var webaccess = require("ep_etherpad-lite/node/hooks/express/webaccess"); var webaccess = require("ep_etherpad-lite/node/hooks/express/webaccess");
// there shouldn't be a browser that isn't compatible to all
// transports in this list at once
// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
var socketio = require('socket.io')({
transports: settings.socketTransportProtocols
});
var padMessageHandler = require("../../handler/PadMessageHandler"); var padMessageHandler = require("../../handler/PadMessageHandler");
var connect = require('connect'); var connect = require('connect');
exports.expressCreateServer = function (hook_name, args, cb) { exports.expressCreateServer = function (hook_name, args, cb) {
//init socket.io and redirect all requests to the MessageHandler //init socket.io and redirect all requests to the MessageHandler
var io = socketio.listen(args.server); // there shouldn't be a browser that isn't compatible to all
// transports in this list at once
// e.g. XHR is disabled in IE by default, so in IE it should use jsonp-polling
var io = socketio({
transports: settings.socketTransportProtocols
}).listen(args.server);
/* Require an express session cookie to be present, and load the /* Require an express session cookie to be present, and load the
* session. See http://www.danielbaulig.de/socket-ioexpress for more * session. See http://www.danielbaulig.de/socket-ioexpress for more

View file

@ -14,23 +14,22 @@
* limitations under the License. * limitations under the License.
*/ */
var jsdom = require('jsdom-nocontextifiy').jsdom;
var log4js = require('log4js'); var log4js = require('log4js');
var Changeset = require("ep_etherpad-lite/static/js/Changeset"); var Changeset = require("ep_etherpad-lite/static/js/Changeset");
var contentcollector = require("ep_etherpad-lite/static/js/contentcollector"); var contentcollector = require("ep_etherpad-lite/static/js/contentcollector");
var cheerio = require("cheerio");
function setPadHTML(pad, html, callback) function setPadHTML(pad, html, callback)
{ {
var apiLogger = log4js.getLogger("ImportHtml"); var apiLogger = log4js.getLogger("ImportHtml");
// Parse the incoming HTML with jsdom var $ = cheerio.load(html);
try{
var doc = jsdom(html.replace(/>\n+</g, '><'));
}catch(e){
apiLogger.warn("Error importing, possibly caused by malformed HTML");
var doc = jsdom("<html><body><div>Error during import, possibly malformed HTML</div></body></html>");
}
// Appends a line break, used by Etherpad to ensure a caret is available
// below the last line of an import
$('body').append("<p></p>");
var doc = $('html')[0];
apiLogger.debug('html:'); apiLogger.debug('html:');
apiLogger.debug(html); apiLogger.debug(html);
@ -38,7 +37,7 @@ function setPadHTML(pad, html, callback)
// using the content collector object // using the content collector object
var cc = contentcollector.makeContentCollector(true, null, pad.pool); var cc = contentcollector.makeContentCollector(true, null, pad.pool);
try{ // we use a try here because if the HTML is bad it will blow up try{ // we use a try here because if the HTML is bad it will blow up
cc.collectContent(doc.childNodes[0]); cc.collectContent(doc);
}catch(e){ }catch(e){
apiLogger.warn("HTML was not properly formed", e); apiLogger.warn("HTML was not properly formed", e);
return; // We don't process the HTML because it was bad.. return; // We don't process the HTML because it was bad..

View file

@ -2,6 +2,7 @@
"pad.js": [ "pad.js": [
"pad.js" "pad.js"
, "pad_utils.js" , "pad_utils.js"
, "browser.js"
, "pad_cookie.js" , "pad_cookie.js"
, "pad_editor.js" , "pad_editor.js"
, "pad_editbar.js" , "pad_editbar.js"
@ -24,6 +25,7 @@
, "colorutils.js" , "colorutils.js"
, "draggable.js" , "draggable.js"
, "pad_utils.js" , "pad_utils.js"
, "browser.js"
, "pad_cookie.js" , "pad_cookie.js"
, "pad_editor.js" , "pad_editor.js"
, "pad_editbar.js" , "pad_editbar.js"
@ -42,6 +44,7 @@
] ]
, "ace2_inner.js": [ , "ace2_inner.js": [
"ace2_inner.js" "ace2_inner.js"
, "browser.js"
, "AttributePool.js" , "AttributePool.js"
, "Changeset.js" , "Changeset.js"
, "ChangesetUtils.js" , "ChangesetUtils.js"
@ -58,6 +61,7 @@
] ]
, "ace2_common.js": [ , "ace2_common.js": [
"ace2_common.js" "ace2_common.js"
, "browser.js"
, "jquery.js" , "jquery.js"
, "rjquery.js" , "rjquery.js"
, "$async.js" , "$async.js"

View file

@ -25,7 +25,7 @@
"formidable" : "1.0.9", "formidable" : "1.0.9",
"log4js" : "0.6.6", "log4js" : "0.6.6",
"nodemailer" : "0.3.x", "nodemailer" : "0.3.x",
"jsdom-nocontextifiy" : "0.2.10", "cheerio" : "0.18.0",
"async-stacktrace" : "0.0.2", "async-stacktrace" : "0.0.2",
"npm" : "1.4.x", "npm" : "1.4.x",
"ejs" : "0.6.1", "ejs" : "0.6.1",

View file

@ -698,9 +698,6 @@ table#otheruserstable {
margin-top: 12px; margin-top: 12px;
padding:2px 4px 2px 4px; padding:2px 4px 2px 4px;
} }
#importstatusball {
height: 50px
}
#chatthrob { #chatthrob {
display: none; display: none;
position: absolute; position: absolute;

View file

@ -28,7 +28,6 @@ $ = jQuery = require('./rjquery').$;
_ = require("./underscore"); _ = require("./underscore");
var isNodeText = Ace2Common.isNodeText, var isNodeText = Ace2Common.isNodeText,
browser = $.browser,
getAssoc = Ace2Common.getAssoc, getAssoc = Ace2Common.getAssoc,
setAssoc = Ace2Common.setAssoc, setAssoc = Ace2Common.setAssoc,
isTextNode = Ace2Common.isTextNode, isTextNode = Ace2Common.isTextNode,
@ -52,6 +51,7 @@ function Ace2Inner(){
var SkipList = require('./skiplist'); var SkipList = require('./skiplist');
var undoModule = require('./undomodule').undoModule; var undoModule = require('./undomodule').undoModule;
var AttributeManager = require('./AttributeManager'); var AttributeManager = require('./AttributeManager');
var browser = require('./browser');
var DEBUG = false; //$$ build script replaces the string "var DEBUG=true;//$$" with "var DEBUG=false;" var DEBUG = false; //$$ build script replaces the string "var DEBUG=true;//$$" with "var DEBUG=false;"
// changed to false // changed to false
@ -3700,7 +3700,7 @@ function Ace2Inner(){
}, 0); }, 0);
specialHandled = true; specialHandled = true;
} }
if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "s" && (evt.metaKey || evt.ctrlKey)) /* Do a saved revision on ctrl S */ if ((!specialHandled) && isTypeForCmdKey && String.fromCharCode(which).toLowerCase() == "s" && (evt.metaKey || evt.ctrlKey) && !evt.altKey) /* Do a saved revision on ctrl S */
{ {
evt.preventDefault(); evt.preventDefault();
var originalBackground = parent.parent.$('#revisionlink').css("background") var originalBackground = parent.parent.$('#revisionlink').css("background")
@ -3857,7 +3857,7 @@ function Ace2Inner(){
/* Attempt to apply some sanity to cursor handling in Chrome after a copy / paste event /* Attempt to apply some sanity to cursor handling in Chrome after a copy / paste event
We have to do this the way we do because rep. doesn't hold the value for keyheld events IE if the user We have to do this the way we do because rep. doesn't hold the value for keyheld events IE if the user
presses and holds the arrow key .. Sorry if this is ugly, blame Chrome's weird handling of viewports after new content is added*/ presses and holds the arrow key .. Sorry if this is ugly, blame Chrome's weird handling of viewports after new content is added*/
if((evt.which == 37 || evt.which == 38 || evt.which == 39 || evt.which == 40) && $.browser.chrome){ if((evt.which == 37 || evt.which == 38 || evt.which == 39 || evt.which == 40) && browser.chrome){
var viewport = getViewPortTopBottom(); var viewport = getViewPortTopBottom();
var myselection = document.getSelection(); // get the current caret selection, can't use rep. here because that only gives us the start position not the current var myselection = document.getSelection(); // get the current caret selection, can't use rep. here because that only gives us the start position not the current
var caretOffsetTop = myselection.focusNode.parentNode.offsetTop || myselection.focusNode.offsetTop; // get the carets selection offset in px IE 214 var caretOffsetTop = myselection.focusNode.parentNode.offsetTop || myselection.focusNode.offsetTop; // get the carets selection offset in px IE 214

View file

@ -10,7 +10,8 @@ $(document).ready(function () {
resource = baseURL.substring(1) + "socket.io"; resource = baseURL.substring(1) + "socket.io";
//connect //connect
socket = io.connect(url, {resource : resource}).of("/pluginfw/installer"); var room = url + "pluginfw/installer";
socket = io.connect(room, {resource : resource});
function search(searchTerm, limit) { function search(searchTerm, limit) {
if(search.searchTerm != searchTerm) { if(search.searchTerm != searchTerm) {

View file

@ -9,7 +9,8 @@ $(document).ready(function () {
resource = baseURL.substring(1) + "socket.io"; resource = baseURL.substring(1) + "socket.io";
//connect //connect
socket = io.connect(url, {resource : resource}).of("/settings"); var room = url + "settings";
socket = io.connect(room, {resource : resource});
socket.on('settings', function (settings) { socket.on('settings', function (settings) {

View file

@ -66,7 +66,7 @@ function loadBroadcastJS(socket, sendSocketMsg, fireWhenAllScriptsAreLoaded, Bro
} }
// for IE // for IE
if ($.browser.msie) if (browser.msie)
{ {
try try
{ {

240
src/static/js/browser.js Normal file
View file

@ -0,0 +1,240 @@
/*!
* Bowser - a browser detector
* https://github.com/ded/bowser
* MIT License | (c) Dustin Diaz 2014
*/
!function (name, definition) {
if (typeof module != 'undefined' && module.exports) module.exports['browser'] = definition()
else if (typeof define == 'function' && define.amd) define(definition)
else this[name] = definition()
}('bowser', function () {
/**
* See useragents.js for examples of navigator.userAgent
*/
var t = true
function detect(ua) {
function getFirstMatch(regex) {
var match = ua.match(regex);
return (match && match.length > 1 && match[1]) || '';
}
var iosdevice = getFirstMatch(/(ipod|iphone|ipad)/i).toLowerCase()
, likeAndroid = /like android/i.test(ua)
, android = !likeAndroid && /android/i.test(ua)
, versionIdentifier = getFirstMatch(/version\/(\d+(\.\d+)?)/i)
, tablet = /tablet/i.test(ua)
, mobile = !tablet && /[^-]mobi/i.test(ua)
, result
if (/opera|opr/i.test(ua)) {
result = {
name: 'Opera'
, opera: t
, version: versionIdentifier || getFirstMatch(/(?:opera|opr)[\s\/](\d+(\.\d+)?)/i)
}
}
else if (/windows phone/i.test(ua)) {
result = {
name: 'Windows Phone'
, windowsphone: t
, msie: t
, version: getFirstMatch(/iemobile\/(\d+(\.\d+)?)/i)
}
}
else if (/msie|trident/i.test(ua)) {
result = {
name: 'Internet Explorer'
, msie: t
, version: getFirstMatch(/(?:msie |rv:)(\d+(\.\d+)?)/i)
}
}
else if (/chrome|crios|crmo/i.test(ua)) {
result = {
name: 'Chrome'
, chrome: t
, version: getFirstMatch(/(?:chrome|crios|crmo)\/(\d+(\.\d+)?)/i)
}
}
else if (iosdevice) {
result = {
name : iosdevice == 'iphone' ? 'iPhone' : iosdevice == 'ipad' ? 'iPad' : 'iPod'
}
// WTF: version is not part of user agent in web apps
if (versionIdentifier) {
result.version = versionIdentifier
}
}
else if (/sailfish/i.test(ua)) {
result = {
name: 'Sailfish'
, sailfish: t
, version: getFirstMatch(/sailfish\s?browser\/(\d+(\.\d+)?)/i)
}
}
else if (/seamonkey\//i.test(ua)) {
result = {
name: 'SeaMonkey'
, seamonkey: t
, version: getFirstMatch(/seamonkey\/(\d+(\.\d+)?)/i)
}
}
else if (/firefox|iceweasel/i.test(ua)) {
result = {
name: 'Firefox'
, firefox: t
, version: getFirstMatch(/(?:firefox|iceweasel)[ \/](\d+(\.\d+)?)/i)
}
if (/\((mobile|tablet);[^\)]*rv:[\d\.]+\)/i.test(ua)) {
result.firefoxos = t
}
}
else if (/silk/i.test(ua)) {
result = {
name: 'Amazon Silk'
, silk: t
, version : getFirstMatch(/silk\/(\d+(\.\d+)?)/i)
}
}
else if (android) {
result = {
name: 'Android'
, version: versionIdentifier
}
}
else if (/phantom/i.test(ua)) {
result = {
name: 'PhantomJS'
, phantom: t
, version: getFirstMatch(/phantomjs\/(\d+(\.\d+)?)/i)
}
}
else if (/blackberry|\bbb\d+/i.test(ua) || /rim\stablet/i.test(ua)) {
result = {
name: 'BlackBerry'
, blackberry: t
, version: versionIdentifier || getFirstMatch(/blackberry[\d]+\/(\d+(\.\d+)?)/i)
}
}
else if (/(web|hpw)os/i.test(ua)) {
result = {
name: 'WebOS'
, webos: t
, version: versionIdentifier || getFirstMatch(/w(?:eb)?osbrowser\/(\d+(\.\d+)?)/i)
};
/touchpad\//i.test(ua) && (result.touchpad = t)
}
else if (/bada/i.test(ua)) {
result = {
name: 'Bada'
, bada: t
, version: getFirstMatch(/dolfin\/(\d+(\.\d+)?)/i)
};
}
else if (/tizen/i.test(ua)) {
result = {
name: 'Tizen'
, tizen: t
, version: getFirstMatch(/(?:tizen\s?)?browser\/(\d+(\.\d+)?)/i) || versionIdentifier
};
}
else if (/safari/i.test(ua)) {
result = {
name: 'Safari'
, safari: t
, version: versionIdentifier
}
}
else result = {}
// set webkit or gecko flag for browsers based on these engines
if (/(apple)?webkit/i.test(ua)) {
result.name = result.name || "Webkit"
result.webkit = t
if (!result.version && versionIdentifier) {
result.version = versionIdentifier
}
} else if (!result.opera && /gecko\//i.test(ua)) {
result.name = result.name || "Gecko"
result.gecko = t
result.version = result.version || getFirstMatch(/gecko\/(\d+(\.\d+)?)/i)
}
// set OS flags for platforms that have multiple browsers
if (android || result.silk) {
result.android = t
} else if (iosdevice) {
result[iosdevice] = t
result.ios = t
}
// OS version extraction
var osVersion = '';
if (iosdevice) {
osVersion = getFirstMatch(/os (\d+([_\s]\d+)*) like mac os x/i);
osVersion = osVersion.replace(/[_\s]/g, '.');
} else if (android) {
osVersion = getFirstMatch(/android[ \/-](\d+(\.\d+)*)/i);
} else if (result.windowsphone) {
osVersion = getFirstMatch(/windows phone (?:os)?\s?(\d+(\.\d+)*)/i);
} else if (result.webos) {
osVersion = getFirstMatch(/(?:web|hpw)os\/(\d+(\.\d+)*)/i);
} else if (result.blackberry) {
osVersion = getFirstMatch(/rim\stablet\sos\s(\d+(\.\d+)*)/i);
} else if (result.bada) {
osVersion = getFirstMatch(/bada\/(\d+(\.\d+)*)/i);
} else if (result.tizen) {
osVersion = getFirstMatch(/tizen[\/\s](\d+(\.\d+)*)/i);
}
if (osVersion) {
result.osversion = osVersion;
}
// device type extraction
var osMajorVersion = osVersion.split('.')[0];
if (tablet || iosdevice == 'ipad' || (android && (osMajorVersion == 3 || (osMajorVersion == 4 && !mobile))) || result.silk) {
result.tablet = t
} else if (mobile || iosdevice == 'iphone' || iosdevice == 'ipod' || android || result.blackberry || result.webos || result.bada) {
result.mobile = t
}
// Graded Browser Support
// http://developer.yahoo.com/yui/articles/gbs
if ((result.msie && result.version >= 10) ||
(result.chrome && result.version >= 20) ||
(result.firefox && result.version >= 20.0) ||
(result.safari && result.version >= 6) ||
(result.opera && result.version >= 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] >= 6) ||
(result.blackberry && result.version >= 10.1)
) {
result.a = t;
}
else if ((result.msie && result.version < 10) ||
(result.chrome && result.version < 20) ||
(result.firefox && result.version < 20.0) ||
(result.safari && result.version < 6) ||
(result.opera && result.version < 10.0) ||
(result.ios && result.osversion && result.osversion.split(".")[0] < 6)
) {
result.c = t
} else result.x = t
return result
}
var bowser = detect(typeof navigator !== 'undefined' ? navigator.userAgent : '')
/*
* Set our detect method to the main bowser object so we can
* reuse it to test other user agents.
* This is needed to implement future tests.
*/
bowser._detect = detect;
return bowser
});

View file

@ -82,7 +82,7 @@ function getCollabClient(ace2editor, serverVars, initialUserInfo, options, _pad)
{} {}
}; };
if ($.browser.mozilla) if (browser.mozilla)
{ {
// Prevent "escape" from taking effect and canceling a comet connection; // Prevent "escape" from taking effect and canceling a comet connection;
// doesn't work if focus is on an iframe. // doesn't work if focus is on an iframe.

View file

@ -54,10 +54,14 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
}, },
nodeNumChildren: function(n) nodeNumChildren: function(n)
{ {
if(n.childNodes == null) return 0;
return n.childNodes.length; return n.childNodes.length;
}, },
nodeChild: function(n, i) nodeChild: function(n, i)
{ {
if(n.childNodes.item == null){
return n.childNodes[i];
}
return n.childNodes.item(i); return n.childNodes.item(i);
}, },
nodeProp: function(n, p) nodeProp: function(n, p)
@ -66,6 +70,7 @@ function makeContentCollector(collectStyles, browser, apool, domInterface, class
}, },
nodeAttr: function(n, a) nodeAttr: function(n, a)
{ {
if(n.getAttribute == null) return null;
return n.getAttribute(a); return n.getAttribute(a);
}, },
optNodeInnerHTML: function(n) optNodeInnerHTML: function(n)

View file

@ -170,7 +170,7 @@ $._farbtastic = function (container, options) {
// New color // New color
color2 = fb.pack(fb.HSLToRGB([d2, 1, 0.5])); color2 = fb.pack(fb.HSLToRGB([d2, 1, 0.5]));
if (i > 0) { if (i > 0) {
if ($.browser.msie) { if (browser.msie) {
// IE's gradient calculations mess up the colors. Correct along the diagonals. // IE's gradient calculations mess up the colors. Correct along the diagonals.
var corr = (1 + Math.min(Math.abs(Math.tan(angle1)), Math.abs(Math.tan(Math.PI / 2 - angle1)))) / n; var corr = (1 + Math.min(Math.abs(Math.tan(angle1)), Math.abs(Math.tan(Math.PI / 2 - angle1)))) / n;
color1 = fb.pack(fb.HSLToRGB([d1 - 0.15 * corr, 1, 0.5])); color1 = fb.pack(fb.HSLToRGB([d1 - 0.15 * corr, 1, 0.5]));
@ -254,7 +254,7 @@ $._farbtastic = function (container, options) {
fb.ctxMask.drawImage(buffer, 0, 0, sz + 1, sz + 1, -sq, -sq, sq * 2, sq * 2); fb.ctxMask.drawImage(buffer, 0, 0, sz + 1, sz + 1, -sq, -sq, sq * 2, sq * 2);
} }
// Method #2: drawing commands (old Canvas). // Method #2: drawing commands (old Canvas).
else if (!$.browser.msie) { else if (!browser.msie) {
// Render directly at half-resolution // Render directly at half-resolution
var sz = Math.floor(size / 2); var sz = Math.floor(size / 2);
calculateMask(sz, sz, function (x, y, c, a) { calculateMask(sz, sz, function (x, y, c, a) {

View file

@ -1,50 +0,0 @@
/*
Copied from jQuery 1.8, the last jquery version with browser recognition support
*/
(function(){
// Use of jQuery.browser is frowned upon.
// More details: http://api.jquery.com/jQuery.browser
// jQuery.uaMatch maintained for back-compat
var uaMatch = function( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
var userAgent = navigator.userAgent;
var matched = uaMatch(userAgent);
var browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
// Chrome is Webkit, but Webkit is also Safari.
if ( browser.chrome ) {
browser.webkit = true;
} else if ( browser.webkit ) {
browser.safari = true;
}
//custom extensions, the original jquery didn't have these
browser.windows = /windows/i.test(userAgent);
browser.mobile = /mobile/i.test(userAgent) || /android/i.test(userAgent);
if(typeof exports !== 'undefined'){
exports.browser = browser;
} else{
$.browser = browser;
}
})();

View file

@ -43,7 +43,6 @@ var padsavedrevs = require('./pad_savedrevs');
var paduserlist = require('./pad_userlist').paduserlist; var paduserlist = require('./pad_userlist').paduserlist;
var padutils = require('./pad_utils').padutils; var padutils = require('./pad_utils').padutils;
var colorutils = require('./colorutils').colorutils; var colorutils = require('./colorutils').colorutils;
var createCookie = require('./pad_utils').createCookie; var createCookie = require('./pad_utils').createCookie;
var readCookie = require('./pad_utils').readCookie; var readCookie = require('./pad_utils').readCookie;
var randomString = require('./pad_utils').randomString; var randomString = require('./pad_utils').randomString;
@ -453,13 +452,13 @@ var pad = {
pad.initTime = +(new Date()); pad.initTime = +(new Date());
pad.padOptions = clientVars.initialOptions; pad.padOptions = clientVars.initialOptions;
if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) if ((!browser.msie) && (!(browser.mozilla && browser.version.indexOf("1.8.") == 0)))
{ {
document.domain = document.domain; // for comet document.domain = document.domain; // for comet
} }
// for IE // for IE
if ($.browser.msie) if (browser.msie)
{ {
try try
{ {

View file

@ -730,7 +730,7 @@ var paduserlist = (function()
$("#myswatch").css({'background-color': myUserInfo.colorId}); $("#myswatch").css({'background-color': myUserInfo.colorId});
if ($.browser.msie && parseInt($.browser.version) <= 8) { if (browser.msie && parseInt(browser.version) <= 8) {
$("li[data-key=showusers] > a").css({'box-shadow': 'inset 0 0 30px ' + myUserInfo.colorId,'background-color': myUserInfo.colorId}); $("li[data-key=showusers] > a").css({'box-shadow': 'inset 0 0 30px ' + myUserInfo.colorId,'background-color': myUserInfo.colorId});
} }
else else

View file

@ -1,10 +1,5 @@
// Proviedes a require'able version of jQuery without leaking $ and jQuery; // Proviedes a require'able version of jQuery without leaking $ and jQuery;
require('./jquery'); require('./jquery');
var jq = window.$.noConflict(true); var jq = window.$.noConflict(true);
//added the old browser recognition
jq.browser = require('./jquery_browser').browser;
exports.jQuery = exports.$ = jq; exports.jQuery = exports.$ = jq;

View file

@ -10,7 +10,7 @@
<body> <body>
<div id="wrapper"> <div id="wrapper">
<div class="menu"> <div class="menu">
<h1><a href="../../">Etherpad</a></h1> <h1><a href="../">Etherpad</a></h1>
<ul> <ul>
<% e.begin_block("adminMenu"); %> <% e.begin_block("adminMenu"); %>
<li><a href="plugins">Plugin manager</a> </li> <li><a href="plugins">Plugin manager</a> </li>

View file

@ -11,7 +11,7 @@
<body> <body>
<div id="wrapper"> <div id="wrapper">
<div class="menu"> <div class="menu">
<h1><a href="../../../">Etherpad</a></h1> <h1><a href="../../">Etherpad</a></h1>
<ul> <ul>
<% e.begin_block("adminMenu"); %> <% e.begin_block("adminMenu"); %>
<li><a href="../plugins">Plugin manager</a> </li> <li><a href="../plugins">Plugin manager</a> </li>

View file

@ -20,7 +20,7 @@
<% } %> <% } %>
<div class="menu"> <div class="menu">
<h1><a href="../../">Etherpad</a></h1> <h1><a href="../">Etherpad</a></h1>
<ul> <ul>
<% e.begin_block("adminMenu"); %> <% e.begin_block("adminMenu"); %>
<li><a href="plugins">Plugin manager</a> </li> <li><a href="plugins">Plugin manager</a> </li>

View file

@ -24,7 +24,7 @@
<div class="menu"> <div class="menu">
<h1><a href="../../">Etherpad</a></h1> <h1><a href="../">Etherpad</a></h1>
<ul> <ul>
<% e.begin_block("adminMenu"); %> <% e.begin_block("adminMenu"); %>
<li><a href="plugins">Plugin manager</a> </li> <li><a href="plugins">Plugin manager</a> </li>

View file

@ -367,8 +367,8 @@
require.setGlobalKeyPath("require"); require.setGlobalKeyPath("require");
$ = jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery; // Expose jQuery #HACK $ = jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery; // Expose jQuery #HACK
browser = require('ep_etherpad-lite/static/js/browser').browser;
if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) { if ((!browser.msie) && (!(browser.mozilla && browser.version.indexOf("1.8.") == 0))) {
document.domain = document.domain; // for comet document.domain = document.domain; // for comet
} }

View file

@ -215,8 +215,9 @@
require.setGlobalKeyPath("require"); require.setGlobalKeyPath("require");
$ = jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery; // Expose jQuery #HACK $ = jQuery = require('ep_etherpad-lite/static/js/rjquery').jQuery; // Expose jQuery #HACK
browser = require('ep_etherpad-lite/static/js/browser').browser;
if ((!$.browser.msie) && (!($.browser.mozilla && $.browser.version.indexOf("1.8.") == 0))) { if ((!browser.msie) && (!(browser.mozilla && browser.version.indexOf("1.8.") == 0))) {
document.domain = document.domain; // for comet document.domain = document.domain; // for comet
} }