简体   繁体   中英

Prevent modal window scrolling up when I click into ace editor

I have a modal window which contains ace editor . When the modal window is open, I scroll down and click inside the ace editor to add some text. And then suddenly the window is scrolled up automatically. Again I scroll down, click inside the editor and it is scrolled up once more. Finally, on the third time, I'm able to insert text into the editor. It happens when the modal is high enough and the editor is not visible unless you scroll down for it.

Why is it? How to prevent this autoscrolling behavior?

Here is plunker: http://plnkr.co/edit/NHHkUtrw8SIDIzViNiqw?p=preview

Controller:

angular.module('ui.bootstrap.demo', ['ui.bootstrap', 'ui.ace']);
angular.module('ui.bootstrap.demo').controller('ModalDemoCtrl', function ($scope, $modal, $log) {

  $scope.items = ['item1', 'item2', 'item3'];

  $scope.open = function (size) {

    var modalInstance = $modal.open({
      templateUrl: 'myModalContent.html',
      controller: 'ModalInstanceCtrl',
      size: size,
      resolve: {
        items: function () {
          return $scope.items;
        }
      }
    });

    modalInstance.result.then(function (selectedItem) {
      $scope.selected = selectedItem;
    }, function () {
      $log.info('Modal dismissed at: ' + new Date());
    });
  };
});

// Please note that $modalInstance represents a modal window (instance) dependency.
// It is not the same as the $modal service used above.

angular.module('ui.bootstrap.demo').controller('ModalInstanceCtrl', function ($scope, $modalInstance, items) {

  $scope.items = items;
  $scope.selected = {
    item: $scope.items[0]
  };

  $scope.editor = {
    text: 'Hello, how are you getting on?'
  };

  $scope.aceOptions = function (mode) {
    return {
      mode: mode,
      onLoad: function (_ace) {
        // HACK to have the ace instance in the scope...
        $scope.modeChanged = function () {
          _ace.getSession().setMode("ace/mode/" + mode);
        };
      }
    };
  };

  $scope.ok = function () {
    $modalInstance.close($scope.selected.item);
  };

  $scope.cancel = function () {
    $modalInstance.dismiss('cancel');
  };
});

HTML:

<!doctype html>
<html ng-app="ui.bootstrap.demo">
  <head>
    <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.16/angular.js"></script>
    <script src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.js"></script>
    <script src="//rawgit.com/ajaxorg/ace-builds/v1.2.6/src-min-noconflict/ace.js"></script>
    <script src="//rawgithub.com/ajaxorg/ace-builds/master/src-min-noconflict/mode-css.js"></script>
    <script src="//rawgithub.com/angular-ui/ui-ace/bower/ui-ace.min.js"></script>
    <script src="example.js"></script>
    <link href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" rel="stylesheet">
  </head>
  <body>

<div ng-controller="ModalDemoCtrl">
    <script type="text/ng-template" id="myModalContent.html">
        <div class="modal-header">
            <h3 class="modal-title">I'm a modal!</h3>
        </div>
        <div class="modal-body">
            <ul>
                <li ng-repeat="item in items">
                    <a ng-click="selected.item = item">{{ item }}</a>
                </li>
            </ul>
            Selected: <b>{{ selected.item }}</b>
            <p>
            Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
            </p>
            <p>Editor:</p>
            <div ui-ace="{
              useWrapMode : true,
              showGutter: true,
              theme:'twilight',
              mode: 'markdown',
              rendererOptions: {
                maxLines: 5,
                minLines: 3
              }
            }" ng-model="editor.text"></div>

        </div>
        <div class="modal-footer">
            <button class="btn btn-primary" ng-click="ok()">OK</button>
            <button class="btn btn-warning" ng-click="cancel()">Cancel</button>
        </div>
    </script>

    <button class="btn btn-default" ng-click="open()">Open me!</button>
    <button class="btn btn-default" ng-click="open('lg')">Large modal</button>
    <button class="btn btn-default" ng-click="open('sm')">Small modal</button>
    <div ng-show="selected">Selection from a modal: {{ selected }}</div>
</div>
  </body>
</html>

Browsers scroll textarea into view when it is focused. This causes all kinds of problems with overflow:hidden elements getting scrolled, and editor jumping when clicked.

Ace tries to prevent this, by setting position fixed to make sure the textarea is on screen, but there is a bug in the specification of position:fixed, https://bugs.chromium.org/p/chromium/issues/detail?id=20574 which makes postion:fixed work like position:absolute in relation to transformed element.

If you do not have a way to remove transform from parent elements of ace, the best workaround is to add css to make .ace_text-input always absolutely positioned.

TLDR add the following css to your page

.ace_text-input {
    position: absolute!important;
}

If you set focus manually it doesn't seem to jump (testing on Chrome 58). You can set the focus on the element manually after it initialises.

Add an onLoad event to the ui-ace options and then add this to the ModalInstanceCtrl :

$scope.focusEditor = function(editor) {
  editor.focus();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM