Figure doesn't show correct string on event - rascal

In the following code I create 3 boxes with the text 1 to 3, in a fourth box I'd like to show the text of the box my mouse is hovering over. So i set an onMouseEnter FProperty for each of the boxes where I change the string of the fourth box and tell it to redraw.
bool redraw = false;
str s = "0";
Figure getTextbox() {
return computeFigure(bool() {bool temp = redraw; redraw = false; return temp; },
Figure() {
return text(str() {return s; });
});
}
list[Figure] boxes = [];
for (i <- [1..4]) {
boxes += box(text(toString(i)), onMouseEnter(void () {s = toString(i); redraw = true; }));
}
Figure changer = box(getTextbox());
render(vcat(boxes + changer));
However, for some odd reason all three boxes will tell the onMouseEnter method to change the text of the fourth box into "3" (the value of the last box) instead of their individual value.
Any clue why? Thanks!

Ah yes, this is the variable capturing closure problem with for loops, also known from other languages which have this particular feature like Javascript. This is the code with the issue:
for (i <- [1..4]) {
boxes += box(text(toString(i)), onMouseEnter(void () {s = toString(i); redraw = true; }));
}
The variable i is bound by the void closure and not its value. So every time the function which is created and passed to onMouseEnter it will read the latest value of the i variable. Since the callback is called after the loop terminates, all calls to the mouse enter function will have the value 3.
To fix this and "do what you want", the following code would work I believe:
for (i <- [1..4]) {
newS = toString(i);
boxes += box(text(toString(i)), onMouseEnter(void () {s = newS; redraw = true; }));
}
This works because for every pass of the for loop a new environment is created which binds the newS variable. So you'll get a fresh newS for every loop instead of the reused i.

Related

box callback functions returning the same string in Rascal

