Expanding all details tags - javascript

Anyone know if there is a way to create an expand all link for pages that use the semantic <details> tag? I managed to create a link that would auto-open closed details: Link to details section that expands details section as well
Now I'm trying to add a link that will expand all <details>.
I'm guessing you can do it with javascript but I'm weak there. Something to the effect of clicking a link that initiates a script that finds all "<details in the html and inserting the word "open" before displaying the html. Little help would be appreciated.
So far I'v got
<button onclick="openAll()">Expand All</button>
<script>function openAll() {
var x = document.getElementsByTagName("details");
var i;
for (i = 0; i < x.length; i++) {
x[i].setAttribute("open", "true");
}
</script>
The below works for the first <details> tag but I guess my loop in the above is not correct ...
<script>
function openAll() {
document.getElementsByTagName("details")[0].setAttribute("open", "true");
}
</script>
The below is the dummy html that I'm testing on
<details>Hello World<summary>summary</summary>lost</details>
<details>another<summary>good night moon</summary>find me</details>

To toggle all details elements in the page from JavaScript:
// Toggle open all details elements, onload
// Regardless of their initial status
document.body.querySelectorAll('details')
.forEach((e) => {(e.hasAttribute('open')) ?
e.removeAttribute('open') : e.setAttribute('open',true);
console.log(e.hasAttribute('open'))
})
<details> <!-- Initial status: closed -->
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
<details> <!-- Initial status: closed -->
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
<details> <!-- Initial status: closed -->
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
To close all other details, when one is opened (only one at a time):
document.body.querySelectorAll('summary').forEach((e) => e.addEventListener("click", (e) => {
document.body.querySelectorAll('details').forEach((e) => (e.hasAttribute('open')) ? e.removeAttribute('open') : '')
}))
<details>
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
<details>
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
<details>
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
To toggle every details all at once, when one is opened or closed:
document.body.querySelectorAll('summary').forEach((e) => e.addEventListener("click", (e) => {
e.preventDefault()
document.body.querySelectorAll('details').forEach((e) => (e.hasAttribute('open')) ? e.removeAttribute('open') : e.setAttribute('open', true))
}))
<details>
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
<details>
<summary>Details</summary>
Something small enough to escape casual notice.
</details>
<details>
<summary>Details</summary>
Something small enough to escape casual notice.
</details>

UPDATES
05/31/22 nucleon informed that the open attribute value isn't coerced into a boolean so even a "false" is treated strictly as a string which defaults to a truthy value. The correct way to handle it is to remove open instead. The change is located at the bottom of both snippets:
obj.open = false;
obj.removeAttribute('open');
Thanks, nucleon
04/12/21 trigger-segfault mentioned that should #expAll have any descendants there's a chance that the user could click it making it e.target which would foul up the class switching. Even though in the examples it's not a concern, trigger-segfault makes a good point, so in Snippet 1 e.target is replaced with e.currentTarget which always points to the element that listens for the event (#expAll):
e.currentTarget.classList.toggle('exp');
e.currentTarget.classList.toggle('col');
//...
if (e.currentTarget.classList.contains('exp')) {//...
In Snippet 2 the alternate solution is used -- e.target replaced with this. this also points to the element registered to event(s):
this.classList.toggle('exp');
this.classList.toggle('col');
//...
if (this.classList.contains('exp')) {//...
Thanks trigger-segfault
03/27/17 OP requested that the first 6 <detail>s be excluded. Swapped out .forEach() method for for loop.
See Snippet 2
Use the open attribute of <details>. It's true if open false if closed.
Details commented in Snippet.
SNIPPET 1
// Reference the toggle link
const xa = document.getElementById('expAll');
// Register link on click event
xa.addEventListener('click', function(e) {
/* Toggle the two classes that represent "state"
|| determined when link is clicked
*/
e.currentTarget.classList.toggle('exp');
e.currentTarget.classList.toggle('col');
// Collect all <details> into a NodeList
const details = document.querySelectorAll('details');
/* Convert NodeList into an array then iterate
|| through it...
*/
Array.from(details).forEach(function(obj, idx) {
/* If the link has the class .exp...
|| make each <detail>'s open attribute true
*/
if (e.currentTarget.classList.contains('exp')) {
obj.open = true;
// Otherwise remove [open]
} else {
obj.removeAttribute('open');
}
});
}, false);
<a href='#/' id='expAll' class='col'>Expand All</a>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
SNIPPET 2
// Reference the toggle link
const xa = document.getElementById('expAll');
// Register link on click event
xa.addEventListener('click', function(e) {
/* Toggle the two classes that represent "state"
|| determined when link is clicked
*/
this.classList.toggle('exp');
this.classList.toggle('col');
// Collect all <details> into a NodeList
const details = document.querySelectorAll('details');
/* Convert NodeList into an array then iterate
|| through it...
*/
const D = Array.from(details);
/* Start a for loop at 6 instead of 0
|| Now 0 - 5 details are excluded
*/
for (let i = 6; i < D.length; i++) {
/* If the link has the class .exp...
|| make each <detail>'s open attribute true
*/
if (this.classList.contains('exp')) {
D[i].open = true;
// Otherwise remove [open]
} else {
D[i].removeAttribute('open');
}
}
}, false);
<a href='#/' id='expAll' class='col'>Expand All</a>
<details>Hello World
<summary>summary 0</summary>lost</details>
<details>another
<summary>good night moon 1</summary>find me</details>
<details>Hello World
<summary>summary 2</summary>lost</details>
<details>another
<summary>good night moon 3</summary>find me</details>
<details>Hello World
<summary>summary 4</summary>lost</details>
<details>another
<summary>good night moon 5</summary>find me</details>
<details>Hello World
<summary>summary 6</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>
<details>Hello World
<summary>summary</summary>lost</details>
<details>another
<summary>good night moon</summary>find me</details>

The solutions didn't work for me. So, I altered #testing123 solution to get it to work with a complete example.
function openAll() {
var elems = document.getElementsByTagName("details");
document.getElementById("btnExpandHideAllDetails").innerHTML = "Hide All Details on page";
document.getElementById("btnExpandHideAllDetails").setAttribute( "onClick", "javascript: closeAll();");
for (var i = 4; i <= elems.length; i++){
elems[i].setAttribute("open", "true");
}
}
function closeAll() {
var elems = document.getElementsByTagName("details");
document.getElementById("btnExpandHideAllDetails").setAttribute( "onClick", "javascript: openAll();" );
document.getElementById("btnExpandHideAllDetails").innerHTML = "Expand All Details on Page";
for (var i = 4; i <= elems.length; i++){
elems[i].removeAttribute("open");
}
}
<button id="btnExpandHideAllDetails" onclick="openAll()" style="color:white;background-color:green;">Expand All Details on Page</button>
<details>
<summary>0</summary>
</details>
<details>
<summary>1</summary>
</details>
<details>
<summary>2</summary>
</details>
<details>
<summary>3</summary>
</details>
<details>
<summary>Expand me.</summary>
Hello World!
</details>

Here is my solution:
const expandElements = shouldExpand => {
let detailsElements = document.querySelectorAll("details");
detailsElements = [...detailsElements];
if (shouldExpand) {
detailsElements.map(item => item.setAttribute("open", shouldExpand));
} else {
detailsElements.map(item => item.removeAttribute("open"));
}
};
Here how you could use it:
<button onClick="expandElements(true)">Expand</button>
<button onClick="expandElements(false)">Collapse</button>

So zer00ne's solution seems to sometimes work in the browsers (Chrome / Firefox). Sometimes on the second click it works. Sometimes on the first. Sometimes not at all. Maybe because the details tag is still not fully supported?
I went with the solution below ... just has an absolute endpoint at 31 instead of stop at end.
<button id="expand" onclick="openAll()">Expand All +</button>
var elems = document.getElementsByTagName("details");
function openAll() {
for (var i = 4; i <= 31; i++){
elems[i].setAttribute("open", "true");
}
document.getElementById("expand").setAttribute( "onClick", "javascript: closeAll();" );
document.getElementById("expand").innerHTML = "Collapse All -";
}
function closeAll() {
for (var i = 4; i <= 31; i++){
elems[i].removeAttribute("open");
}
document.getElementById("expand").setAttribute( "onClick", "javascript: openAll();" );
document.getElementById("expand").innerHTML = "Expand All +";
}

I wanted something for my own use so I don't care if it works in all browsers.
My approach was to create the expand/close button in each heading of every section of the page containing details elements. The button as an inline block sits at the end of each section heading without me having to add them in manually.
The code goes through the page detail elements to find the closest parent that is either a section, an aside, an article, the main or a div. A unique array of those parent grouping elements is then used to add the buttons to their respective headings. It does not matter whether those headings are h1 - h6, whatever the first one is in each section will have the heading amended with an 'expand' button.
The button itself updates to show 'close' when 'expanded' and visa-versa, therefore behaving like a toggle.
Because I want to be able to search content on the page I have also included a 'expand all' button after the first heading in the main element. This explains that you need to 'expand all' to search in the page.
This 'expand all' updates the daughter 'expand' buttons in each section to show 'close'. It also toggles to 'close all'.
In my opinion this approach is necessary only if you are working with structured content that is using the semantic elements and have a lot of content on the page.
A failing of the details element is that it does hide content from on page search, this is my best effort to work around that for content that is likely to be search, such as technical notes where you might want to hide code snippets and lengthy instructions for setting up software yet still want to search for a given keyword.
document.addEventListener("DOMContentLoaded", function (t) {
var groups = ["section", "aside", "article", "main", "div"], headings = ["h1", "h2", "h3", "h4", "h5", "h6"],
parents = [],
details = document.querySelectorAll("details");
for (var detail of details) for (var group of groups) {
var parent = detail.closest(group);
if (parent) {
if (!parents.includes(parent)) for (var heading in parents.push(parent), headings) {
var location = parent.getElementsByTagName(headings[heading]);
if (location.length) {
var button = document.createElement("button");
button.classList.add("details-helper"),
button.setAttribute("type", "button"),
button.textContent = "Expand",
button.style.display = "inline-block",
location[0].appendChild(button),
button.addEventListener("click", expandGroup(parent));
}
}
break;
}
}
if (parents.length) {
var nav = document.createElement("nav");
nav.classList.add("text-search");
var button = document.createElement("button");
button.classList.add("search-helper"),
button.setAttribute("type", "button"),
button.textContent = "Expand All",
button.style.display = "inline-block",
nav.appendChild(button),
button.addEventListener("click", expandAll());
var p = document.createElement("p");
p.style.display = "inline-block";
var em = document.createElement("em");
em.textContent = "Press before searching this page with CTRL+F";
p.appendChild(em);
nav.appendChild(p);
for (heading of headings) {
if (location = document.querySelector("main " + heading)) {
location.parentNode.insertBefore(nav, location.nextSibling);
break;
}
}
}
function expandGroup(group) {
return function () {
this.classList.contains("close-details") ? (this.classList.remove("close-details"), this.textContent = "Expand", state = false) : (this.classList.add("close-details"), this.textContent = "Close", state = true);
var details = group.getElementsByTagName("details");
Array.from(details).forEach(function (detail) {
detail.open = state;
})
}
}
function expandAll() {
return function () {
this.classList.contains("close-all-details") ? (this.classList.remove("close-all-details"), this.textContent = "Expand All", state = false) : (this.classList.add("close-all-details"), this.textContent = "Close All", state = true);
var buttons = document.querySelectorAll('.details-helper');
Array.from(buttons).forEach(function (button) {
if(!state) {
button.classList.remove("close-details");
} else {
button.classList.add("close-details");
}
button.textContent = state ? "Close" : "Expand";
for (var group of groups) {
var parent = button.closest(group);
if (parent) {
var details = parent.querySelectorAll("details");
Array.from(details).forEach(function (detail) {
detail.open = state;
})
}
}
})
}
}
});
This can be included in a document with a script tag - 'details-helper.js' - and the created buttons include styles.
To keep buttons consistent with the default styling of details elements:
.search-helper,
.details-helper {
font-size: .66em;
margin: 0 1em;
outline: none;
padding: 0.25em;
text-transform: uppercase;
vertical-align: text-bottom;
width: 8em;
}
.search-helper {
width: 10em;
}
.search-helper::after,
.details-helper::after {
content: ' ▶';
}
.close-all-details::after,
.close-details::after {
content: ' ▼';
}
Your mileage may vary with this solution but hopefully you may find some of it useful. Assumptions are made that your page has a main and logical structure to the content. This has not been tested on a page where every element is nested in lots of divs and there are no articles or sections.

Related

.click in Javascript not having any effect - should update two elements based on array

I'm fairly new to javascript and trying to create a language-learning tool that plays clips from a music video and displays a translation. I'm using arrays to organize and access the links and translations. However, I must have left out something essential, because clicking on the phrase elements to display each video and translation has no effect.
http://jsfiddle.net/KireniaV/XaK7G/1/
I created the clips using Spliced and am displaying them via an iFrame (also tried embedding the video clips, but ran into the same problem either way).
HTML:
<body>
<div class="nav">
<ul>
<li id="phrase1">Ne dunun bamimyon byori doeji</li>
<li id="phrase2">naui jibun dwidgolmog dalgwa byori tujiyo</li>
<li id="phrase3">dubon dashin sengson gage tolji anha</li>
<li id="phrase4">sorobge uldon naldul nanun wetorirane</li>
</ul>
</div>
<div class="content">
<h3>Nangman Goyangi (Romantic Cat)</h3>
<h4>by Cherry Filter, lyrics and translation courtesy of DavichiLyrics</h4>
<iframe id="player" title="player" src="http://www.youtube.com/v/U6EcOiKWfZI" width="341" height="192" frameborder="0" marginheight="0" marginwidth="0" id="myframe">You can't see iFrames :(.</iframe>
<p id="text">Select a phrase from the song (to either side) to view a video clip, transcription, and translation!</p>
</div>
<div class="nav">
<ul>
<li id="phrase5">Ijen badaro tonalgoeyo (do jayurobge)</li>
<li id="phrase6">gomiro gumulchyoso mulgogi jaburo</li>
<li id="phrase7">Nanun nangman goyangi</li>
<li id="phrase8">sulphun doshirul bichwo chumchunun jagun byolbid</li>
</ul>
</div>
</body>
CSS:
ul {
list-style-type:none;
margin:0;
padding:0;
}
li {
cursor:pointer;
display:block;
font-weight:bold;
color:#FFFFFF;
background-color:#889999;
width:120px;
text-align:center;
padding:4px;
text-decoration:none;
text-transform:uppercase;
}
li:hover {
background-color:#999988;
}
.nav {
float: left;
}
.content {
float: left;
width: 341px;
}
Javascript:
var videos = [];
videos[1] = "http://www.youtube.com/v/U6EcOiKWfZI&start=26&end=31";
videos[2] = "http://www.youtube.com/v/U6EcOiKWfZI&start=31&end=37";
videos[3] = "http://www.youtube.com/v/U6EcOiKWfZI&start=38&end=42";
videos[4] = "http://www.youtube.com/v/U6EcOiKWfZI&start=43&end=49";
videos[5] = "http://www.youtube.com/v/U6EcOiKWfZI&start=49&end=54";
videos[6] = "http://www.youtube.com/v/U6EcOiKWfZI&start=55&end=60";
videos[7] = "http://www.youtube.com/v/U6EcOiKWfZI&start=60&end=65";
videos[8] = "http://www.youtube.com/v/U6EcOiKWfZI&start=65&end=72";
var translations = [];
translations[1] = "In the dark night, My eyes become stars.";
translations[2] = "I won’t rob a fish market again.";
translations[3] = "My weeping days and days, I’m quite alone.";
translations[4] = "Now, I will go to the sea.";
translations[5] = "To catch fish using spider’s web.";
translations[6] = "I’m a romantic cat.";
translations[7] = "I’m a tiny star twinkling over the lonely city.";
translations[8] = "My deep and sad sea, it has gone away.";
function changePhrase3(clicked) {
var oldText = document.getElementById('text').innerHTML;
var newText = translations[clicked];
oldText = newText;
document.getElementById('player').src = videos[clicked];
}
document.getElementById('phrase1').click(changePhrase(1));
document.getElementById('phrase2').click(changePhrase(2));
document.getElementById('phrase3').click(changePhrase(3));
document.getElementById('phrase4').click(changePhrase(4));
document.getElementById('phrase5').click(changePhrase(5));
document.getElementById('phrase6').click(changePhrase(6));
document.getElementById('phrase7').click(changePhrase(7));
document.getElementById('phrase8').click(changePhrase(8));
Just a typo and invalid call.
I just fixed it. please checkout FIDDLE
First rename function changePhrase3 to changePhrase (3 is typo).
Second you should bind click function likes this. (# is not needed, use onclick instead of click)
document.getElementById('phrase1').onclick = function(){ changePhrase(1) };
because if you bind like document.getElementById('phrase1').click(changePhrase(1)); is means you send the result of changePhrase(1) to click function. so you have to warp it up in function.
Third modify changePhrase like this
function changePhrase(clicked){
var newText = translations[clicked]; // get new text
document.getElementById('text').innerHTML = newText; // assign to the old one
document.getElementById('player').src = videos[clicked];
}
There's a few little things awry here,
Firstly, as Patrick Evans pointed out in the comments, there is a typo in either your function name, or your function calls. Make sure these match up.
Secondly, click() is a jQuery method; You are using straight JS, so you want to use 'onclick':
http://www.w3schools.com/jsref/event_onclick.asp
And last of all, getElementById does not require the '#' symbol.. You've got this right in the code in your post, but not in the fiddle. Just double check that this is how it is in your actual code.
All in all, you should get something like this for your click event listeners:
document.getElementById('phrase1').onclick=function(){changePhrase3(1)};
Added autoplay=1 to your youtube links so they would play immediately.
Changed some of your jQuery functions click() to normal javascript onclick.
You don't care about what the old text was for your translation, just what the container is so you can update it, correct? This should get you started:
var txtContainer = document.getElementById('text');
var newText = translations[clicked];
txtContainer.innerHTML = newText;
document.getElementById('player').src = videos[clicked];
Here is the result: http://jsfiddle.net/zyglobe/XaK7G/3/
Gomiro gumulchyoso mulgogi jaburo.

CSS/Javascript Mouseover Popup box

I have table cell with a javascript/css content box that pops up upon mouseover.
There are 20 cells on the page. Everything is working correctly, in that when you mouseover the product link, you see the content box. However, I want to put a LINK inside the content box that the user can click on if they choose. So, the popup box has to stay up long enough for the user to mouseover to click the link.
Really, I want the OnMouseOver to stay open until either a second or two has gone by and/or the user OnMouseOver's another cell.
The problem I'm having is that the pop up box doesn't stay open (due to OnMouseOut) to click the link. If I turn OnMouseOut off (which I tried), then all the pop up boxes just stay open, so this doesn't do the job either.
My CSS looks like this:
<style type="text/css" title="">
.NameHighlights {position:relative; }
.NameHighlights div {display: none;}
.NameHighlightsHover {position:relative;}
.NameHighlightsHover div {display:block;position:absolute;width: 15em;top:1.3em;*top:20px;left:70px;z-index:1000;}
</style>
And the html:
<td>
<span class="NameHighlights" onMouseOver="javascript:this.className='NameHighlightsHover'" onMouseOut="javascript:this.className='NameHighlights'">
Product 1
<div>
# of Votes: 123<br>
% Liked<br>
<a href="product review link>See User reviews</a>
</div>
</span>
</td>
So, how can I make the pop up box stay open long enough to click on the link, but also make it disappear if another content box is activated?
Thanks in advance.
You have to improve your HTML markup for this task, need to get rid of inline event handlers:
<span class="NameHighlights">
Product 1
<div>
# of Votes: 123<br>
% Liked<br>
See User reviews
</div>
</span>
Then you have to bind your events to all .NameHighlights spans:
var span = document.querySelectorAll('.NameHighlights');
for (var i = span.length; i--;) {
(function () {
var t;
span[i].onmouseover = function () {
hideAll();
clearTimeout(t);
this.className = 'NameHighlightsHover';
};
span[i].onmouseout = function () {
var self = this;
t = setTimeout(function () {
self.className = 'NameHighlights';
}, 300);
};
})();
}
http://jsfiddle.net/3wyHJ/
So the idea is to use setTimeout method.
Notes: I used querySelectorAll which is not supported by IE7, if you need to support it then you can use any of implementations of the getElementsByClassName method.
In case anyone is looking for a jQuery version of the accepted answer:
var t;
$(function(){
$('span.NameHighlights').mouseover(
function(e){
hideAll();
clearTimeout(t);
$(this).attr('class', 'NameHighlightsHover');
}
).mouseout(
function(e){
t = setTimeout(function() {
//$(this).attr('class', 'NameHighlights');
hideAll();
}, 300);
}
);
});
function hideAll() {
$('span.NameHighlightsHover').each(function(index) {
console.log('insde hideAll');
$(this).attr('class', 'NameHighlights');
})
};
jsFiddle

4 toggle buttons speak javascript to each other but none of them are good listeners- the sequel: stupidity strikes back

This is the sequel to this thread:
4 toggle buttons speak javascript to each other but none of them are good listeners
Our heros have overcome the ridiculous amount of nonsense originally presented in the fiddle http://jsfiddle.net/EjW7A/8/ (no longer available) when #nbrooks -reinvigorated by the forces of good- conquered all of the stupidly placed arrays, functions and the mammoth amount of redundant content with his solution:
http://jsfiddle.net/EjW7A/24/
We rejoin Luhring after 8 hours of poking, prodding, red bull drinking, concrete wall head-bashing at the final step of solving the epic problem of doom- implementation:
The new fiddle:
http://jsfiddle.net/Luhring/EjW7A/38/
Problem:
How can I insert the content dynamically- allowing each button to toggle it's own content while making sure the other buttons are toggled off and their content hidden? ex, if button 1 is toggled on (it is animated as if it were a 'real' pressed button), button 1s content is displayed in a gallery where the contents can be clicked to display a lightbox. when button 2 is clicked should toggle button 1 off and replace button 1's contents with its own.
New Working Demo
Anything invoking jQuery on DOM elements must be wrapped within the DOM ready function to work correctly (this is why your $('a').click() was failing. Also, normally if you see yourself creating multiple arrays that you never end up using, and still end up referencing each element directly, you're making a lot of wasted effort. I cleaned your code up a bit - take a look:
jQuery(document).ready(function($) {
//variable declaration section.
var contentArray = ['albumArt', 'logoDesign', 'UX', 'other'],
content = {}, newClassName, $selectedArray, i;
for ( i = 0; i < contentArray.length; i++) {
var className = contentArray[i];
content[className] = $('.' + className);
}
//prevent links that are clicked from going anywhere
$("a").click(function(e) {
e.preventDefault();
});
$('.workTypes').click(function() {
if ($(this).is('#centeringDiv a')) return;
$(this).toggleClass('workTypesSelected');
$('.workTypesSelected').not(this).removeClass('workTypesSelected');
$selectedArray = content[$('.workTypesSelected').attr('id')];
$('#galleryDiv').empty();
if ( $selectedArray ) {
// note creates #largeGallery elements dynamically
for ( i = 0; i < $selectedArray.length; i++ ) {
var $selected = $selectedArray.eq(i);
$('<a>').attr({
href: $selected.attr('href'),
title: $selected.attr('title'),
class: "lb_gal"
}).append(
$('<img>').attr({
id: "largeGallery"+i,
src: $selected.attr('href'),
class: "gallery cf"
}).rlightbox()
)
.appendTo('#galleryDiv')
.rlightbox();
}
}
}); // end click handler
}); //end the document ready jquery function​

Using Javascript to change an anchor link's text when window width changes

I'm trying to build a simple javascript that will change the contents of an anchor link when the browser window goes below a certain width, and change it back when it goes above said width.
HTML:
<footer id="about" style="">
<ul id="aboutFooter" style="">
<li>OUR 140-CHARACTER THOUGHTS</li>
<li>EMAIL US AT WHATEVER#GMAIL.COM</li>
<li>OR KEEP THINGS SIMPLE AND HIT "NEXT"</li>
</ul>
</footer>
JAVASCRIPT:
var mq = window.matchMedia( "(min-width: 1074px)" );
if (mq.matches) {
document.getElementById("email").firstChild.nodeValue = "EMAIL US AT whatever#gmail.com";
document.getElementById("twitter").firstChild.nodeValue = "OUR 140-CHARACTER THOUGHTS";
}
else {
document.getElementById("email").firstChild.nodeValue = "EMAIL";
document.getElementById("twitter").firstChild.nodeValue = "TWITTER";
}
At the moment, it's not working at all - just stays on the initial values for each element. I have jQuery running on the same page, is it possible that the two are interfering?
You have to add a listener so it updates when the state changes. Example from http://dbaron.org/log/20110422-matchMedia (this is copy-and-paste, not my code):
function setup_for_width(mql) {
if (mql.matches) {
// The screen width is 400px or wider. Set up or change things
// appropriately.
} else {
// The screen width is less than 400px. Set up or change things
// appropriately.
}
}
var width_mql = window.matchMedia("(min-width: 400px)");
// Add a listener for when the result changes
width_mql.addListener(setup_for_width);
// And share the same code to set things up with our current state.
setup_for_width(width_mql);
Just change the 400px in their example to 1074px, fill in the blanks (where the comments are), and it should work for you. Like this:
function setup_for_width(mql) {
if (mql.matches) {
document.getElementById("email").firstChild.nodeValue = "EMAIL US AT whatever#gmail.com";
document.getElementById("twitter").firstChild.nodeValue = "OUR 140-CHARACTER THOUGHTS";
} else {
document.getElementById("email").firstChild.nodeValue = "EMAIL";
document.getElementById("twitter").firstChild.nodeValue = "TWITTER";
}
}
var width_mql = window.matchMedia("(min-width: 1074px)");
// Add a listener for when the result changes
width_mql.addListener(setup_for_width);
// And share the same code to set things up with our current state.
setup_for_width(width_mql);

Access Div Contents using Up and Down Arrow Keys using javascript

I have a Div Tag which contains 4 child Div Tags
<Div id="Parent">
<div id="childOne">ChildOne &lt/div>
<div id="childOne">ChildTwo &lt/div>
<div id="childOne">ChildThree &lt/div>
<div id="childOne">ChildFour &lt/div>
&lt/Div>
Now I would like to access these Child Div's using up and Down Arrow Keys through Javascript
The above div is show on click of a TextBox.I want that the user can choose any of the child div and its selected value appears in the TextBox. I have acheived the end result by attachinh onClick event to each childDiv.
Here's a library free solution to get you started.
You might like to add events that hide and show the div when the textbox gains or loses focus. Perhaps [esc] should clear the selection?
( I haven't tested it in ie )
<style>div.active{ background: red }</style>
<input type="text" id="tb">
<div id="Parent">
<div id="childOne">ChildOne </div>
<div id="childOne">ChildTwo </div>
<div id="childOne">ChildThree </div>
<div id="childOne">ChildFour </div>
</div>
<script type="text/javascript">
function autocomplete( textBoxId, containerDivId ) {
var ac = this;
this.textbox = document.getElementById(textBoxId);
this.div = document.getElementById(containerDivId);
this.list = this.div.getElementsByTagName('div');
this.pointer = null;
this.textbox.onkeydown = function( e ) {
e = e || window.event;
switch( e.keyCode ) {
case 38: //up
ac.selectDiv(-1);
break;
case 40: //down
ac.selectDiv(1);
break;
}
}
this.selectDiv = function( inc ) {
if( this.pointer !== null && this.pointer+inc >= 0 && this.pointer+inc < this.list.length ) {
this.list[this.pointer].className = '';
this.pointer += inc;
this.list[this.pointer].className = 'active';
this.textbox.value = this.list[this.pointer].innerHTML;
}
if( this.pointer === null ) {
this.pointer = 0;
this.list[this.pointer].className = 'active';
this.textbox.value = this.list[this.pointer].innerHTML;
}
}
}
new autocomplete( 'tb', 'Parent' );
</script>
Are you looking for what is known as auto-completion or suggestions?
You're definitely looking for 'Autosuggest/Autocomplete' This is rather time-consuming to implement fully if you want to do it in pure javascript, but yes, you could use the example from strager to get started.
What I recommend is using JQuery instead. JQuery has a very nice plugin for autocomplete that you can use. I just implemented in one of my projects a couple of days ago and it seems to work fine.
There's an important saying that you must remember while making software -- 'Don't try to re-invent the wheel.'
If other programmers have done it already, and they are kind enough to share, use it, and thank them.
Cheers!
What do you mean "access them with arrow keys"? There is text in each of the divs... they don't contain any interaction elements, so keyboard has no relevance here. Maybe you need to elaborate your question?

Categories

Resources