Front-end Interview Prompt: Box into Quarters - javascript

I had a front-end interview a few months ago with the following problem and guideline:
You are given the baseline CSS, HTML, and JS
You are not allowed to directly edit the predefined HTML or CSS
You are allowed to add new CSS classes and use whatever version of jQuery you want or Vanilla JS
Goal 1: When you click the #container, divide the box (which is 400px by 400px) into four equal sized boxes.
Goal 2: When you click one of the boxes that were created in Goal 1, said box also divides into 4 equal sized boxes as well.
My Problem
No matter what I do, the boxes do not divide perfectly. Not sure why inline-block isn't doing it's think, or what I can't append more than one node. Anyone have some expert tips?
var c = document.getElementById("container");
c.addEventListener("click", function(e) {
var node = document.createElement("div");
node.className = "boxxie";
c.appendChild(node);
c.appendChild(node);
c.appendChild(node);
c.appendChild(node);
})
*,
*:before,
*:after {
box-sizing: border-box;
}
#container {
border: 1px solid #2196f3;
width: 400px;
height: 400px;
}
.boxxie {
display: inline-block;
height: 50%;
width: 50%;
outline: 1px solid black;
}
<div id="container"></div>
Here is the jsfiddle
https://jsfiddle.net/drewkiimon/fvx632ab/
Thanks to #wbarton, I was able to get this answer to work without using flexbox. I was adamant without using flexbox since I was pretty confident that it would not need it. Long and behold, there is a solution without it. By using float: left, we can avoid the vertical align, and by creating a for-loop where we re-create a "new" node, we can just append it four times. I also used a class with my div instead of a direct CSS selector on the div.
Thank you for all the help everyone! Case closed.
document.getElementById("container").addEventListener('click', function(e) {
for (var i = 0; i < 4; i ++) {
var node = document.createElement("div");
node.className = "boxxie";
e.target.appendChild(node);
}
})
*,
*:before,
*:after {
box-sizing: border-box;
}
#container {
border: 1px solid #2196f3;
width: 400px;
height: 400px;
}
.boxxie {
outline: 1px solid tomato;
width: 50%;
height: 50%;
float: left;
}
<div id="container"></div>

My solution: https://jsfiddle.net/fvx632ab/106/
Added CSS:
div {
display: flex;
flex-grow: 0;
flex-shrink: 0;
outline: 1px solid #f33;
width: 50%;
flex-wrap: wrap;
}
Flexbox makes this easy for us, by defining some sensible layouts. We set the width of the child to 50%, and also enable wrapping so that we get two rows (since we're going to add four elements).
Then, in my JavaScript:
document.querySelector('body').addEventListener('click', (e) => {
if (!e.target.matches('div')) {
return;
}
for (let i=0; i<=3; i++) {
e.target.appendChild(document.createElement('div'));
}
});
We listen for clicks on the body (because we're going to be adding more divs later), but filter for only the selector we want, which is div. Then, we just add 4 children.

Nothing new from a JS perspective but to answer #drewkiimon "is possible without flex?"
This example uses floats.
document.querySelector('body').addEventListener('click', (e) => {
if (!e.target.matches('div')) {
return;
}
for (let i = 0; i < 4; i++) {
e.target.appendChild(document.createElement('div'));
}
})
*,
*:before,
*:after {
box-sizing: border-box;
}
#container {
border: 1px solid #2196f3;
width: 400px;
height: 400px;
}
/* ---------- */
#container div {
float: left;
width: 50%;
height: 50%;
outline: 1px solid tomato;
background-color: rgba(64, 224, 208, .1);
}
<div id="container"></div>

Here is my solution.
Using e.target allows you to keep drilling down.
vertical-align: top and line-height: 1px; address spacing issues you might find using inline-block per Get rid of space underneath inline-block image
const c = document.getElementById("container");
c.addEventListener("click", e => {
const target = e.target;
for (let i = 0; i < 4; i++) {
const child = document.createElement("div");
target.appendChild(child);
}
});
#container {
width: 400px;
height: 400px;
border: 1px solid blue;
box-sizing: border-box;
}
#container div {
border: 1px solid red;
display: inline-block;
box-sizing: border-box;
width: 50%;
height: 50%;
vertical-align: top;
line-height: 1px;
}
<div id="container"></div>

