【问题标题】:angularjs textarea with colors (with html5 contenteditable)带有颜色的angularjs textarea(带有html5 contenteditable)
【发布时间】:2016-02-18 16:21:39
【问题描述】:

我正在尝试创建一个执行“语法高亮”的编辑器, 这很简单:

yellow -> <span style="color:yellow">yellow</span>

我也是用&lt;code contenteditable&gt;html5标签代替&lt;textarea&gt;,并有颜色输出。

我从 angularjs 文档开始,并创建了以下简单指令。它确实有效,除了它不使用生成的 html 更新 contenteditable 区域。 如果我使用element.html(htmlTrusted) 而不是ngModel.$setViewValue(htmlTrusted),一切正常,除了每次按键时光标都会跳到开头。

指令:

app.directive("contenteditable", function($sce) {
  return {
    restrict: "A", // only activate on element attribute
    require: "?ngModel", // get ng-model, if not provided in html, then null
    link: function(scope, element, attrs, ngModel) {
      if (!ngModel) {return;} // do nothing if no ng-model

      element.on('blur keyup change', function() {
        console.log('app.directive->contenteditable->link->element.on()');
        //runs at each event inside <div contenteditable>
        scope.$evalAsync(read);
      });

       function read() {
         console.log('app.directive->contenteditable->link->read()');
         var html = element.html();
        // 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 = '';
        }

        html = html.replace(/&lt;/, '<');
        html = html.replace(/&gt;/, '>');
        html = html.replace(/<span\ style=\"color:\w+\">(.*?)<\/span>/g, "$1");

        html = html.replace('yellow', '<span style="color:yellow">yellow</span>');
        html = html.replace('green', '<span style="color:green">green</span>');
        html = html.replace('purple', '<span style="color:purple">purple</span>');
        html = html.replace('blue', '<span style="color:yellow">blue</span>');

        console.log('read()-> html:', html);
        var htmlTrusted = $sce.trustAsHtml(html);
        ngModel.$setViewValue(htmlTrusted);
      }
      read(); // INITIALIZATION, run read() when initializing
    }
  };
});  

html:

<body ng-app="MyApp">

 <code contenteditable
      name="myWidget" ng-model="userContent"
      strip-br="true"
      required>This <span style="color:purple">text is purple.</span> Change me!</code>
 <hr>
 <pre>{{userContent}}</pre>

</body>

plunkr:demo(输入 yellowgreenblue 到更改我的输入区域)

我试过scope.$apply()ngModel.$render(),但没有效果。我必须错过一些非常明显的东西......

我已经阅读过的链接:

非常感谢任何帮助。请参阅上面的 plunker 演示。

【问题讨论】:

    标签: angularjs angularjs-directive contenteditable angularjs-sce


    【解决方案1】:

    将近一年后,我终于落户Codemirror,我从未如此快乐过。 我正在使用实时更新进行并行 Markdown 源代码编辑(带有语法突出显示,因此甚至比 stackoverflow 的编辑页面更高级。)

    我创建了一个简单的 codeEditor 角度指令,它需要 codeMirror,并使用它。

    为了完整起见,这里是组件源代码:

    $ cat components/codeEditor/code-editor.html
    <div class="code-editor"></div>
    
    $ cat codeEditor.js 
    'use strict';
    
    angular.module('myApp')
    .directive('codeEditor', function($timeout, TextUtils){
      return {
        restrict: 'E',
        replace: true,
        require: '?ngModel',
        transclude: true,
        scope: {
          syntax: '@',
          theme: '@'
        },
        templateUrl: 'components/codeEditor/code-editor.html',
        link: function(scope, element, attrs, ngModelCtrl, transclude){
          // Initialize Codemirror
          var option = {
            mode: scope.syntax || 'xml',
            theme: scope.theme || 'default',
            lineNumbers: true
          };
          if (option.mode === 'xml') {
            option.htmlMode = true;
          }
    
          scope.$on('toedit', function () { //event
            //This is required to correctly refresh the codemirror view.
            // otherwise the view stuck with 'Both <code...empty.' initial text.
            $timeout(function() {
              editor.refresh();
            });
          });
    
          // Require CodeMirror
          if (angular.isUndefined(window.CodeMirror)) {
            throw new Error('codeEditor.js needs CodeMirror to work... (o rly?)');
          }
    
          var editor = window.CodeMirror(element[0], option);
    
          // Handle setting the editor when the model changes if ngModel exists
          if(ngModelCtrl) {
            // Timeout is required here to give ngModel a chance to setup. This prevents
            // a value of undefined getting passed as the view is rendered for the first
            // time, which causes CodeMirror to throw an error.
            $timeout(function(){
              ngModelCtrl.$render = function() {
                if (!!ngModelCtrl.$viewValue) {
                  // overwrite <code-editor>SOMETHING</code-editor>
                  // if the $scope.content.code (ngModelCtrl.$viewValue) is not empty.
                  editor.setValue(ngModelCtrl.$viewValue); //THIRD happening
                }
              };
              ngModelCtrl.$render();
            });
          }
    
          transclude(scope, function(clonedEl){
            var initialText = clonedEl.text();
            if (!!initialText) {
              initialText = TextUtils.normalizeWhitespace(initialText);
            } else {
              initialText = 'Both <code-editor> tag and $scope.content.code is empty.';
            }
            editor.setValue(initialText); // FIRST happening
    
            // Handle setting the model if ngModel exists
            if(ngModelCtrl){
              // Wrap these initial setting calls in a $timeout to give angular a chance
              // to setup the view and set any initial model values that may be set in the view
              $timeout(function(){
                // Populate the initial ng-model if it exists and is empty.
                // Prioritize the value in ngModel.
                if(initialText && !ngModelCtrl.$viewValue){
                  ngModelCtrl.$setViewValue(initialText); //SECOND happening
                }
    
                // Whenever the editor emits any change events, update the value
                // of the model.
                editor.on('change', function(){
                  ngModelCtrl.$setViewValue(editor.getValue());
                });
              });
            }
          });
    
          // Clean up the CodeMirror change event whenever the directive is destroyed
          scope.$on('$destroy', function(){
            editor.off('change');
          });
        }
      };
    });
    

    components/codeEditor/vendor 目录内还有完整的 codemirror 源代码。

    我强烈推荐codeMirror。它是一个坚如磐石的组件,适用于 每个浏览器组合(firefox、firefox for android、chromium)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-01
      • 2013-12-07
      • 1970-01-01
      相关资源
      最近更新 更多