`this.previous().previous().element == this.element`? - jquery-waypoints

I'm upgrading my code from jquery-waypoints 2.x to 4.x and have identified strange behavior related to this.previous(). I find that in a handler that was triggered at the correct time, this.element is correct. However, this.previous().element points to the next element in the DOM with a waypoint and this.previous().previous().element points to the same element as this.element. I can set a break point in the code and have validated that this.previous().previous().element == this.element.
I have to imagine I'm doing something very wrong, or this is a bug. I'm on v4.0.1 and I'm using the jQuery version. I'm binding my waypoints like so:
$selector.waypoints(
function goingUp(direction) {
console.log(this.previous().previous().element == this.element); // true
console.log(this.next().previous().element == this.element); // true
}, {
offset: offsetCalculator(this),
});

The problem turned out to be the grouping of waypoints. The .previous() waypoint, not counting for grouping, appeared later in document order than the current waypoint. Once I added groups to the waypoints, .previous() and .next() worked as expected.

Related

Scroll to selected row in GtkListBox

I'm a bit out of ideas here. I want a very simple thing: to be able to select a given GtkListBox row programmatically and then scroll the list box (which is wrapped in a ScrolledWindow and a Viewport).
Selecting a row is trivial (my code is Go & gotk3, but that's not so important):
listBox.SelectRow(row)
But scrolling to the row proved to be a real challenge. Whatever I tried, I failed:
I tried to focus the row, but it helped nothing
I tried to figure out the row's Y-coordinate using gtk_widget_translate_coordinates(), but it returns -1 for any row
Perhaps I can find out which row is at the top and the bottom of the list box and use that to scroll the ScrolledWindow but I can't figure out how to do that.
Update: I've tried what's proposed here: Manually scroll to a child in a Gtk.ScrolledWindow, but it didn't work as still no scrolling occurred:
listbox.SelectRow(rowToSelect)
listbox.SetFocusVAdjustment(listbox.GetAdjustment())
if rowToSelect != nil {
rowToSelect.GrabFocus()
}
I also tried the same with rowToSelect's child using the code below, to no avail:
if c, err := rowToSelect.GetChild(); err == nil {
c.GrabFocus()
}
I've finally nailed it thanks to the hint by Emmanuel Touzery. I didn't have to go as far as to use timers, but the problem was indeed that at the moment of filling of the list box the row hasn't been realised yet so no coordinate translation could possibly happen.
What I did is scheduled the scrolling using GLib's idle_add(), which makes it happen later downstream, and that seemed to have worked perfectly: see this commit for details.
In short, it all boils down to the following code:
func ListBoxScrollToSelected(listBox *gtk.ListBox) {
// If there's selection
if row := listBox.GetSelectedRow(); row != nil {
// Convert the row's Y coordinate into the list box's coordinate
if _, y, _ := row.TranslateCoordinates(listBox, 0, 0); y >= 0 {
// Scroll the vertical adjustment to center the row in the viewport
if adj := listBox.GetAdjustment(); adj != nil {
_, rowHeight := row.GetPreferredHeight()
adj.SetValue(float64(y) - (adj.GetPageSize()-float64(rowHeight))/2)
}
}
}
}
The above function has to be called using the glib.IdleAdd() and not in the code that fills the list box.
So, I had the same issue but managed to make it work in my case. I think there are good chances my solution will work for you too.
Since the grab_focus method didn't work, I started implementing a workaround solution using listbox_get_row_at_y. Highly unsatisfying, but hopefully it was going to work. And.. it didn't work, because get_row_at_y would always return null, for all the y values I'd feed it. And I knew the listbox wasn't empty. So that made me realize I was trying to focus a row that I had just been adding to the listbox.. The row wasn't realized yet, it couldn't be focused because it wasn't ready for that yet.
So I changed my code to fill the listbox, wait a 100ms timeout, and only then call grab_focus. And that worked!
I'm actually using a library which is wrapping the timeout call for me, but I think you could use g_timeout_add in 'raw' gtk for that purpose.
Note that this means that calling grab_focus on a listbox that was already filled beforehand and the items realized on screen should work directly. If that's your situation then this won't help you.

How can I remove a group from a Three.js scene on click?

I have a group of objects (actually 3D text on an arc) that I want to remove from the scene on a specific click. Does .remove not work on groups? Here's basically what I have:
$(".inscript").on("mousedown", function(event){
var x = scene.getObjectByName("inscriptArc");
scene.remove(x);
});
This answer seems to suggest you can (remove a group from a scene using .remove), but it isn't working for me.
THREE.Scene.getObjectByName returns the first instance of a child with that name. If you have multiples you won't catch them by calling it once.
To remove all instances I would use the THREE.Object.traverse(fn(child){}) function ie:
var children_to_remove = [];
scene.traverse(function(child){
if(child.name == "inscriptArc"){
children_to_remove.push(child);
}
});
children_to_remove.forEach(function(child){
scene.remove(child);
});
you might be able to just do
scene.traverse(function(child){
if(child.name == "inscriptArc"){
scene.remove(child);
}
});
but I think there are some cases where this could cause an error if you are loading/removing anything from the scene asyncronously - because removing a child might throw an error when that child's children get traversed. Not sure, so I would try the simple one and swap with the more complicated one if it causes issues.
Yes, you definitely can remove a group of objects. You might have named children of the object instead of the actual group. Function getObjectByName did not always work as promised in older three.js releases so maybe try this.
scene.children.forEach(child => child.name == "inscriptArc" ? scene.remove(child) : null)

d3.selection type check in IE

How to check if a given object is a d3 selection?
The following code prints true in Chrome and Firefox, but false in Internet Explorer:
console.log(d3.select(document.body) instanceof d3.selection)
Update 2017-01-17
With the release of D3 v4 this problem has vanished (changelog):
Selections no longer subclass Array using prototype chain injection; they are now plain objects, improving performance.
And the API docs explicitly state:
# d3.selection() <>
[…] This function can also be used to test for selections (instanceof d3.selection)
Using the new version, the following code will actually evaluate to true in all browsers:
d3.select() instanceof d3.selection // true in Chrome, FF, IE
For all those still on v3 the original answer below has an analysis and a workaround for the problem.
Problem
Due to the inner workings of D3 every browser which supports Object.prototype.__proto__ will print true, whereas browsers lacking support for __proto__ will print false. Checking the compatibility list it's obvious, that IE<11 will evaluate the expression to false. For this reason, you won't be able to use instanceof d3.selection to check for a D3 selection in IE<11. This is a known issue with D3, but it was closed and will not get fixed.
Analysis
From D3's github repository:
selection/selection.js
Looking at the definition of d3.select() which is the entry point of your call:
d3.select = function(node) {
// ... removed for brevity
return d3_selection([group]);
};
This will eventually return the result of the call to d3_selection(), which in turn will subclass d3_selectionPrototype = d3.selection.prototype.
function d3_selection(groups) {
d3_subclass(groups, d3_selectionPrototype);
return groups;
}
core/subclass.js
Finally, the implementation of d3_subclass() provides the answer to the problem:
var d3_subclass = {}.__proto__?
// Until ECMAScript supports array subclassing, prototype injection works well.
function(object, prototype) {
object.__proto__ = prototype;
}:
// And if your browser doesn't support __proto__, we'll use direct extension.
function(object, prototype) {
for (var property in prototype) object[property] = prototype[property];
};
It checks, if the browser supports Object.prototype.__proto__ by checking for the existence of the __proto__ accessor property on an empty object {}. If the browser supports it, D3 will directly assign the prototype, thus making it an instance of d3.selection. Otherwise, all properties of the prototype will be copied over to the object to be returned without explicitely setting the prototype. In this case your expression will evaluate to false.
Workaround
Because d3.selection is provided as a means to extend the selection's functionality you could implement a workaround by adding a new property to d3.selection which will, as was explained above, be made accessible by any selection, wether by prototyping or by copying properties.
// Include this at the start of your script to include the
// property in any selection created afterwards.
d3.selection.prototype.isD3Selection = true;
console.log(d3.select(document.body).isD3Selection); // true in any browser

Inserting nodes in a KendoUI TreeView dynamically

I have the following code:
var cnt = 0;
$(document).ready(function () {
var data = [
{
"id": cnt++,
"text":"node_" + cnt
}
];
var tree = $("#treeview").kendoTreeView({
dataSource:kendo.observableHierarchy(data)
}).data("kendoTreeView");
$("#push").click(function () {
var pos = tree.dataItem(tree.select());
pos.items.push({id:cnt++, text:"node_" + cnt});
});
$("#append").click(function () {
var pos = tree.select();
tree.append({id:cnt++, text:"node_" + cnt}, pos);
});
$("#show").click(function () {
var data = tree.dataItem(".k-item:first");
$("#content").html(JSON.stringify(data, null, 2));
});
});
And there are two functions:
1. push: once selected a node in the tree, it uses dataItem to get current data item and pushes one additional node into it (child node). This should be valid since dataSource is an ObservableHierarchy object.
2. append: once selected a node in the tree, it uses append to introduce one additional node into it (child node). This was valid on previous release of KendoUI and modify the tree but should not reflect changes in the DataSource.
The question / problem is:
1. If I use append the tree is update (visually) but the dataItem is not updated.
2. If I use push then dataItem is update but not the tree.
3. If I select a node, use append and then push, the tree is visually updated and the model too.
It seems that the first time that I introduce a child append updates some internal structure and from there the tree 'observes' the observable hierarchy put if I directly push it then the tree does not observe the observable hierarchy.
How should I insert nodes dynamically being able to check the DataSource and get the current state of the tree?
NOTE This is with the latest version of KendoUI Q2.1024.
Ok so,I just got an answer on a ticket about this matter after 2 days.
It is indeed a BUG which is already fixed in the latest builds,but the builds are only available for customers with an active subscription...
It will be available for the rest of the community in the next official release (around March 2013).So currently the only solution is to purchase a commercial subscription and you will get immediate access to the new builds...
Kinda disappointed with all this commercial stuff since it is a bug..But anyway,nothing we can do about it..
At least we know we are not crazy,and in a few months we can replace our code with the fixed build. :P
Kinda my problem too at the moment since append doesn't update the dataSource at all and while push updates the dataSource,it does so only the first time I add a node,I can't even select that node afterwards until I save the dataSource and refresh the page.(or I get an pos.items is undifined error)
What I've though so far is that maybe we can use the push method that adds the child-node to the dataSource and try to force load the selected node's children in the dataSource everytime through treeview.dataSource.get(treeview.select()).load()
According to documentation here http://docs.kendoui.com/documentation/api/framework/node
If we can get the selected Node we can load it's children forcibly.But I haven't been able to have datasource.get() or dataSource.view()[] read the selected node so far..
PS I know this is not a complete answer but maybe it helps..

Unable to remove element loaded by AJAX

I am trying to remove an element on AJAX success which was loaded and attached to the document during a previous AJAX call.
My code looks something like this:
$("#jobs-table-body").on("click", ".one-rc-button", function() {
var ctx = $.parseJSON($(this).siblings(".context").html());
$("#one-rc-candidate-id").val(ctx.candidateId);
$("#one-rc-job-id").val(ctx.jobId);
var loader = $("#wrapper").loader();
$.post($("#one-rc-form").attr("action"), $("#one-rc-form").serialize(), function(result) {
loader.remove();
if(result.success) {
// This works and returns 1
alert($("#candidate-row-" + result.rejectedCandidateId).length);
// This doesn't seem to be doing anything
$("#candidate-row-" + result.rejectedCandidateId).remove();
} else {
//$("#one-jc-messages").html(result.error);
}
});
});
The elements .one-rc-button and #candidate-row-<candidateId> were loaded by a previous AJAX call and they are attached to the document as I can very well see them on my page.
Now, on click of the previously generated .one-rc-button, I trigger a second AJAX call (which works fine) and on result.success, I want to delete the #candidate-row-<candidateId> (which is within the previously generated parent element).
The alert works and returns 1. So I know for sure that the selector is fine and it is matching one unique element.
What I don't understand is why it is unable to remove the element from the page.
Observations
I use Firefox 10.0.2 where this problem is reproducible.
On IE 8, it works (element gets removed)
On debugging the script on Firebug, I can verify that I have got a handle to the right eleemnt.
Try using FireBug to set a breakpoint on that line so you can see exactly what it's getting from that selector. Ideally break up the statement first, like this:
var unwantedDiv = $("#candidate-row-" + result.rejectedCandidateId);
unwantedDiv.remove(); // <-- Set a breakpoint on this line
You can then look at the unwantedDiv variable in the watch pane on the right of the firebug debugger and see what it is, what methods it has/has not got etc. I would assume that you are not getting back exactly what you think you are, possibly because of how you attached the div after the previous AJAX call. More information about JavaScript debugging with FireBug here.
Another option is to turn on strict warnings in the firebug console and see if you get any 'undefined method' errors, which don't stop the show on FireFox, but just bounce you out of that function. Do you get an error in IE?
Solved it by a really ugly workaround. I am still not sure what causes this behaviour.
if(result.success) {
var removeThis = $("#candidate-row-" + result.rejectedCandidateId);
removeThis.remove();
removeThis = $("#candidate-row-" + result.rejectedCandidateId);
if(removeThis.length != 0) {
removeThis.remove();
}
}
Now it works on both Firefox and IE.

Resources