Related

Remove CSS with JavaScript or jQuery

I have a style tag in my project, which is generated automatically. I want to remove some of the styles of this tag that interfere with other classes
this is my CSS and style tag:
<style id="style-inline-inline-css">
#et-boc .et-l div {
text-align: inherit;
margin: 0;
padding: 0;
border: none;
outline: 0;
vertical-align: baseline;
background: transparent;
letter-spacing: normal;
color: inherit;
box-shadow: none;
-webkit-box-shadow: none;
-moz-box-shadow: none;
text-shadow: inherit;
border-radius: 0;
-moz-border-radius: 0;
-webkit-border-radius: 0;
transition: none;
}
#et-boc .et-l img {
max-width: 100%;
height: auto;
}
</style>
I want to remove this two CSS #et-boc .et-l img and #et-boc .et-l div with JavaScript or jQuery and other ways, Due to the structure of the project and the automatic generation of the codes, I cannot delete them on the back-end side. The only way in the front-end is to prevent them from being applied to the site elements
I'm not sure this would be the best approach for your exact goal. Anyway, I took the chance to craft a demo that shows how to access the stylesheets from JavaScript and how to remove a specific CSS rule.
For reference:
https://developer.mozilla.org/en-US/docs/Web/API/CSSRule
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/cssRules
https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleSheet/deleteRule
This demo shows how a CSS rule can be found and deleted from a given style element (fetched by ID) using its selector as a key:
document.addEventListener('DOMContentLoaded',()=>{
const styleElement = document.getElementById('style-inline-inline-css');
const stylesheet = styleElement.sheet;
removeCssRuleMatchingSelector(stylesheet, '#et-boc .et-l div');
});
function removeCssRuleMatchingSelector(stylesheet, selector){
const cssRules = stylesheet.cssRules;
let foundRule = null;
let foundRuleIndex = -1;
for(let i=0; i<cssRules.length; i++){
if (cssRules[i].selectorText == selector){
foundRule = cssRules[i];
foundRuleIndex = i;
break;
}
}
if (foundRule !== null){
stylesheet.deleteRule( foundRuleIndex );
}
}
<style id="style-inline-inline-css">
/*css rule to delete*/
#et-boc .et-l div {
background: green;
}
/*css rule to remain unchanged*/
.test{
background: red;
}
</style>
<div id="et-boc">
<div class="et-l">
<div>If the rule was not deleted, this paragraph would be styled with bg green</div>
</div>
</div>
<div class="test">TEST</div>

How make a textarea with tags in react that have clickable dropdown

