Commit b1d5b0ae authored by Romain Loth's avatar Romain Loth

Merge branch 'better_related_docs_conf_2'

parents 9fe65bd2 24648495
...@@ -13,9 +13,9 @@ Après commits de la semaine 26-30 juin 2017, une structure plus facile pour les ...@@ -13,9 +13,9 @@ Après commits de la semaine 26-30 juin 2017, une structure plus facile pour les
│   └── (fusionné avec ./doc) │   └── (fusionné avec ./doc)
├── data ├── data
│   └── (graphes par sous-projets) │   └── (graphes par sous-projets)
├── db.json
├── explorerjs.html <= point d'entrée lancement ├── explorerjs.html <= point d'entrée lancement
├── settings_explorerjs.js <= point d'entrée config ├── settings_explorerjs.js <= config générale
├── db.json <= config additionnelle par sources gexf/json
├── favicon.ico ├── favicon.ico
├── LICENSE ├── LICENSE
├── README.md ├── README.md
...@@ -34,7 +34,6 @@ Après commits de la semaine 26-30 juin 2017, une structure plus facile pour les ...@@ -34,7 +34,6 @@ Après commits de la semaine 26-30 juin 2017, une structure plus facile pour les
│   ├── jquery-3 │   ├── jquery-3
│   ├── readmore.js │   ├── readmore.js
│   ├── sigma_v1.2 │   ├── sigma_v1.2
│   ├── sigma_v1.5
│   └── tweets │   └── tweets
| |
├── twmain <= ancien dossier tinawebJS ├── twmain <= ancien dossier tinawebJS
......
...@@ -64,55 +64,103 @@ Having a node0.name entry and optionally a node1.name is enough to display the g ...@@ -64,55 +64,103 @@ Having a node0.name entry and optionally a node1.name is enough to display the g
The servermenu file also allows configuration of associated queries for selected node(s): **relatedDocs** The servermenu file also allows configuration of associated queries for selected node(s): **relatedDocs**
To enable it, you need to add to your node entry the `reldbfile` key: To enable it, you need to add to your node entry the `reldbs` key with minimally a db type :
```json ```json
"node0": { "node0": {
"name": "$$blabla", "name": "$$blabla",
"reldbfile": "$$relpath/to/csv/or/sqlite" "reldbs": {
"$$myType" : {}
}
} }
``` ```
The presence of this property `reldbfile` makes the API usable in db.json. The presence of this property "reldbs" makes the API usable in db.json.
##### 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.
###### => for a CSV doc-by-doc table ###### => for a CSV doc-by-doc table
Expected type is `"csv"` and you should fill the columns to search in. Expected type is `"csv"` and you should fill the columns to search in and the template to use to render hits
```json ```json
"reldbtype": "csv", "reldbs": {
"reldbqcols": ["list", "of", "columns", "to", "search", "in", "for", "node0"] "csv" : {
"file": "$$relpath/to/some.csv",
"qcols": ["list", "of", "cols", "to", "search", "in", "for", "node0"],
"template": "bib_details"
}
}
``` ```
###### Real life example ###### => for a cortext sql base
Expected type is `"CortextDB"` and you should fill the tables to search in.
```json
"reldbs": {
"CortextDB": {
"file": "$$relpath/to/some.db",
"qtable": "$$tableNameToSearchIn",
"template": "cortext_with_link"
}
}
```
###### => for twitter queries
Expected type is `"twitter"` and no additional conf is needed (POSS for the future: add twitter query context, ex: "Présidentielles 2017 AND (query)").
```json
"reldbs": {
"twitter": {}
}
```
###### Real life examples
```json ```json
"data/gargistex": { "data/gargistex": {
"first": "shale_and_ice.gexf", "graphs":{
"graphs": { "model_calibration.gexf": {
"shale_and_ice.gexf": {
"node0": { "node0": {
"name": "terms", "name": "terms",
"reldbtype": "csv", "reldbs": {
"reldbfile": "shale_and_ice.csv", "csv": {
"reldbqcols": ["title", "abstract"] "file": "model_calibration.csv",
} "qcols": ["title"],
"template": "bib_details"
}, },
"model_calibration.gexf": { "twitter": {}
}
}
}
}
},
"data/test": {
"first" : "mini_for_csv.gexf",
"graphs": {
"mini_for_csv.gexf": {
"node0": { "node0": {
"name": "terms", "name": "terms",
"reldbtype": "csv", "reldbs": {
"reldbfile": "model_calibration.csv", "csv": {
"reldbqcols": ["title", "abstract"] "file": "mini_for_csv.csv",
"qcols": ["title","keywords","text"],
"template": "bib_details"
},
"twitter": {}
}
},
"node1": {
"name": "authors",
"reldbs": {
"csv": {
"file": "mini_for_csv.csv",
"qcols": ["author"],
"template": "bib_details"
}
}
} }
} }
} }
} }
``` ```
###### => for CortextDB SQL tables In the last exemple, we have two nodetypes:
Expected type is `"CortextDB"` and you should fill the table to search in. - node0 allows both CSV and twitter relatedDocs tabs.
```json - node1 allows only the CSV relatedDocs tab.
"reldbtype": "CortextDB",
"reldbqtable": []
```
This is a stub for a future documentation for developers. This is a stub for a future documentation for developers.
#### About settings
- system-wide settings are in `settings_explorerjs.js`
- source-by-source settings (nodetypes, relatedDocs APIs) are in `db.json`
## Graph input choices ## Graph input choices
...@@ -13,7 +16,7 @@ Tina allows 3 main ways of input : ...@@ -13,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 a list of files called `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 `db.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.
...@@ -33,6 +36,7 @@ This will still evolve but the main steps for any graph initialization messily u ...@@ -33,6 +36,7 @@ This will still evolve but the main steps for any graph initialization messily u
1. precomputes display properties (grey color, etc.) 1. precomputes display properties (grey color, etc.)
2. calls [`sigmaUtils`] where the function `FillGraph()` was a central point for filtering and preparing properties but now with 2 and 3 it just creates a filtered copy of the nodes and edges of the current active types to a new structure that groups them together (POSSIBLE remove this extra step) 2. calls [`sigmaUtils`] where the function `FillGraph()` was a central point for filtering and preparing properties but now with 2 and 3 it just creates a filtered copy of the nodes and edges of the current active types to a new structure that groups them together (POSSIBLE remove this extra step)
3. back in [`main.js`], finally all sigma settings (user + defaults) are merged and we initialize the sigma instance (`new sigma` etc.) 3. back in [`main.js`], finally all sigma settings (user + defaults) are merged and we initialize the sigma instance (`new sigma` etc.)
at this point, any additional conf located in db.json is used for nodeTypes and relatedDocsTypes
4. finally a call to [`TinawebJS`] initializes the action listeners and this phase should crucially initialize items that need the sigma instance (because they may depend the displayed categories, the number of displayed nodes, etc) 4. finally a call to [`TinawebJS`] initializes the action listeners and this phase should crucially initialize items that need the sigma instance (because they may depend the displayed categories, the number of displayed nodes, etc)
......
{ {
"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": { "data/gargistex": {
"first" : "shale_and_ice.gexf", "first" : "shale_and_ice.gexf",
"graphs":{ "graphs":{
"shale_and_ice.gexf": { "shale_and_ice.gexf": {
"node0": { "node0": {
"name": "terms", "name": "terms",
"reldbtype": "csv", "reldbs": {
"reldbfile": "shale_and_ice.csv", "csv": {
"reldbqcols": ["title"], "file": "shale_and_ice.csv",
"reltemplate": "bib_details" "qcols": ["title"],
"template": "bib_details"
},
"twitter": {}
}
} }
}, },
"model_calibration.gexf": { "model_calibration.gexf": {
"node0": { "node0": {
"name": "terms", "name": "terms",
"reldbtype": "csv", "reldbs": {
"reldbfile": "model_calibration.csv", "csv": {
"reldbqcols": ["title"], "file": "model_calibration.csv",
"reltemplate": "bib_details" "qcols": ["title"],
"template": "bib_details"
},
"twitter": {}
}
} }
} }
} }
...@@ -37,17 +62,24 @@ ...@@ -37,17 +62,24 @@
"mini_for_csv.gexf": { "mini_for_csv.gexf": {
"node0": { "node0": {
"name": "term", "name": "term",
"reldbtype": "csv", "reldbs": {
"reldbfile": "mini_for_csv.csv", "csv": {
"reldbqcols": ["title","keywords","text"], "file": "mini_for_csv.csv",
"reltemplate": "bib_details" "qcols": ["title","keywords","text"],
"template": "bib_details"
},
"twitter": {}
}
}, },
"node1": { "node1": {
"name": "person", "name": "person",
"reldbtype": "csv", "reldbs": {
"reldbfile": "mini_for_csv.csv", "csv": {
"reldbqcols": ["author"], "file": "mini_for_csv.csv",
"reltemplate": "bib_details" "qcols": ["author"],
"template": "bib_details"
}
}
} }
}, },
"test_with_various_atts.gexf": {} "test_with_various_atts.gexf": {}
...@@ -59,23 +91,21 @@ ...@@ -59,23 +91,21 @@
"first" : "ProgrammeDesCandidats.enrichi.gexf", "first" : "ProgrammeDesCandidats.enrichi.gexf",
"graphs": { "graphs": {
"ProgrammeDesCandidats.enrichi.gexf": { "ProgrammeDesCandidats.enrichi.gexf": {
"node0": { "name": "terms" } "node0": { "name": "terms", "reldbs": { "twitter": {} } }
}, },
"ProgrammeDesCandidats.gexf": { "ProgrammeDesCandidats.gexf": {
"node0": { "name": "terms" } "node0": { "name": "terms", "reldbs": { "twitter": {} } }
} }
} }
}, },
"data/ClimateChange": { "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": { "graphs": {
"Maps_S_800.gexf": { "default": {
"node0": { "node0": { "name": "NGram", "reldbs": { "twitter": {} } },
"name": "ISItermsWhitelistV2Oct_5 &amp; ISItermsWhitelistV2Oct_5", "node1": { "name": "Document" }
"reldbqtable": "ISItermsWhitelistV2Oct_5",
"reldbfile" : "wos_climate-change_title_2014-2015.db",
"reldbtype": "CortextDB",
"reltemplate": "cortext_with_link"
}
} }
} }
} }
......
...@@ -475,9 +475,13 @@ ...@@ -475,9 +475,13 @@
<!-- One tab pane <!-- One tab pane
(only one with topPapers, we change content ourselves) (only one with topPapers, we change content ourselves)
--> -->
<div class="tab-content"> <div id="reldocs-boxes" class="tab-content">
<div id="topPapers" role="tabpanel" class="tab-pane active"> <!--
exemple:
<div id="rd-0-csv" role="tabpanel" class="topPapers tab-pane active">
</div> </div>
-->
</div> </div>
</div> </div>
...@@ -764,7 +768,7 @@ ...@@ -764,7 +768,7 @@
<script src="twlibs3/freshslider/freshslider.1.0.js" type="text/javascript" ></script> <script src="twlibs3/freshslider/freshslider.1.0.js" type="text/javascript" ></script>
<script src="twlibs3/readmore.js" type="text/javascript"></script> <script src="twlibs3/readmore.js" type="text/javascript"></script>
<script src="twlibs3/tweets/widgets.js" type="text/javascript" language="javascript"></script> <script src="twlibs3/tweets/widgets.js" type="text/javascript" language="javascript"></script>
<script src="twlibs3/bootstrap-native/bootstrap-native.min.js"></script> <script src="twlibs3/bootstrap-native/bootstrap-native.js"></script>
<!-- new sigma 1.2 imports --> <!-- new sigma 1.2 imports -->
<!-- <script src="twlibs3/sigma_v1.2/sigma.min.js" type="text/javascript" language="javascript"></script> --> <!-- <script src="twlibs3/sigma_v1.2/sigma.min.js" type="text/javascript" language="javascript"></script> -->
<script src="twlibs3/sigma_v1.2/sigma.noIndexes.js" type="text/javascript" language="javascript"></script> <script src="twlibs3/sigma_v1.2/sigma.noIndexes.js" type="text/javascript" language="javascript"></script>
......
...@@ -31,13 +31,15 @@ TW.conf = (function(TW){ ...@@ -31,13 +31,15 @@ TW.conf = (function(TW){
TWConf.getRelatedDocs = true TWConf.getRelatedDocs = true
TWConf.relatedDocsMax = 10 TWConf.relatedDocsMax = 10
TWConf.relatedDocsType = "LocalDB" // accepted: "twitter" | "LocalDB" // fallback type (if no detailed source-by-source conf from db.json)
TWConf.relatedDocsType = "csv" // accepted: "twitter" | "csv" | "CortextDB"
// POSSible: "elastic" // POSSible: "elastic"
TWConf.relatedDocsAPIS = {
// routes by corresponding type // routes by corresponding type
"LocalDB": "twbackends/phpAPI", TWConf.relatedDocsAPIS = {
"twitter": "http://127.0.0.1:5000/twitter_search" "twitter": "http://127.0.0.1:5000/twitter_search",
"CortextDB": "twbackends/phpAPI",
"csv": "twbackends/phpAPI"
} }
// fallback topPapers API if none found by type // fallback topPapers API if none found by type
......
...@@ -6,7 +6,7 @@ $elems = json_decode($query); ...@@ -6,7 +6,7 @@ $elems = json_decode($query);
// the table used as search perimeter is from db.json conf // the table used as search perimeter is from db.json conf
$table = $my_conf[$ntid]['reldbqtable'] ; $table = $my_conf["node".$ntid][$dbtype]['qtable'] ;
// values for CortextDB that seem to never change: /!\ hardcoded here /!\ // values for CortextDB that seem to never change: /!\ hardcoded here /!\
// the column accessors // the column accessors
...@@ -100,7 +100,7 @@ foreach ($wos_ids as $id => $score) { ...@@ -100,7 +100,7 @@ foreach ($wos_ids as $id => $score) {
foreach ($base->query($sql) as $row) { foreach ($base->query($sql) as $row) {
$external_link="<a href=http://google.com/webhp?#q=".urlencode('"'.$row['data'].'"')." target=blank>".' <img width=15px src="'.$our_libs_root.'/img/google.png"></a>'; $external_link="<a href=http://google.com/webhp?#q=".urlencode('"'.$row['data'].'"')." target=blank>".' <img width=15px src="'.$our_libs_root.'/img/google.png"></a>';
$link = 'JavaScript:newPopup(\''.$our_php_root.'/default_doc_details.php?gexf='.urlencode($gexf).'&index='.$table.'&query='.urlencode($query).'&type='.urlencode($_GET['type']).'&id='.$id.' \')'; $link = 'JavaScript:newPopup(\''.$our_php_root.'/default_doc_details.php?gexf='.urlencode($gexf).'&dbtype='.$dbtype.'&query='.urlencode($query).'&ndtype='.$ntid.'&id='.$id.'\')';
if ($output_mode == "html") { if ($output_mode == "html") {
$htmlout.="<li title='".$score."'>"; $htmlout.="<li title='".$score."'>";
......
...@@ -6,6 +6,9 @@ $base = new PDO("sqlite:" .$mainpath.$graphdb); ...@@ -6,6 +6,9 @@ $base = new PDO("sqlite:" .$mainpath.$graphdb);
$query = str_replace( '__and__', '&', $_GET["query"] ); $query = str_replace( '__and__', '&', $_GET["query"] );
$terms_of_query = json_decode($query); $terms_of_query = json_decode($query);
// the table used as search perimeter is from db.json conf
$table = $my_conf["node".$ntid][$dbtype]['qtable'] ;
// echo "mainpath: ".$mainpath."<br>"; // echo "mainpath: ".$mainpath."<br>";
// echo "thedb: ".$mainpath.$graphdb."<br>"; // echo "thedb: ".$mainpath.$graphdb."<br>";
// echo "thequery: ".var_dump($terms_of_query); // echo "thequery: ".var_dump($terms_of_query);
...@@ -32,7 +35,7 @@ echo ' ...@@ -32,7 +35,7 @@ echo '
<div id="tabs"> <div id="tabs">
<ul> <ul>
<li><a href="#tabs-1">Selected Document</a></li> <li><a href="#tabs-1">Selected Document</a></li>
<li><a href="full_doc_list.php?'.'gexf='.urlencode($gexf).'&query='.urlencode($_GET["query"]).'&index='.$_GET["index"].'&type='.urlencode($_GET["type"]).'">Full list</a></li>'; <li><a href="full_doc_list.php?'.'gexf='.urlencode($gexf).'&query='.urlencode($_GET["query"]).'&ndtype='.$ntid.'&dbtype='.$dbtype.'">Full list</a></li>';
echo '</ul>'; echo '</ul>';
echo '<div id="tabs-1">'; echo '<div id="tabs-1">';
...@@ -81,7 +84,7 @@ $id=$_GET["id"]; ...@@ -81,7 +84,7 @@ $id=$_GET["id"];
// } // }
// // get the date // // get the date
if(strpos($_GET["index"],'terms') ) $sql = 'SELECT data FROM '.$_GET["index"].' WHERE id='.$id; if(strpos($table,'terms') ) $sql = "SELECT data FROM $table WHERE id=".$id;
else $sql = 'SELECT data FROM ISItermsListV1 WHERE id='.$id; else $sql = 'SELECT data FROM ISItermsListV1 WHERE id='.$id;
$output.='<br/><b>Keywords: </b>'; $output.='<br/><b>Keywords: </b>';
$terms=array(); $terms=array();
......
...@@ -8,7 +8,7 @@ $base = new PDO("sqlite:" .$mainpath.$graphdb); ...@@ -8,7 +8,7 @@ $base = new PDO("sqlite:" .$mainpath.$graphdb);
$output = "<ul>"; // string sent to the javascript for display $output = "<ul>"; // string sent to the javascript for display
$type = $_GET["type"]; $type = $_GET["ndtype"];
$query = str_replace( '__and__', '&', $_GET["query"] ); $query = str_replace( '__and__', '&', $_GET["query"] );
$terms_of_query=json_decode($_GET["query"]); $terms_of_query=json_decode($_GET["query"]);
$elems = json_decode($query); $elems = json_decode($query);
...@@ -19,25 +19,20 @@ foreach ($base->query($sql) as $row) { ...@@ -19,25 +19,20 @@ foreach ($base->query($sql) as $row) {
$table_size=$row['COUNT(*)']; $table_size=$row['COUNT(*)'];
} }
$table = ""; // the table used as search perimeter is from db.json conf
$column = ""; $table = $my_conf["node".$ntid][$dbtype]['qtable'] ;
$id="";
if($type=="social"){ // values for CortextDB that seem to never change: /!\ hardcoded here /!\
$table = "ISIAUTHOR"; // the column accessors
$column = "data"; $column = "data";
$id = "id"; $id = "id";
$restriction='';
$factor=10;// factor for normalisation of stars
}
if($type=="semantic"){ // the output tables
$table = $_GET["index"]; $author_table = "ISIAUTHOR";
$column = "data"; $titles_table = "ISITITLE";
$id = "id";
$restriction=''; $factor=10;// factor for normalisation of stars
$factor=10; $restriction='';
}
$sql = 'SELECT count(*),'.$id.' $sql = 'SELECT count(*),'.$id.'
...@@ -88,7 +83,7 @@ foreach ($wos_ids as $id => $score) { ...@@ -88,7 +83,7 @@ foreach ($wos_ids as $id => $score) {
$count+=1; $count+=1;
$output.="<li title='".$score."'>"; $output.="<li title='".$score."'>";
$output.=imagestar($score,$factor,'./').' '; $output.=imagestar($score,$factor,'./').' ';
$sql = 'SELECT data FROM ISITITLE WHERE id='.$id." group by data"; $sql = "SELECT data FROM $titles_table WHERE id=".$id." group by data";
foreach ($base->query($sql) as $row) { foreach ($base->query($sql) as $row) {
$output.='<a href="default_doc_details.php?gexf='.urlencode($gexf).'&type='.urlencode($_GET["type"]).'&query='.urlencode($query).'&id='.$id.'">'.$row['data']." </a> "; $output.='<a href="default_doc_details.php?gexf='.urlencode($gexf).'&type='.urlencode($_GET["type"]).'&query='.urlencode($query).'&id='.$id.'">'.$row['data']." </a> ";
...@@ -96,7 +91,7 @@ foreach ($wos_ids as $id => $score) { ...@@ -96,7 +91,7 @@ foreach ($wos_ids as $id => $score) {
} }
// get the authors // get the authors
$sql = 'SELECT data FROM ISIAUTHOR WHERE id='.$id; $sql = "SELECT data FROM $author_table WHERE id=".$id;
foreach ($base->query($sql) as $row) { foreach ($base->query($sql) as $row) {
$output.=strtoupper($row['data']).', '; $output.=strtoupper($row['data']).', ';
} }
......
...@@ -14,25 +14,6 @@ if ($output_mode == "json") { ...@@ -14,25 +14,6 @@ if ($output_mode == "json") {
header('Content-Type: application/json'); header('Content-Type: application/json');
} }
$dbtype = null;
if (array_key_exists('reldbtype', $my_conf[$ntid])) {
$dbtype = $my_conf[$ntid]['reldbtype'];
}
else {
$guess_src = '';
if (array_key_exists('dbtype', $_GET)) {
$dbtype = $_GET['dbtype'];
$guess_src = "via url parameters";
}
else {
$dbtype = 'csv'; // new default
$guess_src = "by default";
}
errmsg("not filled", "$gexf -> node$ntid -> 'reldbtype'", "...Assuming dbtype is $dbtype ($guess_src).");
}
if ($dbtype == "CortextDB") { if ($dbtype == "CortextDB") {
$base = new PDO("sqlite:".$mainpath.$graphdb); $base = new PDO("sqlite:".$mainpath.$graphdb);
include('default_div.php'); include('default_div.php');
...@@ -42,13 +23,20 @@ else { ...@@ -42,13 +23,20 @@ else {
// to index: the union of "searchable columns" qcols for all nodetypes // to index: the union of "searchable columns" qcols for all nodetypes
$idxcolsbytype = []; $idxcolsbytype = [];
for ($i = 0; $i < $ntypes ; $i++) { for ($i = 0; $i < $ntypes ; $i++) {
if ($my_conf[$i]['active']) {
$idxcolsbytype[$i] = []; // if nodetype is active
$idxcolsbytype[$i] = $my_conf[$i]['reldbqcols']; if (count($my_conf["node".$i])) {
// ... and well-formed
if (array_key_exists('qcols', $my_conf["node".$i][$dbtype])) {
$idxcolsbytype[$i] = $my_conf["node".$i][$dbtype]['qcols'];
}
else {
echo("<p>Your settings for relatedDocsType are set on a local database,
but your servermenu file does not provide any information about
the CSV or DB table to query for related documents
(on nodetypeId ".$i.")</p>");
}
} }
// else {
// echo("no nodetype ".$i."<br>");
// }
} }
if (! $idxcolsbytype) { if (! $idxcolsbytype) {
...@@ -98,7 +86,7 @@ else { ...@@ -98,7 +86,7 @@ else {
// DO THE SEARCH // DO THE SEARCH
// ------------- // -------------
$searchcols = $my_conf[$ntid]['reldbqcols']; $searchcols = $my_conf["node".$ntid][$dbtype]['qcols'];
// a - split the query // a - split the query
$qtokens = preg_split('/\W/', $_GET["query"]); $qtokens = preg_split('/\W/', $_GET["query"]);
......
...@@ -21,7 +21,10 @@ $mainpath=dirname(dirname(getcwd()))."/"; // default fs path to ProjectExplorer ...@@ -21,7 +21,10 @@ $mainpath=dirname(dirname(getcwd()))."/"; // default fs path to ProjectExplorer
$project_menu_path = "db.json"; $project_menu_path = "db.json";
// 3 - others // 3 - others
$ntypes = 2; // max node types $ntypes = 2; // max node types (node0 & node1)
// accepted entries in db.json -> source -> reldbs -> dbtype
$supported_dbtypes = ['csv', 'CortextDB'];
// number of docs to display setting // number of docs to display setting
$max_item_displayed = 7; $max_item_displayed = 7;
...@@ -38,30 +41,39 @@ $memport = 11211; ...@@ -38,30 +41,39 @@ $memport = 11211;
// CONFIGURATION PARAMS // 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); $conf = read_conf($mainpath.$project_menu_path, $ntypes, $supported_dbtypes);
// ======================================= // =======================================
// echodump("== READ CONF ==<br>", $conf); // echodump("== READ CONF ==<br>", $conf);
// ======================================= // =======================================
$gexf= str_replace('"','',$_GET["gexf"]); $gexf= str_replace('"','',$_GET["gexf"]);
$ndtype = $_GET["type"]; $ntid = $_GET["ndtype"];
$ntid = null; $dbtype = $_GET["dbtype"];
$ndtype = null;
$my_conf = null; $my_conf = null;
// legacy types => generic types with 0 as default // new types => legacy types (with semantic as default)
if ($ndtype == 'social') { $ntid = 1; } if ($ntid == 0) { $ndtype = 'social' ; }
else { $ntid = 0; } else { $ndtype = 'semantic'; }
// echodump("params: node type id", $ntid); // echodump("params: node type id", $ntid);
if (! $conf[$gexf][$ntid]['active']) { if (! count($conf[$gexf]['node'.$ntid])) {
errmsg("not active", "your graph ($gexf)"); errmsg("has no php reldbs configured for nodetype $ntid", "your graph ($gexf)");
exit(1);
}
else if (! array_key_exists($dbtype, $conf[$gexf]['node'.$ntid])) {
errmsg("reldbs isn't configured for nodes of type $ntid and dbtype $dbtype", "your graph ($gexf)");
exit(1);
}
else if (! array_key_exists('file', $conf[$gexf]['node'.$ntid][$dbtype])) {
errmsg("reldb has no DB file for nodes of type $ntid and dbtype $dbtype", "your graph ($gexf)");
exit(1); exit(1);
} }
else { else {
$my_conf = $conf[$gexf]; $my_conf = $conf[$gexf];
$graphdb = $my_conf[$ntid]['dir'].'/'.$my_conf[$ntid]['reldbfile']; $graphdb = $my_conf['node'.$ntid][$dbtype]['file'];
} }
// echodump("params: reldb", $graphdb); // echodump("params: reldb", $graphdb);
......
...@@ -11,13 +11,15 @@ function echodump($title, $anyObj) { ...@@ -11,13 +11,15 @@ function echodump($title, $anyObj) {
function errmsg($message, $context, $more = "") { function errmsg($message, $context, $more = "") {
echo "<p class='micromessage'>The relatedDocs DB conf for $context is $message echo "<p class='micromessage'>The relatedDocs DB conf for $context $message
(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 db.json associations
// source graph file <=> (db, dbtype, cols) as relatedDocs php API // source graph file <=> (db, dbtype, cols) as relatedDocs php API
function read_conf($filepath, $ntypes) { // 1) we filter db.json entries by active/inactive nodetypes
// 2) we filter db.json entries by supported dbtypes
function read_conf($filepath, $ntypes, $our_dbtypes) {
$project_menu_fh = fopen($filepath, "r"); $project_menu_fh = fopen($filepath, "r");
$json_st = ''; $json_st = '';
while (!feof($project_menu_fh)) { while (!feof($project_menu_fh)) {
...@@ -45,21 +47,40 @@ function read_conf($filepath, $ntypes) { ...@@ -45,21 +47,40 @@ function read_conf($filepath, $ntypes) {
// node0 <=> classic type 'semantic' // node0 <=> classic type 'semantic'
// node1 <=> classic type 'social' // node1 <=> classic type 'social'
$conf[$gpath] = array($ntypes); // NB2 now additionnally, each nodetype can have several dbs configured !
// $conf[$gpath] = array($ntypes);
for ($i = 0 ; $i < $ntypes ; $i++) { for ($i = 0 ; $i < $ntypes ; $i++) {
// check node0, node1, etc to see if they at least have a reldbfile $conf[$gpath]['node'.$i] = array();
if (! property_exists($graph_conf, 'node'.$i)
|| ! property_exists($graph_conf->{'node'.$i}, 'reldbfile') ) { // check node0, node1, etc to see if they at least have a reldb conf
$conf[$gpath][$i] = array('active' => false); if (property_exists($graph_conf, 'node'.$i)
continue; && property_exists($graph_conf->{'node'.$i}, 'reldbs') ) {
// check for each configured db that is listed under reldbs
$dbinfos = $graph_conf->{'node'.$i}->reldbs;
foreach ($dbinfos as $dbtype => $dbconf) {
// filter: supported and valid conf cases
if (in_array($dbtype, $our_dbtypes) && $dbconf->file) {
// we have a file for this nodetype and dbtype: copy entire conf
$conf[$gpath]['node'.$i][$dbtype] = (array)$dbconf ;
// update files path with dirpath
if (array_key_exists('file', $conf[$gpath]['node'.$i][$dbtype])) {
$relpath = $conf[$gpath]['node'.$i][$dbtype]['file'];
$conf[$gpath]['node'.$i][$dbtype]['file'] = $project_dir.'/'.$relpath;
}
}
}
// echodump("got conf", $conf[$gpath]['node'.$i]);
} }
else {
// we have a file for this type: copy entire conf
$conf[$gpath][$i] = (array)$graph_conf->{'node'.$i};
$conf[$gpath][$i]['active'] = true; else {
$conf[$gpath][$i]['dir'] = $project_dir; // 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 // POSS here info on higher level may be propagated for lower ones
// (ex: if dbtype is on the project level, its value should count // (ex: if dbtype is on the project level, its value should count
...@@ -67,6 +88,8 @@ function read_conf($filepath, $ntypes) { ...@@ -67,6 +88,8 @@ function read_conf($filepath, $ntypes) {
} }
} }
} }
// echodump("full conf", $conf);
return $conf; return $conf;
} }
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
background-color: #BBB; background-color: #BBB;
} }
#topPapers { .topPapers {
-moz-box-shadow: none ; -moz-box-shadow: none ;
-webkit-box-shadow: none ; -webkit-box-shadow: none ;
box-shadow: none; box-shadow: none;
......
...@@ -325,12 +325,14 @@ ul.infoitems { ...@@ -325,12 +325,14 @@ ul.infoitems {
border-right: 1px solid #222; border-right: 1px solid #222;
} }
#topPapers{ .topPapers{
display: none; display: none;
color:black; color:black;
} }
.tab-pane {
transition: height 0.5s ease-out;
}
......
...@@ -369,53 +369,6 @@ var TinaWebJS = function ( sigmacanvas ) { ...@@ -369,53 +369,6 @@ var TinaWebJS = function ( sigmacanvas ) {
defaultTab: 'li#tabneigh' defaultTab: 'li#tabneigh'
}); });
// initialize reldocs tabs
if (TW.conf.getRelatedDocs) {
// POSSible: create them on a settings list (currently in the HTML)
let ul = document.getElementById('reldocs-tabs')
let tabEls = []
for (var possibleAPI in TW.conf.relatedDocsAPIS) {
// create valid tabs
let newLi = document.createElement('li')
newLi.setAttribute("role", "presentation")
let newRDTab = document.createElement('a')
newRDTab.text = possibleAPI
newRDTab.href = '#topPapers'
newRDTab.setAttribute("role", "tab")
newRDTab.dataset.toggle = 'tab'
newRDTab.dataset.reldocstype = possibleAPI
if (possibleAPI == TW.conf.relatedDocsType) {
newLi.setAttribute("class", "active")
}
// add to DOM
ul.append(newLi)
newLi.append(newRDTab)
// keep access
TW.gui.reldocTabs[possibleAPI] = newRDTab
}
// afterwards to get all types and the active type
for (let rdtype in TW.gui.reldocTabs) {
let tab = TW.gui.reldocTabs[rdtype]
// init toggle mecanisms (bootstrap.native/#componentTab)
// (just used for the tabs active/inactive handling,
// content is *always* topPapers and we modify it ourselves)
new Tab(tab);
// add handler to switch relatedDocsType
tab.addEventListener('click', function(){
TW.conf.relatedDocsType = this.dataset.reldocstype
getTopPapers()
})
}
}
// show any already existing panel // show any already existing panel
document.getElementById("graph-panels").style.display = "block" document.getElementById("graph-panels").style.display = "block"
...@@ -745,11 +698,6 @@ var TinaWebJS = function ( sigmacanvas ) { ...@@ -745,11 +698,6 @@ var TinaWebJS = function ( sigmacanvas ) {
} }
}) })
// select currently preferred reldoc tab
if (TW.conf.getRelatedDocs && document.getElementById('reldocs-tabs')) {
TW.gui.reldocTabs[TW.conf.relatedDocsType].Tab.show()
}
$("#tips").html(getTips()); $("#tips").html(getTips());
// we start with no selection // we start with no selection
...@@ -915,7 +863,7 @@ var TinaWebJS = function ( sigmacanvas ) { ...@@ -915,7 +863,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) { this.initSigmaListeners = function(partialGraph, initialActivetypes, initialActivereltypes, optionalConfEntry) {
// 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)
...@@ -1105,10 +1053,18 @@ var TinaWebJS = function ( sigmacanvas ) { ...@@ -1105,10 +1053,18 @@ var TinaWebJS = function ( sigmacanvas ) {
} }
}); });
if (TW.conf.filterSliders) { // initialize reldocs tabs if declared in additionalConf
if (TW.conf.getRelatedDocs) {
let moreConfKey = optionalConfEntry || TW.File
resetTabs(initialActivetypes, TW.gmenuInfos[moreConfKey])
// the indice of the first cat to be active (ex: '1') }
let activeId = initialActivetypes.indexOf(true)
// select currently active sliders
if (TW.conf.filterSliders) {
// also for all active cats
for (let activeId in initialActivetypes) { for (let activeId in initialActivetypes) {
if (initialActivetypes[activeId]) { if (initialActivetypes[activeId]) {
// args: for display: target div , // args: for display: target div ,
......
...@@ -25,7 +25,7 @@ TW.gui.foldedSide=false; ...@@ -25,7 +25,7 @@ TW.gui.foldedSide=false;
TW.gui.manuallyChecked = false; TW.gui.manuallyChecked = false;
TW.gui.handpickedcolor = false; // <= changes edge rendering strategy TW.gui.handpickedcolor = false; // <= changes edge rendering strategy
TW.gui.lastFilters = {} TW.gui.lastFilters = {}
TW.gui.reldocTabs = [] TW.gui.reldocTabs = [{}, {}] // <= by nodetype and then dbtype
TW.gui.sizeRatios = [1,1] // sizeRatios per nodetype TW.gui.sizeRatios = [1,1] // sizeRatios per nodetype
...@@ -248,7 +248,9 @@ function createFilechooserEl () { ...@@ -248,7 +248,9 @@ function createFilechooserEl () {
TW.resetGraph() TW.resetGraph()
// run // run
mainStartGraph(theFormat, rdr.result, TW.instance) mainStartGraph(theFormat, rdr.result, null, TW.instance)
// NB 3rd arg null = we got no additional conf for this "unknown" file
writeLabel(`Local file: ${clientLocalGraphFile.name}`) writeLabel(`Local file: ${clientLocalGraphFile.name}`)
} }
...@@ -1126,6 +1128,120 @@ function createWaitIcon(idname, width) { ...@@ -1126,6 +1128,120 @@ function createWaitIcon(idname, width) {
return icon return icon
} }
activateRDTab = function(elTgt) {
let relDbType = elTgt.dataset.reldocstype
let ndTypeId = elTgt.dataset.nodetype
let tabs = document.querySelectorAll('ul#reldocs-tabs > li')
for (var tabLi of tabs) {
if (tabLi != elTgt.parentNode)
tabLi.classList.remove("active")
else
tabLi.classList.add("active")
}
let divs = document.querySelectorAll("div#reldocs-boxes > div.tab-pane")
let theId = `rd-${ndTypeId}-${relDbType}`
// POSS: animate with transitions here
for (var tabDiv of divs) {
if (tabDiv.id != theId)
tabDiv.classList.remove("active", "in")
else
tabDiv.classList.add("active", "in")
}
}
// set up tabs for a given activetypes state and db.json entry
function resetTabs(activetypes, dbconf) {
let ul = document.getElementById('reldocs-tabs')
let divs = document.getElementById('reldocs-boxes')
// remove any previous tabs
ul.innerHTML = ""
divs.innerHTML = ""
TW.gui.reldocTabs = [{},{}]
// used with no args for full reset
if (!activetypes || !dbconf) {
return
}
console.log("dbconf for this source", dbconf)
// for all active nodetypes
for (let nodetypeId in activetypes) {
if (activetypes[nodetypeId]) {
let additionalConf = dbconf[nodetypeId]
if (TW.conf.debug.logSettings)
console.log ("additionalConf for this source", additionalConf)
let possibleAPIs = []
if (additionalConf.reldbs) {
possibleAPIs = additionalConf.reldbs
// 3 vars to know which one to activate
let nAPIs = Object.keys(possibleAPIs).length
let iAPI = 0
let didActiveFlag = false
for (var possibleAPI in possibleAPIs){
// the tab's id
let tabref = `rd-${nodetypeId}-${possibleAPI}`
// create valid tabs
let newLi = document.createElement('li')
newLi.setAttribute("role", "presentation")
let newRDTab = document.createElement('a')
newRDTab.text = `${possibleAPI} (${nodetypeId==0?'sem':'soc'})`
newRDTab.setAttribute("role", "tab")
newRDTab.dataset.reldocstype = possibleAPI
newRDTab.dataset.nodetype = nodetypeId
newRDTab.setAttribute("class", `for-nodecategory-${nodetypeId}`)
// newRDTab.dataset.toggle = 'tab' // only needed if using bootstrap
// keep access
TW.gui.reldocTabs[nodetypeId][possibleAPI] = newRDTab
// create corresponding content box
let newContentDiv = document.createElement('div')
newContentDiv.setAttribute("role", "tabpanel")
newContentDiv.setAttribute("class", "topPapers tab-pane")
newContentDiv.id = tabref
// add to DOM
ul.append(newLi)
newLi.append(newRDTab)
divs.append(newContentDiv)
// select currently preferred reldoc tabs
// (we activate if favorite or if no matching favorite and last)
if (possibleAPI == TW.conf.relatedDocsType
|| (!didActiveFlag && iAPI == nAPIs - 1)) {
newLi.classList.add("active")
newContentDiv.classList.add("active", "in")
didActiveFlag = true
}
// add handler to switch relatedDocsType
newRDTab.addEventListener('click', function(e){
// tab mecanism
activateRDTab(e.target)
// no need to run associated query:
// (updateRelatedNodesPanel did it at selection time)
})
iAPI++
}
}
}
}
}
function jsActionOnGexfSelector(graphBasename){ function jsActionOnGexfSelector(graphBasename){
let graphPath = TW.gmenuPaths[graphBasename] || graphBasename+".gexf" let graphPath = TW.gmenuPaths[graphBasename] || graphBasename+".gexf"
...@@ -1141,20 +1257,8 @@ function jsActionOnGexfSelector(graphBasename){ ...@@ -1141,20 +1257,8 @@ function jsActionOnGexfSelector(graphBasename){
// remove any previous instance and flags // remove any previous instance and flags
TW.resetGraph() TW.resetGraph()
// override default categories with the ones from db.json
if (TW.gmenuInfos[graphPath]) {
if (TW.gmenuInfos[graphPath][0] && TW.gmenuInfos[graphPath][0].name) {
TW.conf.catSem = TW.gmenuInfos[graphPath][0].name
console.log("new catSem:", TW.conf.catSem)
}
if (TW.gmenuInfos[graphPath][1] && TW.gmenuInfos[graphPath][1].name) {
TW.conf.catSoc = TW.gmenuInfos[graphPath][1].name
console.log("new catSoc:", TW.conf.catSoc)
}
}
mainStartGraph(newDataRes["format"], newDataRes["data"], TW.instance)
writeLabel(graphBasename)
TW.File = graphPath TW.File = graphPath
mainStartGraph(newDataRes["format"], newDataRes["data"], TW.File, TW.instance)
writeLabel(graphBasename)
} }
//============================= </OTHER ACTIONS > =============================// //============================= </OTHER ACTIONS > =============================//
This diff is collapsed.
...@@ -298,7 +298,6 @@ saferString = function(string) { ...@@ -298,7 +298,6 @@ saferString = function(string) {
} }
/** /**
* function to test if file exists * function to test if file exists
* via XHR, enhanced from http://stackoverflow.com/questions/5115141 * via XHR, enhanced from http://stackoverflow.com/questions/5115141
......
This diff is collapsed.
...@@ -60,6 +60,16 @@ TW.pushGUIState = function( args ) { ...@@ -60,6 +60,16 @@ TW.pushGUIState = function( args ) {
} }
} }
// recreate tabs after type changes
// db.json conf entry (£TODO unify s/(?:TW.File|inConfKey)/TW.sourceId/g)
let inConfKey = (sourcemode != "api") ? TW.File : 'graphapi/default'
if (TW.conf.getRelatedDocs
&& !isUndef(args.activetypes)
&& TW.gmenuInfos[inConfKey]) {
resetTabs(newState.activetypes, TW.gmenuInfos[inConfKey])
}
// 4) store it in TW.states // 4) store it in TW.states
TW.states.push(newState) TW.states.push(newState)
...@@ -78,16 +88,12 @@ TW.resetGraph = function() { ...@@ -78,16 +88,12 @@ TW.resetGraph = function() {
// remove the selection // remove the selection
cancelSelection(false, {norender: true}) cancelSelection(false, {norender: true})
// and set tabs to none
resetTabs()
// call the sigma graph clearing // call the sigma graph clearing
TW.instance.clearSigma() TW.instance.clearSigma()
// TW.categories, TW.Nodes and TW.Edges will be reset by mainStartGraph
// reset remaining global vars
TW.labels = []
TW.Relations = {}
TW.states = [TW.initialSystemState]
// reset rendering gui flags // reset rendering gui flags
TW.gui.selectionActive = false TW.gui.selectionActive = false
TW.gui.handpickedcolor = false TW.gui.handpickedcolor = false
...@@ -99,6 +105,90 @@ TW.resetGraph = function() { ...@@ -99,6 +105,90 @@ TW.resetGraph = function() {
// reset other gui flags // reset other gui flags
TW.gui.checkBox=false TW.gui.checkBox=false
TW.gui.lastFilters = {} TW.gui.lastFilters = {}
// remaining global vars will be reset by new graph mainStartGraph
}
// 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": {}
// }
// }
// }
// }
// }
if (TW.conf.debug.logFetchers) console.info(`attempting to load filemenu ${infofile}`)
var preRES = AjaxSync({ url: infofile, datatype:"json" });
if (preRES['OK'] && preRES.data) {
if (TW.conf.debug.logFetchers) console.log('initial AjaxSync result preRES', preRES)
}
// 1 - store the first one (b/c we'll loose order)
var first_file = "", first_dir = "" , first_path = ""
for( var path in preRES.data ) {
if (TW.conf.debug.logFetchers) console.log("db.json path", path)
first_file = preRES.data[path]["first"] || Object.keys(preRES.data[path]["graphs"])[0]
first_dir = path
break;
}
first_path = first_dir+"/"+first_file
// 2 - process all the paths and associated confs
let paths = {}
let details = {}
for( var path in preRES.data ) {
var theGraphs = preRES.data[path]["graphs"]
for(var aGraph in theGraphs) {
var graphBasename = aGraph.replace(/\.gexf$/, "") // more human-readable in the menu
paths[graphBasename] = path+"/"+aGraph
// ex : "RiskV2PageRank1000.gexf":data/AXA/RiskV2PageRank1000.gexf
// (we assume there's no duplicate basenames)
if (TW.conf.debug.logSettings)
console.log("db conf entry: "+graphBasename)
// for associated LocalDB php queries: CSV (or CortextDBs sql)
if (theGraphs[aGraph]) {
let gSrcEntry = theGraphs[aGraph]
details[path+"/"+aGraph] = new Array(2)
if (gSrcEntry.node0) {
details[path+"/"+aGraph][0] = gSrcEntry.node0
}
if (gSrcEntry.node1) {
details[path+"/"+aGraph][1] = gSrcEntry.node1
}
}
else {
details[path+"/"+aGraph] = null
}
}
}
return [paths, details, first_path]
} }
...@@ -183,20 +273,6 @@ function getNActive(someState) { ...@@ -183,20 +273,6 @@ function getNActive(someState) {
return TW.SystemState().activetypes.filter(function(bool){return bool}).length return TW.SystemState().activetypes.filter(function(bool){return bool}).length
} }
// transitional function:
// ----------------------
// Goal: determine if a single nodetype or global activetype is semantic or social
// Explanation: some older functions (eg topPapers) used this distinction
// (via semi-deprecated global swclickActual),
// but the specification changed twice since then:
// - 1st change: types described as type 0 and type 1 and possible default type
// - 2nd change default type of monopartite case changed from document to semantic
function swActual(aNodetype) {
return (aNodetype == TW.categories[0]) ? 'semantic' : 'social'
}
// changes attributes of nodes and edges to remove active, highlight and activeEdge flags // changes attributes of nodes and edges to remove active, highlight and activeEdge flags
// NB: "low-level" <=> by design, does NOT change the state, gui nor global flag // NB: "low-level" <=> by design, does NOT change the state, gui nor global flag
...@@ -307,6 +383,7 @@ function clearHover() { ...@@ -307,6 +383,7 @@ function clearHover() {
// nodes information div // nodes information div
// POSS: merge with hit_templates from additional conf
function htmlfied_nodesatts(elems){ function htmlfied_nodesatts(elems){
var socnodes=[] var socnodes=[]
...@@ -321,7 +398,7 @@ function htmlfied_nodesatts(elems){ ...@@ -321,7 +398,7 @@ function htmlfied_nodesatts(elems){
var id=elems[i] var id=elems[i]
var node = TW.Nodes[id] var node = TW.Nodes[id]
if(swActual(node.type) == 'social'){ if(TW.catDict[node.type] == 1){
information += '<li><b>' + node.label + '</b></li>'; information += '<li><b>' + node.label + '</b></li>';
if(node.htmlCont==""){ if(node.htmlCont==""){
if (!isUndef(node.level)) { if (!isUndef(node.level)) {
...@@ -332,8 +409,7 @@ function htmlfied_nodesatts(elems){ ...@@ -332,8 +409,7 @@ function htmlfied_nodesatts(elems){
} }
socnodes.push(information) socnodes.push(information)
} }
else {
if(swActual(node.type) == 'semantic'){
information += '<li><b>' + node.label + '</b></li>'; information += '<li><b>' + node.label + '</b></li>';
let google='<a href=http://www.google.com/#hl=en&source=hp&q=%20'+node.label.replace(" ","+")+'%20><img src="'+TW.conf.paths.ourlibs+'/img/google.png"></img></a>'; let google='<a href=http://www.google.com/#hl=en&source=hp&q=%20'+node.label.replace(" ","+")+'%20><img src="'+TW.conf.paths.ourlibs+'/img/google.png"></img></a>';
let wiki = '<a href=http://en.wikipedia.org/wiki/'+node.label.replace(" ","_")+'><img src="'+TW.conf.paths.ourlibs+'/img/wikipedia.png"></img></a>'; let wiki = '<a href=http://en.wikipedia.org/wiki/'+node.label.replace(" ","_")+'><img src="'+TW.conf.paths.ourlibs+'/img/wikipedia.png"></img></a>';
...@@ -442,12 +518,30 @@ function updateRelatedNodesPanel( sels , same, oppos ) { ...@@ -442,12 +518,30 @@ function updateRelatedNodesPanel( sels , same, oppos ) {
$("#information").html(informationDIV); $("#information").html(informationDIV);
if (TW.conf.getRelatedDocs) { if (TW.conf.getRelatedDocs) {
$("#reldocs-tabs-wrapper").show(); let rdTabCount = 0
$("#topPapers").show(); // update all related docs tabs
getTopPapers() for (let ntId in TW.SystemState().activetypes) {
if (TW.SystemState().activetypes[ntId]) {
let qWords = queryForType(ntId)
// console.log("available topPapers tabs:", TW.gui.reldocTabs[ntId])
for (let relDbType in TW.gui.reldocTabs[ntId]) {
let tabId = `rd-${ntId}-${relDbType}`
rdTabCount ++
// if not already done
if (! TW.lastRelDocQueries[tabId]
|| TW.lastRelDocQueries[tabId] != qWords) {
getTopPapers(qWords, ntId, relDbType, tabId)
// memoize
TW.lastRelDocQueries[tabId] = qWords
}
}
}
}
if (rdTabCount > 0) $("#reldocs-tabs-wrapper").show();
} }
else { else {
$("#topPapers").hide()
$("#reldocs-tabs-wrapper").hide(); $("#reldocs-tabs-wrapper").hide();
} }
} }
......
...@@ -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 ) { var ParseCustom = function ( format , data, optionalConf ) {
if (format == 'gexf') { if (format == 'gexf') {
this.data = $.parseXML(data) this.data = $.parseXML(data)
...@@ -14,9 +14,13 @@ var ParseCustom = function ( format , data ) { ...@@ -14,9 +14,13 @@ var ParseCustom = function ( format , data ) {
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() {
return scanGexf( this.data ); let observedCategories = scanGexf(this.data)
let finalCategories = sortNodeTypes(observedCategories, this.additionalConf)
return finalCategories;
}// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}} }// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}}
...@@ -29,7 +33,9 @@ var ParseCustom = function ( format , data ) { ...@@ -29,7 +33,9 @@ var ParseCustom = function ( format , data ) {
// input = JSONstring // input = JSONstring
this.getJSONCategories = function(json) { this.getJSONCategories = function(json) {
return scanJSON( this.data ); let observedCategories = scanJSON(this.data)
let finalCategories = sortNodeTypes(observedCategories, this.additionalConf)
return finalCategories;
}// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}} }// output = {'cats':[ "cat1" , "cat2" , ...], 'rev': {cat1: 0, cat2: 1...}}
...@@ -201,8 +207,7 @@ function scanGexf(gexfContent) { ...@@ -201,8 +207,7 @@ function scanGexf(gexfContent) {
} }
} }
// sorting observed json node types into Sem (=> 1)/Soc (=> 0) return categoriesDict
return sortNodeTypes(categoriesDict)
} }
// sorting observed node types into Sem/Soc // sorting observed node types into Sem/Soc
...@@ -212,10 +217,25 @@ function scanGexf(gexfContent) { ...@@ -212,10 +217,25 @@ 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) { function sortNodeTypes(observedTypesDict, optConf) {
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
var declaredTypes = []
for (var i = 0 ; i < nbNodeTypes ; i++ ) {
if (optConf[i] && optConf[i].name) {
declaredTypes[i] = optConf[i].name
if (TW.conf.debug.logSettings)
console.log("expected cat (from db.json addtional conf)", i, declaredTypes[i])
}
else {
declaredTypes[i] = TW.conf[i == 0 ? 'catSem' : 'catSoc']
if (TW.conf.debug.logSettings)
console.log("expected cat (from settings_explorer defaults)", i, declaredTypes[i])
}
}
var newcats = [] var newcats = []
var catDict = {} var catDict = {}
...@@ -236,13 +256,14 @@ function sortNodeTypes(observedTypesDict) { ...@@ -236,13 +256,14 @@ function sortNodeTypes(observedTypesDict) {
// allows multiple node types, with an "all the rest" node1 // allows multiple node types, with an "all the rest" node1
// try stipulated cats, then fallbacks // try stipulated cats, then fallbacks
if (observedTypesDict[TW.conf.catSem]) { // possible: loop
newcats[0] = TW.conf.catSem; if (observedTypesDict[declaredTypes[0]]) {
catDict[TW.conf.catSem] = 0; newcats[0] = declaredTypes[0];
catDict[declaredTypes[0]] = 0;
} }
if (observedTypesDict[TW.conf.catSoc]) { if (observedTypesDict[declaredTypes[1]]) {
newcats[1] = TW.conf.catSoc; newcats[1] = declaredTypes[1];
catDict[TW.conf.catSoc] = 1; catDict[declaredTypes[1]] = 1;
} }
// NB: type for nodes0 will be the majoritary by default, unless taken // NB: type for nodes0 will be the majoritary by default, unless taken
...@@ -1018,8 +1039,7 @@ function scanJSON( data ) { ...@@ -1018,8 +1039,7 @@ function scanJSON( data ) {
} }
} }
// sorting observed json node types into Sem (=> 1)/Soc (=> 0) return categoriesDict
return sortNodeTypes(categoriesDict);
} }
// Level-00 // Level-00
......
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