Get modified element in HTML slot - javascript

I am trying to create a custom HTML component which creates tabs for every child element that it has. Here is the code for that custom component:
const code_window = document.getElementById("window");
class CodeWindow extends HTMLElement {
constructor() {
super();
this.attachShadow({
mode: 'open'
});
this.shadowRoot.appendChild(code_window.content.cloneNode(true));
this.code = this.shadowRoot.getElementById("code");
this.tabbar = this.shadowRoot.getElementById("tabbar");
this.code.addEventListener("slotchange", e => {
var elems = e.target.assignedNodes();
for (let i = 0; i < elems.length; i++) {
var tab = document.createElement("div");
tab.classList.add("tab");
var name = elems[i].getAttribute("name");
tab.innerHTML = name;
tab.setAttribute("name", name);
this.tabbar.appendChild(tab);
if (elems[i].hasAttribute("active")) this.activateTab(name);
tab.addEventListener("click", e => this.activateTab(e.target.getAttribute("name")));
}
if (!this.previous_tab && this.tabbar.children.length > 0) this.activateTab(this.tabbar.children[0].getAttribute("name"));
});
}
activateTab(name) {
if (this.previous_tab) {
this.previous_frame.removeAttribute("active");
this.previous_tab.removeAttribute("active");
}
var tabs = this.tabbar.children,
frames = this.code.assignedElements();
for (let i = 0; i < tabs.length; i++) {
if (tabs[i].getAttribute("name") == name) {
tabs[i].setAttribute("active", "");
frames[i].setAttribute("active", "");
this.previous_frame = frames[i];
this.previous_tab = tabs[i];
break;
}
}
}
}
customElements.define("c-window", CodeWindow);
<template id="window">
<style>
:host {
display: flex;
flex-direction: column;
}
#titlebar {
display: flex;
background-color: green;
}
#tabbar {
flex-grow: 1;
display: flex;
}
#tabbar .tab {
display: flex;
align-items: center;
padding: 5px 10px;
background-color: #bbb;
}
#tabbar .tab[active] {
background-color: #fff;
}
#code {
flex-grow: 1;
display: block;
position: relative;
}
#code::slotted(*) {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
padding: 5px;
display: none;
}
#code::slotted(*[active]) {
display: block;
}
</style>
<div id="titlebar">
<div id="tabbar"></div>
</div>
<slot id="code" name="frames"></slot>
</template>
<c-window style="border: 2px solid green; height: 300px;">
<div slot="frames" name="Content 1">Contents of tab 1</div>
<div slot="frames" name="Content 2">Contents of tab 2</div>
</c-window>
There is a slot inside the custom component and I want that every time a child element is added, a tab should be added, if a child element is removed, the tab associated with that child should be removed.
But the slotchange event carries no information about which element has been added/removed, so currently, I have to loop through the slot.assignedElements() every time slotchange event is called and create tabs for each and every element. It means that for a particular child, duplicate tabs will be created, which can also be quite CPU intensive.
So, I was thinking if there is some way to get the information about the modified element so that the action can be performed on only the modified element. Is there any way of getting only the modified element? If not, what method can I apply for achieving this?

You are doing the oldskool Switch-DIVs approach for Tabs
You can do it all with one shadowDOM <slot ="active">
and one click handler
Needs some more work; but you get the slot="active" concept
<template id="TABS-MEISTER">
<style>
#bar { display:flex }
#bar div { width: 100px; background: lightgreen ; margin-right:1em ; cursor:pointer}
</style>
<div id="bar"></div>
<div style="clear:both"><slot name="active"></slot></div>
</template>
<tabs-meister>
<div title="Tab1">Tab #1</div>
<div slot="active" title="Tab2">Tab #2</div>
<div title="Tab3">Tab #3</div>
</tabs-meister>
<script>
customElements.define('tabs-meister', class extends HTMLElement {
constructor() {
let template = (id) => document.getElementById(id).content.cloneNode(true);
super()
.attachShadow({mode: 'open'})
.append(template(this.nodeName));
this.onclick = (evt) => {
if (this.activetab) this.activetab.removeAttribute("slot");
let tab = evt.composedPath()[0];
this.activetab = this.querySelector(`[title="${tab.title}"]`);
this.activetab.slot = 'active';
}
}
connectedCallback() {
let tabs = [...this.children].map(node => {
return `<div title=${node.title}>${node.title}</div>`;
}).join ``;
this.shadowRoot.querySelector("#bar").innerHTML = tabs;
}
});
</script>

