Подтвердить что ты не робот

Как я могу "отменить" программную вставку текста в текстовое поле?

У меня есть текстовое поле и кнопка. Нажатие кнопки заставляет текст вставляться в текстовое поле.

Есть ли способ разрешить пользователю нажимать Ctrl/Cmd + z, чтобы отменить вставку текста и вернуть текстовое поле в прежнее состояние?

4b9b3361

Ответ 1

Вам нужно вставить текст особым образом, чтобы пользователь мог использовать нормальное поведение отменить/повторить.

var textEvent = document.createEvent('TextEvent');

textEvent.initTextEvent('textInput', true, true, null, "new text");

document.getElementById("your-textarea").dispatchEvent(textEvent);

Ответ 2

Сохраните исходное значение textarea в data:

var $textarea = $('textarea');

$('button').on('click', function () {
    var val = $textarea.val();

    $textarea.data('old-val', val).val(val + ' some text');
});

Если вы хотите, чтобы массив данных (как предлагал @ahren), используйте это:

var $textarea = $('textarea');

$('button').on('click', function () {
    var val = $textarea.val();

    if ( ! $textarea.data('old-val')) {
        $textarea.data('old-val', []);
    }

    $textarea.data('old-val').push(val);

    $textarea.val(val + ' some text');
});

Ответ 3

Я думаю, что самый простой подход к использованию стека браузера для отмены, а не для захвата событий.

Для этого вам нужно использовать разные коды для разных браузеров. К счастью из всех основных браузеров только Firefox имеет другой подход.

// http://stackoverflow.com/a/9851769/529024
// Opera 8.0+
var isOpera = (!!window.opr && !!opr.addons) || !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;

// Firefox 1.0+
var isFirefox = typeof InstallTrigger !== 'undefined';

// Safari 3.0+ "[object HTMLElementConstructor]" 
var isSafari = Object.prototype.toString.call(window.HTMLElement).indexOf('Constructor') > 0 || (function(p) {
  return p.toString() === "[object SafariRemoteNotification]";
})(!window['safari'] || safari.pushNotification);

// Internet Explorer 6-11
var isIE = /*@[email protected]*/ false || !!document.documentMode;

// Edge 20+
var isEdge = !isIE && !!window.StyleMedia;

// Chrome 1+
var isChrome = !!window.chrome && !!window.chrome.webstore;



var position = 0;

// text to anser
var text = 'Inserted Text';

// Just for fun :)
if (isFirefox)
  text = "  __ Firefox __ ";
else if (isIE)
  text = "  __ IE __ ";
else if (isEdge)
  text = "  __ Edge __ ";
else if (isSafari)
  text = "  __ Safari __ ";
else if (isOpera)
  text = "  __ Opera __ ";
else if (isChrome)
  text = "  __ Chrome __ ";

/* Adding text on click based on browser */
jQuery(".addText").on("click", function() {
  if (isFirefox) {
    // Firefox
    var val = jQuery(".textArea").val();

    var firstText = val.substring(0, position);
    var secondText = val.substring(position);

    jQuery(".textArea").val(firstText + text + secondText);
  } else {

    jQuery(".textArea").focus();
    var val = jQuery(".textArea").val();

    jQuery(".textArea")[0].selectionStart = position;
    jQuery(".textArea")[0].selectionEnd = position;

    document.execCommand('insertText', false, text);
  }
});

