188 lines
6.9 KiB
Swift
188 lines
6.9 KiB
Swift
//
|
|
// FindTextHighlightJS.swift
|
|
// flutter_inappwebview
|
|
//
|
|
// Created by Lorenzo Pichilli on 16/02/21.
|
|
//
|
|
|
|
import Foundation
|
|
|
|
let FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT_GROUP_NAME = "IN_APP_WEBVIEW_FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT"
|
|
let FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._searchResultCount"
|
|
let FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._currentHighlight"
|
|
let FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE = "window.\(JAVASCRIPT_BRIDGE_NAME)._isDoneCounting"
|
|
|
|
let FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT = PluginScript(
|
|
groupName: FIND_TEXT_HIGHLIGHT_JS_PLUGIN_SCRIPT_GROUP_NAME,
|
|
source: FIND_TEXT_HIGHLIGHT_JS_SOURCE,
|
|
injectionTime: .atDocumentStart,
|
|
forMainFrameOnly: true,
|
|
requiredInAllContentWorlds: false,
|
|
messageHandlerNames: ["onFindResultReceived"])
|
|
|
|
let FIND_TEXT_HIGHLIGHT_JS_SOURCE = """
|
|
\(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE) = 0;
|
|
\(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE) = 0;
|
|
\(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE) = false;
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._findAllAsyncForElement = function(element, keyword) {
|
|
if (element) {
|
|
if (element.nodeType == 3) {
|
|
// Text node
|
|
|
|
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;
|
|
|
|
var span = document.createElement("span");
|
|
var text = document.createTextNode(value.substr(idx, keyword.length));
|
|
span.appendChild(text);
|
|
|
|
span.setAttribute(
|
|
"id",
|
|
"\(JAVASCRIPT_BRIDGE_NAME)_SEARCH_WORD_" + \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE)
|
|
);
|
|
span.setAttribute("class", "\(JAVASCRIPT_BRIDGE_NAME)_Highlight");
|
|
var backgroundColor = \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE) == 0 ? "#FF9732" : "#FFFF00";
|
|
span.setAttribute("style", "color: #000 !important; background: " + backgroundColor + " !important; padding: 0px !important; margin: 0px !important; border: 0px !important;");
|
|
|
|
text = document.createTextNode(value.substr(idx + keyword.length));
|
|
element.deleteData(idx, value.length - idx);
|
|
|
|
var next = element.nextSibling;
|
|
element.parentNode.insertBefore(span, next);
|
|
element.parentNode.insertBefore(text, next);
|
|
element = text;
|
|
|
|
\(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE)++;
|
|
elementTmp = document.createTextNode(
|
|
value.substr(idx + keyword.length)
|
|
);
|
|
|
|
var _windowId = \(WINDOW_ID_VARIABLE_JS_SOURCE);
|
|
|
|
window.webkit.messageHandlers["onFindResultReceived"].postMessage(
|
|
{
|
|
'findResult': {
|
|
'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE),
|
|
'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE),
|
|
'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE)
|
|
},
|
|
'_windowId': _windowId
|
|
}
|
|
);
|
|
}
|
|
} 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--) {
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._findAllAsyncForElement(
|
|
element.childNodes[element.childNodes.length - 1 - i],
|
|
keyword
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// the main entry point to start the search
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._findAllAsync = function(keyword) {
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._clearMatches();
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._findAllAsyncForElement(document.body, keyword.toLowerCase());
|
|
\(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE) = true;
|
|
|
|
var _windowId = \(WINDOW_ID_VARIABLE_JS_SOURCE);
|
|
|
|
window.webkit.messageHandlers["onFindResultReceived"].postMessage(
|
|
{
|
|
'findResult': {
|
|
'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE),
|
|
'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE),
|
|
'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE)
|
|
},
|
|
'_windowId': _windowId
|
|
}
|
|
);
|
|
}
|
|
|
|
// helper function, recursively removes the highlights in elements and their childs
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._clearMatchesForElement = function(element) {
|
|
if (element) {
|
|
if (element.nodeType == 1) {
|
|
if (element.getAttribute("class") == "\(JAVASCRIPT_BRIDGE_NAME)_Highlight") {
|
|
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 (window.\(JAVASCRIPT_BRIDGE_NAME)._clearMatchesForElement(element.childNodes[i])) {
|
|
normalize = true;
|
|
}
|
|
}
|
|
if (normalize) {
|
|
element.normalize();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// the main entry point to remove the highlights
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._clearMatches = function() {
|
|
\(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE) = 0;
|
|
\(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE) = 0;
|
|
\(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE) = false;
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._clearMatchesForElement(document.body);
|
|
}
|
|
|
|
window.\(JAVASCRIPT_BRIDGE_NAME)._findNext = function(forward) {
|
|
if (\(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE) <= 0) return;
|
|
|
|
var idx = \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE) + (forward ? +1 : -1);
|
|
idx =
|
|
idx < 0
|
|
? \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE) - 1
|
|
: idx >= \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE)
|
|
? 0
|
|
: idx;
|
|
\(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE) = idx;
|
|
|
|
var scrollTo = document.getElementById("\(JAVASCRIPT_BRIDGE_NAME)_SEARCH_WORD_" + idx);
|
|
if (scrollTo) {
|
|
var highlights = document.getElementsByClassName("\(JAVASCRIPT_BRIDGE_NAME)_Highlight");
|
|
for (var i = 0; i < highlights.length; i++) {
|
|
var span = highlights[i];
|
|
span.style.backgroundColor = "#FFFF00";
|
|
}
|
|
scrollTo.style.backgroundColor = "#FF9732";
|
|
|
|
scrollTo.scrollIntoView({
|
|
behavior: "auto",
|
|
block: "center"
|
|
});
|
|
|
|
var _windowId = \(WINDOW_ID_VARIABLE_JS_SOURCE);
|
|
|
|
window.webkit.messageHandlers["onFindResultReceived"].postMessage(
|
|
{
|
|
'findResult': {
|
|
'activeMatchOrdinal': \(FIND_TEXT_HIGHLIGHT_CURRENT_HIGHLIGHT_JS_SOURCE),
|
|
'numberOfMatches': \(FIND_TEXT_HIGHLIGHT_SEARCH_RESULT_COUNT_JS_SOURCE),
|
|
'isDoneCounting': \(FIND_TEXT_HIGHLIGHT_IS_DONE_COUNTING_JS_SOURCE)
|
|
},
|
|
'_windowId': _windowId
|
|
}
|
|
);
|
|
}
|
|
}
|
|
"""
|