Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make multiple chunk of lines readonly in ace editor

I tried to make parts of code read-only in Ace editor.

I have tried by using code given in JsFiddle

$(function() {
    var editor     = ace.edit("editor1")
        , session  = editor.getSession()
        , Range    = require("ace/range").Range
        , range    = new Range(1, 4, 1, 10)
        , markerId = session.addMarker(range, "readonly-highlight");

    session.setMode("ace/mode/javascript");
    editor.keyBinding.addKeyboardHandler({
        handleKeyboard : function(data, hash, keyString, keyCode, event) {
            if (hash === -1 || (keyCode <= 40 && keyCode >= 37)) return false;

            if (intersects(range)) {
                return {command:"null", passEvent:false};
            }
        }
    });

    before(editor, 'onPaste', preventReadonly);
    before(editor, 'onCut',   preventReadonly);

    range.start  = session.doc.createAnchor(range.start);
    range.end    = session.doc.createAnchor(range.end);
    range.end.$insertRight = true;

    function before(obj, method, wrapper) {
        var orig = obj[method];
        obj[method] = function() {
            var args = Array.prototype.slice.call(arguments);
            return wrapper.call(this, function(){
                return orig.apply(obj, args);
            }, args);
        }

        return obj[method];
    }

    function intersects(range) {
        return editor.getSelectionRange().intersects(range);
    }

    function preventReadonly(next, args) {
        if (intersects(range)) return;
        next();
    }
});

I got a problem when I keep pressing backspace it went into the read-only part and there was no editable part left.

How can I make multiple chunks of code read-only and avoid last character from read-only getting deleted.

Also, how to achieve the whole thing dynamically where I have markers in text specifying editable portions ?

like image 654
Bhavani Ravi Avatar asked Sep 22 '16 13:09

Bhavani Ravi


2 Answers

Check the below code that allows multiple chunk of lines read-only with Enter at end of range to prevent non reversible delete and drag/drop handled.

function set_readonly(editor,readonly_ranges) {
      var  session  = editor.getSession()
          , Range    = require("ace/range").Range;
          ranges    = [];

      function before(obj, method, wrapper) {
        var orig = obj[method];
        obj[method] = function() {
          var args = Array.prototype.slice.call(arguments);
          return wrapper.call(this, function(){
              return orig.apply(obj, args);
          }, args);
        }
        return obj[method];
      }
      function intersects(range) {
          return editor.getSelectionRange().intersects(range);
      }
      function intersectsRange(newRange) {
        for (i=0;i<ranges.length;i++)
          if(newRange.intersects(ranges[i]))
            return true;
        return false;
      }
      function preventReadonly(next, args) {
          for(i=0;i<ranges.length;i++){if (intersects(ranges[i])) return;}
          next();
      }
      function onEnd(position){
        var row = position["row"],column=position["column"];
        for (i=0;i<ranges.length;i++)
          if(ranges[i].end["row"] == row && ranges[i].end["column"]==column)
            return true;
        return false;
      }
      function outSideRange(position){
        var row = position["row"],column=position["column"];
        for (i=0;i<ranges.length;i++){
          if(ranges[i].start["row"]< row && ranges[i].end["row"]>row)
              return false;
          if(ranges[i].start["row"]==row && ranges[i].start["column"]<column){
              if(ranges[i].end["row"] != row || ranges[i].end["column"]>column)
                return false;
          }
          else if(ranges[i].end["row"] == row&&ranges[i].end["column"]>column){
                return false;
          }
        }
        return true; 
      }
      for(i=0;i<readonly_ranges.length;i++){
        ranges.push(new Range(...readonly_ranges[i]));
      }
      ranges.forEach(function(range){session.addMarker(range, "readonly-highlight");});
      session.setMode("ace/mode/javascript");
      editor.keyBinding.addKeyboardHandler({
          handleKeyboard : function(data, hash, keyString, keyCode, event) {
            if (Math.abs(keyCode) == 13 && onEnd(editor.getCursorPosition())){
              return false;
            }
            if (hash === -1 || (keyCode <= 40 && keyCode >= 37)) return false;
            for(i=0;i<ranges.length;i++){
              if (intersects(ranges[i])) {
                  return {command:"null", passEvent:false};
              }
            }
          }
      });
      before(editor, 'onPaste', preventReadonly);
      before(editor, 'onCut',   preventReadonly);
      for(i=0;i<ranges.length;i++){
        ranges[i].start  = session.doc.createAnchor(ranges[i].start);
        ranges[i].end    = session.doc.createAnchor(ranges[i].end);
        ranges[i].end.$insertRight = true;
       }

      var old$tryReplace = editor.$tryReplace;
      editor.$tryReplace = function(range, replacement) {
          return intersectsRange(range)?null:old$tryReplace.apply(this, arguments);                        
      }
      var session = editor.getSession();
      var oldInsert = session.insert;
      session.insert = function(position, text) {
          return oldInsert.apply(this, [position, outSideRange(position)?text:""]);
      }
      var oldRemove = session.remove;
      session.remove = function(range) {
          return intersectsRange(range)?false:oldRemove.apply(this, arguments);                        
      }
      var oldMoveText = session.moveText;
      session.moveText = function(fromRange, toPosition, copy) {
          if (intersectsRange(fromRange) || !outSideRange(toPosition)) return fromRange;
          return oldMoveText.apply(this, arguments);
      }

}
function refresheditor(id,content,readonly) {
      var temp_id=id+'_temp';
      document.getElementById(id).innerHTML="<div id='"+temp_id+"'></div>";
      document.getElementById(temp_id).innerHTML=content;
      var editor     = ace.edit(temp_id);
      set_readonly(editor,readonly);

}

