How to create buttons and text enters with javascript in scripts. (Tampermonkey) - javascript

Im creating scripts (Javascript) using tamper monkey. The most used scripts on this platform create buttons and boxes to enter text on the website they want the script to happen (for example creating an extra button on google.com and when clicked it does a function). I have a few examples like a you tube to mp4 converter thats directly on the youtube website itself. (If this helps) If this requires HTML or CSS In not really familiar with those languages.
How do I create buttons and text boxes like this script to put into my JavaScript code?
Script

This code will create a button (Add a JavaScript button using Greasemonkey or Tampermonkey?) :
// ==UserScript==
// #name _Adding a live button
// #description Adds live example button, with styling.
// #include https://stackoverflow.com/questions/*
// #grant GM_addStyle
// ==/UserScript==
/*--- Create a button in a container div. It will be styled and
positioned with CSS.
*/
var zNode = document.createElement ('div');
zNode.innerHTML = '<button id="myButton" type="button">'
+ 'For Pete\'s sake, don\'t click me!</button>'
;
zNode.setAttribute ('id', 'myContainer');
document.body.appendChild (zNode);
//--- Activate the newly added button.
document.getElementById ("myButton").addEventListener (
"click", ButtonClickAction, false
);
function ButtonClickAction (zEvent) {
/*--- For our dummy action, we'll just add a line of text to the top
of the screen.
*/
var zNode = document.createElement ('p');
zNode.innerHTML = 'The button was clicked.';
document.getElementById ("myContainer").appendChild (zNode);
}
//--- Style our newly added elements using CSS.
GM_addStyle ( multilineStr ( function () {/*!
#myContainer {
position: absolute;
top: 0;
left: 0;
font-size: 20px;
background: orange;
border: 3px outset black;
margin: 5px;
opacity: 0.9;
z-index: 222;
padding: 5px 20px;
}
#myButton {
cursor: pointer;
}
#myContainer p {
color: red;
background: white;
}
*/} ) );
function multilineStr (dummyFunc) {
var str = dummyFunc.toString ();
str = str.replace (/^[^\/]+\/\*!?/, '') // Strip function () { /*!
.replace (/\s*\*\/\s*\}\s*$/, '') // Strip */ }
.replace (/\/\/.+$/gm, '') // Double-slash comments wreck CSS. Strip them.
;
return str;
}

Related

problem appending getJSON at the end of my webpage

