mirror of
https://github.com/ether/etherpad-lite.git
synced 2025-01-19 14:13:34 +01:00
Create setting to control if a new line will be indented or not
Currently pressing ENTER on a line that ends with ':', '[', '(' or '{' automaticaly indents the new line with 4 spaces. The variable added by this commit to settings.json allow an Etherpad instance to not have this behavior.
This commit is contained in:
parent
9d29b15def
commit
5deb06d589
5 changed files with 128 additions and 31 deletions
|
@ -131,6 +131,11 @@
|
||||||
// Allow Load Testing tools to hit the Etherpad Instance. Warning this will disable security on the instance.
|
// Allow Load Testing tools to hit the Etherpad Instance. Warning this will disable security on the instance.
|
||||||
"loadTest": false,
|
"loadTest": false,
|
||||||
|
|
||||||
|
// Disable indentation on new line when previous line ends with some special chars (':', '[', '(', '{')
|
||||||
|
/*
|
||||||
|
"indentationOnNewLine": false,
|
||||||
|
*/
|
||||||
|
|
||||||
/* The toolbar buttons configuration.
|
/* The toolbar buttons configuration.
|
||||||
"toolbar": {
|
"toolbar": {
|
||||||
"left": [
|
"left": [
|
||||||
|
|
|
@ -630,8 +630,8 @@ function handleUserChanges(data, cb)
|
||||||
messageLogger.warn("Dropped message, USER_CHANGES Message has no changeset!");
|
messageLogger.warn("Dropped message, USER_CHANGES Message has no changeset!");
|
||||||
return cb();
|
return cb();
|
||||||
}
|
}
|
||||||
//TODO: this might happen with other messages too => find one place to copy the session
|
//TODO: this might happen with other messages too => find one place to copy the session
|
||||||
//and always use the copy. atm a message will be ignored if the session is gone even
|
//and always use the copy. atm a message will be ignored if the session is gone even
|
||||||
//if the session was valid when the message arrived in the first place
|
//if the session was valid when the message arrived in the first place
|
||||||
if(!sessioninfos[client.id])
|
if(!sessioninfos[client.id])
|
||||||
{
|
{
|
||||||
|
@ -960,7 +960,7 @@ function handleSwitchToPad(client, message)
|
||||||
roomClients[i].leave(padId);
|
roomClients[i].leave(padId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// start up the new pad
|
// start up the new pad
|
||||||
createSessionInfo(client, message);
|
createSessionInfo(client, message);
|
||||||
handleClientReady(client, message);
|
handleClientReady(client, message);
|
||||||
|
@ -1231,6 +1231,7 @@ function handleClientReady(client, message)
|
||||||
"plugins": plugins.plugins,
|
"plugins": plugins.plugins,
|
||||||
"parts": plugins.parts,
|
"parts": plugins.parts,
|
||||||
},
|
},
|
||||||
|
"indentationOnNewLine": settings.indentationOnNewLine,
|
||||||
"initialChangesets": [] // FIXME: REMOVE THIS SHIT
|
"initialChangesets": [] // FIXME: REMOVE THIS SHIT
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,11 @@ exports.disableIPlogging = false;
|
||||||
*/
|
*/
|
||||||
exports.loadTest = false;
|
exports.loadTest = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable indentation on new lines
|
||||||
|
*/
|
||||||
|
exports.indentationOnNewLine = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* log4js appender configuration
|
* log4js appender configuration
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1894,7 +1894,11 @@ function Ace2Inner(){
|
||||||
var prevLine = rep.lines.prev(thisLine);
|
var prevLine = rep.lines.prev(thisLine);
|
||||||
var prevLineText = prevLine.text;
|
var prevLineText = prevLine.text;
|
||||||
var theIndent = /^ *(?:)/.exec(prevLineText)[0];
|
var theIndent = /^ *(?:)/.exec(prevLineText)[0];
|
||||||
if (/[\[\(\:\{]\s*$/.exec(prevLineText)) theIndent += THE_TAB;
|
var shouldIndent = parent.parent.clientVars.indentationOnNewLine;
|
||||||
|
if (shouldIndent && /[\[\(\:\{]\s*$/.exec(prevLineText))
|
||||||
|
{
|
||||||
|
theIndent += THE_TAB;
|
||||||
|
}
|
||||||
var cs = Changeset.builder(rep.lines.totalWidth()).keep(
|
var cs = Changeset.builder(rep.lines.totalWidth()).keep(
|
||||||
rep.lines.offsetOfIndex(lineNum), lineNum).insert(
|
rep.lines.offsetOfIndex(lineNum), lineNum).insert(
|
||||||
theIndent, [
|
theIndent, [
|
||||||
|
@ -2336,7 +2340,7 @@ function Ace2Inner(){
|
||||||
|
|
||||||
function getAttributeOnSelection(attributeName){
|
function getAttributeOnSelection(attributeName){
|
||||||
if (!(rep.selStart && rep.selEnd)) return
|
if (!(rep.selStart && rep.selEnd)) return
|
||||||
|
|
||||||
var withIt = Changeset.makeAttribsString('+', [
|
var withIt = Changeset.makeAttribsString('+', [
|
||||||
[attributeName, 'true']
|
[attributeName, 'true']
|
||||||
], rep.apool);
|
], rep.apool);
|
||||||
|
@ -2347,14 +2351,14 @@ function Ace2Inner(){
|
||||||
}
|
}
|
||||||
|
|
||||||
return rangeHasAttrib(rep.selStart, rep.selEnd)
|
return rangeHasAttrib(rep.selStart, rep.selEnd)
|
||||||
|
|
||||||
function rangeHasAttrib(selStart, selEnd) {
|
function rangeHasAttrib(selStart, selEnd) {
|
||||||
// if range is collapsed -> no attribs in range
|
// if range is collapsed -> no attribs in range
|
||||||
if(selStart[1] == selEnd[1] && selStart[0] == selEnd[0]) return false
|
if(selStart[1] == selEnd[1] && selStart[0] == selEnd[0]) return false
|
||||||
|
|
||||||
if(selStart[0] != selEnd[0]) { // -> More than one line selected
|
if(selStart[0] != selEnd[0]) { // -> More than one line selected
|
||||||
var hasAttrib = true
|
var hasAttrib = true
|
||||||
|
|
||||||
// from selStart to the end of the first line
|
// from selStart to the end of the first line
|
||||||
hasAttrib = hasAttrib && rangeHasAttrib(selStart, [selStart[0], rep.lines.atIndex(selStart[0]).text.length])
|
hasAttrib = hasAttrib && rangeHasAttrib(selStart, [selStart[0], rep.lines.atIndex(selStart[0]).text.length])
|
||||||
|
|
||||||
|
@ -2365,22 +2369,22 @@ function Ace2Inner(){
|
||||||
|
|
||||||
// for the last, potentially partial, line
|
// for the last, potentially partial, line
|
||||||
hasAttrib = hasAttrib && rangeHasAttrib([selEnd[0], 0], [selEnd[0], selEnd[1]])
|
hasAttrib = hasAttrib && rangeHasAttrib([selEnd[0], 0], [selEnd[0], selEnd[1]])
|
||||||
|
|
||||||
return hasAttrib
|
return hasAttrib
|
||||||
}
|
}
|
||||||
|
|
||||||
// Logic tells us we now have a range on a single line
|
// Logic tells us we now have a range on a single line
|
||||||
|
|
||||||
var lineNum = selStart[0]
|
var lineNum = selStart[0]
|
||||||
, start = selStart[1]
|
, start = selStart[1]
|
||||||
, end = selEnd[1]
|
, end = selEnd[1]
|
||||||
, hasAttrib = true
|
, hasAttrib = true
|
||||||
|
|
||||||
// Iterate over attribs on this line
|
// Iterate over attribs on this line
|
||||||
|
|
||||||
var opIter = Changeset.opIterator(rep.alines[lineNum])
|
var opIter = Changeset.opIterator(rep.alines[lineNum])
|
||||||
, indexIntoLine = 0
|
, indexIntoLine = 0
|
||||||
|
|
||||||
while (opIter.hasNext()) {
|
while (opIter.hasNext()) {
|
||||||
var op = opIter.next();
|
var op = opIter.next();
|
||||||
var opStartInLine = indexIntoLine;
|
var opStartInLine = indexIntoLine;
|
||||||
|
@ -2394,11 +2398,11 @@ function Ace2Inner(){
|
||||||
}
|
}
|
||||||
indexIntoLine = opEndInLine;
|
indexIntoLine = opEndInLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hasAttrib
|
return hasAttrib
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
editorInfo.ace_getAttributeOnSelection = getAttributeOnSelection;
|
editorInfo.ace_getAttributeOnSelection = getAttributeOnSelection;
|
||||||
|
|
||||||
function toggleAttributeOnSelection(attributeName)
|
function toggleAttributeOnSelection(attributeName)
|
||||||
|
@ -3641,7 +3645,7 @@ function Ace2Inner(){
|
||||||
// Is caret potentially hidden by the chat button?
|
// Is caret potentially hidden by the chat button?
|
||||||
var myselection = document.getSelection(); // get the current caret selection
|
var myselection = document.getSelection(); // get the current caret selection
|
||||||
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
|
||||||
|
|
||||||
if(myselection.focusNode.wholeText){ // Is there any content? If not lineHeight will report wrong..
|
if(myselection.focusNode.wholeText){ // Is there any content? If not lineHeight will report wrong..
|
||||||
var lineHeight = myselection.focusNode.parentNode.offsetHeight; // line height of populated links
|
var lineHeight = myselection.focusNode.parentNode.offsetHeight; // line height of populated links
|
||||||
}else{
|
}else{
|
||||||
|
@ -3713,13 +3717,13 @@ function Ace2Inner(){
|
||||||
// As ubuntu cannot use Alt F10....
|
// As ubuntu cannot use Alt F10....
|
||||||
// Focus on the editbar. -- TODO: Move Focus back to previous state (we know it so we can use it)
|
// Focus on the editbar. -- TODO: Move Focus back to previous state (we know it so we can use it)
|
||||||
var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first();
|
var firstEditbarElement = parent.parent.$('#editbar').children("ul").first().children().first().children().first().children().first();
|
||||||
$(this).blur();
|
$(this).blur();
|
||||||
firstEditbarElement.focus();
|
firstEditbarElement.focus();
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
}
|
}
|
||||||
if ((!specialHandled) && altKey && keyCode == 67 && type === "keydown"){
|
if ((!specialHandled) && altKey && keyCode == 67 && type === "keydown"){
|
||||||
// Alt c focuses on the Chat window
|
// Alt c focuses on the Chat window
|
||||||
$(this).blur();
|
$(this).blur();
|
||||||
parent.parent.chat.show();
|
parent.parent.chat.show();
|
||||||
parent.parent.$("#chatinput").focus();
|
parent.parent.$("#chatinput").focus();
|
||||||
evt.preventDefault();
|
evt.preventDefault();
|
||||||
|
@ -4961,7 +4965,7 @@ function Ace2Inner(){
|
||||||
|
|
||||||
// Disabled: https://github.com/ether/etherpad-lite/issues/2546
|
// Disabled: https://github.com/ether/etherpad-lite/issues/2546
|
||||||
// Will break OL re-numbering: https://github.com/ether/etherpad-lite/pull/2533
|
// Will break OL re-numbering: https://github.com/ether/etherpad-lite/pull/2533
|
||||||
// $(document).on("cut", handleCut);
|
// $(document).on("cut", handleCut);
|
||||||
|
|
||||||
$(root).on("blur", handleBlur);
|
$(root).on("blur", handleBlur);
|
||||||
if (browser.msie)
|
if (browser.msie)
|
||||||
|
@ -4972,7 +4976,7 @@ function Ace2Inner(){
|
||||||
|
|
||||||
// Don't paste on middle click of links
|
// Don't paste on middle click of links
|
||||||
$(root).on("paste", function(e){
|
$(root).on("paste", function(e){
|
||||||
// TODO: this breaks pasting strings into URLS when using
|
// TODO: this breaks pasting strings into URLS when using
|
||||||
// Control C and Control V -- the Event is never available
|
// Control C and Control V -- the Event is never available
|
||||||
// here.. :(
|
// here.. :(
|
||||||
if(e.target.a || e.target.localName === "a"){
|
if(e.target.a || e.target.localName === "a"){
|
||||||
|
|
|
@ -15,7 +15,7 @@ describe("indentation button", function(){
|
||||||
//select this text element
|
//select this text element
|
||||||
$firstTextElement.sendkeys('{selectall}');
|
$firstTextElement.sendkeys('{selectall}');
|
||||||
|
|
||||||
if(inner$(window)[0].bowser.firefox || inner$(window)[0].bowser.modernIE){ // if it's a mozilla or IE
|
if(inner$(window)[0].bowser.firefox || inner$(window)[0].bowser.modernIE){ // if it's a mozilla or IE
|
||||||
var evtType = "keypress";
|
var evtType = "keypress";
|
||||||
}else{
|
}else{
|
||||||
var evtType = "keydown";
|
var evtType = "keydown";
|
||||||
|
@ -31,7 +31,7 @@ describe("indentation button", function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
it("indent text with button", function(done){
|
it("indent text with button", function(done){
|
||||||
var inner$ = helper.padInner$;
|
var inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
var chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $indentButton = chrome$(".buttonicon-indent");
|
var $indentButton = chrome$(".buttonicon-indent");
|
||||||
|
@ -43,7 +43,7 @@ describe("indentation button", function(){
|
||||||
});
|
});
|
||||||
|
|
||||||
it("keeps the indent on enter for the new line", function(done){
|
it("keeps the indent on enter for the new line", function(done){
|
||||||
var inner$ = helper.padInner$;
|
var inner$ = helper.padInner$;
|
||||||
var chrome$ = helper.padChrome$;
|
var chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
var $indentButton = chrome$(".buttonicon-indent");
|
var $indentButton = chrome$(".buttonicon-indent");
|
||||||
|
@ -51,9 +51,9 @@ describe("indentation button", function(){
|
||||||
|
|
||||||
//type a bit, make a line break and type again
|
//type a bit, make a line break and type again
|
||||||
var $firstTextElement = inner$("div span").first();
|
var $firstTextElement = inner$("div span").first();
|
||||||
$firstTextElement.sendkeys('line 1');
|
$firstTextElement.sendkeys('line 1');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
$firstTextElement.sendkeys('line 2');
|
$firstTextElement.sendkeys('line 2');
|
||||||
$firstTextElement.sendkeys('{enter}');
|
$firstTextElement.sendkeys('{enter}');
|
||||||
|
|
||||||
helper.waitFor(function(){
|
helper.waitFor(function(){
|
||||||
|
@ -68,13 +68,83 @@ describe("indentation button", function(){
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("indents text with spaces on enter if previous line ends with ':', '[', '(', or '{'", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
|
//type a bit, make a line break and type again
|
||||||
|
var $firstTextElement = inner$("div").first();
|
||||||
|
$firstTextElement.sendkeys("line with ':'{enter}");
|
||||||
|
$firstTextElement.sendkeys("line with '['{enter}");
|
||||||
|
$firstTextElement.sendkeys("line with '('{enter}");
|
||||||
|
$firstTextElement.sendkeys("line with '{{}'{enter}");
|
||||||
|
|
||||||
|
helper.waitFor(function(){
|
||||||
|
return inner$("div span").first().text().indexOf("line with '{'") === -1;
|
||||||
|
}).done(function(){
|
||||||
|
// we validate bottom to top for easier implementation
|
||||||
|
|
||||||
|
// curly braces
|
||||||
|
var $lineWithCurlyBraces = inner$("div").first().next().next().next();
|
||||||
|
$lineWithCurlyBraces.sendkeys('{{}');
|
||||||
|
pressEnter(); // cannot use sendkeys('{enter}') here, browser does not read the command properly
|
||||||
|
var $lineAfterCurlyBraces = inner$("div").first().next().next().next().next();
|
||||||
|
expect($lineAfterCurlyBraces.text()).to.match(/\s{4}/); // tab === 4 spaces
|
||||||
|
|
||||||
|
// parenthesis
|
||||||
|
var $lineWithParenthesis = inner$("div").first().next().next();
|
||||||
|
$lineWithParenthesis.sendkeys('(');
|
||||||
|
pressEnter();
|
||||||
|
var $lineAfterParenthesis = inner$("div").first().next().next().next();
|
||||||
|
expect($lineAfterParenthesis.text()).to.match(/\s{4}/);
|
||||||
|
|
||||||
|
// bracket
|
||||||
|
var $lineWithBracket = inner$("div").first().next();
|
||||||
|
$lineWithBracket.sendkeys('[');
|
||||||
|
pressEnter();
|
||||||
|
var $lineAfterBracket = inner$("div").first().next().next();
|
||||||
|
expect($lineAfterBracket.text()).to.match(/\s{4}/);
|
||||||
|
|
||||||
|
// colon
|
||||||
|
var $lineWithColon = inner$("div").first();
|
||||||
|
$lineWithColon.sendkeys(':');
|
||||||
|
pressEnter();
|
||||||
|
var $lineAfterColon = inner$("div").first().next();
|
||||||
|
expect($lineAfterColon.text()).to.match(/\s{4}/);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("appends indentation to the indent of previous line if previous line ends with ':', '[', '(', or '{'", function(done){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
var chrome$ = helper.padChrome$;
|
||||||
|
|
||||||
|
//type a bit, make a line break and type again
|
||||||
|
var $firstTextElement = inner$("div").first();
|
||||||
|
$firstTextElement.sendkeys(" line with some indentation and ':'{enter}");
|
||||||
|
$firstTextElement.sendkeys("line 2{enter}");
|
||||||
|
|
||||||
|
helper.waitFor(function(){
|
||||||
|
return inner$("div span").first().text().indexOf("line 2") === -1;
|
||||||
|
}).done(function(){
|
||||||
|
var $lineWithColon = inner$("div").first();
|
||||||
|
$lineWithColon.sendkeys(':');
|
||||||
|
pressEnter();
|
||||||
|
var $lineAfterColon = inner$("div").first().next();
|
||||||
|
expect($lineAfterColon.text()).to.match(/\s{6}/); // previous line indentation + regular tab (4 spaces)
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
it("makes text indented and outdented", function() {
|
it("makes text indented and outdented", function() {
|
||||||
|
|
||||||
//get the inner iframe
|
//get the inner iframe
|
||||||
var $inner = testHelper.$getPadInner();
|
var $inner = testHelper.$getPadInner();
|
||||||
|
|
||||||
//get the first text element out of the inner iframe
|
//get the first text element out of the inner iframe
|
||||||
var firstTextElement = $inner.find("div").first();
|
var firstTextElement = $inner.find("div").first();
|
||||||
|
|
||||||
|
@ -87,7 +157,7 @@ describe("indentation button", function(){
|
||||||
|
|
||||||
//ace creates a new dom element when you press a button, so just get the first text element again
|
//ace creates a new dom element when you press a button, so just get the first text element again
|
||||||
var newFirstTextElement = $inner.find("div").first();
|
var newFirstTextElement = $inner.find("div").first();
|
||||||
|
|
||||||
// is there a list-indent class element now?
|
// is there a list-indent class element now?
|
||||||
var firstChild = newFirstTextElement.children(":first");
|
var firstChild = newFirstTextElement.children(":first");
|
||||||
var isUL = firstChild.is('ul');
|
var isUL = firstChild.is('ul');
|
||||||
|
@ -160,12 +230,12 @@ describe("indentation button", function(){
|
||||||
/* this test creates the below content, both should have double indentation
|
/* this test creates the below content, both should have double indentation
|
||||||
line1
|
line1
|
||||||
line2
|
line2
|
||||||
|
|
||||||
|
|
||||||
firstTextElement.sendkeys('{rightarrow}'); // simulate a keypress of enter
|
firstTextElement.sendkeys('{rightarrow}'); // simulate a keypress of enter
|
||||||
firstTextElement.sendkeys('{enter}'); // simulate a keypress of enter
|
firstTextElement.sendkeys('{enter}'); // simulate a keypress of enter
|
||||||
firstTextElement.sendkeys('line 1'); // simulate writing the first line
|
firstTextElement.sendkeys('line 1'); // simulate writing the first line
|
||||||
firstTextElement.sendkeys('{enter}'); // simulate a keypress of enter
|
firstTextElement.sendkeys('{enter}'); // simulate a keypress of enter
|
||||||
firstTextElement.sendkeys('line 2'); // simulate writing the second line
|
firstTextElement.sendkeys('line 2'); // simulate writing the second line
|
||||||
|
|
||||||
//get the second text element out of the inner iframe
|
//get the second text element out of the inner iframe
|
||||||
|
@ -203,3 +273,15 @@ describe("indentation button", function(){
|
||||||
});*/
|
});*/
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function pressEnter(){
|
||||||
|
var inner$ = helper.padInner$;
|
||||||
|
if(inner$(window)[0].bowser.firefox || inner$(window)[0].bowser.modernIE){ // if it's a mozilla or IE
|
||||||
|
var evtType = "keypress";
|
||||||
|
}else{
|
||||||
|
var evtType = "keydown";
|
||||||
|
}
|
||||||
|
var e = inner$.Event(evtType);
|
||||||
|
e.keyCode = 13; // enter :|
|
||||||
|
inner$("#innerdocbody").trigger(e);
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue