show an element only if contentEditable div is changed - javascript

$('#story').on('keypress', function(){
$('#btnsave').show();
});
#story{
background:gold;
min-height:54px;
padding:9px;
}
#btnsave{
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='story' contentEditable='true'>lorem ipsum</div>
<br>
<button id='btnsave'>SAVE</div>
I need to show btnsave only if story is changed.
kyedown and keyup don't work because of funcional and other keys included.
keypress seems to be ok, except backspace and delete - when pressing - nothing happens.
What to do?

Change
$('#story').on('keypress', function(){
$('#btnsave').show();
});
To
document.getElementById("story").addEventListener("input", function() {
$('#btnsave').show();
}, false);
OR
$('#story').on('input', (e) => {
$('#btnsave').show();
});
Working Demo: https://codepen.io/OtakunityJL/pen/vVOvxV

as comment above you need to change keypress to input, and if you want to show only #btnsave when it different with previous content save original content as variable, then compare.
var oldContent = $('#story').text();
var myTimeout;
$('#story').on('input', function() {
clearTimeout(myTimeout);
myTimeout = setTimeout(function() {
if ($('#story').text() != oldContent) {
$('#btnsave').show();
}
else{
$('#btnsave').hide();
}
}, 200)
});
$('#btnsave').on('click', function(){
oldContent = $('#story').text();
$('#btnsave').hide();
})
#story{
background:gold;
min-height:54px;
padding:9px;
}
#btnsave{
display:none;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id='story' contentEditable='true'>lorem ipsum</div>
<br>
<button id='btnsave'>SAVE</div>

you can store the contents to a variable and check if it is different after blur() event. If it is different, then it changed. http://jsfiddle.net/maxofpower/a4QNB/850/
another scenario is that user maybe press key but doesn't change anything...
var content = $('#story').html();
$('#story').blur(function() {
if (content!=$(this).html()){
alert('change() called.');
content = $(this).html();
}
});

To handle this kind is issue, you can trigger an event handler when the div with attribute contenteditable set to true loose the focus. Which can be done by setting an event handler on the blur event. The other way is to set a timer which wait a certain number of second in which a user doesn't type any thing on they keybord and manualy trigger disable the contenteditable and set the display property of the button to block
var story = document.querySelector('#story');
var btn = document.querySelector('#btnsave');
story.addEventListener('blur', function(event){
btn.style.display = "block";
});
#btnsave {
display: none;
}
#story{
background:gold;
min-height:54px;
padding:9px;
}
<div id='story' contentEditable='true'>lorem ipsum</div>
<br>
<button id='btnsave'>SAVE</div>

Related

Focus textarea on mobile from click event using jQuery .trigger()

