Commit 4a5a0cd2 authored by delanoe's avatar delanoe

Merge remote-tracking branch 'origin/romain-testing' into testing-merge

parents 47398dcf b5ff7a7f
#!/bin/bash #!/bin/bash
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/srv/gargantext_lib/taggers/nlpserver/TurboParser/deps/local/lib:" export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/srv/gargantext_lib/taggers/nlpserver:/srv/gargantext_lib/taggers/nlpserver/TurboParser/deps/local/lib:"
if [[ ! "$VIRTUAL_ENV" ]] if [[ ! "$VIRTUAL_ENV" ]]
then then
......
...@@ -27,7 +27,6 @@ def is_stop_word(ngram, stop_words=None): ...@@ -27,7 +27,6 @@ def is_stop_word(ngram, stop_words=None):
# , "(.*)(\.)(.*)" trop fort (enlève les sigles !) # , "(.*)(\.)(.*)" trop fort (enlève les sigles !)
, "(.*)(\,)(.*)" , "(.*)(\,)(.*)"
, "(.*)(< ?/?p ?>)(.*)" # marques de paragraphes , "(.*)(< ?/?p ?>)(.*)" # marques de paragraphes
, "(.*)(study|elsevier)(.*)"
, "(.*)\b(xx|xi|xv)\b(.*)" , "(.*)\b(xx|xi|xv)\b(.*)"
, "(.*)(result)(.*)" , "(.*)(result)(.*)"
, "(.*)(year|année|nombre|moitié)(.*)" , "(.*)(year|année|nombre|moitié)(.*)"
...@@ -37,6 +36,87 @@ def is_stop_word(ngram, stop_words=None): ...@@ -37,6 +36,87 @@ def is_stop_word(ngram, stop_words=None):
, "(.*)(terme)(.*)" , "(.*)(terme)(.*)"
, "(.*)(différent)(.*)" , "(.*)(différent)(.*)"
, "(.*)(travers)(.*)" , "(.*)(travers)(.*)"
# academic stamps
, ".*\belsevier\b.*"
, ".*\bwiley\b.*)"
, ".*\bspringer\b.*"
, ".*university press\b.*"
, ".*\bstudy\b.*"
# academic terms when alone ~~> usually not informative
, "hypothes[ie]s$"
, "analys[ie]s$"
, "bas[ie]s$"
, "online$"
, "importance$"
, "uses?$"
, "cases?$"
, "effects?$"
, "times?$"
, "methods?$"
, "types?$"
, "evidences?$"
, "findings?$"
, "relations?$"
, "terms?$"
, "procedures?$"
, "factors?$"
, "reports?$"
, "changes?$"
, "facts?$"
, "others?$"
, "applications?$"
, "periods?$"
, "investigations?$"
, "orders?$"
, "forms?$"
, "conditions?$"
, "situations?$"
, "papers?$"
, "relationships?$"
, "values?$"
, "areas?$"
, "techniques?$"
, "means?$"
, "conclusions?$"
, "comparisons?$"
, "parts?$"
, "amounts?$"
, "aims?$"
, "lacks?$"
, "issues?$"
, "ways?$"
, "ranges?$"
, "models?$"
, "articles?$"
, "series?$"
, "totals?$"
, "influences?$"
, "journals?$"
, "rules?$"
, "persons?$"
, "abstracts?$"
, "(?:book)? reviews?$"
, "process(?:es)?$"
, "approach(?:es)?$"
, "theor(?:y|ies)?$"
, "methodolog(?:y|ies)?$"
, "similarit(?:y|ies)?$"
, "possibilit(?:y|ies)?$"
, "stud(?:y|ies)?$"
# non-thematic or non-NP expressions
, "none$"
, "other(?: hand)?$"
, "whereas$"
, "usually$"
, "and$"
# , "vol$"
, "eds?$"
, "ltd$"
, "copyright$"
, "e-?mails?$"
, ".*="
, "=.*"
, "further(?:more)?$"
, "(.*)(:|\|)(.*)" , "(.*)(:|\|)(.*)"
] : ] :
compiled_regexes.append(compile(regex)) compiled_regexes.append(compile(regex))
......
...@@ -85,8 +85,8 @@ class CSVLists(APIView): ...@@ -85,8 +85,8 @@ class CSVLists(APIView):
# import the csv # import the csv
try: try:
new_lists = import_ngramlists(csv_file) new_lists = import_ngramlists(csv_file)
print("===============================!!!") print("======new_lists=========================!!!")
print(new_lists) # print(new_lists) # very long
del csv_file del csv_file
# merge the new_lists onto those of the target corpus # merge the new_lists onto those of the target corpus
......
...@@ -38,7 +38,6 @@ def countCooccurrences( corpus_id=None , cooc_id=None ...@@ -38,7 +38,6 @@ def countCooccurrences( corpus_id=None , cooc_id=None
limit :: Int limit :: Int
''' '''
# FIXME remove the lines below after factorization of parameters # FIXME remove the lines below after factorization of parameters
parameters = dict() parameters = dict()
parameters['field1'] = field1 parameters['field1'] = field1
...@@ -68,14 +67,20 @@ def countCooccurrences( corpus_id=None , cooc_id=None ...@@ -68,14 +67,20 @@ def countCooccurrences( corpus_id=None , cooc_id=None
cooc_id = coocNode.id cooc_id = coocNode.id
else : else :
cooc_id = int(cooc_id[0]) cooc_id = int(cooc_id[0])
# when cooc_id preexisted, but we want to continue (reset = True)
# (to give new contents to this cooc_id)
elif reset:
print("GRAPH #%s ... Counting new cooccurrences data." % cooc_id)
session.query( NodeNgramNgram ).filter( NodeNgramNgram.node_id == cooc_id ).delete()
session.commit()
# when cooc_id preexisted and we just want to load it (reset = False)
else: else:
print("GRAPH #%s ... Loading cooccurrences computed already." % cooc_id) print("GRAPH #%s ... Loading cooccurrences computed already." % cooc_id)
cooc = session.query( NodeNgramNgram.ngram1_id, NodeNgramNgram.ngram2_id, NodeNgramNgram.weight ).filter( NodeNgramNgram.node_id == cooc_id ).all() cooc = session.query( NodeNgramNgram.ngram1_id, NodeNgramNgram.ngram2_id, NodeNgramNgram.weight ).filter( NodeNgramNgram.node_id == cooc_id ).all()
return(int(cooc_id),WeightedMatrix(cooc)) return(int(cooc_id),WeightedMatrix(cooc))
if reset == True :
session.query( NodeNgramNgram ).filter( NodeNgramNgram.node_id == cooc_id ).delete()
session.commit()
NodeNgramX = aliased(NodeNgram) NodeNgramX = aliased(NodeNgram)
...@@ -202,29 +207,29 @@ def countCooccurrences( corpus_id=None , cooc_id=None ...@@ -202,29 +207,29 @@ def countCooccurrences( corpus_id=None , cooc_id=None
#cooc_query = cooc_query.order_by(desc('cooc_score')) #cooc_query = cooc_query.order_by(desc('cooc_score'))
matrix = WeightedMatrix(cooc_query) matrix = WeightedMatrix(cooc_query)
print("GRAPH #%s Filtering the matrix with Map and Group Lists." % cooc_id) print("GRAPH #%s Filtering the matrix with Map and Group Lists." % cooc_id)
cooc = filterMatrix(matrix, mapList_id, groupList_id) cooc = filterMatrix(matrix, mapList_id, groupList_id)
parameters['MapList_id'] = str(mapList_id) parameters['MapList_id'] = str(mapList_id)
parameters['GroupList_id'] = str(groupList_id) parameters['GroupList_id'] = str(groupList_id)
# TODO factorize savings on db # TODO factorize savings on db
if save_on_db: if save_on_db:
# Saving the cooccurrences # Saving the cooccurrences
cooc.save(cooc_id) cooc.save(cooc_id)
print("GRAPH #%s ... Node Cooccurrence Matrix saved" % cooc_id) print("GRAPH #%s ... Node Cooccurrence Matrix saved" % cooc_id)
# Saving the parameters # Saving the parameters
print("GRAPH #%s ... Parameters saved in Node." % cooc_id) print("GRAPH #%s ... Parameters saved in Node." % cooc_id)
coocNode = session.query(Node).filter(Node.id==cooc_id).first() coocNode = session.query(Node).filter(Node.id==cooc_id).first()
coocNode.hyperdata["parameters"] = dict() coocNode.hyperdata["parameters"] = dict()
coocNode.hyperdata["parameters"] = parameters coocNode.hyperdata["parameters"] = parameters
coocNode.save_hyperdata() coocNode.save_hyperdata()
session.commit() session.commit()
#data = cooc2graph(coocNode.id, cooc, distance=distance, bridgeness=bridgeness) #data = cooc2graph(coocNode.id, cooc, distance=distance, bridgeness=bridgeness)
#return data #return data
return(coocNode.id, cooc) return(coocNode.id, cooc)
...@@ -51,7 +51,7 @@ def compute_graph( corpus_id=None , cooc_id=None ...@@ -51,7 +51,7 @@ def compute_graph( corpus_id=None , cooc_id=None
, mapList_id=mapList_id , groupList_id=groupList_id , mapList_id=mapList_id , groupList_id=groupList_id
, isMonopartite=True , threshold = threshold , isMonopartite=True , threshold = threshold
, distance=distance , bridgeness=bridgeness , distance=distance , bridgeness=bridgeness
, save_on_db = True , save_on_db = True , reset = reset
) )
print("GRAPH #%d ... Cooccurrences computed." % (cooc_id)) print("GRAPH #%d ... Cooccurrences computed." % (cooc_id))
...@@ -73,13 +73,13 @@ def compute_graph( corpus_id=None , cooc_id=None ...@@ -73,13 +73,13 @@ def compute_graph( corpus_id=None , cooc_id=None
node.hyperdata[distance] = dict() node.hyperdata[distance] = dict()
node.hyperdata[distance][bridgeness] = data node.hyperdata[distance][bridgeness] = data
node.hyperdata[distance]["nodes"] = len(G.nodes()) node.hyperdata[distance]["nodes"] = len(G.nodes())
node.hyperdata[distance]["edges"] = len(G.edges()) node.hyperdata[distance]["edges"] = len(G.edges())
node.save_hyperdata() node.save_hyperdata()
session.commit() session.commit()
print("GRAPH #%d ... Notify by email owner of the graph." % cooc_id) print("GRAPH #%d ... Notify by email owner of the graph." % cooc_id)
corpus = session.query(Node).filter(Node.id==corpus_id).first() corpus = session.query(Node).filter(Node.id==corpus_id).first()
notify_owner(corpus, cooc_id, distance, bridgeness) notify_owner(corpus, cooc_id, distance, bridgeness)
...@@ -99,25 +99,25 @@ def get_graph( request=None , corpus=None ...@@ -99,25 +99,25 @@ def get_graph( request=None , corpus=None
''' '''
Get_graph : main steps: Get_graph : main steps:
0) Check the parameters 0) Check the parameters
get_graph :: GraphParameters -> Either (Dic Nodes Links) (Dic State Length) get_graph :: GraphParameters -> Either (Dic Nodes Links) (Dic State Length)
where type Length = Int where type Length = Int
get_graph first checks the parameters and return either graph data or a dict with get_graph first checks the parameters and return either graph data or a dict with
state "type" with an integer to indicate the size of the parameter state "type" with an integer to indicate the size of the parameter
(maybe we could add a String in that step to factor and give here the error message) (maybe we could add a String in that step to factor and give here the error message)
1) compute_graph (see function above) 1) compute_graph (see function above)
2) return graph 2) return graph
''' '''
overwrite_node_contents = False
# Case of graph has been computed already # Case of graph has been computed already
if cooc_id is not None: if cooc_id is not None:
print("GRAPH#%d ... Loading data already computed." % int(cooc_id)) print("GRAPH#%d ... Loading data already computed." % int(cooc_id))
node = session.query(Node).filter(Node.id == cooc_id).first() node = session.query(Node).filter(Node.id == cooc_id).first()
# Structure of the Node.hyperdata[distance][bridbeness] # Structure of the Node.hyperdata[distance][bridbeness]
# All parameters (but distance and bridgeness) # All parameters (but distance and bridgeness)
# are in Node.hyperdata["parameters"] # are in Node.hyperdata["parameters"]
...@@ -130,6 +130,25 @@ def get_graph( request=None , corpus=None ...@@ -130,6 +130,25 @@ def get_graph( request=None , corpus=None
if graph.get(str(bridgeness), None) is not None: if graph.get(str(bridgeness), None) is not None:
return graph[str(bridgeness)] return graph[str(bridgeness)]
# new graph: we give it an empty node with new id and status
elif saveOnly:
# NB: we do creation already here (instead of same in countCooccurrences)
# to guarantee a unique ref id to the saveOnly graph (async generation)
new_node = corpus.add_child(
typename = "COOCCURRENCES",
name = "GRAPH (in corpus %s)" % corpus.id
)
session.add(new_node)
session.commit()
cooc_id = new_node.id
cooc_name = new_node.name
cooc_date = new_node.date
# and the empty content will need redoing by countCooccurrences
overwrite_node_contents = True
print("GRAPH #%d ... Created new empty data node for saveOnly" % int(cooc_id))
# Case of graph has not been computed already # Case of graph has not been computed already
# First, check the parameters # First, check the parameters
...@@ -198,10 +217,14 @@ def get_graph( request=None , corpus=None ...@@ -198,10 +217,14 @@ def get_graph( request=None , corpus=None
, mapList_id=mapList_id , groupList_id=groupList_id , mapList_id=mapList_id , groupList_id=groupList_id
, isMonopartite=True , threshold = threshold , isMonopartite=True , threshold = threshold
, distance=distance , bridgeness=bridgeness , distance=distance , bridgeness=bridgeness
, save_on_db = True , save_on_db = True , reset=overwrite_node_contents
#, limit=size #, limit=size
) )
return {"state" : "saveOnly"}
return {"state" : "saveOnly",
"target_id" : cooc_id,
"target_name": cooc_name,
"target_date": cooc_date}
elif corpus_size > graph_constraints['corpusMax']: elif corpus_size > graph_constraints['corpusMax']:
# Then compute cooc asynchronously with celery # Then compute cooc asynchronously with celery
...@@ -211,10 +234,10 @@ def get_graph( request=None , corpus=None ...@@ -211,10 +234,10 @@ def get_graph( request=None , corpus=None
, mapList_id=mapList_id , groupList_id=groupList_id , mapList_id=mapList_id , groupList_id=groupList_id
, isMonopartite=True , threshold = threshold , isMonopartite=True , threshold = threshold
, distance=distance , bridgeness=bridgeness , distance=distance , bridgeness=bridgeness
, save_on_db = True , save_on_db = True , reset=overwrite_node_contents
#, limit=size #, limit=size
) )
# Dict to inform user that corpus maximum is reached # Dict to inform user that corpus maximum is reached
# then graph is computed asynchronously # then graph is computed asynchronously
return {"state" : "corpusMax", "length" : corpus_size} return {"state" : "corpusMax", "length" : corpus_size}
...@@ -230,7 +253,7 @@ def get_graph( request=None , corpus=None ...@@ -230,7 +253,7 @@ def get_graph( request=None , corpus=None
, mapList_id=mapList_id , groupList_id=groupList_id , mapList_id=mapList_id , groupList_id=groupList_id
, isMonopartite=True , threshold = threshold , isMonopartite=True , threshold = threshold
, distance=distance , bridgeness=bridgeness , distance=distance , bridgeness=bridgeness
, save_on_db = True , save_on_db = True , reset=overwrite_node_contents
#, limit=size #, limit=size
) )
......
...@@ -18,6 +18,11 @@ class Graph(APIView): ...@@ -18,6 +18,11 @@ class Graph(APIView):
Get all the parameters first Get all the parameters first
graph?field1=ngrams&field2=ngrams& graph?field1=ngrams&field2=ngrams&
graph?field1=ngrams&field2=ngrams&start=''&end='' graph?field1=ngrams&field2=ngrams&start=''&end=''
NB save new graph mode
(option saveOnly=True without a cooc_id)
can return the new cooc id in the json
before counting + filling data in async
''' '''
if not request.user.is_authenticated(): if not request.user.is_authenticated():
...@@ -56,7 +61,6 @@ class Graph(APIView): ...@@ -56,7 +61,6 @@ class Graph(APIView):
type_ = str(request.GET.get ('type' , 'node_link' )) type_ = str(request.GET.get ('type' , 'node_link' ))
distance = str(request.GET.get ('distance' , 'conditional')) distance = str(request.GET.get ('distance' , 'conditional'))
# Get default map List of corpus # Get default map List of corpus
if mapList_id == 0 : if mapList_id == 0 :
mapList_id = ( session.query ( Node.id ) mapList_id = ( session.query ( Node.id )
...@@ -100,7 +104,7 @@ class Graph(APIView): ...@@ -100,7 +104,7 @@ class Graph(APIView):
, field1=field1 , field2=field2 , field1=field1 , field2=field2
, mapList_id = mapList_id , groupList_id = groupList_id , mapList_id = mapList_id , groupList_id = groupList_id
, start=start , end=end , start=start , end=end
, threshold =threshold , threshold =threshold
, distance=distance , bridgeness=bridgeness , distance=distance , bridgeness=bridgeness
, saveOnly=saveOnly , saveOnly=saveOnly
) )
...@@ -127,10 +131,12 @@ class Graph(APIView): ...@@ -127,10 +131,12 @@ class Graph(APIView):
# async data case # async data case
link = "http://%s/projects/%d/corpora/%d/myGraphs" % (request.get_host(), corpus.parent_id, corpus.id) link = "http://%s/projects/%d/corpora/%d/myGraphs" % (request.get_host(), corpus.parent_id, corpus.id)
return JsonHttpResponse({ return JsonHttpResponse({
'msg': '''Your graph is saved: 'id': data["target_id"],
'name': data["target_name"],
'date': data["target_date"],
'msg': '''Your graph is being saved:
%s %s
''' % format_html(link), ''' % format_html(link)
}, status=200) }, status=200)
elif data["state"] == "corpusMin": elif data["state"] == "corpusMin":
......
...@@ -78,6 +78,8 @@ def myGraphs(request, project_id, corpus_id): ...@@ -78,6 +78,8 @@ def myGraphs(request, project_id, corpus_id):
#coocs_count[cooc.id] = len(cooc_nodes) #coocs_count[cooc.id] = len(cooc_nodes)
coocs_count[cooc.id] = len([cooc_node for cooc_node in cooc_nodes if cooc_node[1] > 1]) coocs_count[cooc.id] = len([cooc_node for cooc_node in cooc_nodes if cooc_node[1] > 1])
print("coocs_count a posteriori", coocs_count)
return render( return render(
template_name = 'pages/corpora/myGraphs.html', template_name = 'pages/corpora/myGraphs.html',
request = request, request = request,
......
...@@ -47,8 +47,9 @@ ...@@ -47,8 +47,9 @@
* - simplify UpdateTable * - simplify UpdateTable
* - clarify cruds * - clarify cruds
* - fine-grained "created groups" handling * - fine-grained "created groups" handling
* - local cache for user params
* *
* @version 1.3 * @version 1.4
* *
* @requires jquery.dynatable * @requires jquery.dynatable
* @requires d3 * @requires d3
...@@ -59,6 +60,7 @@ ...@@ -59,6 +60,7 @@
// GLOBALS <=> INTERACTIVE STATUS etc // GLOBALS <=> INTERACTIVE STATUS etc
// ============================================================================= // =============================================================================
var corpusId = getIDFromURL("corpora")
// current ngram infos (<-> row data) // current ngram infos (<-> row data)
// ---------------------------------- // ----------------------------------
...@@ -174,6 +176,34 @@ var tableSpan ; ...@@ -174,6 +176,34 @@ var tableSpan ;
var corpusesList = {} var corpusesList = {}
// TABLE'S PARAMS' getter
// -----------------------
// Fetch all current user params for sorting, filtering...
// @param aDynatable (eg: MyTable.data('dynatable'))
function getSelectedParams(aDynatable) {
var tbsettings = aDynatable.settings.dataset
var sorting_obj= tbsettings.sorts
var sort_type = null
if (sorting_obj) {
sort_type = Object.keys(sorting_obj).pop()
}
// returns a "picklistParams object"
return {
'search' : tbsettings.queries['search'],
'multiw' : tbsettings.queries['my_termtype_filter'],
'gtlists': tbsettings.queries['my_state_filter'],
'perpp' : tbsettings.perPage,
'sortk' : sort_type,
'sortdirec': sorting_obj ? sorting_obj[sort_type] : null,
'from' : TheBuffer ? TheBuffer[0] : null,
'to' : TheBuffer ? TheBuffer[1] : null
}
}
// ============================================================================= // =============================================================================
// CACHE MANAGEMENT // CACHE MANAGEMENT
// ============================================================================= // =============================================================================
...@@ -190,18 +220,17 @@ window.onbeforeunload = saveParamsToCache; ...@@ -190,18 +220,17 @@ window.onbeforeunload = saveParamsToCache;
// always called at page close/quit // always called at page close/quit
// £TODO use url instead of corpusId+'/terms' as prefix // £TODO use url instead of corpusId+'/terms' as prefix
function saveParamsToCache() { function saveParamsToCache() {
var corpusId = getIDFromURL("corpora")
var search_filter_status = MyTable.data('dynatable').settings.dataset.queries['search'] var params = getSelectedParams(MyTable.data('dynatable'))
var state_filter_status = MyTable.data('dynatable').settings.dataset.queries['my_state_filter']
var type_filter_status = MyTable.data('dynatable').settings.dataset.queries['my_termtype_filter']
// var page_status = document.getElementsByClassName("dynatable-page-link dynatable-active-page")[0].getAttribute("data-dynatable-page")
var per_page_status = MyTable.data('dynatable').settings.dataset.perPage
// ex: {'name':1} or {'score':-1} var search_filter_status = params.search
var sorting_obj = MyTable.data('dynatable').settings.dataset.sorts var state_filter_status = params.gtlists
var sort_type_status = Object.keys(sorting_obj).pop() var type_filter_status = params.multiw
var sort_direction_status = sorting_obj[sort_type_status] var per_page_status = params.perpp
var sort_type_status = params.sortk
var sort_direction_status = params.sortdirec
var from_status = params.from
var to_status = params.to
// keys and values are str only so we use path-like keys // keys and values are str only so we use path-like keys
if (search_filter_status) { if (search_filter_status) {
...@@ -226,6 +255,13 @@ function saveParamsToCache() { ...@@ -226,6 +255,13 @@ function saveParamsToCache() {
localStorage.removeItem(corpusId+'/terms/type') localStorage.removeItem(corpusId+'/terms/type')
} }
if (typeof(from_status) != "undefined"
&& typeof(to_status) != "undefined") {
console.log("saving STAT")
localStorage[corpusId+'/terms/fromVal'] = from_status
localStorage[corpusId+'/terms/toVal'] = to_status
}
localStorage[corpusId+'/terms/perPage'] = per_page_status localStorage[corpusId+'/terms/perPage'] = per_page_status
// localStorage[corpusId+'/terms/page'] = page_status // localStorage[corpusId+'/terms/page'] = page_status
...@@ -235,40 +271,19 @@ function saveParamsToCache() { ...@@ -235,40 +271,19 @@ function saveParamsToCache() {
return null; return null;
} }
// always called after MyTable init // called after 1st Ajax and given to table init in Main as filtersParams
function restoreSettingsFromCache() { function restoreSettingsFromCache() {
var corpusId = getIDFromURL("corpora") // also returns a "picklistParams object"
// var had_page = localStorage[corpusId+'/terms/page'] return {
var had_type = localStorage[corpusId+'/terms/type'] 'search' : localStorage[corpusId+'/terms/search'],
var had_state = localStorage[corpusId+'/terms/state'] 'multiw' : localStorage[corpusId+'/terms/type'],
var had_search = localStorage[corpusId+'/terms/search'] 'gtlists': localStorage[corpusId+'/terms/state'],
var had_perPage = localStorage[corpusId+'/terms/perPage'] 'perpp' : localStorage[corpusId+'/terms/perPage'],
var had_sortType = localStorage[corpusId+'/terms/sortType'] 'sortk' : localStorage[corpusId+'/terms/sortType'],
var sortDirection = localStorage[corpusId+'/terms/sortDirection'] 'sortdirec':localStorage[corpusId+'/terms/sortDirection'],
// if (had_page) { 'from': localStorage[corpusId+'/terms/fromVal'],
// MyTable.data('dynatable').paginationPage.set(had_page); 'to': localStorage[corpusId+'/terms/toVal']
// }
if (had_type) {
MyTable.data('dynatable').settings.dataset.queries['my_termtype_filter'] = had_type
}
if (had_state) {
MyTable.data('dynatable').settings.dataset.queries['my_state_filter'] = had_state
}
if (had_search) {
MyTable.data('dynatable').settings.dataset.queries['search'] = had_search
} }
if (had_perPage) {
MyTable.data('dynatable').paginationPerPage.set(had_perPage)
}
if (had_sortType) {
MyTable.data('dynatable').sorts.clear();
MyTable.data('dynatable').sorts.add(had_sortType, sortDirection)
console.log("added sort",had_sortType)
}
// re-process to makes the changes visible
MyTable.data('dynatable').process()
return null;
} }
...@@ -346,54 +361,57 @@ function GetUserPortfolio() { ...@@ -346,54 +361,57 @@ function GetUserPortfolio() {
} }
//Getting a corpusB-list and intersecting it with current corpusA-miamlist. //Getting a corpusB-list and intersecting it with current corpusA-miamlist.
function printCorpuses() { // function printCorpuses() {
console.log( "!!!!!!!! in printCorpuses() !!!!!!!! " ) // console.log( "!!!!!!!! in printCorpuses() !!!!!!!! " )
pr(corpusesList) // pr(corpusesList)
//
var selected = $('input[name=optradio]:checked')[0].id.split("_") // var selected = $('input[name=optradio]:checked')[0].id.split("_")
var sel_p = selected[0], sel_c=selected[1] // var sel_p = selected[0], sel_c=selected[1]
//
var current_corpus = getIDFromURL("corpora") // var current_corpus = getIDFromURL("corpora")
//
var selected_corpus = corpusesList[sel_p]["corpuses"][sel_c]["id"] // var selected_corpus = corpusesList[sel_p]["corpuses"][sel_c]["id"]
pr("current corpus: "+current_corpus) // pr("current corpus: "+current_corpus)
var the_ids = [] // var the_ids = []
the_ids.push( current_corpus ) // the_ids.push( current_corpus )
the_ids.push( corpusesList[sel_p]["corpuses"][sel_c]["id"] ) // the_ids.push( corpusesList[sel_p]["corpuses"][sel_c]["id"] )
//
$("#closecorpuses").click(); // $("#closecorpuses").click();
//
// EXTERNAL CORPUS TO COMPARE: // // EXTERNAL CORPUS TO COMPARE:
var whichlist = $('input[name=whichlist]:checked').val() // var whichlist = $('input[name=whichlist]:checked').val()
var url = window.location.origin+"/api/node/"+selected_corpus+"/ngrams/list/"+whichlist//+"?custom" // var url = window.location.origin+"/api/node/"+selected_corpus+"/ngrams/list/"+whichlist//+"?custom"
console.log( url ) // console.log( url )
//
//
GET_( url , function(results, url) { // GET_( url , function(results, url) {
if(Object.keys( results ).length>0) { // if(Object.keys( results ).length>0) {
var sub_ngrams_data = { // var sub_ngrams_data = {
"ngrams":[], // "ngrams":[],
"scores": $.extend({}, OriginalNG.scores) // "scores": $.extend({}, OriginalNG.scores)
} // }
for(var i in OriginalNG["records"].ngrams) { // for(var i in OriginalNG["records"].ngrams) {
if( results[ OriginalNG["records"].ngrams[i].id] ) { // if( results[ OriginalNG["records"].ngrams[i].id] ) {
var a_ngram = OriginalNG["records"].ngrams[i] // var a_ngram = OriginalNG["records"].ngrams[i]
sub_ngrams_data["records"].push( a_ngram ) // sub_ngrams_data["records"].push( a_ngram )
} // }
// if( results[ OriginalNG["records"][i].id] && OriginalNG["records"][i].name.split(" ").length==1 ) { // // if( results[ OriginalNG["records"][i].id] && OriginalNG["records"][i].name.split(" ").length==1 ) {
// if( OriginalNG["map"][ i ] ) { // // if( OriginalNG["map"][ i ] ) {
// var a_ngram = OriginalNG["records"][i] // // var a_ngram = OriginalNG["records"][i]
// // a_ngram["state"] = System[0]["statesD"]["delete"] // // // a_ngram["state"] = System[0]["statesD"]["delete"]
// sub_ngrams_data["ngrams"].push( a_ngram ) // // sub_ngrams_data["ngrams"].push( a_ngram )
// } // // }
// } // // }
} // }
var result = MainTableAndCharts(sub_ngrams_data , OriginalNG.scores.initial , "filter_all") // var result = MainTableAndCharts(sub_ngrams_data , OriginalNG.scores.initial , {})
} // }
}); // });
} // }
// Updates most global var TheBuffer
// TODO should be distinct from time range (of doc view)
// and adapt more for freq ranges
function Push2Buffer( NewVal ) { function Push2Buffer( NewVal ) {
if ( TheBuffer == false) { if ( TheBuffer == false) {
if( ! NewVal ) { if( ! NewVal ) {
...@@ -460,6 +478,7 @@ function Final_UpdateTable( action ) { ...@@ -460,6 +478,7 @@ function Final_UpdateTable( action ) {
} }
} }
// todo: check if necessary to re-init like this
MyTable = $('#my-ajax-table').dynatable({ MyTable = $('#my-ajax-table').dynatable({
dataset: { dataset: {
records: TimeRange records: TimeRange
...@@ -573,13 +592,9 @@ function removeActiveGroupFrameAndUpdate() { ...@@ -573,13 +592,9 @@ function removeActiveGroupFrameAndUpdate() {
// we also close the open sublists in case some of them don't exist any more // we also close the open sublists in case some of them don't exist any more
vizopenGroup = {} vizopenGroup = {}
// reprocess from current record states // reprocess from current record states and params
var currentStateFilter = MyTable.data('dynatable').settings.dataset.queries['my_state_filter'] var FirstScoreParam = OriginalNG.scores.initial // £TODO use when several scores
MainTableAndCharts(AjaxRecords, FirstScoreParam , getSelectedParams(MyTable.data('dynatable')),"removeActiveGroupFrameAndUpdate")
// TODO when several scores, use cache like currentStateFilter
var FirstScore = OriginalNG.scores.initial
// console.log("full re-create table")
MainTableAndCharts(AjaxRecords, FirstScore , currentStateFilter)
} }
// for click open/close // for click open/close
...@@ -1909,17 +1924,14 @@ function GROUPCRUDS( groupnode_id , send_data, http_method , callback) { ...@@ -1909,17 +1924,14 @@ function GROUPCRUDS( groupnode_id , send_data, http_method , callback) {
* - AfterAjax for map items * - AfterAjax for map items
* - ??? for stop items * - ??? for stop items
* 3. Creates the scores distribution chart over table * 3. Creates the scores distribution chart over table
* 4. Set up Search div * 4. Set up Search div and initialize user filter statuses
* *
* @param ngdata: OriginalNG['records'] * @param ngdata: OriginalNG['records']
* @param initial: initial score type "occs" or "tfidf" * @param initial: initial score type "occs" or "tfidf" => £TODO multiscore
* @param search_filter: value among {0,1,2,'reset'} (see #picklistmenu options) * @param filtersParams: contains the option values in a "picklistParams object"
* * It can be {} or custom/cached keys for init of filters
* TODO replace by new @param filters (multiple) for all cached values
* (would allow us to use them directly in settings instead of a posteriori
* with restoreSettingsFromCache)
*/ */
function MainTableAndCharts( ngdata , initial , search_filter) { function MainTableAndCharts( ngdata , initial , filtersParams, callerLabel) {
// debug // debug
// alert("refresh main") // alert("refresh main")
...@@ -1930,8 +1942,10 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -1930,8 +1942,10 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
// console.log(ngdata) // console.log(ngdata)
// console.log("initial:") // // console.log("initial:") //
// console.log(initial) // console.log(initial)
// console.log("search_filter:") // eg 'filter_all' console.log("filtersParams:") // eg {'lists': filter_all'}
// console.log(search_filter) if(typeof(filtersParams) != 'undefined') {console.log(filtersParams)} else {console.log('pas de params')}
console.log("callerLabel:")
if(typeof(callerLabel) != 'undefined') {console.log(callerLabel)} else {console.log('pas de callerLabel')}
// console.log(" = = = = / MainTableAndCharts: = = = = ") // console.log(" = = = = / MainTableAndCharts: = = = = ")
// console.log("") // console.log("")
...@@ -2154,6 +2168,7 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -2154,6 +2168,7 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
// .interpolate("monotone") // .interpolate("monotone")
// .renderDataPoints({radius: 2, fillOpacity: 0.8, strokeOpacity: 0.8}) // .renderDataPoints({radius: 2, fillOpacity: 0.8, strokeOpacity: 0.8})
.brushOn(false) .brushOn(false)
.rangeChart(volumeChart)
.title(function (d) { .title(function (d) {
if (isNaN(d.data.value))  { if (isNaN(d.data.value))  {
console.warn(JSON.stringify(d)) console.warn(JSON.stringify(d))
...@@ -2173,6 +2188,7 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -2173,6 +2188,7 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
LineChart.render() LineChart.render()
// selectable barchart
volumeChart.width(800) volumeChart.width(800)
.height(100) .height(100)
.margins({top: 30, right: 50, bottom: 20, left: 40}) .margins({top: 30, right: 50, bottom: 20, left: 40})
...@@ -2188,6 +2204,9 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -2188,6 +2204,9 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
.renderlet(function (chart) { .renderlet(function (chart) {
chart.select("g.y").style("display", "none"); chart.select("g.y").style("display", "none");
}) })
// ------------------------------------------------------
// main hook between Chart => Buffer => Final_UpdateTable
// ------------------------------------------------------
.on("filtered", function (chart) { .on("filtered", function (chart) {
dc.events.trigger(function () { dc.events.trigger(function () {
var chartfilt = chart.filter() var chartfilt = chart.filter()
...@@ -2211,8 +2230,13 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -2211,8 +2230,13 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
volumeChart.filterAll(); volumeChart.filterAll();
dc.redrawAll(); dc.redrawAll();
// expose selection brush
var ourBrush = volumeChart.brush()
// --------------------------
// DYNATABLE initialization // DYNATABLE initialization
// --------------------------
// writes in the app scope var MyTable
MyTable = [] MyTable = []
MyTable = $('#my-ajax-table').dynatable({ MyTable = $('#my-ajax-table').dynatable({
dataset: { dataset: {
...@@ -2267,19 +2291,13 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -2267,19 +2291,13 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
} }
} }
MyTable.data('dynatable').sorts.clear();
MyTable.data('dynatable').sorts.add('score', 1) // 1=DESCENDING,
// MyTable.data('dynatable').process();
MyTable.data('dynatable').paginationPage.set(1);
MyTable.data('dynatable').paginationPerPage.set(50); // default:10
MyTable.data('dynatable').process();
// hook on page change // hook on page change
MyTable.bind('dynatable:page:set', tidyAfterPageSetUpdate) MyTable.bind('dynatable:page:set', tidyAfterPageSetUpdate)
// hook on any type of update // hook on any type of update
MyTable.bind('dynatable:afterUpdate', tidyAfterUpdate) MyTable.bind('dynatable:afterUpdate', tidyAfterUpdate)
// £TODO multiscore
// // // $("#score_column_id").children()[0].text = FirstScore // // // $("#score_column_id").children()[0].text = FirstScore
// // // // MyTable.data('dynatable').process(); // // // // MyTable.data('dynatable').process();
...@@ -2299,7 +2317,7 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -2299,7 +2317,7 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
} }
} }
// second filter named 'my_termtype_filter' // second filter named 'my_termtype_filter' for gargantext lists (map, )
MyTable.data('dynatable').queries MyTable.data('dynatable').queries
.functions['my_termtype_filter'] = function(record,selectedValue) { .functions['my_termtype_filter'] = function(record,selectedValue) {
if (selectedValue == 'reset') { if (selectedValue == 'reset') {
...@@ -2316,19 +2334,52 @@ function MainTableAndCharts( ngdata , initial , search_filter) { ...@@ -2316,19 +2334,52 @@ function MainTableAndCharts( ngdata , initial , search_filter) {
} }
// and set these filters' initial status // and set these filters' initial status
MyTable.data('dynatable').settings.dataset.queries['my_state_filter'] = search_filter ; var MyTablesQueries = MyTable.data('dynatable').settings.dataset.queries
MyTable.data('dynatable').settings.dataset.queries['my_termtype_filter'] = 'reset' ;
MyTable.data('dynatable').process(); MyTablesQueries['my_state_filter'] = filtersParams.gtlists || 'reset' ;
MyTablesQueries['my_termtype_filter'] = filtersParams.multiw || 'reset' ;
// set main text-search value
MyTablesQueries['search'] = filtersParams.search || ''
// £todo factorize with previous with a param search_filters // set table pagination
restoreSettingsFromCache(localStorage) MyTable.data('dynatable').paginationPage.set(1);
MyTable.data('dynatable').paginationPerPage.set(filtersParams.perpp || 50) ;
// also set sorts
MyTable.data('dynatable').sorts.clear();
MyTable.data('dynatable').sorts.add( filtersParams.sortk || "score",
filtersParams.sortdirec || 1
// 1=DESCENDING,
)
// go ! ------------------------------
MyTable.data('dynatable').process();
// -----------------------------------
// moves pagination over table // moves pagination over table
// £TODO pagination copy instead (hard!)
if ( $(".imadiv").length>0 ) return 1; if ( $(".imadiv").length>0 ) return 1;
$('<br><br><div class="imadiv"></div>').insertAfter(".dynatable-per-page") $('<br><br><div class="imadiv"></div>').insertAfter(".dynatable-per-page")
$(".dynatable-record-count").insertAfter(".imadiv") $(".dynatable-record-count").insertAfter(".imadiv")
$(".dynatable-pagination-links").insertAfter(".imadiv") $(".dynatable-pagination-links").insertAfter(".imadiv")
// restore chart filters
if (typeof(filtersParams.from) != 'undefined'
&& typeof(filtersParams.to) != 'undefined') {
var fromVal = filtersParams.from
var toVal = filtersParams.to
if (fromVal != oldest || toVal != latest) {
// volumeChart.filterAll() // re-init
placeBrush(ourBrush, fromVal, toVal)
// placeBrush also does volumeChart.filter([fromVal, toVal]) and Push2Buffer
}
}
return "OK" return "OK"
} }
...@@ -2347,6 +2398,24 @@ function doATest() { ...@@ -2347,6 +2398,24 @@ function doATest() {
console.log("^---------- /TEST -----------^") console.log("^---------- /TEST -----------^")
} }
/**
* placeBrush cf. http://bl.ocks.org/timelyportfolio/5c136de85de1c2abb6fc:
* -----------
* Adds the brush (aka "chart's selection zone") programmatically
* (for instance at initialize if we want to restore previous selection)
*/
function placeBrush(myBrush, min, max) {
// define our brush extent
myBrush.extent([min, max])
// now draw the brush to match our extent
myBrush(d3.select(".brush"));
// now fire the brushstart, brushmove, and brushend events
myBrush.event(d3.select(".brush"))
}
/** /**
* tidyAfterUpdate: * tidyAfterUpdate:
* ----------- * -----------
...@@ -2526,6 +2595,7 @@ var final_url = window.location.origin+"/api/ngramlists/family?corpus="+corpus_i ...@@ -2526,6 +2595,7 @@ var final_url = window.location.origin+"/api/ngramlists/family?corpus="+corpus_i
// faster call: just the maplist, will return first // faster call: just the maplist, will return first
// 2016-05-13: deactivated because it causes a lag before the table is updated // 2016-05-13: deactivated because it causes a lag before the table is updated
// FIXME: probably because of != nb of records ?
// GET_(prefetch_url, HandleAjax); // GET_(prefetch_url, HandleAjax);
// longer call (full list of terms) to return when ready and refresh all data // longer call (full list of terms) to return when ready and refresh all data
...@@ -2589,10 +2659,7 @@ function HandleAjax(res, sourceUrl) { ...@@ -2589,10 +2659,7 @@ function HandleAjax(res, sourceUrl) {
} }
// unpack ajax values, read table settings from cache if any, and run Main
// throws errors when ngram in list has no infos
// (can't assign state and copy to AjaxRecords)
function AfterAjax(sourceUrl) { function AfterAjax(sourceUrl) {
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// console.log(JSON.stringify(OriginalNG)) // console.log(JSON.stringify(OriginalNG))
...@@ -2657,7 +2724,7 @@ function AfterAjax(sourceUrl) { ...@@ -2657,7 +2724,7 @@ function AfterAjax(sourceUrl) {
// Building the Score-Selector //OriginalNG["scores"] // Building the Score-Selector //OriginalNG["scores"]
var FirstScore = OriginalNG.scores.initial var FirstScore = OriginalNG.scores.initial
// TODO scores_div // TODO scores_div multiscore
// Recreate possible_scores from some constants (tfidf, occs) // Recreate possible_scores from some constants (tfidf, occs)
// and not from ngrams[0], to keep each ngram's info smaller // and not from ngrams[0], to keep each ngram's info smaller
...@@ -2670,11 +2737,17 @@ function AfterAjax(sourceUrl) { ...@@ -2670,11 +2737,17 @@ function AfterAjax(sourceUrl) {
// } // }
// } // }
// show only map (option = 1) or all terms (option = "reset") // show only map (option = 1, good for waiting if async records)
termsfilter = (sourceUrl == final_url) ? "reset" : "1" // or all terms (option = "reset")
// table settings for filters etc.
var configIfAny = {}
configIfAny = restoreSettingsFromCache()
// configIfAny.gtlists = (sourceUrl == final_url) ? "reset" : "1" // condition useful for prefetch
// Initializing the Charts and Table --------------------------------------- // Initializing the Charts and Table ---------------------------------------
var result = MainTableAndCharts(OriginalNG["records"], FirstScore , termsfilter) ; var result = MainTableAndCharts(OriginalNG["records"], FirstScore , configIfAny, "AfterAjax") ;
console.log( result ) // OK console.log( result ) // OK
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
......
...@@ -200,8 +200,34 @@ function getRessources(){ ...@@ -200,8 +200,34 @@ function getRessources(){
//// POST TO API //// POST TO API
//// PUT AND PATCH TO API //// PUT AND PATCH TO API
function deleteOne(url){ function deleteOne(url, thatButton){
// we just show wait image before ajax
var $thatButton = $(thatButton)
var alreadyWaiting = $thatButton.has($('.wait-img-active')).length
if (! alreadyWaiting) {
var previousButtonContent = $thatButton.html()
var availableWidth = $thatButton.width()
var $myWaitImg = $('#wait-img').clone()
$myWaitImg.attr("id", null)
.attr("class","wait-img-active pull-right")
.width(availableWidth)
.css("display", "block") ;
$thatButton.append($myWaitImg)
}
else {
// uncomment if user should stop clicking ;)
// $thatButton.addClass("btn-danger")
// uncomment to prevent a 2nd ajax
return false
}
// now the real ajax
$.ajax({ $.ajax({
url: '/api'+url, url: '/api'+url,
type: 'delete', type: 'delete',
...@@ -306,7 +332,7 @@ $(document).on('change', 'input[type=checkbox]', function() { ...@@ -306,7 +332,7 @@ $(document).on('change', 'input[type=checkbox]', function() {
$(document).on("click","#delete", function(){ $(document).on("click","#delete", function(){
var selected = selectedUrls(); var selected = selectedUrls();
selected.forEach(function(url) { selected.forEach(function(url) {
deleteOne(url); deleteOne(url, this);
}); });
//window.location.reload(); //window.location.reload();
}); });
...@@ -336,7 +362,7 @@ $(document).on("click","#recalculate", function(){ ...@@ -336,7 +362,7 @@ $(document).on("click","#recalculate", function(){
// UNIQUE DELETION // UNIQUE DELETION
$(document).on("click", ".delete", function() { $(document).on("click", ".delete", function() {
var url = $( this ).data("url"); var url = $( this ).data("url");
deleteOne(url); deleteOne(url, this);
//window.location.reload(); //window.location.reload();
}); });
......
...@@ -10,6 +10,290 @@ ...@@ -10,6 +10,290 @@
<script src="{% static "lib/jquery/1.11.1/jquery.min.js" %}" type="text/javascript"></script> <script src="{% static "lib/jquery/1.11.1/jquery.min.js" %}" type="text/javascript"></script>
<style type="text/css">
.first-graph {
padding-top: 3em;
}
</style>
<script type="text/javascript">
// initial vars
var projectId = "{{project.id | escapejs}}"
var corpusId = "{{corpus.id | escapejs }}"
/**
* Some html block templates to render responses after the ajax of goFirstGraph
*
* TODO use template_literals returned by lazy function or any other better templating
*/
var processingHtml='\
<div class="progress">\
<div class=" progress-bar progress-bar-striped active"\
role="progressbar" aria-valuenow="45" aria-valuemin="0" aria-valuemax="100" style="width: 70%">\
<span>\
Processing\
</span>\
</div>\
</div>'
var finishedHtmlTemplate='\
<br>\
From: begin of corpus\
, To: end of corpus\
<br>\
<ul>\
<li>\
<a href="/projects/%%project_id%%/corpora/%%corpus_id%%/explorer?cooc_id=%%cooc_id%%&amp;distance=conditional&amp;bridgeness=5">\
<span class="glyphicon glyphicon-eye-open" style="font-size:150%"></span>\
~%%nb_nodes%% nodes,\
~%%nb_edges%% edges\
with <b>Conditional</b> distance\
</a>\
</li>\
<li>\
<a href="/projects/%%project_id%%/corpora/%%corpus_id%%/explorer?cooc_id=%%cooc_id%%&amp;distance=distributional&amp;bridgeness=5">\
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>\
Compute this graph with Distributional distance\
</a>\
</li>\
</ul>\
<br>'
var baseSkeletonTemplate='\
<div id="graph_%%cooc_id%%" class="first-graph">\
<div class="row">\
<div class="col-md-1 content"></div>\
<div class="col-md-5 content">\
<li>\
<h4 title="%%cooc_id%%">%%cooc_name%%</h4>\
%%cooc_date%%\
\
%%HERE_RESPONSE_DEPENDANT%%\
\
</li>\
</div>\
<div class="col-md-3 content">\
<button type="button" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="bottom"\
data-content="\
<ul>\
<li\
onclick=&quot;\
garganrest.nodes.delete(%%cooc_id%%, function(){$(\'#graph_\'+%%cooc_id%%).remove()});\
$(this).parent().parent().remove();\
&quot;>\
<a href=\'#\'>Delete this</a>\
</li>\
</ul>\
">\
<span class="glyphicon glyphicon-trash" aria-hidden="true"\
title=\'Delete this graph\'></span>\
</button>\
</div>\
</div>\
</div>'
/**
* function showNewCoocDiv(status_code, cooc_id, cooc_name, cooc_date)
*
* (uses the templates to make a new cooc html appear)
*
* @param 'progress_status' || 'finished_status'
* @param projectId
* @param corpusId
* @param coocId
* @param coocName
* @param coocDate
* @param nNodes (optional <=> if finished_status)
* @param nEdges (optional <=> if finished_status)
*/
function showNewCoocDiv(statusCode,
coocId, coocName, coocDate,
nbNodes, nbEdges) {
var resultHtml = baseSkeletonTemplate
// initial if
switch (statusCode) {
case "progress_status":
resultHtml = resultHtml.replace(/%%HERE_RESPONSE_DEPENDANT%%/,
processingHtml
)
break;
case "finished_status":
resultHtml = resultHtml.replace(/%%HERE_RESPONSE_DEPENDANT%%/,
finishedHtmlTemplate
)
break;
default:
console.warning("showNewCoocDiv: can't show div (Unknown statusCode", statusCode,")");
return false
}
// also replace template variables (thx c24b!)
resultHtml = resultHtml.replace(/%%project_id%%/g, projectId);
resultHtml = resultHtml.replace(/%%corpus_id%%/g, corpusId);
resultHtml = resultHtml.replace(/%%cooc_id%%/g, coocId);
resultHtml = resultHtml.replace(/%%cooc_name%%/g, coocName);
resultHtml = resultHtml.replace(/%%cooc_date%%/g, coocDate);
if (typeof nbEdges != 'undefined' && typeof nbNodes != 'undefined') {
resultHtml = resultHtml.replace(/%%nb_nodes%%/g, nbNodes);
resultHtml = resultHtml.replace(/%%nb_edges%%/g, nbEdges);
}
// what do we do with those results ?
switch (statusCode) {
case "progress_status":
// render the result in DOM
$('#graph-list').append(resultHtml)
return null
case "finished_status":
// replace the previous results
var previousDiv = document.getElementById('graph_'+coocId)
previousDiv.innerHTML = resultHtml
return true
}
}
/**
* function goFirstGraph()
*
* 1) run a "save new graph" ajax on graph api
* 2) retrieve the new cooc_id in immediate response
* 3) monitor status of the async generation
*/
function goFirstGraph() {
// ajax config vars
var graphApi = "/api/projects/{{project.id}}/corpora/{{ corpus.id }}/explorer"
var graphParams = "saveOnly=True&distance=conditional&bridgeness=5"
// vars we'll get at creation steps (1: graph init, 2: graph finish)
var coocId = null // 1 & 2
var coocName = null // 1 & 2
var coocDate = null // 1 & 2
var nbNodes = null // 2
var nbEdges = null // 2
// run the "save new graph" ajax
// -----------------------------
// cf. data["state"] == "saveOnly"
$.ajax({
method: "GET",
url: graphApi + '?' + graphParams,
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
},
success: function(data){
// console.log("data", data)
// 1 - retrieve the new coocId etc
if (data.id && data.name && data.date) {
coocId = data['id']
coocName = data['name']
coocDate = data['date']
}
// 2 - show the node with basic info and progressbar
showNewCoocDiv("progress_status",
coocId, coocName, coocDate)
// 3 - run status updating
// (it will call next step of
// showNewCoocDiv when ready)
keepCheckingGraphStatus(coocId)
},
error: function(result) {
console.log("result", result)
}
});
}
/**
* function keepCheckingGraphStatus(coocId)
*
* 1) keeps checking an API of cooc status
* 2) triggers showNewCoocDiv('finished_status') if ready
* or abandons after 5 attempts
*/
var nChecks = 0
var currentJob = null
var graphReadyFlag = false
function keepCheckingGraphStatus(coocNodeId) {
console.log("checking status", nChecks)
nChecks ++
// var the_status_url = "/api/nodes/"+coocNodeId+"/status?format=json"
var the_url_to_check = "/api/nodes/"+coocNodeId+"?fields[]=hyperdata&fields[]=name&fields[]=date"
// we get all hyperdata instead of just statuses because
// we'll need hyperdata.conditional.nodes and edges
// remote call
$.ajax({
type: 'GET',
url: the_url_to_check,
success: function(data) {
// TODO hyperdata would contains statuses too
// var statuses = data['hyperdata']['statuses']
var coocNodeName = data['name']
var coocNodeDate = data['date']
// test if ready like this for the moment
if (typeof data['hyperdata']['conditional'] != "undefined") {
console.log("GRAPH is READY", coocNodeId)
graphReadyFlag = true
var nbNodes = data['hyperdata']['conditional']['nodes']
var nbEdges = data['hyperdata']['conditional']['edges']
// console.warn("running callback for graph id:" + coocNodeId)
showNewCoocDiv("finished_status", coocNodeId,
coocNodeName, coocNodeDate,
nbNodes, nbEdges)
}
// stopping conditions
if (graphReadyFlag || nChecks > 5) {
// we abandon after 5 checks
console.warn("stopping status checks for graph:",
coocNodeId)
nChecks = 0
return null
}
// scheduled recursion
else {
console.log("GRAPH not ready yet...", coocNodeId)
// decreasing intervals (preserving DB while "loosing interest")
var nextTime = nChecks * 3000
// schedule next check
currentJob = setTimeout(function(){keepCheckingGraphStatus(coocNodeId)}, nextTime)
console.log("next status check in", nextTime/1000, "s" )
return false
}
},
error: function(data, s) {
console.warn("status GET: ajax err (s="+s+")")
console.log(data)
},
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
}
})
}
function stopCheckingGraphStatus() {
clearTimeout(currentJob)
}
</script>
{% endblock %} {% endblock %}
...@@ -18,7 +302,7 @@ ...@@ -18,7 +302,7 @@
<div class="container theme-showcase" role="main"> <div class="container theme-showcase" role="main">
<h2>My Graphs </h2> <h2>My Graphs </h2>
<ol> <ol id="graph-list">
{% if coocs %} {% if coocs %}
{% for cooc in coocs %} {% for cooc in coocs %}
<div id="graph_{{cooc.id}}"> <div id="graph_{{cooc.id}}">
...@@ -35,15 +319,15 @@ ...@@ -35,15 +319,15 @@
From: {% if not cooc.hyperdata.parameters.start %} begin of corpus {% else %} {{cooc.hyperdata.parameters.start}} {% endif %} From: {% if not cooc.hyperdata.parameters.start %} begin of corpus {% else %} {{cooc.hyperdata.parameters.start}} {% endif %}
, To: {% if not cooc.hyperdata.parameters.end %} end of corpus {% else %} {{cooc.hyperdata.parameters.end}} {% endif %} , To: {% if not cooc.hyperdata.parameters.end %} end of corpus {% else %} {{cooc.hyperdata.parameters.end}} {% endif %}
<br> <br>
<ul> <ul>
<li> <li>
<a href="/projects/{{project.id}}/corpora/{{corpus.id}}/explorer?cooc_id={{cooc.id}}&distance=conditional&bridgeness=5"> <a href="/projects/{{project.id}}/corpora/{{corpus.id}}/explorer?cooc_id={{cooc.id}}&amp;distance=conditional&amp;bridgeness=5">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
{% if cooc.hyperdata.conditional %} {% if cooc.hyperdata.conditional %}
~{{ cooc.hyperdata.conditional.nodes }} nodes, ~{{ cooc.hyperdata.conditional.nodes }} nodes,
~{{ cooc.hyperdata.conditional.edges }} edges ~{{ cooc.hyperdata.conditional.edges }} edges
with <b>Conditional</b> distance with <b>Conditional</b> distance
{% else %} {% else %}
Compute this graph with Conditional distance Compute this graph with Conditional distance
...@@ -52,12 +336,12 @@ ...@@ -52,12 +336,12 @@
</li> </li>
<li> <li>
<a href="/projects/{{project.id}}/corpora/{{corpus.id}}/explorer?cooc_id={{cooc.id}}&distance=distributional&bridgeness=5"> <a href="/projects/{{project.id}}/corpora/{{corpus.id}}/explorer?cooc_id={{cooc.id}}&amp;distance=distributional&amp;bridgeness=5">
<span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span> <span class="glyphicon glyphicon-eye-open" aria-hidden="true"></span>
{% if cooc.hyperdata.distributional %} {% if cooc.hyperdata.distributional %}
~{{ cooc.hyperdata.distributional.nodes }} nodes, ~{{ cooc.hyperdata.distributional.nodes }} nodes,
~{{ cooc.hyperdata.distributional.edges }} edges ~{{ cooc.hyperdata.distributional.edges }} edges
with <b>Distributional</b> distance with <b>Distributional</b> distance
{% else %} {% else %}
Compute this graph with Distributional distance Compute this graph with Distributional distance
...@@ -68,7 +352,7 @@ ...@@ -68,7 +352,7 @@
<br> <br>
<!-- <li>{{cooc.id}}</li> <!-- <li>{{cooc.id}}</li>
<ul> <ul>
<li> <li>
...@@ -123,7 +407,7 @@ ...@@ -123,7 +407,7 @@
</button> </button>
</a> </a>
--!> -->
<button type="button" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="bottom" <button type="button" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="bottom"
data-content=" data-content="
...@@ -176,13 +460,14 @@ ...@@ -176,13 +460,14 @@
<li>Choose a distance</li> <li>Choose a distance</li>
<li>Click on the distance or on MyGraph which is this page</li> <li>Click on the distance or on MyGraph which is this page</li>
</ol> </ol>
<h4> <h4>
<span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span> <span class="glyphicon glyphicon-ok-circle" aria-hidden="true"></span>
Do you want to test ?</h4> Do you want to test ?</h4>
</li> <btn class="btn btn-info" onclick="goFirstGraph()">
<a href="/projects/{{project.id}}/corpora/{{ corpus.id }}/explorer?field1=ngrams&amp;field2=ngrams&amp;distance=conditional&amp;bridgeness=5">Compute a new graph with conditional distance!</a> <span style="font-size:120%">Compute a new graph</span> <br/> with conditional distance
</btn>
{% endif %} {% endif %}
</ul> </ol>
{% endblock %} {% endblock %}
...@@ -56,15 +56,15 @@ ...@@ -56,15 +56,15 @@
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
<div class="center"> <div class="center">
<button type="submit" class="btn btn-primary btn-rounded">Login</button> <div class="checkbox">
</div> <label>
<div> <input id="terms-accept" type="checkbox" value="" onclick="enableAuth(this)">
<p> I accept the terms of uses [DOC1] [DOC2].
<center> </input>
By submitting I accept the terms of uses [DOC1] [DOC2]. </label>
</center>
</p>
</div> </div>
<button id="login-button" type="submit" class="btn btn-primary btn-rounded" disabled>Login</button>
</div>
</form> </form>
</div> </div>
</div> </div>
...@@ -79,6 +79,16 @@ ...@@ -79,6 +79,16 @@
<!-- Bootstrap --> <!-- Bootstrap -->
<script src="{% static "lib/bootstrap/3.2.0/bootstrap.min.js" %}"></script> <script src="{% static "lib/bootstrap/3.2.0/bootstrap.min.js" %}"></script>
<!-- checkbox => submit -->
<script type="text/javascript">
var okButton = document.getElementById('login-button')
function enableAuth(box) {
okButton.disabled = ! box.checked
}
</script>
</body> </body>
......
...@@ -67,7 +67,8 @@ ...@@ -67,7 +67,8 @@
</li> </li>
{% endif %} {% endif %}
</ul> </ul>
<ul class="nav pull-right">
<ul class="nav navbar-nav pull-right">
<li class="dropdown"> <li class="dropdown">
<a href="#" role="button" class="dropdown-toggle navbar-text" data-toggle="dropdown" title="That is your username"> <a href="#" role="button" class="dropdown-toggle navbar-text" data-toggle="dropdown" title="That is your username">
<i class="icon-user"></i> <i class="icon-user"></i>
......
...@@ -18,6 +18,18 @@ ...@@ -18,6 +18,18 @@
.ui-autocomplete .ui-menu-item { .ui-autocomplete .ui-menu-item {
font-size:x-small; font-size:x-small;
} }
/* for wait gif in buttons */
.wait-img-active {
margin-left: .5em;
}
/* hover red like btn_danger */
.btn.delete:hover {
color: #fff;
background-color: #c9302c;
border-color: #ac2925;
}
</style> </style>
{% endblock %} {% endblock %}
...@@ -97,6 +109,7 @@ ...@@ -97,6 +109,7 @@
<!--here loading projectlist from GET /projects--> <!--here loading projectlist from GET /projects-->
</div> </div>
<img id="wait-img" width="90%" style="display:none" src="{% static "img/ajax-loader.gif"%}"></img>
</div> </div>
...@@ -116,10 +129,10 @@ ...@@ -116,10 +129,10 @@
<!-- DELETE PROJECT --> <!-- DELETE PROJECT -->
<button type="button" class="btn btn-default delete pull-right" data-url="{url}" > <button type="button" class="btn btn-default delete pull-right" data-url="{url}" >
<span class="glyphicon glyphicon-trash pull-right" aria-hidden="true"></span> <span class="glyphicon glyphicon-trash" aria-hidden="true"></span>
</button> </button>
<!-- EDIT PROJECT-->
<!-- EDIT PROJECT-->
<button class="btn btn-default edit pull-right" data-id="{id}" data-url="{url}" data-toggle="collapse"> <button class="btn btn-default edit pull-right" data-id="{id}" data-url="{url}" data-toggle="collapse">
<span class="glyphicon glyphicon-pencil" aria-hidden="true"></span> <span class="glyphicon glyphicon-pencil" aria-hidden="true"></span>
</button> </button>
......
...@@ -23,6 +23,11 @@ ...@@ -23,6 +23,11 @@
margin-top: .3em; margin-top: .3em;
color: grey ; color: grey ;
} }
ul.inside-popover {
padding: .5em ;
list-style-type: none ;
}
</style> </style>
{% endblock %} {% endblock %}
...@@ -111,9 +116,9 @@ ...@@ -111,9 +116,9 @@
<button type="button" class="btn btn-default {% if not state.complete %}hidden{% endif %}" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="focus" <button type="button" class="btn btn-default {% if not state.complete %}hidden{% endif %}" data-container="body" data-toggle="popover" data-placement="bottom" data-trigger="focus"
data-content=" data-content="
<ul> <ul class=&quot;inside-popover&quot;>
<li <li
onclick=&quot;updateCorpus({{corpus.id}})&quot;> onclick=&quot;updateCorpus(event, {{corpus.id}})&quot;>
<a href='#'>Recalculate ngram metrics</a> <br/> (can take a little while) <a href='#'>Recalculate ngram metrics</a> <br/> (can take a little while)
</li> </li>
</ul> </ul>
...@@ -125,19 +130,9 @@ ...@@ -125,19 +130,9 @@
<!-- TODO: delete non seulement si state.complete mais aussi si state.error --> <!-- TODO: delete non seulement si state.complete mais aussi si state.error -->
<button type="button" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="bottom" <button type="button" class="btn btn-default" data-container="body" data-toggle="popover" data-placement="bottom"
data-content=" data-content="
<ul> <ul id=&quot;{{corpus.id}}_trash_msg&quot; class=&quot;inside-popover&quot;>
<li <li
onclick=&quot; onclick=&quot;deleteCorpus(event, {{corpus.id}})&quot;>
trashedIds[{{corpus.id}}] = true ;
garganrest.nodes.delete(
{{corpus.id}},
function(){
$('#corpus_'+{{corpus.id}}).remove()
delete trashedIds[{{corpus.id}}]
}
);
$(this).parent().parent().remove();
&quot;>
<a href='#'>Delete this</a> <a href='#'>Delete this</a>
</li> </li>
</ul> </ul>
...@@ -798,7 +793,36 @@ ...@@ -798,7 +793,36 @@
}); });
} }
function updateCorpus(corpusId) { function deleteCorpus(e, corpusId) {
// prevents scroll back to top of page
e.preventDefault()
// register pending operation
trashedIds[corpusId] = true ;
// visual loader wheel
var statusDiv = document.getElementById("corpus_"+corpusId+"_status")
statusDiv.innerHTML = '<img width="10%" src="{% static "img/ajax-loader.gif"%}"></img>'
var trashMsgDiv = document.getElementById(corpusId+"_trash_msg")
trashMsgDiv.innerHTML = '<h5>Deleting corpus, please wait</h5>'
// REST and callback
garganrest.nodes.delete(
corpusId,
function(){
$('#corpus_'+corpusId).remove()
delete trashedIds[corpusId]
// remove any popover too
$('.popover').remove();
}
);
}
function updateCorpus(e, corpusId) {
// prevents scroll back to top of page
e.preventDefault()
// show 'waiting' // show 'waiting'
var statusDiv = document.getElementById("corpus_"+corpusId+"_status") var statusDiv = document.getElementById("corpus_"+corpusId+"_status")
var previousStatus = statusDiv.innerHTML var previousStatus = statusDiv.innerHTML
......
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