Id like to make a component in react that allows me to have a textarea with tags that can be inserted when clicked from a dropdown. Id also like this textarea to be able to mix text aswell. I have currently been trying to use tagify with react but I cant seem to figure out a way to the tagify's function that adds the tag to be accessed by the onClick that is connected to the dropdown.
Any ideas?
I believe you can get your answer in this URL of other question asked on StackOverflow https://stackoverflow.com/a/38119725/15405352
var $container = $('.container');
var $backdrop = $('.backdrop');
var $highlights = $('.highlights');
var $textarea = $('textarea');
var $toggle = $('button');
// yeah, browser sniffing sucks, but there are browser-specific quirks to handle that are not a matter of feature detection
var ua = window.navigator.userAgent.toLowerCase();
var isIE = !!ua.match(/msie|trident\/7|edge/);
var isWinPhone = ua.indexOf('windows phone') !== -1;
var isIOS = !isWinPhone && !!ua.match(/ipad|iphone|ipod/);
function applyHighlights(text) {
text = text
.replace(/\n$/g, '\n\n')
.replace(/[A-Z].*?\b/g, '<mark>$&</mark>');
if (isIE) {
// IE wraps whitespace differently in a div vs textarea, this fixes it
text = text.replace(/ /g, ' <wbr>');
}
return text;
}
function handleInput() {
var text = $textarea.val();
var highlightedText = applyHighlights(text);
$highlights.html(highlightedText);
}
function handleScroll() {
var scrollTop = $textarea.scrollTop();
$backdrop.scrollTop(scrollTop);
var scrollLeft = $textarea.scrollLeft();
$backdrop.scrollLeft(scrollLeft);
}
function fixIOS() {
// iOS adds 3px of (unremovable) padding to the left and right of a textarea, so adjust highlights div to match
$highlights.css({
'padding-left': '+=3px',
'padding-right': '+=3px'
});
}
function bindEvents() {
$textarea.on({
'input': handleInput,
'scroll': handleScroll
});
$toggle.on('click', function() {
$container.toggleClass('perspective');
});
}
if (isIOS) {
fixIOS();
}
bindEvents();
handleInput();
#import url(https://fonts.googleapis.com/css?family=Open+Sans);
*, *::before, *::after {
box-sizing: border-box;
}
body {
margin: 30px;
background-color: #f0f0f0;
}
.container, .backdrop, textarea {
width: 460px;
height: 180px;
}
.highlights, textarea {
padding: 10px;
font: 20px/28px 'Open Sans', sans-serif;
letter-spacing: 1px;
}
.container {
display: block;
margin: 0 auto;
transform: translateZ(0);
-webkit-text-size-adjust: none;
}
.backdrop {
position: absolute;
z-index: 1;
border: 2px solid #685972;
background-color: #fff;
overflow: auto;
pointer-events: none;
transition: transform 1s;
}
.highlights {
white-space: pre-wrap;
word-wrap: break-word;
color: transparent;
}
textarea {
display: block;
position: absolute;
z-index: 2;
margin: 0;
border: 2px solid #74637f;
border-radius: 0;
color: #444;
background-color: transparent;
overflow: auto;
resize: none;
transition: transform 1s;
}
mark {
border-radius: 3px;
color: transparent;
background-color: #b1d5e5;
}
button {
display: block;
width: 300px;
margin: 30px auto 0;
padding: 10px;
border: none;
border-radius: 6px;
color: #fff;
background-color: #74637f;
font: 18px 'Opens Sans', sans-serif;
letter-spacing: 1px;
appearance: none;
cursor: pointer;
}
.perspective .backdrop {
transform:
perspective(1500px)
translateX(-125px)
rotateY(45deg)
scale(.9);
}
.perspective textarea {
transform:
perspective(1500px)
translateX(155px)
rotateY(45deg)
scale(1.1);
}
textarea:focus, button:focus {
outline: none;
box-shadow: 0 0 0 2px #c6aada;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="container">
<div class="backdrop">
<div class="highlights"></div>
</div>
<textarea>This demo shows how to highlight bits of text within a textarea. Alright, that's a lie. You can't actually render markup inside a textarea. However, you can fake it by carefully positioning a div behind the textarea and adding your highlight markup there. JavaScript takes care of syncing the content and scroll position from the textarea to the div, so everything lines up nicely. Hit the toggle button to peek behind the curtain. And feel free to edit this text. All capitalized words will be highlighted.</textarea>
</div>
<button>Toggle Perspective</button>
Reference- https://codepen.io/lonekorean/pen/gaLEMR for example

Why doesn't the custom caret get consistently positioned corectly in this case?

I am using the distance of the the span from the top to position the caret vertically, that works fine, and I am using the index of the string multiplied by the letter width to position the caret horizontally but that sometimes works, sometimes it doesn't.
Look for example at the second row, and click in the first "this", it doesn't work properly but if you click inside the last "this" the caret gets positioned correctly.
I can't figure out why, doesn't it mean that a mono-space font has the exact same with for each letter which I eyeballed here to be 10.1? Something doesn't work here and I can't figure out what. JsFiddle
let writeDiv = document.querySelector('#write');
let caret = document.querySelector('#caret')
writeDiv.addEventListener('click', (e) => {
if(e.target.tagName == 'SPAN'){
moveCaretOnClick(e)
}
})
function moveCaretOnClick(e) {
let y = window.getSelection().focusOffset * 10.1
caret.style = `left: ${y}px; top: ${e.target.offsetTop + 3}px`;
}
#import url('https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap');
body, html{
margin: 0;
height: 100%;
width: 100%;
}
#write {
font-family: 'Roboto Mono';
height: 100%;
width: 100%;
background: #1f2227;
padding: 10px;
color: white;
box-sizing: border-box;
}
#caret{
height: 15px;
width: 3px;
background: #80ff00;
display: inline-block;
position: absolute;
}
.RowSpan{
width: 100%;
display: inline-block;
box-sizing: border-box;
height: 20px;
}
<div id='write'>
<span class='RowSpan'>This is some text</span>
<span class='RowSpan'>this is some text this</span>
</div>
<div id='caret'></div>
Edit: My guess is that I need the exact dimension of the letters, otherwise, as you go further the line the distance increases more and more, because of multiplying for each letter. If you add more text the distance gets more and more further from the click.
So, somehow either get the exact dimension of the letters that's always consistent or find some other way.
A bit awkward but I fount the solution, it turns out I just had to add a 1 to the focusOffset before multiplying with each letter, otherwise it would basically skip a letter. I think because focusOffset starts with a 0
let writeDiv = document.querySelector('#write');
let caret = document.querySelector('#caret')
writeDiv.addEventListener('click', (e) => {
if(e.target.tagName == 'SPAN'){
moveCaretOnClick(e)
}
})
function moveCaretOnClick(e) {
let y = (window.getSelection().focusOffset + 1) * 9.6
caret.style = `left: ${y}px; top: ${e.target.offsetTop + 3}px`;
}
#import url('https://fonts.googleapis.com/css2?family=Roboto+Mono&display=swap');
body{
margin: 0;
}
#write {
font-family: 'Roboto Mono';
height: 300px;
width: 1200px;
background: #1f2227;
padding: 10px;
color: white;
}
#caret{
height: 15px;
width: 2px;
background: #80ff00;
display: inline-block;
position: absolute;
}
.RowSpan{
width: 100%;
display: inline-block;
box-sizing: border-box;
height: 20px;
}
<div id='write'>
<span class='RowSpan'>This is some text</span>
<span class='RowSpan'>this is some text this more more text BIGGERT TEXT and some small text and some stuff -- __ !%^ () {} and some more text even </span>
</div>
<div id='caret'></div>

