summaryrefslogtreecommitdiff
path: root/tests/frontend/specs/scroll.js
diff options
context:
space:
mode:
Diffstat (limited to 'tests/frontend/specs/scroll.js')
-rw-r--r--tests/frontend/specs/scroll.js649
1 files changed, 649 insertions, 0 deletions
diff --git a/tests/frontend/specs/scroll.js b/tests/frontend/specs/scroll.js
new file mode 100644
index 00000000..096b06b6
--- /dev/null
+++ b/tests/frontend/specs/scroll.js
@@ -0,0 +1,649 @@
+describe('scroll when focus line is out of viewport', function () {
+ before(function (done) {
+ helper.newPad(function(){
+ cleanPad(function(){
+ forceUseMonospacedFont();
+ scrollWhenPlaceCaretInTheLastLineOfViewport();
+ createPadWithSeveralLines(function(){
+ resizeEditorHeight();
+ done();
+ });
+ });
+ });
+ this.timeout(20000);
+ });
+
+ context('when user presses any arrow keys on a line above the viewport', function(){
+ context('and scroll percentage config is set to 0.2 on settings.json', function(){
+ var lineCloseOfTopOfPad = 10;
+ before(function (done) {
+ setScrollPercentageWhenFocusLineIsOutOfViewport(0.2, true);
+ scrollEditorToBottomOfPad();
+
+ placeCaretInTheBeginningOfLine(lineCloseOfTopOfPad, function(){ // place caret in the 10th line
+ // warning: even pressing right arrow, the caret does not change of position
+ // the column where the caret is, it has not importance, only the line
+ pressAndReleaseRightArrow();
+ done();
+ });
+ });
+
+ it('keeps the focus line scrolled 20% from the top of the viewport', function (done) {
+ // default behavior is to put the line in the top of viewport, but as
+ // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2, we have an extra 20% of lines scrolled
+ // (2 lines, which are the 20% of the 10 that are visible on viewport)
+ var firstLineOfViewport = getFirstLineVisibileOfViewport();
+ expect(lineCloseOfTopOfPad).to.be(firstLineOfViewport + 2);
+ done();
+ });
+ });
+ });
+
+ context('when user presses any arrow keys on a line below the viewport', function(){
+ context('and scroll percentage config is set to 0.7 on settings.json', function(){
+ var lineCloseToBottomOfPad = 50;
+ before(function (done) {
+ setScrollPercentageWhenFocusLineIsOutOfViewport(0.7);
+
+ // firstly, scroll to make the lineCloseToBottomOfPad visible. After that, scroll to make it out of viewport
+ scrollEditorToTopOfPad();
+ placeCaretAtTheEndOfLine(lineCloseToBottomOfPad); // place caret in the 50th line
+ setTimeout(function() {
+ // warning: even pressing right arrow, the caret does not change of position
+ pressAndReleaseLeftArrow();
+ done();
+ }, 1000);
+ });
+
+ it('keeps the focus line scrolled 70% from the bottom of the viewport', function (done) {
+ // default behavior is to put the line in the top of viewport, but as
+ // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.7, we have an extra 70% of lines scrolled
+ // (7 lines, which are the 70% of the 10 that are visible on viewport)
+ var lastLineOfViewport = getLastLineVisibleOfViewport();
+ expect(lineCloseToBottomOfPad).to.be(lastLineOfViewport - 7);
+ done();
+ });
+ });
+ });
+
+ context('when user presses arrow up on the first line of the viewport', function(){
+ context('and percentageToScrollWhenUserPressesArrowUp is set to 0.3', function () {
+ var lineOnTopOfViewportWhenThePadIsScrolledDown;
+ before(function (done) {
+ setPercentageToScrollWhenUserPressesArrowUp(0.3);
+
+ // we need some room to make the scroll up
+ scrollEditorToBottomOfPad();
+ lineOnTopOfViewportWhenThePadIsScrolledDown = 91;
+ placeCaretAtTheEndOfLine(lineOnTopOfViewportWhenThePadIsScrolledDown);
+ setTimeout(function() {
+ // warning: even pressing up arrow, the caret does not change of position
+ pressAndReleaseUpArrow();
+ done();
+ }, 1000);
+ });
+
+ it('keeps the focus line scrolled 30% of the top of the viewport', function (done) {
+ // default behavior is to put the line in the top of viewport, but as
+ // PercentageToScrollWhenUserPressesArrowUp is set to 0.3, we have an extra 30% of lines scrolled
+ // (3 lines, which are the 30% of the 10 that are visible on viewport)
+ var firstLineOfViewport = getFirstLineVisibileOfViewport();
+ expect(firstLineOfViewport).to.be(lineOnTopOfViewportWhenThePadIsScrolledDown - 3);
+ done();
+ })
+ });
+ });
+
+ context('when user edits the last line of viewport', function(){
+ context('and scroll percentage config is set to 0 on settings.json', function(){
+ var lastLineOfViewportBeforeEnter = 10;
+ before(function () {
+ // the default value
+ resetScrollPercentageWhenFocusLineIsOutOfViewport();
+
+ // make sure the last line on viewport is the 10th one
+ scrollEditorToTopOfPad();
+ placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
+ pressEnter();
+ });
+
+ it('keeps the focus line on the bottom of the viewport', function (done) {
+ var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
+ expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 1);
+ done();
+ });
+ });
+
+ context('and scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.3', function(){ // this value is arbitrary
+ var lastLineOfViewportBeforeEnter = 9;
+ before(function () {
+ setScrollPercentageWhenFocusLineIsOutOfViewport(0.3);
+
+ // make sure the last line on viewport is the 10th one
+ scrollEditorToTopOfPad();
+ placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
+ pressBackspace();
+ });
+
+ it('scrolls 30% of viewport up', function (done) {
+ var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
+ // default behavior is to scroll one line at the bottom of viewport, but as
+ // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.3, we have an extra 30% of lines scrolled
+ // (3 lines, which are the 30% of the 10 that are visible on viewport)
+ expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 3);
+ done();
+ });
+ });
+
+ context('and it is set to a value that overflow the interval [0, 1]', function(){
+ var lastLineOfViewportBeforeEnter = 10;
+ before(function(){
+ var scrollPercentageWhenFocusLineIsOutOfViewport = 1.5;
+ scrollEditorToTopOfPad();
+ placeCaretAtTheEndOfLine(lastLineOfViewportBeforeEnter);
+ setScrollPercentageWhenFocusLineIsOutOfViewport(scrollPercentageWhenFocusLineIsOutOfViewport);
+ pressEnter();
+ });
+
+ it('keeps the default behavior of moving the focus line on the bottom of the viewport', function (done) {
+ var lastLineOfViewportAfterEnter = getLastLineVisibleOfViewport();
+ expect(lastLineOfViewportAfterEnter).to.be(lastLineOfViewportBeforeEnter + 1);
+ done();
+ });
+ });
+ });
+
+ context('when user edits a line above the viewport', function(){
+ context('and scroll percentage config is set to 0 on settings.json', function(){
+ var lineCloseOfTopOfPad = 10;
+ before(function () {
+ // the default value
+ setScrollPercentageWhenFocusLineIsOutOfViewport(0);
+
+ // firstly, scroll to make the lineCloseOfTopOfPad visible. After that, scroll to make it out of viewport
+ scrollEditorToTopOfPad();
+ placeCaretAtTheEndOfLine(lineCloseOfTopOfPad); // place caret in the 10th line
+ scrollEditorToBottomOfPad();
+ pressBackspace(); // edit the line where the caret is, which is above the viewport
+ });
+
+ it('keeps the focus line on the top of the viewport', function (done) {
+ var firstLineOfViewportAfterEnter = getFirstLineVisibileOfViewport();
+ expect(firstLineOfViewportAfterEnter).to.be(lineCloseOfTopOfPad);
+ done();
+ });
+ });
+
+ context('and scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2', function(){ // this value is arbitrary
+ var lineCloseToBottomOfPad = 50;
+ before(function () {
+ // we force the line edited to be above the top of the viewport
+ setScrollPercentageWhenFocusLineIsOutOfViewport(0.2, true); // set scroll jump to 20%
+ scrollEditorToTopOfPad();
+ placeCaretAtTheEndOfLine(lineCloseToBottomOfPad);
+ scrollEditorToBottomOfPad();
+ pressBackspace(); // edit line
+ });
+
+ it('scrolls 20% of viewport down', function (done) {
+ // default behavior is to scroll one line at the top of viewport, but as
+ // scrollPercentageWhenFocusLineIsOutOfViewport is set to 0.2, we have an extra 20% of lines scrolled
+ // (2 lines, which are the 20% of the 10 that are visible on viewport)
+ var firstLineVisibileOfViewport = getFirstLineVisibileOfViewport();
+ expect(lineCloseToBottomOfPad).to.be(firstLineVisibileOfViewport + 2);
+ done();
+ });
+ });
+ });
+
+ context('when user places the caret at the last line visible of viewport', function(){
+ var lastLineVisible;
+ context('and scroll percentage config is set to 0 on settings.json', function(){
+ before(function (done) {
+ // reset to the default value
+ resetScrollPercentageWhenFocusLineIsOutOfViewport();
+
+ placeCaretInTheBeginningOfLine(0, function(){ // reset caret position
+ scrollEditorToTopOfPad();
+ lastLineVisible = getLastLineVisibleOfViewport();
+ placeCaretInTheBeginningOfLine(lastLineVisible, done); // place caret in the 9th line
+ });
+
+ });
+
+ it('does not scroll', function(done){
+ setTimeout(function() {
+ var lastLineOfViewport = getLastLineVisibleOfViewport();
+ var lineDoesNotScroll = lastLineOfViewport === lastLineVisible;
+ expect(lineDoesNotScroll).to.be(true);
+ done();
+ }, 1000);
+ });
+ });
+ context('and scroll percentage config is set to 0.5 on settings.json', function(){
+ before(function (done) {
+ setScrollPercentageWhenFocusLineIsOutOfViewport(0.5);
+ scrollEditorToTopOfPad();
+ placeCaretInTheBeginningOfLine(0, function(){ // reset caret position
+ // this timeout inside a callback is ugly but it necessary to give time to aceSelectionChange
+ // realizes that the selection has been changed
+ setTimeout(function() {
+ lastLineVisible = getLastLineVisibleOfViewport();
+ placeCaretInTheBeginningOfLine(lastLineVisible, done); // place caret in the 9th line
+ }, 1000);
+ });
+ });
+
+ it('scrolls line to 50% of the viewport', function(done){
+ helper.waitFor(function(){
+ var lastLineOfViewport = getLastLineVisibleOfViewport();
+ var lastLinesScrolledFiveLinesUp = lastLineOfViewport - 5 === lastLineVisible;
+ return lastLinesScrolledFiveLinesUp;
+ }).done(done);
+ });
+ });
+ });
+
+ // This is a special case. When user is selecting a text with arrow down or arrow left we have
+ // to keep the last line selected on focus
+ context('when the first line selected is out of the viewport and user presses shift arrow down', function(){
+ var lastLineOfPad = 99;
+ before(function (done) {
+ scrollEditorToTopOfPad();
+
+ // make a selection bigger than the viewport height
+ var $firstLineOfSelection = getLine(0);
+ var $lastLineOfSelection = getLine(lastLineOfPad);
+ var lengthOfLastLine = $lastLineOfSelection.text().length;
+ helper.selectLines($firstLineOfSelection, $lastLineOfSelection, 0, lengthOfLastLine);
+
+ // place the last line selected on the viewport
+ scrollEditorToBottomOfPad();
+
+ // press a key to make the selection goes down
+ // although we can't simulate the extending of selection. It's possible to send a key event
+ // which is captured on ace2_inner scroll function.
+ pressAndReleaseLeftArrow(true);
+ done();
+ });
+
+ it('keeps the last line selected on focus', function (done) {
+ var lastLineOfSelectionIsVisible = isLineOnViewport(lastLineOfPad);
+ expect(lastLineOfSelectionIsVisible).to.be(true);
+ done();
+ });
+ });
+
+ // In this scenario we avoid the bouncing scroll. E.g Let's suppose we have a big line that is
+ // the size of the viewport, and its top is above the viewport. When user presses '<-', this line
+ // will scroll down because the top is out of the viewport. When it scrolls down, the bottom of
+ // line gets below the viewport so when user presses '<-' again it scrolls up to make the bottom
+ // of line visible. If user presses arrow keys more than one time, the editor will keep scrolling up and down
+ context('when the line height is bigger than the scroll amount percentage * viewport height', function(){
+ var scrollOfEditorBeforePressKey;
+ var BIG_LINE_NUMBER = 0;
+ var MIDDLE_OF_BIG_LINE = 51;
+ before(function (done) {
+ createPadWithALineHigherThanViewportHeight(this, BIG_LINE_NUMBER, function(){
+ setScrollPercentageWhenFocusLineIsOutOfViewport(0.5); // set any value to force scroll to outside to viewport
+ var $bigLine = getLine(BIG_LINE_NUMBER);
+
+ // each line has about 5 chars, we place the caret in the middle of the line
+ helper.selectLines($bigLine, $bigLine, MIDDLE_OF_BIG_LINE, MIDDLE_OF_BIG_LINE);
+
+ scrollEditorToLeaveTopAndBottomOfBigLineOutOfViewport($bigLine);
+ scrollOfEditorBeforePressKey = getEditorScroll();
+
+ // press a key to force to scroll
+ pressAndReleaseRightArrow();
+ done();
+ });
+ });
+
+ // reset pad to the original text
+ after(function (done) {
+ this.timeout(5000);
+ cleanPad(function(){
+ createPadWithSeveralLines(function(){
+ resetEditorWidth();
+ done();
+ });
+ });
+ });
+
+ // as the editor.line is inside of the viewport, it should not scroll
+ it('should not scroll', function (done) {
+ var scrollOfEditorAfterPressKey = getEditorScroll();
+ expect(scrollOfEditorAfterPressKey).to.be(scrollOfEditorBeforePressKey);
+ done();
+ });
+ });
+
+ // Some plugins, for example the ep_page_view, change the editor dimensions. This plugin, for example,
+ // adds padding-top to the ace_outer, which changes the viewport height
+ describe('integration with plugins which changes the margin of editor', function(){
+ context('when editor dimensions changes', function(){
+ before(function () {
+ // reset the size of editor. Now we show more than 10 lines as in the other tests
+ resetResizeOfEditorHeight();
+ scrollEditorToTopOfPad();
+
+ // height of the editor viewport
+ var editorHeight = getEditorHeight();
+
+ // add a big padding-top, 50% of the viewport
+ var paddingTopOfAceOuter = editorHeight/2;
+ var chrome$ = helper.padChrome$;
+ var $outerIframe = chrome$('iframe');
+ $outerIframe.css('padding-top', paddingTopOfAceOuter);
+
+ // we set a big value to check if the scroll is made
+ setScrollPercentageWhenFocusLineIsOutOfViewport(1);
+ });
+
+ context('and user places the caret in the last line visible of the pad', function(){
+ var lastLineVisible;
+ beforeEach(function (done) {
+ lastLineVisible = getLastLineVisibleOfViewport();
+ placeCaretInTheBeginningOfLine(lastLineVisible, done);
+ });
+
+ it('scrolls the line where caret is', function(done){
+ helper.waitFor(function(){
+ var firstLineVisibileOfViewport = getFirstLineVisibileOfViewport();
+ var linesScrolled = firstLineVisibileOfViewport !== 0;
+ return linesScrolled;
+ }).done(done);
+ });
+ });
+ });
+ });
+
+ /* ********************* Helper functions/constants ********************* */
+ var TOP_OF_PAGE = 0;
+ var BOTTOM_OF_PAGE = 5000; // we use a big value to force the page to be scrolled all the way down
+ var LINES_OF_PAD = 100;
+ var ENTER = 13;
+ var BACKSPACE = 8;
+ var LEFT_ARROW = 37;
+ var UP_ARROW = 38;
+ var RIGHT_ARROW = 39;
+ var LINES_ON_VIEWPORT = 10;
+ var WIDTH_OF_EDITOR_RESIZED = 100;
+ var LONG_TEXT_CHARS = 100;
+
+ var cleanPad = function(callback) {
+ var inner$ = helper.padInner$;
+ var $padContent = inner$('#innerdocbody');
+ $padContent.html('');
+
+ // wait for Etherpad to re-create first line
+ helper.waitFor(function(){
+ var lineNumber = inner$('div').length;
+ return lineNumber === 1;
+ }, 2000).done(callback);
+ };
+
+ var createPadWithSeveralLines = function(done) {
+ var line = '<span>a</span><br>';
+ var $firstLine = helper.padInner$('div').first();
+ var lines = line.repeat(LINES_OF_PAD); //arbitrary number, we need to create lines that is over the viewport
+ $firstLine.html(lines);
+
+ helper.waitFor(function(){
+ var linesCreated = helper.padInner$('div').length;
+ return linesCreated === LINES_OF_PAD;
+ }, 4000).done(done);
+ };
+
+ var createPadWithALineHigherThanViewportHeight = function(test, line, done) {
+ var viewportHeight = 160; //10 lines * 16px (height of line)
+ test.timeout(5000);
+ cleanPad(function(){
+ // make the editor smaller to make test easier
+ // with that width the each line has about 5 chars
+ resizeEditorWidth();
+
+ // we create a line with 100 chars, which makes about 20 lines
+ setLongTextOnLine(line);
+ helper.waitFor(function () {
+ var $firstLine = getLine(line);
+
+ var heightOfLine = $firstLine.get(0).getBoundingClientRect().height;
+ return heightOfLine >= viewportHeight;
+ }, 4000).done(done);
+ });
+ };
+
+ var setLongTextOnLine = function(line) {
+ var $line = getLine(line);
+ var longText = 'a'.repeat(LONG_TEXT_CHARS);
+ $line.html(longText);
+ };
+
+ // resize the editor to make the tests easier
+ var resizeEditorHeight = function() {
+ var chrome$ = helper.padChrome$;
+ chrome$('#editorcontainer').css('height', getSizeOfViewport());
+ };
+
+ // this makes about 5 chars per line
+ var resizeEditorWidth = function() {
+ var chrome$ = helper.padChrome$;
+ chrome$('#editorcontainer').css('width', WIDTH_OF_EDITOR_RESIZED);
+ };
+
+ var resetResizeOfEditorHeight = function() {
+ var chrome$ = helper.padChrome$;
+ chrome$('#editorcontainer').css('height', '');
+ };
+
+ var resetEditorWidth = function () {
+ var chrome$ = helper.padChrome$;
+ chrome$('#editorcontainer').css('width', '');
+ };
+
+ var getEditorHeight = function() {
+ var chrome$ = helper.padChrome$;
+ var $editor = chrome$('#editorcontainer');
+ var editorHeight = $editor.get(0).clientHeight;
+ return editorHeight;
+ };
+
+ var getSizeOfViewport = function() {
+ return getLinePositionOnViewport(LINES_ON_VIEWPORT) - getLinePositionOnViewport(0);
+ };
+
+ var scrollPageTo = function(value) {
+ var outer$ = helper.padOuter$;
+ var $ace_outer = outer$('#outerdocbody').parent();
+ $ace_outer.parent().scrollTop(value);
+ };
+
+ var scrollEditorToTopOfPad = function() {
+ scrollPageTo(TOP_OF_PAGE);
+ };
+
+ var scrollEditorToBottomOfPad = function() {
+ scrollPageTo(BOTTOM_OF_PAGE);
+ };
+
+ var scrollEditorToLeaveTopAndBottomOfBigLineOutOfViewport = function ($bigLine) {
+ var lineHeight = $bigLine.get(0).getBoundingClientRect().height;
+ var middleOfLine = lineHeight/2;
+ scrollPageTo(middleOfLine);
+ };
+
+ var getLine = function(lineNum) {
+ var inner$ = helper.padInner$;
+ var $line = inner$('div').eq(lineNum);
+ return $line;
+ };
+
+ var placeCaretAtTheEndOfLine = function(lineNum) {
+ var $targetLine = getLine(lineNum);
+ var lineLength = $targetLine.text().length;
+ helper.selectLines($targetLine, $targetLine, lineLength, lineLength);
+ };
+
+ var placeCaretInTheBeginningOfLine = function(lineNum, cb) {
+ var $targetLine = getLine(lineNum);
+ helper.selectLines($targetLine, $targetLine, 0, 0);
+ helper.waitFor(function() {
+ var $lineWhereCaretIs = getLineWhereCaretIs();
+ return $targetLine.get(0) === $lineWhereCaretIs.get(0);
+ }).done(cb);
+ };
+
+ var getLineWhereCaretIs = function() {
+ var inner$ = helper.padInner$;
+ var nodeWhereCaretIs = inner$.document.getSelection().anchorNode;
+ var $lineWhereCaretIs = $(nodeWhereCaretIs).closest('div');
+ return $lineWhereCaretIs;
+ };
+
+ var getFirstLineVisibileOfViewport = function() {
+ return _.find(_.range(0, LINES_OF_PAD - 1), isLineOnViewport);
+ };
+
+ var getLastLineVisibleOfViewport = function() {
+ return _.find(_.range(LINES_OF_PAD - 1, 0, -1), isLineOnViewport);
+ };
+
+ var pressKey = function(keyCode, shiftIsPressed){
+ var inner$ = helper.padInner$;
+ var evtType;
+ if(inner$(window)[0].bowser.firefox || inner$(window)[0].bowser.modernIE){ // if it's a mozilla or IE
+ evtType = 'keypress';
+ }else{
+ evtType = 'keydown';
+ }
+ var e = inner$.Event(evtType);
+ e.shiftKey = shiftIsPressed;
+ e.keyCode = keyCode;
+ e.which = keyCode; // etherpad listens to 'which'
+ inner$('#innerdocbody').trigger(e);
+ };
+
+ var releaseKey = function(keyCode){
+ var inner$ = helper.padInner$;
+ var evtType = 'keyup';
+ var e = inner$.Event(evtType);
+ e.keyCode = keyCode;
+ e.which = keyCode; // etherpad listens to 'which'
+ inner$('#innerdocbody').trigger(e);
+ };
+
+ var pressEnter = function() {
+ pressKey(ENTER);
+ };
+
+ var pressBackspace = function() {
+ pressKey(BACKSPACE);
+ };
+
+ var pressAndReleaseUpArrow = function() {
+ pressKey(UP_ARROW);
+ releaseKey(UP_ARROW);
+ };
+
+ var pressAndReleaseRightArrow = function() {
+ pressKey(RIGHT_ARROW);
+ releaseKey(RIGHT_ARROW);
+ };
+
+ var pressAndReleaseLeftArrow = function(shiftIsPressed) {
+ pressKey(LEFT_ARROW, shiftIsPressed);
+ releaseKey(LEFT_ARROW);
+ };
+
+ var isLineOnViewport = function(lineNumber) {
+ // in the function scrollNodeVerticallyIntoView from ace2_inner.js, iframePadTop is used to calculate
+ // how much scroll is needed. Although the name refers to padding-top, this value is not set on the
+ // padding-top.
+ var iframePadTop = 8;
+ var $line = getLine(lineNumber);
+ var linePosition = $line.get(0).getBoundingClientRect();
+
+ // position relative to the current viewport
+ var linePositionTopOnViewport = linePosition.top - getEditorScroll() + iframePadTop;
+ var linePositionBottomOnViewport = linePosition.bottom - getEditorScroll();
+
+ var lineBellowTop = linePositionBottomOnViewport > 0;
+ var lineAboveBottom = linePositionTopOnViewport < getClientHeightVisible();
+ var isVisible = lineBellowTop && lineAboveBottom;
+
+ return isVisible;
+ };
+
+ var getEditorScroll = function () {
+ var outer$ = helper.padOuter$;
+ var scrollTopFirefox = outer$('#outerdocbody').parent().scrollTop(); // works only on firefox
+ var scrollTop = outer$('#outerdocbody').scrollTop() || scrollTopFirefox;
+ return scrollTop;
+ };
+
+ // clientHeight includes padding, so we have to subtract it and consider only the visible viewport
+ var getClientHeightVisible = function () {
+ var outer$ = helper.padOuter$;
+ var $ace_outer = outer$('#outerdocbody').parent();
+ var ace_outerHeight = $ace_outer.get(0).clientHeight;
+ var ace_outerPaddingTop = getIntValueOfCSSProperty($ace_outer, 'padding-top');
+ var paddingAddedWhenPageViewIsEnable = getPaddingAddedWhenPageViewIsEnable();
+ var clientHeight = ace_outerHeight - ( ace_outerPaddingTop + paddingAddedWhenPageViewIsEnable);
+
+ return clientHeight;
+ };
+
+ // ep_page_view changes the dimensions of the editor. We have to guarantee
+ // the viewport height is calculated right
+ var getPaddingAddedWhenPageViewIsEnable = function () {
+ var chrome$ = helper.padChrome$;
+ var $outerIframe = chrome$('iframe');
+ var paddingAddedWhenPageViewIsEnable = parseInt($outerIframe.css('padding-top'));
+ return paddingAddedWhenPageViewIsEnable;
+ };
+
+ var getIntValueOfCSSProperty = function($element, property){
+ var valueString = $element.css(property);
+ return parseInt(valueString) || 0;
+ };
+
+ var forceUseMonospacedFont = function () {
+ helper.padChrome$.window.clientVars.padOptions.useMonospaceFont = true;
+ };
+
+ var setScrollPercentageWhenFocusLineIsOutOfViewport = function(value, editionAboveViewport) {
+ var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
+ if (editionAboveViewport) {
+ scrollSettings.percentage.editionAboveViewport = value;
+ }else{
+ scrollSettings.percentage.editionBelowViewport = value;
+ }
+ };
+
+ var resetScrollPercentageWhenFocusLineIsOutOfViewport = function() {
+ var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
+ scrollSettings.percentage.editionAboveViewport = 0;
+ scrollSettings.percentage.editionBelowViewport = 0;
+ };
+
+ var setPercentageToScrollWhenUserPressesArrowUp = function (value) {
+ var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
+ scrollSettings.percentageToScrollWhenUserPressesArrowUp = value;
+ };
+
+ var scrollWhenPlaceCaretInTheLastLineOfViewport = function() {
+ var scrollSettings = helper.padChrome$.window.clientVars.scrollWhenFocusLineIsOutOfViewport;
+ scrollSettings.scrollWhenCaretIsInTheLastLineOfViewport = true;
+ };
+
+ var getLinePositionOnViewport = function(lineNumber) {
+ var $line = getLine(lineNumber);
+ var linePosition = $line.get(0).getBoundingClientRect();
+
+ // position relative to the current viewport
+ return linePosition.top - getEditorScroll();
+ };
+});
+