Alternative to event.keyCode for mobile/tablet - javascript

I have a webpage that if you type in the letters "brain" it will show an alert and redirect you to another page. This is sort of a playful easter egg.
But this only works for desktop, because you have a keyboard. I want to find a way to have this easter egg working on mobile without keystrokes. For context, the webpage is very simple, there is no text or scrolling.
I was thinking, maybe if you press the smartphone/tablet volume up, it could trigger this easter egg. Or maybe with touchscreen strokes/ gestures, like, make a circle or a Z stroke (like Zorro). Any ideas and how to implement?
I kind of have this at the moment:
body {
background: white;
display: flex;
height: 100vh;
}
div {
width: calc(100% - 50px);
height: calc(100% - 50px);
background: #f0e8e6;
overflow: hidden;
margin: auto;
display: flex;
text-align: center;
display: flex;
justify-content: center;
}
<html>
<div>
<h3>type: brain</h3>
</div>
<style type="text/css">
html,
body {
margin: 0;
height: 100%;
overflow: hidden
}
</style>
<script>
var letters = [];
function brain(event) {
letters.push(event.keyCode);
if (letters.length > 4) {
if (letters[letters.length - 1] === 78 &&
letters[letters.length - 2] === 73 &&
letters[letters.length - 3] === 65 &&
letters[letters.length - 4] === 82 &&
letters[letters.length - 5] === 66)
{
alert("The Brain!");
};
window.location.replace("https://upload.wikimedia.org/wikipedia/commons/3/36/Brain_Brodmann_blend.gif");
}
}
document.addEventListener('keydown', brain);
</script>
</html>

Related

Resizable flex box

Intentionally posting this question on stackoverflow instead of posting it on salesforce.stackexchange.com as this problem is specific to JS/CSS
I have below LWC playground where it is not working as expected
https://app.lwc.studio/edit/CTHEQCGrn18rKmQQ0zs1 (unfortunately you might have to login to webcomponents.dev to access this link)
but on the below code pen the same is working as expected not sure what am I doing wrong.
https://codepen.io/gs650x/pen/qByPQKP
I have below HTML
<section class="resizeable-container" >
<div class="resizeable-item">
DIV1
</div>
<div class="resizer-x" onmousedown={handleOnMouseDown} onmouseup={handleOnMouseUp}></div>
<div class="resizeable-item">
DIV2
</div>
</section>
CSS
.resizeable-container {
display: flex;
min-height: 80vh;
}
.resizeable-item {
flex: 50%;
overflow: auto;
}
.resizer-x {
position: relative;
display: flex;
justify-content: center;
align-items: center;
background: hsl(212, 100%, 17%);
padding: 4px;
}
.resizer-x {
z-index: 2;
cursor: col-resize;
}
.resizer-x::before,
.resizer-x::after {
content: "";
width: 2px;
height: 16px;
margin: 2px;
background: lightgray;
}
Below is the javascript
renderedCallback() {
if (!resizer)
resizer = this.template.querySelector(".resizer-x")
//In case mouse up event occurs outside the resizer element
document.addEventListener("mouseup", this.handleOnMouseUp)
}
handleOnMouseDown(event) {
event.preventDefault();
document.addEventListener("mousemove", this.handleOnMouseMove)
document.addEventListener("mouseup", this.handleOnMouseUp)
}
handleOnMouseMove(event) {
event.preventDefault();
const clientX = event.clientX;
const deltaX = clientX - (resizer._clientX || clientX);
resizer._clientX = clientX;
const { previousElementSibling, nextElementSibling } = resizer
// LEFT
if (deltaX < 0) {
const width = Math.round(parseInt(window.getComputedStyle(previousElementSibling).width) + deltaX)
previousElementSibling.style.flex = `0 ${clientX < 10 ? 0 : clientX}px`
nextElementSibling.style.flex = "1 0"
}
// RIGHT
if (deltaX > 0) {
const width = Math.round(parseInt(window.getComputedStyle(nextElementSibling).width) - deltaX)
nextElementSibling.style.flex = `0 ${width < 10 ? 0 : width}px`
previousElementSibling.style.flex = "1 0"
}
}
handleOnMouseUp(event) {
event.preventDefault();
document.removeEventListener("mousemove", this.handleOnMouseMove)
document.removeEventListener("mouseup", this.handleOnMouseUp)
delete event._clientX
}
This works well on my 32 inches monitor but it is not working on my 14 inch laptop
expectation is to move the cursor and resizer-x at the same time but resizer-x moves first and then the cursor moves and mouse up only works if it is coming from the resizer-x anywhere else it is not working. I have added eventListener to document not on a particular object but still removeEventListener to stop handleMouseMove function doesn't stop.
Below is the code pen where it is working as expected but in LWC it doesn't behave in the same manner
https://codepen.io/gs650x/pen/qByPQKP

