The JSFiddle speaks for itself
Open this fiddle http://jsfiddle.net/NfRN5/
Click the input field
Change tabs on your browser
Come back to the fiddle - the width effect will run again =/
Is there a way to prevent this and make it steady when the user navigates away and comes back?
To view the problem in this thread, you will need to click the "Expand snippet" button. The small preview doesn't demonstrate the issue in question.
input.search-field {
width: 100px;
transition: all 1s ease-in-out;
}
input.search-field:focus {
width: 300px;
}
<input type="search" class="search-field">
In chat you mentioned you were trying to emulate Apple.com's search bar.
After peaking at their JS, I came up with this fiddle: http://jsfiddle.net/NfRN5/7/
The trick is to only blur the input in the 10ms following a mousedown, or some keypresses.
var $search = $('.search-field'), searchBlurable = false
$search
// Always focus when focused
.focus(function(e){
$search.addClass('focused')
searchBlurable = false
})
// Only blur after mouse or key events
.blur(function(e){
if(searchBlurable){
$search.removeClass('focused')
}
})
// Set Blurable for tab/esc
.keydown(function(e){
if(e.keyCode === 27 || e.keyCode === 9) { // esc || tab
searchBlurable = true
$search.blur()
}
})
// Set Blurable for 10ms after a mousdown
$('html').mousedown(function(e){
searchBlurable = true
window.setTimeout(function () {
searchBlurable = false
}, 10)
})
I don't believe that can be achieved in pure CSS.
Try some JavaScript / jQuery: http://jsfiddle.net/NfRN5/3/
var $fields = $(".search-field")
$fields.focus(function(){
$fields.removeClass('focused')
$(this).addClass('focused')
})
You can't use the blur event because that is called by the browser when you change tabs.
I made some assumptions about what the rest of the code in your app will look like, you might have to add some other triggers to remove the focused class.
I use a complementary class to handle it.
Add the "focus" class to the active element when the window loses focus (window.blur) and remove the class when it gets focus back.
window.addEventListener("focus", function () {
document.querySelectorAll(".focus").forEach((el) => {
el.classList.remove("focus");
}, false);
});
window.addEventListener("blur", function () {
let el = document.activeElement;
if (el !== null) el.classList.add("focus");
}, false);
input.search-field {
width:100px;
transition: all 1s ease-in-out;
}
input.search-field:focus,
input.search-field.focus {
width:300px;
}
<input type="search" class="search-field">
Related
Working on an Angular 14 application, I want all context menu pop-ups to be only 80% of their size, as the default size is too large and clunky in the context of the data presented in the application. This is working fine to accomplish this:
.cdk-overlay-pane .mat-menu-panel {
transform: scale(0.8);
transform-origin: top left;
}
However, the problem is that the context menu appears at full size for a moment, and then the transform takes effect and it "snaps" to the desired size. I don't want it to appear until the transform is complete. Anybody know how to accomplish this?
I was able to do this by defaulting mat-menu-panel to visibility: hidden, then showing it a fraction of a second after the menu is opened. (I don't like using javascript like this within the context of an Angular app, but I don't know any other way.)
Default CSS:
.mat-menu-panel {
visibility:hidden;
}
Showing after menu is opened:
public onContextMenu(event: MouseEvent, item: any) {
event.preventDefault();
this.contextMenuPosition.x = event.clientX + 'px';
this.contextMenuPosition.y = event.clientY + 'px';
this.matMenuTrigger.menuData = { 'item': item };
this.matMenuTrigger.menuOpened.subscribe(() => {
setTimeout(() => {
const overlayPanes = document.getElementsByClassName('mat-menu-panel') as HTMLCollectionOf<HTMLElement>;
Array.from(overlayPanes).forEach((el) => {
el.style.visibility = 'visible';
});
}, 200);
});
this.matMenuTrigger.openMenu();
}
By adding :
.scroll {
-webkit-user-select: text !important;
-moz-user-select: text !important;
-ms-user-select: text !important;
user-select: text !important;
}
I can select text on desktop browsers except on IE.
I figure out that when I comment my import :
//require('ionic-npm/js/ionic');
On IE I can select text but I need ionic so I can't comment that line. Also I don't what to touch to ionic.js.
Do you have any idea?
I found an answer here:
forum.ionicframework: How to make text selectable?
Link: Original forum Post
Are you referring to using this technique on mobile or desktop?
On mobile it still seems to be working for me, but If it isn't working for you on desktop, that might be because it doesn't work if the user can use their mouse to click-and-drag to scroll the page. To disable this type of scrolling you can either enable overflow-scroll on your content:
<ion-content overflow-scroll="true">
Or you can disable the mouse click-and-drag-to-scroll events by further changing ionic.js like so...
Add 'return;' to the beginning of this mouseDown function:
self.mouseDown = function(e) {
if ( ionic.tap.ignoreScrollStart(e) || e.target.tagName === 'SELECT' ) {
return;
}
self.doTouchStart(getEventTouches(e), e.timeStamp);
if( !ionic.tap.isTextInput(e.target) ) {
e.preventDefault();
}
mousedown = true;
};
So that it looks like this:
self.mouseDown = function(e) {
return; // <--- This disables all mouseDown events from scrolling the page
if ( ionic.tap.ignoreScrollStart(e) || e.target.tagName === 'SELECT' ) {
return;
}
self.doTouchStart(getEventTouches(e), e.timeStamp);
if( !ionic.tap.isTextInput(e.target) ) {
e.preventDefault();
}
mousedown = true;
};
This change makes it so you can still use the ionic scroll features with your mouse wheel, but disables mouse click-and-drag scrolling so that you can use your mouse to select text.
I'm trying to create a drop down list directive, with down-arrow that appears when the mouse is hovering the dropdown header or when the dropdown list is oppend, and disappears otherways.
I succeeded to do this, but if the dropdown list is closed not by selecting element or by pressing on the header list again, than the arrow isn't disappead.
(I.E. If i'm openning one list and than openning another without closing the first one, than arrow of the first list is not disappearing)
JsFiddle - http://jsfiddle.net/rpg2kill/uS4Bs/
code:
var myApp = angular.module('myApp', ['ui.bootstrap']);
function MyCtrl($scope) {
$scope.supportedList= ['Option1', 'Option2', 'Option3', 'Option4'];
$scope.selectedItem = 'Option1';
}
myApp.directive('dropDown',
function () {
return {
restrict: 'E',
replace: false,
scope: {
supportedList:'=',
selectedItem:'='
},
template:
'<div ng-mouseenter="onMouseEntered()" ng-mouseleave="onMouseLeft()">' +
'<a class="dropdown-toggle" data-toggle="dropdown" href="" ng-click="onMouseClicked()" >' +
'<img ng-style="{\'visibility\': dropDownIconVisibility}" src="http://png.findicons.com/files/icons/2222/gloss_basic/16/arrow_down.png"> </img>' + //Arrow down Icon
'<span>{{selectedItem}}</span>' +
'</a>' +
'<ul class="dropdown-menu">' +
'<li ng-repeat="item in supportedList" ng-click="onSelectedItem(item)">' +
'{{item}}' +
'</li>' +
'</ul>' +
'</div>'
,
link: function(scope, element, attrs) {
scope.dropDownIconVisibility = "hidden";
scope.dropDownIconVisibilityLocked = false;
scope.onSelectedItem = function(item) {
scope.dropDownIconVisibilityLocked = false;
scope.selectedItem = item ;
};
scope.onMouseEntered = function()
{
scope.dropDownIconVisibility = "visible";
};
scope.onMouseLeft = function()
{
if (scope.dropDownIconVisibilityLocked)
return;
scope.dropDownIconVisibility = "hidden";
};
scope.onMouseClicked = function()
{
scope.dropDownIconVisibility = "visible";
scope.dropDownIconVisibilityLocked = !scope.dropDownIconVisibilityLocked;
};
}
};
})
The code is little ugly. A better solution is to show the arrow if the mouse is hovering OR the list is openned, but I don't know how to bind angular to the state of the dropdown list.
Is there a way to binding angular to Twitter bootstrap's dropdown event?
Or is there a better way to solve this problem?
I suggest you using full CSS approach - it takes less code, it does not trigger JS evaluations, thus, it performs better (Angular is a bit slow with all its cool features). Once you go mobile - CSS will be more preferable, as supports downgrading with media queries and so on... There are too many pros!
Remove all your mouse-tracking code and add just two CSS rules and here you go:
a.dropdown-toggle img {
visibility: hidden;
}
a.dropdown-toggle:hover img {
visibility: visible;
}
I succeeded to solve the problem, unfortunately the solution is not so pretty, but at least it works.
I'll try to solve this with only CSS as madhead suggested.
The problem was that I didn't know when the user clicked outside the dropdown, that caused the dropdown popup to close but the icon was still displayed. So I attached an handler to each directive that listen on document.click event and hides the Icon.
document.addEventListener('click', function (event) {
scope.$apply(function () {
scope.hideDropdownIcon();
});
}, false);
That worked, but if I clicked on another Dropdown when the current dropdown was opened, the document.click event was not fired. So I had to create my event and attach it to $window and to call it when any dropdown is opens.
var event = new Event('hideDropDownIcon');
$window.addEventListener('hideDropDownIcon', function (e) {
scope.hideDropdownIcon();
}, false);
You can see it here:
http://jsfiddle.net/rpg2kill/uS4Bs/6/
There must be a better solution. So if you know how to do it better or by using only css, I would like to know.
Thanks.
Found CSS solution to the problem.
css is so simple instead all the js events..
The CSS:
a.dropdown-toggle img {
visibility: hidden;
}
li.ng-scope:hover img,li.ng-scope:active img,.open a img{
visibility: visible;
}
You can check this: http://jsfiddle.net/rpg2kill/HVftB/1/
I'm trying to make the upper panel of my application to have top property to be -80px by default so it's invisible except of a small part of it. And when the user hover with his mouse on that part, it slides down again.
The problem is, this div has a textbox, i want the div to stop sliding up when the user is typing on this textbox even if he move his mouse pointer away, but unfortunately don't know how to do this, here's my code :
index.html
<div id="taskInput">
<div id="controllers">
<input type="text" name="mainTask" id="mainTask">
<button id="addMain">Add</button>
<button id="resetMain">Reset</button>
</div>
</div>
css of this part :
#taskInput {
background: red;
width:606px;
height:43px;
padding: 22px;
box-shadow: 0px 3px 4px -3px black;
position: absolute;
z-index : 0;
top:0px;
}
script.js
$(function(){
$("#taskInput").delay(400).animate({top:-80}, 500,function(){});
$("#taskInput").mouseover(
function(){
$(this).stop().animate({top:0}, 200, function(){});
});
$("#taskInput").mouseout(function(evt){
$(this).stop().animate({top:-80}, 200, function(){});
})
$("#mainTask").focus(function(){
//i though i can put something here to stop mouseout event or something
})
})
I've changed my mind from my comment, there's no need to unbind the events or use a global variable to track it. You can use document.activeElement to get the currently focused element on the page, and compare its id to the id of your <input>, like so:
$("#taskInput").mouseout(function(evt){
if(document.activeElement.id !== 'mainTask') {
$(this).stop().animate({top:-80}, 200, function(){});
}
});
Working DEMO
add a flag to the animate to top and change it in the focus function
i have not tested this but it should work
$(function(){
writing = false;
$("#taskInput").delay(400).animate({top:-80}, 500,function(){});
$("#taskInput").mouseover(
function(){
$(this).stop().animate({top:0}, 200, function(){});
});
$("#taskInput").mouseout(function(evt){
if(writing == false){
$(this).stop().animate({top:-80}, 200, function(){});
}
})
$("#mainTask").focus(function(){
//i though i can put something here to stop mouseout event or something
writing = true
})
$("#mainTask").focusout(function(){
//i though i can put something here to stop mouseout event or something
writing = false
})
})
jsFiddle DEMO
Easiest way is to give the #mainTask a data-focus attribute set to true, then when doing the mouseout on #taskInput, make sure it is False before animating the slideUp.
$(function(){
// ... code
$("#taskInput").mouseout(function(evt){
console.log($('#mainTask').data('focus'));
if ($('#mainTask').data('focus') === false) {
$(this).stop().animate({top:-80}, 200, function(){});
}
})
$("#mainTask").on({
focus: function(){
$(this).data('focus', true);
},
blur: function () {
$(this).data('focus', false);
}
});
})
I guess, you could also give this a try:
$('#taskInput').delay(400).animate({top:-80},500);
$('#taskInput').mouseover(function()
{
$(this).stop().animate({top:0},200);
});
$('#taskInput').mouseout(function()
{
if(!$('#mainTask').is(':focus'))
{
$(this).stop().animate({top:-80},200);
}
});
DEMO
Edit:
You could also add this to your code:
$('#mainTask').blur(function()
{
$('#taskInput').stop().animate({top:-80},200);
});
DEMO 2
in the $("#mainTask").focus event handler you can set a global boolean variable to true, set it to false in an blur event handler and check on the value of that variable in the #taskInput mouseout event handler
var preventSlide = false;
$("#taskInput").mouseout(function(evt){
if (!preventSlide) {
$(this).stop().animate({top:-80}, 200, function(){});
}
})
$("#mainTask").focus(function(){
preventSlide = true;
})
$("#mainTask").blur(function(){
preventSlide = false;
})
$(function(){
var flag=true;
$("#taskInput").on('mouseenter mouseleave', function(e) {
if (flag) $(this).stop().animate({top: e.type=='mouseenter'?0:-80}, 200);
}).delay(400).animate({top:-80}, 500);
$("#mainTask").on('blur focus', function(e) {
flag=e.type=='blur';
});
});
FIDDLE
I have a button in html called btnS:
<button type="submit" id="btnS" class="hide" value="button">Send</button>
That I disabled with dom via external script dom:
btnS.setAttribute('disabled', 'false');
I tried to get it "back on" again via:
btnS.setAttribute('enabled', 'true');
But that didn't work? The button was first invisible via a css rule:
.hide {
visibility : hidden;
}
And I changed that as well before with :
btnS.setAttribute('class', 'show');
Rule:
.show { visibility:visible; }
There is only one attribute:
var btnS = document.getElementById("btnS");
// Disable
btnS.setAttribute('disabled', 'disabled');
// Enable
btnS.removeAttribute('disabled');
The problem is that disabled="false" actually means "disable this element": any disabled attribute (even an empty one) means "disabled the element".
You need to remove the attribute:
btnS.removeAttribute('hidden');
Alternatively For better results, work with the DOM property:
btnS.disabled = true;
btnS.disabled = false;