I have been trying to call action from JS code in Xamarin forms on iOS. once I click on the code js is not called. this is an example I have been testing. Once I click the text gets highlighted but the function is not triggered, I don't want to display the action after clicking the button but I after I click the text. Please can you tell me what am I doing wrong.
<StackLayout x:Name="slHybridView" >
</StackLayout>
public MainPage()
{
InitializeComponent();
BindingContext = new LearningPageViewModel();
((LearningPageViewModel)BindingContext).TextChanged += TextChanged;
hybridWebView = new HybridWebView()
{
HorizontalOptions = LayoutOptions.FillAndExpand,
VerticalOptions = LayoutOptions.FillAndExpand,
Content = ((LearningPageViewModel)BindingContext).ArticleHtmlFormat,
};
hybridWebView.RegisterAction(data => DisplayAlert("Alert", "Hello " + data, "OK"));
slHybridView.Children.Clear();
slHybridView.Children.Add(hybridWebView);
}
public class HybridWebViewRenderer : WkWebViewRenderer, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
WKUserContentController userController;
public HybridWebViewRenderer()
{
}
public HybridWebViewRenderer(WKWebViewConfiguration config) : base(config)
{
userController = config.UserContentController;
var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
userController.AddUserScript(script);
userController.AddScriptMessageHandler(this, "invokeAction");
}
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
userController.RemoveAllUserScripts();
userController.RemoveScriptMessageHandler("invokeAction");
HybridWebView hybridWebView = e.OldElement as HybridWebView;
hybridWebView.Cleanup();
}
if (e.NewElement != null)
{
var html = string.Empty;
var iOSHtmlWithScaling = html.Insert(0, "<meta name='viewport' content='width=device-width,initial-scale=1,maximum-scale=1' />");
var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
Configuration.UserContentController.AddUserScript(script);
Configuration.UserContentController.AddScriptMessageHandler(this, JavaScriptFunction);
LoadData(((HybridWebView)Element).Content, iOSHtmlWithScaling, "utf-8", new NSUrl(""));
}
}
public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
((HybridWebView)Element).InvokeAction(message.Body.ToString());
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
((HybridWebView)Element).Cleanup();
}
base.Dispose(disposing);
}
}
public LearningPageViewModel()
{
articleHtmlFormat = ArticleHtml();
}
public string ArticleHtml()
{
var articleHtml = #"<html>
<head>
<meta name='viewport' content='width=device-width,initial-scale=1,maximum-scale=1' />
</head>
<body class='avat'>
<style>
.avat {
font-family: sans-serif;
font-size: 15px;
text-align: justify;
}
.title {
font-size: 16px;
}
.red {
color: red;
}
.word {
font-weight: bold;
}
.phrase {
text-decoration: underline;
}
</style>
<script type='text/javascript'>
function invokeCSCode(data) {
var els = document.getElementsByClassName('red');
while (els[0]) {
els[0].classList.remove('red');
}
invokeCSharpAction(data);
var my_element = document.querySelector('[sentenceId=' + data + ']');
my_element.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest'
});
var sentenceName = my_element.getAttribute('sentenceName');
if (data[0] === 's')
{
var x = document.querySelectorAll('[sentenceName=' + sentenceName + ']');
var i;
for (i = 0; i < x.length; i++)
{
x[i].classList.add('red');
}
}
else
{
my_element.classList.add('red');
}
}
function scrollToPosition(data) {
var els = document.getElementsByClassName('red');
while (els[0]) {
els[0].classList.remove('red');
}
var my_element = document.querySelector('[sentenceId=' + data + ']');
my_element.scrollIntoView({
behavior: 'smooth',
block: 'center',
inline: 'nearest'
});
var sentenceName = my_element.getAttribute('sentenceName');
if (data[0] === 's')
{
var x = document.querySelectorAll('[sentenceName=' + sentenceName + ']');
var i;
for (i = 0; i < x.length; i++)
{
x[i].classList.add('red');
}
}
else
{
my_element.classList.add('red');
}
}
</script>
";
var spans = FindAllClickableSpans(Article()).ToArray();
for (int i = 0; i < spans.Length; i++)
{
articleHtml += "<span ";
articleHtml += " sentenceId='" + i + "' onclick='javascript: invokeCSCode(\"" + i + "\");' sentenceName='" + i + "'>" + spans[i] + "</span>";
}
articleHtmlFormat = articleHtml;
return articleHtmlFormat;
}
public string Article()
{
return #"Excuse me,” said a girl, “you look lost. Can I help you?”\“Yes, please. Thank you.";
}
private IEnumerable<string> FindAllClickableSpans(string article)
{
article = article.ToLower();
return article.Split('.');
}
Related
I am making a blockchain in Node.js and updating the client side with socket.io. I want to add a new block to a list on the client side everytime a new block is generated, but they all get added together at the end when generating is finished. I have an emit event fire everytime after a new block is generated ( inside of a for loop ), so I don't know why the client side only updates when all of the blocks are generated.So basically they all get added at the same time instead of one by one. Any help is greatly appreciated!
client.js
const express = require('express');
const app = express();
const http = require('http');
const server = http.createServer(app);
const { Server } = require("socket.io");
const io = new Server(server);
const myArgs = process.argv.slice(2);
const port = myArgs[0];
const SHA256 = require("crypto-js/sha256");
var indexNumber = 1;
var difficulity = 4;
var Nonce = 0;
const data = "This is block ";
class Block {
constructor(index, timestamp, data, previousHash, diff, nonce) {
this.index = index;
this.timestamp = timestamp;
this.data = data;
this.previousHash = previousHash;
this.diff = diff;
this.nonce = nonce;
this.hash = this.generateHash();
}
generateHash() {
var good;
var failed = 0;
while (true) {
good = false;
var newHash = SHA256(this.index + this.timestamp + this.previousHash + JSON.stringify(this.data) + this.diff + this.nonce).toString();
for (var i = 0; i < this.diff; i++) {
if (newHash[i] == '0')
good = true;
else {
good = false;
break;
}
}
if (good) {
io.emit('goodHash', (newHash + " Difficulity: " + this.diff));
break;
}
else {
this.nonce++;
if (failed == 30000) {
io.emit('wrongHash', (newHash + " Difficulity: " + this.diff));
failed = 0;
}
else
failed++
}
}
return newHash;
}
}
class Blockchain {
constructor() {
this.blockchain = [this.createGenesisBlock()];
}
createGenesisBlock() {
var tmp = new Block(0, Date.now(), "Genesis block", "0", difficulity, Nonce);
io.emit('newBlock', JSON.stringify(tmp));
console.log(tmp);
return tmp;
}
getTheLatestBlock() {
return this.blockchain[this.blockchain.length - 1];
}
addNewBlock(newBlock) {
this.blockchain.push(newBlock);
}
validateBlock(newBlock) {
const latestBlock = this.getTheLatestBlock();
if (newBlock.previousHash !== latestBlock.hash)
return false;
if (newBlock.index <= latestBlock.index)
return false;
if (newBlock.hash !== SHA256(newBlock.index + newBlock.timestamp + newBlock.previousHash + JSON.stringify(newBlock.data) + newBlock.diff + newBlock.nonce).toString())
return false;
return true;
}
validateChain() {
for (let i = 1; i < this.blockchain.length; i++) {
const currentBlock = this.blockchain[i];
const previousBlock = this.blockchain[i - 1];
if (currentBlock.hash !== SHA256(currentBlock.index + currentBlock.timestamp + currentBlock.previousHash + JSON.stringify(currentBlock.data) + currentBlock.diff + currentBlock.nonce).toString()) {
return false;
}
if (currentBlock.previousHash !== previousBlock.hash) {
return false;
}
if (currentBlock.index <= previousBlock.index)
return false;
return true;
}
}
}
app.get('/', (req, res) => {
res.sendFile(__dirname + '/index.html');
});
io.on('connection', (socket) => {
socket.on('set transports',() =>{
socket.transports = ["websocket"];
});
console.log('GUI connected on port: ' + port);
io.emit('onConnection', port);
socket.on('mine', function () {
console.log("mining in progress...");
let logCoin = new Blockchain();
for (var i = 0; i < 5; i++) {
while (true) {
var tmp = new Block(indexNumber, Date.now(), data + indexNumber, logCoin.getTheLatestBlock().hash, difficulity, Nonce);
if (logCoin.validateBlock(tmp)) {
io.emit('newBlock', JSON.stringify(tmp));
console.log(tmp);
logCoin.addNewBlock(tmp);
indexNumber++;
break;
}
}
}
//console.log(logCoin);
//io.emit('blockLedger', JSON.stringify(logCoin, null));
})
socket.on('disconnect', () => {
console.log("Client has disconnected");
indexNumber = 1;
});
});
server.listen(port, () => {
console.log('listening on port ' + port + ':');
});
index.html
<!DOCTYPE html>
<html>
<style>
body {
margin: 10px;
padding-bottom: 3rem;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}
#header {
display: flex;
flex-direction: row;
}
#contentWrap {
display: flex;
margin-top: 10px;
height: 100%;
}
#contentWrap>div {
flex: 1;
border: 1px solid black;
overflow-y: scroll;
overflow-x: visible;
height: 100vh;
}
#blocks {
list-style-type: none;
margin: 0;
padding: 0;
}
#blocks>li {
padding: 0.5rem 1rem;
white-space: pre-wrap;
overflow-wrap: break-word;
}
#minedBlocks {
list-style-type: none;
margin: 0;
padding: 0;
}
#minedBlocks>li {
padding: 0.5rem 1rem;
white-space: pre-wrap;
overflow-wrap: break-word;
}
#port {
position: absolute;
right: 10px;
}
</style>
<body>
<div id="header">
<div id="element1">
<h1>Blockchain</h1>
<p id="connectionStatus">Status: Offline</p>
<form id="form" action="">
<button id="mine">Mine</button>
</form>
</div>
<div id="element2" style="align-self: center;">
<form id="form" action="">
<div id="port">
<input id="portInput" autocomplete="off" /><button>Connect port</button>
</div>
</form>
</div>
</div>
<div id="contentWrap">
<div id="ledger">
<ul id="blocks">
<li>Blockchain ledger</li>
</ul>
</div>
<div id="mined">
<ul id="minedBlocks">
<li>Mining...</li>
</ul>
</div>
</div>
<script src="/socket.io/socket.io.js"></script>
<script>
var socket = io();
var mine = document.getElementById('mine');
function padTo2Digits(num) {
return num.toString().padStart(2, '0');
};
function formatDate(date) {
return (
[
padTo2Digits(date.getDate()),
padTo2Digits(date.getMonth() + 1),
date.getFullYear(),
].join('.') +
' ' +
[
padTo2Digits(date.getHours()),
padTo2Digits(date.getMinutes()),
padTo2Digits(date.getSeconds()),
].join(':')
);
};
function printBlock(block, parent, div) {
var formattedDate;
var timeStamp;
let item = document.createElement("li");
item.style.color = "green";
item.textContent = "Index: " + block.index + "\r\n";
item.textContent += "Data: " + block.data + "\r\n";
timeStamp = new Date(block.timestamp);
formattedDate = formatDate(timeStamp);
item.textContent += "Timestamp: " + formattedDate + "\r\n";
item.textContent += "PreviousHash: " + block.previousHash + "\r\n";
item.textContent += "Difficulity: " + block.diff + "\r\n";
item.textContent += "Nonce: " + block.nonce + "\r\n";
item.textContent += "Hash: " + block.hash + "\r\n";
parent.appendChild(item);
div.scrollTop = ledger.scrollHeight;
}
socket.on('onConnection', function (msg) {
document.getElementById('connectionStatus').innerText = "Status: Online: PORT " + msg;
});
socket.on('blockLedger', function (msg) {
var blocks = document.getElementById('blocks');
var obj = JSON.parse(msg);
var ledger = document.getElementById('ledger');
obj.blockchain.forEach(function (arrayItem) {
printBlock(arrayItem, blocks, ledger);
});
});
socket.on('wrongHash', function (msg) {
var minedBlocks = document.getElementById('minedBlocks');
var mined = document.getElementById('mined');
let item = document.createElement("li");
item.style.color = 'red';
item.textContent = msg;
minedBlocks.appendChild(item);
mined.scrollTop = mined.scrollHeight;
});
socket.on('goodHash', function (msg) {
var minedBlocks = document.getElementById('minedBlocks');
var mined = document.getElementById('mined');
let item = document.createElement("li");
item.style.color = 'green';
item.textContent = msg;
minedBlocks.appendChild(item);
mined.scrollTop = mined.scrollHeight;
});
socket.on('newBlock', function (msg) {
var blocks = document.getElementById('blocks');
var obj = JSON.parse(msg);
var ledger = document.getElementById('ledger');
printBlock(obj, blocks, ledger);
});
mine.addEventListener('click', function (e) {
e.preventDefault();
socket.emit('mine');
});
</script>
</body>
</html>
Edit
I am still trying to find a solution. I tried changing the socket io transport options in both the .js file and index.html, flushing the buffer and using volatile.emit but nothing worked. I think for some reason the emits get buffered and then sent at the end, but i dont know why.
Also, the first two emits execute well (so the 'onConnection' is first and either the 'wrongHash' or 'goodHash' second), but everything after that is sent (or received) after the for loop is executed.
You should call your emit function on
for (var i = 0; i < 5; i++) {
while (true) {
var tmp = new Block(indexNumber, Date.now(), data + indexNumber, logCoin.getTheLatestBlock().hash, difficulity, Nonce);
if (logCoin.validateBlock(tmp)) {
//here you should write this
io.emit('newBlock', JSON.stringify(tmp)); //this is where the new block is emmited
logCoin.addNewBlock(tmp);
indexNumber++;
break;
}
}
//not here
io.emit('newBlock', JSON.stringify(tmp)); //this is where the new block is emmited
console.log(tmp);
}
I want to send either a 1 (New Code) or 0 (no New Code), but still the ViewBag only accepts the first value that is written to it.
Controller
int timesRun = 0;
int newID;
private ApplicationDbContext Context = new ApplicationDbContext();
[HttpGet]
public IActionResult StartPage(string Code)
{
Debug.WriteLine("Start: " + Code);
//Select BauTeilId
var list = (from t in Context.Result select new { t.BauTeilId }).ToList();
//Checking if already exists
for (int i = 0; i < list.Count; i++)
{
if (Code != null)
{
if (list[i].BauTeilId.Equals(Code))
{
newID = 0;
Debug.WriteLine("Keine neue ID " + newID);
}
else
{
newID = 1;
Debug.WriteLine("Neue ID " + newID);
break;
}
Debug.WriteLine(list[i].BauTeilId);
}
}
ViewBag.newID = newID;
return View();
}
HTML
#{
ViewData["Title"] = "Home Page";
}
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title>Starter</title>
<style>
p {
margin-top: 30%;
margin-left: 20%;
margin-right: 20%;
font-family: Arial;
font-size: 25px;
text-align: center;
}
#Code {
border: 2px solid black;
}
</style>
</head>
<body>
<h1>Example Code: 249765876358312345655</h1>
<p>
Eingabe des Maschinen Codes:
<br />
<input id="Code"
name="Code"
pattern=""
size="30"
spellcheck="false"
title="Maschine Code"
value="">
</p>
#{
var data = ViewBag.newID;
if(data != null)
{
data = ViewBag.newID.ToString().ToLower();
}
}
<script>
var x = document.getElementById("Code");
x.addEventListener('input', function (event) {
//Getting the regex sorted out
x = document.getElementById("Code").value;
let vars = x;
let digits = vars.match(/^\d{13}(\d{6})\d{2}$/)[1];
let stringDigits = digits.toString();
if (stringDigits.length == 6 && vars.length == 21) {
//New ID or not
let newID = '#data'.toString().toLowerCase();
Boolean(newID);
alert(newID);
if (newID === '1') window.location.href = '/home/NewIDSettingsPage';
else if(newID === '0')window.location.href = '/home/Kontrolle';
else alert("ERROR");
//Send to Kontrolle
document.getElementById("Code").innerHTML = "";
localStorage.setItem("Code_Kurz", stringDigits);
localStorage.setItem("Code_Lang", x);
//Send Code to Controller
$.ajax({
url: "#Url.Action("StartPage")",
type: "GET",
data: {Code: stringDigits},
success: function (data) { console.log("Succ: " + data); },
error: function (xhr, status, error) {
var errorMessage = xhr.status + ': ' + xhr.statusText;
console.log("ERROR: " + errorMessage);},
});}});
</script>
</body>
</html>
I don't know how to fix that or if there is an other solution to this.
Similar questions:
How To Change or refresh data using ViewBag in MVC3
(That tutorial didnt help me either)
Let assume your list contains 2 rows and during for iteration first time this if (list[i].BauTeilId.Equals(Code)) condition returns true and second time return false.
Your loop will set newID value based on last iteration. In last iteration if if (list[i].BauTeilId.Equals(Code)) return 0 else 1.
Check out below updated code :
if (Code != null)
{
if count > 0 will return 0 else return 1
if (list.Where(x => x.BauTeilId.Equals(Code)).Count() > 0)
{
newID = 0;
Debug.WriteLine("Keine neue ID " + newID);
}
else
{
newID = 1;
Debug.WriteLine("Neue ID " + newID);
}
}
//pass value in viewbag
ViewBag.newID = newID;
i am facing an issue with below mentioned code. The errors are 'aggiungiPrimaOpzione typeError: cannot read property insertBefore of null' and 'inizializza typeError: cannot set property onchange of undefined'.
it also provides a sintaxError: http://i68.tinypic.com/2zdodj5.png
var nodoGenere;
var nodoCategoria;
var nodoCerca;
var nodoRisultato;
var collezione = [
{
genere: "uomo",
categoria: "maglietta",
nome: "maglietta1",
foto: "img/foto1.jpg",
prezzo: 40
},
{
genere: "donna",
categoria: "pantaloni",
nome: "pantalone1",
foto: "img/foto2.jpg",
prezzo: 50
}
];
function gestoreGenere(){
try {
var genere = nodoGenere.value;
var generi = calcolaGenere();
creaSelect(nodoGenere, generi);
nodoGenere.value = genere;
var categorie = ricercaCategoria(genere);
creaSelect(nodoCategoria, categorie);
aggiungiPrimaOpzione(nodoCategoria, "----- categoria ----");
} catch(e) {
alert("gestoreGenere" + e);
}
}
function ricercaCategoria(genere) {
try {
var categorie = {};
for (var i = 0; i < collezione.length; i++) {
var abito = collezione[i];
if (abito.genere == genere) {
categorie[abito.genere] = true;
}
}
return categorie;
} catch(e) {
alert("ricercaCategoria" + e);
}
}
function aggiungiPrimaOpzione(nodoSelect, opzione) {
try {
var nodoOpzione = document.createElement("option");
nodoOpzione.value = opzione;
var nodoTesto = document.createTextNode(opzione);
nodoOpzione.appendChild(nodoTesto);
nodoSelect.insertBefore(nodoOpzione, nodoSelect.firstChild);
nodoSelect.value = opzione;
} catch(e) {
alert("aggiungiPrimaOpzione" + e);
}
}
function gestoreCategoria() {
try {
var genere = nodoGenere.value;
var categoria = nodoCategoria.value;
var categorie = ricercaCategoria(categoria);
creaSelect(nodoCategoria, categorie);
nodoCategoria.value = categoria;
var abiti = ricercaMultipla(genere, categoria);
var listaDescrizioni = calcolaListaDescrizioni(abiti);
creaLista(nodoRisultato, listaDescrizioni);
} catch(e) {
alert("gestoreCategoria" + e);
}
}
function calcolaListaDescrizioni(abiti) {
try {
var listaDescrizioni = [];
for (var i = 0; i < abiti.length; i++){
var abito = abiti[i];
var s = abito.categoria + "dio cane" + abito.genere;
listaDescrizioni.push(s);
}
return listaDescrizioni;
} catch(e) {
alert("calcolaListaDescrizioni" + e);
}
}
function ricercaMultipla(genere, categoria) {
try {
var abiti = [];
for (var i = 0; i < collezione.length; i++) {
var abito = collezione[i];
if (abito.genere == genere && abito.categoria == categoria) {
abiti.push(abito);
}
}
return abiti;
} catch(e) {
alert("ricercaMultipla" + e);
}
}
function calcolaGenere() {
try {
var generi = {};
for (var i = 0; i < collezione.length; i++) {
var abito = collezione[i];
generi[abito.genere] = true;
}
return generi;
} catch(e) {
alert("calcolaGenere" + e);
}
}
function calcolaCategorie() {
try {
var categorie = {};
for (var i = 0; i < collezione.length; i++) {
var abito = collezione[i];
categorie[abito.categoria] = true;
}
return categorie;
} catch(e) {
alert("calcolaCategorie" + e);
}
}
function creaSelect(nodoSelect, opzioni) {
try {
rimuoviFigli(nodoSelect);
for (var opzione in opzioni) {
var nodoOpzione = document.createElement("option");
nodoOpzione.value = opzione;
var nodoTesto = document.createTextNode(opzione);
nodoOpzione.appendChild(nodoTesto);
nodoSelect.appendChild(nodoOpzione);
}
} catch(e) {
alert("creaSelect" + e);
}
}
function creaLista(nodoLista, elementi) {
try {
rimuoviFigli(nodoLista);
for (var i = 0; i < elementi.length; i++) {
var elemento = elementi[i];
var nodoElemento = document.createElement("li");
nodoLista.appendChild(nodoElemento);
var nodoTesto = document.createTextNode(elemento);
nodoElemento.appendChild(nodoTesto);
}
} catch(e) {
alert("creaLista" + e);
}
}
function rimuoviFigli(nodo){
while (nodo.childNodes.lenght > 0) {
nodo.removeChild(nodo.firstChild);
}
}
function inizializza() {
try {
var nodoGenere = document.getElementById("genere");
var nodoCategoria = document.getElementById("categoria");
var nodoRisultato = document.getElementById("risultato");
var genere = calcolaGenere();
creaSelect(nodoGenere, genere);
aggiungiPrimaOpzione(nodoGenere, "----- genere ----");
aggiungiPrimaOpzione(nodoCategoria, "---- categoria ----");
nodoGenere.onchange = gestoreGenere;
nodoCategoria.onchange = gestoreCategoria;
} catch(e) {
alert("inizializza" + e);
}
}
window.onload = inizializza;
and the HTML:
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title> prova </title>
<script src="main.js"></script>
</head>
<body>
<select id="genere"></select>
<select id="categoria"></select>
<input type="button" id="cerca" value="cerca">
<div id="risultato"></div>
</body>
</html>
Thank you in advice for your response.
When I try to call a JS function MyApp_HighlightAllOccurencesOfString() from WebView
String textToSearch = editTextSearchInText.getText().toString();
webSettings.setJavaScriptEnabled(true);
article_web_view.evaluateJavascript("MyApp_HighlightAllOccurencesOfString('" + textToSearch + "')", new ValueCallback<String>() {
#Override
public void onReceiveValue(String s) {
Toast.makeText(getBaseContext(), s, Toast.LENGTH_LONG).show();
}
});
null is returned, and the console is as follows:
"Uncaught ReferenceError: MyApp_HighlightAllOccurencesOfString is not defined", source: (1)
Tell me, please, how correctly to call the JS function from WebView? Why does the "function not defined" error occur? The JS code from the WebView is below:
<script >
var MyApp_SearchResultCount = 0;
function MyApp_HighlightAllOccurencesOfStringForElement (element, keyword){
if (element) {
if (element.nodeType == 3) {
while (true) {
var value = element.nodeValue;
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("class", "MyAppHighlight");
span.style.backgroundColor = "#C5DFEA";
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;
window.scrollTo(0, findPos(span));
MyApp_SearchResultCount++;
}
} else if (element.nodeType == 1) {
if (element.style.display != "none" && element.nodeName.toLowerCase() != "select") {
for (var i = element.childNodes.length - 1; i >= 0; i--) {
MyApp_HighlightAllOccurencesOfStringForElement(element.childNodes[i], keyword);
}
}
}
}
}
function findPos (obj) {var curtop = -100; if (obj.offsetParent) {
do {
curtop += obj.offsetTop;
} while (obj = obj.offsetParent);
return[curtop];
}}
function MyApp_HighlightAllOccurencesOfString (keyword) {MyApp_RemoveAllHighlights();
MyApp_HighlightAllOccurencesOfStringForElement(document.body, keyword.toLowerCase());}function MyApp_RemoveAllHighlightsForElement (element) {
if (element) {
if (element.nodeType == 1) {
if (element.getAttribute("class") == "MyAppHighlight") {
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 (MyApp_RemoveAllHighlightsForElement(element.childNodes[i])) {
normalize = true;
}
}
if (normalize) {
element.normalize();
}
}
}
}
return false;}
function MyApp_RemoveAllHighlights () {
MyApp_SearchResultCount = 0;
MyApp_RemoveAllHighlightsForElement(document.body);
}
function findImage (x, y){
return document.elementFromPoint(x, y).src;
}</script >
try this steps:
//set webviewclient
article_web_view.setWebViewClient(new WebViewClient());
//enable javascript
article_web_view.getSettings().setJavaScriptEnabled(true);
//webchromeclient
article_web_view.setWebChromeClient(new WebChromeClient());
load your file with your functions js
article_web_view.loadUrl("file:///android_asset/myfunctions.html");
then init and run your js script
article_web_view.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
//prefix javascript
wbChart.loadUrl("javascript:MyApp_HighlightAllOccurencesOfString('" + textToSearch + "')");
}
});
I have a JavaScript file using speechSynthesis.
I keep having this error:
"Cannot read property 'attachEvent' of null" in line 129:
Here it is:
speech.bind = function(event, element, callback) {
**if (element.attachEvent) {**
element.attachEvent('on'+event, callback )
} else if (window.addEventListener) {
element.addEventListener(event, callback ,false);
};
};
I will put in here the role code in here so anyone can check the entire JavaScript:
var speech_def = speech_def || {
container: "#glb-materia"
,insert_before: true
,ico: "http://edg-1-1242075393.us-east-1.elb.amazonaws.com/speech/listen_icon.jpg"
,bt_txt: "OUÇA A REPORTAGEM"
,bt_stop: "PARAR!"
,source: ".materia-conteudo"
,ignore: [
".foto-legenda"
,".frase-materia"
,"script"
,"style"
,"#speech"
,".sub-header"
,".chamada-materia"
,".data-autor"
,".box-tags"
,".saibamais"
]
};
var speech = speech || {};
//Polyfill remove()
Element.prototype.remove = function() {
this.parentElement.removeChild(this);
};
NodeList.prototype.remove = HTMLCollection.prototype.remove = function() {
for (var i = 0, len = this.length; i < len; i++) {
if(this[i] && this[i].parentElement) {
this[i].parentElement.removeChild(this[i]);
}
}
};
//Polyfill innerText
if ( (!('innerText' in document.createElement('a'))) && ('getSelection' in window) ) {
HTMLElement.prototype.__defineGetter__("innerText", function() {
var selection = window.getSelection(),
ranges = [],
str;
for (var i = 0; i < selection.rangeCount; i++) {
ranges[i] = selection.getRangeAt(i);
}
selection.removeAllRanges();
selection.selectAllChildren(this);
str = selection.toString();
selection.removeAllRanges();
for (var i = 0; i < ranges.length; i++) {
selection.addRange(ranges[i]);
}
return str;
})
}
speech.iOS = /(iPad|iPhone|iPod)/g.test( navigator.userAgent );
speech.Android = /(Android)/g.test( navigator.userAgent );
speech.include = function() {
var bt = ""
bt += '<div id="speech" '
+'title="'+speech_def.bt_txt+'" '
+'style="'
+'display: none; '
+'margin: 5px; '
+'font-size: 12px; '
+'font-style: italic; '
+'color: #bbbbbb; '
+'cursor: pointer;"'
+'>';
bt += '<img style="width: 25px; height: 25px;" src="'+speech_def.ico+'"> ';
bt += '<i style="vertical-align: top; line-height: 28px;">'+speech_def.bt_txt+'</i>';
bt += '</div>';
var button = document.createElement("SPAN");
button.innerHTML = bt;
var box = document.querySelectorAll(speech_def.container)[0];
if (speech_def.insert_before) {
box.insertBefore(button,box.firstChild);
} else {
box.appendChild(button)
};
};
speech.stop = function() {
window.speechSynthesis.cancel();
}
speech.stop();
speech.content = function() {
var result = "";
var boxes = speech_def.source.split(",");
boxes.reverse();
for (var n = boxes.length - 1; n >= 0; n--) {
var doc = document.querySelector(boxes[n]);
if (doc) {
doc = doc.cloneNode(true);
for (var i = speech_def.ignore.length - 1; i >= 0; i--) {
var els = doc.querySelectorAll(speech_def.ignore[i]);
for (var j = els.length - 1; j >= 0; j--) {
els[j].remove();
};
};
result += "." + doc.innerText;
};
};
return result;
};
speech.start_speech = function() {
var content = speech.content();
// Note: some voices don't support altering params
if (!speech.Android) speech.msg.voice = speech.voices[0];
// msg.voiceURI = 'native';
speech.msg.volume = speech.iOS?1:1; // 0 to 1
speech.msg.rate = speech.iOS?0.6:1; // 0.1 to 10
speech.msg.pitch = speech.iOS?1:1; // 0 to 2
speech.msg.text = content;
speech.msg.lang = 'pt-BR';
speech.msg.onend = function(e) {
// console.log('Finished in ' + event.elapsedTime + ' seconds.');
};
window.speechSynthesis.speak(speech.msg);
};
speech.read = function(){}; //chrome problem
speech.bind = function(event, element, callback) {
if (element.attachEvent) {
element.attachEvent('on'+event, callback )
} else if (window.addEventListener) {
element.addEventListener(event, callback ,false);
};
};
speech.click = function(e){
event.stopPropagation()
if (window.event) window.event.cancelBubble = true;
var control = document.getElementById("speech");
var label;
if (window.speechSynthesis.speaking) {
label = speech_def.bt_txt;
speech.stop();
} else {
label = speech_def.bt_stop;
speech.start_speech();
};
control.querySelector("i").innerHTML = label;
}
speech.bind_button = function() {
var control = document.getElementById("speech");
speech.bind("click",control,speech.click);
};
speech.show_button = function() {
if (!speech.on_page) {
speech.on_page = true;
speech.include();
speech.bind_button();
};
var control = document.getElementById("speech");
control.style.display="inline-block";
};
speech.test_portuguese = function() {
speech.voices = [];
window.speechSynthesis.getVoices().forEach(function(voice) {
if (voice.lang == "pt-BR") {
speech.voices.push(voice);
};
});
if (speech.Android) {
var control = document.getElementById("speech");
var complement = (speech.voices.length > 0)?"*":"";
// control.querySelector("i").innerHTML = "OUÇA A REPORTAGEM"+complement;
return true;
} else {
return (speech.voices.length > 0);
};
};
speech.start = function() {
if ('speechSynthesis' in window) {
speech.msg = new SpeechSynthesisUtterance();
if (speech.test_portuguese()) {
speech.show_button();
} else {
window.speechSynthesis.onvoiceschanged = function() {
if (speech.test_portuguese()) {
speech.show_button();
};
};
};
speech.bind_button();
};
};
speech.start();
speech.bind("load",window,speech.start)
How can i solve this problem?
Thanks so much.
The problem is that element is null at that point.
Probably, because there is no element with id="speech", so control in null in this code:
speech.bind_button = function() {
var control = document.getElementById("speech");
speech.bind("click",control,speech.click);
};