Калитка 6: позиция курсора TextField перемещается при обновлении компонента

У меня есть компонент, который обертывает Wicket TextField, который после обновления я проверяю его содержимое через какой-то другой внешний класс, отвечающий за проверку модели.

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

Это приводит к обновлению обернутого TextField.

Проблема в том, что когда происходит это обновление, курсор внутри текстового поля переходит в позицию 0.

Под «обновлением» я подразумеваю, что я добавляю компонент TextField (или компонент/панель родительского контейнера) в AjaxRequestTarget для обновления.

Есть ли [хороший] способ предотвратить этот скачок курсора и просто оставить его там, где он есть?


person Chris Spiking    schedule 03.10.2017    source источник
comment
можно тоже код отправить?   -  person soorapadman    schedule 04.10.2017
comment
Какое событие JavaScript инициирует проверку?   -  person svenmeier    schedule 04.10.2017
comment
Чтобы уточнить, если курсор в текстовом поле находится, скажем, посередине между текстом, а затем по какой-либо причине я добавляю этот компонент TextField в AjaxRequestTarget для обновления, курсор затем переходит в позицию 0 в тексте. @svenmeier - Javascript не инициирует проверку - это делает запись поведения FormComponentUpdate (onUpdate)   -  person Chris Spiking    schedule 04.10.2017


Ответы (1)


Похоже, я недостаточно усердно искал - я могу указать на решение, найденное здесь:

http://apache-wicket.1842946.n4.nabble.com/TextField-cursor-reset-mid-editing-td4668582.html

В частности, пост ниже:

ChambreNoire, 04 декабря 2014 г.; 16:19 Re: ИСПРАВЛЕНО: курсор TextField сбрасывался во время редактирования

Это сработало для меня хорошо, но просто хочу отметить, что вы не должны принудительно обновлять компонент, если текстовое содержимое модели TextField не изменилось, в противном случае, когда вы выбираете текст с помощью метода клавиатуры (Shift + клавиши со стрелками и т. д.), тогда выбор будет неудачным, и курсор вернется в положение, которое он занимал до выбора.

Собственно, поскольку посты на форуме имеют свойство пропадать, вот текст поста ниже:

OK so this is what I have. Disclaimer: I'm no javascript/jQuery expert so this is mostly cobbled together from things I have found online and tested in my particular situation. Any optimisations are more than welcome! 

So first the script 

(function($) { 
$.fn.getCaretPosition = function() { 
    var input = this.get(0); 
    if (!input) return; // No (input) element found 
    if ('selectionStart' in input) { 
        // Standard-compliant browsers 
        return input.selectionStart; 
    } else if (document.selection) { 
        // IE 
        input.focus(); 
        var sel = document.selection.createRange(); 
        var selLen = document.selection.createRange().text.length; 
        sel.moveStart('character', -input.value.length); 
        return sel.text.length - selLen; 
    } 
}; 
$.fn.setCaretPosition = function(position) { 
    var input = this.get(0); 
    if (!input) return false; // No (input) element found 

    input.value = input.value; 
    // ^ this is used to not only get "focus", but 
    // to make sure we don't have it everything -selected- 
    // (it causes an issue in chrome, and having it doesn't hurt any other browser) 

    if (input.createTextRange) { 
        var range = input.createTextRange(); 
        range.move('character', position); 
        range.select(); 
        return true; 
    } else { 
        // (input.selectionStart === 0 added for Firefox bug) 
        if (input.selectionStart || input.selectionStart === 0) { 
            input.focus(); 
            input.setSelectionRange(position, position); 
            return true; 
        } else  { // fail city, fortunately this never happens (as far as I've tested) :) 
            input.focus(); 
            return false; 
        } 
    } 
} 
})(jQuery); 

Then I add the following behavior to my TextField : 

add(new AjaxFormComponentUpdatingBehavior("onkeyup") { 

@Override 
protected void onUpdate(AjaxRequestTarget target) { 

    String id = getComponent().getMarkupId(); 

    String caret = id + "_caretPosition"; 
    String selector = "$('#" + id + "')"; 

    target.prependJavaScript("var $s = " + selector + ";if($s[0]===document.activeElement){" + 
            "jQuery.data(document,'" + caret + "'," + selector + ".getCaretPosition());}"); 

    onFieldUpdate(getFormComponent(), target); 

    target.appendJavaScript("var $p = jQuery.data(document,'" + caret + "');" + 
            "if($p!=undefined){" + selector + ".setCaretPosition($p);" + 
            "jQuery.removeData(document,'" + caret + "');}"); 
} 

@Override 
protected void updateAjaxAttributes(AjaxRequestAttributes attributes) { 
    super.updateAjaxAttributes(attributes); 

    String id = getFormComponent().getMarkupId() + "_onkeyup"; 

    attributes.setThrottlingSettings(new ThrottlingSettings(id, seconds(1), true)); 
} 
}); 

So this gets round the 'zapping focus back to the original field after hitting tab' issue I experienced as the behavior will be called a bit after I hit tab due to the throttle settings but that won't affect whether the field is focused or not (it won't regain focus). So I can check this and bypass the whole thing if the field isn't focused simply by not storing the caret position and consequently not re-setting it. 

You'll notice I'm storing the caretPosition in 'document' using jQuery.data(). There's probably a more 'js/jquery best practices' way to do this. I should also be clearing the position once I set it (thinking out loud) so I'll add that above. 

CN
person Chris Spiking    schedule 04.10.2017