This code contains the user interface of the banking chatbot. I have used Mozilla's Web Speech API to implement the speech to text feature. After implementing it, I have faced a major bug. As soon as the user starts the speech recognition by clicking on the "Speak" button; the textarea automatically increases in size and covers or hides the Submit button which is preventing the user from submitting his/her query. I haven't been able to locate the error.
//initialize speech recognition API
window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
const recognition = new SpeechRecognition(); //initialize my instance of speech recognition
recognition.interimResults = true; //return results while still working on current recognition
//this is where your speech-to-text results will appear
let p = document.createElement("p")
const words = document.querySelector(".words-container")
words.appendChild(p)
//I want to select and change the color of the body, but this could be any HTML element on your page
let body = document.querySelector("body")
let cap_css_colors = ["AliceBlue","AntiqueWhite","Aqua","Aquamarine","Azure","Beige","Bisque","Black","BlanchedAlmond","Blue","BlueViolet","Brown","BurlyWood","CadetBlue","Chartreuse","Chocolate","Coral","CornflowerBlue","Cornsilk","Crimson","Cyan","DarkBlue","DarkCyan","DarkGoldenRod","DarkGray","DarkGrey","DarkGreen","DarkKhaki","DarkMagenta","DarkOliveGreen","Darkorange","DarkOrchid","DarkRed","DarkSalmon","DarkSeaGreen","DarkSlateBlue","DarkSlateGray","DarkSlateGrey","DarkTurquoise","DarkViolet","DeepPink","DeepSkyBlue","DimGray","DimGrey","DodgerBlue","FireBrick","FloralWhite","ForestGreen","Fuchsia","Gainsboro","GhostWhite","Gold","GoldenRod","Gray","Grey","Green","GreenYellow","HoneyDew","HotPink","IndianRed","Indigo","Ivory","Khaki","Lavender","LavenderBlush","LawnGreen","LemonChiffon","LightBlue","LightCoral","LightCyan","LightGoldenRodYellow","LightGray","LightGrey","LightGreen","LightPink","LightSalmon","LightSeaGreen","LightSkyBlue","LightSlateGray","LightSlateGrey","LightSteelBlue","LightYellow","Lime","LimeGreen","Linen","Magenta","Maroon","MediumAquaMarine","MediumBlue","MediumOrchid","MediumPurple","MediumSeaGreen","MediumSlateBlue","MediumSpringGreen","MediumTurquoise","MediumVioletRed","MidnightBlue","MintCream","MistyRose","Moccasin","NavajoWhite","Navy","OldLace","Olive","OliveDrab","Orange","OrangeRed","Orchid","PaleGoldenRod","PaleGreen","PaleTurquoise","PaleVioletRed","PapayaWhip","PeachPuff","Peru","Pink","Plum","PowderBlue","Purple","Red","RosyBrown","RoyalBlue","SaddleBrown","Salmon","SandyBrown","SeaGreen","SeaShell","Sienna","Silver","SkyBlue","SlateBlue","SlateGray","SlateGrey","Snow","SpringGreen","SteelBlue","Tan","Teal","Thistle","Tomato","Turquoise","Violet","Wheat","White","WhiteSmoke","Yellow","YellowGreen"];
const CSS_COLORS = cap_css_colors.map(color => {
//I need to change all color names to lower case, because comparison between words will be case sensitive
return color.toLowerCase()
})
//once speech recognition determines it has a "result", grab the texts of that result, join all of them, and add to paragraph
recognition.addEventListener("result", e => {
const transcript = Array.from(e.results)
.map(result => result[0])
.map(result => result.transcript)
.join("")
p.innerText = transcript
//once speech recognition determines it has a final result, create a new paragraph and append it to the words-container
//this way every time you add a new p to hold your speech-to-text every time you're finished with the previous results
if (e.results[0].isFinal) {
p = document.createElement("p")
words.appendChild(p)
}
//for each result, map through all color names and check if current result (transcript) contains that color
//i.e. see if a person said any color name you know
CSS_COLORS.forEach(color => {
//if find a match, change your background color to that color
if (transcript.includes(color)) {
body.style.backgroundColor = color;
}
})
})
//add your functionality to the start and stop buttons
function startRecording() {
recognition.start();
recognition.addEventListener("end", recognition.start)
document.getElementById("stop").addEventListener("click", stopRecording)
}
function stopRecording() {
console.log("okay I'll stop")
recognition.removeEventListener("end", recognition.start)
recognition.stop();
}
ul {
list-style: none;
padding: 0;
}
p {
color: #444;
}
button:focus {
outline: 0;
}
.container {
max-width: 700px;
margin: 0 auto;
padding: 100px 50px;
text-align: center;
}
.container h1 {
margin-bottom: 20px;
}
.page-description {
font-size: 1.1rem;
margin: 0 auto;
}
.tz-link {
font-size: 1em;
color: #1da7da;
text-decoration: none;
}
.no-browser-support {
display: none;
font-size: 1.2rem;
color: #e64427;
margin-top: 35px;
}
.app {
margin: 40px auto;
}
#note-textarea {
margin: 20px 0;
}
#recording-instructions {
margin: 15px auto 60px;
}
#notes {
padding-top: 20px;
}
.note .header {
font-size: 0.9em;
color: #888;
margin-bottom: 10px;
}
.note .delete-note,
.note .listen-note {
text-decoration: none;
margin-left: 15px;
}
.note .content {
margin-bottom: 40px;
}
#media (max-width: 768px) {
.container {
padding: 50px 25px;
}
button {
margin-bottom: 10px;
}
}
/* -- Demo ads -- */
#media (max-width: 1200px) {
#bsaHolder{ display:none;}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>MJ BOT </title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="{{ url_for('static', filename='styles/style.css') }}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<!-- partial:index.partial.html -->
<section class="msger">
<header class="msger-header">
<div class="msger-header-title">
<i class=""></i> MJ Chatbot <i class=""></i>
</div>
</header>
<main class="msger-chat">
<div class="msg left-msg">
<div class="msg-img" style="background-image: url(https://image.flaticon.com/icons/svg/145/145867.svg)"></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name"></div>
</div>
<div class="msg-text">
<p> {{ questionAsked }} </p>
</div>
</div>
</div>
</main>
<article>
<main class="msger-chat">
<div class="msg right-msg">
<div class="msg-img" style="background-image: url(https://image.flaticon.com/icons/svg/327/327779.svg)"></div>
<div class="msg-bubble">
<div class="msg-info">
<div class="msg-info-name"></div>
</div>
<div class="msg-text">
<p> {{ response }}</p>
</div>
</div>
</div>
</article>
</main>
<form id="output" class="msger-inputarea" action="signup" method="post">
<input id="output" class="msger-input" type="text" name="question"></input>
<input id='play' class="msger-send-btn" type="submit" value="Submit Message !" > </input>
<input type="button" value="Speak" onclick="runSpeechRecognition()"></input>
<button id='stop'></button>
</form>
<button id=play style="font-size:24px">Listen <i class="fas fa-file-audio"></i></button>
Send Query to Agent !
</section>
<script >onload = function() {
if ('speechSynthesis' in window) with(speechSynthesis) {
var playEle = document.querySelector('#play');
var pauseEle = document.querySelector('#pause');
var stopEle = document.querySelector('#stop');
var flag = false;
playEle.addEventListener('click', onClickPlay);
pauseEle.addEventListener('click', onClickPause);
stopEle.addEventListener('click', onClickStop);
function onClickPlay() {
if(!flag){
flag = true;
utterance = new SpeechSynthesisUtterance(document.querySelector('article').textContent);
utterance.voice = getVoices()[0];
utterance.onend = function(){
flag = false; playEle.className = pauseEle.className = ''; stopEle.className = 'stopped';
};
playEle.className = 'played';
stopEle.className = '';
speak(utterance);
}
if (paused) { /* unpause/resume narration */
playEle.className = 'played';
pauseEle.className = '';
resume();
}
}
function onClickPause() {
if(speaking && !paused){ /* pause narration */
pauseEle.className = 'paused';
playEle.className = '';
pause();
}
}
function onClickStop() {
if(speaking){ /* stop narration */
/* for safari */
stopEle.className = 'stopped';
playEle.className = pauseEle.className = '';
flag = false;
cancel();
}
}
}
else { /* speech synthesis not supported */
msg = document.createElement('h5');
msg.textContent = "Detected no support for Speech Synthesis";
msg.style.textAlign = 'center';
msg.style.backgroundColor = 'red';
msg.style.color = 'white';
msg.style.marginTop = msg.style.marginBottom = 0;
document.body.insertBefore(msg, document.querySelector('div'));
}
}
</script>
<script>
/* JS comes here */
function runSpeechRecognition() {
// get output div reference
var output = document.getElementById("output");
// get action element reference
var action = document.getElementById("help");
// new speech recognition object
var SpeechRecognition = SpeechRecognition || webkitSpeechRecognition;
var recognition = new SpeechRecognition();
// This runs when the speech recognition service starts
recognition.onstart = function() {
action.innerHTML = "<small>listening, please speak...</small>";
};
recognition.onspeechend = function() {
action.innerHTML = "<small>stopped listening, hope you are done...</small>";
recognition.stop();
}
// This runs when the speech recognition service returns result
recognition.onresult = function(event) {
var transcript = event.results[0][0].transcript;
var confidence = event.results[0][0].confidence;
output.innerHTML = "<b></b> " + transcript + "<br/> <b></b> " ;
output.classList.remove("hide");
};
// start recognition
recognition.start();
}
</script>
<!-- partial -->
<script src='https://use.fontawesome.com/releases/v5.0.13/js/all.js'></script>
</body>
</html>
recognition.onend = (event) => {
//insert your code to display button here
}
I have an XYChart with data object like
chart.data = [{
"Area": "Korangi",
"AreaNumber": 120,
"SubArea": [{
"SubAreaName": "Korangi-1",
"SubAreaNumber": 60
}, {
"SubAreaName": "Korangi-2",
"SubAreaNumber": 60
}
]
}];
and a series tooltipHTML adapter as
series.tooltipHTML = `<center><strong> {Area}:</strong>
<strong> {AreaNumber}%</strong></center>
<hr />`;
series.adapter.add("tooltipHTML",
function (html, target) {
if (
target.tooltipDataItem.dataContext &&
target.tooltipDataItem.dataContext.SubArea &&
target.tooltipDataItem.dataContext.SubArea.length
) {
var nameTalClientsNumberCells = "";
Cells = "";
target.tooltipDataItem.dataContext.SubArea.forEach(part => {
if (part.SubAreaName != null) {
nameTalClientsNumberCells +=
`<tr><td><strong>${part.SubAreaName}</strong>:  ${part
.SubAreaNumber}%</td></tr>`;
}
//TalClientsNumberCells += `<td>${part.SubAreaNumber}</td>`;
});
html += `<table>
${nameTalClientsNumberCells}
</table>`;
}
return html;
});
For I have tried bootstrap classes but non of them works in tooltipHTML.
what I want is like this
but I tried so far is like this
Please help or refer if there is another way of adding really rich HTML in tooltip
A link to the codepen
What you're doing is fine. I just didn't see you used any bootstrap4 css class. You can achieve what you want with either bootstrap4 built-in classes, or your own custom styles.
//I don't need to set tooltipHTML since I have the adapter hook up to return
// custom HTML anyway
/*
series.tooltipHTML = `<center><strong> {Area}:</strong>
<strong> {AreaNumber}%</strong></center>
<hr />`;
*/
series.adapter.add("tooltipHTML", function (html, target) {
let data = target.tooltipDataItem.dataContext;
if (data) {
let html = `
<div class="custom-tooltip-container">
<div class="col-left">
<h5>${data.Area}</h5>
<ul class="list-unstyled">
${data.SubArea.map(part =>
`
<li class="part">
<span class="name">${part.SubAreaName}</span>
<span class="area">${part.SubAreaNumber}%</span>
</li>
`
).join('')}
</ul>
</div>
<div class='col-right'>
<span class="badge badge-pill badge-success">${data.AreaNumber}%</span>
</div>
</div>
`;
return html;
}
return '';
});
And here is the custom styles:
#chart {
height: 31rem;
}
.custom-tooltip-container {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
min-width: 13rem;
}
.custom-tooltip-container .col-left {
width: 70%;
}
.custom-tooltip-container .col-right {
width: 30%;
text-align: center;
}
.custom-tooltip-container .col-right .badge {
font-size: 1.1rem;
}
.custom-tooltip-container .part {
display: flex;
flex-flow: row nowrap;
justify-content: space-between;
}
Again, you can do whatever you want. Here as demo I just quickly put things together.
demo: https://jsfiddle.net/davidliang2008/6g4u2qw8/61/
I'm working on a Codeigniter project and I want to show a custom 404 page if a route not found. everything is working fine on localhost but when I upload my project on live server it's not showing anymore. On live server it shows me default 404. and the url is generate like this example.com/my404 but not show my custom 404. Please help me to find out where I missing something. Thanks for you valuable answer.
Here is my view file error_404.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>404 Page Not Found</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css">
<style type="text/css">
body
{
padding: 0px;
margin:0px;
}
h1
{
padding: 0px;
margin: 0px;
font-size: 15px;
text-align: center;
font-weight: 600;
font-family: sans-serif;
color: #003a99;
}
#container
{
width: 100%;
background-position: top center;
background-repeat: no-repeat;
background-attachment: local;
background-size: cover;
}
.web
{
padding-top: 10px;
padding-bottom: 85px;
}
span
{
color:#333;
}
.heading
{
color:#333;
}
</style>
</head>
<body>
<div id="container" class="img-responsive" style="assets/images/background-image:url(404-Page-Not-Found2.jpg);">
<img src="assets/images/404-page.png" class="img-responsive"/>
<h1 class="heading">The page you’re looking for went fishing!</h1>
<h1 class="web">Go back to <span>www.vpacknmove.in</span><h1>
</div>
</body>
</html>
Here is my Controller file My404.php
<?php
class My404 extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function index()
{
$this->output->set_status_header('404');
$this->load->view('error_404');//loading in my template
}
}
?>
And my routes
$route['404_override'] = 'My404';
$route['default_controller'] = 'Home';
Try to lowercase the controller name in your route:
$route['404_override'] = 'my404';
Report back if that doesn't solve your problem.
Regarding what to do if you need to customize the 404 generated when there is no matching route, I've created a file /application/core/MY_Exception.php:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Exceptions extends CI_Exceptions {
/**
* Class constructor
*/
public function __construct()
{
parent::__construct();
}
// --------------------------------------------------------------------
/**
* 404 Error Handler
* -----------------
* This method has been extended so that if we use the show_404
* function, that it is a styled/custom 404 page that is shown.
*/
public function show_404( $page = '', $log_error = TRUE )
{
if( is_cli() )
{
$heading = 'Not Found';
$message = 'The controller/method pair you requested was not found.';
}
else
{
$heading = '404 Error - Page Not Found';
$message = 'The page or resource you were looking for was not found on this server.';
}
// By default we log this, but allow a dev to skip it
if( $log_error )
{
log_message('error', $heading . ': ' . $page );
}
if( is_cli() )
{
echo $this->show_error($heading, $message, 'error_404', 404);
}
else
{
$CI = &get_instance();
$CI->output->set_status_header('404');
$view_data = [
'heading' => $heading,
'message' => $message
];
$data = [
'doc_title' => ['pre' => '404 Error - Page Not Found - '],
'extra_head' => '<meta name="robots" content="noindex,nofollow" />',
'content' => $CI->load->view( 'errors/html/error_404', $view_data, TRUE )
];
$CI->load->view('templates/main', $data);
echo $CI->output->get_output();
}
exit(4); // EXIT_UNKNOWN_FILE
}
// --------------------------------------------------------------------
}
Notice that the way I've done it, I'm nesting the error_404 view inside a template that I created. That's just the way I do it. You'd replace that part with what you use when you create pages in your application (usually your controller).
I am extacting a tiny component from a bigger map component on an app using Leafet and it seems impossible to include the JSX into the html string of Leafet DivIcon.
bigger map component render part:
render () {
const {tobject, strings} = this.props
let circle = classes.redCircle
if (tobject.lastPoint.activeEvents.ignition) {
circle = classes.greenCircle
}
const icon = new window. L. DivIcon({
html:
` <div class= ${classes.tobjecticon}><span class= ${classes.tobjecticontext}><div class= ${circle}></div></span></div> `
})
newly extacted component StatusCircle.js:
import React from 'react'
import classes from './StatusCircle.scss'
export const StatusCircle = ({ status}) => {
let circle = classes.redCircle
if (status) {
circle = classes.greenCircle
}
return (
<div className={circle} ></div>
)
}
export default StatusCircle
My question seems similar to this one. I've tried renderToString() of StatusCircle, but using ReactDOM (deprecated there) and not ReactDOMServer and it didn't work saying there is no such function. Is it okay to use ReactDOMServer.renderToString() or .renderToStaticMarkup() to achieve this or is it better to leave unchanged without extraction?
It is OK to leave inner html inside of parent component. But here is the way to render it to markup without using ReactDOMServer. It's a bit tricky way =)
class Inner extends React.Component {
render () {
return (
<span {...this.props}>Inner Element</span>
)
}
}
class Outer extends React.Component {
render () {
const span = document.createElement('span');
ReactDOM.render(<Inner className="red" />, span);
//target html
console.log(span.innerHTML);
return (
<div>
You can use this html
<pre>
{span.innerHTML}
</pre>
</div>
)
}
}
ReactDOM.render(<Outer />, document.querySelector('#root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
I don't want to add more imports to the project and depend on them, but using ReactDOM.Render instide render () is giving: "Warning: _renderNewRootComponent(): Render methods should be a pure function of props and state; triggering nested component updates from render is not allowed. If necessary, trigger nested updates in componentDidUpdate. Check the render method of StatusCircle". While ReactDOMServer.renderToStaticMarkup() works flawlessly like this:
class App extends React.Component{
render() {
let greenCircle = ReactDOMServer.renderToStaticMarkup(<StatusCircle status={true} />)
console.log(greenCircle)
let redCircle = ReactDOMServer.renderToStaticMarkup(<StatusCircle status={false} />)
console.log(redCircle)
return (
<div>
<StatusCircle status={true} />
<StatusCircle status={false} />
</div>
)
}
}
const StatusCircle = ({status}) => {
let circle = "redCircle"
if (status) {
circle = "greenCircle"
}
return <div className={circle}></div>
}
ReactDOM.render(<App />, document.querySelector('#root'))
.redCircle {
background-color: red;
border-radius: 50px;
width: 10px;
height: 10px;
margin: 10px;
}
.greenCircle {
background-color: green;
border-radius: 50px;
width: 10px;
height: 10px;
margin: 10px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom-server.min.js"></script>
<div id="root"></div>
I am trying to withdraw data from a google spreadsheet, convert it into a DataTable and push the values into a Dashboard LineChart according to Google Apps documentation. I have managed to do this with an array I manually populated but I have not managed to figure out how to do this properly with a spreadsheet. It currently states that one or more participants failed to draw and I have an invalide column label. Any ideas what I am doing wrong.
<html>
<head>
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script>
<script type="text/javascript">
google.charts.load('current', {'packages':['corechart', 'controls']});
google.charts.setOnLoadCallback(drawStuff);
function initialize() {
var opts = {sendMethod: 'auto'};
// Replace the data source URL on next line with your data source URL.
var query = new google.visualization.Query('https://docs.google.com/spreadsheets/d/1bqRWtvB6kxBfeIuVzCwVXZ5_mCn1b542CaIwE116jK8/edit#gid=0', opts);
query.setQuery("Select *");
// Send the query with a callback function.
query.send(handleQueryResponse);
}
function handleQueryResponse(response) {
if (response.isError()){
alert('Error in query: ' + response.getMessage() + ' ' + response.getDetailedMessage());
return;
}
else {
var data = response.getDataTable();
return data;
}
}
function drawStuff() {
var data = initialize;
var dashboard = new google.visualization.Dashboard(
document.getElementById('programmatic_dashboard_div'));
// We omit "var" so that programmaticSlider is visible to changeRange.
programmaticSlider = new google.visualization.ControlWrapper({
'controlType': 'CategoryFilter',
'containerId': 'programmatic_control_div',
'options': {
'filterColumnLabel': 'Query',
'ui': {'labelStacking': 'vertical'}
}
});
programmaticChart = new google.visualization.ChartWrapper({
'chartType': 'LineChart',
'containerId': 'programmatic_chart_div',
'options': {
'width': 750,
'height': 300,
'legend': {position: 'top', textStyle: {color: 'blue', fontSize: 16}},
'chartArea': {'left': 15, 'top': 15, 'right': 0, 'bottom': 0},
'chart': {
title: 'Popular Queries',
subtitle: 'by number of clicks'
},
}
});
dashboard.bind(programmaticSlider, programmaticChart);
dashboard.draw(data);
}
</script>
</head>
<body>
<div id="programmatic_dashboard_div" style="border: 1px solid #ccc">
<table class="columns">
<tr>
<td>
<div id="programmatic_control_div" style="padding-left: 2em; min-width: 250px"></div>
<div>
<button style="margin: 1em 1em 1em 2em" onclick="changeRange();">
Select range [2, 5]
</button><br />
</div>
<script type="text/javascript">
function changeRange() {
programmaticSlider.setState({'lowValue': 2, 'highValue': 5});
programmaticSlider.draw();
}
</script>
</td>
<td>
<div id="programmatic_chart_div"></div>
<div id="chart_div"></div>
</td>
</tr>
</table>
</div>
</body>
</html>