angularjs textarea与颜色(与html5 contenteditable)

时间:2016-02-18 16:21:40

标签: angularjs angularjs-directive contenteditable angularjs-sce

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

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

我也使用<code contenteditable> html5标记来替换<textarea>,并且有颜色输出。

我从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演示。

1 个答案:

答案 0 :(得分:0)

差不多一年后,我终于安顿下来了Codemirror,我从未开心过。 我正在使用实时更新进行并排降价源编辑(使用语法高亮显示,所以甚至比stackoverflow的编辑页面更先进。)

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

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

[ttt] grep -C2 ZZZZ CMakeFiles/t.dir/build.make

CMakeFiles/t:
    echo `printenv ZZZZ`...

t : CMakeFiles/t

$ 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'); }); } }; }); 目录中还有完整的codemirror源代码。

我强烈推荐codeMirror。它是一个rockolid组件,工作于 每个浏览器组合(firefox,firefox for android,chromium)。