Related

How to iterate the div items in HTML, and assign the value to each one?

I consumed an api created, where it will return a list with emails, I created a modal, with a div, where by the amount of emails returned, I want to add a div, and at the same time put the value of the emails in each one of them , the most I got was to put the same email in all of them, but at least I managed to add the amount of divs according to the number of emails returned, follows the code
<div class="modal">
<h2>Lista</h2>
<div id="list">
</div>
</div>
modalList: (json) => {
qS('.screen').style.justifyContent = 'center';
qS('.screen').style.alignItems = 'center';
qS('.rightside').style.display = 'none';
qS('.modal').style.display = 'block';
json.list.forEach((item, index)=>{
let numeroHTML = ''
for(let i = 0; i <= index; i++ ){
numeroHTML += `<div class="result"></div>`;
}
qS('.modal #list').innerHTML = numeroHTML
qSa('.result').forEach((result) => {
result.innerHTML = item
})
});
}
the logic that I'm not able to do is how to put each item in the array, that is, each email in a div only, and thus make a list in this modal
Details are commented in example below
/*
I'll assume the JSON is a typical array of objects and each object having a
property/key "email"
*/
const data=[{email:"tmcgowing0#netlog.com"},{email:"ckelsow1#usa.gov"},{email:"zwrench2#github.io"},{email:"avayne3#biblegateway.com"},{email:"mmarquis4#telegraph.co.uk"},{email:"pbrannigan5#marketwatch.com"},{email:"czannetti6#zimbio.com"},{email:"baspey7#thetimes.co.uk"},{email:"ejaumet8#tripadvisor.com"},{email:"pfellow9#cnbc.com"}];
/**
* Renders a list in HTML from a given array of objects and a key.
* #param {string<CSS>} selector - A CSS selector of the <ul>, <ol>, or <menu>
* #param {array<object>} json - The data to make the list from
* #param {string} key - The property/key to get the value from for the list
*/
const modalList = (selector, json, key) => {
// Reference the list OR <body> (if undefined, null, etc)
const node = document.querySelector(selector) || document.body;
/*
On each iteration through >json< render a htmlString into a <li> and add
the current object's value of >key<
*/
json.forEach(item => node.insertAdjacentHTML('beforeEnd', `<li>${item[key]}</li>`));
};
/*
"click" event handler registered to button.open. When triggered the modal opens
and modalList() is called
*/
document.querySelector('.open').onclick = e => {
document.querySelector('.modal').showModal();
modalList('ul', data, 'email');
};
/* The rest is unrelated to question */
const UI = document.forms.UI;
UI.onclick = modalUI;
UI.onsubmit = funcX;
function modalUI(e) {
const OG = e.target;
if (OG.matches('.close')) {
document.querySelector('.modal').close();
}
};
function funcX(e) {
e.preventDefault();
console.log(e.type + ' event fired');
};
html {
font: 2ch/1.5 'Segoe UI'
}
html,
body {
width: 100%;
height: 100%;
padding: 0;
margin: 0;
}
main {
width: 100%;
height: 100%;
}
dialog {
margin: 10px auto;
min-height: 50%;
width: 50%;
}
header {
display: flex;
justify-content: space-between;
align-items: flex-end;
width: 90%;
padding-bottom: 5px;
border-bottom: 2px ridge grey
}
menu {
width: 90%;
display: flex;
justify-content: flex-end;
align-items: flex-start
}
h3 {
margin: 0 0 -8px 0;
}
.btn {
display: inline-block;
cursor: pointer;
border-radius: 5px;
}
section {
width: 90%
}
ul {
list-style: none;
margin-left: -35px
}
footer {
width: 90%;
border-top: 2px ridge grey;
}
.close {
align-self: flex-start;
}
<main>
<dialog class='modal'>
<form id='UI'>
<header>
<h3>Email List</h3>
<input class='btn close' type='button' value='X'>
</header>
<section>
<ul></ul>
</section>
<footer>
<menu>
<button class='btn confirm'>Confirm</button>
<button class='btn close' type='button'>Cancel</button>
</menu>
</footer>
</form>
</dialog>
<menu>
<button class='btn open'>Open Email List</button>
</menu>
</main>
To create HTML from your array you can use a foreach loop like you're doing.
You should be using the HTML <ul> element with <li>s inside.
Do something like this for each iteration:
const element = document.createElement('li')
element.innerText = item
list.appendChild(element)
const json = {
list: ["one", "two", "three"]
}
const listElement = document.querySelector('#list')
json.list.forEach((item, index) => {
const element = document.createElement('li')
element.classList.add('result')
element.innerText = item
list.appendChild(element)
});
<div class="modal">
<h2>Lista</h2>
<ul id="list">
</ul>
</div>

