Как обернуть предыдущее, текущее и следующее слово внутри тега с помощью jQuery?

Не уверен, правильно ли выбрано название ...

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

Чтобы быть более конкретным, я пытаюсь этого избежать: введите здесь описание изображения

Визуальный:

введите описание изображения здесь

Способ, которым я его построил, и он может измениться, потому что это не имеет значения, заключается в том, что выбранный текст заключен внутри span.selection, а внутри этого тега также есть две вставки, используемые в качестве обработчиков:

Lorem ipsum dolor                            <!-- Unselected Text -->

<span class="selection">                     <!-- Start selection wrapper -->

  <span rel="previous" class="caret"></span> <!-- The left-side caret -->

  sit amet, consectetur                      <!-- The selected texts -->

  <span rel="next" class="caret"></span>     <!-- The right-side caret -->

</span>                                      <!-- End selection wrapper -->

adipiscing elit.                             <!-- Unselected Text -->

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

Вот jsfiddle: http://jsfiddle.net/m6Qx4/

Окружающие тексты также могут содержать HTML-теги, такие как: <i>, <b>, <span> и <ul>/<li> могут присутствовать, что затрудняет синтаксический анализ.

Есть идеи, как это можно сделать?

Обновление статуса:

Мне действительно удалось заставить его работать с .click(); слушателем событий, используя мои собственные методы jQuery.

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

Моя текущая ошибка заключается в изменении положения красных кареток. Я попытался уничтожить их и добавить / добавить обратно, но он все еще не работает. Это может быть ошибка Firefox, которая не может правильно перезагрузить DOM после изменений, внесенных в текстовые узлы?

Ссылка: jsFiddle
< br /> Чтобы проверить рабочее состояние jsFiddle.net из-за недавних отключений, посетите их Твиты.


person Cybrix    schedule 28.06.2012    source источник
comment
Ниже console.info в вашем jsFiddle вам может потребоваться использовать переменную lastWordArray вместо lastWord, поскольку это было предыдущее исправление. Не уверен, что нужно изменить.   -  person arttronics    schedule 30.06.2012
comment
Я не понимаю, почему вы пытаетесь это сделать. В чем смысл? Тем не менее, вам может помочь библиотека rangy.   -  person thirtydot    schedule 04.07.2012
comment
Я редактировал вопрос. С имиджем, должно быть, теперь все более непривычно. И Rangy - действительно хороший плагин, но бесполезный в моем случае, потому что выделение текста под Android имитируется и на самом деле не происходит в WebView.   -  person Cybrix    schedule 04.07.2012
comment
Вот обновление: jsfiddle.net/sNpLw/1 вы запускаете, дважды щелкнув ‹p› . Проверено только в Firefox   -  person Cybrix    schedule 05.07.2012
comment
В Firefox он работает одним щелчком мыши, при этом на крайних концах отображаются две красные вставки. Затем щелчок по каждой каретке переместит ее к центру. Нажатие кнопки в любой момент возвращает содержимое. Виден сбой, когда во время процесса пропадает одно слово, но он правильно фиксируется с помощью подтверждения в окне предупреждения. Нажатие кнопки также изменяет формат исходного текста. Тем не менее, ваш jsFiddle будет отличным ответом, который вы можете выбрать, если хотите, или вы можете включить его в качестве обновления в свой вопрос и посмотреть, могут ли другие помочь с его тонкой настройкой (не думайте, что не так).   -  person arttronics    schedule 05.07.2012
comment
Обновление статуса: вот моя пользовательская версия, почти полная, но еще не совсем готовая. новый метод jsFiddle. Кроме того, вот учебная версия этого незавершенная работа с дополнительными комментариями чем разметка.   -  person arttronics    schedule 05.07.2012
comment
@arttronics, я только что протестировал со своим телефоном, и ваше решение просто потрясающее!   -  person Cybrix    schedule 06.07.2012
comment
@arttronics, В конце я хотел бы обернуть поддельный выбор с помощью ‹span›, потому что это необходимо для более крупного проекта, где я предлагаю пользователю варианты выбора после того, как он дает выбор: удалить, отредактировать или выделить этот выбор.   -  person Cybrix    schedule 07.07.2012
comment
@arttronics, и да, я знаю, что у меня есть еще нерешенные вопросы.   -  person Cybrix    schedule 07.07.2012


Ответы (2)


Несколько мыслей:

Я не понимаю, насколько жизнеспособным решением является упаковка всего в <span>. Что происходит, когда у вас есть что-то подобное?

<p>The <b>important terms</b> will be bolded in this text</p>

Когда вы выбираете The important, у вас будет какой-то хаос тегов, когда тело тега <span> хочет перекрыть тело тега <b>.

Я думаю, что лучшим решением было бы иметь несколько тегов выбора <span> с одним и тем же классом. Каждый раз, когда встречается HTML-тег, вы пропускаете его и создаете новый выбор <span>. Затем, когда вы перемещаете курсор, вы просто делаете это:

$(".selection:first").prepend(startCaret);
$(".selection:last").append(endCaret);

Я поэкспериментировал с этой идеей, и она мне понравилась. Если вы хотите по-настоящему фантазировать, вы можете попробовать объединить выделение <span>s, когда вы найдете закрывающий тег после того, как столкнетесь с его соответствующим начальным тегом, но это потребует много работы.


