Commit ffc4d242 authored by Romain Loth's avatar Romain Loth

split db.json configuration file into servermenu and associated DBs

server_menu.json remains at project root while associated DBs are in new files called project_conf.json in each project dir
parent 24875757
...@@ -96,4 +96,4 @@ There are two exceptions are the html page and the companion backends: ...@@ -96,4 +96,4 @@ There are two exceptions are the html page and the companion backends:
----------------------------------------------- -----------------------------------------------
``` ```
4) finally, to use these backends as related documents search engines for a given graph, you'll need to configure your `db.json` file [as explained here](https://github.com/moma/ProjectExplorer/blob/master/00.DOCUMENTATION/A-Introduction/servermenu_config.md#more-relateddocs-settings). You can also find real-life examples in this distribution's `db.json` file. 4) finally, to use these backends as related documents search engines for a given graph, you'll need to configure your `project_conf.json` file [as explained here](https://github.com/moma/ProjectExplorer/blob/master/00.DOCUMENTATION/A-Introduction/project_config.md#more-relateddocs-settings). You can also find real-life examples in this distribution's `data/test/project_conf.json` file.
## Servermenu Configuration ## Project Configuration
The servermenu file associates some metadata to each graph file. The directories under `data/` are called project directories and should contain:
- a graph file (ending in `.gexf` or `.json`)
- a `project_conf.json` to declare nodetypes and optionally link DBs to each graph file.
- optionally the said associated database of documents
It is used if `sourcemode="servermenu"` is found in the url params or the settings file. See for example `data/test/project_conf.json` in the project dir `test`.
By default, the file is called `./db.json` (this can be modified in settings under `TW.conf.paths.sourceMenu`)
The `db.json` file of this distribution contains many examples.
------------------------------------------------------ ------------------------------------------------------
#### Minimal Config #### Minimal Config
One minimal servermenu entry contains: One minimal entry contains for each graph file of the project dir : a list of expected node types starting by 'node0' (**the nodetypes**)
- a data dir path (**the project**)
- for each project: a list of graph files subpaths (**the graph source**)
- for each graph file: a list of expected node types starting by 'node0' (**the nodetypes**)
```json ```json
"$$data/yourprojectdir": { {
"graphs": { "$$graph_source.gexf":{
"$$graph_source.gexf":{ "node0": {"name": "$$a_typename_of_nodes"}
"node0": {"name": "$$a_typename_of_nodes"} },
}, "$$another_graph_source.json":{
"$$another_graph_source.json":{ "node0": {"name": "$$a_typename_of_nodes"}
"node0": {"name": "$$a_typename_of_nodes"}
}
}
} }
}
``` ```
The value **typename_of_nodes** should match the `type` or `category` attribute value of your nodes in the source gexf or json. It acts as a filter specifying the nodes that will be displayed in the ProjectExplorer GUI. The value **typename_of_nodes** should match the `type` or `category` attribute value of your nodes in the source gexf or json. It acts as a filter specifying the nodes that will be displayed in the ProjectExplorer GUI.
##### For a bipartite graph ##### For a bipartite graph
If the source file has 2 types of nodes, the config should look like this: If the source file has 2 types of nodes, the config should look like this:
```json ```json
"$$data/yourprojectdir": { {
"graphs": { "$$source_file.ext":{
"$$source_file.ext":{ "node0": {"name": "$$typename_of_term_nodes"},
"node0": {"name": "$$typename_of_term_nodes"}, "node1": {"name": "$$typename_of_context_nodes"}
"node1": {"name": "$$typename_of_context_nodes"}
}
}
} }
}
``` ```
NB: giving an empty string value to `node1.name` property will group all other found types in an "other" category. NB: giving an empty string value to `node1.name` property will group all other found types in an "other" category.
...@@ -49,12 +41,10 @@ Having a node0.name entry and optionally a node1.name is enough to display the g ...@@ -49,12 +41,10 @@ Having a node0.name entry and optionally a node1.name is enough to display the g
###### Real life example ###### Real life example
```json ```json
"data/comexjsons": { {
"graphs": { "graph_example.json": {
"graph_example.json": { "node0": { "name": "NGram" },
"node0": { "name": "NGram" }, "node1": { "name": "Document" }
"node1": { "name": "Document" }
}
} }
} }
``` ```
...@@ -62,7 +52,7 @@ Having a node0.name entry and optionally a node1.name is enough to display the g ...@@ -62,7 +52,7 @@ Having a node0.name entry and optionally a node1.name is enough to display the g
------------------------------------------------------ ------------------------------------------------------
#### Activating relatedDocs LocalDB queries #### Activating relatedDocs LocalDB queries
The servermenu file also allows configuration of associated queries for selected node(s): **relatedDocs** The `project_conf.json` file also allows configuration of associated queries for selected node(s): **relatedDocs**
To enable it, you need to add to your node entry the `reldbs` key with minimally a db type : To enable it, you need to add to your node entry the `reldbs` key with minimally a db type :
...@@ -75,7 +65,7 @@ To enable it, you need to add to your node entry the `reldbs` key with minimally ...@@ -75,7 +65,7 @@ To enable it, you need to add to your node entry the `reldbs` key with minimally
} }
``` ```
The presence of this property "reldbs" makes the API usable in db.json. The presence of this property "reldbs" makes the API usable in the interface.
##### More relatedDocs settings ##### More relatedDocs settings
In addition, for full configuration, the following entries can be set under node0 or node1. In addition, for full configuration, the following entries can be set under node0 or node1.
...@@ -115,47 +105,47 @@ Expected type is `"twitter"` and no additional conf is needed (POSS for the futu ...@@ -115,47 +105,47 @@ Expected type is `"twitter"` and no additional conf is needed (POSS for the futu
``` ```
###### Real life examples ###### Real life examples
```json ```json
"data/gargistex": { {
"graphs":{ "model_calibration.gexf": {
"model_calibration.gexf": { "node0": {
"node0": { "name": "terms",
"name": "terms", "reldbs": {
"reldbs": { "csv": {
"csv": { "file": "model_calibration.csv",
"file": "model_calibration.csv", "qcols": ["title"],
"qcols": ["title"], "template": "bib_details"
"template": "bib_details" },
}, "twitter": {}
"twitter": {}
}
} }
} }
} }
}, }
"data/test": { ```
"first" : "mini_for_csv.gexf",
"graphs": {
"mini_for_csv.gexf": { ```json
"node0": { {
"name": "terms", "mini_for_csv.gexf": {
"reldbs": { "node0": {
"csv": { "name": "terms",
"file": "mini_for_csv.csv", "reldbs": {
"qcols": ["title","keywords","text"], "csv": {
"template": "bib_details" "file": "mini_for_csv.csv",
}, "qcols": ["title","keywords","text"],
"twitter": {} "template": "bib_details"
} },
}, "twitter": {}
"node1": { }
"name": "authors", },
"reldbs": { "node1": {
"csv": { "name": "authors",
"file": "mini_for_csv.csv", "reldbs": {
"qcols": ["author"], "csv": {
"template": "bib_details" "file": "mini_for_csv.csv",
} "qcols": ["author"],
"template": "bib_details"
} }
} }
} }
......
...@@ -15,7 +15,7 @@ Après commits de la semaine 26-30 juin 2017, une structure plus facile pour les ...@@ -15,7 +15,7 @@ Après commits de la semaine 26-30 juin 2017, une structure plus facile pour les
│   └── (graphes par sous-projets) │   └── (graphes par sous-projets)
├── explorerjs.html <= point d'entrée lancement ├── explorerjs.html <= point d'entrée lancement
├── settings_explorerjs.js <= config générale ├── settings_explorerjs.js <= config générale
├── db.json <= config additionnelle par sources gexf/json ├── server_menu.json <= liste des sources gexf/json par projet
├── favicon.ico ├── favicon.ico
├── LICENSE ├── LICENSE
├── README.md ├── README.md
......
...@@ -2,7 +2,7 @@ This is a stub for a future documentation for developers. ...@@ -2,7 +2,7 @@ This is a stub for a future documentation for developers.
#### About settings #### About settings
- system-wide settings are in `settings_explorerjs.js` - system-wide settings are in `settings_explorerjs.js`
- source-by-source settings (nodetypes, relatedDocs APIs) are in `db.json` - source-by-source settings (nodetypes, relatedDocs APIs) are in each project dir under `data/${projectname}/project_conf.json`
## Graph input choices ## Graph input choices
...@@ -16,7 +16,7 @@ Tina allows 3 main ways of input : ...@@ -16,7 +16,7 @@ Tina allows 3 main ways of input :
The `sourcemode` value is by default the one in settings_explorerjs.js (`TW.conf.sourcemode`), unless an url argument of the same name is present. The `sourcemode` value is by default the one in settings_explorerjs.js (`TW.conf.sourcemode`), unless an url argument of the same name is present.
The `serverfile` option has an extended version called `servermenu`. It opens the list of files from `db.json` on the server, providing a menu to choose from it. The `serverfile` option has an extended version called `servermenu`. It opens the list of files from `server_menu.json` on the server, providing a menu to choose from it.
The detailed implementation of these choices can be found in the function `syncRemoteGraphData()` in main.js. The detailed implementation of these choices can be found in the function `syncRemoteGraphData()` in main.js.
......
{
"mini_for_csv.gexf": {
"node0": {
"name": "term",
"reldbs": {
"csv": {
"file": "mini_for_csv.csv",
"qcols": ["title","keywords","text"],
"template": "bib_details"
},
"twitter": {}
}
},
"node1": {
"name": "person",
"reldbs": {
"csv": {
"file": "mini_for_csv.csv",
"qcols": ["author"],
"template": "bib_details"
}
}
}
}
}
{
"data/ClimateChange": {
"graphs": {
"Maps_S_800.gexf": {
"node0": {
"name": "ISItermsWhitelistV2Oct_5 &amp; ISItermsWhitelistV2Oct_5",
"reldbs": {
"CortextDB": {
"file": "wos_climate-change_title_2014-2015.db",
"qtable": "ISItermsWhitelistV2Oct_5",
"template": "cortext_with_link"
},
"twitter": {}
}
}
}
}
},
"data/gargistex": {
"first" : "shale_and_ice.gexf",
"graphs":{
"shale_and_ice.gexf": {
"node0": {
"name": "terms",
"reldbs": {
"csv": {
"file": "shale_and_ice.csv",
"qcols": ["title"],
"template": "bib_details"
},
"twitter": {}
}
}
},
"model_calibration.gexf": {
"node0": {
"name": "terms",
"reldbs": {
"csv": {
"file": "model_calibration.csv",
"qcols": ["title"],
"template": "bib_details"
},
"twitter": {}
}
}
}
}
},
"data/comexjsons": {
"first" : "graph_example.json",
"graphs": {
"graph_example.json": {
"node0": { "name": "NGram" },
"node1": { "name": "Document" }
}
}
},
"data/test": {
"first" : "mini_for_csv.gexf",
"graphs": {
"mini_for_csv.gexf": {
"node0": {
"name": "term",
"reldbs": {
"csv": {
"file": "mini_for_csv.csv",
"qcols": ["title","keywords","text"],
"template": "bib_details"
},
"twitter": {}
}
},
"node1": {
"name": "person",
"reldbs": {
"csv": {
"file": "mini_for_csv.csv",
"qcols": ["author"],
"template": "bib_details"
}
}
}
},
"ProgrammeDesCandidats.gexf": {
"node0": {
"name": "term",
"reldbs": {
"csv": {
"file": "ProgrammesCandidats2017.csv",
"delim": ",",
"qcols": ["title","abstract","node0"],
"template": "bib_details"
}
}
}
}
}
},
"data/politoscope": {
"title":"Politoscope",
"date":"2017",
"first" : "ProgrammeDesCandidats.enrichi.gexf",
"graphs": {
"ProgrammeDesCandidats.enrichi.gexf": {
"node0": { "name": "terms", "reldbs": { "twitter": {} } }
},
"ProgrammeDesCandidats.gexf": {
"node0": { "name": "terms", "reldbs": { "twitter": {} } }
}
}
},
"graphapi": {
"__comment__": "special subproject for api sourcemode",
"__comment__": "allows setting nodetypes and reldocs for api graph sources",
"__comment__": "POSS can be avoided if 2 files; filemenu.json, nodeconfs.json",
"graphs": {
"default": {
"node0": { "name": "NGram", "reldbs": { "twitter": {} } },
"node1": { "name": "Document" }
}
}
}
}
{
"data/ClimateChange": [
"Maps_S_800.gexf"
],
"data/gargistex": [
"shale_and_ice.gexf",
"model_calibration.gexf"
],
"data/comexjsons": [
"graph_example.json",
"graph_example2.gexf"
],
"data/test": [
"mini_for_csv.gexf"
],
"data/politoscope": [
"ProgrammeDesCandidats.gexf"
],
"first_project": "data/politoscope"
}
...@@ -20,9 +20,10 @@ TW.conf = (function(TW){ ...@@ -20,9 +20,10 @@ TW.conf = (function(TW){
TWConf.sourcemode = "servermenu" // accepted: "api" | "serverfile" | "servermenu" | "localfile" TWConf.sourcemode = "servermenu" // accepted: "api" | "serverfile" | "servermenu" | "localfile"
// ...or remote bridge to default source api ajax queries // ...or remote bridge to default source api ajax queries
TWConf.sourceAPI={}; TWConf.sourceAPI={}
TWConf.sourceAPI["forNormalQuery"] = "services/api/graph"; TWConf.sourceAPI["nodetypes"] = {"node0": "NGram", "node1": "Document" }
TWConf.sourceAPI["forFilteredQuery"] = "services/api/graph"; TWConf.sourceAPI["forNormalQuery"] = "services/api/graph"
TWConf.sourceAPI["forFilteredQuery"] = "services/api/graph"
// Related documents (topPapers) data source // Related documents (topPapers) data source
...@@ -37,7 +38,7 @@ TW.conf = (function(TW){ ...@@ -37,7 +38,7 @@ TW.conf = (function(TW){
// routes by corresponding type // routes by corresponding type
TWConf.relatedDocsAPIS = { TWConf.relatedDocsAPIS = {
"twitter": "https://134.158.74.111/twitter_search", "twitter": "http://127.0.0.1:5000/twitter_search",
"CortextDB": "twbackends/phpAPI", "CortextDB": "twbackends/phpAPI",
"csv": "twbackends/phpAPI" "csv": "twbackends/phpAPI"
} }
...@@ -195,8 +196,8 @@ TW.conf = (function(TW){ ...@@ -195,8 +196,8 @@ TW.conf = (function(TW){
'templates': 'twlibs/hit_templates', 'templates': 'twlibs/hit_templates',
'modules': 'twmodules', 'modules': 'twmodules',
'sourceFile': "", // server-side .gexf|.json default source 'sourceFile': "", // server-side gexf|json default source
'sourceMenu': "db.json" // ...or server-side gexf default source list 'sourceMenu': "server_menu.json" // ...or server-side gexf|json source list
} }
Object.freeze(TWConf.paths) // /!\ to prevent path modification before load Object.freeze(TWConf.paths) // /!\ to prevent path modification before load
......
...@@ -16,9 +16,9 @@ $our_libs_root="twbackends/phpAPI"; // for our few icons and jquery-ui ...@@ -16,9 +16,9 @@ $our_libs_root="twbackends/phpAPI"; // for our few icons and jquery-ui
// 2 - paths // 2 - paths
$mainpath=dirname(dirname(getcwd()))."/"; // default fs path to ProjectExplorer root $mainpath=dirname(dirname(getcwd()))."/"; // default fs path to ProjectExplorer root
// (where data dir and db.json file reside) // (where data dir resides with the projects)
$project_menu_path = "db.json"; $project_conf_fname='project_conf.json'; // default conf to look for in project dirs
// 3 - others // 3 - others
$ntypes = 2; // max node types (node0 & node1) $ntypes = 2; // max node types (node0 & node1)
...@@ -37,17 +37,25 @@ $csvquote = '"'; ...@@ -37,17 +37,25 @@ $csvquote = '"';
$memserver = 'localhost'; $memserver = 'localhost';
$memport = 11211; $memport = 11211;
// the graph file
$gexf= str_replace('"','',$_GET["gexf"]);
// reconstruct the path $projectdir/project_conf.json
$project_dir = dirname($gexf);
// CONFIGURATION PARAMS
// -------------------- // --------------------
// parse db.json project menu and create a conf by file // parse db.json project menu and create a conf by file
$conf = read_conf($mainpath.$project_menu_path, $ntypes, $supported_dbtypes); $conf = read_conf(
$mainpath.$project_dir.'/'.$project_conf_fname,
$ntypes,
$supported_dbtypes,
$project_dir
);
// ======================================= // =======================================
// echodump("== READ CONF ==<br>", $conf); // echodump("== READ CONF ==<br>", $conf);
// ======================================= // =======================================
$gexf= str_replace('"','',$_GET["gexf"]);
$ntid = $_GET["ndtype"]; $ntid = $_GET["ndtype"];
$dbtype = $_GET["dbtype"]; $dbtype = $_GET["dbtype"];
$ndtype = null; $ndtype = null;
......
...@@ -21,80 +21,71 @@ function errmsg($message, $context, $more = "") { ...@@ -21,80 +21,71 @@ function errmsg($message, $context, $more = "") {
(please read A-Introduction/servermenu_config.md).<br>$more</p>"; (please read A-Introduction/servermenu_config.md).<br>$more</p>";
} }
// reading db.json associations // reading project_conf.json associations
// source graph file <=> (db, dbtype, cols) as relatedDocs php API // source graph file <=> (db, dbtype, cols) as relatedDocs php API
// 1) we filter db.json entries by active/inactive nodetypes // 1) we filter db.json entries by active/inactive nodetypes
// 2) we filter db.json entries by supported dbtypes // 2) we filter db.json entries by supported dbtypes
function read_conf($filepath, $ntypes, $our_dbtypes) { function read_conf($filepath, $ntypes, $our_dbtypes, $project_dir) {
$project_menu_fh = fopen($filepath, "r"); $project_conf_fh = fopen($filepath, "r");
$json_st = ''; $json_st = '';
while (!feof($project_menu_fh)) { while (!feof($project_conf_fh)) {
$json_st .= fgets($project_menu_fh); $json_st .= fgets($project_conf_fh);
} }
fclose($project_menu_fh); fclose($project_conf_fh);
$project_menu = json_decode($json_st); $dir_items = json_decode($json_st);
$conf = array();
// echodump("== db.json menu ==", $project_menu); // echodump("== project_conf.json ==", $dir_items);
$conf = array(); foreach ($dir_items as $graph_file => $graph_conf){
foreach ($project_menu as $project_dir => $dir_items){ // echodump("== $graph_file ==", $graph_conf);
// NB access by obj property (and not array key)
if (! property_exists($dir_items, 'graphs')) {
error_log("tw/phpAPI skip error: conf file ($project_menu_path)
has no 'graphs' entry for project '$project_dir' !");
continue;
}
foreach ($dir_items->graphs as $graph_file => $graph_conf){
// echodump("== $graph_file ==", $graph_conf);
$gpath = $project_dir.'/'.$graph_file; $gpath = $project_dir.'/'.$graph_file;
// NB a graph conf can now have different settings for each nodetype // NB a graph conf can now have different settings for each nodetype
// node0 <=> classic type 'semantic' // node0 <=> classic type 'semantic'
// node1 <=> classic type 'social' // node1 <=> classic type 'social'
// NB2 now additionnally, each nodetype can have several dbs configured ! // NB2 now additionnally, each nodetype can have several dbs configured !
// $conf[$gpath] = array($ntypes); // $conf[$gpath] = array($ntypes);
for ($i = 0 ; $i < $ntypes ; $i++) { for ($i = 0 ; $i < $ntypes ; $i++) {
$conf[$gpath]['node'.$i] = array(); $conf[$gpath]['node'.$i] = array();
// check node0, node1, etc to see if they at least have a reldb conf // check node0, node1, etc to see if they at least have a reldb conf
if (property_exists($graph_conf, 'node'.$i) if (property_exists($graph_conf, 'node'.$i)
&& property_exists($graph_conf->{'node'.$i}, 'reldbs') ) { && property_exists($graph_conf->{'node'.$i}, 'reldbs') ) {
// check for each configured db that is listed under reldbs // check for each configured db that is listed under reldbs
$dbinfos = $graph_conf->{'node'.$i}->reldbs; $dbinfos = $graph_conf->{'node'.$i}->reldbs;
foreach ($dbinfos as $dbtype => $dbconf) { foreach ($dbinfos as $dbtype => $dbconf) {
// filter: supported and valid conf cases // filter: supported and valid conf cases
if (in_array($dbtype, $our_dbtypes) && $dbconf->file) { if (in_array($dbtype, $our_dbtypes) && $dbconf->file) {
// we have a file for this nodetype and dbtype: copy entire conf // we have a file for this nodetype and dbtype: copy entire conf
$conf[$gpath]['node'.$i][$dbtype] = (array)$dbconf ; $conf[$gpath]['node'.$i][$dbtype] = (array)$dbconf ;
// update files path with dirpath // update files path with dirpath
if (array_key_exists('file', $conf[$gpath]['node'.$i][$dbtype])) { if (array_key_exists('file', $conf[$gpath]['node'.$i][$dbtype])) {
$relpath = $conf[$gpath]['node'.$i][$dbtype]['file']; $relpath = $conf[$gpath]['node'.$i][$dbtype]['file'];
$conf[$gpath]['node'.$i][$dbtype]['file'] = $project_dir.'/'.$relpath; $conf[$gpath]['node'.$i][$dbtype]['file'] = $project_dir.'/'.$relpath;
}
} }
} }
// echodump("got conf", $conf[$gpath]['node'.$i]);
} }
else { // echodump("got conf", $conf[$gpath]['node'.$i]);
// empty array <=> inactive nodetype or no supported dbs
$conf[$gpath]['node'.$i] = array ();
}
// POSS here info on higher level may be propagated for lower ones
// (ex: if dbtype is on the project level, its value should count
// for each source file in the project unless overridden)
} }
else {
// empty array <=> inactive nodetype or no supported dbs
$conf[$gpath]['node'.$i] = array ();
}
// POSS here info on higher level may be propagated for lower ones
// (ex: if dbtype is on the project level, its value should count
// for each source file in the project unless overridden)
} }
} }
// echodump("full conf", $conf); // echodump("full conf", $conf);
return $conf; return $conf;
} }
......
...@@ -868,7 +868,7 @@ var TinaWebJS = function ( sigmacanvas ) { ...@@ -868,7 +868,7 @@ var TinaWebJS = function ( sigmacanvas ) {
// to init local, instance-related listeners (need to run at new sigma instance) // to init local, instance-related listeners (need to run at new sigma instance)
// args: @partialGraph = a sigma instance // args: @partialGraph = a sigma instance
this.initSigmaListeners = function(partialGraph, initialActivetypes, initialActivereltypes, optionalConfEntry) { this.initSigmaListeners = function(partialGraph, initialActivetypes, initialActivereltypes, optionalRelDocsConf) {
// console.log("initSigmaListeners TW.categories / types array / reltypeskeys array: ", TW.categories, initialActivetypes, initialActivereltypes) // console.log("initSigmaListeners TW.categories / types array / reltypeskeys array: ", TW.categories, initialActivetypes, initialActivereltypes)
...@@ -1085,13 +1085,10 @@ var TinaWebJS = function ( sigmacanvas ) { ...@@ -1085,13 +1085,10 @@ var TinaWebJS = function ( sigmacanvas ) {
$("#read-opposite-neighs").readmore({maxHeight:200}); $("#read-opposite-neighs").readmore({maxHeight:200});
} }
// initialize reldocs tabs if declared in additionalConf // initialize reldocs tabs if declared in optionalRelDocsConf
if (TW.conf.getRelatedDocs) { // (optionalRelDocsConf function-scope name of TW.currentRelDocsDBs)
if (TW.conf.getRelatedDocs && optionalRelDocsConf) {
let moreConfKey = optionalConfEntry || TW.File resetTabs(initialActivetypes, optionalRelDocsConf)
resetTabs(initialActivetypes, TW.gmenuInfos[moreConfKey])
} }
// defaultColoring: an attribute name to immediately apply color with // defaultColoring: an attribute name to immediately apply color with
......
...@@ -248,7 +248,7 @@ function createFilechooserEl () { ...@@ -248,7 +248,7 @@ function createFilechooserEl () {
TW.resetGraph() TW.resetGraph()
// run // run
mainStartGraph(theFormat, rdr.result, null, TW.instance) mainStartGraph(theFormat, rdr.result, TW.instance)
// NB 3rd arg null = we got no additional conf for this "unknown" file // NB 3rd arg null = we got no additional conf for this "unknown" file
...@@ -1163,7 +1163,7 @@ activateRDTab = function(elTgt) { ...@@ -1163,7 +1163,7 @@ activateRDTab = function(elTgt) {
} }
// set up tabs for a given activetypes state and db.json entry // set up tabs for a given activetypes state and project_conf.json relDB entry
function resetTabs(activetypes, dbconf) { function resetTabs(activetypes, dbconf) {
let ul = document.getElementById('reldocs-tabs') let ul = document.getElementById('reldocs-tabs')
let divs = document.getElementById('reldocs-boxes') let divs = document.getElementById('reldocs-boxes')
...@@ -1178,22 +1178,20 @@ function resetTabs(activetypes, dbconf) { ...@@ -1178,22 +1178,20 @@ function resetTabs(activetypes, dbconf) {
return return
} }
// console.log("dbconf for this source", dbconf)
// for all active nodetypes // for all active nodetypes
for (let nodetypeId in activetypes) { for (let nodetypeId in activetypes) {
if (activetypes[nodetypeId]) { if (activetypes[nodetypeId]) {
let additionalConf = dbconf[nodetypeId]
if (TW.conf.debug.logSettings)
console.log ("additionalConf for this source", additionalConf)
let possibleAPIs = [] let possibleAPIs = []
if (additionalConf.reldbs) {
possibleAPIs = additionalConf.reldbs
// 3 vars to know which one to activate if (dbconf[nodetypeId]) {
let nAPIs = Object.keys(possibleAPIs).length if (TW.conf.debug.logSettings)
console.log ("additional db conf for this source", dbconf[nodetypeId])
possibleAPIs = dbconf[nodetypeId]
}
let nAPIs = Object.keys(possibleAPIs).length
if (nAPIs > 0) {
// some more vars to know which one to activate
let iAPI = 0 let iAPI = 0
let didActiveFlag = false let didActiveFlag = false
...@@ -1266,7 +1264,7 @@ function openGraph(graphPath){ ...@@ -1266,7 +1264,7 @@ function openGraph(graphPath){
TW.resetGraph() TW.resetGraph()
TW.File = graphPath TW.File = graphPath
mainStartGraph(newDataRes["format"], newDataRes["data"], TW.File, TW.instance) mainStartGraph(newDataRes["format"], newDataRes["data"], TW.instance)
writeLabel(graphPathToLabel(graphPath)) writeLabel(graphPathToLabel(graphPath))
} }
//============================= </OTHER ACTIONS > =============================// //============================= </OTHER ACTIONS > =============================//
...@@ -446,7 +446,7 @@ function getTopPapers(qWords, nodetypeId, chosenAPI, tgtDivId) { ...@@ -446,7 +446,7 @@ function getTopPapers(qWords, nodetypeId, chosenAPI, tgtDivId) {
}); });
} }
else { else {
let thisRelDocsConf = TW.gmenuInfos[TW.File][nodetypeId]["reldbs"][chosenAPI] let thisRelDocsConf = TW.currentRelDocsDBs[nodetypeId][chosenAPI]
// /!\ documentation and specification needed for the php use cases /!\ // /!\ documentation and specification needed for the php use cases /!\
let joinedQ = JSON.stringify(qWords).split('&').join('__and__'); let joinedQ = JSON.stringify(qWords).split('&').join('__and__');
// cf. the php code for these url args: // cf. the php code for these url args:
...@@ -511,9 +511,9 @@ function displayTopPapers(jsonHits, ndtypeId, chosenAPI, targetDiv) { ...@@ -511,9 +511,9 @@ function displayTopPapers(jsonHits, ndtypeId, chosenAPI, targetDiv) {
toHtmlFun = renderTweet toHtmlFun = renderTweet
} }
else if (chosenAPI == "CortextDB" || chosenAPI == "csv") { else if (chosenAPI == "CortextDB" || chosenAPI == "csv") {
let thisRelDocsConf = TW.gmenuInfos[TW.File][ndtypeId]["reldbs"] let thisRelDocsConf = TW.currentRelDocsDBs[ndtypeId][chosenAPI]
if (thisRelDocsConf && thisRelDocsConf[chosenAPI] && thisRelDocsConf[chosenAPI].template) { if (thisRelDocsConf && thisRelDocsConf.template) {
toHtmlFun = makeRendererFromTemplate(thisRelDocsConf[chosenAPI].template) toHtmlFun = makeRendererFromTemplate(thisRelDocsConf.template)
} }
else { else {
console.warn(`no rendering template found in ${TW.conf.paths.sourceMenu} for this source ${TW.File}...`) console.warn(`no rendering template found in ${TW.conf.paths.sourceMenu} for this source ${TW.File}...`)
......
...@@ -3,12 +3,7 @@ ...@@ -3,12 +3,7 @@
// ======= [ main TW properties initialization ] ======== // // ======= [ main TW properties initialization ] ======== //
TW.File = "" // remember the currently opened file TW.File = "" // remember the currently opened file
// used iff servermenu
TW.gmenuPaths={}; // map [graphname => graphsource] for file selectors
TW.gmenuInfos={}; // map [graphsource => { node0/1 categories
// + relatedDocs db fields names}]
// a system state is the summary of tina situation // a system state is the summary of tina situation
TW.initialSystemState = { TW.initialSystemState = {
...@@ -47,16 +42,18 @@ TW.instance.init() ...@@ -47,16 +42,18 @@ TW.instance.init()
TW.instance.initGUIListeners(); TW.instance.initGUIListeners();
TW.instance.initSearchListeners(); TW.instance.initSearchListeners();
TW.currentRelDocsDBs = [] // to make available dbconf to topPapers
// show the custom name + home link of the app // show the custom name + home link of the app
writeBrand(TW.conf.branding, TW.conf.brandingLink) writeBrand(TW.conf.branding, TW.conf.brandingLink)
// choosing the input // choosing the input
// ------------------- // -------------------
// type of input // type of input
var sourcemode = isUndef(getUrlParam.sourcemode) ? TW.conf.sourcemode : getUrlParam.sourcemode TW.sourcemode = isUndef(getUrlParam.sourcemode) ? TW.conf.sourcemode : getUrlParam.sourcemode
// if page is being run locally ==> only possible source shall be via file input // if page is being run locally ==> only possible source shall be via file input
if (window.location.protocol == 'file:' || sourcemode == 'localfile') { if (window.location.protocol == 'file:' || TW.sourcemode == 'localfile') {
let inputDiv = document.getElementById('localInput') let inputDiv = document.getElementById('localInput')
inputDiv.style.display = 'block' inputDiv.style.display = 'block'
...@@ -77,23 +74,11 @@ if (window.location.protocol == 'file:' || sourcemode == 'localfile') { ...@@ -77,23 +74,11 @@ if (window.location.protocol == 'file:' || sourcemode == 'localfile') {
} }
// traditional cases: remote read from API or prepared server-side file // traditional cases: remote read from API or prepared server-side file
else { else {
try { // NB it will
// we'll first retrieve the menu of available sources in db.json, // - use global urlParams, TW.conf and possibly server_menu.json
// then get the real data in a second ajax via API or server file // - choose the source and format
[TW.gmenuInfos, TW.File] = readMenu(TW.conf.paths.sourceMenu) var [inFormat, inData, mapLabel] = syncRemoteGraphData()
mainStartGraph(inFormat, inData, TW.instance)
// NB: this menu used to be a file list for only one sourcemode
// but now also contains settings for nodetypes and for
// companion APIs (reldocs searches)
// => we read it for all cases now
}
catch(e) {
console.error(`Couldn't read ${TW.conf.paths.sourceMenu}, trying to start with settings_explorer defaults.`)
}
// NB it will use global urlParams and TW.settings to choose the source
var [inFormat, inData, inConfKey, mapLabel] = syncRemoteGraphData()
mainStartGraph(inFormat, inData, inConfKey, TW.instance)
writeLabel(mapLabel) writeLabel(mapLabel)
} }
...@@ -105,18 +90,16 @@ else { ...@@ -105,18 +90,16 @@ else {
function syncRemoteGraphData () { function syncRemoteGraphData () {
var inFormat; // = { db|api.json , somefile.json|gexf } var inFormat; // = { db|api.json , somefile.json|gexf }
var inData; // = {nodes: [....], edges: [....], cats:...} var inData; // = {nodes: [....], edges: [....], cats:...}
var inConfKey; // = source name for entry in db.json
var mapLabel; // user displayed label for this input dataset var mapLabel; // user displayed label for this input dataset
// case (1) read from remote DB via API bridge fetching // case (1) read from remote DB via API bridge fetching
// ex: /services/api/graph?q=filters... // ex: /services/api/graph?q=filters...
if (sourcemode == "api") { if (TW.sourcemode == "api") {
console.log("input case: api, using TW.conf.sourceAPI") console.log("input case: api, using TW.conf.sourceAPI")
// the only API format, cf. inData // the only API format, cf. inData
inFormat = 'json' inFormat = 'json'
inConfKey = 'graphapi/default'
// TODO-rename: s/nodeidparam/srcparams // TODO-rename: s/nodeidparam/srcparams
var sourceinfo = getUrlParam.nodeidparam var sourceinfo = getUrlParam.nodeidparam
...@@ -218,7 +201,7 @@ function syncRemoteGraphData () { ...@@ -218,7 +201,7 @@ function syncRemoteGraphData () {
} }
// sourcemode == "serverfile" or "servermenu" // TW.sourcemode == "serverfile" or "servermenu"
// cases (2) and (3) : read a file from server // cases (2) and (3) : read a file from server
else { else {
console.log("input case: server-side file, using TW.conf.paths.sourceMenu and/or TW.File") console.log("input case: server-side file, using TW.conf.paths.sourceMenu and/or TW.File")
...@@ -241,20 +224,35 @@ function syncRemoteGraphData () { ...@@ -241,20 +224,35 @@ function syncRemoteGraphData () {
// --> if @file also in url, choose the db.json one matching // --> if @file also in url, choose the db.json one matching
// --> otherwise, choose the "first_file" from db.json list // --> otherwise, choose the "first_file" from db.json list
// menufile case : a list of source files in ./db.json // menufile case : a list of source files in ./db.json
if (sourcemode == 'servermenu') { if (TW.sourcemode == 'servermenu') {
console.log("using entire FILEMENU TW.conf.paths.sourceMenu") console.log("== servermenu mode ==")
if (! linkCheck(TW.conf.paths.sourceMenu)) {
// chooser menu console.error(`servermenu mode: Couldn't read ${TW.conf.paths.sourceMenu}, referenced by TWConf.paths under sourceMenu... file is not accessible, trying to start with settings_explorer defaults.`)
var files_selector = '<select onchange="openGraph(this.options[this.selectedIndex].dataset.fullpath)">'
for (let fullPath in TW.gmenuInfos) {
let shortname = graphPathToLabel(fullPath)
let preSelected = (fullPath == TW.File)
files_selector += `<option ${preSelected ? "selected":""} data-fullpath="${fullPath}">`+shortname+'</option>'
} }
files_selector += "</select>" else {
$("#network").html(files_selector) // we'll first retrieve the menu of available sources in server_menu.json,
// then get the real data in a second ajax via API or server file
let [gmenu, firstProject] = readMenu(TW.conf.paths.sourceMenu)
// if TW.File was not set we keep the first one from readMenu
if (!TW.File) {
TW.File = firstProject + "/" + gmenu[firstProject][0]
}
// NB if TW.File was not in the list we keep the first one from readMenu // chooser menu
var files_selector = '<select onchange="openGraph(this.options[this.selectedIndex].dataset.fullpath)">'
for (var projectPath in gmenu) {
for (var i in gmenu[projectPath]) {
let filePath = gmenu[projectPath][i]
let fullPath = projectPath+'/'+filePath
let shortname = graphPathToLabel(fullPath)
let preSelected = (fullPath == TW.File)
files_selector += `<option ${preSelected ? "selected":""} data-fullpath="${fullPath}">`+shortname+'</option>'
}
}
files_selector += "</select>"
$("#network").html(files_selector)
}
} }
// 3) @mode is serverfile a or b (default) // 3) @mode is serverfile a or b (default)
...@@ -271,7 +269,6 @@ function syncRemoteGraphData () { ...@@ -271,7 +269,6 @@ function syncRemoteGraphData () {
var finalRes = AjaxSync({ url: TW.File }); var finalRes = AjaxSync({ url: TW.File });
inData = finalRes["data"] inData = finalRes["data"]
inFormat = finalRes["format"] inFormat = finalRes["format"]
inConfKey = TW.File
mapLabel = graphPathToLabel(TW.File) mapLabel = graphPathToLabel(TW.File)
if (TW.conf.debug.logFetchers) { if (TW.conf.debug.logFetchers) {
...@@ -282,7 +279,7 @@ function syncRemoteGraphData () { ...@@ -282,7 +279,7 @@ function syncRemoteGraphData () {
} }
} }
return [inFormat, inData, inConfKey, mapLabel] return [inFormat, inData, mapLabel]
} }
...@@ -300,9 +297,10 @@ function syncRemoteGraphData () { ...@@ -300,9 +297,10 @@ function syncRemoteGraphData () {
// args: // args:
// inFormat: 'json' or 'gexf' // inFormat: 'json' or 'gexf'
// inData: source data as str // inData: source data as str
// inConfKey: optional entry in db.json to declare nodetypes and reldbs
// twInstance: a tinaweb object (gui, methods) to bind the graph to // twInstance: a tinaweb object (gui, methods) to bind the graph to
function mainStartGraph(inFormat, inData, inConfKey, twInstance) { //
// NB: function also uses TW.File to get the associated project_conf.json entry
function mainStartGraph(inFormat, inData, twInstance) {
// Graph-related vars // Graph-related vars
// ------------------ // ------------------
...@@ -325,15 +323,30 @@ function mainStartGraph(inFormat, inData, inConfKey, twInstance) { ...@@ -325,15 +323,30 @@ function mainStartGraph(inFormat, inData, inConfKey, twInstance) {
alert("error on data load") alert("error on data load")
} }
else { else {
// override default categories with the ones from db.json if present let optNodeTypes = null
let additionalConf = [] let optRelDBs = null
if (TW.gmenuInfos[inConfKey]) { if (TW.sourcemode == "api") {
additionalConf = TW.gmenuInfos[inConfKey] optNodeTypes = TW.conf.sourceAPI.nodetypes
}
else {
// try and retrieve associated conf
[optNodeTypes, optRelDBs] = readProjectConf(TW.File)
// export to global for getTopPapers function :/
if (optRelDBs) {
TW.currentRelDocsDBs = optRelDBs
}
}
if (TW.conf.debug.logSettings) {
console.log("READ project_conf.json nodetypes", optNodeTypes)
console.log("READ project_conf.json relatedDBs", optRelDBs)
} }
// override default categories with project_conf.json if present
// parse the data // parse the data
if (TW.conf.debug.logParsers) console.log("parsing the data") if (TW.conf.debug.logParsers) console.log("parsing the data")
let start = new ParseCustom( inFormat , inData, additionalConf ); let start = new ParseCustom( inFormat , inData, optNodeTypes);
let catsInfos = start.scanFile(); let catsInfos = start.scanFile();
TW.categories = catsInfos.categories TW.categories = catsInfos.categories
...@@ -473,7 +486,7 @@ function mainStartGraph(inFormat, inData, inConfKey, twInstance) { ...@@ -473,7 +486,7 @@ function mainStartGraph(inFormat, inData, inConfKey, twInstance) {
TW.partialGraph, TW.partialGraph,
initialActivetypes, // to init node sliders and .class gui elements initialActivetypes, // to init node sliders and .class gui elements
initialActivereltypes, // to init edge sliders initialActivereltypes, // to init edge sliders
inConfKey // to init relatedDocs optRelDBs // optional conf to init relatedDocs
) )
// set the initial color // set the initial color
......
...@@ -61,13 +61,12 @@ TW.pushGUIState = function( args ) { ...@@ -61,13 +61,12 @@ TW.pushGUIState = function( args ) {
} }
// recreate tabs after type changes // recreate tabs after type changes
// db.json conf entry (£TODO unify s/(?:TW.File|inConfKey)/TW.sourceId/g) // project_conf.json conf entry (POSS unify s/TW.File/TW.sourceId/g)
let inConfKey = (sourcemode != "api") ? TW.File : 'graphapi/default'
if (TW.conf.getRelatedDocs if (TW.conf.getRelatedDocs
&& !isUndef(args.activetypes) && !isUndef(args.activetypes)
&& TW.gmenuInfos[inConfKey]) { && TW.currentRelDocsDBs) {
resetTabs(newState.activetypes, TW.gmenuInfos[inConfKey]) resetTabs(newState.activetypes, TW.currentRelDocsDBs)
} }
// 4) store it in TW.states // 4) store it in TW.states
...@@ -118,86 +117,127 @@ function graphPathToLabel(fullPath) { ...@@ -118,86 +117,127 @@ function graphPathToLabel(fullPath) {
) )
} }
// read all sources' detailed confs
// -> list of source paths available
// -> declared nodetypes
// -> declared rDocs conf
function readMenu(infofile) {
// exemple entry
// --------------
// "data/gargistex": {
// "first" : "shale_and_ice.gexf",
// "graphs":{
// "shale_and_ice.gexf": {
// "node0": {
// "name": "terms",
// "reldbs": {
// "csv": {
// "file": "shale_and_ice.csv",
// "qcols": ["title"],
// "template": "bib_details"
// },
// "twitter": {}
// }
// }
// }
// }
// }
// read the server files menu list
// (list of source paths available)
function readMenu(infofile) {
if (TW.conf.debug.logFetchers) console.info(`attempting to load filemenu ${infofile}`) if (TW.conf.debug.logFetchers) console.info(`attempting to load filemenu ${infofile}`)
var preRES = AjaxSync({ url: infofile, datatype:"json" }); var preRES = AjaxSync({ url: infofile, datatype:"json" });
if (preRES['OK'] && preRES.data) { if (preRES['OK'] && preRES.data) {
if (TW.conf.debug.logFetchers) console.log('initial AjaxSync result preRES', preRES) if (TW.conf.debug.logFetchers) console.log('initial AjaxSync result preRES', preRES)
} }
// 1 - store the first one (b/c we'll loose order) // we just make a clean copy, skipping invalid entries
var first_file = "", first_dir = "" , first_path = "" let serverMenu = {}
for( var path in preRES.data ) { let firstProject = null
if (TW.conf.debug.logFetchers) console.log("db.json path", path)
first_file = preRES.data[path]["first"] || Object.keys(preRES.data[path]["graphs"])[0] // check all the paths and associated sources
first_dir = path for( var projectPath in preRES.data ) {
break; if (! preRES.data[projectPath] || ! preRES.data[projectPath].length) {
console.warn("sourceMenu: Skipping invalid project entry:", projectPath)
}
else {
if (projectPath == "first_project") {
firstProject = preRES.data['first_project']
}
else {
// test and copy if ok
serverMenu[projectPath] = []
for (var l in preRES.data[projectPath]) {
let sourceFile = preRES.data[projectPath][l]
let fileExists = linkCheck(projectPath+'/'+sourceFile)
if (fileExists) {
serverMenu[projectPath].push(sourceFile)
}
}
if (! serverMenu[projectPath].length) {
console.warn(`sourceMenu: Skipping project path ${projectPath} (none of the referenced source files are present.)`)
delete serverMenu[projectPath]
}
}
}
}
return [serverMenu, firstProject]
}
// read project_conf.json files
function readProjectConf(aFilePath) {
let declaredNodetypes
let declaredDBConf
// we assume the filePath is of the form projectPath/sourceFile
let split = aFilePath.match("^(.*)/([^/]+)$")
if (! split) {
console.warn (`couldn't read associated conf for file, ${aFilePath}, will try using default nodetypes`)
} }
first_path = first_dir+"/"+first_file else {
let projectPath = split[1]
let filePath = split[2]
// 2 - process all the paths and associated confs let projectConfFile = projectPath + '/project_conf.json'
let details = {}
for( var path in preRES.data ) { if (! linkCheck(projectConfFile)) {
var theGraphs = preRES.data[path]["graphs"] console.warn (`no project_conf.json next to the file, ${aFilePath}, will try using default nodetypes`)
}
else {
for(var aGraph in theGraphs) { if (TW.conf.debug.logFetchers) console.info(`attempting to load project conf ${projectConfFile}`)
let fullPath = path+"/"+aGraph var pjconfRes = AjaxSync({ url: projectConfFile, datatype:"json" });
// ex : "RiskV2PageRank1000.gexf":data/AXA/RiskV2PageRank1000.gexf
// (we assume there's no duplicate basenames)
if (TW.conf.debug.logSettings) if (TW.conf.debug.logFetchers) console.log('project conf AjaxSync result pjconfRes', pjconfRes)
console.log("db conf entry: " + fullPath)
// for associated LocalDB php queries: CSV (or CortextDBs sql) if (! pjconfRes['OK']
if (theGraphs[aGraph]) { || ! pjconfRes.data
let gSrcEntry = theGraphs[aGraph] || ! pjconfRes.data[filePath] ) {
details[fullPath] = new Array(2) console.warn (`project_conf.json in ${projectPath} is not valid json or does not contain an entry for ${filePath}, will try using default nodetypes`)
if (gSrcEntry.node0) { }
details[fullPath][0] = gSrcEntry.node0 else {
} let confEntry = pjconfRes.data[filePath]
if (gSrcEntry.node1) { for (var ndtype in confEntry) {
details[fullPath][1] = gSrcEntry.node1 if (! /node\d+/.test(ndtype)) {
} console.warn (`project_conf.json in ${projectPath}, in the entry for ${filePath}, should only contain properties like 'node0', 'node1', etc.`)
} }
else { else {
details[fullPath] = null if (! confEntry[ndtype].name) {
console.warn (`project_conf.json in ${projectPath}, in the entry for ${filePath}.${ndtype}, should contain a 'name' property`)
}
// valid case !
else {
if (! declaredNodetypes) declaredNodetypes = {}
// fill simple nodetypes
declaredNodetypes[ndtype] = confEntry[ndtype].name
}
// optional reldbs -----------------------
if (confEntry[ndtype].reldbs) {
if (! declaredDBConf) declaredDBConf = {}
// it must match because we tested well-formedness above
let ndtypeId = ndtype.match(/^node(\d+)/)[1]
declaredDBConf[ndtypeId] = {}
for (var dbtype in confEntry[ndtype].reldbs) {
if (! TW.conf.relatedDocsAPIS[dbtype]) {
console.info (`project_conf.json: ${projectPath}.${filePath}.${ndtype}: skipping unknown related docs db type **${dbtype}**. The only available db types are: ${Object.keys(TW.conf.relatedDocsAPIS)}.`)
}
else {
declaredDBConf[ndtypeId][dbtype] = confEntry[ndtype].reldbs[dbtype]
}
}
}
// ----------------------------------------
} }
}
} }
}
} }
return [declaredNodetypes, declaredDBConf]
return [details, first_path]
} }
// settings: {norender: Bool} // settings: {norender: Bool}
function cancelSelection (fromTagCloud, settings) { function cancelSelection (fromTagCloud, settings) {
if (TW.conf.debug.logSelections) { console.log("\t***in cancelSelection"); } if (TW.conf.debug.logSelections) { console.log("\t***in cancelSelection"); }
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
// (for instance loop on full gexf in scanGexf then again in dictfyGexf) // (for instance loop on full gexf in scanGexf then again in dictfyGexf)
// Level-01 // Level-01
var ParseCustom = function ( format , data, optionalConf ) { var ParseCustom = function ( format , data, optionalNodeConf ) {
if (format == 'gexf') { if (format == 'gexf') {
this.data = $.parseXML(data) this.data = $.parseXML(data)
...@@ -14,12 +14,10 @@ var ParseCustom = function ( format , data, optionalConf ) { ...@@ -14,12 +14,10 @@ var ParseCustom = function ( format , data, optionalConf ) {
this.format = format; this.format = format;
this.nbCats = 0; this.nbCats = 0;
this.additionalConf = optionalConf
// input = GEXFstring // input = GEXFstring
this.getGEXFCategories = function() { this.getGEXFCategories = function() {
let observedCategories = scanGexf(this.data) let observedCategories = scanGexf(this.data)
let finalCategories = sortNodeTypes(observedCategories, this.additionalConf) let finalCategories = sortNodeTypes(observedCategories,optionalNodeConf)
return finalCategories; return finalCategories;
}// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}} }// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}}
...@@ -34,7 +32,7 @@ var ParseCustom = function ( format , data, optionalConf ) { ...@@ -34,7 +32,7 @@ var ParseCustom = function ( format , data, optionalConf ) {
// input = JSONstring // input = JSONstring
this.getJSONCategories = function(json) { this.getJSONCategories = function(json) {
let observedCategories = scanJSON(this.data) let observedCategories = scanJSON(this.data)
let finalCategories = sortNodeTypes(observedCategories, this.additionalConf) let finalCategories = sortNodeTypes(observedCategories, optionalNodeConf)
return finalCategories; return finalCategories;
}// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}} }// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}}
...@@ -212,15 +210,20 @@ function scanGexf(gexfContent) { ...@@ -212,15 +210,20 @@ function scanGexf(gexfContent) {
// expected content: usually a just a few cats over all nodes // expected content: usually a just a few cats over all nodes
// ex: terms // ex: terms
// ex: ISItermsriskV2_140 & ISItermsriskV2_140 // ex: ISItermsriskV2_140 & ISItermsriskV2_140
function sortNodeTypes(observedTypesDict, optConf) { // optional arg optionalNodeConf should contain keys of the form:
// "node0": "NGram",
// "node1": "Document"
// etc.
// (it's read from project_conf.json)
function sortNodeTypes(observedTypesDict, optionalNodeConf) {
var observedTypes = Object.keys(observedTypesDict) var observedTypes = Object.keys(observedTypesDict)
observedTypes.sort(function(a,b) {return observedTypesDict[b] - observedTypesDict[a]}) observedTypes.sort(function(a,b) {return observedTypesDict[b] - observedTypesDict[a]})
let nbNodeTypes = 2 let nbNodeTypes = 2
var declaredTypes = [] var declaredTypes = []
for (var i = 0 ; i < nbNodeTypes ; i++ ) { for (var i = 0 ; i < nbNodeTypes ; i++ ) {
if (optConf[i] && optConf[i].name) { if (optionalNodeConf["node"+i]) {
declaredTypes[i] = optConf[i].name declaredTypes[i] = optionalNodeConf["node"+i]
if (TW.conf.debug.logSettings) if (TW.conf.debug.logSettings)
console.log("expected cat (from db.json addtional conf)", i, declaredTypes[i]) console.log("expected cat (from db.json addtional conf)", i, declaredTypes[i])
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment