I have a MQTTConnection.js class inside a src folder this class defines methods like subscribe, unsubsribe and connect. Also the App.js class implements the methods imported from MQTTConnection.js and defines the prototypes functions that start with ONMQTT. When I try to run the project the next error is displayed : TypeError: _this.onMQTTLost is not a function.
App.js
import MQTTConnection from './src/MQTTConnection'
import React, {
useEffect
} from 'react'
import {
View,
StyleSheet,
Text,
Button
} from 'react-native'
import {
Buffer
} from 'buffer';
global.Buffer = Buffer;
export default function App() {
useEffect(() => {
this.mqttConnect = new MQTTConnection()
this.mqttConnect.onMQTTConnect = this.onMQTTConnect
this.mqttConnect.onMQTTLost = this.onMQTTLost
this.mqttConnect.onMQTTMessageArrived = this.onMQTTMessageArrived
this.mqttConnect.onMQTTMessageDelivered = this.onMQTTMessageDelivered
onMQTTConnect = () => {
console.log('App onMQTTConnect')
this.mqttConnect.subscribeChannel('hanth2')
}
onMQTTLost = () => {
console.log('App onMQTTLost')
}
onMQTTMessageArrived = (message) => {
console.log('App onMQTTMessageArrived: ', message);
console.log('App onMQTTMessageArrived payloadString: ', message.payloadString);
}
onMQTTMessageDelivered = (message) => {
console.log('App onMQTTMessageDelivered: ', message);
}
this.mqttConnect.connect('4924d328ffbe4e649e261db3563eed0a.s2.eu.hivemq.cloud', 8884)
return () => {
this.mqttConnect.close()
}
}, [])
return ( <
View style = {
styles.container
} >
<
Text > react_native_mqtt < /Text> <
Button title = "Press me"
onPress = {
() => this.mqttConnect.send('hanth2', "message send to channel hanth2 again")
}
/> <
/View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}
})
MQTTConnection.js
import init from 'react_native_mqtt';
import uuid from 'react-native-uuid';
import AsyncStorage from '#react-native-community/async-storage';
init({
size: 10000,
storageBackend: AsyncStorage,
defaultExpires: 1000 * 3600 * 24,
enableCache: true,
sync: {},
});
const defaultConnectOptions = {
reconnect: false,
cleanSession: true,
mqttVersion: 3,
keepAliveInterval: 60,
timeout: 60,
userName: 'serjaumen22',
password: ''
}
export default class MQTTConnection {
constructor() {
this.mqtt = null;
this.QOS = 0;
this.RETAIN = true;
}
connect(host, port, options = null) {
if (options) {
this.QOS = options.qos;
this.RETAIN = options.retain;
}
let currentTime = +new Date();
let clientID = currentTime + uuid.v1();
clientID = clientID.slice(0, 23);
console.log('clientID: ', clientID)
this.mqtt = new Paho.MQTT.Client(host, port, clientID);
this.mqtt.onConnectionLost = (res) => {
this.onMQTTLost;
};
this.mqtt.onMessageArrived = (message) => {
this.onMQTTMessageArrived(message);
};
this.mqtt.onMessageDelivered = (message) => {
this.onMQTTMessageDelivered(message);
};
const connectOptions = options ? options : defaultConnectOptions;
this.mqtt.connect({
onSuccess: this.onMQTTSuccess,
onFailure: this.onMQTTFailure,
...connectOptions
});
}
onMQTTSuccess = () => {
this.onMQTTConnect()
}
onMQTTFailure = () => {
this.onMQTTLost()
}
subscribeChannel(channel) {
console.log('MQTTConnection subscribeChannel: ', channel)
if (!this.mqtt || !this.mqtt.isConnected()) {
return;
}
this.mqtt.subscribe(channel, this.QOS);
}
unsubscribeChannel(channel) {
console.log('MQTTConnection unsubscribeChannel: ', channel)
if (!this.mqtt || !this.mqtt.isConnected()) {
return;
}
this.mqtt.unsubscribe(channel);
}
send(channel = null, payload) {
console.log('MQTTConnection send: ')
if (!this.mqtt || !this.mqtt.isConnected()) {
return;
}
if (!channel || !payload) {
return false;
}
console.log(`MQTTConnection send publish channel: ${channel}, payload: ${payload} qos: ${this.QOS} retained: ${this.RETAIN}`)
this.mqtt.publish(channel, payload, this.QOS, this.RETAIN);
}
close() {
this.mqtt && this.mqtt.disconnect();
this.mqtt = null;
}
}
MQTTConnection.prototype.onMQTTConnect = null
MQTTConnection.prototype.onMQTTLost = null
MQTTConnection.prototype.onMQTTMessageArrived = null
MQTTConnection.prototype.onMQTTMessageDelivered = null
Related
I have created a barcode scanner in my react component using QuaggaJS. The scanner is meant to be used on mobile devices through the web view. It's working fine on all iPhone devices but is not scanning correctly on androids. I am guessing this is a resolution issue in the constraints but have not found a solution that works.
import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import Quagga from "#ericblade/quagga2";
import adapter from "webrtc-adapter";
import LogService from "../../services/LogService";
import "./BarcodeScanner.css";
const BarcodeScanner = (props) => {
const navigate = useNavigate();
const logService = new LogService();
let mainCameraDeviceId = "";
useEffect(() => {
async function getBackDevices() {
await Quagga.CameraAccess.request();
let devices = await Quagga.CameraAccess.enumerateVideoDevices()
.then((devices) => devices)
.catch((err) => {
logService.Log("Error", "Error when enumerating video devices", err);
console.error(`${err.name}: ${err.message}`);
});
let backDevices = [];
devices.forEach((device) => {
logService.Log("Debug", "Detected Device",device);
if(device.kind.toLowerCase().includes("videoinput") && device.label.toLowerCase().includes("back")) {
backDevices.push(device);
console.log(`${device.kind}: ${device.label} id = ${device.deviceId}`);
}
});
if (backDevices.length == 0 && devices.length == 1) {
backDevices.push(devices[0]);
}
logService.Log("Debug", "Detected back devices", backDevices);
mainCameraDeviceId = backDevices[backDevices.length-1].deviceId;
startQuagga();
}
getBackDevices();
}, []);
function startQuagga() {
logService.Log("Debug", "Selected camera device", mainCameraDeviceId);
let customConstraints = {
focusMode: 'continuous',
facingMode: "environment",
zoom: {min: 1.5, max: 2},
deviceId: mainCameraDeviceId,
width: 640,
height: 480
}
if(props.deviceType == "iPhone") {
customConstraints.width = { min: 480 };
customConstraints.height = { min: 1281 };
}
logService.Log("Debug", "Device Type", props.deviceType);
logService.Log("Debug", "Quagga constraints", customConstraints);
try {
Quagga.init(
{
inputStream: {
name: "Live",
type: "LiveStream",
target: document.querySelector("#interactive"),
constraints: customConstraints
},
locate: true,
decoder: {
readers: [
"upc_reader"
],
multiple: false
},
},
function (err) {
if (err != null) {
console.log(err);
props.onError(err);
stopScanner();
return;
}
console.log("Initialization finished. Ready to start");
Quagga.start();
}
);
} catch {
props.onError("Failed to open camera");
}
}
Quagga.onDetected((data) => {
props.onDetected(data.codeResult.code);
Quagga.stop();
});
const stopScanner = () => {
console.log("stopping Quagga");
Quagga.stop();
};
return (
<div
className="barcode-scanner viewport"
id="interactive"
>
<div className="box-overlay"></div>
</div>
);
};
export default BarcodeScanner;
I am facing with this error for days: tried anything written on the internet, but still persisting the error-->
./node_modules/write-json-file/index.js
Module not found: Can't resolve 'node:fs' in 'D:\Codes\ToDo\todo\node_modules\write-json-file'.
Here is my write-json-file/index.js:
import path from 'node:path';
import fs, {promises as fsPromises} from 'node:fs';
import writeFileAtomic from 'write-file-atomic';
import sortKeys from 'sort-keys';
import detectIndent from 'detect-indent';
import isPlainObj from 'is-plain-obj';
const init = (function_, filePath, data, options) => {
if (!filePath) {
throw new TypeError('Expected a filepath');
}
if (data === undefined) {
throw new TypeError('Expected data to stringify');
}
options = {
indent: '\t',
sortKeys: false,
...options,
};
if (options.sortKeys && isPlainObj(data)) {
data = sortKeys(data, {
deep: true,
compare: typeof options.sortKeys === 'function' ? options.sortKeys : undefined,
});
}
return function_(filePath, data, options);
};
const main = async (filePath, data, options) => {
let {indent} = options;
let trailingNewline = '\n';
try {
const file = await fsPromises.readFile(filePath, 'utf8');
if (!file.endsWith('\n')) {
trailingNewline = '';
}
if (options.detectIndent) {
indent = detectIndent(file).indent;
}
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
const json = JSON.stringify(data, options.replacer, indent);
return writeFileAtomic(filePath, `${json}${trailingNewline}`, {mode: options.mode, chown: false});
};
const mainSync = (filePath, data, options) => {
let {indent} = options;
let trailingNewline = '\n';
try {
const file = fs.readFileSync(filePath, 'utf8');
if (!file.endsWith('\n')) {
trailingNewline = '';
}
if (options.detectIndent) {
indent = detectIndent(file).indent;
}
} catch (error) {
if (error.code !== 'ENOENT') {
throw error;
}
}
const json = JSON.stringify(data, options.replacer, indent);
return writeFileAtomic.sync(filePath, `${json}${trailingNewline}`, {mode: options.mode, chown: false});
};
export async function writeJsonFile(filePath, data, options) {
await fsPromises.mkdir(path.dirname(filePath), {recursive: true});
await init(main, filePath, data, options);
}
export function writeJsonFileSync(filePath, data, options) {
fs.mkdirSync(path.dirname(filePath), {recursive: true});
init(mainSync, filePath, data, options);
}
And here is the code where I want to use writeJsonFile, because I want to read from a json file and also write to the same file. The reading part is working, but the problem is at writing to file... The app is a simple Todo App in React.
import React, { useState } from 'react';
import TodoForm from './TodoForm';
import Todo from './Todo';
import data from './data/data.json';
import {writeJsonFile} from 'write-json-file';
function TodoList() {
const [todos, setTodos] = useState(data); // <-- initial state
const fs = require('fs');
const addTodo = (todo) => {
if (!todo.text || /^\s*$/.test(todo.text)) {
return;
}
setTodos((todos) => [todo, ...todos]);
writeJsonFile('data.json', {id: todo.id, text: todo.text});
};
const updateTodo = (id, newTodo) => {
if (!newTodo.text || /^\s*$/.test(newTodo.text)) {
return;
}
setTodos((todos) => todos.map((todo) => (todo.id === id ? newTodo : todo)));
};
const removeTodo = (id) => {
setTodos((todos) => todos.filter((todo) => todo.id !== id));
};
const completeTodo = (id) => {
setTodos((todos) =>
todos.map((todo) =>
todo.id === id
? {
...todo,
isComplete: !todo.isComplete
}
: todo
)
);
};
return (
<>
<TodoForm onSubmit={addTodo} />
<Todo
todos={todos}
completeTodo={completeTodo}
removeTodo={removeTodo}
updateTodo={updateTodo}
/>
</>
);
}
export default TodoList;
It seems clear your issue comes from:
import fs, {promises as fsPromises} from 'node:fs';
But you are experiencing no issue in your second file with:
const fs = require('fs');
Why don't you use the same line of code for your first file?
I want to save an array of object to device using AsyncStorage, I have used AsyncStorage for save my jwt token and it working well. But when i tried to save an array of object it wasn't working here is my code :
const storeCart = async (value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(`cart-${user.id}`, jsonValue);
} catch (e) {
console.log(e);
} finally {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
console.log(
'this is from async storage after save',
JSON.parse(jsonValue),
user.id,
);
}
}
};
const getCart = async () => {
try {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
setCarts(JSON.parse(jsonValue));
console.log('carts after refresh the app', jsonValue, user.id);
}
} catch (e) {
console.log(e);
}
};
I have tried to console log the result after setItem, and it was saved successly, but when i reload the app and tried to console.log, it return and empty array, the key is already correct, and i have console log the user id too for make sure.
Here's the full code, if needed :
import React, { useState, createContext, useEffect, useContext } from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import AuthenticationContext from '../authentication/AuthenticationContext';
const CartsContext = createContext();
export const CartsContextProvider = ({ children }) => {
const { user } = useContext(AuthenticationContext);
const [carts, setCarts] = useState([]);
const storeCart = async (value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(`cart-${user.id}`, jsonValue);
} catch (e) {
console.log(e);
} finally {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
console.log(
'this is from async storage after save',
JSON.parse(jsonValue),
user.id,
);
}
}
};
const getCart = async () => {
try {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
setCarts(JSON.parse(jsonValue));
console.log('carts after refresh the app', jsonValue, user.id);
}
} catch (e) {
console.log(e);
}
};
useEffect(() => {
storeCart(carts);
}, [carts, user]);
useEffect(() => {
getCart();
}, [user]);
const searchByMerchant = (merchantId) => {
for (let i = 0; i < carts.length; i++) {
if (carts[i].merchantId === merchantId) {
return carts[i];
}
}
};
const searchByItem = (itemId, arrayOfItems) => {
for (let i = 0; i < arrayOfItems.length; i++) {
if (itemId === arrayOfItems[i].productId) {
return arrayOfItems[i];
}
}
};
const deletePerMerchant = (merchantId) => {
return carts.filter((x) => {
return x.merchantId != merchantId;
});
};
const deletePerItem = (itemId, arrayOfItems) => {
return arrayOfItems.filter((x) => {
return x.productId != itemId;
});
};
const addItem = (merchantId, productId, qty) => {
let merchantCheck = searchByMerchant(merchantId);
let temp = null;
if (merchantCheck) {
let itemCheck = searchByItem(productId, merchantCheck.items);
if (itemCheck) {
let itemAfterRemoveSelectedItem = deletePerItem(
productId,
merchantCheck.items,
);
temp = deletePerMerchant(merchantId);
if (qty === 0) {
if (itemAfterRemoveSelectedItem.length === 0) {
setCarts([...temp]);
} else {
setCarts([
...temp,
...[
{
merchantId,
items: [...itemAfterRemoveSelectedItem],
},
],
]);
}
} else {
setCarts([
...temp,
...[
{
merchantId,
items: [
...itemAfterRemoveSelectedItem,
...[{ productId, qty: qty }],
],
},
],
]);
}
} else {
temp = deletePerMerchant(merchantId);
setCarts([
...temp,
...[
{
merchantId,
items: [...merchantCheck.items, ...[{ productId, qty }]],
},
],
]);
}
} else {
if (qty > 0) {
setCarts([...carts, ...[{ merchantId, items: [{ productId, qty }] }]]);
}
}
};
return (
<CartsContext.Provider value={{ carts, addItem }}>
{children}
</CartsContext.Provider>
);
};
export default CartsContext;
Thanks !
I believe this is happening because the cart value is being overwritten when you reload the app because the useEffect is called each time you reload the app.
The setCarts is being called after adding something in cart, and therefore the first useEffect (which has in deps [cart, user]) is being called too and it sets correctly the data in local storage. But afterwards, if you reload the app, the same useEffect is being called again and the cart = [] is being set into the local storage.
I would solve this by giving up to the first useEffect and setting directly the data into local storage without having any state related to it.
import React, { useState, createContext, useEffect, useContext } from 'react';
import AsyncStorage from '#react-native-async-storage/async-storage';
import AuthenticationContext from '../authentication/AuthenticationContext';
const CartsContext = createContext();
export const CartsContextProvider = ({ children }) => {
const { user } = useContext(AuthenticationContext);
const storeCart = async (value) => {
try {
const jsonValue = JSON.stringify(value);
await AsyncStorage.setItem(`cart-${user.id}`, jsonValue);
} catch (e) {
console.log(e);
} finally {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
console.log(
'this is from async storage after save',
JSON.parse(jsonValue),
user.id,
);
}
}
};
const getCart = async () => {
try {
const jsonValue = await AsyncStorage.getItem(`cart-${user.id}`);
if (jsonValue != null) {
storeCart(JSON.parse(jsonValue));
console.log('carts after refresh the app', jsonValue, user.id);
}
} catch (e) {
console.log(e);
}
};
useEffect(() => {
getCart();
}, [user]);
const searchByMerchant = (merchantId) => {
for (let i = 0; i < carts.length; i++) {
if (carts[i].merchantId === merchantId) {
return carts[i];
}
}
};
const searchByItem = (itemId, arrayOfItems) => {
for (let i = 0; i < arrayOfItems.length; i++) {
if (itemId === arrayOfItems[i].productId) {
return arrayOfItems[i];
}
}
};
const deletePerMerchant = (merchantId) => {
return carts.filter((x) => {
return x.merchantId != merchantId;
});
};
const deletePerItem = (itemId, arrayOfItems) => {
return arrayOfItems.filter((x) => {
return x.productId != itemId;
});
};
const addItem = (merchantId, productId, qty) => {
let merchantCheck = searchByMerchant(merchantId);
let temp = null;
if (merchantCheck) {
let itemCheck = searchByItem(productId, merchantCheck.items);
if (itemCheck) {
let itemAfterRemoveSelectedItem = deletePerItem(
productId,
merchantCheck.items,
);
temp = deletePerMerchant(merchantId);
if (qty === 0) {
if (itemAfterRemoveSelectedItem.length === 0) {
storeCart([...temp]);
} else {
storeCart([
...temp,
...[
{
merchantId,
items: [...itemAfterRemoveSelectedItem],
},
],
]);
}
} else {
storeCart([
...temp,
...[
{
merchantId,
items: [
...itemAfterRemoveSelectedItem,
...[{ productId, qty: qty }],
],
},
],
]);
}
} else {
temp = deletePerMerchant(merchantId);
storeCart([
...temp,
...[
{
merchantId,
items: [...merchantCheck.items, ...[{ productId, qty }]],
},
],
]);
}
} else {
if (qty > 0) {
storeCart([...carts, ...[{ merchantId, items: [{ productId, qty }] }]]);
}
}
};
return (
<CartsContext.Provider value={{ carts, addItem }}>
{children}
</CartsContext.Provider>
);
};
export default CartsContext;
I am creating a copyCode plugin for QuillJs. Everything seems to be working for the plugin, however, when a space is created between the text and the code-block, you get this error:
Failed to execute 'insertBefore' on 'Node'
Here is the code:
const copyContentIntoClipboard = (rawData: string) => {
const encodedContent = encodeURIComponent(rawData);
const filteredEncodedContent = encodedContent.replace(/%EF%BB%BF/g, "");
const targetContent = decodeURIComponent(filteredEncodedContent);
const tmpHolder = document.createElement("textarea");
tmpHolder.value = targetContent;
document.body.appendChild(tmpHolder);
tmpHolder.select();
document.execCommand("copy");
document.body.removeChild(tmpHolder);
};
const CodeBlock = Quill.import("formats/code-block");
class CopyCode extends CodeBlock {
copyBadge: HTMLDivElement | null;
domNode: HTMLElement;
container: HTMLElement | null;
parent: HTMLElement;
copyHandler: EventListener;
_mountContainer() {
const container = document.createElement("div");
container.classList.add("ql-container");
if (this.domNode.nextSibling) {
this.domNode.parentElement?.insertBefore(
container,
this.domNode
);
container.appendChild(this.domNode); // <-- error starts here
this.container = container;
}
}
_dismountContainer() {
if (this.container) {
this.container.parentElement?.insertBefore(
this.domNode,
this.container.nextSibling
);
this.domNode.parentElement?.removeChild(this.container);
}
this.container = null;
}
_mountBadge() {
const copyBadge = document.createElement("div");
copyBadge.contentEditable = "false";
copyBadge.classList.add("ql-badge", "ql-badge-copy");
copyBadge.textContent = "copy";
this.domNode.parentElement?.insertBefore(
copyBadge,
this.domNode.nextSibling
);
const copyHandler = (e: MouseEvent) => {
e.stopPropagation();
e.preventDefault();
const target = e.target as HTMLElement;
const codeArea = target.previousSibling;
const copyCode = codeArea?.textContent?.trim() || '';
if (!codeArea) {
return;
}
copyBadge.textContent = "copied!";
setTimeout(function() {
copyBadge.textContent = "copy";
}, 2000);
copyContentIntoClipboard(copyCode);
};
copyBadge.addEventListener("click", copyHandler, true);
this.copyHandler = copyHandler;
this.copyBadge = copyBadge;
}
_dismountBadge() {
const badgeIsInDom = this.domNode.parentElement?.contains(this.copyBadge);
if (this.copyBadge && badgeIsInDom) {
this.copyBadge.removeEventListener("click", this.copyHandler, true);
this.copyBadge.parentElement?.removeChild(this.copyBadge);
}
this.copyBadge = null;
this.copyHandler = () => {};
}
_mount() {
this._mountContainer();
this._mountBadge();
}
insertInto(...args: any) {
super.insertInto(...args);
const allowCustomMount = !this.copyBadge && !this.container && this.parent;
if (allowCustomMount) {
this._mount();
}
}
remove() {
this._dismountBadge();
this._dismountContainer();
super.remove();
}
}
Here is the StackBlitz: https://stackblitz.com/edit/typescript-ggvuuy?file=index.html
I believe the error is caused by QuillJS believing the code-block should be a pre block instead of a div block containing a pre block. However, I don't know how to fix it...
Any ideas?
Instead of extending formats/code-block you can use Modules to extend Quill
import hljs from "highlight.js";
import "highlight.js/styles/monokai-sublime.css";
import "./style.css";
import Quill from "quill";
hljs.configure({
languages: ["javascript", "python"]
});
const copyContentIntoClipboard = (rawData: string) => {
const encodedContent = encodeURIComponent(rawData);
const filteredEncodedContent = encodedContent.replace(/%EF%BB%BF/g, "");
const targetContent = decodeURIComponent(filteredEncodedContent);
const tmpHolder = document.createElement("textarea");
tmpHolder.value = targetContent;
document.body.appendChild(tmpHolder);
tmpHolder.select();
document.execCommand("copy");
document.body.removeChild(tmpHolder);
};
class CopyCode {
quill: any;
options: any;
container: HTMLElement;
unusedBadges: HTMLElement[] = [];
reference: { [index: string]: {
parent : HTMLElement | null,
copyBadge : HTMLElement | null
} } = {};
constructor(quill: any, options: any) {
this.quill = quill;
this.options = options;
this.container = this.quill.addContainer('ql-badge-container');
this.quill.root.parentNode.style.position = this.quill.root.parentNode.style.position || 'relative';
this.registerCodeBlock();
this.quill.on('editor-change', () => {
Object.values(this.reference).forEach((item) => {
this.addCopyBadge(item);
this.repositionCopyBadge(item);
})
});
}
registerCodeBlock = () => {
const self = this;
const CodeBlock = Quill.import("formats/code-block");
let counter = 0;
class CopyMode extends CodeBlock {
domNode: HTMLElement;
insertInto(...args: any) {
super.insertInto(...args);
const index = String(counter);
const _node = this.domNode;
_node.setAttribute('data-index', index);
counter++;
self.reference[index] = { parent : _node, copyBadge: null };
}
remove() {
const index = this.domNode.getAttribute("data-index");
if (self.reference[index] && self.reference[index]['copyBadge']) {
const copyBadge = self.reference[index]['copyBadge'];
copyBadge.style.display = 'none';
self.unusedBadges.push(copyBadge);
}
delete self.reference[index];
super.remove();
}
}
Quill.register(CopyMode, true);
}
addCopyBadge = (obj: any) => {
if (obj.copyBadge != null || obj.parent == null) {
return;
}
const index = obj.parent.getAttribute('data-index');
const copyBadge = this.unusedBadges.length ? this.unusedBadges.shift() : document.createElement("span");
copyBadge.style.display = 'block';
copyBadge.contentEditable = "false";
copyBadge.classList.add("ql-badge", "ql-badge-copy");
copyBadge.textContent = "copy";
const copyHandler = (evt: MouseEvent) => {
evt.stopPropagation();
evt.preventDefault();
const codeArea = obj.parent;
const copyText = codeArea?.textContent?.trim() || '';
if (!codeArea) {
return;
}
copyBadge.textContent = "copied!";
setTimeout(function() {
copyBadge.textContent = "copy";
}, 2000);
copyContentIntoClipboard(copyText);
};
copyBadge.addEventListener("click", copyHandler, true);
this.container.appendChild(copyBadge);
this.reference[index]['copyBadge'] = copyBadge;
}
repositionCopyBadge(obj: any) {
const parent: HTMLElement = this.quill.root.parentNode;
const specRect = obj.parent.getBoundingClientRect();
const parentRect = parent.getBoundingClientRect();
Object.assign(obj.copyBadge.style, {
right: `${specRect.left - parentRect.left - 1 + parent.scrollLeft + 4}px`,
top: `${(specRect.top - parentRect.top + parent.scrollTop) + 3}px`,
});
}
}
Quill.register("modules/copy-code", CopyCode);
const quill = new Quill("#editor", {
modules: {
syntax: true,
'copy-code': true,
toolbar: {
container: ["code-block"]
}
},
theme: "snow"
});
Here working example
I'm trying to implement a file reader function in react, but it throws this error of 'TypeError: Cannot add property onload, object is not extensible' on reader.onload part. Could anybody help to clarify what's wrong?
handleFile = (file) => {
const reader = new FileReader();
reader.onload = (event) => {
const file = event.target.result;
const allLines = file.split(/\r\n|\n/);
// Reading line by line
allLines.forEach((line) => {
console.log(line);
});
};
reader.onerror = (event) => {
alert(event.target.error.name);
};
reader.readAsText(file);
}
This is the bits that I'm returning in the class component:
<div className="upload">
<input
type="file"
id="file"
className="input-file"
accept=".txt"
onChange={(e) => this.handleFile(e.target.files[0]) }
/>
</div>
It's odd that code itself works independently but not in my app. Here is my App.js:
import React, { Component } from 'react';
import './App.css';
import Layout from './components/Layout';
import Terminal from './containers/Terminal';
import Prompt from './components/Prompt'
import ChatLine from './components/ChatLine'
import Chat from './containers/Chat';
import FakeData from './components/FakeData';
import FileReader from './components/FileReader'
let optionCount = {
a: 0,
b: 0,
c: 0,
d: 0,
}
//////////////////////////////////////////////////////////////////
console.log("PLEASE FileReader.fakeDataFromReader", typeof FileReader)
class App extends Component {
// regulates the sequence, userinput
state = {
userInput: '',
userAnswer: '',
prevSeq: 'Landing',
currSeq: 'Landing',
nextSeq: '',
backontrackseq: 'Landing',
Landing: {
a: 'Info',
b: 'Upload',
},
Info: {
a: 'Upload',
},
Upload: {
done: 'Person',
},
Person: {
a: 'Ready',
b: 'Ready',
},
Ready: {
a: 'Talk',
b: 'Person',
},
Talk: {
restart: 'Landing',
},
Invalid: {
start: 'Landing',
back: ''
},
renderSeq: 'Landing',
chatContent: [
'I\'m here to talk.',
'Blueberry Placeholder',
'Sheme',
],
optionToRender: null,
};
componentDidMount() {
}
componentWillUnmount() {
}
inputChangedHandler = (event) => {
this.setState({userInput: event.target.value})
}
keyPressedHandler = (event) => {
let key = event.keyCode || event.which;
if (key === 13){
let userAnswer = event.target.value.toLowerCase();
this.setState({userAnswer:userAnswer})
// if currseq is chat, get optiontorender
if (this.state.currSeq === 'Talk' && userAnswer !== 'restart'){
let optionToRender = this.chatOptionHandler(userAnswer)
// this.setState({optionToRender: optionToRender})
// set state here!
let addToChatContent = this.updateChatContent(optionToRender) // this is a new chosen line to add
this.setState({
optionToRender: optionToRender,
chatContent: [...this.state.chatContent, addToChatContent]
})
} else { // otherwise render seq
let seqToRender = this.resHandler(userAnswer)
this.setState({renderSeq: seqToRender})
}
// empty the input field
this.setState({userInput: ''})
}
}
chatOptionHandler = (res) => {
let choice = ''
switch (res) {
case 'give me a shout.':
choice = "a";
// also need to add this to the chatContent?
break;
case 'what?':
choice = "b";
break;
case 'but why?':
choice = "c";
break;
case 'tell me.':
choice = "d";
break;
default:
choice = null;
}
return choice
}
// input: option from the user
// output: random line from the data object
updateChatContent = (opt) => {
try {
let selectedLine;
if (optionCount[opt] <= FakeData.response[opt].length - 1){
selectedLine = FakeData.response[opt][optionCount[opt]]
optionCount[opt] += 1
} else {
optionCount[opt] = 0
selectedLine = FakeData.response[opt][optionCount[opt]]
}
return selectedLine;
}
catch(error) {
console.error(error);
return 'line blackhole'
}
}
resHandler = (res) => {
let currSeq = this.state.currSeq
let nextSeq = this.state[currSeq][res]
// valid next sequence was found
if (nextSeq){
this.setState({
prevSeq: currSeq,
currSeq: nextSeq,
renderSeq: nextSeq
})
return nextSeq
} else { // invalid, there is no nextseq according to the input
// if the currea is 'invalid', render backontrackseq
if (currSeq === 'Invalid'){
return 'Invalid'
} else { // if the currseq is not 'invalid', render Invalid
this.setState({
backontrackseq: currSeq,
Invalid: {
start: 'Landing',
back: currSeq,
},
prevSeq: currSeq,
currSeq: 'Invalid',
renderSeq: 'Invalid'
})
return 'Invalid'
}
}
}
handleFile = (file) => {
const reader = new FileReader();
reader.onload = (event) => {
const file = event.target.result;
const allLines = file.split(/\r\n|\n/);
// Reading line by line
allLines.forEach((line) => {
// IMLEMENT
// from text, get patterns and write it in a json format
console.log(line);
});
};
reader.onerror = (event) => {
alert(event.target.error.name);
};
reader.readAsText(file);
}
handleFile = (file) => {
const reader = new FileReader();
reader.onload = (event) => {
const file = event.target.result;
const allLines = file.split(/\r\n|\n/);
// Reading line by line
allLines.forEach((line) => {
console.log(line);
});
};
reader.onerror = (event) => {
alert(event.target.error.name);
};
reader.readAsText(file);
}
render() {
console.log("[APP] this.state.currSeq:",this.state.currSeq)
let optionToRender = this.state.optionToRender
console.log("[APP] optionToRender", optionToRender)
let chatContentAll = this.state.chatContent
// render line by line
let chatLineComp = chatContentAll.map((line, i) => {
return <ChatLine key={i} lineContent = {line}/>
})
return (
<div className="App">
<Layout>
{this.state.currSeq === 'Upload'?
<Terminal sequence={this.state.renderSeq}>
<div className="upload">
<input
type="file"
id="file"
className="input-file"
accept=".txt"
onChange={(e) => this.handleFile(e.target.files[0])}
/>
</div>
<Prompt userInput = {this.state.userInput}/>
<input
type="text"
onChange={this.inputChangedHandler}
onKeyPress={this.keyPressedHandler}
value={this.state.userInput} />
</Terminal>
:
<Terminal sequence={this.state.renderSeq}>
<Prompt userInput = {this.state.userInput}/>
<input
type="text"
onChange={this.inputChangedHandler}
onKeyPress={this.keyPressedHandler}
value={this.state.userInput} />
</Terminal>
}
<Chat
choice={this.state.userAnswer}
optionToRender={this.state.optionToRender}
content={this.state.chatContent}>
{chatLineComp}
</Chat>
</Layout>
</div>
);
}
}
export default App;