Редактор Ace: блокировка или сегмент кода только для чтения

Могу ли я с помощью редактора кода Ace заблокировать или сделать сегмент кода только для чтения, но при этом разрешить запись или редактирование других строк кода во время сеанса?


person Chris    schedule 25.07.2014    source источник
comment
Вам нужен только один сегмент или несколько? можно ли удалить весь сегмент? Если выделение включает часть сегмента, доступного только для чтения, и пользователь нажимает кнопку «Удалить», следует ли удалить остальную часть выделенного текста?   -  person a user    schedule 26.07.2014


Ответы (3)


Вот начало решения:

$(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();
    }
});

посмотрите, как это работает в этой скрипке: http://jsfiddle.net/bzwheeler/btsxgena/

Основные рабочие части:

  1. создать начальную и конечную привязки ace, которые отслеживают местоположение части «только для чтения» по мере изменения документа вокруг нее.
  2. создать диапазон для инкапсуляции якорей
  3. добавьте пользовательский обработчик клавиш, чтобы проверить, повлияет ли текущее предстоящее нажатие клавиши на диапазон только для чтения, и отменить его, если это так.
  4. добавить пользовательские обработчики вставки/вырезания для защиты от контекстного меню и действий вырезания/вставки в меню браузера
person bzwheeler    schedule 17.10.2014
comment
У меня проблемы с пониманием того, что происходит в функции «до», но я знаю, что «origArgs» никогда не определяется и вызывает рвоту «preventReadOnly», когда он пытается вызвать next() после вырезания или вставки. - person Southerneer; 26.02.2016
comment
Хороший улов! Я отредактировал реализацию before(), чтобы использовать .call и передать args, а не origArgs, который, как вы заметили, не определен. - person bzwheeler; 05.04.2016
comment
что здесь делает addKeyboardHandler? Пожалуйста, объясните. - person rjohari23; 27.04.2017
comment
Как сделать несколько строк только для чтения. Передавая массив диапазона, т.е. начало и конец. - person G Naga Subrahmanyam; 06.04.2018

Вы можете сделать это, прослушивая события exec:

// Prevent editing first and last line of 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/

person Hugodby    schedule 06.02.2019

Я предлагаю что-то еще более простое и надежное, чтобы предотвратить изменение диапазона (проверьте!)

var old$tryReplace = editor.$tryReplace;
editor.$tryReplace = function(range, replacement) {
    return intersects(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 intersects(range)?false:oldRemove.apply(this, arguments);                        
}
var oldMoveText = session.moveText;
session.moveText = function(fromRange, toPosition, copy) {
    if (intersects(fromRange) || !outsideRange(toPosition)) return fromRange;
    return oldMoveText.apply(this, arguments)
}

outsideRange = function (position) {
    var s0 = range.start;
    if (position.row < s0.row || (position.row == s0.row && position.column <= s0.column)) return true; // position must be before range.start
    var e0 = range.end;
    if (position.row > e0.row || (position.row == e0.row && position.column >= e0.column)) return true; // or after range.end
    return false;
}
intersects = function(withRange) {
    var e = withRange.end, s0 = range.start, s = withRange.start, e0 = range.end;
    if (e.row < s0.row || (e.row == s0.row && e.column <= s0.column)) return false; // withRange.end must be before range.start
    if (s.row > e0.row || (s.row == e0.row && s.column >= e0.column)) return false; // or withRange.start must be after range.end
    return true;
}
person user6871461    schedule 23.09.2016