I've been stuck for days with an issue that I think is really easy for anyone.
I'm currently working on building my own "fake" professional webpage using glitch. I managed to put everything I wanted on it using HTML and I stylized it using CSS. So far so good, it looks like a real webpage.
At the end of this web page I want to put a "contact us" section and that's where it get tricky. What I want to do is use Javascript and RANDOM USER GENERATOR to replicate professionals that viewers can contact.
Each professional (10 in total) has a picture and by putting their mouse on each profile, viewers can see the first name and name (maybe I'll add phone number and email address later) of the professional.
I pretty much got that part covered, here is my code,
professional.js :
$.getJSON( "https://randomuser.me/api/?results=10", function( json ) {
console.log( json ); // print data in the console
var users = json.results; // results is an array of users
// store the "body" of our document inside a jQuery object
var body = $( "body" );
// loop through each user in our "users" array
for( var i = 0; i< users.length; i = i + 1 ) {
// store the current user in a variable
var user = users[ i ];
// we create a container for the user image and its data
var imgContainer = $( "<div class='img-container'></div>" );
// we create a jQuery object with an "img" element
var img = $( "<img>" );
// set its "src" attribute with a jquery method
img.attr( "src", user.picture.large );
// and append this element to our container
imgContainer.append( img );
// we create a jQuery object with a new paragraph
var userData = $( "<p class='user-data'></p>" );
// set its inner HTML with jQuery
userData.html( user.name.first + "<br>" + user.name.last );
// and append this to our container
imgContainer.append( userData );
// finally we append the container to the "body" of our document
body.append( imgContainer );
}
} );
Here is the style used with CSS :
* {
margin: 0;
padding: 0;
}
body {
background: black;
text-align: center;
line-height: 0;
}
.img-container {
display: inline-block;
position: relative;
overflow: hidden;
cursor: pointer;
}
.user-data {
position: absolute;
bottom: 0;
left: -120%;
width: 100%;
height: 50px;
background: rgba( 0, 0, 0, 0.3 );
padding-left: 10px;
text-align: left;
color: white;
font-family: sans-serif;
font-size: 20px;
line-height: 24px;
transition: left 0.3s ease-in;
}
.img-container:hover .user-data {
left: 0;
}
The problem is that when I try to "import" my java to my document it "erase" my webpage. It's like it comes above it and hide all the content. I think that the problem comes from the fact that my .js file append the content in the "body" of my web page (body.append( imgContainer );).
So my question is, how can I append my .js project using getJSON into my webpage without erasing everything. I wish to append it at the very bottom of my webpage. It seems silly but I've been searching four hours and couldn't find any answer.
Many thanks in advance.

Capture mouse wheel event as native HTML attribute

I'm about to start working with the mousewheel event but the only thing I can find online uses addEventListener(). I am wanting to detect is with native HTML and CSS. In other words I'm looking for something like:
<span id='fooBar' onmousewheel='alert("fooBar")'></span>
I am creating spans dynamically and injecting them into the DOM and it would work a lot better if I didn't have to run javascript to do so. Every other event I can seem to get working natively but not mousewheel. Is this possible?
The reason you are only finding references to addEventListener() is because that is the standard and correct way to do it (it appears that onmousewheel isn't even supported in Firefox).
While this can be made to work (in browsers that support it) using the code you show in your question (except that your span is empty so you can't initiate the event with it since the element won't have any rendered size) and I have an example of that below, the use of inline HTML event handling attributes hearkens back to the time before we had standards and should not be used. Here's a link to another answer of mine that explains why.
<span id='fooBar' onmousewheel='alert("fooBar")'>Use the mousewheel while mouse is over this</span>
Inline vs. Delegation
In the demo the A side uses the standard addEventListener and registers the wheel event which is the replacement for the deprecated mousewheel event. Using the addEventListener is not only the standard but it's the most efficient if event delegation is used.
The use of onwheel as an attribute event has limited support due to the fact that using any attribute event is non-standard and discouraged. Despite this, I have included side B which uses the deprecated non-standard onmousewheel event for an attribute inline event handler. Because it's an awkwardly coded <span>, I used insertAdjacentHTML on a string that used all three quotes (i.e.', ", `). The use of a string literal was used on the a 2nd level of nested quotes, it's very messy.
Refer to this post on how the Event Object properties are utilized in event delegation.
Details are commented in the demo
Demo
// Reference the buttons
const btnA = document.getElementById('addA');
const btnB = document.getElementById('addB');
// Reference the parent nodes
const secA = document.querySelector('section:first-of-type');
const secB = document.querySelector('section:last-of-type');
// Register the click event on buttons
btnA.addEventListener('click', addNodeA, false);
btnB.addEventListener('click', addNodeB, false);
/* Register the wheel event on section A
|| which is the parent node of the wheeled
|| nodes. Event delegation involves one
|| event handler for multiple event targets.
|| This is far more efficient than multiple
|| inline event handlers.
*/
secA.addEventListener('wheel', markNode, false);
let cnt = 0;
/* Add node A to section A
|| ex. <span id="A1" class="A">A1</span>
*/
function addNodeA(e) {
cnt++;
var nodeA = document.createElement('span');
nodeA.id = 'A' + cnt;
nodeA.textContent = nodeA.id;
nodeA.className = 'A';
secA.appendChild(nodeA);
return false;
}
/* Add node B to section B
|| ex. <span id="B3" class="B" onmousewheel="this.style.outline = `5px dashed red`">B3</span>
*/
function addNodeB(e) {
cnt++;
/* This string is wrapped in single quotes,
|| double quotes for the attributes values,
|| and backticks for the property value of
|| an attribute value. Very messy, confusing,
|| and inefficient.
*/
var nodeB = '<span id="B' + cnt + '" class="B" onmousewheel="this.style.outline = `5px dashed red`">B' + cnt + '</span>';
// insertAdjacentHTML is innerHTML on steroids
secB.insertAdjacentHTML('beforeend', nodeB);
return false;
}
function markNode(e) {
/* If the wheeled node (i.e. e.target) is not the
|| registered node (i.e. e.currentTarget), then...
*/
if (e.target !== e.currentTarget) {
var node = e.target;
if (node.className === 'A') {
node.style.outline = '5px dashed blue';
} else {
return false;
}
}
}
html,
body {
width: 100%;
width: 100%
}
fieldset {
height: 10%;
}
main {
border: 3px solid lime;
height: 90%;
min-height: 250px;
display: flex;
}
section {
width: 50%;
min-height: 250px;
outline: 3px dashed gold;
padding: 10px 25px;
}
span {
height: 50px;
width: 50px;
padding: 2px;
text-align: center;
font-size: 12px;
margin: 5px;
display: inline-block;
}
.A {
background: rgba(0, 100, 200, .3);
}
.B {
background: rgba(200, 100, 0, .3);
}
#addB {
margin-left: 35%
}
<fieldset>
<legend>addNode</legend>
<button id='addA'>nodeA</button>
<button id='addB'>nodeB</button>
</fieldset>
<main>
<section></section>
<section></section>
</main>
You can dynamically create elements with listeners pretty easily. You just need to understand the DOM and how to attach event listeners.
The example below creates 10 spans and attaches a listener to each of them. Just hover over a span and scroll the mouse-wheel. The ID of the span will be logged to the console.
// Create 10 spans with a scroll listener.
var count = 10;
for (var i = 0; i < count; i++) {
var span = document.createElement('SPAN');
span.id = 'foo-bar-' + i;
span.innerHTML = 'Foo #' + i;
addEventListener(span, 'mousewheel', performEvent);
document.body.appendChild(span);
}
// Event function.
function performEvent(e) {
console.log(e.target.id);
}
// IE 8+ via http://youmightnotneedjquery.com/
function addEventListener(el, eventName, handler) {
if (el.addEventListener) {
el.addEventListener(eventName, handler);
} else {
el.attachEvent('on' + eventName, function(){
handler.call(el);
});
}
}
.as-console-wrapper { max-height: 5em !important; }
span[id^="foo-bar-"] {
border: thin solid black;
margin: 0.25em;
}
Try the following:
::-webkit-scrollbar {
width: 0px; /* remove scrollbar space */
background: transparent; /* optional: just make scrollbar invisible */
}
<!DOCTYPE HTML>
<html>
<body style="overflow: auto;
max-height: 100vh;" onscroll="alert('hi')">
<div style="height:2000px;width:100%"></div>
</body>
</html>
The reason you find "addEventListener" examples only is because you need to handle this cross-browser:
var supportedWheelEvent = "onwheel" in HTMLDivElement.prototype ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll";
Also, it's best to do this on one element only! Use delegated event listener to handle this for all of the elements that you need.
HTML Example:
<div id="delegator">
<div class="handleWheel">handle wheel event here</div>
<div> no wheel event handled here </div>
<div class="handleWheel">handle wheel event here</div>
<div> no wheel event handled here </div>
</div>
JS:
var supportedWheelEvent = "onwheel" in HTMLDivElement.prototype ? "wheel" : document.onmousewheel !== undefined ? "mousewheel" : "DOMMouseScroll";
function handler(e){
if(e.target.classList.contains('handleWheel')){
// handle the event here
}
}
var d = document.getElementById('delegator');
d.addEventListener(supportedWheelEvent, handler);
Working codepen sample:
https://codepen.io/Mchaov/pen/zwaMmM

How to call access pseudo elements styling from Javascript? [duplicate]

This question already has answers here:
Selecting and manipulating CSS pseudo-elements such as ::before and ::after using javascript (or jQuery)
(26 answers)
Closed 6 years ago.
Earlier my question was:-
I have the following code in my Sass css file
.random {
box-sizing: content-box;
text-align: center;
line-height: 1;
&:before {
display: inline-block;
margin-right: 0.2em;
width: 0;
height: 0;
border-right: 0.4em solid transparent;
border-left: 0.4em solid transparent;
content: "";
vertical-align: baseline;
}
}
.perc-neg:before {
border-top: 0.5em solid #FCB062;
}
.perc-neg.good:before {
border-top: 0.5em solid #98F1AC;
}
I have a div with
class = "random perc-neg good"
Now I want to change style of the above div. how to do it?
I tried following in console but it returns empty object
$("random perc-neg good:before").css("color","red");
$("random.perc-neg.good:before").css("color","red");
$(".random.perc-neg.good:before").css("color","red");
Someone has suggested its a possible duplicate but its not.
Int he related question, the user just wanted to make it visible or hidden so two classes will be sufficient.
But my requirement is to change the color as per user's choice which he can select from wide range of colors.
Its definitely impossible to define a class with each color changes.
And we cant pass some variable to css as well to change the color property accordingly.
Updated Question:
I am now using Sass.
I have defined an function to update the color
#function em($color) {
#return border-bottom: 0.5em solid $color;
}
.perc-neg.good:before {
em(#98F1AC);
}
definitely, I can call the function from the Sass file but how to call it from javascript
Now I want to pass the hex code of color from javascript
I need to pass something like this from javascript
.perc-neg.good:before(#98F1AC)
looked for the same in google did not find anything relevant
Instead of marking it as duplicate, it would be much better if you can provide a solution
You cannot access pseudo elements in Javascript since these elements are not in the DOM.
If you want the change pseudo elements styling, you need to predefine css classes for that purpose and add/remove those based on your triggering events.
If that is not possible, simply don't set the colorproperty on the pseudo element at all, but on the host element, since :before and :after will then inherit their host element's color property (if they don't have a specific color property assigned to themselves in CSS).
You cannot call a SASS / LESS function from javascript as they are both pre-compilers that just produce a static stylesheet.
If you have a limited color pallet you could create all the rules that cover your use cases.
However you do have the ability to create a style element with javascript and append new rules to it. Here is a simple example that you could expand on
// add Style is wrapped in a closure that locks in a single
// style element that you can add to on the fly
const addStyle = (() => {
// create and append the style element
const styleSheet = document.createElement('style')
document.head.appendChild(styleSheet)
const style = styleSheet.sheet
// helper function to serialize an object to a css string
const serializeStyle = (styles) => {
return Object.keys(styles).reduce((str, prop) => {
return str + kebabCase(prop) + ':' + styles[prop] + ';'
}, '')
}
// helper function to convert camelCase to kebab-case
const kebabCase = (str) =>
str.replace(/([A-Z])/g, (_, letter) => '-'+ letter.toUpperCase())
// return the public function
return (selector, styles) => {
// add a new rule to the created stylesheet
style.insertRule(
selector + '{' + serializeStyle(styles) + '}',
style.cssRules.length
)
}
})()
addStyle('.random::before', {
border: '10px solid #aec369'
})
addStyle('.random::before', {
background: '#bada55',
boxShadow: '5px 5px 10px #777'
})
const el = document.querySelector('#color')
const em = () => {
addStyle('.random::before', {
borderColor: el.value
})
}
el.addEventListener('keyup', em)
el.addEventListener('change', em)
.random {
position: relative;
background-color: #eee;
}
.random::before {
content: '';
display: block;
height: 200px;
width: 200px;
}
<input id="color" placeholder="#000000" />
<div class="random">
</div>

Twitter-style autocomplete in textarea

I am looking for a Javascript autocomplete implementation which includes the following:
Can be used in a HTML textarea
Allows for typing regular text without invoking autocomplete
Detects the # character and starts autocomplete when it is typed
Loads list of options through AJAX
I believe that this is similar to what Twitter is doing when tagging in a tweet, but I can't find a nice, reusable implementation.
A solution with jQuery would be perfect.
Thanks.
Another great library which solves this problem At.js (deprecated)
Source
Demo
They are now suggesting the Tribute library
https://github.com/zurb/tribute
Example
I'm sure your problem is long since solved, but jquery-textcomplete looks like it would do the job.
Have you tried this
GITHUB: https://github.com/podio/jquery-mentions-input
DEMO/CONFIG: http://podio.github.io/jquery-mentions-input/
It is pretty simple to implement.
I've created a Meteor package for this purpose. Meteor's data model allows for fast multi-rule searching with custom rendered lists. If you're not using Meteor for your web app, (I believe) you unfortunately won't find anything this awesome for autocompletion.
Autocompleting users with #, where online users are shown in green:
In the same line, autocompleting something else with metadata and bootstrap icons:
Fork, pull, and improve:
https://github.com/mizzao/meteor-autocomplete
Try this:
(function($){
$.widget("ui.tagging", {
// default options
options: {
source: [],
maxItemDisplay: 3,
autosize: true,
animateResize: false,
animateDuration: 50
},
_create: function() {
var self = this;
this.activeSearch = false;
this.searchTerm = "";
this.beginFrom = 0;
this.wrapper = $("<div>")
.addClass("ui-tagging-wrap");
this.highlight = $("<div></div>");
this.highlightWrapper = $("<span></span>")
.addClass("ui-corner-all");
this.highlightContainer = $("<div>")
.addClass("ui-tagging-highlight")
.append(this.highlight);
this.meta = $("<input>")
.attr("type", "hidden")
.addClass("ui-tagging-meta");
this.container = $("<div></div>")
.width(this.element.width())
.insertBefore(this.element)
.addClass("ui-tagging")
.append(
this.highlightContainer,
this.element.wrap(this.wrapper).parent(),
this.meta
);
var initialHeight = this.element.height();
this.element.height(this.element.css('lineHeight'));
this.element.keypress(function(e) {
// activate on #
if (e.which == 64 && !self.activeSearch) {
self.activeSearch = true;
self.beginFrom = e.target.selectionStart + 1;
}
// deactivate on space
if (e.which == 32 && self.activeSearch) {
self.activeSearch = false;
}
}).bind("expand keyup keydown change", function(e) {
var cur = self.highlight.find("span"),
val = self.element.val(),
prevHeight = self.element.height(),
rowHeight = self.element.css('lineHeight'),
newHeight = 0;
cur.each(function(i) {
var s = $(this);
val = val.replace(s.text(), $("<div>").append(s).html());
});
self.highlight.html(val);
newHeight = self.element.height(rowHeight)[0].scrollHeight;
self.element.height(prevHeight);
if (newHeight < initialHeight) {
newHeight = initialHeight;
}
if (!$.browser.mozilla) {
if (self.element.css('paddingBottom') || self.element.css('paddingTop')) {
var padInt =
parseInt(self.element.css('paddingBottom').replace('px', '')) +
parseInt(self.element.css('paddingTop').replace('px', ''));
newHeight -= padInt;
}
}
self.options.animateResize ?
self.element.stop(true, true).animate({
height: newHeight
}, self.options.animateDuration) :
self.element.height(newHeight);
var widget = self.element.autocomplete("widget");
widget.position({
my: "left top",
at: "left bottom",
of: self.container
}).width(self.container.width()-4);
}).autocomplete({
minLength: 0,
delay: 0,
maxDisplay: this.options.maxItemDisplay,
open: function(event, ui) {
var widget = $(this).autocomplete("widget");
widget.position({
my: "left top",
at: "left bottom",
of: self.container
}).width(self.container.width()-4);
},
source: function(request, response) {
if (self.activeSearch) {
self.searchTerm = request.term.substring(self.beginFrom);
if (request.term.substring(self.beginFrom - 1, self.beginFrom) != "#") {
self.activeSearch = false;
self.beginFrom = 0;
self.searchTerm = "";
}
if (self.searchTerm != "") {
if ($.type(self.options.source) == "function") {
self.options.source(request, response);
} else {
var re = new RegExp("^" + escape(self.searchTerm) + ".+", "i");
var matches = [];
$.each(self.options.source, function() {
if (this.label.match(re)) {
matches.push(this);
}
});
response(matches);
}
}
}
},
focus: function() {
// prevent value inserted on focus
return false;
},
select: function(event, ui) {
self.activeSearch = false;
//console.log("#"+searchTerm, ui.item.label);
this.value = this.value.replace("#" + self.searchTerm, ui.item.label) + ' ';
self.highlight.html(
self.highlight.html()
.replace("#" + self.searchTerm,
$("<div>").append(
self.highlightWrapper
.text(ui.item.label)
.clone()
).html()+' ')
);
self.meta.val((self.meta.val() + " #[" + ui.item.value + ":]").trim());
return false;
}
});
}
});
body, html {
font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
}
.ui-tagging {
position: relative;
border: 1px solid #B4BBCD;
height: auto;
}
.ui-tagging .ui-tagging-highlight {
position: absolute;
padding: 5px;
overflow: hidden;
}
.ui-tagging .ui-tagging-highlight div {
color: transparent;
font-size: 13px;
line-height: 18px;
white-space: pre-wrap;
}
.ui-tagging .ui-tagging-wrap {
position: relative;
padding: 5px;
overflow: hidden;
zoom: 1;
border: 0;
}
.ui-tagging div > span {
background-color: #D8DFEA;
font-weight: normal !important;
}
.ui-tagging textarea {
display: block;
font-family: "lucida grande",tahoma,verdana,arial,sans-serif;
background: transparent;
border-width: 0;
font-size: 13px;
height: 18px;
outline: none;
resize: none;
vertical-align: top;
width: 100%;
line-height: 18px;
overflow: hidden;
}
.ui-autocomplete {
font-size: 13px;
background-color: white;
border: 1px solid black;
margin-bottom: -5px;
width: 0;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<textarea></textarea>
http://jsfiddle.net/mekwall/mcWnL/52/
This link will help you
I could not find any solution that matched my requirements perfectly, so I ended up with the following:
I use the jQuery keypress() event to check for the user pressing the # character.
If this is the case, a modal dialog is shown using jQuery UI. This dialog contains an autocomplete text field (many options can be used here, but I recommmend jQuery Tokeninput)
When the user selects an option in the dialog, a tag is added to the text field and the dialog is closed.
This is not the most elegant solution, but it works and it does not require extra keypresses compared to my original design.
Edit
So basically, we have our large text box where the user can enter text. He should be able to "tag" a user (this just means inserting #<userid> in the text). I attach to the jQuery keyup event and detect the # character using (e.which == 64) to show a modal with a text field for selecting the users to tag.
The meat of the solution is simply this modal dialog with a jQuery Tokeninput text box. As the user types here, the list of users is loaded through AJAX. See the examples on the website for how to use it properly. When the user closes the dialog, I insert the selected IDs into the large text box.
Recently i had to face this problem and this is how i nailed down...
Get the string index at the cursor position in the textarea by using selectionStart
slice the string from index 0 to the cursor position
Insert it into a span (since span has multiple border boxes)
Get the dimensions of the border box using element.getClientRects() relative to the view port. (here is the MDN Reference)
Calculate the top and left and feed it to the dropdown
This works in all latest browsers. haven't tested at old ones
Here is Working bin
Another plugin which provides similar functionality:
AutoSuggest
You can use it with custom triggers or you can use it without any triggers. Works with input fields, textareas and contenteditables. And jQuery is not a dependency.
I would recommend the textcomplete plugin. No jQuery dependency. You may need bootstrap.css to refer, but I recommend to write your own CSS, lighter and simple.
Follow the below steps to give it a try
npm install #textcomplete/core #textcomplete/textarea
Bind it to your input element
const editor = new TextareaEditor(inputEl);
const textcomplete = new Textcomplete(editor, strategy, options);
Set strategy(how to fetch suggestion list) and options(settings to configure the suggestions) according to your need.
JS version
Angular Version
This small extension seems to be the closest at least in presentation to what was asked. Since it's small, it can be easily understood and modified. http://lookapanda.github.io/jquery-hashtags/
THIS should work. With regards to the # kicking off the search, just add (dynamically or not) the symbol to the beginning of each possible search term.

Wait cursor over entire html page

Is it possible to set the cursor to 'wait' on the entire html page in a simple way? The idea is to show the user that something is going on while an ajax call is being completed. The code below shows a simplified version of what I tried and also demonstrate the problems I run into:
if an element (#id1) has a cursor style set it will ignore the one set on body (obviously)
some elements have a default cursor style (a) and will not show the wait cursor on hover
the body element has a certain height depending on the content and if the page is short, the cursor will not show below the footer
The test:
<html>
<head>
<style type="text/css">
#id1 {
background-color: #06f;
cursor: pointer;
}
#id2 {
background-color: #f60;
}
</style>
</head>
<body>
<div id="id1">cursor: pointer</div>
<div id="id2">no cursor</div>
Do something
</body>
</html>
Later edit...
It worked in firefox and IE with:
div#mask { display: none; cursor: wait; z-index: 9999;
position: absolute; top: 0; left: 0; height: 100%;
width: 100%; background-color: #fff; opacity: 0; filter: alpha(opacity = 0);}
<a href="#" onclick="document.getElementById('mask').style.display = 'block'; return false">
Do something</a>
The problem with (or feature of) this solution is that it will prevent clicks because of the overlapping div (thanks Kibbee)
Later later edit...
A simpler solution from Dorward:
.wait, .wait * { cursor: wait !important; }
and then
Do something
This solution only shows the wait cursor but allows clicks.
If you use this slightly modified version of the CSS you posted from Dorward,
html.wait, html.wait * { cursor: wait !important; }
you can then add some really simple jQuery to work for all ajax calls:
$(document).ready(function () {
$(document).ajaxStart(function () { $("html").addClass("wait"); });
$(document).ajaxStop(function () { $("html").removeClass("wait"); });
});
or, for older jQuery versions (before 1.9):
$(document).ready(function () {
$("html").ajaxStart(function () { $(this).addClass("wait"); });
$("html").ajaxStop(function () { $(this).removeClass("wait"); });
});
I understand you may not have control over this, but you might instead go for a "masking" div that covers the entire body with a z-index higher than 1. The center part of the div could contain a loading message if you like.
Then, you can set the cursor to wait on the div and don't have to worry about links as they are "under" your masking div. Here's some example CSS for the "masking div":
body { height: 100%; }
div#mask { cursor: wait; z-index: 999; height: 100%; width: 100%; }
This seems to work in firefox
<style>
*{ cursor: inherit;}
body{ cursor: wait;}
</style>
The * part ensures that the cursor doesn't change when you hover over a link. Although links will still be clickable.
I have been struggling with this problem for hours today.
Basically everything was working just fine in FireFox but (of course) not in IE.
In IE the wait cursor was showing AFTER the time consuming function was executed.
I finally found the trick on this site:
http://www.codingforums.com/archive/index.php/t-37185.html
Code:
//...
document.body.style.cursor = 'wait';
setTimeout(this.SomeLongFunction, 1);
//setTimeout syntax when calling a function with parameters
//setTimeout(function() {MyClass.SomeLongFunction(someParam);}, 1);
//no () after function name this is a function ref not a function call
setTimeout(this.SetDefaultCursor, 1);
...
function SetDefaultCursor() {document.body.style.cursor = 'default';}
function SomeLongFunction(someParam) {...}
My code runs in a JavaScript class hence the this and MyClass (MyClass is a singleton).
I had the same problems when trying to display a div as described on this page. In IE it was showing after the function had been executed. So I guess this trick would solve that problem too.
Thanks a zillion time to glenngv the author of the post. You really made my day!!!
Easiest way I know is using JQuery like this:
$('*').css('cursor','wait');
css: .waiting * { cursor: 'wait' }
jQuery: $('body').toggleClass('waiting');
Why don't you just use one of those fancy loading graphics (eg: http://ajaxload.info/)? The waiting cursor is for the browser itself - so whenever it appears it has something to do with the browser and not with the page.
To set the cursor from JavaScript for the whole window, use:
document.documentElement.style.cursor = 'wait';
From CSS:
html { cursor: wait; }
Add further logic as needed.
Try the css:
html.waiting {
cursor: wait;
}
It seems that if the property body is used as apposed to html it doesn't show the wait cursor over the whole page. Furthermore if you use a css class you can easily control when it actually shows it.
Here is a more elaborate solution that does not require external CSS:
function changeCursor(elem, cursor, decendents) {
if (!elem) elem=$('body');
// remove all classes starting with changeCursor-
elem.removeClass (function (index, css) {
return (css.match (/(^|\s)changeCursor-\S+/g) || []).join(' ');
});
if (!cursor) return;
if (typeof decendents==='undefined' || decendents===null) decendents=true;
let cname;
if (decendents) {
cname='changeCursor-Dec-'+cursor;
if ($('style:contains("'+cname+'")').length < 1) $('<style>').text('.'+cname+' , .'+cname+' * { cursor: '+cursor+' !important; }').appendTo('head');
} else {
cname='changeCursor-'+cursor;
if ($('style:contains("'+cname+'")').length < 1) $('<style>').text('.'+cname+' { cursor: '+cursor+' !important; }').appendTo('head');
}
elem.addClass(cname);
}
with this you can do:
changeCursor(, 'wait'); // wait cursor on all decendents of body
changeCursor($('#id'), 'wait', false); // wait cursor on elem with id only
changeCursor(); // remove changed cursor from body
I used a adaptation of Eric Wendelin's solution. It will show a transparent, animated overlay wait-div over the whole body, the click will be blocked by the wait-div while visible:
css:
div#waitMask {
z-index: 999;
position: absolute;
top: 0;
right: 0;
height: 100%;
width: 100%;
cursor: wait;
background-color: #000;
opacity: 0;
transition-duration: 0.5s;
-webkit-transition-duration: 0.5s;
}
js:
// to show it
$("#waitMask").show();
$("#waitMask").css("opacity"); // must read it first
$("#waitMask").css("opacity", "0.8");
...
// to hide it
$("#waitMask").css("opacity", "0");
setTimeout(function() {
$("#waitMask").hide();
}, 500) // wait for animation to end
html:
<body>
<div id="waitMask" style="display:none;"> </div>
... rest of html ...
My Two pence:
Step 1:
Declare an array. This will be used to store the original cursors that were assigned:
var vArrOriginalCursors = new Array(2);
Step 2:
Implement the function cursorModifyEntirePage
function CursorModifyEntirePage(CursorType){
var elements = document.body.getElementsByTagName('*');
alert("These are the elements found:" + elements.length);
let lclCntr = 0;
vArrOriginalCursors.length = elements.length;
for(lclCntr = 0; lclCntr < elements.length; lclCntr++){
vArrOriginalCursors[lclCntr] = elements[lclCntr].style.cursor;
elements[lclCntr].style.cursor = CursorType;
}
}
What it does:
Gets all the elements on the page. Stores the original cursors assigned to them in the array declared in step 1. Modifies the cursors to the desired cursor as passed by parameter CursorType
Step 3:
Restore the cursors on the page
function CursorRestoreEntirePage(){
let lclCntr = 0;
var elements = document.body.getElementsByTagName('*');
for(lclCntr = 0; lclCntr < elements.length; lclCntr++){
elements[lclCntr].style.cursor = vArrOriginalCursors[lclCntr];
}
}
I have run this in an application and it works fine.
Only caveat is that I have not tested it when you are dynamically adding the elements.
BlockUI is the answer for everything. Give it a try.
http://www.malsup.com/jquery/block/
This pure JavaScript seems to work pretty well ... tested on FireFox, Chrome, and Edge browsers.
I'm not sure about the performance of this if you had an overabundance of elements on your page and a slow computer ... try it and see.
Set cursor for all elements to wait:
Object.values(document.querySelectorAll('*')).forEach(element => element.style.cursor = "wait");
Set cursor for all elements back to default:
Object.values(document.querySelectorAll('*')).forEach(element => element.style.cursor = "default");
An alternative (and perhaps a bit more readable) version would be to create a setCursor function as follows:
function setCursor(cursor)
{
var x = document.querySelectorAll("*");
for (var i = 0; i < x.length; i++)
{
x[i].style.cursor = cursor;
}
}
and then call
setCursor("wait");
and
setCursor("default");
to set the wait cursor and default cursor respectively.
Lots of good answers already, but none of them mentions the <dialog> element.
Using this element we can create a solution similar to the masking <div>.
Here we use showModal() to "hide" elements, and we use ::backdrop to set the cursor style to wait on the entire page:
function showWaitDialog() {
document.getElementById('id_dialog').showModal();
}
#id_dialog, #id_dialog::backdrop {
cursor: wait;
}
<button onclick="showWaitDialog()">click me</button>
<dialog id="id_dialog">busy...</dialog>
The dialog is hidden by default, and can be shown using either the show() method, or the showModal() method, which prevents clicking outside the dialog.
The dialog can be forced to close using the close() method, if necessary.
However, if your button links to another page, for example, then the dialog will disappear automatically as soon as the new page is loaded.
Note that the dialog can also be closed at any time by hitting the Esc key.
CSS can be used to style the dialog however you like.
The example uses the html onclick attribute, just for simplicity. Obviously, addEventListener() could also be used.
Late to the party but simply give the Html tag an id by targeting
document.documentElement
and in the CSS place at the top
html#wait * {
cursor: wait !important;
}
and simply remove it when you want to stop this cursor.

Categories

Resources