How to sort fancytree nodes with folders at the top - fancytree

I've reviewed the docs and examples for fancytree for hours soaking up all of fancytree's goodness like a sponge but I can't seem to figure how to sort my fancytree object with folders first by using the API calls. I've initially got around the problem by arranging my initial JSON data so that it's already sorted with folders at the top (a requirement of the project) but now I need to add a new folder to the tree and I need to re-sort the object making sure the newly added folder appears at the top of the tree with the others.
I notice there is a curious option for sortChildren() that allows for a defining a custom compare function but I'm having trouble wrapping my head around how to use it.
Any ideas would be much appreciated!
Snippet below on how I am doing things currently (I am populating the new child with data from some form elements):
//add the new foldername to the tree and re-order
var rootNode = jQuery("#document_objects").fancytree("getRootNode");
var childNode = rootNode.addChildren({
title: jQuery('#newfoldername').val(),
tooltip: jQuery('#description').val(),
folder: true
});
rootNode.sortChildren(null, true);
Thanks in advance!

sortChildren(cmp, deep) allows to pass a compare function:
http://www.wwwendt.de/tech/fancytree/doc/jsdoc/FancytreeNode.html#sortChildren
The default implementation (if you pass null or nothing for the cmp argument) is
function(a, b) {
var x = a.title.toLowerCase(),
y = b.title.toLowerCase();
return x === y ? 0 : x > y ? 1 : -1;
};
but you could add some prefix to force a different order, e.g.:
function(a, b) {
var x = (a.isFolder() ? "0" : "1") + a.title.toLowerCase(),
y = (b.isFolder() ? "0" : "1") + b.title.toLowerCase();
return x === y ? 0 : x > y ? 1 : -1;
};

Try below code:
var cmp= function(a, b) {
var x = (a.data.isFolder ? "0" : "1") + a.data.title.toLowerCase(),
y = (b.data.isFolder ? "0" : "1") + b.data.title.toLowerCase();
return x === y ? 0 : x > y ? 1 : -1;
};
node.sortChildren(cmp, true);

Related

ag-grid filter not working with formatted number values?

I'm using ag grid with angularjs and the filter does not work with formatted numbers. I use formatted numbers with currency values.
Below is the columndef code:
{ headerName:"GBO", field: "GBO", width: 200, editable:true, cellClass: "number-cell",filter:'agNumberColumnFilter',
cellRenderer : function(params){
if(params.value == "" || params.value == null)
return '-';
else return params.value;
}
}
Before assigning the data to the grid, I format the numbers using :
$scope.formatNumberOnly = function(num,c, d, t){
//console.log(num );
var n = getNumber(num);
//var n = this,
c = isNaN(c = Math.abs(c)) ? 2 : c,
d = d == undefined ? "." : d,
t = t == undefined ? "," : t,
s = n < 0 ? "-" : "",
i = parseInt(n = Math.abs(+n || 0).toFixed(c)) + "",
j = (j = i.length) > 3 ? j % 3 : 0;
return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
};
});
The problem here is that the filter doesn't work with these formatted numbers and only seems to be working for values upto 999.
Can anyone please help me with a solution to this filtering problem?
If you want the filter to work on these formatted values, you should use a valueGetter instead of a valueFormatter
You should implement the above formatter function as a valueGetter in column Definition.
Also a number filter won't work as in order for your formatted number to be interpreted, it should be a text filter.
Here is an example from official docs.

Functional version of a typical nested while loop

I hope this question may please functional programming lovers. Could I ask for a way to translate the following fragment of code to a pure functional implementation in Scala with good balance between readability and execution speed?
Description: for each elements in a sequence, produce a sub-sequence contains the elements that comes after the current elements (including itself) with a distance smaller than a given threshold. Once the threshold is crossed, it is not necessary to process the remaining elements
def getGroupsOfElements(input : Seq[Element]) : Seq[Seq[Element]] = {
val maxDistance = 10 // put any number you may
var outerSequence = Seq.empty[Seq[Element]]
for (index <- 0 until input.length) {
var anotherIndex = index + 1
var distance = input(index) - input(anotherIndex) // let assume a separate function for computing the distance
var innerSequence = Seq(input(index))
while (distance < maxDistance && anotherIndex < (input.length - 1)) {
innerSequence = innerSequence ++ Seq(input(anotherIndex))
anotherIndex = anotherIndex + 1
distance = input(index) - input(anotherIndex)
}
outerSequence = outerSequence ++ Seq(innerSequence)
}
outerSequence
}
You know, this would be a ton easier if you added a description of what you're trying to accomplish along with the code.
Anyway, here's something that might get close to what you want.
def getGroupsOfElements(input: Seq[Element]): Seq[Seq[Element]] =
input.tails.map(x => x.takeWhile(y => distance(x.head,y) < maxDistance)).toSeq

Reducing the number of brackets in Swift

Does anyone know if there is a way to use some kind shorthand in swift? more specifically, leaving out the braces in things like IF statements... eg
if num == 0
// Do something
instead of
if num == 0
{
// Do something
}
Those braces become rather space consuming when you have a few nested IF's.
PS. I do know I can do the following:
if num == 0 {
// Do something }
But I'm still curious if that sort of thing is possible
You can do that :
let x = 10, y = 20;
let max = (x < y) ? y : x ; // So max = 20
And so much interesting things :
let max = (x < y) ? "y is greater than x" : "x is greater than y" // max = "y is greater than x"
let max = (x < y) ? true : false // max = true
let max = (x > y) ? func() : anotherFunc() // max = anotherFunc()
(x < y) ? func() : anotherFunc() // code is running func()
This following stack : http://codereview.stackexchange.com can be better for your question ;)
Edit : ternary operators and compilation
By doing nothing more than replacing the ternary operator with an if else statement, the build time was reduced by 92.9%.
https://medium.com/#RobertGummesson/regarding-swift-build-time-optimizations-fc92cdd91e31#.42uncapwc
In swift you have to add braces even if there is just one statement in if:
if num == 0 {
// Do something
}
You cannot leave the braces, that how swift if statement work.
You could use a shorthand if statement like you would in objective-c:
num1 < num2 ? DO SOMETHING IF TRUE : DO SOMETHING IF FALSE
Swift 2.0 update
Method 1:
a != nil ? a! : b
Method 2: Shorthand if
b = a ?? ""
Referance: Apple Docs: Ternary Conditional Operator
and it does work,
u.dob = (userInfo["dob"] as? String) != nil ? (userInfo["dob"] as! String):""
I am replacing a json string with blank string if it is nil.
Edit: Adding Gerardo Medina`s suggestion...we can always use shorthand If
u.dob = userInfo["dob"] as? String ?? ""
It is called shorthand if-else condition. If you are into iOS development in Swift, then you can also manipulate your UI objects' behaviour with this property.
For e.g. - I want my button to be enabled only when there is some text in the textfield. In other words, should stay disabled when character count in textfield is zero.
button.enabled = (textField.characters.count > 0) ? true : false
its very simple :
in Swift 4
playButton.currentTitle == "Play" ? startPlay() : stopPlay()
Original Code is
if playButton.currentTitle == "Play"{
StartPlay()
}else{
StopPlay()
}
You could always put the entire if on one line:
if num == 0 { temp = 0 }

Change sheet cells color onEdit

I figured out how to compare dates in Google Sheets but when I try to enter more dates for some reason all the cells that were green and red become all red. Also how can I make two cells red if only one cell has a date?
Example: In cell D18 the Due date is 4-18-2014 and in cell E18 the cell is blank. I want to make both cells red so I would know that I should find out why is that cell red.
This is the code I have so far:
function onEdit() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var s = ss.getSheetByName('Copy of Project Sheet 1');
var values1Rule1 = s.getRange('E2:E1000').getValues();
var values2Rule1 = s.getRange('D2:D1000').getValues();
var range3Rule1 = s.getRange('D2:E2');
var color1 = 'Red';
var color2 = 'Green';
for (var row in values1Rule1) {
for (var col in values1Rule1[row]) {
if (values1Rule1[row][col] > values2Rule1[row][col]) s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor(color1);
else if (values1Rule1[row][col] < values2Rule1[row][col]) s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor(color2);
else s.getRange(s.getRange('D2').offset(row, col, 1, 2).getA1Notation()).setBackgroundColor('white'); }}
};
All you need to do is add this condition as an OR clause in your red condition, e.g.
if (values1Rule1[row][col] > values2Rule1[row][col] || values1Rule1[row][col] === '')
But there's lots of "minor" problems with your code. First of all, you're doing way too many API calls unnecessarily. This is a big performance issue. For example, when you offset, you already have the new range, there's no need to getA1Notation then get the range again, you could do:
s.getRange('D2').offset(row, col, 1, 2).setBackgroundColor(color1);
But that's still two calls, getting D2, then offseting. You could get the desired range at once:
s.getRange(row+1, 4, 1, 2).setBackgroundColor(color1);
I'd go even further and build a matrix of colors and set it all at once after the loop:
s.getRange('D2:E1000').setBackgroundColors(colors);
But even better, inside an onEdit you should only work on what has just being edited, instead of triggering a full recalculation of your colors because the user edited something on another column or another sheet entirely.
I think your code should be something like this:
function onEdit(e) {
var ss = e.source;
var s = ss.getActiveSheet();
if( s.getName() !== 'Copy of Project Sheet 1' ) return; //only interested in one sheet
var r = s.getActiveRange();
var c = r.getColumn();
if( c !== 4 && c !== 5 ) return; //only interested in changes on columns D or E
r = r.offset(0, c === 4 ? 0 : -1, 1, 2);
var v = r.getValues()[0];
r.setBackgroundColor(v[1] === '' || v[1] > v[0] ? 'red' : v[1] < v[0] ? 'green' : 'white');
}
--edit
You can not run this function manually directly, because it needs a parameter that is passed only when it runs automatically. But you can emulate it with a test function, like this:
function testEdit() { onEdit({source:SpreadsheetApp.getActive()}); }

Matlab function calling basic

I'm new to Matlab and now learning the basic grammar.
I've written the file GetBin.m:
function res = GetBin(num_bin, bin, val)
if val >= bin(num_bin - 1)
res = num_bin;
else
for i = (num_bin - 1) : 1
if val < bin(i)
res = i;
end
end
end
and I call it with:
num_bin = 5;
bin = [48.4,96.8,145.2,193.6]; % bin stands for the intermediate borders, so there are 5 bins
fea_val = GetBin(num_bin,bin,fea(1,1)) % fea is a pre-defined 280x4096 matrix
It returns error:
Error in GetBin (line 2)
if val >= bin(num_bin - 1)
Output argument "res" (and maybe others) not assigned during call to
"/Users/mac/Documents/MATLAB/GetBin.m>GetBin".
Could anybody tell me what's wrong here? Thanks.
You need to ensure that every possible path through your code assigns a value to res.
In your case, it looks like that's not the case, because you have a loop:
for i = (num_bins-1) : 1
...
end
That loop will never iterate (so it will never assign a value to res). You need to explicitly specify that it's a decrementing loop:
for i = (num_bins-1) : -1 : 1
...
end
For more info, see the documentation on the colon operator.
for i = (num_bin - 1) : -1 : 1