I have to use a website (ticket system) with a select element, that contains currently 9994 options. This is not changeable and has to be accepted as is.
When I work on a ticket on that website, I have to select a specific entry from that select. I have a total set of around 30 entries I have to choose from. I don't care for the other entries.
The required 30 entries can be seperated into 3 patterns for a RegEx filter.
So I decided to use Greasemonkey+JQuery to clean that select element up, so I can easily and quickly find the entries I am looking for.
The filtering is working fine, but it takes time (of course it does...), so I want to show a little "please wait" div as overlay, while the filter is running to give some kind of user feedback.
On page load I create the overlay:
$("body").append('<div id="pleaseWaitOverlay" style="position: fixed; top: 0; left: 0; bottom: 0; right: 0; background-color: rgb(255,255,255);">HALLO WELT</div>');
$("#pleaseWaitOverlay").hide();
//This is the select element with the "few" entries
fixedInReleaseElement = $('select[name=resolvedReleasePath]');
//Adding buttons to filter for one of the patterns are also added on page load
If I press on one of the filter buttons, the following function will be called:
function filterFixedInReleaseList(filterFor) {
$("#pleaseWaitOverlay").show();
//$("#pleaseWaitOverlay").show().delay(500).show(); - or as hack without success...
var pattern;
//Based on "filterFor" parameter, the required pattern will be used.
// [MORE CODE]
fixedInReleaseElement.find("option").each(function() {
var currentOption = $(this);
if (pattern === "") {
currentOption.show();
}
else {
if (pattern.test(currentOption.text())) {
currentOption.show();
}
else {
currentOption.hide();
}
}
});
//$("#pleaseWaitOverlay").hide();
}
But somehow, the filter will take place and THEN the overlay will be shown.
Please note:
Currently, the .hide() lines are commented out, as the popup would not be shown (or rather seen) at all with those lines executed.
The .show().delay(500).show() was a try to kind of hack it, but it changed absolutly nothing.
I also tried fixedInReleaseElement.find("option").delay(1000).each() without success. I appears that delay does not work at all?
So, what is the problem here? Why is the overlay shown after the filter has been executed?
The complete Greasemonkey script can be found here:
http://pastebin.com/auafMSR1
A browser tab only has one thread, that is shared between JavaScript and UI updates. Thus, if your JavaScript is running, the UI is not getting updated.
So, this:
function doSomethingLongWithOverlayWrongly() {
$x.show();
doSomethingLong();
$x.hide();
}
will set appropriate attributes of $x to be hidden, then do something long, then set the attributes back; and when doSomethingLongWithOverlayWrongly (and all the computation that is in its future) finally exits and relinquishes control of the executing thread, the browser will take note that some attributes were changed, and repaint if necessary (but it's not, since the element was set to invisible, and is now still set to invisible).
Do this instead:
function doSomethingLongWithOverlayCorrectly() {
$x.show();
setTimeout(function() {
doSomethingLong();
$x.hide();
}, 0);
}
This will set $x to be hidden, then schedule a timeout, then exit. The browser takes a look, sees a repaint is in order, and shows your overlay. Then the timeouted function gets run, does something long, and sets $x to be hidden again. When it exits, the browser takes another look, sees that a repaint is required, and hides your overlay.
Related
I made a popup feature, which shows the phone number of a user. I was able to apply this feature to one instance. A single user.
Normally, each user has a unique phone number. Each user's number's already embedded, it's just to reveal the numbers, for multiple users.
But then, I thought, what if I have lots of users as they come, to the site? How do I dynamically apply the same popup feature without writing the same lines of code I wrote for the single user, over and over again?
Please, help me out.
This is the JavaScript I wrote...
let tansform_scale_0 = document.querySelector('.transform_scale_0');
let num_btn = document.querySelector('.num_btn');
num_btn.addEventListener('click', ()=>{
if (!tansform_scale_0.classList.contains('scale_to_1')) {
tansform_scale_0.classList.add('scale_to_1');
} else {
tansform_scale_0.classList.remove('scale_to_1');
}
})
Please view the code here: https://codepen.io/matthewdon/pen/MWQEvJM
You need to extend the logic you've applied to each of your cards. For example, the simplest way is to use querySelectorAll rather than the querySelector you currently have.
This is very similar in that it will return you a list of matching elements which you can then loop over and add your event listeners to in much the same way you are doing now.
However to make things a bit easier, you will be better off looping over each of the containing .card elements first. That way you can scope a second querySelector to the containing element and leave the rest of your logic largely intact.
You can shortcut the click handler itself though, by using classList.toggle rather than manually checking the class and then adding/removing it as required.
const cards = document.querySelectorAll('.card');
cards.forEach((card) => {
// rest of your click handler logic
})
Here's a snippet that brings all that together. I've put it on codepen as the editor on here isn't really suited to such a large amount of html: https://codepen.io/29b6/pen/VwQQqrw?editors=1111
I want to have a page turn effect like the one seen on this page: jFlip demo except I want to automate the page turning, like make it happen every second, 20 times (or however many images I have). I want to be able to trigger this animation to run either on page load, when a button is clicked, etc.
Unfortunately I don't understand jQuery all that well and the plugin's events seem rather complicated to me, probably mostly due to my inexperience with jQuery. Any help on which direction I should go, methods I should try? I am not limiting myself to jQuery or even Javascript, this is just the example I have found that achieves my desired effect.
You can find the updated code here. replace this with old one.
Usage :
var jFlip = new Flip("#g1",300,300,{background:"green",cornersTop:true,scale:"fit"});
// here #g1 is a jquery selector (make sure it returns only one).
// The structure is Flip(JQselector,width,height,options)
then use the jFlip object to flip slides/pages
jFlip.flipMe() // for next slide
jFlip.flipMe(true) // for prev slide
for binding a function to slide change event you can use
$("#g1").bind("flip.jflip",function(event,index,total){
$("#l1").html("Image "+(index+1)+" of "+total);
});
// here the selector is same as the one passed inside jFlip function.
Try this and let me know the feedback.
I have some images from another source that need to refresh from their offsite source every 30 seconds. I would like to use JavaScript to accomplish this so as to avoid an entire page reload.
Presently I've attempted something similar to this question: "reloading a page after every 10 sec in rails 3.1"
(This is a Rails application, but I probably don't need a Rails specific answer in this case.)
Notwithstanding, I am ending up with no appreciable result when I add a div around the link + image nor when I add a div to the image itself. I have attempted both solutions in this example by creating a element-reload.js.
The first solution that's marked as the answer simply reloads the page with nearly all of the page elements absent. The second solution makes the image that I'm trying to refresh actually disappear upon first refresh when I surround the link + image with a div, but when I place the id upon which it's acting on the actual image tag, it yields nothing.
I'm sure I'm missing something rather simple since JS is not a strong suit for me at the moment.
Finally, I do have a number of sources to refresh and would like to see an example of performing this for a class vs an id if possible, but having more granular control over each one may be best in the end for varied times for the refreshes.
If you're up for jQuery, this can be done quite easily:
$(function() {
setInterval(function() {
$('img').each(function() {
$this = $(this);
$this.attr('src', $this.getAttribute('src') + '?timestamp=' + new Date().getTime());
console.log($this.prop('src'));
});
}, 30 * 1000);
});
In order to prevent browser caching, you have to fool the browser and load the image with a GET request variable timestamp. It doesn't matter what the parameter is, but the image will load brand-new and not from cache because the URL changes.
jQuery is famous for its use of CSS-like selectors.
Replace $('img') with one of these:
$('img.yourClassName'); // Class
$('#your_id, #another_id, ...'); // ID(s). Omit the comma for a single id
$('img[id^="common_base_id"]'); // Selects all images with an id that starts with "common_base_id".
There's also the :not() selector, which can filter your results:
$('img.yourClassName:not(.do-not-reload)');
$('img.yourClassName:not([src="img/spinner-skip.gif"])');
I took a peek at the source of http://wonderwall.msn.com and noticed how all the span tags that the blocks of the wall have don't seem to be associated with any ID. It makes me very curious how they are able to accomplish the animated repositioning of elements when you click on one of the blocks/images without associated ID.
I am curious how you can click on say an image and get other images around it to move to the side. Is it some sort of formula or algoirthm?
I would like to accomplish getting say, 5 spans/blocks, clicking on one, and getting others to animate/move to the sides.
IDs are not necessary and often harmful. You don't need them, generated or otherwise.
When you put an element on a page with an ID, you're making the claim that there should be only one of whatever it is. Seldom is this true. More often, what you want to do is associate some behavior with some of the elements on the page, of which there may be many, one or zero.
In this case, there are lots of little image dealies, which when clicked, rearrange themselves. I don't have an algorithm for you for calculating how they should move, but here's a framework for how you could achieve the same with jQuery.
// create jQuery plugin for highlighting and shuffling brick dealies
(function($){
function expandify() {
var href = this.attr('href');
// create a popup containing the href
return this;
}
function shuffle() {
this.each(function(index, elem){
// calculate new position and move the element there.
});
return this;
}
$.fn.expandify = expandify;
$.fn.shuffle = shuffle;
})(jQuery);
// attaches behaviors to elements on the page after they've loaded
// either $.ready, or window onload, or after some ajaxing takes place
$('.wallBrick')
.click(function(e){
$(e.target)
.expandify();
$('.wallBrick')
.not(e.target)
.shuffle();
});
The IDs are generated via JavaScript on-the-fly. You won't see it in the source, but you'll see it if you inspect it with Firebug.
I am building the diagram component in JavaScript. It has two layers rendered separately: foreground and background.
To determine the required size of the background:
render the foreground
measure the height of the result
render the foreground and the
background together
In code it looks like this:
var foreground = renderForegroundIntoString();
parentDiv.innerHTML = foreground;
var height = parentDiv.children[0].clientHeight;
var background = renderBackgroundIntoString(height);
parentDiv.innerHTML = foreground + background;
Using IE7, this is a piece of cake. However, Firefox2 is not really willing to render the parentDiv.innerHTML right away, therefore I cannot read out the foreground height.
When does Firefox execute the rendering and how can I delay my background generation till foreground rendering is completed, or is there any alternative way to determine the height of my foreground elements?
[Appended after testing Dan's answer (thanx Dan)]
Within the body of the callback method (called back by setTimeout(...)) I can see, the rendering of the innerHTML is still not complete.
You should never, ever rely on something you just inserted into the DOM being rendered by the next line of code. All browsers will group these changes together to some degree, and it can be tricky to work out when and why.
The best way to deal with it is to execute the second part in response to some kind of event. Though it doesn't look like there's a good one you can use in that situation, so failing that, you can trigger the second part with:
setTimeout(renderBackground, 0)
That will ensure the current thread is completed before the second part of the code is executed.
I don't think you want parentDiv.children[0] (children is not a valid property in FF3 anyway), instead you want parentDiv.childNodes[0], but note that this includes text nodes that may have no height. You could try looping waiting for parentDiv's descendants to be rendered like so:
function getRenderedHeight(parentDiv) {
if (parentDiv.childNodes) {
var i = 0;
while (parentDiv.childNodes[i].nodeType == 3) { i++; }
//Now parentDiv.childNodes[i] is your first non-text child
return parentDiv.childNodes[i].clientHeight;
//your other code here ...
} else {
setTimeout("isRendered("+parentDiv+")",200);
}
}
and then invoke by: getRenderedHeight(parentDiv) after setting the innerHTML.
Hope that gives some ideas, anyway.