]> BookStack Code Mirror - bookstack/commitdiff
Getting the latest changes
authorAbijeet <redacted>
Sun, 4 Jun 2017 04:50:01 +0000 (10:20 +0530)
committerAbijeet <redacted>
Sun, 4 Jun 2017 04:50:01 +0000 (10:20 +0530)
1  2 
resources/assets/js/directives.js
resources/assets/sass/styles.scss
resources/views/pages/show.blade.php

index ff0f93cfa69d3e0e06615dba832932101070b910,221e18b0e1559ca22a56564a9136d74d1c5ae71f..278e0f8c656c74342989213a04659c18f67161f0
@@@ -2,6 -2,7 +2,7 @@@
  const DropZone = require("dropzone");
  const MarkdownIt = require("markdown-it");
  const mdTasksLists = require('markdown-it-task-lists');
+ const code = require('./code');
  
  module.exports = function (ngApp, events) {
  
  
                  // Set initial model content
                  element = element.find('textarea').first();
-                 let content = element.val();
-                 scope.mdModel = content;
-                 scope.mdChange(md.render(content));
  
-                 element.on('change input', (event) => {
-                     content = element.val();
+                 // Codemirror Setup
+                 let cm = code.markdownEditor(element[0]);
+                 cm.on('change', (instance, changeObj) => {
+                     update(instance);
+                 });
+                 cm.on('scroll', instance => {
+                     // Thanks to http://liuhao.im/english/2015/11/10/the-sync-scroll-of-markdown-editor-in-javascript.html
+                     let scroll = instance.getScrollInfo();
+                     let atEnd = scroll.top + scroll.clientHeight === scroll.height;
+                     if (atEnd) {
+                         scope.$emit('markdown-scroll', -1);
+                         return;
+                     }
+                     let lineNum = instance.lineAtHeight(scroll.top, 'local');
+                     let range = instance.getRange({line: 0, ch: null}, {line: lineNum, ch: null});
+                     let parser = new DOMParser();
+                     let doc = parser.parseFromString(md.render(range), 'text/html');
+                     let totalLines = doc.documentElement.querySelectorAll('body > *');
+                     scope.$emit('markdown-scroll', totalLines.length);
+                 });
+                 function update(instance) {
+                     let content = instance.getValue();
+                     element.val(content);
                      $timeout(() => {
                          scope.mdModel = content;
                          scope.mdChange(md.render(content));
                      });
-                 });
+                 }
+                 update(cm);
  
                  scope.$on('markdown-update', (event, value) => {
+                     cm.setValue(value);
                      element.val(value);
                      scope.mdModel = value;
                      scope.mdChange(md.render(value));
       * Markdown Editor
       * Handles all functionality of the markdown editor.
       */
-     ngApp.directive('markdownEditor', ['$timeout', function ($timeout) {
+     ngApp.directive('markdownEditor', ['$timeout', '$rootScope', function ($timeout, $rootScope) {
          return {
              restrict: 'A',
              link: function (scope, element, attrs) {
                      currentCaretPos = $input[0].selectionStart;
                  });
  
-                 // Scroll sync
-                 let inputScrollHeight,
-                     inputHeight,
-                     displayScrollHeight,
-                     displayHeight;
-                 function setScrollHeights() {
-                     inputScrollHeight = $input[0].scrollHeight;
-                     inputHeight = $input.height();
-                     displayScrollHeight = $display[0].scrollHeight;
-                     displayHeight = $display.height();
-                 }
-                 setTimeout(() => {
-                     setScrollHeights();
-                 }, 200);
-                 window.addEventListener('resize', setScrollHeights);
-                 let scrollDebounceTime = 800;
-                 let lastScroll = 0;
-                 $input.on('scroll', event => {
-                     let now = Date.now();
-                     if (now - lastScroll > scrollDebounceTime) {
-                         setScrollHeights()
+                 // Handle scroll sync event from editor scroll
+                 $rootScope.$on('markdown-scroll', (event, lineCount) => {
+                     let elems = $display[0].children[0].children;
+                     if (elems.length > lineCount) {
+                         let topElem = (lineCount === -1) ? elems[elems.length-1] : elems[lineCount];
+                         $display.animate({
+                             scrollTop: topElem.offsetTop
+                         }, {queue: false, duration: 200, easing: 'linear'});
                      }
-                     let scrollPercent = ($input.scrollTop() / (inputScrollHeight - inputHeight));
-                     let displayScrollY = (displayScrollHeight - displayHeight) * scrollPercent;
-                     $display.scrollTop(displayScrollY);
-                     lastScroll = now;
                  });
  
                  // Editor key-presses
              }
          };
      }]);
 +
 +    ngApp.directive('commentReply', [function () {
 +        return {
 +            restrict: 'E',
 +            templateUrl: 'comment-reply.html',
 +            scope: {
 +              pageId: '=',
 +              parentId: '=',
 +              parent: '='
 +            },
 +            link: function (scope, element) {
 +                scope.isReply = true;
 +                element.find('textarea').focus();
 +                scope.$on('evt.comment-success', function (event) {
 +                    // no need for the event to do anything more.
 +                    event.stopPropagation();
 +                    event.preventDefault();
 +                    element.remove();
 +                    scope.$destroy();
 +                });
 +            }
 +        }
 +    }]);
 +
 +    ngApp.directive('commentEdit', [function () {
 +         return {
 +            restrict: 'E',
 +            templateUrl: 'comment-reply.html',
 +            scope: {
 +              comment: '=',
 +            },
 +            link: function (scope, element) {
 +                scope.isEdit = true;
 +                element.find('textarea').focus();
 +                scope.$on('evt.comment-success', function (event, commentId) {
 +                   // no need for the event to do anything more.
 +                   event.stopPropagation();
 +                   event.preventDefault();
 +                   if (commentId === scope.comment.id && !scope.isNew) {
 +                       element.remove();
 +                       scope.$destroy();
 +                   }
 +                });
 +            }
 +        }
 +    }]);
 +
 +
 +    ngApp.directive('commentReplyLink', ['$document', '$compile', '$http', function ($document, $compile, $http) {
 +        return {
 +            scope: {
 +                comment: '='
 +            },
 +            link: function (scope, element, attr) {
 +                element.on('$destroy', function () {
 +                    element.off('click');
 +                    scope.$destroy();
 +                });
 +
 +                element.on('click', function () {
 +                    var $container = element.parents('.comment-box').first();
 +                    if (!$container.length) {
 +                        console.error('commentReplyLink directive should be placed inside a container with class comment-box!');
 +                        return;
 +                    }
 +                    if (attr.noCommentReplyDupe) {
 +                        removeDupe();
 +                    }
 +
 +                    compileHtml($container, scope, attr.isReply === 'true');
 +                });
 +            }
 +        };
 +
 +        function compileHtml($container, scope, isReply) {
 +            let lnkFunc = null;
 +            if (isReply) {
 +                lnkFunc = $compile('<comment-reply page-id="comment.pageId" parent-id="comment.id" parent="comment"></comment-reply>');
 +            } else {
 +                lnkFunc = $compile('<comment-edit comment="comment"></comment-add>');
 +            }
 +            var compiledHTML = lnkFunc(scope);
 +            $container.append(compiledHTML);
 +        }
 +
 +        function removeDupe() {
 +            let $existingElement = $document.find('.comments-list comment-reply');
 +            if (!$existingElement.length) {
 +                return;
 +            }
 +
 +            $existingElement.remove();
 +        }
 +    }]);
  };
index 541e9fbaf69610bdeb588ae30b2ef73c21f9105c,afb9d531bd4a82ae8b17410083f97e1f6b0ab875..3b279b8bd29c9eb523f468225ded1373d72a31b6
  @import "forms";
  @import "animations";
  @import "tinymce";
- @import "highlightjs";
+ @import "codemirror";
  @import "components";
  @import "header";
  @import "lists";
  @import "pages";
 +@import "comments";
  
  [v-cloak], [v-show] {
    display: none; opacity: 0;
index db1d1e5cdbab4d66ebb9a7f64f7abe4359fca330,6b2dc3c2319a7c7656fe4fb86c9926ed57dcb787..480a7603e515505f028e704c66a556d4a9b2d33d
  
          </div>
      </div>
--
 +    <div class="container">
 +        <div class="row">
 +            <div class="col-md-9">
 +                @include('comments/comments', ['pageId' => $page->id])
 +            </div>
 +        </div>
-     </div>
-     @include('partials/highlight')
++    </div>    
  @stop
  
  @section('scripts')
      <script>
-         var defaultAvatar = '{{baseUrl('/user_avatar.png')}}';
          setupPageShow({{$page->id}});
      </script>
  @stop