24

有关此问题的改进解决方案,请参见问题底部

我已经尝试了一段时间来获得 pagedown 工作的指令。这是 stackoverflow 使用的完全相同的编辑器。Stackoverflow 在此处提供此代码:

https://code.google.com/p/pagedown/

互联网上有一些版本,但没有一个很好用。我需要的是一个与所有编辑器按钮一起出现的按钮,就像 stackoverflow 一样,无论是内联编码还是内联作为 ngRepeat 的一部分。

我想让这个指令在使用 Angular 1.2.7 版本内联编码以及在 ng-repeat 中工作。需要的是,当模型数据发生变化时,指令需要更新 pagedown 视图以显示新的问题和答案。当用户更改 pagedown 编辑区域时,指令需要能够更新模型。当用户单击 [save] 时,模型数据需要保存到数据库(或至少保存到另一个对象以确认它有效)。

该指令需要能够响应模型中的更改,并将其原始数据保存到模型中,或者在编辑窗格中按下“更改”按钮时。这是我到目前为止所拥有的。请注意,此版本没有 $wmdInput.on('change' 但它是所需内容的开始。

最重要的是,我希望它与Angular 1.2.7和 jQuery 2.0.3版本一起工作请注意,我发现 1.2.2 和 1.2.7 版本之间的非工作代码存在差异。我认为最好有任何解决方案适用于最新(1.2.7)版本。

更新

我现在这个指令更简单,解决了我最近遇到的一些内容未显示的问题。我强烈建议使用这个指令,它基于接受的答案加上一些改进:https ://github.com/kennyki/angular-pagedown

4

4 回答 4

27

这是一个工作链接:

http://cssdeck.com/labs/qebukp9k

更新

  • 我做了一些优化。
  • 我使用 ngModel.$formatters !不需要另一个 $watch。
  • 我使用 $timeout 然后使用 scope.$apply 来避免 $digest in progress 错误。

Angular.js 和性能

  • 如果你达到了性能,可能你的应用程序使用了太多的 $watch / $on。
  • 根据我的经验,使用 3rd-party 库可能会导致各种非高效/内存泄漏行为,主要是因为它没有考虑到 angular/SPA 实现。
  • 我能够为某些库进行一些智能集成,但有些库不太适合 Angular 的世界。
  • 如果您的应用程序必须显示 1000 多个问题,您可能应该从编写自定义转发器开始,并且更喜欢动态 DOM 插入。
  • Angular.js 在处理大量数据绑定时表现不佳,除非您愿意编写一些智能的低级内容(当您知道如何编写时,这实际上很有趣!)。
  • 再次,更喜欢分页!正如 Misko Hevery 所说:“你不能在一个页面上向人类显示超过 2000 条信息。超过这个范围的用户界面真的很糟糕,人类无论如何也无法处理这些信息”。
  • 阅读本文:AngularJS 中的数据绑定如何工作?
  • 我很乐意为您提供帮助,但首先让我展示代码(联系我)..

解决方案:

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();
        }
    }
});
于 2014-01-06T19:14:22.267 回答
3

你可以改变这个:

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

为了这:

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

另外可以尝试注释掉这段代码:

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

}

我认为这可能与奇怪的行为有关。

于 2014-01-03T17:15:25.673 回答
3

这可能不是答案,但是当您开始使用 Markdown.Editor 时,所有问题都会出现,它不会给您带来很多好处。

当然,对于markdown编辑器初学者,你需要使用它,但是当使用markdown时,他们已经不是初学者了(我可能错了)。

我解决这个问题的方法是在不使用编辑器的情况下制作完整的工作版本。

它也有预览。

这也很简单。

https://github.com/allenhwkim/wiki

---- 编辑 ----
删除
---- 编辑 ----
删除
---- 编辑 ----

为了提供一个完整的编辑器,经过几个小时的试用和提问,以下是我能得到的最简单的。这确实需要任何 $watch 或 $formatters。它只是用 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);
    }
  };
于 2014-01-06T17:50:26.570 回答
1

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

概括

  1. 我删除keyup并添加了一个钩子onPreviewRefresh以确保单击工具栏将正确更新ng-model

  2. 上的函数$rootScope将演示ng-model从 pagedown 外部更新的能力。

  3. 保存功能完全取决于您的选择,因为您ng-model现在可以在任何地方访问。

于 2014-01-06T19:37:57.537 回答