I'm making an HTML5 game with melonjs.
One of my entitie (called ET1) needs to listen on 2 events : pointerup & pointerdown. My events are registered in my game.js file, as follow :
me.input.registerPointerEvent("pointerup", me.game.viewport, function (event) {
me.event.publish("pointerup", [ event ]);
});
me.input.registerPointerEvent("pointerdown", me.game.viewport, function (event) {
me.event.publish("pointerdown", [ event ]);
});
In my ET1 entitie, i'm listening for both of the events :
this.handler = me.event.subscribe("pointerup", function (event) {
...
});
this.handlerDown = me.event.subscribe("pointerdown", function (event) {
...
});
When the pointerdown event is triggered, i'm updating a local property, and if this property reach a certain value, i would like to trigger the pointerup event manually from the update method :
update : function (dt) {
this.handler = me.event.subscribe("pointerup", function (event) {
...
});
this.handlerDown = me.event.subscribe("pointerdown", function (event) {
...
});
localVar++;
if(localVar > 10){
// trigger pointerup event
}
}
I now it's possible with event.publish from withing a registerPointerEvent callback, but i hav no idea how to do this from the entitie update method.
Any idea ?
if you don't do anything with the Event object, you can just manually publish the "pointerup" message, same way as you subscribe to them :
me.event.publish("pointerup", [{}]);
{} here meaning to replace the Event object, although you could pass it as well since it's available in the global scope
Related
I'm trying to find a way to simulate a "change" event when doing E2E testing (with selenium or cypress) and slate.js
In our UI, when the user clicks on a word, we pop-up a modal (related to that word). I've been unable to make this happen as I can't get the change event to trigger
The Cypress input commands (e.g. cy.type() and cy.clear()) work by dispatching input and change events - in the case of cy.type(), one per character. This mimics the behavior of a real browser as a user types on their keyboard and is enough to trigger the behavior of most application JavaScript.
However, Slate relies almost exclusively on the beforeinput event (see here https://docs.slatejs.org/concepts/xx-migrating#beforeinput) which is a new browser technology and an event which the Cypress input commands don’t simulate. Hopefully the Cypress team will update their input commands to dispatch the beforeinput event, but until they do I’ve created a couple of simple custom commands which will trigger Slate’s input event listeners and make it respond.
// commands.js
Cypress.Commands.add('getEditor', (selector) => {
return cy.get(selector)
.click();
});
Cypress.Commands.add('typeInSlate', { prevSubject: true }, (subject, text) => {
return cy.wrap(subject)
.then(subject => {
subject[0].dispatchEvent(new InputEvent('beforeinput', { inputType: 'insertText', data: text }));
return subject;
})
});
Cypress.Commands.add('clearInSlate', { prevSubject: true }, (subject) => {
return cy.wrap(subject)
.then(subject => {
subject[0].dispatchEvent(new InputEvent('beforeinput', { inputType: 'deleteHardLineBackward' }))
return subject;
})
});
// slateEditor.spec.js
cy.getEditor('[data-testid=slateEditor1] [contenteditable]')
.typeInSlate('Some input text ');
cy.getEditor('[data-testid=slateEditor2] [contenteditable]')
.clearInSlate()
.typeInSlate('http://httpbin.org/status/409');
If you need to support other inputTypes, all of the inputTypes supported by Slate are listed in the source code for editable.tsx
Found a solution:
1) Add a ref to the Editor
<Editor
ref={this.editor}
/>
2) Add a document listener for a custom event
componentDidMount() {
document.addEventListener("Test_SelectWord", this.onTestSelectWord)
}
componentWillUnmount() {
document.removeEventListener("Test_SelectWord", this.onTestSelectWord)
}
3) Create a handler that creates a custom select event
onTestSelectWord(val: any) {
let slateEditor = val.detail.parentElement.parentElement.parentElement.parentElement
// Events are special, can't use spread or Object.keys
let selectEvent: any = {}
for (let key in val) {
if (key === 'currentTarget') {
selectEvent['currentTarget'] = slateEditor
}
else if (key === 'type') {
selectEvent['type'] = "select"
}
else {
selectEvent[key] = val[key]
}
}
// Make selection
let selection = window.getSelection();
let range = document.createRange();
range.selectNodeContents(val.detail);
selection.removeAllRanges();
selection.addRange(range)
// Fire select event
this.editor.current.onEvent("onSelect", selectEvent)
}
4) User the following in your test code:
arr = Array.from(document.querySelectorAll(".cl-token-node"))
text = arr.filter(element => element.children[0].innerText === "*WORD_YOU_ARE_SELECTING*")[0].children[0].children[0]
var event = new CustomEvent("Test_SelectWord", {detail: text})
document.dispatchEvent(event, text)
Cypress can explicitly trigger events: https://docs.cypress.io/api/commands/trigger.html#Syntax
This may work for you:
cy.get(#element).trigger("change")
I am trying to test a event in a Template. Within the click event, there is a Reactive Var that gets set.
The test is blocked by the Reactive Var.
Any ideas on how I stub or mock a reactive var in a template? I tried adding it to the template (template.reactiveVar = "whatever"), but no go, as I don't think it's writeable.
The ?? indicate where I am wondering what to put.
it('sets a reactive var when a button is clicked', function(){
Template.button.fireEvent('click ', {
context: { some: 'values'},
event: {'target': {'text': 'randomText' } },
templateInstance:new Template('upload', function(e) {
this.reactiveVar = new ReactiveVar("not clicked)
})
});
chai.assert.equal(Template.reactiveVar, "clicked")});
// The actual template is below..
Template.button.events{(
'click button': function(evt, template){
var text = evt.target.text
template.reactiveVar.set(text)
}
});
The result is...
TypeError: Cannot read property 'set' of undefined
Any ideas?
I suspect the event is actually firing and getting through to your event handler before the callback that creates the reactive var has run.
You should create the reactive var when you first create the template independent of your test:
Template.button.onCreated(function(){
this.reactiveVar = new ReactiveVar("not clicked");
});
I have this script for countdown I wanted it to start as soon as the page loads (ideally i wanted it to run continuously since it is repeating in intervals).
when I call any function such as [startCountdown()] or [ countdown.start($('#countdown_clock').val());] I keep getting the same error [Uncaught ReferenceError: countdown is not defined]
here is the whole function
window.onload = function mainCountdown() {
var countdown = Tock({
countdown: true,
interval: 250,
callback: function () {
// console.log(countdown.lap() / 1000);
$('#countdown_clock').val(countdown.msToTime(countdown.lap()));
// countdown.start($('#countdown_clock').val());
},
complete: function () {
// console.log('end');
// alert("Time's up!");
repeatCountdown();
console.log('alarm');
}
});
$('#startCountdown').on('click', function () {
countdown.start($('#countdown_clock').val());
});
$('#pauseCountdown').on('click', function () {
countdown.pause();
});
$('#stopCountdown').on('click', function () {
countdown.stop();
});
$('#resetCountdown').on('click', function () {
countdown.stop();
$('#countdown_clock').val('00:10');
});
function repeatCountdown() {
countdown.stop();
$('#countdown_clock').val('00:10');
countdown.start($('#countdown_clock').val());
}
function startCountdown(){
countdown.start($('#countdown_clock').val());
}
}
How can I start the countdown without any button events.
Thank you in advance
You seem to have a few syntax issues that might be causing the problem. First, I'd call the window load event like this:
$(window).load(function () {
// functions, etc here
});
Then, inside the window load event, you can create your timer like this:
var countdown = new Tock(...
You were missing the 'var' and 'new' keywords. You might want to revisit the Tock documentation to make sure everything else was correct, too.
I am using Durandal 2.1, and I am having a problem with view composition. I have a view for managing many types of items. I also want a view to manage a subset of those types. So I created a manage view and a managesubset view. The managesubset view just composes the manage view and passes it an array containing the subset of items. This way the user can go to /100/manage or 100/managesubset where managesubset will only allow the user to manage a subset of items. I am using this pattern because I will have multiple different versions of managesubset.
My problem is that the canDeactivate method is not fired when going to managesubset. Is there anyway to fire the canDeactivate and Deactivate lifecycle events when composing?
According to #3 under Activator Lifecycle Callbacks here, I should be able to do this, but I cannot find any good examples.
Code:
manage.js
define(['durandal/app', 'plugins/router'], function (app, router) {
var constructor = function () {
var self = this;
//...variable creation and assignment
//life cycle events
self.activate = function (viewmodel) {
self.recordId(viewmodel.recordId);
self.assignableTypes(viewmodel.assignableTypes);
self.pageHeaderTitle = viewmodel.pageHeaderTitle;
self.pageHeaderIcon = viewmodel.pageHeaderIcon;
};
self.canActivate = function (id) {
var deferred = $.Deferred();
//check if user has access to manage equipment
};
self.canDeactivate = function () {
if (!self.saveSuccessfull() && this.isDirty()) {
return app.showMessage("You have unsaved changes, are you sure you want to leave?", "Unsaved Changes", ["Yes", "No"]);
}
else {
return true;
}
}
};
return constructor;
});
managesubset.js
define([], function () {
var recordId = ko.observable();
var manageRecord = ko.observable();
return {
recordId: recordId,
manageRecord: manageRecord,
activate: function (id) {
recordId(id);
manageRecord({
pageHeaderTitle: 'Manage Subset',
pageHeaderIcon: 'cb-subset',
assignableTypes: [102],
recordId: recordId()
});
},
canActivate: function (id) {
var deferred = $.Deferred();
//check if user has access to manage equipment
}
}
});
managesubset.html
<div data-bind="compose: { model: 'manage', activationData: manageRecord() }"></div>
The activate is called correctly each time. The deactivate and canDeactive are what don't work, and they are never called.
I have the following:
casper.then(function addToBag(){
this.evaluate(function (){
//register sub method - then emit custom event
mns.msg.sub("/ajax/success/addToCart" + $("[name=productCode]").val(), function (response) {
casper.emit('addToCart.loaded');
});
//trigger add to cart click
$('.product-selection input[type=submit]').click();
});
});
The click trigger activates the emit, inside the event function:
casper.on("addToCart.loaded", function checkAddToCartResponse(){
console.log("Added");
test.assert(true,'Add to cart successful');
}),
However, it doesn't seem to run - is this the correct way of running a test when an event has finished?
The event is not emitted because there is no casper instance inside the page context (inside the evaluate context).
You would need to set some flag that the event was emitted.
casper.then(function addToBag(){
this.evaluate(function (){
//register sub method - then emit custom event
window.casperEventEmitted = null;
mns.msg.sub("/ajax/success/addToCart" + $("[name=productCode]").val(), function (response) {
window.casperEventEmitted = 'addToCart.loaded';
});
//trigger add to cart click
$('.product-selection input[type=submit]').click();
});
});
// wait here
and then wait for the event to be set
var timeout = 10000; // msec, some sensible timeout for your event
casper.waitFor(function check() {
return this.getGlobal('casperEventEmitted') == 'addToCart.loaded';
}, function then() {
return this.evaluate(function() {
window.casperEventEmitted = null; // reset for next time
});
this.test.pass("Event triggered");
}, function onTimeout(){
this.test.fail("Event triggered");
}, timeout);
Of course it would be nicer to manage the events in a queue and not as a single string.
The good thing is that there is no break out from the control flow as it would happen with a custom event like in the case of the other answer.
Use inside the evaluate callback:
console.log("casper-event:add:[1234]");
then can do it like this (not tested):
casper.on('remote.message', function(msg) {
if(msg.indexOf("casper-event:" == 0))
{
var event = msg.replace(/^casper-event:/, '').replace(/:.*$/, '');
var result = JSON.parse(msg.replace(/^casper-event:.*?:/, ''));
this.emit(event, result);
}
});
casper.on('add'........