Alrighty, I'm stuck.
I'm trying desperately to focus on a text area programmatically from javascript (jQuery) on mobile. I did my research, and learned that the only way to bring the keyboard up with .focus() is to use a click event. So I made a click event. And it works when I click on the element, except I need to trigger this from a touchhold on a different element. So naturally, I tried .trigger() and .triggerHandler() on the element. But neither of those things work.
TLDR; I need to be able to hold on an element from a list, and after a time, a div will slide down with a textarea and the textarea gets focus (with keyboard).
Any help is appreciated!
Here is my code:
<div class="quicknote" data-id="0">
<span>New Note</span>
<div class="name"></div>
<textarea class="text"></textarea>
<div class="toolbar">
<div class="left cancel">cancel</div>
<div class="right finish">finish</div>
</div>
</div>
jQuery
jQuery(document).ready(function($) {
var holdThresh = 800;
$(".row").on("touchstart", function(e) {
var id = $(this).attr("data-id");
var name = $(this).html();
$(this).addClass("down");
var timer = setTimeout(function() {
$(".quicknote").attr("data-id", id);
$(".quicknote .name").html(name);
$(".quicknote").addClass("open");
$(".quicknote").trigger("click");
e.preventDefault();
}, holdThresh);
$(this).one("touchend touchmove", function(event) {
$(this).removeClass("down");
clearTimeout(timer);
})
$(".quicknote .cancel").on("touchstart", function() {
$(".quicknote").removeClass("open");
})
$(".quicknote").click(function(event) {
$("textarea").focus();
event.preventDefault();
event.stopPropogation();
})
});
I figured it out! For anyone who finds this, here is my updated jQuery:
$(".row").on("touchstart", function(e) {
var id = $(this).attr("data-id");
var name = $(this).html();
var go = true;
var focus = false;
$(this).addClass("down");
var timer = setTimeout(function() {
go = false;
$(".quicknote").attr("data-id", id);
$(".quicknote .name").html(name);
$(".note").val("");
$(".quicknote, .overlay").addClass("open");
focus = true;
e.preventDefault();
}, holdThresh);
$(this).one("touchmove", function(event) {
go = false;
$(this).removeClass("down");
clearTimeout(timer);
});
$(this).one("touchend", function() {
if (go) window.location = "view.php?id=" + id;
else {
if (focus) {
$(".note").focus();
focus = false;
}
$(this).removeClass("down");
clearTimeout(timer);
}
})
})
I'm not sure exactly why this works, but instead of triggering a click on a third element to then focus on the textarea, I set a flag "var focus", and based on some conditions, was able to focus the textarea from the touchend event. Hope this helps someone! :)

Avoid loosing focus in children

Feel free to edit the question title if you find something better.
I am writing a little plugin for my website,
var main = document.getElementById("main"),
fakeInput = document.getElementById("fakeInput"),
zone = document.getElementById("zone"),
input = document.getElementById("input");
main.addEventListener("focusin", function() {
zone.style.display = "block";
});
main.addEventListener("focusout", function() {
zone.style.display = "none";
});
#main {
width: 200px;
}
#fakeInput {
background: blue;
height: 22px;
}
#zone {
background-color: red;
height: 100px;
text-align: center;
}
click in the blue zone :<br>
<div id="main" tabindex="-1">
<div id="fakeInput"></div>
<div id="zone" style="display:none">
<p>Click in the input :</p>
<input id="input" type="text" />
</div>
</div>
when I click on it, it opens (great !). I can click (almost) anywhere, the "focusout" event is not triggered.
Almost, because the input child steal the focus to its parent.
I read here : http://www.quirksmode.org/dom/events/blurfocus.html
focusin and focusout
Fire at the same time as focus and blur, but bubble
In my example, It seems that the focusin event of the input field never reach its parent.
I am looking for a way to fix this, any hints ?
The focusout event is sent to an element when it, or any element
inside of it, loses focus. This is distinct from the blur event in
that it supports detecting the loss of focus from parent elements (in
other words, it supports event bubbling).
Therefore there is a difference between this.
main.addEventListener("focusin", function() {
zone.style.display = "block";
});
main.addEventListener("focusout", function() {
zone.style.display = "none";
});
And this.
main.addEventListener("focus", function() {
zone.style.display = "block";
});
main.addEventListener("blur", function() {
zone.style.display = "none";
});
See this JSFiddle.
In my example, It seems that the focusin event of the input field never reach its parent.
In fact it does. Try to add some debug:
main.addEventListener("focusin", function(event) {
console.log('focusin', event.target)
zone.style.display = "block";
});
main.addEventListener("focusout", function(event) {
console.log('focusout', event.target)
zone.style.display = "none";
});
and you'll see

Prevent click after focus event