function get_readonly_by_editable_tag(id,content){
  var text= content.split("\n");
  var starts=[0],ends=[];
  text.forEach(function(line,index){
    if((line.indexOf("&lt;editable&gt;") !== -1))ends.push(index);
    if((line.indexOf("&lt;/editable&gt;") !== -1))starts.push(index+1);
  });
  ends.push(text.length);
  var readonly_ranges=[];
  for(i=0;i<starts.length;i++){
    readonly_ranges.push([starts[i],0,ends[i],0])
  }
  refresheditor(id,content,readonly_ranges);
}
var content=document.getElementById("code").innerHTML;
function readonly_lines(id,content,line_numbers){
  var readonly_ranges=[];
  all_lines= line_numbers.sort();
 
  for(i=0;i<line_numbers.length;i++){
    readonly_ranges.push([line_numbers[i]-1,0,line_numbers[i],0]);
  }
  refresheditor(id,content,readonly_ranges);
}
get_readonly_by_editable_tag("myeditor",content)
//readonly_lines("myeditor",content,[5,7,9]);
.ace_editor {
    width:100%;
    height:300px;
}
.readonly-highlight{
    background-color: red;
    opacity: 0.2;
    position: absolute;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://ace.c9.io/build/src/ace.js"></script>
<link rel="stylesheet" type="text/css" href="http://jsfiddle.net/css/normalize.css">
<link rel="stylesheet" type="text/css" href="http://jsfiddle.net/css/result-light.css">

<button onclick="get_readonly_by_editable_tag('myeditor',content)">Readonly by tags</button>
<button onclick="readonly_lines('myeditor',content,[3,7])">Readonly lines 3 and 7 </button>
  <div id="myeditor" ></div>
  <div id="code" style="display:none;">//&lt;editable&gt;
//&lt;/editable&gt;
function refresheditor() {
   //&lt;editable&gt;
   document.getElementById("myeditor").innerHTML="&lt;div id='editor'&gt;&lt;/div&gt;";
   document.getElementById("editor").innerHTML=document.getElementById("code").innerHTML;
   //&lt;/editable&gt;
    var editor     = ace.edit("editor")
        , session  = editor.getSession()
        , Range    = require("ace/range").Range;
        ranges    = [];
        var text= document.getElementById("code").innerHTML.split("\n");
        var starts=[0],ends=[];
        text.forEach(function(line,index){
          if((line.indexOf("&amp;lt;editable&amp;gt;") !== -1))ends.push(index);
          if((line.indexOf("&amp;lt;/editable&amp;gt;") !== -1))starts.push(index+1);
        });
        ends.push(text.length);
        for(i=0;i&lt;starts.length;i++){
          ranges.push(new Range(starts[i], 0,ends[i] ,0));
        }
        ranges.forEach(function(range){session.addMarker(range, "readonly-highlight");});
    session.setMode("ace/mode/javascript");
    //&lt;editable&gt;
    editor.keyBinding.addKeyboardHandler({
        handleKeyboard : function(data, hash, keyString, keyCode, event) {
            var pos=editor.getCursorPosition();
            if (Math.abs(keyCode) == 13){
		 for (i=0;i&lt;ranges.length;i++){
			if((ranges[i].end["row"]==pos["row"])&&(ranges[i].end["column"]==pos["column"])){ return false;}
		 }
	    }
            if (hash === -1 || (keyCode &lt;= 40 && keyCode &gt;= 37)) return false;
            for(i=0;i&lt;ranges.length;i++){
              if (intersects(ranges[i])) {
                  return {command:"null", passEvent:false};
              }
            }
        }
    });
    //&lt;/editable&gt;
    before(editor, 'onPaste', preventReadonly);
    before(editor, 'onCut',   preventReadonly);
    for(i=0;i&lt;ranges.length;i++){
      ranges[i].start  = session.doc.createAnchor(ranges[i].start);
      ranges[i].end    = session.doc.createAnchor(ranges[i].end);
      ranges[i].end.$insertRight = true;
     }
    function before(obj, method, wrapper) {
        var orig = obj[method];
        obj[method] = function() {
            var args = Array.prototype.slice.call(arguments);
            return wrapper.call(this, function(){
                return orig.apply(obj, args);
            }, args);
        }
        return obj[method];
    }
    function intersects(range) {
        return editor.getSelectionRange().intersects(range);
    }
    function preventReadonly(next, args) {
        for(i=0;i&lt;ranges.length;i++){if (intersects(ranges[i])) return;}
        next();
    }
}
refresheditor();
        
</div>
like image 154
Mr. A Avatar answered Nov 15 '22 18:11

Mr. A


This code snippet will prevent the user from editing the first or last line of the editor:

editor.commands.on("exec", function(e) { 
  var rowCol = editor.selection.getCursor();
  if ((rowCol.row == 0) || ((rowCol.row + 1) == editor.session.getLength())) {
    e.preventDefault();
    e.stopPropagation();
  }
});

https://jsfiddle.net/tripflex/y0huvc1b/

Source: https://groups.google.com/forum/#!topic/ace-discuss/yffGsSG7GSA

like image 27
sMyles Avatar answered Nov 15 '22 18:11

sMyles