Probably simple answer for the ones who know JS, but I am unable to figure it out.
Current situation is that I am using a button to trigger a emoji window, it looks as follows:
<button><i class="fas fa-smile"></i></button>
<script>
new FgEmojiPicker({
trigger: ['button'],
position: ['top', 'right'],
emit(obj, triggerElement) {
const emoji = obj.emoji;
document.querySelector('textarea').value += emoji;
}
});
</script>
This is working but the downside is that a button is surrounding my smiley icon - makes sense of course since I am using <button>.
Is there a way to trigger this even without a button? Something like:
<i class="fas fa-smile"></i>
There is no reason for you to use 'onclick' or some other type of javascript event. Instead of using this event (onclick="FgEmojiPicker") you have to insert the selector of your element you want to run emojiPicker function with, at this point - 'myemoji'. It should look like this -
<i class="fas fa-smile"></i>
<script>
new FgEmojiPicker({
trigger: ['#myemoji'],
position: ['top', 'right'],
emit(obj, triggerElement) {
const emoji = obj.emoji;
document.querySelector('textarea').value += emoji;
}
});
So instead of this event 'onclick="FgEmojiPicker"' you are doing this - trigger: ['#myemoji'].
Related
I am making a quick throw-together website that requires users to be able to interact with a button to execute a delete action.
I have my button (code is shown below) where I have a basic bootstrap button paired with an icon (provided by their library) in which the user clicks to delete an "Infraction"
<button
referencedInfraction="<%= i.infractionID %>"
targetUserID="<%= i.userID %>"
class="deleteButton btn btn-danger"
>
<i class="bi bi-trash-fill"></i>
</button>
The infraction that the user wants to delete is passed through an attribute to the code below.
$(".deleteButton").click((event) => {
$("#confirmDeleteSingleInfractionModal").modal("toggle");
let data = {
infractionID: $(event.target).attr("referencedInfraction"),
targetUserID: $(event.target).attr("targetUserID"),
};
console.log(data);
$("#confirmDeleteSingleInfractionModal").on("hide.bs.modal", function () {
console.log("deleting");
$.ajax({
type: "delete",
url: `${window.location.origin}/dataLink/infraction`,
data,
success: () => {
console.log("done");
},
error: () => {
showInfractionDeleteError();
},
});
});
});
However, I've run into a bit of an issue. I notice that the only way for the user to actually click the button is if they click around the edges where the <I> element is not present.
Is there any way to prevent this from showing in event.target()?
All I want is the custom attribute from the button clicked, not the image.
Any help would be appreciated.
If you set pointer-events: none on the element with the icon that should prevent the click event from firing on it and instead use the button, allowing you to get the data attributes. Example:
.bi-trash-fill {
pointer-events: none
}
Or whatever element/class makes sense for your application. This allows the user to click anywhere on the button (including on the icon) and the event will fire getting the attributes from the button.
You can check if the element which is been clicked is i tag or button and depending on this change your selector to get required data.
Demo Code :
$('.deleteButton').click((event) => {
console.log(event.target.tagName.toLowerCase())
//get tag which is clicked change selector if needed
var target = event.target.tagName.toLowerCase() === 'button' ? $(event.target) : $(event.target).parent()
//$('#confirmDeleteSingleInfractionModal').modal('toggle');
let data = {
infractionID: target.attr('referencedInfraction'),
targetUserID: target.attr('targetUserID')
}
console.log(data);
//other codes..
});
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.1.0/css/all.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.1.0/css/v4-shims.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button referencedInfraction="1" targetUserID="12" class="deleteButton btn btn-danger"> <i class="fas fa-heart"></i> </button>
<button referencedInfraction="2" targetUserID="13" class="deleteButton btn btn-danger"><i class="fas fa-heart"></i> </button>
The best way to work around this is to add a function to the icon <i></i> that is called once it is clicked and inside this function you can call the same function called by clicking on the button <button></button> itself. Also you can pass the same data from the icon element <i></i> to its function to be used in the button function.
note: you don't want to prevent clicking on the icon because it will be a bad UX (user experience) but actually you want to use it for the right purpose.
I've a HTML code like this.
<a onclick="prompt('Complete','Lorem');">Lorem</a>
<a onclick="prompt('Complete','ipsum');">ipsum</a>
<a onclick="prompt('Complete','dolor');">dolor</a>
<a onclick="prompt('Complete','sit');">sit</a>
<a onclick="prompt('Complete','amet');">amet</a>
...
I want to minify HTML code, like this: <a>Lorem</a><a>ipsum</a>How can I add onclick prompt event to all clickable elements in a page? as in the above code. Is it possible?
Using JavaScript, you have to attach the click handler to each item with a loop.
function userPrompt(event){
prompt("Complete " + event.target.innerText);
}
document.querySelectorAll('a').forEach(item => item.addEventListener('click', userPrompt));
a {
cursor: pointer
}
<a>Lorem</a>
<a>ipsum</a>
<a>dolor</a>
<a>sit</a>
<a>amet</a>
JQuery has a simple way of achieving this.
function userPrompt(event){
prompt("Complete " + event.target.innerText);
}
$('a').on('click', userPrompt);
a {
cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<a>Lorem</a>
<a>ipsum</a>
<a>dolor</a>
<a>sit</a>
<a>amet</a>
Like pointed out, addEventListener is your friend here.
One major advantange of addEventListener compared to say a normal onClick, is that any elements added to the DOM later will also be taken into account, and is also possible to add multiple event listeners to the same element.
Below is a simple example. I basically add the eventListener to the body, filter out any elements that are not A links, and then show a prompt for the user to change the innerText of this element.
document.body.addEventListener("click", (e) => {
//lets limit to just A links
if (e.target.tagName !== "A") return;
const ret = prompt("Confirm", e.target.innerText);
if (ret !== null) {
e.target.innerText = ret;
}
});
a {
text-decoration: underline;
cursor: pointer;
}
<div>Click a link to change the innerText</div>
<a>Lorem</a>
<a>ipsum</a>
<a>dolor</a>
<a>sit</a>
<a>amet</a>
// select all <a> tags
document.querySelectorAll('a')
// loop over them
.forEach(a =>
// append the event by calling addEventListener
a.addEventListener('click', () => window.prompt('Complete', 'Lorem')))
The forEach can take a second argument, the index, so you can define the message on each prompt according to the value of an array.
const promptValue = [
'Lorem',
'ipsum',
'dolor',
'sit',
'amet'
]
document.querySelectorAll('a').forEach((a, i) =>
a.addEventListener('click', () => window.prompt('Complete', promptValue[i])))
Edit: I should probably add that this may become hard to maintain if the list changes order in the future, so it's probably better to keep some reference to the prompt value in the HTML, even if it gets verbose. Nevertheless, it's bad to keep scripts in the HTML, so a data attribute might be a better approach.
HTML:
<a data-prompt="Lorem">Lorem</a>
<a data-prompt="ipsum">ipsum</a>
<a data-prompt="dolor">dolor</a>
<a data-prompt="sit">sit</a>
<a data-prompt="amet">amet</a>
JS:
document.querySelectorAll('a').forEach(a =>
a.addEventListener('click', () => window.prompt('Complete', a.dataset.prompt)))
I would like to change my icon from expand_more to expand_less in following code
<li class="dropdown-bt" onclick="dropdown('content');">
<a>dropdown-content <i class="material-icons">expand_more</i></a>
</li>
I am going to use same code multiple times so it would be better to using function multiple times. I thought of using ID for every piece of code but it would be to hectic. So I want to write single function do it but I don't know how, so please help.
Just pass an object event as a parameter, say e to your dropdown() and use the textContent property to retrieve the current element content, check it's value and replace the content with another text content like this:
var btn = document.getElementById("dropdownBt");
function dropdown(e) {
var innerText = e.target.children[0];
if(innerText.textContent == "expand_more") {
innerText.textContent = "expand_less";
} else {
innerText.textContent = "expand_more";
}
}
btn.addEventListener('click', dropdown);
<li class="dropdown-bt" id="dropdownBt"><a>dropdown-content <i class="material-icons">expand_more</i></a></li>
I am trying to create and initialize multiple popovers, using the same code. The html element is being created in JS-
var panel = ('<a href="javascript://" id= "'+popId+'" data-title="xyz" >');
popId is a unique value for each so the ids getting assigned are unique
Next I am calling the following function-
createPopOver("#"+popId,<another_arg>);
The create function looks like this-
function createPopOver(selector,<another_arg>) {
$(selector).popover({
trigger: 'click',
placement : 'left'
}).on('shown.bs.popover', function () {
console.log("reached here1"+selector);
...
});
}
debugging through the control goes to the function however not inside the shown event and so the console does not print anything.
If I give an id="xyz" so now all the popovers have the same id, the very first popover will show up on clicking but with incorrect text (the content to display is being computed in the create popover function).
Be careful when you create your popovers and when you initialize them.
function createPopOver(selector,another_arg) {
console.log(selector);
//$(selector).popover();
$('[data-toggle="popover"]').popover({
}).on('shown.bs.popover', function () {
console.log("reached here1"+selector);
});
}
$(document).ready(function(){
var panel = $('<p><a href="javascript://" id= "123" data-toggle="popover" title="Popover title" data-content="And here\'s some amazing content. It\'s very engaging. Right?" >123</a></p>');
$('body').append(panel);
panel = $('<p><a href="javascript://" id= "234" data-toggle="popover" title="Popover title 234" data-content="And here\'s some amazing content. It\'s very engaging. Right? 234" >234</a></p>');
$('body').append(panel);
panel = $('<p><a href="javascript://" id= "345" data-title="xyz" >345</a></p>');
$('body').append(panel);
panel = $('<p><a href="javascript://" id= "456" data-title="xyz" >456</a></p>');
$('body').append(panel);
createPopOver("#123",'');
createPopOver("#234",'');
createPopOver("#456",'');
});
https://jsfiddle.net/v761q32b/
First of all, I have a strong feeling that you are initializing popover by calling createPopOver function, before you attach elements to DOM, which ain't gonna work. Because event's can be attached to the elements only when it gets attached to the DOM. Alongside, id isn't necessary to attach popover. You can make use of class which can be given to multiple elements, or you can make use of rel or data-* attributes.
var panel = ('<a href="javascript://" id= "'+popId+'" rel="popover" data-title="xyz" >');
Now you can write createPopOver function without the selector argument and popover has selector option where you can specify the selector and attach the popover to body.
function createPopOver(<another_arg>) {
$('body').popover({
trigger: 'click',
placement : 'left',
container: 'body',
selector: '[rel="popover"]', //considering rel as common attribute here
}).on('shown.bs.popover', function () {
console.log("reached here1"+$(this).attr('id'));
...
});
}
You can call createPopOver once your contents of panel variable gets attached to the DOM.
There are various other ways to work on with. Do refer this answer for a detailed explanation on other options.
I have a div generated via JS with a button in it which I want to make clickable only with a mouse, no manual link following should be possible.
Q1: Is there a way to make the button clickable only if the mouse cursor is inside the div?
<div class='modal-body' style='padding-top: 10px'>
<a href='?hash="+hash+"' class='btn btn-success btn-xs cbut "+hash+"'><span class='glyphicon glyphicon-forward "+hash+"'></span></a>
</div>
To prevent automated scripts from following the link such as iMacros, I have added the "hash" variable to the link name and class which is now random.
Even so they can follow the link by adding a * wildcard in the macro script. So I'm outta ideas here.
Q2: Is there a definitive way to restrict link following to mouse only?
Add an event handler on your div with AddEventListener and the mouseover event.
When the event is triggered add the href attr to your <a> link. And remove the attr on mouseout.
Do not use the <a href inside it>, use javascript onclick, or jquery on
$('div.modal-body').on('click',function(){
window.location = "yourlink"
})
Probably something like this may work.
Basically you watch the cursor position on each click and check if it's inside $('#demo-box'). Otherwise you can e.stopPropagation() and/or e.preventDefault().
Not sure if this will work because I don't know if macro scripts actually move the mouse. If it does, you can throttle or debounce the clicks shorter than 20-30ms. More info on debouncing here.
var $demo_box = $('#demo-box');
var demo_box_width: $demo_box.outerWidth();
var demo_box_height = $demo_box.outerHeight();
var demo_box_offset = $demo_box.offset();
$("#button").on('click', function(e) {
var relativeX = (e.pageX - demo_box_offset.left);
var relativeY = (e.pageY - demo_box_offset.top);
if (relativeX > 0 && relativeY > 0 && relativeX < demo_box_width && relativeY < demo_box_height) {
alert("X: " + relativeX + " Y: " + relativeY);
}
});
So here's how I made it work for me:
1) Wrap the button inside an invisible element
2) Remove the link and add it via the onclick event
3) Disable the button by default
<span style="position:relative;">
<input type="button" onclick="document.location.href='?hash'" class="btn btn-success btn-xs" value="❯❯">
<div style="position: absolute; left: 0px; right: 0px; top: 0px; bottom: 0px; cursor: default; display: none;" id="catch"></div>
</span>
4) Remove the invisible element which also triggers the re-enabling of the disabled button from within the target div:
$("#catch").mouseover(function (evt) {
$(this).hide().prev("input[disabled]").prop("disabled", false).focus();
});
This way the button can no longer be targeted or activated unless the mouse cursor is placed over it.
I've already beaten current iMacro scripts so this will do for now.
LE: Spoke too soon, seems iMacros was able to target the button quite easily. However I also came up with a quick fix by adding a simple timeout for my function:
$("#catch").mouseover(function (evt) {
var $this = $(this)
setTimeout(function () {
$this.hide().prev("input[disabled]").prop("disabled", false).focus();
}, 1000);
});
Thank you for all the inputs here which really kept me going.