When user clicks on input field, two consecutive events are being executed: focus and click.
focus always gets executed first and shows the notice. But click which runs immediately after focus hides the notice. I only have this problem when input field is not focused and both events get executed consecutively.
I'm looking for the clean solution which can help me to implement such functionality (without any timeouts or weird hacks).
HTML:
<label for="example">Example input: </label>
<input type="text" id="example" name="example" />
<p id="notice" class="hide">This text could show when focus, hide when blur and toggle show/hide when click.</p>
JavaScript:
$('#example').on('focus', _onFocus)
.on('blur', _onBlur)
.on('click', _onClick);
function _onFocus(e) {
console.log('focus');
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
$('#notice').removeClass('hide');
}
function _onClick(e) {
console.log('click');
$('#notice').toggleClass('hide');
}
function _onBlur(e) {
console.log('blur');
$('#notice').addClass('hide');
}
UPDATED Fiddle is here:
I think you jumbled up the toggles. No need to prevent propagation and all that. Just check if the notice is already visible when click fires.
Demo: http://jsfiddle.net/3Bev4/13/
Code:
var $notice = $('#notice'); // cache the notice
function _onFocus(e) {
console.log('focus');
$notice.removeClass('hide'); // on focus show it
}
function _onClick(e) {
console.log('click');
if ($notice.is('hidden')) { // on click check if already visible
$notice.removeClass('hide'); // if not then show it
}
}
function _onBlur(e) {
console.log('blur');
$notice.addClass('hide'); // on blur hide it
}
Hope that helps.
Update: based on OP's clarification on click toggling:
Just cache the focus event in a state variable and then based on the state either show the notice or toggle the class.
Demo 2: http://jsfiddle.net/3Bev4/19/
Updated code:
var $notice = $('#notice'), isfocus = false;
function _onFocus(e) {
isFocus = true; // cache the state of focus
$notice.removeClass('hide');
}
function _onClick(e) {
if (isFocus) { // if focus was fired, show/hide based on visibility
if ($notice.is('hidden')) { $notice.removeClass('hide'); }
isFocus = false; // reset the cached state for future
} else {
$notice.toggleClass('hide'); // toggle if there is only click while focussed
}
}
Update 2: based on OP's observation on first click after tab focus:
On second thought, can you just bind the mousedown or mouseup instead of click? That will not fire the focus.
Demo 3: http://jsfiddle.net/3Bev4/24/
Updated code:
$('#example').on('focus', _onFocus)
.on('blur', _onBlur)
.on('mousedown', _onClick);
var $notice = $('#notice');
function _onFocus(e) { $notice.removeClass('hide'); }
function _onClick(e) { $notice.toggleClass('hide'); }
function _onBlur(e) { $notice.addClass('hide'); }
Does that work for you?
Setting a variable for "focus" seems to do the trick : http://jsfiddle.net/3Bev4/9/
Javascript:
$('#example').on('focus', _onFocus)
.on('click', _onClick)
.on('blur', _onBlur);
focus = false;
function _onFocus(e) {
console.log('focus');
$('#notice').removeClass('hide');
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
focus = true;
}
function _onClick(e) {
console.log('click');
if (!focus) {
$('#notice').toggleClass('hide');
} else {
focus = false;
}
}
function _onBlur(e) {
console.log('blur');
$('#notice').addClass('hide');
}
If you want to hide the notice onBlur, surely it needs to be:
function _onBlur(e) {
console.log('blur');
$('#notice').addClass('hide'); // Add the hidden class, not remove it
}
When doing this in the fiddle, it seemed to fix it.
The code you have written is correct, except that you have to replae $('#notice').removeClass('hide'); with $('#notice').addClass('hide');
Because onBlur you want to hide so add hide class, instead you are removing the "hide" calss.
I hope this is what the mistake you have done.
Correct if I am wrong, Because I don't know JQuery much, I just know JavaScript.
you can use many jQuery methods rather than add or move class:
Update: add a params to deal with the click function
http://jsfiddle.net/3Bev4/23/
var showNotice = false;
$('#example').focus(function(){
$('#notice').show();
showNotice = true;
}).click(function(){
if(showNotice){
$('#notice').show();
showNotice = false;
}else{
showNotice = true;
$('#notice').hide();
}
}).blur(function(){
$('#notice').hide();
});

How to exclude Id from focusout