Use trigger scroll on iframe nested beneath an image overlay when there is no content to scroll

Imagine you have an SVG or an image of a computer screen and that the screen is completely transparent. You want to place an iframe in the screen and allow the viewer to scroll through the nested website. You can get the iframe to scroll when it's placed on top of the screen, but then it looks pants because it overflows on to the parts of the screen that aren't transparent and are meant to be seen. What you really want to do is place the iframe underneath the screen. However when you do this you lose the ability to scroll.
I'm trying to trigger a scroll or wheel event when there is no direct content to scroll. I want to 'transfer' scroll value to the iframe if this is possible. I have also considered converting the image to an SVG although it would be a big svg file to include inline in html.. All suggestions on how to go about this would be appreciated.
const iframe = document.querySelector(".iframe-cv");
const pc = document.querySelector(".image-desktop");
let pcWidth;
const observer = new ResizeObserver((entries) => {
pcWidth = entries[0].contentRect.width
console.log(pcWidth);
return pcWidth
});
observer.observe(pc);
function mousemove(e) {
const x = e.pageX - e.currentTarget.offsetLeft;
const y = e.pageY - e.currentTarget.offsetTop;
if (pcWidth === 700 && x >= 140 && x < 640 && y >= 30 && y < 375) {
// alert("you are hovering over the screen");
}
if (pcWidth === 850 && x >= 170 && x < 775 && y >= 35 && y < 450) {
// alert("you are hovering over the screen");
}
if (pcWidth === 1100 && x >= 220 && x < 1010 && y >= 40 && y < 585) {
// alert("you are hovering over the screen");
}
if (pcWidth === 1350 && x >= 265 && x < 1235 && y >= 55 && y < 715) {
// alert("you are hovering over the screen");
}
}
pc.addEventListener("mousemove", mousemove);
// =====================================
// Iframe positioning
// Get the top, left coordinates of two elements
const elRect = pc.getBoundingClientRect()
const targetRect = iframe.getBoundingClientRect()
// Calculate the top and left positions
const up = elRect.top + targetRect.top;
const left = elRect.left - targetRect.left;
console.log(up, left);
if (pcWidth === 700) {
iframe.style.left = 'px'
}
// ============================
// Measure scroll position of iframe
/*
scrollY is like scrollLeft
scrolly reads scroll position
scrollLeft reads AND sets scroll position
*/
/*
Test
If I scroll on a page and there is no scrollable material. Will I still log 'scrolling'?
Answer - no
*/
let boolean;
let iframeScrollposition = iframe.scrollTop;
console.log(`iframe is at scroll postion ${iframeScrollposition}`);
let iframeScrollHeight = iframe.scrollHeight;
console.log(`iframe has ${iframeScrollHeight} pixels to scroll`);
// while (iframeScrollposition < iframeScrollHeight) {
// if (boolean !== true) {
// boolean = true
// }
// }
iframe.dispatchEvent(new CustomEvent("scroll", { detail: { deltaY: 1 } }));
if (iframeScrollposition < iframeScrollHeight) {
boolean = true
}
console.log(boolean);
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
body {
margin: 0;
}
.container {
display: flex;
justify-content: center;
/* background-color: blue; */
width: 90%;
margin: 0 auto;
}
.iframe-cv {
z-index: 0;
position: absolute;
left: 14%;
top: 5%;
height: 60%;
width: 72%;
display: block;
/* display: none; */
}
.image-container {
position: relative;
width: fit-content;
height: fit-content;
/* background-color: yellow; */
/* overflow: hidden; */
}
::-webkit-scrollbar {
width: 0px;
height: 0px;
}
.image-desktop {
/* position: relative; ensures that z-index works appropriately */
position: relative;
z-index: 1;
}
#media (max-width: 299px) {
.iframe-cv {
display: none;
}
.image-desktop {
display: none;
}
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="style.css">
<title>Desktop PC Curriculum Vitae</title>
</head>
<body>
<div class="container">
<div class="image-container">
<iframe class="iframe-cv" src="https://lauro235.github.io/freecodecamptribute/" frameborder="0"></iframe>
<img class="image-desktop" srcset="./assets/images/pc850.png 850w,
./assets/images/pc850.png 850w,
./assets/images/pc1100.png 1100w,
./assets/images/pc1350.png 1350w"
sizes=" (max-width: 899px) 700px,
(max-width: 1295px) 850px,
(max-width: 1499px) 1100px,
(max-width: 2000px) 1350px"
src="./assets/images/pc1350.png"
alt="Desktop PC bebe" />
</div>
</div>
<script src="./main.js"></script>
</body>
</html>

