SWUP JS external function call - javascript

this is my first time using swup js with the js plugin. https://swup.js.org/plugins/js-plugin
I can see that the trigger to go to the clicked page lies inside the object array of options.
My question is there anyway I can trigger the "next" from external function
const options = [
{
from: '(.*)',
to: '(.*)',
in: function(next) {
document.querySelector('#swup').style.opacity = 0;
TweenLite.to(document.querySelector('#swup'), 0.5, {
opacity: 1,
onComplete: next
});
},
out: (next) => {
document.querySelector('#swup').style.opacity = 1;
TweenLite.to(document.querySelector('#swup'), 0.5, {
opacity: 0,
onComplete: next
});
}
}
];
const swup = new Swup({
plugins: [new SwupJsPlugin(options)]
});
how do I trigger the "next " from another outside function not within Const options?
for example
counts trigger = function(){
options.next();
thanks
this doesn't work
thanks

You cannot do that. Swup JS plugin uses the defined options to run in and out functions at the right time while passing the next argument to it.
The next argument is present only as a way to let swup know that the animation has finished and it can continue in whatever it needs to do next.

Related

Make slideshow/animation with multiple images

i know that there are question similar to this one, but my goal is different.
I have an array of Sceneobjects like this:
const scene = {
Id: Math.floor(Math.random() * 10000),
JsonObj: canvas.getJsonObj(),
image: this.editor?.export.toImage(),
duration: 1000,
};
And am using a library PikasoJS that alows me to export/import an image of a html div.
I put each image of div in scene object, and i want to display all these images in array scenes one by one automatically, and duration of scene is specified in duration field.
How can i implement something like this, i tried working with setInterval but it didn't work as i espected:
const playScene = () => {
const cpScenes = [...scenes];
let i = 0;
for(let i = 0;i < cpScenes.length;i++) {
setTimeout(() => {
let image = cpScenes[i].image;
console.log("am runnig");
this.editor.loadImage(image);
}, cpScenes[i].duration);
}
clearTimeout();
};
The way am thinking is that setTimeout should block execution of for loop and then executes it's code after specified time. But from what i noticed i was wrong.
This is my first time working with react and js.

Leaflet Routing Machine - update/redraw route

I'm new about Laflet Routing Machine (liedman) https://www.liedman.net/leaflet-routing-machine/ and I would like to update the first route calculated every 30 seconds because I would like refresh it and I don't need to make many server request.
I'll make a setInterval but at the moment I need to know if it works and if this is the way... this is my code:
routingControl = L.Routing.control({
waypoints: [
L.latLng(43.12, 11.99),
L.latLng(43.37, 12.08)
]
createMarker: function() { return null; },
routeWhileDragging: false,
draggableWaypoints: false,
reverseWaypoints: false,
fitSelectedRoutes: true,
addWaypoints: false
}).addTo(OSM_Map);
var newLat = routingControl.options.waypoints[0].lat+0.01;
var newLng = routingControl.options.waypoints[0].lng+0.01;
setTimeout(function () {
routingControl.options.waypoints=[
L.latLng(newLat, newLng),
routingControl.options.waypoints[1]
];
}, 10000);
With setTimeout I change the start point (adding 0.01) and checking the waypoints with console.dir they are changed but not the drawn route... how I can refresh it?
The options are only used when initializing the routing control. Changing them afterwards does nothing, since the control uses its own waypoints internally.
You should be able to use the setWaypoints function like this
setInterval(function () {
var newWaypoint = routingControl.getWaypoints()[0].latLng;
var newLat = newWaypoint.lat + 0.01;
var newLng = newWaypoint.lng + 0.01;
routingControl.setWaypoints([
L.latLng(newLat, newLng),
routingControl.options.waypoints[1]
]);
}, 10000);
Unlike the options, the getWaypoints always returns the current waypoints, so you can freely modify them.
setWaypoints will then trigger a change event for the routes and update them accordingly.
Here's a working fiddle you can play around with

jQuery prevent reload if button clicked

I have a jQuery datatable that immediately loads ON READY. After that, the datatable is reloaded every 30 seconds. This feature is functioning properly.
I have added a search feature that automatically reloads the datatable with new search results. This part is also functioning properly.
The problem I am experiencing is when I am using the search feature, and the new search results are returned. After 30 seconds, the new results are cleared and the datatable reloads with all of the original records.
Here is what I am currently attempting:
$(document).ready(function()
{
var searchCriteria = "";
displayBookings(searchCriteria);
var idle = 0;
var idleInterval = setInterval(timer, 30000);
$(this).mousemove(function(e){idle = 0;});
$(this).keypress(function(e){idle = 0;});
function timer()
{
idle = idle + 1;
if(idle > 2)
{
displayBookings(searchCriteria);
console.log('table reloaded');
}
}
$('#searchPending').on('click', function()
{
var isPending = 'Y';
var searchCriteria = {
isPending: isPending
};
displayBookings(searchCriteria);
});
});
The function displayBookings() takes searchCriteria. If searchCriteria is blank, then a basic query is fired. Obviously is searchCriteria contains parameters, then the same query is fired with a WHERE clause attached. I did not disclose the code for displayBookings().
All I need to do is stop the 30 second interval if the #searchPending button is clicked.
Clear the interval so it will stop loading.
clearInterval(idleInterval)
specifically in your code:
$('#searchPending').on('click', function()
{
clearInterval(idleInterval)
var isPending = 'Y';
var searchCriteria = {
isPending: isPending
};
displayBookings(searchCriteria);
});
Rather than start and stop the timer interval, since you'll run into a bit of a race condition, you can just have the "refresh" (your "timer" function) refresh using the latest search criteria. To do this, just pass the same object into your displayBookings function. E.g.
const search = { criteria: "" };
$(...).click(() => {
search.criteria = 'change it...';
displayBookings(search.criteria);
});
setInterval(() => displayBookings(search.criteria), 30000);
This way, if a refresh happens, it will use the latest search.criteria. You can achieve the same result with minimal change in your code by simply removing the var from the second searchCriteria. Currently, without removing the var, your outer criteria is being "shadowed" by your inner.
I alluded to debouncing1 in one of my comments. I misread the code and debouncing is not what you want. Instead, you want to only "refresh" if there hasn't been any user activity within some threshold. Here's an alternative from the approach you used:
let lastInteraction = 0;
function interact() {
lastInteraction = Date.now();
}
$(this).mousemove(interact);
$(this).keypress(interact);
Then in your refresh function:
if (Date.now() - lastInteraction > threshold) { ...
Implementing both the central criteria and revised idle check:
$(document).ready(function() {
const idle = {
threshold: 1000,
lastInteraction: 0,
interact() {
idle.lastInteraction = Date.now();
},
isIdle() {
return Date.now() - idle.lastInteraction > idle.threshold;
}
};
const search = { criteria: "" };
$(this).mousemove(idle.interact);
$(this).keypress(idle.interact);
setInterval(() => {
if (idle.isIdle()) {
displayBookings(search.criteria);
}
}, 30000);
$('#searchPending').on('click', () => {
search.criteria = { isPending: 'Y' };
displayBookings(search.criteria);
});
displayBookings(search.criteria);
});
1 The Wikipedia article linked to discusses debouncing with a keyboard. It's the same concept. You'd use debouncing on your displayBookings function if you plan on having it execute live as the user is typing. This would prevent too many HTTP requests from happening in a short duration of time.

How can I wait for a condition?

I'm new on protractor, and I'm trying to implement an e2e test.
I don't know if this is the right way to do this, but...
The page that I want to test is not a full angular page based, so... I'm having some trouble.
On my first spec I have:
describe('should open contact page', function() {
var ptor = protractor.getInstance();
beforeEach(function(){
var Login = require('./util/Login');
new Login(ptor);
});
I have created this Login class, but after login I want to open the contact page, but protractor immediately try to find element before the page is fully loaded.
I've tried to use:
browser.driver.wait(function() {
expect(browser.findElement(by.xpath("//a[#href='#/contacts']")).isDisplayed());
ptor.findElement(by.xpath("//a[#href='#/contacts']")).click();
});
But it doesn't work... it always try to find the element before the page loads.
I tried this one too:
browser.driver.wait(function() {
expect(ptor.isElementPresent(by.xpath("//a[#href='#/contacts']")));
ptor.findElement(by.xpath("//a[#href='#/contacts']")).click();
});
I'm able to do that using browser.sleep(); but I don't think that is a good option. Any idea? On my login class I have:
ptor.ignoreSynchronization = true;
How can I wait for this #href='#/contacts before protractor tries to click on it?
Protractor 1.7.0 has also introduced a new feature: Expected Conditions.
There are several predefined conditions to explicitly wait for. In case you want to wait for an element to become present:
var EC = protractor.ExpectedConditions;
var e = element(by.id('xyz'));
browser.wait(EC.presenceOf(e), 10000);
expect(e.isPresent()).toBeTruthy();
See also:
Expected conditions in protractor
I finally find out...
var waitLoading = by.css('#loading.loader-state-hidden');
browser.wait(function() {
return ptor.isElementPresent(waitLoading);
}, 8000);
expect(ptor.isElementPresent(waitLoading)).toBeTruthy();
var openContact = by.xpath("//a[#href='#/contacts']");
element(openContact).click();
With this protractor could wait for that element until it loading page disappears.
Thanks for those who tried to help XD.
I had the same problem you were having for the longest time while using protractor. In my e2e test I start in a non angular app, then get into an angular portion, then get back out to a non angular portion. Made things tricky. The key is to understand promises and how they work. Here's some examples of my real world code in a functioning e2e test. Hoping this gives you an idea of how to structure your tests. Probably some bad practice in this code, please feel free to improve upon this, but I know that it works, maybe not the best way.
To get to angular I use
var ptor;
var events = require('events');
var eventEmitter = new events.EventEmitter();
var secondClick = require('./second-click');
beforeEach(function () {
browser.driver.get('http://localhost:8080/');
},10000);
it("should start the test", function () {
describe("starting", function () {
it("should find the link and start the test", function(){
var elementToFind = by.linkText('Start'); //what element we are looking for
browser.driver.isElementPresent(elementToFind).then(function(isPresent){
expect(isPresent).toBe(true); //the test, kind of redundant but it helps pass or fail
browser.driver.findElement(elementToFind).then(function(start){
start.click().then(function(){ //once we've found the element and its on the page click it!! :)
ptor = protractor.getInstance(); //pass down protractor and the events to other files so we can emit events
secondClick(eventEmitter, ptor); //this is your callback to keep going on to other actions or test in another file
});
});
});
});
});
},60000);
While in angular this code works
describe("type in a message ", function(){
it("should find and type in a random message", function(){
var elementToFind = by.css('form textarea.limited');
browser.driver.isElementPresent(elementToFind).then(function(isPresent){
element(elementToFind).sendKeys(randomSentence).then(function(){
console.log("typed in random message");
continueOn();
});
});
});
},15000);
After exiting angular
browser.driver.wait(function(){
console.log("polling for a firstName to appear");
return browser.driver.isElementPresent(by.name('firstName')).then(function(el){
return el === true;
});
}).
then(function(){
somefunctionToExecute()
});
Hope that gives some guidance and helps you out!
browser.driver.wait(function() {
return browser.driver.isElementPresent(by.xpath("//a[#href='#/contacts']"));
});
This works for me too (without the timeout param)..
for more information, see http://angular.github.io/protractor/#/api?view=webdriver.WebDriver.prototype.wait
Thanks to answers above, this was my simplified and updated usage
function waitFor (selector) {
return browser.wait(function () {
return browser.isElementPresent(by.css(selector));
}, 50000);
}
Have you tried putting the ng-app in the <html> tag (assuming this part of code is under your control)? This solved a lot of initialization timing problems for me.
Best way to use wait conditions in protractor that helps to show proper error message to particular element if test case failed
const EC = ExpectedConditions;
const ele = element(by.xpath(your xpath));
return browser.wait(EC.visibilityOf(ele),9000,'element not found').then(() => {
ele.click();
});
I'm surprised that nobody has added this solution. Basically, if you are using modal dialogues you often get an element visible and available to click but not being clickable due to the modal dialogue being in front of it. This happens because protractor moves faster than angular and is ready to click the next element while angular is still closing the modal.
I suggest using
public async clickElementBug(elementLocator: Locator) {
const elem = await element(elementLocator);
await browser.wait(
async function() {
try {
await elem.click();
return true;
} catch (error) {
return false;
}
},
this.TIMEOUT_MILLIS,
'Clicking of element failed: ' + elem
);
}
browser.wait may sound too ordinary, but it's not!
browser.wait is the way to go. Just pass a function to it that would have a condition which to wait for. For example wait until there is no loading animation on the page
let $animation = $$('.loading');
await browser.wait(
async () => (await animation.count()) === 0, // function; if returns true it stops waiting; can wait for anything in the world if you get creative with it
5000, // timeout
`message on timeout` // comment on error
);
Make sure to use await
You can also use existing library called ExpectedConditions that has lots of predefined conditions to wait for
You can't imagine what you can do with it...
A few of my favorite ones:
wait until the number of browser's tab's is 2
// wait until the number of browser's tab's is 2
await browser.wait(
async () => {
let tabCount = await browser.getAllWindowHandles();
return tabCount.length === 2;
},
5000,
'the url didnt open in a new window'
);
wait until the loading animation is gone for at last 750ms
// wait until the loading animation is gone for at last 750ms
await browser.wait(
async () => (await this.$$loadAnimations.count()) === 0 && !(await browser.sleep(750)) && (await this.$$loadAnimations.count()) === 0,
5000,
`waiting timeout`
);
wait for ANY number of elements to be present
// wait for any number of elements to be present
async waitForElements($elem, timeout = 120000, start = +new Date()) {
let conditions = [];
for (let i = 0; i < $elem.length; i++) {
conditions.push(ExpectedConditions.presenceOf($elem[i]));
}
await browser.wait(
ExpectedConditions.and(...conditions),
remainingTimeout(timeout, start),
`wait for all elements`
);
}
// and use
await waitForElements([
$usernameField,
$passwordFiend,
$submitButton
])

javascript WAIT for something to be true

i create in a javascript function a prototype window. in the window i load a site where the user has to select something. i want the javascript function to wait until the user selected something and then return the value of the what the user selected.
function showTargetDirectoryChooser(){
var win = new Window( 'dirchooser_' + new Date().getTime() , {className: 'alphacube', width: 320, height: 470, url: '/directories/choose', maximizable: false});
win.showCenter();
win.setDestroyOnClose();
// WAIT_UNTIL( win.content.contentWindow.Directory != null )
return win.content.contentWindow.Directory
}
i found here something i could maybe use - but i dont understand how to...
This is an asynchronous process; it’s probably better to handle this with a callback.
For example, couldn’t you use a closeCallback?
function showTargetDirectoryChooser(done){
var win = new Window( 'dirchooser_' + new Date().getTime() , {className: 'alphacube', width: 320, height: 470, url: '/directories/choose', maximizable: false});
win.showCenter();
win.setDestroyOnClose();
// This will ensure
win.setCloseCallback(function () {
done(win.content.contentWindow.Directory);
return true; // or return false if you don't want the window to be closed
});
return true;
}
With this, you would change
var chosenDir = showTargetDirectoryChooser();
// do something with chosen directory
into
var chosenDir;
showTargetDirectoryChooser(function (directory) {
chosenDir = directory;
// do something with the chosen directory
});
One option would be to use an event handler. When Directory is set via click or perhaps a change event, if that is fired, attach a handler which takes that event and passes it back to a function in your main window. This will require making your code asynchronous - so that you have a caller that calls showTargetDirectoryChooser() and a callback that takes the result of the directory as separate functions. It shouldn't be too complicated to re-architect your code there and break it up to the caller and the callback, though.
You can also use setTimeout and poll the contents of win.content.contentWindow.Directory like so:
function showTargetDirectoryChooser(){
var win = new Window( 'dirchooser_' + new Date().getTime() , {className: 'alphacube', width: 320, height: 470, url: '/directories/choose', maximizable: false});
win.showCenter();
win.setDestroyOnClose();
setTimeout("pollDirectory()", 500); // poll in a half second
}
function pollDirectory() {
if(win.content.contentWindow.Directory != null) {
callback(win.content.contentWindow.Directory); // you will need an asynch callback
} else {
setTimeout("pollDirectory()", 500); // poll in a half second
}
}
Doing it this way also requires that your code be asynchronous.
Another option is to look into jquery wait, but that is a timeout as opposed to waiting on a condition. Or there is a set of reactive extensions to JS, but that looks to be overkill for what you are doing. The concept of an observable may be something you want to look into, though.

Categories

Resources