jQuery(".textArea").on("focusout", function(e) {
  position = jQuery(this)[0].selectionStart;
});
textarea {
  padding: 10px;
  font-family: Calibri;
  font-size: 18px;
  line-height: 1.1;
  resize: none;
}
.addText {
  padding: 5px 15px;
  transition: all 0.5s;
  border: 1px solid black;
  border-radius: 2px;
  background-color: #169c16;
  width: 70px;
  margin: 10px 0;
  color: white;
  cursor: pointer;
}
.addText:hover {
  background-color: #2776b9;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea name='textArea' class='textArea' rows="7" cols="50">Suspendisse convallis, metus at laoreet congue, sapien dui ornare magna, a porttitor felis purus a ipsum. Morbi vulputate erat rhoncus, luctus neque ut, lacinia orci. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis
  egestas. Fusce aliquam, nulla nec fringilla ultrices, ipsum lectus maximus nisl, ut laoreet purus lectus eget nisl. Duis blandit cursus nulla. Vestibulum consectetur, nunc non viverra condimentum, neque neque tincidunt diam, nec vestibulum neque nisi
  ac sem. Integer aliquam a leo id laoreet. Mauris ultrices mauris lorem, eu hendrerit odio volutpat ut. Nam eget hendrerit metus.</textarea>
<div class='addText'>
  Add Text
</div>

Ответ 4

$("#target").keypress(function(event) {
  if ( event.which == 'Z' && first press == 'Cmd' && second press == 'Ctrl') {//check for key press
     event.preventDefault();
    text.value = defaultValueForTextField
   }
});

Это должно быть то, что вы ищете. Первое и второе нажатие необходимо сохранить, как вы хотите, комбо-прессы. Вам действительно нужно сохранить текстовое значение по умолчанию.

Ответ 5

Вот мысль:

Если мы сможем генерировать события keyborad так же, как если бы пользователь вводил текстовое поле, тогда браузер автоматически сможет обрабатывать событие Undo. Поэтому вместо того, чтобы просто добавлять/изменять значение textarea, мы должны попытаться имитировать события клавиатуры для текста, который мы хотим вставить.

В соответствии с документацией в MDN (ссылки, приведенные ниже), мы можем использовать объект KeyboardEvent для создания таких событий, как:

  var e1 = new KeyboardEvent(<type>, <details>);
  var b1 = <textbox>.dispatchEvent(e1);

Где:

  • <type> представляет тип события, например keydown, keypress или keyup
  • <details> представляет объект, имеющий сведения о событии, такие как key, code
  • <textbox> представляет целевое текстовое поле, на котором мы хотим вызвать событие

Вот JSFiddle, где я попытался имитировать события keydown, keypress и keyup для каждого символа в заданной строке. Несмотря на то, что он запускает соответствующие обработчики событий, некоторые символы не отображаются/добавляются в текстовое поле.

Я заметил, что есть некоторые отличия в объекте события, сгенерированном при вводе a в стихах текстового поля, когда я имитирую 3 события для a с помощью моего кода. Различия (при тестировании в Firefox 50.1.0):

  • explicitOriginalTarget отличается от originalTarget, когда я имитирую события; и когда я печатаю текстовое поле, оба имеют одинаковое значение
  • rangeParent и rangeOffset значения null/0 при вводе в текстовое поле; и когда я имитирую события, у них есть некоторые значения.
  • isTrusted свойство true при вводе текстового поля; и когда я имитирую события его false (для любого события, сгенерированного с помощью script, он будет иметь false)

Ссылки MDN:

Ответ 6

Даже если этот вопрос год назад старый, я тоже хочу поделиться своим путем.

Вы можете сделать это следующим образом:

    $(function () {

  // Check to see if an array is not already defined.
  if (!$('#t').data('old-val')) {

    // If the check returns True we proceed to create an array in old-val.
    $('#t').data('old-val', []);

  }

  // Get the current content value.
  inputValue = $('#t').val();

  // Push it to the old-val array.
  $('#t').data('old-val').push(inputValue);

  // We start with a current array position of 0.
  curArrPos = 0;


  $('#c').click(function () {
    // Append a string to the #t.
    $('#t').val(' ==this is the 2nd appended text==');


    // Save the current content value.
    inputValue = $('#t').val();
    // Push it to the array.
    $('#t').data('old-val').push(inputValue);
    // Increment current array position.
    ++curArrPos;

  });


  $('#b').click(function () {
    // Append a string to the #t.
    $('#t').val(' ==this is the 1st appended text==');


    // Save the current content value.
    inputValue = $('#t').val();
    // Push it to the array.
    $('#t').data('old-val').push(inputValue);
    // Increment current array position.
    ++curArrPos;

  });

  $('#undo').click(function () {
    // First check that the old-val array length is greater than 1 (It the initial position. No need undoing to a blank state) and current array position greater than 0 (for the same reason).
    if ($('#t').data('old-val').length > 1 && curArrPos > 0) {

      // Set current #t value to the one in the current array position, minus one.
      // Minus one gets you to the previous array position (ex. current=5; previous= current - 1 = 4).
      $('#t').val($('#t').data('old-val')[curArrPos - 1]);

      // Decrease current array position, because we effectively shifted back by 1 position.
      --curArrPos;
    }
  });

  $('#redo').click(function () {
    if (currentArrayPos < $('#c').data('old-val').length - 1) {

      $('#t').val($('#t').data('old-val')[curArrPos + 1]);

      // Increase current array position, because we effectively shifted forward by 1 position.
      ++curArrPos;

    }
  });

});

Вот скрипка, если вы хотите поэкспериментировать с ней http://jsfiddle.net/45Jwz/1/

Я написал код, подобный этому, для хорошего понимания, но вы должны, конечно, написать реальный код лучше и менее подробный, чем это.

Ответ 7

Конкретные библиотеки и технологии сильно зависят от вашего стека.

Есть два общих способа, о которых я могу думать мгновенно.

Во-первых: Сохраните предыдущее состояние в контроллере. Вставьте ярлык и замените содержимое на предыдущее состояние. Если сделаны другие модификации, удалите крючок. Более-менее ваш подход к 2013 году

Это быстрый способ и не играет хорошо, если вы хотите иметь стек с историей редактирования более одного раза.

Во-вторых: Следите за текстом и периодически сохраняйте состояние в стеке. Захватите ярлык. (Возьмите весь процесс). Это более чистый способ, потому что ваша модификация концептуально совпадает с модификациями пользователя.

Это может быть довольно просто с архитектурой сокращения/потока http://redux.js.org/docs/recipes/ImplementingUndoHistory.html

Для захвата cmd/ctrl + z вы можете посмотреть https://github.com/madrobby/keymaster

Если вы подробно расскажете о своем стеке/требованиях, я был бы рад расширить этот ответ.

Ответ 8

Самый простой способ выглядит так:

  • сохранить предыдущее содержимое textarea при нажатии кнопки, в атрибуте самой текстовой области DOM.
  • перехватить клавиатуру на уровне BODY (вы не знаете, где будет фокус, когда и если нажата комбинация Ctrl-Z)
  • (необязательно) также перехватывает как можно больше событий из разных объектов: input, keyPress и т.д., также на уровне BODY.

Сейчас:

  • когда пользователь нажимает кнопку, сохраняется старое содержимое, а пользовательский "грязный" атрибут textarea имеет значение true
  • Если пользователь нажимает Ctrl-Z или Cmd-Z, процедура отмены является простой (в jQuery, которая была бы $('#idOfTextarea').val($('#idOfTextarea').attr('prevContents'));). Процедура отмены также очищает атрибут "грязный", так что отмена не вызывается дважды.
  • (необязательно), если пользователь изменяет другое поле, щелкает в другом месте и т.д., также очищается грязный атрибут текстового поля, и изменение становится недействительным.
  • (необязательно) объекты со своей функцией отмены могут/должны останавливать распространение события, чтобы избежать другого отмены, имеющего два эффекта.

Вы можете захотеть или не перехватить onChange в текстовом поле. Если onChange огни и загрязнение не установлены, то это начальный щелчок кнопки и может быть проигнорирован. В противном случае это может указывать на то, что пользователь добавил некоторые изменения в свой текст, нажав кнопку. В этом случае вы можете отключить отмену, чтобы сохранить эти изменения, или попросить пользователя подтвердить.

Ответ 9

Вы можете сделать это,

HTML

<div id="text-content">
 <textarea rows="10" cols="50"></textarea>
   <input type="button" name="Insert" value="Insert" />
</div>

Jquery

var oldText = [],ctrl=false;
   $(function(){
      $("input[name=Insert]").click(function(){
          var text = oldText.length+1;
          oldText.push(text);
          var textAreaText = $('textarea').val();
          textAreaText +=text;
          $('textarea').val(textAreaText);
          $("input[name=insertText]").val('');
     });
     $('textarea').keydown(function(e){
            if(e.which == 17){ ctrl = true;}
     });
     $('textarea').keyup(function(e){
         var c = e.which;
         if(c == 17){ ctrl = false;}
         if(ctrl==true && c==90 ){
            oldText.pop(); 
            var text = '';
            $.each(oldText,function(i,ele){
               text += ele;
            });
            $('textarea').val(text);
        }
     })
  })

Вы также можете проверить и поэкспериментировать с fiddle.

Ответ 10

Сначала добавьте html, и вы можете использовать событие нажатия клавиши для отмены

здесь вы можете попробовать здесь http://jsfiddle.net/surendra786/1v5jxaa0/              

            <input type="text" class="reset actor_input" name="actor" value="add actors"></input>

            <input type="text" name="actors"></input>

            <div class="found_actors"></div>

            <div id="add" class="button_content">ADD</div>

            <div id="undo" class="button_content">UNDO</div>

            <div class="actors_list"><textarea readonly style="resize: none;" rows="20" cols="20" name="actors-list"></textarea></div>

        </div>

** затем добавьте jquery **

    var items = [];

$("#add").click(function() {
    // Push the new actor in the array
    items.push($("[name='actor']").val());
    populate();
});



$(document).keydown(function(e){
       if( e.which === 90 && e.ctrlKey ){
         console.log('control + z'); 
         if (items.length > 0) {
        // remove last element of the array
        items.splice(-1,1);
        populate();
    }
      }          
}); 

populate = function() {
    $("[name='actors-list']").text('');
    $("[name='actors-list']").append(items.join('&#13;&#10;'));
    $("[name='actors']").val(items.join(','));   
}

вы можете попробовать здесь http://jsfiddle.net/surendra786/1v5jxaa0/

это работает для меня

Ответ 11

Здесь много полезных ответов, которые будут работать для вас. Вот что я сделал бы в ваших обстоятельствах. Это позволяет изменять текстовую переменную, которую вы, скорее всего, используете, вы можете установить ее или пользователь может установить ее с другим полем и т.д.

codepen here

Суть этого будет что-то вроде этого.

$(document).ready(function(){
  function deployText(){
    var textArray = [];
    var textToAdd = 'let\ go ahead and add some more text';
    var textarea = $('textarea');
    var origValue = textarea.text();
    textArray.push(origValue);

    $('button').on('click', function(e){
      textArray.push(textToAdd);
      textarea.text(textArray);
      console.log(textArray.length);
      console.log(textArray);
    });

    $(document).on('keypress', function(e){
      var zKey = 26;
      if(e.ctrlKey && e.which === zKey){
        removePreviousText();
      }
    })

    function removePreviousText(){
      console.log(textArray);
      if(textArray.length > 1){
        textArray.pop();
        $('textarea').text(textArray);
      }
    }
  }
  deployText()
})