Google pagedown AngularJS directive

淺唱寂寞╮ 提交于 2019-11-29 21:00:49
Ilan Frumer

Here is a working link:

http://cssdeck.com/labs/qebukp9k

UPDATE

  • I made some optimizations.
  • I use ngModel.$formatters ! no need for another $watch.
  • I use $timeout and then scope.$apply to avoid $digest in progress errors.

Angular.js & Performance

  • If you hit performance maybe your application is using too many $watch / $on.
  • In my experience, using 3rd-party libraries can cause all sort of non efficient / memory leaking behavior, mostly because it was not implemented with angular / SPA in mind.
  • I was able to do some smart integration for some libraries but some just don't fit well to angular's world.
  • If your application must show 1000+ questions you should probably start with writing your custom repeater, and prefer dynamic DOM insertions.
  • Angular.js will not perform well with tons of data bindings unless you are willing to write some smart lower level stuff (It's actually fun when you know how!).
  • Again, prefer pagination! As Misko Hevery says: "You can't really show more than about 2000 pieces of information to a human on a single page. Anything more than that is really bad UI, and humans can't process this anyway".
  • Read this: How does data binding work in AngularJS?
  • I'm more than happy to help you, but First let me show the code (contact me)..

Solution:

var app = angular.module('App', []);

app.directive('pagedownAdmin', function ($compile, $timeout) {
    var nextId = 0;
    var converter = Markdown.getSanitizingConverter();
    converter.hooks.chain("preBlockGamut", function (text, rbg) {
        return text.replace(/^ {0,3}""" *\n((?:.*?\n)+?) {0,3}""" *$/gm, function (whole, inner) {
            return "<blockquote>" + rbg(inner) + "</blockquote>\n";
        });
    });

    return {
        require: 'ngModel',
        replace: true,
        template: '<div class="pagedown-bootstrap-editor"></div>',
        link: function (scope, iElement, attrs, ngModel) {

            var editorUniqueId;

            if (attrs.id == null) {
                editorUniqueId = nextId++;
            } else {
                editorUniqueId = attrs.id;
            }

            var newElement = $compile(
                '<div>' +
                   '<div class="wmd-panel">' +
                      '<div id="wmd-button-bar-' + editorUniqueId + '"></div>' +
                      '<textarea class="wmd-input" id="wmd-input-' + editorUniqueId + '">' +
                      '</textarea>' +
                   '</div>' +
                   '<div id="wmd-preview-' + editorUniqueId + '" class="pagedown-preview wmd-panel wmd-preview"></div>' +
                '</div>')(scope);

            iElement.html(newElement);

            var help = function () {
                alert("There is no help");
            }

            var editor = new Markdown.Editor(converter, "-" + editorUniqueId, {
                handler: help
            });

            var $wmdInput = iElement.find('#wmd-input-' + editorUniqueId);

            var init = false;

            editor.hooks.chain("onPreviewRefresh", function () {
              var val = $wmdInput.val();
              if (init && val !== ngModel.$modelValue ) {
                $timeout(function(){
                  scope.$apply(function(){
                    ngModel.$setViewValue(val);
                    ngModel.$render();
                  });
                });
              }              
            });

            ngModel.$formatters.push(function(value){
              init = true;
              $wmdInput.val(value);
              editor.refreshPreview();
              return value;
            });

            editor.run();
        }
    }
});

You can change this:

scope.$watch(attrs.ngModel, function () {
var val = scope.$eval(attrs.ngModel);

For this:

scope.$watch(attrs.ngModel, function(newValue, oldValue) {
  var val = newValue;
});

Additionally can try commenting this code out:

if (val !== undefined) {
    $wmdInput.val(val);
    ...    

}

I think it may be associated with the odd behavior.

It might not be the answer, but all the problem occurs when you start using Markdown.Editor which does not gives you a lot of benefits.

Of course, you need to use it for markdown editor beginners, but when use markdown, they are already not beginners anyway(I might be wrong).

What I approached to this problem was to make fully working version of this without using editor.

It has preview also.

It's also very simple.

https://github.com/allenhwkim/wiki

---- edit ----
removed
---- edit ----
removed
---- edit ----

To provide a fully working editor, after few hours of trial and asking questions, the following is the simplest I can get. This does require any $watch nor $formatters. It just wraps the given element with all attributes given by the textarea.

http://plnkr.co/edit/jeZ5EdLwOfwo6HzcTAOR?p=preview

app.directive('pagedownEditor', function($compile, $timeout) {
  var num=0;
  return {
    priority: 1001, //higher than ng-repeat, 1000
    link: function(scope, el, attrs) {
      var uniqNum = scope.$index || num++;
      var wmdPanel = document.createElement('div');
      wmdPanel.className = "wmd-panel";
      var wmdButtonBar = document.createElement('div');
      wmdButtonBar.id = 'wmd-button-bar-'+uniqNum;
      wmdPanel.appendChild(wmdButtonBar);
      el.wrap(wmdPanel); // el is ng-repeat comment, it takes tim

      var converter = Markdown.getSanitizingConverter();
      var editor = new Markdown.Editor(converter, "-"+uniqNum);
      $timeout(function() {
        wmdPanel.querySelector('textarea').id = 'wmd-input-'+uniqNum;
        wmdPanel.querySelector('textarea').className += ' wmd-input';
        wmdPanel.insertAdjacentHTML('afterend', '<div id="wmd-preview-'+uniqNum+'" '
          +'class="pagedown-preview wmd-panel wmd-preview">');
        editor.run()
      }, 50);
    }
  };

Demo: http://plnkr.co/edit/FyywJS?p=preview

Summary

  1. I removed keyup and added a hook on onPreviewRefresh to ensure clicking on toolbar will properly update ng-model.

  2. Functions on $rootScope will demonstrate the ability to update ng-model from outside of pagedown.

  3. save functionality purely depends on your choice, since you can access ng-model anywhere now.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!