I'm trying to draw some boxes in Rascal and trying to give each box its own callback function. On entering the box with the mouse the corresponding string should get displayed in the text element (so hovering box1 should display box1 etc.).
However, at the moment the text does pop up but just displays "box3" for each of the 3 boxes.
Any ideas?
strings = ["box1", "box2", "box3"];
boxes = [ box(
size(100, 100),
onMouseEnter(void() {
output = s;
})
) | s <- strings];
render(hcat([
vcat(boxes),
text(str () {return output;})
]));
Good question, classical problem. The essence of the problem is that Rascal uses "non-capturing closures": this means that functions that are returned from another function share the same context. In your case this is the variable s introduced by s <- strings. This nearly always happens when you create function values in a loop (as you do here). The solution is to wrap another function layer around the returned function.
Here is a simple example:
list[int()] makeClosures()
= [ int() {return i;} | i <- [0,1,2]];
void wrong(){
lst = makeClosures();
println(lst[0]());
println(lst[1]());
println(lst[2]());
}
which will print surprisingly the values 2,2and2`. The solution is, as said, to introduce another function level:
int() makeClosure(int i)
= int() { return i;};
list[int()] makeClosuresOK()
= [ makeClosure(i) | i <- [0,1,2]];
void right(){
lst = makeClosuresOK();
println(lst[0]());
println(lst[1]());
println(lst[2]());
}
now calling right() will print 1, 2, and 3 as expected.
I leave it as an exercise how this is done in your example, but I am prepared to give a solution when you ask for it. Good luck!

How do I configure the options in Highcharts to allow multiple drilldowns asynchronously?

I'm trying to convert the following options in Highcharts to multiple series with multiple drilldowns. The problem is that I've changed the loop to progress over the points so as to add both drilldown series. However, in the loop I've written, it seems to be the case that after one go through the loop, the points array is overwritten with nulls, which makes the whole thing irrelevant.
I'm a beginner with the options, and after having spent quite a bit of time on it I can't crack it. An explanation and a solution would be an ideal answer to the question: "How do I do the following with multiple drilldowns?" It's all asynchronous requests on datasets.
I'm starting with
options.chart = options.chart || {};
options.chart.events = options.chart.events || {};
var dd = options.chart.events.drilldown || function(e) {};
options.chart.events.drilldown = function(e) {
var chart = this;
chart._drilldowns = chart._drilldowns || {};
var series = chart._drilldowns[e.point.drilldown];
if (series) {
e.seriesOptions = series;
chart.addSeriesAsDrilldown(e.point, series);
dd(e);
}
if (!e.seriesOptions) {
chart.showLoading('Fetching data...');
$.getJSON(
'%(url)s?' + analytics.get_form_data(),
function(drilldowns) {
chart.hideLoading();
chart._drilldowns = drilldowns;
var series = drilldowns[e.point.drilldown];
chart.addSeriesAsDrilldown(e.point, series);
e.seriesOptions = series;
dd(e);
}
);
}
};
''' % {'url': self.get_drilldown_url()}
and I've tried to change the second part to:
...
function(drilldowns) {
chart.hideLoading();
chart._drilldowns = drilldowns;
e.points.forEach(function(value, key){
var series = drilldowns[value.drilldown];
chart.addSeriesAsDrilldown(value, series);
})
e.seriesOptions = series;
dd(e);
}
);
}
};
But I don't get both my series drilling down. I actually get a Property xAxis of null is not allowed error, as when I go through the loop the second time, the set of points has been changed to null.
UPDATE
We eventually fixed (actually a collegue did!) using promises. We engineered it to wait until the first async request for data was retrieved, and then called addSingleSeriesAsDrilldown on each one until we hit the last one (derived off the chart state) at which point we called addSeriesAsDrilldown which does the applyDrilldown as part of the code.
It's not the part of official API, but this way you can get multiple drilldowns: http://jsfiddle.net/p2xw9416/
In the lowest level of AJAX requests (if you have multiple of them), add each series as single object:
chart.hideLoading();
chart.addSingleSeriesAsDrilldown(e.point, series_1);
chart.addSingleSeriesAsDrilldown(e.point, series_2);
chart.applyDrilldown(); // update && animate

onFullSync action, show updated info - DHTMLX Grid + RoR

I have a Ruby on Rails project where I use a DHTMLX Grid.
Is there a way of showing, using the event handler "onFullSync" provided by the grid API, to show updated data?
Let me explain a little better... I know I can do something like:
dp.attachEvent("onFullSync", function(){
alert("update complete");
})
But what I want is something more complex. I want to, after each completed update, alter a div adding the information like this:
Field 2 was updated to XYZ and field 3 was updated to XER on line X
Field 1 was updated to 123 and field 3 was updated to XSD on line Y
Is this possible?
Thanks
There is a onAfterUpdate event that can be used similar to onFullSync
http://docs.dhtmlx.com/api__dataprocessor_onafterupdate_event.html
It will fire after each data saving operation ( if you are saving 5 rows - it will fire 5 times )
Still, info about updated columns will not be available here.
Also, you can try onEditCell event of grid. It fires after changing data in db, but before real saving in database. Here you can get all necessary info - row, column, old value and new value.
http://docs.dhtmlx.com/api__link__dhtmlxtreegrid_oneditcell_event.html
So, what I end up doing was:
After creating the grid I created an array:
var samples = [];
Then, as per #Aquatic suggestion, I added to "onEditCell" event the following line:
samples[samples.length] = grid.cells(rId, 5).getValue();
This allowed me to add to the array the value present on column 5 of the row changed. Then, on "onFullSync" event I hide or show the div created on the view with the messages (I distinguish if it's on row or more changed on the grid).
//Deals with messages after update
dp.attachEvent("onFullSync", function(){
unique_samples = uniq_fast(samples.sort());
if (unique_samples.length == 1){
$('#updated-samples').text("");
$(".messages").show();
$('#updated-samples').text("A seguinte amostra foi actualizada: " + unique_samples[0]);
//to clear the array
samples = [];
} else if (unique_samples.length > 1){
$('#updated-samples').text("");
$(".messages").show();
$('#updated-samples').text("As seguintes amostras foram actualizadas: " + unique_samples.sort().join(", "));
//to clear the array
samples = [];
} else {
$('#updated-samples').text("");
$(".messages").hide();
//to clear the array
samples = [];
}
})
The problem with using "onEditCell" is that everytime a field is changed on that row I get a repeated value on my "samples" array, I I had to remove duplicate from that array. For that I used one of the suggestions at this answer
// remove duplicates in array
function uniq_fast(a) {
var seen = {};
var out = [];
var len = a.length;
var j = 0;
for(var i = 0; i < len; i++) {
var item = a[i];
if(seen[item] !== 1) {
seen[item] = 1;
out[j++] = item;
}
}
return out;
}
Then I have on the beginning of the view, to show the messages:
<div class="alert alert-success messages" id="updated-samples">
And that's it. I could be not the most efficient way but it works for what I wanted. I will leave the question open a few more days to see if any other option appears.

onMouseDown pointers inside a loop in rascal

In the following code I want each box (Figure) to have his own mousedown.
But after rendering all the boxes use the same file, the last read file.
for(loc file <- lsFile){
lsBox += box(
onMouseDown(bool (int butnr, map[KeyModifier,bool] modifiers) {
renderFile(file);
return true;
})
);
}
Anyone knows how to fix this?
for(loc file <- lsFile){
loc tmp = file;
lsBox += box(
onMouseDown(bool (int butnr, map[KeyModifier,bool] modifiers) {
renderFile(tmp);
return true;
})
);
}
The closure captures the file variable, not its value. So you slways have a reference to its last value. The tmp variable is newly allocated for each iteration, so it doesnot have this problem.

how to copy link name to title

i wanna ask how to change title in
name
so i want to make link name copy to title automatic
so if i make this code
title link
to
title link
how to do that in php or javascript
i know some in php
but need to make all words in link at database or make for every link variable $
can some one help me in that?
I'd suggest:
function textToTitle(elem, attr) {
if (!elem || !attr) {
// if function's called without an element/node,
// or without a string (an attribute such as 'title',
// 'data-customAttribute', etc...) then returns false and quits
return false;
}
else {
// if elem is a node use that node, otherwise assume it's a
// a string containing the id of an element, search for that element
// and use that
elem = elem.nodeType == 1 ? elem : document.getElementById(elem);
// gets the text of the element (innerText for IE)
var text = elem.textContent || elem.innerText;
// sets the attribute
elem.setAttribute(attr, text);
}
}
var link = document.getElementsByTagName('a');
for (var i = 0, len = link.length; i < len; i++) {
textToTitle(link[i], 'title');
}
JS Fiddle demo.
And since it seems traditional to offer a concise jQuery option:
$('a').attr('title', function() { return $(this).text(); });
JS Fiddle demo.
If you don't want to use a library:
var allLinks = document.getElementsByTagName('a');
for(var i = 0; i < allLinks.length; i++){
allLinks[i].title = allLinks[i].innerHTML;
}
Since you wanted to do all this to one element on the page, consider using something like this:
var allLinks = document.getElementById('myelement').getElementsByTagName('a'); // gets all the link elements out of #myelement
for ( int i = 0; i < allLinks.length; i++ ){
allLinks[i].title = allLinks[i].innerHTML;
}
Actually, this is roughly the same as before but we are changing the input elements.
Or, assuming you use jQuery, you could do something like this:
$('a').each(function(){ // runs through each link element on the page
$(this).attr('title', $(this).html()); // and changes the title to the text within itself ($(this).html())
});
In JQuery you can change an attribute by knowing the current tag and using the .attr() feature. Something like $('a').attr('title', 'new_title'); http://api.jquery.com/attr/

Resources