jsTree : how to add a complex node - jstree

How to add a branch in a jstree instance (ie. a node with childrens of unknown levels).
// example of a branch (with one level)
var branch = {
"data":"Folder 1",
"attr":{"rel":"Layer","elt":1},
"state":"closed",
"children":[
{
"data":"Item 4",
"attr":{"rel":"File 1","elt":2},
"state":"",
"children":null
}
]
};
And to add this branch in a jstree instance :
// -1 means root
$.jstree._reference('#tree').create_node(-1, 'last', branch, false, false);
But it fails ! The children are not created.

My solution is to create all the nodes manually and recursively :
function LoadElement(node, branch) {
data = {
data: branch.name,
attr: branch.attr,
state: branch.state
};
var node = $.jstree._reference('#tree').create_node(
node, 'last', data, false, false
);
if (typeof branch.children === 'undefined') return false;
for (var i=0; i<branch.children.length; i++) {
LoadElement(node, branch.children[i]);
}
}
// -1 means root
LoadElement(-1, branch);

Related

TinyMCE 5: Autocomplete that can be ignored so you can just type your own entry

I want to help the user author handlebars/mustache templates so when they type a { character, an autocomplete of known template values comes up to assist the user. But the user may not want to choose one of the suggested options, they might just want to continue typing a new template value and terminate it with a }. In the example in the code below, the options "Order Number" and "Delivery Date" are the known autocomplete options, but I want the user to be able to type {Invoice Number} for example.
I've succeeded in make this work in one way. As a user is typing {Invoice Number} I add it to the list of allowed options in the autocompleter fetch function. So the user can get what they want into the document if the click on the suggested option. Clicking fires the onAction function. I want onAction to fire as soon as the user types the closing handlebars character i.e. }.
Here is the code I have tried. I am using TinyMCE 5.
let template = (function () {
'use strict';
tinymce.PluginManager.add("template", function (editor, url) {
const properties = [
{value: "Order Number", text: "Order Number"},
{value: "Delivery Date", text: "Delivery Date"}
];
const insertNewProperty = function(value) {
let property = {value: value, text: value};
properties.push(property);
return property;
};
editor.ui.registry.addAutocompleter('autocompleter-template', {
ch: '{',
minChars: 0,
columns: 1,
fetch: function (pattern) {
return new tinymce.util.Promise(function (resolve) {
let filteredProperties = pattern ? properties.filter(p => p.text.indexOf(pattern) > -1) : properties;
if (filteredProperties.length > 0) {
resolve(filteredProperties);
} else {
resolve([{value: pattern, text: pattern}]);
}
});
},
onAction: function (autocompleteApi, rng, value) {
let property = properties.find(p => p.value === value);
if (!property) {
property = insertNewProperty(value)
}
let content = `{${property.text}}`;
editor.selection.setRng(rng);
editor.insertContent(content);
autocompleteApi.hide();
}
});
return {
getMetadata: function () {
return {
name: "Learning",
url: "https://stackoverflow.com"
};
}
};
});
}());
})();```
You can add a matches function to your callbacks, along with your onAction, this help you do it.
matches: function (rng, text, pattern) {
if(pattern.endsWith('}')){
pattern = pattern.replace('}', '');
/**
* Check if pattern does not match an existing
* variable and do what you want
*/
return true;
}
},
And make sure the function always returns true.

How to Convert below Line in Page Object using Protractor

want to convert below line
rows.element(by.xpath(".//*[#ng-model='strategy.COMMENT']")).clear()
into page object like
rows.dataCatcherPage.strategyAUMValue.clear()
But i am getting the error
"Failed: Cannot read property 'strategyAUMValue' of undefined"
This is the Page object
strategyAUMValue: {
get: function () {
return element(by.xpath(".//*[#ng-model='strategy.AUM_VALUE']"));
}
},
How about this:
page
module.exports = new function () {
var elements : {
strategyAUMValue : element(by.xpath(".//*[#ng-model='strategy.AUM_VALUE']"))
};
this.clear = {
strategyAUMValue : elements.strategyAUMValue.clear()
};
this.getText = {
strategyAUMValue : elements.strategyAUMValue.getText()
};
};
spec
var dataCacherPage = require('./dataCacher.page.js');
describe('Data cacher', function(){
it('can clear the strategy aum value', function(){
dataCacherPage.clear.strategyAUMValue();
expect(dataCacherPage.clear.strategyAUMValue()).toEqual('', 'Strategy AUM Value should have been an empty string');
});
});
This lets your page elements be private(separating your framework layers), but gives you full access to all of the actions a test would be taking. You can expand on it by adding any other elements to the elements section, then adding to any this.clear/getText/isDisplayed type function that the element will need for testing.
Some extensibility:
module.exports = new function () {
var elements : {
strategyAUMValue : element(by.xpath(".//*[#ng-model='strategy.AUM_VALUE']")),
// Get an element where multiple exist
coolElement : $$('[name="coolElement"]')
};
this.clear = {
strategyAUMValue : elements.strategyAUMValue.clear()
};
this.getText = {
strategyAUMValue : elements.strategyAUMValue.getText(),
coolElement : elements.coolElement.getText()
};
};
.
var dataCacherPage = require('./dataCacher.page.js');
describe('Data cacher', function(){
it('can hit multiple elements', function(){
// Just add an index on coolElement to get whichever you want
expect(dataCacherPage.clear.coolElement(2)).toEqual('This is the third cool element on the page', 'Should have gotten the text from the third cool element');
});
});

Backbone pagination

can anyone explain to me how this backbone.paginator example works?
https://github.com/backbone-paginator/backbone.paginator/blob/master/examples/request-paging/collections/PaginatedCollection.js
I see that the backend can be reached using the URL:
paginator_core: {
type: 'GET',
dataType: 'jsonp',
url: 'https://api.github.com/repos/twitter/bootstrap/issues?'
},
But what/where does this example pass the page number and amount of itmes to retreive from the backend? My backend is accessible through the following restfull url: and i cant figure out how the next page details are inserted in the url above...
www.test.com/getItems/{query}/{from}/{size}
Is this automatically inserted by the paginator plugin?
Just check internal implementation for fetch method
// map params except directions
var queryParams = this.mode == "client" ?
_pick(this.queryParams, "sortKey", "order") :
_omit(_pick(this.queryParams, _keys(PageableProto.queryParams)),
"directions");
var i, kvp, k, v, kvps = _pairs(queryParams), thisCopy = _clone(this);
for (i = 0; i < kvps.length; i++) {
kvp = kvps[i], k = kvp[0], v = kvp[1];
v = _isFunction(v) ? v.call(thisCopy) : v;
if (state[k] != null && v != null) {
data[v] = state[k];
}
}
request creates based on
queryParams: {
currentPage: "page",
pageSize: "per_page",
totalPages: "total_pages",
totalRecords: "total_entries",
sortKey: "sort_by",
order: "order",
directions: {
"-1": "asc",
"1": "desc"
}
},
property - thus current collection state mapps over setting from queryParams for generations url

How to make nested group in MongoDB?

Assume there's a data in Mongo! There are a few projects, and there're managers, to who the problems are assigned. Each problem is assigned to different people as the project has different parts.
How can one compute the number, each assignee has been assigned within a project.
For example:
{
"Project A": {
"Ted":10,
"Matt":5
},
"Project B": {
"Mary":3,
"Hector":30
}
}
The following writes the sum but doesn't group it:
db.test.issues.group({
"key": {
"project": true
"assignee":true
},
"initial": {
"countassignee": 0
},
"reduce": function(obj, prev) {
prev.countassignee++;
}
});
It will return as:
{
{
"project": "Project A",
"countassignee":10,
"assignee":"Ted"
}
....
}
The data sample provide by you is pretty confusing. its Project A and project B supposed to be different document.
I believe the best use of group is to aggegrate within a collections, if you want to count within a doucment you may use javascript.
OK! It doesn't seem like the best answer, but it'll do!
first define a cursor sorting by projects
var cursor = db.test.find().sort({projects:1});
a list for the counter:
var asgn_nums = {};
and a variable holding project name;:
var project = '0';
Here counts for each project:
while (cursor.hasNext()) {
var issue = cursor.next();
var p = issue.project;
if(p != project)
{
if(project != '0'){
print(project+":");
printjson(asgn_nums);
}
project = p;
asgn_nums = {};
}
if(issue.assignee != null)
{
if (asgn_nums[issue.assignee] == null)
asgn_nums[issue.assignee] = 1;
else
asgn_nums[issue.assignee]+= 1;
}
if(!cursor.hasNext())
{
print(project+":");
printjson(asgn_nums);
}
}

Removing documents while preserving at least one

I have a MongoDB collection containing history data with id and timestamp.
I want to delete data from the collection older than a specific
timestamp. But for every id at least one
document (the newest) must stay in the collection.
Suppose I have the following documents in my collection ...
{"id" : "11", "timestamp" : ISODate("2011-09-09T10:27:34.785Z")} //1
{"id" : "11", "timestamp" : ISODate("2011-09-08T10:27:34.785Z")} //2
{"id" : "22", "timestamp" : ISODate("2011-09-05T10:27:34.785Z")} //3
{"id" : "22", "timestamp" : ISODate("2011-09-01T10:27:34.785Z")} //4
... and I want to delete documents having a timestamp older than
2011-09-07 then
1 and 2 should not be deleted because they are newer.
4 should be deleted because it is older, but 3 should not be deleted
(although it is older) because
at least one document per id should stay in the collection.
Does anyone know how I can do this with casbah and/or on the mongo
console?
Regards,
Christian
I can think of a couple of ways. First, try this:
var cutoff = new ISODate("2011-09-07T00:00:00.000Z");
db.testdata.find().forEach(function(data) {
if (data.timestamp.valueOf() < cutoff.valueOf()) {
// A candidate for deletion
if (db.testdata.find({"id": data.id, "timestamp": { $gt: data.timestamp }}).count() > 0) {
db.testdata.remove({"_id" : data._id});
}
}
});
This does the job you want. Or you can use a MapReduce job to do it as well. Load this into a text file:
var map = function() {
emit(this.id, {
ref: this._id,
timestamp: this.timestamp
});
};
var reduce = function(key, values) {
var cutoff = new ISODate("2011-09-07T00:00:00.000Z");
var newest = null;
var ref = null;
var i;
for (i = 0; i < values.length; ++i) {
if (values[i].timestamp.valueOf() < cutoff.valueOf()) {
// falls into the delete range
if (ref == null) {
ref = values[i].ref;
newest = values[i].timestamp;
} else if (values[i].timestamp.valueOf() > newest.valueOf()) {
// This one is newer than the one we are currently saving.
// delete ref
db.testdata.remove({_id : ref});
ref = values[i].ref;
newest = values[i].timestamp;
} else {
// This one is older
// delete values[i].ref
db.testdata.remove({_id : values[i].ref});
}
} else if (ref == null) {
ref = values[i].ref;
newest = values[i].timestamp;
}
}
return { ref: ref, timestamp: newest };
};
Load the above file into the shell: load("file.js");
Then run it: db.testdata.mapReduce(map, reduce, {out: "results"});
Then remove the mapReduce output: db.results.drop();