I have a working paper with graph. I have added several cells to the graph and I'm trying to listen to the cell:highlight event but I never receive it.
I'm doing:
paper.on('cell:highlight', function() { ... });
Other events seem to work fine, for example: blank:pointerup,...
Is there something special to do to make cell events work ?
According to documentation:
cell:highlight - triggered when highlight() method is called on either
an element or a link. Note that this method is also called
automatically when the user is reconnecting a link and the connection
is valid (validateConnection() returns true) or if embeddingMode is
enabled on the paper and the dragging element is above another element
it could be dropped into (validateEmbedding() returns true). The
handler for this event has the following signature: function(cellView,el). The handler defaults to function(cellView, el) {
V(el).addClass('highlighted') }. In other words, the 'higlighted' CSS
class is added and so you can style the highlighted element in CSS. If
you want to use a different method for highlighting cells, call
paper.off('cell:highlight') first to unregister the default handler
and then paper.on('cell:highlight', myHandler) to register your own.
You can read more about it here.
Related
I have a desktop robot device, which connects to a web browser(chrome) using ble(Bluetooth low energy), I have created a custom event in js code to catch some motion values when the robot moves.
but in pixijs all events are base on mouse move, how can I extend it to adapt my scenarios.
See: https://github.com/pixijs/pixi.js/blob/v6.0.0/packages/interaction/src/InteractionManager.ts#L858
I think that you would need to create your own version of InteractionManager as a plugin, and modify that method addEvents(). You would need to listen to your custom event which is fired when the robot moves.
// instead of:
self.document.addEventListener('mousemove', this.onPointerMove, true);
// do like this:
self.document.addEventListener('my_custom_robot_move', this.onPointerMove, true);
etc.
Normally the InteractionManager is registered here: https://github.com/pixijs/pixi.js/blob/fe7b2191e0311b8174a012366ff21c8e2b6dc153/bundles/pixi.js/src/index.ts#L30 - so you would need to call something like this at beginning of your js code (just after the pixi scripts are loaded probably):
Renderer.registerPlugin('interaction', MyInteractionManager);
Essentially I want to have a script execute when the contents of a DIV change. Since the scripts are separate (content script in the Chrome extension & webpage script), I need a way simply observe changes in DOM state. I could set up polling but that seems sloppy.
For a long time, DOM3 mutation events were the best available solution, but they have been deprecated for performance reasons. DOM4 Mutation Observers are the replacement for deprecated DOM3 mutation events. They are currently implemented in modern browsers as MutationObserver (or as the vendor-prefixed WebKitMutationObserver in old versions of Chrome):
MutationObserver = window.MutationObserver || window.WebKitMutationObserver;
var observer = new MutationObserver(function(mutations, observer) {
// fired when a mutation occurs
console.log(mutations, observer);
// ...
});
// define what element should be observed by the observer
// and what types of mutations trigger the callback
observer.observe(document, {
subtree: true,
attributes: true
//...
});
This example listens for DOM changes on document and its entire subtree, and it will fire on changes to element attributes as well as structural changes. The draft spec has a full list of valid mutation listener properties:
childList
Set to true if mutations to target's children are to be observed.
attributes
Set to true if mutations to target's attributes are to be observed.
characterData
Set to true if mutations to target's data are to be observed.
subtree
Set to true if mutations to not just target, but also target's descendants are to be observed.
attributeOldValue
Set to true if attributes is set to true and target's attribute value before the mutation needs to be recorded.
characterDataOldValue
Set to true if characterData is set to true and target's data before the mutation needs to be recorded.
attributeFilter
Set to a list of attribute local names (without namespace) if not all attribute mutations need to be observed.
(This list is current as of April 2014; you may check the specification for any changes.)
Edit
This answer is now deprecated. See the answer by apsillers.
Since this is for a Chrome extension, you might as well use the standard DOM event - DOMSubtreeModified. See the support for this event across browsers. It has been supported in Chrome since 1.0.
$("#someDiv").bind("DOMSubtreeModified", function() {
alert("tree changed");
});
See a working example here.
Many sites use AJAX/XHR/fetch to add, show, modify content dynamically and window.history API instead of in-site navigation so current URL is changed programmatically. Such sites are called SPA, short for Single Page Application.
Usual JS methods of detecting page changes
MutationObserver (docs) to literally detect DOM changes.
Info/examples:
How to change the HTML content as it's loading on the page
Performance of MutationObserver to detect nodes in entire DOM.
Lightweight observer to react to a change only if URL also changed:
let lastUrl = location.href;
new MutationObserver(() => {
const url = location.href;
if (url !== lastUrl) {
lastUrl = url;
onUrlChange();
}
}).observe(document, {subtree: true, childList: true});
function onUrlChange() {
console.log('URL changed!', location.href);
}
Event listener for sites that signal content change by sending a DOM event:
pjax:end on document used by many pjax-based sites e.g. GitHub,
see How to run jQuery before and after a pjax load?
message on window used by e.g. Google search in Chrome browser,
see Chrome extension detect Google search refresh
yt-navigate-finish used by Youtube,
see How to detect page navigation on YouTube and modify its appearance seamlessly?
Periodic checking of DOM via setInterval:
Obviously this will work only in cases when you wait for a specific element identified by its id/selector to appear, and it won't let you universally detect new dynamically added content unless you invent some kind of fingerprinting the existing contents.
Cloaking History API:
let _pushState = History.prototype.pushState;
History.prototype.pushState = function (state, title, url) {
_pushState.call(this, state, title, url);
console.log('URL changed', url)
};
Listening to hashchange, popstate events:
window.addEventListener('hashchange', e => {
console.log('URL hash changed', e);
doSomething();
});
window.addEventListener('popstate', e => {
console.log('State changed', e);
doSomething();
});
P.S. All these methods can be used in a WebExtension's content script. It's because the case we're looking at is where the URL was changed via history.pushState or replaceState so the page itself remained the same with the same content script environment.
Another approach depending on how you are changing the div.
If you are using JQuery to change a div's contents with its html() method, you can extend that method and call a registration function each time you put html into a div.
(function( $, oldHtmlMethod ){
// Override the core html method in the jQuery object.
$.fn.html = function(){
// Execute the original HTML method using the
// augmented arguments collection.
var results = oldHtmlMethod.apply( this, arguments );
com.invisibility.elements.findAndRegisterElements(this);
return results;
};
})( jQuery, jQuery.fn.html );
We just intercept the calls to html(), call a registration function with this, which in the context refers to the target element getting new content, then we pass on the call to the original jquery.html() function. Remember to return the results of the original html() method, because JQuery expects it for method chaining.
For more info on method overriding and extension, check out http://www.bennadel.com/blog/2009-Using-Self-Executing-Function-Arguments-To-Override-Core-jQuery-Methods.htm, which is where I cribbed the closure function. Also check out the plugins tutorial at JQuery's site.
In addition to the "raw" tools provided by MutationObserver API, there exist "convenience" libraries to work with DOM mutations.
Consider: MutationObserver represents each DOM change in terms of subtrees. So if you're, for instance, waiting for a certain element to be inserted, it may be deep inside the children of mutations.mutation[i].addedNodes[j].
Another problem is when your own code, in reaction to mutations, changes DOM - you often want to filter it out.
A good convenience library that solves such problems is mutation-summary (disclaimer: I'm not the author, just a satisfied user), which enables you to specify queries of what you're interested in, and get exactly that.
Basic usage example from the docs:
var observer = new MutationSummary({
callback: updateWidgets,
queries: [{
element: '[data-widget]'
}]
});
function updateWidgets(summaries) {
var widgetSummary = summaries[0];
widgetSummary.added.forEach(buildNewWidget);
widgetSummary.removed.forEach(cleanupExistingWidget);
}
I set up a listener for an event emitter and what I want to do is to remove the same listener if I get certain events. The problem I am running into is that I don't know how to pass the callback function to removeListener inside the callback function. I tried "this", but it errors out. Is there any ways to achieve this? By the way, I am not using once because I am only removing the listener on a certain event.
P.S. I am using redis here so whatever message I receive I would always be listening on the key "message". It would not be possible to just listen on different keys. Channel wouldn't help either because I only want to remove a specific listener.
Also, what I want to do is communication between two completely independent process. No hierarchy of any kind. In process B, there are many independent functions that will get data from process A. My initial thought was using a message queue, but with that I cannot think of a way to ensure that each function in B will get the right data from A.
One cool thing about closures is that you can assign them a name, and that name can be used internally by the function. I haven't tested this, but you should try:
object.on('event', function handler() {
// do stuff
object.off('event', handler);
});
You should also look into whether your event emitter supports namespaces. That would let you do something like:
object.on('event.namespace', function() {
// do stuff
object.off('.namespace');
});
I am writing a program which need to listen the user keyboard stroks.
I use function XGrabKeyboard() and this is my code:
XGrabKeyboard(pDisplay, DefaultRootWindow(pDisplay), True, GrabModeAsync, GrabModeAsync, CurrentTime);
XEvent event;
while (true)
{
XNextEvent(pDisplay, &event);
switch (event.type)
{
...
}
}
But it causes the keyboard and cursor to be frozen.
I looked up the man page, it only says: "The third parameter specifies a Boolean value that indicates whether the keyboard events are to be reported as usual."
I tried both true or false or the 3rd param, both GrabModeAsync and GrabModeSync for the 4th and 5th param, but it doesn't work.
After calling XGrabKeyboard(), the keyboard is frozen and mouse click doesn't response.
Any ideas?
XGrabKeyboard() (if successful - be sure to check the return value), redirects all key events to your client.
So if your "..." inside the while(true) does not properly handle those key events, or does not ever ungrab (XUngrabKeyboard) or release sync events (XAllowEvents, only applies to GrabModeSync), then the keyboard would appear to lock up.
The boolean parameter is owner_events which indicates whether to report key events always to the window provided to XGrabKeyboard, or report them to the window they normally would have gone to without the grab. Typically you want False (report to the grab window).
For typical uses of XGrabKeyboard (I don't know your use-case) the parameters you would want are:
grab window = some window in your app that relates to the reason for the grab
owner_events=False to send all events to that window
pointer_mode=Async to not screw with the pointer
keyboard_mode=Async to just redirect all key events and avoid need for AllowEvents
time=the timestamp from the event triggering the grab, ideally, or one generated by changing a property and grabbing the timestamp off the PropertyNotify
But, it depends. To give any definitive answer you'd probably need to post a compilable program, I think the bug is likely in the "..." part of your code. Try narrowing your app down to a single-file test case that can be run by others perhaps. Or explain more why you are grabbing and what you're trying to accomplish in the big picture.
I cant help with the XGrabKeyboard function - I havent used it before and dont know how it works - but I can suggest another way of getting the keyboard events.
When creating my window using XCreateWindow, the last argument is a XSetWindowAttributes object. This object has a member event_mask, which you can use to choose which events your window will receive.
I set mine like this:
XSetWindowAttributes setWindAttrs
setWindAttrs.event_mask = ExposureMask
| KeyPressMask
| KeyReleaseMask
| ButtonPressMask
| ButtonReleaseMask;
That will mean you receive events for keyboard key presses and mouse button clicks if you pass this object to XCreateWindow on window creation.
Also another note you can use XPending(pDisplay) to check if there are still events waiting to be handled - so it could replace true in your while(true) line.
Edit: Also your freezing issue could be that you dont return false anywhere in your while loop? It may be stuck in an infinite loop, unless you just removed that bit for the post. Try replacing true with xpending as I suggested above and it may fix the issue, or just returning false after handling the event, but this would only handle one event per frame rather than handling all the currently pending events like XPending would do, and I assume that is what you want to do.
EmployeeId is the id of a select element with a set of options. This approach will not work:
var tar = document.getElementById("EmployeeId");
$(tar).live("click", function(){
console.log("Changed");
});
However, this approach does:
$("#EmployeeId").live("click", function(){
console.log("Changed");
});
What is the difference between $("#EmployeeId") and $(tar)?? I was under the impression there was no difference between the two. Moreover, when I try
console.log($(tar));
console.log($("#EmployeeId"));
The same exact thing is sent to the console.
What am I missing, what is different, why is one approach not attaching the event handler?
.live needs the selector to work with, since it binds the event handler to document and then tests whether the origin (or any element in the path) of the event matches the selector.
If no selector is provided, it won't work. That's why chaining methods like $('foo').children().live(..) does not work either.
Since jQuery 1.7, .live is deprecated for various reasons listed in its documentation: http://api.jquery.com/live/.
Alternatives are .on (1.7) and .delegate (1.4.2).