Replicating nested and togglable <frameset> in HTML5

I'm given to understand that the <frameset> tag is deprecated as of HTML5. Thankfully, Chrome still supports rendering it, and unfortunately, it's currently the only thing I've found that fits my use case.
The important element of the <frameset> tag that other frame-like objects lack is draggable borders, which I haven't been able to get working with iframes even with a prohibitive amount of javascript assistance.
The other important thing in my case is that one of the frames contains a button/link that causes the other frame to disappear or reappear. When that happens, the frames should resize appropriately to fill the space.
My current HTML looks like the following MCVE:
index.html
<html>
<head>
<script language="javascript">
function toggleBottomFrame() {
var bottomFrame = document.getElementById("bottomFrame");
var horizFrameset = document.getElementById("horizFrameset");
if (bottomFrame.style.display == "none") {
bottomFrame.style.display = "";
horizFrameset.rows = "*,25%";
} else {
bottomFrame.style.display = "none";
horizFrameset.rows = "*,0px";
}
}
document.toggleBottomFrame = toggleBottomFrame;
</script>
</head>
<frameset id="horizFrameset" rows="*,0px">
<frameset id="vertFrameset" cols="300px,*">
<frame id="topLeftFrame" src="buttonpage.html"></frame>
<frame id="topRightFrame"></frame>
</frameset>
<frame id="bottomFrame" style="display:none"></frame>
</frameset>
</html>
buttonpage.html
<html>
<head></head>
<body>
<button onclick="parent.frameElement.ownerDocument.toggleBottomFrame();">
</body>
</html>
This works both in the IE11 that the code was initially written for (and needs to continue to support), as well as in Chrome.
How do I implement the exact same functionality (including, most importantly, the ability to drag around the borders of the frames with my mouse to expand or shrink one of the frames) using non-deprecated functionality?
If possible, I'd like a solution in standard client-side JS or HTML, without needing to import another library like resize.js. This is meant for a very lightweight frontend, and I don't want to bloat it down with libraries I don't need.
You should be able to achieve the shrink and grown functionality using the flex layout. Below 2 approaches may work. Both the approaches has the right section and bottom section as iframe and the left section has button to show and hide the right and bottom sections.
Option 1
Using flex and using the css resize property.
Drawback is that you will need to resize using the resize button shown at the bottom right corners. The left section's bottom right corner can be used for horizontal resizing and the right section's bottom right corner can be used for vertical resizing. Note that due to the iframe contents the right section's bottom right corner resize button may not be visible, but if you bring the cursor to the bottom right you will see the cursor changing to resize and allowing you to resize.
function toggleBottom() {
if (document.getElementById('bottomFrame').clientHeight > 0) {
document.getElementById('topFrame').style.height = '100%';
} else {
document.getElementById('topFrame').style.height = '80%';
}
}
function toggleRight() {
if (document.getElementById('topRightFrame').clientWidth > 0) {
document.getElementById('topLeftFrame').style.width = '100%';
} else {
document.getElementById('topLeftFrame').style.width = '50%';
}
}
html,
body {
height: 98%;
}
.page-container {
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex-direction: row;
resize: vertical;
border: 1px solid #000;
overflow: hidden;
}
.container-top {
height: 80%;
}
.container-bottom {
flex: 1 1;
overflow: hidden;
}
.container-left {
width: 30%;
border: 1px solid #000;
resize: horizontal;
overflow: hidden;
}
.container-right {
flex: 1 1;
height: 100%;
border: 1px solid #000;
overflow: hidden;
display: flex;
}
.frame-right {
flex: 1 1;
}
.frame-bottom {
flex: 1 1 100%;
border: 1px solid #000;
}
<html>
<body class="page-container">
<div class="container container-top" id="topFrame">
<div class="container-left" id="topLeftFrame">
<button onclick="toggleBottom()">Toggle Bottom</button>
<button onclick="toggleRight()">Toggle Right</button>
</div>
<div class="container-right" id="topRightFrame" >
<iframe src="https://stackoverflow.com" class="frame-right">
</iframe>
</div>
</div>
<div class="container container-bottom" id="bottomFrame">
<iframe class="frame-bottom" src="https://stackoverflow.com"></iframe>
</div>
</body>
</html>
Option 2
Using flex and using some scripting we should be able to make the whole border draggable. This is inspired from the answer in https://stackoverflow.com/a/53220241/2772300
const topRightFrame = document.getElementById("topRightFrame");
const topLeftFrame = document.getElementById("topLeftFrame");
const bottomFrame = document.getElementById("bottomFrame");
const topFrame = document.getElementById("topFrame");
const borderSize = 4;
function toggleBottom() {
if (bottomFrame.clientHeight > borderSize) {
topFrame.style.height = '100%';
} else {
topFrame.style.height = '80%';
}
}
function toggleRight() {
if (topRightFrame.clientWidth > borderSize) {
topLeftFrame.style.width = '100%';
} else {
topLeftFrame.style.width = '50%';
}
}
let mousePosition;
function resizeHorizontal(e){
const dx = mousePosition - e.x;
mousePosition = e.x;
topLeftFrame.style.width = (parseInt(getComputedStyle(topLeftFrame, '').width) - dx) + "px";
}
topRightFrame.addEventListener("mousedown", function(e){
if (e.offsetX < borderSize) {
mousePosition = e.x;
document.addEventListener("mousemove", resizeHorizontal, false);
}
}, false);
document.addEventListener("mouseup", function(){
document.removeEventListener("mousemove", resizeHorizontal, false);
}, false);
function resizeVertical(e){
const dy = mousePosition - e.y;
mousePosition = e.y;
topFrame.style.height = (parseInt(getComputedStyle(topFrame, '').height) - dy) + "px";
}
bottomFrame.addEventListener("mousedown", function(e){
if (e.offsetY < borderSize) {
mousePosition = e.y;
document.addEventListener("mousemove", resizeVertical, false);
}
}, false);
document.addEventListener("mouseup", function(){
document.removeEventListener("mousemove", resizeVertical, false);
}, false);
html,
body {
height: 98%;
}
.page-container {
display: flex;
flex-direction: column;
}
.container {
display: flex;
flex-direction: row;
overflow: hidden;
}
.container-top {
height: 80%;
}
.container-left {
width: 50%;
overflow: hidden;
height: 100%;
}
.container-right {
flex: 1 1;
height: 100%;
overflow: hidden;
display: flex;
padding-left: 4px;
background-color: #ccc;
cursor: ew-resize;
}
.frame-right {
flex: 1 1;
}
.container-bottom {
flex: 1 1;
overflow: hidden;
padding-top: 4px;
background-color: #ccc;
cursor: ns-resize;
}
.frame-bottom {
flex: 1 1 100%;
}
iframe {
border: 0;
}
<html>
<body class="page-container">
<div class="container container-top" id="topFrame">
<div class="container-left" id="topLeftFrame">
<button onclick="toggleBottom()">Toggle Bottom</button>
<button onclick="toggleRight()">Toggle Right</button>
</div>
<div class="container-right" id="topRightFrame" >
<iframe src="https://stackoverflow.com" class="frame-right">
</iframe>
</div>
</div>
<div class="container container-bottom" id="bottomFrame">
<iframe class="frame-bottom" src="https://stackoverflow.com"></iframe>
</div>
</body>
</html>
Have you looked a Golden Layout to do the resizing? You could then place iframes inside to match the size of the containing div.
Sorry this not a more complete answer, but though this might be an area worth exploring that is not likely to come up.