Target multiple classes in a div and count number of times they have been clicked Vanilla JS

The purpose of this is to be able to track the number of times a button with class testButton or incButton has been clicked and if either has been clicked twice to show a overlay.
There are 2 main issues:
1: I'm not sure how to select 2 different classes of buttons
2: Once there are more than 1 button with the same class name the existing JS code does only works on the first button with the testButton class.
The code I have is:
<style>
#winOverlay {
position: fixed;
z-index: 200;
width: 100%;
height: 100%;
background-color: red;
top: 0;
left: 0;
}
</style>
<div id="winOverlay" style="display:none"></div>
<div id="buttonContainer">
<button class="testButton">1</button>
<button class="incButton">2</button>
<button class="testButton">3</button>
<button class="incButton">4</button>
<button class="testButton">5</button>
</div>
<script>
var count = 0;
var btn = document.getElementById("buttonContainer").querySelector(".testButton");
btn.onclick = function () {
count++;
if (count == 2) {
document.getElementById('winOverlay').style.display = "block";
}
}
</script>
Any help would be greatly appreciated.
You can make use of event Delegation where you add event listener on the common parent container with class buttonContainer and you can check if the button clicked with id only testButton and incButon
1) This code will work if you have to calculate of count of irrespective of which button is clicked.
var count = 0;
var btn = document.getElementById("buttonContainer");
const winOverlay = document.getElementById('winOverlay');
btn.addEventListener("click", e => {
const classes = e.target.classList;
if (classes.contains("testButton") || classes.contains("incButon")) {
count++;
if (count === 2) winOverlay.style.display = "block";
}
})
#winOverlay {
position: fixed;
z-index: 200;
width: 100%;
height: 100%;
background-color: red;
top: 0;
left: 0;
}
<div id="winOverlay" style="display:none"></div>
<div id="buttonContainer">
<button class="testButton">1</button>
<button class="incButon">2</button>
<button class="testButton">3</button>
<button class="incButon">4</button>
<button class="testButton">5</button>
</div>
2) This code will work if you have to calculate the count of specif key on which you clicked and show overlay if it's count is 2
var btn = document.getElementById("buttonContainer");
const winOverlay = document.getElementById("winOverlay");
const dict = {};
btn.addEventListener("click", (e) => {
const classes = e.target.classList;
const addOverlay = () => (winOverlay.style.display = "block");
if (classes.contains("testButton") || classes.contains("incButon")) {
const key = e.target.dataset.key;
dict[key] = (dict[key] || 0) + 1;
if (dict[key] === 2) addOverlay();
}
});
#winOverlay {
position: fixed;
z-index: 200;
width: 100%;
height: 100%;
background-color: red;
top: 0;
left: 0;
}
button {
color: white;
border: none;
padding: 1rem;
cursor: pointer;
}
button.testButton {
background-color: teal;
}
button.incButon {
background-color: orange;
}
<div id="winOverlay" style="display: none;"></div>
<div id="buttonContainer">
<button class="testButton" data-key="testButton">1</button>
<button class="incButon" data-key="incButon">2</button>
<button class="testButton" data-key="testButton">3</button>
<button class="incButon" data-key="incButon">4</button>
<button class="testButton" data-key="testButton">5</button>
</div>
You need to select all buttons with querySelectorAll add listener to all of them.
var count = 0;
const buttons = document.querySelectorAll("#buttonContainer > button");
for (let index = 0; index < buttons.length; index++) {
const e = buttons[index];
e.onclick = function() {
count++;
if (count == 2) {
document.getElementById('winOverlay').style.display = "block";
}
}
}
#winOverlay {
position: fixed;
z-index: 200;
width: 100%;
height: 100%;
background-color: red;
top: 0;
left: 0;
}
<div id="winOverlay" style="display:none"></div>
<div id="buttonContainer">
<button class="testButton">1</button>
<button class="incButon">2</button>
<button class="testButton">3</button>
<button class="incButon">4</button>
<button class="testButton">5</button>
</div>
To select 2 class you should do as in css:
querySelector(class1 class2)
But don't work because you can't use querySelector for two or more classes.
This code say only select class1 or class2 and take the first Element.
Use querySelectorAll() to have all of them
As the others have suggested querySelectorAll provides support for multiple selectors. It will return an array-like nodelist which you can then iterate over.
document.querySelectorAll('testButton', 'incButton');
I'm going to offer an alternative approach using event delegation which allows you to attach one listener to a parent element that captures events as they bubble up the DOM.
This example also uses a closure (basically a function that's returned from another function but that can carry any variables set outside it in the local lexical environment with it when it's returned. This is a useful pattern if you want to avoid global variables. In this case we create an object to hold the totals of the two types of buttons.
// Cache your container and overlay elements
const container = document.querySelector('.buttonContainer');
const overlay = document.querySelector('.overlay');
// Add one listener to the container which calls `handleClick`.
// `handleClick` sets up the object and returns a new function
// (the closure) that carries the object with it.
container.addEventListener('click', handleClick(), false);
function handleClick() {
// An object that holds the button totals
const cases = {
testButton: 0,
incButton: 0
};
// The function that will be added to the listener
// It has the event argument
return function (e) {
// Destructure the nodeName/className from the
// element that was clicked
const { nodeName, className } = e.target;
// Check to see if the element was a button
if (nodeName === 'BUTTON') {
// Increase the value in the object where
// the key matches the className
++cases[className];
console.log(JSON.stringify(cases));
// If that value is 2 show the overlay
if (cases[className] === 2) {
overlay.classList.add('show');
}
}
}
}
.overlay { display: none; margin: 1em; background-color: #acaccc; black: white; padding: 2em; }
.show { display: block; }
button { padding: 0.7em; }
button:hover { cursor: pointer; background-color: #acacac; }
<div class="buttonContainer">
<button class="testButton">1</button>
<button class="incButton">2</button>
<button class="testButton">3</button>
<button class="incButton">4</button>
<button class="testButton">5</button>
</div>
<div class="overlay">Overlay</div>
Additional documentation
Destructuring assignment
nodeName
classList

How to apply a function that affects the parent of each element with a certain class name?

I have a series of divs with the class name x that are inside of other divs with the class name item. The item divs are inside a section of the main.
What I want to do is create a function that applies equally to every x class div by affecting their respective parent (in this case changing their CSS).
I coded this:
var openbtn = document.getElementsByClassName("x")[0];
openbtn.onclick = function() {
document.body.parentElement.style.backgroundColor = "red";
}
However, this only works on the first x class <div>. When it works, it changes the background color of the section, or main or body element, and not the x class div parent (the item class div).
If you want to handle this with a handler on each .x element, you have to add a handler to each .x element. (But you may not want to do that, keep reading.) That would look like this:
var openbtns = document.getElementsByClassName("x");
for (var n = 0; n < openbtns.length; ++n) {
openbtns[n].addEventListener("click", xClickHandler);
}
...where xClickHandler uses this (or event.currentTarget) to know which .x element was clicked:
function xClickHandler() {
this.parentElement.style.backgroundColor = "red"; // I suggest using a class instead of doing this, btw
}
But, if all of these .x elements are within the same overall container, you can do it with event delegation, like this:
document.querySelector("selector-for-the-overall-container").addEventListener("click", function(event) {
// Find the `.x` that was clicked (which may be `event.target` or may be
// an ancestor node of it
var x = event.target.closest(".x");
if (x && this.contains(x)) {
x.parentElement.style.backgroundColor = "red"; // Again, suggest using a class
}
});
More:
closest
contains
Live Example using the HTML from your comment:
document.getElementById("items").addEventListener("click", function(event) {
// Find the `.x` that was clicked (which may be `event.target` or may be
// an ancestor node of it
var x = event.target.closest(".x");
if (x && this.contains(x)) {
x.parentElement.style.backgroundColor = "red"; // Again, suggest using a class
}
});
.x {
display: inline-block;
width: 10px;
height: 10px;
background-color: blue;
}
section {
background-color: yellow;
padding: 8px;
}
<main id="items">
<section id="design">
<div class="item">
<div class="x"></div>
<h1>Design stuff</h1>
</div>
</section>
<section id="art">
<div class="item">
<h1>Art stuff</h1>
<div class="x"></div>
</div>
</section>
</main>
Add the event listener to each element using a for of loop:
var openbtnList = document.getElementsByClassName("x");
for (let x of openbtnList) {
x.addEventListener("click", clickX, false);
};
function clickX() {
this.parentElement.classList.toggle("red"); // sstyle.backgroundColor = "red";
}
main {
display: flex;
}
.item {
width: 80px;
height: 100px;
padding: 30px;
}
.item::before {
content: " ";
background: url(http://placekitten.com/80/100) center/cover;
width: 80px;
height: 100px;
position: absolute;
}
.x::before {
content: "X";
color: white;
font: 30px/30px sans-serif;
padding: 10px;
position: absolute;
}
.red {
background: rgba(255, 0, 0, 0.5);
}
<main>
<div class="item">
<div class="x"></div>
</div>
<div class="item">
<div class="x"></div>
</div>
<div class="item">
<div class="x"></div>
</div>
</main>

React JS Rendering parent does not render children again

I am having some issues with React JS rendering children when rendering the parent.
Here I am trying to implement the "Game of Life" (a project from Freecodecamp class).
I am stuck in this situation. I click on a dead cell and it becomes alive (blue). Then, suppose I want to clear the grid, that is, make all cells dead, but it doesn't work. It seems that even re-rendering the parent will not re-render the children.
Any idea?
var board = [];
var width = 80;
var length = 50;
var cells = width * length;
var states = ["alive", "dead"];
class BoardGrid extends React.Component {
constructor(props) {
super(props);
//this.initBoardArray = this.initBoardArray.bind(this);
}
render() {
//this.initBoardArray();
let boardDOM = this.props.board.map(function(cell) {
return <BoardGridCell status={cell.status} id={cell.id} />;
});
return (
<div id="game-grid">
{boardDOM}
</div>
);
}
}
class BoardGridCell extends React.Component {
render() {
return (
<div
id={this.props.id}
className={`cell ${this.props.status}`}
data-status={this.props.status}
/>
);
}
}
function initBoard() {
for (let cellIndex = 0; cellIndex < cells; cellIndex++) {
let cell = { id: cellIndex, status: "dead" };
board[cellIndex] = cell;
}
}
function drawBoard() {
ReactDOM.render(
<BoardGrid board={board} />,
document.getElementById("game-grid-wrapper")
);
}
function clearBoard() {
for (let cellIndex = 0; cellIndex < cells; cellIndex++) {
let cell = { id: cellIndex, status: "dead" };
board[cellIndex] = cell;
}
}
$("#game-grid-wrapper").on("click", ".cell", function() {
let currentState = $(this).attr("data-status");
let currentStateIndex = states.indexOf(currentState);
let newState = states[(currentStateIndex + 1) % 2];
$(this).attr("class", `cell ${newState}`);
$(this).attr("data-status", newState);
});
$("#stop").on("click", function() {
alert("clearing");
clearBoard();
drawBoard();
});
initBoard();
drawBoard();
html,
body {
height: 100%;
text-align: center;
font-family: 'Open Sans', sans-serif;
}
h1,
h2 {
font-family: 'Press Start 2P', cursive;
}
.button {
width: 100px;
border: 1px solid #555;
padding: 5px;
margin: 5px;
cursor: pointer;
border-radius: 4px;
}
.button:hover {
opacity: 0.9;
}
#main {
margin: 10px;
}
#game-grid {
background-color: #000;
display: flex;
flex-wrap: wrap;
align-content: flex-start;
width: 800px;
height: 500px;
overflow: hidden;
}
#game-grid .cell {
border: 1px solid #767676;
width: 10px;
height: 10px;
color: #fff;
font-size: 9px;
box-sizing: border-box;
}
.alive {
background-color: #2185d0;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="main">
<div id="game-actions">
<div id="start" class="button"><i class="fa fa-play"></i> Start</div>
<div id="pause" class="button"><i class="fa fa-pause"></i> Pause</div>
<div id="stop" class="button"><i class="fa fa-stop"></i> Stop</div>
</div>
<div id='game-grid-wrapper'></div>
</div>
You should not use jQuery together with React if you don't have to. Both manipulate the DOM but based on different information which can make them interfere in an unexpected way.
For your board state you should use the state of your BoardGrid component. Initialize your state in the constructor and add an onClick() callback to each cell when rendering it.
When the cell is clicked call the callback function given by the board component and pass it's id with it. Use that id to update the board state using setState() in your BoardGrid component.
I can add some example code later, if you struggle with anything.

How to change class and text of one tag by clicking on another tag?

I don't know how to describe this without making it more complicated.
So look at the result of the code and click on the first link with "Show", then the second one and third one.
When the second link is clicked, first one closes but text remains "Hide" and i want it to change to "Show".
So, when clicking a link, detect if any other link has text "Hide" and change it to "Show".
And please no jQuery...
document.getElementsByClassName("show")[0].onclick = function() {
var x = document.getElementsByClassName("hide")[0];
var y = document.getElementsByClassName("show")[0];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
document.getElementsByClassName("show")[1].onclick = function() {
var x = document.getElementsByClassName("hide")[1];
var y = document.getElementsByClassName("show")[1];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
document.getElementsByClassName("show")[2].onclick = function() {
var x = document.getElementsByClassName("hide")[2];
var y = document.getElementsByClassName("show")[2];
if (x.classList.contains("visible")) {
x.classList.remove("visible");
y.textContent = "Show";
} else {
closeOther();
x.classList.add("visible");
y.textContent = "Hide";
}
};
function closeOther() {
var visible = document.querySelectorAll(".visible"),
i, l = visible.length;
for (i = 0; i < l; ++i) {
visible[i].classList.remove("visible");
}
}
.style {
background-color: yellow;
width: 200px;
height: 200px;
display: inline-block;
}
.hide {
background-color: red;
width: 50px;
height: 50px;
display: none;
position: relative;
top: 50px;
left: 50px;
}
.hide.visible {
display: block;
}
<div class="style">
Show
<div class="hide">
</div>
</div>
<div class="style">
Show
<div class="hide">
</div>
</div>
<div class="style">
Show
<div class="hide">
</div>
</div>
I tried to write a solution which didn't use any javascript at all and worked using CSS alone. I couldn't get it to work though - CSS can identify focus but it can't identify blur (ie. when focus has just been removed).
So here is a solution which uses javascript and the classList API, instead:
var divs = document.getElementsByTagName('div');
function toggleFocus() {
for (var i = 0; i < divs.length; i++) {
if (divs[i] === this) continue;
divs[i].classList.add('show');
divs[i].classList.remove('hide');
}
this.classList.toggle('show');
this.classList.toggle('hide');
}
for (let i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', toggleFocus, false);
}
div {
display: inline-block;
position: relative;
width: 140px;
height: 140px;
background-color: rgb(255,255,0);
}
.show::before {
content: 'show';
}
.hide::before {
content: 'hide';
}
div::before {
color: rgb(0,0,255);
text-decoration: underline;
cursor: pointer;
}
.hide::after {
content: '';
position: absolute;
top: 40px;
left: 40px;
width: 50px;
height: 50px;
background-color: rgb(255,0,0);
}
<div class="show"></div>
<div class="show"></div>
<div class="show"></div>
Like this?
Just added following to closeOther():
visible = document.querySelectorAll(".show"),
i, l = visible.length;
for (i = 0; i < l; ++i) {
visible[i].textContent="Show";
}

Categories

Resources