How to display the information from a textarea comment box onto the current html page

I am trying to basically take the information my user is putting into my comment box and then simply input it below that box.
Like a simple comment box that shows the username and the comment of that person below it.
Just on the same starting index.html page is fine not trying to send it to a server or anything like that.
What would be the easiest way to do this with javaScript?
I have tried getting document.getElementByID() of the whole form, and then doing submit but its not working?
You put an ID on the input element and then you can get the information with element.value
Below is an example: any text you type in the input field will be copied over to the div
document.getElementById("input").addEventListener("input", e => {
document.getElementById("output").innerText = e.target.value;
});
<div id="output"></div>
<input id="input"></input>
And an example if they press a button
function foo() {
document.getElementById("output").innerText = document.getElementById("input").value;
}
<input id="input"></input>
<div id="output"></div>
<button onclick="foo()">Copy text</button>
You can pull the .value of the textarea into whichever element you target. One important note to make is that, because HTML elements don't respect line breaks as actual line breaks in their text content, you'll probably want to include a quick regex to replace all line breaks with <br> tags, and another regex to replace every instance of multiple spaces with multiple spaces to retain multiple spaces.
Alternatively, if you want to avoid any of the regex replacing, you can simply apply the CSS property white-space: pre; to whatever element you're outputting the text into and it will respect whatever spacing is passed into it, whether it be line-breaks or multiple spaces between words.
1. Here's an example (with regex):
const textarea = document.querySelector('textarea');
const div = document.querySelector('div');
textarea.addEventListener('input', function(e) {
div.innerHTML = e.target.value.replace(/(?:\r\n|\r|\n)/g, '<br>').replace(/ +/g, m => " " + Array(m.length).join(' '));
});
html {
height: 100%;
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: space-between;
overflow: hidden;
margin: 0;
padding: 20px;
height: inherit;
box-sizing: border-box;
}
body > * {
position: relative;
-webkit-appearance: none;
width: calc(50% - 10px);
height: 100%;
padding: 20px;
border-width: 0;
background-color: #ccc;
box-sizing: border-box;
}
<textarea></textarea>
<div></div>
CodePen interactive example: https://codepen.io/brandonmcconnell/pen/2177e440bb55f5a7f035ebcd315a1bdf
2. Here is the same example (with white-space: pre;, no regex):
const textarea = document.querySelector('textarea');
const div = document.querySelector('div');
textarea.addEventListener('input', function(e) {
div.innerHTML = e.target.value;
});
html {
height: 100%;
margin: 0;
padding: 0;
border: 0;
box-sizing: border-box;
}
body {
display: flex;
align-items: center;
justify-content: space-between;
overflow: hidden;
margin: 0;
padding: 20px;
height: inherit;
box-sizing: border-box;
}
body > * {
position: relative;
-webkit-appearance: none;
width: calc(50% - 10px);
height: 100%;
padding: 20px;
border-width: 0;
background-color: #ccc;
box-sizing: border-box;
}
div {
white-space: pre;
}
<textarea></textarea>
<div></div>
CodePen interactive example: https://codepen.io/brandonmcconnell/pen/0be96bb4ec0168deda587328180cca86