List item is not getting focus even though I am using focus()

I need to display the list and focus first list item in the list when user selects key 'm' on the keyboard. I tried calling focus() on the list item but it is not getting focus or it is not showing any effect. Below is the code.
HTML:
<!DOCTYPE html>
<html>
<head>
<title>VOD</title>
<script src='js/index.js'>
</script>
<style>
html, body {
height:100%
}
#mid {
display: flex;
height: 100%;
width: 100%;
justify-content: stretch;
flex-flow: row nowrap;
z-index: 2;
}
#mid.hidden {
display: none;
}
#mid1, #mid2 {
display: flex;
flex: 1;
align-items: center;
}
#mid1 {
justify-content: center;
background-color: rgba(255, 255, 255, 0.5);
}
#mid2 {
background-color: rgba(255, 255, 255, 0.6);
}
#ulid {
list-style-type: none;
width: 100%;
margin: 0;
border: 0;
padding: 0;
}
.list-item {
width: 100%;
height: 150px;
border-style: solid;
border-width: 1px;
display:flex;
align-items: center;
justify-content: flex-start;
}
li:focus, li:active {
background-color: green;
}
</style>
</head>
<body>
<video id='vid' src='textMotion.mp4' autoplay loop></video>
<div id='mid' class='hidden'>
<div id='mid1'>
<h1>TEXT</h1>
</div>
<div id='mid2'>
<ul id='ulid'></ul>
</div>
</div>
</body>
</html>
JavaScript:
function displayMenu() {
var mid = document.getElementById('mid');
if(mid.classList.contains('hidden') == false) {
mid.classList.toggle("hidden");
let ulid = document.getElementById('ulid');
while(ulid.firstChild) {
ulid.removeChild(ulid.firstChild);
}
return;
}
var ulid = document.getElementById('ulid');
for(let index = 0; index < 3; index ++) {
let lItem = document.createElement('li');
lItem.classList.add('list-item');
lItem.setAttribute('id', 'li' + index);
var lineBreak = document.createElement('br');
lItem.appendChild(document.createTextNode('TEXT'));
lItem.appendChild(lineBreak);
lItem.appendChild(document.createTextNode('TEXT'));
ulid.appendChild(lItem);
}
mid.classList.toggle("hidden");
document.getElementById('li0').focus();
}
function changeChannel(e) {
console.log('received keyEvent : ' + e.keyCode);
let keyCode = e.keyCode;
if(keyCode == 77) {
displayMenu();
}
}
document.addEventListener('keydown', changeChannel);
Even though list is getting displayed when user presses 'm', list item is not getting focused.
below is the jsfiddle link
https://jsfiddle.net/t75gojd7/
Can anyone please help me to focus the list element.
It looks like adding a tabindex might work. Add this to the attributes.
lItem.setAttribute('tabindex', index);
Got the idea from here. Worked for some people not all.
What is happening here is that the element you are trying to focus is a div which doesn't actually remain in focus after click unlike a button or a input text field.
You can observe this behavior by pressing down the pointer on the div and not releasing it. Your CSS stylings will be applied.
I would suggest instead on :focus CSS class, you use some other pseudo CSS class. OR you can do event.preventDefault() on div click.
Quoting from MDN
If you call HTMLElement.focus() from a mousedown event handler, you must call event.preventDefault() to keep the focus from leaving the HTMLElement.
Also check out this ans Is it possible to focus on a <div> using JavaScript focus() function? which suggests adding tabindex attribute.

