Давайте попробуем разобрать, что делает ваша функция поиска:
function search() {
// get the searched text OK
var text = document.getElementById("query").value;
// make a regexp out of the searched text OK
var query = new RegExp("(\\b" + text + "\\b)", "gim");
// retrieve the html content of the grid items's container OK
var e = document.getElementById("searchtext").innerHTML;
// remove all the spans tags from this html content (span tags in #searchtext are red)
var enew = e.replace(/(<span>|<\/span>)/igm, "");
// set the html stripped from the span tags as the content of #searchtext
document.getElementById("searchtext").innerHTML = enew;
// in the html stripped from span, wrap with spans all contents matching the search string
var newe = enew.replace(query, "<span>$1</span>");
// set the final html as the content of #searchtext
document.getElementById("searchtext").innerHTML = newe;
}
Итак, сначала вы извлекаете HTML-код и пытаетесь найти текст в этом HTML-коде.
Но так как вы сохраняете большинство тегов (вы удаляете только интервалы), вы не сможете найти текст только в содержимом ваших элементов div (ваш поиск будет загрязнен самими тегами div).
Мы могли бы делать сложные вещи с заменой, но должен быть другой путь.
Давайте теперь разберем проблему под рукой:
мы хотели бы написать функцию, которая выделяет искомое слово в сетке в соответствии с правилами этой игры в словаре поиска (по горизонтали, по диагонали по вертикали).
`function highlightSearchedWord() {....}`
Для этого нет встроенной функции javascript, поэтому мы должны разделить проблему.
function highlightSearchedWord() {
var text = getSearchedWord();
highlightText(text);
}
мы можем решить getSearchedWord:
function getSearchedWord() {
var text = document.getElementById("query").value;
return text;
}
Теперь в highlightText нам нужно найти слово, которое способно читать буквы по заданным позициям в сетке, сравнивать их с искомым текстом, сохранять список позиций, если слово найдено, и выделять эти позиции.
Положение в сетке можно рассматривать как координаты x (индекс столбца буквы) и y (индекс строки буквы).
В javascript мы можем определить структурированные объекты с фигурными скобками {}
, поэтому, например, позиция 0,0 (первая буква первой строки сетки) будет { x: 0, y: 0}
Первая буква вашей сетки находится в первом div (.grid-item) вашей сетки.
Javascript дает вам возможность извлекать элементы на основе их имени класса.
`document.getElementsByClassName()`
Документация getElementsByClassName
Таким образом, мы можем составить список всех ваших элементов сетки, написав var items= document.getElementsByClassName('grid-item');
Позволяет определить функцию getItems
:
function getItems() {
var items= document.getElementsByClassName('grid-item');
return items;
}
Отсюда мы можем легко получить новую функцию:
function getLetterAtPos(pos) {
var items = getItems();
// items is an array so we have to convert position {x, y} to index
return items[posToIndex(pos)].innerHTML;
}
с индексом posToIndex:
function posToIndex(pos) {
// if the grid is 10x10 the first element of first row is index 0 (0 * 10 + 0)
// !remember first indice is 0!
// the first item of second row is index 10 (1 * 10 + 0)
// the second item of the third row is index 21 (1 * 10 + 1)
return pos.y * 10 + pos.x;
}
Я собираюсь идти быстрее, чтобы ограничить размер ответа, но комментарии должны помочь.
Также может быть полезен способ выделить позицию:
Сначала определите класс css, делая выделение (проще добавить или удалить класс из элемента, чем обернуть / развернуть его содержимое в промежутке):
CSS:
.highlight {
background-color:#F5A623;
}
Тогда вспомогательные функции javascript
ЯШ:
function addClass(elem, className) {
// HTMLElement.className is a string with one or several class names separated by a space
var classNames = elem.className.split(" ");
// we search the array classNames with indexOf to check if the class needs to be added
if (classNames.indexOf(className) == -1) {
// the class name is not found in the existing class names of this element so we just concatenate className to t elem.className
elem.className += " " + className;
}
}
function removeClass(elem, className) {
// same as above we split elem.className into an array of classNames
var classNames = elem.className.split(" ");
// we search for index of the className we want to remove
// index === -1 means not found, otherwise the index is the position of className in classNames
var index = classNames.indexOf(className);
if (index !== -1) {
// javascript's version of remove at, splice(index, 1) means remove one item at index
classNames.splice(index, 1);
// join(' ') re concatenate classNames into a string of space separated class names
elem.className = classNames.join(' ');
}
}
function highlightPos(pos) {
var item = getItems()[posToIndex(pos)];
addClass(item, 'highlight');
}
// to reset highlights between searches
function clearHighlights() {
var items = getGridItems();
for (var i = 0; i < items.length; i++) {
removeClass(items[i], 'sel');
}
}
Ссылки:
split , indexOf и splice
Теперь, чтобы прочитать слова в сетке, мы должны найти как минимум позиции первой буквы искомого текста, а затем попытаться сопоставить каждую букву искомого текста:
function findLetterPositions(letter) {
// we define a new array to receive our results
var positions = [];
// there are 10 columns x 10 rows of items
var itemCount = 10 * 10;
for (let i = 0; i < itemCount; i++) {
var pos = indexToPos(i);
// we compare letters lowercased
if (getLetterAtPos(pos).toLowerCase() === letter.toLowerCase()) {
// we have found letter at pos, so we add it to our array of positions (push)
positions.push(pos);
}
}
return positions;
}
с indexToPos, определяемым как обратная операция posToIndex (принимает индекс, возвращает pos):
function indexToPos(index) {
var y = Math.floor(index / columnCount);
var x = index - y * columnCount;
return { x: x, y: y };
}
Для каждой найденной позиции нам нужно будет попытаться сопоставить каждую букву искомого текста, начиная с этой позиции и в указанном направлении. Например, вправо (с учетом начальной позиции первой буквы):
function tryAndMatchRight(text,initialPos) {
var x = initialPos.x;
var y = initialPos.y;
var columnCount = 10;
// we need to check that we are far enough from the edge of the grid for the whole word to fit, otherwise give up by returning
if (x + text.length > columnCount) {
return;
}
// word found == true by default, the for loop below will try to prove otherwise
var wholeWordFound = true;
// we will keep track of the letter positions we're trying
var wordPositions = [];
// obviously
wordPositions.push(initialPos);
// we will try each letter of text starting from the second (index 1) to the end of text (index length-1)
for (var x2 = 1; x2 < text.length; x2++) {
// building the position object for the current letter
var pos = { x: x + x2, y: y};
// if the comparaison fails we can stop
if (text[x2].toLowerCase() !== getLetterAtPos(pos).toLowerCase()) {
wholeWordFound = false;
break;
}
wordPositions.push(pos);
}
if (wholeWordFound) {
highLightPositions(wordPositions);
}
}
function hightlightPositions(positions) {
for(var i = 0; i < positions.length; i++) {
highlightPos(positions[i]);
}
}
Подводя итог, функция, вызываемая при нажатии кнопки поиска, может быть:
function search() {
clearHighlights();
var text = getSearchedText();
var firstLetterPositions = findLetterPositions(text[0]);
for (var i = 0; i < firstLetterPositions.length; i++) {
var initialPos = firstLetterPositions[i];
tryAndMatchRight(text,initialPos);
// we only did it rightward, but other directions need their own functions
// tryAndMatchDown(text,initialPos);
// tryAndMatchDownRight(text,initialPos);
// tryAndMatchUpRight(text,initialPos);
}
}
Полностью рабочий раствор, как скрипка здесь
Если вы действительно хотите разбираться в программировании, надеюсь, вы оцените этот ответ, демонстрирующий, что программирование в основном сводится к разделению больших проблем на более мелкие, пока проблемы не будут легко решаемы (и понятны) инструментами, предоставляемыми самим языком.
Мне все равно было весело! Приветствия
(PS: как указано Evochrome в комментариях ниже, две вспомогательные функции addClass и removeClass уже решаются простым js таким образом element.classList.add("mystyle")
и element.classList.remove("mystyle")
)