With Jquery, focusout is just called when you click anywhere out of the focused area when "focusout" is set.
How do I exclude some id(s) from activiting the "focusout" function. ?
e.g here.
You have an input text field ( id="A")that hides some div on focus and shows that very div when it's out of focus, so but now it obviously will show the div when you click anywhere out of this ("#A") input field.
Question is, how do you set some id(maybe a select field(Id="B" next to it), not to fire off the "focusout" function. Hope it makes sense.
Try using relatedTarget event property:
$('#id').focusout (function (e) {
if (e.relatedTarget && e.relatedTarget.id === 'dontFocusOut') {
return;
}
//do your thing
});
You can unbind the focusout when you click on a div. This may return some expected results, and at some point in your code you'll probably want to rebind it. See here for an example: http://jsfiddle.net/hdCFA/
$("input").on("focus", function() {
$(".hidden").show();
});
$("input").on("focusout",function() {
$(".hidden").hide();
});
$(".clickable").on("mousedown", function() {
$("input").unbind("focusout");
});
HTML:
<input />
<div class="hidden">Hidden div</div>
<div class="clickable">Click me</div>
CSS:
.clickable { background:blue; }
.hidden {
display:none;
}

How to close a javascript menu

I'm creating pulldown menus that must be clicked on to open. This code lets the user opening menus just fine. The only problem is I haven't figured out how to close the menus yet by clicking outside the menus. I tried adding the "document.onclick" shown, but it takes effect even in the menus.
I think I need to prevent document.onclick from being captured by other elements, but am not sure how to do this cross-platform. Can someone please show me how?
<script type="text/javascript">
var lastOpenedMenuId = null;
function showMenu(menuId) {
if (lastOpenedMenuId != null && lastOpenedMenuId != menuId) {
hideLastOpenedMenu();
}
setMenuVisibility(menuId, 'visible');
lastOpenedMenuId = menuId;
}
function hideMenu(menuId) {
setMenuVisibility(menuId, 'hidden');
}
function hideLastOpenedMenu() {
if (lastOpenedMenuId != null) {
hideMenu(lastOpenedMenuId);
}
}
function setMenuVisibility(menuId, visibleOrHidden) {
var menuElement = document.getElementById(menuId);
menuElement.style.visibility = visibleOrHidden;
}
document.onclick = hideLastOpenedMenu;
</script>
<div onmousedown="showMenu('foodmenu')"><a>FOOD</a></div>
<div id="foodmenu" onmouseup="hideMenu('foodmenu');">
Meat
Tofu
</div>
Thanks in advance.
I have made some progress and have reformulated the question here:
How to stop onclick event in div from propagating to the document?
Depending on whether you have a page layout like this:
<body>
<div id="menu"><!--Menu Stuff--></div>
<div id="main"><!--Main page stuff--></div>
</body>
you could put the onClick handler to close the menu on the div with the id "main" which should work
Someone pointed me to a solution that uses addEventListener. Say, the div is the menu. This code allows the user to click on the document outside the div to do something, such as close the menu. Clicking on the div (say, on a link) will not propagate to the document.
<head>
<script>
function menuHandler(event) {
alert("div clicked");
// Don't propogate the event to the document
if (event.stopPropagation) {
event.stopPropagation(); // W3C model
} else {
event.cancelBubble = true; // IE model
}
}
document.onclick = function() {
alert('document clicked');
};
function addListener() {
var foodMenuElement = document.getElementById('foodmenu');
if (foodMenuElement.addEventListener) {
foodMenuElement.addEventListener('click', menuHandler, false);
} else {
foodMenuElement.attachEvent('onclick', menuHandler);
}
}
</script>
</head>
<body onload="addListener()">
<div id="foodmenu" style="border: 1px solid red;">Click inside this div</div>
or click outside the div.
</body>
Note that the third argument "false" to addEventListener means "fire the event during the capturing phase", but the value doesn't matter because the event propagation is canceled in menuHandler.
This solution works, but I'd like to do the same thing more simply, without addEventListener, so have posted a question at How to stop onclick event in div from propagating to the document?

Categories