when zoomed, div does not place scrollbars on certain cases

This is a simple HTML placeholder for a thing I am working on.
You can ignore the rest (I hope!) and focus on this sole issue:
The zoom on the image works, and it focus on the quadrant you press on, as I want it to. But it only places top and bottom scroll bars if the zoom is made on the top left quadrant.
I want it to always show the scroll bars. What am I missing?
Thanks
var images = ["Species_copy_number.png", "Species_coverage.png", "Species_distribution.png", "Gene_copy_distribution.png"];
var descriptions = ["cariño", "muis bueno", "caliente", "CABRÓN!"];
var titles = ["ay", "ay ay", "ay ay ay", "AY AY AY MI HIJJJJJJOOOOOOOOOOOOO"];
function changeImage(index){
var img = document.getElementById("img_place");
img.src = "Figures/" + images[index];
document.getElementById("desc_place").textContent = descriptions[index];
document.getElementById("subtitle").textContent = titles[index];
}
window.zoomedIn = false;
window.onload = function(){
var canvas = document.getElementById("img_wrapper");
canvas.onclick = function(event){
var imgWrapper = this, zoomContainer = document.getElementById("zoom-container");
var imgPlace = document.getElementById("img_place");
if (window.zoomedIn) {
imgPlace.setAttribute("style", "transform :\"\"");
window.zoomedIn = false;
} else {
var width = zoomContainer.offsetTop + zoomContainer.offsetWidth;
var height = zoomContainer.offsetTop + zoomContainer.offsetHeight;
var tro = (zoomContainer.offsetTop + event.clientY > height / 2) ? "bottom" : "top";
tro += (zoomContainer.offsetLeft + event.clientX > width / 2) ? " right" : " left";
imgPlace.setAttribute("style", "transform-origin: "+ tro + " 0px; transform: scale(2);");
window.zoomedIn = true;
}
}
}
body, html { height: 100%; }
.flex-container {
display: -webkit-flex;
display: -ms-flex;
display: -moz-flex;
display: flex;
-webkit-flex-direction: row;
flex-direction: row;
}
.flex-item {
display: -webkit-flex;
display: -ms-flex;
display: -moz-flex;
display: flex;
margin: 3px;
padding: 0 0 10px;
}
.flex-item img{
width: 100%;
}
span {
min-width: 5em;
margin-top: 3em;
padding-right: 1em;
}
a {
padding-left: 0.3em;
}
.img-wrapper {
border: 1px solid gray;
}
img {
height: 100%;
width: 100%;
}
#zoom-container{
overflow: auto;
}
<h1>Mega title</h1>
<h2 id="subtitle">Title</h2>
<div class="flex-container">
<div class="flex-item">
<span>
cenas<br>
Img #1
Img #2
cenas<br>
Img #3
Img #4
</span>
<div id="zoom-container">
<div id="img_wrapper" class="img-wrapper">
<img id="img_place" src="https://i.ytimg.com/vi/ddqvuwXBK5k/maxresdefault.jpg"/>
</div>
</div>
</div>
</div>
<h2>Description</h2>
<span id="desc_place">Description</span>
The coordinate system starts from left upper corner of the parent element. Since you are transforming the origin of the image in your quadrant on click, you are starting it from a clipped point.
With regard to document flow directions, the top and left sides are the block-start and inline-start sides and browsers or UA behave as though content is clipped beyond that direction.
From W3C specs: Scrolling Origin, Direction, and Restriction
Due to Web-compatibility constraints ... UAs must clip the scrollable overflow region of scroll containers on the block-start and inline-start sides of the box (thereby behaving as if they had no scrollable overflow on that side).
There may be a JS hack. I am not sure.
Here are some work-arounds (with) better explanations.
CSS Transforms / JS to zoom into element
Canvas Method
The best I could think of in your case is to add this CSS for .img-wrapper
.img-wrapper {
height: 100%;
width: 100%;
overflow: auto
}
and add overflow: auto; to imgPlace.setAttribute()in your last else statement
imgPlace.setAttribute("style", "transform-origin: "+ tro + " 0px; transform: scale(2);position: relative;overflow: auto;");
That way you will get scroll bars in quadrant 1, 2 and 3. In the fourth quadrant scroll restriction will be enabled.
Here is a codepen edit of your code
Simply create two new classes in css
.zoomed {
transform:scale(2);
}
.scroll {
overflow:scroll;
}
Add some jquery code
$ ('#img_wrapper').click(function() {
var top = $('#img_place').height() / 2;
$('#img_place').toggleClass('zoomed');
$(this).toggleClass('scroll');
if ($('#img_place').hasClass('zoomed')) {
$('#img_place').css('top', top);
}
else {
$('#img_place').css('top', '0');
}
});
Here is Updated fiddle chek out this.
Hope it's fine for you

Categories

Resources