0

I'm making a text-searching mechanism (like ⌘ + F) for an iOS app and It's working but I have two issues.

  1. Whenever someone searches something in Arabic, the word becomes disconnected.

  2. Users can't search if there are diacritics in the text but their search does not (so basically I'm trying to make it diacritic-insensitive)

Here's the code for my highlighting (which I found from this):

var uiWebview_SearchResultCount = 0;

/*!
 @method     uiWebview_HighlightAllOccurencesOfStringForElement
 @abstract   // helper function, recursively searches in elements and their child nodes
 @discussion // helper function, recursively searches in elements and their child nodes

 element    - HTML elements
 keyword    - string to search
 */

function uiWebview_HighlightAllOccurencesOfStringForElement(element,keyword) {
    if (element) {
        if (element.nodeType == 3) {        // Text node

            var count = 0;
            var elementTmp = element;
            while (true) {
                var value = elementTmp.nodeValue;  // Search for keyword in text node
                var idx = value.toLowerCase().indexOf(keyword);

                if (idx < 0) break;

                count++;
                elementTmp = document.createTextNode(value.substr(idx+keyword.length));
            }

            uiWebview_SearchResultCount += count;

            var index = uiWebview_SearchResultCount;

            while (true) {
                var value = element.nodeValue;  // Search for keyword in text node
                var idx = value.toLowerCase().indexOf(keyword);

                if (idx < 0) break;             // not found, abort

                //we create a SPAN element for every parts of matched keywords
                var span = document.createElement("span");
                var text = document.createTextNode(value.substr(idx,keyword.length));
                var spacetxt = document.createTextNode("\u200D");//\u200D
                span.appendChild(text);
                span.appendChild(spacetxt);

                span.setAttribute("class","uiWebviewHighlight");
                span.style.backgroundColor="#007DC8a3";
                span.style.borderRadius="3px";

                index--;
                span.setAttribute("id", "SEARCH WORD"+(index));
                //span.setAttribute("id", "SEARCH WORD"+uiWebview_SearchResultCount);

                //element.parentNode.setAttribute("id", "SEARCH WORD"+uiWebview_SearchResultCount);

                //uiWebview_SearchResultCount++;    // update the counter

                text = document.createTextNode(value.substr(idx+keyword.length));
                element.deleteData(idx, value.length - idx);

                var next = element.nextSibling;
                //alert(element.parentNode);
                element.parentNode.insertBefore(span, next);
                element.parentNode.insertBefore(text, next);
                element = text;
            }


        } else if (element.nodeType == 1) { // Element node
            if (element.style.display != "none" && element.nodeName.toLowerCase() != 'select') {
                for (var i=element.childNodes.length-1; i>=0; i--) {
                    uiWebview_HighlightAllOccurencesOfStringForElement(element.childNodes[i],keyword);
                }
            }
        }
    }
}

// the main entry point to start the search
function uiWebview_HighlightAllOccurencesOfString(keyword) {
    uiWebview_RemoveAllHighlights();
    uiWebview_HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());
}

// helper function, recursively removes the highlights in elements and their childs
function uiWebview_RemoveAllHighlightsForElement(element) {
    if (element) {
        if (element.nodeType == 1) {
            if (element.getAttribute("class") == "uiWebviewHighlight") {
                var text = element.removeChild(element.firstChild);
                element.parentNode.insertBefore(text,element);
                element.parentNode.removeChild(element);
                return true;
            } else {
                var normalize = false;
                for (var i=element.childNodes.length-1; i>=0; i--) {
                    if (uiWebview_RemoveAllHighlightsForElement(element.childNodes[i])) {
                        normalize = true;
                    }
                }
                if (normalize) {
                    element.normalize();
                }
            }
        }
    }
    return false;
}

// the main entry point to remove the highlights
function uiWebview_RemoveAllHighlights() {
    uiWebview_SearchResultCount = 0;
    uiWebview_RemoveAllHighlightsForElement(document.body);
}

function uiWebview_ScrollTo(idx) {
    var idkNum = uiWebview_SearchResultCount - idx
    var scrollTo = document.getElementById("SEARCH WORD" + idkNum);
    if (scrollTo) scrollTo.scrollIntoView();
}

and I also found this that actually does exactly what I want (does not disconnect words and is diacritic-insensitive) but it's in JQuery and I couldn't figure out how to implement it in my code.

enigrify
  • 281
  • 3
  • 17

1 Answers1

0

Instead of using indexOf, you can convert the string to an NSString and then use range(of:options:):

var range = value.range(of: keyword, options: [.caseInsensitive, .diacriticInsensitive])
Yonat
  • 4,382
  • 2
  • 28
  • 37
  • Thanks for the reply, but what I meant is that the text on the page has diacritics, so I whenever someone searches something without diacritics, it should still work. Not the other way around. – enigrify Sep 29 '19 at 18:23