In my project, I am adding li tags dynamically to ul elements and then when the focus is on textarea element, I am trying to generate a hover effect on the first li element whenever the user presses down arrow key. Somehow my effort is not working.
The code which I tried till now is as follows:
JS Fiddle
HTML
<textarea id="result" rows="4" cols="50"></textarea>
<ul class="autoComplete"></ul>
CSS
.autoComplete li {
background-color:#E1E1E1;
cursor: hand;
cursor: pointer;
}
.autoComplete li:hover {
background-color:#BDBDBD;
}
js
var result = $('#result');
var autoComplete = $('.autoComplete');
result.keydown(function (event) {
if (event.keyCode == 40) {
if (autoComplete.children('li').length > 0) {
console.log('down');
//should work with IE
autoComplete.children(":first").focus().hover();
}
}
});
PS: The solution should be crossbrowser (IE8+)
Try
CSS
.autoComplete li {
background-color:#E1E1E1;
cursor: hand;
cursor: pointer;
}
.autoComplete li.hover {
background-color:#BDBDBD;
}
JS
var result = $('#result');
var autoComplete = $('.autoComplete');
result.keyup(function (event) {
console.log('keydown');
if (event.keyCode == 40) {
if (autoComplete.children('li').length > 0) {
console.log('down');
//should work with IE
autoComplete.children(":first").mouseenter();
}
}
});
autoComplete.on('mouseenter', 'li', function(){
$(this).addClass('hover');
}).on('mouseleave', 'li', function(){
$(this).removeClass('hover');
});
Demo: Fiddle
Related
I found (and tweaked) the code below that was designed for switching the larger img src with the src of thumbnails in a list, but I'm not sure how to adjust it to use something like https://picsum.photos/id/CLICKED_LI_textContent/200/200 as the URL instead of pulling from a thumbnail's src.
For some more context here's the original post in which I was looking into this
How can I change img src from list of (non-image) items?
I haven't taken any JS classes, so I'm not sure how every component of the script works. I'm more comfortable with pure HTML and CSS, but think JS is the answer for making this work more smoothly.
(I did add the jquery script src to the document for this)
Sorry the code is a little ugly, I would have added the script and style tags and such but I ran out of time while posting this
$("#list li").click(function(e) {
// if i use this getting undefined
// var src = $(this).attr("src");
// so i use this method
var target = e.target;
var src = target.src;
console.log(src);
$("#display").fadeOut(function() {
$(this).on('load', function() {
$(this).fadeIn();
});
$(this).attr("src", src);
});
//record which thumb was clicked
$("#list li").removeClass("active"); //remove class
$(this).addClass("active"); //apply class to selected thumb
});
//move next
$("#left-arrow").click(function() {
if ($("#list li.active").next("#list li").length > 0) {
$("#list li.active").next().children( 'img' ).trigger("click");
} else {
$("#list li:first > img").trigger("click"); //go to first
}
return false;
});
//move previous
$("#right-arrow").click(function() {
if ($("#list li.active").prev("#list li").length > 0) {
$("#list li.active").prev().children( 'img' ).trigger("click");
} else {
$("#list li:last > img").trigger("click"); //go to end
}
return false;
});
//click the first thumb to begin
$("#list li:first > img").trigger("click");
.container {
display: flex;
}
.active {
border-bottom: 1px solid #990000;
}
.list {
width: 200px;
cursor: pointer;
padding: 0.25rem;
}
list > li * {
/* so only the li tag can be event.target, and none of it's children */
pointer-events: none;
}
.display {
max-width: 500px;
max-height: 500px;
}
<div class="container">
<div class="list">
<ul id="list">
<li>237</li>
<li>240</li>
<li>100</li>
<li>301</li>
</ul>
$larr; $rarr;
</div>
<div class="show">
<img src="https://picsum.photos/id/237/200/200" class="display" id="display">
</div>
</div>
Here is a pure javascript solution. The only difference is that it lacks the fading between the images.
I tried to write the code as pedagogic as possible, using variables as explanations. The code goes more with your original thread, where you had a bunch of images with different file endings. I gave the image an alt attribute, so you can see the change.
A short explanation:
Use an array for the images.
Create your list through javascript, using the array.
Add click listeners to your #list, where you read the .textContent. I added pointer-events: none; to any children to the li tags so they don't trigger the click listener.
Add click listeners to your prev/next buttons, where you check which index that the currently visible image has in the array (from 0 to 3 in imageArr) and then adds +1 och -1 to that index.
[edit] Added code for updating the CSS.
const listEl = document.getElementById('list');
const imgElement = document.querySelector('.right > img');
let imageArr = ["237.jpg", "240.gif", "100.jpeg", "301.png"]; // 1
let currentImage = '';
document.getElementById('next').addEventListener('click', () => shiftImage(1));
document.getElementById('prev').addEventListener('click', () => shiftImage(-1));
listEl.addEventListener('click', displayImage);
function updateImage(imageName) {
const subfolder = 'images/';
changeActive(imageName, currentImage); /* ADDED in EDIT */
currentImage = imageName;
imgElement.src = subfolder + imageName;
imgElement.alt = imageName;
}
/* ADDED in EDIT */
function changeActive(newImage, oldImage) {
if (oldImage) {
let oldIndex = imageArr.indexOf(oldImage);
toggleActiveClass(oldIndex);
}
let currentIndex = imageArr.indexOf(newImage);
toggleActiveClass(currentIndex);
}
/* ADDED in EDIT */
function toggleActiveClass(imageIndex) {
let liElements = listEl.childNodes;
liElements[imageIndex].classList.toggle('active');
}
function shiftImage(direction) {
let currentIndex = imageArr.indexOf(currentImage);
let newIndex = currentIndex + direction;
if (newIndex < 0) { newIndex = imageArr.length - 1; }
else if (newIndex >= imageArr.length) { newIndex = 0; }
let newImageName = imageArr[newIndex];
updateImage(newImageName);
}
function displayImage(event) {
let liElement = event.target;
updateImage(liElement.textContent);
}
function constructImageLinks() { // 2
let htmlOutput = '';
for (let imageSrc of imageArr) {
htmlOutput += `<li>${imageSrc}</li>`;
}
listEl.innerHTML = htmlOutput;
}
constructImageLinks();
updateImage(imageArr[0]);
section {
display: flex;
}
section ul {
margin-top: 0px;
}
section > .left li {
cursor: pointer;
padding: 0.25rem;
}
section > .left li.active {
background-color: pink;
}
section > .left li > * {
pointer-events: none;
}
section > div {
padding: 1rem;
}
section > .right > img {
width: 200px;
border: 1px solid;
padding: 0.5rem;
}
<section>
<div class="left">
<ul id="list"></ul>
<button id="prev">Previous</button>
<button id="next">Next</button>
</div>
<div class="right">
<img>
</div>
</section>
JSFiddle - Link
HTML
<div class="container">
<div class="list">
<ul id="list">
<li>237</li>
<li>240</li>
<li>100</li>
<li>301</li>
</ul>
$larr; $rarr;
</div>
<div class="show">
<img src="https://picsum.photos/id/240/200/200" class="display" id="display">
</div>
</div>
Javascript
// HELPER FUNCTIONS
function getImageURL(id, width=200, height=200){
return "https://picsum.photos/id/"+ id + "/" + width + "/" + height;
}
function removeActive(){
let lis = $('#list li');
for(let i=0;i<lis.length;i++){
$(lis[i]).removeClass('active');
}
}
// HANDLE EVENTS
$(document).on('click', "#list li", async (e)=>{
await $('#display').fadeOut();
removeActive();
let li = $(e.target);
li.addClass('active');
let image_id = parseInt($(e.target).html());
let image_url = getImageURL(image_id);
$('#display').attr('src', image_url);
await $('#display').fadeIn();
});
//move next
$(document).on('click', "#left-arrow", (e)=>{
// Handler Here
});
//move previous
$(document).on('click', "#right-arrow", (e)=>{
// Handler Here
});
CSS
.active {
border-bottom: 1px solid #990000;
}
.list {
width: 200px;
cursor: pointer;
padding: 0.25rem;
}
list > li * {
/* so only the li tag can be event.target, and none of it's children */
pointer-events: none;
}
.display {
max-width: 500px;
max-height: 500px;
}
.container {
display: flex;
}
I have a menu that open a sub-menu section onclick (let's name the container: "sub-menu").
I would like "sub-menu" to disapear if the user click outside of it / on the rest of the page.
It seems to be solved on How do I detect a click outside an element?
But I can't get how to use the code snipet from the second most popular answer:
export function hideOnClickOutside(selector) {
const outsideClickListener = (event) => {
const $target = $(event.target);
if (!$target.closest(selector).length && $(selector).is(':visible')) {
$(selector).hide();
removeClickListener();
}
}
const removeClickListener = () => {
document.removeEventListener('click', outsideClickListener)
}
document.addEventListener('click', outsideClickListener)
}
Could you please guide me on how to use it?
I edited, and included a basic example. -> I want sub menu to also close when clicking on the "white" space. But not on the parent "main menu" element.
document.getElementById("main-menu").addEventListener("click", function() {bouttonexpand('sub-menu-class')});
function bouttonexpand(id) {
var elemeacacher = document.getElementsByClassName(id);
if (elemeacacher[0].style.display != "none"){
for(var y=0;y<elemeacacher.length;y++)
elemeacacher[y].style.display = "none";
}
else {
for(var y=0;y<elemeacacher.length;y++)
elemeacacher[y].style.display = "block";
}
}
#main-menu {
display:inline-block;
height:20px;
width:100px;
background: blue;
padding: 5%;
}
#sub-menu {
display:inline-block;
height:50px;
width:50px;
background: red;
display: none;
}
<div><div id="main-menu">Main menu</div></div>
<div><div id="sub-menu" class="sub-menu-class">Sub menu</div></div>
Thanks
By using jQuery, you can bind to the document click event and hides the div container when the clicked element isn’t the container itself or descendant of the div element.
var container = $("#sub-menu");
if (!container.is(event.target) && !container.has(event.target).length) {
container.hide();
}
If you want to hide that container without being tested the container itself or descendant of the div element just remove the condition and simply use container.hide();.
Also, rather than setting display: none; on sub-menu in the CSS, set it manually so that you can toggle the sub-menu from the very first click.
Have a look at the snippet below:
var x = document.getElementById("sub-menu");
x.style.display = "none";
$(document).click(function (evt) {
if ($(evt.target).is('#main-menu')) { // control click event if it's main-menu
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
else {
var container = $("#sub-menu");
if (!container.is(event.target) && !container.has(event.target).length) { // if you don't want that remove the condition and write container.hide(); only
container.hide();
}
}
});
#main-menu {
display: inline-block;
height: 20px;
width: 100px;
background: blue;
padding: 5%;
}
#sub-menu {
display: inline-block;
height: 50px;
width: 50px;
background: red;
}
<script src="https://code.jquery.com/jquery-3.5.1.min.js"
integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<div id="main-menu">Main menu</div>
<div id="sub-menu" class="sub-menu-class">Sub menu</div>
I need switches between 2 icons (in this example colors) by css class on element if i click on it. I have this code (which is not working):
$( ".play" ).on('click', function(event) {
event.preventDefault();
$(this).removeClass('play');
$(this).addClass('stop');
console.log('play');
});
$( ".stop" ).on('click', function(event) {
event.preventDefault();
alert();
$(this).removeClass('stop');
$(this).addClass('play');
console.log('stop');
});
.play {
background-color: black;
}
.stop {
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
You appear to be using Event Delegation with jQuery, but I think you might have it a little wrong:
$("body")
.on("click", ".play", function(event) {
// change "play" to "stop"
})
.on("click", ".stop", function(event) {
// change "stop" to "play"
});
You want to attach the click handler to the <body> tag, and then provide jQuery with the event name, CSS selector, and event handler.
Reference: http://api.jquery.com/on/
$( "a" ).on('click', function(event) {
event.preventDefault();
var anchor = $(this);
if(anchor.hasClass('play'))
{
$(this).removeClass('play');
$(this).addClass('stop');
console.log('play');
}
else
{
alert();
$(this).removeClass('stop');
$(this).addClass('play');
}
});
.play {
background-color: black;
}
.stop {
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Don't bind the event handlers to a class, bind it to the id of your element. Then you can just see what class the element has and switch between them.
Here is a working codepen
HTML:
CSS: Doesn't change
JS:
$( "#clickable" ).on('click', function(event) {
if($(this).hasClass('play')) {
$(this).removeClass('play');
$(this).addClass('stop');
} else {
$(this).removeClass('stop');
$(this).addClass('play');
}
});
As easy as.....
$( "a" ).on('click', function(event) {
event.preventDefault();
$(this).toggleClass('stop');
$(this).toggleClass('play');
});
.play {
background-color: black;
}
.stop {
background-color: green;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Or you can also do this:-
css:
.play {
background-color: black;
}
.stop {
background-color: green;
}
JS:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
$(document).ready(function() {
$(".play").on('click', function(event) {
if ($('a').hasClass('stop')) {
$(".play").addClass("play").removeClass("stop");
} else {
$(".play").addClass("stop");
}
console.log('play');
});
});
</script>
html and css remain the same.
I have made a different right click context menu and want to include a 'Copy text' button, But I dont know what type of code to use. I have tried CopyText(this.form.txtSelect); but have not put it in properly/It isnt compatible, and also how would I would I remove the bullets, I tried changing it to something like <a> but it doesnt use the css style
Here is my current script:
JSfiddle
HTML:
TEST Text
<ul class='custom-menu'>
<li data-action = "first">Copy Text</li>
<li data-action = "second">Second thing</li>
<li data-action = "third">Third thing</li>
</ul>
Javascript:
function CopyText(el){
var selectedText = "";
if(window.getSelection){
selectedText = window.getSelection();
}else if (document.getSelection){
selectedText = document.getSelection();
}else if (document.selection){
selectedText = document.selection.createRange().text;
}
if(selectedText != ""){
selectedText = selectedText.toString();
el.focus();
el.value = selectedText;
}else {
alert("Select a text in the page and then press this button!");
}
}
// Trigger action when the contexmenu is about to be shown
$(document).bind("contextmenu", function (event) {
// Avoid the real one
event.preventDefault();
// Show contextmenu
$(".custom-menu").finish().toggle(100).
// In the right position (the mouse)
css({
top: event.pageY + "px",
left: event.pageX + "px"
});
});
// If the document is clicked somewhere
$(document).bind("mousedown", function (e) {
// If the clicked element is not the menu
if (!$(e.target).parents(".custom-menu").length > 0) {
// Hide it
$(".custom-menu").hide(100);
}
});
// If the menu element is clicked
$(".custom-menu li").click(function(){
// This is the triggered action name
switch($(this).attr("data-action")) {
// A case for each action. Your actions here
case "first": CopyText(this.form.txtSelect); break;
case "second": alert("second"); break;
case "third": alert("third"); break;
}
// Hide it AFTER the action was triggered
$(".custom-menu").hide(100);
});
CSS:
.custom-menu {
display: none;
z-index: 1000;
position: absolute;
overflow: hidden;
border: none;
white-space: nowrap;
font-family: sans-serif;
font-size: 12px;
background: #FAFCFD;
color: #6E6E6E;
border-radius: 0px;
}
.custom-menu li {
padding: 8px 6px;
cursor: pointer;
}
.custom-menu li:hover {
background-color: #49C1FF;
color: #FFFFFF;
}
While attaching a contextmenu event to a content-editable div filled with spelling mistakes, IE(11) is ignoring the callback and showing its own Spell-check menu.
jsbin: http://jsbin.com/favit/3/ (You should preview it, then edit the div, and you will see the problem)
Turning off Spell-check is not an option, because i can't tell clients to do so.
I came across this question on Google and I figured I would post an answer in case anyone else Googles this. This is how to add your own context menu on IE without disabling spellcheck. It even works when you right-click on an incorrectly-spelled word with a red underline beneath it.
Basically, there are 2 steps:
1) In the mousedown event, you need to disable spellcheck on the contenteditable element.
2) Afterwards, you re-enable spellcheck on the contenteditable element.
Below is a working example.
var editable = $('#editable');
var mouseX, mouseY;
$(document).mousemove(function(event) {
mouseX = event.pageX;
mouseY = event.pageY;
});
editable.mousedown(function(e) {
if (e.button == 2) {
editable.attr('spellcheck','false');
e.preventDefault ? e.preventDefault : e.returnValue = false;
e.stopPropagation();
return false;
}
return true;
});
editable.get(0).oncontextmenu = function(e) {
e.preventDefault ? e.preventDefault : e.returnValue = false;
return false;
};
editable.on("contextmenu", function(e) {
e.preventDefault ? e.preventDefault : e.returnValue = false;
e.stopPropagation();
if ($('#contextmenu').length == 0) {
$('<div>').attr('id', 'contextmenu').appendTo('body');
$('#contextmenu').css('z-index', 1000);
$('#contextmenu').css('position', 'absolute');
$('<ul>').appendTo('#contextmenu');
$('<li>').html('some').appendTo('#contextmenu ul');
$('<li>').html('text').appendTo('#contextmenu ul');
$('<li>').html('here').appendTo('#contextmenu ul');
}
$('#contextmenu').css('top', mouseY);
$('#contextmenu').css('left', mouseX);
$('#contextmenu li').click(function() {
$('#contextmenu').remove();
editable.attr('spellcheck','true');
});
});
#contextmenu {
border: 1px solid #000;
background-color: #fff;
padding: 5px;
}
#contextmenu ul {
list-style-type: none;
padding: 0px;
margin: 0px;
}
#contextmenu li {
cursor: pointer;
padding: 2px;
}
#contextmenu li:hover {
background-color: #2daade;
color: #fff;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="editable" contenteditable="true">Click me and type some badly spelled words.</div>
Got it:
Adding the attribute "spellcheck", setting its value to "false" has fixed it.
<div contenteditable="true" spellcheck="false">
example notaword
</div>