2020-01-31 13:14:08 +00:00
class RessourceList extends List {
2020-02-12 11:19:54 +00:00
constructor ( idOrElement , subscriberList , type , options = { } ) {
if ( ! [ 'corpus' , 'job' ] . includes ( type ) ) {
console . error ( "Unknown Type!" ) ;
return ;
}
super ( idOrElement , { ... RessourceList . options [ 'common' ] ,
... RessourceList . options [ type ] ,
... options } ) ;
this . type = type ;
2020-01-29 09:50:31 +00:00
subscriberList . push ( this ) ;
}
2020-01-31 13:14:08 +00:00
_init ( ressources ) {
2020-02-07 15:00:48 +00:00
this . addRessources ( Object . values ( ressources ) ) ;
2020-02-07 14:21:59 +00:00
this . sort ( "creation_date" , { order : "desc" } ) ;
2020-01-29 09:50:31 +00:00
}
_update ( patch ) {
2020-01-31 13:14:08 +00:00
let item , pathArray ;
2020-01-29 09:50:31 +00:00
2020-01-31 13:14:08 +00:00
for ( let operation of patch ) {
/* "/ressourceId/valueName" -> ["ressourceId", "valueName"] */
2020-01-29 09:50:31 +00:00
pathArray = operation . path . split ( "/" ) . slice ( 1 ) ;
switch ( operation . op ) {
case "add" :
2020-02-03 15:04:47 +00:00
if ( pathArray . includes ( "results" ) ) { break ; }
2020-02-07 15:00:48 +00:00
this . addRessources ( [ operation . value ] ) ;
2020-01-29 09:50:31 +00:00
break ;
case "remove" :
this . remove ( "id" , pathArray [ 0 ] ) ;
break ;
case "replace" :
item = this . get ( "id" , pathArray [ 0 ] ) [ 0 ] ;
switch ( pathArray [ 1 ] ) {
case "status" :
item . values ( { status : operation . value } ) ;
break ;
default :
break ;
}
default :
break ;
}
}
}
2020-02-07 15:00:48 +00:00
addRessources ( ressources ) {
2020-02-12 11:19:54 +00:00
this . add ( ressources . map ( x => RessourceList . dataMapper [ this . type ] ( x ) ) ) ;
2020-01-29 09:50:31 +00:00
}
}
2020-01-31 13:14:08 +00:00
RessourceList . dataMapper = {
2020-02-07 14:21:59 +00:00
corpus : corpus => ( { creation _date : corpus . creation _date ,
description : corpus . description ,
id : corpus . id ,
2020-02-12 11:19:54 +00:00
"analyse-link" : ` /corpora/ ${ corpus . id } /analyse ` ,
"edit-link" : ` /corpora/ ${ corpus . id } ` ,
2020-02-07 14:21:59 +00:00
status : corpus . status ,
title : corpus . title } ) ,
job : job => ( { creation _date : job . creation _date ,
description : job . description ,
id : job . id ,
link : ` /jobs/ ${ job . id } ` ,
service : job . service ,
status : job . status ,
title : job . title } )
2020-01-31 13:14:08 +00:00
} ;
RessourceList . options = {
2020-02-12 11:19:54 +00:00
common : { page : 4 , pagination : { innerWindow : 8 , outerWindow : 1 } } ,
corpus : { item : ` <tr>
< td >
< a class = "btn-floating disabled" >
< i class = "material-icons service" > book < / i >
< / a >
< / t d >
< td >
< b class = "title" > < / b > < b r >
< i class = "description" > < / i >
< / t d >
< td >
< span class = "badge new status" data - badge - caption = "" > < / s p a n >
< / t d >
< td class = "right-align" >
< a class = "btn-small edit-link waves-effect waves-light" > < i class = "material-icons" > edit < / i > < / a >
< a class = "btn-small analyse-link waves-effect waves-light" > Analyse < i class = "material-icons right" > search < / i > < / a >
< / t d >
< / t r > ` ,
valueNames : [ "creation_date" , "description" , "title" ,
{ data : [ "id" ] } ,
{ name : "analyse-link" , attr : "href" } ,
{ name : "edit-link" , attr : "href" } ,
{ name : "status" , attr : "data-status" } ] } ,
job : { item : ` <tr>
< td >
< a class = "btn-floating disabled" >
< i class = "material-icons service" > < / i >
< / a >
< / t d >
< td >
< b class = "title" > < / b > < b r >
< i class = "description" > < / i >
< / t d >
< td >
< span class = "badge new status" data - badge - caption = "" > < / s p a n >
< / t d >
< td class = "right-align" >
< a class = "btn-small link waves-effect waves-light" > View < i class = "material-icons right" > send < / i > < / a >
< / t d >
< / t r > ` ,
valueNames : [ "creation_date" , "description" , "title" ,
{ data : [ "id" ] } ,
{ name : "link" , attr : "href" } ,
{ name : "service" , attr : "data-service" } ,
{ name : "status" , attr : "data-status" } ] }
} ;
2020-01-29 15:12:57 +00:00
2020-04-02 12:22:03 +00:00
class ResultsList extends List {
2020-01-29 15:12:57 +00:00
2020-04-07 11:13:48 +00:00
// get display options from display options form element
static getDisplayOptions ( displayOptionsFormElement ) {
// gets display options parameters
let displayOptionsFormData
let displayOptionsData ;
displayOptionsFormData = new FormData ( displayOptionsFormElement ) ;
displayOptionsData = { "resultsPerPage" : displayOptionsFormData . get ( "display-options-form-results_per_page" ) ,
"resultsContex" : displayOptionsFormData . get ( "display-options-form-result_context" ) ,
"expertMode" : displayOptionsFormData . get ( "display-options-form-expert_mode" ) } ;
return displayOptionsData
}
// ###### Functions to inspect one match, to show more details ######
// activate inspect buttons if queryFinished is true
static activateInspect ( ) {
if ( progress === 100 ) {
let inspectBtnElements ;
inspectBtnElements = document . getElementsByClassName ( "inspect" ) ;
for ( let inspectBtn of inspectBtnElements ) {
inspectBtn . classList . remove ( "disabled" ) ;
}
} else {
return
}
}
//gets result cpos infos for one dataIndex to send back to the server
inspect ( dataIndex ) {
// This function should be in the AnalysisClient class as a method.
console . log ( "Inspect!" ) ;
console . log ( results . resultsJSON . matches [ dataIndex ] . c ) ;
let contextResultsElement = document . getElementById ( "context-results" ) ;
contextResultsElement . innerHTML = "" ; // clear it from old inspects
contextModal . open ( ) ;
nopaque . socket . emit ( "corpus_analysis_inspect_match" ,
{ payload : {
first _cpos : results . resultsJSON . matches [ dataIndex ] . c [ 0 ] ,
last _cpos : results . resultsJSON . matches [ dataIndex ] . c [ 1 ]
}
} ) ;
}
showMatchContext ( response ) {
let contextData = response . payload
let contextResultsElement ;
let contextModalLoading ;
let contextModalReady ;
let expertModeSwitchElement
let partElement
let token ;
let tokenElement ;
let tokenElements ;
let lc ;
let c ;
let rc ;
console . log ( "###### match_context ######" ) ;
console . log ( "Incoming data:" , contextData ) ;
expertModeSwitchElement = document . getElementById ( "display-options-form-expert_mode" ) ;
contextResultsElement = document . getElementById ( "context-results" ) ;
if ( contextData . cpos _ranges == true ) {
// python range like function from MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Sequence_generator_(range)
const range = ( start , stop , step ) => Array . from ( { length : ( stop - start ) / step + 1 } , ( _ , i ) => start + ( i * step ) ) ;
lc = range ( contextData . match . lc [ 0 ] , contextData . match . lc [ 1 ] , 1 )
c = range ( contextData . match . c [ 0 ] , contextData . match . c [ 1 ] , 1 )
rc = range ( contextData . match . rc [ 0 ] , contextData . match . rc [ 1 ] , 1 )
} else {
lc = contextData . match . lc ;
c = contextData . match . c ;
rc = contextData . match . rc ;
}
partElement = document . createElement ( "p" ) ;
for ( let cpos of lc ) {
token = contextData [ "cpos_lookup" ] [ cpos ] ;
partElement . insertAdjacentHTML ( "beforeend" , ` <span class="token" data-cpos=" ${ cpos } "> ${ token [ "word" ] } </span> ` ) ;
contextResultsElement . append ( partElement ) ;
}
for ( let cpos of c ) {
token = contextData [ "cpos_lookup" ] [ cpos ] ;
partElement . insertAdjacentHTML ( "beforeend" , ` <span class="token bold light-green" data-cpos=" ${ cpos } " style="text-decoration-line: underline;"> ${ token [ "word" ] } </span> ` ) ;
contextResultsElement . append ( partElement ) ;
}
for ( let cpos of rc ) {
token = contextData [ "cpos_lookup" ] [ cpos ] ;
partElement . insertAdjacentHTML ( "beforeend" , ` <span class="token" data-cpos=" ${ cpos } "> ${ token [ "word" ] } </span> ` ) ;
contextResultsElement . append ( partElement ) ;
}
if ( expertModeSwitchElement . checked ) {
tokenElements = partElement . getElementsByClassName ( "token" ) ;
console . log ( this ) ;
this . expertModeOn ( tokenElements , contextData ) ;
}
}
// ###### Display options changing live how the matches are being displayed ######
// Event function that changes the shown hits per page.
// Just alters the resultsList.page property
changeHitsPerPage ( event ) {
try {
resultsList . page = event . target . value ;
resultsList . update ( ) ;
nopaque . flash ( "Updated matches per page." )
} catch ( e ) {
console . log ( "resultsList has no results right now. Live update of items per page is useless for now." ) ;
}
}
// Event function triggered on context select change and also if pagination is clicked
changeContext ( event ) {
let newContextValue ;
let lc ;
let rc ;
let array ;
try {
if ( event . type === "change" ) {
nopaque . flash ( "Updated context per match!" ) ;
}
} catch ( e ) {
// console.log(e);
// console.log("This error is expected.");
} finally {
newContextValue = document . getElementById ( "display-options-form-result_context" ) . value ;
console . log ( "Context value is:" , newContextValue ) ;
lc = document . getElementsByClassName ( "left-context" ) ;
rc = document . getElementsByClassName ( "right-context" ) ;
for ( let element of lc ) {
array = Array . from ( element . childNodes ) ;
2020-04-08 07:46:37 +00:00
for ( let element of array . reverse ( ) . slice ( newContextValue ) ) {
2020-04-07 11:13:48 +00:00
element . classList . add ( "hide" ) ;
}
for ( let element of array . slice ( 0 , newContextValue ) ) {
element . classList . remove ( "hide" ) ;
}
}
for ( let element of rc ) {
array = Array . from ( element . childNodes ) ;
for ( let element of array . slice ( newContextValue ) ) {
element . classList . add ( "hide" ) ;
}
for ( let element of array . slice ( 0 , newContextValue ) ) {
element . classList . remove ( "hide" ) ;
}
}
}
}
// ###### Expert view event functions ######
// Event function to check if pagination is used and then look if
// expertModeSwitchElement is checked
// if checked than expertModeOn is executed
// if unchecked expertModeOff is executed
eventHandlerCheck ( event ) {
console . log ( "pagination used!" ) ;
console . log ( expertModeSwitchElement . checked ) ;
if ( expertModeSwitchElement . checked ) {
this . expertModeOn ( event . currentTarget . tokenElements , resultsJSON ) ;
} else if ( ! expertModeSwitchElement . checked ) {
event . preventDefault ( ) ;
console . log ( "prevented! Destroy" ) ;
this . expertModeOff ( event . currentTarget . tokenElements ) ;
}
}
// function to apply extra information and animation to every token
expertModeOn ( tokenElements , results ) {
let token ;
console . log ( "expertModeOn!" ) ;
for ( let tokenElement of tokenElements ) {
tokenElement . classList . add ( "chip" ) ;
tokenElement . classList . add ( "hoverable" ) ;
tokenElement . classList . add ( "expert-view" ) ;
token = results [ "cpos_lookup" ] [ tokenElement . dataset . cpos ] ;
tokenElement . addEventListener ( "mouseover" , ( event ) => {
console . log ( "Mouseover!" ) ;
console . log ( event . target ) ;
token = results [ "cpos_lookup" ] [ event . target . dataset . cpos ] ;
this . addToolTipToTokenElement ( event . target , token ) ;
} ) ;
}
}
// fuction that creates Tooltip for one token and extracts the corresponding
// infos from the result JSON
addToolTipToTokenElement ( tokenElement , token ) {
M . Tooltip . init ( tokenElement ,
{ "html" : ` <table>
< tr >
< th > Token information < / t h >
< th > Source information < / t h >
< / t r >
< tr >
< td class = "left-align" >
Word : $ { token [ "word" ] } < br >
Lemma : $ { token [ "lemma" ] } < br >
POS : $ { token [ "pos" ] } < br >
Simple POS : $ { token [ "simple_pos" ] } < br >
NER : $ { token [ "ner" ] }
< / t d >
< td class = "left-align" >
Title : $ { resultsJSON [ "text_lookup" ] [ token [ "text" ] ] [ "title" ] } < br >
Author : $ { resultsJSON [ "text_lookup" ] [ token [ "text" ] ] [ "author" ] } < br >
Publishing year : $ { resultsJSON [ "text_lookup" ] [ token [ "text" ] ] [ "publishing_year" ] }
< / t d >
< / t r >
< / t a b l e > ` } ) ;
}
// function to remove extra informations and animations from tokens
expertModeOff ( tokenElements ) {
console . log ( "expertModeOff!" ) ;
for ( let tokenElement of tokenElements ) {
tokenElement . classList . remove ( "chip" ) ;
tokenElement . classList . remove ( "hoverable" ) ;
tokenElement . classList . remove ( "expert-view" ) ;
tokenElement . outerHTML = tokenElement . outerHTML ; // this is actually a workaround, but it works pretty fast
}
}
2020-01-30 13:23:19 +00:00
createResultRowElement ( item , chunk ) {
2020-04-02 09:37:45 +00:00
let values , cpos , token , matchRowElement , lcCellElement , hitCellElement , rcCellElement , textTitlesCellElement , matchNrElement , lc , c , rc ;
2020-01-29 15:12:57 +00:00
// gather values from item
values = item . values ( ) ;
2020-04-02 09:37:45 +00:00
if ( chunk . cpos _ranges == true ) {
// python range like function from MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from#Sequence_generator_(range)
const range = ( start , stop , step ) => Array . from ( { length : ( stop - start ) / step + 1 } , ( _ , i ) => start + ( i * step ) ) ;
lc = range ( values . lc [ 0 ] , values . lc [ 1 ] , 1 )
c = range ( values . c [ 0 ] , values . c [ 1 ] , 1 )
rc = range ( values . rc [ 0 ] , values . rc [ 1 ] , 1 )
} else {
lc = values . lc ;
c = values . c ;
rc = values . rc ;
}
2020-01-29 15:12:57 +00:00
// get infos for full match row
matchRowElement = document . createElement ( "tr" ) ;
2020-02-03 11:58:40 +00:00
matchRowElement . setAttribute ( "data-index" , values [ "index" ] )
lcCellElement = document . createElement ( "td" ) ;
lcCellElement . classList . add ( "left-context" ) ;
matchRowElement . appendChild ( lcCellElement ) ;
2020-04-02 09:37:45 +00:00
for ( cpos of lc ) {
2020-01-29 15:12:57 +00:00
token = chunk [ "cpos_lookup" ] [ cpos ] ;
2020-02-03 11:58:40 +00:00
lcCellElement . insertAdjacentHTML ( "beforeend" , ` <span class="token" data-cpos=" ${ cpos } "> ${ token [ "word" ] } </span> ` ) ;
2020-01-29 15:12:57 +00:00
}
2020-02-03 11:58:40 +00:00
// get infos for hit of match
let textTitles = new Set ( ) ;
hitCellElement = document . createElement ( "td" ) ;
hitCellElement . classList . add ( "match-hit" ) ;
textTitlesCellElement = document . createElement ( "td" ) ;
textTitlesCellElement . classList . add ( "titles" ) ;
2020-02-03 12:59:37 +00:00
matchNrElement = document . createElement ( "td" ) ;
matchNrElement . classList . add ( "match-nr" ) ;
2020-02-03 11:58:40 +00:00
matchRowElement . appendChild ( hitCellElement ) ;
2020-04-02 09:37:45 +00:00
for ( cpos of c ) {
2020-02-03 11:58:40 +00:00
token = chunk [ "cpos_lookup" ] [ cpos ] ;
hitCellElement . insertAdjacentHTML ( "beforeend" , ` <span class="token" data-cpos=" ${ cpos } "> ${ token [ "word" ] } </span> ` ) ;
// get text titles of every hit cpos token
2020-04-07 14:25:44 +00:00
textTitles . add ( chunk [ "text_lookup" ] [ token [ "text" ] ] [ "title" ] ) ;
2020-02-03 11:58:40 +00:00
// add button to trigger more context to every match td
var inspectBtn = document . createElement ( "a" ) ;
2020-03-18 14:52:53 +00:00
inspectBtn . setAttribute ( "class" , "btn-floating btn-flat waves-effect waves-light grey right inspect disabled" ) ;
2020-02-03 11:58:40 +00:00
inspectBtn . innerHTML = '<i class="material-icons">search</i>' ;
2020-04-07 11:13:48 +00:00
inspectBtn . onclick = ( ) => { this . inspect ( values [ "index" ] ) } ;
2020-02-03 11:58:40 +00:00
}
// add text titles at front as first td of one row
hitCellElement . appendChild ( inspectBtn ) ;
textTitlesCellElement . innerText = [ ... textTitles ] . join ( ", " ) ;
matchRowElement . insertAdjacentHTML ( "afterbegin" , textTitlesCellElement . outerHTML ) ;
2020-02-03 12:59:37 +00:00
matchNrElement . innerText = values [ "index" ] + 1 ;
matchRowElement . insertAdjacentHTML ( "afterbegin" , matchNrElement . outerHTML ) ;
2020-02-03 11:58:40 +00:00
// get infos for right context of match
rcCellElement = document . createElement ( "td" ) ;
rcCellElement . classList . add ( "right-context" ) ;
matchRowElement . appendChild ( rcCellElement ) ;
2020-04-02 09:37:45 +00:00
for ( cpos of rc ) {
2020-02-03 11:58:40 +00:00
token = chunk [ "cpos_lookup" ] [ cpos ] ;
rcCellElement . insertAdjacentHTML ( "beforeend" , ` <span class="token" data-cpos=" ${ cpos } "> ${ token [ "word" ] } </span> ` ) ;
}
2020-01-30 13:23:19 +00:00
return matchRowElement
2020-01-29 15:12:57 +00:00
}
}