【问题标题】:Google pagedown AngularJS directive谷歌 pagedown AngularJS 指令
【发布时间】:2014-01-03 16:55:02
【问题描述】:

请参阅问题底部以了解针对此问题的改进解决方案

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

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

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

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

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

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

更新

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

【问题讨论】:

  • 我终于能够重现你的错误...
  • @llan - 很高兴听到它,但不确定解决方案。我用尽可能大的赏金将我的问题打包在这里。希望能找到喜欢挑战的人。肯定有很多人想在 AngularJS 中使用 pagedown,所以我希望有人能提出解决方案。
  • 一定要使用300ms延迟吗?
  • 不,我只是补充说,因为我认为当用户快速单击按键时可能会降低性能。顺便说一句,如果你想出一个解决方案,如果你能把它放到一个 plunker 或 fiddler 或其他东西中,这样我就可以测试它,我们可以有一些共同的东西可以使用。我的 plunker 技能几乎为零,所以我不知道如何制作一个显示带有几个按钮的侧边栏和一个带有编辑窗口的屏幕区域的工具。
  • 将您在赏金描述中写的描述放在问题文本本身中会更有意义!

标签: angularjs angularjs-directive pagedown


【解决方案1】:

这是一个有效的链接:

http://cssdeck.com/labs/qebukp9k

更新

  • 我做了一些优化。
  • 我使用 ngModel.$formatters !无需再购买 $watch。
  • 我使用 $timeout 然后使用 scope.$apply 来避免 $digest in progress 错误。

Angular.js 和性能

  • 如果您达到了性能,可能是您的应用程序使用了太多的 $watch / $on。
  • 根据我的经验,使用 3rd 方库可能会导致各种低效/内存泄漏行为,主要是因为在实现时未考虑到 Angular/SPA。
  • 我能够对某些库进行一些智能集成,但有些库不能很好地适应 Angular 的世界。
  • 如果您的应用程序必须显示 1000 多个问题,您可能应该从编写自定义转发器开始,并且更喜欢动态 DOM 插入。
  • Angular.js 无法很好地处理大量数据绑定,除非您愿意编写一些智能的低级内容(当您知道如何编写时,这真的很有趣!)。
  • 再次强调,更喜欢分页!正如 Misko Hevery 所说:“你不能在一个页面上向人类显示超过 2000 条信息。超过这个范围的用户界面真的很糟糕,人类无论如何也无法处理这些”。
  • 阅读:How does data binding work in 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();
        }
    }
});

【讨论】:

  • @llan - 您的代码对我有用,但与使用 1.2.2 的原始代码相比,它在我的应用程序中非常慢。当我快速输入 5-6 个单词时,它们可能需要 3-4 秒才能出现在屏幕上。我试图弄清楚为什么你的例子效果很好,但我的例子很慢。顺便说一句,你说你能够重现我的问题。这是否意味着你可以让它在 1.2.2 中工作。但不是在 1.2.3 中?我注意到这些版本之间的更改包括对“修复(输入):支持现代浏览器上的自动完成表单”的更改我想知道我的代码不起作用的原因是否与此有关
  • @llan - 感谢您的帮助!第二版效果很好。我现在注意到您刚刚进行了更多改进,因此我将很快进行测试。我可以请您在文件顶部添加一个单词注释,例如 // 3.1,以便我知道您何时进行更改。我在问题中添加了一件小事,并提到我的指令在表单中。在表单提交按钮上,我检查是否已进行更改。看来您的代码不会更改 $pristine 的值。您是否可以进行更改,以便在进行更改时使表单“变脏”?
  • 看起来我的上一个版本已经将 $pristine 设置为 false。我使用 ngModel.$render() 所以它可能会自动设置 $pristine。您可以查看:cssdeck.com/labs/qebukp9k
  • 已修复!我添加了填充/取消填充按钮,以便您了解它是如何工作的。
  • 我做了另一个更改(所有指令中使用相同的 Markdown.Converter)至于它很慢,我删除了所有 $watchers 和隔离范围绑定,您的编辑器应该尽可能快涉及代码。
【解决方案2】:

你可以改变这个:

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);
    ...    

}

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

【讨论】:

  • 我相信这是在其他 pagedown 指令之一中。我现在会尝试并报告。谢谢
  • 我按照您的建议进行了更改,但仍然无法正常工作。结果是一样的。
  • 我把它作为另一张海报放在申请中,然后说它应该在 $apply 中。也许其他人可以对此发表评论。谢谢
  • 你能把这段代码注释掉再试一次吗 if (val !== undefined) { $wmdInput.val(val); editor.refreshPreview(); }
  • 注释掉它就可以了。但它没有填充 modal.data.text 的初始值。当窗口打开时,它是空白的。当我添加字母时,它们会正确添加。请注意,顺序是指令更改 DOM,然后我的 HTTP 调用返回以填充数据。我确实尝试在我的控制器中强制输入日期: $("#wmd-input-question-text").val ($scope.modal.data.text);但是我认为这不是推荐的方法,而且非常混乱,因为我必须在任何地方进行更改。
【解决方案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);
    }
  };

【讨论】:

  • 感谢您的链接,但我真的需要一个像 stackoverflow 这样的编辑器的解决方案,因为用户希望能够点击代码等按钮。
  • 这可以使用 element.wrap() 更简化,它会删除所有与 ng-model 相关的代码。
【解决方案4】:

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

总结

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

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

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

【讨论】:

  • 我在尝试让您的代码在我的应用程序中运行时遇到问题。您使用了 templateUrl,也许这是我的问题的一部分。我确实将模板添加到了我的页面,但出现了各种错误,并且没有显示编辑按钮。您能否尝试更改您的代码,使其看起来尽可能像我的原始代码,以便轻松插入和尝试。同样在您的示例 plnkr 中,您可以尝试在 ng-repeat 中放入多个 pagedown 实例。这样就和我一样了。非常感谢您迄今为止的帮助。
  • @SamanthaJ 感谢您的信息。我更新了我的代码并删除了templateUrl。还在演示中添加了ng-repeat。但是,如果您看不到编辑器栏按钮图标,则需要检查您的 css 是否有 .wmd-button &gt; span { background-image: url(../../wmd-buttons.png); },因为工具栏按钮的图标不受 JS 控制。让我知道您的问题的任何进一步发展。
  • @SamanthaJ 我添加了&lt;link rel="stylesheet" href="http://pagedown.googlecode.com/hg/demo/browser/demo.css"&gt; 以确保图标显示出来。
猜你喜欢
  • 2013-09-23
  • 1970-01-01
  • 2016-05-23
  • 2016-01-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多