<!doctype html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Example - example-NgModelController-production</title>
  <link href="style.css" rel="stylesheet" type="text/css">
  

  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.1/angular.min.js"></script>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.0-rc.1/angular-sanitize.js"></script>
  <script src="https://rawgit.com/gregjacobs/Autolinker.js/master/dist/Autolinker.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-core.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/rangy/1.3.0/rangy-selectionsaverestore.js"></script>
  <script src="script.js"></script>
  

  
</head>
  <body ng-app="customControl">
      <h4>Caret Position screws up after pasting or writing a link</h4>
   <div contenteditable
        name="myWidget"
        ng-bind-html ="userContent"
        ng-model="userContent"
        strip-br="true"
        required>Change me </div>
    <span ng-show="myForm.myWidget.$error.required">Required </span>
   <hr>
   Model: <p aria-label="Dynamic textarea">{{userContent}}</p>
   <script>
    rangy.init();
  </script>
  </body>
</html>


[contenteditable] {
  border: 1px solid black;
  background-color: white;
  min-height: 20px;
}

.ng-invalid {
  border: 1px solid red;
}

/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/


(function(angular) {
  'use strict';

angular.module('customControl', ['ngSanitize']).
  directive('contenteditable', ['$sce','$filter','$timeout', function($sce,$filter,$timeout) {
    return {
      restrict: 'A', // only activate on element attribute
      require: '?ngModel', // get a hold of NgModelController
      link: function(scope, element, attrs, ngModel) {
        if (!ngModel) return; // do nothing if no ng-model

        // Specify how UI should be updated
        ngModel.$render = function() {
          element.html($sce.getTrustedHtml(ngModel.$viewValue || ''));
        };

        // Listen for change events to enable binding
        element.on('blur keyup change', function() {
          scope.$evalAsync(read);
        });
        read(); // initialize

        // Write data to the model
        function read() {
          var html = element.html();
          // var pos = getCaretCharacterOffsetWithin(element[0]);
          // console.log(pos);
          var caret_position = rangy.saveSelection();


          // When we clear the content editable the browser leaves a <br> behind
          // If strip-br attribute is provided then we strip this out
          if ( attrs.stripBr && html == '<br>' ) {
            html = '';
          }
          var autoLinked = Autolinker.link(html, "_blank");
          ngModel.$setViewValue(autoLinked);

          // var el, el2, range, sel;
          
          // el = element[0];
          // range = document.createRange();
          // sel = window.getSelection();
          // if (el.childNodes.length > 0) {
          // el2 = el.childNodes[el.childNodes.length - 1];
          // range.setStartAfter(el2);
          // } else {
          // range.setStartAfter(el);
          // }
          // range.collapse(true);
          // sel.removeAllRanges();
          // sel.addRange(range);
          
          rangy.restoreSelection(caret_position);
        }
      }
    };
  }]);
})(window.angular);