Ваши каретки перемещаются неправильно, потому что вы указали стиль абсолютного позиционирования. Измените это на относительное и дайте каждой вставке тела &nbsp;. Вам придется поиграть с некоторыми другими настройками CSS для позиционирования, чтобы он выглядел правильно, но он движется так, как вы ожидаете, с этими изменениями (пример здесь).


Когда я обдумывал некоторые идеи для этого, я попытался выполнить абсолютное позиционирование кареток, чтобы их не нужно было перемещать внутри выделения <span>. Это была ошибка. У меня возникли проблемы с абзацами, которые выходили за пределы новой строки без какой-либо разметки. Оставайтесь с вашей идеей использования каретки внутри вашего выделения <span>.


И напоследок несколько вопросов для размышлений:

  • Собираетесь ли вы ограничить объем? (т. е. если вы начинаете выбирать внутри тега <p>, не позволяйте выделению выходить за пределы этого тега на следующий <p> или что-то еще, что следует за ним)
  • Некоторые теги будут недоступны для выбора? (например, <table>, <script>, <select> и т. д.)

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

person RustyTheBoyRobot    schedule 03.07.2012
comment
Я не хочу уклоняться от размаха. Потому что это также означало бы, что мы также не можем выбирать через сильный тег. Мой код пока ограничивается только окружающими текстовыми узлами. Я пытаюсь найти способ обнаруживать и восстанавливать любые встречающиеся теги внутри моего .selection, не дублируя эти теги тоже. - person Cybrix; 03.07.2012
comment
+1 @RustyTheBoyRobot, интересная идея множественного выбора <span> тегов с одним и тем же классом, которая позволяет для отдельных слов иметь background-color набор имитацию текста -выбор. - person arttronics; 03.07.2012
comment
@arttronics - Очевидно, это может вызвать головную боль, если вы получите два пролета, которые не были рядом друг с другом. Компонент будет действовать так, как будто все, что находится между промежутками, было выбрано, но это не так. (Если в этом есть смысл ....) - person RustyTheBoyRobot; 03.07.2012
comment
Хамм, это само по себе звучит для меня как еще один метод ... чтобы начало и смещение пролетов действовали как привратник, так сказать. - person arttronics; 03.07.2012
comment
Означает ли это, что мы должны заключить все слова в диапазон, и только выбранные из них будут содержать .selected? - person Cybrix; 04.07.2012
comment
@Cybrix, я нашел несколько SO-ответов на то, что вы только что сказали. - person arttronics; 05.07.2012
comment
Хотя ответ еще не найден, вы получили вознаграждение, потому что участвовали в период вознаграждения. Цель этого спонсируемого вознаграждения теперь завершена: привлечь внимание, которое могло привести к жизнеспособному ответу. Ваше здоровье! - person arttronics; 09.07.2012

Чтобы осветить проблему Расти:

Сначала разделите теги:

var textBlock = textContainer.html(),
taglessArray = textBlock.split(/<[^>]*>/),
arrayOfTags = textBlock.match(/<[^>]*>/g),
tagsFirst = (textBlock[0] === '<') ? true : false, //parens for legibility only
//tagsFirst is a switch that tells us which to start splicing back in later

Теперь давайте обернем все наши непробельные теги в теги span, которые мы можем использовать

var i = taglessArray.length;
while(i--){
    taglessArray[i].replace(/([^\s]*)/g,'<span class="selectableWord">$1</span>');
}
//not 100% sure I got that right - haven't tested - but the idea is , wrap all non
//whitespace/word boundary blocks in 'selectableWord' classed span tags

А теперь склеиваем их вместе. Исходные теги форматирования текста должны сохранять позицию. Очевидно, что классифицированные интервалы 'selectableWord' должны избегать воздействия на макет / форматирование

var addToArray, adderArray;
if(tagsFirst){ addToArray = arrayOfTags; adderArray = taglessArray; }
else { addToArray = taglessArray; adderArray = arrayOfTags; }

var oLen, //used to retain 'original length'
i2 = oLen = (tagsFirst.length + arrayOfTags.length),
rejoinArray = [];

while(i2--){ //not 100% sure I got this right - hope you get the general idea
    var currentKey = oLen - 1 - i2;
    //if first or alternating from first 0,2,4,etc...
    if(currentKey === 0 || ( currentKey % 2 === 0) {
        rejoinArray[currentKey] = addToArray.shift(); //remove first element and return
    }
    //should be keys 1,3,5,etc...
    else {
        rejoinArray[currentKey] = adderArray.shift();
    }
}

Все вышеперечисленное, конечно, очень непроверено и, вероятно, содержит ошибки / ошибки, но я думаю, что основная идея довольно крутая. Вырвите бирки. Оберните массив непомеченных слов в интервалы, которые вы можете использовать. Затем снова вставьте все эти глупые теги. Они все равно должны заключать в себя все те же слова. Это предполагает базовую целостность HTML. Ваши текстовые блоки содержат только встроенные отображаемые теги, которые охватывают слова или наборы слов. Неправильное размещение может не быть проблемой, если нет неправильного размещения промежутков.

person Erik Reppen    schedule 08.07.2012
comment
Я попытаюсь реализовать это в jsfiddle, чтобы мы могли его отладить. - person Cybrix; 08.07.2012