Create new div-tabs with Javascript

I have a huge question about how to create div with JavaScript. In this case, I have tabs and I would like to be able to create a new one out of two variable obtained from the form in the left; one for the name and other the content. Example: http://s2.subirimagenes.com/imagen/previo/thump_8932774captura-de-pantalla.png
How should the function be to create this new tab out of the two variables?
This is the HTML of the tabs:
<div class="w3c">
<div id="tab16">
Tab 16
<div>One might well argue, that...</div>
</div>
<div id="tab17">
Tab 17
<div>... 30 lines of CSS is rather a lot, and...</div>
</div>
<div id="tab18">
Tab 18
<div id="Prueba">... that 2 should have been enough, but...</div>
</div>
</div>
and the CSS:
.w3c {
min-height: 250px;
position: relative;
width: 100%;
}
.w3c > div {
display: inline;
}
.w3c > div > a {
margin-left: -1px;
position: relative;
left: 1px;
text-decoration: none;
color: black;
background: white;
display: block;
float: left;
padding: 5px 10px;
border: 1px solid #ccc;
border-bottom: 1px solid white;
}
.w3c > div:not(:target) > a {
border-bottom: 0;
background: -moz-linear-gradient(top, white, #eee);
}
.w3c > div:target > a {
background: white;
}
.w3c > div > div {
background: white;
z-index: -2;
left: 0;
top: 30px;
bottom: 0;
right: 0;
padding: 20px;
border: 1px solid #ccc;
}
.w3c > div:not(:target) > div {
position: absolute
}
.w3c > div:target > div {
position: absolute;
z-index: -1;
}
First of all, create the new element:
Best way of creating a new element in jQuery
var $div = $("<div>", {id: "tabN"});
Then, add the content:
$div.html("some content");
Finally, append the newly created element where you need it.
$(".w3c").append($div);
The pure-JavaScript-version of BenSorter's jQuery answer:
var div = document.createElement('div');
div.id = "tabN";
div.innerHTML = "some content";
document.querySelector(".w3c").appendChild(div);
Documentation:
Document.prototype.createElement to create a new element
Document.prototype.querySelector to query the DOM for exactly one existing element
Document.prototype.querySelectorAll to query all DOM nodes that match a selector
Node.prototype.appendChild to add the created DOM node(s) to an existing one
Note: The jQuery-free solution above only works in reasonably "modern" browsers, meaning only Internet Explorer 8 and below will not support these methods. In the sad case that you need to support very old IEs, using jQuery will be a lot easier.

Categories