Select formatting button on selection (#3301)
[feat] Select button when selection is on formatted textpull/3309/merge
parent
f1fcd16894
commit
454f539561
|
@ -400,7 +400,19 @@ AttributeManager.prototype = _(AttributeManager.prototype).extend({
|
|||
this.removeAttributeOnLine(lineNum, attributeName) :
|
||||
this.setAttributeOnLine(lineNum, attributeName, attributeValue);
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
hasAttributeOnSelectionOrCaretPosition: function(attributeName) {
|
||||
var hasSelection = ((this.rep.selStart[0] !== this.rep.selEnd[0]) || (this.rep.selEnd[1] !== this.rep.selStart[1]));
|
||||
var hasAttrib;
|
||||
if (hasSelection) {
|
||||
hasAttrib = this.getAttributeOnSelection(attributeName);
|
||||
}else {
|
||||
var attributesOnCaretPosition = this.getAttributesOnCaret();
|
||||
hasAttrib = _.contains(_.flatten(attributesOnCaretPosition), attributeName);
|
||||
}
|
||||
return hasAttrib;
|
||||
},
|
||||
});
|
||||
|
||||
module.exports = AttributeManager;
|
||||
|
|
|
@ -75,6 +75,9 @@ function Ace2Inner(){
|
|||
var EDIT_BODY_PADDING_TOP = 8;
|
||||
var EDIT_BODY_PADDING_LEFT = 8;
|
||||
|
||||
var FORMATTING_STYLES = ['bold', 'italic', 'underline', 'strikethrough'];
|
||||
var SELECT_BUTTON_CLASS = 'selected';
|
||||
|
||||
var caughtErrors = [];
|
||||
|
||||
var thisAuthor = '';
|
||||
|
@ -2472,17 +2475,11 @@ function Ace2Inner(){
|
|||
}
|
||||
}
|
||||
|
||||
if (selectionAllHasIt)
|
||||
{
|
||||
documentAttributeManager.setAttributesOnRange(rep.selStart, rep.selEnd, [
|
||||
[attributeName, '']
|
||||
]);
|
||||
}
|
||||
else
|
||||
{
|
||||
documentAttributeManager.setAttributesOnRange(rep.selStart, rep.selEnd, [
|
||||
[attributeName, 'true']
|
||||
]);
|
||||
|
||||
var attributeValue = selectionAllHasIt ? '' : 'true';
|
||||
documentAttributeManager.setAttributesOnRange(rep.selStart, rep.selEnd, [[attributeName, attributeValue]]);
|
||||
if (attribIsFormattingStyle(attributeName)) {
|
||||
updateStyleButtonState(attributeName, !selectionAllHasIt); // italic, bold, ...
|
||||
}
|
||||
}
|
||||
editorInfo.ace_toggleAttributeOnSelection = toggleAttributeOnSelection;
|
||||
|
@ -2911,6 +2908,9 @@ function Ace2Inner(){
|
|||
rep.selFocusAtStart = newSelFocusAtStart;
|
||||
currentCallStack.repChanged = true;
|
||||
|
||||
// select the formatting buttons when there is the style applied on selection
|
||||
selectFormattingButtonIfLineHasStyleApplied(rep);
|
||||
|
||||
hooks.callAll('aceSelectionChanged', {
|
||||
rep: rep,
|
||||
callstack: currentCallStack,
|
||||
|
@ -2939,6 +2939,22 @@ function Ace2Inner(){
|
|||
return (eventType === 'setup') || (eventType === 'setBaseText') || (eventType === 'importText');
|
||||
}
|
||||
|
||||
function updateStyleButtonState(attribName, hasStyleOnRepSelection) {
|
||||
var $formattingButton = parent.parent.$('[data-key="' + attribName + '"]').find('a');
|
||||
$formattingButton.toggleClass(SELECT_BUTTON_CLASS, hasStyleOnRepSelection);
|
||||
}
|
||||
|
||||
function attribIsFormattingStyle(attributeName) {
|
||||
return _.contains(FORMATTING_STYLES, attributeName);
|
||||
}
|
||||
|
||||
function selectFormattingButtonIfLineHasStyleApplied (rep) {
|
||||
_.each(FORMATTING_STYLES, function (style) {
|
||||
var hasStyleOnRepSelection = documentAttributeManager.hasAttributeOnSelectionOrCaretPosition(style);
|
||||
updateStyleButtonState(style, hasStyleOnRepSelection);
|
||||
})
|
||||
}
|
||||
|
||||
function doCreateDomLine(nonEmpty)
|
||||
{
|
||||
if (browser.msie && (!nonEmpty))
|
||||
|
|
|
@ -0,0 +1,166 @@
|
|||
describe("select formatting buttons when selection has style applied", function(){
|
||||
var STYLES = ['italic', 'bold', 'underline', 'strikethrough'];
|
||||
var SHORTCUT_KEYS = ['I', 'B', 'U', '5']; // italic, bold, underline, strikethrough
|
||||
var FIRST_LINE = 0;
|
||||
|
||||
before(function(cb){
|
||||
helper.newPad(cb);
|
||||
this.timeout(60000);
|
||||
});
|
||||
|
||||
var applyStyleOnLine = function(style, line) {
|
||||
var chrome$ = helper.padChrome$;
|
||||
selectLine(line);
|
||||
var $formattingButton = chrome$('.buttonicon-' + style);
|
||||
$formattingButton.click();
|
||||
}
|
||||
|
||||
var isButtonSelected = function(style) {
|
||||
var chrome$ = helper.padChrome$;
|
||||
var $formattingButton = chrome$('.buttonicon-' + style);
|
||||
return $formattingButton.parent().hasClass('selected');
|
||||
}
|
||||
|
||||
var selectLine = function(lineNumber, offsetStart, offsetEnd) {
|
||||
var inner$ = helper.padInner$;
|
||||
var $line = inner$("div").eq(lineNumber);
|
||||
helper.selectLines($line, $line, offsetStart, offsetEnd);
|
||||
}
|
||||
|
||||
var placeCaretOnLine = function(lineNumber) {
|
||||
var inner$ = helper.padInner$;
|
||||
var $line = inner$("div").eq(lineNumber);
|
||||
$line.sendkeys('{leftarrow}');
|
||||
}
|
||||
|
||||
var undo = function() {
|
||||
var $undoButton = helper.padChrome$(".buttonicon-undo");
|
||||
$undoButton.click();
|
||||
}
|
||||
|
||||
var testIfFormattingButtonIsDeselected = function(style) {
|
||||
it('deselects the ' + style + ' button', function(done) {
|
||||
helper.waitFor(function(){
|
||||
return isButtonSelected(style) === false;
|
||||
}).done(done)
|
||||
});
|
||||
}
|
||||
|
||||
var testIfFormattingButtonIsSelected = function(style) {
|
||||
it('selects the ' + style + ' button', function(done) {
|
||||
helper.waitFor(function(){
|
||||
return isButtonSelected(style);
|
||||
}).done(done)
|
||||
});
|
||||
}
|
||||
|
||||
var applyStyleOnLineAndSelectIt = function(line, style, cb) {
|
||||
applyStyleOnLineOnFullLineAndRemoveSelection(line, style, selectLine, cb);
|
||||
}
|
||||
|
||||
var applyStyleOnLineAndPlaceCaretOnit = function(line, style, cb) {
|
||||
applyStyleOnLineOnFullLineAndRemoveSelection(line, style, placeCaretOnLine, cb);
|
||||
}
|
||||
|
||||
var applyStyleOnLineOnFullLineAndRemoveSelection = function(line, style, selectTarget, cb) {
|
||||
applyStyleOnLine(style, line);
|
||||
|
||||
// we have to give some time to Etherpad detects the selection changed
|
||||
setTimeout(function() {
|
||||
// remove selection from previous line
|
||||
selectLine(line + 1);
|
||||
setTimeout(function() {
|
||||
// select the text or place the caret on a position that
|
||||
// has the formatting text applied previously
|
||||
selectTarget(line);
|
||||
cb();
|
||||
}, 1000);
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
var pressFormattingShortcutOnSelection = function(key) {
|
||||
var inner$ = helper.padInner$;
|
||||
var chrome$ = helper.padChrome$;
|
||||
|
||||
//get the first text element out of the inner iframe
|
||||
var $firstTextElement = inner$("div").first();
|
||||
|
||||
//select this text element
|
||||
$firstTextElement.sendkeys('{selectall}');
|
||||
|
||||
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.ctrlKey = true; // Control key
|
||||
e.which = key.charCodeAt(0); // I, U, B, 5
|
||||
inner$("#innerdocbody").trigger(e);
|
||||
}
|
||||
|
||||
STYLES.forEach(function(style){
|
||||
context('when selection is in a text with ' + style + ' applied', function(){
|
||||
before(function (done) {
|
||||
this.timeout(4000);
|
||||
applyStyleOnLineAndSelectIt(FIRST_LINE, style, done);
|
||||
});
|
||||
|
||||
after(function () {
|
||||
undo();
|
||||
});
|
||||
|
||||
testIfFormattingButtonIsSelected(style);
|
||||
});
|
||||
|
||||
context('when caret is in a position with ' + style + ' applied', function(){
|
||||
before(function (done) {
|
||||
this.timeout(4000);
|
||||
applyStyleOnLineAndPlaceCaretOnit(FIRST_LINE, style, done);
|
||||
});
|
||||
|
||||
after(function () {
|
||||
undo();
|
||||
});
|
||||
|
||||
testIfFormattingButtonIsSelected(style)
|
||||
});
|
||||
});
|
||||
|
||||
context('when user applies a style and the selection does not change', function() {
|
||||
var style = STYLES[0]; // italic
|
||||
before(function () {
|
||||
applyStyleOnLine(style, FIRST_LINE);
|
||||
});
|
||||
|
||||
// clean the style applied
|
||||
after(function () {
|
||||
applyStyleOnLine(style, FIRST_LINE);
|
||||
});
|
||||
|
||||
it('selects the style button', function (done) {
|
||||
expect(isButtonSelected(style)).to.be(true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
SHORTCUT_KEYS.forEach(function(key, index){
|
||||
var styleOfTheShortcut = STYLES[index]; // italic, bold, ...
|
||||
context('when user presses CMD + ' + key, function() {
|
||||
before(function () {
|
||||
pressFormattingShortcutOnSelection(key);
|
||||
});
|
||||
|
||||
testIfFormattingButtonIsSelected(styleOfTheShortcut);
|
||||
|
||||
context('and user presses CMD + ' + key + ' again', function() {
|
||||
before(function () {
|
||||
pressFormattingShortcutOnSelection(key);
|
||||
});
|
||||
|
||||
testIfFormattingButtonIsDeselected(styleOfTheShortcut);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue