JavaScript iOS9 Bug - ClassList - javascript

I have a block of JavaScript written with some ES6 that transpiles down with Babel. What the code is looking to do is check to see whenever a section scrolls into view, at which point a class it added to toggle in its content. I have been told this isn't working on an iOS9 device and I don't have one here to test myself to replicate the error. Can anybody see what part of this isn't supported? I suspect it would be classList.contains but I'm not positive. Any suggestions would be great!
function toggleLume() {
const lumeImages = document.querySelectorAll('.model-image.lume');
lumeImages.forEach(image => image.classList.toggle('is-active'));
lumeIcons.forEach(icon => icon.classList.toggle('is-active'));
}
function checkIfInView() {
const windowHeight = window.innerHeight;
const windowTopPosition = window.scrollY;
const windowBottomPosition = (windowHeight + windowTopPosition);
const buffer = 120;
const panels = document.querySelectorAll('.panel');
panels.forEach(panel => {
const panelHeight = panel.clientHeight;
const panelTop = (panel.offsetTop - panel.scrollTop) + buffer;
const panelBottom = (panelTop + panelHeight);
if ((panelBottom >= windowTopPosition) && (panelTop <= windowBottomPosition) && !panel.classList.contains('in-view')) {
panel.classList.add('in-view');
}
});
}
Side note, I am interested in JavaScript solutions first and jQuery if I have no other plain JS option.

Related

Slow Render/Delayed Render in Vanilla Javascript App

