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
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.
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
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!)
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;
}
};
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.