This code re-adds information only to the first block:
window.onload = function() {
document.querySelectorAll(".codemirror-textarea").forEach(el => {
const [output] = document.querySelectorAll(".codemirror-textarea");
const editor = CodeMirror.fromTextArea(output, {lineNumbers: true, readOnly: true});
});}
You are looping over the elements, but applies CodeMirror to the first element each time, use el in your loop.
window.onload = function(e) {
document.querySelectorAll(".codemirror-textarea").forEach(el => {
const editor = CodeMirror.fromTextArea(el, {lineNumbers: true, readOnly: true});
});
}
Another way:
window.onload = function() {
Array.from(document.querySelectorAll(".codemirror-textarea")).forEach(el => {
CodeMirror.fromTextArea(el, {lineNumbers: true, readOnly: true});
});}
I am building an Electron app that gets a certain kind of json file from the user and logs all the data from it. But I am getting an error about getting undefined from the quantity:
Json File:
{
"tiers": [
{
"trades": [
{
"wants": [
{
"item": "minecraft:string",
"quantity": {
"min": 15,
"max": 20
}
}
],
"gives": [
{
"item": "minecraft:emerald"
}
]
},
{
"wants": [
{
"item": "minecraft:emerald"
}
],
"gives": [
{
"item": "minecraft:arrow",
"quantity": {
"min": 8,
"max": 12
}
}
]
}
]
},
{
"trades": [
{
"wants": [
{
"item": "minecraft:gravel",
"quantity": 10
},
{
"item": "minecraft:emerald",
"quantity": 1
}
],
"gives": [
{
"item": "minecraft:flint",
"quantity": {
"min": 6,
"max": 10
}
}
]
},
{
"wants": [
{
"item": "minecraft:emerald",
"quantity": {
"min": 2,
"max": 3
}
}
],
"gives": [
{
"item": "minecraft:bow"
}
]
}
]
}
]
}
And this is the main.js:
const { app, BrowserWindow, ipcMain, dialog, ipcRenderer, globalShortcut } = require('electron');
const { autoUpdater } = require('electron-updater');
const path = require('path');
const Store = require('./classes/Store.js');
const { electron } = require('process');
const { setTimeout } = require('timers');
// import Vue from 'vue';
// import Vuetify from 'vuetify';
// import "vuetify/dist/vuetify.min.css";
// Vue.use(Vuetify);
let win;
let loadingScreen;
const store = new Store({
configName: 'settings',
defaults: {
windowBounds: {
width: 800,
height: 600,
x: 0,
y: 0,
},
isMaximized: false,
fullscreen: false
}
});
function createLoadingScreen() {
loadingScreen = new BrowserWindow(Object.assign({
width: 200,
height: 220,
frame: false,
transparent: true,
icon: 'build/icons/icon.png',
webPreferences: {
worldSafeExecuteJavaScript: true
}
}));
loadingScreen.setResizable(false);
loadingScreen.loadURL('file://' + __dirname + '/extraWindows/loadingScreen/loading.html');
loadingScreen.setOverlayIcon('build/icons/icon.png', "Route");
loadingScreen.on('closed', () => loadingScreen = null);
loadingScreen.webContents.on('did-finish-load', () => {
loadingScreen.show();
});
}
function createWindow() {
let width = store.get('windowBounds.width');
let height = store.get('windowBounds.height');
let x = store.get('windowBounds.x');
let y = store.get('windowBounds.y');
let isMaximized = store.get('isMaximized');
win = new BrowserWindow({
width,
height,
x,
y,
icon: 'build/icons/icon.png',
frame: false,
titleBarStyle: "hidden",
webPreferences: {
enableRemoteModule: true,
nodeIntegration: true,
webSafeExecuteJavaScript: true
},
show: false
})
win.setOverlayIcon('build/icons/icon.png', "Route");
if(isMaximized == true) {
win.maximize();
}
win.loadFile('index.html');
win.on('closed', function() {
win = null;
settingScreen = null;
});
win.webContents.on('did-finish-load', () => {
if(loadingScreen) {
loadingScreen.close();
win.show();
}
})
win.on('resize', () => {
store.set('windowBounds', win.getBounds());
});
win.on('move', () => {
store.set('windowBounds', win.getBounds());
})
win.on('maximize', () => {
store.set('isMaximized', true);
})
win.on('unmaximize', () => {
store.set('isMaximized', false);
})
win.on('show', () => {
win.setFullScreen(store.get('fullscreen'));
})
win.once('ready-to-show', () => {
autoUpdater.checkForUpdatesAndNotify();
})
}
function createSettings() {
settingScreen = new BrowserWindow({
width: 600,
height: 800,
frame: false,
parent: win,
modal: true,
titleBarStyle: "hidden",
webPreferences: {
enableRemoteModule: true,
nodeIntegration: true,
worldSafeExecuteJavaScript: true
},
show: false
})
settingScreen.loadFile('extraWindows/settingsScreen/settings.html');
settingScreen.on('close', (event) => {
event.preventDefault();
settingScreen.hide();
})
}
app.on('ready', () => {
createLoadingScreen();
setTimeout(() => {
createWindow();
createSettings();
}, 5000); // Set to 5000
});
app.on('window-all-closed', () => {
if(process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if(BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
})
app.whenReady().then(() => {
globalShortcut.register('CmdOrCtrl+O', () => {
win.webContents.send('openFile');
})
globalShortcut.register('CmdOrCtrl+D', () => {
win.webContents.send('closeFile');
})
})
// These are all of the ipc functions needed for Route to work
ipcMain.handle('viewSettings', (event, arg) => {
if(arg === "true") {
settingScreen.show();
} else if(arg === "false") {
settingScreen.hide();
}
});
ipcMain.handle('changeSettings', (event, arg) => {
if(arg === "fullScreen") {
if(win.isFullScreen() == false) {
win.setFullScreen(true);
store.set('fullscreen', true);
} else {
win.setFullScreen(false);
store.set('fullscreen', false);
}
// Fill in the data for fullscreen
} else if(arg === 'themechooser') {
// Fill in the data for themes
}
});
ipcMain.on('appVersion', (event) => {
event.sender.send('appVersion', { version: app.getVersion() });
});
ipcMain.on('restartApp', () => {
autoUpdater.quitAndInstall();
})
autoUpdater.on('updateAvailable', () => {
win.webContents.send('updateAvailable');
});
autoUpdater.on('updateDownloaded', () => {
win.webContents.send('updateDownloaded');
})
And this is the renderer.js:
const { app, ipcRenderer } = require('electron');
const Store = require('./classes/Store.js');
const remote = require('electron').remote;
const dialog = require('electron').remote.dialog;
const fs = require('fs');
const { S_IFDIR } = require('constants');
const { electron } = require('process');
const { version } = require('os');
let currentWindow = remote.getCurrentWindow();
let $ = function(selector) {
return document.querySelector(selector);
}
let projectArray = [];
// There can only be 5 projects max. Might add more.
let projectCount = 0;
document.querySelector('#tradeSetup').addEventListener('click', () => {
//Create a new setup.
alert("This works!");
});
let fileOpenerOptions = {
title: "Open Trade File",
defaultPath: "C:\\",
buttonLabel: "Start Coding",
properties: [ 'openFile' ],
filters: [
{ name: 'Json', extensions: ['json'] },
{ name: 'All FIles', extensions: ['*'] }
]
}
//Top bar buttons
function openFile() {
dialog.showOpenDialog(currentWindow, fileOpenerOptions).then(fileNames => {
if(fileNames == undefined || fileNames == null) {
console.log("No file selected.");
return;
} else {
let projectName = path.basename(fileNames.filePaths[0], path.extname(fileNames.filePaths[0]));
let rawFileData = fs.readFileSync(fileNames.filePaths[0]);
let fileData = JSON.parse(rawFileData);
console.log(fileData);
if(projectCount < 5) {
projectCount++;
createProject(projectName, fileData);
// Run code
} else if (projectCount == 5) {
alert('Support for more projects is not available yet!\nPlease wait until a later update to have more than 5 projects.');
}
}
});
}
function openSettings() {
ipcRenderer.invoke('viewSettings', "true");
}
function closeFile() {
if(document.querySelector('.activeProjectButton') == null) {
console.log("No project to close.");
} else {
let contine = confirm("Is this project the furthest project to the right? If not, please don't close it.\nThis is a bug that is being worked on.");
if(contine == true) {
document.querySelector('.activeProjectButton').remove();
document.querySelector('.activeWorkspace').remove();
projectCount--;
document.querySelectorAll('.inactiveProjectWorkspace').j--;
}
// Add a fun little secret for users
}
}
document.querySelector('#openFile').addEventListener('click', () => {
openFile();
});
document.querySelector('#openSettings').addEventListener('click', () => {
openSettings();
});
document.querySelector('#closeFile').addEventListener('click', () => {
closeFile();
})
// Create and switch projects
function createProject(name, projectData) {
// This is a beta feature for now. It is not finished
// Create the tab
let projectInProduction = document.createElement("button");
projectInProduction.id = "project" + projectCount + "Click";
projectInProduction.classList.add("invisButton");
projectInProduction.classList.add("inactiveProjectButton");
projectInProduction.classList.add("project" + projectCount);
projectInProduction.innerHTML += (name);
// Remove the welcome message
document.querySelector('.unHidden').classList.add('hidden');
document.querySelector('.unHidden').classList.remove('unHidden');
//Create the workspace
let workspaceInProduction = document.createElement("div");
workspaceInProduction.classList.add("inactiveWorkspace");
projectArray.push(projectData);
if(projectArray[projectCount - 1].tiers == null) {
alert("This is not a trade file!\nPlease use a trade file!");
} else {
$('.projects').appendChild(projectInProduction);
$('#jsonProjectContainer').appendChild(workspaceInProduction);
let table = document.createElement('table');
table.innerHTML += '<tr><th colspan="3">Buying</th><th colspan="2">Selling</th></tr>';
table.classList.add('table' + projectCount);
workspaceInProduction.appendChild(table);
let tiers = Object.keys(projectArray[projectCount - 1].tiers).length;
console.log(tiers);
for(let i = 0; i < tiers; i++) {
let tradesC = Object.keys(projectArray[projectCount - 1].tiers[i].trades).length;
for(let j = 0; j < tradesC; j++) {
let wants = Object.keys(projectArray[projectCount - 1].tiers[i].trades[j].wants);
let wantsC = Object.keys(projectArray[projectCount - 1].tiers[i].trades[j].wants).length;
let gives = Object.keys(projectArray[projectCount - 1].tiers[i].trades[j].gives);
for(let k = 0; k < wantsC; k++) {
let wantsItem = projectArray[projectCount - 1].tiers[i].trades[j].wants[k].item;
let wantsMin = projectArray[projectCount - 1].tiers[i].trades[j].wants[k].quantity["min"];
let wantsMax = projectArray[projectCount - 1].tiers[i].trades[j].wants[k].quantity["max"];
let givesItem = projectArray[projectCount - 1].tiers[i].trades[j].gives[0].item;
console.log("Wants: " + wants[k]);
console.log("Min: " + wantsMin);
console.log("Max: " + wantsMax);
console.log("Item: " + wantsItem);
console.log("Gives: " + gives);
console.log("Item: " + givesItem);
}
}
}
}
// Add a onlclick function to make switching projects work
j = projectCount;
document.getElementById('project' + projectCount + 'Click').addEventListener('click', function(j) {
let buttonIndex = j;
let buttonNodes = $('.projects').children;
let workspaceNodes = $('#jsonProjectContainer').children;
for(let i = 0; i < buttonNodes.length; i++) {
if(i == (j - 1)) {
buttonNodes[i].classList.add('activeProjectButton');
buttonNodes[i].classList.remove('inactiveProjectButton');
workspaceNodes[i].classList.add('activeWorkspace');
workspaceNodes[i].classList.remove('inactiveWorkspace');
} else {
buttonNodes[i].classList.remove('activeProjectButton');
buttonNodes[i].classList.add('inactiveProjectButton');
workspaceNodes[i].classList.remove('activeWorkspace');
workspaceNodes[i].classList.add('inactiveWorkspace');
}
}
}.bind(null, j));
}
// Title bar scripts
ipcRenderer.on('openFile', () => {
openFile();
})
ipcRenderer.on('closeFile', () => {
closeFile();
})
// App updates
ipcRenderer.send('appVersion');
ipcRenderer.on('appVersion', (event, arg) => {
ipcRenderer.removeAllListeners('appVersion');
//version.innerText = ;
});
const updateNotifier = document.getElementById('updateNotifier');
const updateAvailability = document.getElementById('updateAvailability');
const restartButton = document.getElementById('restartButton');
ipcRenderer.on('updateAvailable', () => {
ipcRenderer.removeAllListeners('updateAvailable');
updateAvailability.innerText = 'A new version of Route is available. Downloading now...';
updateNotifier.classList.remove('hidden');
});
ipcRenderer.on('update_downloaded', () => {
ipcRenderer.removeAllListeners('updateDownloaded');
updateAvailability.innerText = 'Update downloaded. It will be installed on restart. Restart to continue.';
restartButton.classList.remove('hidden');
updateNotifier.classList.remove('hidden');
});
function restartApp() {
ipcRenderer.send('restartApp');
}
And this is the index.html:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>route - Minecraft Addon Tool</title>
<!-- https://electronjs.org/docs/tutorial/security#csp-meta-tag -->
<meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
<link href="index.css" type="text/css" rel="stylesheet" />
<link href="node_modules/#mdi/font/css/materialdesignicons.min.css" type="text/css" rel="stylesheet" />
</head>
<body>
<script>
// const electron = require('electron').remote;
const path = require('path');
const customTitleBar = require('custom-electron-titlebar');
const Menu = require('electron').remote.Menu;
const MenuItem = require('electron').remote.MenuItem;
let mainTitlebar = new customTitleBar.Titlebar({
backgroundColor: customTitleBar.Color.fromHex('#391B47'),
icon: 'build/icons/icon.png'
});
const menu = new Menu();
menu.append(new MenuItem({
label: 'Github',
click: () => {
currentWindow.webContents.on('new-window', require('electron').shell.openExternal('https://github.com/Gekocaretaker/route'));
}
}));
menu.append(new MenuItem({
label: 'Discord',
click: () => {
console.log("Hiding the link!");
}
}));
menu.append(new MenuItem({
label: 'File',
submenu: [
{
label: 'Open File',
accelerator: 'Ctrl+O',
click: () => {
openFile();
}
},
{
label: 'Close File',
accelerator: 'Ctrl+D',
click: () => {
closeFile();
}
},
{
label: 'New File',
accelerator: 'Ctrl+N',
click: () => {
console.log("This is not yet available.");
}
}
]
}))
mainTitlebar.updateMenu(menu);
</script>
<div class="grid-container">
<div class="buttons">
<div class="tooltip openFileContainer">
<button id="openFile" class="invisButton"><span class="mdi mdi-file mdi-48px"></span></button>
<div>File</div>
</div>
<div class="tooltip settingsContainer">
<button id="openSettings" class="invisButton"><span class="mdi mdi-cog-outline mdi-48px"></span></button>
<div>Settings</div>
</div>
<div class="tooltip closeProjectContainer">
<button id="closeFile" class="invisButton"><span class="mdi mdi-close mdi-48px"></span></button>
<div>Close Project</div>
</div>
</div>
<div class="projects">
<!-- <div class="project1">
<button class="invisButton activeProjectButton" id="project1Click">Project 1</button>
</div> -->
</div>
<div class="jsonEditor">
<!-- <div class="workSpace1 activeWorkSpace">
<h3>This is Workspace 1</h3>
</div> -->
<div id="jsonProjectContainer"></div>
<div class="unHidden">
<p id="welcomeMessage">Hello User! Welcome to Route. I hope you enjoy using this!</p>
</div>
<div id="updateNotifier" class="hidden">
<p id="updateAvailability"></p>
<button id="restartButton" onclick="restartApp()"></button>
</div>
</div>
<div class="sidebar">
<div class="tooltip tradeBuilder">
<button id="tradeSetup" class="invisButton"><span class="mdi mdi-apache-kafka mdi-48px"></span></button>
<div>Basic Trade</div>
</div>
<div class="tooltip whatNext">
<button id="whatsNext" class="invisButton"><span class="mdi mdi-help mdi-48px"></span></button>
<div>Whats Next?</div>
</div>
</div>
</div>
<script src="renderer.js"></script>
</body>
</html>
This is the error:
Uncaught (in promise) TypeError: Cannot read property 'min' of undefined
at createProject (renderer.js:126)
at renderer.js:48
And I am pretty sure the error comes from how I get "min". I have tried using ["min"], ['min'], .min, and as a last resort, [0].
I have the code hosted on github, if needing to be shared.
If you would debug your code, you would notice that the error occurs when j=1 and k=0. Then if you check the object, you notice that at that location there is no question property:
{
"tiers": [
{
"trades": [
{
/* ... */
},
{
"wants": [
{
"item": "minecraft:emerald"
/* no quantity here */
}
],
"gives": [
/* ... */
]
}
]
},
/* ... */
So you'll have to decide what you want to happen when there is no quantity property. You can for instance use the optional chaining operator to use a default value:
let wantsMin = projectArray[projectCount - 1].tiers[i].trades[j].wants[k].quantity.?min || 0;
let wantsMax = projectArray[projectCount - 1].tiers[i].trades[j].wants[k].quantity.?max || 0;
The above would give 0 as value for the min/max values that are missing. But all depends on what you want to happen in this scenario.
This is just an example on how you can circumvent the error, but might not be the right way to deal with it in light of the rest of your code. That is up to you to determine.
This code is to access or process the values that are in nested array.we are iterating with loops and checks the iterating values that either it is an array or not with .isArray if yes we fetch the value ,if no we return the value.
var arr=[['hi'],
['hello',['welcome','bye']],
['world']];
for(var i=0; i<arr.length; i++)
{
for(var j=0; j<arr.length; j++)
{
if(Array.isArray(arr[i][j]))
{
for(var k=0; k<arr.length; k++)
{
console.log(arr[i][j][k]);
}
}
else
{
console.log(arr[i][j]);
}
}
}
On our project we use pell WYSIWYG text editor, with following code:
import { moduleInit } from 'gs-components/export/js/_utils';
import pell from 'pell';
class Wysiwyg {
constructor (element) {
this._element = element;
this._store = this._element.querySelector('.input__input')
this._placeholder = this._element.querySelector('.input__label');
this._element.appendChild(this._placeholder);
this._editor = pell.init({
element: this._element.querySelector('.wysiwyg__editor'),
defaultParagraphSeparator: 'p',
onChange: html => this._store.value = html,
actions: [
{
name: 'heading2',
icon: '<b>Überschrift</b>',
title: 'Überschrift'
},
{
name: 'paragraph',
icon: 'Text',
title: 'Text'
},
'bold',
'italic',
'underline',
'olist',
'ulist'
],
classes: {
button: 'gs-btn gs-btn--xs gs-btn--bordered',
selected: 'gs-btn--dark'
}
});
this._editor.content.innerHTML = this._store.value;
const pellContent = this._element.querySelector('.pell-content');
pellContent.addEventListener('focus', (e) => {
this._store.dispatchEvent(this._buildEvent('focus'));
});
pellContent.addEventListener('blur', (e) => {
this._store.dispatchEvent(this._buildEvent('blur'));
});
this._store.dispatchEvent(this._buildEvent('blur'));
}
_buildEvent(type) {
const event = document.createEvent('HTMLEvents');
event.initEvent(type, true, true);
return event;
}
}
export const init = () => moduleInit('.input--wysiwyg', element => {
new Wysiwyg(element);
});
and we must implement paste event and striptags function:
Example
var striptags = require('striptags');
var html =
'<a href="https://example.com">' +
'lorem ipsum <strong>dolor</strong> <em>sit</em> amet' +
'</a>';
striptags(html);
striptags(html, '<strong>');
striptags(html, ['a']);
striptags(html, [], '\n');
But, how and where?
Here is answer:
pellContent.addEventListener('paste', (e) => {
setTimeout(() => {
this._editor.content.innerHTML = striptags(this._editor.content.innerHTML, ['h2', 'p', 'br', 'ul', 'ol', 'li']);
this._store.value = this._editor.content.innerHTML;
})
});
Codepen
I am trying to add a custom button on the toolbar so that once a user is done editing they can remove the text area.
var init = false;
var quill = null;
document.getElementById('editor-container').addEventListener('click', () => {
console.log(quill);
if(!init) {
quill = new Quill('#editor-container', {
modules: {
toolbar: '#toolbar-container'
},
placeholder: 'Compose an epic...',
theme: 'snow' // or 'bubble'
});
init = true;
};
var Parchment = Quill.import("parchment");
let CustomClass = new Parchment.Attributor.Class('custom', 'ql-custom', {
scope: Parchment.Scope.INLINE
});
Quill.register(CustomClass, true);
var customButton = document.querySelector('#custom-button');
customButton.addEventListener('click', function(event) {
event.stopPropagation();
quill = null;
console.log(quill);
});
})
I have the following code:
var modal = $.modal({
title: title,
closeButton: true,
content: content,
width: 1000,
maxHeight: 850,
resizeOnLoad: true,
buttons: {
'Submit': function (win) {
submitHandler($link, $('#main-form'));
},
'Submit & Close': function (win) {
var rc = submitHandler($link, $('#main-form'));
if (rc == true) { win.closeModal(); }
},
'Close': function (win) {
win.closeModal();
}
}
});
What I would like to do is have a different set of buttons depending on the type of modal window that is being created. I tried to do this using the following code but I get an error:
if (title.substr(0, 4) == "Crea") {
title += $('#RowKey').val();
var btns = btns1;
}
if (title.substr(0, 4) == "Edit") {
var btns = btns1;
}
if (title.substr(0, 4) == "Dele") {
var btns = btns2;
}
var btns1 = new {
'Submit': function (win) {
submitHandler($link, $('#main-form'));
},
'Submit & Close': function (win) {
var rc = submitHandler($link, $('#main-form'));
if (rc == true) { win.closeModal(); }
},
'Close': function (win) {
win.closeModal();
}
}
var btns2 = new {
'Submit & Close': function (win) {
var rc = submitHandler($link, $('#main-form'));
if (rc == true) { win.closeModal(); }
},
'Close': function (win) {
win.closeModal();
}
}
var modal = $.modal({
title: title,
closeButton: true,
content: content,
width: 1000,
maxHeight: 850,
resizeOnLoad: true,
buttons: btns
});
The error that I get is on the line:
var btns1 = new {
Error message is:
Object doesn't support this action
I guess there is something wrong with the way I make the assignment but I am not sure how to do this. I hope someone can help me out.
Can someone help me by telling me what I am doing wrong.
omit the new for objects.
var btns1 = new { .. };
should be
var btns1 = {someProperty: someValue, ... };
alternativ way with new:
var bts1 = new Object();
btns1.someProperty = someValue; ...
No need for the new operator: you can instantiate your new Object via the Object literal:
var btns1 = { ... };