I have a couple issues - the app is a vanilla javascript app for school that maps audio to each alphabetical key. The issues are as follows:
It takes quite a while to load the audio - the app proceeds like normal but with no audio - it usually can run as intended after a few minutes or a few refreshes, but I do want to get rid of that period. I tried to fix that using (document.readyState === "interactive") and if (allAudio.entries(audio => (audio.readyState === 4)))
It doesn't take the first key down event to change the intro slides, it takes the second - but I'm also not sure how to fix this. The slides are in an array that goes through each item and then makes them display as none. I also tried to add the event listener for the keyboard earlier, but to no avail.
To look at the bugs yourself, live link is here: https://haeuncreative.github.io/mosatic/
relevant code:
if (document.readyState === "interactive") {
const allAudio = document.querySelectorAll("audio")
console.log(allAudio)
if (allAudio.entries(audio => (audio.readyState === 4)))
window.addEventListener('load', function() {
const keysDown = new KeyDownHandler()
const canvas = document.querySelector('canvas');
const context = canvas.getContext('2d');
context.fillStyle = '#967bb6'
context.fillRect(0, 0, 1000, 562.5)
const clickDown = new ClickHandler(keysDown)
}
);
}
export default class KeyDownHandler {
constructor() {
this.addPressListener()
// audio
this.soundBank = new AudioBank
this.soundBank.createBank(CONSTANTS.KEY_ALPHABET)
// visual // intro
this.intro1 = document.querySelector('#intro1')
this.intro2a = document.querySelector('#intro2a')
this.intro2b = document.querySelector('#intro2b')
this.intro2c = document.querySelector('#intro2c')
this.intro3 = document.querySelector('#intro3')
this.intro4 = document.querySelector('#intro4')
this.introBank = [
this.intro1,
this.intro2a,
this.intro2b,
this.intro2c,
this.intro3,
this.intro4
]
// visual // main
this.body = document.querySelector('body')
this.canvas = document.querySelector('canvas');
this.context = this.canvas.getContext('2d');
this.background_colors = ["#95c88c", "#967bb6", "#A7C7E7", "#FF6961"]
this.aniBank = new AniBank;
// recording/user interaction
this.keys = [];
this.durations = [];
this.recording = false;
}
introSwitch() {
this.soundBank.playSpace()
if (this.currentSlide) {
this.currentSlide.style.animation = "fadeOut 1s"
this.currentSlide.style.display = "none"
this.currentSlide = ""
}
if (!this.introBank.length) {
slide.style.display = "none"
this.introFinish = true
}
if (this.introBank.length) {
let slide = (this.introBank.shift())
slide.style.filter = "brightness(60%)"
console.log(slide)
if (slide === this.intro4 || !slide) {
this.canvas.style.display = "flex";
this.addKeyListeners()
}
if (slide.style.display = "none") {
slide.style.display = "flex"
slide.style.filter = "brightness(60%)"
}
this.currentSlide = slide;
slide.style.filter = "brightness(100%)"
}
}
addPressListener() {
window.addEventListener('keypress', e => {
e.preventDefault()
e.stopImmediatePropagation()
this.introSwitch()
if (this.currentSlide === this.intro4) {
this.currentSlide.style.display = "none"
window.removeEventListener("keypress", this.introSwitch)
this.addKeyListeners()
}
})
}`
It takes quite a while to load the audio - the app proceeds like normal but with no audio - it usually can run as intended after a few minutes or a few refreshes, but I do want to get rid of that period. I tried to fix that using (document.readyState === "interactive") and if (allAudio.entries(audio => (audio.readyState === 4)))
It doesn't take the first key down event to change the intro slides, it takes the second - but I'm also not sure how to fix this. The slides are in an array that goes through each item and then makes them display as none. I also tried to add the event listener for the keyboard earlier, but to no avail.

Async JS validation issues for html textarea

I'm trying to replicate the code in this article:
https://depth-first.com/articles/2020/08/24/smiles-validation-in-the-browser/
What I'm trying to do different is that I'm using a textarea instead of input to take multi-line input. In addition to displaying an error message, I also want to display the entry which doesn't pass the validation.
The original validation script is this:
const path = '/target/wasm32-unknown-unknown/release/smival.wasm';
const read_smiles = instance => {
return smiles => {
const encoder = new TextEncoder();
const encoded = encoder.encode(`${smiles}\0`);
const length = encoded.length;
const pString = instance.exports.alloc(length);
const view = new Uint8Array(
instance.exports.memory.buffer, pString, length
);
view.set(encoded);
return instance.exports.read_smiles(pString);
};
};
const watch = instance => {
const read = read_smiles(instance);
document.querySelector('input').addEventListener('input', e => {
const { target } = e;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
(async () => {
const response = await fetch(path);
const bytes = await response.arrayBuffer();
const wasm = await WebAssembly.instantiate(bytes, { });
watch(wasm.instance);
})();
For working with a textarea, I've changed the watch function to this and added a <p id="indicator"> element to the html to display an error:
const watch = instance => {
const read = read_smiles(instance);
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
var lines_array = target.value.split('/n');
var p = document.getElementById("indicator");
p.style.display = "block";
p.innerHTML = "The size of the input is : " + lines_array.length;
if (read(target.value) === 0) {
target.classList.remove('invalid');
} else {
target.classList.add('invalid');
}
});
}
I'm not even able to get a count of entries that fail the validation. I believe this is async js and I'm just a beginner in JavaScript so it's hard to follow what is happening here, especially the part where the function e is referencing itself.
document.querySelector("textarea").addEventListener('input', e => {
const { target } = e;
Can someone please help me in understanding this complicated code and figuring out how to get a count of entries that fail the validation and also printing the string/index of the same for helping the user?
There is a mistake in you code to count entries in the textarea:
var lines_array = target.value.split('\n'); // replace /n with \n
You are asking about the function e is referencing itself:
The destructuring assignment syntax is a JavaScript expression that makes it possible to unpack values from arrays, or properties from objects, into distinct variables. You can find more informations Mdn web docs - Destructuring object

JS for loop not working on Live Wordpress website, although it works locally

everyone. I am a beginner programmer building the website for our own language academy.
I am building a schedule app with JavaScript in WordPress (REST API). the code runs just fine, until it reaches this loop.
Tried for, forEach, and they do not work. I tried modifying the PHP / MySQL settings, and have spent hours around this.
The live website is hosted on Cloudways, and I am using FlyWheel Local locally.
Any ideas? (Thanks)
This is part of the code...
teacherBlocks.forEach((t)=>{
const blockFragment = new DocumentFragment()
//block info
const classID = t.te_schedule_class_ID
const thePermalink = t.te_schedule_class_permalink
//Create theBlock
const theBlock = document.createElement('div')
theBlock.className = `class-desc outlined__dotted`
theBlock.setAttribute('data-class-id', classID)
theBlock.setAttribute('tabindex', 0)
/************************************************************** */
/** theBlock attributes */
//Data attributes
theBlock.setAttribute('teacher-term-id', t.te_teacher_term_id)
theBlock.setAttribute('teacher-name', t.te_teacher_in_block)
theBlock.setAttribute('attendance-type', t.te_schedule_attendance_type)
theBlock.setAttribute('type-of-class', t.te_schedule_lesson_type)
theBlock.setAttribute('teacher-color', teachColor)
/************************************************************** */
/** theBlock Data preparation */
//Get day
const dayInBlockTermID = t.te_schedule_day_term_id
const dayInBlock = t.te_schedule_day
//Get time
const timeInBlock = t.te_schedule_time
//Ready times for height
const timeInBlockStr = timeInBlock.replace(/:/g,'').replace('-','')
const startTime = timeInBlockStr.substr(0,4)
const endTime = timeInBlockStr.substr(4,4)
//Block height
const startTimePx = timeNotation[startTime]
const endTimePx = timeNotation[endTime]
const blockHeight = (endTimePx - startTimePx)
//Block styles
theBlock.style.position = 'absolute'
theBlock.style.top = startTimePx + 'px'
theBlock.style.minHeight = blockHeight + 'px'
theBlock.style.maxHeight = blockHeight + 'px'
theBlock.style.width = theBlockWidthPx + 'px'
theBlock.style.backgroundColor = teachColor
//block text content
const highlightText = t.te_schedule_block_highlight_text
const blockText = t.te_schedule_block_normal_text
//room_label + room_url
const roomLabel = t.te_room_label
const roomURL = t.te_room_url
/************************************************************** */
/** theBlock Data preparation: Students */
//Get students
const profiles = t.te_st_profiles
const students = t.te_schedule_students //To replace with PROFILES
//students Div
const studentNamesDiv = document.createElement('div')
studentNamesDiv.className = 'student-names-in-block'
//Profiles
if(profiles){
const profileFragment = new DocumentFragment()
profiles.forEach(profile =>{
//delete the 'students' and leave only 'profiles'
const oldSt = studentNamesDiv.querySelectorAll('[old="yes"]')
oldSt.forEach(old => {
old.classList.add('hidden')
})
const profileID = profile.st_profile_id
const profileName = profile.st_profile_name
const profileSlug = profile.st_profile_slug
const profileEmail = profile.st_user_email
const profileLink = document.createElement('a')
profileLink.className = 'profile-link'
profileLink.setAttribute('target', '_blank')
profileLink.setAttribute('data-id', profileID)
profileLink.setAttribute('data-slug', profileSlug)
profileLink.setAttribute('data-name', profileName)
profileLink.setAttribute('href', `${scheduleLocalize.teSiteUrl}/st-student/${profileName}`)
//const copyBtn = document.createElement('span')
//copyBtn.className = 'copy-btn dashicons dashicons-paperclip'
//profileLink.appendChild(copyBtn)
if(profileEmail === null){
const errorAsterisk = document.createElement('span')
errorAsterisk.innerHTML = '*'
profileLink.appendChild(errorAsterisk)
}
profileLink.innerHTML += profileName + '</br>'
profileFragment.appendChild(profileLink)
})
studentNamesDiv.appendChild(profileFragment)
}
/************************************************************** */
/** theBlock innerHTML*/
theBlock.innerHTML +=
`<div class="block-text-contents">
${highlightText ? `<span class="highlight-text"> ${highlightText} </span>` : ''}
<span class="block-text">${blockText}</span>
</div>
<a class="day-time" day-term-id="${dayInBlockTermID}" day="${dayInBlock}" time="${timeInBlock}" target="_blank" href="${thePermalink}">${dayInBlock + ` ` + timeInBlock}</a>
<div class="block-buttons">
${roomLabel != false
? `<a target="_blank" class="room-button" href="${roomURL}">${roomLabel}</a>`
: ``}<a target="_blank" class="report-button" href="${thePermalink}">Report</a>
</div>`
/*************************************************** */
/** Insert the theBlock in its day > teacher column */
/** They will be sorted by their class Desc ID */
blockFragment.appendChild(theBlock)
teacherDiv.appendChild(blockFragment)
})
My server on Cloudways: PHP 7.4 -- MySQL MariaDB 10.1 -- server Apache/Nginx
My local server: PHP 7.3.5 -- MySQL 8.0.16 -- server Nginx in Local by FlyWheel
This issue does not happen in my local environment, only on Cloudways.
Does anyone have any ideas of where I could look for more errors?
Update 2021-04-25:
Using DevTools, I found out that the same variable "d" = undefined on my live website whereas it is equal to 1 on my local website.
Trying to identify why.
Finally! Found the answer.
In my local server, I had changed one ACF field to return the ID instead of the object.
It now returned this in the json response:
"te_schedule_day_term_id": 247,
On my live website, I had not made this change to the field, so it was returning the whole object, like this:
"te_schedule_day_term_id": {
"term_id": 247,
"name": "Friday",
"slug": "friday",
(...)
}
So, it turns out my JavaScript code was just fine. I found it out while debugging with DevTools; the teacherBlocks array was empty, so I verified the response text and found the difference between the live/local json responses.
(Pretty much a beginner's issue!)

Javascript function to not load in images from a Http-source

I am new to Javascript and are trying to become better.
I was wondering how i can with the help och template-tag load the image in it if a Image is unsafe like from a http-source. Think of it like a email-client asking you if you want to load in images if not then it breaks the src. like src=temp-data, and when clicked to download and show the images then it sets the src to the correct one. here is the code i have written thus far
function removeUnsafeImgLinks(bodyContent) {
let _bodyContent = bodyContent
const el = document.createElement('template');
el.innerHTML = _bodyContent
const nodes = el.querySelectorAll('img[src^="http://"]');
if (nodes.length > 0) {
nodes.forEach((x => {
x.innerHTML.replace("src=temp-data")
}));
}
iframe.srcdoc = el.innerHTML;
return newBod;
}
Anyone got any tip or solution?
x.innerHTML.replace("src=temp-data") does not actually change anything
Fixing your syntax errors you might mean
const removeUnsafeImgLinks = bodyContent => {
const el = document.createElement('template');
el.innerHTML = bodyContent
const imgs = [...el.querySelectorAll('img[src^="http://"]')];
if (imgs.length>0) {
imgs.forEach(x => x.src='temp-data')
iframe.srcdoc = el.innerHTML;
}
};

Excel JavaScript API - How to select cells until filled range end

What would be the JavaScript API version for VBA:
Range(ActiveCell, ActiveCell.End(xlDown)).Select
In essence, I want to do the same what ctrl+down arrow keycombo does. Extend current selection down to the last cell with value.
I've had to write a custom function. Here it is. But I was hoping for having a native API for such a frequently used piece of functionality. I'd argue, that it is top frequently used.
export const get_nonempty_range_down = async (startingCell, context) => {
const distanceLimit = 999;
const rangeToTest = startingCell.getResizedRange(distanceLimit, 0);
rangeToTest.load("values");
await context.sync();
const matrixValues = rangeToTest.values;
let finalCellPosition = null;
matrixValues.some((row, i) => {
if (row[0] === "") {
finalCellPosition = i - 1;
return true;
}
return false;
});
const result = startingCell.getResizedRange(finalCellPosition, 0);
// Debug
// result.load("address");
// await context.sync();
// console.log(result.address);
return result;
};
And it is still imperfect as it traverses only a thousand cells down. Ok for my needs, but not a complete solution.

Categories

Resources