I have the following code that runs on device ready:
var app = {
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
onDeviceReady: function() {
var div = document.querySelector('.app');
div.appendChild(document.createTextNode('Scanning...'));
div.appendChild(document.createElement('br'));
// scan for any BLE devices for 10 seconds
ble.scan([], 10, app.onDeviceDiscovered);
setTimeout(app.scanComplete, 10500);
},
onDeviceDiscovered: function(peripheral) {
// print peripheral details to the the console and the UI
var peripheralString = JSON.stringify(peripheral, null, 2);
console.log(peripheralString);
var div = document.querySelector('.app');
div.appendChild(document.createTextNode('Found Device'));
var pre = document.createElement('pre');
pre.innerText = peripheralString;
div.appendChild(pre);
},
scanComplete: function() {
// update the UI indicating the scan is complete
var div = document.querySelector('.app');
div.appendChild(document.createTextNode('Scan complete.'));
}
};
app.initialize();
What I need to do is to run the above code only if a button is clicked and NOT on device ready.
Something like this:
$(document).on('click', ".letmepairBtn", function(){
var app = {
initialize: function() {
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
},
onDeviceReady: function() {
var div = document.querySelector('.app');
div.appendChild(document.createTextNode('Scanning...'));
div.appendChild(document.createElement('br'));
// scan for any BLE devices for 10 seconds
ble.scan([], 10, app.onDeviceDiscovered);
setTimeout(app.scanComplete, 10500);
},
onDeviceDiscovered: function(peripheral) {
// print peripheral details to the the console and the UI
var peripheralString = JSON.stringify(peripheral, null, 2);
console.log(peripheralString);
var div = document.querySelector('.app');
div.appendChild(document.createTextNode('Found Device'));
var pre = document.createElement('pre');
pre.innerText = peripheralString;
div.appendChild(pre);
},
scanComplete: function() {
// update the UI indicating the scan is complete
var div = document.querySelector('.app');
div.appendChild(document.createTextNode('Scan complete.'));
}
};
app.initialize();
});
But when I run my code, the code fails to work. The reason is because I am still putting the deviceReady inside the click function which doesn't make sense at all. But i am struggling to figure out how to do this properly.
Can someone please advice on the above?
Any help would be appreciated.
thanks in advance.
EDIT:
The main issue is this line of code (I think):
document.addEventListener('deviceready', this.onDeviceReady.bind(this), false);
because of this line, the following code only runs onDeviceReady:
onDeviceReady: function() {
var div = document.querySelector('.app');
div.appendChild(document.createTextNode('Scanning...'));
div.appendChild(document.createElement('br'));
// scan for any BLE devices for 10 seconds
ble.scan([], 10, app.onDeviceDiscovered);
setTimeout(app.scanComplete, 10500);
}
Which makes the code die at that stage.
Thers is no need to add and .on to document. You can keep everything the same, just change the listener from listening to the document to listen to the button your specifying
If your using jquery you can just change the event listener of your initialize function to this:
initialize: function() {
$(".letmepairBtn").click(this.onDeviceReady.bind(this));
}
Or you can acheive the same thing with vanilla javascript, just change the eventlistener and the target:
initialize: function() {
document.getElementsbyClassName('letmepairBtn')[0].addEventListener('click', this.onDeviceReady.bind(this), false)
}
Either way you can keep the same code as before, just call app.initialize at the end and wait for the click on the button.
Related
I can't figure out how to do it.
I have two separate scripts. The first one generates an interval (or a timeout) to run a specified function every x seconds, i.e. reload the page.
The other script contains actions for a button to control (pause/play) this interval.
The pitfall here is that both sides must be asyncronous (both run when the document is loaded).
How could I properly use the interval within the second script?
Here's the jsFiddle: http://jsfiddle.net/hm2d6d6L/4/
And here's the code for a quick view:
var interval;
// main script
(function($){
$(function(){
var reload = function() {
console.log('reloading...');
};
// Create interval here to run reload() every time
});
})(jQuery);
// Another script, available for specific users
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
$icon = $playerButton.children('i');
buttonAction = function(e){
e.preventDefault();
if ($(this).hasClass('playing')) {
// Pause/clear interval here
$(this).removeClass('playing').addClass('paused');
$icon.removeClass('glyphicon-pause').addClass('glyphicon-play');
}
else {
// Play/recreate interval here
$(this).removeClass('paused').addClass('playing');
$icon.removeClass('glyphicon-play').addClass('glyphicon-pause');
}
},
buttonInit = function() {
$playerButton.on('click', buttonAction);
};
buttonInit();
});
})(jQuery);
You could just create a simple event bus. This is pretty easy to create with jQuery, since you already have it in there:
// somewhere globally accessible (script 1 works fine)
var bus = $({});
// script 1
setInterval(function() {
reload();
bus.trigger('reload');
}, 1000);
// script 2
bus.on('reload', function() {
// there was a reload in script 1, yay!
});
I've found a solution. I'm sure it's not the best one, but it works.
As you pointed out, I eventually needed at least one global variable to act as a join between both scripts, and the use of a closure to overcome asyncronous issues. Note that I manipulate the button within reload, just to remark that sometimes it's not as easy as moving code outside in the global namespace:
Check it out here in jsFiddle: yay! this works!
And here's the code:
var intervalControl;
// main script
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
reload = function() {
console.log('reloading...');
$playerButton.css('top', parseInt($playerButton.css('top')) + 1);
};
var interval = function(callback) {
var timer,
playing = false;
this.play = function() {
if (! playing) {
timer = setInterval(callback, 2000);
playing = true;
}
};
this.pause = function() {
if (playing) {
clearInterval(timer);
playing = false;
}
};
this.play();
return this;
};
intervalControl = function() {
var timer = interval(reload);
return {
play: function() {
timer.play();
},
pause: function(){
timer.pause();
}
}
}
});
})(jQuery);
// Another script, available for specific users
(function($){
$(function(){
var $playerButton = $('body').find('button.player'),
$icon = $playerButton.children('i'),
interval;
buttonAction = function(e){
e.preventDefault();
if ($(this).hasClass('playing')) {
interval.pause();
$(this).removeClass('playing').addClass('paused');
$icon.removeClass('glyphicon-pause').addClass('glyphicon-play');
}
else {
interval.play();
$(this).removeClass('paused').addClass('playing');
$icon.removeClass('glyphicon-play').addClass('glyphicon-pause');
}
},
buttonInit = function() {
$playerButton.on('click', buttonAction);
interval = intervalControl();
};
buttonInit();
});
})(jQuery);
Any better suggestion is most welcome.
I am making an experimental addon that will search for a single term on several different art sites at once.
The addon works by doing the following:
Opens a window asking for user input (the term to search for)
Stores this input
Starts a crude loop process
The loop opens the first tab in the list
The loop attaches runs the first script in the list
(these scripts pretty much all work the same way)
This script is attached as a worker to the tab
The script enters the term into a search box in the tab then submits it
The submit triggers the worker to be destroyed
Steps 4-8 repeat until the list runs out of tabs to open
Note: the number of these steps have nothing to do with the step numbers in the code
Main.js
var data = require("sdk/self").data;
var tabs = require("sdk/tabs");
var journal_entry = require("sdk/panel").Panel({
contentURL: data.url("DeltaLogPanel.html"),
contentScriptFile: data.url("get-text.js")
});
// Creates the button
require("sdk/ui/button/action").ActionButton({
id: "make-post",
label: "Make post",
icon: {
"16": "./icon-16.png",
"32": "./icon-32.png",
"64": "./icon-64.png"
},
onClick: handleClick
});
var count = 0;
function handleClick(state) {
journal_entry.show();
}
journal_entry.once("show", function() {
journal_entry.port.emit("show");
});
function doit() {
console.log("Step 1, loop "+ count +" started!");;
if(count < sites.urls.length)
{
TabIt(count);
}
else
{
console.log("loop ended");
}
}
function TabIt(x) {
console.log("Step 2, tab "+ count +" is opening!");
tabs.open(sites.urls[count]);
handleTab(count);
}
//this is our cargo. There's normally more stuff in it
var Cargo = {
Title: ""
};
var sites = {
urls: ["https://www.sofurry.com/", "https://inkbunny.net/search.php", "http://www.furaffinity.net/search/", "https://www.weasyl.com/search", "http://www.deviantart.com/"],
scripts: ["searchSF.js", "searchIB.js", "searchFA.js", "searchWS.js", "searchDA.js"]
};
function handleTab(X)
{
console.log("Step 3, tab "+ count +" is processing!");
//I tried tabs.on('load'.. and that didn't fix the problem
tabs.on('ready', function RunPostScript(tab)
{
console.log("The tab is ready");
worker = tab.attach(
{
contentScriptFile: sites.scripts[X],
contentScriptOptions:
{
Cargo
}
});
worker.port.once("myMessage", function handleMyMessage()
{
console.log("Step 4, search "+ count +" is shuttin down!");
//tab.close();
worker.destroy();
});
tabs.removeListener("ready", RunPostScript);
console.log("Step 5, search "+ count +" should be finished!");
count=count+1;
console.log("Ready to do it again?");
doit();
});
}
journal_entry.port.once("cargo-shipping", function (cargo) {
Cargo.Title = cargo.title;
console.log("title: " + Cargo.Title);
//All data from panel should be imported. So panel is now hidden
journal_entry.hide();
//this starts the tab opening process
TabIt(count);
});
DeltaLogPanel.js
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<!-- <link type="text/css" rel="stylesheet" href="DeltaLogPanel.css"/> -->
<style>
#MainPanel
{
width: 180px;
height:180px;
background-color: #ACA1A1;
}
</style>
</head>
<body id="MainPanel">
<div id="simpleOptions">
<textarea id="titleBox" placeholder="Title" rows="1"></textarea>
<button type="button" id="publishButton">Publish</button>
</div>
</body>
</html>
get-text.js
var titleArea = document.getElementById("titleBox");
var finalButton = document.getElementById("publishButton");
//this defines the cargo on the button press then ships it.
finalButton.addEventListener('click', function() {
// Remove the newline.
var cargo = {
title: ""
};
cargo.title = titleArea.value;
self.port.emit("cargo-shipping", cargo);
titleArea.value = "";
}, false);
//focusses on title box when button is pressed
self.port.on("show", function onShow() {
titleArea.focus();
});
searchFA.js
document.addEventListener("submit", function(event) {
console.log("Unloading now");
self.port.emit("myMessage");
}, false);
//puts words in the input box
var titlePort = function(x){
var FAzA = document.querySelector("form#search-form fieldset input#q");
FAzA.value = x;
};
//hits the submit button
var ShipIt = function(){
document.querySelector("form#search-form").submit();
};
var Finalize = function(){
titlePort(self.options.Cargo.Title);
ShipIt();
};
Finalize();
searchIB.js
document.addEventListener("submit", function(event) {
console.log("Unloading now");
self.port.emit("myMessage");
}, false);
//puts words in the input box
var titlePort = function(x){
var IBzA = document.querySelector("#text");
IBzA.value = x;
};
//hits the submit button
var ShipIt = function(){
var x = document.querySelector("body > form:nth-child(12)");
var y =document.querySelector("body > form:nth-child(9)");
if (x !==null || y !==null)
{
if (x !== null)
{
x.submit();
}
else
{
y.submit();
}
}
};
var Finalize = function(){
titlePort(self.options.Cargo.Title);
ShipIt();
};
Finalize();
searchSF.js
document.addEventListener("submit", function(event) {
console.log("Unloading now");
self.port.emit("myMessage");
}, false);
//puts words in the input box
var titlePort = function(x){
var SFzA = document.querySelector("#headersearch");
SFzA.value = x;
};
//hits the submit button
var ShipIt = function(){
document.querySelector(".topbar-nav > form:nth-child(3)").submit();
};
var Finalize = function(){
titlePort(self.options.Cargo.Title);
ShipIt();
};
Finalize();
searchWS.js
document.addEventListener("submit", function(event) {
console.log("Unloading now");
self.port.emit("myMessage");
}, false);
//puts words in the input box
var titlePort = function(x){
var WSzA = document.querySelector("form#search-backup-search input");
WSzA.value = x;
};
//hits the submit button
var ShipIt = function(){
document.querySelector("form#search-backup-search").submit();
};
var Finalize = function(){
titlePort(self.options.Cargo.Title);
ShipIt();
};
Finalize();
searchDA.js
document.addEventListener("submit", function(event) {
console.log("Unloading now");
self.port.emit("myMessage");
}, false);
//puts words in the input box
var titlePort = function(x){
var DAzA = document.querySelector("input.gmbutton2");
DAzA.value = x;
};
//hits the submit button
var ShipIt = function(){
document.querySelector("#search7").submit();
};
var Finalize = function(){
titlePort(self.options.Cargo.Title);
ShipIt();
};
Finalize();
What does work
It stores the user input.
The addon loads all the tabs in the series perfectly.
The first script runs smoothly on the first tab.
When tested separately, each of the scripts runs the search result like they should.
The problem
When everything is finished, not all the tabs display the search results. Several of the search boxes are left blank as if the scripts never ran on those tabs.
The script of the first tab always works, but the scripts on the rest of the tabs have a random chance of not working.
I noticed the console.log("Step 4, search "+ count +" is shuttin down!"); is never executed. I think this means the worker is never destroyed.
That might be causing these issues.
The worker for each script should be destroyed after the script runs the following: self.port.emit("myMessage");
This little segment of code is at the top of every script. But I think the submit process happens too fast for the event listener to be triggered.
Error message
I am getting the following error message for each of the scripts that do not work:
Object
- _errorType = TypeError
- message = FAzA is null
- fileName = resource://gre/modules/commonjs/toolkit/loader.js -> resource:/
/gre/modules/commonjs/sdk/loader/sandbox.js -> resource://jid1-tbpzbqttcoeaag-at
-jetpack/my-addon/data/searchFA.js
- lineNumber = 8
- stack = titlePort#resource://gre/modules/commonjs/toolkit/loader.js -> res
ource://gre/modules/commonjs/sdk/loader/sandbox.js -> resource://jid1- tbpzbqttco
eaag-at-jetpack/my- addon/data/searchFA.js:8:2|Finalize#resource://gre/modules/co
mmonjs/toolkit/loader.js -> resource://gre/modules/commonjs/sdk/loader/sandbox.j
s -> resource://jid1-tbpzbqttcoeaag-at-jetpack/my- addon/data/searchFA.js:15:1|#r
esource://gre/modules/commonjs/toolkit/loader.js -> resource://gre/modules/commo
njs/sdk/loader/sandbox.js -> resource://jid1-tbpzbqttcoeaag-at-jetpack/my- addon/
data/searchFA.js:18:1|
- name = TypeError
If only one tab/script is run, this error never happens. This is true for every tab/script combination. So I know they should all work.
My Question to you
How can I destroy the worker of each script after the script runs the submit function?
Your error:
FAzA is null
indicates that the element was not found in the page when using querySelector().
The problem is mostly here:
tabs.on('ready', function RunPostScript(tab) {...});
This monitors all the tabs and creates a race condition when submitting a search. The following happens:
attach ready event listener to tabs waiting for site A
open site A
page A fires ready event, attach script A to site A
remove ready event listener
increment count
end of loop, call next tab
attach ready event listener to tabs waiting for site B
meanwhile, site A submits the search, it loads the result page and fires a ready event
attach script B to site A
site A is now processed as site B, script B can't find the search input, outputs error
remove ready event listener
increment count
end of loop, call next tab
attach ready event listener to tabs waiting for site C
etc
You should monitor events at the tab level. Use once() so you don't have to remove the listener. Something like this:
function TabIt(x) {
tabs.open({
url:sites.urls[x],
onOpen: function(x, tab) {
// fire once
// count is available in this scope, no need to setup as arg again
tab.once('ready', function readyStuff(tab) {
tab.attach({
contentScriptFile: sites.scripts[x],
contentScriptOptions:{Cargo}
});
});
}
});
++count;
doit();
}
You also keep using count instead of x, while it's possible to do so, it would require binding the value because of the scope in which count exists. But since you have x, just use it.
I also advised in comments to use DOMContentLoaded in attached scripts. After reading more on script attachment to tabs, that was bad advice.
Your code could be vastly optimized but let's do one thing at a time.
const { getMostRecentBrowserWindow } = require('sdk/window/utils');
var aDOMWindow = getMostRecentBrowserWindow();
if (aDOMWindow.gBrowser && aDOMWindow.gBrowser.tabContainer) {
var tabs = aDOMWindow.gBrowser.tabContainer.childNodes;
for (var i=0; i<tabs.length; i++) {
// tabs[i].contentWindow.wrappedJSObject.... // not e10s friendly, so to tabs[i].messageManager or something like that
}
}
here is frame scripts which are absolutely easy:
https://github.com/mdn/e10s-example-addons/tree/master/run-script-in-all-pages
I'm doing some HTML prototyping to explore some UX stuff. Whilst trying to work out why a Javascript function (which uses a lot of jQuery) wasn't working I broke it out into a JS Fiddle. It seems that when the function is called on document.ready it won't work and can't be executed with a click event. However, if it isn't called at document.ready then it will work! I'm probably missing something obvious...
Working: http://jsfiddle.net/NWmB5/
$(document).ready(function() {
$('#targetFirstDiv').click(function() {
setTimelinePosition($('#anotherDiv'));
});
$('#targetSecondDiv').click(function() {
setTimelinePosition($('#testDiv'));
});
});
var toDoCategories = [$("#testDiv"),$("#anotherDiv")];
/* Show current position on timeline */
function setTimelinePosition($position) {
var $theTimelineTrigger = $('span.timelineTrigger');
toDoCategories.forEach(function(currentCategory) {
var $deselectTimelinePositionElement = $(currentCategory, $theTimelineTrigger);
$($deselectTimelinePositionElement).removeClass('currentPosition');
});
var $selectTimelinePositionElement = ($($position,$theTimelineTrigger));
$($selectTimelinePositionElement).addClass('currentPosition');
}
Not Working: http://jsfiddle.net/NWmB5/5/
$(document).ready(function() {
setTimelinePosition($('#thirdDiv'));
$('#targetFirstDiv').click(function() {
setTimelinePosition($('#anotherDiv'));
});
$('#targetSecondDiv').click(function() {
setTimelinePosition($('#testDiv'));
});
});
var toDoCategories = [$("#testDiv"),$("#anotherDiv"),$("thirdDiv")];
/* Show current position on timeline */
function setTimelinePosition($position) {
var $theTimelineTrigger = $('span.timelineTrigger');
toDoCategories.forEach(function(currentCategory) {
var $deselectTimelinePositionElement = $(currentCategory, $theTimelineTrigger);
$($deselectTimelinePositionElement).removeClass('currentPosition');
});
var $selectTimelinePositionElement = ($($position,$theTimelineTrigger));
$($selectTimelinePositionElement).addClass('currentPosition');
}
You trying to get $("#testDiv"),$("#anotherDiv"),$("thirdDiv") before DOM ready event fired that's where the exact problem.Try after DOM ready fired
var toDoCategories = [$("#testDiv"),$("#anotherDiv"),$("thirdDiv")];
So get $("#testDiv"),$("#anotherDiv"),$("thirdDiv") after DOM ready event dispatched.
var toDoCategories; //NOTE HERE
$(document).ready(function() {
toDoCategories = [$("#testDiv"),$("#anotherDiv"),$("thirdDiv")]; //NOTE HERE
setTimelinePosition($('#thirdDiv'));
$('#targetFirstDiv').click(function() {
setTimelinePosition($('#anotherDiv'));
});
$('#targetSecondDiv').click(function() {
setTimelinePosition($('#testDiv'));
});
});
/* Show current position on timeline */
function setTimelinePosition($position) {
var $theTimelineTrigger = $('span.timelineTrigger');
toDoCategories.forEach(function(currentCategory) {
var $deselectTimelinePositionElement = $(currentCategory, $theTimelineTrigger);
$($deselectTimelinePositionElement).removeClass('currentPosition');
});
var $selectTimelinePositionElement = ($($position,$theTimelineTrigger));
$($selectTimelinePositionElement).addClass('currentPosition');
}
Ok with this..
$(window).scroll(function()
{
$('.slides_layover').removeClass('showing_layover');
$('#slides_effect').show();
});
I can tell when someone is scrolling from what I understand. So with that I am trying to figure out how to catch when someone has stopped. From the above example you can see I am removing a class from a set of elements while the scrolling is occurring. However, I want to put that class back on when the user stops scrolling.
The reason for this is I am intent on having a layover show while the page is scrolling to give the page a special effect I am attempting to work on. But the one class I am trying to remove while scrolling conflicts with that effect as its a transparency effect to some nature.
$(window).scroll(function() {
clearTimeout($.data(this, 'scrollTimer'));
$.data(this, 'scrollTimer', setTimeout(function() {
// do something
console.log("Haven't scrolled in 250ms!");
}, 250));
});
Update
I wrote an extension to enhance jQuery's default on-event-handler. It attaches an event handler function for one or more events to the selected elements and calls the handler function if the event was not triggered for a given interval. This is useful if you want to fire a callback only after a delay, like the resize event, or such.
It is important to check the github-repo for updates!
https://github.com/yckart/jquery.unevent.js
;(function ($) {
var on = $.fn.on, timer;
$.fn.on = function () {
var args = Array.apply(null, arguments);
var last = args[args.length - 1];
if (isNaN(last) || (last === 1 && args.pop())) return on.apply(this, args);
var delay = args.pop();
var fn = args.pop();
args.push(function () {
var self = this, params = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(self, params);
}, delay);
});
return on.apply(this, args);
};
}(this.jQuery || this.Zepto));
Use it like any other on or bind-event handler, except that you can pass an extra parameter as a last:
$(window).on('scroll', function(e) {
console.log(e.type + '-event was 250ms not triggered');
}, 250);
http://yckart.github.com/jquery.unevent.js/
(this demo uses resize instead of scroll, but who cares?!)
Using jQuery throttle / debounce
jQuery debounce is a nice one for problems like this. jsFidlle
$(window).scroll($.debounce( 250, true, function(){
$('#scrollMsg').html('SCROLLING!');
}));
$(window).scroll($.debounce( 250, function(){
$('#scrollMsg').html('DONE!');
}));
The second parameter is the "at_begin" flag. Here I've shown how to execute code both at "scroll start" and "scroll finish".
Using Lodash
As suggested by Barry P, jsFiddle, underscore or lodash also have a debounce, each with slightly different apis.
$(window).scroll(_.debounce(function(){
$('#scrollMsg').html('SCROLLING!');
}, 150, { 'leading': true, 'trailing': false }));
$(window).scroll(_.debounce(function(){
$('#scrollMsg').html('STOPPED!');
}, 150));
Rob W suggected I check out another post here on stack that was essentially a similar post to my original one. Which reading through that I found a link to a site:
http://james.padolsey.com/javascript/special-scroll-events-for-jquery/
This actually ended up helping solve my problem very nicely after a little tweaking for my own needs, but over all helped get a lot of the guff out of the way and saved me about 4 hours of figuring it out on my own.
Seeing as this post seems to have some merit, I figured I would come back and provide the code found originally on the link mentioned, just in case the author ever decided to go a different direction with the site and ended up taking down the link.
(function(){
var special = jQuery.event.special,
uid1 = 'D' + (+new Date()),
uid2 = 'D' + (+new Date() + 1);
special.scrollstart = {
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
} else {
evt.type = 'scrollstart';
jQuery.event.handle.apply(_self, _args);
}
timer = setTimeout( function(){
timer = null;
}, special.scrollstop.latency);
};
jQuery(this).bind('scroll', handler).data(uid1, handler);
},
teardown: function(){
jQuery(this).unbind( 'scroll', jQuery(this).data(uid1) );
}
};
special.scrollstop = {
latency: 300,
setup: function() {
var timer,
handler = function(evt) {
var _self = this,
_args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout( function(){
timer = null;
evt.type = 'scrollstop';
jQuery.event.handle.apply(_self, _args);
}, special.scrollstop.latency);
};
jQuery(this).bind('scroll', handler).data(uid2, handler);
},
teardown: function() {
jQuery(this).unbind( 'scroll', jQuery(this).data(uid2) );
}
};
})();
I agreed with some of the comments above that listening for a timeout wasn't accurate enough as that will trigger when you stop moving the scroll bar for long enough instead of when you stop scrolling. I think a better solution is to listen for the user letting go of the mouse (mouseup) as soon as they start scrolling:
$(window).scroll(function(){
$('#scrollMsg').html('SCROLLING!');
var stopListener = $(window).mouseup(function(){ // listen to mouse up
$('#scrollMsg').html('STOPPED SCROLLING!');
stopListner(); // Stop listening to mouse up after heard for the first time
});
});
and an example of it working can be seen in this JSFiddle
ES6 style with checking scrolling start also.
function onScrollHandler(params: {
onStart: () => void,
onStop: () => void,
timeout: number
}) {
const {onStart, onStop, timeout = 200} = params
let timer = null
return (event) => {
if (timer) {
clearTimeout(timer)
} else {
onStart && onStart(event)
}
timer = setTimeout(() => {
timer = null
onStop && onStop(event)
}, timeout)
}
}
Usage:
yourScrollableElement.addEventListener('scroll', onScrollHandler({
onStart: (event) => {
console.log('Scrolling has started')
},
onStop: (event) => {
console.log('Scrolling has stopped')
},
timeout: 123 // Remove to use default value
}))
You could set an interval that runs every 500 ms or so, along the lines of the following:
var curOffset, oldOffset;
oldOffset = $(window).scrollTop();
var $el = $('.slides_layover'); // cache jquery ref
setInterval(function() {
curOffset = $(window).scrollTop();
if(curOffset != oldOffset) {
// they're scrolling, remove your class here if it exists
if($el.hasClass('showing_layover')) $el.removeClass('showing_layover');
} else {
// they've stopped, add the class if it doesn't exist
if(!$el.hasClass('showing_layover')) $el.addClass('showing_layover');
}
oldOffset = curOffset;
}, 500);
I haven't tested this code, but the principle should work.
function scrolled() {
//do by scroll start
$(this).off('scroll')[0].setTimeout(function(){
//do by scroll end
$(this).on('scroll',scrolled);
}, 500)
}
$(window).on('scroll',scrolled);
very small Version with start and end ability
This detects the scroll stop after 1 milisecond (or change it) using a global timer:
var scrollTimer;
$(window).on("scroll",function(){
clearTimeout(scrollTimer);
//Do what you want whilst scrolling
scrollTimer=setTimeout(function(){afterScroll()},1);
})
function afterScroll(){
//I catched scroll stop.
}
Ok this is something that I've used before.
Basically you look a hold a ref to the last scrollTop().
Once your timeout clears, you check the current scrollTop() and if they are the same, you are done scrolling.
$(window).scroll((e) ->
clearTimeout(scrollTimer)
$('header').addClass('hidden')
scrollTimer = setTimeout((() ->
if $(this).scrollTop() is currentScrollTop
$('header').removeClass('hidden')
), animationDuration)
currentScrollTop = $(this).scrollTop()
)
please check the jquery mobile scrollstop event
$(document).on("scrollstop",function(){
alert("Stopped scrolling!");
});
For those Who Still Need This Here Is The Solution
$(function(){
var t;
document.addEventListener('scroll',function(e){
clearTimeout(t);
checkScroll();
});
function checkScroll(){
t = setTimeout(function(){
alert('Done Scrolling');
},500); /* You can increase or reduse timer */
}
});
This should work:
var Timer;
$('.Scroll_Table_Div').on("scroll",function()
{
// do somethings
clearTimeout(Timer);
Timer = setTimeout(function()
{
console.log('scrolling is stop');
},50);
});
Here is how you can handle this:
var scrollStop = function (callback) {
if (!callback || typeof callback !== 'function') return;
var isScrolling;
window.addEventListener('scroll', function (event) {
window.clearTimeout(isScrolling);
isScrolling = setTimeout(function() {
callback();
}, 66);
}, false);
};
scrollStop(function () {
console.log('Scrolling has stopped.');
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>.<br>
</body>
</html>
when using the ckeditor link dialog, I have custom code for some extra options. I would also like to grab the selected text to use - so I have called:
selectedContents = CKEDITOR.instances['my_editor'].getSelection().getSelectedText();
I want this to happen when the dialog is loaded. So I wrote an "onShow()" handler function... but that messes up the customizations that I have made to the dialog. I'm guessing that my onShow is grabbing the normal process for that event - how can I continue with the normal processing at that point?
dialogDefinition.onShow = function(evt)
{
contents = CKEDITOR.instances['my_editor'].getSelection().getSelectedText();
// now here, continue as you were...
}
Ok, I still have some issues, but the answer to this question is to grab the existing "onShow" handler before overwriting it. Use a global, then it can be called within the new handler:
var dialogDefinition = ev.data.definition;
var oldOnShow = dialogDefinition.onShow;
dialogDefinition.onShow = function(evt) {
// do some stuff
// do some more stuff
// call old function
oldOnShow();
}
Depending on Andy Wallace code:
var oldOnShow = dialogDefinition.onShow;
var newOnShow = function () {
//your code
}
and then:
dialogDefinition.onShow = function(){
oldOnShow.call(this, arguments);
newOnShow.call(this, arguments);
}
It helps me!
Correct syntax is:
/* if new picture, then open the Upload tab */
CKEDITOR.on('dialogDefinition', function(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
var dialog = dialogDefinition.dialog;
if (dialogName == 'image2') {
dialogDefinition.onShow = CKEDITOR.tools.override(dialogDefinition.onShow, function(original) {
return function() {
original.call(this);
CKEDITOR.tools.setTimeout( function() {
if (dialog.getContentElement('info', 'src').getValue() == '') {
dialog.selectPage('Upload');
}
}, 0);
}
});
}
});